diff --git a/javafx-template/src/main/java/app/AppController.java b/javafx-template/src/main/java/app/AppController.java index 1cbbd295aac1d9594c7610f135965215c8bbebbb..d47da69d76a9dbbfd1678a5d6787a9f53466b019 100644 --- a/javafx-template/src/main/java/app/AppController.java +++ b/javafx-template/src/main/java/app/AppController.java @@ -100,6 +100,11 @@ public class AppController { // TODO clear operand } + @FXML + void handleSwap() { + // TODO clear operand + } + private void performOperation(UnaryOperator<Double> op) { // TODO } diff --git a/javafx-template/src/main/java/app/Calc.java b/javafx-template/src/main/java/app/Calc.java index 6102e31383fcdb96fa94197a73a7774bfcbd70a1..8ff70b8fedecadf649989648439d43499a485763 100644 --- a/javafx-template/src/main/java/app/Calc.java +++ b/javafx-template/src/main/java/app/Calc.java @@ -7,10 +7,13 @@ import java.util.function.UnaryOperator; public class Calc { - private List<Double> operandStack = new ArrayList<>(); + private final List<Double> operandStack; - public Calc(Double... operands) { - operandStack.addAll(List.of(operands)); + public Calc(double... operands) { + operandStack = new ArrayList<>(operands.length + 2); + for (var d : operands) { + operandStack.add(d); + } } /** @@ -20,29 +23,24 @@ public class Calc { return operandStack.size(); } - /** - * Pushes a new operand into the n'th place from the top. - * @param n the place to push - * @param d the new operand - */ - public void pushOperand(int n, double d) { - operandStack.add(operandStack.size() - n, d); - } - /** * Pushes a new operand onto top of the stack. * @param d the new operand */ public void pushOperand(double d) { - pushOperand(0, d); + operandStack.add(d); } /** * @param n the place (from the top) to peek * @return the n'th operand from the top + * @throws IllegalArgumentException if n is larger than the operand count */ public double peekOperand(int n) { - return operandStack.get(operandStack.size() - n - 1); + if (n > getOperandCount()) { + throw new IllegalArgumentException("Cannot peek at position " + n + " when the operand count is " + getOperandCount()); + } + return operandStack.get(getOperandCount() - n - 1); } /** @@ -52,30 +50,26 @@ public class Calc { return peekOperand(0); } - /** - * Removes and returns the n'th operand from the top. - * @param n the place from the top to remove - * @return the n'th operand from the top - */ - public double popOperand(int n) { - return operandStack.remove(operandStack.size() - n - 1); - } - /** * Removes and returns the top operand. * @return the top operand + * @throws IllegalStateException if the stack is empty */ public double popOperand() { - return popOperand(0); + if (getOperandCount() == 0) { + throw new IllegalStateException("Cannot pop from an empty stack"); + } + return operandStack.remove(operandStack.size() - 1); } - + /** * Performs the provided operation in the top operand, and * replaces it with the result. * @param op the operation to perform * @return the result of performing the operation + * @throws IllegalStateException if the operand stack is empty */ - public double performOperation(UnaryOperator<Double> op) { + public double performOperation(UnaryOperator<Double> op) throws IllegalStateException { // TODO return 0.0; } @@ -85,8 +79,12 @@ public class Calc { * replaces them with the result. * @param op the operation to perform * @return the result of performing the operation + * @throws IllegalStateException if the operand count is less than two */ - public double performOperation(BinaryOperator<Double> op) { + public double performOperation(BinaryOperator<Double> op) throws IllegalStateException { + if (getOperandCount() < 2) { + throw new IllegalStateException("Too few operands (" + getOperandCount() + ") on the stack"); + } var op1 = popOperand(); var op2 = popOperand(); var result = op.apply(op1, op2); diff --git a/javafx-template/src/main/resources/app/App.fxml b/javafx-template/src/main/resources/app/App.fxml index 41f4e4f1816de5e5e8134f3f6c45307279f7e554..7356474389da1d59fbedba33e5186b44f993c4f3 100644 --- a/javafx-template/src/main/resources/app/App.fxml +++ b/javafx-template/src/main/resources/app/App.fxml @@ -15,7 +15,7 @@ <!-- multi-line button label with XML entity for newline --> <Button text="E n t e r" onAction="#handleEnter" - GridPane.rowIndex="2" GridPane.columnIndex="3" GridPane.rowSpan="4"/> + GridPane.rowIndex="2" GridPane.columnIndex="3" GridPane.rowSpan="3"/> <Button text="7" onAction="#handleDigit" GridPane.rowIndex="2" GridPane.columnIndex="0"/> @@ -23,24 +23,29 @@ GridPane.rowIndex="2" GridPane.columnIndex="1"/> <Button text="9" onAction="#handleDigit" GridPane.rowIndex="2" GridPane.columnIndex="2"/> + <Button text="4" onAction="#handleDigit" GridPane.rowIndex="3" GridPane.columnIndex="0"/> <Button text="5" onAction="#handleDigit" GridPane.rowIndex="3" GridPane.columnIndex="1"/> <Button text="6" onAction="#handleDigit" GridPane.rowIndex="3" GridPane.columnIndex="2"/> + <Button text="1" onAction="#handleDigit" GridPane.rowIndex="4" GridPane.columnIndex="0"/> <Button text="2" onAction="#handleDigit" GridPane.rowIndex="4" GridPane.columnIndex="1"/> <Button text="3" onAction="#handleDigit" GridPane.rowIndex="4" GridPane.columnIndex="2"/> + <Button text="0" onAction="#handleDigit" GridPane.rowIndex="5" GridPane.columnIndex="0"/> <Button text="." onAction="#handlePoint" GridPane.rowIndex="5" GridPane.columnIndex="1"/> <Button text="C" onAction="#handleClear" GridPane.rowIndex="5" GridPane.columnIndex="2"/> + <Button text="~" onAction="#handleSwap" + GridPane.rowIndex="5" GridPane.columnIndex="3"/> <Button text="+" onAction="#handleOpAdd" GridPane.rowIndex="6" GridPane.columnIndex="0"/> diff --git a/javafx-template/src/test/java/app/CalcTest.java b/javafx-template/src/test/java/app/CalcTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9a7c0df0cc7517529e1b579ed515ddc89a8e8eda --- /dev/null +++ b/javafx-template/src/test/java/app/CalcTest.java @@ -0,0 +1,39 @@ +package app; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CalcTest { + + private static void checkCalc(Calc calc, double... operands) { + Assertions.assertEquals(operands.length, calc.getOperandCount(), "Wrong operand count"); + for (int i = 0; i < operands.length; i++) { + Assertions.assertEquals(operands[i], calc.peekOperand(i), "Wrong value at #" + i + " of operand stack"); + } + } + + @Test + public void testCalc() { + checkCalc(new Calc()); + checkCalc(new Calc(1.0), 1.0); + checkCalc(new Calc(3.14, 1.0), 1.0, 3.14); + } + + @Test + public void testPushOperand() { + Calc calc = new Calc(); + calc.pushOperand(1.0); + checkCalc(calc, 1.0); + calc.pushOperand(3.14); + checkCalc(calc, 3.14, 1.0); + } + + @Test + public void testPopOperand() { + Calc calc = new Calc(1.0, 3.14); + Assertions.assertEquals(3.14, calc.popOperand()); + checkCalc(calc, 1.0); + Assertions.assertEquals(1.0, calc.popOperand()); + checkCalc(calc); + } +}