Skip to content
Open
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
25 changes: 25 additions & 0 deletions src/main/java/calculator/StringAddCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package calculator;

import calculator.extractor.NumbersExtractor;

import java.util.List;

public class StringAddCalculator {

public static int calculateWith(String inputString) {
verifyInputStringNotNull(inputString);
if (inputString.isEmpty()) {
return 0;
}
List<Integer> numbers = NumbersExtractor.extract(inputString);
return numbers.stream()
.mapToInt(Integer::intValue)
.sum();
}

private static void verifyInputStringNotNull(String inputString) {
if (inputString == null) {
throw new IllegalArgumentException("input string cannot be null");
}
}
}
20 changes: 20 additions & 0 deletions src/main/java/calculator/extractor/NumbersExtractor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package calculator.extractor;

import calculator.vo.Delimiters;
import calculator.vo.NumberString;

import java.util.List;
import java.util.stream.Collectors;

public class NumbersExtractor {

public static List<Integer> extract(String inputString) {
Delimiters delimiters = new Delimiters(inputString);
NumberString numberString = new NumberString(inputString);

return numberString.getSplitStringNumbers(delimiters).stream()
.mapToInt(Integer::valueOf)
.boxed()

Choose a reason for hiding this comment

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

mapToInt 말고 map으로만 하면 boxed 할 필요없이 Integer 리스트로 collect 되지않나요??

.collect(Collectors.toList());
}
}
34 changes: 34 additions & 0 deletions src/main/java/calculator/vo/Delimiters.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package calculator.vo;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Delimiters {

public static final String BASIC_DELIMITER_REGEX = ",|:";
public static final String CUSTOM_DELIMITER_REGEX = "//(.)\n(.*)";

public static final Pattern CUSTOM_DELIMITER_PATTERN = Pattern.compile(CUSTOM_DELIMITER_REGEX);

private String delimiterRegex = BASIC_DELIMITER_REGEX;

public Delimiters(String inputString) {
Matcher matcher = CUSTOM_DELIMITER_PATTERN.matcher(inputString);
if (matcher.find()) {
String customDelimiter = matcher.group(1);
delimiterRegex = createDelimiterRegexWith(customDelimiter);
}
}

public String toRegexString() {
return delimiterRegex;
}

private String createDelimiterRegexWith(String customDelimiter) {
return new StringBuilder(delimiterRegex)
.append("|")
.append(customDelimiter)
.toString();
}

}
41 changes: 41 additions & 0 deletions src/main/java/calculator/vo/NumberString.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package calculator.vo;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NumberString {

public static final String CUSTOM_DELIMITER_REGEX = "//(.)\n(.*)";
public static final String VALID_NUMBER_STRING_REGEX = "([0-9]([,:][0-9])*)?";

private final String value;

public NumberString(String inputString) {
Pattern customDelimiterPattern = Pattern.compile(CUSTOM_DELIMITER_REGEX);
Matcher matcher = customDelimiterPattern.matcher(inputString);
if (matcher.find()) {
String numberString = matcher.group(2);
value = numberString;
return;
}
validateString(inputString);
Copy link
Contributor

Choose a reason for hiding this comment

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

위에서 matcher.find()로 통과한상태인데 만약 NumberString이 아니면 어떻게 되나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

find를 거쳐서 제대로 값이 들어갔다고 생각을 하는데.. 어떤 문제인지 잘 모르겠습니다.

value = inputString;
}

public List<String> getSplitStringNumbers(Delimiters delimiters) {
String delimiterRegex = delimiters.toRegexString();
return Arrays.asList(value.split(delimiterRegex));
}

private void validateString(String string) {
Pattern customDelimiterPattern = Pattern.compile(VALID_NUMBER_STRING_REGEX);
Matcher matcher = customDelimiterPattern.matcher(string);

if (!matcher.matches()) {
throw new IllegalArgumentException("invalid string");
}
}

}
61 changes: 61 additions & 0 deletions src/test/java/calculator/StringAddCalculatorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package calculator;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class StringAddCalculatorTest {

@DisplayName("유효한 계산식이 잘 계산 되는지 확인")
@Test
void calculateTest() {
// given
String inputString = "1,2:3";

// when
int result = StringAddCalculator.calculateWith(inputString);

// then
assertThat(result).isEqualTo(6);
}

@DisplayName("커스텀 구분자 계산식이 잘 계산 되는지 확인")
@Test
void calculateWithCustomDelimiter() {
// given
String inputString = "//;\n1;2;3";

// when
int result = StringAddCalculator.calculateWith(inputString);

// then
assertThat(result).isEqualTo(6);
}

@DisplayName("공백 확인")
Copy link
Contributor

Choose a reason for hiding this comment

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

요구사항을 다시 확인하세요 :)

@Test
void calculateWithBlank() {
// given
String inputString = "";

// when
int result = StringAddCalculator.calculateWith(inputString);

// then
assertThat(result).isEqualTo(0);
}

@DisplayName("단일 숫자 확인")
@Test
void calculateWithSingleNumber() {
// given
String inputString = "6";

// when
int result = StringAddCalculator.calculateWith(inputString);

// then
assertThat(result).isEqualTo(6);
}
}
26 changes: 26 additions & 0 deletions src/test/java/calculator/extractor/NumbersExtractorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package calculator.extractor;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class NumbersExtractorTest {

@DisplayName("문자열에서 정수 리스트를 잘 추출해 내는지 테스트")
@Test
void numberExtractTest() {
// given
String inputString = "1,2:3";

// when
List<Integer> extractedNumbers = NumbersExtractor.extract(inputString);

// then
assertThat(extractedNumbers).isEqualTo(Arrays.asList(1, 2, 3));
}

}
31 changes: 31 additions & 0 deletions src/test/java/calculator/vo/DelimitersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package calculator.vo;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class DelimitersTest {

@DisplayName("커스텀 구분자 없을 때 디폴트 구분자 regex만 존재")
@Test
void noCustomDelimiter() {
// given
String inputString = "1,2:3";
Delimiters delimiters = new Delimiters(inputString);

// then
assertThat(delimiters.toRegexString()).isEqualTo(",|:");
}

@DisplayName("커스텀 구분자 있을 때, 디폴트 구분자와 커스텀 구분자가 regex가 존재")
@Test
void haveCustomDelimiter() {
// given
String inputString = "//;\n1;2;3";
Delimiters delimiters = new Delimiters(inputString);

// then
assertThat(delimiters.toRegexString()).isEqualTo(",|:|;");
}
}
73 changes: 73 additions & 0 deletions src/test/java/calculator/vo/NumberStringTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package calculator.vo;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Collections;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class NumberStringTest {

@DisplayName("커스텀 구분자 없을 때 분리된 문자열 숫자 가져오기")
@Test
void noCustomDelimiter() {
// given
String inputString = "1,2:3";
NumberString numberString = new NumberString(inputString);
Delimiters delimiters = new Delimiters(inputString);

// then
assertThat(numberString.getSplitStringNumbers(delimiters)).isEqualTo(Arrays.asList("1", "2", "3"));
}

@DisplayName("유효하지 않은 문자열에 커스텀 구분자 없을 때 에러처리")
@Test
void invalidateStringWithoutCustomDelimiter() {
// given
String inputString = "/1,2:3";

// then
assertThatThrownBy(() -> new NumberString(inputString))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("invalid string");
}

@DisplayName("커스텀 구분자 있을 때 분리된 문자열 숫자 가져오기")
@Test
void haveCustomDelimiter() {
// given
String inputString = "//;\n1;2;3";
NumberString numberString = new NumberString(inputString);
Delimiters delimiters = new Delimiters(inputString);

// then
assertThat(numberString.getSplitStringNumbers(delimiters)).isEqualTo(Arrays.asList("1", "2", "3"));
}

@DisplayName("유효하지 않은 문자열에 커스텀 구분자 있을 때 에러처리")
@Test
void invalidateStringWithCustomDelimiter() {
// given
String inputString = "/;\n1;2;3";

// then
assertThatThrownBy(() -> new NumberString(inputString))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("invalid string");
}

@DisplayName("공백 검사")
@Test
void blankString() {
// given
String inputString = "";
NumberString numberString = new NumberString(inputString);
Delimiters delimiters = new Delimiters(inputString);

// then
assertThat(numberString.getSplitStringNumbers(delimiters)).isEqualTo(Collections.singletonList(""));
}
}