diff --git a/README.md b/README.md index bd90ef0247..b3e97b0840 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# java-calculator-precourse \ No newline at end of file +# java-calculator-precourse + +1. 쉼표 혹은 콜론을 구분자로 가지는 문자열을 구분자 기준으로 분리한 각 숫자의 합을 반환 +2. 커스텀 구분자 지정 +3. 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시키기 + - 음수를 입력했을 때 + - 숫자가 아닌값을 입력했을 때 +4. 빈 문자열이나 null을 입력 받았을 때 +5. 숫자 하나를 입력 받았을 때 그대로 반환한다 \ No newline at end of file diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index 573580fb40..8981ffa7b4 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,7 +1,27 @@ package calculator; +import camp.nextstep.edu.missionutils.Console; + +import java.util.Scanner; +import static java.lang.Integer.parseInt; public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + // 사용자에게 입력을 요청합니다. + System.out.println("덧셈할 문자열을 입력해 주세요."); + + String input; + try { + input = Console.readLine(); + } catch (Exception e) { + // 빈 입력이나 예외 발생 시 빈 문자열로 처리 + input = ""; + } + + // 계산기 인스턴스 생성하고 덧셈을 수행합니다. + StringCalculator calculator = new StringCalculator(); + int result = calculator.add(input); + + // 결과를 출력합니다. + System.out.println("결과 : " + result); } -} +} \ No newline at end of file diff --git a/src/main/java/calculator/StringCalculator.java b/src/main/java/calculator/StringCalculator.java new file mode 100644 index 0000000000..d5e02dfaa4 --- /dev/null +++ b/src/main/java/calculator/StringCalculator.java @@ -0,0 +1,51 @@ +package calculator; + +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StringCalculator { + + private static final Pattern CUSTOM_DELIMITER_PATTERN = Pattern.compile("//(.)\\\\n(.*)"); + + public int add(final String text) { + // 1. 입력값이 null 이거나 비어있으면 0을 반환합니다. + if(text == null || text.trim().isEmpty()){ + return 0; + } + + // Matcher를 사용하여 커스텀 구분자 패턴과 일치하는지 확인합니다. + Matcher matcher = CUSTOM_DELIMITER_PATTERN.matcher(text); + if (matcher.find()) { + String customDelimiter = matcher.group(1); // 커스텀 구분자 + String numbersPart = matcher.group(2); // 숫자 구분 + return splitAndSum(numbersPart, Pattern.quote(customDelimiter)); + } + // 커스텀 구분자가 없으면 기본 구분자를 사용하여 계산 + return splitAndSum(text, "[,:]"); + } + + private int splitAndSum(final String text, final String delimiter) { + // 구분자를 기준으로 문자열을 분리 + String[] numbers = text.split(delimiter); + + // 분리된 각 문자열을 숫자로 변환하고 합계를 구함 + return Arrays.stream(numbers) + .mapToInt(this::parseAndValidate) + .sum(); + } + + private int parseAndValidate(final String numberStr) { + try { + int number = Integer.parseInt(numberStr.trim()); + // 음수인지 확인하여 예외를 발생시킵니다. + if(number < 0){ + throw new IllegalArgumentException("음수는 입력할 수 없습니다."); + } + return number; + } catch (NumberFormatException e) { + // 숫자로 변환할 수 없는 경우 예외를 발생시킵니다. + throw new IllegalArgumentException("숫자가 아닌 값이 포함되어 있습니다."); + } + } +} diff --git a/src/test/java/calculator/ApplicationTest.java b/src/test/java/calculator/ApplicationTest.java index 93771fb011..b8bbbf2506 100644 --- a/src/test/java/calculator/ApplicationTest.java +++ b/src/test/java/calculator/ApplicationTest.java @@ -1,6 +1,7 @@ package calculator; import camp.nextstep.edu.missionutils.test.NsTest; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import static camp.nextstep.edu.missionutils.test.Assertions.assertSimpleTest; @@ -8,19 +9,76 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; class ApplicationTest extends NsTest { + + @Test + @DisplayName("기본 구분자(쉼표)를 사용한 덧셈") + void 기본_구분자_쉼표() { + assertSimpleTest(() -> { + run("1,2,3"); + assertThat(output()).contains("결과 : 6"); + }); + } + + @Test + @DisplayName("기본 구분자(콜론)를 사용한 덧셈") + void 기본_구분자_콜론() { + assertSimpleTest(() -> { + run("1:2:3"); + assertThat(output()).contains("결과 : 6"); + }); + } + + @Test + @DisplayName("기본 구분자(쉼표와 콜론 혼용)를 사용한 덧셈") + void 기본_구분자_혼용() { + assertSimpleTest(() -> { + run("1,2:3"); + assertThat(output()).contains("결과 : 6"); + }); + } + @Test - void 커스텀_구분자_사용() { + @DisplayName("커스텀 구분자를 사용한 덧셈") + void 커스텀_구분자_덧셈() { assertSimpleTest(() -> { - run("//;\\n1"); - assertThat(output()).contains("결과 : 1"); + run("//;\n1;2;3"); + assertThat(output()).contains("결과 : 6"); }); } @Test - void 예외_테스트() { + @DisplayName("단일 숫자 입력 시 해당 숫자 반환") + void 단일_숫자() { + assertSimpleTest(() -> { + run("5"); + assertThat(output()).contains("결과 : 5"); + }); + } + + @Test + @DisplayName("빈 문자열 또는 null 입력 시 0 반환") + void 빈_문자열_또는_null() { + assertSimpleTest(() -> { + run(""); + assertThat(output()).contains("결과 : 0"); + }); + } + + @Test + @DisplayName("음수 입력 시 IllegalArgumentException 발생") + void 음수_예외() { + assertSimpleTest(() -> + assertThatThrownBy(() -> runException("-1,2,3")) + .isInstanceOf(IllegalArgumentException.class) + ); + } + + @Test + @DisplayName("숫자가 아닌 문자 입력 시 IllegalArgumentException 발생") + void 숫자가_아닌_문자_예외() { assertSimpleTest(() -> - assertThatThrownBy(() -> runException("-1,2,3")) - .isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> runException("1,a,2")) + .isInstanceOf(IllegalArgumentException.class) ); }