From 0b5a2d63f6fec0d7c4e1ba219582272b1d0c9245 Mon Sep 17 00:00:00 2001 From: Faishal Nelwan <108632813+pesolosep@users.noreply.github.com> Date: Thu, 16 May 2024 13:11:34 +0700 Subject: [PATCH] [GREEN] [REFACTOR] Reimplement TDD with factory pattern on subscription box :D --- .../controller/SubscriptionBoxController.java | 121 +++++--- .../dto/DTOMapper.java | 39 +++ .../dto/SubscriptionBoxDTO.java | 17 ++ .../factory/Factory.java | 11 + .../factory/SubscriptionBoxFactory.java | 17 ++ .../model/SubscriptionBox.java | 41 ++- .../model/builder/SubscriptionBoxBuilder.java | 7 +- .../repository/SubscriptionBoxRepository.java | 166 ++++++++--- .../service/SubscriptionBoxService.java | 40 ++- .../service/SubscriptionBoxServiceImpl.java | 125 +++++++- src/main/resources/application-dev.properties | 12 +- .../resources/application-test.properties | 2 +- .../SubscriptionBoxControllerTest.java | 213 +++++++++----- .../factory/SubscriptionBoxFactoryTest.java | 39 +++ .../model/SubscriptionBoxTest.java | 20 +- .../SubscriptionBoxRepositoryTest.java | 269 +++++++++++++----- .../SubscriptionBoxServiceImplTest.java | 237 +++++++++------ 17 files changed, 1040 insertions(+), 336 deletions(-) create mode 100644 src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java create mode 100644 src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java create mode 100644 src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/Factory.java create mode 100644 src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactory.java create mode 100644 src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java index 7cb9ea8..725c95b 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxController.java @@ -1,65 +1,112 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.controller; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.service.SubscriptionBoxService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; -import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; -import id.ac.ui.cs.advprog.snackscription_subscriptionbox.service.SubscriptionBoxService; - import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; @RestController @RequestMapping("/subscription-box") -@CrossOrigin(origins = "*") +@CrossOrigin(origins = "http://localhost:3000") // Change to specific origin if needed +public class SubscriptionBoxController { + private final SubscriptionBoxService subscriptionBoxService; -public class SubscriptionBoxController { @Autowired - private SubscriptionBoxService subscriptionBoxService; - String createHTML = "userCreate"; - @GetMapping("../") - public String createUserPage(Model model) { - return "

Subscription Box Management sudah berhasil!

"; + public SubscriptionBoxController(SubscriptionBoxService subscriptionBoxService) { + this.subscriptionBoxService = subscriptionBoxService; } @PostMapping("/create") - public ResponseEntity createSubscriptionBox(@RequestBody SubscriptionBox subscriptionBox, Model model) { - SubscriptionBox newBox = subscriptionBoxService.addBox(subscriptionBox); - return ResponseEntity.ok(newBox); + public CompletableFuture> createSubscriptionBox(@RequestBody SubscriptionBox subscriptionBox) { + return subscriptionBoxService.save(subscriptionBox) + .thenApply(ResponseEntity::ok) + .exceptionally(ex -> ResponseEntity.badRequest().build()); } - @GetMapping("/viewAll") - public ResponseEntity> viewAll() { - List allBoxes = subscriptionBoxService.viewAll(); - return ResponseEntity.ok(allBoxes); + @GetMapping("/list") + public CompletableFuture>> findAll() { + return subscriptionBoxService.findAll() + .thenApply(ResponseEntity::ok); } - @GetMapping("/view-details/{boxId}") - public ResponseEntity viewDetails(@PathVariable String boxId) { - String boxName = subscriptionBoxService.viewDetails(boxId); - return ResponseEntity.ok(boxName); + @GetMapping("/{id}") + public CompletableFuture> findById(@PathVariable String id) { + try { + UUID.fromString(id); + } catch (IllegalArgumentException e) { + return CompletableFuture.completedFuture(ResponseEntity.badRequest().build()); + } + + return subscriptionBoxService.findById(id) + .thenApply(optionalSubscriptionBox -> + optionalSubscriptionBox.map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build())); } - @DeleteMapping("/delete/{boxId}") - public ResponseEntity deleteBox(@PathVariable String boxId) { - SubscriptionBox deletedBox = subscriptionBoxService.deleteBox(boxId); - return ResponseEntity.ok(deletedBox); + @PatchMapping("/update") + public CompletableFuture> updateSubscriptionBox(@RequestBody SubscriptionBox subscriptionBox) { + if (subscriptionBox.getId() == null || subscriptionBox.getId().isEmpty()) { + return CompletableFuture.completedFuture(ResponseEntity.badRequest().build()); + } + + return subscriptionBoxService.findById(subscriptionBox.getId()) + .thenCompose(optionalSubscriptionBox -> { + if (optionalSubscriptionBox.isEmpty()) { + return CompletableFuture.completedFuture(ResponseEntity.notFound().build()); + } else { + return subscriptionBoxService.update(subscriptionBox) + .thenApply(ResponseEntity::ok); + } + }); } - @PutMapping("/edit/{boxId}") - public ResponseEntity editBox(@PathVariable String boxId, @RequestBody SubscriptionBox subscriptionBox) { - SubscriptionBox editedBox = subscriptionBoxService.editBox(boxId, subscriptionBox); - if (editedBox == null) { - return ResponseEntity.notFound().build(); + @DeleteMapping("/{id}") + public CompletableFuture> deleteSubscriptionBox(@PathVariable String id) { + try { + UUID.fromString(id); + } catch (IllegalArgumentException e) { + return CompletableFuture.completedFuture(ResponseEntity.badRequest().build()); } - return ResponseEntity.ok(editedBox); + + return subscriptionBoxService.delete(id) + .thenApply(result -> ResponseEntity.ok("DELETE SUCCESS")) + .exceptionally(ex -> ResponseEntity.notFound().build()); + } + + @GetMapping("/price/less-than/{price}") + public CompletableFuture>> findByPriceLessThan(@PathVariable int price) { + return subscriptionBoxService.findByPriceLessThan(price) + .thenApply(ResponseEntity::ok); + } + + @GetMapping("/price/greater-than/{price}") + public CompletableFuture>> findByPriceGreaterThan(@PathVariable int price) { + return subscriptionBoxService.findByPriceGreaterThan(price) + .thenApply(ResponseEntity::ok); + } + + @GetMapping("/price/equals/{price}") + public CompletableFuture>> findByPriceEquals(@PathVariable int price) { + return subscriptionBoxService.findByPriceEquals(price) + .thenApply(ResponseEntity::ok); + } + + @GetMapping("/name/{name}") + public CompletableFuture>>> findByName(@PathVariable String name) { + return subscriptionBoxService.findByName(name) + .thenApply(ResponseEntity::ok); } - @GetMapping("/filterByPrice/{price}") - public ResponseEntity> filterByPrice(@PathVariable int price) { - List filteredBoxes = subscriptionBoxService.filterByPrice(price); - return ResponseEntity.ok(filteredBoxes); + @GetMapping("/distinct-names") + public CompletableFuture>>> findDistinctNames() { + return subscriptionBoxService.findDistinctNames() + .thenApply(ResponseEntity::ok); } -} \ No newline at end of file +} diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java new file mode 100644 index 0000000..710e0e6 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/DTOMapper.java @@ -0,0 +1,39 @@ +package id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto; + +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; +import org.springframework.stereotype.Component; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.factory.SubscriptionBoxFactory; + +import java.util.List; +import java.util.Optional; + +@Component +public class DTOMapper { + public static SubscriptionBoxDTO convertModeltoDto (SubscriptionBox subscriptionBox){ + return new SubscriptionBoxDTO( + subscriptionBox.getId(), + subscriptionBox.getName(), + subscriptionBox.getType(), + subscriptionBox.getPrice(), + subscriptionBox.getItems() + ); + } + + public static SubscriptionBox convertDTOtoModel(SubscriptionBoxDTO subscriptionBoxDTO){ + String id = subscriptionBoxDTO.getId(); + String name = subscriptionBoxDTO.getName(); + String type = subscriptionBoxDTO.getType(); + int price = subscriptionBoxDTO.getPrice(); + List items = subscriptionBoxDTO.getItems(); + return new SubscriptionBoxFactory().create(id,name,type,price,items); + } + + public static SubscriptionBox updateSubscriptionBox(SubscriptionBox subscriptionBox, SubscriptionBoxDTO subscriptionBoxDTO){ + Optional.ofNullable(subscriptionBoxDTO.getItems()).ifPresent(subscriptionBox::setItems); + Optional.of( + subscriptionBoxDTO.getPrice()).ifPresent(subscriptionBox::setPrice); + return subscriptionBox; + + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java new file mode 100644 index 0000000..e608fb1 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/dto/SubscriptionBoxDTO.java @@ -0,0 +1,17 @@ +package id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto; + +import lombok.*; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter @Setter +public class SubscriptionBoxDTO { + String id; + String name; + String type; + int price; + List items; +} diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/Factory.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/Factory.java new file mode 100644 index 0000000..f5f4d16 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/Factory.java @@ -0,0 +1,11 @@ +package id.ac.ui.cs.advprog.snackscription_subscriptionbox.factory; + +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; + +import java.util.List; + +public interface Factory { + T create(); + + T create(String id, String name, String type, int price, List items ); +} \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactory.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactory.java new file mode 100644 index 0000000..c35f306 --- /dev/null +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactory.java @@ -0,0 +1,17 @@ +package id.ac.ui.cs.advprog.snackscription_subscriptionbox.factory; + +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; + +import java.util.List; + +public class SubscriptionBoxFactory implements Factory { + @Override + public SubscriptionBox create(){ + return new SubscriptionBox(); + } + + public SubscriptionBox create(String id, String name, String type, int price, List items ){ + return new SubscriptionBox( name, type, price, items); + } +} diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java index f0a499b..27b9af7 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBox.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.Setter; import java.util.List; +import java.util.UUID; @Entity @@ -31,4 +32,42 @@ public class SubscriptionBox { ) List items; // Rating rating; -} \ No newline at end of file + + public SubscriptionBox(){ + this.id = UUID.randomUUID().toString(); + } + + public SubscriptionBox( String name, String type, int price, List items){ + this.id = UUID.randomUUID().toString(); + this.name = name; + this.setType(type); + this.setPrice(price); + this.items = items; + } + + public void setType(String type) { + if (type.equalsIgnoreCase("monthly") | + type.equalsIgnoreCase("quarterly") | + type.equalsIgnoreCase("semi-annual") + ){ + this.type = type; + } + else{ + throw new IllegalArgumentException("Invalid type"); + } + + + } + + public void setPrice(int price) { + if (price >0){ + this.price = price; + } + else{ + throw new IllegalArgumentException("Invalid Price, Please enter integer above 0"); + } + + + } +} +; diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/builder/SubscriptionBoxBuilder.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/builder/SubscriptionBoxBuilder.java index 9494137..5555acb 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/builder/SubscriptionBoxBuilder.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/builder/SubscriptionBoxBuilder.java @@ -24,10 +24,11 @@ public SubscriptionBoxBuilder setName(String name) { } public SubscriptionBoxBuilder setType(String type) { - if (!type.equals("MONTHLY") | !type.equals("QUARTERLY") | !type.equals("SEMI-ANNUALLY")){ - throw new IllegalArgumentException("Invalid Type."); + if (type.equals("MONTHLY") | type.equals("QUARTERLY") | type.equals("SEMI-ANNUALLY")){ + return this; + } - return this; + throw new IllegalArgumentException("Invalid Type."); } public SubscriptionBoxBuilder setPrice(int price) { diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java index fad78bf..b45df42 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepository.java @@ -2,68 +2,150 @@ import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; +import jakarta.transaction.TransactionScoped; import org.springframework.stereotype.Repository; import java.util.ArrayList; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; +import jakarta.transaction.Transactional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; @Repository public class SubscriptionBoxRepository { + @Autowired + private EntityManager entityManager; - private List subscriptionBoxes = new ArrayList<>(); - private List filteredBoxesByPrice = new ArrayList<>(); -// private List filteredBoxesByRating = new ArrayList<>(); + @Transactional + public SubscriptionBox save(SubscriptionBox subscriptionBox) { + entityManager.persist(subscriptionBox); + return subscriptionBox; + } - public SubscriptionBox addBox(SubscriptionBox box) { - subscriptionBoxes.add(box); - return box; + @Transactional + public Optional findById(String id){ + SubscriptionBox subscription = entityManager.find(SubscriptionBox.class, id); + return Optional.ofNullable(subscription); + } + @Transactional + public List findAll(){ + String jpql = "SELECT sb FROM SubscriptionBox sb"; + TypedQuery query = entityManager.createQuery(jpql, SubscriptionBox.class); + return query.getResultList(); } - public SubscriptionBox deleteBox(String id) { - for (SubscriptionBox subscriptionBox : subscriptionBoxes) { - if (subscriptionBox.getId().equals(id)) { - subscriptionBoxes.remove(subscriptionBox); - return subscriptionBox; - } - } - return null; + @Transactional + public SubscriptionBox update(SubscriptionBox subscriptionBox){ + return entityManager.merge(subscriptionBox); } - public SubscriptionBox editBox(String id, SubscriptionBox updatedBox) { - for (SubscriptionBox box : subscriptionBoxes) { - if (box.getId().equals(id)) { - // Assuming the updatedBox object contains the updated fields - box.setName(updatedBox.getName()); - box.setPrice(updatedBox.getPrice()); - return box; // Return the updated box - } - } - return null; // Return null if no box with the given id was found + @Transactional + public void delete(String id){ + SubscriptionBox subscription = findById(id) + .orElseThrow(() -> new IllegalArgumentException("Subscription Box ID not found")); + entityManager.remove(subscription); } + @Transactional + public List findByPriceLessThan(int price) { + String jpql = "SELECT sb FROM SubscriptionBox sb WHERE sb.price < :price"; + TypedQuery query = entityManager.createQuery(jpql, SubscriptionBox.class); + query.setParameter("price", price); + return query.getResultList(); + } + + @Transactional + public List findByPriceGreaterThan(int price) { + String jpql = "SELECT sb FROM SubscriptionBox sb WHERE sb.price > :price"; + TypedQuery query = entityManager.createQuery(jpql, SubscriptionBox.class); + query.setParameter("price", price); + return query.getResultList(); + } - public List viewAll() { - return subscriptionBoxes; + @Transactional + public List findByPriceEquals(int price) { + String jpql = "SELECT sb FROM SubscriptionBox sb WHERE sb.price = :price"; + TypedQuery query = entityManager.createQuery(jpql, SubscriptionBox.class); + query.setParameter("price", price); + return query.getResultList(); } - public String viewDetails(String boxId) { - for (SubscriptionBox subscriptionBox : subscriptionBoxes) { - if (subscriptionBox.getId().equals(boxId)) { - return subscriptionBox.getName(); - } - } - return null; + @Transactional + public Optional> findByName(String name) { + String jpql = "SELECT sb FROM SubscriptionBox sb WHERE LOWER(sb.name) LIKE LOWER(:name)"; + TypedQuery query = entityManager.createQuery(jpql, SubscriptionBox.class); + query.setParameter("name", "%" + name.toLowerCase() + "%"); // Convert input name to lowercase + List result = query.getResultList(); + return Optional.ofNullable(result.isEmpty() ? null : result); } - public List filterByPrice(int price) { - List filteredBoxes = new ArrayList<>(); - for (SubscriptionBox subscriptionBox : subscriptionBoxes) { - if (subscriptionBox.getPrice() == price) { - filteredBoxes.add(subscriptionBox); - } - } - filteredBoxesByPrice = filteredBoxes; - return filteredBoxesByPrice; + @Transactional + public Optional> findDistinctNames() { + String jpql = "SELECT DISTINCT sb.name FROM SubscriptionBox sb"; + TypedQuery query = entityManager.createQuery(jpql, String.class); + List result = query.getResultList(); + return Optional.ofNullable(result.isEmpty() ? null : result); } + +// private List subscriptionBoxes = new ArrayList<>(); +// private List filteredBoxesByPrice = new ArrayList<>(); +//// private List filteredBoxesByRating = new ArrayList<>(); +// +// public SubscriptionBox addBox(SubscriptionBox box) { +// subscriptionBoxes.add(box); +// return box; +// } +// +// public SubscriptionBox deleteBox(String id) { +// for (SubscriptionBox subscriptionBox : subscriptionBoxes) { +// if (subscriptionBox.getId().equals(id)) { +// subscriptionBoxes.remove(subscriptionBox); +// return subscriptionBox; +// } +// } +// return null; +// } +// +// public SubscriptionBox editBox(String id, SubscriptionBox updatedBox) { +// for (SubscriptionBox box : subscriptionBoxes) { +// if (box.getId().equals(id)) { +// // Assuming the updatedBox object contains the updated fields +// box.setName(updatedBox.getName()); +// box.setPrice(updatedBox.getPrice()); +// return box; // Return the updated box +// } +// } +// return null; // Return null if no box with the given id was found +// } +// +// +// public List viewAll() { +// return subscriptionBoxes; +// } +// +// public String viewDetails(String boxId) { +// for (SubscriptionBox subscriptionBox : subscriptionBoxes) { +// if (subscriptionBox.getId().equals(boxId)) { +// return subscriptionBox.getName(); +// } +// } +// return null; +// } +// +// public List filterByPrice(int price) { +// List filteredBoxes = new ArrayList<>(); +// for (SubscriptionBox subscriptionBox : subscriptionBoxes) { +// if (subscriptionBox.getPrice() == price) { +// filteredBoxes.add(subscriptionBox); +// } +// } +// filteredBoxesByPrice = filteredBoxes; +// return filteredBoxesByPrice; +// } } \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java index 5596309..a8c52c7 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxService.java @@ -3,13 +3,39 @@ import java.util.List; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; +import org.springframework.scheduling.annotation.Async; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; public interface SubscriptionBoxService { - public SubscriptionBox addBox(SubscriptionBox subscriptionBox); - public SubscriptionBox editBox(String id, SubscriptionBox subscriptionBox); - public SubscriptionBox deleteBox(String id); - public List viewAll(); - public String viewDetails(String boxId); - public List filterByPrice(int price); - // public List filterByRating(int rating); + CompletableFuture save(SubscriptionBox subscriptionBox); + + CompletableFuture> findById(String id); + + CompletableFuture> findAll(); + + CompletableFuture update(SubscriptionBox subscriptionBox); + + CompletableFuture delete(String id); + + CompletableFuture> findByPriceLessThan(int price); + + CompletableFuture> findByPriceGreaterThan(int price); + + CompletableFuture> findByPriceEquals(int price); + + CompletableFuture>> findByName(String name); + + CompletableFuture>> findDistinctNames(); + + + +// public SubscriptionBox addBox(SubscriptionBox subscriptionBox); +// public SubscriptionBox editBox(String id, SubscriptionBox subscriptionBox); +// public SubscriptionBox deleteBox(String id); +// public List viewAll(); +// public String viewDetails(String boxId); +// public List filterByPrice(int price); +// // public List filterByRating(int rating); } \ No newline at end of file diff --git a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java index f0624b1..1c64846 100644 --- a/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java +++ b/src/main/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImpl.java @@ -1,47 +1,144 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.service; + + import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.repository.SubscriptionBoxRepository; @Service -public class SubscriptionBoxServiceImpl implements SubscriptionBoxService{ +public class SubscriptionBoxServiceImpl implements SubscriptionBoxService { @Autowired private SubscriptionBoxRepository subscriptionBoxRepository; @Override - public SubscriptionBox addBox(SubscriptionBox box) { - return subscriptionBoxRepository.addBox(box); + @Async + public CompletableFuture save(SubscriptionBox subscriptionBox) { + return CompletableFuture.completedFuture(subscriptionBoxRepository.save(subscriptionBox)); + } + + @Override + @Async + public CompletableFuture> findById(String id) { + if (id == null || id.isEmpty()) { + throw new IllegalArgumentException("ID cannot be null or empty"); + } + return CompletableFuture.completedFuture(subscriptionBoxRepository.findById(id)); + } + + @Override + @Async + public CompletableFuture> findAll() { + List subscriptionBoxes = subscriptionBoxRepository.findAll(); + return CompletableFuture.completedFuture(subscriptionBoxes); } @Override - public SubscriptionBox deleteBox(String id) { - return subscriptionBoxRepository.deleteBox(id); + @Async + public CompletableFuture update(SubscriptionBox subscriptionBox) { + if (subscriptionBox == null) { + throw new IllegalArgumentException("SubscriptionBox cannot be null"); + } + return CompletableFuture.completedFuture(subscriptionBoxRepository.update(subscriptionBox)); } @Override - public SubscriptionBox editBox(String id, SubscriptionBox box) { - return subscriptionBoxRepository.editBox(id, box); + @Async + public CompletableFuture delete(String id) { + if (id == null || id.isEmpty()) { + throw new IllegalArgumentException("ID cannot be null or empty"); + } + Optional subscriptionBox = subscriptionBoxRepository.findById(id); + if (!subscriptionBox.isPresent()) { + throw new IllegalArgumentException("Subscription Box not found"); + } + subscriptionBoxRepository.delete(id); + return CompletableFuture.completedFuture(null); } @Override - public List viewAll() { - return subscriptionBoxRepository.viewAll(); + @Async + public CompletableFuture> findByPriceLessThan(int price) { + List result = subscriptionBoxRepository.findByPriceLessThan(price); + return CompletableFuture.completedFuture(result); } @Override - public String viewDetails(String boxId) { - return subscriptionBoxRepository.viewDetails(boxId); + @Async + public CompletableFuture> findByPriceGreaterThan(int price) { + List result = subscriptionBoxRepository.findByPriceGreaterThan(price); + return CompletableFuture.completedFuture(result); } @Override - public List filterByPrice(int price) { - return subscriptionBoxRepository.filterByPrice(price); + @Async + public CompletableFuture> findByPriceEquals(int price) { + List result = subscriptionBoxRepository.findByPriceEquals(price); + return CompletableFuture.completedFuture(result); } + @Override + @Async + public CompletableFuture>> findByName(String name) { + Optional> result = subscriptionBoxRepository.findByName(name); + return CompletableFuture.completedFuture(result); + } + + @Override + public CompletableFuture>> findDistinctNames() { + Optional> distinctNames = subscriptionBoxRepository.findDistinctNames(); + return CompletableFuture.completedFuture(distinctNames); + } + + +} -} \ No newline at end of file +// +//@Service +//public class SubscriptionBoxServiceImpl implements SubscriptionBoxService{ +// @Autowired +// private SubscriptionBoxRepository subscriptionBoxRepository; +// +// @Override +// @Async +// public CompletableFuture +// +// @Override +// public SubscriptionBox addBox(SubscriptionBox box) { +// return subscriptionBoxRepository.addBox(box); +// } +// +// @Override +// public SubscriptionBox deleteBox(String id) { +// return subscriptionBoxRepository.deleteBox(id); +// } +// +// @Override +// public SubscriptionBox editBox(String id, SubscriptionBox box) { +// return subscriptionBoxRepository.editBox(id, box); +// } +// +// @Override +// public List viewAll() { +// return subscriptionBoxRepository.viewAll(); +// } +// +// @Override +// public String viewDetails(String boxId) { +// return subscriptionBoxRepository.viewDetails(boxId); +// } +// +// @Override +// public List filterByPrice(int price) { +// return subscriptionBoxRepository.filterByPrice(price); +// } +// +// +//} \ No newline at end of file diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 9999f38..4176bef 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -1,6 +1,12 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/postgres -spring.datasource.password= ${LOCAL_PASSWORD} -spring.jpa.hibernate.ddl-auto=create-drop +#spring.datasource.password= ${LOCAL_PASSWORD} +spring.datasource.username= postgres +spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect -spring.jpa.properties.hibernate.format_sql=true \ No newline at end of file +spring.jpa.properties.hibernate.format_sql=true + + + + +spring.datasource.password= nelwanfamily2004 \ No newline at end of file diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties index 4963b8e..92d131d 100644 --- a/src/main/resources/application-test.properties +++ b/src/main/resources/application-test.properties @@ -1,7 +1,7 @@ spring.datasource.url=jdbc:postgresql://aws-0-us-west-1.pooler.supabase.com:5432/postgres spring.datasource.username=postgres.eihhrciqsxfomnqhrgle spring.datasource.password=${TEST_PASSWORD} -spring.jpa.hibernate.ddl-auto=create +spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.properties.hibernate.format_sql=true \ No newline at end of file diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java index 9441edc..303cc0a 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/controller/SubscriptionBoxControllerTest.java @@ -1,33 +1,25 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.controller; -import com.fasterxml.jackson.databind.ObjectMapper; - import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.service.SubscriptionBoxService; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.http.ResponseEntity; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.mockito.Mockito.when; -@ExtendWith(SpringExtension.class) -public class SubscriptionBoxControllerTest { - - private MockMvc mockMvc; +class SubscriptionBoxControllerTest { @Mock private SubscriptionBoxService subscriptionBoxService; @@ -35,79 +27,158 @@ public class SubscriptionBoxControllerTest { @InjectMocks private SubscriptionBoxController subscriptionBoxController; - private ObjectMapper objectMapper = new ObjectMapper(); + private SubscriptionBox subscriptionBox; @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - mockMvc = MockMvcBuilders.standaloneSetup(subscriptionBoxController).build(); + void setUp() { + MockitoAnnotations.openMocks(this); + + subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + subscriptionBox.setId(UUID.randomUUID().toString()); } @Test - public void testCreateSubscriptionBox() throws Exception { - SubscriptionBox subscriptionBox = new SubscriptionBox(); - subscriptionBox.setId(UUID.randomUUID().toString()); - subscriptionBox.setName("Test Subscription Box"); - subscriptionBox.setPrice(100000); - // subscriptionBox.setRating(5); - - given(subscriptionBoxService.addBox(any(SubscriptionBox.class))).willReturn(subscriptionBox); - - mockMvc.perform(post("/subscription-box/create") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(subscriptionBox))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.id").value(subscriptionBox.getId())) - .andExpect(jsonPath("$.name").value(subscriptionBox.getName())) - .andExpect(jsonPath("$.price").value(subscriptionBox.getPrice())); + void testCreateSubscriptionBox() { + when(subscriptionBoxService.save(any(SubscriptionBox.class))) + .thenReturn(CompletableFuture.completedFuture(subscriptionBox)); + + CompletableFuture> result = subscriptionBoxController.createSubscriptionBox(subscriptionBox); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBox), result.join()); } @Test - public void testDeleteSubscriptionBox() throws Exception { - String boxId = UUID.randomUUID().toString(); - SubscriptionBox subscriptionBox = new SubscriptionBox(); - subscriptionBox.setId(boxId); - subscriptionBox.setType("MONTHLY"); - subscriptionBox.setName("Test Box"); - subscriptionBox.setPrice(20000); - - given(subscriptionBoxService.deleteBox(subscriptionBox.getId())).willReturn(subscriptionBox); - - mockMvc.perform(delete("/subscription-box/delete/" + boxId)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.id").value(boxId)) - .andExpect(jsonPath("$.name").value("Test Box")) - .andExpect(jsonPath("$.type").value("MONTHLY")) - .andExpect(jsonPath("$.price").value(20000)); + void testFindAll() { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + + when(subscriptionBoxService.findAll()) + .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + + CompletableFuture>> result = subscriptionBoxController.findAll(); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); } + @Test + void testFindById() { + when(subscriptionBoxService.findById(subscriptionBox.getId())) + .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBox))); + + CompletableFuture> result = subscriptionBoxController.findById(subscriptionBox.getId()); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBox), result.join()); + } @Test - public void testViewSubscriptionBox() throws Exception { - SubscriptionBox subscriptionBox = new SubscriptionBox(); - subscriptionBox.setId(UUID.randomUUID().toString()); - subscriptionBox.setName("Test Subscription Box"); - subscriptionBox.setPrice(100000); - // subscriptionBox.setRating(5); + void testFindByIdInvalidId() { + String invalidId = "invalid_id"; + + CompletableFuture> result = subscriptionBoxController.findById(invalidId); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.badRequest().build(), result.join()); + } + + @Test + void testUpdateSubscriptionBox() { + when(subscriptionBoxService.findById(subscriptionBox.getId())) + .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBox))); + when(subscriptionBoxService.update(any(SubscriptionBox.class))) + .thenReturn(CompletableFuture.completedFuture(subscriptionBox)); + + CompletableFuture> result = subscriptionBoxController.updateSubscriptionBox(subscriptionBox); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBox), result.join()); + } + + @Test + void testDeleteSubscriptionBox() { + when(subscriptionBoxService.delete(subscriptionBox.getId())) + .thenReturn(CompletableFuture.completedFuture(null)); - given(subscriptionBoxService.viewDetails(any(String.class))).willReturn(subscriptionBox.toString()); + CompletableFuture> result = subscriptionBoxController.deleteSubscriptionBox(subscriptionBox.getId()); - mockMvc.perform(get("/subscription-box/view-details/" + subscriptionBox.getId())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$").value(subscriptionBox.toString())); + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok("DELETE SUCCESS"), result.join()); } @Test - public void testViewAllSubscriptionBox() throws Exception { - mockMvc.perform(get("/subscription-box/viewAll/")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$").isArray()); + void testFindByPriceLessThan() { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + + when(subscriptionBoxService.findByPriceLessThan(150)) + .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + + CompletableFuture>> result = subscriptionBoxController.findByPriceLessThan(150); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); } @Test - public void testFilterByPrice() throws Exception { - mockMvc.perform(get("/subscription-box/filterByPrice/100000")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$").isArray()); + void testFindByPriceGreaterThan() { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + + when(subscriptionBoxService.findByPriceGreaterThan(50)) + .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + + CompletableFuture>> result = subscriptionBoxController.findByPriceGreaterThan(50); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); + } + + @Test + void testFindByPriceEquals() { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + + when(subscriptionBoxService.findByPriceEquals(100)) + .thenReturn(CompletableFuture.completedFuture(subscriptionBoxes)); + + CompletableFuture>> result = subscriptionBoxController.findByPriceEquals(100); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(subscriptionBoxes), result.join()); + } + + @Test + void testFindByName() { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + + when(subscriptionBoxService.findByName("Basic")) + .thenReturn(CompletableFuture.completedFuture(Optional.of(subscriptionBoxes))); + + CompletableFuture>>> result = subscriptionBoxController.findByName("Basic"); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(Optional.of(subscriptionBoxes)), result.join()); + } + + @Test + void testFindDistinctNames() { + List names = Arrays.asList("Basic", "Premium"); + + when(subscriptionBoxService.findDistinctNames()) + .thenReturn(CompletableFuture.completedFuture(Optional.of(names))); + + CompletableFuture>>> result = subscriptionBoxController.findDistinctNames(); + + assertNotNull(result); + assertTrue(result.isDone()); + assertEquals(ResponseEntity.ok(Optional.of(names)), result.join()); } -} \ No newline at end of file +} diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java new file mode 100644 index 0000000..a8bea7e --- /dev/null +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/factory/SubscriptionBoxFactoryTest.java @@ -0,0 +1,39 @@ +package id.ac.ui.cs.advprog.snackscription_subscriptionbox.factory; + +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; +import java.util.List; + +class SubscriptionBoxFactoryTest { + + @Test + void testCreateEmptySubscriptionBox() { + SubscriptionBoxFactory subscriptionBoxFactory = new SubscriptionBoxFactory(); + SubscriptionBox subscriptionBox = subscriptionBoxFactory.create(); + assertNotNull(subscriptionBox.getId()); // Check if ID is auto-generated + assertNull(subscriptionBox.getName()); // Expect null for name as none set + assertNull(subscriptionBox.getType()); // Expect null for type as none set + assertEquals(0, subscriptionBox.getPrice()); // Default price should be 0 + assertNull(subscriptionBox.getItems()); // Items should be null by default + } + + @Test + void testCreateSubscriptionBoxWithParameters() { + SubscriptionBoxFactory subscriptionBoxFactory = new SubscriptionBoxFactory(); + List items = new ArrayList<>(); + items.add(new Item()); // Assuming you have a constructor in Item class like this + items.add(new Item()); + + SubscriptionBox subscriptionBox = subscriptionBoxFactory.create("1", "Deluxe Box", "Monthly", 150, items); + + assertEquals("Deluxe Box", subscriptionBox.getName()); + assertEquals("Monthly", subscriptionBox.getType()); + assertEquals(150, subscriptionBox.getPrice()); + assertNotNull(subscriptionBox.getItems()); + assertEquals(2, subscriptionBox.getItems().size()); // Check that two items were added + } +} diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBoxTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBoxTest.java index d385804..205f22d 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBoxTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/model/SubscriptionBoxTest.java @@ -1,13 +1,14 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.model; -import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; + +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.dto.SubscriptionBoxDTO; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import java.util.ArrayList; import java.util.List; -import java.util.UUID; + public class SubscriptionBoxTest { List items; @@ -43,6 +44,21 @@ public void testGetType() { assertEquals("MONTHLY", subscriptionBox.getType()); } + @Test + public void testCreateInvalidType(){ + assertThrows(IllegalArgumentException.class, () -> { + SubscriptionBox subscriptionBoxTest = new SubscriptionBox(subscriptionBox.getName(), "Daily", subscriptionBox.getPrice(), subscriptionBox.getItems()); + }); + + } + + @Test + public void testInvalidPrice(){ + assertThrows(IllegalArgumentException.class, () -> { + subscriptionBox.setPrice(-1); + }); + + } @Test public void testGetPrice() { assertEquals(100000, subscriptionBox.getPrice()); diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepositoryTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepositoryTest.java index f37992e..42067ef 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepositoryTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/repository/SubscriptionBoxRepositoryTest.java @@ -1,82 +1,201 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.repository; -import org.junit.jupiter.api.BeforeEach; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import java.util.Arrays; import java.util.List; +import java.util.Optional; -import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; -import id.ac.ui.cs.advprog.snackscription_subscriptionbox.repository.SubscriptionBoxRepository; -import org.mockito.Mock; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class SubscriptionBoxRepositoryTest { + + @Mock + private EntityManager entityManager; + + @InjectMocks + private SubscriptionBoxRepository subscriptionBoxRepository; + + @Test + void testSave() { + SubscriptionBox subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + SubscriptionBox savedSubscriptionBox = subscriptionBoxRepository.save(subscriptionBox); + assertEquals(subscriptionBox, savedSubscriptionBox); + verify(entityManager, times(1)).persist(subscriptionBox); + } + + @Test + void testFindAll() { + SubscriptionBox subscriptionBox1 = new SubscriptionBox("Basic", "Monthly", 100, null); + SubscriptionBox subscriptionBox2 = new SubscriptionBox("Premium", "Monthly", 200, null); + + TypedQuery query = mock(TypedQuery.class); + when(entityManager.createQuery("SELECT sb FROM SubscriptionBox sb", SubscriptionBox.class)).thenReturn(query); + when(query.getResultList()).thenReturn(Arrays.asList(subscriptionBox1, subscriptionBox2)); + + List subscriptionBoxes = subscriptionBoxRepository.findAll(); + + assertEquals(2, subscriptionBoxes.size()); + verify(entityManager, times(1)).createQuery("SELECT sb FROM SubscriptionBox sb", SubscriptionBox.class); + verify(query, times(1)).getResultList(); + } + + @Test + void testFindById() { + SubscriptionBox subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + subscriptionBox.setId("1"); + + when(entityManager.find(SubscriptionBox.class, "1")).thenReturn(subscriptionBox); + + Optional optionalSubscriptionBox = subscriptionBoxRepository.findById("1"); + + assertEquals(Optional.of(subscriptionBox), optionalSubscriptionBox); + verify(entityManager, times(1)).find(SubscriptionBox.class, "1"); + } + + @Test + void testFindByIdSubscriptionNotFound() { + when(entityManager.find(SubscriptionBox.class, "nonexistentId")).thenReturn(null); + + assertNull(subscriptionBoxRepository.findById("nonexistentId").orElse(null)); + + verify(entityManager, times(1)).find(SubscriptionBox.class, "nonexistentId"); + } + + @Test + void testUpdate() { + SubscriptionBox subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + + when(entityManager.merge(subscriptionBox)).thenReturn(subscriptionBox); + + SubscriptionBox updatedSubscriptionBox = subscriptionBoxRepository.update(subscriptionBox); + + assertEquals(subscriptionBox, updatedSubscriptionBox); + verify(entityManager, times(1)).merge(subscriptionBox); + } + + @Test + void testDelete() { + SubscriptionBox subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + subscriptionBox.setId("1"); + + when(entityManager.find(SubscriptionBox.class, "1")).thenReturn(subscriptionBox); + doNothing().when(entityManager).remove(subscriptionBox); + + subscriptionBoxRepository.delete("1"); + + verify(entityManager, times(1)).find(SubscriptionBox.class, "1"); + verify(entityManager, times(1)).remove(subscriptionBox); + } + + @Test + void testDeleteSubscriptionNotFound() { + when(entityManager.find(SubscriptionBox.class, "1")).thenReturn(null); + + assertThrows(IllegalArgumentException.class, () -> subscriptionBoxRepository.delete("1")); + + verify(entityManager, times(1)).find(SubscriptionBox.class, "1"); + verify(entityManager, never()).remove(any()); + } + + @Test + void testFindByPriceLessThan() { + SubscriptionBox subscriptionBox1 = new SubscriptionBox("Basic", "Monthly", 100, null); + SubscriptionBox subscriptionBox2 = new SubscriptionBox("Premium", "Monthly", 200, null); + + TypedQuery query = mock(TypedQuery.class); + when(entityManager.createQuery("SELECT sb FROM SubscriptionBox sb WHERE sb.price < :price", SubscriptionBox.class)).thenReturn(query); + when(query.setParameter("price", 150)).thenReturn(query); + when(query.getResultList()).thenReturn(Arrays.asList(subscriptionBox1)); + + List result = subscriptionBoxRepository.findByPriceLessThan(150); + + assertEquals(1, result.size()); + assertEquals(subscriptionBox1, result.get(0)); + verify(entityManager, times(1)).createQuery("SELECT sb FROM SubscriptionBox sb WHERE sb.price < :price", SubscriptionBox.class); + verify(query, times(1)).setParameter("price", 150); + verify(query, times(1)).getResultList(); + } + + @Test + void testFindByPriceGreaterThan() { + SubscriptionBox subscriptionBox1 = new SubscriptionBox("Basic", "Monthly", 100, null); + SubscriptionBox subscriptionBox2 = new SubscriptionBox("Premium", "Monthly", 200, null); + + TypedQuery query = mock(TypedQuery.class); + when(entityManager.createQuery("SELECT sb FROM SubscriptionBox sb WHERE sb.price > :price", SubscriptionBox.class)).thenReturn(query); + when(query.setParameter("price", 150)).thenReturn(query); + when(query.getResultList()).thenReturn(Arrays.asList(subscriptionBox2)); + + List result = subscriptionBoxRepository.findByPriceGreaterThan(150); + + assertEquals(1, result.size()); + assertEquals(subscriptionBox2, result.get(0)); + verify(entityManager, times(1)).createQuery("SELECT sb FROM SubscriptionBox sb WHERE sb.price > :price", SubscriptionBox.class); + verify(query, times(1)).setParameter("price", 150); + verify(query, times(1)).getResultList(); + } + + @Test + void testFindByPriceEquals() { + SubscriptionBox subscriptionBox1 = new SubscriptionBox("Basic", "Monthly", 100, null); + SubscriptionBox subscriptionBox2 = new SubscriptionBox("Premium", "Monthly", 200, null); + + TypedQuery query = mock(TypedQuery.class); + when(entityManager.createQuery("SELECT sb FROM SubscriptionBox sb WHERE sb.price = :price", SubscriptionBox.class)).thenReturn(query); + when(query.setParameter("price", 100)).thenReturn(query); + when(query.getResultList()).thenReturn(Arrays.asList(subscriptionBox1)); + + List result = subscriptionBoxRepository.findByPriceEquals(100); + + assertEquals(1, result.size()); + assertEquals(subscriptionBox1, result.get(0)); + verify(entityManager, times(1)).createQuery("SELECT sb FROM SubscriptionBox sb WHERE sb.price = :price", SubscriptionBox.class); + verify(query, times(1)).setParameter("price", 100); + verify(query, times(1)).getResultList(); + } + + @Test + void testFindByName() { + SubscriptionBox subscriptionBox1 = new SubscriptionBox("Basic Box", "Monthly", 100, null); + SubscriptionBox subscriptionBox2 = new SubscriptionBox("Premium Box", "Monthly", 200, null); + + TypedQuery query = mock(TypedQuery.class); + when(entityManager.createQuery("SELECT sb FROM SubscriptionBox sb WHERE LOWER(sb.name) LIKE LOWER(:name)", SubscriptionBox.class)).thenReturn(query); + when(query.setParameter("name", "%box%")).thenReturn(query); + when(query.getResultList()).thenReturn(Arrays.asList(subscriptionBox1, subscriptionBox2)); + + Optional> result = subscriptionBoxRepository.findByName("box"); + + assertTrue(result.isPresent()); + assertEquals(2, result.get().size()); + verify(entityManager, times(1)).createQuery("SELECT sb FROM SubscriptionBox sb WHERE LOWER(sb.name) LIKE LOWER(:name)", SubscriptionBox.class); + verify(query, times(1)).setParameter("name", "%box%"); + verify(query, times(1)).getResultList(); + } + + @Test + void testFindDistinctNames() { + TypedQuery query = mock(TypedQuery.class); + when(entityManager.createQuery("SELECT DISTINCT sb.name FROM SubscriptionBox sb", String.class)).thenReturn(query); + when(query.getResultList()).thenReturn(Arrays.asList("Basic Box", "Premium Box")); + + Optional> result = subscriptionBoxRepository.findDistinctNames(); -public class SubscriptionBoxRepositoryTest { - @Mock - private SubscriptionBoxRepository subscriptionBoxRepository; - - - @BeforeEach - public void setUp() { - subscriptionBoxRepository = new SubscriptionBoxRepository(); - } - - @Test - public void testAddBox() { - SubscriptionBox box = new SubscriptionBox(); - SubscriptionBox addedBox = subscriptionBoxRepository.addBox(box); - assertNotNull(addedBox); - } - - @Test - public void testDeleteBox() { - SubscriptionBox box = new SubscriptionBox(); - box.setId("1"); - subscriptionBoxRepository.addBox(box); - SubscriptionBox deletedBox = subscriptionBoxRepository.deleteBox(box.getId()); - assertNotNull(deletedBox); - } - - @Test - public void testEditBox() { - SubscriptionBox box = new SubscriptionBox(); - box.setId("1"); - String id = box.getId(); - box.setName("abc"); - subscriptionBoxRepository.addBox(box); - box.setName("def"); - SubscriptionBox editedBox = subscriptionBoxRepository.editBox(id, box); - assertEquals("def", editedBox.getName()); - } - - @Test - public void testViewAll() { - SubscriptionBox box1 = new SubscriptionBox(); - SubscriptionBox box2 = new SubscriptionBox(); - subscriptionBoxRepository.addBox(box1); - subscriptionBoxRepository.addBox(box2); - List allBoxes = subscriptionBoxRepository.viewAll(); - assertEquals(2, allBoxes.size()); - } - - @Test - public void testViewDetails() { - SubscriptionBox box = new SubscriptionBox(); - box.setName("abc"); - box.setId("1"); - subscriptionBoxRepository.addBox(box); - String details = subscriptionBoxRepository.viewDetails(box.getId()); - assertEquals("abc", details); - } - - @Test - public void testFilterByPrice() { - SubscriptionBox box1 = new SubscriptionBox(); - box1.setPrice(15); - SubscriptionBox box2 = new SubscriptionBox(); - box2.setPrice(25); - subscriptionBoxRepository.addBox(box1); - subscriptionBoxRepository.addBox(box2); - List filteredBoxes = subscriptionBoxRepository.filterByPrice(15); - assertEquals(1, filteredBoxes.size()); - } -} \ No newline at end of file + assertTrue(result.isPresent()); + assertEquals(2, result.get().size()); + assertTrue(result.get().contains("Basic Box")); + assertTrue(result.get().contains("Premium Box")); + verify(entityManager, times(1)).createQuery("SELECT DISTINCT sb.name FROM SubscriptionBox sb", String.class); + verify(query, times(1)).getResultList(); + } +} diff --git a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java index b208bb9..aa05b32 100644 --- a/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java +++ b/src/test/java/id/ac/ui/cs/advprog/snackscription_subscriptionbox/service/SubscriptionBoxServiceImplTest.java @@ -1,24 +1,25 @@ package id.ac.ui.cs.advprog.snackscription_subscriptionbox.service; - -import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.Item; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.model.SubscriptionBox; import id.ac.ui.cs.advprog.snackscription_subscriptionbox.repository.SubscriptionBoxRepository; +import id.ac.ui.cs.advprog.snackscription_subscriptionbox.service.SubscriptionBoxServiceImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) -public class SubscriptionBoxServiceImplTest { +class SubscriptionBoxServiceImplTest { @Mock private SubscriptionBoxRepository subscriptionBoxRepository; @@ -26,98 +27,174 @@ public class SubscriptionBoxServiceImplTest { @InjectMocks private SubscriptionBoxServiceImpl subscriptionBoxService; - private SubscriptionBox box1, box2; - private Item item1, item2; + private SubscriptionBox subscriptionBox; @BeforeEach void setUp() { - // Set up SubscriptionBox and Items - item1 = new Item(); - item1.setName("Chocolate Bar"); - - - item2 = new Item(); - item2.setName("Face Mask"); - - List items1 = new ArrayList<>(); - items1.add(item1); - List items2 = new ArrayList<>(); - items2.add(item2); - - box1 = new SubscriptionBox(); - box1.setId("1"); - box1.setName("Basic Box"); - box1.setType("MONTHLY"); - box1.setPrice(100); - box1.setItems(items1); - - box2 = new SubscriptionBox(); - box2.setId("2"); - box2.setName("Premium Box"); - box2.setType("QUARTERLY"); - box2.setPrice(200); - box2.setItems(items2); + subscriptionBox = new SubscriptionBox("Basic", "Monthly", 100, null); + subscriptionBox.setId("1"); + } + + @Test + void testSave() throws ExecutionException, InterruptedException { + when(subscriptionBoxRepository.save(subscriptionBox)).thenReturn(subscriptionBox); + + CompletableFuture future = subscriptionBoxService.save(subscriptionBox); + SubscriptionBox result = future.get(); + + assertEquals(subscriptionBox, result); + verify(subscriptionBoxRepository, times(1)).save(subscriptionBox); + } + + @Test + void testFindById() throws ExecutionException, InterruptedException { + when(subscriptionBoxRepository.findById("1")).thenReturn(Optional.of(subscriptionBox)); + + CompletableFuture> future = subscriptionBoxService.findById("1"); + Optional result = future.get(); + + assertTrue(result.isPresent()); + assertEquals(subscriptionBox, result.get()); + verify(subscriptionBoxRepository, times(1)).findById("1"); + } + + @Test + void testFindByIdInvalidId() { + assertThrows(IllegalArgumentException.class, () -> { + subscriptionBoxService.findById("").get(); + }); + verify(subscriptionBoxRepository, never()).findById(anyString()); + } + + @Test + void testFindAll() throws ExecutionException, InterruptedException { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + when(subscriptionBoxRepository.findAll()).thenReturn(subscriptionBoxes); + + CompletableFuture> future = subscriptionBoxService.findAll(); + List result = future.get(); + + assertEquals(1, result.size()); + assertEquals(subscriptionBox, result.get(0)); + verify(subscriptionBoxRepository, times(1)).findAll(); + } + + @Test + void testUpdate() throws ExecutionException, InterruptedException { + when(subscriptionBoxRepository.update(subscriptionBox)).thenReturn(subscriptionBox); + + CompletableFuture future = subscriptionBoxService.update(subscriptionBox); + SubscriptionBox result = future.get(); + + assertEquals(subscriptionBox, result); + verify(subscriptionBoxRepository, times(1)).update(subscriptionBox); } @Test - public void testAddBox() { - when(subscriptionBoxRepository.addBox(box1)).thenReturn(box1); - SubscriptionBox result = subscriptionBoxService.addBox(box1); - assertEquals(box1, result); - verify(subscriptionBoxRepository).addBox(box1); + void testUpdateInvalidBox() { + assertThrows(IllegalArgumentException.class, () -> { + subscriptionBoxService.update(null).get(); + }); + verify(subscriptionBoxRepository, never()).update(any()); } @Test - public void testEditBox() { - SubscriptionBox updatedBox = new SubscriptionBox(); - updatedBox.setId("1"); - updatedBox.setName("Updated Basic Box"); - updatedBox.setType("Monthly"); - updatedBox.setPrice(150); - updatedBox.setItems(new ArrayList<>(box1.getItems())); - - when(subscriptionBoxRepository.editBox("1", updatedBox)).thenReturn(updatedBox); - SubscriptionBox result = subscriptionBoxService.editBox("1", updatedBox); - assertEquals("Updated Basic Box", result.getName()); - assertEquals(150, result.getPrice()); - verify(subscriptionBoxRepository).editBox("1", updatedBox); + void testDelete() throws ExecutionException, InterruptedException { + when(subscriptionBoxRepository.findById("1")).thenReturn(Optional.of(subscriptionBox)); + doNothing().when(subscriptionBoxRepository).delete("1"); + + CompletableFuture future = subscriptionBoxService.delete("1"); + future.get(); + + verify(subscriptionBoxRepository, times(1)).findById("1"); + verify(subscriptionBoxRepository, times(1)).delete("1"); } @Test - public void testDeleteBox() { - when(subscriptionBoxRepository.deleteBox("1")).thenReturn(box1); - SubscriptionBox result = subscriptionBoxService.deleteBox("1"); - assertEquals(box1, result); - verify(subscriptionBoxRepository).deleteBox("1"); + void testDeleteInvalidId() { + assertThrows(IllegalArgumentException.class, () -> { + subscriptionBoxService.delete("").get(); + }); + verify(subscriptionBoxRepository, never()).delete(anyString()); } @Test - public void testViewAll() { - List boxes = new ArrayList<>(); - boxes.add(box1); - boxes.add(box2); - when(subscriptionBoxRepository.viewAll()).thenReturn(boxes); - List result = subscriptionBoxService.viewAll(); - assertEquals(2, result.size()); - verify(subscriptionBoxRepository).viewAll(); + void testDeleteSubscriptionNotFound() { + when(subscriptionBoxRepository.findById("1")).thenReturn(Optional.empty()); + + assertThrows(IllegalArgumentException.class, () -> { + subscriptionBoxService.delete("1").get(); + }); + + verify(subscriptionBoxRepository, times(1)).findById("1"); + verify(subscriptionBoxRepository, never()).delete(anyString()); } @Test - public void testViewDetails() { - when(subscriptionBoxRepository.viewDetails("1")).thenReturn("Basic Box"); - String result = subscriptionBoxService.viewDetails("1"); - assertEquals("Basic Box", result); - verify(subscriptionBoxRepository).viewDetails("1"); + void testFindByPriceLessThan() throws ExecutionException, InterruptedException { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + when(subscriptionBoxRepository.findByPriceLessThan(150)).thenReturn(subscriptionBoxes); + + CompletableFuture> future = subscriptionBoxService.findByPriceLessThan(150); + List result = future.get(); + + assertEquals(1, result.size()); + assertEquals(subscriptionBox, result.get(0)); + verify(subscriptionBoxRepository, times(1)).findByPriceLessThan(150); } @Test - public void testFilterByPrice() { - List filteredBoxes = new ArrayList<>(); - filteredBoxes.add(box1); - when(subscriptionBoxRepository.filterByPrice(100)).thenReturn(filteredBoxes); - List result = subscriptionBoxService.filterByPrice(100); + void testFindByPriceGreaterThan() throws ExecutionException, InterruptedException { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + when(subscriptionBoxRepository.findByPriceGreaterThan(50)).thenReturn(subscriptionBoxes); + + CompletableFuture> future = subscriptionBoxService.findByPriceGreaterThan(50); + List result = future.get(); + assertEquals(1, result.size()); - assertTrue(result.contains(box1)); - verify(subscriptionBoxRepository).filterByPrice(100); + assertEquals(subscriptionBox, result.get(0)); + verify(subscriptionBoxRepository, times(1)).findByPriceGreaterThan(50); + } + + @Test + void testFindByPriceEquals() throws ExecutionException, InterruptedException { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + when(subscriptionBoxRepository.findByPriceEquals(100)).thenReturn(subscriptionBoxes); + + CompletableFuture> future = subscriptionBoxService.findByPriceEquals(100); + List result = future.get(); + + assertEquals(1, result.size()); + assertEquals(subscriptionBox, result.get(0)); + verify(subscriptionBoxRepository, times(1)).findByPriceEquals(100); + } + + @Test + void testFindByName() throws ExecutionException, InterruptedException { + List subscriptionBoxes = Arrays.asList(subscriptionBox); + when(subscriptionBoxRepository.findByName("Basic")).thenReturn(Optional.of(subscriptionBoxes)); + + CompletableFuture>> future = subscriptionBoxService.findByName("Basic"); + Optional> result = future.get(); + + assertTrue(result.isPresent()); + assertEquals(1, result.get().size()); + assertEquals(subscriptionBox, result.get().get(0)); + verify(subscriptionBoxRepository, times(1)).findByName("Basic"); + } + + @Test + void testFindDistinctNames() throws ExecutionException, InterruptedException { + List names = Arrays.asList("Basic", "Premium"); + when(subscriptionBoxRepository.findDistinctNames()).thenReturn(Optional.of(names)); + + CompletableFuture>> future = subscriptionBoxService.findDistinctNames(); + Optional> result = future.get(); + + assertTrue(result.isPresent()); + assertEquals(2, result.get().size()); + assertTrue(result.get().contains("Basic")); + assertTrue(result.get().contains("Premium")); + verify(subscriptionBoxRepository, times(1)).findDistinctNames(); } }