diff --git a/08.Mock/pom.xml b/08.Mock/pom.xml new file mode 100644 index 0000000..2aaa4a6 --- /dev/null +++ b/08.Mock/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + 08 + Mock + 1.0-SNAPSHOT + + + org.jetbrains + annotations-java5 + 15.0 + + + junit + junit + 4.12 + + + org.mockito + mockito-all + 1.8.4 + test + + + + + + \ No newline at end of file diff --git a/08.Mock/src/main/java/ru/spbau/mit/alyokhina/Calculator.java b/08.Mock/src/main/java/ru/spbau/mit/alyokhina/Calculator.java new file mode 100644 index 0000000..d49454c --- /dev/null +++ b/08.Mock/src/main/java/ru/spbau/mit/alyokhina/Calculator.java @@ -0,0 +1,165 @@ +package ru.spbau.mit.alyokhina; + + +import org.jetbrains.annotations.NotNull; + +/** By arithmetic expression receives a reverse Polish notation and computes the value */ +public class Calculator { + public static void main(String[] argv) { + if (argv.length == 0) { + System.out.println("Expected expression"); + } else { + Stack expr = new Stack(); + for (int i = argv[0].length() - 1; i >= 0; i--) { + if ((argv[0].charAt(i) >= '0' && argv[0].charAt(i) <= '9') || (argv[0].charAt(i) == '.')) { + StringBuilder sb = new StringBuilder(); + while (i < argv[0].length() && ((argv[0].charAt(i) >= '0' && argv[0].charAt(i) <= '9') || (argv[0].charAt(i) == '.'))) { + sb.insert(0, argv[0].charAt(i)); + i--; + } + i++; + expr.push(sb.toString()); + } else if (argv[0].charAt(i) == '+' || argv[0].charAt(i) == '-' || argv[0].charAt(i) == '*' || + argv[0].charAt(i) == '/' || argv[0].charAt(i) == '(' || argv[0].charAt(i) == ')') { + expr.push(argv[0].substring(i, i + 1)); + } + } + Calculator calculator = new Calculator(expr); + System.out.println(calculator.getRPN()); + System.out.println(calculator.calculate()); + } + } + /** Stack for storing the expression */ + private Stack expression = new Stack(); + + /** Stack for storing current operands */ + private Stack operand = new Stack(); + + /** Stack for storing reverse Polish notation */ + private Stack rpn = new Stack(); + + /** + * Constructor + * @param newExpression an expression that needs to be translated into a reverse Polish notation + */ + public Calculator(@NotNull Stack newExpression) { + expression = newExpression; + rpn = new Stack(); + operand = new Stack(); + } + + /** + * Constructor + * @param newExpression an expression that needs to be translated into a reverse Polish notation + * @param forOperand stack for storing the operands + * @param forRPN stack for storing reverse Polish notation + */ + public Calculator(@NotNull Stack newExpression, @NotNull Stack forOperand, @NotNull Stack forRPN) { + expression = newExpression; + rpn = forRPN; + operand = forOperand; + } + + /** + * Get reverse Polish notation + * @return reverse Polish notation as a string. All elements are separated by a space. The same value is stored in rpn + */ + public String getRPN() { + StringBuilder stringBuilder = new StringBuilder(); + + while (!expression.isEmpty()) { + String cur = expression.pop(); + if (cur.equals("(")) { + operand.push("("); + } else if (cur.equals(")")) { + while (!operand.isEmpty() && !operand.peek().equals("(")) { + String str = operand.pop(); + rpn.push(str); + stringBuilder.append(" "); + stringBuilder.append(str); + } + if (!operand.isEmpty()) { + operand.pop(); + } + } else if (isOperand(cur)) { + while (!operand.isEmpty() && !operand.peek().equals("(") + && (priority(operand.peek()) >= priority(cur))) { + String str = operand.pop(); + rpn.push(str); + stringBuilder.append(" "); + stringBuilder.append(str); + } + operand.push(cur); + } else { + rpn.push(cur); + stringBuilder.append(" "); + stringBuilder.append(cur); + } + } + while (!operand.isEmpty()) { + String str = operand.pop(); + rpn.push(str); + stringBuilder.append(" "); + stringBuilder.append(str); + } + return stringBuilder.toString(); + } + + /** + * Calculates the value of the expression + * @return The result of calculation of type Double + */ + public Double calculate() { + if (!rpn.isEmpty()) { + if (isOperand(rpn.peek())) { + String op = rpn.pop(); + return apply(calculate(), calculate(), op); + } else { + return (Double.parseDouble(rpn.pop())); + } + } else { + return 0.0; + } + } + + /** + * Whether the string is an operand + * @param str string, which we want to check + * @return true, if this string is operand, else - false + */ + private boolean isOperand(String str) { + return (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")); + } + + /** + * Application of operations + * @param a,b these values will be applied to the operation + * @param op the operation to be applied + * @return result of type Double + */ + @NotNull + private Double apply(Double a, Double b, String op) { + if (op.equals("+")) { + return a + b; + } else if (op.equals("-")) { + return a - b; + } else if (op.equals("*")) { + return a * b; + } else { + return a / b; + } + } + + /** + * the priority of an operation + * @param operand the operand, the priority of which will be issued + * @return priority + */ + private static int priority(@NotNull String operand) { + if (operand.equals("+") || operand.equals("-")) { + return 1; + } else { + return 2; + } + } +} diff --git a/08.Mock/src/main/java/ru/spbau/mit/alyokhina/Stack.java b/08.Mock/src/main/java/ru/spbau/mit/alyokhina/Stack.java new file mode 100644 index 0000000..5e1b70c --- /dev/null +++ b/08.Mock/src/main/java/ru/spbau/mit/alyokhina/Stack.java @@ -0,0 +1,76 @@ +package ru.spbau.mit.alyokhina; + +import org.jetbrains.annotations.NotNull; + +/** + * Stack for Calculator + * @param type of stored items + */ +public class Stack { + /** First element in Stack */ + Node head = null; + + /** + * Add element in Stack + * @param newValue element, which will be add + */ + public void push(@NotNull T newValue) { + Node newHead = new Node(); + newHead.value = newValue; + newHead.next = head; + head = newHead; + } + + /** + * Delete last added item + * @return item that was deleted or null, if there was no such element + */ + public T pop() { + if (head != null) { + T returnValue = head.value; + head = head.next; + return returnValue; + } else + return null; + } + + /** + * last added item + * @return last added item or null if stack is empty + */ + public T peek() { + if (head != null) + return head.value; + else + return null; + } + + /** + * Checking the existence of elements in stack + * @return tru, if stack is empty, else - false + */ + public boolean isEmpty() { + return (head == null); + } + + /** + * Moves the stack to a string, separated by a space + * @return resulting string + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + Node v = head; + while (v != null) { + sb.append((v.value).toString()); + sb.append(" "); + v = v.next; + } + return sb.toString(); + } + + /** Class for Stack. Element of Stack */ + private class Node { + private Node next; + private T value; + } +} diff --git a/08.Mock/src/test/java/ru/spbau/mit/alyokhina/CalculatorTest.java b/08.Mock/src/test/java/ru/spbau/mit/alyokhina/CalculatorTest.java new file mode 100644 index 0000000..b75df57 --- /dev/null +++ b/08.Mock/src/test/java/ru/spbau/mit/alyokhina/CalculatorTest.java @@ -0,0 +1,95 @@ +package ru.spbau.mit.alyokhina; + +import org.junit.Test; + +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +public class CalculatorTest { + @Test + public void testGetRPN() { + Stack expression = mock(Stack.class); + Stack operand = mock(Stack.class); + Stack rpn = mock(Stack.class); + when(expression.isEmpty()) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(true); + + when(expression.pop()) + .thenReturn("(") + .thenReturn("1") + .thenReturn("+") + .thenReturn("3") + .thenReturn(")") + .thenReturn("*") + .thenReturn("2"); + + when(operand.isEmpty()) + .thenReturn(true) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(true) + .thenReturn(false) + .thenReturn(true); + + when(operand.peek()) + .thenReturn("+") + .thenReturn("("); + + when(operand.pop()) + .thenReturn("+") + .thenReturn("(") + .thenReturn("*"); + + Calculator calculator = new Calculator(expression, operand, rpn); + assertEquals(" 1 3 + 2 *", calculator.getRPN()); + + + verify(operand).push("("); + verify(rpn).push("1"); + verify(operand).push("+"); + verify(rpn).push("3"); + verify(rpn).push("+"); + verify(operand).push("*"); + verify(rpn).push("2"); + verify(rpn).push("*"); + } + + @Test + public void testCalculate() { + Stack expression = mock(Stack.class); + Stack operand = mock(Stack.class); + Stack rpn = mock(Stack.class); + when(rpn.isEmpty()) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(false) + .thenReturn(true); + when(rpn.peek()) + .thenReturn("*") + .thenReturn("2") + .thenReturn("+") + .thenReturn("3") + .thenReturn("1"); + + when(rpn.pop()) + .thenReturn("*") + .thenReturn("2") + .thenReturn("+") + .thenReturn("3") + .thenReturn("1"); + Calculator calculator = new Calculator(expression, operand, rpn); + assertEquals((Double) 8.0, calculator.calculate()); + + } + +} diff --git a/08.Mock/src/test/java/ru/spbau/mit/alyokhina/StackTest.java b/08.Mock/src/test/java/ru/spbau/mit/alyokhina/StackTest.java new file mode 100644 index 0000000..b8a5569 --- /dev/null +++ b/08.Mock/src/test/java/ru/spbau/mit/alyokhina/StackTest.java @@ -0,0 +1,75 @@ +package ru.spbau.mit.alyokhina; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class StackTest { + @Test + public void testConstructor() { + Stack s; + } + + @Test + public void testPush() { + Stack s = new Stack(); + s.push(3); + assertEquals((Integer) 3, s.peek()); + s.push(5); + assertEquals((Integer) 5, s.peek()); + } + + @Test + public void testPopFromEmptyStack() { + Stack s = new Stack(); + assertEquals(null, s.pop()); + } + + + @Test + public void testPop() { + Stack s = new Stack(); + s.push(3); + s.push(5); + assertEquals((Integer) 5, s.pop()); + assertEquals((Integer) 3, s.peek()); + } + + @Test + public void testPeekFromEmptyStack() { + Stack s = new Stack(); + assertEquals(null, s.peek()); + } + + @Test + public void testPeek() { + Stack s = new Stack(); + s.push(3); + s.push(5); + assertEquals((Integer) 5, s.peek()); + } + + + @Test + public void testIsEmptyIfTrue() { + Stack s = new Stack(); + assertEquals(true, s.isEmpty()); + } + + @Test + public void testIsEmptyIfFalse() { + Stack s = new Stack(); + s.push(1); + assertEquals(false, s.isEmpty()); + } + + @Test + public void print() { + Stack s = new Stack(); + s.push(3); + s.push(5); + String t = "5 3 "; + assertEquals(t, s.toString()); + } + +} \ No newline at end of file