diff --git a/src/main/java/calculator/StringCalculator.java b/src/main/java/calculator/StringCalculator.java new file mode 100644 index 000000000..3c07fada2 --- /dev/null +++ b/src/main/java/calculator/StringCalculator.java @@ -0,0 +1,59 @@ +package calculator; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 요구사항 + * 1. 빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다. + * 2. 숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다. + * 3. 숫자 두개를 쉼표(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다. + * 4. 구분자를 쉼표(,) 이외에 콜론(:)을 사용할 수 있다. + * 5. "//"와 "\n" 문자 사이에 커스텀 구분자를 지정할 수 있다. + * 6. 음수를 전달하는 경우 RuntimeException 예외 처리를 한다. + */ +public class StringCalculator { + + public int add(String text) { + if (isBlank(text)) { + return 0; + } + return sum(toPositives(split(text))); + } + + private boolean isBlank(String text) { + return text == null || text.isEmpty(); + } + + private String[] split(String text) { + Matcher m = Pattern.compile("//(.)\n(.*)").matcher(text); + if (m.find()) { + String customDelimiter = m.group(1); + return m.group(2).split(customDelimiter); + } + return text.split(",|:"); + } + + private int[] toPositives(String[] values) { + int[] numbers = new int[values.length]; + for (int i = 0; i < values.length; i++) { + numbers[i] = Integer.parseInt(values[i]); + } + return numbers; + } + + private int sum(int[] numbers) { + int sum = 0; + for (int number : numbers) { + checkIfNumberIsNegative(number); + sum += number; + } + return sum; + } + + private static void checkIfNumberIsNegative(int number) { + if (number < 0) { + throw new RuntimeException(); + } + } +} diff --git a/src/main/java/string/SubstringTest.java b/src/main/java/string/SubstringTest.java new file mode 100644 index 000000000..95b536040 --- /dev/null +++ b/src/main/java/string/SubstringTest.java @@ -0,0 +1,10 @@ +package string; + +public class SubstringTest { + + public static void main(String[] args) { + String str = "(1,2)"; + String substring = str.substring(1, 4); + System.out.println("substring = " + substring); + } +} diff --git a/src/test/java/calculator/StringCalculatorTest.java b/src/test/java/calculator/StringCalculatorTest.java new file mode 100644 index 000000000..b45c9efa2 --- /dev/null +++ b/src/test/java/calculator/StringCalculatorTest.java @@ -0,0 +1,71 @@ +package calculator; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + +class StringCalculatorTest { + + private final StringCalculator stringCalculator = new StringCalculator(); + + @DisplayName("빈 문자열 또는 null 값을 입력할 경우 0을 반환해야 한다.") + @Test + void add1() { + //given //when + int result1 = stringCalculator.add(""); + int result2 = stringCalculator.add(null); + + //then + assertThat(result1).isZero(); + assertThat(result2).isZero(); + } + + @DisplayName("숫자 하나를 문자열로 입력할 경우 해당 숫자를 반환한다.") + @Test + void add2() { + //given //when + int result = stringCalculator.add("1"); + + //then + assertThat(result).isEqualTo(1); + } + + @DisplayName("숫자 두개를 쉼표(,) 구분자로 입력할 경우 두 숫자의 합을 반환한다.") + @Test + void add3() { + //given //when + int result = stringCalculator.add("1,3"); + + //then + assertThat(result).isEqualTo(4); + } + + @DisplayName("구분자를 쉼표(,) 이외에 콜론(:)을 사용할 수 있다.") + @Test + void add4() { + //given //when + int result = stringCalculator.add("1,2:3"); + + //then + assertThat(result).isEqualTo(6); + } + + @DisplayName("지정 문자 사이에 커스텀 구분자를 지정할 수 있다.") + @Test + void add5() { + //given //when + int result = stringCalculator.add("//;\n1;2;3"); + + //then + assertThat(result).isEqualTo(6); + } + + @DisplayName("음수를 전달하는 경우 RuntimeException 예외 처리를 한다.") + @Test + void add6() { + //given //when //then + assertThatThrownBy(() -> stringCalculator.add("1,-2")) + .isInstanceOf(RuntimeException.class); + } +} \ No newline at end of file diff --git a/src/test/java/study/SetTest.java b/src/test/java/study/SetTest.java new file mode 100644 index 000000000..0821cb21a --- /dev/null +++ b/src/test/java/study/SetTest.java @@ -0,0 +1,43 @@ +package study; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.HashSet; +import java.util.Set; + +import static org.assertj.core.api.Assertions.*; + +class SetTest { + + private Set numbers; + + @BeforeEach + void setUp() { + numbers = new HashSet<>(); + numbers.add(1); + numbers.add(1); + numbers.add(2); + numbers.add(3); + } + + @Test + void size() { + assertThat(numbers.size()).isEqualTo(3); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3}) + void contains(int value) { + assertThat(numbers.contains(value)).isTrue(); + } + + @ParameterizedTest + @CsvSource(value = {"1,true", "4,false", "5,false"}) + void containsUsingCsv(int value, boolean expected) { + assertThat(numbers.contains(value)).isEqualTo(expected); + } +} diff --git a/src/test/java/study/StringTest.java b/src/test/java/study/StringTest.java index 43e47d90b..538536e79 100644 --- a/src/test/java/study/StringTest.java +++ b/src/test/java/study/StringTest.java @@ -1,13 +1,35 @@ package study; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; + +class StringTest { -public class StringTest { @Test void replace() { String actual = "abc".replace("b", "d"); assertThat(actual).isEqualTo("adc"); } + + @Test + void split() { + String[] actual = "1,2".split(","); + assertThat(actual).contains("1", "2"); + } + + @Test + void split2() { + String[] actual = "1".split(","); + assertThat(actual).containsExactly("1"); + } + + @DisplayName("문자열 범위 밖의 인덱스로 문자열을 참조할 때 에러가 발생한다.") + @Test + void charAt() { + String actual = "abc"; + assertThatThrownBy(() -> actual.charAt(4)) + .isInstanceOf(StringIndexOutOfBoundsException.class); + } }