diff --git a/build.gradle b/build.gradle index db8d2fd..5272ea8 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,9 @@ repositories { } dependencies { + implementation 'junit:junit:4.12' + implementation 'junit:junit:4.12' + implementation 'org.testng:testng:7.1.0' testCompile('org.junit.jupiter:junit-jupiter:5.6.0') testCompile('org.assertj:assertj-core:3.15.0') } diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..bcf30bf --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'java-calculator' + diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..0680f67 --- /dev/null +++ b/src/README.md @@ -0,0 +1,61 @@ +# Java-Calculator + +Create a string calculator and write test code for it + +## Contributor +- oereo + +## Branch structure + +### oereo branch +* from `oereo/java-calculator[oereo branch]` to `biforest/java-calculator [oereo branch]` + +### java-calculator-structure branch +* Feature branch : Branch to develop the function ex)feature/java-calculator +* Fix branch : Branch to fix the function ex)fix/java-calculator + +## TDD +### Failure case +#### (1) When divided by 0 +```console + 연산을 입력해주세요 : 2/0 // error +``` +#### (2) When two or more operation symbols appear in a row +```console + 연산을 입력해주세요 : 2++0 // error +``` +#### (3) When the operation symbol appears at the beginning +```console + 연산을 입력해주세요 : +2+0 // error +``` +#### (4) When special characters other than operation symbols are entered +```console + 연산을 입력해주세요 : 2^4 // error +``` +#### (5) When characters excluding numbers and operators are entered +```console + 연산을 입력해주세요 : 2ㄱㄴ4*4 // error +``` +#### (6) When the formula ends with an operation symbol +```console + 연산을 입력해주세요 : 2-1* // error +``` +## Structure +#### 1. Class +- Calculator class + - `+ class` + - `- class` + - `* class` + - `/ class` +- Input class +- Output class + - `Error message` output + - `Calculation result` output +- Error exception class + - Precautions : only use `try ~ catch` +- Init class + - When an error occurs, reset after outputting an error message + - Reset and input when pressing any key value + +#### 2. Algorithm +- DFS, Node \ No newline at end of file diff --git a/src/main/java/calculator/AddOperation.java b/src/main/java/calculator/AddOperation.java new file mode 100644 index 0000000..29235f1 --- /dev/null +++ b/src/main/java/calculator/AddOperation.java @@ -0,0 +1,14 @@ +package calculator; + +public class AddOperation implements Operation { + @Override + public String operationName() { + return "+"; + } + + @Override + public int calculation(int beforeNumber, int afterNumber) { + int Result = beforeNumber + afterNumber; + return Result; + } +} diff --git a/src/main/java/calculator/Application.java b/src/main/java/calculator/Application.java new file mode 100644 index 0000000..62e6657 --- /dev/null +++ b/src/main/java/calculator/Application.java @@ -0,0 +1,11 @@ +package calculator; + + +public class Application { + public static void main(String[] args) { + + // Declare calculator object and start calculation + Calculator calculator = new Calculator(); + calculator.calculation(); + } +} diff --git a/src/main/java/calculator/ArithmeticExpressionStack.java b/src/main/java/calculator/ArithmeticExpressionStack.java new file mode 100644 index 0000000..1762174 --- /dev/null +++ b/src/main/java/calculator/ArithmeticExpressionStack.java @@ -0,0 +1,46 @@ +package calculator; + + +interface Stack{ + boolean isEmpty(); + String pop(); + void clear(); +} + +public class ArithmeticExpressionStack implements Stack { + private int stackSize; + private int flag; + private String stack[]; + + public ArithmeticExpressionStack(String[] equation, int stackSize){ + clear(); + flag = 0; + this.stackSize = stackSize; + stack = equation; + } + + public String pop(){ + if(isEmpty()){ + return "스택이 존재하지 않습니다."; + } + else{ + return stack[flag++]; + } + } + + public boolean isEmpty(){ + return (flag == this.stackSize); + } + + public void clear(){ + if(!isEmpty()){ + flag = -1; + this.stackSize = stackSize; + } + } + + public int getStackSize(){ + return this.stackSize; + } + +} diff --git a/src/main/java/calculator/Calculator.java b/src/main/java/calculator/Calculator.java new file mode 100644 index 0000000..4099de6 --- /dev/null +++ b/src/main/java/calculator/Calculator.java @@ -0,0 +1,143 @@ +package calculator; + +import java.util.Scanner; + + +public class Calculator { + private Message message = new Message(); + + /** + * calculation method + * 1. getEquation - Receives numeric expression in string format entered by user + * 2. Put numeric expressions on the stack + * 3. Passing the stack to the operatorSetting method + * + * return type : void + */ + public void calculation(){ + String[] equation_list = getEquation(); + ArithmeticExpressionStack arithmeticExpressionStack = new ArithmeticExpressionStack(equation_list, equation_list.length); + OperatorSetting(arithmeticExpressionStack); + + } + + /** + * OperatorSetting method + * 1. Pop each operator and number onto the stack. + * 2. Perform error exception check and calculate + * 3. After the calculation process is complete, call init() to determine whether to return the calculator + * + * return type : void + */ + public void OperatorSetting(ArithmeticExpressionStack arithmeticExpressionStack) { + ErrorException exceptionCheck = new ErrorException(); + String firstString = arithmeticExpressionStack.pop(); + // Error checking when converting string to int + int cumulativeResult = exceptionCheck.NumericalError(firstString); + + for(int i = 0; i<(arithmeticExpressionStack.getStackSize())/2;i++){ + String operator = arithmeticExpressionStack.pop(); + String secondString = arithmeticExpressionStack.pop(); + int secondNumber = exceptionCheck.NumericalError(secondString); + + // calculated value are continuously accumulated + cumulativeResult = chooseOperatorAndCalculate(cumulativeResult, operator, secondNumber); + } + + if(cumulativeResult != 0){ + message.calculationResult(cumulativeResult); + } + + // Whether to re-execute after calculation + init(); + } + + /** + * chooseOperatorAndCalculate method + * 1. Pop each operator and number onto the stack. + * 2. Perform error exception check and calculate + * 3. After the calculation process is complete, call init() to determine whether to return the calculator + * + * return type : int + */ + public int chooseOperatorAndCalculate(int firstNumber, String operator, int SecondNumber){ + AddOperation addOperation = new AddOperation(); + SubOperation subOperation = new SubOperation(); + MultiplyOperation multiplyOperation = new MultiplyOperation(); + DivideOperation divideOperation = new DivideOperation(); + int result = 0; + + // When the operator is equal to "+" + if (operator.equals(addOperation.operationName())){ + result = addOperation.calculation(firstNumber, SecondNumber); + } + + // When the operator is equal to "-" + else if (operator.equals(subOperation.operationName())){ + result = subOperation.calculation(firstNumber, SecondNumber); + } + + // When the operator is equal to "*" + else if (operator.equals(multiplyOperation.operationName())){ + result = multiplyOperation.calculation(firstNumber, SecondNumber); + } + + // When the operator is equal to "/" + else if (operator.equals(divideOperation.operationName())){ + result = divideOperation.calculation(firstNumber, SecondNumber); + } + + // Raise error when a symbol that does not correspond to the arithmetic operations(+, -, *, /) comes + else{ + try { + throw new Exception(); + } catch (Exception e) { + e.getMessage(); + message.exceptionResult("NOT_OPERATOR"); + } + } + + return result; + } + + /** + * init method + * - Input "1" to redo calculator. + * - Input another key to exit + * + * return type : void + */ + public void init(){ + Scanner scanner = new Scanner(System.in); + System.out.println("계산을 계속 진행하시려면 1, 멈추시려면 임의의 다른키를 눌러주세요"); + String value = scanner.nextLine(); + + if(value.equals("1")){ + calculation(); + } + else{ + System.exit(0); + } + } + + /** + * getEquation method + * - Method to receive user input data + * + * return type : void + */ + String[] getEquation() { + String value = inputValues(); + String[] values = value.split(" "); + return values; + } + + private String inputValues() { + Scanner scanner = new Scanner(System.in); + System.out.print("수식을 입력해주세요 : "); + String value = scanner.nextLine(); + return value; + } + + +} diff --git a/src/main/java/calculator/DivideOperation.java b/src/main/java/calculator/DivideOperation.java new file mode 100644 index 0000000..5333383 --- /dev/null +++ b/src/main/java/calculator/DivideOperation.java @@ -0,0 +1,21 @@ +package calculator; + +public class DivideOperation implements Operation { + @Override + public String operationName() { + return "/"; + } + + @Override + public int calculation(int beforeNumber, int afterNumber) { + Message message = new Message(); + try{ + int Result = beforeNumber / afterNumber; + return Result; + } + catch (ArithmeticException e){ + message.exceptionResult("INVALID_DIVIDE"); + } + return 0; + } +} diff --git a/src/main/java/calculator/ErrorException.java b/src/main/java/calculator/ErrorException.java new file mode 100644 index 0000000..dd886e8 --- /dev/null +++ b/src/main/java/calculator/ErrorException.java @@ -0,0 +1,23 @@ +package calculator; + +public class ErrorException { + Message message = new Message(); + + /** + * NumericalError method + * - Raise error when string is not converted to int + * + * return type : void + */ + public int NumericalError(String number) { + int numberConverted = 0; + try { + numberConverted = Integer.parseInt(number); + } catch (NumberFormatException e) { + message.exceptionResult("INVALID_EQUATION"); + Calculator calculator = new Calculator(); + calculator.init(); + } + return numberConverted; + } +} diff --git a/src/main/java/calculator/Message.java b/src/main/java/calculator/Message.java new file mode 100644 index 0000000..fc6db1f --- /dev/null +++ b/src/main/java/calculator/Message.java @@ -0,0 +1,32 @@ +package calculator; + +import java.util.HashMap; + +/** + * Message class + * - message output class + * + * return type : void + */ +public class Message { + HashMap exceptionMessageList = new HashMap(); + + // Result output method when operation is normally performed + public void calculationResult(int result){ + System.out.print("결과 : "); + System.out.println(result); + } + + // Error message list management method + private void exceptionMessageList(){ + exceptionMessageList.put("NOT_OPERATOR", "사칙연산 기호에 해당하지 않는 기호가 존재합니다."); + exceptionMessageList.put("INVALID_EQUATION", "잘못된 연산식입니다."); + exceptionMessageList.put("INVALID_DIVIDE", "0으로 나눌수가 없습니다."); + } + + // Error message output method + public void exceptionResult(String exceptionKeyword){ + exceptionMessageList(); + System.out.println(exceptionMessageList.get(exceptionKeyword)); + } +} diff --git a/src/main/java/calculator/MultiplyOperation.java b/src/main/java/calculator/MultiplyOperation.java new file mode 100644 index 0000000..420217f --- /dev/null +++ b/src/main/java/calculator/MultiplyOperation.java @@ -0,0 +1,14 @@ +package calculator; + +public class MultiplyOperation implements Operation { + @Override + public String operationName() { + return "*"; + } + + @Override + public int calculation(int beforeNumber, int afterNumber) { + int Result = beforeNumber * afterNumber; + return Result; + } +} diff --git a/src/main/java/calculator/Operation.java b/src/main/java/calculator/Operation.java new file mode 100644 index 0000000..77cc374 --- /dev/null +++ b/src/main/java/calculator/Operation.java @@ -0,0 +1,12 @@ +package calculator; + +interface Operation { + String operationName(); + + int calculation(int beforeNumber, int afterNumber); +} + + + + + diff --git a/src/main/java/calculator/SubOperation.java b/src/main/java/calculator/SubOperation.java new file mode 100644 index 0000000..c1839f9 --- /dev/null +++ b/src/main/java/calculator/SubOperation.java @@ -0,0 +1,15 @@ +package calculator; + +public class SubOperation implements Operation { + + @Override + public String operationName() { + return "-"; + } + + @Override + public int calculation(int beforeNumber, int afterNumber) { + int Result = beforeNumber - afterNumber; + return Result; + } +} \ No newline at end of file diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/java/calculator/CalculatorTest.java b/src/test/java/calculator/CalculatorTest.java new file mode 100644 index 0000000..67454eb --- /dev/null +++ b/src/test/java/calculator/CalculatorTest.java @@ -0,0 +1,57 @@ +package calculator; + +import org.junit.jupiter.api.BeforeEach; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +class CalculatorTest { + Calculator calculator; + int firstNumber; + int secondNumber; + String operator; + + @BeforeEach + void setUp() { + calculator = new Calculator(); + firstNumber = 2; + secondNumber = 3; + } + + @Test + void addChooseOperatorAndCalculate(){ + operator = "+"; + int result = 0; + result = calculator.chooseOperatorAndCalculate(firstNumber, operator, secondNumber); + assertEquals(5, result); + assertThat(5).isEqualTo(result); + } + + @Test + void subChooseOperatorAndCalculate(){ + operator = "-"; + int result = 0; + result = calculator.chooseOperatorAndCalculate(firstNumber, operator, secondNumber); + assertThat(-1).isEqualTo(result); + } + + @Test + void multiplyChooseOperatorAndCalculate(){ + operator = "*"; + int result = 0; + result = calculator.chooseOperatorAndCalculate(firstNumber, operator, secondNumber); + assertThat(6).isEqualTo(result); + } + + @Test + void divideChooseOperatorAndCalculate(){ + operator = "/"; + int result = 0; + result = calculator.chooseOperatorAndCalculate(firstNumber, operator, secondNumber); + assertThat(0).isEqualTo(result); + } +} \ No newline at end of file