diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..c9cc48b --- /dev/null +++ b/build.gradle @@ -0,0 +1,21 @@ +plugins { + id 'java' +} + +group = 'org.example' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation platform('org.junit:junit-bom:5.9.1') + testImplementation 'org.junit.jupiter:junit-jupiter' + + testImplementation 'org.assertj:assertj-core:3.24.2' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/db/wiseSaying/lastId.txt b/db/wiseSaying/lastId.txt new file mode 100644 index 0000000..3cacc0b --- /dev/null +++ b/db/wiseSaying/lastId.txt @@ -0,0 +1 @@ +12 \ No newline at end of file diff --git a/src/main/java/com/ll/wiseSaying/App.java b/src/main/java/com/ll/wiseSaying/App.java new file mode 100644 index 0000000..6a66857 --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/App.java @@ -0,0 +1,21 @@ +package com.ll.wiseSaying; + +import java.util.Scanner; + +public class App { + + static final int INITIAL_SAMPLE_SIZE = 10; + + public void run(Scanner scanner) { + WiseSayingController controller = new WiseSayingController(); + initSampleData(controller); + System.out.println("== 명언 앱 =="); + controller.handleCommand(scanner); + } + + private void initSampleData(WiseSayingController controller) { + for(int i = 1; i <= INITIAL_SAMPLE_SIZE; i++) { + controller.addSampleData("명언 " + i, "작자미상 " + i); + } + } +} diff --git a/src/main/java/com/ll/wiseSaying/CustomList.java b/src/main/java/com/ll/wiseSaying/CustomList.java new file mode 100644 index 0000000..4ff1f0f --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/CustomList.java @@ -0,0 +1,233 @@ +package com.ll.wiseSaying; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +// List non Library 용 +public class CustomList { + private WiseSaying[] wiseSayings; + private int listSize; + private static final int PAGE_SIZE = 5; // 페이징 기능 사이즈 5 + + public CustomList() { + // 초기값 10(생성 10개로 인해) + wiseSayings = new WiseSaying[10]; + listSize = 0; + } + + // 10개에서 listSize에 맞춰서 크거나 작게 변경 더해지면 -> 배열크기 늘리고, 배열값을 다시 넣어줘야됨 + public void add(WiseSaying wiseSaying) { + if (listSize == wiseSayings.length) { + resize(); + } + wiseSayings[listSize] = wiseSaying; + listSize++; + } + + public WiseSaying getWiseSaying(int idx) { + for(int i = 0; i < listSize; i++) { + if(wiseSayings[i].idx == idx) { + return wiseSayings[i]; + } + } + + return null; + } + + public void modifyWiseSaying(int idx, String modifySaying, String modifyAuthor) { + for(int i = 0; i < listSize; i++) { + if(wiseSayings[i].idx == idx) { + wiseSayings[i].setSaying(modifySaying); + wiseSayings[i].setAuthor(modifyAuthor); + } + } + } + + // 배열지울때 -> 값 찾아서 지우면, 해당 배열을 한칸씩 앞으로 놓고 마지막 배열을 null로 두고, listSize의 크기를 하나 줄이면됩니다. + public void remove(int idx) { + int rmIdx = -1; + + for(int i = 0; i < listSize; i++) { + if(wiseSayings[i].idx == idx) { + rmIdx = i; + break; + } + } + + if(rmIdx == -1) { + System.out.println(idx + "번 명언은 존재하지 않습니다."); + return; + } + + for (int i = rmIdx; i < listSize - 1; i++) { + wiseSayings[i] = wiseSayings[i + 1]; + } + + wiseSayings[listSize - 1] = null; + + listSize--; + + System.out.println(idx + "번 명언이 삭제되었습니다."); + } + + public int size() { + return listSize; + } + + void resize() { + WiseSaying[] newList = new WiseSaying[wiseSayings.length * 2]; + for (int i = 0; i < wiseSayings.length; i++) { + newList[i] = wiseSayings[i]; + } + wiseSayings = newList; + } + + public void saveSingleWiseSaying(WiseSaying wiseSaying) { + createDirectoryIfNeeded(); + String json = "{\n" + + " \"id\": " + wiseSaying.getIdx() + ",\n" + + " \"content\": \"" + wiseSaying.getSaying() + "\",\n" + + " \"author\": \"" + wiseSaying.getAuthor() + "\"\n" + + "}"; + try (BufferedWriter writer = new BufferedWriter(new FileWriter("db/wiseSaying/" + wiseSaying.getIdx() + ".json"))) { + writer.write(json); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void deleteSingleWiseSaying(int idx) { + createDirectoryIfNeeded(); + File file = new File("db/wiseSaying/" + idx + ".json"); + if (file.exists()) { + boolean deleted = file.delete(); + if (!deleted) { + System.out.println(idx + ".json 파일 삭제 실패!"); + } + } else { + System.out.println(idx + ".json 파일이 존재하지 않습니다."); + } + } + + public void saveFile() { + + createDirectoryIfNeeded(); + + for (int i = 0; i < listSize; i++) { + String json = "{\n" + + " \"id\": " + wiseSayings[i].getIdx() + ",\n" + + " \"content\": \"" + wiseSayings[i].getSaying() + "\",\n" + + " \"author\": \"" + wiseSayings[i].getAuthor() + "\"\n" + + "}"; + + try (BufferedWriter writer = new BufferedWriter(new FileWriter("db/wiseSaying/" + wiseSayings[i].idx + ".json"))) { + writer.write(json); + } catch (IOException e) { + e.printStackTrace(); + } + } + + try (BufferedWriter writer = new BufferedWriter(new FileWriter("db/wiseSaying/lastId.txt"))) { + writer.write(Integer.toString(listSize)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void totalJsonFileSave() { + + createDirectoryIfNeeded(); + + String json = "[\n"; + + for (int i = 0; i < listSize; i++) { + json += " {\n" + + " \"id\": " + wiseSayings[i].getIdx() + ",\n" + + " \"content\": \"" + wiseSayings[i].getSaying() + "\",\n" + + " \"author\": \"" + wiseSayings[i].getAuthor() + "\"\n" + + " }"; + + if(listSize - 1 != i) { + json += ","; + } + } + + json += "\n" + + "]"; + try (BufferedWriter writer = new BufferedWriter(new FileWriter("data.json"))) { + writer.write(json); + } catch (IOException e) { + e.printStackTrace(); + } + } + + void createDirectoryIfNeeded() { + File directory = new File("db/wiseSaying"); + if (!directory.exists()) { + directory.mkdirs(); + } + } + + public WiseSaying get(int index) { + if (index < 0 || index >= listSize) { + throw new IndexOutOfBoundsException("Invalid index: " + index); + } + return wiseSayings[index]; + } + + public CustomList searchByKeyword(String keywordType, String keyword) { + CustomList searchResult = new CustomList(); + + for(int i = 0; i < listSize; i++) { + if(keywordType.equals("content")) { + if(wiseSayings[i].getSaying().contains(keyword)) { + searchResult.add(wiseSayings[i]); + } + } else if(keywordType.equals("author")) { + if(wiseSayings[i].getAuthor().contains(keyword)) { + searchResult.add(wiseSayings[i]); + } + } + } + + return searchResult; + } + + public int getTotalPages() { + return (int) Math.ceil((double) listSize / PAGE_SIZE); + } + + public CustomList getPage(int page) { + CustomList pageList = new CustomList(); + int startIdx = (page - 1) * PAGE_SIZE; + int endIdx = Math.min(startIdx + PAGE_SIZE, listSize); // 5보다 작은 경우도 + + // 최신글이 먼저 나오도록 역순으로 + for(int i = listSize - 1 - startIdx; i >= listSize - endIdx; i--) { + if(i >= 0) { + pageList.add(wiseSayings[i]); + } + } + return pageList; + } + + public void printPageInfo(int currentPage) { + System.out.println("----------------------"); + int totalPages = getTotalPages(); + + System.out.print("페이지 : "); + for (int i = 1; i <= totalPages; i++) { + if (i == currentPage) { + System.out.print("[" + i + "]"); + } else { + System.out.print(i); + } + if (i < totalPages) { + System.out.print(" / "); + } + } + System.out.println(); + } +} diff --git a/src/main/java/com/ll/wiseSaying/ListCommand.java b/src/main/java/com/ll/wiseSaying/ListCommand.java new file mode 100644 index 0000000..84ae7f0 --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/ListCommand.java @@ -0,0 +1,43 @@ +package com.ll.wiseSaying; + +public class ListCommand { + private final String keywordType; + private final String keyword; + private final int page; + + // keyword 검색타입, author = 검색어(13단계), page = 페이징(14단계 페이징) + public ListCommand(String cmd) { + String[] params = parseParams(cmd); + this.keywordType = findParam(params, "keywordType"); + this.keyword = findParam(params, "keyword"); + String pageStr = findParam(params, "page"); + this.page = pageStr.isEmpty() ? 1 : Integer.parseInt(pageStr); // 페이지 없을때 1페이지고정 + } + + private String[] parseParams(String cmd) { + if(cmd.contains("?")) { + // url에서 파라미터 나누기와 동일한 과정입니다.(명령어 파싱 ex 목록?keywordType=author&keyword=name) + + return cmd.substring(cmd.indexOf("?") + 1).split("&"); + } + return new String[0]; + } + + private String findParam(String[] params, String paramName) { + for(String param : params) { + String[] keyValue = param.split("="); + if(keyValue[0].equals(paramName)) { + return keyValue[1]; + } + } + return ""; + } + + public boolean hasSearch() { + return !keywordType.isEmpty() && !keyword.isEmpty(); + } + + public String getKeywordType() { return keywordType; } + public String getKeyword() { return keyword; } + public int getPage() { return page; } +} diff --git a/src/main/java/com/ll/wiseSaying/Main.java b/src/main/java/com/ll/wiseSaying/Main.java new file mode 100644 index 0000000..115eede --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/Main.java @@ -0,0 +1,11 @@ +package com.ll.wiseSaying; + +import java.util.Scanner; + +public class Main { + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + new App().run(scanner); + } +} \ No newline at end of file diff --git a/src/main/java/com/ll/wiseSaying/WiseSaying.java b/src/main/java/com/ll/wiseSaying/WiseSaying.java new file mode 100644 index 0000000..e66314c --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/WiseSaying.java @@ -0,0 +1,29 @@ +package com.ll.wiseSaying; + +public class WiseSaying { + int idx; + String saying; + String author; + + public WiseSaying(int idx, String saying, String author) { + this.idx = idx; + this.saying = saying; + this.author = author; + } + + public int getIdx() { + return idx; + } + + public String getSaying() { + return saying; + } + + public void setSaying(String saying) { this.saying = saying; }; + + public void setAuthor(String author) { this.author = author; }; + + public String getAuthor() { + return author; + } +} diff --git a/src/main/java/com/ll/wiseSaying/WiseSayingController.java b/src/main/java/com/ll/wiseSaying/WiseSayingController.java new file mode 100644 index 0000000..cbd43d8 --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/WiseSayingController.java @@ -0,0 +1,158 @@ +package com.ll.wiseSaying; + +import java.util.Scanner; + +public class WiseSayingController { + private final WiseSayingService service; + + public WiseSayingController() { + this.service = new WiseSayingService(); + } + + public void handleCommand(Scanner scanner) { + + while(true) { + System.out.print("명령) "); + if(!scanner.hasNextLine()) break; // Scanner가 nextLine이 없으면 종료 -> 입력값이 없으면 종료를 해야되기 때문에 + + String cmd = scanner.nextLine().trim(); + switch(getCommandType(cmd)) { + case "등록" -> handleAdd(scanner); + case "목록" -> handleList(cmd); + case "삭제" -> handleDelete(cmd); + case "수정" -> handleModify(scanner, cmd); + case "빌드" -> handleBuild(); + case "종료" -> { + handleExit(); + handleCommand(scanner); + return; + } + } + } + } + + private String getCommandType(String cmd) { + if(cmd.contains("?")) { + return cmd.split("\\?")[0]; + } + return cmd; + } + + private void handleAdd(Scanner scanner) { + System.out.print("명언 : "); + String saying = scanner.nextLine(); + System.out.print("작가 : "); + String author = scanner.nextLine(); + int id = service.addWiseSaying(saying, author); + System.out.println(id + "번 명언이 등록되었습니다."); + + WiseSaying wiseSaying = service.getWiseSayings().getWiseSaying(id); + // 등록 직후 파일 저장 + service.getWiseSayings().saveSingleWiseSaying(wiseSaying); + } + + void handleBuild() { + service.getWiseSayings().totalJsonFileSave(); + System.out.println("data.json 파일의 내용이 갱신되었습니다."); + } + + void handleExit() { + System.out.println(); + CustomList wiseSayings = service.getWiseSayings(); + service.initWiseSayingService(); + System.out.println("프로그램 다시 시작..."); + System.out.println(); + System.out.print("== 명언 앱 =="); + System.out.println(); + } + + private void handleModify(Scanner scanner, String cmd) { + String[] splitStr = cmd.split("\\?id="); + + if(splitStr.length == 1) { + System.out.println("잘못된 값 입니다. 다시 입력해 주세요"); + return; + } + + int idx = Integer.parseInt(splitStr[1]); + WiseSaying curWiseSaying = service.getWiseSayings().getWiseSaying(idx); + + if(curWiseSaying == null) { + System.out.println(idx + "번 명언은 존재하지 않습니다."); + return; + } + + System.out.println("명언(기존) : " + curWiseSaying.getSaying()); + System.out.print("명언 : "); + String modifySaying = scanner.nextLine(); + System.out.println("작가(기존) : " + curWiseSaying.getAuthor()); + System.out.print("작가 : "); + String modifyAuthor = scanner.nextLine(); + + service.getWiseSayings().modifyWiseSaying(idx, modifySaying, modifyAuthor); + + // 저장하면, 수정이되므로 + service.getWiseSayings().saveSingleWiseSaying(curWiseSaying); + } + + private void handleDelete(String cmd) { + String[] splitStr = cmd.split("\\?id="); + int idx = Integer.parseInt(splitStr[1]); + service.deleteWiseSaying(idx); + + service.getWiseSayings().deleteSingleWiseSaying(idx); + } + + private void handleList(String cmd) { + ListCommand listCommand = new ListCommand(cmd); + CustomList wiseSayings = service.getWiseSayings(); + + System.out.println("번호 / 작가 / 명언"); + System.out.println("----------------------"); + + if(listCommand.hasSearch()) { + handleSearchList(wiseSayings, listCommand); + } else { + handlePagedList(wiseSayings, listCommand.getPage()); + } + } + + private void handlePagedList(CustomList wiseSayings, int page) { + CustomList pageResults = wiseSayings.getPage(page); + printWiseSayings(pageResults); + wiseSayings.printPageInfo(page); + } + + private void handleSearchList(CustomList wiseSayings, ListCommand cmd) { + System.out.println("----------------------"); + System.out.println("검색타입 : " + cmd.getKeywordType()); + System.out.println("검색어 : " + cmd.getKeyword()); + System.out.println("----------------------"); + System.out.println("번호 / 작가 / 명언"); + System.out.println("----------------------"); + + CustomList searchResults = service.searchWiseSayings( + cmd.getKeywordType(), + cmd.getKeyword() + ); + CustomList pageResults = searchResults.getPage(cmd.getPage()); + printWiseSayings(pageResults); + wiseSayings.printPageInfo(cmd.getPage()); + } + + private void printWiseSayings(CustomList list) { + for (int i = 0; i < list.size(); i++) { + WiseSaying wiseSaying = list.get(i); + System.out.println(wiseSaying.getIdx() + " / " + + wiseSaying.getAuthor() + " / " + + wiseSaying.getSaying()); + } + } + + public void addSampleData(String saying, String author) { + int id = service.addWiseSaying(saying, author); + WiseSaying wiseSaying = service.getWiseSayings().getWiseSaying(id); + // 등록 직후 파일 저장 + service.getWiseSayings().saveSingleWiseSaying(wiseSaying); + } +} diff --git a/src/main/java/com/ll/wiseSaying/WiseSayingRepository.java b/src/main/java/com/ll/wiseSaying/WiseSayingRepository.java new file mode 100644 index 0000000..0e44941 --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/WiseSayingRepository.java @@ -0,0 +1,40 @@ +package com.ll.wiseSaying; + +public class WiseSayingRepository { + private CustomList wiseSayings = new CustomList(); + private int lastId = 0; + + public int save(WiseSaying wiseSaying) { + wiseSayings.add(wiseSaying); + return wiseSaying.getIdx(); + } + + public void init() { + wiseSayings = new CustomList(); + } + + public boolean deleteById(int id) { + WiseSaying wiseSaying = wiseSayings.getWiseSaying(id); + if (wiseSaying == null) { + System.out.println(id + "번 명언은 존재하지 않습니다."); + return false; + } + wiseSayings.remove(id); + + return true; + } + + public CustomList findAll() { + return wiseSayings; + } + + public int getNextId() { + return ++lastId; + } + + public CustomList search(String keywordType, String keyword) { + return wiseSayings.searchByKeyword(keywordType, keyword); + } + + +} diff --git a/src/main/java/com/ll/wiseSaying/WiseSayingService.java b/src/main/java/com/ll/wiseSaying/WiseSayingService.java new file mode 100644 index 0000000..424efcf --- /dev/null +++ b/src/main/java/com/ll/wiseSaying/WiseSayingService.java @@ -0,0 +1,29 @@ +package com.ll.wiseSaying; + +public class WiseSayingService { + private final WiseSayingRepository repository; + + public WiseSayingService() { + this.repository = new WiseSayingRepository(); + } + + public int addWiseSaying(String wiseSaying, String author) { + return repository.save(new WiseSaying(repository.getNextId(), wiseSaying, author)); + } + + public CustomList getWiseSayings() { + return repository.findAll(); + } + + public void deleteWiseSaying(int id) { + repository.deleteById(id); + } + + public void initWiseSayingService() { + repository.init(); + } + + public CustomList searchWiseSayings(String keywordType, String keyword) { + return repository.search(keywordType, keyword); + } +} diff --git a/src/test/java/com/ll/wiseSaying/TestUtil.java b/src/test/java/com/ll/wiseSaying/TestUtil.java new file mode 100644 index 0000000..1cf73c4 --- /dev/null +++ b/src/test/java/com/ll/wiseSaying/TestUtil.java @@ -0,0 +1,32 @@ +package com.ll.wiseSaying; + +import java.io.*; +import java.util.Scanner; + +public class TestUtil { + // gen == generate 생성하다. + // 테스트용 스캐너 생성 + public static Scanner genScanner(final String input) { + final InputStream in = new ByteArrayInputStream(input.getBytes()); + + return new Scanner(in); + } + + // System.out의 출력을 스트림으로 받기 + public static ByteArrayOutputStream setOutToByteArray() { + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + System.setOut(new PrintStream(output)); + + return output; + } + + // setOutToByteArray 함수의 사용을 완료한 후 정리하는 함수, 출력을 다시 정상화 하는 함수 + public static void clearSetOutToByteArray(final ByteArrayOutputStream output) { + System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); + try { + output.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/com/ll/wiseSaying/WiseSayingControllerTest.java b/src/test/java/com/ll/wiseSaying/WiseSayingControllerTest.java new file mode 100644 index 0000000..7f206d6 --- /dev/null +++ b/src/test/java/com/ll/wiseSaying/WiseSayingControllerTest.java @@ -0,0 +1,308 @@ + +package com.ll.wiseSaying; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Scanner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +public class WiseSayingControllerTest { + + App app; + + @BeforeEach + void beforeEach() { + app = new App(); + } + + private void runTest(String input, String... expectedOutputs) { + Scanner scanner = TestUtil.genScanner(input); + ByteArrayOutputStream outputStream = TestUtil.setOutToByteArray(); // 이게 먼저 실행되야, scanner의 값을 가져올 수 있습니다. + + app.run(scanner); + String output = outputStream.toString().trim(); + + for (String expected : expectedOutputs) { + assertThat(output).contains(expected); + } + + TestUtil.clearSetOutToByteArray(outputStream); + } + + @Test + @DisplayName("등록 명령 처리") + void testRegisterWiseSaying() { + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + """; + + runTest(input, "== 명언 앱 ==", "명언 :", "작가 :", "1번 명언이 등록되었습니다."); + } + + @Test + @DisplayName("목록 명령 처리") + void testListWiseSaying() { + + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 목록 + """; + + runTest(input, "번호 / 작가 / 명언" + , "----------------------" + , "2 / 작자미상 / 과거에 집착하지 마라." + , "1 / 작자미상 / 현재를 사랑하라."); + } + + @Test + @DisplayName("삭제 명령 처리") + void testDeleteWiseSaying() { + + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 목록 + 삭제?id=1 + 삭제?id=1 + """; + + runTest(input, "1번 명언이 삭제되었습니다." + , "1번 명언은 존재하지 않습니다."); + } + + // 초기 10개의 임시데이터로 인한 숫자 수정 + @Test + @DisplayName("수정 명령 처리") + void testModifyWiseSaying() { + + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 목록 + 삭제?id=11 + 삭제?id=11 + 수정?id=13 + 수정?id=12 + 현재와 자신을 사랑하라. + 홍길동 + 목록 + """; + + runTest(input, "명언(기존) : 과거에 집착하지 마라." + , "명언 : " + , "작가(기존) : 작자미상" + , "작가 : " + , "번호 / 작가 / 명언" + , "----------------------" + , "12 / 홍길동 / 현재와 자신을 사랑하라."); + } + + @Test + @DisplayName("종료 명령 처리") + void testEndWiseSaying() { + + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 종료 + """; + + runTest(input, "11번 명언이 등록되었습니다." + , "12번 명언이 등록되었습니다." + , "프로그램 다시 시작..."); + + File lastIdFile = new File("db/wiseSaying/lastId.txt"); + assertThat(lastIdFile.exists()).isTrue(); + + try { + String lastIdContent = Files.readString(lastIdFile.toPath()).trim(); + assertThat(lastIdContent).isEqualTo("12"); + + // 개별 명언 파일 확인 + File file11 = new File("db/wiseSaying/11.json"); // 1.json -> 11.json + File file12 = new File("db/wiseSaying/12.json"); // 2.json -> 12.json + assertThat(file11.exists()).isTrue(); + assertThat(file12.exists()).isTrue(); + + // 11.json 파일 내용 확인 + String content11 = Files.readString(file11.toPath()); + assertThat(content11).contains("\"id\": 11") + .contains("\"content\": \"현재를 사랑하라.\"") + .contains("\"author\": \"작자미상\""); + + // 12.json 파일 내용 확인 + String content12 = Files.readString(file12.toPath()); + assertThat(content12).contains("\"id\": 12") + .contains("\"content\": \"과거에 집착하지 마라.\"") + .contains("\"author\": \"작자미상\""); + + } catch (IOException e) { + fail("JSON파일을 읽는데 실패했습니다."); + } + } + + @Test + @DisplayName("빌드 명령 처리") + void testBuildWiseSaying() { + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 빌드 + """; + + Scanner scanner = TestUtil.genScanner(input); + ByteArrayOutputStream outputStream = TestUtil.setOutToByteArray(); + app.run(scanner); + + // data.json 파일 확인 + File dataFile = new File("data.json"); + assertThat(dataFile.exists()).isTrue(); + + try { + String content = Files.readString(dataFile.toPath()); + // JSON 배열 형식 확인 + assertThat(content) + .startsWith("[") + .endsWith("]") + // 초기 10개의 데이터와 추가된 2개의 데이터가 있어야 함 + .contains("\"id\": 11") + .contains("\"content\": \"현재를 사랑하라.\"") + .contains("\"author\": \"작자미상\"") + .contains("\"id\": 12") + .contains("\"content\": \"과거에 집착하지 마라.\"") + .contains("\"author\": \"작자미상\""); + + // 출력 메시지 확인 + String output = outputStream.toString().trim(); + assertThat(output).contains("data.json 파일의 내용이 갱신되었습니다."); + } catch (IOException e) { + fail("data.json 파일을 읽는데 실패했습니다."); + } finally { + TestUtil.clearSetOutToByteArray(outputStream); + } + } + + @Test + @DisplayName("명언 검색 테스트") + void testSearchWiseSaying() { + // 첫 번째 테스트: content 검색 + String input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 목록?keywordType=content&keyword=과거 + """; + + Scanner scanner = TestUtil.genScanner(input); + ByteArrayOutputStream outputStream = TestUtil.setOutToByteArray(); + app.run(scanner); + + String output = outputStream.toString().trim(); + assertThat(output) + .contains("검색타입 : content") + .contains("검색어 : 과거") + .contains("번호 / 작가 / 명언") + .contains("2 / 작자미상 / 과거에 집착하지 마라.") + .doesNotContain("1 / 작자미상 / 현재를 사랑하라."); + TestUtil.clearSetOutToByteArray(outputStream); + + // 두 번째 테스트: author 검색 + input = """ + 등록 + 현재를 사랑하라. + 작자미상 + 등록 + 과거에 집착하지 마라. + 작자미상 + 목록?keywordType=author&keyword=작자 + """; + + scanner = TestUtil.genScanner(input); + outputStream = TestUtil.setOutToByteArray(); + app.run(scanner); + + output = outputStream.toString().trim(); + assertThat(output) + .contains("검색타입 : author") + .contains("검색어 : 작자") + .contains("2 / 작자미상 / 과거에 집착하지 마라.") + .contains("1 / 작자미상 / 현재를 사랑하라."); + + TestUtil.clearSetOutToByteArray(outputStream); + } + + @Test + @DisplayName("페이징 테스트") + void testPaging() { + String input = """ + 목록 + 목록?page=2 + 목록?keywordType=content&keyword=명언&page=1 + 목록?keywordType=author&keyword=작자&page=2 + """; + + Scanner scanner = TestUtil.genScanner(input); + ByteArrayOutputStream outputStream = TestUtil.setOutToByteArray(); + app.run(scanner); + + String output = outputStream.toString().trim(); + + // 기본 페이징 - 첫 페이지 + assertThat(output) + .contains("10 / 작자미상 10 / 명언 10") + .contains("9 / 작자미상 9 / 명언 9") + .contains("8 / 작자미상 8 / 명언 8") + .contains("7 / 작자미상 7 / 명언 7") + .contains("6 / 작자미상 6 / 명언 6") + .contains("페이지 : [1] / 2") + // 기본 페이징 - 두 번째 페이지 + .contains("5 / 작자미상 5 / 명언 5") + .contains("4 / 작자미상 4 / 명언 4") + .contains("3 / 작자미상 3 / 명언 3") + .contains("2 / 작자미상 2 / 명언 2") + .contains("1 / 작자미상 1 / 명언 1") + .contains("페이지 : 1 / [2]") + // content 검색 결과 + .contains("검색타입 : content") + .contains("검색어 : 명언") + // author 검색 결과 + .contains("검색타입 : author") + .contains("검색어 : 작자"); + + TestUtil.clearSetOutToByteArray(outputStream); + } +}