diff --git a/README.md b/README.md index 22621e3..7a97609 100644 --- a/README.md +++ b/README.md @@ -1 +1,38 @@ # Calculator + +## πŸ“Œ κ΅¬ν˜„ κΈ°λŠ₯ λͺ©λ‘ + +### μž…λ ₯λ°›κΈ° + +"μˆ˜μ‹μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”." ← μ‚¬μš©μžμ—κ²Œ 문ꡬ 좜λ ₯ + +μž…λ ₯ λ°›κΈ° + +### 둜직 + +#### μž…λ ₯ 검사 + +##### 톡과 + +- 곡백은 0 +- μ—°μ‚°λ°©ν–₯은 μ™Όμͺ½μ—μ„œ 였λ₯Έμͺ½ +- (μ—°μ‚°μž μš°μ„ μˆœμœ„) + +##### μ—λŸ¬ + +`IllegalArgumentException` + +- μ—°μ†λœ μ—°μ‚°μž +- νƒ€μž… μ—λŸ¬ + + + +### 좜λ ₯ + +#### 정상 좜λ ₯ + +"κ²°κ³Ό : ?" + +#### μ—λŸ¬ λ°œμƒ + +"[ERROR] 잘λͺ»λœ μˆ˜μ‹μž…λ‹ˆλ‹€. μž…λ ₯ ν˜•μ‹μ„ 확인해 μ£Όμ„Έμš”." \ No newline at end of file diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java index d909a50..388237e 100644 --- a/src/main/java/calculator/Application.java +++ b/src/main/java/calculator/Application.java @@ -1,11 +1,35 @@ package calculator; +import java.util.ArrayList; + public class Application { + + private static final Console console = new Console(); + public static void main(String[] args) { - // TODO: μ½”λ“œ μž‘μ„± + String inputString = console.readInput(); + + run(inputString); + } - // μ˜ˆμ‹œ μ½”λ“œ + public static int run(String inputString) { + Validator validator = new Validator(); Calculator calculator = new Calculator(); - calculator.calculate(""); + + ArrayList inputArrayList; + int result = 0; + + try { + inputArrayList = validator.divideInput(inputString); + result = calculator.calculate(inputArrayList); + } catch (IllegalStateException e) { + // μž…λ ₯값이 곡백값 λ˜λŠ” λΉ„μ–΄μžˆλŠ” 경우 + } catch (IllegalArgumentException illegalArgumentException) { + System.out.println(illegalArgumentException.getMessage()); + return -1; + } + + console.printResult(result); + return result; } } diff --git a/src/main/java/calculator/Calculator.java b/src/main/java/calculator/Calculator.java index 88e8552..b54a18a 100644 --- a/src/main/java/calculator/Calculator.java +++ b/src/main/java/calculator/Calculator.java @@ -1,13 +1,55 @@ package calculator; -/* - 1μ£Όμ°¨μ—λ§Œ μ œκ³΅λ˜λŠ” μ˜ˆμ‹œ μ½”λ“œμž…λ‹ˆλ‹€. - μ½”λ“œλŠ” κ·ΈλŒ€λ‘œ μ‚¬μš©ν•΄λ„ 되고 μˆ˜μ •ν•΄λ„ λ©λ‹ˆλ‹€. - */ +import java.util.*; +// μ—°μ‚° μ±…μž„ public class Calculator { - public int calculate(String input) { - // TODO: μ½”λ“œ κ΅¬ν˜„ - throw new IllegalArgumentException("아직 κ΅¬ν˜„λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€."); + + private int result = 0; + + public int calculate(ArrayList inputArrayList) { + + // 단일 μ›μ†ŒμΈ 경우 κ·ΈλŒ€λ‘œ return + if (isSingleElement(inputArrayList)) { + return Integer.parseInt(inputArrayList.get(0)); + } + + // 큐 μ„ μ–Έ + LinkedList stringQueue = toQueue(inputArrayList); + + while (stringQueue.size() > 1) { + + result = operate( + stringQueue.poll(), + stringQueue.poll(), + stringQueue.poll() + ); + + stringQueue.addFirst(String.valueOf(result)); + } + + return result; + } + + + private boolean isSingleElement(ArrayList inputArrayList) { + return inputArrayList.size() == 1; + } + + private LinkedList toQueue(ArrayList inputArrayList) { + return new LinkedList<>(inputArrayList); + } + + private int operate(String num1String, String operator, String num2String) { + int num1 = Integer.parseInt(num1String); + int num2 = Integer.parseInt(num2String); + + return switch (operator) { + case "+" -> num1 + num2; + case "-" -> num1 - num2; + case "*" -> num1 * num2; + case "/" -> num1 / num2; + default -> throw new IllegalStateException("Unexpected value: " + operator); + }; } } diff --git a/src/main/java/calculator/Console.java b/src/main/java/calculator/Console.java new file mode 100644 index 0000000..aef9bd4 --- /dev/null +++ b/src/main/java/calculator/Console.java @@ -0,0 +1,26 @@ +package calculator; + +import java.util.Scanner; + +// TODO: SINGLETON? +// μž…μΆœλ ₯ μ±…μž„ +public class Console { + private static final String MESSAGE_INPUT_GUIDE = "μˆ˜μ‹μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”."; + private static final String MESSAGE_OUTPUT_FORMATTED = "κ²°κ³Ό : %d"; + + public static final String MESSAGE_ERROR_FORMAT = "[ERROR] 잘λͺ»λœ μˆ˜μ‹μž…λ‹ˆλ‹€. μž…λ ₯ ν˜•μ‹μ„ 확인해 μ£Όμ„Έμš”."; + public static final String MESSAGE_ERROR_WRONG_POSITION_OPERATORS = "[ERROR] 잘λͺ»λœ μ—°μ‚°μž μœ„μΉ˜μž…λ‹ˆλ‹€. μž…λ ₯ ν˜•μ‹μ„ 확인해 μ£Όμ„Έμš”."; + public static final String MESSAGE_ERROR_EMPTY_OR_BLANK = "[ERROR] μž…λ ₯값이 μ—†κ±°λ‚˜ κ³΅λ°±μž…λ‹ˆλ‹€. μž…λ ₯ ν˜•μ‹μ„ 확인해 μ£Όμ„Έμš”."; + + + private static final Scanner scanner = new Scanner(System.in); + + public String readInput() { + System.out.println(MESSAGE_INPUT_GUIDE); + return scanner.nextLine(); + } + + public void printResult(int result) { + System.out.println(String.format(MESSAGE_OUTPUT_FORMATTED, result)); + } +} diff --git a/src/main/java/calculator/Validator.java b/src/main/java/calculator/Validator.java new file mode 100644 index 0000000..c31e32f --- /dev/null +++ b/src/main/java/calculator/Validator.java @@ -0,0 +1,63 @@ +package calculator; + +import java.util.ArrayList; +import java.util.Set; + +// 검사 μ±…μž„ + +public class Validator { + + // 검사λ₯Ό μœ„ν•œ λ°°μ—΄ 생성 + private final ArrayList inputArrayList = new ArrayList<>(); + // 검사λ₯Ό μœ„ν•œ μ—°μ‚°μž set + private static final Set OPERATORS = Set.of('+', '-', '*', '/'); + + // 검사 이후 μˆ«μžμ™€ μ—°μ‚°μžλ‘œ μͺΌκ°œμ–΄ λ°°μ—΄λ‘œ return + public ArrayList divideInput(String input) { + String currentNumber = ""; + + validateEmptyOrBlank(input); + + for (int i = 0; i < input.length(); i++) { + char ch = input.charAt(i); + + if (Character.isDigit(ch)) { + currentNumber += ch; + + validateLastNumber(i, input.length() - 1, currentNumber); + + } else if (OPERATORS.contains(ch)) { + validateOperatorPosition(currentNumber); + + inputArrayList.add(currentNumber); + inputArrayList.add(String.valueOf(ch)); + + currentNumber = ""; + + } else { // μˆ«μžλ‚˜ λ¬Έμžμ—΄μ΄ μ•„λ‹Œ 경우 + throw new IllegalArgumentException(Console.MESSAGE_ERROR_FORMAT); + } + } + + return inputArrayList; + } + + private void validateLastNumber(int position, int length, String currentNumber) { + if (position == length) { + inputArrayList.add(currentNumber); + } + } + + private void validateEmptyOrBlank(String input) { + if (input.isBlank()) { + throw new IllegalStateException(Console.MESSAGE_ERROR_EMPTY_OR_BLANK); + } + } + + private void validateOperatorPosition(String currentNumber) { + if (currentNumber.isEmpty()) { + throw new IllegalArgumentException(Console.MESSAGE_ERROR_WRONG_POSITION_OPERATORS); + } + } + +} diff --git a/src/test/java/calculator/ApplicationTest.java b/src/test/java/calculator/ApplicationTest.java index f3e71c7..4a9e3d1 100644 --- a/src/test/java/calculator/ApplicationTest.java +++ b/src/test/java/calculator/ApplicationTest.java @@ -1,36 +1,31 @@ package calculator; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; + import org.junit.jupiter.api.Test; + public class ApplicationTest { - Calculator calculator = new Calculator(); @Test public void 빈_λ¬Έμžμ—΄_μž…λ ₯_μ‹œ_0을_λ°˜ν™˜ν•œλ‹€() { - // 아직 calculate ν•¨μˆ˜κ°€ κ΅¬ν˜„λ˜μ§€ μ•Šμ€ μƒνƒœμ—μ„œ TDD Red Test용 μ½”λ“œ - int result = calculator.calculate(""); - assertThat(result).isEqualTo(0); + assertThat(Application.run(" ")).isEqualTo(0); } @Test public void λ§μ…ˆκ³Ό_λΊ„μ…ˆλ§Œ_ν¬ν•¨λœ_μˆ˜μ‹_계산() { - int result = calculator.calculate("1+2-3"); - assertThat(result).isEqualTo(0); + assertThat(Application.run("1+2-3")).isEqualTo(0); } @Test public void κ³±μ…ˆκ³Ό_λ§μ…ˆ_포함_μˆ˜μ‹_계산() { - int result = calculator.calculate("2*3+4"); - assertThat(result).isEqualTo(10); + assertThat(Application.run("2*3+4")).isEqualTo(10); + } @Test public void 잘λͺ»λœ_μˆ˜μ‹_μž…λ ₯_μ‹œ_μ˜ˆμ™Έ_λ°œμƒ() { - assertThrows(IllegalArgumentException.class, () -> { - calculator.calculate("1++2"); - }); + assertThat(Application.run("1++2")).isEqualTo(-1); } // TODO: ν…ŒμŠ€νŠΈ μ½”λ“œ μΆ”κ°€ κ°€λŠ₯ν•©λ‹ˆλ‹€. diff --git a/src/test/java/calculator/CalculatorTest.java b/src/test/java/calculator/CalculatorTest.java new file mode 100644 index 0000000..aa7fddf --- /dev/null +++ b/src/test/java/calculator/CalculatorTest.java @@ -0,0 +1,53 @@ +package calculator; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class CalculatorTest { + + Calculator calculator = new Calculator(); + + @Test + void calculate_test_single() { + ArrayList input = new ArrayList<>(List.of("12")); + int result = calculator.calculate(input); + + assertThat(result).isEqualTo(12); + } + + @Test + void calculate_test_simple() { + ArrayList input = new ArrayList<>(List.of("1", "+", "2")); + int result = calculator.calculate(input); + + assertThat(result).isEqualTo(3); + } + + @Test + void calculate_test_divide() { + ArrayList input = new ArrayList<>(List.of("4", "/", "2")); + int result = calculator.calculate(input); + + assertThat(result).isEqualTo(2); + } + + @Test + void calculate_test_complex() { + ArrayList input = new ArrayList<>(List.of("2", "+", "3", "*", "4")); + int result = calculator.calculate(input); + + assertThat(result).isEqualTo(20); + } + + @Test + void calculate_test_wrong_operator() { + ArrayList input = new ArrayList<>(List.of("1", "&", "2")); + + assertThrows(IllegalStateException.class, () -> calculator.calculate(input)); + } +} diff --git a/src/test/java/calculator/ValidatorTest.java b/src/test/java/calculator/ValidatorTest.java new file mode 100644 index 0000000..cea3a1c --- /dev/null +++ b/src/test/java/calculator/ValidatorTest.java @@ -0,0 +1,55 @@ +package calculator; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ValidatorTest { + + Validator validator = new Validator(); + + @Test + void split_test() { + String input = "3+5*2"; + List result = validator.divideInput(input); + + assertThat(result).containsExactly("3", "+", "5", "*", "2"); + } + + @Test + void exception_test_for_blank() { + String input = " "; + Exception e = assertThrows(IllegalStateException.class, () -> validator.divideInput(input)); + + assertThat(e.getMessage()).isEqualTo(Console.MESSAGE_ERROR_EMPTY_OR_BLANK); + } + + @Test + void exception_test_for_operators() { + String input = "3++2"; + Exception e = assertThrows(IllegalArgumentException.class, () -> validator.divideInput(input)); + + assertThat(e.getMessage()).isEqualTo(Console.MESSAGE_ERROR_WRONG_POSITION_OPERATORS); + } + + @Test + void exception_test_for_input_format() { + String input = "5+a"; + Exception e = assertThrows(IllegalArgumentException.class, () -> validator.divideInput(input)); + + assertThat(e.getMessage()).isEqualTo(Console.MESSAGE_ERROR_FORMAT); + } + + @Test + void exception_test_for_first_starts_with_operator() { + String input = "+12+3-5"; + Exception e = assertThrows(IllegalArgumentException.class, () -> validator.divideInput(input)); + + assertThat(e.getMessage()).isEqualTo(Console.MESSAGE_ERROR_WRONG_POSITION_OPERATORS); + + } + +}