-
Notifications
You must be signed in to change notification settings - Fork 85
[이동훈] 1차시 미션 제출합니다. #106
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
Merged
+308
−157
Merged
[이동훈] 1차시 미션 제출합니다. #106
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
4ee4ba1
feat. 사칙연산 계산기 구현
dh2906 54afa40
feat. 0으로 나누는 경우 예외 발생
dh2906 06502aa
fix. 연산 후 int 범위를 벗어나면 예외 발생하도록 수정
dh2906 faa2f88
feat. 누락된 메소드 접근 제어자 추가
dh2906 6aaeab5
feat. 사칙연산 단위 테스트 추가
dh2906 eae23cd
fix. 0으로 나눌 경우 발생하는 예외 종류 수정
dh2906 0b0bd61
feat. 사칙연산 예외 발생 단위 테스트 추가
dh2906 4a76f60
feat. 문자열 계산기 구현
dh2906 4b08af2
feat. 문자열 계산기 테스트 추가
dh2906 11d80e0
build. AssertJ 의존성 추가
dh2906 682929a
refactor. 사칙연산 계산기 테스트 코드 JUnit -> AssertJ로 리팩토링
dh2906 65e7e2c
fix. 문자열이 비어있는지 검증하기 전 커스텀 구분자 파싱으로 발생하는 문제 해결
dh2906 98b0f3f
refactor. 문자열 계산기 테스트 코드 JUnit -> AssertJ로 리팩토링
dh2906 2394319
refactor. 에러 메시지를 하드 코딩 방식에서 상수 변수로 분리
dh2906 6546a24
refactor. 에러 메시지 포함 검증 시 상수 변수 활용
dh2906 3357666
style. 개행 컨벤션 적용
dh2906 6e1cc54
refactor. 메소드 책임 분할
dh2906 015db6f
fix. 단어 철자 오타 수정
dh2906 98575d9
fix. 메소드 명 수정
dh2906 32da58d
chore. 이전에 구현한 계산기 클래스 삭제
dh2906 fa35922
fix. 공백 문자열이 들어온 경우 계산 결과 0 반환하도록 수정
dh2906 f7824c7
fix. 문자열로 공백이 들어온 경우 테스트 분할
dh2906 640f52e
feat. 에러 메세지 집합 클래스 생성
dh2906 e71b3db
refactor. ErrorMessage 상수 사용하도록 변경
dh2906 859680d
refactor. 구분자 정규 표현식 필드 변수 -> 메소드 지역 변수로 수정
dh2906 b2a779c
refactor. 문자열 유틸 클래스로 분할
dh2906 d8d8ecc
refactor. 유틸 테스트 클래스 분할
dh2906 a5edf2c
fix. 잘못된 에러 메시지 반환하는 문제 수정
dh2906 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package domain; | ||
|
||
import exception.ErrorMessage; | ||
|
||
public class Calculator { | ||
|
||
public int add(int num1, int num2) { | ||
return Math.addExact(num1, num2); | ||
} | ||
|
||
public int sub(int num1, int num2) { | ||
return Math.subtractExact(num1, num2); | ||
} | ||
|
||
public int mul(int num1, int num2) { | ||
return Math.multiplyExact(num1, num2); | ||
} | ||
|
||
public int div(int num1, int num2) { | ||
if (num2 == 0) | ||
throw new ArithmeticException(ErrorMessage.DIVIDE_BY_ZERO); | ||
|
||
return num1 / num2; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package domain; | ||
|
||
import exception.ErrorMessage; | ||
import util.DelimiterUtil; | ||
import util.ParseUtil; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.regex.Pattern; | ||
|
||
public class StringCalculator { | ||
|
||
public int calculate(String str) { | ||
if (str == null) { | ||
throw new RuntimeException(ErrorMessage.NULL_STRING); | ||
} | ||
|
||
if (str.isBlank()) | ||
return 0; | ||
|
||
String customDelimiter = DelimiterUtil.findCustomDelimiter(str); | ||
String strNumbers = extractNumber(str, customDelimiter); | ||
String[] tokens = splitTokens(strNumbers, customDelimiter); | ||
List<Integer> numbers = ParseUtil.parseNumber(tokens); | ||
|
||
return sum(numbers); | ||
} | ||
|
||
private String extractNumber(String str, String customDelimiter) { | ||
if (customDelimiter != null) { | ||
return str.substring(str.indexOf("\n") + 1); | ||
} | ||
|
||
return str; | ||
} | ||
|
||
private String[] splitTokens(String strNumbers, String customDelimiter) { | ||
String delimiterRegex = "[,|:]"; | ||
|
||
if (customDelimiter == null) { | ||
return strNumbers.split(delimiterRegex); | ||
} | ||
|
||
return strNumbers.split(Pattern.quote(customDelimiter)); | ||
} | ||
|
||
private int sum(List<Integer> numbers) { | ||
return numbers.stream() | ||
.mapToInt(Integer::intValue) | ||
.sum(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package exception; | ||
|
||
public class ErrorMessage { | ||
|
||
public static final String NULL_STRING = "문자열에 null 값이 전달되었습니다."; | ||
public static final String CUSTOM_DELIMITER_NOT_FOUND = "커스텀 구분자를 찾을 수 없습니다."; | ||
public static final String NEGATIVE_NUMBER_NOT_ALLOWED = "음수는 처리할 수 없습니다."; | ||
public static final String INVALID_STRING = "문자열은 처리할 수 없습니다."; | ||
public static final String DIVIDE_BY_ZERO = "0으로 나눌 수 없습니다."; | ||
|
||
private ErrorMessage() { | ||
throw new RuntimeException(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package util; | ||
|
||
import exception.ErrorMessage; | ||
|
||
public class DelimiterUtil { | ||
|
||
public static String findCustomDelimiter(String str) { | ||
int startDelimiterIdx = str.indexOf("//"); | ||
int endDelimiterIdx = str.indexOf("\n"); | ||
|
||
if (startDelimiterIdx == -1 && endDelimiterIdx == -1) { | ||
return null; | ||
} | ||
|
||
if ((startDelimiterIdx == -1) ^ (endDelimiterIdx == -1) || (startDelimiterIdx + 2 == endDelimiterIdx)) { | ||
throw new RuntimeException(ErrorMessage.CUSTOM_DELIMITER_NOT_FOUND); | ||
} | ||
|
||
return str.substring(startDelimiterIdx + 2, endDelimiterIdx); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package util; | ||
|
||
import exception.ErrorMessage; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class ParseUtil { | ||
|
||
public static List<Integer> parseNumber(String[] tokens) { | ||
return Arrays.stream(tokens) | ||
.map(ParseUtil::parseTokenToInt) | ||
.toList(); | ||
} | ||
|
||
public static int parseTokenToInt(String token) { | ||
try { | ||
int number = Integer.parseInt(token.trim()); | ||
|
||
if (number < 0) { | ||
throw new RuntimeException(ErrorMessage.NEGATIVE_NUMBER_NOT_ALLOWED); | ||
} | ||
|
||
return number; | ||
} catch (NumberFormatException ex) { | ||
throw new RuntimeException(ErrorMessage.INVALID_STRING); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,83 @@ | ||
import org.junit.jupiter.api.DisplayName; | ||
import domain.Calculator; | ||
import exception.ErrorMessage; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
import static org.assertj.core.api.Assertions.*; | ||
|
||
@DisplayName("계산기 기능 테스트 클래스") | ||
public class CalculatorTest { | ||
|
||
private final Calculator calculator = new Calculator(); | ||
|
||
@Test | ||
public void 덧셈_테스트() { | ||
final int num1 = 1; | ||
final int num2 = 2; | ||
final int actual = calculator.add(num1, num2); | ||
|
||
assertThat(actual).isEqualTo(num1 + num2); | ||
} | ||
|
||
@Test | ||
@DisplayName("더하기 연산 테스트") | ||
public void testAdd() { | ||
int num1 = 1, num2 = 2; | ||
public void 뺄셈_테스트() { | ||
final int num1 = 3; | ||
final int num2 = 2; | ||
final int actual = calculator.sub(num1, num2); | ||
|
||
assertThat(3).isEqualTo(Calculator.add(num1, num2)); | ||
assertThat(actual).isEqualTo(num1 - num2); | ||
} | ||
|
||
@Test | ||
@DisplayName("빼기 연산 테스트") | ||
public void testSub() { | ||
int num1 = 1, num2 = 2; | ||
public void 곱셈_테스트() { | ||
final int num1 = 3; | ||
final int num2 = 2; | ||
final int actual = calculator.mul(num1, num2); | ||
|
||
assertThat(-1).isEqualTo(Calculator.sub(num1, num2)); | ||
assertThat(actual).isEqualTo(num1 * num2); | ||
} | ||
|
||
@Test | ||
@DisplayName("곱하기 연산 테스트") | ||
public void testMul() { | ||
int num1 = 10, num2 = 2; | ||
public void 나눗셈_테스트() { | ||
final int num1 = 4; | ||
final int num2 = 2; | ||
final int actual = calculator.div(num1, num2); | ||
|
||
assertThat(20).isEqualTo(Calculator.mul(num1, num2)); | ||
assertThat(actual).isEqualTo(num1 / num2); | ||
} | ||
|
||
@Test | ||
@DisplayName("나누기 연산 테스트") | ||
public void testDiv() { | ||
int num1 = 1, num2 = 2; | ||
public void 덧셈_오버플로우_예외_발생() { | ||
final int num1 = Integer.MAX_VALUE; | ||
final int num2 = Integer.MAX_VALUE; | ||
|
||
assertThat(0).isEqualTo(Calculator.div(num1, num2)); | ||
assertThatThrownBy(() -> calculator.add(num1, num2)) | ||
.isInstanceOf(ArithmeticException.class); | ||
} | ||
|
||
@Test | ||
@DisplayName("나누기 연산에서 나누는 값이 0인지 테스트") | ||
public void testDivideByZero() { | ||
int num1 = 2, num2 = 0; | ||
public void 뺄셈_오버플로우_예외_발생() { | ||
final int num1 = Integer.MIN_VALUE; | ||
final int num2 = Integer.MAX_VALUE; | ||
|
||
assertThatThrownBy(() -> { | ||
Calculator.div(num1, num2); | ||
}).isInstanceOf(ArithmeticException.class); | ||
assertThatThrownBy(() -> calculator.sub(num1, num2)) | ||
.isInstanceOf(ArithmeticException.class); | ||
} | ||
|
||
@Test | ||
@DisplayName("연산 후 int 범위를 벗어나는 지 테스트") | ||
public void testOverflow() { | ||
assertThatThrownBy(() -> { | ||
Calculator.add(Integer.MAX_VALUE, 1); | ||
}).isInstanceOf(ArithmeticException.class); | ||
|
||
assertThatThrownBy(() -> { | ||
Calculator.sub(Integer.MIN_VALUE, 1); | ||
}).isInstanceOf(ArithmeticException.class); | ||
|
||
assertThatThrownBy(() -> { | ||
Calculator.mul(Integer.MAX_VALUE, 2); | ||
}).isInstanceOf(ArithmeticException.class); | ||
public void 곱셈_오버플로우_예외_발생() { | ||
final int num1 = Integer.MAX_VALUE; | ||
final int num2 = Integer.MAX_VALUE; | ||
|
||
assertThatThrownBy(() -> calculator.mul(num1, num2)) | ||
.isInstanceOf(ArithmeticException.class); | ||
} | ||
|
||
@Test | ||
public void 나눗셈_0으로_나누면_예외_발생() { | ||
final int num1 = Integer.MAX_VALUE; | ||
final int num2 = 0; | ||
|
||
assertThatThrownBy(() -> calculator.div(num1, num2)) | ||
.isInstanceOf(ArithmeticException.class) | ||
.hasMessageContaining(ErrorMessage.DIVIDE_BY_ZERO); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
~~Exact()
메서드는 어떤 장점이 있나요?일반 연산자(
+
,-
등) 과 어떤 차이점이 있나요?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
대표적인 예로 addExact는 비트 연산을 통해 int 타입인 두 수의 합이 int형의 저장 가능 범위를 벗어난다면 예외를 발생시켜주고 있습니다.
일반적인 연산자를 사용한다면 오버플로우 발생 시 부호 비트가 값의 크기를 나타내기 위한 비트로 사용되서 결과 값이 예상치 못한 값으로 나올 수 있습니다.