Skip to content

[BCSD Lab 임아리] 1차시 미션 제출합니다. #105

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
merged 15 commits into from
Aug 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/main/java/SimpleCalculator.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
public class SimpleCalculator {
public int add(int firstNum, int secondNum){
return firstNum + secondNum;
public int add(int a, int b) {
return Math.addExact(a, b);

Choose a reason for hiding this comment

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

addExact()subtractExact() 함수들은 일단 +, - 랑 어떤점이 다른가요?

Copy link
Author

Choose a reason for hiding this comment

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

내부적으로 long으로 연산한 후 int 범위를 벗어나면 ArithmeticException을 던집니다! 예전 코드에서는 그저 +, - 만 사용하여 계산하였기 때문에 오버플로우 처리가 되지 않았습니다. 그래서 이번에는 추가했습니다!

}
public int multiply(int firstNum, int secondNum){
return firstNum * secondNum;
}
public int divide(int firstNum, int secondNum){
return firstNum / secondNum;

public int minus(int a, int b) {
return Math.subtractExact(a, b);
}
public int minus(int firstNum, int secondNum){
return firstNum - secondNum;

public int multiply(int a, int b) {
return Math.multiplyExact(a, b);
}

public int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("0으로 나눌 수 없습니다.");
}
if (a == Integer.MIN_VALUE && b == -1) {
Copy link

Choose a reason for hiding this comment

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

오... int 형의 음수와 양수의 절댓값이 음수가 더 크니까 해당 케이스에서 오버플로우가 발생할 수 있네요.
하나 배워갑니다!

throw new ArithmeticException("정수 범위를 벗어났습니다.");
}
return a / b;
}
}
77 changes: 36 additions & 41 deletions src/main/java/StringCalculator.java
Original file line number Diff line number Diff line change
@@ -1,72 +1,64 @@
/*
input을 받고 빈문자열인지 null인지 체크
구분자 체크 -> 구분자 예외 체크
구분자 대로 문자열 계산기 구현
*/

import java.util.regex.Pattern;

public class StringCalculator {

//입력 문자열이 null인지 확인
public String checkInput(String input){
if(input == null) throw new RuntimeException("null은 허용되지 않습니다.");
return input;
private void validateInput(String input){
if (input == null){
throw new RuntimeException("null은 허용되지 않습니다.");
}
}

//커스텀 구분자가 있는지 확인
public int checkDelimiter(String checkedInput) {
if(checkedInput.isEmpty()) return -2; //문자열이 빈 경우


if (checkedInput.startsWith("//")) { //커스텀 구분자를 설정하는가?
int idx = checkedInput.indexOf("\n"); //제대로된 형식인가?
if (idx == -1) throw new RuntimeException("잘못된 커스텀 구분자 형식입니다.");
return idx; //구분자 위치 전달
private int getDelimiterIndex(String input) {
if (input.startsWith("//")) {
int delimiterIdx = input.indexOf("\n");
if (delimiterIdx == -1){
throw new RuntimeException("잘못된 커스텀 구분자 형식입니다.");
}
return delimiterIdx;
}

return -1; //기본 구분자대로 문자열을 나눔
}

private String[] splitInput(String checkedInput, int idx){
if(idx == -1){
private String[] splitInput(String checkedInput, int delimiterIdx){
if (delimiterIdx == -1){
String delimiter = "[,:]";
return checkedInput.split(delimiter); //기본 구분자대로 나누기
}
else if(idx == -2){
return new String[0]; //빈 문자열인 경우
return checkedInput.split(delimiter);
}
else{
String delimiter = checkedInput.substring(2, idx); //구분자 나누기
String regex = Pattern.quote(delimiter); //정규표현식에 사용되는 문자가 커스텀 구분자일 경우를 위해 설정
return checkedInput.substring(idx + 1).split(regex); //커스텀 구분자대로 문자열을 나눔
String delimiter = checkedInput.substring(2, delimiterIdx);
String regex = Pattern.quote(delimiter);
return checkedInput.substring(delimiterIdx + 1).split(regex);
}
}

//문자열 덧셈 실행
public int sum(String[] strings){
if(strings.length == 0) return 0;
private int sum(String[] strings){
if (strings.length == 0){
return 0;
}

int sum = 0;

for(var n : strings){
if(n.isEmpty()) throw new RuntimeException("빈 문자열입니다.");
if (n.isEmpty()){
throw new RuntimeException("빈 문자열입니다.");
}

int num = checkException(n);
int num = validateNumbers(n);

//예외 처리
if(sum > Integer.MAX_VALUE - num || sum < Integer.MIN_VALUE + num) throw new RuntimeException("int 범위를 벗어났습니다.");
if (sum > Integer.MAX_VALUE - num || sum < Integer.MIN_VALUE + num) throw new RuntimeException("int 범위를 벗어났습니다.");

sum += num;
}
return sum;
}

private int checkException(String n){
private int validateNumbers(String n){
int num;
try{
num = Integer.parseInt(n);
if(num < 0) throw new RuntimeException("음수는 입력이 불가합니다.");
if (num < 0){
throw new RuntimeException("음수는 입력이 불가합니다.");
}
}
catch(NumberFormatException msg){
throw new RuntimeException("int 값을 벗어났거나 잘못된 숫자 형식입니다.");
Expand All @@ -75,9 +67,12 @@ private int checkException(String n){
}

public int calculate(String input){
String checkedInput = checkInput(input);
int idx = checkDelimiter(checkedInput);
String[] strings = splitInput(checkedInput, idx);
validateInput(input);
if (input.isEmpty()){
return 0;
}
int delimiterIndex = getDelimiterIndex(input);
String[] strings = splitInput(input, delimiterIndex);
return sum(strings);
}
}
45 changes: 36 additions & 9 deletions src/test/java/SimpleCalculatorTest.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,64 @@
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.assertj.core.api.Assertions.assertThat;

public class SimpleCalculatorTest {

private final SimpleCalculator calc = new SimpleCalculator();

@Nested

Choose a reason for hiding this comment

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

이건 어떤 역할을 하는 어노테이션인가요?

Copy link
Author

Choose a reason for hiding this comment

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

중첩된 테스트 클래스를 정의할 때 붙이는 어노테이션입니다! Junit5랑 AssertJ 테스트로 나누고 싶어서 어노테이션을 쓰고 나누려고 했는데... 지금 보니 코드가 그 부분을 제대로 설명하지 못하고 있어보이네요. 이 부분도 수정하겠습니다!

class SimpleTest {
class TestWithJunit5 {

@Test
void addTest(){
SimpleCalculator calc = new SimpleCalculator();
void addTest() {
assertEquals(3, calc.add(1, 2));
assertEquals(5, calc.add(3, 2));
}

@Test
void minusTest(){
SimpleCalculator calc = new SimpleCalculator();
void minusTest() {
assertEquals(3, calc.minus(5, 2));
assertEquals(-2, calc.minus(3, 5));
}

@Test
void multiply(){
SimpleCalculator calc = new SimpleCalculator();
void multiply() {
assertEquals(10, calc.multiply(5, 2));
assertEquals(15, calc.multiply(3, 5));
}

@Test
void divide(){
SimpleCalculator calc = new SimpleCalculator();
void divide() {
assertEquals(5, calc.divide(10, 2));
assertEquals(30, calc.divide(180, 6));
}
}

@Nested
class TestWithAssertJ {

@Test
void simpleCalcTest(){
assertThat(calc.add(1, 2)).isEqualTo(3);

Choose a reason for hiding this comment

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

assertThat() 방식과 assertEquals() 방식을 사용하신것 같은데 둘의 차이가 뭔가요?
각각의 장단점이 있나요? (궁금)

Copy link
Author

Choose a reason for hiding this comment

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

https://velog.io/@doolchong/assertEqual%EA%B3%BC-assertThat

이런 장점들이 존재합니다! 이번 미션에서는 테스트 코드를 학습하는 것을 중점으로 두었기 때문에 AssertJ, Junit5 모두 사용해보고 싶어서 이런식으로 작성해보았습니다. 이 부분도 장단점에 맞게 수정해보겠습니다!

assertThat(calc.minus(1,2)).isEqualTo(-1);
assertThat(calc.divide(4, 2)).isEqualTo(2);
assertThat(calc.multiply(3,2)).isEqualTo(6);
}

@Test
void errorTestDivideZero() {
assertThatThrownBy(() -> calc.divide(2, 0)).isInstanceOf(ArithmeticException.class);
}

@Test
void errorTestOverFlow() {
assertThatThrownBy(() -> calc.add(Integer.MAX_VALUE, 1)).isInstanceOf(ArithmeticException.class);
assertThatThrownBy(() -> calc.minus(Integer.MAX_VALUE, -3)).isInstanceOf(ArithmeticException.class);
assertThatThrownBy(() -> calc.multiply(Integer.MAX_VALUE, 3)).isInstanceOf(ArithmeticException.class);
assertThatThrownBy(() -> calc.divide(Integer.MIN_VALUE, -1)).isInstanceOf(ArithmeticException.class);
}
}
}
36 changes: 18 additions & 18 deletions src/test/java/StringCalculatorTest.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class StringCalculatorTest {

private final StringCalculator calc = new StringCalculator();

@Nested
class StringTest{

@Test
void default_delimiter_Test(){
StringCalculator calc = new StringCalculator();
void defaultDelimiterTest(){
assertEquals(3, calc.calculate("1,2"));
assertEquals(6, calc.calculate("1,2,3"));
assertEquals(3, calc.calculate("1:2"));
assertEquals(38, calc.calculate("1:2,3:4,5:6:7:10"));
assertEquals(0, calc.calculate(""));
}

@Test
void custom_delimiter_Test(){
StringCalculator calc = new StringCalculator();
void customDelimiterTest(){
assertEquals(6, calc.calculate("//;\n1;2;3"));
assertEquals(5, calc.calculate("//;;\n1;;1;;2;;1"));
assertEquals(6, calc.calculate("//.\n1.2.3"));
Expand All @@ -29,19 +30,18 @@ void custom_delimiter_Test(){

@Test
void exceptionTest(){
StringCalculator calc = new StringCalculator();

RuntimeException exception = assertThrows(RuntimeException.class, () ->
calc.calculate("-1,2")
);

assertEquals("음수는 입력이 불가합니다.", exception.getMessage());

RuntimeException exception2 = assertThrows(RuntimeException.class, () ->
calc.calculate("2147483647,10")
);
assertThatThrownBy(() -> calc.calculate("-1,2")).isInstanceOf(RuntimeException.class).
hasMessageContaining("음수는 입력이 불가합니다.");
assertThatThrownBy(() -> calc.calculate("2147483647,10")).isInstanceOf(RuntimeException.class).
hasMessageContaining("int 범위를 벗어났습니다.");
assertThatThrownBy(() -> calc.calculate("hello")).isInstanceOf(RuntimeException.class).
hasMessageContaining("int 값을 벗어났거나 잘못된 숫자 형식입니다.");
}

assertEquals("int 범위를 벗어났습니다.", exception2.getMessage());
@Test
void blankTest(){
assertEquals(0, calc.calculate(""));
assertThatThrownBy(() -> calc.calculate(" ")).isInstanceOf(RuntimeException.class);
}
}
}