Skip to content

Commit 34fd4ec

Browse files
authored
고생하셨습니다.
🎉 PR 머지 완료! 🎉
1 parent 3aa0cd2 commit 34fd4ec

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ repositories {
1212
dependencies {
1313
testImplementation platform('org.junit:junit-bom:5.9.1')
1414
testImplementation('org.junit.jupiter:junit-jupiter')
15+
testImplementation platform('org.junit:junit-bom:5.9.1')
16+
testImplementation platform('org.assertj:assertj-bom:3.25.1')
17+
testImplementation('org.junit.jupiter:junit-jupiter')
18+
testImplementation('org.assertj:assertj-core')
1519
}
1620

1721
test {

src/main/java/Calculator.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import java.util.function.BiFunction;
2+
3+
public class Calculator {
4+
public static int calculate(BiFunction<Integer, Integer, Integer> func, int num1, int num2) {
5+
try {
6+
return func.apply(num1, num2);
7+
} catch (ArithmeticException e) {
8+
throw new ArithmeticException("연산 결과가 자료형 int의 범위를 벗어났습니다.");
9+
}
10+
}
11+
12+
public static int add(int num1, int num2) {
13+
return calculate(Math::addExact, num1, num2);
14+
}
15+
16+
public static int sub(int num1, int num2) {
17+
return calculate(Math::subtractExact, num1, num2);
18+
}
19+
20+
public static int mul(int num1, int num2) {
21+
return calculate(Math::multiplyExact, num1, num2);
22+
}
23+
24+
public static int div(int num1, int num2) {
25+
if (num2 == 0) {
26+
throw new ArithmeticException("0으로 나눌 수 없습니다.");
27+
}
28+
29+
return num1 / num2;
30+
}
31+
}

src/main/java/StringCalculator.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
public class StringCalculator {
2+
public static int calculate(String str) {
3+
String delimeter = "[,|:]";
4+
String[] tokens;
5+
int res = 0;
6+
7+
if (str == null || str.isBlank()) {
8+
return 0;
9+
}
10+
11+
String customDelimter = findCustomDelimeter(str);
12+
13+
if (customDelimter != null) {
14+
delimeter = customDelimter;
15+
tokens = str.substring(str.indexOf("\n") + 1).split(delimeter);
16+
}
17+
18+
else {
19+
tokens = str.split(delimeter);
20+
}
21+
22+
return sum(tokens);
23+
}
24+
25+
public static String findCustomDelimeter(String str) {
26+
int idx = 0;
27+
int startIdx = str.indexOf("//");
28+
int endIdx = str.indexOf("\n");
29+
30+
if ((startIdx == -1) != (endIdx == -1) || (startIdx + 2 == endIdx)) { // 커스텀 구분자 형식인 // 과 \n 중 하나만 존재하거나 구분자가 없는 경우
31+
throw new RuntimeException("커스텀 구분자 형식에 맞지 않는 문자열을 전달했습니다.");
32+
}
33+
34+
else if ((startIdx != -1)) { // 커스텀 구분자 형식인 경우
35+
return str.substring(startIdx + 2, endIdx);
36+
}
37+
38+
else { // 디폴트 구분자 형식인 경우
39+
return null;
40+
}
41+
}
42+
43+
public static int sum(String[] tokens) {
44+
int res = 0;
45+
46+
for (String token : tokens) {
47+
try {
48+
res = Math.addExact(res, Integer.parseInt(token));
49+
} catch (NumberFormatException e) {
50+
throw new RuntimeException("숫자 이외의 값 또는 음수를 전달할 수 없습니다.");
51+
} catch (ArithmeticException e) {
52+
throw new ArithmeticException("연산 결과가 자료형 int의 범위를 벗어났습니다.");
53+
}
54+
}
55+
56+
return res;
57+
}
58+
}

src/test/java/CalculatorTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import org.junit.jupiter.api.DisplayName;
2+
import org.junit.jupiter.api.Test;
3+
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
6+
7+
@DisplayName("계산기 기능 테스트 클래스")
8+
public class CalculatorTest {
9+
@Test
10+
@DisplayName("더하기 연산 테스트")
11+
public void testAdd() {
12+
int num1 = 1, num2 = 2;
13+
14+
assertThat(3).isEqualTo(Calculator.add(num1, num2));
15+
}
16+
17+
@Test
18+
@DisplayName("빼기 연산 테스트")
19+
public void testSub() {
20+
int num1 = 1, num2 = 2;
21+
22+
assertThat(-1).isEqualTo(Calculator.sub(num1, num2));
23+
}
24+
25+
@Test
26+
@DisplayName("곱하기 연산 테스트")
27+
public void testMul() {
28+
int num1 = 10, num2 = 2;
29+
30+
assertThat(20).isEqualTo(Calculator.mul(num1, num2));
31+
}
32+
33+
@Test
34+
@DisplayName("나누기 연산 테스트")
35+
public void testDiv() {
36+
int num1 = 1, num2 = 2;
37+
38+
assertThat(0).isEqualTo(Calculator.div(num1, num2));
39+
}
40+
41+
@Test
42+
@DisplayName("나누기 연산에서 나누는 값이 0인지 테스트")
43+
public void testDivideByZero() {
44+
int num1 = 2, num2 = 0;
45+
46+
assertThatThrownBy(() -> {
47+
Calculator.div(num1, num2);
48+
}).isInstanceOf(ArithmeticException.class);
49+
}
50+
51+
@Test
52+
@DisplayName("연산 후 int 범위를 벗어나는 지 테스트")
53+
public void testOverflow() {
54+
assertThatThrownBy(() -> {
55+
Calculator.add(Integer.MAX_VALUE, 1);
56+
}).isInstanceOf(ArithmeticException.class);
57+
58+
assertThatThrownBy(() -> {
59+
Calculator.sub(Integer.MIN_VALUE, 1);
60+
}).isInstanceOf(ArithmeticException.class);
61+
62+
assertThatThrownBy(() -> {
63+
Calculator.mul(Integer.MAX_VALUE, 2);
64+
}).isInstanceOf(ArithmeticException.class);
65+
}
66+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import org.junit.jupiter.api.DisplayName;
2+
import org.junit.jupiter.api.Test;
3+
import org.junit.jupiter.params.ParameterizedTest;
4+
import org.junit.jupiter.params.provider.ValueSource;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
8+
9+
public class StringCalculatorTest {
10+
@ParameterizedTest
11+
@DisplayName("문자열 계산기 기능 테스트")
12+
@ValueSource(strings = {"1:2:3", "1,2,3", "3:2,1", "3,2:1"})
13+
public void testDefaultDelimeter(String str) {
14+
assertThat(StringCalculator.calculate(str)).isEqualTo(6);
15+
}
16+
17+
@ParameterizedTest
18+
@ValueSource(strings = {"", " ", " "})
19+
@DisplayName("공백을 줬을 경우 테스트")
20+
public void testEmptyValue(String value) {
21+
assertThat(StringCalculator.calculate(value)).isEqualTo(0);
22+
}
23+
24+
@ParameterizedTest
25+
@ValueSource(strings = {"//;\n1;2;3", "//!!\n1!!2!!3"})
26+
@DisplayName("커스텀 구분자 테스트")
27+
public void testCustomDelimeter(String value) {
28+
assertThat(StringCalculator.calculate(value)).isEqualTo(6);
29+
}
30+
31+
@ParameterizedTest
32+
@ValueSource(strings = {"/;\n1;2;3", "/;\t1;2;3", "//;;\n1;2;3", "// n1 2 3"})
33+
@DisplayName("커스텀 구분자 형식에 맞지 않을 경우 예외 발생 테스트")
34+
public void testCustomDelimeterFormatError(String value) {
35+
assertThatThrownBy(() -> StringCalculator.calculate(value)).isInstanceOf(RuntimeException.class);
36+
}
37+
38+
@Test
39+
@DisplayName("커스텀 구분자에 아무것도 주지 않은 상황 테스트")
40+
public void testEmptyCustomDelimeter() {
41+
assertThatThrownBy(() -> StringCalculator.calculate("//\n1;2;3")).isInstanceOf(RuntimeException.class);
42+
}
43+
44+
@Test
45+
@DisplayName("계산 결과가 int 범위를 벗어나는 경우 예외 발생 테스트")
46+
public void testReusltOverflow() {
47+
assertThatThrownBy(() -> StringCalculator.calculate("2147483647:2:3")).isInstanceOf(ArithmeticException.class);
48+
}
49+
}

0 commit comments

Comments
 (0)