From 69d9e0d7360951d6b2a72dfa14dc775f5ba3a3a6 Mon Sep 17 00:00:00 2001 From: js0ny Date: Mon, 24 Nov 2025 00:35:29 +0000 Subject: [PATCH] refractor(dto): Use nested data package --- .../controller/ApiController.java | 42 +-- .../controller/DroneController.java | 26 +- .../data/AttrComparatorDto.java | 7 - .../ilp_coursework/data/DeliveryPathDto.java | 7 - .../data/DistanceRequestDto.java | 13 - .../js0ny/ilp_coursework/data/DroneDto.java | 10 - .../ilp_coursework/data/DronePathDto.java | 4 - .../data/MedDispatchRecDto.java | 12 - .../data/MedRequirementDto.java | 8 - .../data/ServicePointDronesDto.java | 18 -- .../DroneAvailability.java} | 6 +- .../DroneCapability.java} | 4 +- .../data/common/DronePathDto.java | 4 + .../{LngLatDto.java => common/LngLat.java} | 4 +- .../data/common/MedRequirement.java | 9 + .../{RegionDto.java => common/Region.java} | 18 +- .../TimeWindow.java} | 4 +- .../ilp_coursework/data/external/Drone.java | 12 + .../data/external/ServicePointDrones.java | 19 ++ .../data/request/AttrQueryRequest.java | 7 + .../data/request/DistanceRequest.java | 15 ++ .../data/request/MedDispatchRecRequest.java | 15 ++ .../MovementRequest.java} | 8 +- .../RegionCheckRequest.java} | 11 +- .../data/response/DeliveryPathResponse.java | 9 + .../service/DroneInfoService.java | 46 ++-- .../service/GpsCalculationService.java | 68 +++-- .../controller/ApiControllerTest.java | 250 +++++++++--------- .../service/GpsCalculationServiceTest.java | 132 ++++----- 29 files changed, 405 insertions(+), 383 deletions(-) delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/DeliveryPathDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/DistanceRequestDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/DronePathDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/MedDispatchRecDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/MedRequirementDto.java delete mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/ServicePointDronesDto.java rename src/main/java/io/github/js0ny/ilp_coursework/data/{DroneAvailabilityDto.java => common/DroneAvailability.java} (76%) rename src/main/java/io/github/js0ny/ilp_coursework/data/{DroneCapabilityDto.java => common/DroneCapability.java} (68%) create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/common/DronePathDto.java rename src/main/java/io/github/js0ny/ilp_coursework/data/{LngLatDto.java => common/LngLat.java} (68%) create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/common/MedRequirement.java rename src/main/java/io/github/js0ny/ilp_coursework/data/{RegionDto.java => common/Region.java} (78%) rename src/main/java/io/github/js0ny/ilp_coursework/data/{AvailabilityTimeSegDto.java => common/TimeWindow.java} (62%) create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/external/Drone.java create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/external/ServicePointDrones.java create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/request/AttrQueryRequest.java create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/request/DistanceRequest.java create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/request/MedDispatchRecRequest.java rename src/main/java/io/github/js0ny/ilp_coursework/data/{MovementRequestDto.java => request/MovementRequest.java} (70%) rename src/main/java/io/github/js0ny/ilp_coursework/data/{RegionCheckRequestDto.java => request/RegionCheckRequest.java} (61%) create mode 100644 src/main/java/io/github/js0ny/ilp_coursework/data/response/DeliveryPathResponse.java diff --git a/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java b/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java index 7eb937f..3b73161 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java @@ -6,11 +6,11 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import io.github.js0ny.ilp_coursework.data.DistanceRequestDto; -import io.github.js0ny.ilp_coursework.data.LngLatDto; -import io.github.js0ny.ilp_coursework.data.MovementRequestDto; -import io.github.js0ny.ilp_coursework.data.RegionCheckRequestDto; -import io.github.js0ny.ilp_coursework.data.RegionDto; +import io.github.js0ny.ilp_coursework.data.request.DistanceRequest; +import io.github.js0ny.ilp_coursework.data.common.LngLat; +import io.github.js0ny.ilp_coursework.data.request.MovementRequest; +import io.github.js0ny.ilp_coursework.data.request.RegionCheckRequest; +import io.github.js0ny.ilp_coursework.data.common.Region; import io.github.js0ny.ilp_coursework.service.GpsCalculationService; /** @@ -48,39 +48,39 @@ public class ApiController { /** * Handles POST requests to get the distance between two positions * - * @param request A {@link DistanceRequestDto} containing the two coordinates + * @param request A {@link DistanceRequest} containing the two coordinates * @return A {@code double} representing the calculated distance */ @PostMapping("/distanceTo") - public double getDistance(@RequestBody DistanceRequestDto request) { + public double getDistance(@RequestBody DistanceRequest request) { - LngLatDto position1 = request.position1(); - LngLatDto position2 = request.position2(); + LngLat position1 = request.position1(); + LngLat position2 = request.position2(); return gpsService.calculateDistance(position1, position2); } /** * Handles POST requests to check if the two coordinates are close to each other * - * @param request A {@link DistanceRequestDto} containing the two coordinates + * @param request A {@link DistanceRequest} containing the two coordinates * @return {@code true} if the distance is less than the predefined threshold, {@code false} otherwise */ @PostMapping("/isCloseTo") - public boolean getIsCloseTo(@RequestBody DistanceRequestDto request) { - LngLatDto position1 = request.position1(); - LngLatDto position2 = request.position2(); + public boolean getIsCloseTo(@RequestBody DistanceRequest request) { + LngLat position1 = request.position1(); + LngLat position2 = request.position2(); return gpsService.isCloseTo(position1, position2); } /** * Handles POST requests to get the next position after an angle of movement * - * @param request A {@link MovementRequestDto} containing the start coordinate and angle of the movement. - * @return A {@link LngLatDto} representing the destination + * @param request A {@link MovementRequest} containing the start coordinate and angle of the movement. + * @return A {@link LngLat} representing the destination */ @PostMapping("/nextPosition") - public LngLatDto getNextPosition(@RequestBody MovementRequestDto request) { - LngLatDto start = request.start(); + public LngLat getNextPosition(@RequestBody MovementRequest request) { + LngLat start = request.start(); double angle = request.angle(); return gpsService.nextPosition(start, angle); } @@ -88,13 +88,13 @@ public class ApiController { /** * Handles POST requests to check if a point is inside a given region * - * @param request A {@link RegionCheckRequestDto} containing the coordinate and the region + * @param request A {@link RegionCheckRequest} containing the coordinate and the region * @return {@code true} if the coordinate is inside the region, {@code false} otherwise */ @PostMapping("/isInRegion") - public boolean getIsInRegion(@RequestBody RegionCheckRequestDto request) { - LngLatDto position = request.position(); - RegionDto region = request.region(); + public boolean getIsInRegion(@RequestBody RegionCheckRequest request) { + LngLat position = request.position(); + Region region = request.region(); return gpsService.checkIsInRegion(position, region); } } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java b/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java index 4beea49..ee9a8dd 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java @@ -1,10 +1,10 @@ package io.github.js0ny.ilp_coursework.controller; -import io.github.js0ny.ilp_coursework.data.AttrComparatorDto; -import io.github.js0ny.ilp_coursework.data.DeliveryPathDto; -import io.github.js0ny.ilp_coursework.data.DroneDto; -import io.github.js0ny.ilp_coursework.data.DronePathDto; -import io.github.js0ny.ilp_coursework.data.MedDispatchRecDto; +import io.github.js0ny.ilp_coursework.data.response.DeliveryPathResponse; +import io.github.js0ny.ilp_coursework.data.external.Drone; +import io.github.js0ny.ilp_coursework.data.common.DronePathDto; +import io.github.js0ny.ilp_coursework.data.request.MedDispatchRecRequest; +import io.github.js0ny.ilp_coursework.data.request.AttrQueryRequest; import io.github.js0ny.ilp_coursework.service.DroneInfoService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -55,13 +55,13 @@ public class DroneController { * Handles GET requests to retrieve the drone detail identified by id * * @param id The id of the drone to be queried. - * @return 200 with {@link DroneDto}-style json if success, 404 if {@code id} + * @return 200 with {@link Drone}-style json if success, 404 if {@code id} * not found, 400 otherwise */ @GetMapping("/droneDetails/{id}") - public ResponseEntity getDroneDetail(@PathVariable String id) { + public ResponseEntity getDroneDetail(@PathVariable String id) { try { - DroneDto drone = droneService.droneDetail(id); + Drone drone = droneService.droneDetail(id); return ResponseEntity.ok(drone); } catch (IllegalArgumentException ex) { return ResponseEntity.notFound().build(); @@ -84,22 +84,22 @@ public class DroneController { } @PostMapping("/query") - public String[] getIdByAttrMapPost(@RequestBody AttrComparatorDto[] attrComparators) { + public String[] getIdByAttrMapPost(@RequestBody AttrQueryRequest[] attrComparators) { return droneService.dronesSatisfyingAttributes(attrComparators); } @PostMapping("/queryAvailableDrones") - public String[] queryAvailableDrones(@RequestBody MedDispatchRecDto[] records) { + public String[] queryAvailableDrones(@RequestBody MedDispatchRecRequest[] records) { return droneService.dronesMatchesRequirements(records); } @PostMapping("/calcDeliveryPath") - public DeliveryPathDto calculateDeliveryPath(@RequestBody MedDispatchRecDto[] record) { - return new DeliveryPathDto(0.0f, 0, new DronePathDto[]{}); + public DeliveryPathResponse calculateDeliveryPath(@RequestBody MedDispatchRecRequest[] record) { + return new DeliveryPathResponse(0.0f, 0, new DronePathDto[]{}); } @PostMapping("/calcDeliveryPathAsGeoJson") - public String calculateDeliveryPathAsGeoJson(@RequestBody MedDispatchRecDto[] record) { + public String calculateDeliveryPathAsGeoJson(@RequestBody MedDispatchRecRequest[] record) { return "{}"; } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java deleted file mode 100644 index 478a570..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -// TODO: Convert operator to Enum -// import io.github.js0ny.ilp_coursework.util.AttrOperator; - -public record AttrComparatorDto(String attribute, String operator, String value) { -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DeliveryPathDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/DeliveryPathDto.java deleted file mode 100644 index cf5fc84..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/DeliveryPathDto.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -public record DeliveryPathDto( - float totalCost, - int totalMoves, - DronePathDto[] dronePaths) { -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DistanceRequestDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/DistanceRequestDto.java deleted file mode 100644 index 7ba3f79..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/DistanceRequestDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -/** - * Represents the data transfer object for a distance operation request. - *

- * This record encapsulates the data for several endpoints that involves two {@code LngLatDto} - * and serves as the data contract for those API operation - * - * @param position1 Nested object of {@link LngLatDto} - * @param position2 Nested object of {@link LngLatDto} - */ -public record DistanceRequestDto(LngLatDto position1, LngLatDto position2) { -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java deleted file mode 100644 index 1997d26..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -/** - * Represents the data transfer object for a drone, gained from the endpoints - */ -public record DroneDto( - String name, - String id, - DroneCapabilityDto capability) { -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DronePathDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/DronePathDto.java deleted file mode 100644 index 807c62f..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/DronePathDto.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -public record DronePathDto() { -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/MedDispatchRecDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/MedDispatchRecDto.java deleted file mode 100644 index 52e7c4d..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/MedDispatchRecDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -import java.time.LocalDate; -import java.time.LocalTime; - -public record MedDispatchRecDto( - int id, - LocalDate date, - LocalTime time, - MedRequirementDto requirements, - LngLatDto delivery) { -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/MedRequirementDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/MedRequirementDto.java deleted file mode 100644 index 6cb2d4c..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/MedRequirementDto.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -public record MedRequirementDto( - float capacity, - boolean cooling, - boolean heating, - float maxCost -) {} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/ServicePointDronesDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/ServicePointDronesDto.java deleted file mode 100644 index 6022969..0000000 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/ServicePointDronesDto.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.js0ny.ilp_coursework.data; - -import org.springframework.lang.Nullable; - -public record ServicePointDronesDto( - String servicePointId, - DroneAvailabilityDto[] drones) { - - @Nullable - public DroneAvailabilityDto locateDroneById(String droneId) { - for (var drone : drones) { - if (drone.id().equals(droneId)) { - return drone; - } - } - return null; - } -} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneAvailabilityDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/DroneAvailability.java similarity index 76% rename from src/main/java/io/github/js0ny/ilp_coursework/data/DroneAvailabilityDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/common/DroneAvailability.java index 9e2a8f1..231fdfd 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneAvailabilityDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/DroneAvailability.java @@ -1,11 +1,11 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.common; import java.time.DayOfWeek; import java.time.LocalTime; -public record DroneAvailabilityDto( +public record DroneAvailability( String id, - AvailabilityTimeSegDto[] availability) { + TimeWindow[] availability) { public boolean checkAvailability(DayOfWeek day, LocalTime time) { diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneCapabilityDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/DroneCapability.java similarity index 68% rename from src/main/java/io/github/js0ny/ilp_coursework/data/DroneCapabilityDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/common/DroneCapability.java index 6f7d824..66689b1 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneCapabilityDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/DroneCapability.java @@ -1,6 +1,6 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.common; -public record DroneCapabilityDto( +public record DroneCapability( boolean cooling, boolean heating, float capacity, diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/common/DronePathDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/DronePathDto.java new file mode 100644 index 0000000..88aa359 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/DronePathDto.java @@ -0,0 +1,4 @@ +package io.github.js0ny.ilp_coursework.data.common; + +public record DronePathDto() { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/LngLatDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/LngLat.java similarity index 68% rename from src/main/java/io/github/js0ny/ilp_coursework/data/LngLatDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/common/LngLat.java index c3997ec..b239d8e 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/LngLatDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/LngLat.java @@ -1,4 +1,4 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.common; /** * Represents the data transfer object for a point or coordinate @@ -7,5 +7,5 @@ package io.github.js0ny.ilp_coursework.data; * @param lng longitude of the coordinate/point * @param lat latitude of the coordinate/point */ -public record LngLatDto(double lng, double lat) { +public record LngLat(double lng, double lat) { } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/common/MedRequirement.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/MedRequirement.java new file mode 100644 index 0000000..b06e190 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/MedRequirement.java @@ -0,0 +1,9 @@ +package io.github.js0ny.ilp_coursework.data.common; + +public record MedRequirement( + float capacity, + boolean cooling, + boolean heating, + float maxCost +) { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/RegionDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/Region.java similarity index 78% rename from src/main/java/io/github/js0ny/ilp_coursework/data/RegionDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/common/Region.java index dd29144..c491c55 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/RegionDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/Region.java @@ -1,4 +1,6 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.common; + +import io.github.js0ny.ilp_coursework.data.request.RegionCheckRequest; import java.util.List; import java.util.Objects; @@ -18,11 +20,11 @@ import java.util.Objects; * In order to define a valid region, the last element of the * list should be the same as the first, or * known as closed - * @see RegionCheckRequestDto - * @see io.github.js0ny.ilp_coursework.service.GpsCalculationService#checkIsInRegion(LngLatDto, - * RegionDto) + * @see RegionCheckRequest + * @see io.github.js0ny.ilp_coursework.service.GpsCalculationService#checkIsInRegion(LngLat, + * Region) */ -public record RegionDto(String name, List vertices) { +public record Region(String name, List vertices) { /** * Magic number 4: For a polygon, 3 edges is required. *

@@ -35,14 +37,14 @@ public record RegionDto(String name, List vertices) { * {@code vertices} forms a closed polygon * * @return {@code true} if the {@code vertices} are able to form a polygon and - * form a closed polygon + * form a closed polygon */ public boolean isClosed() { if (vertices == null || vertices.size() < MINIMUM_VERTICES) { return false; } - LngLatDto first = vertices.getFirst(); - LngLatDto last = vertices.getLast(); + LngLat first = vertices.getFirst(); + LngLat last = vertices.getLast(); return Objects.equals(last, first); } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/AvailabilityTimeSegDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/common/TimeWindow.java similarity index 62% rename from src/main/java/io/github/js0ny/ilp_coursework/data/AvailabilityTimeSegDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/common/TimeWindow.java index d080bc1..04daeae 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/AvailabilityTimeSegDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/common/TimeWindow.java @@ -1,9 +1,9 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.common; import java.time.DayOfWeek; import java.time.LocalTime; -public record AvailabilityTimeSegDto( +public record TimeWindow( DayOfWeek dayOfWeek, LocalTime from, LocalTime until) { diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/external/Drone.java b/src/main/java/io/github/js0ny/ilp_coursework/data/external/Drone.java new file mode 100644 index 0000000..62baae2 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/external/Drone.java @@ -0,0 +1,12 @@ +package io.github.js0ny.ilp_coursework.data.external; + +import io.github.js0ny.ilp_coursework.data.common.DroneCapability; + +/** + * Represents the data transfer object for a drone, gained from the endpoints + */ +public record Drone( + String name, + String id, + DroneCapability capability) { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/external/ServicePointDrones.java b/src/main/java/io/github/js0ny/ilp_coursework/data/external/ServicePointDrones.java new file mode 100644 index 0000000..9c17fce --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/external/ServicePointDrones.java @@ -0,0 +1,19 @@ +package io.github.js0ny.ilp_coursework.data.external; + +import io.github.js0ny.ilp_coursework.data.common.DroneAvailability; +import org.springframework.lang.Nullable; + +public record ServicePointDrones( + String servicePointId, + DroneAvailability[] drones) { + + @Nullable + public DroneAvailability locateDroneById(String droneId) { + for (var drone : drones) { + if (drone.id().equals(droneId)) { + return drone; + } + } + return null; + } +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/request/AttrQueryRequest.java b/src/main/java/io/github/js0ny/ilp_coursework/data/request/AttrQueryRequest.java new file mode 100644 index 0000000..f87a351 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/request/AttrQueryRequest.java @@ -0,0 +1,7 @@ +package io.github.js0ny.ilp_coursework.data.request; + +// TODO: Convert operator to Enum +// import io.github.js0ny.ilp_coursework.util.AttrOperator; + +public record AttrQueryRequest(String attribute, String operator, String value) { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/request/DistanceRequest.java b/src/main/java/io/github/js0ny/ilp_coursework/data/request/DistanceRequest.java new file mode 100644 index 0000000..34ac900 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/request/DistanceRequest.java @@ -0,0 +1,15 @@ +package io.github.js0ny.ilp_coursework.data.request; + +import io.github.js0ny.ilp_coursework.data.common.LngLat; + +/** + * Represents the data transfer object for a distance operation request. + *

+ * This record encapsulates the data for several endpoints that involves two {@code LngLatDto} + * and serves as the data contract for those API operation + * + * @param position1 Nested object of {@link LngLat} + * @param position2 Nested object of {@link LngLat} + */ +public record DistanceRequest(LngLat position1, LngLat position2) { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/request/MedDispatchRecRequest.java b/src/main/java/io/github/js0ny/ilp_coursework/data/request/MedDispatchRecRequest.java new file mode 100644 index 0000000..d361464 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/request/MedDispatchRecRequest.java @@ -0,0 +1,15 @@ +package io.github.js0ny.ilp_coursework.data.request; + +import io.github.js0ny.ilp_coursework.data.common.MedRequirement; +import io.github.js0ny.ilp_coursework.data.common.LngLat; + +import java.time.LocalDate; +import java.time.LocalTime; + +public record MedDispatchRecRequest( + int id, + LocalDate date, + LocalTime time, + MedRequirement requirements, + LngLat delivery) { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/MovementRequestDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/request/MovementRequest.java similarity index 70% rename from src/main/java/io/github/js0ny/ilp_coursework/data/MovementRequestDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/request/MovementRequest.java index ddfd5eb..2eedade 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/MovementRequestDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/request/MovementRequest.java @@ -1,4 +1,6 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.request; + +import io.github.js0ny.ilp_coursework.data.common.LngLat; /** * Represents the data transfer object for a movement action request. @@ -9,7 +11,7 @@ package io.github.js0ny.ilp_coursework.data; * @param start The starting coordinate of the movement * @param angle The angle to movement in degree. This corresponds to compass directions. * For example: 0 for East, 90 for North - * @see io.github.js0ny.ilp_coursework.controller.ApiController#getNextPosition(MovementRequestDto) + * @see io.github.js0ny.ilp_coursework.controller.ApiController#getNextPosition(MovementRequest) */ -public record MovementRequestDto(LngLatDto start, double angle) { +public record MovementRequest(LngLat start, double angle) { } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/RegionCheckRequestDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/request/RegionCheckRequest.java similarity index 61% rename from src/main/java/io/github/js0ny/ilp_coursework/data/RegionCheckRequestDto.java rename to src/main/java/io/github/js0ny/ilp_coursework/data/request/RegionCheckRequest.java index 11ab0c3..959253c 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/RegionCheckRequestDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/request/RegionCheckRequest.java @@ -1,4 +1,7 @@ -package io.github.js0ny.ilp_coursework.data; +package io.github.js0ny.ilp_coursework.data.request; + +import io.github.js0ny.ilp_coursework.data.common.LngLat; +import io.github.js0ny.ilp_coursework.data.common.Region; /** * Represents the data transfer object for a region check request. @@ -9,8 +12,8 @@ package io.github.js0ny.ilp_coursework.data; * * @param position The coordinate to be checked * @param region The region for the check. - * This is a nested object represented by {@link RegionDto} - * @see io.github.js0ny.ilp_coursework.controller.ApiController#getIsInRegion(RegionCheckRequestDto) + * This is a nested object represented by {@link Region} + * @see io.github.js0ny.ilp_coursework.controller.ApiController#getIsInRegion(RegionCheckRequest) */ -public record RegionCheckRequestDto(LngLatDto position, RegionDto region) { +public record RegionCheckRequest(LngLat position, Region region) { } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/response/DeliveryPathResponse.java b/src/main/java/io/github/js0ny/ilp_coursework/data/response/DeliveryPathResponse.java new file mode 100644 index 0000000..5270863 --- /dev/null +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/response/DeliveryPathResponse.java @@ -0,0 +1,9 @@ +package io.github.js0ny.ilp_coursework.data.response; + +import io.github.js0ny.ilp_coursework.data.common.DronePathDto; + +public record DeliveryPathResponse( + float totalCost, + int totalMoves, + DronePathDto[] dronePaths) { +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java index fcea5a8..b764552 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java @@ -1,10 +1,10 @@ package io.github.js0ny.ilp_coursework.service; -import io.github.js0ny.ilp_coursework.data.AttrComparatorDto; -import io.github.js0ny.ilp_coursework.data.DroneDto; -import io.github.js0ny.ilp_coursework.data.MedDispatchRecDto; -import io.github.js0ny.ilp_coursework.data.ServicePointDronesDto; +import io.github.js0ny.ilp_coursework.data.external.Drone; +import io.github.js0ny.ilp_coursework.data.request.MedDispatchRecRequest; +import io.github.js0ny.ilp_coursework.data.external.ServicePointDrones; import io.github.js0ny.ilp_coursework.util.AttrOperator; +import io.github.js0ny.ilp_coursework.data.request.AttrQueryRequest; import static io.github.js0ny.ilp_coursework.util.AttrComparator.isValueMatched; @@ -59,9 +59,9 @@ public class DroneInfoService { */ public String[] dronesWithCooling(boolean state) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); - DroneDto[] drones = restTemplate.getForObject( + Drone[] drones = restTemplate.getForObject( droneUrl, - DroneDto[].class); + Drone[].class); if (drones == null) { return new String[]{}; @@ -69,12 +69,12 @@ public class DroneInfoService { return Arrays.stream(drones) .filter(drone -> drone.capability().cooling() == state) - .map(DroneDto::id) + .map(Drone::id) .toArray(String[]::new); } /** - * Return a {@link DroneDto}-style json data structure with the given {@code id} + * Return a {@link Drone}-style json data structure with the given {@code id} *

* Associated service method with {@code /droneDetails/{id}} * @@ -87,11 +87,11 @@ public class DroneInfoService { * this should lead to a 404 * @see io.github.js0ny.ilp_coursework.controller.DroneController#getDroneDetail(String) */ - public DroneDto droneDetail(String id) { + public Drone droneDetail(String id) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); - DroneDto[] drones = restTemplate.getForObject( + Drone[] drones = restTemplate.getForObject( droneUrl, - DroneDto[].class); + Drone[].class); if (drones == null) { throw new NullPointerException("drone cannot be found"); @@ -131,7 +131,7 @@ public class DroneInfoService { * @param attrComparators The filter rule with Name, Value and Operator * @return array of drone ids that matches all rules */ - public String[] dronesSatisfyingAttributes(AttrComparatorDto[] attrComparators) { + public String[] dronesSatisfyingAttributes(AttrQueryRequest[] attrComparators) { Set matchingDroneIds = null; for (var comparator : attrComparators) { String attribute = comparator.attribute(); @@ -170,9 +170,9 @@ public class DroneInfoService { private String[] dronesWithAttributeCompared(String attrName, String attrVal, AttrOperator op) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); // This is required to make sure the response is valid - DroneDto[] drones = restTemplate.getForObject( + Drone[] drones = restTemplate.getForObject( droneUrl, - DroneDto[].class); + Drone[].class); if (drones == null) { return new String[]{}; @@ -193,7 +193,7 @@ public class DroneInfoService { return false; } }) - .map(DroneDto::id) + .map(Drone::id) .toArray(String[]::new); } @@ -207,11 +207,11 @@ public class DroneInfoService { * @return array of drone ids that match all the requirements * @see io.github.js0ny.ilp_coursework.controller.DroneController#queryAvailableDrones */ - public String[] dronesMatchesRequirements(MedDispatchRecDto[] rec) { + public String[] dronesMatchesRequirements(MedDispatchRecRequest[] rec) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); - DroneDto[] drones = restTemplate.getForObject( + Drone[] drones = restTemplate.getForObject( droneUrl, - DroneDto[].class); + Drone[].class); if (drones == null || rec == null || rec.length == 0) { return new String[]{}; @@ -226,7 +226,7 @@ public class DroneInfoService { .filter(record -> record != null && record.requirements() != null) // Every record must be met .allMatch(record -> meetsRequirement(drone, record))) - .map(DroneDto::id) + .map(Drone::id) .toArray(String[]::new); } @@ -240,7 +240,7 @@ public class DroneInfoService { * is invalid (capacity and id cannot be null * in {@code MedDispathRecDto}) */ - private boolean meetsRequirement(DroneDto drone, MedDispatchRecDto record) { + private boolean meetsRequirement(Drone drone, MedDispatchRecRequest record) { var requirements = record.requirements(); if (requirements == null) { throw new IllegalArgumentException("requirements cannot be null"); @@ -284,11 +284,11 @@ public class DroneInfoService { * time * @return true if the drone is available, false otherwise */ - private boolean checkAvailability(String droneId, MedDispatchRecDto record) { + private boolean checkAvailability(String droneId, MedDispatchRecRequest record) { URI droneUrl = URI.create(baseUrl).resolve(dronesForServicePointsEndpoint); - ServicePointDronesDto[] servicePoints = restTemplate.getForObject( + ServicePointDrones[] servicePoints = restTemplate.getForObject( droneUrl, - ServicePointDronesDto[].class); + ServicePointDrones[].class); LocalDate requiredDate = record.date(); DayOfWeek requiredDay = requiredDate.getDayOfWeek(); diff --git a/src/main/java/io/github/js0ny/ilp_coursework/service/GpsCalculationService.java b/src/main/java/io/github/js0ny/ilp_coursework/service/GpsCalculationService.java index be193a2..fc78234 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/service/GpsCalculationService.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/service/GpsCalculationService.java @@ -1,16 +1,19 @@ package io.github.js0ny.ilp_coursework.service; -import io.github.js0ny.ilp_coursework.data.*; - import java.util.List; +import io.github.js0ny.ilp_coursework.data.common.LngLat; +import io.github.js0ny.ilp_coursework.data.common.Region; +import io.github.js0ny.ilp_coursework.data.request.DistanceRequest; +import io.github.js0ny.ilp_coursework.data.request.MovementRequest; +import io.github.js0ny.ilp_coursework.data.request.RegionCheckRequest; import org.springframework.stereotype.Service; /** * Class that handles calculations about Coordinates * - * @see LngLatDto - * @see RegionDto + * @see LngLat + * @see Region */ @Service public class GpsCalculationService { @@ -18,30 +21,28 @@ public class GpsCalculationService { /** * Given step size * - * @see #nextPosition(LngLatDto, double) + * @see #nextPosition(LngLat, double) */ private static final double STEP = 0.00015; /** * Given threshold to judge if two points are close to each other * - * @see #isCloseTo(LngLatDto, LngLatDto) + * @see #isCloseTo(LngLat, LngLat) */ private static final double CLOSE_THRESHOLD = 0.00015; /** * Calculate the Euclidean distance between {@code position1} and * {@code position2}, which are coordinates - * defined as {@link LngLatDto} + * defined as {@link LngLat} * * @param position1 The coordinate of the first position - * * @param position2 The coordinate of the second position * @return The Euclidean distance between {@code position1} and - * {@code position2} - * @see - * io.github.js0ny.ilp_coursework.controller.ApiController#getDistance(DistanceRequestDto) + * {@code position2} + * @see io.github.js0ny.ilp_coursework.controller.ApiController#getDistance(DistanceRequest) */ - public double calculateDistance(LngLatDto position1, LngLatDto position2) { + public double calculateDistance(LngLat position1, LngLat position2) { double lngDistance = position2.lng() - position1.lng(); double latDistance = position2.lat() - position1.lat(); // Euclidean: \sqrt{a^2 + b^2} @@ -51,20 +52,19 @@ public class GpsCalculationService { /** * Check if {@code position1} and * {@code position2} are close to each other, the threshold is < 0.00015 - * + * *

* Note that = 0.00015 will be counted as not close to and will return {@code * false} * * @param position1 The coordinate of the first position - * * @param position2 The coordinate of the second position * @return {@code true} if {@code position1} and - * {@code position2} are close to each other + * {@code position2} are close to each other * @see #CLOSE_THRESHOLD - * @see io.github.js0ny.ilp_coursework.controller.ApiController#getIsCloseTo(DistanceRequestDto) + * @see io.github.js0ny.ilp_coursework.controller.ApiController#getIsCloseTo(DistanceRequest) */ - public boolean isCloseTo(LngLatDto position1, LngLatDto position2) { + public boolean isCloseTo(LngLat position1, LngLat position2) { double distance = calculateDistance(position1, position2); return distance < CLOSE_THRESHOLD; } @@ -75,17 +75,16 @@ public class GpsCalculationService { * 0.00015 * * @param start The coordinate of the original start point. - * * @param angle The direction to be moved in angle. * @return The next position moved from {@code start} * @see #STEP - * @see io.github.js0ny.ilp_coursework.controller.ApiController#getNextPosition(MovementRequestDto) + * @see io.github.js0ny.ilp_coursework.controller.ApiController#getNextPosition(MovementRequest) */ - public LngLatDto nextPosition(LngLatDto start, double angle) { + public LngLat nextPosition(LngLat start, double angle) { double rad = Math.toRadians(angle); // Convert to radian for Java triangle function calculation double newLng = Math.cos(rad) * STEP + start.lng(); double newLat = Math.sin(rad) * STEP + start.lat(); - return new LngLatDto(newLng, newLat); + return new LngLat(newLng, newLat); } /** @@ -93,14 +92,14 @@ public class GpsCalculationService { * is inside the {@code region}, on edge and vertex is considered as inside. * * @param position The coordinate of the position. - * @param region A {@link RegionDto} that contains name and a list of + * @param region A {@link Region} that contains name and a list of * {@code LngLatDto} * @return {@code true} if {@code position} is inside the {@code region}. * @throws IllegalArgumentException If {@code region} is not closed - * @see io.github.js0ny.ilp_coursework.controller.ApiController#getIsInRegion(RegionCheckRequestDto) - * @see RegionDto#isClosed() + * @see io.github.js0ny.ilp_coursework.controller.ApiController#getIsInRegion(RegionCheckRequest) + * @see Region#isClosed() */ - public boolean checkIsInRegion(LngLatDto position, RegionDto region) throws IllegalArgumentException { + public boolean checkIsInRegion(LngLat position, Region region) throws IllegalArgumentException { if (!region.isClosed()) { // call method from RegionDto to check if not closed throw new IllegalArgumentException("Region is not closed."); } @@ -115,16 +114,16 @@ public class GpsCalculationService { * @param polygon The region that forms a polygon to check if {@code point} * sits inside. * @return If the {@code point} sits inside the {@code polygon} then - * return {@code true} - * @see #isPointOnEdge(LngLatDto, LngLatDto, LngLatDto) - * @see #checkIsInRegion(LngLatDto, RegionDto) + * return {@code true} + * @see #isPointOnEdge(LngLat, LngLat, LngLat) + * @see #checkIsInRegion(LngLat, Region) */ - private boolean rayCasting(LngLatDto point, List polygon) { + private boolean rayCasting(LngLat point, List polygon) { int intersections = 0; int n = polygon.size(); for (int i = 0; i < n; ++i) { - LngLatDto a = polygon.get(i); - LngLatDto b = polygon.get((i + 1) % n); // Next vertex + LngLat a = polygon.get(i); + LngLat b = polygon.get((i + 1) % n); // Next vertex if (isPointOnEdge(point, a, b)) { return true; @@ -132,7 +131,7 @@ public class GpsCalculationService { // Ensure that `a` is norther than `b`, in order to easy classification if (a.lat() > b.lat()) { - LngLatDto temp = a; + LngLat temp = a; a = b; b = temp; } @@ -165,13 +164,12 @@ public class GpsCalculationService { * {@code a} and {@code b} * * @param p point to be checked on the edge - * * @param a point that forms the edge * @param b point that forms the edge * @return {@code true} if {@code p} is on {@code ab} - * @see #rayCasting(LngLatDto, List) + * @see #rayCasting(LngLat, List) */ - private boolean isPointOnEdge(LngLatDto p, LngLatDto a, LngLatDto b) { + private boolean isPointOnEdge(LngLat p, LngLat a, LngLat b) { // Cross product: (p - a) × (b - a) double crossProduct = (p.lng() - a.lng()) * (b.lat() - a.lat()) - (p.lat() - a.lat()) * (b.lng() - a.lng()); diff --git a/src/test/java/io/github/js0ny/ilp_coursework/controller/ApiControllerTest.java b/src/test/java/io/github/js0ny/ilp_coursework/controller/ApiControllerTest.java index 137eab5..d79f7aa 100644 --- a/src/test/java/io/github/js0ny/ilp_coursework/controller/ApiControllerTest.java +++ b/src/test/java/io/github/js0ny/ilp_coursework/controller/ApiControllerTest.java @@ -8,9 +8,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.ObjectMapper; -import io.github.js0ny.ilp_coursework.data.*; +import io.github.js0ny.ilp_coursework.data.common.LngLat; +import io.github.js0ny.ilp_coursework.data.common.Region; +import io.github.js0ny.ilp_coursework.data.request.DistanceRequest; +import io.github.js0ny.ilp_coursework.data.request.MovementRequest; +import io.github.js0ny.ilp_coursework.data.request.RegionCheckRequest; import io.github.js0ny.ilp_coursework.service.GpsCalculationService; + import java.util.List; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -55,22 +61,22 @@ public class ApiControllerTest { @Test @DisplayName("POST /distanceTo -> 200 OK") void getDistance_shouldReturn200AndDistance_whenCorrectInput() - throws Exception { + throws Exception { double expected = 5.0; String endpoint = "/api/v1/distanceTo"; - LngLatDto p1 = new LngLatDto(0, 4.0); - LngLatDto p2 = new LngLatDto(3.0, 0); - var req = new DistanceRequestDto(p1, p2); + LngLat p1 = new LngLat(0, 4.0); + LngLat p2 = new LngLat(3.0, 0); + var req = new DistanceRequest(p1, p2); when( - service.calculateDistance( - any(LngLatDto.class), - any(LngLatDto.class) - ) + service.calculateDistance( + any(LngLat.class), + any(LngLat.class) + ) ).thenReturn(expected); var mock = mockMvc.perform( - post(endpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(req)) + post(endpoint) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req)) ); mock.andExpect(status().isOk()); @@ -82,23 +88,23 @@ public class ApiControllerTest { void getDistance_shouldReturn400_whenMissingField() throws Exception { String endpoint = "/api/v1/distanceTo"; String req = """ - { - "position1": { - "lng": 3.0, - "lat": 4.0 + { + "position1": { + "lng": 3.0, + "lat": 4.0 + } } - } - """; + """; when( - service.calculateDistance(any(LngLatDto.class), isNull()) + service.calculateDistance(any(LngLat.class), isNull()) ).thenThrow(new NullPointerException()); mockMvc - .perform( - post(endpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(req) - ) - .andExpect(status().isBadRequest()); + .perform( + post(endpoint) + .contentType(MediaType.APPLICATION_JSON) + .content(req) + ) + .andExpect(status().isBadRequest()); } } @@ -109,19 +115,19 @@ public class ApiControllerTest { @Test @DisplayName("POST /isCloseTo -> 200 OK") void getIsCloseTo_shouldReturn200AndBoolean_whenCorrectInput() - throws Exception { + throws Exception { boolean expected = false; String endpoint = "/api/v1/isCloseTo"; - LngLatDto p1 = new LngLatDto(0, 4.0); - LngLatDto p2 = new LngLatDto(3.0, 0); - var req = new DistanceRequestDto(p1, p2); + LngLat p1 = new LngLat(0, 4.0); + LngLat p2 = new LngLat(3.0, 0); + var req = new DistanceRequest(p1, p2); when( - service.isCloseTo(any(LngLatDto.class), any(LngLatDto.class)) + service.isCloseTo(any(LngLat.class), any(LngLat.class)) ).thenReturn(expected); var mock = mockMvc.perform( - post(endpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(req)) + post(endpoint) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req)) ); mock.andExpect(status().isOk()); @@ -131,19 +137,19 @@ public class ApiControllerTest { @Test @DisplayName("POST /isCloseTo -> 400 Bad Request: Malformed JSON ") void getIsCloseTo_shouldReturn400_whenJsonIsMalformed() - throws Exception { + throws Exception { // json without a bracket String malformedJson = """ - { - "position1": { "lng": 0.0, "lat": 3.0 } - """; + { + "position1": { "lng": 0.0, "lat": 3.0 } + """; mockMvc - .perform( - post("/api/v1/isCloseTo") - .contentType(MediaType.APPLICATION_JSON) - .content(malformedJson) - ) - .andExpect(status().isBadRequest()); + .perform( + post("/api/v1/isCloseTo") + .contentType(MediaType.APPLICATION_JSON) + .content(malformedJson) + ) + .andExpect(status().isBadRequest()); } } @@ -156,46 +162,46 @@ public class ApiControllerTest { @Test @DisplayName("POST /nextPosition -> 200 OK") void getNextPosition_shouldReturn200AndCoordinate_whenCorrectInput() - throws Exception { - LngLatDto expected = new LngLatDto(0.00015, 0.0); - LngLatDto p = new LngLatDto(0, 0); - var req = new MovementRequestDto(p, 0); + throws Exception { + LngLat expected = new LngLat(0.00015, 0.0); + LngLat p = new LngLat(0, 0); + var req = new MovementRequest(p, 0); when( - service.nextPosition(any(LngLatDto.class), anyDouble()) + service.nextPosition(any(LngLat.class), anyDouble()) ).thenReturn(expected); var mock = mockMvc.perform( - post(endpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(req)) + post(endpoint) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req)) ); mock.andExpect(status().isOk()); mock.andExpect( - content().json(objectMapper.writeValueAsString(expected)) + content().json(objectMapper.writeValueAsString(expected)) ); } @Test @DisplayName("POST /nextPosition -> 400 Bad Request: Missing Field") void getNextPosition_shouldReturn400_whenKeyNameError() - throws Exception { + throws Exception { // "position" should be "start" String malformedJson = """ - { - "position": { "lng": 0.0, "lat": 3.0 }, - "angle": 180 - } - """; + { + "position": { "lng": 0.0, "lat": 3.0 }, + "angle": 180 + } + """; when(service.nextPosition(isNull(), anyDouble())).thenThrow( - new NullPointerException() + new NullPointerException() ); mockMvc - .perform( - post("/api/v1/nextPosition") - .contentType(MediaType.APPLICATION_JSON) - .content(malformedJson) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()); + .perform( + post("/api/v1/nextPosition") + .contentType(MediaType.APPLICATION_JSON) + .content(malformedJson) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()); } } @@ -206,31 +212,31 @@ public class ApiControllerTest { @Test @DisplayName("POST /isInRegion -> 200 OK") void getIsInRegion_shouldReturn200AndBoolean_whenCorrectInput() - throws Exception { + throws Exception { boolean expected = false; String endpoint = "/api/v1/isInRegion"; - var position = new LngLatDto(1.234, 1.222); - var region = new RegionDto( - "central", - List.of( - new LngLatDto(-3.192473, 55.946233), - new LngLatDto(-3.192473, 55.942617), - new LngLatDto(-3.184319, 55.942617), - new LngLatDto(-3.184319, 55.946233), - new LngLatDto(-3.192473, 55.946233) - ) + var position = new LngLat(1.234, 1.222); + var region = new Region( + "central", + List.of( + new LngLat(-3.192473, 55.946233), + new LngLat(-3.192473, 55.942617), + new LngLat(-3.184319, 55.942617), + new LngLat(-3.184319, 55.946233), + new LngLat(-3.192473, 55.946233) + ) ); - var req = new RegionCheckRequestDto(position, region); + var req = new RegionCheckRequest(position, region); when( - service.checkIsInRegion( - any(LngLatDto.class), - any(RegionDto.class) - ) + service.checkIsInRegion( + any(LngLat.class), + any(Region.class) + ) ).thenReturn(expected); var mock = mockMvc.perform( - post(endpoint) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(req)) + post(endpoint) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(req)) ); mock.andExpect(status().isOk()); @@ -239,59 +245,59 @@ public class ApiControllerTest { @Test @DisplayName( - "POST /isInRegion -> 400 Bad Request: Passing a list of empty vertices to isInRegion" + "POST /isInRegion -> 400 Bad Request: Passing a list of empty vertices to isInRegion" ) void getIsInRegion_shouldReturn400_whenPassingIllegalArguments() - throws Exception { - var position = new LngLatDto(1, 1); - var region = new RegionDto("illegal", List.of()); - var request = new RegionCheckRequestDto(position, region); + throws Exception { + var position = new LngLat(1, 1); + var region = new Region("illegal", List.of()); + var request = new RegionCheckRequest(position, region); when( - service.checkIsInRegion( - any(LngLatDto.class), - any(RegionDto.class) - ) + service.checkIsInRegion( + any(LngLat.class), + any(Region.class) + ) ).thenThrow(new IllegalArgumentException("Region is not closed.")); mockMvc - .perform( - post("/api/v1/isInRegion") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request)) - ) - .andExpect(status().isBadRequest()); + .perform( + post("/api/v1/isInRegion") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request)) + ) + .andExpect(status().isBadRequest()); } @Test @DisplayName( - "POST /isInRegion -> 400 Bad Request: Passing a list of not-closing vertices to isInRegion" + "POST /isInRegion -> 400 Bad Request: Passing a list of not-closing vertices to isInRegion" ) void getIsInRegion_shouldReturn400_whenPassingNotClosingVertices() - throws Exception { - var position = new LngLatDto(1, 1); - var region = new RegionDto( - "illegal", - List.of( - new LngLatDto(1, 2), - new LngLatDto(3, 4), - new LngLatDto(5, 6), - new LngLatDto(7, 8), - new LngLatDto(9, 10) - ) + throws Exception { + var position = new LngLat(1, 1); + var region = new Region( + "illegal", + List.of( + new LngLat(1, 2), + new LngLat(3, 4), + new LngLat(5, 6), + new LngLat(7, 8), + new LngLat(9, 10) + ) ); - var request = new RegionCheckRequestDto(position, region); + var request = new RegionCheckRequest(position, region); when( - service.checkIsInRegion( - any(LngLatDto.class), - any(RegionDto.class) - ) + service.checkIsInRegion( + any(LngLat.class), + any(Region.class) + ) ).thenThrow(new IllegalArgumentException("Region is not closed.")); mockMvc - .perform( - post("/api/v1/isInRegion") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request)) - ) - .andExpect(status().isBadRequest()); + .perform( + post("/api/v1/isInRegion") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request)) + ) + .andExpect(status().isBadRequest()); } } } diff --git a/src/test/java/io/github/js0ny/ilp_coursework/service/GpsCalculationServiceTest.java b/src/test/java/io/github/js0ny/ilp_coursework/service/GpsCalculationServiceTest.java index 49e74c3..3eff87e 100644 --- a/src/test/java/io/github/js0ny/ilp_coursework/service/GpsCalculationServiceTest.java +++ b/src/test/java/io/github/js0ny/ilp_coursework/service/GpsCalculationServiceTest.java @@ -1,7 +1,7 @@ package io.github.js0ny.ilp_coursework.service; -import io.github.js0ny.ilp_coursework.data.LngLatDto; -import io.github.js0ny.ilp_coursework.data.RegionDto; +import io.github.js0ny.ilp_coursework.data.common.LngLat; +import io.github.js0ny.ilp_coursework.data.common.Region; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -32,8 +32,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("False: Given Example For Testing") void isCloseTo_shouldReturnFalse_givenExample() { - var p1 = new LngLatDto(-3.192473, 55.946233); - var p2 = new LngLatDto(-3.192473, 55.942617); + var p1 = new LngLat(-3.192473, 55.946233); + var p2 = new LngLat(-3.192473, 55.942617); double expected = 0.0036; double actual = service.calculateDistance(p1, p2); assertThat(actual).isCloseTo(expected, within(1e-4)); @@ -42,8 +42,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("General Case: 3-4-5 Triangle") void calculateDistance_shouldReturnCorrectEuclideanDistance_forGeneralCase() { - var p1 = new LngLatDto(0, 3.0); - var p2 = new LngLatDto(4.0, 0); + var p1 = new LngLat(0, 3.0); + var p2 = new LngLat(4.0, 0); double expected = 5.0; double actual = service.calculateDistance(p1, p2); assertThat(actual).isCloseTo(expected, within(PRECISION)); @@ -52,7 +52,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Points are Identical") void calculateDistance_shouldReturnZero_whenPointsAreIdentical() { - var p1 = new LngLatDto(123.85, 983.2119); + var p1 = new LngLat(123.85, 983.2119); double expected = 0.0; double actual = service.calculateDistance(p1, p1); assertThat(actual).isEqualTo(expected); @@ -61,8 +61,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Longitudinal-only movement") void calculateDistance_shouldReturnCorrectDistance_forPointsWithSameLatitude() { - var p1 = new LngLatDto(123.85, 983.2119); - var p2 = new LngLatDto(133.85, 983.2119); + var p1 = new LngLat(123.85, 983.2119); + var p2 = new LngLat(133.85, 983.2119); double expected = 10.0; double actual = service.calculateDistance(p1, p2); assertThat(actual).isCloseTo(expected, within(PRECISION)); @@ -71,8 +71,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Latitude-only movement") void calculateDistance_shouldReturnCorrectDistance_forPointsWithSameLongitude() { - var p1 = new LngLatDto(123.85, 983.2119); - var p2 = new LngLatDto(123.85, 973.2119); + var p1 = new LngLat(123.85, 983.2119); + var p2 = new LngLat(123.85, 973.2119); double expected = 10.0; double actual = service.calculateDistance(p1, p2); assertThat(actual).isCloseTo(expected, within(PRECISION)); @@ -81,8 +81,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("General Case: Calculate with negative Coordinates") void calculateDistance_shouldReturnCorrectEuclideanDistance_forNegativeCoordinates() { - LngLatDto p1 = new LngLatDto(-1.0, -2.0); - LngLatDto p2 = new LngLatDto(2.0, 2.0); // lngDiff = 3, latDiff = 4 + LngLat p1 = new LngLat(-1.0, -2.0); + LngLat p2 = new LngLat(2.0, 2.0); // lngDiff = 3, latDiff = 4 double expected = 5.0; double actual = service.calculateDistance(p1, p2); assertThat(actual).isCloseTo(expected, within(PRECISION)); @@ -95,8 +95,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("False: Given Example For Testing") void isCloseTo_shouldReturnFalse_givenExample() { - var p1 = new LngLatDto(-3.192473, 55.946233); - var p2 = new LngLatDto(-3.192473, 55.942617); + var p1 = new LngLat(-3.192473, 55.946233); + var p2 = new LngLat(-3.192473, 55.942617); boolean expected = false; boolean actual = service.isCloseTo(p1, p2); assertThat(actual).isEqualTo(expected); @@ -105,7 +105,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("True: Two points are the same") void isCloseTo_shouldReturnTrue_whenPointsAreIdentical() { - var p1 = new LngLatDto(151.86, 285.37); + var p1 = new LngLat(151.86, 285.37); boolean expected = true; boolean actual = service.isCloseTo(p1, p1); assertThat(actual).isEqualTo(expected); @@ -114,8 +114,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("True: Two points are close to each other and near threshold") void isCloseTo_shouldReturnTrue_whenCloseAndSmallerThanThreshold() { - var p1 = new LngLatDto(0.0, 0.0); - var p2 = new LngLatDto(0.0, 0.00014); + var p1 = new LngLat(0.0, 0.0); + var p2 = new LngLat(0.0, 0.00014); boolean expected = true; boolean actual = service.isCloseTo(p1, p2); assertThat(actual).isEqualTo(expected); @@ -124,8 +124,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("False: Distance nears the threshold") void isCloseTo_shouldReturnFalse_whenEqualsToThreshold() { - var p1 = new LngLatDto(0.0, 0.0); - var p2 = new LngLatDto(0.0, 0.00015); + var p1 = new LngLat(0.0, 0.0); + var p2 = new LngLat(0.0, 0.00015); boolean expected = false; boolean actual = service.isCloseTo(p1, p2); assertThat(actual).isEqualTo(expected); @@ -134,8 +134,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("False: Distance larger to threshold") void isCloseTo_shouldReturnFalse_whenNotCloseAndLargerThanThreshold() { - var p1 = new LngLatDto(0.0, 0.0); - var p2 = new LngLatDto(0.0, 0.00016); + var p1 = new LngLat(0.0, 0.0); + var p2 = new LngLat(0.0, 0.00016); boolean expected = false; boolean actual = service.isCloseTo(p1, p2); assertThat(actual).isEqualTo(expected); @@ -149,10 +149,10 @@ public class GpsCalculationServiceTest { @Test @DisplayName("General Case: nextPosition in East direction (0 degrees)") void nextPosition_shouldMoveEast_forAngleZero() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); double angle = 0; // For 0 degrees, cos(0)=1, sin(0)=0. Move happens entirely on lng axis. - var expected = new LngLatDto(STEP, 0.0); + var expected = new LngLat(STEP, 0.0); var actual = service.nextPosition(start, angle); @@ -163,10 +163,10 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Cardinal Direction: nextPosition in North direction (90 degrees)") void nextPosition_shouldMoveNorth_forAngle90() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); double angle = 90; // For 90 degrees, cos(90)=0, sin(90)=1. Move happens entirely on lat axis. - var expected = new LngLatDto(0.0, STEP); + var expected = new LngLat(0.0, STEP); var actual = service.nextPosition(start, angle); @@ -177,11 +177,11 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Cardinal Direction: nextPosition in West direction (180 degrees)") void nextPosition_shouldMoveWest_forAngle180() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); double angle = 180; // For 180 degrees, cos(180)=-1, sin(180)=0. Move happens entirely on negative // lng axis. - var expected = new LngLatDto(-STEP, 0.0); + var expected = new LngLat(-STEP, 0.0); var actual = service.nextPosition(start, angle); @@ -192,11 +192,11 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Cardinal Direction: nextPosition in South direction (270 degrees)") void nextPosition_shouldMoveSouth_forAngle270() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); double angle = 270; // For 270 degrees, cos(270)=0, sin(270)=-1. Move happens entirely on negative // lat axis. - var expected = new LngLatDto(0.0, -STEP); + var expected = new LngLat(0.0, -STEP); var actual = service.nextPosition(start, angle); @@ -207,12 +207,12 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Intercardinal Direction: nextPosition in Northeast direction (45 degrees)") void nextPosition_shouldMoveNortheast_forAngle45() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); double angle = 45; // Δlng = step * cos(45°), Δlat = step * sin(45°) double expectedLng = STEP * Math.cos(Math.toRadians(angle)); double expectedLat = STEP * Math.sin(Math.toRadians(angle)); - var expected = new LngLatDto(expectedLng, expectedLat); + var expected = new LngLat(expectedLng, expectedLat); var actual = service.nextPosition(start, angle); @@ -223,13 +223,13 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Angle larger than 360 should wrap around") void nextPosition_shouldHandleAngleGreaterThan360() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); // 405 degrees is equivalent to 45 degrees (405 % 360 = 45). double angle = 405; double equivalentAngle = 45; double expectedLng = STEP * Math.cos(Math.toRadians(equivalentAngle)); double expectedLat = STEP * Math.sin(Math.toRadians(equivalentAngle)); - var expected = new LngLatDto(expectedLng, expectedLat); + var expected = new LngLat(expectedLng, expectedLat); var actual = service.nextPosition(start, angle); @@ -240,12 +240,12 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Negative angle should work correctly") void nextPosition_shouldHandleNegativeAngle() { - var start = new LngLatDto(0.0, 0.0); + var start = new LngLat(0.0, 0.0); // A negative angle of -45° corresponds to the Southeast direction. double angle = -45; double expectedLng = STEP * Math.cos(Math.toRadians(angle)); double expectedLat = STEP * Math.sin(Math.toRadians(angle)); - var expected = new LngLatDto(expectedLng, expectedLat); + var expected = new LngLat(expectedLng, expectedLat); var actual = service.nextPosition(start, angle); @@ -258,17 +258,17 @@ public class GpsCalculationServiceTest { @DisplayName("Test for checkIsInRegion(LngLatDto, RegionDto) -> boolean") class CheckIsInRegionTests { - public static final RegionDto RECTANGLE_REGION = new RegionDto("rectangle", List.of(new LngLatDto(0.0, 0.0), - new LngLatDto(2.0, 0.0), new LngLatDto(2.0, 2.0), new LngLatDto(0.0, 2.0), new LngLatDto(0.0, 0.0))); + public static final Region RECTANGLE_REGION = new Region("rectangle", List.of(new LngLat(0.0, 0.0), + new LngLat(2.0, 0.0), new LngLat(2.0, 2.0), new LngLat(0.0, 2.0), new LngLat(0.0, 0.0))); @Test @DisplayName("General Case: Given Example for Testing") void isInRegion_shouldReturnFalse_givenPolygonCentral() { - var position = new LngLatDto(1.234, 1.222); - var region = new RegionDto("central", - List.of(new LngLatDto(-3.192473, 55.946233), new LngLatDto(-3.192473, 55.942617), - new LngLatDto(-3.184319, 55.942617), new LngLatDto(-3.184319, 55.946233), - new LngLatDto(-3.192473, 55.946233))); + var position = new LngLat(1.234, 1.222); + var region = new Region("central", + List.of(new LngLat(-3.192473, 55.946233), new LngLat(-3.192473, 55.942617), + new LngLat(-3.184319, 55.942617), new LngLat(-3.184319, 55.946233), + new LngLat(-3.192473, 55.946233))); boolean expected = false; boolean actual = service.checkIsInRegion(position, region); assertThat(actual).isEqualTo(expected); @@ -277,7 +277,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("General Case: Simple Rectangle") void isInRegion_shouldReturnTrue_forSimpleRectangle() { - var position = new LngLatDto(1.0, 1.0); + var position = new LngLat(1.0, 1.0); boolean expected = true; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -286,7 +286,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("General Case: Simple Rectangle") void isInRegion_shouldReturnFalse_forSimpleRectangle() { - var position = new LngLatDto(3.0, 1.0); + var position = new LngLat(3.0, 1.0); boolean expected = false; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -295,11 +295,11 @@ public class GpsCalculationServiceTest { @Test @DisplayName("General Case: Simple Hexagon") void isInRegion_shouldReturnTrue_forSimpleHexagon() { - var position = new LngLatDto(2.0, 2.0); - var region = new RegionDto("hexagon", - List.of(new LngLatDto(1.0, 0.0), new LngLatDto(4.0, 0.0), new LngLatDto(5.0, 2.0), - new LngLatDto(4.0, 4.0), new LngLatDto(1.0, 4.0), new LngLatDto(0.0, 2.0), - new LngLatDto(1.0, 0.0))); + var position = new LngLat(2.0, 2.0); + var region = new Region("hexagon", + List.of(new LngLat(1.0, 0.0), new LngLat(4.0, 0.0), new LngLat(5.0, 2.0), + new LngLat(4.0, 4.0), new LngLat(1.0, 4.0), new LngLat(0.0, 2.0), + new LngLat(1.0, 0.0))); boolean expected = true; boolean actual = service.checkIsInRegion(position, region); assertThat(actual).isEqualTo(expected); @@ -308,9 +308,9 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Small Triangle") void isInRegion_shouldReturnTrue_forSmallTriangle() { - var position = new LngLatDto(0.00001, 0.00001); - var region = new RegionDto("triangle", List.of(new LngLatDto(0.0, 0.0), new LngLatDto(0.0001, 0.0), - new LngLatDto(0.00005, 0.0001), new LngLatDto(0.0, 0.0))); + var position = new LngLat(0.00001, 0.00001); + var region = new Region("triangle", List.of(new LngLat(0.0, 0.0), new LngLat(0.0001, 0.0), + new LngLat(0.00005, 0.0001), new LngLat(0.0, 0.0))); boolean expected = true; boolean actual = service.checkIsInRegion(position, region); assertThat(actual).isEqualTo(expected); @@ -319,7 +319,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Point on Lower Edge of Rectangle") void isInRegion_shouldReturnTrue_whenPointOnLowerEdge() { - var position = new LngLatDto(0.0, 1.0); + var position = new LngLat(0.0, 1.0); boolean expected = true; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -328,7 +328,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Point on Upper Edge of Rectangle") void isInRegion_shouldReturnTrue_whenPointOnUpperEdge() { - var position = new LngLatDto(2.0, 1.0); + var position = new LngLat(2.0, 1.0); boolean expected = true; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -337,7 +337,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Point on Left Edge") void isInRegion_shouldReturnTrue_whenPointOnLeftEdge() { - var position = new LngLatDto(0.0, 1.0); + var position = new LngLat(0.0, 1.0); boolean expected = true; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -346,7 +346,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Point on Lower Vertex") void isInRegion_shouldReturnTrue_whenPointOnLowerVertex() { - var position = new LngLatDto(0.0, 0.0); + var position = new LngLat(0.0, 0.0); boolean expected = true; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -355,7 +355,7 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Point on Upper Vertex") void isInRegion_shouldReturnTrue_whenPointOnUpperVertex() { - var position = new LngLatDto(2.0, 2.0); + var position = new LngLat(2.0, 2.0); boolean expected = true; boolean actual = service.checkIsInRegion(position, RECTANGLE_REGION); assertThat(actual).isEqualTo(expected); @@ -364,9 +364,9 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Region not forming polygon") void isInRegion_shouldThrowExceptions_whenRegionNotFormingPolygon() { - var position = new LngLatDto(2.0, 2.0); - var region = new RegionDto("line", - List.of(new LngLatDto(0.0, 0.0), new LngLatDto(0.0001, 0.0), new LngLatDto(0.0, 0.0))); + var position = new LngLat(2.0, 2.0); + var region = new Region("line", + List.of(new LngLat(0.0, 0.0), new LngLat(0.0001, 0.0), new LngLat(0.0, 0.0))); assertThatThrownBy(() -> { service.checkIsInRegion(position, region); }).isInstanceOf(IllegalArgumentException.class).hasMessage("Region is not closed."); @@ -375,9 +375,9 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Region is not closed") void isInRegion_shouldThrowExceptions_whenRegionNotClose() { - var position = new LngLatDto(2.0, 2.0); - var region = new RegionDto("rectangle", List.of(new LngLatDto(0.0, 0.0), new LngLatDto(2.0, 0.0), - new LngLatDto(2.0, 2.0), new LngLatDto(0.0, 2.0), new LngLatDto(0.0, -1.0))); + var position = new LngLat(2.0, 2.0); + var region = new Region("rectangle", List.of(new LngLat(0.0, 0.0), new LngLat(2.0, 0.0), + new LngLat(2.0, 2.0), new LngLat(0.0, 2.0), new LngLat(0.0, -1.0))); assertThatThrownBy(() -> { service.checkIsInRegion(position, region); }).isInstanceOf(IllegalArgumentException.class).hasMessage("Region is not closed."); @@ -386,8 +386,8 @@ public class GpsCalculationServiceTest { @Test @DisplayName("Edge Case: Vertex list is empty") void isInRegion_shouldThrowExceptions_whenListIsEmpty() { - var position = new LngLatDto(2.0, 2.0); - var region = new RegionDto("rectangle", List.of()); + var position = new LngLat(2.0, 2.0); + var region = new Region("rectangle", List.of()); assertThatThrownBy(() -> { service.checkIsInRegion(position, region); }).isInstanceOf(IllegalArgumentException.class).hasMessage("Region is not closed.");