From 9eb43f29520b35c2dc62bc1e24245e485cf52655 Mon Sep 17 00:00:00 2001 From: dd Date: Mon, 18 May 2020 11:45:17 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - path 요청 POST방식에서 GET방식으로 수정 - 시간 관련 데이터 TimeEntity로 통합 - 가독성을 위해 스트림 사이 공백 추가 - 불필요한 생성자 파라미터 삭제 - PathType, GraphResponse˜ 클래스 패키지 이동 - GraphTest 추가 - Algorithm 확장성을 위한 수정 - Algorithm 테스트 추가 --- .../admin/controller/LineController.java | 6 +- .../admin/controller/PathController.java | 13 ++-- .../subway/admin/domain/CreateTime.java | 22 ------ .../wooteco/subway/admin/domain/Graph.java | 51 +++---------- .../wooteco/subway/admin/domain/Line.java | 6 +- .../subway/admin/domain/LineStation.java | 2 +- .../subway/admin/domain/LineStationEdge.java | 10 ++- .../subway/admin/domain/PathAlgorithm.java | 6 ++ .../admin/domain/PathAlgorithmByDijkstra.java | 50 +++++++++++++ .../PathResult.java} | 6 +- .../admin/{dto => domain}/PathType.java | 11 ++- .../wooteco/subway/admin/domain/Station.java | 2 +- .../subway/admin/domain/TimeEntity.java | 39 ++++++++++ .../subway/admin/domain/UpdateTime.java | 27 ------- .../subway/admin/service/PathService.java | 22 +++--- src/main/resources/schema.sql | 1 + .../static/service/js/views/Search.js | 16 ++--- .../admin/acceptance/AcceptanceTest.java | 19 ++--- .../subway/admin/domain/GraphTest.java | 72 +++++++++++++++++++ .../domain/PathAlgorithmByDijkstraTest.java | 62 ++++++++++++++++ .../subway/admin/service/PathServiceTest.java | 8 ++- 21 files changed, 294 insertions(+), 157 deletions(-) delete mode 100644 src/main/java/wooteco/subway/admin/domain/CreateTime.java create mode 100644 src/main/java/wooteco/subway/admin/domain/PathAlgorithm.java create mode 100644 src/main/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstra.java rename src/main/java/wooteco/subway/admin/{dto/GraphResponse.java => domain/PathResult.java} (76%) rename src/main/java/wooteco/subway/admin/{dto => domain}/PathType.java (91%) create mode 100644 src/main/java/wooteco/subway/admin/domain/TimeEntity.java delete mode 100644 src/main/java/wooteco/subway/admin/domain/UpdateTime.java create mode 100644 src/test/java/wooteco/subway/admin/domain/GraphTest.java create mode 100644 src/test/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstraTest.java diff --git a/src/main/java/wooteco/subway/admin/controller/LineController.java b/src/main/java/wooteco/subway/admin/controller/LineController.java index 7bc9132a4..4ace36d3f 100644 --- a/src/main/java/wooteco/subway/admin/controller/LineController.java +++ b/src/main/java/wooteco/subway/admin/controller/LineController.java @@ -33,7 +33,7 @@ public LineController(LineService lineService) { } @PostMapping - public ResponseEntity createLine(@Valid @RequestBody LineRequest request) { + public ResponseEntity create(@Valid @RequestBody LineRequest request) { LineResponse lineResponse = lineService.save(request.toLine()); return ResponseEntity @@ -52,14 +52,14 @@ public ResponseEntity retrieveLine(@PathVariable Long id) { } @PutMapping("/{id}") - public ResponseEntity updateLine(@PathVariable Long id, + public ResponseEntity update(@PathVariable Long id, @RequestBody LineRequest request) { lineService.updateLine(id, request); return ResponseEntity.ok().build(); } @DeleteMapping("/{id}") - public ResponseEntity deleteLine(@PathVariable Long id) { + public ResponseEntity delete(@PathVariable Long id) { lineService.deleteLineById(id); return ResponseEntity.noContent().build(); } diff --git a/src/main/java/wooteco/subway/admin/controller/PathController.java b/src/main/java/wooteco/subway/admin/controller/PathController.java index ade14478f..b2f36f87e 100644 --- a/src/main/java/wooteco/subway/admin/controller/PathController.java +++ b/src/main/java/wooteco/subway/admin/controller/PathController.java @@ -1,11 +1,9 @@ package wooteco.subway.admin.controller; -import javax.validation.Valid; - import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import wooteco.subway.admin.dto.PathRequest; @@ -22,9 +20,10 @@ public PathController(PathService pathService) { this.pathService = pathService; } - @PostMapping - ResponseEntity findPath(@Valid @RequestBody PathRequest pathRequest) { - PathResponse response = pathService.findPath(pathRequest); + @GetMapping + ResponseEntity findPath(@RequestParam String sourceName, + @RequestParam String targetName, @RequestParam String type) { + PathResponse response = pathService.findPath(new PathRequest(sourceName, targetName, type)); return ResponseEntity.ok(response); } diff --git a/src/main/java/wooteco/subway/admin/domain/CreateTime.java b/src/main/java/wooteco/subway/admin/domain/CreateTime.java deleted file mode 100644 index e5818b906..000000000 --- a/src/main/java/wooteco/subway/admin/domain/CreateTime.java +++ /dev/null @@ -1,22 +0,0 @@ -package wooteco.subway.admin.domain; - -import java.time.LocalDateTime; - -import org.springframework.data.annotation.CreatedDate; - -public abstract class CreateTime { - - @CreatedDate - private LocalDateTime createdAt; - - public CreateTime() { - } - - public CreateTime(LocalDateTime createdAt) { - this.createdAt = createdAt; - } - - public LocalDateTime getCreatedAt() { - return createdAt; - } -} diff --git a/src/main/java/wooteco/subway/admin/domain/Graph.java b/src/main/java/wooteco/subway/admin/domain/Graph.java index 742fd8b81..05800a211 100644 --- a/src/main/java/wooteco/subway/admin/domain/Graph.java +++ b/src/main/java/wooteco/subway/admin/domain/Graph.java @@ -3,24 +3,22 @@ import java.util.List; import java.util.Objects; -import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.graph.WeightedMultigraph; -import wooteco.subway.admin.dto.GraphResponse; -import wooteco.subway.admin.dto.PathType; -import wooteco.subway.admin.exception.IllegalStationNameException; import wooteco.subway.admin.exception.NotFoundLineException; -import wooteco.subway.admin.exception.NotFoundPathException; public class Graph { private final WeightedMultigraph graph; - private Graph( - WeightedMultigraph graph) { + private Graph(WeightedMultigraph graph) { this.graph = graph; } + public static Graph of(WeightedMultigraph graph) { + return new Graph(graph); + } + public static Graph of(List lines, PathType pathType) { return new Graph(mapLinesToGraph(lines, pathType)); } @@ -30,11 +28,12 @@ private static WeightedMultigraph mapLinesToGraph(List
  • graph - = new WeightedMultigraph(LineStationEdge.class); + WeightedMultigraph graph = new WeightedMultigraph<>( + LineStationEdge.class); lines.stream() .flatMap(it -> it.getLineStationsId().stream()) .forEach(graph::addVertex); + lines.stream() .flatMap(it -> it.getStations().stream()) .filter(it -> Objects.nonNull(it.getPreStationId())) @@ -44,37 +43,7 @@ private static WeightedMultigraph mapLinesToGraph(List
  • dijkstraShortestPath = new DijkstraShortestPath<>( - graph); - - if (Objects.isNull(dijkstraShortestPath.getPath(sourceId, targetId))) { - throw new NotFoundPathException(sourceId, targetId); - } - - return mapToGraphResponse(sourceId, targetId, dijkstraShortestPath); - } - - private void validate(Long sourceId, Long targetId) { - if (Objects.equals(sourceId, targetId)) { - throw new IllegalStationNameException(sourceId, targetId); - } - } - - private GraphResponse mapToGraphResponse(Long source, Long target, - DijkstraShortestPath dijkstraShortestPath) { - List path = dijkstraShortestPath.getPath(source, target).getVertexList(); - int totalDistance = dijkstraShortestPath.getPath(source, target) - .getEdgeList() - .stream() - .mapToInt(LineStationEdge::getDistance) - .sum(); - int totalDuration = dijkstraShortestPath.getPath(source, target) - .getEdgeList() - .stream() - .mapToInt(LineStationEdge::getDuration) - .sum(); - return new GraphResponse(path, totalDistance, totalDuration); + public WeightedMultigraph getGraph() { + return graph; } } \ No newline at end of file diff --git a/src/main/java/wooteco/subway/admin/domain/Line.java b/src/main/java/wooteco/subway/admin/domain/Line.java index 20faa1584..fa22b220b 100644 --- a/src/main/java/wooteco/subway/admin/domain/Line.java +++ b/src/main/java/wooteco/subway/admin/domain/Line.java @@ -1,6 +1,5 @@ package wooteco.subway.admin.domain; -import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; import java.util.HashSet; @@ -11,7 +10,7 @@ import org.springframework.data.annotation.Id; -public class Line extends UpdateTime { +public class Line extends TimeEntity { @Id private Long id; @@ -26,8 +25,7 @@ public Line() { } public Line(Long id, String name, String backgroundColor, LocalTime startTime, - LocalTime endTime, int intervalTime, LocalDateTime createdAt, LocalDateTime updatedAt, - Set stations) { + LocalTime endTime, int intervalTime, Set stations) { this(name, backgroundColor, startTime, endTime, intervalTime); this.id = id; this.stations = stations; diff --git a/src/main/java/wooteco/subway/admin/domain/LineStation.java b/src/main/java/wooteco/subway/admin/domain/LineStation.java index 7f51f6254..3b960ee51 100644 --- a/src/main/java/wooteco/subway/admin/domain/LineStation.java +++ b/src/main/java/wooteco/subway/admin/domain/LineStation.java @@ -1,6 +1,6 @@ package wooteco.subway.admin.domain; -public class LineStation { +public class LineStation extends TimeEntity { private Long preStationId; private final Long stationId; private final int distance; diff --git a/src/main/java/wooteco/subway/admin/domain/LineStationEdge.java b/src/main/java/wooteco/subway/admin/domain/LineStationEdge.java index ed576e657..2ea4ed6e8 100644 --- a/src/main/java/wooteco/subway/admin/domain/LineStationEdge.java +++ b/src/main/java/wooteco/subway/admin/domain/LineStationEdge.java @@ -2,8 +2,6 @@ import org.jgrapht.graph.DefaultWeightedEdge; -import wooteco.subway.admin.dto.PathType; - public class LineStationEdge extends DefaultWeightedEdge { private final LineStation lineStation; @@ -26,4 +24,12 @@ public int getDistance() { public int getDuration() { return lineStation.getDuration(); } + + public LineStation getLineStation() { + return lineStation; + } + + public PathType getPathType() { + return pathType; + } } diff --git a/src/main/java/wooteco/subway/admin/domain/PathAlgorithm.java b/src/main/java/wooteco/subway/admin/domain/PathAlgorithm.java new file mode 100644 index 000000000..3b17563e1 --- /dev/null +++ b/src/main/java/wooteco/subway/admin/domain/PathAlgorithm.java @@ -0,0 +1,6 @@ +package wooteco.subway.admin.domain; + +public interface PathAlgorithm { + + PathResult findPath(Long sourceId, Long targetId, Graph graph); +} diff --git a/src/main/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstra.java b/src/main/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstra.java new file mode 100644 index 000000000..773139505 --- /dev/null +++ b/src/main/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstra.java @@ -0,0 +1,50 @@ +package wooteco.subway.admin.domain; + +import java.util.List; +import java.util.Objects; + +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.springframework.stereotype.Component; + +import wooteco.subway.admin.exception.IllegalStationNameException; +import wooteco.subway.admin.exception.NotFoundPathException; + +@Component +public class PathAlgorithmByDijkstra implements PathAlgorithm { + + public PathResult findPath(Long sourceId, Long targetId, Graph graph) { + DijkstraShortestPath dijkstraShortestPath = + new DijkstraShortestPath<>(graph.getGraph()); + validate(sourceId, targetId); + + if (Objects.isNull(dijkstraShortestPath.getPath(sourceId, targetId))) { + throw new NotFoundPathException(sourceId, targetId); + } + + return mapToPahtResponse(sourceId, targetId, dijkstraShortestPath); + } + + private void validate(Long sourceId, Long targetId) { + if (Objects.equals(sourceId, targetId)) { + throw new IllegalStationNameException(sourceId, targetId); + } + } + + private PathResult mapToPahtResponse(Long source, Long target, + DijkstraShortestPath dijkstraShortestPath) { + List path = dijkstraShortestPath.getPath(source, target).getVertexList(); + + int totalDistance = dijkstraShortestPath.getPath(source, target) + .getEdgeList() + .stream() + .mapToInt(LineStationEdge::getDistance) + .sum(); + + int totalDuration = dijkstraShortestPath.getPath(source, target) + .getEdgeList() + .stream() + .mapToInt(LineStationEdge::getDuration) + .sum(); + return new PathResult(path, totalDistance, totalDuration); + } +} diff --git a/src/main/java/wooteco/subway/admin/dto/GraphResponse.java b/src/main/java/wooteco/subway/admin/domain/PathResult.java similarity index 76% rename from src/main/java/wooteco/subway/admin/dto/GraphResponse.java rename to src/main/java/wooteco/subway/admin/domain/PathResult.java index 289d2edb7..4718a46ca 100644 --- a/src/main/java/wooteco/subway/admin/dto/GraphResponse.java +++ b/src/main/java/wooteco/subway/admin/domain/PathResult.java @@ -1,13 +1,13 @@ -package wooteco.subway.admin.dto; +package wooteco.subway.admin.domain; import java.util.List; -public class GraphResponse { +public class PathResult { private final List path; private final int totalDistance; private final int totalDuration; - public GraphResponse(List path, int totalDistance, int totalDuration) { + public PathResult(List path, int totalDistance, int totalDuration) { this.path = path; this.totalDistance = totalDistance; this.totalDuration = totalDuration; diff --git a/src/main/java/wooteco/subway/admin/dto/PathType.java b/src/main/java/wooteco/subway/admin/domain/PathType.java similarity index 91% rename from src/main/java/wooteco/subway/admin/dto/PathType.java rename to src/main/java/wooteco/subway/admin/domain/PathType.java index afbd78ade..4e7673d77 100644 --- a/src/main/java/wooteco/subway/admin/dto/PathType.java +++ b/src/main/java/wooteco/subway/admin/domain/PathType.java @@ -1,9 +1,8 @@ -package wooteco.subway.admin.dto; +package wooteco.subway.admin.domain; import java.util.Objects; import java.util.function.Function; -import wooteco.subway.admin.domain.LineStation; import wooteco.subway.admin.exception.IllegalTypeNameException; public enum PathType { @@ -16,10 +15,6 @@ public enum PathType { this.function = function; } - public int getWeight(LineStation lineStation) { - return function.apply(lineStation); - } - public static PathType of(String typeName) { String upperCaseName = typeName.toUpperCase(); if (!Objects.equals(upperCaseName, DURATION.name()) && !Objects.equals(upperCaseName, @@ -28,4 +23,8 @@ public static PathType of(String typeName) { } return valueOf(upperCaseName); } + + public int getWeight(LineStation lineStation) { + return function.apply(lineStation); + } } diff --git a/src/main/java/wooteco/subway/admin/domain/Station.java b/src/main/java/wooteco/subway/admin/domain/Station.java index 5b6c602cc..d65da44a7 100644 --- a/src/main/java/wooteco/subway/admin/domain/Station.java +++ b/src/main/java/wooteco/subway/admin/domain/Station.java @@ -2,7 +2,7 @@ import org.springframework.data.annotation.Id; -public class Station extends CreateTime { +public class Station extends TimeEntity { @Id private Long id; diff --git a/src/main/java/wooteco/subway/admin/domain/TimeEntity.java b/src/main/java/wooteco/subway/admin/domain/TimeEntity.java new file mode 100644 index 000000000..76d151c43 --- /dev/null +++ b/src/main/java/wooteco/subway/admin/domain/TimeEntity.java @@ -0,0 +1,39 @@ +package wooteco.subway.admin.domain; + +import java.time.LocalDateTime; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; + +public abstract class TimeEntity { + + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; + + public TimeEntity() { + } + + public TimeEntity(LocalDateTime createdAt, LocalDateTime updatedAt) { + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public void create(LocalDateTime createdAt) { + this.createdAt = createdAt; + } + + public void update(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } +} diff --git a/src/main/java/wooteco/subway/admin/domain/UpdateTime.java b/src/main/java/wooteco/subway/admin/domain/UpdateTime.java deleted file mode 100644 index 152bf2899..000000000 --- a/src/main/java/wooteco/subway/admin/domain/UpdateTime.java +++ /dev/null @@ -1,27 +0,0 @@ -package wooteco.subway.admin.domain; - -import java.time.LocalDateTime; - -import org.springframework.data.annotation.LastModifiedDate; - -public abstract class UpdateTime extends CreateTime { - - @LastModifiedDate - private LocalDateTime updatedAt; - - public UpdateTime() { - } - - public UpdateTime(LocalDateTime updatedAt) { - this.updatedAt = updatedAt; - } - - public UpdateTime(LocalDateTime createdAt, LocalDateTime updatedAt) { - super(createdAt); - this.updatedAt = updatedAt; - } - - public LocalDateTime getUpdatedAt() { - return updatedAt; - } -} diff --git a/src/main/java/wooteco/subway/admin/service/PathService.java b/src/main/java/wooteco/subway/admin/service/PathService.java index 115569a87..384ff9da8 100644 --- a/src/main/java/wooteco/subway/admin/service/PathService.java +++ b/src/main/java/wooteco/subway/admin/service/PathService.java @@ -8,10 +8,11 @@ import wooteco.subway.admin.domain.Graph; import wooteco.subway.admin.domain.Line; -import wooteco.subway.admin.dto.GraphResponse; +import wooteco.subway.admin.domain.PathAlgorithm; +import wooteco.subway.admin.domain.PathResult; +import wooteco.subway.admin.domain.PathType; import wooteco.subway.admin.dto.PathRequest; import wooteco.subway.admin.dto.PathResponse; -import wooteco.subway.admin.dto.PathType; import wooteco.subway.admin.dto.StationResponse; import wooteco.subway.admin.exception.NotFoundStationException; @@ -21,27 +22,27 @@ public class PathService { private final StationService stationService; private final LineService lineService; + private final PathAlgorithm pathAlgorithm; - public PathService(StationService stationService, LineService lineService) { + public PathService(StationService stationService, + LineService lineService, PathAlgorithm pathAlgorithm) { this.stationService = stationService; this.lineService = lineService; + this.pathAlgorithm = pathAlgorithm; } public PathResponse findPath(PathRequest request) { Long sourceId = stationService.findIdByName(request.getSourceName()); Long targetId = stationService.findIdByName(request.getTargetName()); List lines = lineService.findAll(); - Graph graph = Graph.of(lines, PathType.of(request.getType())); - GraphResponse graphResponse = graph.findPath(sourceId, targetId); - - List path = graphResponse.getPath(); + PathResult pathResult = pathAlgorithm.findPath(sourceId, targetId, graph); + List path = pathResult.getPath(); List stationResponses = StationResponse.listOf( stationService.findAllById(path)); - int totalDistance = graphResponse.getTotalDistance(); - int totalDuration = graphResponse.getTotalDuration(); - + int totalDistance = pathResult.getTotalDistance(); + int totalDuration = pathResult.getTotalDuration(); List sortedStationResponses = sort(path, stationResponses); return new PathResponse(sortedStationResponses, totalDistance, totalDuration); @@ -49,7 +50,6 @@ public PathResponse findPath(PathRequest request) { private List sort(List path, List stationResponses) { List result = new ArrayList<>(); - for (Long stationId : path) { StationResponse response = stationResponses.stream() .filter(stationResponse -> stationResponse.getId().equals(stationId)) diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index be056ea9b..cdc1973ba 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -3,6 +3,7 @@ create table if not exists STATION id bigint auto_increment not null, name varchar(255) unique not null, created_at datetime, + updated_at datetime, primary key (id) ); diff --git a/src/main/resources/static/service/js/views/Search.js b/src/main/resources/static/service/js/views/Search.js index 4a425e205..512670ea5 100644 --- a/src/main/resources/static/service/js/views/Search.js +++ b/src/main/resources/static/service/js/views/Search.js @@ -68,18 +68,10 @@ function Search() { } event.preventDefault() - const searchInput = { - sourceName: $departureStationName.value, - targetName: $arrivalStationName.value, - type: $type - } - fetch('/path', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(searchInput) - }).then(response => { + fetch("/path?sourceName=" + $departureStationName.value + "&targetName=" + $arrivalStationName.value + "&type=" + $type, + { + method: 'GET', + }).then(response => { if (!response.ok) { throw response; } diff --git a/src/test/java/wooteco/subway/admin/acceptance/AcceptanceTest.java b/src/test/java/wooteco/subway/admin/acceptance/AcceptanceTest.java index e6ed9ed8c..fefe8b09a 100644 --- a/src/test/java/wooteco/subway/admin/acceptance/AcceptanceTest.java +++ b/src/test/java/wooteco/subway/admin/acceptance/AcceptanceTest.java @@ -198,18 +198,14 @@ void removeLineStation(Long lineId, Long stationId) { } PathResponse findPath(String source, String target, String type) { - Map params = new HashMap<>(); - params.put("sourceName", source); - params.put("targetName", target); - params.put("type", type); - + String encodingUrl = + "/path?sourceName=" + source + "&targetName=" + target + "&type=" + type; return given(). - body(params). contentType(MediaType.APPLICATION_JSON_VALUE). accept(MediaType.APPLICATION_JSON_VALUE). when(). - post("/path"). + get(encodingUrl). then(). log().all(). statusCode(HttpStatus.OK.value()). @@ -217,18 +213,11 @@ PathResponse findPath(String source, String target, String type) { } ErrorResponse findPathByWrongType(String source, String target, String type) { - Map params = new HashMap<>(); - params.put("sourceName", source); - params.put("targetName", target); - params.put("type", type); - return given(). - body(params). - contentType(MediaType.APPLICATION_JSON_VALUE). accept(MediaType.APPLICATION_JSON_VALUE). when(). - post("/path"). + get("/path?sourceName=" + source + "&targetName=" + target + "&type=" + type). then(). log().all(). statusCode(HttpStatus.BAD_REQUEST.value()). diff --git a/src/test/java/wooteco/subway/admin/domain/GraphTest.java b/src/test/java/wooteco/subway/admin/domain/GraphTest.java new file mode 100644 index 000000000..2ad8980ff --- /dev/null +++ b/src/test/java/wooteco/subway/admin/domain/GraphTest.java @@ -0,0 +1,72 @@ +package wooteco.subway.admin.domain; + +import static org.assertj.core.api.Assertions.*; + +import java.time.LocalTime; +import java.util.Arrays; + +import org.jgrapht.graph.WeightedMultigraph; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.jdbc.Sql; + +@Sql("/truncate.sql") +class GraphTest { + + private Line line1; + private Line line2; + + private WeightedMultigraph graphByDistance; + private WeightedMultigraph graphByDuration; + + @BeforeEach + void setUp() { + line1 = new Line(1L, "2호선", "bg-green-400", LocalTime.of(5, 30), LocalTime.of(22, 30), 5); + line1.addLineStation(new LineStation(null, 1L, 5, 10)); + line1.addLineStation(new LineStation(1L, 2L, 5, 10)); + line1.addLineStation(new LineStation(2L, 3L, 5, 10)); + + line2 = new Line(2L, "분당선", "bg-yellow-500", LocalTime.of(5, 30), LocalTime.of(22, 30), 5); + line2.addLineStation(new LineStation(null, 4L, 10, 5)); + line2.addLineStation(new LineStation(4L, 2L, 10, 5)); + line2.addLineStation(new LineStation(2L, 5L, 10, 5)); + + graphByDistance = Graph.of(Arrays.asList(line1, line2), PathType.DISTANCE).getGraph(); + graphByDuration = Graph.of(Arrays.asList(line1, line2), PathType.DURATION).getGraph(); + } + + @Test + @DisplayName("그래프에 vertex가 존재한다") + void vertex() { + assertThat(graphByDistance.vertexSet()).containsExactly(1L, 2L, 3L, 4L, 5L); + assertThat(graphByDuration.vertexSet()).containsExactly(1L, 2L, 3L, 4L, 5L); + } + + @Test + @DisplayName("그래프에 Edge가 존재한다") + void edge() { + assertThat(graphByDistance.containsEdge(1L, 2L)).isTrue(); + assertThat(graphByDistance.containsEdge(2L, 3L)).isTrue(); + assertThat(graphByDistance.containsEdge(4L, 2L)).isTrue(); + assertThat(graphByDistance.containsEdge(2L, 5L)).isTrue(); + + assertThat(graphByDuration.containsEdge(1L, 2L)).isTrue(); + assertThat(graphByDuration.containsEdge(2L, 3L)).isTrue(); + assertThat(graphByDuration.containsEdge(4L, 2L)).isTrue(); + assertThat(graphByDuration.containsEdge(2L, 5L)).isTrue(); + } + + @Test + void weight() { + assertThat(graphByDistance.getEdge(1L, 2L).getWeight()).isEqualTo(5); + assertThat(graphByDistance.getEdge(2L, 3L).getWeight()).isEqualTo(5); + assertThat(graphByDistance.getEdge(4L, 2L).getWeight()).isEqualTo(10); + assertThat(graphByDistance.getEdge(2L, 5L).getWeight()).isEqualTo(10); + + assertThat(graphByDuration.getEdge(1L, 2L).getWeight()).isEqualTo(10); + assertThat(graphByDuration.getEdge(2L, 3L).getWeight()).isEqualTo(10); + assertThat(graphByDuration.getEdge(4L, 2L).getWeight()).isEqualTo(5); + assertThat(graphByDuration.getEdge(2L, 5L).getWeight()).isEqualTo(5); + } +} \ No newline at end of file diff --git a/src/test/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstraTest.java b/src/test/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstraTest.java new file mode 100644 index 000000000..f920f6577 --- /dev/null +++ b/src/test/java/wooteco/subway/admin/domain/PathAlgorithmByDijkstraTest.java @@ -0,0 +1,62 @@ +package wooteco.subway.admin.domain; + +import static org.assertj.core.api.Assertions.*; + +import java.time.LocalTime; +import java.util.Arrays; + +import org.jgrapht.graph.WeightedMultigraph; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.jdbc.Sql; + +@Sql("/truncate.sql") +class PathAlgorithmByDijkstraTest { + + private Line line1; + private Line line2; + + private WeightedMultigraph graphByDistance; + private WeightedMultigraph graphByDuration; + + private PathAlgorithm pathAlgorithm; + + @BeforeEach + void setUp() { + line1 = new Line(1L, "2호선", "bg-green-400", LocalTime.of(5, 30), LocalTime.of(22, 30), 5); + line1.addLineStation(new LineStation(null, 1L, 0, 0)); + line1.addLineStation(new LineStation(1L, 2L, 5, 10)); + line1.addLineStation(new LineStation(2L, 3L, 5, 10)); + line1.addLineStation(new LineStation(3L, 6L, 5, 10)); + + line2 = new Line(2L, "분당선", "bg-yellow-500", LocalTime.of(5, 30), LocalTime.of(22, 30), 5); + line2.addLineStation(new LineStation(null, 1L, 0, 0)); + line2.addLineStation(new LineStation(1L, 4L, 10, 5)); + line2.addLineStation(new LineStation(4L, 5L, 10, 5)); + line2.addLineStation(new LineStation(5L, 6L, 10, 5)); + + graphByDistance = Graph.of(Arrays.asList(line1, line2), PathType.DISTANCE).getGraph(); + graphByDuration = Graph.of(Arrays.asList(line1, line2), PathType.DURATION).getGraph(); + + pathAlgorithm = new PathAlgorithmByDijkstra(); + } + + @Test + @DisplayName("최단 거리 경로를 구한다") + void getShortestPathByDistance() { + PathResult path = pathAlgorithm.findPath(1L, 6L, Graph.of(graphByDistance)); + assertThat(path.getPath()).containsExactly(1L, 2L, 3L, 6L); + assertThat(path.getTotalDistance()).isEqualTo(15); + assertThat(path.getTotalDuration()).isEqualTo(30); + } + + @Test + @DisplayName("최소 시간 경로를 구한다") + void getShortestPathByDuration() { + PathResult path = pathAlgorithm.findPath(1L, 6L, Graph.of(graphByDuration)); + assertThat(path.getPath()).containsExactly(1L, 4L, 5L, 6L); + assertThat(path.getTotalDistance()).isEqualTo(30); + assertThat(path.getTotalDuration()).isEqualTo(15); + } +} \ No newline at end of file diff --git a/src/test/java/wooteco/subway/admin/service/PathServiceTest.java b/src/test/java/wooteco/subway/admin/service/PathServiceTest.java index b992cde71..bddab2a26 100644 --- a/src/test/java/wooteco/subway/admin/service/PathServiceTest.java +++ b/src/test/java/wooteco/subway/admin/service/PathServiceTest.java @@ -15,10 +15,12 @@ import wooteco.subway.admin.domain.Line; import wooteco.subway.admin.domain.LineStation; +import wooteco.subway.admin.domain.PathAlgorithm; +import wooteco.subway.admin.domain.PathAlgorithmByDijkstra; +import wooteco.subway.admin.domain.PathType; import wooteco.subway.admin.domain.Station; import wooteco.subway.admin.dto.PathRequest; import wooteco.subway.admin.dto.PathResponse; -import wooteco.subway.admin.dto.PathType; import wooteco.subway.admin.dto.StationResponse; import wooteco.subway.admin.exception.IllegalStationNameException; import wooteco.subway.admin.exception.NotFoundLineException; @@ -43,6 +45,8 @@ class PathServiceTest { @Mock private LineService lineService; + private PathAlgorithm pathAlgorithm = new PathAlgorithmByDijkstra(); + private PathService pathService; private Line line1; @@ -64,7 +68,7 @@ class PathServiceTest { @BeforeEach void setUp() { - pathService = new PathService(stationService, lineService); + pathService = new PathService(stationService, lineService, pathAlgorithm); station1 = new Station(1L, STATION_NAME1); station2 = new Station(2L, STATION_NAME2);