From d5ba8f5c9e26ec60fc8a1b57974dbb8da2b650da Mon Sep 17 00:00:00 2001 From: Lukas Karsch <lk224@hdm-stuttgart.de> Date: Fri, 28 Apr 2023 16:42:54 +0200 Subject: [PATCH] tests for Recipe.java --- pom.xml | 4 +- src/main/java/mi/hdm/recipes/Category.java | 3 +- .../mi/hdm/recipes/NutritionCalculator.java | 5 + .../java/mi/hdm/recipes/NutritionTable.java | 29 ++++- src/main/java/mi/hdm/recipes/Recipe.java | 57 +++++++++- .../hdm/recipes/NutritionCalculatorTest.java | 2 +- src/test/java/mi/hdm/recipes/RecipeTest.java | 106 ++++++++++++++++++ .../java/mi/hdm/recipes/ValidObjectsPool.java | 8 +- 8 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 src/test/java/mi/hdm/recipes/RecipeTest.java diff --git a/pom.xml b/pom.xml index 061e241..32d414b 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,9 @@ <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> - <release>11</release> + <release>17</release> + <source>17</source> + <target>17</target> </configuration> </plugin> diff --git a/src/main/java/mi/hdm/recipes/Category.java b/src/main/java/mi/hdm/recipes/Category.java index 95b40ff..1932640 100644 --- a/src/main/java/mi/hdm/recipes/Category.java +++ b/src/main/java/mi/hdm/recipes/Category.java @@ -30,8 +30,7 @@ public class Category { @Override public boolean equals(Object o){ - if (o instanceof Category) { - Category c = (Category) o; + if (o instanceof Category c) { return this.name.equals(c.getName()) || this.colourCode == c.getColourCode(); } return false; diff --git a/src/main/java/mi/hdm/recipes/NutritionCalculator.java b/src/main/java/mi/hdm/recipes/NutritionCalculator.java index 20ccdec..6233f3b 100644 --- a/src/main/java/mi/hdm/recipes/NutritionCalculator.java +++ b/src/main/java/mi/hdm/recipes/NutritionCalculator.java @@ -11,6 +11,10 @@ public class NutritionCalculator { * @return the nutrition table for this recipe based on its ingredients. All nutrition values are added up. */ public static NutritionTable calculateNutritionTable(Map<RecipeComponent, Integer> ingredients) { + if (ingredients == null || ingredients.isEmpty()) { + return NutritionTable.empty(); + } + double totalCals = 0, totalCarbs = 0, totalFats = 0, @@ -32,6 +36,7 @@ public class NutritionCalculator { return new NutritionTable(totalCals, totalCarbs, totalFats, totalProteins, totalFibers, totalSalt); } + //TODO: implement calcuating nutrition table from meal plan public static NutritionTable calculateNutritionTable(MealPlan mealPlan) { return null; } diff --git a/src/main/java/mi/hdm/recipes/NutritionTable.java b/src/main/java/mi/hdm/recipes/NutritionTable.java index 1ff9019..36ea565 100644 --- a/src/main/java/mi/hdm/recipes/NutritionTable.java +++ b/src/main/java/mi/hdm/recipes/NutritionTable.java @@ -26,6 +26,17 @@ public class NutritionTable { table.put(Nutrition.SALT, salt); } + private NutritionTable() { + this.table = new HashMap<>(); + + table.put(Nutrition.CALORIES, 0.0); + table.put(Nutrition.CARBS, 0.0); + table.put(Nutrition.FAT, 0.0); + table.put(Nutrition.PROTEINS, 0.0); + table.put(Nutrition.FIBERS, 0.0); + table.put(Nutrition.SALT, 0.0); + } + public Map<Nutrition, Double> getTable() { return table; } @@ -34,12 +45,18 @@ public class NutritionTable { return this; } + //TODO: use big decimal instead of double to avoid this trouble? + + /** + * Overridden equals method to account for rounding errors when calculating nutrition scores. + * + * @param o Object that is being compared + * @return true if the given object is a NutritionTable and the difference between all of the values inside of the nutrition table are within a certain limit delta = 0.001 + */ @Override public boolean equals(Object o) { - if (o instanceof NutritionTable) { - NutritionTable n = (NutritionTable) o; - - double delta = 0.03; + if (o instanceof NutritionTable n) { + double delta = 0.001; return n.getTable().get(Nutrition.CALORIES) - table.get(Nutrition.CALORIES) < delta && n.getTable().get(Nutrition.CARBS) - table.get(Nutrition.CARBS) < delta && n.getTable().get(Nutrition.FAT) - table.get(Nutrition.FAT) < delta @@ -49,4 +66,8 @@ public class NutritionTable { } return false; } + + public static NutritionTable empty() { + return new NutritionTable(); + } } diff --git a/src/main/java/mi/hdm/recipes/Recipe.java b/src/main/java/mi/hdm/recipes/Recipe.java index bd8eeaa..dce8c0b 100644 --- a/src/main/java/mi/hdm/recipes/Recipe.java +++ b/src/main/java/mi/hdm/recipes/Recipe.java @@ -3,11 +3,12 @@ package mi.hdm.recipes; import mi.hdm.exceptions.InvalidRecipeException; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.Map; public class Recipe implements RecipeComponent { - private Map<RecipeComponent, Integer> ingredients; + private final Map<RecipeComponent, Integer> ingredients; private String name; private String description; private List<String> preparation; @@ -16,22 +17,70 @@ public class Recipe implements RecipeComponent { private NutritionTable nutritionTable; private final LocalDateTime creationTime; + /** + * This constructor will create a new recipe and calculate the nutrition values for the recipe by its ingredients. + * + * @param name Name for this recipe + * @param ingredients Map of ingredients used in this recipe. The value for each component should be the amount that is needed of this ingredient (in its respective unit= + * @param description Description for this recipe + * @param preparation List of preparation steps for this recipe + * @param categories Categories that this recipe belongs to + * @param preparationTimeMins Time that it takes to prepare this recipe in minutes + */ public Recipe( - Map<RecipeComponent, Integer> ingredients, String name, + Map<RecipeComponent, Integer> ingredients, String description, List<String> preparation, List<Category> categories, Integer preparationTimeMins) { + + //Das ruft den anderen Konstruktor dieser Klasse auf (siehe unten) + this(name, ingredients, description, preparation, categories, preparationTimeMins, NutritionCalculator.calculateNutritionTable(ingredients)); + } + + /** + * This constructor will create a new recipe and set the nutrition table provided by the user instead of calculating the nutrition values from the ingredients. + * + * @param name Name for this recipe + * @param ingredients Map of ingredients used in this recipe. The value for each component should be the amount that is needed of this ingredient (in its respective unit= + * @param description Description for this recipe + * @param preparation List of preparation steps for this recipe + * @param categories Categories that this recipe belongs to + * @param preparationTimeMins Time that it takes to prepare this recipe in minutes + * @param nutritionTable The nutrition table that will be set for this recipe + */ + public Recipe( + String name, + Map<RecipeComponent, Integer> ingredients, + String description, + List<String> preparation, + List<Category> categories, + Integer preparationTimeMins, + NutritionTable nutritionTable) { + + if (ingredients == null || ingredients.size() == 0) { + throw new InvalidRecipeException("Ingredient list can not be null or empty"); + } + if (name == null || name.isEmpty()) { + throw new InvalidRecipeException("Name can not be null or empty"); + } + if (preparation == null || preparation.isEmpty()) { + throw new InvalidRecipeException("Preparation can not be null or empty"); + } + if (categories == null) { + categories = new ArrayList<>(); + } + this.ingredients = ingredients; this.name = name; this.description = description; this.preparation = preparation; this.categories = categories; this.preparationTimeMins = preparationTimeMins; - nutritionTable = NutritionCalculator.calculateNutritionTable(ingredients); + this.nutritionTable = nutritionTable; - creationTime = LocalDateTime.now(); + this.creationTime = LocalDateTime.now(); } public void setName(String name) { diff --git a/src/test/java/mi/hdm/recipes/NutritionCalculatorTest.java b/src/test/java/mi/hdm/recipes/NutritionCalculatorTest.java index cb5a28a..215a62b 100644 --- a/src/test/java/mi/hdm/recipes/NutritionCalculatorTest.java +++ b/src/test/java/mi/hdm/recipes/NutritionCalculatorTest.java @@ -9,7 +9,7 @@ import java.util.List; import java.util.Map; public class NutritionCalculatorTest { - List<Ingredient> ingredients = ValidObjectsPool.getValidIngredientList(); + List<RecipeComponent> ingredients = ValidObjectsPool.getValidIngredientList(); Map<RecipeComponent, Integer> recipeMap; @BeforeEach diff --git a/src/test/java/mi/hdm/recipes/RecipeTest.java b/src/test/java/mi/hdm/recipes/RecipeTest.java new file mode 100644 index 0000000..4caf909 --- /dev/null +++ b/src/test/java/mi/hdm/recipes/RecipeTest.java @@ -0,0 +1,106 @@ +package mi.hdm.recipes; + +import mi.hdm.exceptions.InvalidRecipeException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class RecipeTest { + private final static List<RecipeComponent> ingredients = ValidObjectsPool.getValidIngredientList(); + private final static Map<RecipeComponent, Integer> recipeMap = new HashMap<>(); + + @BeforeAll + public static void setUpAll() { + ingredients.forEach(ingredient -> recipeMap.put(ingredient, 100)); + } + + @Test + @DisplayName("Test invalid name: Recipes with an invalid name (name is null or empty) should not be created") + void shouldNotCreateRecipeWithInvalidName() { + assertThrows(InvalidRecipeException.class, () -> new Recipe(null, recipeMap, "Description!", List.of("step 1"), null, 100)); + assertThrows(InvalidRecipeException.class, () -> new Recipe("", recipeMap, "Description!", List.of("step 1"), null, 100)); + } + + @Test + @DisplayName("Test invalid ingredients: Recipes with an invalid ingredient map (map is null or empty) should not be created") + void shouldNotCreateRecipeWithInvalidIngredientMap() { + assertThrows(InvalidRecipeException.class, () -> new Recipe("Valid name", null, "Description!", List.of("step 1"), null, 100)); + assertThrows(InvalidRecipeException.class, () -> new Recipe("Valid name", Map.of(), "Description!", List.of("step 1"), null, 100)); + } + + @Test + @DisplayName("Test invalid preparation: Recipes with an invalid preparation list (list is null or empty) should not be created") + void shouldNotCreateRecipeWithInvalidPrep() { + assertThrows(InvalidRecipeException.class, () -> new Recipe("Valid name", recipeMap, "Description!", null, null, 100)); + assertThrows(InvalidRecipeException.class, () -> new Recipe("Valid name", recipeMap, "Description!", List.of(), null, 100)); + } + + @Test + void getNutritionTableWhenSetManually() { + //given + NutritionTable nutritionTable = ValidObjectsPool.getValidNutritionTableOne(); + + //when + Recipe underTest = new Recipe("Valid name", recipeMap, "Valid description", List.of("Step 1"), null, 20, nutritionTable); + + //then + assertEquals(nutritionTable, underTest.getNutritionTable()); + } + + @Test + void getNutritionTableWhenCalculated() { + //given + NutritionTable nutritionTable = ValidObjectsPool.getValidNutritionTableOne(); + Ingredient ingredientOne = new Ingredient(Measurement.GRAM, "Zucker", nutritionTable); + + //when + Recipe underTest = new Recipe("Valid name", Map.of(ingredientOne, 100), "Valid description", List.of("Step 1"), null, 20); + + //then + assertEquals(nutritionTable, underTest.getNutritionTable()); + } + + @Test + void canAddCategory() { + //given + Category category = new Category("Category", 0xFF0000); + NutritionTable nutritionTable = ValidObjectsPool.getValidNutritionTableOne(); + Ingredient ingredientOne = new Ingredient(Measurement.GRAM, "Zucker", nutritionTable); + Recipe underTest = new Recipe("Valid name", Map.of(ingredientOne, 100), "Valid description", List.of("Step 1"), new ArrayList<>(), 20); + + //when + underTest.addCategory(category); + + //then + assertEquals( + List.of(category), + underTest.getCategories() + ); + } + + @Test + void canAddCategoryWhenNull() { + //given + Category category = new Category("Category", 0xFF0000); + NutritionTable nutritionTable = ValidObjectsPool.getValidNutritionTableOne(); + Ingredient ingredientOne = new Ingredient(Measurement.GRAM, "Zucker", nutritionTable); + Recipe underTest = new Recipe("Valid name", Map.of(ingredientOne, 100), "Valid description", List.of("Step 1"), null, 20); + + //when + underTest.addCategory(category); + + //then + assertEquals( + List.of(category), + underTest.getCategories() + ); + } +} \ No newline at end of file diff --git a/src/test/java/mi/hdm/recipes/ValidObjectsPool.java b/src/test/java/mi/hdm/recipes/ValidObjectsPool.java index bec6bfe..c9a1bd0 100644 --- a/src/test/java/mi/hdm/recipes/ValidObjectsPool.java +++ b/src/test/java/mi/hdm/recipes/ValidObjectsPool.java @@ -26,14 +26,18 @@ public class ValidObjectsPool { return ingredientTwo; } - public static List<Ingredient> getValidIngredientList() { + public static List<RecipeComponent> getValidIngredientList() { return List.of(ingredientOne, ingredientTwo); } - public static Category getValidCategory() { + public static Category getValidCategoryOne() { return categoryOne; } + public static Category getValidCategoryTwo() { + return categoryTwo; + } + public static List<Category> getValidCategoryList() { return List.of(categoryOne, categoryTwo); } -- GitLab