diff --git a/Mock/.gitignore b/Mock/.gitignore
new file mode 100644
index 0000000..345e61a
--- /dev/null
+++ b/Mock/.gitignore
@@ -0,0 +1,49 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/Mock/.idea/compiler.xml b/Mock/.idea/compiler.xml
new file mode 100644
index 0000000..691ff71
--- /dev/null
+++ b/Mock/.idea/compiler.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Mock/.idea/misc.xml b/Mock/.idea/misc.xml
new file mode 100644
index 0000000..9896aeb
--- /dev/null
+++ b/Mock/.idea/misc.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Mock/.idea/modules.xml b/Mock/.idea/modules.xml
new file mode 100644
index 0000000..10cf8c4
--- /dev/null
+++ b/Mock/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Mock/Mock.iml b/Mock/Mock.iml
new file mode 100644
index 0000000..690021f
--- /dev/null
+++ b/Mock/Mock.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Mock/pom.xml b/Mock/pom.xml
new file mode 100644
index 0000000..84bb5ee
--- /dev/null
+++ b/Mock/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ ru.spbau.mit.kazakov
+ Mock
+ 1.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.8
+
+
+ org.jetbrains
+ annotations
+ 13.0
+
+
+ com.google.guava
+ guava
+ r05
+
+
+ org.mockito
+ mockito-all
+ 1.9.5
+ test
+
+
+
+
\ No newline at end of file
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticCalculator.java b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticCalculator.java
new file mode 100644
index 0000000..b284499
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticCalculator.java
@@ -0,0 +1,26 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+import ru.mit.spbau.kazakov.util.Stack;
+
+import java.util.List;
+
+/**
+ * A class for evaluating arithmetic expressions.
+ * Operators and operands must be separated by whitespace character.
+ * Supported operators: +, -, *, /, %, ^
+ * Don't use brackets for unary minus.
+ */
+public class ArithmeticCalculator {
+ public static void main(String[] args) {
+ String expression = String.join(" ", args);
+ PolishNotationCalculator calculator = new PolishNotationCalculator(new Stack<>());
+
+ try {
+ List polishNotation = ExpressionParser.toPolishNotation(expression);
+ System.out.println(calculator.evaluate(polishNotation));
+ } catch (ArithmeticException exception) {
+ System.out.println(exception.getMessage());
+ }
+ }
+}
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticUtility.java b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticUtility.java
new file mode 100644
index 0000000..34c3f9e
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticUtility.java
@@ -0,0 +1,158 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import org.jetbrains.annotations.NotNull;
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * A class with arithmetic utilities.
+ */
+public class ArithmeticUtility {
+ private static final Map OPERATORS = new HashMap<>();
+
+ static {
+ OPERATORS.put("+", Operator.ADDITION);
+ OPERATORS.put("-", Operator.SUBTRACTION);
+ OPERATORS.put("*", Operator.MULTIPLICATION);
+ OPERATORS.put("/", Operator.DIVISION);
+ OPERATORS.put("%", Operator.MODULO);
+ OPERATORS.put("^", Operator.EXPONENTIATION);
+ }
+
+ private enum Operator {
+ ADDITION(0, true) {
+ @Override
+ public double apply(double augend, double addend) {
+ return augend + addend;
+ }
+ },
+ SUBTRACTION(0, true) {
+ @Override
+ public double apply(double minuend, double subtrahend) {
+ return minuend - subtrahend;
+ }
+ },
+ MULTIPLICATION(5, true) {
+ @Override
+ public double apply(double multiplier, double multiplicand) {
+ return multiplier * multiplicand;
+ }
+ },
+ DIVISION(5, true) {
+ @Override
+ public double apply(double dividend, double divisor) throws ArithmeticException {
+ if (divisor == 0) {
+ throw new ArithmeticException("Division by zero");
+ }
+ return dividend / divisor;
+ }
+ },
+ MODULO(5, true) {
+ @Override
+ public double apply(double dividend, double divisor) {
+ return dividend % divisor;
+ }
+ },
+ EXPONENTIATION(10, false) {
+ @Override
+ public double apply(double base, double exponent) {
+ return Math.pow(base, exponent);
+ }
+ };
+
+ private final int precedence;
+ private final boolean isLeftAssociative;
+
+ Operator(int precedence, boolean isLeftAssociative) {
+ this.precedence = precedence;
+ this.isLeftAssociative = isLeftAssociative;
+ }
+
+ public abstract double apply(double operand1, double operand2) throws ArithmeticException;
+ }
+
+ private static final Pattern IS_NUMERIC = Pattern.compile("[+-]?\\d+(\\.\\d+)?");
+
+ /**
+ * Checks if specified token is a number.
+ *
+ * @param token to check
+ * @return true if specified token is a number, and false otherwise
+ */
+ public static boolean isNumeric(@NotNull String token) {
+ return IS_NUMERIC.matcher(token).matches();
+ }
+
+ /**
+ * Checks if specified token is an operator.
+ *
+ * @param token to check
+ * @return true if specified token is an operator, and false otherwise
+ */
+ public static boolean isOperator(@NotNull String token) {
+ return OPERATORS.containsKey(token);
+ }
+
+ /**
+ * Checks if specified operator is left associative.
+ *
+ * @param operator to check
+ * @return true if specified operator is left associative, and false otherwise
+ */
+ public static boolean isLeftAssociative(@NotNull String operator) throws ArithmeticException {
+ if (!ArithmeticUtility.isOperator(operator)) {
+ throw new ArithmeticException("Unsupported operator: " + operator);
+ }
+ return OPERATORS.get(operator).isLeftAssociative;
+ }
+
+ /**
+ * Compares precedences of specified operators.
+ *
+ * @param operator1 the first operator
+ * @param operator2 the second operator
+ * @return negative number if first operator's precedence is smaller than second operator's precedence,
+ * zero if precedences are equal, and positive number otherwise.
+ */
+ public static int comparePrecedences(@NotNull String operator1, @NotNull String operator2) throws ArithmeticException {
+ if (!isOperator(operator1)) {
+ throw new ArithmeticException("Unsupported operator: " + operator1);
+ }
+ if (!isOperator(operator2)) {
+ throw new ArithmeticException("Unsupported operator: " + operator2);
+ }
+ return OPERATORS.get(operator1).precedence - OPERATORS.get(operator2).precedence;
+ }
+
+ /**
+ * Determines which of two operators evaluates first.
+ *
+ * @param operator1 the first operator
+ * @param operator2 the second operator
+ * @return true if the second operator evaluates before the first one, and false otherwise
+ * @throws ArithmeticException if there is unsupported operator
+ */
+ public static boolean isGoesAfter(@NotNull String operator1, @NotNull String operator2) throws ArithmeticException {
+ return (isLeftAssociative(operator1) && comparePrecedences(operator1, operator2) <= 0)
+ || (!isLeftAssociative(operator1) && comparePrecedences(operator1, operator2) < 0);
+ }
+
+ /**
+ * Applies specified operator to specified arguments.
+ *
+ * @param operator operator for applying
+ * @param operand1 the first argument
+ * @param operand2 the second argument
+ * @return result of application
+ * @throws ArithmeticException if there is unsupported operator
+ */
+ public static double apply(@NotNull String operator, double operand1, double operand2) throws ArithmeticException {
+ if (!isOperator(operator)) {
+ throw new ArithmeticException("Unsupported operator: " + operator);
+ }
+ return OPERATORS.get(operator).apply(operand1, operand2);
+ }
+}
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ExpressionParser.java b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ExpressionParser.java
new file mode 100644
index 0000000..6d1a1ea
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/ExpressionParser.java
@@ -0,0 +1,60 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import org.jetbrains.annotations.NotNull;
+import ru.mit.spbau.kazakov.util.Stack;
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class for parsing mathematical expressions.
+ * Operators and operands must be separated by whitespace character.
+ * Supported operators: +, -, *, /, %, ^
+ * Don't use brackets for unary minus.
+ */
+public class ExpressionParser {
+ /**
+ * Parses specified expression to Polish notation.
+ *
+ * @param expression to parse
+ * @return resulting stack
+ * @throws ArithmeticException if input is invalid
+ */
+ public static List toPolishNotation(@NotNull String expression) throws ArithmeticException {
+ if (expression.trim().length() == 0) {
+ throw new ArithmeticException("Empty expression");
+ }
+
+ ArrayList polishNotation = new ArrayList<>();
+ Stack processingStack = new Stack<>();
+
+ for (String token : expression.trim().split("\\s+")) {
+ if (ArithmeticUtility.isOperator(token)) {
+ while (!processingStack.empty() && ArithmeticUtility.isOperator(processingStack.peek())
+ && ArithmeticUtility.isGoesAfter(token, processingStack.peek())) {
+ polishNotation.add(processingStack.pop());
+ }
+ processingStack.push(token);
+ } else if (token.equals("(")) {
+ processingStack.push("(");
+ } else if (token.equals(")")) {
+ while (!processingStack.empty() && !processingStack.peek().equals("(")) {
+ polishNotation.add(processingStack.pop());
+ }
+ processingStack.pop();
+ } else if (ArithmeticUtility.isNumeric(token)) {
+ polishNotation.add(token);
+ } else {
+ throw new ArithmeticException("Unsupported operator: " + token);
+ }
+ }
+
+ while (!processingStack.empty()) {
+ polishNotation.add(processingStack.pop());
+ }
+
+ return polishNotation;
+ }
+
+}
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/PolishNotationCalculator.java b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/PolishNotationCalculator.java
new file mode 100644
index 0000000..cec53b0
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/arithmetic/PolishNotationCalculator.java
@@ -0,0 +1,65 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import com.google.common.collect.Iterables;
+import org.jetbrains.annotations.NotNull;
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+import ru.mit.spbau.kazakov.exception.EmptyStackException;
+import ru.mit.spbau.kazakov.util.Stack;
+
+import java.util.List;
+
+/**
+ * A class for evaluating expressions in Polish notation.
+ * Supported operators: +, -, *, /, %, ^
+ */
+public class PolishNotationCalculator {
+ /**
+ * Initializes processing stack.
+ *
+ * @param processingStack a stack for evaluating expression
+ */
+ public PolishNotationCalculator(@NotNull Stack processingStack) {
+ this.processingStack = processingStack;
+ }
+
+ /**
+ * Evaluates specified expression.
+ *
+ * @param polishNotation an expression in Polish notation
+ * @return value of the evaluated expression
+ */
+ public double evaluate(@NotNull List polishNotation) throws ArithmeticException {
+ if (polishNotation.size() == 0) {
+ throw new ArithmeticException("Empty expression");
+ }
+
+ try {
+ processingStack.push(Double.parseDouble(polishNotation.get(0)));
+ processingStack.push(Double.parseDouble(polishNotation.get(1)));
+
+ for (String token : Iterables.skip(polishNotation, 2)) {
+ if (ArithmeticUtility.isOperator(token)) {
+ double operand2 = processingStack.pop();
+ double operand1 = processingStack.pop();
+ double operationResult = ArithmeticUtility.apply(token, operand1, operand2);
+ processingStack.push(operationResult);
+ } else if (ArithmeticUtility.isNumeric(token)) {
+ processingStack.push(Double.parseDouble(token));
+ } else {
+ throw new ArithmeticException("Unsupported operator: " + token);
+ }
+ }
+
+ if (processingStack.size() != 1) {
+ throw new ArithmeticException("Invalid expression");
+ }
+
+ return processingStack.pop();
+ }
+ catch (EmptyStackException exception) {
+ throw new ArithmeticException("Invalid expression");
+ }
+ }
+
+ private Stack processingStack;
+}
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/exception/ArithmeticException.java b/Mock/src/main/java/ru/mit/spbau/kazakov/exception/ArithmeticException.java
new file mode 100644
index 0000000..4b5b6f2
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/exception/ArithmeticException.java
@@ -0,0 +1,10 @@
+package ru.mit.spbau.kazakov.exception;
+
+/**
+ * Thrown when unsupported arithmetic operation called.
+ */
+public class ArithmeticException extends Exception {
+ public ArithmeticException(String message) {
+ super(message);
+ }
+}
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/exception/EmptyStackException.java b/Mock/src/main/java/ru/mit/spbau/kazakov/exception/EmptyStackException.java
new file mode 100644
index 0000000..8275884
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/exception/EmptyStackException.java
@@ -0,0 +1,4 @@
+package ru.mit.spbau.kazakov.exception;
+
+public class EmptyStackException extends RuntimeException {
+}
diff --git a/Mock/src/main/java/ru/mit/spbau/kazakov/util/Stack.java b/Mock/src/main/java/ru/mit/spbau/kazakov/util/Stack.java
new file mode 100644
index 0000000..b12a848
--- /dev/null
+++ b/Mock/src/main/java/ru/mit/spbau/kazakov/util/Stack.java
@@ -0,0 +1,87 @@
+package ru.mit.spbau.kazakov.util;
+
+import ru.mit.spbau.kazakov.exception.EmptyStackException;
+
+/**
+ * An implementation of stack interface for arithmetic calculator.
+ *
+ * @param type of stored data
+ */
+public class Stack {
+ /**
+ * Pushes new element to the top of stack.
+ *
+ * @param value to push
+ * @return pushed value
+ */
+ public T push(T value) {
+ top = new Node<>(value, top);
+ size++;
+
+ return value;
+ }
+
+ /**
+ * Returns top element.
+ */
+ public T peek() {
+ if (empty()) {
+ throw new EmptyStackException();
+ }
+ return top.value;
+ }
+
+ /**
+ * Deletes top element from stack.
+ *
+ * @return deleted element
+ */
+ public T pop() {
+ if (empty()) {
+ throw new EmptyStackException();
+ }
+
+ T returnValue = top.value;
+ top = top.prev;
+ size--;
+
+ return returnValue;
+ }
+
+ /**
+ * Checks if stack is empty.
+ *
+ * @return true if stack is empty, and false otherwise.
+ */
+ public boolean empty() {
+ return top == null;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ private Node top = null;
+ private int size = 0;
+
+ /**
+ * A stack entry for storing a value and previous entry.
+ *
+ * @param type of stored data
+ */
+ private static class Node {
+ private T value;
+ private Node prev;
+
+ /**
+ * Initializes stored value and reference to previous Node.
+ *
+ * @param value to initialize with
+ * @param prev a previous Node
+ */
+ Node(T value, Node prev) {
+ this.value = value;
+ this.prev = prev;
+ }
+ }
+}
diff --git a/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticUtilityTest.java b/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticUtilityTest.java
new file mode 100644
index 0000000..cef8080
--- /dev/null
+++ b/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/ArithmeticUtilityTest.java
@@ -0,0 +1,199 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+
+import static org.junit.Assert.*;
+
+public class ArithmeticUtilityTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testIsNumericEmpty() {
+ assertFalse(ArithmeticUtility.isNumeric(""));
+ }
+
+ @Test
+ public void testIsNumericMinus() {
+ assertFalse(ArithmeticUtility.isNumeric("+"));
+ }
+
+ @Test
+ public void testIsNumericPlus() {
+ assertFalse(ArithmeticUtility.isNumeric("-"));
+ }
+
+ @Test
+ public void testIsNumericInt() {
+ assertTrue(ArithmeticUtility.isNumeric("54576545332"));
+ }
+
+ @Test
+ public void testIsNumericDouble() {
+ assertTrue(ArithmeticUtility.isNumeric("32312.54576545332"));
+ }
+
+ @Test
+ public void testIsOperatorPlus() {
+ assertTrue(ArithmeticUtility.isOperator("+"));
+ }
+
+ @Test
+ public void testIsOperatorMinus() {
+ assertTrue(ArithmeticUtility.isOperator("-"));
+ }
+
+ @Test
+ public void testIsOperatorMultiply() {
+ assertTrue(ArithmeticUtility.isOperator("*"));
+ }
+
+ @Test
+ public void testIsOperatorDivide() {
+ assertTrue(ArithmeticUtility.isOperator("/"));
+ }
+
+ @Test
+ public void testIsOperatorModulo() {
+ assertTrue(ArithmeticUtility.isOperator("%"));
+ }
+
+ @Test
+ public void testIsOperatorPow() {
+ assertTrue(ArithmeticUtility.isOperator("^"));
+ }
+
+ @Test
+ public void testIsOperatorIncrement() {
+ assertFalse(ArithmeticUtility.isOperator("++"));
+ }
+
+ @Test
+ public void testIsOperatorXor() {
+ assertFalse(ArithmeticUtility.isOperator("xor"));
+ }
+
+ @Test
+ public void testIsLeftAssociativeThrowsArithmeticException() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Unsupported operator: xor");
+ ArithmeticUtility.isLeftAssociative("xor");
+ }
+
+ @Test
+ public void testIsLeftAssociativePlus() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.isLeftAssociative("+"));
+ }
+
+ @Test
+ public void testIsLeftAssociativeMinus() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.isLeftAssociative("-"));
+ }
+
+ @Test
+ public void testIsLeftAssociativeMultiply() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.isLeftAssociative("*"));
+ }
+
+ @Test
+ public void testIsLeftAssociativeDivide() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.isLeftAssociative("/"));
+ }
+
+ @Test
+ public void testIsLeftAssociativeModulo() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.isLeftAssociative("%"));
+ }
+
+ @Test
+ public void testIsLeftAssociativePow() throws ArithmeticException {
+ assertFalse(ArithmeticUtility.isLeftAssociative("^"));
+ }
+
+ @Test
+ public void testComparePrecedencesThrowsArithmeticException() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Unsupported operator: ++");
+ ArithmeticUtility.comparePrecedences("++", "-");
+ }
+
+ @Test
+ public void testComparePrecedencesEqual() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.comparePrecedences("+", "-") == 0);
+ }
+
+ @Test
+ public void testComparePrecedencesLess() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.comparePrecedences("+", "*") < 0);
+ }
+
+ @Test
+ public void testComparePrecedencesGreater() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.comparePrecedences("^", "%") > 0);
+ }
+
+ @Test
+ public void testIsGoesAfterThrowsArithmeticException() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Unsupported operator: **");
+ ArithmeticUtility.isGoesAfter("+", "**");
+ }
+
+ @Test
+ public void testIsGoesAfterTrue() throws ArithmeticException {
+ assertTrue(ArithmeticUtility.isGoesAfter("+", "%"));
+ }
+
+ @Test
+ public void testIsGoesAfterFalse() throws ArithmeticException {
+ assertFalse(ArithmeticUtility.isGoesAfter("/", "-"));
+ }
+
+ @Test
+ public void testApplyThrowsArithmeticException() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Unsupported operator: xor");
+ ArithmeticUtility.apply("xor", 5.0, 0.5);
+ }
+
+ @Test
+ public void testApplyPlus() throws ArithmeticException {
+ assertEquals(5.5, ArithmeticUtility.apply("+", 5.0, 0.5), 0.000001);
+ }
+
+ @Test
+ public void testApplyMinus() throws ArithmeticException {
+ assertEquals(103.3, ArithmeticUtility.apply("-", 103.4, 0.1), 0.000001);
+ }
+
+ @Test
+ public void testApplyMultiply() throws ArithmeticException {
+ assertEquals(10.0, ArithmeticUtility.apply("*", 5.0, 2.0), 0.000001);
+ }
+
+ @Test
+ public void testApplyDivide() throws ArithmeticException {
+ assertEquals(5.0, ArithmeticUtility.apply("/", 40.0, 8.0), 0.000001);
+ }
+
+ @Test
+ public void testApplyDivideThrowsArithmeticException() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Division by zero");
+ assertEquals(5.0, ArithmeticUtility.apply("/", 40.0, 0.0), 0.000001);
+ }
+
+ @Test
+ public void testApplyModulo() throws ArithmeticException {
+ assertEquals(1.0, ArithmeticUtility.apply("%", 15.0, 7.0), 0.000001);
+ }
+
+ @Test
+ public void testApplyPow() throws ArithmeticException {
+ assertEquals(64.0, ArithmeticUtility.apply("^", 2.0, 6.0), 0.000001);
+ }
+
+}
\ No newline at end of file
diff --git a/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/ExpressionParserTest.java b/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/ExpressionParserTest.java
new file mode 100644
index 0000000..e0734fb
--- /dev/null
+++ b/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/ExpressionParserTest.java
@@ -0,0 +1,36 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class ExpressionParserTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testToPolishNotation1() throws ArithmeticException {
+ List polishNotation = ExpressionParser.toPolishNotation("( 1 + 2 ) * ( 3 / 4 ) ^ ( 5 + 6 )");
+ assertEquals(Arrays.asList("1", "2", "+", "3", "4", "/", "5", "6", "+", "^", "*"), polishNotation);
+ }
+
+ @Test
+ public void testToPolishNotation2() throws ArithmeticException {
+ List polishNotation = ExpressionParser.toPolishNotation("( -4 + 6 ) % 3 - ( 5 - 4 ) * ( 11 + 54 )");
+ assertEquals(Arrays.asList("-4", "6", "+", "3", "%", "5", "4", "-", "11", "54", "+", "*", "-"), polishNotation);
+ }
+
+ @Test
+ public void testToPolishNotationThrowsArithmeticException() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Unsupported operator: xor");
+ ExpressionParser.toPolishNotation("( 1 + 2 ) * ( 3 / 4 ) ^ ( 5 xor 6 )");
+ }
+
+}
\ No newline at end of file
diff --git a/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/PolishNotationCalculatorTest.java b/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/PolishNotationCalculatorTest.java
new file mode 100644
index 0000000..29e5c09
--- /dev/null
+++ b/Mock/src/test/java/ru/mit/spbau/kazakov/arithmetic/PolishNotationCalculatorTest.java
@@ -0,0 +1,100 @@
+package ru.mit.spbau.kazakov.arithmetic;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.InOrder;
+import ru.mit.spbau.kazakov.exception.ArithmeticException;
+import ru.mit.spbau.kazakov.util.Stack;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class PolishNotationCalculatorTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testEvaluateEasy() throws ArithmeticException {
+ Stack stack = mock(Stack.class);
+ when(stack.pop()).thenReturn(2.0, -3.0, -1.0);
+ when(stack.size()).thenReturn(1);
+
+ PolishNotationCalculator calculator = new PolishNotationCalculator(stack);
+ assertEquals(-1.0,
+ calculator.evaluate(Arrays.asList("-3", "2", "%")), 0.00001);
+
+ InOrder inOrder = inOrder(stack);
+ inOrder.verify(stack).push(-3.0);
+ inOrder.verify(stack).push(2.0);
+ inOrder.verify(stack, times(2)).pop();
+ inOrder.verify(stack).push(-1.0);
+ inOrder.verify(stack).size();
+ inOrder.verify(stack).pop();
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testEvaluateMedium() throws ArithmeticException {
+ Stack stack = mock(Stack.class);
+ when(stack.pop()).thenReturn(2.0, 1.0, 3.0, 4.0, 1.3333333333333333, 3.0, 6.0, 5.0, 11.0, 4.0, 4194304.0);
+ when(stack.size()).thenReturn(1);
+
+ PolishNotationCalculator calculator = new PolishNotationCalculator(stack);
+ assertEquals(4194304.0,
+ calculator.evaluate(Arrays.asList("1", "2", "+", "4", "3", "/", "*", "5", "6", "+", "^")), 0.00001);
+
+ InOrder inOrder = inOrder(stack);
+ inOrder.verify(stack).push(1.0);
+ inOrder.verify(stack).push(2.0);
+ inOrder.verify(stack, times(2)).pop();
+ inOrder.verify(stack).push(3.0);
+ inOrder.verify(stack).push(4.0);
+ inOrder.verify(stack).push(3.0);
+ inOrder.verify(stack, times(2)).pop();
+ inOrder.verify(stack).push(1.3333333333333333);
+ inOrder.verify(stack, times(2)).pop();
+ inOrder.verify(stack).push(4.0);
+ inOrder.verify(stack).push(5.0);
+ inOrder.verify(stack).push(6.0);
+ inOrder.verify(stack, times(2)).pop();
+ inOrder.verify(stack).push(11.0);
+ inOrder.verify(stack, times(2)).pop();
+ inOrder.verify(stack).push(4194304.0);
+ inOrder.verify(stack).size();
+ inOrder.verify(stack).pop();
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testEvaluateInvalidExpression() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Invalid expression");
+
+ Stack stack = mock(Stack.class);
+ when(stack.pop()).thenReturn(2.0, 1.0, 1.0, 5.0);
+ when(stack.size()).thenReturn(2);
+
+ PolishNotationCalculator calculator = new PolishNotationCalculator(stack);
+ calculator.evaluate(Arrays.asList("1", "2", "%", "5"));
+
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testEvaluateUnsupportedOperator() throws ArithmeticException {
+ thrown.expect(ArithmeticException.class);
+ thrown.expectMessage("Unsupported operator: div");
+
+ Stack stack = mock(Stack.class);
+ when(stack.pop()).thenReturn(2.0, 1.0);
+
+ PolishNotationCalculator calculator = new PolishNotationCalculator(stack);
+ calculator.evaluate(Arrays.asList("1", "2", "div"));
+
+ }
+
+}
\ No newline at end of file
diff --git a/Mock/src/test/java/ru/mit/spbau/kazakov/util/StackTest.java b/Mock/src/test/java/ru/mit/spbau/kazakov/util/StackTest.java
new file mode 100644
index 0000000..e8d99b3
--- /dev/null
+++ b/Mock/src/test/java/ru/mit/spbau/kazakov/util/StackTest.java
@@ -0,0 +1,103 @@
+package ru.mit.spbau.kazakov.util;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import ru.mit.spbau.kazakov.exception.EmptyStackException;
+
+import static org.junit.Assert.*;
+
+public class StackTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testConstructor() {
+ new Stack<>();
+ }
+
+ @Test
+ public void testPushReturnValue() {
+ Stack stack = new Stack<>();
+ assertEquals("abc", stack.push("abc"));
+ }
+
+ @Test
+ public void testPeek() {
+ Stack stack = new Stack<>();
+ stack.push("xyz");
+ assertEquals("xyz", stack.peek());
+ }
+
+ @Test
+ public void testOneHundredPeek() {
+ Stack stack = new Stack<>();
+ for (int i = 0; i < 100; i++) {
+ stack.push(Integer.toString(i));
+ assertEquals(Integer.toString(i), stack.peek());
+ }
+ }
+
+ @Test
+ public void testPopThrowsEmptyStackException() throws EmptyStackException {
+ thrown.expect(EmptyStackException.class);
+ new Stack<>().pop();
+ }
+
+ @Test
+ public void testPopReturnValue() throws EmptyStackException {
+ Stack stack = new Stack<>();
+ stack.push(".");
+ assertEquals(".", stack.pop());
+ }
+
+ @Test
+ public void testSizeEmpty() {
+ assertEquals(0, new Stack<>().size());
+ }
+
+ @Test
+ public void testSizeOnePushed() {
+ Stack stack = new Stack<>();
+ stack.push(33);
+ assertEquals(1, stack.size());
+ }
+
+ @Test
+ public void testSizeOneHundredPushed() {
+ Stack stack = new Stack<>();
+ for (int i = 0; i < 100; i++) {
+ stack.push(i);
+ }
+ assertEquals(100, stack.size());
+ }
+
+ @Test
+ public void testSizeAfterPop() {
+ Stack stack = new Stack<>();
+ stack.push(21);
+ stack.push(76);
+ stack.pop();
+ assertEquals(1, stack.size());
+ }
+
+ @Test
+ public void testEmptyEmpty() {
+ assertTrue(new Stack<>().empty());
+ }
+
+ @Test
+ public void testEmptyAfterPush() {
+ Stack stack = new Stack<>();
+ stack.push("r");
+ assertFalse(stack.empty());
+ }
+
+ @Test
+ public void testEmptyAfterPop() {
+ Stack stack = new Stack<>();
+ stack.push("r");
+ stack.pop();
+ assertTrue(stack.empty());
+ }
+}
\ No newline at end of file