From 579247025249a4587c7b3896b1c229f141ccb200 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Thu, 4 Apr 2024 20:12:47 +0000 Subject: [PATCH 01/12] feat: implements MediaItemsController --- .../lesson16/web/MediaItemsController.java | 40 +++++++++++++++++++ .../lesson16/web/PatronsController.java | 0 2 files changed, 40 insertions(+) create mode 100644 lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java index cae5ff06..02461077 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java @@ -4,11 +4,20 @@ import com.codedifferently.lesson16.library.Library; import com.codedifferently.lesson16.library.MediaItem; import com.codedifferently.lesson16.library.search.SearchCriteria; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; import java.util.Set; +import java.util.UUID; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +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.RestController; +import org.springframework.web.server.ResponseStatusException; @RestController public class MediaItemsController { @@ -27,4 +36,35 @@ public GetMediaItemsResponse getItems() { var response = GetMediaItemsResponse.builder().items(responseItems).build(); return response; } + + @PostMapping("/items") + public CreateMediaItemResponse postItem(@Valid @RequestBody CreateMediaItemRequest request) { + MediaItem item = MediaItemRequest.asMediaItem(request.getItem()); + library.addMediaItem(item, librarian); + var response = CreateMediaItemResponse.builder().item(MediaItemResponse.from(item)).build(); + return response; + } + + @GetMapping("/items/{id}") + public GetMediaItemsResponse getItem(@PathVariable String id) { + SearchCriteria criteria = SearchCriteria.builder().id(id).build(); + Set items = library.search(criteria); + + if (items.isEmpty()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Media item not found"); + } + + List responseItems = items.stream().map(MediaItemResponse::from).toList(); + return GetMediaItemsResponse.builder().items(responseItems).build(); + } + + @DeleteMapping("/items/{id}") + public ResponseEntity deleteItem(@PathVariable String id) { + if (!library.hasMediaItem(UUID.fromString(id))) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Media item not found"); + } + + library.removeMediaItem(UUID.fromString(id), librarian); + return ResponseEntity.noContent().build(); + } } diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java new file mode 100644 index 00000000..e69de29b From ed6df4fdb37a5df91e956bd7f887f3d70a358822 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Fri, 5 Apr 2024 15:32:45 +0000 Subject: [PATCH 02/12] chore:adds PatronResponse file and functionality --- .../lesson16/web/PatronRequest.java | 1 + .../lesson16/web/PatronResponse.java | 28 +++++++++++++++++++ .../lesson16/web/PatronsController.java | 1 + 3 files changed, 30 insertions(+) create mode 100644 lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java create mode 100644 lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java @@ -0,0 +1 @@ + diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java new file mode 100644 index 00000000..4323fcbd --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java @@ -0,0 +1,28 @@ +package com.codedifferently.lesson16.web; + +import java.util.UUID; + +import com.codedifferently.lesson16.library.Patron; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class PatronResponse { + + private UUID id; + private String name; + private String email; + + /** + * Converts a Patron object to a PatronResponse object. + * + * @param patron The Patron object to convert. + * @return The converted PatronResponse object. + */ + public static PatronResponse from(Patron patron) { + return PatronResponse.builder().id(patron.getId()).name(patron.getName()).email(patron.getEmail()).build(); + + } +} \ No newline at end of file diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index e69de29b..8b137891 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -0,0 +1 @@ + From 511ab7e31c2e621d43b84dba4a6e61f76f511a08 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Fri, 5 Apr 2024 21:44:10 +0000 Subject: [PATCH 03/12] chore:refactoring code --- .../lesson16/web/PatronRequest.java | 24 +++++++++++++++++++ .../lesson16/web/PatronsController.java | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java index 8b137891..fe18821c 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java @@ -1 +1,25 @@ +package com.codedifferently.lesson16.web; +import java.util.UUID; + +import com.codedifferently.lesson16.library.Patron; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PatronRequest { + private UUID id; + private String name; + private String email; + + public static Patron asPatron(PatronRequest request) { + return new Patron (request.getName(), request.getEmail()); + +} +} \ No newline at end of file diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index 8b137891..536a315f 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -1 +1,3 @@ - +public class PatronsController { + +} From 478dca38cb153ccb42f17bd6c8966f77c3a7a734 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Sat, 6 Apr 2024 15:26:56 +0000 Subject: [PATCH 04/12] chore: refactors code --- .../com/codedifferently/lesson16/web/PatronRequest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java index fe18821c..8ddf7466 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java @@ -4,6 +4,7 @@ import com.codedifferently.lesson16.library.Patron; +import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -15,11 +16,15 @@ @Builder public class PatronRequest { private UUID id; + @NotBlank(message = "name is required") private String name; + @NotBlank(message = "email is required") private String email; - public static Patron asPatron(PatronRequest request) { - return new Patron (request.getName(), request.getEmail()); + public static Patron asPatron(PatronRequest request) { + String name = request.getName(); + String email = request.getEmail(); + return new Patron(name, email); } } \ No newline at end of file From acd5ea277d716b07cd5b0f27d60de85146a7688c Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Sat, 6 Apr 2024 16:51:05 +0000 Subject: [PATCH 05/12] chore: adds getpatronresponse,createpatronrequest, and createpatron response files --- .../lesson16/web/CreatePatronRequest.java | 17 ++++++++++ .../lesson16/web/CreatePatronResponse.java | 10 ++++++ .../lesson16/web/GetPatronsResponse.java | 12 +++++++ .../lesson16/web/PatronRequest.java | 28 ++++++++--------- .../lesson16/web/PatronResponse.java | 31 ++++++++++--------- .../lesson16/web/PatronsController.java | 4 +-- 6 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronRequest.java create mode 100644 lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java create mode 100644 lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/GetPatronsResponse.java diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronRequest.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronRequest.java new file mode 100644 index 00000000..db557148 --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronRequest.java @@ -0,0 +1,17 @@ +package com.codedifferently.lesson16.web; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CreatePatronRequest { + @NotNull(message = "patron is required") @Valid + private PatronRequest patron; +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java new file mode 100644 index 00000000..3799bed1 --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java @@ -0,0 +1,10 @@ +package com.codedifferently.lesson16.web; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class CreatePatronResponse { + private PatronResponse patron; +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/GetPatronsResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/GetPatronsResponse.java new file mode 100644 index 00000000..846639a5 --- /dev/null +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/GetPatronsResponse.java @@ -0,0 +1,12 @@ +package com.codedifferently.lesson16.web; + +import java.util.List; +import lombok.Builder; +import lombok.Data; +import lombok.Singular; + +@Data +@Builder +public class GetPatronsResponse { + @Singular private List patrons; +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java index 8ddf7466..ee5a36e6 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronRequest.java @@ -1,10 +1,8 @@ package com.codedifferently.lesson16.web; -import java.util.UUID; - import com.codedifferently.lesson16.library.Patron; - import jakarta.validation.constraints.NotBlank; +import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -15,16 +13,18 @@ @NoArgsConstructor @Builder public class PatronRequest { - private UUID id; - @NotBlank(message = "name is required") - private String name; - @NotBlank(message = "email is required") - private String email; + private UUID id; + + @NotBlank(message = "name is required") + private String name; + + @NotBlank(message = "email is required") + private String email; + + public static Patron asPatron(PatronRequest request) { + String name = request.getName(); + String email = request.getEmail(); - public static Patron asPatron(PatronRequest request) { - String name = request.getName(); - String email = request.getEmail(); - - return new Patron(name, email); + return new Patron(name, email); + } } -} \ No newline at end of file diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java index 4323fcbd..11da5296 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java @@ -1,9 +1,7 @@ package com.codedifferently.lesson16.web; -import java.util.UUID; - import com.codedifferently.lesson16.library.Patron; - +import java.util.UUID; import lombok.Builder; import lombok.Data; @@ -11,18 +9,21 @@ @Builder public class PatronResponse { - private UUID id; - private String name; - private String email; + private UUID id; + private String name; + private String email; - /** - * Converts a Patron object to a PatronResponse object. - * - * @param patron The Patron object to convert. - * @return The converted PatronResponse object. - */ + /** + * Converts a Patron object to a PatronResponse object. + * + * @param patron The Patron object to convert. + * @return The converted PatronResponse object. + */ public static PatronResponse from(Patron patron) { - return PatronResponse.builder().id(patron.getId()).name(patron.getName()).email(patron.getEmail()).build(); - + return PatronResponse.builder() + .id(patron.getId()) + .name(patron.getName()) + .email(patron.getEmail()) + .build(); } -} \ No newline at end of file +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index 536a315f..705e1598 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -1,3 +1 @@ -public class PatronsController { - -} +public class PatronsController {} From b1f993b66e4b8020e421537ec3340311903700f9 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Mon, 8 Apr 2024 15:31:30 +0000 Subject: [PATCH 06/12] feat: MediaItems and Patrons Controller implemented, incomplete tests for patrons controller. --- .../lesson16/web/PatronResponse.java | 6 +- .../lesson16/web/PatronsController.java | 68 +++++++++++++- .../web/MediaItemsControllerTest.java | 72 +++++++-------- .../lesson16/web/PatronsControllerTest.java | 91 +++++++++++++++++++ 4 files changed, 198 insertions(+), 39 deletions(-) create mode 100644 lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java index 11da5296..6bff48d0 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java @@ -1,7 +1,9 @@ package com.codedifferently.lesson16.web; -import com.codedifferently.lesson16.library.Patron; import java.util.UUID; + +import com.codedifferently.lesson16.library.LibraryGuest; + import lombok.Builder; import lombok.Data; @@ -19,7 +21,7 @@ public class PatronResponse { * @param patron The Patron object to convert. * @return The converted PatronResponse object. */ - public static PatronResponse from(Patron patron) { + public static PatronResponse from(LibraryGuest patron) { return PatronResponse.builder() .id(patron.getId()) .name(patron.getName()) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index 705e1598..f5503cf8 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -1 +1,67 @@ -public class PatronsController {} +package com.codedifferently.lesson16.web; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +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.RestController; +import org.springframework.web.server.ResponseStatusException; + +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; +import com.codedifferently.lesson16.library.Patron; + +import jakarta.validation.Valid; + +@RestController +public class PatronsController { + private final Library library; + + public PatronsController(Library library) throws IOException { + this.library = library; + } + //Mohamed helped me sort out this method! + @GetMapping("/patrons") + public GetPatronsResponse getPatrons() { + Set patrons = library.getPatrons(); + List responsePatrons = patrons.stream().map(PatronResponse::from).toList(); + var response = GetPatronsResponse.builder().patrons(responsePatrons).build(); + return response; + } + + @PostMapping("/patrons") + public CreatePatronResponse postPatron(@Valid @RequestBody CreatePatronRequest request) { + Patron patron = PatronRequest.asPatron(request.getPatron()); + library.addLibraryGuest(patron); + var response = CreatePatronResponse.builder().patron(PatronResponse.from(patron)).build(); + return response; + } + + @GetMapping("/patrons/{id}") + public ResponseEntity getPatronById(@PathVariable UUID id) { + for (LibraryGuest patron : library.getPatrons()) { + if (patron.getId().equals(id)) { + return ResponseEntity.ok(patron); + } + } + return ResponseEntity.notFound().build(); + } + + @DeleteMapping("/patrons/{id}") + public ResponseEntity deleteItem(@PathVariable String id) { + if (!library.hasLibraryGuest(UUID.fromString(id))) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Patron not found"); + } + + library.removeLibraryGuest(UUID.fromString(id)); + return ResponseEntity.noContent().build(); + } +} diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java index fdb1ea7d..ae39a967 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java @@ -1,27 +1,27 @@ package com.codedifferently.lesson16.web; +import java.util.Set; + import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; import com.codedifferently.lesson16.Lesson16; -import com.codedifferently.lesson16.library.Book; import com.codedifferently.lesson16.library.Library; import com.codedifferently.lesson16.library.MediaItem; import com.codedifferently.lesson16.library.search.SearchCriteria; -import java.util.Set; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; @SpringBootTest @ContextConfiguration(classes = Lesson16.class) @@ -62,11 +62,11 @@ void testController_returnsNotFoundOnGetItem() throws Exception { } @Test - void testController_reportsBadRequestOnAddItem() throws Exception { + void testController_reportsBadRequestOnAddPatron() throws Exception { String json = "{}"; mockMvc - .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) + .perform(post("/patrons").contentType(MediaType.APPLICATION_JSON).content(json)) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.errors").isArray()) .andExpect(jsonPath("$.errors.length()").value(1)); @@ -74,31 +74,31 @@ void testController_reportsBadRequestOnAddItem() throws Exception { @Test void testController_addsItem() throws Exception { - String json = - """ - { - "item": { - "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", - "type": "BOOK", - "title": "Becoming", - "isbn": "9781524763138", - "authors": ["Michelle Obama"], - "pages": 448 - } - } - """; + // String json = + // """ + // { + // "item": { + // "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + // "type": "BOOK", + // "title": "Becoming", + // "isbn": "9781524763138", + // "authors": ["Michelle Obama"], + // "pages": 448 + // } + // } + // """; - mockMvc - .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); + // mockMvc + // .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) + // .andExpect(status().isOk()) + // .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); - Set items = - library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); - assertThat(items).hasSize(1); - var item = items.iterator().next(); - assertThat(item).isInstanceOf(Book.class); - assertThat(item.getTitle()).isEqualTo("Becoming"); + // Set items = + // library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); + // assertThat(items).hasSize(1); + // var item = items.iterator().next(); + // assertThat(item).isInstanceOf(Book.class); + // assertThat(item.getTitle()).isEqualTo("Becoming"); } @Test diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java new file mode 100644 index 00000000..cd27f6fc --- /dev/null +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java @@ -0,0 +1,91 @@ +package com.codedifferently.lesson16.web; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.codedifferently.lesson16.Lesson16; +import com.codedifferently.lesson16.library.Library; + + + + +@SpringBootTest +@ContextConfiguration(classes = Lesson16.class) +class PatronsControllerTest { + private static MockMvc mockMvc; + @Autowired private Library library; + + @BeforeAll + static void setUp(WebApplicationContext wac) { + mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); + } + + @Test + void testController_getsAllPatrons() throws Exception { + mockMvc + .perform(get("/patrons").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.patrons").isArray()) + .andExpect(jsonPath("$.patrons.length()").value(5)); + } + + @Test + void testController_getsAPatron() throws Exception { + mockMvc + .perform( + get("/patrons/e4258931-fad0-4372-84d8-de32022c3334") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + @Test + void testController_returnsNotFoundOnGetPatron() throws Exception { + mockMvc + .perform( + get("/patrons/00000000-0000-0000-0000-000000000000") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } + + @Test + void testController_reportsBadRequestOnAddPatron() throws Exception { + String json = "{}"; + + mockMvc + .perform(post("/patrons").contentType(MediaType.APPLICATION_JSON).content(json)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.errors").isArray()) + .andExpect(jsonPath("$.errors.length()").value(1)); + } + + @Test + void testPostPatron() throws Exception { + + } + + @Test + void testController_returnsNotFoundOnDeletePatron() throws Exception { + mockMvc + .perform( + delete("/patrons/00000000-0000-0000-0000-000000000000") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()); + } + + @Test + void testController_deletesPatron() throws Exception { + + } +} From 6676daa318052f12d55adb4a4b793bae5ebd00cc Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Mon, 8 Apr 2024 15:36:25 +0000 Subject: [PATCH 07/12] fix: runs spotlessApply --- .../lesson16/web/PatronResponse.java | 4 +-- .../lesson16/web/PatronsController.java | 14 +++++----- .../web/MediaItemsControllerTest.java | 24 ++++++++--------- .../lesson16/web/PatronsControllerTest.java | 27 +++++++------------ 4 files changed, 29 insertions(+), 40 deletions(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java index 6bff48d0..10d96c79 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronResponse.java @@ -1,9 +1,7 @@ package com.codedifferently.lesson16.web; -import java.util.UUID; - import com.codedifferently.lesson16.library.LibraryGuest; - +import java.util.UUID; import lombok.Builder; import lombok.Data; diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index f5503cf8..e419878a 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -1,10 +1,13 @@ package com.codedifferently.lesson16.web; +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; +import com.codedifferently.lesson16.library.Patron; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; import java.util.Set; import java.util.UUID; - import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -15,12 +18,6 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; -import com.codedifferently.lesson16.library.Library; -import com.codedifferently.lesson16.library.LibraryGuest; -import com.codedifferently.lesson16.library.Patron; - -import jakarta.validation.Valid; - @RestController public class PatronsController { private final Library library; @@ -28,7 +25,8 @@ public class PatronsController { public PatronsController(Library library) throws IOException { this.library = library; } - //Mohamed helped me sort out this method! + + // Mohamed helped me sort out this method! @GetMapping("/patrons") public GetPatronsResponse getPatrons() { Set patrons = library.getPatrons(); diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java index ae39a967..66d52695 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java @@ -1,27 +1,26 @@ package com.codedifferently.lesson16.web; -import java.util.Set; - import static org.assertj.core.api.Assertions.assertThat; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; import com.codedifferently.lesson16.Lesson16; import com.codedifferently.lesson16.library.Library; import com.codedifferently.lesson16.library.MediaItem; import com.codedifferently.lesson16.library.search.SearchCriteria; +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; @SpringBootTest @ContextConfiguration(classes = Lesson16.class) @@ -94,7 +93,8 @@ void testController_addsItem() throws Exception { // .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); // Set items = - // library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); + // + // library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); // assertThat(items).hasSize(1); // var item = items.iterator().next(); // assertThat(item).isInstanceOf(Book.class); diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java index cd27f6fc..55aab508 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java @@ -1,5 +1,13 @@ package com.codedifferently.lesson16.web; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.codedifferently.lesson16.Lesson16; +import com.codedifferently.lesson16.library.Library; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -7,20 +15,9 @@ import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.codedifferently.lesson16.Lesson16; -import com.codedifferently.lesson16.library.Library; - - - - @SpringBootTest @ContextConfiguration(classes = Lesson16.class) class PatronsControllerTest { @@ -71,9 +68,7 @@ void testController_reportsBadRequestOnAddPatron() throws Exception { } @Test - void testPostPatron() throws Exception { - - } + void testPostPatron() throws Exception {} @Test void testController_returnsNotFoundOnDeletePatron() throws Exception { @@ -85,7 +80,5 @@ void testController_returnsNotFoundOnDeletePatron() throws Exception { } @Test - void testController_deletesPatron() throws Exception { - - } + void testController_deletesPatron() throws Exception {} } From ec53358787d12bb6f3d059acfa78a3ec0d108f78 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Tue, 9 Apr 2024 14:55:06 +0000 Subject: [PATCH 08/12] feat: adds test for postPatron --- .../lesson16/web/CreatePatronResponse.java | 14 +++- .../lesson16/web/PatronsController.java | 23 +++--- .../web/MediaItemsControllerTest.java | 74 ++++++++++--------- .../lesson16/web/PatronsControllerTest.java | 57 ++++++++++---- 4 files changed, 106 insertions(+), 62 deletions(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java index 3799bed1..2d146305 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java @@ -7,4 +7,16 @@ @Builder public class CreatePatronResponse { private PatronResponse patron; -} + + // public CreatePatronResponse(PatronResponse patron) { + // this.patron = patron; + // } + + // public PatronResponse getPatron() { + // return patron; + // } + + // public void setPatron(PatronResponse patron) { + // this.patron = patron; + // } +} \ No newline at end of file diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index e419878a..2bed3f0d 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -1,13 +1,10 @@ package com.codedifferently.lesson16.web; -import com.codedifferently.lesson16.library.Library; -import com.codedifferently.lesson16.library.LibraryGuest; -import com.codedifferently.lesson16.library.Patron; -import jakarta.validation.Valid; import java.io.IOException; import java.util.List; import java.util.Set; import java.util.UUID; + import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -18,6 +15,12 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; +import com.codedifferently.lesson16.library.Patron; + +import jakarta.validation.Valid; + @RestController public class PatronsController { private final Library library; @@ -44,14 +47,14 @@ public CreatePatronResponse postPatron(@Valid @RequestBody CreatePatronRequest r } @GetMapping("/patrons/{id}") - public ResponseEntity getPatronById(@PathVariable UUID id) { +public GetPatronsResponse getPatronById(@PathVariable UUID id) { for (LibraryGuest patron : library.getPatrons()) { - if (patron.getId().equals(id)) { - return ResponseEntity.ok(patron); - } + if (patron.getId().equals(id)) { + return GetPatronsResponse.builder().patron(PatronResponse.from(patron)).build(); + } } - return ResponseEntity.notFound().build(); - } + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Patron not found"); +} @DeleteMapping("/patrons/{id}") public ResponseEntity deleteItem(@PathVariable String id) { diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java index 66d52695..bc9f4d82 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java @@ -1,26 +1,28 @@ package com.codedifferently.lesson16.web; +import java.util.Set; + import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; import com.codedifferently.lesson16.Lesson16; +import com.codedifferently.lesson16.library.Book; import com.codedifferently.lesson16.library.Library; import com.codedifferently.lesson16.library.MediaItem; import com.codedifferently.lesson16.library.search.SearchCriteria; -import java.util.Set; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; @SpringBootTest @ContextConfiguration(classes = Lesson16.class) @@ -73,32 +75,32 @@ void testController_reportsBadRequestOnAddPatron() throws Exception { @Test void testController_addsItem() throws Exception { - // String json = - // """ - // { - // "item": { - // "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", - // "type": "BOOK", - // "title": "Becoming", - // "isbn": "9781524763138", - // "authors": ["Michelle Obama"], - // "pages": 448 - // } - // } - // """; - - // mockMvc - // .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) - // .andExpect(status().isOk()) - // .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); - - // Set items = - // - // library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); - // assertThat(items).hasSize(1); - // var item = items.iterator().next(); - // assertThat(item).isInstanceOf(Book.class); - // assertThat(item.getTitle()).isEqualTo("Becoming"); + String json = + """ + { + "item": { + "id": "e27a4e0d-9664-420d-955e-c0e295d0ce02", + "type": "BOOK", + "title": "Becoming", + "isbn": "9781524763138", + "authors": ["Michelle Obama"], + "pages": 448 + } + } + """; + + mockMvc + .perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(json)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); + + Set items = + + library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); + assertThat(items).hasSize(1); + var item = items.iterator().next(); + assertThat(item).isInstanceOf(Book.class); + assertThat(item.getTitle()).isEqualTo("Becoming"); } @Test diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java index 55aab508..d23cea89 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java @@ -1,23 +1,28 @@ package com.codedifferently.lesson16.web; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.util.Set; +import java.util.UUID; -import com.codedifferently.lesson16.Lesson16; -import com.codedifferently.lesson16.library.Library; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +import com.codedifferently.lesson16.Lesson16; +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.Patron; + @SpringBootTest @ContextConfiguration(classes = Lesson16.class) class PatronsControllerTest { @@ -38,14 +43,20 @@ void testController_getsAllPatrons() throws Exception { .andExpect(jsonPath("$.patrons.length()").value(5)); } + @Test - void testController_getsAPatron() throws Exception { - mockMvc - .perform( - get("/patrons/e4258931-fad0-4372-84d8-de32022c3334") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - } +void testGetPatronById() throws Exception { + // Given + UUID id = UUID.randomUUID(); + Patron patron = new Patron("John Doe", "john.doe@example.com"); + when(library.getPatrons()).thenReturn(Set.of(patron)); + + // When & Then + mockMvc.perform(get("/patrons/{id}", id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name").value("John Doe")) + .andExpect(jsonPath("$.email").value("john.doe@example.com")); +} @Test void testController_returnsNotFoundOnGetPatron() throws Exception { @@ -68,7 +79,23 @@ void testController_reportsBadRequestOnAddPatron() throws Exception { } @Test - void testPostPatron() throws Exception {} + void testPostPatron() throws Exception { + String json = + """ + { + "patron": { + "name": "Rich Hawkins", + "email": "rich@email.com" + } + } + """; + +mockMvc + .perform(post("/patrons").contentType(MediaType.APPLICATION_JSON).content(json)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.patron.name").value("Rich Hawkins")); + + } @Test void testController_returnsNotFoundOnDeletePatron() throws Exception { From 36de172e245455ce87fb9faef3838ec8e3f9e4e0 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Wed, 10 Apr 2024 13:03:49 +0000 Subject: [PATCH 09/12] feat: completed test suite --- .../lesson16/web/CreatePatronResponse.java | 13 +---- .../lesson16/web/PatronsControllerTest.java | 58 +++++++++++++------ 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java index 2d146305..69669245 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java @@ -7,16 +7,5 @@ @Builder public class CreatePatronResponse { private PatronResponse patron; - - // public CreatePatronResponse(PatronResponse patron) { - // this.patron = patron; - // } - - // public PatronResponse getPatron() { - // return patron; - // } - - // public void setPatron(PatronResponse patron) { - // this.patron = patron; - // } + } \ No newline at end of file diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java index d23cea89..06d3f2b9 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java @@ -1,11 +1,11 @@ package com.codedifferently.lesson16.web; -import java.util.Set; +import java.util.List; import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; @@ -21,7 +21,7 @@ import com.codedifferently.lesson16.Lesson16; import com.codedifferently.lesson16.library.Library; -import com.codedifferently.lesson16.library.Patron; +import com.codedifferently.lesson16.library.LibraryGuest; @SpringBootTest @ContextConfiguration(classes = Lesson16.class) @@ -43,19 +43,16 @@ void testController_getsAllPatrons() throws Exception { .andExpect(jsonPath("$.patrons.length()").value(5)); } - + // Got help from Mohamed on this one. Learned that .stream() is super useful. @Test void testGetPatronById() throws Exception { - // Given - UUID id = UUID.randomUUID(); - Patron patron = new Patron("John Doe", "john.doe@example.com"); - when(library.getPatrons()).thenReturn(Set.of(patron)); - - // When & Then - mockMvc.perform(get("/patrons/{id}", id)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.name").value("John Doe")) - .andExpect(jsonPath("$.email").value("john.doe@example.com")); + + List patron = library.getPatrons().stream().toList(); + UUID ids = patron.get(3).getId(); + + mockMvc + .perform(get("/patrons/" + ids.toString()).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); } @Test @@ -105,7 +102,34 @@ void testController_returnsNotFoundOnDeletePatron() throws Exception { .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isNotFound()); } - +// Mo' also helped on this...didn't think of making a helper function. Kudos to him! @Test - void testController_deletesPatron() throws Exception {} -} + void testController_deletesPatron() throws Exception { + Library lib = library; + List pat = library.getPatrons().stream().toList(); + UUID ids = getGuestId(pat); + + mockMvc + .perform(delete("/patrons/" + ids.toString()).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()); + int i = 0; + pat = library.getPatrons().stream().toList(); + for (LibraryGuest guest : pat) { + if (guest.getId() == ids) { + i++; + } + } + library = lib; + assertThat(i).isEqualTo(0); + } + + UUID getGuestId(List list) { + for (LibraryGuest guest : list) { + if (guest.getCheckedOutMediaItems().isEmpty()) { + return guest.getId(); + } + } + return list.get(4).getId(); + } + } + From 3af578a35c3e7f0199d7d724e82e3b236b303976 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Wed, 10 Apr 2024 13:31:07 +0000 Subject: [PATCH 10/12] fix: runs spotlessApply --- .../lesson16/web/CreatePatronResponse.java | 3 +- .../lesson16/web/PatronsController.java | 21 ++-- .../web/MediaItemsControllerTest.java | 24 ++--- .../lesson16/web/PatronsControllerTest.java | 100 +++++++++--------- 4 files changed, 70 insertions(+), 78 deletions(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java index 69669245..3799bed1 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/CreatePatronResponse.java @@ -7,5 +7,4 @@ @Builder public class CreatePatronResponse { private PatronResponse patron; - -} \ No newline at end of file +} diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java index 2bed3f0d..f2516988 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/PatronsController.java @@ -1,10 +1,13 @@ package com.codedifferently.lesson16.web; +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; +import com.codedifferently.lesson16.library.Patron; +import jakarta.validation.Valid; import java.io.IOException; import java.util.List; import java.util.Set; import java.util.UUID; - import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -15,12 +18,6 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ResponseStatusException; -import com.codedifferently.lesson16.library.Library; -import com.codedifferently.lesson16.library.LibraryGuest; -import com.codedifferently.lesson16.library.Patron; - -import jakarta.validation.Valid; - @RestController public class PatronsController { private final Library library; @@ -47,14 +44,14 @@ public CreatePatronResponse postPatron(@Valid @RequestBody CreatePatronRequest r } @GetMapping("/patrons/{id}") -public GetPatronsResponse getPatronById(@PathVariable UUID id) { + public GetPatronsResponse getPatronById(@PathVariable UUID id) { for (LibraryGuest patron : library.getPatrons()) { - if (patron.getId().equals(id)) { - return GetPatronsResponse.builder().patron(PatronResponse.from(patron)).build(); - } + if (patron.getId().equals(id)) { + return GetPatronsResponse.builder().patron(PatronResponse.from(patron)).build(); + } } throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Patron not found"); -} + } @DeleteMapping("/patrons/{id}") public ResponseEntity deleteItem(@PathVariable String id) { diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java index bc9f4d82..3baf159b 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java @@ -1,28 +1,27 @@ package com.codedifferently.lesson16.web; -import java.util.Set; - import static org.assertj.core.api.Assertions.assertThat; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; import com.codedifferently.lesson16.Lesson16; import com.codedifferently.lesson16.library.Book; import com.codedifferently.lesson16.library.Library; import com.codedifferently.lesson16.library.MediaItem; import com.codedifferently.lesson16.library.search.SearchCriteria; +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; @SpringBootTest @ContextConfiguration(classes = Lesson16.class) @@ -95,8 +94,7 @@ void testController_addsItem() throws Exception { .andExpect(jsonPath("$.item.id").value("e27a4e0d-9664-420d-955e-c0e295d0ce02")); Set items = - - library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); + library.search(SearchCriteria.builder().id("e27a4e0d-9664-420d-955e-c0e295d0ce02").build()); assertThat(items).hasSize(1); var item = items.iterator().next(); assertThat(item).isInstanceOf(Book.class); diff --git a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java index 06d3f2b9..b550f427 100644 --- a/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java +++ b/lesson_16/api/api_app/src/test/java/com/codedifferently/lesson16/web/PatronsControllerTest.java @@ -1,9 +1,17 @@ package com.codedifferently.lesson16.web; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.codedifferently.lesson16.Lesson16; +import com.codedifferently.lesson16.library.Library; +import com.codedifferently.lesson16.library.LibraryGuest; import java.util.List; import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -11,18 +19,9 @@ import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import com.codedifferently.lesson16.Lesson16; -import com.codedifferently.lesson16.library.Library; -import com.codedifferently.lesson16.library.LibraryGuest; - @SpringBootTest @ContextConfiguration(classes = Lesson16.class) class PatronsControllerTest { @@ -45,15 +44,15 @@ void testController_getsAllPatrons() throws Exception { // Got help from Mohamed on this one. Learned that .stream() is super useful. @Test -void testGetPatronById() throws Exception { - - List patron = library.getPatrons().stream().toList(); - UUID ids = patron.get(3).getId(); - - mockMvc - .perform(get("/patrons/" + ids.toString()).contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); -} + void testGetPatronById() throws Exception { + + List patron = library.getPatrons().stream().toList(); + UUID ids = patron.get(3).getId(); + + mockMvc + .perform(get("/patrons/" + ids.toString()).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } @Test void testController_returnsNotFoundOnGetPatron() throws Exception { @@ -78,7 +77,7 @@ void testController_reportsBadRequestOnAddPatron() throws Exception { @Test void testPostPatron() throws Exception { String json = - """ + """ { "patron": { "name": "Rich Hawkins", @@ -87,11 +86,10 @@ void testPostPatron() throws Exception { } """; -mockMvc - .perform(post("/patrons").contentType(MediaType.APPLICATION_JSON).content(json)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.patron.name").value("Rich Hawkins")); - + mockMvc + .perform(post("/patrons").contentType(MediaType.APPLICATION_JSON).content(json)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.patron.name").value("Rich Hawkins")); } @Test @@ -102,34 +100,34 @@ void testController_returnsNotFoundOnDeletePatron() throws Exception { .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isNotFound()); } -// Mo' also helped on this...didn't think of making a helper function. Kudos to him! + + // Mo' also helped on this...didn't think of making a helper function. Kudos to him! @Test - void testController_deletesPatron() throws Exception { - Library lib = library; - List pat = library.getPatrons().stream().toList(); - UUID ids = getGuestId(pat); - - mockMvc - .perform(delete("/patrons/" + ids.toString()).contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isNoContent()); - int i = 0; - pat = library.getPatrons().stream().toList(); - for (LibraryGuest guest : pat) { - if (guest.getId() == ids) { - i++; - } + void testController_deletesPatron() throws Exception { + Library lib = library; + List pat = library.getPatrons().stream().toList(); + UUID ids = getGuestId(pat); + + mockMvc + .perform(delete("/patrons/" + ids.toString()).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNoContent()); + int i = 0; + pat = library.getPatrons().stream().toList(); + for (LibraryGuest guest : pat) { + if (guest.getId() == ids) { + i++; } - library = lib; - assertThat(i).isEqualTo(0); } - - UUID getGuestId(List list) { - for (LibraryGuest guest : list) { - if (guest.getCheckedOutMediaItems().isEmpty()) { - return guest.getId(); - } + library = lib; + assertThat(i).isEqualTo(0); + } + + UUID getGuestId(List list) { + for (LibraryGuest guest : list) { + if (guest.getCheckedOutMediaItems().isEmpty()) { + return guest.getId(); } - return list.get(4).getId(); } + return list.get(4).getId(); } - +} From 67b25f00edb380d7d794a5b3c0bf288a0e865c69 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Wed, 10 Apr 2024 13:36:07 +0000 Subject: [PATCH 11/12] fix: runs spotlessApply --- .../com/codedifferently/lesson16/web/MediaItemsController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java index 07e5842a..b66f2f6b 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java @@ -8,7 +8,6 @@ import java.io.IOException; import java.util.List; import java.util.Set; - import java.util.UUID; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; From 25405e16fab73250f04bf2d4b24f71415bbe8810 Mon Sep 17 00:00:00 2001 From: RichHawkins Date: Wed, 10 Apr 2024 13:40:28 +0000 Subject: [PATCH 12/12] fix: adds crossorigin import --- .../com/codedifferently/lesson16/web/MediaItemsController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java index b66f2f6b..8859cdb7 100644 --- a/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java +++ b/lesson_16/api/api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java @@ -11,6 +11,7 @@ import java.util.UUID; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable;