From a0cc935af668064d0db23d018f589550bdeae5c8 Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 10:02:19 +0900 Subject: [PATCH 01/12] =?UTF-8?q?docs:=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bd90ef0247..bc337504cf 100644 --- a/README.md +++ b/README.md @@ -1 +1,15 @@ -# java-calculator-precourse \ No newline at end of file +# java-calculator-precourse + +## 기능 구현 목록 + +1. 덧셈할 문자열 입력 및 검증 + - 예외 사항 + - 잘못된 형식인 경우 + - 잘못된 형식입니다. + - 커스텀 구분자의 기준 + - 기본 구분자, 빈문자열, 숫자, “/“, “\”, “n”을 제외한 모든 문자 허용 + - 1개만 허용 +2. 문자열 파싱 + 1. 커스텀 구분자가 정의되었다면 저장 +3. 숫자 계산 +4. 출력 \ No newline at end of file From 2a4422652685a060b0979d72d735d413cb208b52 Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 10:16:09 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20=EB=8D=A7=EC=85=88=ED=95=A0=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=9E=85=EB=A0=A5=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/calculator/Application.java | 7 +++++- .../calculator/constant/ErrorMessage.java | 18 ++++++++++++++ .../controller/CalculatorController.java | 24 +++++++++++++++++++ .../java/calculator/util/InputParser.java | 15 ++++++++++++ src/main/java/calculator/util/Validator.java | 17 +++++++++++++ src/main/java/calculator/view/InputView.java | 11 +++++++++ 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/main/java/calculator/constant/ErrorMessage.java create mode 100644 src/main/java/calculator/controller/CalculatorController.java create mode 100644 src/main/java/calculator/util/InputParser.java create mode 100644 src/main/java/calculator/util/Validator.java create mode 100644 src/main/java/calculator/view/InputView.java diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..b1561b903c 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,12 @@ package calculator; +import calculator.controller.CalculatorController; +import calculator.service.CalculatorService; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + CalculatorService calculatorService = new CalculatorService(); + CalculatorController calculatorController = new CalculatorController(calculatorService); + calculatorController.run(); } } diff --git a/src/main/java/calculator/constant/ErrorMessage.java b/src/main/java/calculator/constant/ErrorMessage.java new file mode 100644 index 0000000000..86d0d74cac --- /dev/null +++ b/src/main/java/calculator/constant/ErrorMessage.java @@ -0,0 +1,18 @@ +package calculator.constant; + +public enum ErrorMessage { + + FORMAT_ERROR("잘못된 형식입니다."), + ; + + private static final String ERROR_MESSAGE_PREFIX = "[ERROR] "; + private final String errorMessage; + + ErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getErrorMessage(Object... args) { + return ERROR_MESSAGE_PREFIX + String.format(errorMessage, args); + } +} diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java new file mode 100644 index 0000000000..067930b890 --- /dev/null +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -0,0 +1,24 @@ +package calculator.controller; + +import calculator.service.CalculatorService; +import calculator.util.InputParser; +import calculator.view.InputView; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +public class CalculatorController { + + private final CalculatorService calculatorService; + + public CalculatorController(CalculatorService calculatorService) { + this.calculatorService = calculatorService; + } + + public void run() { + String rawInput = InputView.readInput(); + String input = InputParser.parseInput(rawInput); + } +} + diff --git a/src/main/java/calculator/util/InputParser.java b/src/main/java/calculator/util/InputParser.java new file mode 100644 index 0000000000..3b03cae10c --- /dev/null +++ b/src/main/java/calculator/util/InputParser.java @@ -0,0 +1,15 @@ +package calculator.util; + +public final class InputParser { + + private InputParser() { + } + + public static String parseInput(String rawInput) { + rawInput = rawInput.strip(); + + Validator.validateInputFormat(rawInput); + + return rawInput; + } +} diff --git a/src/main/java/calculator/util/Validator.java b/src/main/java/calculator/util/Validator.java new file mode 100644 index 0000000000..7d12c209bf --- /dev/null +++ b/src/main/java/calculator/util/Validator.java @@ -0,0 +1,17 @@ +package calculator.util; + +import calculator.constant.ErrorMessage; + +public final class Validator { + + private static final String FORMAT = "(//[^\\d,:/\\n]\\\\n)?.*"; + + private Validator() {} + + + public static void validateInputFormat(String input) { + if (!input.matches(FORMAT)) { + throw new IllegalArgumentException(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + } +} diff --git a/src/main/java/calculator/view/InputView.java b/src/main/java/calculator/view/InputView.java new file mode 100644 index 0000000000..db1fd6880f --- /dev/null +++ b/src/main/java/calculator/view/InputView.java @@ -0,0 +1,11 @@ +package calculator.view; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + + public static String readInput() { + System.out.println("덧셈할 문자열을 입력해주세요."); + return Console.readLine(); + } +} From 98c5c39b57155db4fec88c7a4f6a8ea7678900ff Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 10:20:23 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=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 --- .../controller/CalculatorController.java | 1 + .../java/calculator/domain/Delimiter.java | 30 ++++++++++++ src/main/java/calculator/domain/Parser.java | 48 +++++++++++++++++++ .../calculator/service/CalculatorService.java | 14 ++++++ 4 files changed, 93 insertions(+) create mode 100644 src/main/java/calculator/domain/Delimiter.java create mode 100644 src/main/java/calculator/domain/Parser.java create mode 100644 src/main/java/calculator/service/CalculatorService.java diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java index 067930b890..9a849edfad 100644 --- a/src/main/java/calculator/controller/CalculatorController.java +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -19,6 +19,7 @@ public CalculatorController(CalculatorService calculatorService) { public void run() { String rawInput = InputView.readInput(); String input = InputParser.parseInput(rawInput); + int sum = calculatorService.calculate(input); } } diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java new file mode 100644 index 0000000000..d352e28419 --- /dev/null +++ b/src/main/java/calculator/domain/Delimiter.java @@ -0,0 +1,30 @@ +package calculator.domain; + +import java.util.List; + +public class Delimiter { + + private static final String INIT_DELIMITER = ",:"; + + private String delimiter; + + private Delimiter() { + delimiter = INIT_DELIMITER; + } + + public static Delimiter newInstance() { + return new Delimiter(); + } + + public void addDelimiter(String customDelimiter) { + delimiter += customDelimiter; + } + + public String getDelimiter() { + return delimiter; + } + + public List split(String target) { + return null; + } +} diff --git a/src/main/java/calculator/domain/Parser.java b/src/main/java/calculator/domain/Parser.java new file mode 100644 index 0000000000..207582c4f6 --- /dev/null +++ b/src/main/java/calculator/domain/Parser.java @@ -0,0 +1,48 @@ +package calculator.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +public class Parser { + + private final Delimiter delimiter; + private final String input; + + private Parser(Delimiter delimiter, String input) { + this.delimiter = delimiter; + this.input = input; + } + + public static Parser from(String input) { + Delimiter delimiter = Delimiter.newInstance(); + return new Parser(delimiter, input); + } + + public List parseTarget() { + String target = input; + + if (isCustom()) { + String customDelimiter = extractCustomDelimiter(input); + delimiter.addDelimiter(customDelimiter); + target = parseInput(input); + } + + return delimiter.split(target); + } + + private boolean isCustom() { + return input.startsWith("/"); + } + + private String extractCustomDelimiter(String input) { + int beginIndex = input.lastIndexOf("/") + 1; + int endIndex = input.indexOf("\\") - 1; + return input.substring(beginIndex, endIndex); + } + + private String parseInput(String input) { + int beginIndex = input.indexOf("n") + 1; + return input.substring(beginIndex); + } +} diff --git a/src/main/java/calculator/service/CalculatorService.java b/src/main/java/calculator/service/CalculatorService.java new file mode 100644 index 0000000000..9a38bb44b9 --- /dev/null +++ b/src/main/java/calculator/service/CalculatorService.java @@ -0,0 +1,14 @@ +package calculator.service; + +import calculator.domain.Numbers; +import calculator.domain.Parser; +import java.util.List; + +public class CalculatorService { + + public int calculate(String input) { + Parser parser = Parser.from(input); + List strings = parser.parseTarget(); + + } +} From 2bd60ca4682ee1b5b559055cdccf31ac8e720abc Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 10:30:46 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20=EC=88=AB=EC=9E=90=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=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 --- .../java/calculator/domain/Delimiter.java | 8 ++---- src/main/java/calculator/domain/Number.java | 28 +++++++++++++++++++ src/main/java/calculator/domain/Numbers.java | 27 ++++++++++++++++++ .../calculator/service/CalculatorService.java | 2 ++ .../java/calculator/util/NumberConvertor.java | 14 ++++++++++ src/main/java/calculator/view/OutputView.java | 27 ++++++++++++++++++ 6 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 src/main/java/calculator/domain/Number.java create mode 100644 src/main/java/calculator/domain/Numbers.java create mode 100644 src/main/java/calculator/util/NumberConvertor.java create mode 100644 src/main/java/calculator/view/OutputView.java diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java index d352e28419..d877e8abd7 100644 --- a/src/main/java/calculator/domain/Delimiter.java +++ b/src/main/java/calculator/domain/Delimiter.java @@ -1,6 +1,7 @@ package calculator.domain; import java.util.List; +import java.util.stream.Stream; public class Delimiter { @@ -20,11 +21,8 @@ public void addDelimiter(String customDelimiter) { delimiter += customDelimiter; } - public String getDelimiter() { - return delimiter; - } - public List split(String target) { - return null; + return Stream.of(target.split(delimiter)) + .toList(); } } diff --git a/src/main/java/calculator/domain/Number.java b/src/main/java/calculator/domain/Number.java new file mode 100644 index 0000000000..27ee54a4c9 --- /dev/null +++ b/src/main/java/calculator/domain/Number.java @@ -0,0 +1,28 @@ +package calculator.domain; + +import calculator.constant.ErrorMessage; +import calculator.util.NumberConvertor; + +public class Number { + + private final int number; + + private Number(int number) { + this.number = number; + } + + public static Number from(String s) { + validateNumber(s); + return new Number(NumberConvertor.convertToNumber(s)); + } + + private static void validateNumber(String s) { + if (!s.matches("\\d+")) { + throw new IllegalArgumentException(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + } + + public int addNumber(int addNumber) { + return addNumber + number; + } +} diff --git a/src/main/java/calculator/domain/Numbers.java b/src/main/java/calculator/domain/Numbers.java new file mode 100644 index 0000000000..12c40222c1 --- /dev/null +++ b/src/main/java/calculator/domain/Numbers.java @@ -0,0 +1,27 @@ +package calculator.domain; + +import java.util.List; + +public class Numbers { + + private final List numbers; + + private Numbers(List numbers) { + this.numbers = numbers; + } + + public static Numbers from(List strings) { + List numbers = strings.stream() + .map(Number::from) + .toList(); + return new Numbers(numbers); + } + + public int calculateSum() { + int sum = 0; + for (Number number : numbers) { + sum = number.addNumber(sum); + } + return sum; + } +} diff --git a/src/main/java/calculator/service/CalculatorService.java b/src/main/java/calculator/service/CalculatorService.java index 9a38bb44b9..7699ab978f 100644 --- a/src/main/java/calculator/service/CalculatorService.java +++ b/src/main/java/calculator/service/CalculatorService.java @@ -10,5 +10,7 @@ public int calculate(String input) { Parser parser = Parser.from(input); List strings = parser.parseTarget(); + Numbers numbers = Numbers.from(strings); + return numbers.calculateSum(); } } diff --git a/src/main/java/calculator/util/NumberConvertor.java b/src/main/java/calculator/util/NumberConvertor.java new file mode 100644 index 0000000000..4db39ed0a6 --- /dev/null +++ b/src/main/java/calculator/util/NumberConvertor.java @@ -0,0 +1,14 @@ +package calculator.util; + +import calculator.constant.ErrorMessage; + +public final class NumberConvertor { + + public static Integer convertToNumber(String input) { + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + } +} diff --git a/src/main/java/calculator/view/OutputView.java b/src/main/java/calculator/view/OutputView.java new file mode 100644 index 0000000000..b0054a9ef8 --- /dev/null +++ b/src/main/java/calculator/view/OutputView.java @@ -0,0 +1,27 @@ +package calculator.view; + +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +public class OutputView { + + private static final String NEW_LINE = System.lineSeparator(); + private static final Locale KOREA = Locale.KOREA; + private static final DateTimeFormatter DATETIME_FMT = + DateTimeFormatter.ofPattern("M월 dd일 E요일 HH:mm", KOREA); + private static final DateTimeFormatter DATE_FMT = + DateTimeFormatter.ofPattern("M월 dd일 E요일", KOREA); + private static final DateTimeFormatter TIME_FMT = + DateTimeFormatter.ofPattern("HH:mm", KOREA); + + private OutputView() { + } + + public static void print1() { + + } + + public static void printErrorMessage(IllegalArgumentException e) { + System.out.println(e.getMessage()); + } +} From da192d578189adb9f8df4920d6df5578d4d4823e Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 10:36:50 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=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 --- .../java/calculator/controller/CalculatorController.java | 8 ++++---- src/main/java/calculator/view/OutputView.java | 8 ++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java index 9a849edfad..aa4760ee90 100644 --- a/src/main/java/calculator/controller/CalculatorController.java +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -3,10 +3,7 @@ import calculator.service.CalculatorService; import calculator.util.InputParser; import calculator.view.InputView; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; +import calculator.view.OutputView; public class CalculatorController { @@ -19,7 +16,10 @@ public CalculatorController(CalculatorService calculatorService) { public void run() { String rawInput = InputView.readInput(); String input = InputParser.parseInput(rawInput); + int sum = calculatorService.calculate(input); + + OutputView.printSum(sum); } } diff --git a/src/main/java/calculator/view/OutputView.java b/src/main/java/calculator/view/OutputView.java index b0054a9ef8..33cbc472c9 100644 --- a/src/main/java/calculator/view/OutputView.java +++ b/src/main/java/calculator/view/OutputView.java @@ -17,11 +17,7 @@ public class OutputView { private OutputView() { } - public static void print1() { - - } - - public static void printErrorMessage(IllegalArgumentException e) { - System.out.println(e.getMessage()); + public static void printSum(int sum) { + System.out.printf("결과 : %d\n", sum); } } From 732f2d943a6629d4f6c13a2a1bdb14c36cb36cae Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 10:38:08 +0900 Subject: [PATCH 06/12] =?UTF-8?q?fix:=20=EA=B5=AC=EB=B6=84=EC=9E=90=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=20=EB=A1=9C=EC=A7=81=20=EB=B2=84=EA=B7=B8=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/main/java/calculator/domain/Delimiter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java index d877e8abd7..a9c51dd825 100644 --- a/src/main/java/calculator/domain/Delimiter.java +++ b/src/main/java/calculator/domain/Delimiter.java @@ -5,7 +5,7 @@ public class Delimiter { - private static final String INIT_DELIMITER = ",:"; + private static final String INIT_DELIMITER = "[,:]"; private String delimiter; @@ -18,7 +18,7 @@ public static Delimiter newInstance() { } public void addDelimiter(String customDelimiter) { - delimiter += customDelimiter; + delimiter += "|" + customDelimiter; } public List split(String target) { From 42845797fd6a71d1f7f3e6768440c02ec4ebe3a4 Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 11:54:19 +0900 Subject: [PATCH 07/12] =?UTF-8?q?fix:=20=EC=9E=85=EB=A0=A5=EA=B0=92=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EB=B2=84=EA=B7=B8=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/main/java/calculator/util/Validator.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/calculator/util/Validator.java b/src/main/java/calculator/util/Validator.java index 7d12c209bf..06a022b9ac 100644 --- a/src/main/java/calculator/util/Validator.java +++ b/src/main/java/calculator/util/Validator.java @@ -4,11 +4,10 @@ public final class Validator { - private static final String FORMAT = "(//[^\\d,:/\\n]\\\\n)?.*"; + private static final String FORMAT = "(//[^\\d,:/n\\\\]\\\\n)?[^/n\\\\]*"; private Validator() {} - public static void validateInputFormat(String input) { if (!input.matches(FORMAT)) { throw new IllegalArgumentException(ErrorMessage.FORMAT_ERROR.getErrorMessage()); From 2fca56dba59d9b1780acba2061d80e64cefe7754 Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 11:54:41 +0900 Subject: [PATCH 08/12] =?UTF-8?q?test:=20=EB=8B=A8=EC=9C=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=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 --- .../java/calculator/domain/DelimiterTest.java | 38 +++++++++++++++ .../java/calculator/domain/NumberTest.java | 29 +++++++++++ .../java/calculator/domain/NumbersTest.java | 25 ++++++++++ .../java/calculator/domain/ParserTest.java | 23 +++++++++ .../service/CalculatorServiceTest.java | 48 +++++++++++++++++++ .../java/calculator/util/InputParserTest.java | 15 ++++++ .../calculator/util/NumberConvertorTest.java | 23 +++++++++ .../java/calculator/util/ValidatorTest.java | 48 +++++++++++++++++++ 8 files changed, 249 insertions(+) create mode 100644 src/test/java/calculator/domain/DelimiterTest.java create mode 100644 src/test/java/calculator/domain/NumberTest.java create mode 100644 src/test/java/calculator/domain/NumbersTest.java create mode 100644 src/test/java/calculator/domain/ParserTest.java create mode 100644 src/test/java/calculator/service/CalculatorServiceTest.java create mode 100644 src/test/java/calculator/util/InputParserTest.java create mode 100644 src/test/java/calculator/util/NumberConvertorTest.java create mode 100644 src/test/java/calculator/util/ValidatorTest.java diff --git a/src/test/java/calculator/domain/DelimiterTest.java b/src/test/java/calculator/domain/DelimiterTest.java new file mode 100644 index 0000000000..315ea97110 --- /dev/null +++ b/src/test/java/calculator/domain/DelimiterTest.java @@ -0,0 +1,38 @@ +package calculator.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class DelimiterTest { + + @Test + void 기본구분자로_문자열_파싱() { + Delimiter delimiter = Delimiter.newInstance(); + + List result = delimiter.split("1,2:3").stream().toList(); + + assertThat(result).containsExactly("1", "2", "3"); + } + + @Test + void 커스텀구분자로_문자열_파싱() { + Delimiter delimiter = Delimiter.newInstance(); + delimiter.addDelimiter(";"); + + List result = delimiter.split("1;2;3").stream().toList(); + + assertThat(result).containsExactly("1", "2", "3"); + } + + @Test + void 기본구분자_및_커스텀구분자로_문자열_파싱() { + Delimiter delimiter = Delimiter.newInstance(); + delimiter.addDelimiter(";"); + + List result = delimiter.split("1,2:3;4").stream().toList(); + + assertThat(result).containsExactly("1", "2", "3", "4"); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/domain/NumberTest.java b/src/test/java/calculator/domain/NumberTest.java new file mode 100644 index 0000000000..993c8b46f5 --- /dev/null +++ b/src/test/java/calculator/domain/NumberTest.java @@ -0,0 +1,29 @@ +package calculator.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import calculator.constant.ErrorMessage; +import org.junit.jupiter.api.Test; + +class NumberTest { + + @Test + void 숫자_아닌_오류() { + assertThatThrownBy(() -> Number.from("a")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + + @Test + void 숫자_정상_저장() { + Number.from("1"); + } + + @Test + void 더하기() { + Number number = Number.from("1"); + int result = number.addNumber(2); + assertThat(result).isEqualTo(3); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/domain/NumbersTest.java b/src/test/java/calculator/domain/NumbersTest.java new file mode 100644 index 0000000000..9db0e78a5d --- /dev/null +++ b/src/test/java/calculator/domain/NumbersTest.java @@ -0,0 +1,25 @@ +package calculator.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import calculator.constant.ErrorMessage; +import java.util.List; +import org.junit.jupiter.api.Test; + +class NumbersTest { + + @Test + void 숫자가_아닌_문자_오류() { + assertThatThrownBy(() -> Numbers.from(List.of("a", "1", "2"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + + @Test + void 합계_구하기() { + Numbers numbers = Numbers.from(List.of("1", "2", "3", "4", "5")); + int result = numbers.calculateSum(); + assertThat(result).isEqualTo(15); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/domain/ParserTest.java b/src/test/java/calculator/domain/ParserTest.java new file mode 100644 index 0000000000..3083ba3508 --- /dev/null +++ b/src/test/java/calculator/domain/ParserTest.java @@ -0,0 +1,23 @@ +package calculator.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class ParserTest { + + @Test + void 기본구분자_문자열_파싱() { + Parser parser = Parser.from("1,2:3"); + List result = parser.parseTarget(); + assertThat(result).containsExactly("1", "2", "3"); + } + + @Test + void 커스텀구분자_문자열_파싱() { + Parser parser = Parser.from("//;\\n1,2:3;4"); + List result = parser.parseTarget(); + assertThat(result).containsExactly("1", "2", "3", "4"); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/service/CalculatorServiceTest.java b/src/test/java/calculator/service/CalculatorServiceTest.java new file mode 100644 index 0000000000..8b1b981557 --- /dev/null +++ b/src/test/java/calculator/service/CalculatorServiceTest.java @@ -0,0 +1,48 @@ +package calculator.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import calculator.constant.ErrorMessage; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class CalculatorServiceTest { + + private final CalculatorService calculatorService = new CalculatorService(); + + @ParameterizedTest + @MethodSource("SuccessInputProvider") + void 결과값_반환_성공(String input, int expectedResult) { + int result = calculatorService.calculate(input); + assertThat(result).isEqualTo(expectedResult); + } + + static Stream SuccessInputProvider() { + return Stream.of( + Arguments.of("//;\\n1,2:3;4", 10), + Arguments.of("//;\\n1234", 1234), + Arguments.of("1,2,3", 6), + Arguments.of("1,2:3", 6), + Arguments.of("123", 123) + ); + } + + @ParameterizedTest + @MethodSource("FailureInputProvider") + void 결과값_반환_실패(String input) { + assertThatThrownBy(() -> calculatorService.calculate(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + + static Stream FailureInputProvider() { + return Stream.of( + Arguments.of("//;\\na,b:c;d"), + Arguments.of("//;\\nabcd"), + Arguments.of("a,b,c") + ); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/util/InputParserTest.java b/src/test/java/calculator/util/InputParserTest.java new file mode 100644 index 0000000000..914a4dc725 --- /dev/null +++ b/src/test/java/calculator/util/InputParserTest.java @@ -0,0 +1,15 @@ +package calculator.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class InputParserTest { + + @Test + void 입력값_파싱() { + String input = InputParser.parseInput(" 1,2,3 "); + assertThat(input).isEqualTo("1,2,3"); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/util/NumberConvertorTest.java b/src/test/java/calculator/util/NumberConvertorTest.java new file mode 100644 index 0000000000..8548216f12 --- /dev/null +++ b/src/test/java/calculator/util/NumberConvertorTest.java @@ -0,0 +1,23 @@ +package calculator.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import calculator.constant.ErrorMessage; +import org.junit.jupiter.api.Test; + +class NumberConvertorTest { + + @Test + void 숫자_변환_성공() { + Integer number = NumberConvertor.convertToNumber("3"); + assertThat(number).isEqualTo(3); + } + + @Test + void 숫자_변환_오류() { + assertThatThrownBy(() -> NumberConvertor.convertToNumber("a")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/calculator/util/ValidatorTest.java b/src/test/java/calculator/util/ValidatorTest.java new file mode 100644 index 0000000000..f4dc5b6758 --- /dev/null +++ b/src/test/java/calculator/util/ValidatorTest.java @@ -0,0 +1,48 @@ +package calculator.util; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import calculator.constant.ErrorMessage; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ValidatorTest { + + @ParameterizedTest + @MethodSource("passInputProvider") + void 검증_통과(String input) { + Validator.validateInputFormat(input); + } + + static Stream passInputProvider() { + return Stream.of( + Arguments.of("//;\\n1,2:3;4"), + Arguments.of("//;\\n1234"), + Arguments.of("//;\\na,b:c;d"), + Arguments.of("//;\\nabcd"), + Arguments.of("1,2,3"), + Arguments.of("1,2:3"), + Arguments.of("123"), + Arguments.of("a,b,c") + ); + } + + @ParameterizedTest + @MethodSource("failInputProvider") + void 검증_예외_발생(String input) { + assertThatThrownBy(() -> Validator.validateInputFormat(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(ErrorMessage.FORMAT_ERROR.getErrorMessage()); + } + + static Stream failInputProvider() { + return Stream.of( + Arguments.of("//;-\\n1-2:3;4"), + Arguments.of("//;\\\\n1,2:3;4"), + Arguments.of("//;\\n//-\\n1,2-3;4"), + Arguments.of("//;\\n1,2\\3;4") + ); + } +} \ No newline at end of file From 6ff4b94542e389531a01d5f76460866b2aac8bfb Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 11:57:41 +0900 Subject: [PATCH 09/12] =?UTF-8?q?test:=20=ED=86=B5=ED=95=A9=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=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/calculator/ApplicationTest.java | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/src/test/java/calculator/ApplicationTest.java b/src/test/java/calculator/ApplicationTest.java index 93771fb011..ff5cab7e1c 100644 --- a/src/test/java/calculator/ApplicationTest.java +++ b/src/test/java/calculator/ApplicationTest.java @@ -1,12 +1,17 @@ package calculator; -import camp.nextstep.edu.missionutils.test.NsTest; -import org.junit.jupiter.api.Test; - import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import calculator.constant.ErrorMessage; +import camp.nextstep.edu.missionutils.test.NsTest; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + class ApplicationTest extends NsTest { @Test void 커스텀_구분자_사용() { @@ -19,8 +24,49 @@ class ApplicationTest extends NsTest { @Test void 예외_테스트() { assertSimpleTest(() -> - assertThatThrownBy(() -> runException("-1,2,3")) - .isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> runException("-1,2,3")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @ParameterizedTest + @MethodSource("successInputProvider") + void 성공_케이스(String input, int expectedResult) { + assertSimpleTest(() -> { + run(input); + assertThat(output()).contains("결과 : " + expectedResult); + }); + } + + static Stream successInputProvider() { + return Stream.of( + Arguments.of("//;\\n1,2:3;4", 10), + Arguments.of("//;\\n1234", 1234), + Arguments.of("1,2,3", 6), + Arguments.of("1,2:3", 6), + Arguments.of("123", 123) + ); + } + + @ParameterizedTest + @MethodSource("failureInputProvider") + void 실패_케이스(String input) { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining(ErrorMessage.FORMAT_ERROR.getErrorMessage()) + ); + } + + static Stream failureInputProvider() { + return Stream.of( + Arguments.of("//;\\na,b:c;d"), + Arguments.of("//;\\nabcd"), + Arguments.of("a,b,c"), + Arguments.of("//;-\\n1-2:3;4"), + Arguments.of("//;\\\\n1,2:3;4"), + Arguments.of("//;\\n//-\\n1,2-3;4"), + Arguments.of("//;\\n1,2\\3;4") ); } @@ -29,3 +75,4 @@ public void runMain() { Application.main(new String[]{}); } } + From 89f8ccfe1c82bf884866656c116fb31fa15fa831 Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 11:57:59 +0900 Subject: [PATCH 10/12] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/controller/CalculatorController.java | 1 - src/main/java/calculator/domain/Parser.java | 4 +--- src/main/java/calculator/view/OutputView.java | 12 ------------ 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/calculator/controller/CalculatorController.java b/src/main/java/calculator/controller/CalculatorController.java index aa4760ee90..9202dc8282 100644 --- a/src/main/java/calculator/controller/CalculatorController.java +++ b/src/main/java/calculator/controller/CalculatorController.java @@ -22,4 +22,3 @@ public void run() { OutputView.printSum(sum); } } - diff --git a/src/main/java/calculator/domain/Parser.java b/src/main/java/calculator/domain/Parser.java index 207582c4f6..2236cbbbce 100644 --- a/src/main/java/calculator/domain/Parser.java +++ b/src/main/java/calculator/domain/Parser.java @@ -1,8 +1,6 @@ package calculator.domain; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Stream; public class Parser { @@ -37,7 +35,7 @@ private boolean isCustom() { private String extractCustomDelimiter(String input) { int beginIndex = input.lastIndexOf("/") + 1; - int endIndex = input.indexOf("\\") - 1; + int endIndex = input.indexOf("\\"); return input.substring(beginIndex, endIndex); } diff --git a/src/main/java/calculator/view/OutputView.java b/src/main/java/calculator/view/OutputView.java index 33cbc472c9..99fcc65b7d 100644 --- a/src/main/java/calculator/view/OutputView.java +++ b/src/main/java/calculator/view/OutputView.java @@ -1,19 +1,7 @@ package calculator.view; -import java.time.format.DateTimeFormatter; -import java.util.Locale; - public class OutputView { - private static final String NEW_LINE = System.lineSeparator(); - private static final Locale KOREA = Locale.KOREA; - private static final DateTimeFormatter DATETIME_FMT = - DateTimeFormatter.ofPattern("M월 dd일 E요일 HH:mm", KOREA); - private static final DateTimeFormatter DATE_FMT = - DateTimeFormatter.ofPattern("M월 dd일 E요일", KOREA); - private static final DateTimeFormatter TIME_FMT = - DateTimeFormatter.ofPattern("HH:mm", KOREA); - private OutputView() { } From 5fea6c82b9e3ffbf5ec4dce9b16a8225a3adc09c Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 17:57:44 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20=EB=B9=88=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=20=EC=9E=85=EB=A0=A5=EC=8B=9C=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=EA=B3=BC=20=EB=8B=A4=EB=A5=B8=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=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/calculator/domain/Delimiter.java | 3 ++- src/main/java/calculator/service/CalculatorService.java | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/calculator/domain/Delimiter.java b/src/main/java/calculator/domain/Delimiter.java index a9c51dd825..27cfe6d0ab 100644 --- a/src/main/java/calculator/domain/Delimiter.java +++ b/src/main/java/calculator/domain/Delimiter.java @@ -1,6 +1,7 @@ package calculator.domain; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Stream; public class Delimiter { @@ -18,7 +19,7 @@ public static Delimiter newInstance() { } public void addDelimiter(String customDelimiter) { - delimiter += "|" + customDelimiter; + delimiter += "|" + Pattern.quote(customDelimiter); } public List split(String target) { diff --git a/src/main/java/calculator/service/CalculatorService.java b/src/main/java/calculator/service/CalculatorService.java index 7699ab978f..84235c1e05 100644 --- a/src/main/java/calculator/service/CalculatorService.java +++ b/src/main/java/calculator/service/CalculatorService.java @@ -7,6 +7,9 @@ public class CalculatorService { public int calculate(String input) { + if (input.isBlank()) { + return 0; + } Parser parser = Parser.from(input); List strings = parser.parseTarget(); From 724bdfbdeda12bd4c5c895e217f896164da75c6b Mon Sep 17 00:00:00 2001 From: khcho96 Date: Fri, 2 Jan 2026 17:58:16 +0900 Subject: [PATCH 12/12] =?UTF-8?q?fix:=20=EB=B9=88=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=20=EC=9E=85=EB=A0=A5=EC=8B=9C=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=EA=B3=BC=20=EB=8B=A4=EB=A5=B8=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=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/calculator/service/CalculatorService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/calculator/service/CalculatorService.java b/src/main/java/calculator/service/CalculatorService.java index 84235c1e05..cf1aa9a4bb 100644 --- a/src/main/java/calculator/service/CalculatorService.java +++ b/src/main/java/calculator/service/CalculatorService.java @@ -12,7 +12,6 @@ public int calculate(String input) { } Parser parser = Parser.from(input); List strings = parser.parseTarget(); - Numbers numbers = Numbers.from(strings); return numbers.calculateSum(); }