From 07d3fe304dcae24811ec15e49f07eefe9a656c14 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 27 Nov 2025 14:29:18 +0100 Subject: [PATCH] Revert "Merge branch 'backend' into 'main'" This reverts merge request !2 --- commons/src/main/java/commons/Recipe.java | 216 ---------------- commons/src/test/java/commons/RecipeTest.java | 121 --------- docs/recipe-api.md | 243 ------------------ .../java/server/api/RecipeController.java | 130 ---------- .../server/database/RecipeRepository.java | 22 -- .../application-mock-data-test.properties | 18 -- .../java/server/api/RecipeControllerTest.java | 149 ----------- 7 files changed, 899 deletions(-) delete mode 100644 commons/src/main/java/commons/Recipe.java delete mode 100644 commons/src/test/java/commons/RecipeTest.java delete mode 100644 docs/recipe-api.md delete mode 100644 server/src/main/java/server/api/RecipeController.java delete mode 100644 server/src/main/java/server/database/RecipeRepository.java delete mode 100644 server/src/main/resources/application-mock-data-test.properties delete mode 100644 server/src/test/java/server/api/RecipeControllerTest.java diff --git a/commons/src/main/java/commons/Recipe.java b/commons/src/main/java/commons/Recipe.java deleted file mode 100644 index 0472175..0000000 --- a/commons/src/main/java/commons/Recipe.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2021 Delft University of Technology - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package commons; - -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import jakarta.persistence.Entity; -import jakarta.persistence.CollectionTable; -import jakarta.persistence.Column; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OrderColumn; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.ElementCollection; - - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Collection; - -// TABLE named recipes -@Entity -@Table(name = "recipes") -public class Recipe { - - // PRIMARY Key, unique id for recipe, generated automatically. - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - @Column(name = "id", nullable = false, unique = true) - private Long id; - - // Recipe name - @Column(name = "name", nullable = false, unique = true) - private String name; - - /** - * Creates another table named recipe_ingredients which stores: - * recipe_ingredients(recipe_id -> recipes(id), ingredient). - *

- * Example recipe_ingredients table: - *

-     * | recipe_id           | ingredient |
-     * |---------------------|------------|
-     * | 0 (Chocolate Cake)  | Egg        |
-     * | 0 (Chocolate Cake)  | Egg        |
-     * | 0 (Chocolate Cake)  | Flour      |
-     * | 1 (Steak)           | 40g salt   |
-     * | 1 (Steak)           | 40g pepper |
-     * | 1 (Steak)           | Meat       |
-     * |----------------------------------|
-     * 
- * TODO: Replace String with Embeddable Ingredient Class - */ - @ElementCollection - @CollectionTable(name = "recipe_ingredients", joinColumns = @JoinColumn(name = "recipe_id")) - @Column(name = "ingredient") - private List ingredients = new ArrayList<>(); - - /** - * Creates another table named recipe_preparation which stores: - * recipe_preparation(recipe_id -> recipes(id), preparation_step, step_order). - *

- * Example recipe_preparation table: - *

-     * | recipe_id           | preparation_step     | step_order |
-     * |---------------------|----------------------|------------|
-     * | 0 (Chocolate Cake)  | Preheat oven         | 1          |
-     * | 0 (Chocolate Cake)  | Mix eggs and sugar   | 2          |
-     * | 0 (Chocolate Cake)  | Add flour gradually  | 3          |
-     * | 1 (Steak)           | Season meat          | 1          |
-     * | 1 (Steak)           | Heat pan             | 2          |
-     * |---------------------------------------------------------|
-     * 
- */ - @ElementCollection - @CollectionTable(name = "recipe_preparation", joinColumns = @JoinColumn(name = "recipe_id")) - @Column(name = "preparation_step") - @OrderColumn(name = "step_order") - private List preparationSteps = new ArrayList<>(); - - @SuppressWarnings("unused") - public Recipe() { - // for object mapper - } - - public Recipe(Long id, String name) { - // Not used by JPA/Spring - this.id = id; - this.name = name; - } - - // TODO: Replace String with Embeddable Ingredient Class for ingredients - public Recipe(Long id, String name, List ingredients, List preparationSteps) { - // Not used by JPA/Spring - this.id = id; - this.name = name; - this.ingredients = ingredients; - this.preparationSteps = preparationSteps; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - /** - * Returns an unmodifiable view of the ingredients list. - *

- * The returned list cannot be modified directly. To modify ingredients, - * create a copy using {@link List#copyOf(Collection)} or create your own list, - * populate it, and use {@link #setIngredients(List)} to update. - * - * @return An unmodifiable list of ingredients. - * @see #setIngredients(List) - */ - // TODO: Replace String with Embeddable Ingredient Class - public List getIngredients() { - // Disallow modifying the returned list. - // You can still copy it with List.copyOf(...) - return Collections.unmodifiableList(ingredients); - } - - - // TODO: Replace String with Embeddable Ingredient Class - public void setIngredients(List ingredients) { - this.ingredients = ingredients; - } - - /** - * Returns an unmodifiable view of the preparation steps list. - *

- * The returned list cannot be modified directly. To modify preparation steps, - * create a copy using {@link List#copyOf(Collection)} or create your own list, - * populate it, and use {@link #setPreparationSteps(List)} to update. - * - * @return An unmodifiable list of preparation steps in order. - * @see #setPreparationSteps(List) - */ - public List getPreparationSteps() { - // Disallow modifying the returned list. - // You can still copy it with List.copyOf(...) - return Collections.unmodifiableList(preparationSteps); - } - - public void setPreparationSteps(List preparationSteps) { - this.preparationSteps = preparationSteps; - } - - @Override - public boolean equals(Object o) { - // Faster/Better equals than reflectionEquals - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Recipe recipe = (Recipe) o; - return Objects.equals(id, recipe.id); // Check only for ID, as its unique! - } - - @Override - public int hashCode() { - return Objects.hash(id); // Use ID only, as its unique. - } - - @Override - public String toString() { - return "Recipe{" + - "name='" + name + '\'' + - ", ingredientsCount=" + ingredients.size() + - ", preparationStepsCount=" + preparationSteps.size() + - "}"; - } - - /** - * Returns a more detailed string than {@link #toString()} of this recipe, including - * the full contents of all ingredients and preparation steps. - *

- * Intended only for debugging. - * - * @return A detailed string representation containing all recipe data. - * @see #toString() - */ - @SuppressWarnings("unused") - public String toDetailedString() { - return "Recipe{" + - "name='" + name + '\'' + - ", ingredients=" + ingredients + - ", preparationSteps=" + preparationSteps + - '}'; - } - -} diff --git a/commons/src/test/java/commons/RecipeTest.java b/commons/src/test/java/commons/RecipeTest.java deleted file mode 100644 index db70bf2..0000000 --- a/commons/src/test/java/commons/RecipeTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package commons; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -class RecipeTest { - - Recipe recipe; - static final Long RECIPE_ID = 1L; - - @BeforeEach - void setupRecipe() { - this.recipe = new Recipe(RECIPE_ID, "Chocolate Cake"); - } - - @Test - void getId() { - assertEquals(RECIPE_ID, recipe.getId()); - } - - @Test - void setId() { - recipe.setId(RECIPE_ID + 1); - assertEquals(RECIPE_ID + 1, recipe.getId()); - } - - @Test - void getName() { - assertEquals("Chocolate Cake", recipe.getName()); - } - - @Test - void setName() { - recipe.setName("Steak"); - assertEquals("Steak", recipe.getName()); - } - - @Test - void getIngredientsAddThrow() { - // TODO: Change to actual Ingredient class later - assertThrows(UnsupportedOperationException.class, () -> recipe.getIngredients().add("Lasagna")); - } - - @Test - void getIngredientsClearThrow() { - assertThrows(UnsupportedOperationException.class, () -> recipe.getIngredients().clear()); - } - - @Test - void setIngredients() { - // TODO: Change to actual Ingredient class later - List ingredients = new ArrayList<>(List.of("Chocolate", "Flour", "Egg")); - recipe.setIngredients(ingredients); - - assertEquals(recipe.getIngredients(), ingredients); - assertEquals(recipe.getIngredients().size(), ingredients.size()); - } - - @Test - void getPreparationStepsAddThrow() { - assertThrows(UnsupportedOperationException.class, () -> recipe.getPreparationSteps().add("Preheat Oven")); - } - - @Test - void getPreparationStepsClearThrow() { - assertThrows(UnsupportedOperationException.class, () -> recipe.getPreparationSteps().clear()); - } - - @Test - void setPreparationSteps() { - List steps = new ArrayList<>(List.of("Preheat oven", "Mix stuff", "decorate")); - recipe.setPreparationSteps(steps); - - assertEquals(recipe.getPreparationSteps(), steps); - assertEquals(recipe.getPreparationSteps().size(), steps.size()); - } - - @Test - void testEqualsSame() { - Recipe recipe2 = new Recipe(RECIPE_ID, "Chocolate Cake"); - assertEquals(recipe, recipe2); - } - - @Test - void testEqualsSameExceptId() { - Recipe recipe2 = new Recipe(RECIPE_ID + 1, "Chocolate Cake"); - assertNotEquals(recipe, recipe2); - } - - @Test - void testEqualsOnlySameId() { - Recipe recipe2 = new Recipe(RECIPE_ID, "Some random recipe"); - assertEquals(recipe, recipe2); // Equals, we only look at ID!!! - } - - @Test - void testHashCodeSame() { - Recipe recipe2 = new Recipe(RECIPE_ID, "Chocolate Cake"); - - assertEquals(recipe.hashCode(), recipe2.hashCode()); - } - - @Test - void testHashCodeSameExceptId() { - Recipe recipe2 = new Recipe(RECIPE_ID + 1, "Chocolate Cake"); - - assertNotEquals(recipe.hashCode(), recipe2.hashCode()); - } - - @Test - void testHashCodeOnlySameId() { - Recipe recipe2 = new Recipe(RECIPE_ID, "Some random recipe"); - - assertEquals(recipe.hashCode(), recipe2.hashCode()); // Same, only looks at ID!!! - } -} \ No newline at end of file diff --git a/docs/recipe-api.md b/docs/recipe-api.md deleted file mode 100644 index e2b9b4f..0000000 --- a/docs/recipe-api.md +++ /dev/null @@ -1,243 +0,0 @@ -## Recipe API - -Base path: `/api` - -This API allows clients to create, read, update, and delete `Recipe` resources. - ---- - -## Endpoints - -### Get a Recipe by ID - -**GET** `/api/recipe/{id}` - -Retrieves a specific recipe by its unique identifier. - -* **Path Parameters** - - | Name | Type | Required | Description | - | ---- | ------ | -------- | ------------------------------ | - | `id` | `Long` | Yes | The ID of the recipe to fetch. | - -* **Responses** - - | Status Code | Description | - | --------------- | ------------------------------------- | - | `200 OK` | Returns the recipe with the given ID. | - | `404 Not Found` | No recipe exists with that ID. | - -* **Example Request** - - ```bash - curl -X GET "http://SERVER_ADDRESS/api/recipe/1" \ - -H "Accept: application/json" - ``` - -* **Example Response (200)** - - ```json - { - "id": 1, - "name": "Pancakes", - "ingredients": ["Ingredient 1", "Ingredient 2"], - "preparationSteps": ["Step 1", "Step 2"] - } - ``` - ---- - -### List Recipes - -**GET** `/api/recipes` - -Retrieves a list of recipes. Supports optional pagination via a `limit` query parameter. - -* **Query Parameters** - - | Name | Type | Required | Description | - | ------- | --------- | -------- | ---------------------------------------------------------------------------- | - | `limit` | `Integer` | No | Maximum number of recipes to return. If not provided, returns *all* recipes. | - -* **Responses** - - | Status Code | Description | - | ----------- | --------------------------------------------- | - | `200 OK` | Returns a list of recipes (possibly limited). | - -* **Example Request (no limit)** - - ```bash - curl -X GET "http://SERVER_ADDRESS/api/recipes" \ - -H "Accept: application/json" - ``` - -* **Example Request (with limit)** - - ```bash - curl -X GET "http://SERVER_ADDRESS/api/recipes?limit=10" \ - -H "Accept: application/json" - ``` - -* **Example Response (200)** - - ```json - [ - { - "id": 10, - "name": "Recipe 0", - "ingredients": ["Flour", "Milk"], - "preparationSteps": ["Do something", "Do something else"] - }, - { - "id": 11, - "name": "Recipe 1", - "ingredients": ["Flour", "Milk"], - "preparationSteps": ["Do something", "Do something else"] - } - // etc. max {limit} items - ] - ``` - ---- - -### Create a New Recipe - -**PUT** `/api/recipe/new` - -Creates a new recipe. The recipe name must be unique in the repository. - -* **Request Body** - - A JSON object representing the recipe. Example: - - ```json - { - "name": "Pancakes", - "ingredients": ["Flour", "Milk", "Eggs"], - "preparationSteps": ["Step 1", "Step 2"] - } - ``` - -* **Responses** - - | Status Code | Description | - | ----------------- | -------------------------------------------------------------------------------------------- | - | `200 OK` | The recipe was successfully created. Returns the created recipe (including its assigned ID). | - | `400 Bad Request` | A recipe with the same name already exists. | - -* **Example Request** - - ```bash - curl -X PUT "https://SERVER_ADDRESS/api/recipe/new" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "Pancakes", - "ingredients": ["Flour", "Milk", "Eggs"], - "preparationSteps": ["Step 1", "Step 2"] - }' - ``` - -* **Example Response (200)** - - ```json - { - "id": 125, - "name": "Pancakes", - "ingredients": ["Flour", "Milk", "Eggs"], - "preparationSteps": ["Step 1", "Step 2"] - } - ``` - ---- - -### Update an Existing Recipe - -**POST** `/api/recipe/{id}` - -Replaces or updates the recipe with the given ID. - -* **Path Parameters** - - | Name | Type | Required | Description | - | ---- | ------ | -------- | ------------------------------- | - | `id` | `Long` | Yes | The ID of the recipe to update. | - -* **Request Body** - - A JSON object containing the new recipe data. It is expected to include the ID (or the server-side save will override it), or at least map correctly to the stored entity. - - Example: - - ```json - { - "id": 123, - "name": "Better Pancakes", - "ingredients": ["Flour", "Almond milk", "Eggs"], - "preparationSteps": ["Step 10", "Step 11"] - } - ``` - -* **Responses** - - | Status Code | Description | - | ----------------- | ---------------------------------------------------------------- | - | `200 OK` | The recipe was successfully updated. Returns the updated recipe. | - | `400 Bad Request` | No recipe exists with the given ID. | - - * **Example Request** - - ```bash - curl -X POST "https://your-domain.com/api/recipe/123" \ - -H "Content-Type: application/json" \ - -d '{ - "id": 123, - "name": "Better Pancakes", - "ingredients": ["Flour", "Almond milk", "Eggs"], - "preparationSteps": ["Step 10", "Step 11"] - }' - ``` - -* **Example Response (200)** - - ```json - { - "id": 123, - "name": "Updated Pancakes", - "ingredients": ["Flour", "Almond milk", "Eggs"], - "preparationSteps": "Mix and fry differently." - } - ``` - ---- - -### Delete a Recipe - -**DELETE** `/api/recipe/{id}` - -Deletes the recipe with the given ID. - -* **Path Parameters** - - | Name | Type | Required | Description | - | ---- | ------ | -------- | ------------------------------- | - | `id` | `Long` | Yes | The ID of the recipe to delete. | - -* **Responses** - - | Status Code | Description | - | ----------------- | ---------------------------------------------------- | - | `200 OK` | The recipe was successfully deleted. Returns `true`. | - | `400 Bad Request` | No recipe exists with the given ID. | - -* **Example Request** - - ```bash - curl -X DELETE "https://your-domain.com/api/recipe/123" - ``` - -* **Example Response (200)** - - ```json - true - ``` \ No newline at end of file diff --git a/server/src/main/java/server/api/RecipeController.java b/server/src/main/java/server/api/RecipeController.java deleted file mode 100644 index a1d79fe..0000000 --- a/server/src/main/java/server/api/RecipeController.java +++ /dev/null @@ -1,130 +0,0 @@ -package server.api; - -import commons.Recipe; - -import org.springframework.data.domain.Example; -import org.springframework.data.domain.PageRequest; -import org.springframework.http.ResponseEntity; - -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import server.database.RecipeRepository; - -import java.util.List; -import java.util.Optional; - -@RestController -@RequestMapping("/api") -public class RecipeController { - private final RecipeRepository recipeRepository; // JPA repository used in this controller - - public RecipeController(RecipeRepository recipeRepository) { - this.recipeRepository = recipeRepository; - } - - /** - * Mapping for GET /recipe/{id} - *

- * Gets a specific recipe by its unique id. - *

- * @param id id of the recipe - * @return The recipe if it exists in the repository; otherwise returns 404 Not Found status - */ - @GetMapping("/recipe/{id}") - public ResponseEntity getRecipe(@PathVariable Long id) { - if (!recipeRepository.existsById(id)) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(recipeRepository.findById(id).get()); - } - - /** - * Mapping for GET /recipes(?limit=) - *

- * If the limit parameter is unspecified, return all recipes in the repository. - * @param limit Integer limit of items you want to get - * @return The list of recipes - */ - @GetMapping("/recipes") - public ResponseEntity> getRecipes(@RequestParam Optional limit) { - if (limit.isPresent()) { - return ResponseEntity.ok( - recipeRepository.findAll( - PageRequest.of(0, limit.get()) - ).toList()); - } - return ResponseEntity.ok(recipeRepository.findAll()); - } - - /** - * Mapping for POST /recipe/{id} - * @param id The recipe id to replace - * @param recipe The new recipe to be replaced from the original - * @return The changed recipe; returns 400 Bad Request if the recipe does not exist - */ - @PostMapping("/recipe/{id}") - public ResponseEntity updateRecipe(@PathVariable Long id, @RequestBody Recipe recipe) { - if (!recipeRepository.existsById(id)) { - return ResponseEntity.badRequest().build(); - } - - // TODO: Send WS update to all subscribers with the updated recipe - - return ResponseEntity.ok(recipeRepository.save(recipe)); - } - - /** - * Mapping for PUT /recipe/new - *

- * Inserts a new recipe into the repository - *

- * @param recipe The new recipe as a request body - * @return 200 OK with the recipe you added; or 400 Bad Request if the recipe already exists by name - */ - @PutMapping("/recipe/new") - public ResponseEntity createRecipe(@RequestBody Recipe recipe) { - - // We initialize a new example recipe with the name of input recipe - // This is the only attribute we are concerned about making sure it's unique - Recipe example = new Recipe(); - example.setName(recipe.getName()); - - /* Here we use very funny JPA magic repository.exists(Example) - We check if any recipe in the repository has the same name as the input - */ - if (recipeRepository.exists(Example.of(example))) { - return ResponseEntity.badRequest().build(); - } - - // TODO: Send WS update to all subscribers with the new recipe - - return ResponseEntity.ok(recipeRepository.save(recipe)); - } - - /** - * Mapping for DELETE /recipe/{id} - *

- * Deletes a recipe identified by its id. - *

- * @param id The id of the recipe to be deleted. - * @return 200 OK with true; or 400 Bad Request if the recipe doesn't exist. - */ - @DeleteMapping("/recipe/{id}") - public ResponseEntity deleteRecipe(@PathVariable Long id) { - if (!recipeRepository.existsById(id)) { - return ResponseEntity.badRequest().build(); - } - recipeRepository.deleteById(id); - - // TODO: Send WS update to propagate deletion - return ResponseEntity.ok(true); - } -} diff --git a/server/src/main/java/server/database/RecipeRepository.java b/server/src/main/java/server/database/RecipeRepository.java deleted file mode 100644 index 60ec130..0000000 --- a/server/src/main/java/server/database/RecipeRepository.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2021 Delft University of Technology - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package server.database; - -import org.springframework.data.jpa.repository.JpaRepository; - -import commons.Recipe; - -public interface RecipeRepository extends JpaRepository {} \ No newline at end of file diff --git a/server/src/main/resources/application-mock-data-test.properties b/server/src/main/resources/application-mock-data-test.properties deleted file mode 100644 index c68d6fa..0000000 --- a/server/src/main/resources/application-mock-data-test.properties +++ /dev/null @@ -1,18 +0,0 @@ -spring.datasource.driverClassName=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password= -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect - -# use one of these alternatives... -# ... purely in-memory, wiped on restart, but great for testing -spring.datasource.url=jdbc:h2:mem:testdb -# ... persisted on disk (in project directory) -#spring.datasource.url=jdbc:h2:file:./h2-database - -# enable DB view on http://localhost:8080/h2-console -spring.h2.console.enabled=true - -# strategy for table (re-)generation -spring.jpa.hibernate.ddl-auto=update -# show auto-generated SQL commands -#spring.jpa.hibernate.show_sql=true diff --git a/server/src/test/java/server/api/RecipeControllerTest.java b/server/src/test/java/server/api/RecipeControllerTest.java deleted file mode 100644 index f1a766e..0000000 --- a/server/src/test/java/server/api/RecipeControllerTest.java +++ /dev/null @@ -1,149 +0,0 @@ -package server.api; - - -import commons.Recipe; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.http.HttpStatus; -import org.springframework.test.context.ActiveProfiles; -import server.database.RecipeRepository; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.LongStream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -// Spring Boot unit testing magic -// Before each test the state of the repository is reset by -// rolling back transaction of changes from previous test -@DataJpaTest - -// This test sources its application profile from -// resources/application-mock-data-test.properties -// This config uses an in-memory database -@ActiveProfiles("mock-data-test") -public class RecipeControllerTest { - private RecipeController controller; - private List recipes; - private final RecipeRepository recipeRepository; - private List recipeIds; - public static final int NUM_RECIPES = 10; - - // Injects a test repository into the test class - @Autowired - public RecipeControllerTest(RecipeRepository recipeRepository) { - this.recipeRepository = recipeRepository; - } - - @BeforeEach - public void setup(TestInfo info) { - recipes = LongStream - .range(0, NUM_RECIPES) - .mapToObj(x -> new Recipe(null, "Recipe " + x, List.of(), List.of())) - .toList(); - controller = new RecipeController(recipeRepository); - Set tags = info.getTags(); - List ids = new ArrayList<>(); - - // Some tests want initial data to be created. - if (tags.contains("test-from-init-data")) { - ids = LongStream - .range(0, NUM_RECIPES) - .map(idx -> recipeRepository.save(recipes.get((int) idx)).getId()) - .boxed().toList(); - } - - // Some tests need to know the stored IDs of objects - if (tags.contains("need-ids")) { - recipeIds = ids; - } - - // If no tags specified, the repository is initialized as empty. - } - @Test - public void createOneRecipe() { - controller.createRecipe(recipes.getFirst()); - - // There is 1 recipe in the repository - assertEquals(1, recipeRepository.count()); - } - @Test - public void createManyRecipes() { - recipes.forEach(recipe -> controller.createRecipe(recipe)); - - // There are the same number of recipes in the repository as the input list - assertEquals(recipes.size(), recipeRepository.count()); - } - @Test - @Tag("test-from-init-data") - public void getManyRecipes() { - // The number of recipes returned is the same as the entire input list - assertEquals(recipes.size(), controller.getRecipes(Optional.empty()).getBody().size()); - } - @Test - @Tag("test-from-init-data") - public void getSomeRecipes() { - final int LIMIT = 5; - // The number of recipes returned is the same as the entire input list - assertEquals(LIMIT, controller.getRecipes(Optional.of(LIMIT)).getBody().size()); - } - @Test - @Tag("test-from-init-data") - @Tag("need-ids") - public void findOneRecipeExists() { - final int CHECK_INDEX = 3; - // The third item in the input list is the same as the third item retrieved from the database - assertEquals( - recipes.get(CHECK_INDEX), - controller.getRecipe(recipeIds.get(CHECK_INDEX)).getBody()); - } - @Test - public void findOneRecipeNotExists() { - final int CHECK_INDEX = 3; - // There does not exist a recipe with ID=3 since there are no items in the repository. - assertEquals( - HttpStatus.NOT_FOUND, - controller.getRecipe((long) CHECK_INDEX).getStatusCode()); - } - @Test - @Tag("test-from-init-data") - @Tag("need-ids") - public void deleteOneRecipeGood() { - final int DELETE_INDEX = 5; - - // The object has been successfully deleted - assertEquals(HttpStatus.OK, controller.deleteRecipe(recipeIds.get(DELETE_INDEX)).getStatusCode()); - } - @Test - @Tag("test-from-init-data") - @Tag("need-ids") - public void deleteOneRecipeCountGood() { - final int DELETE_INDEX = 5; - controller.deleteRecipe(recipeIds.get(DELETE_INDEX)); - // The count of items decreased by 1 after the 5th item has been removed. - assertEquals(recipeIds.size() - 1, recipeRepository.count()); - } - @Test - public void deleteOneRecipeFail() { - final Long DELETE_INDEX = 5L; - assertEquals(HttpStatus.BAD_REQUEST, controller.deleteRecipe(DELETE_INDEX).getStatusCode()); - } - - @Test - @Tag("test-from-init-data") - @Tag("need-ids") - public void updateOneRecipeHasNewData() { - final int UPDATE_INDEX = 5; - Recipe newRecipe = controller.getRecipe(recipeIds.get(UPDATE_INDEX)).getBody(); - newRecipe.setName("New recipe"); - controller.updateRecipe(newRecipe.getId(), newRecipe); - assertEquals("New recipe", recipeRepository.getReferenceById(recipeIds.get(UPDATE_INDEX)).getName()); - } -}