From f761dc656ffacad5b81ff397db5e325567da365a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 28 Apr 2025 22:04:46 +0900 Subject: [PATCH 01/67] =?UTF-8?q?docs(README)=20:=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=EA=B8=B0=20=EB=AF=B8=EC=85=98=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1e3356ca..3e9ca46a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ -# java-calculator +# 기능 요구 사항 + +- [ ] 인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다. +- [ ] 사칙연산과 매칭되는 4개의 메서드를 제공한다. +- [ ] 계산된 결과는 정수를 반환한다. +- [ ] 메인 메서드는 만들지 않는다. -계산기 미션 저장소 From 86bcbed23b2fa30fc21d9d3919f1e8090d778446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 28 Apr 2025 22:06:27 +0900 Subject: [PATCH 02/67] =?UTF-8?q?feat(OutputView)=20:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=20=EC=B6=9C=EB=A0=A5=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/.gitkeep | 0 src/main/java/OutputView.java | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) delete mode 100644 src/main/java/.gitkeep create mode 100644 src/main/java/OutputView.java diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java new file mode 100644 index 00000000..f4262220 --- /dev/null +++ b/src/main/java/OutputView.java @@ -0,0 +1,18 @@ +public class OutputView { + + private static final String FIRST_NUMBER_PROMPT = "첫 번째 숫자를 입력하세요: "; + private static final String SECOND_NUMBER_PROMPT = "두 번째 숫자를 입력하세요: "; + private static final String RESULT_MESSAGE = "계산 결과: "; + + public void printFirstNumberPrompt() { + System.out.print(FIRST_NUMBER_PROMPT); + } + + public void printSecondNumberPrompt() { + System.out.print(SECOND_NUMBER_PROMPT); + } + + public void printResult(int result) { + System.out.println(RESULT_MESSAGE + result); + } +} \ No newline at end of file From 81fb8ba375dfece531b1aa85f06bdf2151ef97df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 28 Apr 2025 22:07:04 +0900 Subject: [PATCH 03/67] =?UTF-8?q?feat(InputView)=20:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=88=AB=EC=9E=90=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/InputView.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/InputView.java diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java new file mode 100644 index 00000000..c6b30494 --- /dev/null +++ b/src/main/java/InputView.java @@ -0,0 +1,10 @@ +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner = new Scanner(System.in); + + public int readNumber() { + return Integer.parseInt(scanner.nextLine()); + } +} \ No newline at end of file From 5757e1b111caa06d0628a8d78ceb6fa22e24dd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 28 Apr 2025 22:07:49 +0900 Subject: [PATCH 04/67] =?UTF-8?q?feat(Calculator)=20:=20=EB=8D=A7=EC=85=88?= =?UTF-8?q?,=20=EB=BA=84=EC=85=88,=20=EA=B3=B1=EC=85=88,=20=EB=82=98?= =?UTF-8?q?=EB=88=97=EC=85=88=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=200=20=EB=82=98=EB=88=84=EA=B8=B0=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Calculator.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/Calculator.java diff --git a/src/main/java/Calculator.java b/src/main/java/Calculator.java new file mode 100644 index 00000000..3935e16f --- /dev/null +++ b/src/main/java/Calculator.java @@ -0,0 +1,23 @@ +public class Calculator { + + private static final String DIVIDE_BY_ZERO_ERROR_MESSAGE = "[ERROR] 0으로 나눌 수 없습니다."; + + public int add(int firstNumber, int secondNumber) { + return firstNumber + secondNumber; + } + + public int subtract(int firstNumber, int secondNumber) { + return firstNumber - secondNumber; + } + + public int multiply(int firstNumber, int secondNumber) { + return firstNumber * secondNumber; + } + + public int divide(int firstNumber, int secondNumber) { + if (secondNumber == 0) { + throw new IllegalArgumentException(DIVIDE_BY_ZERO_ERROR_MESSAGE); + } + return firstNumber / secondNumber; + } +} \ No newline at end of file From 91c60eaa32813f5b01bfcb64a8d48a74888465c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 28 Apr 2025 22:08:12 +0900 Subject: [PATCH 05/67] =?UTF-8?q?docs(README)=20:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3e9ca46a..85fe6f31 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # 기능 요구 사항 -- [ ] 인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다. -- [ ] 사칙연산과 매칭되는 4개의 메서드를 제공한다. -- [ ] 계산된 결과는 정수를 반환한다. -- [ ] 메인 메서드는 만들지 않는다. +- [x] 인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다. +- [x] 사칙연산과 매칭되는 4개의 메서드를 제공한다. +- [x] 계산된 결과는 정수를 반환한다. +- [x] 메인 메서드는 만들지 않는다. From 393680ee3f62357c6475e0d8c04deecc84fc4478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Mon, 28 Apr 2025 23:08:22 +0900 Subject: [PATCH 06/67] =?UTF-8?q?docs(README)=20:=20Step2=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 85fe6f31..e32b81fd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ # 기능 요구 사항 +# Step1 - [x] 인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다. - [x] 사칙연산과 매칭되는 4개의 메서드를 제공한다. - [x] 계산된 결과는 정수를 반환한다. - [x] 메인 메서드는 만들지 않는다. +# Step2 +- [ ] 구현한 초간단 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. +- [ ] 메인 메서드 없이 동작을 검증하는 경험을 해본다. +- [ ] 메인 메서드는 만들지 않는다. + From 25c169947e0a9b1442b7c1848185777c78f1354d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:01:07 +0900 Subject: [PATCH 07/67] =?UTF-8?q?test(Calculator)=20:=20=EB=8D=A7=EC=85=88?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EB=8C=80=ED=95=9C=20JUnit5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/.gitkeep | 0 src/test/java/CalculatorTest.java | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+) delete mode 100644 src/test/java/.gitkeep create mode 100644 src/test/java/CalculatorTest.java diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/test/java/CalculatorTest.java b/src/test/java/CalculatorTest.java new file mode 100644 index 00000000..f20fa7fa --- /dev/null +++ b/src/test/java/CalculatorTest.java @@ -0,0 +1,26 @@ +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +@DisplayName("Calculator Test") +class CalculatorTest { + + private final Calculator calculator = new Calculator(); + + @ParameterizedTest + @CsvSource({ + "1, 2, 3", + "3, 5, 8", + "-1, -2, -3", + "-5, 5, 0" + }) + @DisplayName("덧셈: 두 수를 더한 결과를 반환한다.") + void addMethod(int firstNumber, int secondNumber, int expected) { + int result = calculator.add(firstNumber, secondNumber); + assertEquals(expected, result); + } + +} \ No newline at end of file From 9baf34e2f16f016d82f1e6715b1a78804eb51142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:01:47 +0900 Subject: [PATCH 08/67] =?UTF-8?q?test(Calculator)=20:=20=EB=BA=84=EC=85=88?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EB=8C=80=ED=95=9C=20JUnit5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/CalculatorTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/CalculatorTest.java b/src/test/java/CalculatorTest.java index f20fa7fa..62c60060 100644 --- a/src/test/java/CalculatorTest.java +++ b/src/test/java/CalculatorTest.java @@ -23,4 +23,17 @@ void addMethod(int firstNumber, int secondNumber, int expected) { assertEquals(expected, result); } + @ParameterizedTest + @CsvSource({ + "5, 2, 3", + "10, 5, 5", + "0, 0, 0", + "-5, -5, 0" + }) + @DisplayName("뺄셈: 두 수를 뺀 결과를 반환한다.") + void subtractMethod(int firstNumber, int secondNumber, int expected) { + int result = calculator.subtract(firstNumber, secondNumber); + assertEquals(expected, result); + } + } \ No newline at end of file From d0036582689a417988951261ab6ad0be0f4d0278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:02:38 +0900 Subject: [PATCH 09/67] =?UTF-8?q?test(Calculator)=20:=20=EA=B3=B1=EC=85=88?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EB=8C=80=ED=95=9C=20JUnit5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/CalculatorTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/CalculatorTest.java b/src/test/java/CalculatorTest.java index 62c60060..a3f26ab9 100644 --- a/src/test/java/CalculatorTest.java +++ b/src/test/java/CalculatorTest.java @@ -36,4 +36,17 @@ void subtractMethod(int firstNumber, int secondNumber, int expected) { assertEquals(expected, result); } + @ParameterizedTest + @CsvSource({ + "2, 3, 6", + "-2, 3, -6", + "0, 5, 0", + "-3, -3, 9" + }) + @DisplayName("곱셈: 두 수를 곱한 결과를 반환한다.") + void multiplyMethod(int firstNumber, int secondNumber, int expected) { + int result = calculator.multiply(firstNumber, secondNumber); + assertEquals(expected, result); + } + } \ No newline at end of file From 2cceffbc0d83b99749855dac6a98362fed20bd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:03:11 +0900 Subject: [PATCH 10/67] =?UTF-8?q?test(Calculator)=20:=20=EB=82=98=EB=88=97?= =?UTF-8?q?=EC=85=88=20=EA=B8=B0=EB=8A=A5=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?JUnit5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/CalculatorTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/CalculatorTest.java b/src/test/java/CalculatorTest.java index a3f26ab9..5961713c 100644 --- a/src/test/java/CalculatorTest.java +++ b/src/test/java/CalculatorTest.java @@ -49,4 +49,17 @@ void multiplyMethod(int firstNumber, int secondNumber, int expected) { assertEquals(expected, result); } + @ParameterizedTest + @CsvSource({ + "6, 3, 2", + "9, 3, 3", + "-9, 3, -3", + "10, -2, -5" + }) + @DisplayName("나눗셈: 두 수를 나눈 결과를 반환한다.") + void divideMethod(int firstNumber, int secondNumber, int expected) { + int result = calculator.divide(firstNumber, secondNumber); + assertEquals(expected, result); + } + } \ No newline at end of file From 23eb753e712fbdf2a0aa1b178313ad00af64aed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:03:42 +0900 Subject: [PATCH 11/67] =?UTF-8?q?test(Calculator)=20:=200=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=82=98=EB=88=8C=20=EB=95=8C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/CalculatorTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/CalculatorTest.java b/src/test/java/CalculatorTest.java index 5961713c..e90ca200 100644 --- a/src/test/java/CalculatorTest.java +++ b/src/test/java/CalculatorTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.params.provider.CsvSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; @DisplayName("Calculator Test") @@ -62,4 +63,14 @@ void divideMethod(int firstNumber, int secondNumber, int expected) { assertEquals(expected, result); } + @ParameterizedTest + @CsvSource({ + "5, 0", + "0, 0", + "-3, 0" + }) + @DisplayName("나눗셈: 0으로 나누면 IllegalArgumentException이 발생한다.") + void divideByZeroException(int firstNumber, int secondNumber) { + assertThrows(IllegalArgumentException.class, () -> calculator.divide(firstNumber, secondNumber)); + } } \ No newline at end of file From c9987be498bda953d96f3de4a941525ca8180342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:08:51 +0900 Subject: [PATCH 12/67] =?UTF-8?q?refactor(OutputView)=20:=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=B4=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=20=EB=B2=94=EC=9C=84=EB=A5=BC=20default?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/OutputView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/OutputView.java b/src/main/java/OutputView.java index f4262220..f65713ad 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/OutputView.java @@ -1,8 +1,8 @@ public class OutputView { - private static final String FIRST_NUMBER_PROMPT = "첫 번째 숫자를 입력하세요: "; - private static final String SECOND_NUMBER_PROMPT = "두 번째 숫자를 입력하세요: "; - private static final String RESULT_MESSAGE = "계산 결과: "; + static final String FIRST_NUMBER_PROMPT = "첫 번째 숫자를 입력하세요: "; + static final String SECOND_NUMBER_PROMPT = "두 번째 숫자를 입력하세요: "; + static final String RESULT_MESSAGE = "계산 결과: "; public void printFirstNumberPrompt() { System.out.print(FIRST_NUMBER_PROMPT); From 95a2615e7aa00cdc3365dd2780c5318f972d207d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:09:43 +0900 Subject: [PATCH 13/67] =?UTF-8?q?test(OutputViewTest)=20:=20=EC=B2=AB=20?= =?UTF-8?q?=EB=B2=88=EC=A7=B8=20=EC=88=AB=EC=9E=90=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=ED=94=84=EB=A1=AC=ED=94=84=ED=8A=B8=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/OutputViewTest.java | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/java/OutputViewTest.java diff --git a/src/test/java/OutputViewTest.java b/src/test/java/OutputViewTest.java new file mode 100644 index 00000000..145b9d59 --- /dev/null +++ b/src/test/java/OutputViewTest.java @@ -0,0 +1,35 @@ +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 java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@DisplayName("OutputView Test") +class OutputViewTest { + + private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + private final OutputView outputView = new OutputView(); + + @BeforeEach + void setUp() { + System.setOut(new PrintStream(outputStream)); + } + + @AfterEach + void tearDown() { + System.setOut(originalOut); + } + + @Test + @DisplayName("첫 번째 숫자 입력 프롬프트를 출력한다.") + void printFirstNumberPrompt() { + outputView.printFirstNumberPrompt(); + String output = outputStream.toString(); + assertTrue(output.contains(OutputView.FIRST_NUMBER_PROMPT)); + } +} From c700c13d67bb0d543d8b8597ed974d2e80c67b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:10:26 +0900 Subject: [PATCH 14/67] =?UTF-8?q?test(OutputViewTest)=20:=20=EB=91=90=20?= =?UTF-8?q?=EB=B2=88=EC=A7=B8=20=EC=88=AB=EC=9E=90=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=ED=94=84=EB=A1=AC=ED=94=84=ED=8A=B8=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/OutputViewTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/OutputViewTest.java b/src/test/java/OutputViewTest.java index 145b9d59..7e0ceb3a 100644 --- a/src/test/java/OutputViewTest.java +++ b/src/test/java/OutputViewTest.java @@ -32,4 +32,12 @@ void printFirstNumberPrompt() { String output = outputStream.toString(); assertTrue(output.contains(OutputView.FIRST_NUMBER_PROMPT)); } + + @Test + @DisplayName("두 번째 숫자 입력 프롬프트를 출력한다.") + void printSecondNumberPrompt() { + outputView.printSecondNumberPrompt(); + String output = outputStream.toString(); + assertTrue(output.contains(OutputView.SECOND_NUMBER_PROMPT)); + } } From d3e000542752797dba90e17e080a65c305cbf0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:11:34 +0900 Subject: [PATCH 15/67] =?UTF-8?q?test(OutputViewTest)=20:=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/OutputViewTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/OutputViewTest.java b/src/test/java/OutputViewTest.java index 7e0ceb3a..ccd323d4 100644 --- a/src/test/java/OutputViewTest.java +++ b/src/test/java/OutputViewTest.java @@ -40,4 +40,13 @@ void printSecondNumberPrompt() { String output = outputStream.toString(); assertTrue(output.contains(OutputView.SECOND_NUMBER_PROMPT)); } + + @Test + @DisplayName("계산 결과를 출력한다.") + void printResult() { + int result = 10; + outputView.printResult(result); + String output = outputStream.toString(); + assertTrue(output.contains(OutputView.RESULT_MESSAGE + result)); + } } From 80829b8c7bdc06ec77f828db61453ba2850309f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:14:43 +0900 Subject: [PATCH 16/67] =?UTF-8?q?test(InputViewTest)=20:=20readNumber=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=95=EC=83=81=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/InputViewTest.java | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/java/InputViewTest.java diff --git a/src/test/java/InputViewTest.java b/src/test/java/InputViewTest.java new file mode 100644 index 00000000..1e843dbd --- /dev/null +++ b/src/test/java/InputViewTest.java @@ -0,0 +1,28 @@ +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@DisplayName("InputView Test") +class InputViewTest { + + private static final String INPUT = "42\n"; + private static final InputStream ORIGINAL_IN = System.in; + + @AfterEach + void tearDown() { + System.setIn(ORIGINAL_IN); + } + + @Test + @DisplayName("readNumber: 입력받은 문자열을 정수로 변환하여 반환한다.") + void readNumber() { + System.setIn(new ByteArrayInputStream(INPUT.getBytes())); + InputView inputView = new InputView(); + assertEquals(42, inputView.readNumber()); + } +} From fd6099c550f9f87d0bc9567616b0431eb290ab17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:18:09 +0900 Subject: [PATCH 17/67] =?UTF-8?q?refactor(InputView)=20:=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EA=B3=BC=20=ED=8C=8C=EC=8B=B1=20=EC=B1=85=EC=9E=84?= =?UTF-8?q?=EC=9D=84=20=EB=B6=84=EB=A6=AC=ED=95=98=EC=97=AC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=A7=8C=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/InputView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java index c6b30494..4c8355a4 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/InputView.java @@ -4,7 +4,7 @@ public class InputView { private final Scanner scanner = new Scanner(System.in); - public int readNumber() { - return Integer.parseInt(scanner.nextLine()); + public String readInput() { + return scanner.nextLine(); } } \ No newline at end of file From 95b22bf332266bb71319c83e203a883c6bacfec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:22:28 +0900 Subject: [PATCH 18/67] =?UTF-8?q?feat(NumberParser)=20:=20=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EC=97=B4=20=EC=9E=85=EB=A0=A5=EC=9D=84=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=ED=95=98=EA=B3=A0=20Number=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/NumberParser.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/NumberParser.java diff --git a/src/main/java/NumberParser.java b/src/main/java/NumberParser.java new file mode 100644 index 00000000..6f92ee36 --- /dev/null +++ b/src/main/java/NumberParser.java @@ -0,0 +1,13 @@ +public class NumberParser { + + private static final String ERROR_NOT_A_NUMBER = "[ERROR] 입력은 숫자여야 합니다."; + + public static Number parse(String input) { + try { + int number = Integer.parseInt(input); + return new Number(number); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(ERROR_NOT_A_NUMBER); + } + } +} From d302d13b190ea54e610709f684187b6e3ecaa7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:22:41 +0900 Subject: [PATCH 19/67] =?UTF-8?q?feat(Number)=20:=20=EC=88=AB=EC=9E=90=20?= =?UTF-8?q?=EA=B0=92=EC=9D=84=20=ED=91=9C=ED=98=84=ED=95=98=EB=8A=94=20VO(?= =?UTF-8?q?Value=20Object)=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Number.java | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/Number.java diff --git a/src/main/java/Number.java b/src/main/java/Number.java new file mode 100644 index 00000000..5279235c --- /dev/null +++ b/src/main/java/Number.java @@ -0,0 +1,32 @@ +import java.util.Objects; + +public class Number { + + private final int value; + + public Number(int value) { + this.value = value; + } + + public int value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Number)) return false; + Number number = (Number) o; + return value == number.value; + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return String.valueOf(value); + } +} From 92c719082b426979a38ef02da26d331b289ddaba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:23:42 +0900 Subject: [PATCH 20/67] =?UTF-8?q?test(InputViewTest)=20:=20readInput=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90=20=EB=A7=9E=EA=B2=8C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/InputViewTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/InputViewTest.java b/src/test/java/InputViewTest.java index 1e843dbd..26fb34b0 100644 --- a/src/test/java/InputViewTest.java +++ b/src/test/java/InputViewTest.java @@ -19,10 +19,10 @@ void tearDown() { } @Test - @DisplayName("readNumber: 입력받은 문자열을 정수로 변환하여 반환한다.") - void readNumber() { + @DisplayName("readInput: 입력받은 문자열을 그대로 반환한다.") + void readInput() { System.setIn(new ByteArrayInputStream(INPUT.getBytes())); InputView inputView = new InputView(); - assertEquals(42, inputView.readNumber()); + assertEquals("42", inputView.readInput()); } } From 18281a9ab6686d30f60f82db659f9301d03adfaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:24:36 +0900 Subject: [PATCH 21/67] =?UTF-8?q?test(NumberParserTest)=20:=20=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EC=97=B4=20=ED=8C=8C=EC=8B=B1=20=EC=84=B1=EA=B3=B5=20?= =?UTF-8?q?=EB=B0=8F=20=EC=8B=A4=ED=8C=A8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/NumberParserTest.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/java/NumberParserTest.java diff --git a/src/test/java/NumberParserTest.java b/src/test/java/NumberParserTest.java new file mode 100644 index 00000000..4011f128 --- /dev/null +++ b/src/test/java/NumberParserTest.java @@ -0,0 +1,22 @@ +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@DisplayName("NumberParser Test") +class NumberParserTest { + + @Test + @DisplayName("정상 입력: 문자열을 정수로 변환하여 Number 객체를 반환한다.") + void parseValidInput() { + Number number = NumberParser.parse("42"); + assertEquals(new Number(42), number); + } + + @Test + @DisplayName("비정상 입력: 숫자가 아닌 문자열 입력 시 예외를 발생시킨다.") + void parseInvalidInput() { + assertThrows(IllegalArgumentException.class, () -> NumberParser.parse("abc")); + } +} From ad8e38f389adb593af751011a847ece65df159f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:25:37 +0900 Subject: [PATCH 22/67] =?UTF-8?q?test(NumberTest)=20:=20Number=20VO?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20value,=20equals=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/NumberTest.java | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/java/NumberTest.java diff --git a/src/test/java/NumberTest.java b/src/test/java/NumberTest.java new file mode 100644 index 00000000..df41e861 --- /dev/null +++ b/src/test/java/NumberTest.java @@ -0,0 +1,32 @@ +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +@DisplayName("Number Test") +class NumberTest { + + @Test + @DisplayName("value 메서드는 저장된 값을 반환한다.") + void valueMethodReturnsStoredValue() { + Number number = new Number(42); + assertEquals(42, number.value()); + } + + @Test + @DisplayName("동일한 값을 가진 Number 객체는 equals로 비교 시 같다.") + void numbersWithSameValueAreEqual() { + Number number1 = new Number(42); + Number number2 = new Number(42); + assertEquals(number1, number2); + } + + @Test + @DisplayName("다른 값을 가진 Number 객체는 equals로 비교 시 다르다.") + void numbersWithDifferentValuesAreNotEqual() { + Number number1 = new Number(42); + Number number2 = new Number(43); + assertNotEquals(number1, number2); + } +} From 30da163ba17b01f290ea0abef85f6df39e83e895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 00:34:44 +0900 Subject: [PATCH 23/67] =?UTF-8?q?docs(README)=20:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e32b81fd..690b384b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - [x] 메인 메서드는 만들지 않는다. # Step2 -- [ ] 구현한 초간단 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. -- [ ] 메인 메서드 없이 동작을 검증하는 경험을 해본다. -- [ ] 메인 메서드는 만들지 않는다. +- [x] 구현한 초간단 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. +- [x] 메인 메서드 없이 동작을 검증하는 경험을 해본다. +- [x] 메인 메서드는 만들지 않는다. From 112be7eb5de7fa67c96f39edd5c1917017a3fc9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 10:40:25 +0900 Subject: [PATCH 24/67] =?UTF-8?q?docs(README)=20:=20step3=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=B0=8F=20=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98?= =?UTF-8?q?=EB=B0=8D=20=EC=9A=94=EA=B5=AC=20=EC=82=AC=ED=95=AD=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 690b384b..71478ccf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,28 @@ -# 기능 요구 사항 +# 기능 및 프로그래밍 요구 사항 + +# Step3 +- [ ] 쉼표(`,`) 또는 콜론(`:`)을 구분자로 가지는 문자열을 전달하면, 구분자를 기준으로 분리한 숫자들의 합을 반환해야 한다. + - 예시: + - "" → 0 + - "1,2" → 3 + - "1,2,3" → 6 + - "1,2:3" → 6 +- [ ] 입력 문자열을 받아 처리해야 한다. +- [ ] 입력받은 문자열을 쉼표(`,`) 또는 콜론(`:`)을 기준으로 분리할 수 있어야 한다. +- [ ] 분리한 숫자들을 합산하여 반환해야 한다. +- [ ] 기본 구분자(쉼표, 콜론) 외에 **커스텀 구분자**를 지정할 수 있어야 한다. +- [ ] 커스텀 구분자는 문자열 앞부분 `"//"`와 `"\n"` 사이에 위치한 문자를 사용한다. + - 예시: + - "//;\n1;2;3" → 커스텀 구분자 `;` 사용 → 결과값 6 +- [ ] 문자열에 숫자가 아닌 값이나 음수가 포함되면 `RuntimeException`을 발생시켜야 한다. +- [ ] 구현한 문자열 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. +- [ ] 조금 더 복잡한 도메인을 대상으로 테스트를 작성하는 경험을 해본다. +- [ ] 메인 메서드는 만들지 않는다. + +# Step2 +- [x] 구현한 초간단 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. +- [x] 메인 메서드 없이 동작을 검증하는 경험을 해본다. +- [x] 메인 메서드는 만들지 않는다. # Step1 - [x] 인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다. @@ -6,8 +30,4 @@ - [x] 계산된 결과는 정수를 반환한다. - [x] 메인 메서드는 만들지 않는다. -# Step2 -- [x] 구현한 초간단 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. -- [x] 메인 메서드 없이 동작을 검증하는 경험을 해본다. -- [x] 메인 메서드는 만들지 않는다. From 7708187010f303f78e392691079dbb73f10a9e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 10:44:10 +0900 Subject: [PATCH 25/67] =?UTF-8?q?refactor(InputView)=20:=20readInput=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=EC=9D=84=20readExpression?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/InputView.java | 2 +- src/test/java/InputViewTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/InputView.java b/src/main/java/InputView.java index 4c8355a4..c79b557e 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/InputView.java @@ -4,7 +4,7 @@ public class InputView { private final Scanner scanner = new Scanner(System.in); - public String readInput() { + public String readExpression() { return scanner.nextLine(); } } \ No newline at end of file diff --git a/src/test/java/InputViewTest.java b/src/test/java/InputViewTest.java index 26fb34b0..aab8517e 100644 --- a/src/test/java/InputViewTest.java +++ b/src/test/java/InputViewTest.java @@ -20,9 +20,9 @@ void tearDown() { @Test @DisplayName("readInput: 입력받은 문자열을 그대로 반환한다.") - void readInput() { + void readExpression() { System.setIn(new ByteArrayInputStream(INPUT.getBytes())); InputView inputView = new InputView(); - assertEquals("42", inputView.readInput()); + assertEquals("42", inputView.readExpression()); } } From e9b2dd211bdf4b33350c1b7caa852e454ed44224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 10:44:30 +0900 Subject: [PATCH 26/67] =?UTF-8?q?docs(README)=20:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71478ccf..d9c0f9b1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - "1,2" → 3 - "1,2,3" → 6 - "1,2:3" → 6 -- [ ] 입력 문자열을 받아 처리해야 한다. +- [x] 입력 문자열을 받아 처리해야 한다. - [ ] 입력받은 문자열을 쉼표(`,`) 또는 콜론(`:`)을 기준으로 분리할 수 있어야 한다. - [ ] 분리한 숫자들을 합산하여 반환해야 한다. - [ ] 기본 구분자(쉼표, 콜론) 외에 **커스텀 구분자**를 지정할 수 있어야 한다. From 264d73a412df61b86704590cbb83a0206d6a11e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 10:53:19 +0900 Subject: [PATCH 27/67] =?UTF-8?q?feat(Delimiters)=20:=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=83=81=EC=88=98=ED=99=94=20?= =?UTF-8?q?=EB=B0=8F=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=EC=9E=90=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Delimiters.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/Delimiters.java diff --git a/src/main/java/Delimiters.java b/src/main/java/Delimiters.java new file mode 100644 index 00000000..b5e18c58 --- /dev/null +++ b/src/main/java/Delimiters.java @@ -0,0 +1,18 @@ +import java.util.ArrayList; +import java.util.List; + +public class Delimiters { + + private static final String COMMA = ","; + private static final String COLON = ":"; + private static final List DEFAULT_DELIMITERS = List.of(COMMA, COLON); + + private final List delimiters = new ArrayList<>(DEFAULT_DELIMITERS); + + public void addCustomDelimiters(String customDelimiters) { + if (customDelimiters == null || customDelimiters.isEmpty()) { + return; + } + delimiters.add(customDelimiters); + } +} \ No newline at end of file From 1197396786e60772c2f92f36d61c51dfbf845a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 10:57:56 +0900 Subject: [PATCH 28/67] =?UTF-8?q?docs(README)=20:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d9c0f9b1..04dfbcb2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 기능 및 프로그래밍 요구 사항 +**# 기능 및 프로그래밍 요구 사항 # Step3 - [ ] 쉼표(`,`) 또는 콜론(`:`)을 구분자로 가지는 문자열을 전달하면, 구분자를 기준으로 분리한 숫자들의 합을 반환해야 한다. @@ -10,7 +10,9 @@ - [x] 입력 문자열을 받아 처리해야 한다. - [ ] 입력받은 문자열을 쉼표(`,`) 또는 콜론(`:`)을 기준으로 분리할 수 있어야 한다. - [ ] 분리한 숫자들을 합산하여 반환해야 한다. -- [ ] 기본 구분자(쉼표, 콜론) 외에 **커스텀 구분자**를 지정할 수 있어야 한다. +- [x] 기본 구분자(쉼표, 콜론) 외에 **커스텀 구분자**를 지정할 수 있어야 한다. + - [x] 쉼표, 콜론은 기분 구분자이다. + - [x] 커스텀 구분자를 기본 구분자에 **추가 등록**할 수 있어야 한다. - [ ] 커스텀 구분자는 문자열 앞부분 `"//"`와 `"\n"` 사이에 위치한 문자를 사용한다. - 예시: - "//;\n1;2;3" → 커스텀 구분자 `;` 사용 → 결과값 6 @@ -28,6 +30,6 @@ - [x] 인자 2개를 받아 사칙연산을 할 수 있는 계산기를 구현한다. - [x] 사칙연산과 매칭되는 4개의 메서드를 제공한다. - [x] 계산된 결과는 정수를 반환한다. -- [x] 메인 메서드는 만들지 않는다. +- [x] 메인 메서드는 만들지 않는다.** From 5c51178aaab9f57ce2de31a22b7e8b48bcf7fc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:41:31 +0900 Subject: [PATCH 29/67] =?UTF-8?q?feat(Delimiters)=20:=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EB=93=B1=EB=A1=9D=EB=90=9C=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=EC=9E=90=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Delimiters.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/Delimiters.java b/src/main/java/Delimiters.java index b5e18c58..1b8d810e 100644 --- a/src/main/java/Delimiters.java +++ b/src/main/java/Delimiters.java @@ -9,10 +9,14 @@ public class Delimiters { private final List delimiters = new ArrayList<>(DEFAULT_DELIMITERS); - public void addCustomDelimiters(String customDelimiters) { - if (customDelimiters == null || customDelimiters.isEmpty()) { + public void addCustomDelimiters(String customDelimiter) { + if (customDelimiter == null || customDelimiter.isEmpty()) { return; } - delimiters.add(customDelimiters); + delimiters.add(customDelimiter); } -} \ No newline at end of file + + public List getDelimiters() { + return new ArrayList<>(delimiters); + } +} From f4b698de687ee5a6f722e4eb4af6ce095187fc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:41:58 +0900 Subject: [PATCH 30/67] =?UTF-8?q?test(DelimitersTest)=20:=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EB=B0=8F=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84?= =?UTF-8?q?=EC=9E=90=20=EC=B6=94=EA=B0=80=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/DelimitersTest.java | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/test/java/DelimitersTest.java diff --git a/src/test/java/DelimitersTest.java b/src/test/java/DelimitersTest.java new file mode 100644 index 00000000..e57632f9 --- /dev/null +++ b/src/test/java/DelimitersTest.java @@ -0,0 +1,37 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.List; + +class DelimitersTest { + + @Test + @DisplayName("기본 구분자가 등록되어 있어야 한다") + void 기본구분자등록_검증() { + Delimiters delimiters = new Delimiters(); + + List expected = List.of(",", ":"); + assertEquals(expected, delimiters.getDelimiters()); + } + + @Test + @DisplayName("커스텀 구분자를 추가할 수 있다") + void 커스텀구분자_추가() { + Delimiters delimiters = new Delimiters(); + delimiters.addCustomDelimiters(";"); + + List expected = List.of(",", ":", ";"); + assertEquals(expected, delimiters.getDelimiters()); + } + + @Test + @DisplayName("null 또는 빈 문자열을 추가해도 구분자가 추가되지 않는다") + void 커스텀구분자_null또는빈문자열() { + Delimiters delimiters = new Delimiters(); + delimiters.addCustomDelimiters(null); + delimiters.addCustomDelimiters(""); + + List expected = List.of(",", ":"); + assertEquals(expected, delimiters.getDelimiters()); + } +} From 43a73018bcd4d915c26c5b85b2118a046d80aa31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:54:56 +0900 Subject: [PATCH 31/67] =?UTF-8?q?feat(CustomDelimiterParser)=20:=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=20=EC=97=AC=EB=B6=80=20=ED=99=95=EC=9D=B8,?= =?UTF-8?q?=20=EA=B5=AC=EB=B6=84=EC=9E=90=20=EC=B6=94=EC=B6=9C,=20?= =?UTF-8?q?=EC=88=AB=EC=9E=90=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/CustomDelimiterParser.java | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/CustomDelimiterParser.java diff --git a/src/main/java/CustomDelimiterParser.java b/src/main/java/CustomDelimiterParser.java new file mode 100644 index 00000000..6e2b64b5 --- /dev/null +++ b/src/main/java/CustomDelimiterParser.java @@ -0,0 +1,28 @@ +public class CustomDelimiterParser { + + private static final String CUSTOM_DELIMITER_PREFIX = "//"; + private static final String CUSTOM_DELIMITER_SUFFIX = "\n"; + private static final int CUSTOM_DELIMITER_PREFIX_LENGTH = CUSTOM_DELIMITER_PREFIX.length(); + private static final String ERROR_INVALID_CUSTOM_DELIMITER_FORMAT = "[ERROR] 커스텀 구분자 형식이 잘못되었습니다."; + + public boolean hasCustomDelimiter(String expression) { + return expression.startsWith(CUSTOM_DELIMITER_PREFIX); + } + + public String parseCustomDelimiter(String expression) { + validate(expression); + int delimiterEndIndex = expression.indexOf(CUSTOM_DELIMITER_SUFFIX); + return expression.substring(CUSTOM_DELIMITER_PREFIX_LENGTH, delimiterEndIndex); + } + + public String parseNumbersExpression(String expression) { + int delimiterEndIndex = expression.indexOf(CUSTOM_DELIMITER_SUFFIX); + return expression.substring(delimiterEndIndex + 1); + } + + private void validate(String expression) { + if (!expression.contains(CUSTOM_DELIMITER_SUFFIX)) { + throw new IllegalArgumentException(ERROR_INVALID_CUSTOM_DELIMITER_FORMAT); + } + } +} From 3cae3164258afe6700313c7b2508f4814344d659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:55:26 +0900 Subject: [PATCH 32/67] =?UTF-8?q?test(CustomDelimiterParserTest)=20:=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=20=EA=B8=B0=EB=8A=A5=20=EB=8B=A8=EC=9C=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/CustomDelimiterParserTest.java | 56 ++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/test/java/CustomDelimiterParserTest.java diff --git a/src/test/java/CustomDelimiterParserTest.java b/src/test/java/CustomDelimiterParserTest.java new file mode 100644 index 00000000..e78d3fb0 --- /dev/null +++ b/src/test/java/CustomDelimiterParserTest.java @@ -0,0 +1,56 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CustomDelimiterParserTest { + + private final CustomDelimiterParser parser = new CustomDelimiterParser(); + + @Test + @DisplayName("문자열이 커스텀 구분자 형식을 가지면 true를 반환한다") + void hasCustomDelimiter_true() { + String expression = "//;\n1;2;3"; + + assertTrue(parser.hasCustomDelimiter(expression)); + } + + @Test + @DisplayName("문자열이 커스텀 구분자 형식을 가지지 않으면 false를 반환한다") + void hasCustomDelimiter_false() { + String expression = "1,2:3"; + + assertFalse(parser.hasCustomDelimiter(expression)); + } + + @Test + @DisplayName("커스텀 구분자를 정상적으로 파싱한다") + void parseCustomDelimiter_success() { + String expression = "//;\n1;2;3"; + + String customDelimiter = parser.parseCustomDelimiter(expression); + + assertEquals(";", customDelimiter); + } + + @Test + @DisplayName("커스텀 구분자 파싱 시 형식이 잘못되면 예외를 던진다") + void parseCustomDelimiter_invalidFormat() { + String invalidExpression = "//;1;2;3"; + + assertThrows(IllegalArgumentException.class, () -> parser.parseCustomDelimiter(invalidExpression)); + } + + @Test + @DisplayName("숫자 문자열을 정상적으로 파싱한다") + void parseNumbersExpression_success() { + String expression = "//;\n1;2;3"; + + String numbers = parser.parseNumbersExpression(expression); + + assertEquals("1;2;3", numbers); + } +} From 06f5f7c5aaec5514541aa212e3cdea85d4af6524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:57:03 +0900 Subject: [PATCH 33/67] =?UTF-8?q?feat(CustomDelimiterRegister)=20:=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90?= =?UTF-8?q?=EB=A5=BC=20=EB=93=B1=EB=A1=9D=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/CustomDelimiterRegister.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/CustomDelimiterRegister.java diff --git a/src/main/java/CustomDelimiterRegister.java b/src/main/java/CustomDelimiterRegister.java new file mode 100644 index 00000000..8639fd78 --- /dev/null +++ b/src/main/java/CustomDelimiterRegister.java @@ -0,0 +1,12 @@ +public class CustomDelimiterRegister { + + private final Delimiters delimiters; + + public CustomDelimiterRegister(Delimiters delimiters) { + this.delimiters = delimiters; + } + + public void register(String customDelimiter) { + delimiters.addCustomDelimiters(customDelimiter); + } +} From 3fcf1a51b82be2499d19186bcc8f85e62947a072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:57:14 +0900 Subject: [PATCH 34/67] =?UTF-8?q?test(CustomDelimiterRegisterTest)=20:=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/CustomDelimiterRegisterTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/java/CustomDelimiterRegisterTest.java diff --git a/src/test/java/CustomDelimiterRegisterTest.java b/src/test/java/CustomDelimiterRegisterTest.java new file mode 100644 index 00000000..29c99077 --- /dev/null +++ b/src/test/java/CustomDelimiterRegisterTest.java @@ -0,0 +1,24 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +class CustomDelimiterRegisterTest { + + @Test + @DisplayName("커스텀 구분자를 등록할 수 있다") + void 커스텀구분자_등록() { + // given + Delimiters delimiters = new Delimiters(); + CustomDelimiterRegister register = new CustomDelimiterRegister(delimiters); + + // when + register.register(";"); + + // then + List expected = List.of(",", ":", ";"); + assertEquals(expected, delimiters.getDelimiters()); + } +} From dc457d4a7cf62da583d9a7685862305f6341c2bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 15:59:08 +0900 Subject: [PATCH 35/67] =?UTF-8?q?docs(README)=20:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 04dfbcb2..17edcabc 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,9 @@ - [ ] 입력받은 문자열을 쉼표(`,`) 또는 콜론(`:`)을 기준으로 분리할 수 있어야 한다. - [ ] 분리한 숫자들을 합산하여 반환해야 한다. - [x] 기본 구분자(쉼표, 콜론) 외에 **커스텀 구분자**를 지정할 수 있어야 한다. - - [x] 쉼표, 콜론은 기분 구분자이다. - - [x] 커스텀 구분자를 기본 구분자에 **추가 등록**할 수 있어야 한다. -- [ ] 커스텀 구분자는 문자열 앞부분 `"//"`와 `"\n"` 사이에 위치한 문자를 사용한다. - - 예시: - - "//;\n1;2;3" → 커스텀 구분자 `;` 사용 → 결과값 6 + - [x] 쉼표, 콜론은 기본 구분자이다. + - [x] 커스텀 구분자를 기본 구분자에 **추가 등록**할 수 있어야 한다. + - [x] 커스텀 구분자는 문자열 앞부분 `"//"`와 `"\n"` 사이에 위치한 문자를 추출하여 등록할 수 있어야 한다. - [ ] 문자열에 숫자가 아닌 값이나 음수가 포함되면 `RuntimeException`을 발생시켜야 한다. - [ ] 구현한 문자열 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. - [ ] 조금 더 복잡한 도메인을 대상으로 테스트를 작성하는 경험을 해본다. From 399f22160a7767f8d4b790a5811405789635ceae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:18:35 +0900 Subject: [PATCH 36/67] =?UTF-8?q?feat(ExpressionSplitter)=20:=20=EA=B5=AC?= =?UTF-8?q?=EB=B6=84=EC=9E=90=EB=A5=BC=20=EA=B8=B0=EC=A4=80=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=AC=B8=EC=9E=90=EC=97=B4=EC=9D=84=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ExpressionSplitter.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/ExpressionSplitter.java diff --git a/src/main/java/ExpressionSplitter.java b/src/main/java/ExpressionSplitter.java new file mode 100644 index 00000000..b29a9aec --- /dev/null +++ b/src/main/java/ExpressionSplitter.java @@ -0,0 +1,16 @@ +import java.util.List; + +public class ExpressionSplitter { + + private final Delimiters delimiters; + + public ExpressionSplitter(Delimiters delimiters) { + this.delimiters = delimiters; + } + + public String[] split(String expression) { + List delimiterList = delimiters.getDelimiters(); + String regex = String.join("|", delimiterList); + return expression.split(regex); + } +} From 12a0e4fc1613c13864369d6513476649bd734f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:18:48 +0900 Subject: [PATCH 37/67] =?UTF-8?q?test(ExpressionSplitterTest)=20:=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EA=B5=AC=EB=B6=84=EC=9E=90=EC=99=80=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EA=B5=AC=EB=B6=84=EC=9E=90?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/ExpressionSplitterTest.java | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/test/java/ExpressionSplitterTest.java diff --git a/src/test/java/ExpressionSplitterTest.java b/src/test/java/ExpressionSplitterTest.java new file mode 100644 index 00000000..7dedb106 --- /dev/null +++ b/src/test/java/ExpressionSplitterTest.java @@ -0,0 +1,52 @@ +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ExpressionSplitterTest { + + @Test + @DisplayName("기본 구분자(쉼표, 콜론)로 문자열을 분리한다") + void 기본구분자_분리() { + // given + Delimiters delimiters = new Delimiters(); + ExpressionSplitter splitter = new ExpressionSplitter(delimiters); + String expression = "1,2:3"; + + // when + String[] result = splitter.split(expression); + + // then + assertArrayEquals(new String[]{"1", "2", "3"}, result); + } + + @Test + @DisplayName("커스텀 구분자가 추가된 경우 문자열을 분리한다") + void 커스텀구분자_추가후_분리() { + // given + Delimiters delimiters = new Delimiters(); + delimiters.addCustomDelimiters(";"); + ExpressionSplitter splitter = new ExpressionSplitter(delimiters); + String expression = "1;2,3:4"; + + // when + String[] result = splitter.split(expression); + + // then + assertArrayEquals(new String[]{"1", "2", "3", "4"}, result); + } + + @Test + @DisplayName("빈 문자열을 분리하면 빈 배열을 반환한다") + void 빈문자열_분리() { + // given + Delimiters delimiters = new Delimiters(); + ExpressionSplitter splitter = new ExpressionSplitter(delimiters); + String expression = ""; + + // when + String[] result = splitter.split(expression); + + // then + assertArrayEquals(new String[]{""}, result); + } +} From 4fae504401206fdbef1046b5210955965f1ea717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:22:48 +0900 Subject: [PATCH 38/67] =?UTF-8?q?refactor(ExpressionSplitter)=20:=20split?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B0=98=ED=99=98=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=9D=84=20String=20=EB=B0=B0=EC=97=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20List=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ExpressionSplitter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/ExpressionSplitter.java b/src/main/java/ExpressionSplitter.java index b29a9aec..0b323711 100644 --- a/src/main/java/ExpressionSplitter.java +++ b/src/main/java/ExpressionSplitter.java @@ -1,3 +1,4 @@ +import java.util.Arrays; import java.util.List; public class ExpressionSplitter { @@ -8,9 +9,9 @@ public ExpressionSplitter(Delimiters delimiters) { this.delimiters = delimiters; } - public String[] split(String expression) { + public List split(String expression) { List delimiterList = delimiters.getDelimiters(); String regex = String.join("|", delimiterList); - return expression.split(regex); + return Arrays.asList(expression.split(regex)); } } From 541702d13c54816b4a1eb0d88855502d5a67d070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:23:33 +0900 Subject: [PATCH 39/67] =?UTF-8?q?refactor(ExpressionSplitterTest)=20:=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EC=B6=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20List=20=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/ExpressionSplitterTest.java | 25 +++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/test/java/ExpressionSplitterTest.java b/src/test/java/ExpressionSplitterTest.java index 7dedb106..8c05e49e 100644 --- a/src/test/java/ExpressionSplitterTest.java +++ b/src/test/java/ExpressionSplitterTest.java @@ -1,27 +1,30 @@ -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.List; + class ExpressionSplitterTest { @Test @DisplayName("기본 구분자(쉼표, 콜론)로 문자열을 분리한다") - void 기본구분자_분리() { + void splitByDefaultDelimiters() { // given Delimiters delimiters = new Delimiters(); ExpressionSplitter splitter = new ExpressionSplitter(delimiters); String expression = "1,2:3"; // when - String[] result = splitter.split(expression); + List result = splitter.split(expression); // then - assertArrayEquals(new String[]{"1", "2", "3"}, result); + assertEquals(List.of("1", "2", "3"), result); } @Test @DisplayName("커스텀 구분자가 추가된 경우 문자열을 분리한다") - void 커스텀구분자_추가후_분리() { + void splitByCustomDelimiter() { // given Delimiters delimiters = new Delimiters(); delimiters.addCustomDelimiters(";"); @@ -29,24 +32,24 @@ class ExpressionSplitterTest { String expression = "1;2,3:4"; // when - String[] result = splitter.split(expression); + List result = splitter.split(expression); // then - assertArrayEquals(new String[]{"1", "2", "3", "4"}, result); + assertEquals(List.of("1", "2", "3", "4"), result); } @Test - @DisplayName("빈 문자열을 분리하면 빈 배열을 반환한다") - void 빈문자열_분리() { + @DisplayName("빈 문자열을 분리하면 빈 리스트를 반환한다") + void splitEmptyString() { // given Delimiters delimiters = new Delimiters(); ExpressionSplitter splitter = new ExpressionSplitter(delimiters); String expression = ""; // when - String[] result = splitter.split(expression); + List result = splitter.split(expression); // then - assertArrayEquals(new String[]{""}, result); + assertEquals(List.of(""), result); } } From 40d57c250159cea201a2873dc51b331367c41b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:25:52 +0900 Subject: [PATCH 40/67] =?UTF-8?q?feat(NumberTokens)=20:=20List?= =?UTF-8?q?=EC=9D=84=20=EC=9E=85=EB=A0=A5=EC=9C=BC=EB=A1=9C=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=20=EC=88=AB=EC=9E=90=EB=A5=BC=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=ED=95=A9=EC=82=B0=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/NumberTokens.java | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/NumberTokens.java diff --git a/src/main/java/NumberTokens.java b/src/main/java/NumberTokens.java new file mode 100644 index 00000000..20a9227d --- /dev/null +++ b/src/main/java/NumberTokens.java @@ -0,0 +1,30 @@ +import java.util.List; +import java.util.stream.Collectors; + +public class NumberTokens { + + private static final String ERROR_NEGATIVE_NUMBER = "[ERROR] 음수는 입력할 수 없습니다."; + + private final List numbers; + + public NumberTokens(List tokens) { + this.numbers = tokens.stream() + .map(NumberParser::parse) + .collect(Collectors.toList()); + validateNoNegative(); + } + + private void validateNoNegative() { + for (Number number : numbers) { + if (number.value() < 0) { + throw new IllegalArgumentException(ERROR_NEGATIVE_NUMBER); + } + } + } + + public int sum() { + return numbers.stream() + .mapToInt(Number::value) + .sum(); + } +} \ No newline at end of file From 56875811cf8671856926e36d3d1829ffd58774d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:28:23 +0900 Subject: [PATCH 41/67] =?UTF-8?q?test(NumberTokensTest)=20:=20List?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=EC=9D=84=20=EA=B8=B0=EB=B0=98=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=88=AB=EC=9E=90=20=ED=95=A9=EC=82=B0=20=EB=B0=8F?= =?UTF-8?q?=20=EC=9D=8C=EC=88=98=20=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/NumberTokensTest.java | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/test/java/NumberTokensTest.java diff --git a/src/test/java/NumberTokensTest.java b/src/test/java/NumberTokensTest.java new file mode 100644 index 00000000..2aaac6f8 --- /dev/null +++ b/src/test/java/NumberTokensTest.java @@ -0,0 +1,46 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +class NumberTokensTest { + + @Test + @DisplayName("숫자 문자열 리스트를 합산한다") + void sumNumbers_success() { + // given + List tokens = List.of("1", "2", "3"); + + // when + NumberTokens numberTokens = new NumberTokens(tokens); + + // then + assertEquals(6, numberTokens.sum()); + } + + @Test + @DisplayName("음수가 포함된 경우 예외를 던진다") + void throwException_whenNegativeNumberExists() { + // given + List tokens = List.of("1", "-2", "3"); + + // when & then + assertThrows(IllegalArgumentException.class, () -> new NumberTokens(tokens)); + } + + @Test + @DisplayName("빈 리스트가 주어지면 합은 0이다") + void sumZero_whenEmptyList() { + // given + List tokens = List.of(); + + // when + NumberTokens numberTokens = new NumberTokens(tokens); + + // then + assertEquals(0, numberTokens.sum()); + } +} From c45a3348f14b39596353774a76fc040576869c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:32:10 +0900 Subject: [PATCH 42/67] =?UTF-8?q?feat(StringCalculator)=20:=20calculateSum?= =?UTF-8?q?=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=8D=A7=EC=85=88=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/StringCalculator.java | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/main/java/StringCalculator.java diff --git a/src/main/java/StringCalculator.java b/src/main/java/StringCalculator.java new file mode 100644 index 00000000..c4794b62 --- /dev/null +++ b/src/main/java/StringCalculator.java @@ -0,0 +1,53 @@ +import java.util.List; + +public class StringCalculator { + + private final Delimiters delimiters; + private final CustomDelimiterParser parser; + private final CustomDelimiterRegister register; + private final ExpressionSplitter splitter; + + public StringCalculator() { + this.delimiters = new Delimiters(); + this.parser = new CustomDelimiterParser(); + this.register = new CustomDelimiterRegister(delimiters); + this.splitter = new ExpressionSplitter(delimiters); + } + + public int calculateSum(String expression) { + if (isEmpty(expression)) { + return 0; + } + + String numbersExpression = extractNumbersExpression(expression); + List tokens = splitNumbers(numbersExpression); + NumberTokens numberTokens = new NumberTokens(tokens); + + return numberTokens.sum(); + } + + private boolean isEmpty(String expression) { + return expression == null || expression.isEmpty(); + } + + private String extractNumbersExpression(String expression) { + if (parser.hasCustomDelimiter(expression)) { + registerCustomDelimiter(expression); + return extractPureNumbers(expression); + } + return expression; + } + + private void registerCustomDelimiter(String expression) { + String customDelimiter = parser.parseCustomDelimiter(expression); + register.register(customDelimiter); + } + + private String extractPureNumbers(String expression) { + return parser.parseNumbersExpression(expression); + } + + private List splitNumbers(String numbersExpression) { + return splitter.split(numbersExpression); + } +} From 1db605beeecd760a7f641e2cffa149fc2969abaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:32:33 +0900 Subject: [PATCH 43/67] =?UTF-8?q?test(StringCalculatorTest)=20:=20calculat?= =?UTF-8?q?eSum=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=EC=A0=95=EC=83=81=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/StringCalculatorTest.java | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/test/java/StringCalculatorTest.java diff --git a/src/test/java/StringCalculatorTest.java b/src/test/java/StringCalculatorTest.java new file mode 100644 index 00000000..36da13fc --- /dev/null +++ b/src/test/java/StringCalculatorTest.java @@ -0,0 +1,39 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class StringCalculatorTest { + + private final StringCalculator calculator = new StringCalculator(); + + @Test + @DisplayName("빈 문자열 또는 null 입력 시 결과는 0이다") + void returnZero_whenInputIsEmptyOrNull() { + // when & then + assertEquals(0, calculator.calculateSum("")); + assertEquals(0, calculator.calculateSum(null)); + } + + @Test + @DisplayName("쉼표 또는 콜론 구분자로 구분된 숫자를 합산한다") + void sumNumbers_whenDefaultDelimiters() { + // when & then + assertEquals(6, calculator.calculateSum("1,2:3")); + } + + @Test + @DisplayName("커스텀 구분자가 지정된 경우 해당 구분자로 숫자를 합산한다") + void sumNumbers_whenCustomDelimiter() { + // when & then + assertEquals(6, calculator.calculateSum("//;\n1;2;3")); + } + + @Test + @DisplayName("음수가 포함된 경우 예외를 던진다") + void throwException_whenNegativeNumberExists() { + // when & then + assertThrows(IllegalArgumentException.class, () -> calculator.calculateSum("1,-2,3")); + } +} From 2c41e59478906b5c65b9297fe1730453e6d5a302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:52:50 +0900 Subject: [PATCH 44/67] =?UTF-8?q?docs(README)=20:=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 17edcabc..5687d185 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,24 @@ -**# 기능 및 프로그래밍 요구 사항 +# 기능 및 프로그래밍 요구 사항 # Step3 -- [ ] 쉼표(`,`) 또는 콜론(`:`)을 구분자로 가지는 문자열을 전달하면, 구분자를 기준으로 분리한 숫자들의 합을 반환해야 한다. +- [x] 쉼표(`,`) 또는 콜론(`:`)을 구분자로 가지는 문자열을 전달하면, 구분자를 기준으로 분리한 숫자들의 합을 반환해야 한다. - 예시: - "" → 0 - "1,2" → 3 - "1,2,3" → 6 - "1,2:3" → 6 - [x] 입력 문자열을 받아 처리해야 한다. -- [ ] 입력받은 문자열을 쉼표(`,`) 또는 콜론(`:`)을 기준으로 분리할 수 있어야 한다. -- [ ] 분리한 숫자들을 합산하여 반환해야 한다. +- [x] 입력받은 문자열을 쉼표(`,`) 또는 콜론(`:`)을 기준으로 분리할 수 있어야 한다. +- [x] 분리한 숫자들을 합산하여 반환해야 한다. - [x] 기본 구분자(쉼표, 콜론) 외에 **커스텀 구분자**를 지정할 수 있어야 한다. - [x] 쉼표, 콜론은 기본 구분자이다. - [x] 커스텀 구분자를 기본 구분자에 **추가 등록**할 수 있어야 한다. - [x] 커스텀 구분자는 문자열 앞부분 `"//"`와 `"\n"` 사이에 위치한 문자를 추출하여 등록할 수 있어야 한다. -- [ ] 문자열에 숫자가 아닌 값이나 음수가 포함되면 `RuntimeException`을 발생시켜야 한다. -- [ ] 구현한 문자열 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. -- [ ] 조금 더 복잡한 도메인을 대상으로 테스트를 작성하는 경험을 해본다. -- [ ] 메인 메서드는 만들지 않는다. +- [x] 문자열에 숫자가 아닌 값이나 음수가 포함되면 `RuntimeException`을 발생시켜야 한다. +- [x] 구현한 문자열 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. +- [x] 조금 더 복잡한 도메인을 대상으로 테스트를 작성하는 경험을 해본다. +- [x] 메인 메서드는 만들지 않는다. + # Step2 - [x] 구현한 초간단 계산기가 예상한대로 동작하는지 Junit5를 활용하여 테스트를 자동화한다. From 3776796687c9f7be079d5f91eacc56a946f91aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:54:57 +0900 Subject: [PATCH 45/67] =?UTF-8?q?refactor(utils):=20splitter,=20parser?= =?UTF-8?q?=EB=A5=BC=20utils=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=ED=95=98=EC=97=AC=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/{ => utils}/CustomDelimiterParser.java | 2 ++ src/main/java/{ => utils}/ExpressionSplitter.java | 4 ++++ src/main/java/{ => utils}/NumberParser.java | 4 ++++ src/test/java/{ => utils}/CustomDelimiterParserTest.java | 2 ++ src/test/java/{ => utils}/ExpressionSplitterTest.java | 3 +++ src/test/java/{ => utils}/NumberParserTest.java | 7 +++++-- 6 files changed, 20 insertions(+), 2 deletions(-) rename src/main/java/{ => utils}/CustomDelimiterParser.java (98%) rename src/main/java/{ => utils}/ExpressionSplitter.java (91%) rename src/main/java/{ => utils}/NumberParser.java (91%) rename src/test/java/{ => utils}/CustomDelimiterParserTest.java (99%) rename src/test/java/{ => utils}/ExpressionSplitterTest.java (97%) rename src/test/java/{ => utils}/NumberParserTest.java (84%) diff --git a/src/main/java/CustomDelimiterParser.java b/src/main/java/utils/CustomDelimiterParser.java similarity index 98% rename from src/main/java/CustomDelimiterParser.java rename to src/main/java/utils/CustomDelimiterParser.java index 6e2b64b5..61bae072 100644 --- a/src/main/java/CustomDelimiterParser.java +++ b/src/main/java/utils/CustomDelimiterParser.java @@ -1,3 +1,5 @@ +package utils; + public class CustomDelimiterParser { private static final String CUSTOM_DELIMITER_PREFIX = "//"; diff --git a/src/main/java/ExpressionSplitter.java b/src/main/java/utils/ExpressionSplitter.java similarity index 91% rename from src/main/java/ExpressionSplitter.java rename to src/main/java/utils/ExpressionSplitter.java index 0b323711..16d5b0e7 100644 --- a/src/main/java/ExpressionSplitter.java +++ b/src/main/java/utils/ExpressionSplitter.java @@ -1,3 +1,7 @@ +package utils; + +import domain.Delimiters; + import java.util.Arrays; import java.util.List; diff --git a/src/main/java/NumberParser.java b/src/main/java/utils/NumberParser.java similarity index 91% rename from src/main/java/NumberParser.java rename to src/main/java/utils/NumberParser.java index 6f92ee36..2f32090a 100644 --- a/src/main/java/NumberParser.java +++ b/src/main/java/utils/NumberParser.java @@ -1,3 +1,7 @@ +package utils; + +import domain.Number; + public class NumberParser { private static final String ERROR_NOT_A_NUMBER = "[ERROR] 입력은 숫자여야 합니다."; diff --git a/src/test/java/CustomDelimiterParserTest.java b/src/test/java/utils/CustomDelimiterParserTest.java similarity index 99% rename from src/test/java/CustomDelimiterParserTest.java rename to src/test/java/utils/CustomDelimiterParserTest.java index e78d3fb0..e99568f3 100644 --- a/src/test/java/CustomDelimiterParserTest.java +++ b/src/test/java/utils/CustomDelimiterParserTest.java @@ -1,3 +1,5 @@ +package utils; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertFalse; diff --git a/src/test/java/ExpressionSplitterTest.java b/src/test/java/utils/ExpressionSplitterTest.java similarity index 97% rename from src/test/java/ExpressionSplitterTest.java rename to src/test/java/utils/ExpressionSplitterTest.java index 8c05e49e..34d61fa2 100644 --- a/src/test/java/ExpressionSplitterTest.java +++ b/src/test/java/utils/ExpressionSplitterTest.java @@ -1,5 +1,8 @@ +package utils; + import static org.junit.jupiter.api.Assertions.assertEquals; +import domain.Delimiters; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/NumberParserTest.java b/src/test/java/utils/NumberParserTest.java similarity index 84% rename from src/test/java/NumberParserTest.java rename to src/test/java/utils/NumberParserTest.java index 4011f128..f04e0cb4 100644 --- a/src/test/java/NumberParserTest.java +++ b/src/test/java/utils/NumberParserTest.java @@ -1,14 +1,17 @@ +package utils; + +import domain.Number; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -@DisplayName("NumberParser Test") +@DisplayName("parser.NumberParser Test") class NumberParserTest { @Test - @DisplayName("정상 입력: 문자열을 정수로 변환하여 Number 객체를 반환한다.") + @DisplayName("정상 입력: 문자열을 정수로 변환하여 domain.Number 객체를 반환한다.") void parseValidInput() { Number number = NumberParser.parse("42"); assertEquals(new Number(42), number); From 6c1a374c350ed1c4343d7fd21fd8eee1807ce5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:56:03 +0900 Subject: [PATCH 46/67] =?UTF-8?q?refactor(view):=20InputView,=20OutputView?= =?UTF-8?q?=EB=A5=BC=20view=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=ED=95=98=EC=97=AC=20=EC=9E=85=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/{ => view}/InputView.java | 2 ++ src/main/java/{ => view}/OutputView.java | 2 ++ src/test/java/{ => view}/InputViewTest.java | 4 +++- src/test/java/{ => view}/OutputViewTest.java | 4 +++- 4 files changed, 10 insertions(+), 2 deletions(-) rename src/main/java/{ => view}/InputView.java (92%) rename src/main/java/{ => view}/OutputView.java (97%) rename src/test/java/{ => view}/InputViewTest.java (93%) rename src/test/java/{ => view}/OutputViewTest.java (96%) diff --git a/src/main/java/InputView.java b/src/main/java/view/InputView.java similarity index 92% rename from src/main/java/InputView.java rename to src/main/java/view/InputView.java index c79b557e..bdba2664 100644 --- a/src/main/java/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,3 +1,5 @@ +package view; + import java.util.Scanner; public class InputView { diff --git a/src/main/java/OutputView.java b/src/main/java/view/OutputView.java similarity index 97% rename from src/main/java/OutputView.java rename to src/main/java/view/OutputView.java index f65713ad..f97eb73a 100644 --- a/src/main/java/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,3 +1,5 @@ +package view; + public class OutputView { static final String FIRST_NUMBER_PROMPT = "첫 번째 숫자를 입력하세요: "; diff --git a/src/test/java/InputViewTest.java b/src/test/java/view/InputViewTest.java similarity index 93% rename from src/test/java/InputViewTest.java rename to src/test/java/view/InputViewTest.java index aab8517e..d4e0827d 100644 --- a/src/test/java/InputViewTest.java +++ b/src/test/java/view/InputViewTest.java @@ -1,3 +1,5 @@ +package view; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -7,7 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -@DisplayName("InputView Test") +@DisplayName("view.InputView Test") class InputViewTest { private static final String INPUT = "42\n"; diff --git a/src/test/java/OutputViewTest.java b/src/test/java/view/OutputViewTest.java similarity index 96% rename from src/test/java/OutputViewTest.java rename to src/test/java/view/OutputViewTest.java index ccd323d4..c5388ca3 100644 --- a/src/test/java/OutputViewTest.java +++ b/src/test/java/view/OutputViewTest.java @@ -1,3 +1,5 @@ +package view; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -8,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -@DisplayName("OutputView Test") +@DisplayName("view.OutputView Test") class OutputViewTest { private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); From 53fc2e462afb2c182c74a87696ccaba1769e0433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 16:57:02 +0900 Subject: [PATCH 47/67] =?UTF-8?q?refactor(domain):=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B4=80=EB=A0=A8=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20domain=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=ED=95=98=EC=97=AC=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/{ => domain}/Calculator.java | 2 ++ src/main/java/{ => domain}/CustomDelimiterRegister.java | 2 ++ src/main/java/{ => domain}/Delimiters.java | 2 ++ src/main/java/{ => domain}/Number.java | 2 ++ src/main/java/{ => domain}/NumberTokens.java | 8 ++++++-- src/main/java/{ => domain}/StringCalculator.java | 5 +++++ src/test/java/{ => domain}/CalculatorTest.java | 4 +++- .../java/{ => domain}/CustomDelimiterRegisterTest.java | 2 ++ src/test/java/{ => domain}/DelimitersTest.java | 3 +++ src/test/java/{ => domain}/NumberTest.java | 8 +++++--- src/test/java/{ => domain}/NumberTokensTest.java | 2 ++ src/test/java/{ => domain}/StringCalculatorTest.java | 2 ++ 12 files changed, 36 insertions(+), 6 deletions(-) rename src/main/java/{ => domain}/Calculator.java (97%) rename src/main/java/{ => domain}/CustomDelimiterRegister.java (94%) rename src/main/java/{ => domain}/Delimiters.java (97%) rename src/main/java/{ => domain}/Number.java (97%) rename src/main/java/{ => domain}/NumberTokens.java (84%) rename src/main/java/{ => domain}/StringCalculator.java (95%) rename src/test/java/{ => domain}/CalculatorTest.java (97%) rename src/test/java/{ => domain}/CustomDelimiterRegisterTest.java (97%) rename src/test/java/{ => domain}/DelimitersTest.java (98%) rename src/test/java/{ => domain}/NumberTest.java (76%) rename src/test/java/{ => domain}/NumberTokensTest.java (98%) rename src/test/java/{ => domain}/StringCalculatorTest.java (98%) diff --git a/src/main/java/Calculator.java b/src/main/java/domain/Calculator.java similarity index 97% rename from src/main/java/Calculator.java rename to src/main/java/domain/Calculator.java index 3935e16f..a6dd6e6a 100644 --- a/src/main/java/Calculator.java +++ b/src/main/java/domain/Calculator.java @@ -1,3 +1,5 @@ +package domain; + public class Calculator { private static final String DIVIDE_BY_ZERO_ERROR_MESSAGE = "[ERROR] 0으로 나눌 수 없습니다."; diff --git a/src/main/java/CustomDelimiterRegister.java b/src/main/java/domain/CustomDelimiterRegister.java similarity index 94% rename from src/main/java/CustomDelimiterRegister.java rename to src/main/java/domain/CustomDelimiterRegister.java index 8639fd78..21c812d1 100644 --- a/src/main/java/CustomDelimiterRegister.java +++ b/src/main/java/domain/CustomDelimiterRegister.java @@ -1,3 +1,5 @@ +package domain; + public class CustomDelimiterRegister { private final Delimiters delimiters; diff --git a/src/main/java/Delimiters.java b/src/main/java/domain/Delimiters.java similarity index 97% rename from src/main/java/Delimiters.java rename to src/main/java/domain/Delimiters.java index 1b8d810e..a13157f2 100644 --- a/src/main/java/Delimiters.java +++ b/src/main/java/domain/Delimiters.java @@ -1,3 +1,5 @@ +package domain; + import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/Number.java b/src/main/java/domain/Number.java similarity index 97% rename from src/main/java/Number.java rename to src/main/java/domain/Number.java index 5279235c..3e12ea19 100644 --- a/src/main/java/Number.java +++ b/src/main/java/domain/Number.java @@ -1,3 +1,5 @@ +package domain; + import java.util.Objects; public class Number { diff --git a/src/main/java/NumberTokens.java b/src/main/java/domain/NumberTokens.java similarity index 84% rename from src/main/java/NumberTokens.java rename to src/main/java/domain/NumberTokens.java index 20a9227d..884d92a5 100644 --- a/src/main/java/NumberTokens.java +++ b/src/main/java/domain/NumberTokens.java @@ -1,3 +1,7 @@ +package domain; + +import utils.NumberParser; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -10,7 +14,7 @@ public class NumberTokens { public NumberTokens(List tokens) { this.numbers = tokens.stream() .map(NumberParser::parse) - .collect(Collectors.toList()); + .collect(Collectors.toCollection(ArrayList::new)); validateNoNegative(); } @@ -27,4 +31,4 @@ public int sum() { .mapToInt(Number::value) .sum(); } -} \ No newline at end of file +} diff --git a/src/main/java/StringCalculator.java b/src/main/java/domain/StringCalculator.java similarity index 95% rename from src/main/java/StringCalculator.java rename to src/main/java/domain/StringCalculator.java index c4794b62..432fa494 100644 --- a/src/main/java/StringCalculator.java +++ b/src/main/java/domain/StringCalculator.java @@ -1,3 +1,8 @@ +package domain; + +import utils.CustomDelimiterParser; +import utils.ExpressionSplitter; + import java.util.List; public class StringCalculator { diff --git a/src/test/java/CalculatorTest.java b/src/test/java/domain/CalculatorTest.java similarity index 97% rename from src/test/java/CalculatorTest.java rename to src/test/java/domain/CalculatorTest.java index e90ca200..6045f7b2 100644 --- a/src/test/java/CalculatorTest.java +++ b/src/test/java/domain/CalculatorTest.java @@ -1,3 +1,5 @@ +package domain; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -6,7 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; -@DisplayName("Calculator Test") +@DisplayName("domain.Calculator Test") class CalculatorTest { private final Calculator calculator = new Calculator(); diff --git a/src/test/java/CustomDelimiterRegisterTest.java b/src/test/java/domain/CustomDelimiterRegisterTest.java similarity index 97% rename from src/test/java/CustomDelimiterRegisterTest.java rename to src/test/java/domain/CustomDelimiterRegisterTest.java index 29c99077..b94d5de6 100644 --- a/src/test/java/CustomDelimiterRegisterTest.java +++ b/src/test/java/domain/CustomDelimiterRegisterTest.java @@ -1,3 +1,5 @@ +package domain; + import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/DelimitersTest.java b/src/test/java/domain/DelimitersTest.java similarity index 98% rename from src/test/java/DelimitersTest.java rename to src/test/java/domain/DelimitersTest.java index e57632f9..f1a3dcfe 100644 --- a/src/test/java/DelimitersTest.java +++ b/src/test/java/domain/DelimitersTest.java @@ -1,4 +1,7 @@ +package domain; + import static org.junit.jupiter.api.Assertions.assertEquals; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/src/test/java/NumberTest.java b/src/test/java/domain/NumberTest.java similarity index 76% rename from src/test/java/NumberTest.java rename to src/test/java/domain/NumberTest.java index df41e861..20f9933e 100644 --- a/src/test/java/NumberTest.java +++ b/src/test/java/domain/NumberTest.java @@ -1,10 +1,12 @@ +package domain; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -@DisplayName("Number Test") +@DisplayName("domain.Number Test") class NumberTest { @Test @@ -15,7 +17,7 @@ void valueMethodReturnsStoredValue() { } @Test - @DisplayName("동일한 값을 가진 Number 객체는 equals로 비교 시 같다.") + @DisplayName("동일한 값을 가진 domain.Number 객체는 equals로 비교 시 같다.") void numbersWithSameValueAreEqual() { Number number1 = new Number(42); Number number2 = new Number(42); @@ -23,7 +25,7 @@ void numbersWithSameValueAreEqual() { } @Test - @DisplayName("다른 값을 가진 Number 객체는 equals로 비교 시 다르다.") + @DisplayName("다른 값을 가진 domain.Number 객체는 equals로 비교 시 다르다.") void numbersWithDifferentValuesAreNotEqual() { Number number1 = new Number(42); Number number2 = new Number(43); diff --git a/src/test/java/NumberTokensTest.java b/src/test/java/domain/NumberTokensTest.java similarity index 98% rename from src/test/java/NumberTokensTest.java rename to src/test/java/domain/NumberTokensTest.java index 2aaac6f8..d560d7d9 100644 --- a/src/test/java/NumberTokensTest.java +++ b/src/test/java/domain/NumberTokensTest.java @@ -1,3 +1,5 @@ +package domain; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/StringCalculatorTest.java b/src/test/java/domain/StringCalculatorTest.java similarity index 98% rename from src/test/java/StringCalculatorTest.java rename to src/test/java/domain/StringCalculatorTest.java index 36da13fc..54f483cf 100644 --- a/src/test/java/StringCalculatorTest.java +++ b/src/test/java/domain/StringCalculatorTest.java @@ -1,3 +1,5 @@ +package domain; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; From 7dd86ad7547071b88404e02a9559ac9f6d181731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 17:06:15 +0900 Subject: [PATCH 48/67] =?UTF-8?q?feat(Number)=20:=20=EC=9D=8C=EC=88=98=20?= =?UTF-8?q?=EA=B0=92=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=82=AC=EB=A5=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Number.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/domain/Number.java b/src/main/java/domain/Number.java index 3e12ea19..a18675f3 100644 --- a/src/main/java/domain/Number.java +++ b/src/main/java/domain/Number.java @@ -4,12 +4,21 @@ public class Number { + private static final String ERROR_NEGATIVE_NUMBER = "[ERROR] 숫자는 0 이상이어야 합니다."; + private final int value; public Number(int value) { + validateNonNegative(value); this.value = value; } + private void validateNonNegative(int value) { + if (value < 0) { + throw new IllegalArgumentException(ERROR_NEGATIVE_NUMBER); + } + } + public int value() { return value; } From 8b64f44e8764afb2c7fa4fac91c531c0dfc87553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 17:06:35 +0900 Subject: [PATCH 49/67] =?UTF-8?q?test(NumberTest)=20:=20=EC=9D=8C=EC=88=98?= =?UTF-8?q?=20=EA=B0=92=20=EC=98=88=EC=99=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20DisplayName=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/NumberTest.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/test/java/domain/NumberTest.java b/src/test/java/domain/NumberTest.java index 20f9933e..fc970d50 100644 --- a/src/test/java/domain/NumberTest.java +++ b/src/test/java/domain/NumberTest.java @@ -3,10 +3,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.*; -@DisplayName("domain.Number Test") class NumberTest { @Test @@ -17,7 +15,7 @@ void valueMethodReturnsStoredValue() { } @Test - @DisplayName("동일한 값을 가진 domain.Number 객체는 equals로 비교 시 같다.") + @DisplayName("동일한 값을 가진 Number 객체는 equals로 비교 시 같다.") void numbersWithSameValueAreEqual() { Number number1 = new Number(42); Number number2 = new Number(42); @@ -25,10 +23,16 @@ void numbersWithSameValueAreEqual() { } @Test - @DisplayName("다른 값을 가진 domain.Number 객체는 equals로 비교 시 다르다.") + @DisplayName("다른 값을 가진 Number 객체는 equals로 비교 시 다르다.") void numbersWithDifferentValuesAreNotEqual() { Number number1 = new Number(42); Number number2 = new Number(43); assertNotEquals(number1, number2); } + + @Test + @DisplayName("음수 값을 가진 경우 예외가 발생한다.") + void throwsExceptionWhenNegativeValue() { + assertThrows(IllegalArgumentException.class, () -> new Number(-1)); + } } From 56940b520e042406b75cac7244f50f997f32c113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Tue, 29 Apr 2025 17:10:34 +0900 Subject: [PATCH 50/67] =?UTF-8?q?refactor(Numbers)=20:=20NumberTokens=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A5=BC=20Numbers=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=98=EA=B3=A0=20=EC=9D=8C=EC=88=98=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=B1=85=EC=9E=84=EC=9D=84=20=EC=9D=BC?= =?UTF-8?q?=EC=9B=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/{NumberTokens.java => Numbers.java} | 17 +++-------------- src/main/java/domain/StringCalculator.java | 4 ++-- .../{NumberTokensTest.java => NumbersTest.java} | 12 ++++++------ 3 files changed, 11 insertions(+), 22 deletions(-) rename src/main/java/domain/{NumberTokens.java => Numbers.java} (51%) rename src/test/java/domain/{NumberTokensTest.java => NumbersTest.java} (78%) diff --git a/src/main/java/domain/NumberTokens.java b/src/main/java/domain/Numbers.java similarity index 51% rename from src/main/java/domain/NumberTokens.java rename to src/main/java/domain/Numbers.java index 884d92a5..626a0e45 100644 --- a/src/main/java/domain/NumberTokens.java +++ b/src/main/java/domain/Numbers.java @@ -5,25 +5,14 @@ import java.util.List; import java.util.stream.Collectors; -public class NumberTokens { - - private static final String ERROR_NEGATIVE_NUMBER = "[ERROR] 음수는 입력할 수 없습니다."; +public class Numbers { private final List numbers; - public NumberTokens(List tokens) { + public Numbers(List tokens) { this.numbers = tokens.stream() .map(NumberParser::parse) .collect(Collectors.toCollection(ArrayList::new)); - validateNoNegative(); - } - - private void validateNoNegative() { - for (Number number : numbers) { - if (number.value() < 0) { - throw new IllegalArgumentException(ERROR_NEGATIVE_NUMBER); - } - } } public int sum() { @@ -31,4 +20,4 @@ public int sum() { .mapToInt(Number::value) .sum(); } -} +} \ No newline at end of file diff --git a/src/main/java/domain/StringCalculator.java b/src/main/java/domain/StringCalculator.java index 432fa494..f24fb1f2 100644 --- a/src/main/java/domain/StringCalculator.java +++ b/src/main/java/domain/StringCalculator.java @@ -26,9 +26,9 @@ public int calculateSum(String expression) { String numbersExpression = extractNumbersExpression(expression); List tokens = splitNumbers(numbersExpression); - NumberTokens numberTokens = new NumberTokens(tokens); + Numbers numbers = new Numbers(tokens); - return numberTokens.sum(); + return numbers.sum(); } private boolean isEmpty(String expression) { diff --git a/src/test/java/domain/NumberTokensTest.java b/src/test/java/domain/NumbersTest.java similarity index 78% rename from src/test/java/domain/NumberTokensTest.java rename to src/test/java/domain/NumbersTest.java index d560d7d9..86d551c1 100644 --- a/src/test/java/domain/NumberTokensTest.java +++ b/src/test/java/domain/NumbersTest.java @@ -8,7 +8,7 @@ import java.util.List; -class NumberTokensTest { +class NumbersTest { @Test @DisplayName("숫자 문자열 리스트를 합산한다") @@ -17,10 +17,10 @@ void sumNumbers_success() { List tokens = List.of("1", "2", "3"); // when - NumberTokens numberTokens = new NumberTokens(tokens); + Numbers numbers = new Numbers(tokens); // then - assertEquals(6, numberTokens.sum()); + assertEquals(6, numbers.sum()); } @Test @@ -30,7 +30,7 @@ void throwException_whenNegativeNumberExists() { List tokens = List.of("1", "-2", "3"); // when & then - assertThrows(IllegalArgumentException.class, () -> new NumberTokens(tokens)); + assertThrows(IllegalArgumentException.class, () -> new Numbers(tokens)); } @Test @@ -40,9 +40,9 @@ void sumZero_whenEmptyList() { List tokens = List.of(); // when - NumberTokens numberTokens = new NumberTokens(tokens); + Numbers numbers = new Numbers(tokens); // then - assertEquals(0, numberTokens.sum()); + assertEquals(0, numbers.sum()); } } From 3ae18056c2020342517d836a463c4d49f8360b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:06:48 +0900 Subject: [PATCH 51/67] =?UTF-8?q?docs(README)=20:=20Step4=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 5687d185..4e866101 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ # 기능 및 프로그래밍 요구 사항 +# Step4 + +- [ ] build.gradle에 AssertJ 의존성을 추가한다. +- [ ] 기존 JUnit5로 작성되어 있던 단위 테스트를 AssertJ로 리팩터링한다. +- [ ] JUnit5에서 제공하는 기능과 AssertJ에서 제공하는 기능을 사용해보고, 어떠한 차이가 있는지 경험한다. +- [ ] 메인 메서드는 만들지 않는다. + # Step3 - [x] 쉼표(`,`) 또는 콜론(`:`)을 구분자로 가지는 문자열을 전달하면, 구분자를 기준으로 분리한 숫자들의 합을 반환해야 한다. - 예시: From 5659694fe092010bfc1131190a46802028b3faf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:07:29 +0900 Subject: [PATCH 52/67] =?UTF-8?q?chore(build.gradle)=20:=20AssertJ=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 87254a3a..239f9e78 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,9 @@ repositories { dependencies { testImplementation platform('org.junit:junit-bom:5.9.1') + testImplementation platform('org.assertj:assertj-bom:3.25.1') testImplementation('org.junit.jupiter:junit-jupiter') + testImplementation('org.assertj:assertj-core') } test { From d8f51821329614e8c0221836ec15c815949e3ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:07:49 +0900 Subject: [PATCH 53/67] =?UTF-8?q?docs(README)=20:=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80=20=EC=9E=91=EC=97=85=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 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e866101..1009a8ee 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Step4 -- [ ] build.gradle에 AssertJ 의존성을 추가한다. +- [x] build.gradle에 AssertJ 의존성을 추가한다. - [ ] 기존 JUnit5로 작성되어 있던 단위 테스트를 AssertJ로 리팩터링한다. - [ ] JUnit5에서 제공하는 기능과 AssertJ에서 제공하는 기능을 사용해보고, 어떠한 차이가 있는지 경험한다. - [ ] 메인 메서드는 만들지 않는다. From cb64fa79973ff613d0add51b06b5b7ed5fbc5564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:15:34 +0900 Subject: [PATCH 54/67] =?UTF-8?q?refactor(CalculatorTest)=20:=20AssertJ?= =?UTF-8?q?=EB=A1=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/CalculatorTest.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/java/domain/CalculatorTest.java b/src/test/java/domain/CalculatorTest.java index 6045f7b2..dca16ccc 100644 --- a/src/test/java/domain/CalculatorTest.java +++ b/src/test/java/domain/CalculatorTest.java @@ -7,8 +7,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.*; -@DisplayName("domain.Calculator Test") class CalculatorTest { private final Calculator calculator = new Calculator(); @@ -23,7 +23,7 @@ class CalculatorTest { @DisplayName("덧셈: 두 수를 더한 결과를 반환한다.") void addMethod(int firstNumber, int secondNumber, int expected) { int result = calculator.add(firstNumber, secondNumber); - assertEquals(expected, result); + assertThat(expected).isEqualTo(result); } @ParameterizedTest @@ -36,7 +36,7 @@ void addMethod(int firstNumber, int secondNumber, int expected) { @DisplayName("뺄셈: 두 수를 뺀 결과를 반환한다.") void subtractMethod(int firstNumber, int secondNumber, int expected) { int result = calculator.subtract(firstNumber, secondNumber); - assertEquals(expected, result); + assertThat(expected).isEqualTo(result); } @ParameterizedTest @@ -49,7 +49,7 @@ void subtractMethod(int firstNumber, int secondNumber, int expected) { @DisplayName("곱셈: 두 수를 곱한 결과를 반환한다.") void multiplyMethod(int firstNumber, int secondNumber, int expected) { int result = calculator.multiply(firstNumber, secondNumber); - assertEquals(expected, result); + assertThat(expected).isEqualTo(result); } @ParameterizedTest @@ -62,7 +62,7 @@ void multiplyMethod(int firstNumber, int secondNumber, int expected) { @DisplayName("나눗셈: 두 수를 나눈 결과를 반환한다.") void divideMethod(int firstNumber, int secondNumber, int expected) { int result = calculator.divide(firstNumber, secondNumber); - assertEquals(expected, result); + assertThat(expected).isEqualTo(result); } @ParameterizedTest @@ -73,6 +73,9 @@ void divideMethod(int firstNumber, int secondNumber, int expected) { }) @DisplayName("나눗셈: 0으로 나누면 IllegalArgumentException이 발생한다.") void divideByZeroException(int firstNumber, int secondNumber) { - assertThrows(IllegalArgumentException.class, () -> calculator.divide(firstNumber, secondNumber)); +// assertThrows(IllegalArgumentException.class, () -> calculator.divide(firstNumber, secondNumber)); + assertThatThrownBy(() -> calculator.divide(firstNumber, secondNumber)) + .isInstanceOf(IllegalArgumentException.class); + } } \ No newline at end of file From 876f38b92d96fc9724bfef8468c3afaeefb8c8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:16:08 +0900 Subject: [PATCH 55/67] =?UTF-8?q?refactor(CalculatorTest)=20:=20AssertJ?= =?UTF-8?q?=EB=A1=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/CalculatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/domain/CalculatorTest.java b/src/test/java/domain/CalculatorTest.java index dca16ccc..0e8869e7 100644 --- a/src/test/java/domain/CalculatorTest.java +++ b/src/test/java/domain/CalculatorTest.java @@ -73,7 +73,6 @@ void divideMethod(int firstNumber, int secondNumber, int expected) { }) @DisplayName("나눗셈: 0으로 나누면 IllegalArgumentException이 발생한다.") void divideByZeroException(int firstNumber, int secondNumber) { -// assertThrows(IllegalArgumentException.class, () -> calculator.divide(firstNumber, secondNumber)); assertThatThrownBy(() -> calculator.divide(firstNumber, secondNumber)) .isInstanceOf(IllegalArgumentException.class); From 3f668c9b3323e2dc7882ee48766a304860ebfbe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:19:09 +0900 Subject: [PATCH 56/67] =?UTF-8?q?refactor(CustomDelimiterRegisterTest)=20:?= =?UTF-8?q?=20AssertJ=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/CustomDelimiterRegisterTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/domain/CustomDelimiterRegisterTest.java b/src/test/java/domain/CustomDelimiterRegisterTest.java index b94d5de6..cfd75330 100644 --- a/src/test/java/domain/CustomDelimiterRegisterTest.java +++ b/src/test/java/domain/CustomDelimiterRegisterTest.java @@ -1,6 +1,6 @@ package domain; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,6 +21,6 @@ class CustomDelimiterRegisterTest { // then List expected = List.of(",", ":", ";"); - assertEquals(expected, delimiters.getDelimiters()); + assertThat(delimiters.getDelimiters()).isEqualTo(expected); } } From 504a9a24bd6e81c88e9a3f36d1ada273b0910a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:20:45 +0900 Subject: [PATCH 57/67] =?UTF-8?q?refactor(DelimitersTest)=20:=20AssertJ=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/DelimitersTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/domain/DelimitersTest.java b/src/test/java/domain/DelimitersTest.java index f1a3dcfe..1d785908 100644 --- a/src/test/java/domain/DelimitersTest.java +++ b/src/test/java/domain/DelimitersTest.java @@ -1,6 +1,6 @@ package domain; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -14,7 +14,7 @@ class DelimitersTest { Delimiters delimiters = new Delimiters(); List expected = List.of(",", ":"); - assertEquals(expected, delimiters.getDelimiters()); + assertThat(delimiters.getDelimiters()).isEqualTo(expected); } @Test @@ -24,7 +24,7 @@ class DelimitersTest { delimiters.addCustomDelimiters(";"); List expected = List.of(",", ":", ";"); - assertEquals(expected, delimiters.getDelimiters()); + assertThat(delimiters.getDelimiters()).isEqualTo(expected); } @Test @@ -35,6 +35,6 @@ class DelimitersTest { delimiters.addCustomDelimiters(""); List expected = List.of(",", ":"); - assertEquals(expected, delimiters.getDelimiters()); + assertThat(delimiters.getDelimiters()).isEqualTo(expected); } } From bbfee4cb84aacee3c01a23fafa5ee90f403e9740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:23:36 +0900 Subject: [PATCH 58/67] =?UTF-8?q?refactor(NumbersTest)=20:=20AssertJ=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/NumbersTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/domain/NumbersTest.java b/src/test/java/domain/NumbersTest.java index 86d551c1..c70fb564 100644 --- a/src/test/java/domain/NumbersTest.java +++ b/src/test/java/domain/NumbersTest.java @@ -1,7 +1,6 @@ package domain; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -20,7 +19,7 @@ void sumNumbers_success() { Numbers numbers = new Numbers(tokens); // then - assertEquals(6, numbers.sum()); + assertThat(6).isEqualTo(numbers.sum()); } @Test @@ -30,7 +29,8 @@ void throwException_whenNegativeNumberExists() { List tokens = List.of("1", "-2", "3"); // when & then - assertThrows(IllegalArgumentException.class, () -> new Numbers(tokens)); + assertThatThrownBy(() -> new Numbers(tokens)) + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -43,6 +43,6 @@ void sumZero_whenEmptyList() { Numbers numbers = new Numbers(tokens); // then - assertEquals(0, numbers.sum()); + assertThat(0).isEqualTo(numbers.sum()); } } From f717a2bdbfab99a43686513c9c748cb171571920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:24:30 +0900 Subject: [PATCH 59/67] =?UTF-8?q?refactor(NumberTest)=20:=20AssertJ=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/NumberTest.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/java/domain/NumberTest.java b/src/test/java/domain/NumberTest.java index fc970d50..2436f348 100644 --- a/src/test/java/domain/NumberTest.java +++ b/src/test/java/domain/NumberTest.java @@ -3,7 +3,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.*; class NumberTest { @@ -11,7 +11,7 @@ class NumberTest { @DisplayName("value 메서드는 저장된 값을 반환한다.") void valueMethodReturnsStoredValue() { Number number = new Number(42); - assertEquals(42, number.value()); + assertThat(number.value()).isEqualTo(42); } @Test @@ -19,7 +19,7 @@ void valueMethodReturnsStoredValue() { void numbersWithSameValueAreEqual() { Number number1 = new Number(42); Number number2 = new Number(42); - assertEquals(number1, number2); + assertThat(number1).isEqualTo(number2); } @Test @@ -27,12 +27,13 @@ void numbersWithSameValueAreEqual() { void numbersWithDifferentValuesAreNotEqual() { Number number1 = new Number(42); Number number2 = new Number(43); - assertNotEquals(number1, number2); + assertThat(number1).isNotEqualTo(number2); } @Test @DisplayName("음수 값을 가진 경우 예외가 발생한다.") void throwsExceptionWhenNegativeValue() { - assertThrows(IllegalArgumentException.class, () -> new Number(-1)); + assertThatThrownBy(() -> new Number(-1)) + .isInstanceOf(IllegalArgumentException.class); } -} +} \ No newline at end of file From 6194d53dec543ca529ae1fb5343389583d08f98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:28:08 +0900 Subject: [PATCH 60/67] =?UTF-8?q?refactor(StringCalculatorTest)=20:=20Asse?= =?UTF-8?q?rtJ=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/StringCalculatorTest.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/test/java/domain/StringCalculatorTest.java b/src/test/java/domain/StringCalculatorTest.java index 54f483cf..1e543146 100644 --- a/src/test/java/domain/StringCalculatorTest.java +++ b/src/test/java/domain/StringCalculatorTest.java @@ -1,7 +1,6 @@ package domain; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,29 +12,26 @@ class StringCalculatorTest { @Test @DisplayName("빈 문자열 또는 null 입력 시 결과는 0이다") void returnZero_whenInputIsEmptyOrNull() { - // when & then - assertEquals(0, calculator.calculateSum("")); - assertEquals(0, calculator.calculateSum(null)); + assertThat(calculator.calculateSum("")).isZero(); + assertThat(calculator.calculateSum(null)).isZero(); } @Test @DisplayName("쉼표 또는 콜론 구분자로 구분된 숫자를 합산한다") void sumNumbers_whenDefaultDelimiters() { - // when & then - assertEquals(6, calculator.calculateSum("1,2:3")); + assertThat(calculator.calculateSum("1,2:3")).isEqualTo(6); } @Test @DisplayName("커스텀 구분자가 지정된 경우 해당 구분자로 숫자를 합산한다") void sumNumbers_whenCustomDelimiter() { - // when & then - assertEquals(6, calculator.calculateSum("//;\n1;2;3")); + assertThat(calculator.calculateSum("//;\n1;2;3")).isEqualTo(6); } @Test @DisplayName("음수가 포함된 경우 예외를 던진다") void throwException_whenNegativeNumberExists() { - // when & then - assertThrows(IllegalArgumentException.class, () -> calculator.calculateSum("1,-2,3")); + assertThatThrownBy(() -> calculator.calculateSum("1,-2,3")) + .isInstanceOf(IllegalArgumentException.class); } } From 42d9f76ff4d5dca6339b0b6227e155ec89a87cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:32:19 +0900 Subject: [PATCH 61/67] =?UTF-8?q?refactor(CustomDelimiterParserTest)=20:?= =?UTF-8?q?=20AssertJ=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/utils/CustomDelimiterParserTest.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/test/java/utils/CustomDelimiterParserTest.java b/src/test/java/utils/CustomDelimiterParserTest.java index e99568f3..4a43f927 100644 --- a/src/test/java/utils/CustomDelimiterParserTest.java +++ b/src/test/java/utils/CustomDelimiterParserTest.java @@ -1,9 +1,6 @@ package utils; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -17,7 +14,7 @@ class CustomDelimiterParserTest { void hasCustomDelimiter_true() { String expression = "//;\n1;2;3"; - assertTrue(parser.hasCustomDelimiter(expression)); + assertThat(parser.hasCustomDelimiter(expression)).isTrue(); } @Test @@ -25,7 +22,7 @@ void hasCustomDelimiter_true() { void hasCustomDelimiter_false() { String expression = "1,2:3"; - assertFalse(parser.hasCustomDelimiter(expression)); + assertThat(parser.hasCustomDelimiter(expression)).isFalse(); } @Test @@ -35,7 +32,7 @@ void parseCustomDelimiter_success() { String customDelimiter = parser.parseCustomDelimiter(expression); - assertEquals(";", customDelimiter); + assertThat(customDelimiter).isEqualTo(";"); } @Test @@ -43,7 +40,8 @@ void parseCustomDelimiter_success() { void parseCustomDelimiter_invalidFormat() { String invalidExpression = "//;1;2;3"; - assertThrows(IllegalArgumentException.class, () -> parser.parseCustomDelimiter(invalidExpression)); + assertThatThrownBy(() -> parser.parseCustomDelimiter(invalidExpression)) + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -53,6 +51,6 @@ void parseNumbersExpression_success() { String numbers = parser.parseNumbersExpression(expression); - assertEquals("1;2;3", numbers); + assertThat(numbers).isEqualTo("1;2;3"); } -} +} \ No newline at end of file From d8929e8e4313b152ffb4f92bf1b8e93fae79e831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:33:08 +0900 Subject: [PATCH 62/67] =?UTF-8?q?refactor(ExpressionSplitterTest)=20:=20As?= =?UTF-8?q?sertJ=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/utils/ExpressionSplitterTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/utils/ExpressionSplitterTest.java b/src/test/java/utils/ExpressionSplitterTest.java index 34d61fa2..6dac4df9 100644 --- a/src/test/java/utils/ExpressionSplitterTest.java +++ b/src/test/java/utils/ExpressionSplitterTest.java @@ -1,6 +1,6 @@ package utils; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.*; import domain.Delimiters; import org.junit.jupiter.api.DisplayName; @@ -22,7 +22,7 @@ void splitByDefaultDelimiters() { List result = splitter.split(expression); // then - assertEquals(List.of("1", "2", "3"), result); + assertThat(result).isEqualTo(List.of("1", "2", "3")); } @Test @@ -38,7 +38,7 @@ void splitByCustomDelimiter() { List result = splitter.split(expression); // then - assertEquals(List.of("1", "2", "3", "4"), result); + assertThat(result).isEqualTo(List.of("1", "2", "3", "4")); } @Test @@ -53,6 +53,6 @@ void splitEmptyString() { List result = splitter.split(expression); // then - assertEquals(List.of(""), result); + assertThat(result).isEqualTo(List.of("")); } -} +} \ No newline at end of file From 2d3e456bfc8a90b03674d5445ac1ef2dcce75785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:34:20 +0900 Subject: [PATCH 63/67] =?UTF-8?q?refactor(NumberParserTest)=20:=20AssertJ?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/utils/NumberParserTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/utils/NumberParserTest.java b/src/test/java/utils/NumberParserTest.java index f04e0cb4..85c9fbf9 100644 --- a/src/test/java/utils/NumberParserTest.java +++ b/src/test/java/utils/NumberParserTest.java @@ -4,8 +4,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.*; @DisplayName("parser.NumberParser Test") class NumberParserTest { @@ -14,12 +13,13 @@ class NumberParserTest { @DisplayName("정상 입력: 문자열을 정수로 변환하여 domain.Number 객체를 반환한다.") void parseValidInput() { Number number = NumberParser.parse("42"); - assertEquals(new Number(42), number); + assertThat(number).isEqualTo(new Number(42)); } @Test @DisplayName("비정상 입력: 숫자가 아닌 문자열 입력 시 예외를 발생시킨다.") void parseInvalidInput() { - assertThrows(IllegalArgumentException.class, () -> NumberParser.parse("abc")); + assertThatThrownBy(() -> NumberParser.parse("abc")) + .isInstanceOf(IllegalArgumentException.class); } } From 7a7d00ad9634fe380c33f27b2266f95b06807d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:35:00 +0900 Subject: [PATCH 64/67] =?UTF-8?q?refactor(InputViewTest)=20:=20AssertJ=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/view/InputViewTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/view/InputViewTest.java b/src/test/java/view/InputViewTest.java index d4e0827d..d81cf497 100644 --- a/src/test/java/view/InputViewTest.java +++ b/src/test/java/view/InputViewTest.java @@ -7,7 +7,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.*; @DisplayName("view.InputView Test") class InputViewTest { @@ -25,6 +25,9 @@ void tearDown() { void readExpression() { System.setIn(new ByteArrayInputStream(INPUT.getBytes())); InputView inputView = new InputView(); - assertEquals("42", inputView.readExpression()); + + String result = inputView.readExpression(); + + assertThat(result).isEqualTo("42"); } } From c53caac40a046446ed855d560efa2f18cd6fd21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:35:39 +0900 Subject: [PATCH 65/67] =?UTF-8?q?refactor(OutputViewTest)=20:=20AssertJ=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/view/OutputViewTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/view/OutputViewTest.java b/src/test/java/view/OutputViewTest.java index c5388ca3..e3ddd2a3 100644 --- a/src/test/java/view/OutputViewTest.java +++ b/src/test/java/view/OutputViewTest.java @@ -8,7 +8,7 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.*; @DisplayName("view.OutputView Test") class OutputViewTest { @@ -32,7 +32,7 @@ void tearDown() { void printFirstNumberPrompt() { outputView.printFirstNumberPrompt(); String output = outputStream.toString(); - assertTrue(output.contains(OutputView.FIRST_NUMBER_PROMPT)); + assertThat(output).contains(OutputView.FIRST_NUMBER_PROMPT); } @Test @@ -40,7 +40,7 @@ void printFirstNumberPrompt() { void printSecondNumberPrompt() { outputView.printSecondNumberPrompt(); String output = outputStream.toString(); - assertTrue(output.contains(OutputView.SECOND_NUMBER_PROMPT)); + assertThat(output).contains(OutputView.SECOND_NUMBER_PROMPT); } @Test @@ -49,6 +49,6 @@ void printResult() { int result = 10; outputView.printResult(result); String output = outputStream.toString(); - assertTrue(output.contains(OutputView.RESULT_MESSAGE + result)); + assertThat(output).contains(OutputView.RESULT_MESSAGE + result); } } From 29b269fcc0846c01661057875e85b066cb6a922f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Wed, 30 Apr 2025 15:50:36 +0900 Subject: [PATCH 66/67] =?UTF-8?q?docs(README)=20:=20AssertJ=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EC=99=84=EB=A3=8C=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1009a8ee..fbc83637 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ # Step4 - [x] build.gradle에 AssertJ 의존성을 추가한다. -- [ ] 기존 JUnit5로 작성되어 있던 단위 테스트를 AssertJ로 리팩터링한다. -- [ ] JUnit5에서 제공하는 기능과 AssertJ에서 제공하는 기능을 사용해보고, 어떠한 차이가 있는지 경험한다. -- [ ] 메인 메서드는 만들지 않는다. +- [x] 기존 JUnit5로 작성되어 있던 단위 테스트를 AssertJ로 리팩터링한다. +- [x] JUnit5에서 제공하는 기능과 AssertJ에서 제공하는 기능을 사용해보고, 어떠한 차이가 있는지 경험한다. +- [x] 메인 메서드는 만들지 않는다. # Step3 - [x] 쉼표(`,`) 또는 콜론(`:`)을 구분자로 가지는 문자열을 전달하면, 구분자를 기준으로 분리한 숫자들의 합을 반환해야 한다. From bdd834ce9ab113ef2d981ebb770fdf47b046432f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Thu, 1 May 2025 13:32:05 +0900 Subject: [PATCH 67/67] =?UTF-8?q?refactor(step4)=20:=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Calculator.java | 2 +- .../java/domain/CustomDelimiterRegister.java | 14 ----- src/main/java/domain/Delimiters.java | 23 ++++++-- src/main/java/domain/Number.java | 43 -------------- src/main/java/domain/PositiveNumber.java | 43 ++++++++++++++ .../{Numbers.java => PositiveNumbers.java} | 14 ++--- src/main/java/domain/StringCalculator.java | 45 ++++++--------- .../java/utils/CustomDelimiterParser.java | 30 ---------- src/main/java/utils/ExpressionSplitter.java | 7 ++- src/main/java/utils/NumberParser.java | 6 +- src/main/java/view/InputView.java | 12 ---- src/main/java/view/OutputView.java | 20 ------- src/test/java/domain/CalculatorTest.java | 5 +- .../domain/CustomDelimiterRegisterTest.java | 26 --------- src/test/java/domain/DelimitersTest.java | 37 +++++++++--- src/test/java/domain/NumberTest.java | 39 ------------- src/test/java/domain/PositiveNumberTest.java | 40 +++++++++++++ ...bersTest.java => PositiveNumbersTest.java} | 12 ++-- .../java/utils/CustomDelimiterParserTest.java | 56 ------------------- .../java/utils/ExpressionSplitterTest.java | 4 +- ...est.java => PositiveNumberParserTest.java} | 8 +-- src/test/java/view/InputViewTest.java | 33 ----------- src/test/java/view/OutputViewTest.java | 54 ------------------ 23 files changed, 176 insertions(+), 397 deletions(-) delete mode 100644 src/main/java/domain/CustomDelimiterRegister.java delete mode 100644 src/main/java/domain/Number.java create mode 100644 src/main/java/domain/PositiveNumber.java rename src/main/java/domain/{Numbers.java => PositiveNumbers.java} (51%) delete mode 100644 src/main/java/utils/CustomDelimiterParser.java delete mode 100644 src/main/java/view/InputView.java delete mode 100644 src/main/java/view/OutputView.java delete mode 100644 src/test/java/domain/CustomDelimiterRegisterTest.java delete mode 100644 src/test/java/domain/NumberTest.java create mode 100644 src/test/java/domain/PositiveNumberTest.java rename src/test/java/domain/{NumbersTest.java => PositiveNumbersTest.java} (72%) delete mode 100644 src/test/java/utils/CustomDelimiterParserTest.java rename src/test/java/utils/{NumberParserTest.java => PositiveNumberParserTest.java} (75%) delete mode 100644 src/test/java/view/InputViewTest.java delete mode 100644 src/test/java/view/OutputViewTest.java diff --git a/src/main/java/domain/Calculator.java b/src/main/java/domain/Calculator.java index a6dd6e6a..5974e9fa 100644 --- a/src/main/java/domain/Calculator.java +++ b/src/main/java/domain/Calculator.java @@ -22,4 +22,4 @@ public int divide(int firstNumber, int secondNumber) { } return firstNumber / secondNumber; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/CustomDelimiterRegister.java b/src/main/java/domain/CustomDelimiterRegister.java deleted file mode 100644 index 21c812d1..00000000 --- a/src/main/java/domain/CustomDelimiterRegister.java +++ /dev/null @@ -1,14 +0,0 @@ -package domain; - -public class CustomDelimiterRegister { - - private final Delimiters delimiters; - - public CustomDelimiterRegister(Delimiters delimiters) { - this.delimiters = delimiters; - } - - public void register(String customDelimiter) { - delimiters.addCustomDelimiters(customDelimiter); - } -} diff --git a/src/main/java/domain/Delimiters.java b/src/main/java/domain/Delimiters.java index a13157f2..2a098fd1 100644 --- a/src/main/java/domain/Delimiters.java +++ b/src/main/java/domain/Delimiters.java @@ -11,14 +11,29 @@ public class Delimiters { private final List delimiters = new ArrayList<>(DEFAULT_DELIMITERS); - public void addCustomDelimiters(String customDelimiter) { - if (customDelimiter == null || customDelimiter.isEmpty()) { - return; - } + public void registerCustomDelimiter(String customDelimiter) { + validate(customDelimiter); delimiters.add(customDelimiter); } public List getDelimiters() { return new ArrayList<>(delimiters); } + + private void validate(String customDelimiter) { + validateNotBlank(customDelimiter); + validateNotDuplicate(customDelimiter); + } + + private void validateNotBlank(String customDelimiter) { + if (customDelimiter == null || customDelimiter.isBlank()) { + throw new IllegalArgumentException("[ERROR] 커스텀 구분자는 비어 있을 수 없습니다."); + } + } + + private void validateNotDuplicate(String customDelimiter) { + if (delimiters.contains(customDelimiter)) { + throw new IllegalArgumentException("[ERROR] 이미 등록된 구분자입니다."); + } + } } diff --git a/src/main/java/domain/Number.java b/src/main/java/domain/Number.java deleted file mode 100644 index a18675f3..00000000 --- a/src/main/java/domain/Number.java +++ /dev/null @@ -1,43 +0,0 @@ -package domain; - -import java.util.Objects; - -public class Number { - - private static final String ERROR_NEGATIVE_NUMBER = "[ERROR] 숫자는 0 이상이어야 합니다."; - - private final int value; - - public Number(int value) { - validateNonNegative(value); - this.value = value; - } - - private void validateNonNegative(int value) { - if (value < 0) { - throw new IllegalArgumentException(ERROR_NEGATIVE_NUMBER); - } - } - - public int value() { - return value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Number)) return false; - Number number = (Number) o; - return value == number.value; - } - - @Override - public int hashCode() { - return Objects.hash(value); - } - - @Override - public String toString() { - return String.valueOf(value); - } -} diff --git a/src/main/java/domain/PositiveNumber.java b/src/main/java/domain/PositiveNumber.java new file mode 100644 index 00000000..de0e6e6e --- /dev/null +++ b/src/main/java/domain/PositiveNumber.java @@ -0,0 +1,43 @@ +package domain; + +import java.util.Objects; + +public class PositiveNumber { + + private static final String ERROR_NEGATIVE_NUMBER = "[ERROR] 숫자는 0 이상이어야 합니다."; + + private final int positiveNumber; + + public PositiveNumber(int positiveNumber) { + validateNonNegative(positiveNumber); + this.positiveNumber = positiveNumber; + } + + private void validateNonNegative(int positiveNumber) { + if (positiveNumber < 0) { + throw new IllegalArgumentException(ERROR_NEGATIVE_NUMBER); + } + } + + public int getPositiveNumber() { + return positiveNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PositiveNumber that = (PositiveNumber) o; + return positiveNumber == that.positiveNumber; + } + + @Override + public int hashCode() { + return Objects.hash(positiveNumber); + } + + @Override + public String toString() { + return String.valueOf(positiveNumber); + } +} diff --git a/src/main/java/domain/Numbers.java b/src/main/java/domain/PositiveNumbers.java similarity index 51% rename from src/main/java/domain/Numbers.java rename to src/main/java/domain/PositiveNumbers.java index 626a0e45..0e984b5f 100644 --- a/src/main/java/domain/Numbers.java +++ b/src/main/java/domain/PositiveNumbers.java @@ -5,19 +5,19 @@ import java.util.List; import java.util.stream.Collectors; -public class Numbers { +public class PositiveNumbers { - private final List numbers; + private final List positiveNumbers; - public Numbers(List tokens) { - this.numbers = tokens.stream() + public PositiveNumbers(List tokens) { + this.positiveNumbers = tokens.stream() .map(NumberParser::parse) .collect(Collectors.toCollection(ArrayList::new)); } public int sum() { - return numbers.stream() - .mapToInt(Number::value) + return positiveNumbers.stream() + .mapToInt(PositiveNumber::getPositiveNumber) .sum(); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/StringCalculator.java b/src/main/java/domain/StringCalculator.java index f24fb1f2..bf00f852 100644 --- a/src/main/java/domain/StringCalculator.java +++ b/src/main/java/domain/StringCalculator.java @@ -1,6 +1,5 @@ package domain; -import utils.CustomDelimiterParser; import utils.ExpressionSplitter; import java.util.List; @@ -8,14 +7,10 @@ public class StringCalculator { private final Delimiters delimiters; - private final CustomDelimiterParser parser; - private final CustomDelimiterRegister register; private final ExpressionSplitter splitter; public StringCalculator() { this.delimiters = new Delimiters(); - this.parser = new CustomDelimiterParser(); - this.register = new CustomDelimiterRegister(delimiters); this.splitter = new ExpressionSplitter(delimiters); } @@ -24,35 +19,29 @@ public int calculateSum(String expression) { return 0; } - String numbersExpression = extractNumbersExpression(expression); - List tokens = splitNumbers(numbersExpression); - Numbers numbers = new Numbers(tokens); + String numbersExpression = extract(expression); + List tokens = splitter.split(numbersExpression); + PositiveNumbers positiveNumbers = new PositiveNumbers(tokens); - return numbers.sum(); + return positiveNumbers.sum(); } private boolean isEmpty(String expression) { - return expression == null || expression.isEmpty(); + return expression == null || expression.isBlank(); } - private String extractNumbersExpression(String expression) { - if (parser.hasCustomDelimiter(expression)) { - registerCustomDelimiter(expression); - return extractPureNumbers(expression); + private String extract(String expression) { + final String prefix = "//"; + final String suffix = "\n"; + if (!expression.startsWith(prefix)) { + return expression; } - return expression; - } - - private void registerCustomDelimiter(String expression) { - String customDelimiter = parser.parseCustomDelimiter(expression); - register.register(customDelimiter); - } - - private String extractPureNumbers(String expression) { - return parser.parseNumbersExpression(expression); - } - - private List splitNumbers(String numbersExpression) { - return splitter.split(numbersExpression); + int endIndex = expression.indexOf(suffix); + if (endIndex == -1) { + throw new IllegalArgumentException("[ERROR] 커스텀 구분자 형식이 잘못되었습니다."); + } + String customDelimiter = expression.substring(prefix.length(), endIndex); + delimiters.registerCustomDelimiter(customDelimiter); + return expression.substring(endIndex + 1); } } diff --git a/src/main/java/utils/CustomDelimiterParser.java b/src/main/java/utils/CustomDelimiterParser.java deleted file mode 100644 index 61bae072..00000000 --- a/src/main/java/utils/CustomDelimiterParser.java +++ /dev/null @@ -1,30 +0,0 @@ -package utils; - -public class CustomDelimiterParser { - - private static final String CUSTOM_DELIMITER_PREFIX = "//"; - private static final String CUSTOM_DELIMITER_SUFFIX = "\n"; - private static final int CUSTOM_DELIMITER_PREFIX_LENGTH = CUSTOM_DELIMITER_PREFIX.length(); - private static final String ERROR_INVALID_CUSTOM_DELIMITER_FORMAT = "[ERROR] 커스텀 구분자 형식이 잘못되었습니다."; - - public boolean hasCustomDelimiter(String expression) { - return expression.startsWith(CUSTOM_DELIMITER_PREFIX); - } - - public String parseCustomDelimiter(String expression) { - validate(expression); - int delimiterEndIndex = expression.indexOf(CUSTOM_DELIMITER_SUFFIX); - return expression.substring(CUSTOM_DELIMITER_PREFIX_LENGTH, delimiterEndIndex); - } - - public String parseNumbersExpression(String expression) { - int delimiterEndIndex = expression.indexOf(CUSTOM_DELIMITER_SUFFIX); - return expression.substring(delimiterEndIndex + 1); - } - - private void validate(String expression) { - if (!expression.contains(CUSTOM_DELIMITER_SUFFIX)) { - throw new IllegalArgumentException(ERROR_INVALID_CUSTOM_DELIMITER_FORMAT); - } - } -} diff --git a/src/main/java/utils/ExpressionSplitter.java b/src/main/java/utils/ExpressionSplitter.java index 16d5b0e7..669ffce1 100644 --- a/src/main/java/utils/ExpressionSplitter.java +++ b/src/main/java/utils/ExpressionSplitter.java @@ -4,6 +4,8 @@ import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; public class ExpressionSplitter { @@ -14,8 +16,9 @@ public ExpressionSplitter(Delimiters delimiters) { } public List split(String expression) { - List delimiterList = delimiters.getDelimiters(); - String regex = String.join("|", delimiterList); + String regex = delimiters.getDelimiters().stream() + .map(Pattern::quote) + .collect(Collectors.joining("|")); return Arrays.asList(expression.split(regex)); } } diff --git a/src/main/java/utils/NumberParser.java b/src/main/java/utils/NumberParser.java index 2f32090a..a3018b43 100644 --- a/src/main/java/utils/NumberParser.java +++ b/src/main/java/utils/NumberParser.java @@ -1,15 +1,15 @@ package utils; -import domain.Number; +import domain.PositiveNumber; public class NumberParser { private static final String ERROR_NOT_A_NUMBER = "[ERROR] 입력은 숫자여야 합니다."; - public static Number parse(String input) { + public static PositiveNumber parse(String input) { try { int number = Integer.parseInt(input); - return new Number(number); + return new PositiveNumber(number); } catch (NumberFormatException e) { throw new IllegalArgumentException(ERROR_NOT_A_NUMBER); } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java deleted file mode 100644 index bdba2664..00000000 --- a/src/main/java/view/InputView.java +++ /dev/null @@ -1,12 +0,0 @@ -package view; - -import java.util.Scanner; - -public class InputView { - - private final Scanner scanner = new Scanner(System.in); - - public String readExpression() { - return scanner.nextLine(); - } -} \ No newline at end of file diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java deleted file mode 100644 index f97eb73a..00000000 --- a/src/main/java/view/OutputView.java +++ /dev/null @@ -1,20 +0,0 @@ -package view; - -public class OutputView { - - static final String FIRST_NUMBER_PROMPT = "첫 번째 숫자를 입력하세요: "; - static final String SECOND_NUMBER_PROMPT = "두 번째 숫자를 입력하세요: "; - static final String RESULT_MESSAGE = "계산 결과: "; - - public void printFirstNumberPrompt() { - System.out.print(FIRST_NUMBER_PROMPT); - } - - public void printSecondNumberPrompt() { - System.out.print(SECOND_NUMBER_PROMPT); - } - - public void printResult(int result) { - System.out.println(RESULT_MESSAGE + result); - } -} \ No newline at end of file diff --git a/src/test/java/domain/CalculatorTest.java b/src/test/java/domain/CalculatorTest.java index 0e8869e7..1bfd6c0d 100644 --- a/src/test/java/domain/CalculatorTest.java +++ b/src/test/java/domain/CalculatorTest.java @@ -4,9 +4,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - import static org.assertj.core.api.Assertions.*; class CalculatorTest { @@ -77,4 +74,4 @@ void divideByZeroException(int firstNumber, int secondNumber) { .isInstanceOf(IllegalArgumentException.class); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/CustomDelimiterRegisterTest.java b/src/test/java/domain/CustomDelimiterRegisterTest.java deleted file mode 100644 index cfd75330..00000000 --- a/src/test/java/domain/CustomDelimiterRegisterTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package domain; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.List; - -class CustomDelimiterRegisterTest { - - @Test - @DisplayName("커스텀 구분자를 등록할 수 있다") - void 커스텀구분자_등록() { - // given - Delimiters delimiters = new Delimiters(); - CustomDelimiterRegister register = new CustomDelimiterRegister(delimiters); - - // when - register.register(";"); - - // then - List expected = List.of(",", ":", ";"); - assertThat(delimiters.getDelimiters()).isEqualTo(expected); - } -} diff --git a/src/test/java/domain/DelimitersTest.java b/src/test/java/domain/DelimitersTest.java index 1d785908..e45f17cb 100644 --- a/src/test/java/domain/DelimitersTest.java +++ b/src/test/java/domain/DelimitersTest.java @@ -4,13 +4,14 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; + import java.util.List; class DelimitersTest { @Test @DisplayName("기본 구분자가 등록되어 있어야 한다") - void 기본구분자등록_검증() { + void shouldContainDefaultDelimiters() { Delimiters delimiters = new Delimiters(); List expected = List.of(",", ":"); @@ -19,22 +20,40 @@ class DelimitersTest { @Test @DisplayName("커스텀 구분자를 추가할 수 있다") - void 커스텀구분자_추가() { + void shouldAddCustomDelimiter() { Delimiters delimiters = new Delimiters(); - delimiters.addCustomDelimiters(";"); + delimiters.registerCustomDelimiter(";"); List expected = List.of(",", ":", ";"); assertThat(delimiters.getDelimiters()).isEqualTo(expected); } @Test - @DisplayName("null 또는 빈 문자열을 추가해도 구분자가 추가되지 않는다") - void 커스텀구분자_null또는빈문자열() { + @DisplayName("null을 입력하면 예외가 발생한다") + void shouldThrowExceptionWhenCustomDelimiterIsNull() { Delimiters delimiters = new Delimiters(); - delimiters.addCustomDelimiters(null); - delimiters.addCustomDelimiters(""); + assertThatThrownBy(() -> delimiters.registerCustomDelimiter(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] 커스텀 구분자는 비어 있을 수 없습니다."); + } - List expected = List.of(",", ":"); - assertThat(delimiters.getDelimiters()).isEqualTo(expected); + @Test + @DisplayName("빈 문자열을 입력하면 예외가 발생한다") + void shouldThrowExceptionWhenCustomDelimiterIsBlank() { + Delimiters delimiters = new Delimiters(); + assertThatThrownBy(() -> delimiters.registerCustomDelimiter(" ")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] 커스텀 구분자는 비어 있을 수 없습니다."); + } + + @Test + @DisplayName("이미 등록된 구분자를 추가하면 예외가 발생한다") + void shouldThrowExceptionWhenCustomDelimiterIsDuplicate() { + Delimiters delimiters = new Delimiters(); + delimiters.registerCustomDelimiter(";"); + + assertThatThrownBy(() -> delimiters.registerCustomDelimiter(";")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] 이미 등록된 구분자입니다."); } } diff --git a/src/test/java/domain/NumberTest.java b/src/test/java/domain/NumberTest.java deleted file mode 100644 index 2436f348..00000000 --- a/src/test/java/domain/NumberTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package domain; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.*; - -class NumberTest { - - @Test - @DisplayName("value 메서드는 저장된 값을 반환한다.") - void valueMethodReturnsStoredValue() { - Number number = new Number(42); - assertThat(number.value()).isEqualTo(42); - } - - @Test - @DisplayName("동일한 값을 가진 Number 객체는 equals로 비교 시 같다.") - void numbersWithSameValueAreEqual() { - Number number1 = new Number(42); - Number number2 = new Number(42); - assertThat(number1).isEqualTo(number2); - } - - @Test - @DisplayName("다른 값을 가진 Number 객체는 equals로 비교 시 다르다.") - void numbersWithDifferentValuesAreNotEqual() { - Number number1 = new Number(42); - Number number2 = new Number(43); - assertThat(number1).isNotEqualTo(number2); - } - - @Test - @DisplayName("음수 값을 가진 경우 예외가 발생한다.") - void throwsExceptionWhenNegativeValue() { - assertThatThrownBy(() -> new Number(-1)) - .isInstanceOf(IllegalArgumentException.class); - } -} \ No newline at end of file diff --git a/src/test/java/domain/PositiveNumberTest.java b/src/test/java/domain/PositiveNumberTest.java new file mode 100644 index 00000000..e007aabe --- /dev/null +++ b/src/test/java/domain/PositiveNumberTest.java @@ -0,0 +1,40 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + +class PositiveNumberTest { + + @Test + @DisplayName("getPositiveNumber 메서드는 저장된 값을 반환한다.") + void getPositiveNumberReturnsStoredValue() { + PositiveNumber positiveNumber = new PositiveNumber(42); + assertThat(positiveNumber.getPositiveNumber()).isEqualTo(42); + } + + @Test + @DisplayName("동일한 값을 가진 PositiveNumber 객체는 equals로 비교 시 같다.") + void positiveNumbersWithSameValueAreEqual() { + PositiveNumber a = new PositiveNumber(42); + PositiveNumber b = new PositiveNumber(42); + assertThat(a).isEqualTo(b); + } + + @Test + @DisplayName("서로 다른 값을 가진 PositiveNumber 객체는 equals로 비교 시 다르다.") + void positiveNumbersWithDifferentValuesAreNotEqual() { + PositiveNumber a = new PositiveNumber(42); + PositiveNumber b = new PositiveNumber(43); + assertThat(a).isNotEqualTo(b); + } + + @Test + @DisplayName("음수 값으로 생성 시 예외가 발생한다.") + void throwsExceptionWhenNegativeValueProvided() { + assertThatThrownBy(() -> new PositiveNumber(-1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("[ERROR] 숫자는 0 이상이어야 합니다."); + } +} diff --git a/src/test/java/domain/NumbersTest.java b/src/test/java/domain/PositiveNumbersTest.java similarity index 72% rename from src/test/java/domain/NumbersTest.java rename to src/test/java/domain/PositiveNumbersTest.java index c70fb564..d951a5c6 100644 --- a/src/test/java/domain/NumbersTest.java +++ b/src/test/java/domain/PositiveNumbersTest.java @@ -7,7 +7,7 @@ import java.util.List; -class NumbersTest { +class PositiveNumbersTest { @Test @DisplayName("숫자 문자열 리스트를 합산한다") @@ -16,10 +16,10 @@ void sumNumbers_success() { List tokens = List.of("1", "2", "3"); // when - Numbers numbers = new Numbers(tokens); + PositiveNumbers positiveNumbers = new PositiveNumbers(tokens); // then - assertThat(6).isEqualTo(numbers.sum()); + assertThat(6).isEqualTo(positiveNumbers.sum()); } @Test @@ -29,7 +29,7 @@ void throwException_whenNegativeNumberExists() { List tokens = List.of("1", "-2", "3"); // when & then - assertThatThrownBy(() -> new Numbers(tokens)) + assertThatThrownBy(() -> new PositiveNumbers(tokens)) .isInstanceOf(IllegalArgumentException.class); } @@ -40,9 +40,9 @@ void sumZero_whenEmptyList() { List tokens = List.of(); // when - Numbers numbers = new Numbers(tokens); + PositiveNumbers positiveNumbers = new PositiveNumbers(tokens); // then - assertThat(0).isEqualTo(numbers.sum()); + assertThat(0).isEqualTo(positiveNumbers.sum()); } } diff --git a/src/test/java/utils/CustomDelimiterParserTest.java b/src/test/java/utils/CustomDelimiterParserTest.java deleted file mode 100644 index 4a43f927..00000000 --- a/src/test/java/utils/CustomDelimiterParserTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package utils; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class CustomDelimiterParserTest { - - private final CustomDelimiterParser parser = new CustomDelimiterParser(); - - @Test - @DisplayName("문자열이 커스텀 구분자 형식을 가지면 true를 반환한다") - void hasCustomDelimiter_true() { - String expression = "//;\n1;2;3"; - - assertThat(parser.hasCustomDelimiter(expression)).isTrue(); - } - - @Test - @DisplayName("문자열이 커스텀 구분자 형식을 가지지 않으면 false를 반환한다") - void hasCustomDelimiter_false() { - String expression = "1,2:3"; - - assertThat(parser.hasCustomDelimiter(expression)).isFalse(); - } - - @Test - @DisplayName("커스텀 구분자를 정상적으로 파싱한다") - void parseCustomDelimiter_success() { - String expression = "//;\n1;2;3"; - - String customDelimiter = parser.parseCustomDelimiter(expression); - - assertThat(customDelimiter).isEqualTo(";"); - } - - @Test - @DisplayName("커스텀 구분자 파싱 시 형식이 잘못되면 예외를 던진다") - void parseCustomDelimiter_invalidFormat() { - String invalidExpression = "//;1;2;3"; - - assertThatThrownBy(() -> parser.parseCustomDelimiter(invalidExpression)) - .isInstanceOf(IllegalArgumentException.class); - } - - @Test - @DisplayName("숫자 문자열을 정상적으로 파싱한다") - void parseNumbersExpression_success() { - String expression = "//;\n1;2;3"; - - String numbers = parser.parseNumbersExpression(expression); - - assertThat(numbers).isEqualTo("1;2;3"); - } -} \ No newline at end of file diff --git a/src/test/java/utils/ExpressionSplitterTest.java b/src/test/java/utils/ExpressionSplitterTest.java index 6dac4df9..f4b1c6ae 100644 --- a/src/test/java/utils/ExpressionSplitterTest.java +++ b/src/test/java/utils/ExpressionSplitterTest.java @@ -30,7 +30,7 @@ void splitByDefaultDelimiters() { void splitByCustomDelimiter() { // given Delimiters delimiters = new Delimiters(); - delimiters.addCustomDelimiters(";"); + delimiters.registerCustomDelimiter(";"); ExpressionSplitter splitter = new ExpressionSplitter(delimiters); String expression = "1;2,3:4"; @@ -55,4 +55,4 @@ void splitEmptyString() { // then assertThat(result).isEqualTo(List.of("")); } -} \ No newline at end of file +} diff --git a/src/test/java/utils/NumberParserTest.java b/src/test/java/utils/PositiveNumberParserTest.java similarity index 75% rename from src/test/java/utils/NumberParserTest.java rename to src/test/java/utils/PositiveNumberParserTest.java index 85c9fbf9..353cf55d 100644 --- a/src/test/java/utils/NumberParserTest.java +++ b/src/test/java/utils/PositiveNumberParserTest.java @@ -1,19 +1,19 @@ package utils; -import domain.Number; +import domain.PositiveNumber; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.*; @DisplayName("parser.NumberParser Test") -class NumberParserTest { +class PositiveNumberParserTest { @Test @DisplayName("정상 입력: 문자열을 정수로 변환하여 domain.Number 객체를 반환한다.") void parseValidInput() { - Number number = NumberParser.parse("42"); - assertThat(number).isEqualTo(new Number(42)); + PositiveNumber positiveNumber = NumberParser.parse("42"); + assertThat(positiveNumber).isEqualTo(new PositiveNumber(42)); } @Test diff --git a/src/test/java/view/InputViewTest.java b/src/test/java/view/InputViewTest.java deleted file mode 100644 index d81cf497..00000000 --- a/src/test/java/view/InputViewTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package view; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; - -import static org.assertj.core.api.Assertions.*; - -@DisplayName("view.InputView Test") -class InputViewTest { - - private static final String INPUT = "42\n"; - private static final InputStream ORIGINAL_IN = System.in; - - @AfterEach - void tearDown() { - System.setIn(ORIGINAL_IN); - } - - @Test - @DisplayName("readInput: 입력받은 문자열을 그대로 반환한다.") - void readExpression() { - System.setIn(new ByteArrayInputStream(INPUT.getBytes())); - InputView inputView = new InputView(); - - String result = inputView.readExpression(); - - assertThat(result).isEqualTo("42"); - } -} diff --git a/src/test/java/view/OutputViewTest.java b/src/test/java/view/OutputViewTest.java deleted file mode 100644 index e3ddd2a3..00000000 --- a/src/test/java/view/OutputViewTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package view; - -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 java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import static org.assertj.core.api.Assertions.*; - -@DisplayName("view.OutputView Test") -class OutputViewTest { - - private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - private final PrintStream originalOut = System.out; - private final OutputView outputView = new OutputView(); - - @BeforeEach - void setUp() { - System.setOut(new PrintStream(outputStream)); - } - - @AfterEach - void tearDown() { - System.setOut(originalOut); - } - - @Test - @DisplayName("첫 번째 숫자 입력 프롬프트를 출력한다.") - void printFirstNumberPrompt() { - outputView.printFirstNumberPrompt(); - String output = outputStream.toString(); - assertThat(output).contains(OutputView.FIRST_NUMBER_PROMPT); - } - - @Test - @DisplayName("두 번째 숫자 입력 프롬프트를 출력한다.") - void printSecondNumberPrompt() { - outputView.printSecondNumberPrompt(); - String output = outputStream.toString(); - assertThat(output).contains(OutputView.SECOND_NUMBER_PROMPT); - } - - @Test - @DisplayName("계산 결과를 출력한다.") - void printResult() { - int result = 10; - outputView.printResult(result); - String output = outputStream.toString(); - assertThat(output).contains(OutputView.RESULT_MESSAGE + result); - } -}