diff --git a/client/src/test/java/client/ServerUtilsMockTest.java b/client/src/test/java/client/ServerUtilsMockTest.java new file mode 100644 index 0000000..369c48c --- /dev/null +++ b/client/src/test/java/client/ServerUtilsMockTest.java @@ -0,0 +1,280 @@ +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. + 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. + 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. + 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. + 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. + 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. + 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. + 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()); + } + +}