diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/FoodItem.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/FoodItem.java new file mode 100644 index 0000000000000000000000000000000000000000..94c956d7149385d2a83597e69b90c4849081cf11 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/FoodItem.java @@ -0,0 +1,22 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +public enum FoodItem { + + ONION("onion"), + MINCED_MEAT("minced meat"), + POTATO("potatoes"), + YELLOW_CHEESE("yellow cheese"), + WHEAT_FLOUR("wheat flour"), + MILK("milk"), + TOMATO("tomato"), + ORANGE("orange"), + LEMON("lemon"), + SALSA_SAUCE("salsa sauce") + ; + + public final String label; + + FoodItem(String label) { + this.label = label; + } +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/Ingredient.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/Ingredient.java new file mode 100644 index 0000000000000000000000000000000000000000..50c850574dc549e12891bc41ed2c5f512225c8bb --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/Ingredient.java @@ -0,0 +1,123 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import java.util.Objects; + +/** + * The Ingredient class represents an ingredient that can be part of a recipe in real life and/or + * be available to the user in real life. When the ingredient is part of a recipe, the subclass called + * RecipeIngredient is used. An ingredient belongs to a food type among the values of the FoodItem enum class. + * Examples are onion, tomato, spaghetti, chicken etc. The ingredient is provided in a specific amount and unit + * of measure. + * + * @author hannesofie + */ +public class Ingredient { + + private FoodItem foodType; + private double amount; + private MeasuringUnit unit; + + /** + * The constructor of a new Ingredient object takes in three mandatory fields; ingredient type as defined in + * the enum class FoodItem, an amount and a unit of measure defined in the enum class MeasuringUnit. The amount + * must be a positive number. + * @param ingredient What type of food the ingredient is. + * @param amount The amount of the ingredient. + * @param unit The unit of measure of the given amount of the ingredient. + */ + public Ingredient(FoodItem ingredient, double amount, MeasuringUnit unit) { + if(ingredient == null | amount <= 0.0f | unit == null) { + throw new IllegalArgumentException("The ingredient must have a type, amount and measuring unit."); + } + this.foodType = ingredient; + this.amount = amount; + this.unit = unit; + } + + /** + * The method returns the food type that the ingredient belongs to among the valid types in the FoodItem enum class. + * @return What type of food the ingredient is. + */ + public FoodItem getFoodType() { + return foodType; + } + + public void setFoodType(FoodItem foodType) { + if(foodType == null) { + throw new IllegalArgumentException("The food type must be set to a valid value of FoodItem."); + } + this.foodType = foodType; + } + + /** + * The method returns the amount of an ingredient as the datatype double. + * @return The amount of an ingredient as double. + */ + public double getAmount() { + return amount; + } + + /** + * The method takes in a new amount as a double and sets the ingredient's amount field equal to this value. + * If the provided value is not a positive double, an IllegalArgumentException is thrown. + * @param amount The amount of an ingredient as double. + */ + public void setAmount(double amount) { + if(amount <= 0.0f) { + throw new IllegalArgumentException("The amount of an ingredient cannot be zero or negative."); + } + this.amount = amount; + } + + /** + * The method returns the unit of measure of the ingredient as a value of the MeasuringUnit enum class. + * @return The unit of measure of the given amount of the ingredient. + */ + public MeasuringUnit getUnit() { + return unit; + } + + /** + * The method takes in a value of the MeasuringUnit enum class and sets the ingredient's unit equal to this + * value. + * @param unit The unit of measure of the given amount of the ingredient. + */ + public void setUnit(MeasuringUnit unit) { + if(unit == null) { + throw new IllegalArgumentException("The food's measuring unit must be set to a valid value of MeasuringUnit."); + } + this.unit = unit; + } + + /** + * The method returns a String representation of an Ingredient object, listing its type, amount and unit. + * @return A String representation of the ingredient object. + */ + @Override + public String toString() { + return "Ingredient{" + + "foodType=" + foodType.label + + ", amount=" + amount + + ", unit=" + unit.label + + '}'; + } + + /** + * The method checks if a given object is equal to the ingredient object. + * If the object is of the same class as well as having the same value for each class field, + * the object is equal to the Ingredient. + * @param o An Object to which the Ingredient should be compared. + * @return True if the object is equivalent to the Ingredient, false otherwise. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Ingredient that)) return false; + return Double.compare(that.amount, amount) == 0 && foodType == that.foodType && unit == that.unit; + } + +/* @Override + public int hashCode() { + return Objects.hash(foodType, amount, unit); + }*/ +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/IngredientsAtHand.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/IngredientsAtHand.java new file mode 100644 index 0000000000000000000000000000000000000000..72318cd4f29e3228c6300bcd17bba64beb585805 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/IngredientsAtHand.java @@ -0,0 +1,84 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import java.util.ArrayList; +import java.util.List; + +/** + * The IngredientsAtHand class contains a collection of Ingredient objects that are currently available to the user. + * Only one instance of each ingredient type may exist in the collection. If an ingredient is already present in the + * collection, the old will be replaced by the new. + * + * @author hannesofie + */ +public class IngredientsAtHand { + + private final List<Ingredient> ingredientsAtHand = new ArrayList<>(); + + /** + * The method returns the collection of ingredients at hand as an arraylist of ingredient objects. + * @return The collection of ingredients at hand to the user. + */ + public List<Ingredient> getIngredientsAtHand() { + return ingredientsAtHand; + } + + /** + * The method takes in an ingredient object and adds it to the collection of ingredients at hand. + * @param ingredient The ingredient object to add to the collection of ingredients at hand. + */ + public void addIngredient(Ingredient ingredient) { + this.ingredientsAtHand.add(ingredient); + } + + /** + * Returns null if no ingredient of the requested type is found in the collection. + * @param ingredientType What type of food the ingredient is. + * @return The ingredient of the specified type found among the ingredients at hand, null otherwise. + */ + public Ingredient getIngredient(FoodItem ingredientType) { + if(ingredientType == null) return null; + return this.getIngredientsAtHand().stream() + .filter((ingredient) -> ingredient.getFoodType() == ingredientType) + .findFirst().orElse(null); + } + + /** + * The method takes in three parameters. The method first checks if the Ingredient is at hand in the first place. + * If it is, the old amount and unit of this ingredient are replaced by the provided amount and unit if they + * differ. If not, the ingredient is left as is. If the ingredient is not in the collection, + * @param ingredientType What type of food the ingredient is. + * @param amount The amount of the ingredient. + * @return True if Ingredient is successfully altered or added, false if not. + */ + public boolean alterIngredient(FoodItem ingredientType, double amount, MeasuringUnit unit) { + //TODO: Consider handling exceptions differently. + if(ingredientsAtHand.stream().anyMatch((ingredient) -> ingredient.getFoodType() == ingredientType)) { + try { + getIngredient(ingredientType).setAmount(amount); + getIngredient(ingredientType).setUnit(unit); + + } catch (IllegalArgumentException e) { + return false; + } + } else { + try { + addIngredient(new Ingredient(ingredientType, amount, unit)); + } catch (IllegalArgumentException e) { + return false; + } + } + return true; + } + + /** + * The method takes in a value of the FoodItem enum as a parameter and removes it from the collection of + * ingredients at hand if it exists and returns true. If no ingredient of the given type was found in the + * collection, false is returned. + * @param ingredientType What type of food the ingredient is. + * @return True if the ingredient was found among the ingredients at hand and removed, false otherwise. + */ + public boolean removeIngredient(FoodItem ingredientType) { + return ingredientsAtHand.removeIf((ingredient) -> ingredient.getFoodType() == ingredientType); + } + +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/MeasuringUnit.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/MeasuringUnit.java new file mode 100644 index 0000000000000000000000000000000000000000..83f664cd4fc99285c6fc18fffc0b910c633b7412 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/MeasuringUnit.java @@ -0,0 +1,18 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +public enum MeasuringUnit { + + DL("dl."), + L("l."), + TSP("tsp."), + TBS("tbs."), + GR("gr."), + KG("kg."), + PC("pieces"); + + public final String label; + + MeasuringUnit(String label) { + this.label = label; + } +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/Recipe.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/Recipe.java new file mode 100644 index 0000000000000000000000000000000000000000..dd6330f177983aa20d7ae9f548983214d4014f1a --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/Recipe.java @@ -0,0 +1,119 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +// Method in case we want to check if also the amount is enough for the recipe. +// Recipes without any ingredients can be showed among all ingredients, but not in suggestion based on ingredients +// at hand. +//TODO: Record? +public class Recipe { + + private String name = ""; + private List<RecipeIngredient> ingredientList = new ArrayList<>(); + private String instructions = ""; + + public Recipe(String name, String description ) { + if(name.isBlank() | description.isBlank()) { + throw new IllegalArgumentException("The recipe must have a name and a description."); + } + this.name = name; + this.instructions = description; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + if(name.isBlank()) { + throw new IllegalArgumentException("The recipe name cannot be left blank."); + } + this.name = name; + } + + public List<RecipeIngredient> getIngredientList() { + return ingredientList; + } + + public String getInstructions() { + return instructions; + } + + public void setInstructions(String instructions) { + if(instructions.isBlank()) { + throw new IllegalArgumentException("The recipe instructions cannot be left blank."); + } + this.instructions = instructions; + } + + + /* public void addIngredients(ArrayList<RecipeIngredient> ingredients) { + ingredients.forEach((ingredient) -> this.ingredientList.add(ingredient)); + }*/ + + //TODO: Make interface for "collects ingredients" and do deep copy. + + public RecipeIngredient getIngredient(FoodItem ingredientType) { + if(ingredientType == null) return null; + return this.getIngredientList().stream() + .filter((ingredient) -> ingredient.getFoodType() == ingredientType) + .findFirst().orElse(null); + } + + + public boolean addIngredient(FoodItem ingredientType, double amount, MeasuringUnit unit) { + if(ingredientList.stream().anyMatch((ingredient) -> ingredient.getFoodType() == ingredientType)) { + try { + getIngredient(ingredientType).setAmount(amount); + getIngredient(ingredientType).setUnit(unit); + + } catch (IllegalArgumentException e) { + return false; + } + } else { + try { + this.ingredientList.add(new RecipeIngredient(ingredientType, amount, unit)); + } catch (IllegalArgumentException e) { + return false; + } + } + return true; + } + + /** + * The functionality may be expanded upon in order to also check if the amount is sufficient for the current recipe. + * @param ingredientsAtHand + */ + public void updateIngredientStatus(IngredientsAtHand ingredientsAtHand) { + // Will need a supporting class for converting between units to be accurate. + if(ingredientsAtHand == null) { + throw new NullPointerException("The ingredients at hand object must exist"); + } else if (ingredientsAtHand.getIngredientsAtHand().size() < 1) { + throw new IllegalArgumentException("The collection of ingredients at hand is empty."); + } else { + ingredientList.forEach((inRecipe) -> { + ingredientsAtHand.getIngredientsAtHand().forEach((atHand) -> { + if(inRecipe.getFoodType() == atHand.getFoodType()) { + inRecipe.setAtHand(true); + } + }); + }); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Recipe recipe = (Recipe) o; + return Objects.equals(name, recipe.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, ingredientList, instructions); + } +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/RecipeIngredient.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/RecipeIngredient.java new file mode 100644 index 0000000000000000000000000000000000000000..36850d072b18816f5bdd231400eedef305e8cf84 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/RecipeIngredient.java @@ -0,0 +1,44 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +/** + * The RecipeIngredient class is an extension of the Ingredient class used as part of recipes + * that also stored the boolean value 'atHand'. This value can be set to true whenever the given ingredient, + * being part of a recipe, is also at hand to the user. Ingredients that the user has available are stored in + * the IngredientsAtHand class. + * + * @author hannesofie + */ +public class RecipeIngredient extends Ingredient{ + + private boolean atHand = false; + + /** + * The constructor of a RecipeIngredient object inherits from the superclass Ingredient. The additional 'atHand' + * field is set to false ar default. + * @param ingredient What type of food the ingredient is. + * @param amount The amount of the ingredient. + * @param unit The unit of measure of the given amount of the ingredient. + */ + public RecipeIngredient(FoodItem ingredient, double amount, MeasuringUnit unit) { + super(ingredient, amount, unit); + } + + /** + * The method returns the boolean value of the atHand field for the ingredient. If the ingredient being part of + * a recipe is also contained in the collection of ingredients at hand to the user, true is returned, if not, + * false is returned. + * @return True of the current recipe ingredient is available to the user. + */ + public boolean isAtHand() { + return atHand; + } + + /** + * The method sets the value of the atHand field for the ingredient to either true or false. + * @param atHand + */ + public void setAtHand(boolean atHand) { + this.atHand = atHand; + } + +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/recipes/RecipeRegister.java b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/RecipeRegister.java new file mode 100644 index 0000000000000000000000000000000000000000..1ec98e95879698ac7e6088f46f18e54a2bf67062 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/recipes/RecipeRegister.java @@ -0,0 +1,31 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import java.util.ArrayList; +import java.util.List; + +public class RecipeRegister { + + private final List<Recipe> recipes = new ArrayList<>(); + + + //TODO: Copy-constructor + + public List<Recipe> getRecipes() { + return recipes; + } + + public void addRecipe (Recipe recipe) { + if(recipes.contains(recipe)) { + throw new IllegalArgumentException("The recipe already exists in the register."); // Or just replace? + } else if (recipe == null) { + throw new NullPointerException("The recipe cannot be null."); + } + this.recipes.add(recipe); + } + + public Recipe getRecipe(String name) { + return recipes.stream(). + filter((recipe) -> recipe.getName().equals(name)) + .findFirst().orElse(null); + } +} diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/recipes/IngredientTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/IngredientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..79dd0439298817a773fc8ac9c6c70f19575c0957 --- /dev/null +++ b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/IngredientTest.java @@ -0,0 +1,76 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class IngredientTest { + + Ingredient testIngredient; + + @BeforeEach + void beforeEach() { + testIngredient = new Ingredient(FoodItem.ONION, 0.5f, MeasuringUnit.KG); + } + + @Test + @DisplayName("The constructor creates an ingredient object successfully") + void constructValidIngredient() { + Ingredient validIngredient = new Ingredient(FoodItem.ONION, 1, MeasuringUnit.KG); + assertEquals(validIngredient, new Ingredient(FoodItem.ONION, 1, MeasuringUnit.KG)); + } + + @Test + @DisplayName("The constructor throws exceptions for illegal input.") + void constructorThrowsExceptionsWhenItShould() { + assertThrows(IllegalArgumentException.class, () -> new Ingredient(null, 2, MeasuringUnit.DL)); + assertThrows(IllegalArgumentException.class, () -> new Ingredient(FoodItem.ONION, -5, MeasuringUnit.DL)); + assertThrows(IllegalArgumentException.class, () -> new Ingredient(FoodItem.ONION, 0, MeasuringUnit.DL)); + assertThrows(IllegalArgumentException.class, () -> new Ingredient(FoodItem.ONION, 2, null)); + } + + @Test + @DisplayName("Change of food type works for valid food type.") + void setFoodTypeWorksForValidType() { + testIngredient.setFoodType(FoodItem.LEMON); + assertEquals(new Ingredient(FoodItem.LEMON, 0.5f, MeasuringUnit.KG), testIngredient); + } + + @Test + @DisplayName("Change of food type to invalid type throws exception.") + void setFoodTypeThrowsException() { + assertThrows(IllegalArgumentException.class, () -> testIngredient.setFoodType(null)); + } + + @Test + @DisplayName("Change of food amount works for valid amount.") + void setAmountWorksForValidAmount() { + testIngredient.setAmount(2.5); + assertEquals(new Ingredient(FoodItem.ONION, 2.5f, MeasuringUnit.KG), testIngredient); + } + + @Test + @DisplayName("Change of food amount to invalid amount throws exception.") + void setAmountThrowsException() { + assertThrows(IllegalArgumentException.class, () -> testIngredient.setAmount(0)); + assertThrows(IllegalArgumentException.class, () -> testIngredient.setAmount(-1)); + } + + @Test + @DisplayName("Change of measuring unit works for valid unit.") + void setUnitWorksForValidUnit() { + testIngredient.setUnit(MeasuringUnit.TBS); + assertEquals(new Ingredient(FoodItem.ONION, 0.5f, MeasuringUnit.TBS), testIngredient); + } + + @Test + @DisplayName("Change of measuring to invalid unit throws exception.") + void setUnitThrowsException() { + assertThrows(IllegalArgumentException.class, () -> testIngredient.setUnit(null)); + } + +//TODO: Test for equals method? + +} \ No newline at end of file diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/recipes/IngredientsAtHandTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/IngredientsAtHandTest.java new file mode 100644 index 0000000000000000000000000000000000000000..369d7c43de2309fda39160a9cbe50b566075d800 --- /dev/null +++ b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/IngredientsAtHandTest.java @@ -0,0 +1,92 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class IngredientsAtHandTest { + + IngredientsAtHand ingredientsAtHand = new IngredientsAtHand(); + + @BeforeEach + void beforeEach() { + ingredientsAtHand.addIngredient(new Ingredient(FoodItem.LEMON, 3, MeasuringUnit.PC)); + ingredientsAtHand.addIngredient(new Ingredient(FoodItem.MILK, 1.5f, MeasuringUnit.L)); + ingredientsAtHand.addIngredient(new Ingredient(FoodItem.MINCED_MEAT, 400, MeasuringUnit.GR)); + + } + + @Test + @DisplayName("The getIngredient method returns the correct ingredient.") + void getIngredientReturnsSuccessfully() { + assertEquals(new Ingredient(FoodItem.LEMON, 3, MeasuringUnit.PC), + ingredientsAtHand.getIngredient(FoodItem.LEMON)); + + } + + @Test + @DisplayName("The getIngredient method returns null if the ingredient is not in the collection.") + void getIngredientReturnsNullWhenNotFoundOrNull(){ + assertNull(ingredientsAtHand.getIngredient(FoodItem.ONION)); + assertNull(ingredientsAtHand.getIngredient(null)); + } + + + @Test + @DisplayName("Altering ingredient successfully and return true.") + void alterIngredientSuccessfully() { + assertNotEquals(new Ingredient(FoodItem.ONION, 500, MeasuringUnit.GR), + ingredientsAtHand.getIngredient(FoodItem.ONION)); + + assertTrue(ingredientsAtHand.alterIngredient(FoodItem.ONION, 500, MeasuringUnit.GR)); + + assertEquals(new Ingredient(FoodItem.ONION, 500, MeasuringUnit.GR), + ingredientsAtHand.getIngredient(FoodItem.ONION)); + + } + + @Test + @DisplayName("Altering ingredient that does not yet exist in collection adds it and returns true.") + void alterNewIngredientAddsIt() { + int ingredientsAtStart = ingredientsAtHand.getIngredientsAtHand().size(); + assertTrue(ingredientsAtHand.alterIngredient(FoodItem.ORANGE, 8, MeasuringUnit.PC)); + + assertEquals(ingredientsAtStart + 1, ingredientsAtHand.getIngredientsAtHand().size()); + } + + @Test + @DisplayName("Attempting to alter ingredient in illegal way does not alter the collection and returns false.") + void alterIngredientUnchangedForInvalidChange() { + assertFalse(ingredientsAtHand.alterIngredient(null, 350, MeasuringUnit.GR)); + assertEquals(new Ingredient(FoodItem.LEMON, 3, MeasuringUnit.PC), + ingredientsAtHand.getIngredient(FoodItem.LEMON)); + } + + @Test + @DisplayName("Altering an ingredients without changing values, leaves no change on the collection and returns true.") + void alterNothingLeavesCollectionIntact() { + int ingredientsAtStart = ingredientsAtHand.getIngredientsAtHand().size(); + + assertTrue(ingredientsAtHand.alterIngredient(FoodItem.LEMON, 3, MeasuringUnit.PC)); + + assertEquals(ingredientsAtStart, ingredientsAtHand.getIngredientsAtHand().size()); + } + + @Test + @DisplayName("Ingredient is removed successfully and true is returned.") + void removeIngredientSuccessfully() { + int ingredientsAtStart = ingredientsAtHand.getIngredientsAtHand().size(); + assertTrue(ingredientsAtHand.removeIngredient(FoodItem.LEMON)); + assertEquals(ingredientsAtStart-1, ingredientsAtHand.getIngredientsAtHand().size()); + } + + @Test + @DisplayName("Removing ingredient that is not in the collection, leaves it unchanged and returns false.") + void removeIngredientNotInCollection() { + + assertFalse(ingredientsAtHand.removeIngredient(FoodItem.SALSA_SAUCE)); + } + +} \ No newline at end of file diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/recipes/RecipeRegisterTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/RecipeRegisterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4176a2451f7ed7ba28f9653b5f77ef1ba00abd49 --- /dev/null +++ b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/RecipeRegisterTest.java @@ -0,0 +1,45 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class RecipeRegisterTest { + + RecipeRegister myRecipes; + + @BeforeEach + void beforeEach() { + myRecipes = new RecipeRegister(); + myRecipes.addRecipe(new Recipe("Pasta al Limone", "Instructions")); + } + + @Test + @DisplayName("Adding recipe to register successfully.") + void addRecipeToRegister() { + int numberOfRecipes = myRecipes.getRecipes().size(); + myRecipes.addRecipe(new Recipe("Carbonara", "Instructions")); + assertEquals(numberOfRecipes + 1, myRecipes.getRecipes().size()); + } + + @Test + @DisplayName("Throw exception when adding already registered recipe.") + void recipeAlreadyInRegister() { + assertThrows(IllegalArgumentException.class, () -> myRecipes.addRecipe( new Recipe("Pasta al Limone", "Instructions"))); + } + + @Test + @DisplayName("Throw exception when adding null recipe.") + void addNullRecipe() { + assertThrows(NullPointerException.class, () -> myRecipes.addRecipe(null)); + } + + @Test + @DisplayName("Returns correct recipe based on name.") + void getRecipeByName() { + assertEquals(new Recipe("Pasta al Limone", "Instructions"), myRecipes.getRecipe("Pasta al Limone")); + } + +} \ No newline at end of file diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/recipes/RecipeTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/RecipeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..46d4955720b089e6391f3e5f0aaa5f70fb014b06 --- /dev/null +++ b/src/test/java/no/ntnu/idatt1002/demo/data/recipes/RecipeTest.java @@ -0,0 +1,117 @@ +package no.ntnu.idatt1002.demo.data.recipes; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class RecipeTest { + + Recipe recipe; + + @BeforeEach + void beforeEach() { + recipe = new Recipe("Meat, cheese and potatoes", "Instructions"); + + recipe.addIngredient(FoodItem.MINCED_MEAT, 500, MeasuringUnit.GR); + recipe.addIngredient(FoodItem.POTATO, 750, MeasuringUnit.GR); + recipe.addIngredient(FoodItem.YELLOW_CHEESE, 2, MeasuringUnit.DL); + + } + + @Test + @DisplayName("Constructor creates Recipe successfully.") + void constructorCreatesRecipe() { + assertEquals(recipe, new Recipe("Meat, cheese and potatoes", "Instructions")); + // Recipes are equal if name and Instructions are equal. + } + + @Test + @DisplayName("Constructor throws exception for empty name or instruction.") + void constructorThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new Recipe("", "Instructions")); + assertThrows(IllegalArgumentException.class, () -> new Recipe("Name", "")); + + } + + @Test + @DisplayName("Can change name of recipe successfully.") + void setNameSuccessfully() { + String newName = "Meat and cheese"; + recipe.setName(newName); + assertEquals(newName, recipe.getName()); + } + + @Test + @DisplayName("Throws exception when name set to empty string.") + void setNameEmptyThrowsException() { + assertThrows(IllegalArgumentException.class, () -> recipe.setName(" ")); + } + + @Test + @DisplayName("Can change instructions of recipe successfully.") + void setInstructionsSuccessfully() { + String newInstruction = "New instructions"; + recipe.setInstructions(newInstruction); + assertEquals(newInstruction, recipe.getInstructions()); + } + + @Test + @DisplayName("Throws exception when Instructions set to empty string.") + void setInstructionsEmptyThrowsException() { + assertThrows(IllegalArgumentException.class, () -> recipe.setInstructions("")); + } + + + @Test + @DisplayName("Ingredient is added to recipe successfully.") + void addNewIngredient() { + int ingredientsInRecipe = recipe.getIngredientList().size(); + assertTrue(recipe.addIngredient(FoodItem.LEMON, 1, MeasuringUnit.PC)); + assertEquals(ingredientsInRecipe + 1, recipe.getIngredientList().size()); + } + + @Test + @DisplayName("Ingredient already in recipe does not alter and returns true.") + void addAlreadyIncludedIngredient() { + int ingredientsInRecipe = recipe.getIngredientList().size(); + assertTrue(recipe.addIngredient(FoodItem.MINCED_MEAT, 500, MeasuringUnit.GR)); + assertEquals(ingredientsInRecipe, recipe.getIngredientList().size()); + } + + @Test + @DisplayName("Invalid ingredient change is not made and false is returned.") + void addInvalidIngredientReturnsFalse() { + int ingredientsInRecipe = recipe.getIngredientList().size(); + assertFalse(recipe.addIngredient(null, 500, MeasuringUnit.GR)); + assertEquals(ingredientsInRecipe, recipe.getIngredientList().size()); + } + + + @Test + @DisplayName("Updating ingredient status works as expected.") + void updateIngredientStatus() { + IngredientsAtHand inFridge = new IngredientsAtHand(); + inFridge.addIngredient(new Ingredient(FoodItem.MINCED_MEAT, 400, MeasuringUnit.GR)); + inFridge.addIngredient(new Ingredient(FoodItem.YELLOW_CHEESE, 500, MeasuringUnit.GR)); + + + recipe.getIngredientList().forEach((ingredient) -> assertFalse(ingredient.isAtHand())); + recipe.updateIngredientStatus(inFridge); + + assertTrue(recipe.getIngredient(FoodItem.MINCED_MEAT).isAtHand()); + assertTrue(recipe.getIngredient(FoodItem.YELLOW_CHEESE).isAtHand()); + assertFalse(recipe.getIngredient(FoodItem.POTATO).isAtHand()); + } + + @Test + @DisplayName("Update of ingredient status based on empty or null ingredients at hand collection.") + void nullOrEmptyIngredientsAtHand() { + IngredientsAtHand emptyFridge = new IngredientsAtHand(); + + assertThrows(NullPointerException.class, () -> recipe.updateIngredientStatus(null)); + assertThrows(IllegalArgumentException.class, () -> recipe.updateIngredientStatus(emptyFridge)); + } + +} \ No newline at end of file