From 6fa2360bb6210ed13b5ca99f936439ad82af24b0 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Mon, 12 Jun 2023 00:16:28 +0900 Subject: [PATCH 01/16] =?UTF-8?q?feat:=20=EC=A1=B0=ED=9A=8C=EC=99=80=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EB=8B=B4?= =?UTF-8?q?=EC=9D=84=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wonu606/calculator/CalculatorApp.java | 25 ++++++++++++++++++- .../calculator/storage/Persistence.java | 15 +++++++++++ .../wonu606/calculator/strategy/Strategy.java | 10 ++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 calculator/src/main/java/com/wonu606/calculator/storage/Persistence.java create mode 100644 calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index 7a54931cc..b904b3f93 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -1,21 +1,44 @@ package com.wonu606.calculator; import com.wonu606.app.App; +import com.wonu606.calculator.storage.Persistence; +import com.wonu606.calculator.strategy.Strategy; import com.wonu606.io.Input; import com.wonu606.io.Print; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; public class CalculatorApp implements App { + private final List strategies = new ArrayList<>(); + private final Persistence store; Input input; Print printer; + public CalculatorApp() { + initStrategies(); + } + + private void initStrategies() { + // TODO 조회와 계산 기능을 생성하여 추가해야 함 + } + public void execute(Input input, Print printer) throws IOException { this.input = input; this.printer = printer; while (true) { - String selection = input.getInput(); + int selection = Integer.parseInt(input.getInput()); + + Optional selectedStrategy = + Optional.ofNullable(strategies.get(selection - 1)); + selectedStrategy.ifPresentOrElse( + strategy -> strategy.execute(input, printer, store), + () -> { + throw new IllegalArgumentException("잘못된 입력입니다."); + }); } } } diff --git a/calculator/src/main/java/com/wonu606/calculator/storage/Persistence.java b/calculator/src/main/java/com/wonu606/calculator/storage/Persistence.java new file mode 100644 index 000000000..cfa0a76ba --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/storage/Persistence.java @@ -0,0 +1,15 @@ +package com.wonu606.calculator.storage; + +import com.wonu606.calculator.model.CalculationResult; +import java.util.List; + +public interface Persistence { + + void saveResult(CalculationResult calculationResult); + + CalculationResult findResult(int sequence); + + List findAllResult(); + + void clear(); +} diff --git a/calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java b/calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java new file mode 100644 index 000000000..badf761b0 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java @@ -0,0 +1,10 @@ +package com.wonu606.calculator.strategy; + +import com.wonu606.calculator.storage.Persistence; +import com.wonu606.io.Input; +import com.wonu606.io.Print; + +public interface Strategy { + + void execute(Input input, Print printer, Persistence store); +} From 490ce1d48db203dce851d1e303e36f036ee5968f Mon Sep 17 00:00:00 2001 From: wonu606 Date: Mon, 12 Jun 2023 00:44:15 +0900 Subject: [PATCH 02/16] =?UTF-8?q?test:=20=EC=A0=80=EC=9E=A5=EC=86=8C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=B2=B4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/model/CalculationResult.java | 40 ++++++ .../com/wonu606/storage/ResultStoreTest.java | 114 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 calculator/src/main/java/com/wonu606/calculator/model/CalculationResult.java create mode 100644 calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java diff --git a/calculator/src/main/java/com/wonu606/calculator/model/CalculationResult.java b/calculator/src/main/java/com/wonu606/calculator/model/CalculationResult.java new file mode 100644 index 000000000..d398c155d --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/model/CalculationResult.java @@ -0,0 +1,40 @@ +package com.wonu606.calculator.model; + +import java.util.Objects; + +public class CalculationResult { + + private final String expression; + private final double result; + + public CalculationResult(String expression, double result) { + this.expression = expression; + this.result = result; + } + + public String getExpression() { + return expression; + } + + public double getResult() { + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CalculationResult that = (CalculationResult) o; + return Double.compare(that.getResult(), getResult()) == 0 && Objects.equals( + getExpression(), that.getExpression()); + } + + @Override + public int hashCode() { + return Objects.hash(getExpression(), getResult()); + } +} diff --git a/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java b/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java new file mode 100644 index 000000000..e1418fbaa --- /dev/null +++ b/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java @@ -0,0 +1,114 @@ +package com.wonu606.storage; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.wonu606.calculator.model.CalculationResult; +import com.wonu606.calculator.storage.Persistence; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ResultStoreTest { + + @Test + @DisplayName("저장") + void testSave() { + // given + Persistence store; + + // when + CalculationResult calculationResult = new CalculationResult("2 + 2", 4.0d); + store.saveResult(calculationResult); + + // then + assertThat(store.findAllResult().size()).isEqualTo(1); + } + + @Test + @DisplayName("순서로 결과 찾기") + void testFind() { + // given + Persistence store; + + // when + CalculationResult saveResult = new CalculationResult("5 + 10", 15.0d); + store.saveResult(saveResult); + + // then + CalculationResult foundResult = store.findResult(1); + assertThat(foundResult).isEqualTo(saveResult); + } + + @Test + @DisplayName("1 미만의 수로 찾은 경우 예외 발생") + void testFindNumberLessThan1() { + // given + Persistence store; + + // then + CalculationResult saveResult = new CalculationResult("5 + 10", 15.0d); + store.saveResult(saveResult); + + // then + assertThatThrownBy(() -> store.findResult(0)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("잘못된 순번입니다."); + } + + @Test + @DisplayName("사이즈 초과의 수로 찾은 경우 예외 발생") + void testFindNumberMoreThanSize() { + // given + Persistence store; + + // when + CalculationResult saveResult = new CalculationResult("5 + 10", 15.0d); + store.saveResult(saveResult); + + // then + assertThatThrownBy(() -> store.findResult(store.findAllResult().size() + 1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("잘못된 순번입니다."); + } + + @Test + @DisplayName("모두 찾기") + void testFindAll() { + // given + Persistence store; + + // when + List results = new ArrayList<>(); + results.add(new CalculationResult("5 + 6", 11.0d)); + results.add(new CalculationResult("5 + 6", 11.0d)); + + for (CalculationResult result : results) { + store.saveResult(result); + } + + // then + List foundResults = store.findAllResult(); + for (CalculationResult foundResult : foundResults) { + assertThat(results.indexOf(foundResult)).isNotEqualTo(-1); + } + } + + @Test + @DisplayName("클리어") + void testClear() { + // given + Persistence store; + + // when + store.saveResult(new CalculationResult("11 + 6", 17.0d)); + store.saveResult(new CalculationResult("11 + 10", 21.0d)); + + // then + assertThat(store.findAllResult().size()).isNotEqualTo(0); + store.clear(); + assertThat(store.findAllResult().size()).isEqualTo(0); + } +} From 728fcadd3e85d1f846f9b90a8b0181298ef5abe9 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Mon, 12 Jun 2023 02:40:17 +0900 Subject: [PATCH 03/16] =?UTF-8?q?feat:=20=EC=A0=80=EC=9E=A5=EC=86=8C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=B2=B4,=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EB=8B=B4=EC=9D=84=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wonu606/calculator/CalculatorApp.java | 6 ++-- .../calculator/storage/ResultStore.java | 35 +++++++++++++++++++ .../calculator/util/CalculatorMessage.java | 17 +++++++++ .../com/wonu606/storage/ResultStoreTest.java | 20 +++++------ 4 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 calculator/src/main/java/com/wonu606/calculator/storage/ResultStore.java create mode 100644 calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index b904b3f93..514459df9 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -2,9 +2,11 @@ import com.wonu606.app.App; import com.wonu606.calculator.storage.Persistence; +import com.wonu606.calculator.storage.ResultStore; import com.wonu606.calculator.strategy.Strategy; import com.wonu606.io.Input; import com.wonu606.io.Print; +import com.wonu606.calculator.util.CalculatorMessage; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -13,7 +15,7 @@ public class CalculatorApp implements App { private final List strategies = new ArrayList<>(); - private final Persistence store; + private final Persistence store = new ResultStore(); Input input; Print printer; @@ -37,7 +39,7 @@ public void execute(Input input, Print printer) throws IOException { selectedStrategy.ifPresentOrElse( strategy -> strategy.execute(input, printer, store), () -> { - throw new IllegalArgumentException("잘못된 입력입니다."); + throw new IllegalArgumentException(CalculatorMessage.INVALID_INPUT.message); }); } } diff --git a/calculator/src/main/java/com/wonu606/calculator/storage/ResultStore.java b/calculator/src/main/java/com/wonu606/calculator/storage/ResultStore.java new file mode 100644 index 000000000..5387b0a71 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/storage/ResultStore.java @@ -0,0 +1,35 @@ +package com.wonu606.calculator.storage; + +import com.wonu606.calculator.model.CalculationResult; +import com.wonu606.calculator.util.CalculatorMessage; +import java.util.ArrayList; +import java.util.List; + +public class ResultStore implements Persistence { + + private final List store = new ArrayList<>(); + + @Override + public void saveResult(CalculationResult calculationResult) { + store.add(calculationResult); + } + + @Override + public CalculationResult findResult(int sequence) { + try { + return store.get(sequence - 1); + } catch (IndexOutOfBoundsException exception) { + throw new IllegalArgumentException(CalculatorMessage.INVALID_ORDER.message); + } + } + + @Override + public List findAllResult() { + return new ArrayList<>(store); + } + + @Override + public void clear() { + store.clear(); + } +} diff --git a/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java b/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java new file mode 100644 index 000000000..a07575b1c --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java @@ -0,0 +1,17 @@ +package com.wonu606.calculator.util; + +public enum CalculatorMessage { + INVALID_ORDER("잘못된 순번입니다."), + INVALID_INPUT("잘못된 입력입니다."); + + public final String message; + + CalculatorMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return message; + } +} diff --git a/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java b/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java index e1418fbaa..c60e88acd 100644 --- a/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java +++ b/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java @@ -5,19 +5,19 @@ import com.wonu606.calculator.model.CalculationResult; import com.wonu606.calculator.storage.Persistence; +import com.wonu606.calculator.storage.ResultStore; +import com.wonu606.calculator.util.CalculatorMessage; import java.util.ArrayList; import java.util.List; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class ResultStoreTest { - @Test @DisplayName("저장") void testSave() { // given - Persistence store; + Persistence store = new ResultStore(); // when CalculationResult calculationResult = new CalculationResult("2 + 2", 4.0d); @@ -31,7 +31,7 @@ void testSave() { @DisplayName("순서로 결과 찾기") void testFind() { // given - Persistence store; + Persistence store = new ResultStore(); // when CalculationResult saveResult = new CalculationResult("5 + 10", 15.0d); @@ -46,7 +46,7 @@ void testFind() { @DisplayName("1 미만의 수로 찾은 경우 예외 발생") void testFindNumberLessThan1() { // given - Persistence store; + Persistence store = new ResultStore(); // then CalculationResult saveResult = new CalculationResult("5 + 10", 15.0d); @@ -55,14 +55,14 @@ void testFindNumberLessThan1() { // then assertThatThrownBy(() -> store.findResult(0)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("잘못된 순번입니다."); + .hasMessageContaining(CalculatorMessage.INVALID_ORDER.message); } @Test @DisplayName("사이즈 초과의 수로 찾은 경우 예외 발생") void testFindNumberMoreThanSize() { // given - Persistence store; + Persistence store = new ResultStore(); // when CalculationResult saveResult = new CalculationResult("5 + 10", 15.0d); @@ -71,14 +71,14 @@ void testFindNumberMoreThanSize() { // then assertThatThrownBy(() -> store.findResult(store.findAllResult().size() + 1)) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("잘못된 순번입니다."); + .hasMessageContaining(CalculatorMessage.INVALID_ORDER.message); } @Test @DisplayName("모두 찾기") void testFindAll() { // given - Persistence store; + Persistence store = new ResultStore(); // when List results = new ArrayList<>(); @@ -100,7 +100,7 @@ void testFindAll() { @DisplayName("클리어") void testClear() { // given - Persistence store; + Persistence store = new ResultStore(); // when store.saveResult(new CalculationResult("11 + 6", 17.0d)); From b99177be632ae788b674a194486644f6e5e812c8 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Mon, 12 Jun 2023 03:59:55 +0900 Subject: [PATCH 04/16] =?UTF-8?q?refactor:=20Strategy=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=8A=A4=20->=20CalculatorStrategy=20?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/wonu606/calculator/CalculatorApp.java | 8 ++++---- .../strategy/{Strategy.java => CalculatorStrategy.java} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename calculator/src/main/java/com/wonu606/calculator/strategy/{Strategy.java => CalculatorStrategy.java} (85%) diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index 514459df9..458849849 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -3,7 +3,7 @@ import com.wonu606.app.App; import com.wonu606.calculator.storage.Persistence; import com.wonu606.calculator.storage.ResultStore; -import com.wonu606.calculator.strategy.Strategy; +import com.wonu606.calculator.strategy.CalculatorStrategy; import com.wonu606.io.Input; import com.wonu606.io.Print; import com.wonu606.calculator.util.CalculatorMessage; @@ -14,7 +14,7 @@ public class CalculatorApp implements App { - private final List strategies = new ArrayList<>(); + private final List strategies = new ArrayList<>(); private final Persistence store = new ResultStore(); Input input; Print printer; @@ -30,11 +30,11 @@ private void initStrategies() { public void execute(Input input, Print printer) throws IOException { this.input = input; this.printer = printer; - + while (true) { int selection = Integer.parseInt(input.getInput()); - Optional selectedStrategy = + Optional selectedStrategy = Optional.ofNullable(strategies.get(selection - 1)); selectedStrategy.ifPresentOrElse( strategy -> strategy.execute(input, printer, store), diff --git a/calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java b/calculator/src/main/java/com/wonu606/calculator/strategy/CalculatorStrategy.java similarity index 85% rename from calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java rename to calculator/src/main/java/com/wonu606/calculator/strategy/CalculatorStrategy.java index badf761b0..54d0907e2 100644 --- a/calculator/src/main/java/com/wonu606/calculator/strategy/Strategy.java +++ b/calculator/src/main/java/com/wonu606/calculator/strategy/CalculatorStrategy.java @@ -4,7 +4,7 @@ import com.wonu606.io.Input; import com.wonu606.io.Print; -public interface Strategy { +public interface CalculatorStrategy { void execute(Input input, Print printer, Persistence store); } From bac3c9f71c1e88d1fd3d872c87adf70ef4043567 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Mon, 12 Jun 2023 04:45:31 +0900 Subject: [PATCH 05/16] =?UTF-8?q?refactor:=20CalculatorApp=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EC=97=90=EC=84=9C=20Input,=20Print=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wonu606/calculator/CalculatorApp.java | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index 458849849..feada55e7 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -9,15 +9,15 @@ import com.wonu606.calculator.util.CalculatorMessage; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; public class CalculatorApp implements App { - private final List strategies = new ArrayList<>(); + private final Map strategies = new HashMap(); private final Persistence store = new ResultStore(); - Input input; - Print printer; public CalculatorApp() { initStrategies(); @@ -27,20 +27,34 @@ private void initStrategies() { // TODO 조회와 계산 기능을 생성하여 추가해야 함 } - public void execute(Input input, Print printer) throws IOException { - this.input = input; - this.printer = printer; - + public void execute(Input input, Print printer) { + + while (true) { + String selection = inputMenuSelection(input); + CalculatorStrategy selectedStrategy = getStrategyOrThrow(selection); + performStrategy(input, printer, selectedStrategy); + } + } + + private void performStrategy(Input input, Print printer, CalculatorStrategy selectedStrategy) { + selectedStrategy.execute(input, printer, store); + } + + private CalculatorStrategy getStrategyOrThrow(String selection) { + CalculatorStrategy selectedStrategy = strategies.get(selection); + if (selectedStrategy == null) { + throw new IllegalArgumentException(CalculatorMessage.INVALID_INPUT.message); + } + return selectedStrategy; + } + + private String inputMenuSelection(Input input) { while (true) { - int selection = Integer.parseInt(input.getInput()); - - Optional selectedStrategy = - Optional.ofNullable(strategies.get(selection - 1)); - selectedStrategy.ifPresentOrElse( - strategy -> strategy.execute(input, printer, store), - () -> { - throw new IllegalArgumentException(CalculatorMessage.INVALID_INPUT.message); - }); + try { + return input.getInput(); + } catch (IOException e) { + e.printStackTrace(); + } } } } From 463f1992c8207cb76749e61f279622b78e90c454 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Mon, 12 Jun 2023 18:35:32 +0900 Subject: [PATCH 06/16] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5=EC=8B=9C?= =?UTF-8?q?=20throw=20IOException=20=EC=98=88=EC=99=B8=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- calculator/src/main/java/com/wonu606/Main.java | 2 +- calculator/src/main/java/com/wonu606/app/App.java | 2 +- .../java/com/wonu606/calculator/CalculatorApp.java | 11 +---------- .../src/main/java/com/wonu606/io/ConsoleInput.java | 2 +- calculator/src/main/java/com/wonu606/io/Input.java | 4 +--- .../test/java/com/wonu606/io/ConsoleInputTest.java | 6 +++--- 6 files changed, 8 insertions(+), 19 deletions(-) diff --git a/calculator/src/main/java/com/wonu606/Main.java b/calculator/src/main/java/com/wonu606/Main.java index 945b902ef..c829d621d 100644 --- a/calculator/src/main/java/com/wonu606/Main.java +++ b/calculator/src/main/java/com/wonu606/Main.java @@ -25,7 +25,7 @@ public static void main(String[] args) { } } - private static void runApp(App app, Input input, Print printer) throws IOException { + private static void runApp(App app, Input input, Print printer) { app.execute(input, printer); } } diff --git a/calculator/src/main/java/com/wonu606/app/App.java b/calculator/src/main/java/com/wonu606/app/App.java index 86c560082..ad21f26c1 100644 --- a/calculator/src/main/java/com/wonu606/app/App.java +++ b/calculator/src/main/java/com/wonu606/app/App.java @@ -6,5 +6,5 @@ public interface App { - void execute(Input input, Print printer) throws IOException; + void execute(Input input, Print printer); } diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index feada55e7..2a6a9bd78 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -7,10 +7,7 @@ import com.wonu606.io.Input; import com.wonu606.io.Print; import com.wonu606.calculator.util.CalculatorMessage; -import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; @@ -49,12 +46,6 @@ private CalculatorStrategy getStrategyOrThrow(String selection) { } private String inputMenuSelection(Input input) { - while (true) { - try { - return input.getInput(); - } catch (IOException e) { - e.printStackTrace(); - } - } + return input.getInput(); } } diff --git a/calculator/src/main/java/com/wonu606/io/ConsoleInput.java b/calculator/src/main/java/com/wonu606/io/ConsoleInput.java index 38a712bad..b281b61c1 100644 --- a/calculator/src/main/java/com/wonu606/io/ConsoleInput.java +++ b/calculator/src/main/java/com/wonu606/io/ConsoleInput.java @@ -8,7 +8,7 @@ public class ConsoleInput implements Input { Scanner scanner = new Scanner(System.in); @Override - public String getInput() throws IOException { + public String getInput() { return scanner.nextLine(); } diff --git a/calculator/src/main/java/com/wonu606/io/Input.java b/calculator/src/main/java/com/wonu606/io/Input.java index f6942d541..88dc18ad8 100644 --- a/calculator/src/main/java/com/wonu606/io/Input.java +++ b/calculator/src/main/java/com/wonu606/io/Input.java @@ -1,10 +1,8 @@ package com.wonu606.io; -import java.io.IOException; - public interface Input { - String getInput() throws IOException; + String getInput(); void tearDown(); } diff --git a/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java b/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java index 783dacddc..2fc1cbbab 100644 --- a/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java +++ b/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java @@ -12,7 +12,7 @@ class ConsoleInputTest { @Test @DisplayName("메뉴 입력") - void testMenuSelectionInput() throws IOException { + void testMenuSelectionInput() { String menuSelection = "1"; InputStream in = new ByteArrayInputStream(menuSelection.getBytes()); System.setIn(in); @@ -24,7 +24,7 @@ void testMenuSelectionInput() throws IOException { @Test @DisplayName("표현식 입력") - void testExpressionInput() throws IOException { + void testExpressionInput() { String expression = "2 + 3"; InputStream in = new ByteArrayInputStream(expression.getBytes()); System.setIn(in); @@ -36,7 +36,7 @@ void testExpressionInput() throws IOException { @Test @DisplayName("개행 입력") - void testNewLineInput() throws IOException { + void testNewLineInput() { String newLine = "\n"; InputStream in = new ByteArrayInputStream(newLine.getBytes()); System.setIn(in); From 8a836099bc30086968c6aa9cbe7af3464ecf2330 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Tue, 13 Jun 2023 01:50:38 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20=EC=97=B0=EC=82=B0=EC=9E=90=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wonu606/calculator/model/Operator.java | 52 +++++++++++++++++++ .../calculator/util/CalculatorMessage.java | 3 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 calculator/src/main/java/com/wonu606/calculator/model/Operator.java diff --git a/calculator/src/main/java/com/wonu606/calculator/model/Operator.java b/calculator/src/main/java/com/wonu606/calculator/model/Operator.java new file mode 100644 index 000000000..35c24703d --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/model/Operator.java @@ -0,0 +1,52 @@ +package com.wonu606.calculator.model; + +import com.wonu606.calculator.util.CalculatorMessage; + +public enum Operator { + ADD("+", 2){ + @Override + public double apply(double a, double b) { + return a + b; + } + }, + SUBTRACT("-", 2) { + @Override + public double apply(double a, double b) { + return a - b; + } + }, + MULTIPLY("*", 1) { + @Override + public double apply(double a, double b) { + return a * b; + } + }, + DIVIDE("/", 1) { + @Override + public double apply(double a, double b) { + if (b == 0) { + throw new ArithmeticException(CalculatorMessage.NOT_DIVISIBLE_BY_ZERO.message); + } + return a / b; + } + }; + + public final String symbol; + public final int precedence; + + Operator(String symbol, int precedence) { + this.symbol = symbol; + this.precedence = precedence; + } + + public abstract double apply(double a, double b); + + public static Operator get(String symbol) { + for (Operator operator : values()) { + if (operator.symbol.equals(symbol)) { + return operator; + } + } + return null; + } +} diff --git a/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java b/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java index a07575b1c..289162db4 100644 --- a/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java +++ b/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java @@ -2,7 +2,8 @@ public enum CalculatorMessage { INVALID_ORDER("잘못된 순번입니다."), - INVALID_INPUT("잘못된 입력입니다."); + INVALID_INPUT("잘못된 입력입니다."), + NOT_DIVISIBLE_BY_ZERO("0으로 나눌 수 없습니다."); public final String message; From 72db8806e9d523badad234ac2ad9c91124e31d4e Mon Sep 17 00:00:00 2001 From: wonu606 Date: Tue, 13 Jun 2023 03:34:00 +0900 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20=EC=A4=91=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=20=EC=9C=A0=ED=9A=A8=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/validator/InfixValidator.java | 53 +++++++++++++++++++ .../calculator/validator/Validator.java | 6 +++ 2 files changed, 59 insertions(+) create mode 100644 calculator/src/main/java/com/wonu606/calculator/validator/InfixValidator.java create mode 100644 calculator/src/main/java/com/wonu606/calculator/validator/Validator.java diff --git a/calculator/src/main/java/com/wonu606/calculator/validator/InfixValidator.java b/calculator/src/main/java/com/wonu606/calculator/validator/InfixValidator.java new file mode 100644 index 000000000..611d7e2b2 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/validator/InfixValidator.java @@ -0,0 +1,53 @@ +package com.wonu606.calculator.validator; + +import com.wonu606.calculator.model.Operator; +import java.util.ArrayList; +import java.util.List; + +public class InfixValidator implements Validator { + + private static boolean isExpectedNumericPosition(int position) { + return position % 2 == 0; + } + + @Override + public boolean isValid(String expression) { + String[] tokens = expression.split("\\s"); + List operators = getOperators(); + + for (int i = 0; i < tokens.length; i++) { + if (isInvalidToken(i, tokens[i], operators)) { + return false; + } + } + return true; + } + + private boolean isInvalidToken(int position, String str, List operators) { + if (isExpectedNumericPosition(position)) { + return !isNumeric(str); + } + return !isOperator(operators, str); + } + + private List getOperators() { + List operators = new ArrayList<>(); + for (Operator operator : Operator.values()) { + operators.add(operator.symbol); + } + return operators; + } + + private Boolean isNumeric(String str) { + try { + Double.parseDouble(str); + } catch (NumberFormatException e) { + return false; + } + return true; + } + + private boolean isOperator(List operators, String expectedOperator) { + return operators.contains(expectedOperator); + } +} diff --git a/calculator/src/main/java/com/wonu606/calculator/validator/Validator.java b/calculator/src/main/java/com/wonu606/calculator/validator/Validator.java new file mode 100644 index 000000000..e98119545 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/validator/Validator.java @@ -0,0 +1,6 @@ +package com.wonu606.calculator.validator; + +public interface Validator { + + boolean isValid(String expression); +} From 8f347a2a6bd2d1ec1f251d6c67b980e822780594 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Tue, 13 Jun 2023 03:34:52 +0900 Subject: [PATCH 09/16] =?UTF-8?q?test:=20=EC=A4=91=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=20=EC=9C=A0=ED=9A=A8=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EB=B0=8F=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wonu606/validator/InfixValidatorTest.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java diff --git a/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java b/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java new file mode 100644 index 000000000..2f83f20c4 --- /dev/null +++ b/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java @@ -0,0 +1,34 @@ +package com.wonu606.validator; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.wonu606.calculator.validator.InfixValidator; +import com.wonu606.calculator.validator.Validator; +import org.junit.jupiter.api.Test; + +public class InfixValidatorTest { + + @Test + void testNotInfix() { + // given + Validator validator = new InfixValidator(); + + // when + String expression = "+ 1 3"; + + // then + assertThat(validator.isValid(expression)).isFalse(); + } + + @Test + void testInfix() { + // given + Validator validator = new InfixValidator(); + + // when + String expression = "1 + 3 + 2 * -3 / -123"; + + // then + assertThat(validator.isValid(expression)).isTrue(); + } +} From 95306f6aed363f759c3ac3c5d495d99b2bf2254e Mon Sep 17 00:00:00 2001 From: wonu606 Date: Wed, 14 Jun 2023 16:23:30 +0900 Subject: [PATCH 10/16] =?UTF-8?q?feat:=20=EC=A4=91=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9D=84=20=ED=9B=84=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B0=94=EA=BE=B8?= =?UTF-8?q?=EB=8A=94=20converter=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/converter/Converter.java | 6 ++ .../converter/InfixToPostfixConverter.java | 56 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 calculator/src/main/java/com/wonu606/calculator/converter/Converter.java create mode 100644 calculator/src/main/java/com/wonu606/calculator/converter/InfixToPostfixConverter.java diff --git a/calculator/src/main/java/com/wonu606/calculator/converter/Converter.java b/calculator/src/main/java/com/wonu606/calculator/converter/Converter.java new file mode 100644 index 000000000..3cf3afcfc --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/converter/Converter.java @@ -0,0 +1,6 @@ +package com.wonu606.calculator.converter; + +public interface Converter { + + R convert(T input); +} diff --git a/calculator/src/main/java/com/wonu606/calculator/converter/InfixToPostfixConverter.java b/calculator/src/main/java/com/wonu606/calculator/converter/InfixToPostfixConverter.java new file mode 100644 index 000000000..03b8829b9 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/converter/InfixToPostfixConverter.java @@ -0,0 +1,56 @@ +package com.wonu606.calculator.converter; + +import com.wonu606.calculator.model.Operator; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.Objects; + +public class InfixToPostfixConverter implements Converter> { + + @Override + public List convert(String infixExpression) { + Deque operatorStack = new ArrayDeque<>(); + List postfixExpression = new ArrayList<>(); + + String[] tokens = infixExpression.split("\\s"); + + for (String token : tokens) { + processTokenIntoPostfix(operatorStack, postfixExpression, token); + } + + while (!operatorStack.isEmpty()) { + postfixExpression.add(operatorStack.pop()); + } + return postfixExpression; + } + + private void processTokenIntoPostfix( + Deque operatorStack, List postfixExpression, String token) { + if (isOperator(token)) { + popWhileHigherPrecedence(operatorStack, postfixExpression, token); + operatorStack.push(token); + return; + } + postfixExpression.add(token); + } + + private void popWhileHigherPrecedence( + Deque operatorStack, List postfixExpression, String tokenOperator) { + while (!operatorStack.isEmpty() + && isHigherOrEqualPrecedence(operatorStack.peek(), tokenOperator)) { + postfixExpression.add(operatorStack.pop()); + } + } + + private boolean isHigherOrEqualPrecedence(String peekOperator, String tokenOperator) { + int peekPrecedence = Objects.requireNonNull(Operator.get(peekOperator)).precedence; + int tokenPrecedence = Objects.requireNonNull(Operator.get(tokenOperator)).precedence; + return peekPrecedence <= tokenPrecedence; + } + + private boolean isOperator(String token) { + return Operator.get(token) != null; + } +} From 400b2a4268c2481af9da5bdcac3854d3744162e8 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Wed, 14 Jun 2023 16:25:07 +0900 Subject: [PATCH 11/16] =?UTF-8?q?test:=20=EC=A4=91=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9D=84=20=ED=9B=84=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=20Converter=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EB=B0=8F=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InfixToPostfixConverterTest.java | 71 +++++++++++++++++++ .../wonu606/validator/InfixValidatorTest.java | 2 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 calculator/src/test/java/com/wonu606/calculator/converter/InfixToPostfixConverterTest.java diff --git a/calculator/src/test/java/com/wonu606/calculator/converter/InfixToPostfixConverterTest.java b/calculator/src/test/java/com/wonu606/calculator/converter/InfixToPostfixConverterTest.java new file mode 100644 index 000000000..0ed927670 --- /dev/null +++ b/calculator/src/test/java/com/wonu606/calculator/converter/InfixToPostfixConverterTest.java @@ -0,0 +1,71 @@ +package com.wonu606.calculator.converter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class InfixToPostfixConverterTest { + + @Test + @DisplayName("연산자가 1개일 경우") + void testSingle() { + // given + Converter> converter = new InfixToPostfixConverter(); + List expectedList = Arrays.asList("-3", "5.0", "+"); + String infixExpression = "-3 + 5.0"; + + // when + List actualList = converter.convert(infixExpression); + + // then + assertThat(actualList).isEqualTo(expectedList); + } + + @Test + @DisplayName("같은 우선 순위일 경우") + void testPrecedenceEquals() { + // given + Converter> converter = new InfixToPostfixConverter(); + List expectedList = Arrays.asList("3", "5", "+", "2", "-"); + String infixExpression = "3 + 5 - 2"; + + // when + List actualList = converter.convert(infixExpression); + + // then + assertThat(actualList).isEqualTo(expectedList); + } + + @Test + @DisplayName("높은 우선 순위가 뒤에 올 경우") + void testHigherPrecedenceFollows() { + // given + Converter> converter = new InfixToPostfixConverter(); + List expectedList = Arrays.asList("3", "5", "2", "*", "+"); + String infixExpression = "3 + 5 * 2"; + + // when + List actualList = converter.convert(infixExpression); + + // then + assertThat(actualList).isEqualTo(expectedList); + } + + @Test + @DisplayName("높은 우선 순위가 앞에 올 경우") + void testHigherPrecedenceComesFirst() { + // given + Converter> converter = new InfixToPostfixConverter(); + List expectedList = Arrays.asList("3", "5", "*", "2", "+"); + String infixExpression = "3 * 5 + 2"; + + // when + List actualList = converter.convert(infixExpression); + + // then + assertThat(actualList).isEqualTo(expectedList); + } +} \ No newline at end of file diff --git a/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java b/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java index 2f83f20c4..9f3414de5 100644 --- a/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java +++ b/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java @@ -14,7 +14,7 @@ void testNotInfix() { Validator validator = new InfixValidator(); // when - String expression = "+ 1 3"; + String expression = "1 3 +"; // then assertThat(validator.isValid(expression)).isFalse(); From 60a1eb428b5164e802c44ddfb9ce17b8be71c3bc Mon Sep 17 00:00:00 2001 From: wonu606 Date: Wed, 14 Jun 2023 17:00:50 +0900 Subject: [PATCH 12/16] =?UTF-8?q?feat:=20=ED=9B=84=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9D=84=20=EA=B3=84=EC=82=B0=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/calculator/Calculator.java | 8 ++++ .../calculator/PostfixCalculator.java | 42 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 calculator/src/main/java/com/wonu606/calculator/calculator/Calculator.java create mode 100644 calculator/src/main/java/com/wonu606/calculator/calculator/PostfixCalculator.java diff --git a/calculator/src/main/java/com/wonu606/calculator/calculator/Calculator.java b/calculator/src/main/java/com/wonu606/calculator/calculator/Calculator.java new file mode 100644 index 000000000..7d1e9fa44 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/calculator/Calculator.java @@ -0,0 +1,8 @@ +package com.wonu606.calculator.calculator; + +import java.util.List; + +public interface Calculator { + + double calculate(List expression); +} diff --git a/calculator/src/main/java/com/wonu606/calculator/calculator/PostfixCalculator.java b/calculator/src/main/java/com/wonu606/calculator/calculator/PostfixCalculator.java new file mode 100644 index 000000000..f7798ec57 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/calculator/PostfixCalculator.java @@ -0,0 +1,42 @@ +package com.wonu606.calculator.calculator; + +import com.wonu606.calculator.model.Operator; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.Objects; + +public class PostfixCalculator implements Calculator { + + @Override + public double calculate(List postfixExpression) { + Deque operandStack = new ArrayDeque<>(); + + for (String token : postfixExpression) { + handleToken(operandStack, token); + } + + return operandStack.pop(); + } + + private void handleToken(Deque operandStack, String token) { + if (isOperator(token)) { + Operator operator = Objects.requireNonNull(Operator.get(token)); + performOperation(operandStack, operator); + return; + } + operandStack.push(Double.valueOf(token)); + } + + private void performOperation(Deque operandStack, Operator operator) { + double secondOperand = operandStack.pop(); + double firstOperand = operandStack.pop(); + + double result = operator.apply(firstOperand, secondOperand); + operandStack.push(result); + } + + private boolean isOperator(String token) { + return Operator.get(token) != null; + } +} From 3dfc78e7d64cdba9aa0de6e8a48b639956b802af Mon Sep 17 00:00:00 2001 From: wonu606 Date: Wed, 14 Jun 2023 17:02:07 +0900 Subject: [PATCH 13/16] =?UTF-8?q?test:=20=ED=9B=84=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9D=84=20=EA=B3=84=EC=82=B0=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1=20=EB=B0=8F=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/PostCalculatorTest.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java diff --git a/calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java b/calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java new file mode 100644 index 000000000..5155a1b5f --- /dev/null +++ b/calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java @@ -0,0 +1,88 @@ +package com.wonu606.calculator; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.wonu606.calculator.calculator.Calculator; +import com.wonu606.calculator.calculator.PostfixCalculator; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PostCalculatorTest { + + @Test + @DisplayName("연산자가 1개일 경우") + void testSingle() { + // given + Calculator calculator = new PostfixCalculator(); + List actualList = Arrays.asList("-3", "5.0", "+"); + double expected = -3 + 5.0; + + // when + double result = calculator.calculate(actualList); + + // then + assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("같은 우선 순위일 경우") + void testPrecedenceEquals() { + // given + Calculator calculator = new PostfixCalculator(); + List actualList = Arrays.asList("3", "5", "+", "2", "-"); + double expected = 3 + 5 - 2; + + // when + double result = calculator.calculate(actualList); + + // then + assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("높은 우선 순위가 뒤에 올 경우") + void testHigherPrecedenceFollows() { + // given + Calculator calculator = new PostfixCalculator(); + List actualList = Arrays.asList("3", "5", "2", "*", "+"); + double expected = 3 + 5 * 2; + + // when + double result = calculator.calculate(actualList); + + // then + assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("높은 우선 순위가 앞에 올 경우") + void testHigherPrecedenceComesFirst() { + // given + Calculator calculator = new PostfixCalculator(); + List actualList = Arrays.asList("3", "5", "*", "2", "+"); + double expected = 3 * 5 + 2; + + // when + double result = calculator.calculate(actualList); + + // then + assertThat(result).isEqualTo(expected); + } + + @Test + @DisplayName("소수가 나올 경우") + void testIfFraction() { + // given + Calculator calculator = new PostfixCalculator(); + List actualList = Arrays.asList("3", "5", "/", "2", "+"); + double expected = 3.0 / 5 + 2; + + // when + double result = calculator.calculate(actualList); + + // then + assertThat(result).isEqualTo(expected); + } +} \ No newline at end of file From ef0ddd895ffb1809b83d8909af366303c5835319 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Wed, 14 Jun 2023 17:04:43 +0900 Subject: [PATCH 14/16] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=EB=AC=B8=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20?= =?UTF-8?q?=EB=94=94=EB=A0=89=ED=86=A0=EB=A6=AC=20=EC=9E=AC=EC=A0=95?= =?UTF-8?q?=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- calculator/src/main/java/com/wonu606/Main.java | 3 +-- calculator/src/main/java/com/wonu606/app/App.java | 1 - .../src/main/java/com/wonu606/calculator/CalculatorApp.java | 3 +-- .../main/java/com/wonu606/calculator/model/Operator.java | 6 +++--- calculator/src/main/java/com/wonu606/io/ConsoleInput.java | 1 - .../calculator/{ => calculator}/PostCalculatorTest.java | 4 +--- .../wonu606/{ => calculator}/storage/ResultStoreTest.java | 5 ++--- .../{ => calculator}/validator/InfixValidatorTest.java | 4 +--- .../src/test/java/com/wonu606/io/ConsoleInputTest.java | 1 - 9 files changed, 9 insertions(+), 19 deletions(-) rename calculator/src/test/java/com/wonu606/calculator/{ => calculator}/PostCalculatorTest.java (94%) rename calculator/src/test/java/com/wonu606/{ => calculator}/storage/ResultStoreTest.java (96%) rename calculator/src/test/java/com/wonu606/{ => calculator}/validator/InfixValidatorTest.java (82%) diff --git a/calculator/src/main/java/com/wonu606/Main.java b/calculator/src/main/java/com/wonu606/Main.java index c829d621d..14171d396 100644 --- a/calculator/src/main/java/com/wonu606/Main.java +++ b/calculator/src/main/java/com/wonu606/Main.java @@ -2,11 +2,10 @@ import com.wonu606.app.App; import com.wonu606.calculator.CalculatorApp; +import com.wonu606.io.ConsoleInput; import com.wonu606.io.ConsolePrinter; import com.wonu606.io.Input; import com.wonu606.io.Print; -import com.wonu606.io.ConsoleInput; -import java.io.IOException; public class Main { diff --git a/calculator/src/main/java/com/wonu606/app/App.java b/calculator/src/main/java/com/wonu606/app/App.java index ad21f26c1..9e0cbb124 100644 --- a/calculator/src/main/java/com/wonu606/app/App.java +++ b/calculator/src/main/java/com/wonu606/app/App.java @@ -2,7 +2,6 @@ import com.wonu606.io.Input; import com.wonu606.io.Print; -import java.io.IOException; public interface App { diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index 2a6a9bd78..e09802952 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -4,12 +4,11 @@ import com.wonu606.calculator.storage.Persistence; import com.wonu606.calculator.storage.ResultStore; import com.wonu606.calculator.strategy.CalculatorStrategy; +import com.wonu606.calculator.util.CalculatorMessage; import com.wonu606.io.Input; import com.wonu606.io.Print; -import com.wonu606.calculator.util.CalculatorMessage; import java.util.HashMap; import java.util.Map; -import java.util.Optional; public class CalculatorApp implements App { diff --git a/calculator/src/main/java/com/wonu606/calculator/model/Operator.java b/calculator/src/main/java/com/wonu606/calculator/model/Operator.java index 35c24703d..c86f76a70 100644 --- a/calculator/src/main/java/com/wonu606/calculator/model/Operator.java +++ b/calculator/src/main/java/com/wonu606/calculator/model/Operator.java @@ -3,7 +3,7 @@ import com.wonu606.calculator.util.CalculatorMessage; public enum Operator { - ADD("+", 2){ + ADD("+", 2) { @Override public double apply(double a, double b) { return a + b; @@ -39,8 +39,6 @@ public double apply(double a, double b) { this.precedence = precedence; } - public abstract double apply(double a, double b); - public static Operator get(String symbol) { for (Operator operator : values()) { if (operator.symbol.equals(symbol)) { @@ -49,4 +47,6 @@ public static Operator get(String symbol) { } return null; } + + public abstract double apply(double a, double b); } diff --git a/calculator/src/main/java/com/wonu606/io/ConsoleInput.java b/calculator/src/main/java/com/wonu606/io/ConsoleInput.java index b281b61c1..31af5a279 100644 --- a/calculator/src/main/java/com/wonu606/io/ConsoleInput.java +++ b/calculator/src/main/java/com/wonu606/io/ConsoleInput.java @@ -1,6 +1,5 @@ package com.wonu606.io; -import java.io.IOException; import java.util.Scanner; public class ConsoleInput implements Input { diff --git a/calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java b/calculator/src/test/java/com/wonu606/calculator/calculator/PostCalculatorTest.java similarity index 94% rename from calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java rename to calculator/src/test/java/com/wonu606/calculator/calculator/PostCalculatorTest.java index 5155a1b5f..ef472b427 100644 --- a/calculator/src/test/java/com/wonu606/calculator/PostCalculatorTest.java +++ b/calculator/src/test/java/com/wonu606/calculator/calculator/PostCalculatorTest.java @@ -1,9 +1,7 @@ -package com.wonu606.calculator; +package com.wonu606.calculator.calculator; import static org.assertj.core.api.Assertions.assertThat; -import com.wonu606.calculator.calculator.Calculator; -import com.wonu606.calculator.calculator.PostfixCalculator; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.DisplayName; diff --git a/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java b/calculator/src/test/java/com/wonu606/calculator/storage/ResultStoreTest.java similarity index 96% rename from calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java rename to calculator/src/test/java/com/wonu606/calculator/storage/ResultStoreTest.java index c60e88acd..1ffb44188 100644 --- a/calculator/src/test/java/com/wonu606/storage/ResultStoreTest.java +++ b/calculator/src/test/java/com/wonu606/calculator/storage/ResultStoreTest.java @@ -1,11 +1,9 @@ -package com.wonu606.storage; +package com.wonu606.calculator.storage; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.wonu606.calculator.model.CalculationResult; -import com.wonu606.calculator.storage.Persistence; -import com.wonu606.calculator.storage.ResultStore; import com.wonu606.calculator.util.CalculatorMessage; import java.util.ArrayList; import java.util.List; @@ -13,6 +11,7 @@ import org.junit.jupiter.api.Test; public class ResultStoreTest { + @Test @DisplayName("저장") void testSave() { diff --git a/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java b/calculator/src/test/java/com/wonu606/calculator/validator/InfixValidatorTest.java similarity index 82% rename from calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java rename to calculator/src/test/java/com/wonu606/calculator/validator/InfixValidatorTest.java index 9f3414de5..036f59154 100644 --- a/calculator/src/test/java/com/wonu606/validator/InfixValidatorTest.java +++ b/calculator/src/test/java/com/wonu606/calculator/validator/InfixValidatorTest.java @@ -1,9 +1,7 @@ -package com.wonu606.validator; +package com.wonu606.calculator.validator; import static org.assertj.core.api.Assertions.assertThat; -import com.wonu606.calculator.validator.InfixValidator; -import com.wonu606.calculator.validator.Validator; import org.junit.jupiter.api.Test; public class InfixValidatorTest { diff --git a/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java b/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java index 2fc1cbbab..b1c80b440 100644 --- a/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java +++ b/calculator/src/test/java/com/wonu606/io/ConsoleInputTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From 52ddf84c304a1ab51e9c9541759a596a9e326103 Mon Sep 17 00:00:00 2001 From: wonu606 Date: Thu, 15 Jun 2023 01:41:52 +0900 Subject: [PATCH 15/16] =?UTF-8?q?test:=20=EC=A4=91=EC=9C=84=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=8B=9D=EC=9D=84=20=EC=9E=85=EB=A0=A5=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=20=EA=B3=84=EC=82=B0=ED=95=98=EB=8A=94=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculator/util/CalculatorMessage.java | 3 +- .../strategy/CalculationStrategyTest.java | 135 ++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 calculator/src/test/java/com/wonu606/calculator/strategy/CalculationStrategyTest.java diff --git a/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java b/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java index 289162db4..8333dfeff 100644 --- a/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java +++ b/calculator/src/main/java/com/wonu606/calculator/util/CalculatorMessage.java @@ -3,7 +3,8 @@ public enum CalculatorMessage { INVALID_ORDER("잘못된 순번입니다."), INVALID_INPUT("잘못된 입력입니다."), - NOT_DIVISIBLE_BY_ZERO("0으로 나눌 수 없습니다."); + NOT_DIVISIBLE_BY_ZERO("0으로 나눌 수 없습니다."), + OVERFLOW_OCCURS("계산 중 Overflow가 발생했습니다."); public final String message; diff --git a/calculator/src/test/java/com/wonu606/calculator/strategy/CalculationStrategyTest.java b/calculator/src/test/java/com/wonu606/calculator/strategy/CalculationStrategyTest.java new file mode 100644 index 000000000..de522ff80 --- /dev/null +++ b/calculator/src/test/java/com/wonu606/calculator/strategy/CalculationStrategyTest.java @@ -0,0 +1,135 @@ +package com.wonu606.calculator.strategy; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.wonu606.calculator.calculator.PostfixCalculator; +import com.wonu606.calculator.converter.InfixToPostfixConverter; +import com.wonu606.calculator.storage.ResultStore; +import com.wonu606.calculator.util.CalculatorMessage; +import com.wonu606.calculator.validator.InfixValidator; +import com.wonu606.io.ConsoleInput; +import com.wonu606.io.ConsolePrinter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CalculationStrategyTest { + + @Test + @DisplayName("정상 입력") + void testNormalInput() { + // given + CalculatorStrategy calculator = new CalculationStrategy( + new InfixValidator(), new InfixToPostfixConverter(), new PostfixCalculator()); + + String expression = "2 + 3"; + InputStream in = new ByteArrayInputStream(expression.getBytes()); + System.setIn(in); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream out = System.out; + System.setOut(new PrintStream(outContent)); + + // when + calculator.execute(new ConsoleInput(), new ConsolePrinter(), new ResultStore()); + + // then + String expectedResult = 5 + "\n"; + assertThat(expectedResult).isEqualTo(outContent.toString()); + } + + @Test + @DisplayName("Double 오버 플로우 발생") + void testDoubleOverflowOccurs() { + // given + CalculatorStrategy calculator = new CalculationStrategy( + new InfixValidator(), new InfixToPostfixConverter(), new PostfixCalculator()); + + String expression = Double.MAX_VALUE + " + 1"; + InputStream in = new ByteArrayInputStream(expression.getBytes()); + System.setIn(in); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream out = System.out; + System.setOut(new PrintStream(outContent)); + + // when + calculator.execute(new ConsoleInput(), new ConsolePrinter(), new ResultStore()); + + // then + String expectedResult = CalculatorMessage.OVERFLOW_OCCURS.message + "\n"; + assertThat(expectedResult).isEqualTo(outContent.toString()); + } + + @Test + @DisplayName("Integer 오버 플로우 발생") + void testIntegerOverflowOccurs() { + // given + CalculatorStrategy calculator = new CalculationStrategy( + new InfixValidator(), new InfixToPostfixConverter(), new PostfixCalculator()); + + String expression = Integer.MAX_VALUE + " + 1"; + InputStream in = new ByteArrayInputStream(expression.getBytes()); + System.setIn(in); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream out = System.out; + System.setOut(new PrintStream(outContent)); + + // when + calculator.execute(new ConsoleInput(), new ConsolePrinter(), new ResultStore()); + + // then + String expectedResult = CalculatorMessage.OVERFLOW_OCCURS.message + "\n"; + assertThat(expectedResult).isEqualTo(outContent.toString()); + } + + @Test + @DisplayName("0으로 나눌 경우 오류 발생") + void testDividedByZero() { + // given + CalculatorStrategy calculator = new CalculationStrategy( + new InfixValidator(), new InfixToPostfixConverter(), new PostfixCalculator()); + + String expression = "10 / 0"; + InputStream in = new ByteArrayInputStream(expression.getBytes()); + System.setIn(in); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream out = System.out; + System.setOut(new PrintStream(outContent)); + + // when + calculator.execute(new ConsoleInput(), new ConsolePrinter(), new ResultStore()); + + // then + String expectedResult = CalculatorMessage.NOT_DIVISIBLE_BY_ZERO.message + "\n"; + assertThat(expectedResult).isEqualTo(outContent.toString()); + } + + @Test + @DisplayName("중위 연산식이 아닌 경우") + void testIsNotInfixExpression() { + // given + CalculatorStrategy calculator = new CalculationStrategy( + new InfixValidator(), new InfixToPostfixConverter(), new PostfixCalculator()); + + String expression = "3 5 +"; + InputStream in = new ByteArrayInputStream(expression.getBytes()); + System.setIn(in); + + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + PrintStream out = System.out; + System.setOut(new PrintStream(outContent)); + + // when + calculator.execute(new ConsoleInput(), new ConsolePrinter(), new ResultStore()); + + // then + String expectedResult = CalculatorMessage.INVALID_INPUT.message + "\n"; + assertThat(expectedResult).isEqualTo(outContent.toString()); + } +} From 7bba45d1a085a12395865b0f0b81bb5ed6718bab Mon Sep 17 00:00:00 2001 From: wonu606 Date: Thu, 15 Jun 2023 10:01:29 +0900 Subject: [PATCH 16/16] =?UTF-8?q?feat:=20=EA=B3=84=EC=82=B0=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B5=AC=ED=98=84=EC=B2=B4=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=86=B5=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/wonu606/calculator/CalculatorApp.java | 7 +- .../strategy/CalculationStrategy.java | 68 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 calculator/src/main/java/com/wonu606/calculator/strategy/CalculationStrategy.java diff --git a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java index e09802952..cb48abd3f 100644 --- a/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java +++ b/calculator/src/main/java/com/wonu606/calculator/CalculatorApp.java @@ -1,10 +1,14 @@ package com.wonu606.calculator; import com.wonu606.app.App; +import com.wonu606.calculator.calculator.PostfixCalculator; +import com.wonu606.calculator.converter.InfixToPostfixConverter; import com.wonu606.calculator.storage.Persistence; import com.wonu606.calculator.storage.ResultStore; +import com.wonu606.calculator.strategy.CalculationStrategy; import com.wonu606.calculator.strategy.CalculatorStrategy; import com.wonu606.calculator.util.CalculatorMessage; +import com.wonu606.calculator.validator.InfixValidator; import com.wonu606.io.Input; import com.wonu606.io.Print; import java.util.HashMap; @@ -20,7 +24,8 @@ public CalculatorApp() { } private void initStrategies() { - // TODO 조회와 계산 기능을 생성하여 추가해야 함 + strategies.put("1", new CalculationStrategy( + new InfixValidator(), new InfixToPostfixConverter(), new PostfixCalculator())); } public void execute(Input input, Print printer) { diff --git a/calculator/src/main/java/com/wonu606/calculator/strategy/CalculationStrategy.java b/calculator/src/main/java/com/wonu606/calculator/strategy/CalculationStrategy.java new file mode 100644 index 000000000..d5d7cac52 --- /dev/null +++ b/calculator/src/main/java/com/wonu606/calculator/strategy/CalculationStrategy.java @@ -0,0 +1,68 @@ +package com.wonu606.calculator.strategy; + +import com.wonu606.calculator.calculator.Calculator; +import com.wonu606.calculator.converter.Converter; +import com.wonu606.calculator.model.CalculationResult; +import com.wonu606.calculator.storage.Persistence; +import com.wonu606.calculator.util.CalculatorMessage; +import com.wonu606.calculator.validator.Validator; +import com.wonu606.io.Input; +import com.wonu606.io.Print; +import java.util.List; + +public class CalculationStrategy implements CalculatorStrategy { + + Validator validator; + Converter> converter; + Calculator calculator; + + public CalculationStrategy(Validator validator, Converter> converter, + Calculator calculator) { + this.validator = validator; + this.converter = converter; + this.calculator = calculator; + } + + @Override + public void execute(Input input, Print printer, Persistence store) { + String inputExpression = input.getInput(); + if (isNotValidExpression(inputExpression)) { + printer.print(CalculatorMessage.INVALID_INPUT.message); + return; + } + + List convertedExpression = converter.convert(inputExpression); + try { + double result = calculator.calculate(convertedExpression); + + store.saveResult(new CalculationResult(inputExpression, result)); + printCalculationResult(printer, result); + } catch (ArithmeticException exception) { + printer.print(exception.getMessage()); + } + } + + private static void printCalculationResult(Print printer, double result) { + String message = String.valueOf(roundResultToInt(result)); + if (isResultOverflow(result)) { + message = CalculatorMessage.OVERFLOW_OCCURS.message; + } + printer.print(message); + } + + private static int roundResultToInt(double result) { + return (int) Math.round(result); + } + + private static boolean isResultOverflow(double result) { + return Double.isInfinite(result) || (isIntegerOverflow(result)); + } + + private static boolean isIntegerOverflow(double result) { + return result > Integer.MAX_VALUE; + } + + private boolean isNotValidExpression(String inputExpression) { + return !validator.isValid(inputExpression); + } +}