diff --git a/src/main/java/ch/naviqore/app/controller/RoutingController.java b/src/main/java/ch/naviqore/app/controller/RoutingController.java index 4d603718..423c040c 100644 --- a/src/main/java/ch/naviqore/app/controller/RoutingController.java +++ b/src/main/java/ch/naviqore/app/controller/RoutingController.java @@ -35,30 +35,64 @@ public RoutingController(PublicTransitService service) { this.service = service; } + private static GeoCoordinate validateCoordinate(double latitude, double longitude) { + try { + return new GeoCoordinate(latitude, longitude); + } catch (IllegalArgumentException e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Coordinates must be valid, Latitude between -90 and 90 and Longitude between -180 and 180."); + } + } + + private static void validateQueryParams(int maxWalkingDuration, int maxTransferNumber, int maxTravelTime, + int minTransferTime) { + if (maxWalkingDuration < 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Max walking duration must be greater than or equal to 0."); + } + if (maxTransferNumber < 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Max transfer number must be greater than or equal to 0."); + } + if (maxTravelTime <= 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Max travel time must be greater than 0."); + } + if (minTransferTime < 0) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + "Min transfer time must be greater than or equal to 0."); + } + } + @GetMapping("/connections") public List getConnections(@RequestParam(required = false) String sourceStopId, - @RequestParam(required = false, defaultValue = "-1.0") double sourceLatitude, - @RequestParam(required = false, defaultValue = "-1.0") double sourceLongitude, + @RequestParam(required = false, defaultValue = "-91.0") double sourceLatitude, + @RequestParam(required = false, defaultValue = "-181.0") double sourceLongitude, @RequestParam(required = false) String targetStopId, - @RequestParam(required = false, defaultValue = "-1.0") double targetLatitude, - @RequestParam(required = false, defaultValue = "-1.0") double targetLongitude, + @RequestParam(required = false, defaultValue = "-91.0") double targetLatitude, + @RequestParam(required = false, defaultValue = "-181.0") double targetLongitude, @RequestParam(required = false) LocalDateTime departureDateTime, @RequestParam(required = false, defaultValue = "2147483647") int maxWalkingDuration, @RequestParam(required = false, defaultValue = "2147483647") int maxTransferNumber, @RequestParam(required = false, defaultValue = "2147483647") int maxTravelTime, @RequestParam(required = false, defaultValue = "0") int minTransferTime) { + + GeoCoordinate sourceCoordinate = null; + GeoCoordinate targetCoordinate = null; + if (sourceStopId == null) { - if (sourceLatitude < 0 || sourceLongitude < 0) { + if (sourceLatitude == -91.0 || sourceLongitude == -181.0) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Either sourceStopId or sourceLatitude and sourceLongitude must be provided."); } + sourceCoordinate = validateCoordinate(sourceLatitude, sourceLongitude); } if (targetStopId == null) { - if (targetLatitude < 0 || targetLongitude < 0) { + if (targetLatitude == -91.0 || targetLongitude == -181.0) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Either targetStopId or targetLatitude and targetLongitude must be provided."); } + targetCoordinate = validateCoordinate(targetLatitude, targetLongitude); } if (departureDateTime == null) { @@ -68,9 +102,7 @@ public List getConnections(@RequestParam(required = false) String so Stop sourceStop = sourceStopId != null ? getStop(sourceStopId) : null; Stop targetStop = targetStopId != null ? getStop(targetStopId) : null; - GeoCoordinate sourceCoordinate = sourceStop == null ? new GeoCoordinate(sourceLatitude, sourceLongitude) : null; - GeoCoordinate targetCoordinate = targetStop == null ? new GeoCoordinate(targetLatitude, targetLongitude) : null; - + validateQueryParams(maxWalkingDuration, maxTransferNumber, maxTravelTime, minTransferTime); ConnectionQueryConfig config = new ConnectionQueryConfig(maxWalkingDuration, minTransferTime, maxTransferNumber, maxTravelTime); @@ -94,28 +126,35 @@ public List getConnections(@RequestParam(required = false) String so @GetMapping("/isolines") public List getIsolines(@RequestParam(required = false) String sourceStopId, - @RequestParam(required = false, defaultValue = "-1.0") double sourceLatitude, - @RequestParam(required = false, defaultValue = "-1.0") double sourceLongitude, + @RequestParam(required = false, defaultValue = "-91") double sourceLatitude, + @RequestParam(required = false, defaultValue = "-181") double sourceLongitude, @RequestParam(required = false) LocalDateTime departureDateTime, @RequestParam(required = false, defaultValue = "2147483647") int maxWalkingDuration, @RequestParam(required = false, defaultValue = "2147483647") int maxTransferNumber, @RequestParam(required = false, defaultValue = "2147483647") int maxTravelTime, @RequestParam(required = false, defaultValue = "0") int minTransferTime) { + + GeoCoordinate sourceCoordinate = null; if (sourceStopId == null) { - if (sourceLatitude < 0 || sourceLongitude < 0) { + if (sourceLatitude == -91.0 || sourceLongitude == -181.0) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Either sourceStopId or sourceLatitude and sourceLongitude must be provided."); } - throw new ResponseStatusException(HttpStatus.NOT_IMPLEMENTED, - "Location based routing is not implemented yet."); + sourceCoordinate = validateCoordinate(sourceLatitude, sourceLongitude); } - Stop sourceStop = getStop(sourceStopId); + Stop sourceStop = sourceStopId != null ? getStop(sourceStopId) : null; + + validateQueryParams(maxWalkingDuration, maxTransferNumber, maxTravelTime, minTransferTime); ConnectionQueryConfig config = new ConnectionQueryConfig(maxWalkingDuration, minTransferTime, maxTransferNumber, maxTravelTime); - Map connections = service.getIsolines(sourceStop, departureDateTime, - config); + Map connections; + if (sourceStop != null) { + connections = service.getIsolines(sourceStop, departureDateTime, config); + } else { + connections = service.getIsolines(sourceCoordinate, departureDateTime, config); + } List arrivals = new ArrayList<>(); diff --git a/src/main/java/ch/naviqore/app/controller/ScheduleController.java b/src/main/java/ch/naviqore/app/controller/ScheduleController.java index d9b012aa..db0ad37e 100644 --- a/src/main/java/ch/naviqore/app/controller/ScheduleController.java +++ b/src/main/java/ch/naviqore/app/controller/ScheduleController.java @@ -50,7 +50,14 @@ public List getNearestStops(@RequestParam double latitude, @Requ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Max distance can not be negative"); } - return service.getNearestStops(new GeoCoordinate(latitude, longitude), maxDistance, limit) + GeoCoordinate location; + try { + location = new GeoCoordinate(latitude, longitude); + } catch (IllegalArgumentException e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e); + } + + return service.getNearestStops(location, maxDistance, limit) .stream() .map(stop -> map(stop, latitude, longitude)) .toList(); diff --git a/src/main/java/ch/naviqore/example/Container.java b/src/main/java/ch/naviqore/example/Container.java deleted file mode 100644 index 8fdf70b9..00000000 --- a/src/main/java/ch/naviqore/example/Container.java +++ /dev/null @@ -1,15 +0,0 @@ -package ch.naviqore.example; - -import lombok.Getter; -import lombok.Setter; - -/** - * Container class to illustrate mocking - * - * @author munterfi - */ -@Getter -@Setter -public class Container { - private int value = 0; -} diff --git a/src/main/java/ch/naviqore/example/Dummy.java b/src/main/java/ch/naviqore/example/Dummy.java deleted file mode 100644 index bb95f750..00000000 --- a/src/main/java/ch/naviqore/example/Dummy.java +++ /dev/null @@ -1,20 +0,0 @@ -package ch.naviqore.example; - -import lombok.RequiredArgsConstructor; - -/** - * Dummy class - * - * @author munterfi - */ -@RequiredArgsConstructor -public class Dummy { - - private final Container container; - - public int add(int a) { - int newValue = container.getValue() + a; - container.setValue(newValue); - return newValue; - } -} diff --git a/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java new file mode 100644 index 00000000..2455071f --- /dev/null +++ b/src/test/java/ch/naviqore/app/controller/RoutingControllerTest.java @@ -0,0 +1,255 @@ +package ch.naviqore.app.controller; + +import ch.naviqore.app.dto.Connection; +import ch.naviqore.app.dto.EarliestArrival; +import ch.naviqore.service.PublicTransitService; +import ch.naviqore.service.Stop; +import ch.naviqore.service.exception.StopNotFoundException; +import ch.naviqore.utils.spatial.GeoCoordinate; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatusCode; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class RoutingControllerTest { + + @Mock + private PublicTransitService publicTransitService; + + @InjectMocks + private RoutingController routingController; + + @Test + void testGetConnections_WithValidSourceAndTargetStopIds() throws StopNotFoundException { + // Arrange + String sourceStopId = "sourceStopId"; + String targetStopId = "targetStopId"; + LocalDateTime departureDateTime = LocalDateTime.now(); + + Stop sourceStop = mock(Stop.class); + Stop targetStop = mock(Stop.class); + + when(publicTransitService.getStopById(sourceStopId)).thenReturn(sourceStop); + when(publicTransitService.getStopById(targetStopId)).thenReturn(targetStop); + when(publicTransitService.getConnections(eq(sourceStop), eq(targetStop), any(), any(), any())).thenReturn( + Collections.emptyList()); + + // Act + List connections = routingController.getConnections(sourceStopId, -1.0, -1.0, targetStopId, -1.0, + -1.0, departureDateTime, 30, 2, 120, 5); + + // Assert + assertNotNull(connections); + } + + @Test + void testGetConnections_WithoutSourceStopIdButWithCoordinates() throws StopNotFoundException { + // Arrange + double sourceLatitude = 46.2044; + double sourceLongitude = 6.1432; + String targetStopId = "targetStopId"; + LocalDateTime departureDateTime = LocalDateTime.now(); + + Stop targetStop = mock(Stop.class); + + when(publicTransitService.getStopById(targetStopId)).thenReturn(targetStop); + when(publicTransitService.getConnections(any(GeoCoordinate.class), eq(targetStop), any(), any(), + any())).thenReturn(Collections.emptyList()); + + // Act + List connections = routingController.getConnections(null, sourceLatitude, sourceLongitude, + targetStopId, -1.0, -1.0, departureDateTime, 30, 2, 120, 5); + + // Assert + assertNotNull(connections); + } + + @Test + void testGetConnections_InvalidStopId() throws StopNotFoundException { + // Arrange + String invalidStopId = "invalidStopId"; + String targetStopId = "targetStopId"; + + when(publicTransitService.getStopById(invalidStopId)).thenThrow(new StopNotFoundException(invalidStopId)); + + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(invalidStopId, -91.0, -181.0, targetStopId, -91.0, -181.0, + LocalDateTime.now(), 30, 2, 120, 5)); + assertEquals("Stop not found", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(404), exception.getStatusCode()); + } + + @Test + void testGetConnections_MissingSourceAndCoordinates() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, -91.0, -181.0, "targetStopId", -91.0, -181.0, + LocalDateTime.now(), 30, 2, 120, 5)); + assertEquals("Either sourceStopId or sourceLatitude and sourceLongitude must be provided.", + exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetConnections_MissingTargetAndCoordinates() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections("sourceStopId", -91.0, -181.0, null, -91.0, -181.0, + LocalDateTime.now(), 30, 2, 120, 5)); + assertEquals("Either targetStopId or targetLatitude and targetLongitude must be provided.", + exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetConnection_InvalidCoordinates() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, 91, 181, null, 32, 32, LocalDateTime.now(), 30, 2, 120, + 5)); + assertEquals("Coordinates must be valid, Latitude between -90 and 90 and Longitude between -180 and 180.", + exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetConnections_InvalidMaxTransferNumber() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, 0, 0, null, 0, 0, LocalDateTime.now(), 30, -2, 120, 5)); + assertEquals("Max transfer number must be greater than or equal to 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetConnections_InvalidMaxWalkingDuration() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, 0, 0, null, 0, 0, LocalDateTime.now(), -30, 2, 120, 5)); + assertEquals("Max walking duration must be greater than or equal to 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetConnections_InvalidMaxTravelTime() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, 0, 0, null, 0, 0, LocalDateTime.now(), 30, 2, -120, 5)); + assertEquals("Max travel time must be greater than 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetConnections_InvalidMinTransferTime() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getConnections(null, 0, 0, null, 0, 0, LocalDateTime.now(), 30, 2, 120, -5)); + assertEquals("Min transfer time must be greater than or equal to 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetIsoLines() throws StopNotFoundException { + // Arrange + String sourceStopId = "sourceStopId"; + LocalDateTime departureDateTime = LocalDateTime.now(); + + Stop sourceStop = mock(Stop.class); + + when(publicTransitService.getStopById(sourceStopId)).thenReturn(sourceStop); + when(publicTransitService.getIsolines(eq(sourceStop), eq(departureDateTime), any())).thenReturn( + Collections.emptyMap()); + + // Act + List connections = routingController.getIsolines(sourceStopId, -1.0, -1.0, departureDateTime, + 30, 2, 120, 5); + + // Assert + assertNotNull(connections); + } + + @Test + void testGetIsoLines_InvalidSourceStopId() throws StopNotFoundException { + // Arrange + String invalidStopId = "invalidStopId"; + when(publicTransitService.getStopById(invalidStopId)).thenThrow(new StopNotFoundException(invalidStopId)); + + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(invalidStopId, -91.0, -181.0, LocalDateTime.now(), 30, 2, 120, 5)); + assertEquals("Stop not found", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(404), exception.getStatusCode()); + } + + @Test + void testGetIsoLines_MissingSourceAndCoordinates() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(null, -91.0, -181.0, LocalDateTime.now(), 30, 2, 120, 5)); + assertEquals("Either sourceStopId or sourceLatitude and sourceLongitude must be provided.", + exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetIsoLines_InvalidCoordinates() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(null, 91, 181, LocalDateTime.now(), 30, 2, 120, 5)); + assertEquals("Coordinates must be valid, Latitude between -90 and 90 and Longitude between -180 and 180.", + exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetIsoLines_InvalidMaxTransferNumber() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(null, 0, 0, LocalDateTime.now(), 30, -2, 120, 5)); + assertEquals("Max transfer number must be greater than or equal to 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetIsoLines_InvalidMaxWalkingDuration() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(null, 0, 0, LocalDateTime.now(), -30, 2, 120, 5)); + assertEquals("Max walking duration must be greater than or equal to 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetIsoLines_InvalidMaxTravelTime() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(null, 0, 0, LocalDateTime.now(), 30, 2, -120, 5)); + assertEquals("Max travel time must be greater than 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetIsoLines_InvalidMinTransferTime() { + // Act & Assert + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> routingController.getIsolines(null, 0, 0, LocalDateTime.now(), 30, 2, 120, -5)); + assertEquals("Min transfer time must be greater than or equal to 0.", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + +} diff --git a/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java new file mode 100644 index 00000000..f5680ae2 --- /dev/null +++ b/src/test/java/ch/naviqore/app/controller/ScheduleControllerTest.java @@ -0,0 +1,223 @@ +package ch.naviqore.app.controller; + +import ch.naviqore.app.dto.Departure; +import ch.naviqore.app.dto.DistanceToStop; +import ch.naviqore.app.dto.SearchType; +import ch.naviqore.app.dto.Stop; +import ch.naviqore.service.ScheduleInformationService; +import ch.naviqore.service.exception.StopNotFoundException; +import ch.naviqore.utils.spatial.GeoCoordinate; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatusCode; +import org.springframework.web.server.ResponseStatusException; + +import java.time.LocalDateTime; +import java.util.List; + +import static ch.naviqore.app.dto.DtoMapper.map; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class ScheduleControllerTest { + + @Mock + private ScheduleInformationService scheduleInformationService; + + @InjectMocks + private ScheduleController scheduleController; + + @Test + void testGetAutoCompleteStops() { + String query = "query"; + when(scheduleInformationService.getStops(query, map(SearchType.STARTS_WITH))).thenReturn(List.of()); + List stops = scheduleController.getAutoCompleteStops(query, 10, SearchType.STARTS_WITH); + + assertNotNull(stops); + } + + @Test + void testGetAutoCompleteStops_withNegativeLimit() { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getAutoCompleteStops("query", -10, SearchType.STARTS_WITH)); + + assertEquals("Limit must be greater than 0", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetAutoCompleteStops_withZeroLimit() { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getAutoCompleteStops("query", 0, SearchType.STARTS_WITH)); + + assertEquals("Limit must be greater than 0", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetNearestStops() { + GeoCoordinate location = new GeoCoordinate(0, 0); + int radius = 1000; + int limit = 10; + + when(scheduleInformationService.getNearestStops(location, radius, limit)).thenReturn(List.of()); + + List stops = scheduleController.getNearestStops(location.latitude(), location.longitude(), + radius, limit); + + assertNotNull(stops); + } + + @Test + void testGetNearestStops_withNegativeLimit() { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getNearestStops(0, 0, 1000, -10)); + + assertEquals("Limit must be greater than 0", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetNearestStops_withZeroLimit() { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getNearestStops(0, 0, 1000, 0)); + + assertEquals("Limit must be greater than 0", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetNearestStops_withNegativeMaxDistance() { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getNearestStops(0, 0, -1000, 10)); + + assertEquals("Max distance can not be negative", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @ParameterizedTest(name = "Test case {index}: Latitude={0}, Longitude={1}") + @CsvSource({"91, 0", // Invalid latitude + "-91, 0", // Invalid latitude + "0, 181", // Invalid longitude + "0, -181", // Invalid longitude + "91, 181", // Invalid latitude and longitude + "-91, -181" // Invalid latitude and longitude + }) + void testGetNearestStops_withInvalidCoordinates(double latitude, double longitude) { + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getNearestStops(latitude, longitude, 1000, 10)); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetStop() throws StopNotFoundException { + String stopId = "stopId"; + ch.naviqore.service.Stop serviceStop = mock(ch.naviqore.service.Stop.class); + when(scheduleInformationService.getStopById(stopId)).thenReturn(serviceStop); + Stop stop = scheduleController.getStop(stopId); + assertNotNull(stop); + } + + @Test + void testGetStop_withStopNotFoundException() throws StopNotFoundException { + String stopId = "stopId"; + when(scheduleInformationService.getStopById(stopId)).thenThrow(StopNotFoundException.class); + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getStop(stopId)); + assertEquals(HttpStatusCode.valueOf(404), exception.getStatusCode()); + } + + @Test + void testGetDepartures() throws StopNotFoundException { + String stopId = "stopId"; + ch.naviqore.service.Stop serviceStop = mock(ch.naviqore.service.Stop.class); + when(scheduleInformationService.getStopById(stopId)).thenReturn(serviceStop); + List stopTimes = List.of(); + when(scheduleInformationService.getNextDepartures(eq(serviceStop), any(LocalDateTime.class), eq(null), + eq(10))).thenReturn(stopTimes); + List stopTimeDtos = scheduleController.getDepartures(stopId, null, 10, null); + assertNotNull(stopTimeDtos); + } + + @Test + void testGetDepartures_withStopNotFoundException() throws StopNotFoundException { + String stopId = "stopId"; + when(scheduleInformationService.getStopById(stopId)).thenThrow(StopNotFoundException.class); + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getDepartures(stopId, null, 10, null)); + assertEquals(HttpStatusCode.valueOf(404), exception.getStatusCode()); + } + + @Test + void testGetDepartures_withUntilDateTimeBeforeDepartureDateTime() { + String stopId = "stopId"; + LocalDateTime departureTime = LocalDateTime.now(); + LocalDateTime untilTime = departureTime.minusMinutes(1); + + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getDepartures(stopId, departureTime, 10, untilTime)); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + + @Test + void testGetDepartures_withNullDepartureDateTime() throws StopNotFoundException { + String stopId = "stopId"; + int limit = 10; + LocalDateTime untilTime = LocalDateTime.now().plusMinutes(1); + ch.naviqore.service.Stop serviceStop = mock(ch.naviqore.service.Stop.class); + when(scheduleInformationService.getStopById(stopId)).thenReturn(serviceStop); + List stopTimes = List.of(); + when(scheduleInformationService.getNextDepartures(eq(serviceStop), any(), eq(untilTime), eq(limit))).thenReturn( + stopTimes); + List stopTimeDtos = scheduleController.getDepartures(stopId, null, limit, untilTime); + assertNotNull(stopTimeDtos); + } + + @Test + void testGetDepartures_withDepartureDateTime() throws StopNotFoundException { + String stopId = "stopId"; + int limit = 10; + LocalDateTime departureTime = LocalDateTime.now().plusDays(2); + LocalDateTime untilTime = departureTime.plusMinutes(1); + ch.naviqore.service.Stop serviceStop = mock(ch.naviqore.service.Stop.class); + when(scheduleInformationService.getStopById(stopId)).thenReturn(serviceStop); + List stopTimes = List.of(); + when(scheduleInformationService.getNextDepartures(eq(serviceStop), eq(departureTime), eq(untilTime), + eq(limit))).thenReturn(stopTimes); + List stopTimeDtos = scheduleController.getDepartures(stopId, departureTime, limit, untilTime); + assertNotNull(stopTimeDtos); + } + + @Test + void testGetDepartures_withNullUntilDateTime() throws StopNotFoundException { + String stopId = "stopId"; + int limit = 10; + LocalDateTime departureTime = LocalDateTime.now().plusDays(2); + ch.naviqore.service.Stop serviceStop = mock(ch.naviqore.service.Stop.class); + when(scheduleInformationService.getStopById(stopId)).thenReturn(serviceStop); + List stopTimes = List.of(); + when(scheduleInformationService.getNextDepartures(eq(serviceStop), eq(departureTime), any(), + eq(limit))).thenReturn(stopTimes); + List stopTimeDtos = scheduleController.getDepartures(stopId, departureTime, limit, null); + assertNotNull(stopTimeDtos); + } + + @Test + void testGetDepartures_withInvalidLimit() { + int limit = 0; + ResponseStatusException exception = assertThrows(ResponseStatusException.class, + () -> scheduleController.getDepartures("stopId", null, limit, null)); + assertEquals("Limit must be greater than 0", exception.getReason()); + assertEquals(HttpStatusCode.valueOf(400), exception.getStatusCode()); + } + +} diff --git a/src/test/java/ch/naviqore/app/service/ServiceConfigParserIT.java b/src/test/java/ch/naviqore/app/service/ServiceConfigParserIT.java new file mode 100644 index 00000000..fb9d9a66 --- /dev/null +++ b/src/test/java/ch/naviqore/app/service/ServiceConfigParserIT.java @@ -0,0 +1,71 @@ +package ch.naviqore.app.service; + +import ch.naviqore.service.config.ServiceConfig; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ServiceConfigParserIT { + + private static final String GTFS_URL = "src/test/resources/ch/naviqore/gtfs/schedule/sample-feed-1.zip"; + private static final int MINIMUM_TRANSFER_TIME = 200; + private static final int SAME_STATION_TRANSFER_TIME = 200; + private static final int MAXIMUM_WALKING_DISTANCE = 600; + private static final int WALKING_SPEED = 4000; + private static final String WALKING_CALCULATOR_TYPE = "BEE_LINE_DISTANCE"; + + static Stream provideTestCombinations() { + return Stream.of(Arguments.of(-1, SAME_STATION_TRANSFER_TIME, MAXIMUM_WALKING_DISTANCE, WALKING_SPEED, + WALKING_CALCULATOR_TYPE, "Minimum Transfer Time cannot be smaller zero."), + Arguments.of(MINIMUM_TRANSFER_TIME, -1, MAXIMUM_WALKING_DISTANCE, WALKING_SPEED, + WALKING_CALCULATOR_TYPE, "Same Station Transfer Time cannot be smaller zero."), + Arguments.of(MINIMUM_TRANSFER_TIME, SAME_STATION_TRANSFER_TIME, -1, WALKING_SPEED, + WALKING_CALCULATOR_TYPE, "Maximum Walking Distance cannot be smaller zero."), + Arguments.of(MINIMUM_TRANSFER_TIME, SAME_STATION_TRANSFER_TIME, MAXIMUM_WALKING_DISTANCE, -1, + WALKING_CALCULATOR_TYPE, "Walking speed cannot be smaller zero."), + Arguments.of(MINIMUM_TRANSFER_TIME, SAME_STATION_TRANSFER_TIME, MAXIMUM_WALKING_DISTANCE, 0, + WALKING_CALCULATOR_TYPE, "Walking speed cannot be zero."), + Arguments.of(MINIMUM_TRANSFER_TIME, SAME_STATION_TRANSFER_TIME, MAXIMUM_WALKING_DISTANCE, WALKING_SPEED, + "INVALID", "Can't process invalid Walking Calculator Type.")); + } + + @Test + void testServiceConfigParser_withValidInputs() { + ServiceConfigParser parser = new ServiceConfigParser(GTFS_URL, MINIMUM_TRANSFER_TIME, + SAME_STATION_TRANSFER_TIME, MAXIMUM_WALKING_DISTANCE, WALKING_SPEED, WALKING_CALCULATOR_TYPE); + + // check that the service config has been loaded correctly + ServiceConfig config = parser.getServiceConfig(); + assertEquals(GTFS_URL, config.getGtfsUrl()); + assertEquals(MINIMUM_TRANSFER_TIME, config.getMinimumTransferTime()); + assertEquals(MAXIMUM_WALKING_DISTANCE, config.getMaxWalkingDistance()); + assertEquals(WALKING_SPEED, config.getWalkingSpeed()); + assertEquals(ServiceConfig.WalkCalculatorType.BEE_LINE_DISTANCE, config.getWalkCalculatorType()); + } + + @Test + void testServiceConfigParser_withInvalidWalkCalculatorType() { + // check that the service config has been loaded correctly + assertThrows(IllegalArgumentException.class, + () -> new ServiceConfigParser(GTFS_URL, MINIMUM_TRANSFER_TIME, SAME_STATION_TRANSFER_TIME, + MAXIMUM_WALKING_DISTANCE, WALKING_SPEED, "INVALID")); + } + + @ParameterizedTest(name = "{5}") + @MethodSource("provideTestCombinations") + void testServiceConfigParser_withInvalidInputs(int minimumTransferTime, int sameStationTransferTime, + int maxWalkingDistance, int walkingSpeed, + String walkingCalculatorType, String message) { + // check that the service config has been loaded correctly + assertThrows(IllegalArgumentException.class, + () -> new ServiceConfigParser(GTFS_URL, minimumTransferTime, sameStationTransferTime, + maxWalkingDistance, walkingSpeed, walkingCalculatorType), message); + } + +} diff --git a/src/test/java/ch/naviqore/example/DummyIT.java b/src/test/java/ch/naviqore/example/DummyIT.java deleted file mode 100644 index 21cf1535..00000000 --- a/src/test/java/ch/naviqore/example/DummyIT.java +++ /dev/null @@ -1,31 +0,0 @@ -package ch.naviqore.example; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Dummy integration test - * - * @author munterfi - */ -class DummyIT { - - private Container container; - private Dummy dummy; - - @BeforeEach - void setUp() { - container = new Container(); - dummy = new Dummy(container); - } - - @Test - void add() { - int initial = container.getValue(); - int result = dummy.add(10); - - assertThat(result).isEqualTo(initial + 10); - } -} \ No newline at end of file diff --git a/src/test/java/ch/naviqore/example/DummyTest.java b/src/test/java/ch/naviqore/example/DummyTest.java deleted file mode 100644 index 4d9ef7d0..00000000 --- a/src/test/java/ch/naviqore/example/DummyTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package ch.naviqore.example; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; - -/** - * Dummy unit test - * - * @author munterfi - */ -@ExtendWith(MockitoExtension.class) -class DummyTest { - - @Mock - private Container container; - - @InjectMocks - private Dummy dummy; - - @Test - void add() { - // mock getter of container - when(container.getValue()).thenReturn(10); - - // act - int result = dummy.add(5); - - // verify container.setValue(15) is called - verify(container, times(1)).getValue(); - verify(container, times(1)).setValue(15); - assertThat(result).isEqualTo(15); - } -} \ No newline at end of file