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:
+ *
+ * - GET /api/ingredients - Get a list of ingredients, optionally paginated.
+ * - GET /api/ingredients/{id} - Get a specific ingredient by its ID.
+ * - POST /api/ingredients - Create a new ingredient.
+ * - PATCH /api/ingredients/{id} - Update an existing ingredient by its ID.
+ * - DELETE /api/ingredients/{id} - Delete an ingredient by its ID.
+ *
+ *
+ *
+ * @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
-
-