From 3af808ef58effd1af8b275d4dc2541444fd11df0 Mon Sep 17 00:00:00 2001 From: Natalia Cholewa Date: Fri, 5 Dec 2025 14:38:43 +0100 Subject: [PATCH 1/4] feat: ingredient controller, websocket messages, ingredient controller tests --- commons/src/main/java/commons/Ingredient.java | 5 +- commons/src/main/java/commons/ws/Topics.java | 1 + .../ws/messages/CreateIngredientMessage.java | 30 +++ .../ws/messages/DeleteIngredientMessage.java | 28 +++ .../java/commons/ws/messages/Message.java | 23 +- .../ws/messages/UpdateIngredientMessage.java | 30 +++ server/pom.xml | 6 + .../java/server/api/IngredientController.java | 205 ++++++++++++++++++ .../java/server/api/RecipeController.java | 3 +- .../server/api/UpdateMessagingController.java | 3 +- .../{ => database}/IngredientRepository.java | 5 +- .../RecipeIngredientRepository.java | 2 +- .../server/api/IngredientControllerTest.java | 166 ++++++++++++++ 13 files changed, 498 insertions(+), 9 deletions(-) create mode 100644 commons/src/main/java/commons/ws/messages/CreateIngredientMessage.java create mode 100644 commons/src/main/java/commons/ws/messages/DeleteIngredientMessage.java create mode 100644 commons/src/main/java/commons/ws/messages/UpdateIngredientMessage.java create mode 100644 server/src/main/java/server/api/IngredientController.java rename server/src/main/java/server/{ => database}/IngredientRepository.java (57%) rename server/src/main/java/server/{ => database}/RecipeIngredientRepository.java (92%) create mode 100644 server/src/test/java/server/api/IngredientControllerTest.java diff --git a/commons/src/main/java/commons/Ingredient.java b/commons/src/main/java/commons/Ingredient.java index f224f2f..23b2223 100644 --- a/commons/src/main/java/commons/Ingredient.java +++ b/commons/src/main/java/commons/Ingredient.java @@ -33,10 +33,7 @@ public class Ingredient { @Column(name = "carbs", nullable = false) public double carbsPer100g; - @SuppressWarnings("unused") - protected Ingredient() { - // for object mapper says sebastian - } + public Ingredient() {} public Ingredient(String name, double proteinPer100g, diff --git a/commons/src/main/java/commons/ws/Topics.java b/commons/src/main/java/commons/ws/Topics.java index 9eb8d9f..dc407fb 100644 --- a/commons/src/main/java/commons/ws/Topics.java +++ b/commons/src/main/java/commons/ws/Topics.java @@ -2,4 +2,5 @@ package commons.ws; public class Topics { public static final String RECIPES = "/subscribe/recipe"; + public static final String INGREDIENTS = "/subscribe/ingredient"; } diff --git a/commons/src/main/java/commons/ws/messages/CreateIngredientMessage.java b/commons/src/main/java/commons/ws/messages/CreateIngredientMessage.java new file mode 100644 index 0000000..a6392cb --- /dev/null +++ b/commons/src/main/java/commons/ws/messages/CreateIngredientMessage.java @@ -0,0 +1,30 @@ +package commons.ws.messages; + +import commons.Ingredient; + +/** + * Message sent when a new ingredient is created. + * + * @see commons.ws.messages.Message.Type#INGREDIENT_CREATE + */ +public class CreateIngredientMessage implements Message { + private Ingredient ingredient; + + public CreateIngredientMessage(Ingredient ingredient) { + this.ingredient = ingredient; + } + + @Override + public Type getType() { + return Type.INGREDIENT_CREATE; + } + + /** + * Get the created ingredient. + * + * @return The created ingredient. + */ + public Ingredient getIngredient() { + return ingredient; + } +} diff --git a/commons/src/main/java/commons/ws/messages/DeleteIngredientMessage.java b/commons/src/main/java/commons/ws/messages/DeleteIngredientMessage.java new file mode 100644 index 0000000..879df60 --- /dev/null +++ b/commons/src/main/java/commons/ws/messages/DeleteIngredientMessage.java @@ -0,0 +1,28 @@ +package commons.ws.messages; + +/** + * Message sent when an ingredient is deleted. + * + * @see commons.ws.messages.Message.Type#INGREDIENT_DELETE + */ +public class DeleteIngredientMessage implements Message { + private Long ingredientId; + + public DeleteIngredientMessage(Long ingredientId) { + this.ingredientId = ingredientId; + } + + @Override + public Type getType() { + return Type.INGREDIENT_DELETE; + } + + /** + * Get the deleted ingredient's id. + * + * @return The deleted ingredient's id. + */ + public Long getIngredientId() { + return ingredientId; + } +} diff --git a/commons/src/main/java/commons/ws/messages/Message.java b/commons/src/main/java/commons/ws/messages/Message.java index 681474f..9e20df0 100644 --- a/commons/src/main/java/commons/ws/messages/Message.java +++ b/commons/src/main/java/commons/ws/messages/Message.java @@ -21,7 +21,28 @@ public interface Message { * * @see commons.ws.messages.DeleteRecipeMessage */ - RECIPE_DELETE + RECIPE_DELETE, + + /** + * Message sent when a new ingredient is created. + * + * @see commons.ws.messages.CreateIngredientMessage + */ + INGREDIENT_CREATE, + + /** + * Message sent when an existing ingredient is updated. + * + * @see commons.ws.messages.UpdateIngredientMessage + */ + INGREDIENT_UPDATE, + + /** + * Message sent when an ingredient is deleted. + * + * @see commons.ws.messages.DeleteIngredientMessage + */ + INGREDIENT_DELETE } /** diff --git a/commons/src/main/java/commons/ws/messages/UpdateIngredientMessage.java b/commons/src/main/java/commons/ws/messages/UpdateIngredientMessage.java new file mode 100644 index 0000000..e997873 --- /dev/null +++ b/commons/src/main/java/commons/ws/messages/UpdateIngredientMessage.java @@ -0,0 +1,30 @@ +package commons.ws.messages; + +import commons.Ingredient; + +/** + * Message sent when an ingredient is updated. + * + * @see commons.ws.messages.Message.Type#INGREDIENT_UPDATAE + */ +public class UpdateIngredientMessage implements Message { + private Ingredient ingredient; + + public UpdateIngredientMessage(Ingredient ingredient) { + this.ingredient = ingredient; + } + + @Override + public Type getType() { + return Type.INGREDIENT_UPDATE; + } + + /** + * Get the updated ingredient. + * + * @return The updated ingredient. + */ + public Ingredient getIngredient() { + return ingredient; + } +} diff --git a/server/pom.xml b/server/pom.xml index bd9a370..2c4cb0f 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -47,6 +47,12 @@ spring-boot-starter-test test + + org.glassfish.hk2 + hk2-api + 3.0.6 + compile + diff --git a/server/src/main/java/server/api/IngredientController.java b/server/src/main/java/server/api/IngredientController.java new file mode 100644 index 0000000..41d00be --- /dev/null +++ b/server/src/main/java/server/api/IngredientController.java @@ -0,0 +1,205 @@ +package server.api; + +import commons.Ingredient; +import commons.ws.Topics; +import commons.ws.messages.CreateIngredientMessage; +import commons.ws.messages.DeleteIngredientMessage; +import commons.ws.messages.UpdateIngredientMessage; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.ResponseEntity; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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.IngredientRepository; + +import java.util.Optional; +import java.util.List; + +/** + * REST controller for managing ingredients. + *

+ * Exposes the following endpoints: + *

+ *

+ * + * @see Ingredient + * @see IngredientRepository + */ +@RestController +@RequestMapping("/api") +public class IngredientController { + private final IngredientRepository ingredientRepository; + private final SimpMessagingTemplate messagingTemplate; + + public IngredientController(IngredientRepository ingredientRepository, + SimpMessagingTemplate messagingTemplate) { + this.ingredientRepository = ingredientRepository; + this.messagingTemplate = messagingTemplate; + } + + /** + * Get a list of ingredients, optionally paginated.
+ * Maps to GET /api/ingredients(?page=&limit=) + *

+ * If no limit is specified, all ingredients are returned sorted by name ascending. + * When calling this function, consider using pagination to avoid large responses. + *

+ * + *

+ * When using pagination, you should provide a limit. + * The page defaults to 0 if not provided. + *

+ * + * @param page The page number to retrieve (0-indexed). Optional. + * @param limit The maximum number of ingredients to return. Optional. + * @return A ResponseEntity containing the list of ingredients. + * + * @see Ingredient + */ + @GetMapping("/ingredients") + public ResponseEntity> getIngredients( + @RequestParam Optional page, + @RequestParam Optional limit + ) { + List ingredients = limit + .map(l -> { + return ingredientRepository.findAllByOrderByNameAsc +(PageRequest.of(page.orElse(0), l)).toList(); + }) + .orElseGet(ingredientRepository::findAllByOrderByNameAsc); + + return ResponseEntity.ok(ingredients); + } + + /** + * Get a specific ingredient by its ID. + * Maps to GET /api/ingredients/{id} + * + *

+ * Returns 200 OK with the ingredient if found, + * or 404 Not Found if the ingredient does not exist. + *

+ * + * @param id The ID of the ingredient to retrieve. + * @return The ingredient wrapped in a ResponseEntity. + * + * @see Ingredient + */ + @GetMapping("/ingredients/{id}") + public ResponseEntity getIngredientById(@PathVariable Long id) { + return ingredientRepository.findById(id) + .map(ResponseEntity::ok) + .orElseGet(() -> ResponseEntity.notFound().build()); + } + + /** + * Update an existing ingredient by its ID. + * Maps to PATCH /api/ingredients/{id} + * + *

+ * If the ingredient with the specified ID does not exist, + * returns 404 Not Found. + *

+ * If the ingredient exists, updates it with the provided data + * and returns the updated ingredient with 200 OK. + *

+ * + * @param id The ID of the ingredient to update. + * @param updated The updated ingredient data. + * @return The updated ingredient wrapped in a ResponseEntity. + * + * @see Ingredient + */ + @PatchMapping("/ingredients/{id}") + public ResponseEntity updateIngredient( + @PathVariable Long id, + @RequestBody Ingredient updated + ) { + if (!ingredientRepository.existsById(id)) { + return ResponseEntity.notFound().build(); + } + + // TODO: Refactor to use setters + updated.id = id; + Ingredient savedIngredient = ingredientRepository.save(updated); + messagingTemplate.convertAndSend(Topics.INGREDIENTS, new CreateIngredientMessage(savedIngredient)); + + return ResponseEntity.ok(savedIngredient); + } + + /** + * Create a new ingredient. + * Maps to POST /api/ingredients + * + *

+ * If an ingredient with the same name already exists, + * returns 400 Bad Request. + * + * If the ingredient is created successfully, + * returns the created ingredient with 200 OK. + *

+ * + * @param ingredient The ingredient to create. + * @return The created ingredient wrapped in a ResponseEntity. + * + * @see Ingredient + */ + @PostMapping("/ingredients") + public ResponseEntity createIngredient(@RequestBody Ingredient ingredient) { + if (ingredient.name == null || ingredient.name.isEmpty()) { + return ResponseEntity.badRequest().build(); + } + + Ingredient example = new Ingredient(); + example.name = ingredient.name; + + if (ingredientRepository.exists(Example.of(example))) { + return ResponseEntity.badRequest().build(); + } + + Ingredient saved = ingredientRepository.save(ingredient); + messagingTemplate.convertAndSend(Topics.INGREDIENTS, new UpdateIngredientMessage(saved)); + + return ResponseEntity.ok(saved); + } + + /** + * Delete an ingredient by its ID. + * Maps to DELETE /api/ingredients/{id} + * + *

+ * Returns 404 Not Found if the ingredient does not exist. + * If the ingredient is deleted successfully, returns 200 OK with true. + *

+ * + * @param id The ID of the ingredient to delete. + * @return A ResponseEntity indicating the result of the operation. + * + * @see Ingredient + */ + @DeleteMapping("/ingredients/{id}") + public ResponseEntity deleteIngredient(@PathVariable Long id) { + if (!ingredientRepository.existsById(id)) { + return ResponseEntity.notFound().build(); + } + + ingredientRepository.deleteById(id); + messagingTemplate.convertAndSend(Topics.INGREDIENTS, new DeleteIngredientMessage(id)); + + return ResponseEntity.ok(true); + } +} diff --git a/server/src/main/java/server/api/RecipeController.java b/server/src/main/java/server/api/RecipeController.java index 989f9f0..403de13 100644 --- a/server/src/main/java/server/api/RecipeController.java +++ b/server/src/main/java/server/api/RecipeController.java @@ -32,7 +32,8 @@ public class RecipeController { private final RecipeRepository recipeRepository; // JPA repository used in this controller private final SimpMessagingTemplate messagingTemplate; - public RecipeController(RecipeRepository recipeRepository, SimpMessagingTemplate messagingTemplate) { + public RecipeController(RecipeRepository recipeRepository, + SimpMessagingTemplate messagingTemplate) { this.recipeRepository = recipeRepository; this.messagingTemplate = messagingTemplate; } diff --git a/server/src/main/java/server/api/UpdateMessagingController.java b/server/src/main/java/server/api/UpdateMessagingController.java index a78d0fb..e7e75bd 100644 --- a/server/src/main/java/server/api/UpdateMessagingController.java +++ b/server/src/main/java/server/api/UpdateMessagingController.java @@ -1,6 +1,7 @@ package server.api; import commons.Recipe; +import commons.ws.Topics; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.messaging.handler.annotation.MessageMapping; @@ -22,7 +23,7 @@ public class UpdateMessagingController { * @return The updated {@link Recipe} object wrapped in a {@link org.springframework.http.ResponseEntity}. */ @MessageMapping("/updates/recipe") - @SendTo("/subscribe/recipe") + @SendTo(Topics.RECIPES) public ResponseEntity broadcastRecipeUpdate(Recipe recipe) { return recipeController.updateRecipe(recipe.getId(), recipe); } diff --git a/server/src/main/java/server/IngredientRepository.java b/server/src/main/java/server/database/IngredientRepository.java similarity index 57% rename from server/src/main/java/server/IngredientRepository.java rename to server/src/main/java/server/database/IngredientRepository.java index fe3a155..ea32d67 100644 --- a/server/src/main/java/server/IngredientRepository.java +++ b/server/src/main/java/server/database/IngredientRepository.java @@ -1,11 +1,14 @@ -package server; +package server.database; import commons.Ingredient; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface IngredientRepository extends JpaRepository { List findAllByOrderByNameAsc(); + Page findAllByOrderByNameAsc(Pageable pageable); } diff --git a/server/src/main/java/server/RecipeIngredientRepository.java b/server/src/main/java/server/database/RecipeIngredientRepository.java similarity index 92% rename from server/src/main/java/server/RecipeIngredientRepository.java rename to server/src/main/java/server/database/RecipeIngredientRepository.java index 9ebbb12..9f3264e 100644 --- a/server/src/main/java/server/RecipeIngredientRepository.java +++ b/server/src/main/java/server/database/RecipeIngredientRepository.java @@ -1,4 +1,4 @@ -package server; +package server.database; import commons.RecipeIngredient; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/server/src/test/java/server/api/IngredientControllerTest.java b/server/src/test/java/server/api/IngredientControllerTest.java new file mode 100644 index 0000000..71abef8 --- /dev/null +++ b/server/src/test/java/server/api/IngredientControllerTest.java @@ -0,0 +1,166 @@ +package server.api; + +import commons.Ingredient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpStatusCode; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.test.context.ActiveProfiles; +import server.database.IngredientRepository; +import server.WebSocketConfig; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +@DataJpaTest +@ActiveProfiles("mock-data-test") +@Import(WebSocketConfig.class) +public class IngredientControllerTest { + private final SimpMessagingTemplate template; + private final IngredientRepository ingredientRepository; + private IngredientController controller; + + @Autowired + public IngredientControllerTest(IngredientRepository ingredientRepository, + SimpMessagingTemplate template) { + this.ingredientRepository = ingredientRepository; + this.template = template; + } + + private void createInitialIngredients() { + ingredientRepository.deleteAll(); + + Stream.of("Salt", "Sugar", "Flour", "Eggs", "Milk") + .map(name -> { + return new Ingredient(name, 1.0, 2.0, 3.0); + }) + .forEach(ingredientRepository::save); + } + + @BeforeEach + public void setup() { + controller = new IngredientController(ingredientRepository, template); + + this.createInitialIngredients(); + } + + @Test + public void testGetAllIngredients() { + List ingredients = controller.getIngredients(Optional.empty(), Optional.empty()).getBody(); + + assertNotNull(ingredients); + assertEquals(5, ingredients.size()); + assertEquals("Eggs", ingredients.getFirst().name); + } + + @Test + public void testGetPaginatedIngredients() { + List ingredients = controller.getIngredients(Optional.of(0), Optional.of(2)).getBody(); + + assertNotNull(ingredients); + assertEquals(2, ingredients.size()); + assertEquals("Eggs", ingredients.get(0).name); + assertEquals("Flour", ingredients.get(1).name); + } + + @Test + public void testGetIngredientById() { + Ingredient ingredient = ingredientRepository.findAll().getFirst(); + Long id = ingredient.id; + + Ingredient fetchedIngredient = controller.getIngredientById(id).getBody(); + + assertNotNull(fetchedIngredient); + assertEquals(ingredient.name, fetchedIngredient.name); + } + + @Test + public void testGetIngredientByInvalidId() { + Long invalidId = 2137L; + + var response = controller.getIngredientById(invalidId); + + assertEquals(HttpStatusCode.valueOf(404), response.getStatusCode()); + } + + @Test + public void testCreateIngredient() { + Ingredient newIngredient = new Ingredient("Butter", 0.5, 1.0, 1.5); + + Ingredient createdIngredient = controller.createIngredient(newIngredient).getBody(); + + assertNotNull(createdIngredient); + assertEquals("Butter", createdIngredient.name); + assertEquals(6, ingredientRepository.count()); + } + + @Test + public void testCreateIngredientMissingName() { + Ingredient newIngredient = new Ingredient(null, 0.5, 1.0, 1.5); + + var response = controller.createIngredient(newIngredient); + + assertEquals(HttpStatusCode.valueOf(400), response.getStatusCode()); + } + + @Test + public void testUpdateIngredient() { + Ingredient ingredient = ingredientRepository.findAll() + .stream() + .filter(i -> i.name.equals("Salt")) + .findFirst() + .get(); // Should exist, no need for a check + + Long id = ingredient.id; + + Ingredient updatedData = new Ingredient("Sea Salt", 1.5, 2.5, 3.5); + + Ingredient updatedIngredient = controller.updateIngredient(id, updatedData).getBody(); + + assertNotNull(updatedIngredient); + assertEquals("Sea Salt", updatedIngredient.name); + assertEquals(1.5, updatedIngredient.proteinPer100g); + } + + @Test + public void testUpdateMissingIngredient() { + Long invalidId = 2137L; + + Ingredient updatedData = new Ingredient("Sea Salt", 1.5, 2.5, 3.5); + + var response = controller.updateIngredient(invalidId, updatedData); + + assertEquals(HttpStatusCode.valueOf(404), response.getStatusCode()); + } + + @Test + public void testDeleteIngredient() { + Ingredient ingredient = ingredientRepository.findAll() + .stream() + .filter(i -> i.name.equals("Sugar")) + .findFirst() + .get(); // Should exist, no need for a check + + Long id = ingredient.id; + + var response = controller.deleteIngredient(id); + + assertEquals(HttpStatusCode.valueOf(200), response.getStatusCode()); + assertEquals(4, ingredientRepository.count()); + } + + @Test + public void testDeleteMissingIngredient() { + Long invalidId = 2137L; + + var response = controller.deleteIngredient(invalidId); + + assertEquals(HttpStatusCode.valueOf(404), response.getStatusCode()); + } +} From 6b659a2ced3eed62708f4dc0a5929af4b974310f Mon Sep 17 00:00:00 2001 From: Natalia Cholewa Date: Fri, 5 Dec 2025 14:40:12 +0100 Subject: [PATCH 2/4] fix: formatting in ingredient controller --- server/src/main/java/server/api/IngredientController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/server/api/IngredientController.java b/server/src/main/java/server/api/IngredientController.java index 41d00be..7015aca 100644 --- a/server/src/main/java/server/api/IngredientController.java +++ b/server/src/main/java/server/api/IngredientController.java @@ -77,8 +77,9 @@ public class IngredientController { ) { List ingredients = limit .map(l -> { - return ingredientRepository.findAllByOrderByNameAsc -(PageRequest.of(page.orElse(0), l)).toList(); + return ingredientRepository.findAllByOrderByNameAsc( + PageRequest.of(page.orElse(0), l) + ).toList(); }) .orElseGet(ingredientRepository::findAllByOrderByNameAsc); From 6d5f7af2256bb36978f5a02826206f3aaabf4c18 Mon Sep 17 00:00:00 2001 From: Natalia Cholewa Date: Fri, 5 Dec 2025 14:47:30 +0100 Subject: [PATCH 3/4] fix: the 26 checkstyle violations in tests (Thank you checkstyle) --- .../server/api/IngredientControllerTest.java | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/server/src/test/java/server/api/IngredientControllerTest.java b/server/src/test/java/server/api/IngredientControllerTest.java index 71abef8..57523b9 100644 --- a/server/src/test/java/server/api/IngredientControllerTest.java +++ b/server/src/test/java/server/api/IngredientControllerTest.java @@ -26,6 +26,20 @@ public class IngredientControllerTest { private final IngredientRepository ingredientRepository; private IngredientController controller; + private static final double PROTEIN_BASE = 1.0; + private static final double FAT_BASE = 2.0; + private static final double CARBS_BASE = 2.0; + + private static final double PROTEIN_ALT = 0.5; + private static final double FAT_ALT = 1.0; + private static final double CARBS_ALT = 1.5; + + private static final int OK_STATUS = 200; + private static final int BAD_REQUEST_STATUS = 400; + private static final int NOT_FOUND_STATUS = 404; + + private static final Long INVALID_ID = 2137L; + @Autowired public IngredientControllerTest(IngredientRepository ingredientRepository, SimpMessagingTemplate template) { @@ -38,7 +52,7 @@ public class IngredientControllerTest { Stream.of("Salt", "Sugar", "Flour", "Eggs", "Milk") .map(name -> { - return new Ingredient(name, 1.0, 2.0, 3.0); + return new Ingredient(name, PROTEIN_BASE, FAT_BASE, CARBS_BASE); }) .forEach(ingredientRepository::save); } @@ -55,16 +69,19 @@ public class IngredientControllerTest { List ingredients = controller.getIngredients(Optional.empty(), Optional.empty()).getBody(); assertNotNull(ingredients); - assertEquals(5, ingredients.size()); + final int expectedCount = 5; + assertEquals(expectedCount, ingredients.size()); assertEquals("Eggs", ingredients.getFirst().name); } @Test public void testGetPaginatedIngredients() { - List ingredients = controller.getIngredients(Optional.of(0), Optional.of(2)).getBody(); + final int limit = 2; + List ingredients = controller.getIngredients(Optional.of(0), Optional.of(limit)).getBody(); assertNotNull(ingredients); - assertEquals(2, ingredients.size()); + final int expectedCount = 2; + assertEquals(expectedCount, ingredients.size()); assertEquals("Eggs", ingredients.get(0).name); assertEquals("Flour", ingredients.get(1).name); } @@ -82,31 +99,31 @@ public class IngredientControllerTest { @Test public void testGetIngredientByInvalidId() { - Long invalidId = 2137L; + var response = controller.getIngredientById(INVALID_ID); - var response = controller.getIngredientById(invalidId); - - assertEquals(HttpStatusCode.valueOf(404), response.getStatusCode()); + assertEquals(HttpStatusCode.valueOf(NOT_FOUND_STATUS), response.getStatusCode()); } @Test public void testCreateIngredient() { - Ingredient newIngredient = new Ingredient("Butter", 0.5, 1.0, 1.5); + Ingredient newIngredient = new Ingredient("Butter", PROTEIN_ALT, FAT_ALT, CARBS_ALT); Ingredient createdIngredient = controller.createIngredient(newIngredient).getBody(); + final int expectedCount = 6; + assertNotNull(createdIngredient); assertEquals("Butter", createdIngredient.name); - assertEquals(6, ingredientRepository.count()); + assertEquals(expectedCount, ingredientRepository.count()); } @Test public void testCreateIngredientMissingName() { - Ingredient newIngredient = new Ingredient(null, 0.5, 1.0, 1.5); + Ingredient newIngredient = new Ingredient(null, PROTEIN_ALT, FAT_ALT, CARBS_ALT); var response = controller.createIngredient(newIngredient); - assertEquals(HttpStatusCode.valueOf(400), response.getStatusCode()); + assertEquals(HttpStatusCode.valueOf(BAD_REQUEST_STATUS), response.getStatusCode()); } @Test @@ -119,24 +136,22 @@ public class IngredientControllerTest { Long id = ingredient.id; - Ingredient updatedData = new Ingredient("Sea Salt", 1.5, 2.5, 3.5); + Ingredient updatedData = new Ingredient("Sea Salt", PROTEIN_ALT, FAT_ALT, CARBS_ALT); Ingredient updatedIngredient = controller.updateIngredient(id, updatedData).getBody(); assertNotNull(updatedIngredient); assertEquals("Sea Salt", updatedIngredient.name); - assertEquals(1.5, updatedIngredient.proteinPer100g); + assertEquals(PROTEIN_ALT, updatedIngredient.proteinPer100g); } @Test public void testUpdateMissingIngredient() { - Long invalidId = 2137L; + Ingredient updatedData = new Ingredient("Sea Salt", PROTEIN_ALT, FAT_ALT, CARBS_ALT); - Ingredient updatedData = new Ingredient("Sea Salt", 1.5, 2.5, 3.5); + var response = controller.updateIngredient(INVALID_ID, updatedData); - var response = controller.updateIngredient(invalidId, updatedData); - - assertEquals(HttpStatusCode.valueOf(404), response.getStatusCode()); + assertEquals(HttpStatusCode.valueOf(NOT_FOUND_STATUS), response.getStatusCode()); } @Test @@ -151,16 +166,15 @@ public class IngredientControllerTest { var response = controller.deleteIngredient(id); - assertEquals(HttpStatusCode.valueOf(200), response.getStatusCode()); - assertEquals(4, ingredientRepository.count()); + final int expectedCount = 4; + assertEquals(HttpStatusCode.valueOf(OK_STATUS), response.getStatusCode()); + assertEquals(expectedCount, ingredientRepository.count()); } @Test public void testDeleteMissingIngredient() { - Long invalidId = 2137L; + var response = controller.deleteIngredient(INVALID_ID); - var response = controller.deleteIngredient(invalidId); - - assertEquals(HttpStatusCode.valueOf(404), response.getStatusCode()); + assertEquals(HttpStatusCode.valueOf(NOT_FOUND_STATUS), response.getStatusCode()); } } From 566a46178fa2563c41db52885559f978c88916af Mon Sep 17 00:00:00 2001 From: Natalia Cholewa Date: Fri, 5 Dec 2025 20:39:32 +0100 Subject: [PATCH 4/4] chore: remove unnecessary dependency --- server/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/server/pom.xml b/server/pom.xml index 2c4cb0f..41b64c9 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -47,13 +47,6 @@ spring-boot-starter-test test - - org.glassfish.hk2 - hk2-api - 3.0.6 - compile - -