diff --git a/client/pom.xml b/client/pom.xml index 509f836..b9eb186 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -11,7 +11,6 @@ UTF-8 5.10.1 - 5.8.0 3.1.9 25.0.1 @@ -92,9 +91,9 @@ test - org.mockito - mockito-core - ${version.mockito} + org.wiremock + wiremock + 3.3.1 test diff --git a/client/src/main/java/client/utils/ServerUtils.java b/client/src/main/java/client/utils/ServerUtils.java index 101486a..113ed01 100644 --- a/client/src/main/java/client/utils/ServerUtils.java +++ b/client/src/main/java/client/utils/ServerUtils.java @@ -149,7 +149,7 @@ public class ServerUtils { //Get the recipe HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(SERVER + "/recipe/" + id)) - .GET() //Needs to be changed to POST() when api is changed + .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); diff --git a/client/src/test/java/client/ServerUtilsMockTest.java b/client/src/test/java/client/ServerUtilsMockTest.java new file mode 100644 index 0000000..57e3e42 --- /dev/null +++ b/client/src/test/java/client/ServerUtilsMockTest.java @@ -0,0 +1,287 @@ +package client; + +import client.utils.ServerUtils; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import commons.FormalIngredient; +import commons.Ingredient; +import commons.Recipe; +import commons.RecipeIngredient; +import commons.VagueIngredient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static org.junit.jupiter.api.Assertions.*; + +@WireMockTest(httpPort = 8080) +class ServerUtilsMockTest { + private ServerUtils serverUtils; + private ObjectMapper objectMapper; + + static final List ingredients = List.of( + new Ingredient("Bread", 1, 2, 3), + new Ingredient("Cheese", 2, 2, 2), + new Ingredient("Ham", 3, 3, 3) + ); + + static final List testIngredients = List.of( + new VagueIngredient(ingredients.get(0), "2 pieces of"), + new VagueIngredient(ingredients.get(1), "1 slice of"), + new VagueIngredient(ingredients.get(2), "1 slice of") + ); + + static final List testPrepSteps = List.of("1. do smth", "2. do smth else"); + + @BeforeEach + void setup() { + objectMapper = new ObjectMapper(); + serverUtils = new ServerUtils(); + } + + /** + * Returns a deep copy of recipe, but with null as id. + * @param recipe recipe to be stripped of id. + * @return new recipe without id. + */ + Recipe stripId(Recipe recipe) { + Recipe newRecipe = new Recipe(); + newRecipe.setId(null); + newRecipe.setName(recipe.getName()); + newRecipe.setIngredients(recipe.getIngredients()); + newRecipe.setPreparationSteps(recipe.getPreparationSteps()); + return newRecipe; + } + + @Test + void addRecipeTest() throws IOException, InterruptedException { + Recipe input = new Recipe( + 1L, + "Eggs on toast", + "en", + testIngredients, + testPrepSteps); + + String inputJson = objectMapper.writeValueAsString(input); + + // Setup fake endpoint that returns empty list for getRecipes. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); + + // Setup fake endpoint that returns the input recipe when creating new recipe. + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(inputJson))); + + // The addRecipe should strip the recipe of id when sending to server. + Recipe verifyRecipe = stripId(input); + String verifyJson = objectMapper.writeValueAsString(verifyRecipe); + + Recipe result = serverUtils.addRecipe(input); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + assertNotNull(result); + assertEquals(1L, result.getId()); + assertEquals("Eggs on toast", result.getName()); + assertEquals(testIngredients, result.getIngredients()); + assertEquals(testPrepSteps, result.getPreparationSteps()); + } + + @Test + void addRecipeDuplicateTest() throws IOException, InterruptedException { + Recipe pre = new Recipe( + 1L, + "Steak", + "en", + testIngredients, + testPrepSteps); + + // We start with name Steak already being taken. + List recipes = List.of(pre); + String recipesJson = objectMapper.writeValueAsString(recipes); + + // Setup fake endpoint that returns list with 1 recipe in it. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); + + // Our input to add. + Recipe inputRecipe = new Recipe( + 1337L, + pre.getName(), + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + + // addRecipe should generate this. + Recipe generatedRecipe = new Recipe( + null, + pre.getName()+"(1)", + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + String verifyJson = objectMapper.writeValueAsString(generatedRecipe); + + // Server will return this. + Recipe serverReturnRecipe = new Recipe( + pre.getId()+1, + pre.getName()+"(1)", + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + String serverReturnJson = objectMapper.writeValueAsString(serverReturnRecipe); + + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(serverReturnJson))); + + // Ignore the return value as it's tested in addRecipeTest. + serverUtils.addRecipe(inputRecipe); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + } + + @Test + void addRecipeDoubleDuplicateTest() throws IOException, InterruptedException { + Recipe pre = new Recipe( + 1L, + "Steak", + "en", + testIngredients, + testPrepSteps); + + // We start with name Steak already being taken. + List recipes = new ArrayList<>(List.of(pre)); + String recipesJson = objectMapper.writeValueAsString(recipes); + + // Setup fake endpoint that returns list with 1 recipe in it. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); + + // Our input to add. + Recipe inputRecipe = new Recipe( + 1337L, + pre.getName(), + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + + // addRecipe should generate this. + Recipe generatedRecipe = new Recipe( + null, + pre.getName()+"(2)", + "en", + pre.getIngredients(), + pre.getPreparationSteps()); + String verifyJson = objectMapper.writeValueAsString(generatedRecipe); + + // Doesn't matter what we return here, verifyJson is just convenient as it's a recipe. + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(verifyJson))); + + // Ignore the return value as it's tested in addRecipeTest. + serverUtils.addRecipe(inputRecipe); + + // update recipes + recipes.add(inputRecipe); + recipesJson = objectMapper.writeValueAsString(recipes); + inputRecipe.setName(pre.getName()); // Reset name back to Steak without the (1) + + // Setup fake endpoint that returns list with 2 recipes in it. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson(recipesJson))); + + serverUtils.addRecipe(inputRecipe); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + } + + @Test + void addRecipeIngredientIdNullTest() throws IOException, InterruptedException { + // This test checks if RecipeIngredient and recipe ids are null. + Ingredient i1 = new Ingredient(1L, "salt",1,2,3); + Ingredient i2 = new Ingredient(2L, "pepper",4,5,6); + + // input + List ingredients = List.of( + new FormalIngredient(1L, i1, 40, "g"), + new FormalIngredient(2L, i2, 50, "g") + ); + + // generated + List ingredientsStripped = List.of( + new FormalIngredient(null, i1, 40, "g"), + new FormalIngredient(null, i2, 50, "g") + ); + + Recipe inputRecipe = new Recipe( + 1L, + "Steak", + "en", + ingredients, + testPrepSteps); + String inputJson = objectMapper.writeValueAsString(inputRecipe); + + Recipe generatedRecipe = new Recipe( + null, + "Steak", + "en", + ingredientsStripped, + testPrepSteps); + String verifyJson = objectMapper.writeValueAsString(generatedRecipe); + + // Setup fake endpoint that returns empty list for getRecipes. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); + + // Setup fake endpoint that returns the input recipe when creating new recipe. + stubFor(put(urlEqualTo("/api/recipe/new")).willReturn(okJson(inputJson))); + + serverUtils.addRecipe(inputRecipe); + + // Confirm a put request has been made with the verifyRecipe + verify(putRequestedFor(urlEqualTo("/api/recipe/new")) + .withRequestBody(equalToJson(verifyJson))); + + } + + @Test + void findIdNotFoundTest() throws IOException, InterruptedException { + // Setup fake endpoint that returns empty list for getRecipes. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipes")).willReturn(okJson("[]"))); + + assertThrows(IOException.class, () -> serverUtils.findId(1L)); + } + + @Test + void findIdFoundTest() throws IOException, InterruptedException { + Recipe recipe = new Recipe( + 1L, + "Steak", + "en", + testIngredients, + testPrepSteps); + + String recipeJson = objectMapper.writeValueAsString(recipe); + + // Setup fake endpoint that returns the recipe by id. + // urlPathEqualTo, because it ignores query params. + stubFor(get(urlPathEqualTo("/api/recipe/"+recipe.getId())).willReturn(okJson(recipeJson))); + + Recipe found = serverUtils.findId(recipe.getId()); + + assertEquals(recipe.getId(), found.getId()); + assertEquals(recipe.getName(), found.getName()); + assertEquals(recipe.getIngredients(), found.getIngredients()); + assertEquals(recipe.getPreparationSteps(), found.getPreparationSteps()); + } + +} diff --git a/commons/pom.xml b/commons/pom.xml index f48fbcf..0c4e972 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -11,7 +11,6 @@ UTF-8 5.10.1 - 5.8.0 @@ -39,12 +38,6 @@ ${version.junit} test - - org.mockito - mockito-core - ${version.mockito} - test - com.fasterxml.jackson.core jackson-databind diff --git a/commons/src/main/java/commons/FormalIngredient.java b/commons/src/main/java/commons/FormalIngredient.java index 19f514c..88d713a 100644 --- a/commons/src/main/java/commons/FormalIngredient.java +++ b/commons/src/main/java/commons/FormalIngredient.java @@ -31,6 +31,13 @@ public class FormalIngredient extends RecipeIngredient implements Scalable ingredientUnitMap; private Map ingredientDescriptorMap; @@ -17,12 +16,14 @@ public class RecipeIngredientTest { Ingredient ingredient = new Ingredient("Bread", 1, 2, 3); return new FormalIngredient(ingredient, 1.0, unit); } + private VagueIngredient getVague(String descriptor) { Ingredient ingredient = new Ingredient("Bread", 1, 2, 3); return new VagueIngredient(ingredient, descriptor); } + @BeforeEach - void setup(){ + void setup() { ingredientUnitMap = new HashMap<>(); ingredientDescriptorMap = new HashMap<>(); List.of("g", "kg", "ml", "l", "tbsp", "cup") @@ -37,6 +38,7 @@ public class RecipeIngredientTest { FormalIngredient fi = new FormalIngredient(ingredient, 1.0, "g"); assertEquals(ingredient, fi.getIngredient()); } + @Test void testInstantiateVagueIngredient() { Ingredient ingredient = new Ingredient("Bread", 1, 2, 3);