diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..2e3a3bb51 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,140 @@ +# 지하철 노선도 경로 조회 미션 +- 등록된 지하철 노선도에서 경로를 조회하는 기능을 구현한다. + +
+ +## 🚀 기능 요구사항 + +> 프리코스 3주차 미션에서 사용한 코드를 참고해도 무관하다. + +### 초기 설정 +- 프로그램 시작 시 역, 노선, 구간 정보를 초기 설정 해야 한다. +- 거리와 소요 시간은 양의 정수이며 단위는 km와 분을 의미한다. +- 아래의 사전 등록 정보로 반드시 초기 설정을 한다. + +``` + 1. 지하철역으로 교대역, 강남역, 역삼역, 남부터미널역, 양재역, 양재시민의숲역, 매봉역이 등록되어 있다. + 2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다. + 3. 노선에 역이 아래와 같이 등록되어 있다.(왼쪽 끝이 상행 종점) + - 2호선: 교대역 - ( 2km / 3분 ) - 강남역 - ( 2km / 3분 ) - 역삼역 + - 3호선: 교대역 - ( 3km / 2분 ) - 남부터미널역 - ( 6km / 5분 ) - 양재역 - ( 1km / 1분 ) - 매봉역 + - 신분당선: 강남역 - ( 2km / 8분 ) - 양재역 - ( 10km / 3분 ) - 양재시민의숲역 + ``` + +## Livenow 프로그램 구현 +## 🚩 객체 책임 (아는 것과 하는 것) +### **지하철 역** +- 아는 것 + - 역 이름 + +
+ +- 하는 것 + + +### **지하철 역 저장소** +- 아는 것 + - 지하철 역 + +
+ +- 하는 것 + - 지하철 역 저장 + +### **거리** +- 아는 것 + - 거리(km) + +
+ +- 하는 것 + +### **시간** +- 아는 것 + - 분 + +
+ +- 하는 것 + +### **거리(분)** +- 아는 것 + - 거리(분) + +
+ +- 하는 것 + +### **노선** +- 아는 것 + - 노선 이름 + - 지하철 역(들) + +
+ +- 하는 것 + +### **라인(들)** +- 아는 것 + - 라인 + +
+ +- 하는 것 +### **라인 저장소** +- 아는 것 + - 라인 + +
+ +- 하는 것 + - 라인저장 + + +## 🚩 구현할 기능 +### **메인 화면** +- [x] 객체 모델링 +- [x] 메인화면 출력 +- [x] 보장된 값 입력 + - 보장된 값(1,Q 만을 허용) + - 보장된 값이 아닐 시 에러 출력 + - `SelectionException` +- [x] Q가 입력될 시, 종료 ( 소문자 q 도 허용 함. ) + +### **경로 조회** +- [x] 경로 조회 화면 출력 +- [x] 보장된 값 입력 + - 보장된 값(1,2,B 만을 허용) + - 보장된 값이 아닐 시 에러 출력 + - `SelectionException` +- [x] 지하철 역 저장 +- [x] 노선 저장 +- [x] 구간 저장 +- [x] 초기 저장 (시간(분) 미포함) +- [x] 초기 저장(구간마다 거리, 시간 포함) +- [x] 1을 입력시 최단 거리 조회 + - [x] 출발역을 입력 + - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다. + - `StationException` + - [x] 도착역 역을 입력 + - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다. + - `StationException` + - [x] 출발역과 도착역이 같으면 에러를 출력한다 + - `StationException` + - [x] 최단 거리를 조회한다. + +- [x] 2를 입력시 최소 시간 조회 + - [x] 출발역을 입력 + - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다. + - `에러 발생` + - [x] 도착역 역을 입력 + - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다. + - `에러 발생` + - [x] 출발역과 도착역이 같으면 에러를 출력한다 + - `에러 발생` + - [x] 최소 시간를 조회한다. + +- [ ] 최단 거리 최소시간 같이 출력 + +### **에러가 발생해도 서비스가 죽지 않아야 한다** +- [x] 에러 핸들링 diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..489a0d3ae 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,21 @@ package subway; +import subway.domain.section.SectionRepository; +import subway.domain.section.SectionService; +import subway.domain.station.StationService; +import subway.view.InputView; +import subway.view.OutputView; + import java.util.Scanner; public class Application { public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); // TODO: 프로그램 구현 + DataInitService dataInitService = new DataInitService(new StationService(), new SectionService(new SectionRepository())); + dataInitService.init(); + + SubwayManageApp subwayManageApp = new SubwayManageApp(new InputView(scanner), new OutputView(new StringBuilder())); + subwayManageApp.startApp(); } } diff --git a/src/main/java/subway/DataInitService.java b/src/main/java/subway/DataInitService.java new file mode 100644 index 000000000..fbc44d6ff --- /dev/null +++ b/src/main/java/subway/DataInitService.java @@ -0,0 +1,120 @@ +package subway; + +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.WeightedMultigraph; +import subway.domain.distanceTime.Distance; +import subway.domain.distanceTime.Time; +import subway.domain.section.SectionService; +import subway.domain.section.dto.SectionSaveReqDto; +import subway.domain.section.dto.SectionStationAddReqDto; +import subway.domain.station.StationService; +import subway.domain.station.dto.StationSaveReqDto; + +public class DataInitService { + private static final String STATION_GYODAE = "교대역"; + private static final String STATION_GANGNAM = "강남역"; + private static final String STATION_YEOKSAM = "역삼역"; + private static final String STATION_SOUTH_TERMINAL = "남부터미널역"; + private static final String STATION_YANGJAE = "양재역"; + private static final String STATION_CITIZEN_FOREST = "양재시민의숲역"; + private static final String STATION_MAEBONG = "매봉역"; + private static final String LINE_TWO = "2호선"; + private static final String LINE_THREE = "3호선"; + private static final String LINE_SINBUNDANG = "신분당선"; + + private static final int SECOND = 2; + private static final int THIRD = 3; + + private static final int KM_ONE = 1; + private static final int KM_TWO = 2; + private static final int KM_THREE = 3; + private static final int KM_SIX = 6; + private static final int KM_TEN = 10; + + private static final int MINUTE_ONE = 1; + private static final int MINUTE_TWO = 2; + private static final int MINUTE_THREE = 3; + private static final int MINUTE_FIVE = 5; + private static final int MINUTE_EIGHT = 8; + + private final StationService stationService; + private final SectionService sectionService; + + public DataInitService(StationService stationService, SectionService sectionService) { + this.stationService = stationService; + this.sectionService = sectionService; + } + + public void init() { + saveStation(); + saveSection(); + saveDistance(); + saveTime(); + } + + private void saveDistance() { + WeightedMultigraph graph = getStringDefaultWeightedEdgeWeightedMultigraph(); + + graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_GANGNAM), new Distance(KM_TWO).getKm()); + graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YEOKSAM), new Distance(KM_TWO).getKm()); + + graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_SOUTH_TERMINAL), new Distance(KM_THREE).getKm()); + graph.setEdgeWeight(graph.addEdge(STATION_SOUTH_TERMINAL, STATION_YANGJAE), new Distance(KM_SIX).getKm()); + graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_MAEBONG), new Distance(KM_ONE).getKm()); + + graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YANGJAE), new Distance(KM_TWO).getKm()); + graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_CITIZEN_FOREST), new Distance(KM_TEN).getKm()); + + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph); + SearchService.addDijkstraShortestPath(dijkstraShortestPath); + } + + private void saveTime() { + WeightedMultigraph graph = getStringDefaultWeightedEdgeWeightedMultigraph(); + + graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_GANGNAM), new Time(MINUTE_THREE).getMinute()); + graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YEOKSAM), new Time(MINUTE_THREE).getMinute()); + + graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_SOUTH_TERMINAL), new Time(MINUTE_TWO).getMinute()); + graph.setEdgeWeight(graph.addEdge(STATION_SOUTH_TERMINAL, STATION_YANGJAE), new Time(MINUTE_FIVE).getMinute()); + graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_MAEBONG), new Time(MINUTE_ONE).getMinute()); + + graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YANGJAE), new Time(MINUTE_EIGHT).getMinute()); + graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_CITIZEN_FOREST), new Time(MINUTE_THREE).getMinute()); + + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph); + SearchService.addDijkstraShortestPath(dijkstraShortestPath); + } + + private WeightedMultigraph getStringDefaultWeightedEdgeWeightedMultigraph() { + WeightedMultigraph graph = new WeightedMultigraph(DefaultWeightedEdge.class); + graph.addVertex(STATION_GYODAE); + graph.addVertex(STATION_GANGNAM); + graph.addVertex(STATION_YEOKSAM); + graph.addVertex(STATION_SOUTH_TERMINAL); + graph.addVertex(STATION_YANGJAE); + graph.addVertex(STATION_MAEBONG); + graph.addVertex(STATION_CITIZEN_FOREST); + return graph; + } + + private void saveSection() { + sectionService.saveSection(new SectionSaveReqDto(LINE_TWO, STATION_GYODAE, STATION_YEOKSAM)); + sectionService.addStation(new SectionStationAddReqDto(LINE_TWO, STATION_GANGNAM, SECOND)); + + sectionService.saveSection(new SectionSaveReqDto(LINE_THREE, STATION_GYODAE, STATION_MAEBONG)); + sectionService.addStation(new SectionStationAddReqDto(LINE_THREE, STATION_SOUTH_TERMINAL, SECOND)); + sectionService.addStation(new SectionStationAddReqDto(LINE_THREE, STATION_YANGJAE, THIRD)); + + sectionService.saveSection(new SectionSaveReqDto(LINE_SINBUNDANG, STATION_GANGNAM, STATION_CITIZEN_FOREST)); + sectionService.addStation(new SectionStationAddReqDto(LINE_SINBUNDANG, STATION_YANGJAE, SECOND)); + } + + private void saveStation() { + String[] stationNames = {STATION_GYODAE, STATION_GANGNAM, STATION_YEOKSAM, STATION_SOUTH_TERMINAL, STATION_YANGJAE, STATION_CITIZEN_FOREST, STATION_MAEBONG}; + for (String stationName : stationNames) { + stationService.saveStation(new StationSaveReqDto(stationName)); + } + } +} diff --git a/src/main/java/subway/SearchService.java b/src/main/java/subway/SearchService.java new file mode 100644 index 000000000..a7891d206 --- /dev/null +++ b/src/main/java/subway/SearchService.java @@ -0,0 +1,79 @@ +package subway; + +import org.jgrapht.GraphPath; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import subway.domain.station.Station; +import subway.domain.station.StationRepository; +import subway.exception.ErrorCode; +import subway.exception.StationException; +import subway.view.InputView; +import subway.view.screen.SearchView; + +import java.util.ArrayList; +import java.util.List; + +public class SearchService { + private static final List dijkstraShortestPaths = new ArrayList<>(); + private static final int DISTANCE_INDEX = 0; + private static final int TIME_INDEX = 1; + + private final InputView inputView; + private final SearchView searchView; + + public SearchService(InputView inputView, SearchView searchView) { + this.inputView = inputView; + this.searchView = searchView; + } + + public static void addDijkstraShortestPath(DijkstraShortestPath dijkstraShortestPath) { + dijkstraShortestPaths.add(dijkstraShortestPath); + } + + public void findShortestDistance() { + searchView.printAdd(); + String firstStationName = inputView.inputNextLine(); + Station firstStation = StationRepository.findByName(firstStationName); + + searchView.printSecondAdd(); + String secondStationName = inputView.inputNextLine(); + Station secondStation = StationRepository.findByName(secondStationName); + checkSameName(firstStationName, secondStationName); + + searchView.printAfterAdd(); + printDistance(firstStation, secondStation); + } + + public void findShortestTime() { + searchView.printAdd(); + String firstStationName = inputView.inputNextLine(); + Station firstStation = StationRepository.findByName(firstStationName); + + searchView.printSecondAdd(); + String secondStationName = inputView.inputNextLine(); + Station secondStation = StationRepository.findByName(secondStationName); + checkSameName(firstStationName, secondStationName); + + searchView.printAfterAdd(); + printTime(firstStation, secondStation); + } + + private void printTime(Station firstStation, Station secondStation) { + DijkstraShortestPath dijkstraShortestPathDistance = dijkstraShortestPaths.get(TIME_INDEX); + double pathWeight = dijkstraShortestPathDistance.getPathWeight(firstStation.getName(), secondStation.getName()); + GraphPath path = dijkstraShortestPathDistance.getPath(firstStation.getName(), secondStation.getName()); + searchView.printTimeList(path, pathWeight); + } + + private void printDistance(Station firstStation, Station secondStation) { + DijkstraShortestPath dijkstraShortestPathDistance = dijkstraShortestPaths.get(DISTANCE_INDEX); + double pathWeight = dijkstraShortestPathDistance.getPathWeight(firstStation.getName(), secondStation.getName()); + GraphPath path = dijkstraShortestPathDistance.getPath(firstStation.getName(), secondStation.getName()); + searchView.printDistanceList(path, pathWeight); + } + + private void checkSameName(String firstStationName, String secondStationName) { + if (firstStationName.equals(secondStationName)) { + throw new StationException(ErrorCode.STATION_SAME_NAME); + } + } +} diff --git a/src/main/java/subway/SubwayManageApp.java b/src/main/java/subway/SubwayManageApp.java new file mode 100644 index 000000000..7f951dcf7 --- /dev/null +++ b/src/main/java/subway/SubwayManageApp.java @@ -0,0 +1,71 @@ +package subway; + +import subway.view.InputView; +import subway.view.Prefix; +import subway.view.screen.SearchView; +import subway.view.selection.MainSelection; +import subway.view.OutputView; +import subway.view.selection.SearchSelection; +import subway.view.screen.MainView; + +public class SubwayManageApp { + private final InputView inputView; + private final OutputView outputView; + + public SubwayManageApp(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void startApp() { + MainView mainView = new MainView(outputView); + while (true) { + mainView.showOptions(); + MainSelection mainSelection; + try { + mainSelection = new MainSelection(inputView.inputNextLine()); + chooseOption(mainSelection); + } catch (Exception exception) { + System.out.println(Prefix.ENTER.getPrefix() + Prefix.ERROR.getPrefix() + exception.getMessage()); + continue; + } + if (mainSelection.isQuit()) { + break; + } + } + } + + private void chooseOption(MainSelection mainSelection) { + if (mainSelection.isOptionOne()) { + manageSearch(); + } + } + + private void manageSearch() { + SearchView searchView = new SearchView(outputView); + while (true) { + try { + searchView.showOptions(); + SearchSelection searchSelection = new SearchSelection(inputView.inputNextLine()); + chooseSearchOption(searchSelection); + break; + } catch (Exception exception) { + System.out.println(Prefix.ENTER.getPrefix() + Prefix.ERROR.getPrefix() + exception.getMessage()); + continue; + } + } + } + + private void chooseSearchOption(SearchSelection searchSelection) { + SearchService searchService = new SearchService(inputView, new SearchView(outputView)); + if (searchSelection.isOptionOne()) { + searchService.findShortestDistance(); + } + if (searchSelection.isOptionTwo()) { + searchService.findShortestTime(); + } + if (searchSelection.isBack()) { + return; + } + } +} diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/Station.java deleted file mode 100644 index bdb142590..000000000 --- a/src/main/java/subway/domain/Station.java +++ /dev/null @@ -1,15 +0,0 @@ -package subway.domain; - -public class Station { - private String name; - - public Station(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - // 추가 기능 구현 -} diff --git a/src/main/java/subway/domain/distanceTime/Distance.java b/src/main/java/subway/domain/distanceTime/Distance.java new file mode 100644 index 000000000..a92033ab6 --- /dev/null +++ b/src/main/java/subway/domain/distanceTime/Distance.java @@ -0,0 +1,23 @@ +package subway.domain.distanceTime; + +import subway.exception.DistanceTimeException; +import subway.exception.ErrorCode; + +public class Distance { + private int km; + + public Distance(int km) { + this.km = km; + validate(km); + } + + private void validate(int km) { + if (km < 1) { + throw new DistanceTimeException(ErrorCode.INPUT_VALUE_MUST_NATURAL); + } + } + + public int getKm() { + return km; + } +} diff --git a/src/main/java/subway/domain/distanceTime/Time.java b/src/main/java/subway/domain/distanceTime/Time.java new file mode 100644 index 000000000..d45a381be --- /dev/null +++ b/src/main/java/subway/domain/distanceTime/Time.java @@ -0,0 +1,23 @@ +package subway.domain.distanceTime; + +import subway.exception.DistanceTimeException; +import subway.exception.ErrorCode; + +public class Time { + private int minute; + + public Time(int minute) { + this.minute = minute; + validate(minute); + } + + private void validate(int minute) { + if (minute < 1) { + throw new DistanceTimeException(ErrorCode.INPUT_VALUE_MUST_NATURAL); + } + } + + public int getMinute() { + return minute; + } +} diff --git a/src/main/java/subway/domain/line/Line.java b/src/main/java/subway/domain/line/Line.java new file mode 100644 index 000000000..0280b0d50 --- /dev/null +++ b/src/main/java/subway/domain/line/Line.java @@ -0,0 +1,34 @@ +package subway.domain.line; + +import subway.exception.ErrorCode; +import subway.exception.LineException; + +public class Line { + private static final int MIN_SIZE = 2; + private static final String MUST_CONTAIN_LAST = "선"; + private static final String PERMIT_CHARACTER = "^[가-힣|0-9]*$"; + + private String name; + + public Line(String name) { + this.name = name; + validateName(name); + } + + public String getName() { + return name; + } + + // 추가 기능 구현 + private void validateName(String name) { + if (name.length() < MIN_SIZE) { + throw new LineException(ErrorCode.LINE_NAME_LENGTH_ERROR); + } + if (!name.endsWith(MUST_CONTAIN_LAST)) { + throw new LineException(ErrorCode.LINE_INVALID_LAST_NAME); + } + if (!name.matches(PERMIT_CHARACTER)) { + throw new LineException(ErrorCode.LINE_INVALID_CHARACTER); + } + } +} diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/line/LineRepository.java similarity index 59% rename from src/main/java/subway/domain/LineRepository.java rename to src/main/java/subway/domain/line/LineRepository.java index 2c4a723c9..2c98c6fe5 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/line/LineRepository.java @@ -1,4 +1,7 @@ -package subway.domain; +package subway.domain.line; + +import subway.exception.ErrorCode; +import subway.exception.LineException; import java.util.ArrayList; import java.util.Collections; @@ -23,4 +26,12 @@ public static boolean deleteLineByName(String name) { public static void deleteAll() { lines.clear(); } + + public static Line findByName(String lineName) { + Line findLine = lines.stream() + .filter(line -> line.getName().equals(lineName)) + .findAny() + .orElseThrow(() -> new LineException(ErrorCode.LINE_NOT_FOUND)); + return findLine; + } } diff --git a/src/main/java/subway/domain/line/LineService.java b/src/main/java/subway/domain/line/LineService.java new file mode 100644 index 000000000..a025029c9 --- /dev/null +++ b/src/main/java/subway/domain/line/LineService.java @@ -0,0 +1,21 @@ +package subway.domain.line; + +import subway.domain.line.dto.LineSaveReqDto; +import subway.exception.ErrorCode; +import subway.exception.LineException; + +public class LineService { + public LineService() { + } + + public Line saveLine(LineSaveReqDto saveReqDto) { + try { + LineRepository.findByName(saveReqDto.getName()); + } catch (LineException lineException) { + Line line = new Line(saveReqDto.getName()); + LineRepository.addLine(line); + return line; + } + throw new LineException(ErrorCode.LINE_ALREADY_EXIST); + } +} diff --git a/src/main/java/subway/domain/line/Lines.java b/src/main/java/subway/domain/line/Lines.java new file mode 100644 index 000000000..fbeecad44 --- /dev/null +++ b/src/main/java/subway/domain/line/Lines.java @@ -0,0 +1,12 @@ +package subway.domain.line; + +import java.util.ArrayList; +import java.util.List; + +public class Lines { + private final List lines; + + public Lines(List lines) { + this.lines = new ArrayList<>(lines); + } +} diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/line/dto/LineSaveReqDto.java similarity index 53% rename from src/main/java/subway/domain/Line.java rename to src/main/java/subway/domain/line/dto/LineSaveReqDto.java index f4d738d5a..45067758f 100644 --- a/src/main/java/subway/domain/Line.java +++ b/src/main/java/subway/domain/line/dto/LineSaveReqDto.java @@ -1,15 +1,13 @@ -package subway.domain; +package subway.domain.line.dto; -public class Line { +public class LineSaveReqDto { private String name; - public Line(String name) { + public LineSaveReqDto(String name) { this.name = name; } public String getName() { return name; } - - // 추가 기능 구현 } diff --git a/src/main/java/subway/domain/section/Section.java b/src/main/java/subway/domain/section/Section.java new file mode 100644 index 000000000..e937c22e8 --- /dev/null +++ b/src/main/java/subway/domain/section/Section.java @@ -0,0 +1,40 @@ +package subway.domain.section; + +import subway.domain.line.Line; +import subway.domain.station.Station; +import subway.domain.station.Stations; + +import java.util.List; +import java.util.stream.Collectors; + +public class Section { + private final Line line; + private final Stations stations; + + private Section(Line line, Stations stations) { + this.line = line; + this.stations = stations; + } + + public static Section of(Line line, Stations stations) { + return new Section(line, stations); + } + + public void addStation(Station station, int sequence) { + stations.addStation(station, sequence); + } + + public String getLineName() { + return line.getName(); + } + + public int getStationsLength() { + return stations.size(); + } + + public List getStationsName() { + return stations.getStations().stream() + .map(Station::getName) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/subway/domain/section/SectionRepository.java b/src/main/java/subway/domain/section/SectionRepository.java new file mode 100644 index 000000000..306611950 --- /dev/null +++ b/src/main/java/subway/domain/section/SectionRepository.java @@ -0,0 +1,37 @@ +package subway.domain.section; + +import subway.exception.ErrorCode; +import subway.exception.SectionException; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public class SectionRepository { + private static final Map sections = new ConcurrentHashMap<>(); + + public SectionRepository() { + } + + public Section addSection(Section section) { + if (findByName(section.getLineName()) != null) { + throw new SectionException(ErrorCode.LINE_ALREADY_EXIST); + } + sections.put(section.getLineName(), section); + return section; + } + + public Section findByName(String lineName) { + Section section = sections.get(lineName); + return section; + } + + public List
sections() { + return sections.values().stream().collect(Collectors.toList()); + } + + public void removeAll() { + sections.clear(); + } +} diff --git a/src/main/java/subway/domain/section/SectionService.java b/src/main/java/subway/domain/section/SectionService.java new file mode 100644 index 000000000..09ce59425 --- /dev/null +++ b/src/main/java/subway/domain/section/SectionService.java @@ -0,0 +1,95 @@ +package subway.domain.section; + +import subway.domain.line.Line; +import subway.domain.line.LineRepository; +import subway.domain.section.dto.SectionSaveReqDto; +import subway.domain.section.dto.SectionStationAddReqDto; +import subway.domain.station.Station; +import subway.domain.station.StationRepository; +import subway.domain.station.Stations; +import subway.exception.ErrorCode; +import subway.exception.LineException; +import subway.exception.SectionException; +import subway.exception.StationException; + +import java.util.Arrays; + +public class SectionService { + public static final int CONVERT_SEQUENCE = 1; + + private final SectionRepository sectionRepository; + + public SectionService(SectionRepository sectionRepository) { + this.sectionRepository = sectionRepository; + } + + public Section saveSection(SectionSaveReqDto saveReqDto) { + Line line = new Line(saveReqDto.getLineName()); + checkAlreadyExist(line.getName()); + + Station upwardStation = new Station(saveReqDto.getUpwardStationName()); + checkUpwardNotFound(upwardStation.getName()); + + Station downwardStation = new Station(saveReqDto.getDownwardStationName()); + checkDownwardNotFound(downwardStation.getName()); + checkSameName(upwardStation.getName(), downwardStation.getName()); + + LineRepository.addLine(line); + Section section = Section.of(line, new Stations(Arrays.asList(upwardStation, downwardStation))); + return sectionRepository.addSection(section); + } + + public void addStation(SectionStationAddReqDto sectionStationAddReqDto) { + Section section = findByName(sectionStationAddReqDto.getLineName()); + Station station = StationRepository.findByName(sectionStationAddReqDto.getStationName()); + int sequence = sectionStationAddReqDto.getSequence(); + if (sequence > section.getStationsLength()) { + sequence = section.getStationsLength() + CONVERT_SEQUENCE; + } + section.addStation(station, sequence - CONVERT_SEQUENCE); + } + + public Section findByName(String lineName) { + Section findSection = sectionRepository.findByName(lineName); + if (findSection == null) { + throw new SectionException(ErrorCode.SECTION_NOT_FOUND); + } + return findSection; + } + + private void checkSameName(String upwardStationName, String downwardStationName) { + if (upwardStationName.equals(downwardStationName)) { + throw new SectionException(ErrorCode.SECTION_SAME_STATION_NAME); + } + } + + public void checkUpwardNotFound(String stationName) { + try { + StationRepository.findByName(stationName); + } catch (StationException stationException) { + throw new SectionException(ErrorCode.SECTION_NOT_FOUND); + } + } + + public void checkDownwardNotFound(String stationName) { + try { + StationRepository.findByName(stationName); + } catch (StationException stationException) { + throw new SectionException(ErrorCode.SECTION_NOT_FOUND); + } + } + + private void checkAlreadyExist(String name) { + try { + LineRepository.findByName(name); + } catch (LineException lineException) { + return; + } + throw new SectionException(ErrorCode.LINE_ALREADY_EXIST); + } + + public void removeAll() { + sectionRepository.removeAll(); + LineRepository.deleteAll(); + } +} diff --git a/src/main/java/subway/domain/section/dto/SectionFindResDto.java b/src/main/java/subway/domain/section/dto/SectionFindResDto.java new file mode 100644 index 000000000..3e4ccd7a4 --- /dev/null +++ b/src/main/java/subway/domain/section/dto/SectionFindResDto.java @@ -0,0 +1,13 @@ +package subway.domain.section.dto; + +public class SectionFindResDto { + private String lineName; + + public SectionFindResDto(String lineName) { + this.lineName = lineName; + } + + public String getLineName() { + return lineName; + } +} diff --git a/src/main/java/subway/domain/section/dto/SectionSaveReqDto.java b/src/main/java/subway/domain/section/dto/SectionSaveReqDto.java new file mode 100644 index 000000000..1757c6200 --- /dev/null +++ b/src/main/java/subway/domain/section/dto/SectionSaveReqDto.java @@ -0,0 +1,25 @@ +package subway.domain.section.dto; + +public class SectionSaveReqDto { + private String lineName; + private String upwardStationName; + private String downwardStationName; + + public SectionSaveReqDto(String lineName, String upwardStationName, String downwardStationName) { + this.lineName = lineName; + this.upwardStationName = upwardStationName; + this.downwardStationName = downwardStationName; + } + + public String getLineName() { + return lineName; + } + + public String getUpwardStationName() { + return upwardStationName; + } + + public String getDownwardStationName() { + return downwardStationName; + } +} diff --git a/src/main/java/subway/domain/section/dto/SectionStationAddReqDto.java b/src/main/java/subway/domain/section/dto/SectionStationAddReqDto.java new file mode 100644 index 000000000..40f57f95a --- /dev/null +++ b/src/main/java/subway/domain/section/dto/SectionStationAddReqDto.java @@ -0,0 +1,25 @@ +package subway.domain.section.dto; + +public class SectionStationAddReqDto { + private String lineName; + private String stationName; + private int sequence; + + public SectionStationAddReqDto(String lineName, String stationName, int sequence) { + this.lineName = lineName; + this.stationName = stationName; + this.sequence = sequence; + } + + public String getLineName() { + return lineName; + } + + public String getStationName() { + return stationName; + } + + public int getSequence() { + return sequence; + } +} diff --git a/src/main/java/subway/domain/section/dto/SectionStationDeleteReqDto.java b/src/main/java/subway/domain/section/dto/SectionStationDeleteReqDto.java new file mode 100644 index 000000000..0196777b0 --- /dev/null +++ b/src/main/java/subway/domain/section/dto/SectionStationDeleteReqDto.java @@ -0,0 +1,19 @@ +package subway.domain.section.dto; + +public class SectionStationDeleteReqDto { + private String lineName; + private String stationName; + + public SectionStationDeleteReqDto(String lineName, String stationName) { + this.lineName = lineName; + this.stationName = stationName; + } + + public String getLineName() { + return lineName; + } + + public String getStationName() { + return stationName; + } +} diff --git a/src/main/java/subway/domain/station/Station.java b/src/main/java/subway/domain/station/Station.java new file mode 100644 index 000000000..5a73e2c33 --- /dev/null +++ b/src/main/java/subway/domain/station/Station.java @@ -0,0 +1,34 @@ +package subway.domain.station; + +import subway.exception.ErrorCode; +import subway.exception.StationException; + +public class Station { + private static final int MIN_SIZE = 2; + private static final String MUST_CONTAIN_LAST = "역"; + private static final String PERMIT_CHARACTER = "^[가-힣|0-9]*$"; + + private String name; + + public Station(String name) { + this.name = name; + validateName(name); + } + + public String getName() { + return name; + } + + // 추가 기능 구현 + private void validateName(String name) { + if (name.length() < MIN_SIZE) { + throw new StationException(ErrorCode.STATION_NAME_LENGTH_ERROR); + } + if (!name.endsWith(MUST_CONTAIN_LAST)) { + throw new StationException(ErrorCode.STATION_INVALID_LAST_NAME); + } + if (!name.matches(PERMIT_CHARACTER)) { + throw new StationException(ErrorCode.STATION_INVALID_CHARACTER); + } + } +} diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/station/StationRepository.java similarity index 58% rename from src/main/java/subway/domain/StationRepository.java rename to src/main/java/subway/domain/station/StationRepository.java index 8ed9d103f..5cb972afe 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/station/StationRepository.java @@ -1,4 +1,7 @@ -package subway.domain; +package subway.domain.station; + +import subway.exception.ErrorCode; +import subway.exception.StationException; import java.util.ArrayList; import java.util.Collections; @@ -23,4 +26,12 @@ public static boolean deleteStation(String name) { public static void deleteAll() { stations.clear(); } + + public static Station findByName(String stationName) { + Station findStation = stations.stream() + .filter(station -> station.getName().equals(stationName)) + .findAny() + .orElseThrow(() -> new StationException(ErrorCode.STATION_NOT_FOUND)); + return findStation; + } } diff --git a/src/main/java/subway/domain/station/StationService.java b/src/main/java/subway/domain/station/StationService.java new file mode 100644 index 000000000..da24eee69 --- /dev/null +++ b/src/main/java/subway/domain/station/StationService.java @@ -0,0 +1,25 @@ +package subway.domain.station; + +import subway.domain.station.dto.StationSaveReqDto; +import subway.exception.ErrorCode; +import subway.exception.StationException; + +public class StationService { + public StationService() { + } + + public Station saveStation(StationSaveReqDto saveReqDto) { + try { + StationRepository.findByName(saveReqDto.getStationName()); + } catch (StationException stationException) { + Station station = new Station(saveReqDto.getStationName()); + StationRepository.addStation(station); + return station; + } + throw new StationException(ErrorCode.STATION_ALREADY_EXIST); + } + + public void removeAll() { + StationRepository.deleteAll(); + } +} diff --git a/src/main/java/subway/domain/station/StationTime.java b/src/main/java/subway/domain/station/StationTime.java new file mode 100644 index 000000000..8806df1a6 --- /dev/null +++ b/src/main/java/subway/domain/station/StationTime.java @@ -0,0 +1,4 @@ +package subway.domain.station; + +public class StationTime { +} diff --git a/src/main/java/subway/domain/station/Stations.java b/src/main/java/subway/domain/station/Stations.java new file mode 100644 index 000000000..50332f5b6 --- /dev/null +++ b/src/main/java/subway/domain/station/Stations.java @@ -0,0 +1,25 @@ +package subway.domain.station; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Stations { + private final List stations; + + public Stations(List stations) { + this.stations = new ArrayList<>(stations); + } + + public List getStations() { + return Collections.unmodifiableList(stations); + } + + public void addStation(Station station, int sequence) { + stations.add(sequence, station); + } + + public int size() { + return stations.size(); + } +} diff --git a/src/main/java/subway/domain/station/dto/StationSaveReqDto.java b/src/main/java/subway/domain/station/dto/StationSaveReqDto.java new file mode 100644 index 000000000..8d43e8af4 --- /dev/null +++ b/src/main/java/subway/domain/station/dto/StationSaveReqDto.java @@ -0,0 +1,13 @@ +package subway.domain.station.dto; + +public class StationSaveReqDto { + private final String stationName; + + public StationSaveReqDto(String stationName) { + this.stationName = stationName; + } + + public String getStationName() { + return stationName; + } +} diff --git a/src/main/java/subway/exception/DistanceTimeException.java b/src/main/java/subway/exception/DistanceTimeException.java new file mode 100644 index 000000000..3d375750b --- /dev/null +++ b/src/main/java/subway/exception/DistanceTimeException.java @@ -0,0 +1,14 @@ +package subway.exception; + +public class DistanceTimeException extends IllegalArgumentException { + private final ErrorCode errorCode; + + public DistanceTimeException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + public ErrorCode getErrorCode() { + return errorCode; + } +} diff --git a/src/main/java/subway/exception/ErrorCode.java b/src/main/java/subway/exception/ErrorCode.java new file mode 100644 index 000000000..03c7ab2e5 --- /dev/null +++ b/src/main/java/subway/exception/ErrorCode.java @@ -0,0 +1,48 @@ +package subway.exception; + +import subway.view.Prefix; + +public enum ErrorCode { + //Selection + INVALID_INPUT_VALUE("S001", "선택할 수 없는 기능입니다."), + + //Station + STATION_EMTPY("ST001", "존재하지 않는 역입니다."), + STATION_NAME_LENGTH_ERROR("ST002", "역 이름은 2글자 이상이어야 합니다."), + STATION_INVALID_LAST_NAME("ST003", "마지막 글자에 역이 들어가야합니다."), + STATION_INVALID_CHARACTER("ST004", "한글, 숫자만 입력 가능합니다."), + STATION_ALREADY_EXIST("ST005", "이미 등록된 지하철 역입니다."), + STATION_NOT_FOUND("ST006", "입력된 이름으로 등록된 지하철 역이 없습니다."), + STATION_SAME_NAME("ST007", "출발역과 도착역의 이름이 같을 수 없습니다."), + + + //Line + LINE_NAME_LENGTH_ERROR("L001", "노선 이름은 2글자 이상이어야 합니다."), + LINE_INVALID_LAST_NAME("L002", "마지막 글자에 선이 들어가야합니다."), + LINE_INVALID_CHARACTER("L003", "한글, 숫자만 입력 가능합니다."), + LINE_NOT_FOUND("S004", "입력된 이름으로 등록된 노선이 없습니다."), + LINE_ALREADY_EXIST("S005", "이미 등록된 지하철 노선입니다."), + + //Section + SECTION_SAME_STATION_NAME("SE001", "상행 좀점역과 하행 종점역의 이름이 같을 수 없습니다."), + SECTION_NOT_FOUND("SE002", "입력된 이름으로 등록된 노선이 없습니다."), + + //DistanceTime + INPUT_VALUE_MUST_NATURAL("D001", "1이상의 자연수만 입력 가능합니다."); + + private final String code; + private final String message; + + ErrorCode(String code, String message) { + this.code = code; + this.message = message; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/subway/exception/LineException.java b/src/main/java/subway/exception/LineException.java new file mode 100644 index 000000000..2105643a0 --- /dev/null +++ b/src/main/java/subway/exception/LineException.java @@ -0,0 +1,14 @@ +package subway.exception; + +public class LineException extends IllegalArgumentException { + private final ErrorCode errorCode; + + public LineException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + public ErrorCode getErrorCode() { + return errorCode; + } +} \ No newline at end of file diff --git a/src/main/java/subway/exception/SectionException.java b/src/main/java/subway/exception/SectionException.java new file mode 100644 index 000000000..4d169c805 --- /dev/null +++ b/src/main/java/subway/exception/SectionException.java @@ -0,0 +1,14 @@ +package subway.exception; + +public class SectionException extends IllegalArgumentException { + private final ErrorCode errorCode; + + public SectionException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + public ErrorCode getErrorCode() { + return errorCode; + } +} diff --git a/src/main/java/subway/exception/SelectionException.java b/src/main/java/subway/exception/SelectionException.java new file mode 100644 index 000000000..751b82072 --- /dev/null +++ b/src/main/java/subway/exception/SelectionException.java @@ -0,0 +1,15 @@ +package subway.exception; + +public class SelectionException extends IllegalArgumentException { + private final ErrorCode errorCode; + + public SelectionException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + public ErrorCode getErrorCode() { + return errorCode; + } +} + diff --git a/src/main/java/subway/exception/StationException.java b/src/main/java/subway/exception/StationException.java new file mode 100644 index 000000000..d5d928fe7 --- /dev/null +++ b/src/main/java/subway/exception/StationException.java @@ -0,0 +1,14 @@ +package subway.exception; + +public class StationException extends IllegalArgumentException { + private final ErrorCode errorCode; + + public StationException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + public ErrorCode getErrorCode() { + return errorCode; + } +} \ No newline at end of file diff --git a/src/main/java/subway/view/InputView.java b/src/main/java/subway/view/InputView.java new file mode 100644 index 000000000..520577799 --- /dev/null +++ b/src/main/java/subway/view/InputView.java @@ -0,0 +1,15 @@ +package subway.view; + +import java.util.Scanner; + +public class InputView { + private final Scanner scanner; + + public InputView(Scanner scanner) { + this.scanner = scanner; + } + + public String inputNextLine() { + return scanner.nextLine(); + } +} diff --git a/src/main/java/subway/view/OutputView.java b/src/main/java/subway/view/OutputView.java new file mode 100644 index 000000000..0f4cab5fc --- /dev/null +++ b/src/main/java/subway/view/OutputView.java @@ -0,0 +1,42 @@ +package subway.view; + +public class OutputView { + private static final int START_INDEX = 0; + + private final StringBuilder sb; + + public OutputView(StringBuilder sb) { + this.sb = sb; + } + + public void printOptions(String[] strings) { + sb.append(Prefix.ENTER.getPrefix()); + for (String string : strings) { + sb.append(string).append(Prefix.ENTER.getPrefix()); + } + sb.append(Prefix.ENTER.getPrefix()); + sb.append(Prefix.CHOOSE_FUNCTION.getPrefix()); + System.out.println(sb.toString()); + clearSb(); + } + + public void printSharp(String text) { + sb.append(Prefix.ENTER.getPrefix()); + sb.append(Prefix.SHARP.getPrefix()); + sb.append(text); + + System.out.println(sb.toString()); + clearSb(); + } + + public void printInfos(String string) { + sb.append(Prefix.INFO.getPrefix()); + sb.append(string); + System.out.println(sb.toString()); + clearSb(); + } + + private void clearSb() { + sb.delete(START_INDEX, sb.length()); + } +} diff --git a/src/main/java/subway/view/Prefix.java b/src/main/java/subway/view/Prefix.java new file mode 100644 index 000000000..dbe7d9357 --- /dev/null +++ b/src/main/java/subway/view/Prefix.java @@ -0,0 +1,25 @@ +package subway.view; + +public enum Prefix { + ERROR("[ERROR] "), + INFO("[INFO] "), + SHARP("## "), + ONE("1. "), + TWO("2. "), + QUIT("Q. "), + BACK("B. "), + ENTER("\n"), + CONTOUR("---"), + CHOOSE_FUNCTION(SHARP.getPrefix() + "원하는 기능을 선택하세요."); + + + private String prefix; + + Prefix(String prefix) { + this.prefix = prefix; + } + + public String getPrefix() { + return prefix; + } +} diff --git a/src/main/java/subway/view/screen/MainView.java b/src/main/java/subway/view/screen/MainView.java new file mode 100644 index 000000000..7d38c5b8c --- /dev/null +++ b/src/main/java/subway/view/screen/MainView.java @@ -0,0 +1,19 @@ +package subway.view.screen; + +import subway.view.OutputView; +import subway.view.Prefix; + +public class MainView { + private static final String MAIN = Prefix.SHARP.getPrefix() + "메인 화면"; + private static final String SEARCH = Prefix.ONE.getPrefix() + "경로 조회"; + private static final String QUIT = Prefix.QUIT.getPrefix() + "종료"; + private final OutputView outputView; + + public MainView(OutputView outputView) { + this.outputView = outputView; + } + + public void showOptions() { + outputView.printOptions(new String[]{MAIN, SEARCH, QUIT}); + } +} diff --git a/src/main/java/subway/view/screen/SearchView.java b/src/main/java/subway/view/screen/SearchView.java new file mode 100644 index 000000000..966fec1a3 --- /dev/null +++ b/src/main/java/subway/view/screen/SearchView.java @@ -0,0 +1,71 @@ +package subway.view.screen; + +import org.jgrapht.GraphPath; +import subway.view.OutputView; +import subway.view.Prefix; + +public class SearchView { + private static final String MAIN = Prefix.SHARP.getPrefix() + "경로 기준"; + private static final String DISTANCE = Prefix.ONE.getPrefix() + "최단 거리"; + private static final String TIME = Prefix.TWO.getPrefix() + "최소 시간"; + private static final String BACK = Prefix.BACK.getPrefix() + "돌아가기"; + private static final String PRINT_ADD = "출발역을 입력하세요."; + private static final String PRINT_ADD_SECOND = "도착역을 입력하세요."; + private static final String PRINT_AFTER_ADD = "조회결과"; + + private final OutputView outputView; + + public SearchView(OutputView outputView) { + this.outputView = outputView; + } + + public void showOptions() { + outputView.printOptions(new String[]{MAIN, DISTANCE, TIME, BACK}); + } + + public void printAdd() { + outputView.printSharp(PRINT_ADD); + } + + public void printAfterAdd() { + outputView.printSharp(PRINT_AFTER_ADD); + } + + public void printSecondAdd() { + outputView.printSharp(PRINT_ADD_SECOND); + } + + public void printDistanceList(GraphPath path, double pathWeight) { + outputView.printInfos(Prefix.CONTOUR.getPrefix()); + outputView.printInfos("총 거리: " + (int)pathWeight + "km"); + outputView.printInfos(Prefix.CONTOUR.getPrefix()); + path.getEdgeList().stream() + .forEach(edge -> { + String tmp = edge.toString(); + int index = tmp.indexOf(":"); + String substring = tmp.substring(1, index); + outputView.printInfos(substring); + }); + String lastText = path.getEdgeList().get(path.getEdgeList().size() - 1).toString(); + int index = lastText.indexOf(":"); + String substring = lastText.substring(index + 2, lastText.length() -1); + outputView.printInfos(substring); + } + + public void printTimeList(GraphPath path, double pathWeight) { + outputView.printInfos(Prefix.CONTOUR.getPrefix()); + outputView.printInfos("총 시간: " + (int)pathWeight + "분"); + outputView.printInfos(Prefix.CONTOUR.getPrefix()); + path.getEdgeList().stream() + .forEach(edge -> { + String tmp = edge.toString(); + int index = tmp.indexOf(":"); + String substring = tmp.substring(1, index); + outputView.printInfos(substring); + }); + String lastText = path.getEdgeList().get(path.getEdgeList().size() - 1).toString(); + int index = lastText.indexOf(":"); + String substring = lastText.substring(index + 2, lastText.length() -1); + outputView.printInfos(substring); + } +} diff --git a/src/main/java/subway/view/selection/MainSelection.java b/src/main/java/subway/view/selection/MainSelection.java new file mode 100644 index 000000000..3162f19fc --- /dev/null +++ b/src/main/java/subway/view/selection/MainSelection.java @@ -0,0 +1,35 @@ +package subway.view.selection; + +import subway.exception.ErrorCode; +import subway.exception.SelectionException; + +public class MainSelection { + private final static String OPTION_ONE = "1"; + private final static String OPTION_QUIT = "Q"; + private final static String OPTION_QUIT_LOWERCASE = "q"; + + private final String option; + + public MainSelection(String option) { + this.option = option; + validate(option); + } + + private void validate(String option) { + if (!option.equals(OPTION_ONE) && !option.equals(OPTION_QUIT) && !option.equals(OPTION_QUIT_LOWERCASE)) { + throw new SelectionException(ErrorCode.INVALID_INPUT_VALUE); + } + } + + public String getOption() { + return option; + } + + public boolean isOptionOne() { + return option.equals(OPTION_ONE); + } + + public boolean isQuit() { + return option.equals(OPTION_QUIT) | option.equals(OPTION_QUIT_LOWERCASE); + } +} diff --git a/src/main/java/subway/view/selection/SearchSelection.java b/src/main/java/subway/view/selection/SearchSelection.java new file mode 100644 index 000000000..22e6844da --- /dev/null +++ b/src/main/java/subway/view/selection/SearchSelection.java @@ -0,0 +1,41 @@ +package subway.view.selection; + +import subway.exception.ErrorCode; +import subway.exception.SelectionException; + +public class SearchSelection { + private final static String OPTION_ONE = "1"; + private final static String OPTION_TWO = "2"; + private final static String OPTION_BACK = "B"; + private final static String OPTION_BACK_LOWERCASE = "b"; + + private final String option; + + public SearchSelection(String option) { + this.option = option; + validate(option); + } + + private void validate(String option) { + if (!option.equals(OPTION_ONE) && !option.equals(OPTION_TWO) + && !option.equals(OPTION_BACK) && !option.equals(OPTION_BACK_LOWERCASE)) { + throw new SelectionException(ErrorCode.INVALID_INPUT_VALUE); + } + } + + public String getOption() { + return option; + } + + public boolean isOptionOne() { + return option.equals(OPTION_ONE); + } + + public boolean isOptionTwo() { + return option.equals(OPTION_TWO); + } + + public boolean isBack() { + return option.equals(OPTION_BACK) | option.equals(OPTION_BACK_LOWERCASE); + } +} diff --git a/src/test/java/subway/JGraphtTest.java b/src/test/java/subway/JGraphtTest.java index 4f5f76536..5cfd1ebff 100644 --- a/src/test/java/subway/JGraphtTest.java +++ b/src/test/java/subway/JGraphtTest.java @@ -17,12 +17,14 @@ public void getDijkstraShortestPath() { graph.addVertex("v2"); graph.addVertex("v3"); graph.setEdgeWeight(graph.addEdge("v1", "v2"), 2); - graph.setEdgeWeight(graph.addEdge("v2", "v3"), 2); + graph.setEdgeWeight(graph.addEdge("v2", "v3"), 3); graph.setEdgeWeight(graph.addEdge("v1", "v3"), 100); DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph); List shortestPath = dijkstraShortestPath.getPath("v3", "v1").getVertexList(); + double pathWeight = dijkstraShortestPath.getPathWeight("v3", "v1"); assertThat(shortestPath.size()).isEqualTo(3); + assertThat(pathWeight).isEqualTo(5); } } diff --git a/src/test/java/subway/domain/line/LineServiceTest.java b/src/test/java/subway/domain/line/LineServiceTest.java new file mode 100644 index 000000000..dbe44f5df --- /dev/null +++ b/src/test/java/subway/domain/line/LineServiceTest.java @@ -0,0 +1,36 @@ +package subway.domain.line; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.domain.line.dto.LineSaveReqDto; +import subway.exception.ErrorCode; +import subway.exception.LineException; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +class LineServiceTest { + LineService lineService; + + @BeforeEach + void before() { + lineService = new LineService(); + } + + @Test + @DisplayName("이미 등록된 노선일 시 에러가 발생한다. ") + void testDuplicateSave() { + //given + String line = "1호선"; + String line2 = "1호선"; + + //when + lineService.saveLine(new LineSaveReqDto(line)); + + //then + assertThatThrownBy(() -> lineService.saveLine(new LineSaveReqDto(line2))) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_ALREADY_EXIST.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/subway/domain/line/LineTest.java b/src/test/java/subway/domain/line/LineTest.java new file mode 100644 index 000000000..530fcb16e --- /dev/null +++ b/src/test/java/subway/domain/line/LineTest.java @@ -0,0 +1,75 @@ +package subway.domain.line; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.exception.ErrorCode; +import subway.exception.LineException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class LineTest { + @Test + @DisplayName("숫자, 한글이 포함된 노선을 저장할 수 있다") + void testSave() { + //given + String line = "1호선"; + String line2 = "2호선"; + + //when + Line saveLine = new Line(line); + Line saveLine2 = new Line(line2); + + //then + assertThat(saveLine.getName()).isEqualTo(line); + assertThat(saveLine2.getName()).isEqualTo(line2); + } + + @Test + @DisplayName("2글자 미만인 구간의 이름이 들어올 시 에러가 발생한다.") + void testLengthError() { + //given + String line = "선"; + String line2 = "샨"; + + //then + assertThatThrownBy(() -> new Line(line)) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_NAME_LENGTH_ERROR.getMessage()); + assertThatThrownBy(() -> new Line(line2)) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_NAME_LENGTH_ERROR.getMessage()); + } + + @Test + @DisplayName("한글, 숫자가 아닌 이름이 들어올 시 에러가 발생한다.") + void testSaveError() { + //given + String line = "Q선"; + String line2 = "기 선"; + + //then + assertThatThrownBy(() -> new Line(line)) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_INVALID_CHARACTER.getMessage()); + assertThatThrownBy(() -> new Line(line2)) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_INVALID_CHARACTER.getMessage()); + } + + @Test + @DisplayName("마지막 글자가 선이 아닐 시 에러가 발생한다.") + void testLastNameError() { + //given + String line = "1호션"; + String line2 = "2호신"; + + //then + assertThatThrownBy(() -> new Line(line)) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_INVALID_LAST_NAME.getMessage()); + assertThatThrownBy(() -> new Line(line2)) + .isInstanceOf(LineException.class) + .hasMessage(ErrorCode.LINE_INVALID_LAST_NAME.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/subway/domain/section/SectionServiceTest.java b/src/test/java/subway/domain/section/SectionServiceTest.java new file mode 100644 index 000000000..f64e72f91 --- /dev/null +++ b/src/test/java/subway/domain/section/SectionServiceTest.java @@ -0,0 +1,117 @@ +package subway.domain.section; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.domain.section.dto.SectionSaveReqDto; +import subway.domain.section.dto.SectionStationAddReqDto; +import subway.domain.station.StationService; +import subway.domain.station.dto.StationSaveReqDto; +import subway.exception.ErrorCode; +import subway.exception.SectionException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +class SectionServiceTest { + SectionService sectionService; + StationService stationService; + + @BeforeEach + void before() { + sectionService = new SectionService(new SectionRepository()); + stationService = new StationService(); + String stationName = "행복역"; + String stationName2 = "사랑역"; + String stationName3 = "희망역"; + String stationName4 = "소망역"; + stationService.saveStation(new StationSaveReqDto(stationName)); + stationService.saveStation(new StationSaveReqDto(stationName2)); + stationService.saveStation(new StationSaveReqDto(stationName3)); + stationService.saveStation(new StationSaveReqDto(stationName4)); + + String lineName = "1호선"; + String upwardName = "행복역"; + String downwardName = "사랑역"; + sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName)); + sectionService.addStation(new SectionStationAddReqDto(lineName, stationName3, 2)); + } + + @AfterEach + void after() { + stationService.removeAll(); + sectionService.removeAll(); + } + + @Test + @DisplayName("노선을 저장한다") + void testSaved() { + //given + String lineName = "2호선"; + String upwardName = "희망역"; + String downwardName = "소망역"; + + //when + Section savedSection = sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName)); + + //then + assertThat(savedSection.getLineName()).isEqualTo(lineName); + } + + @Test + @DisplayName("이미 저장된 노선일 시 에러가 발생한다.") + void testAlreadySavedError() { + //given + String lineName = "1호선"; + String upwardName = "희망역"; + String downwardName = "소망역"; + + //then + assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName))) + .isInstanceOf(SectionException.class) + .hasMessage(ErrorCode.LINE_ALREADY_EXIST.getMessage()); + } + + @Test + @DisplayName("등룍하려는 상행 종점역이 존재하지 않으면 에러가 발생한다") + void testUpwardNotFound() { + //given + String lineName = "2호선"; + String upwardName = "역곡역"; + String downwardName = "소망역"; + + //then + assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName))) + .isInstanceOf(SectionException.class); + } + + @Test + @DisplayName("등룍하려는 하행 종점역이 존재하지 않으면 에러가 발생한다") + void testDownwardNotFound() { + //given + String lineName = "2호선"; + String upwardName = "소망역"; + String downwardName = "역곡역"; + + //then + assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName))) + .isInstanceOf(SectionException.class); + } + + @Test + @DisplayName("등룍하려는 하행 종점역이 앞서 등록한 상행 종점역일 시 에러가 발생한다") + void testDownwardSaveError() { + //given + String lineName = "2호선"; + String upwardName = "소망역"; + String downwardName = "소망역"; + + //then + assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName))) + .isInstanceOf(SectionException.class) + .hasMessage(ErrorCode.SECTION_SAME_STATION_NAME.getMessage()); + } +} + diff --git a/src/test/java/subway/domain/station/StationServiceTest.java b/src/test/java/subway/domain/station/StationServiceTest.java new file mode 100644 index 000000000..70d0ab6a3 --- /dev/null +++ b/src/test/java/subway/domain/station/StationServiceTest.java @@ -0,0 +1,50 @@ +package subway.domain.station; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.domain.station.dto.StationSaveReqDto; +import subway.exception.ErrorCode; +import subway.exception.StationException; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class StationServiceTest { + + StationService stationService; + + @BeforeEach + void before() { + stationService = new StationService(); + String stationName = "행복역"; + String stationName2 = "사랑역"; + String stationName3 = "희망역"; + String stationName4 = "소망역"; + stationService.saveStation(new StationSaveReqDto(stationName)); + stationService.saveStation(new StationSaveReqDto(stationName2)); + stationService.saveStation(new StationSaveReqDto(stationName3)); + stationService.saveStation(new StationSaveReqDto(stationName4)); + } + + @AfterEach + void after() { + stationService.removeAll(); + } + + @Test + @DisplayName("이미 등록된 지하철 역일 시 에러가 발생한다. ") + void testDuplicateSave() { + //given + String name = "인천시청역"; + String name2 = "인천시청역"; + + //when + Station savedIncheonStation = stationService.saveStation(new StationSaveReqDto(name)); + + //then + assertThatThrownBy(() -> stationService.saveStation(new StationSaveReqDto(name2))) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_ALREADY_EXIST.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/subway/domain/station/StationTest.java b/src/test/java/subway/domain/station/StationTest.java new file mode 100644 index 000000000..13aea2477 --- /dev/null +++ b/src/test/java/subway/domain/station/StationTest.java @@ -0,0 +1,81 @@ +package subway.domain.station; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.exception.ErrorCode; +import subway.exception.StationException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class StationTest { + @Test + @DisplayName("숫자, 한글이 포함된 역을 저장할 수 있다.") + void testStationSave() { + //given + String name = "하이2역"; + String name2 = "바이역"; + + //when + Station stationName = new Station(name); + Station stationName2 = new Station(name2); + + //then + assertThat(stationName.getName()).isEqualTo(name); + assertThat(stationName2.getName()).isEqualTo(name2); + } + + @Test + @DisplayName("2글자 이하일 시 에러가 발생한다") + void testStationSaveLengthError() { + //given + String name = "하"; + String name2 = "바"; + String name3 = ""; + + //when + + //then + assertThatThrownBy(() -> new Station(name)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_NAME_LENGTH_ERROR.getMessage()); + assertThatThrownBy(() -> new Station(name2)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_NAME_LENGTH_ERROR.getMessage()); + assertThatThrownBy(() -> new Station(name3)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_NAME_LENGTH_ERROR.getMessage()); + } + + @Test + @DisplayName("저장할 이름의 마지막 글자가 '역'이 아니면 에러가 발생한다") + void testStationSaveLastNameError() { + //given + String name = "하이욕"; + String name2 = "바이염"; + + //then + assertThatThrownBy(() -> new Station(name)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_INVALID_LAST_NAME.getMessage()); + assertThatThrownBy(() -> new Station(name2)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_INVALID_LAST_NAME.getMessage()); + } + + @Test + @DisplayName("저장할 이름에 한글, 숫자 외의 문자가 들어오면 에러가 발생한다") + void testStationSaveInvalidCharacter() { + //given + String name = "하 역"; + String name2 = "바e역"; + + //then + assertThatThrownBy(() -> new Station(name)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_INVALID_CHARACTER.getMessage()); + assertThatThrownBy(() -> new Station(name2)) + .isInstanceOf(StationException.class) + .hasMessage(ErrorCode.STATION_INVALID_CHARACTER.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/subway/view/MainSelectionTest.java b/src/test/java/subway/view/MainSelectionTest.java new file mode 100644 index 000000000..38f76d232 --- /dev/null +++ b/src/test/java/subway/view/MainSelectionTest.java @@ -0,0 +1,45 @@ +package subway.view; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.exception.ErrorCode; +import subway.exception.SelectionException; +import subway.view.selection.MainSelection; + +import static org.assertj.core.api.Assertions.*; + +class MainSelectionTest { + + @Test + @DisplayName("메인 옵션 선택시 보장된 입력 값만 입력해야한다.") + void testInput() { + //given + String inputOne = "1"; + String inputQuit = "Q"; + + //when + MainSelection mainSelectionOne = new MainSelection(inputOne); + MainSelection mainSelectionQuit = new MainSelection(inputQuit); + + //then + assertThat(mainSelectionOne.getOption()).isEqualTo(inputOne); + assertThat(mainSelectionQuit.getOption()).isEqualTo(inputQuit); + } + + @Test + @DisplayName("메인 옵션 선택시 보장되지 않은 입력 값일 시 에러가 발생한다.") + void testInputError() { + //given + String inputWrong = "2"; + String inputWrong2 = "0"; + + //then + assertThatThrownBy(() -> new MainSelection(inputWrong)) + .isInstanceOf(SelectionException.class) + .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage()); + assertThatThrownBy(() -> new MainSelection(inputWrong2)) + .isInstanceOf(SelectionException.class) + .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage()); + + } +} \ No newline at end of file diff --git a/src/test/java/subway/view/SearchSelectionTest.java b/src/test/java/subway/view/SearchSelectionTest.java new file mode 100644 index 000000000..3ce8b6de0 --- /dev/null +++ b/src/test/java/subway/view/SearchSelectionTest.java @@ -0,0 +1,52 @@ +package subway.view; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.exception.ErrorCode; +import subway.exception.SelectionException; +import subway.view.selection.SearchSelection; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class SearchSelectionTest { + + @Test + @DisplayName("메인 옵션 선택시 보장된 입력 값만 입력해야한다.") + void testInput() { + //given + String inputOne = "1"; + String input2 = "2"; + String input3 = "B"; + String input4 = "b"; + + //when + SearchSelection searchSelection = new SearchSelection(inputOne); + SearchSelection searchSelection2 = new SearchSelection(input2); + SearchSelection searchSelection3 = new SearchSelection(input3); + SearchSelection searchSelection4 = new SearchSelection(input4); + + //then + assertThat(searchSelection.getOption()).isEqualTo(inputOne); + assertThat(searchSelection2.getOption()).isEqualTo(input2); + assertThat(searchSelection3.getOption()).isEqualTo(input3); + assertThat(searchSelection4.getOption()).isEqualTo(input4); + } + + @Test + @DisplayName("메인 옵션 선택시 보장되지 않은 입력 값일 시 에러가 발생한다.") + void testInputError() { + //given + String inputWrong = "3"; + String inputWrong2 = "-b"; + + //then + assertThatThrownBy(() -> new SearchSelection(inputWrong)) + .isInstanceOf(SelectionException.class) + .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage()); + assertThatThrownBy(() -> new SearchSelection(inputWrong2)) + .isInstanceOf(SelectionException.class) + .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage()); + + } +} \ No newline at end of file