Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LBP] 윤준석 3, 4단계 과제 제출합니다. #74

Merged
merged 11 commits into from
Feb 13, 2025
Merged
69 changes: 36 additions & 33 deletions src/main/java/StringCalculator.java
Original file line number Diff line number Diff line change
@@ -1,59 +1,62 @@
import java.util.regex.Pattern;


/**
* 문자열을 숫자로 변환하여 합산하는 계산기임. <br>
* 쉼표 또는 콜론을 기본 구분자로 사용함.<br>
* //<구분자>\n 해당 위치에 원하는 구분자를 넣으면,<br>
* 단일 문자로 커스텀 구분자 지정이 가능함.<br>
* //@\n1:2@3,4 같은 형식도 처리 가능<br>
* 음수나 숫자가 아닌 값이 포함되면 예외를 발생시킴.
*/
public class StringCalculator {

// 기본 구분자
private static final String DEFAULT_DELIMITER = "[,|:]";
private static final String CUSTOM_DELIMITER_PREFIX = "//";
private static final String NEW_LINE = "\n";
private static final int CUSTOM_DELIMITER_PREFIX_LENGTH = 2;

public static int add(String input) {
if (input.isEmpty()) {
return 0;
}

String delimiter = "[,|:]"; // 기본 구분자 정의
String delimiter = DEFAULT_DELIMITER; // 기본 구분자 정의

if (input.startsWith("//")) { // 커스텀 구분자 처리 (여러 글자 지원)
int delimiterEnd = input.indexOf("\n");
String customDelimiter = input.substring(2, delimiterEnd);
delimiter = "[,|:]|" + Pattern.quote(customDelimiter);
if (input.startsWith(CUSTOM_DELIMITER_PREFIX)) { // 커스텀 구분자 처리 (여러 글자 지원)
int delimiterEnd = input.indexOf(NEW_LINE);
String customDelimiter = input.substring(CUSTOM_DELIMITER_PREFIX_LENGTH, delimiterEnd);
delimiter = DEFAULT_DELIMITER + "|" + Pattern.quote(customDelimiter);
input = input.substring(delimiterEnd + 1);
}

String[] numbers = input.split(Pattern.compile(delimiter).pattern());
Pattern pattern = Pattern.compile(delimiter);
String[] numbers = pattern.split(input);
return sum(numbers);
}

public static int sum(String[] numbers) { //문자열을 숫자로 변환하여 합을 계산
private static int sum(String[] numbers) { // 문자열을 숫자로 변환하여 합을 계산
int sum = 0;
StringBuilder negativeNumber = new StringBuilder(); // 음수가 포함될 경우 예외메시지 만드는데 사용
StringBuilder negativeNumbers = new StringBuilder(); // 음수값을 저장

for (String num : numbers) {
int value;

try {
value = Integer.parseInt(num); // parseInt 사용하여 문자열을 숫자로 변환
} catch (NumberFormatException e) {
// 숫자가 아닌 값이 포함되면 런타임 에러 발생
throw new RuntimeException("Invalid input: 숫자가 아닌 값이 포함되었습니다.");
}
// 음수값이 발견되면 negativeNumber에 추가
if (value < 0) {
negativeNumber.append(value).append(" ");
}

int value = parseAndValidateNumber(num, negativeNumbers); // 숫자 변환 및 검증
sum += value;
}
// 음수값이 있는 경우 예외처리
if (!negativeNumber.isEmpty()) {
throw new RuntimeException("입력한 값 중 음수 값이 존재합니다.: " + negativeNumber.toString().trim());

// 음수값이 존재하면 예외 발생
if (!negativeNumbers.isEmpty()) {
throw new RuntimeException("입력한 값 중 음수 값이 존재합니다: " + negativeNumbers.toString().trim());
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

생각해보니 어차피 예외를 던질 코드라면 입력된 모든 음수를 파악해서 알리는 것보다
아래 parseAndValidateNumber()의 조건문에서 바로 예외를 던지는 편이 더 낫지 않을까요?

준석의 생각은 어떤가요?

Copy link
Author

@junseok0304 junseok0304 Feb 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영 완료했습니다!


return sum;
}

private static int parseAndValidateNumber(String num, StringBuilder negativeNumbers) {
int value;

try {
value = Integer.parseInt(num);
} catch (NumberFormatException e) {
throw new RuntimeException("Invalid input: 숫자가 아닌 값이 포함되었습니다.");
}

if (value < 0) {
negativeNumbers.append(value).append(" ");
}

return value;
}
}
44 changes: 29 additions & 15 deletions src/test/java/StringCalculatorTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
Expand All @@ -13,11 +15,15 @@ void testEmptyStringReturnsZero() {
.isEqualTo(0);
}

@Test
@DisplayName("단일 숫자 출력 기능")
void testSingleNumber() {
assertThat(StringCalculator.add("1")).isEqualTo(1);
assertThat(StringCalculator.add("5")).isEqualTo(5);
@ParameterizedTest
@DisplayName("단일 숫자 입력 테스트")
@CsvSource({
"1, 1",
"5, 5",
"10, 10"
})
void testSingleNumber(String input, int expected) {
assertThat(StringCalculator.add(input)).isEqualTo(expected);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿! 👍


@Test
Expand All @@ -40,28 +46,36 @@ void testCustomDelimiter() {
assertThat(StringCalculator.add("//|\n2,3|50")).isEqualTo(55);
}

@Test
@ParameterizedTest
@DisplayName("특수문자가 포함된 커스텀 구분자를 사용한 숫자 합산 기능")
void testCustomDelimiterWithSpecialCharacters() {
assertThat(StringCalculator.add("//.\n2.3.5")).isEqualTo(10);
assertThat(StringCalculator.add("//$\n1$2$3")).isEqualTo(6);
@CsvSource({
"'//.\n2.3.5', 10",
"'//$\n1$2$3', 6"
})
void testCustomDelimiterWithSpecialCharacters(String input, int expected) {
assertThat(StringCalculator.add(input)).isEqualTo(expected);
}

@Test
@DisplayName("입력값 중 음수가 존재하는 경우를 식별하는 기능")
@DisplayName("입력값 중 음수가 존재하는 경우 예외 발생")
void testNegativeNumbersThrowException() {
assertThatThrownBy(() -> StringCalculator.add("1,-2,3"))
String input = "1,-2,3";
String expectedMessage = "입력한 값 중 음수 값이 존재합니다: -2";

assertThatThrownBy(() -> StringCalculator.add(input))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("입력한 값 중 음수 값이 존재합니다.");
.hasMessage(expectedMessage); // 예외 메시지가 정확히 일치하는지 검증
}

@Test
@DisplayName("입력값이 숫자가 아닌 값이 존재하는 경우를 식별하는 기능")
@DisplayName("입력값이 숫자가 아닌 값이 존재하는 경우 예외 발생")
void testNonNumericValuesThrowException() {
assertThatThrownBy(() -> StringCalculator.add("1,a,3"))
.isInstanceOf(RuntimeException.class);
.isInstanceOf(RuntimeException.class)
.hasMessage("Invalid input: 숫자가 아닌 값이 포함되었습니다.");

assertThatThrownBy(() -> StringCalculator.add("//;\n1;B;3"))
.isInstanceOf(RuntimeException.class);
.isInstanceOf(RuntimeException.class)
.hasMessage("Invalid input: 숫자가 아닌 값이 포함되었습니다.");
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 두 친구도 @ParameterizedTest를 활용할 수 있을 것 같은데 어떤가요?

Copy link
Author

@junseok0304 junseok0304 Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영 완료!

}