Reformat files to use 2 space indentation

This commit is contained in:
Oystein Kristoffer Tveit 2021-09-05 19:04:28 +02:00
parent 82169b0a2e
commit 736b3c4da0
7 changed files with 504 additions and 514 deletions

View File

@ -1,51 +1,51 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>it1901</groupId> <groupId>it1901</groupId>
<artifactId>javafx-template</artifactId> <artifactId>javafx-template</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source> <maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target> <maven.compiler.target>16</maven.compiler.target>
</properties> </properties>
<dependencies> <dependencies>
<!-- javafx --> <!-- javafx -->
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId> <artifactId>javafx-controls</artifactId>
<version>16</version> <version>16</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId> <artifactId>javafx-fxml</artifactId>
<version>16</version> <version>16</version>
</dependency> </dependency>
<!-- junit testing with jupiter --> <!-- junit testing with jupiter -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>5.7.2</version> <version>5.7.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.7.2</version> <version>5.7.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId> <artifactId>junit-jupiter-params</artifactId>
<version>5.7.2</version> <version>5.7.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- test javafx with TextFX --> <!-- test javafx with TextFX -->
<dependency> <dependency>
<groupId>org.testfx</groupId> <groupId>org.testfx</groupId>
<artifactId>testfx-core</artifactId> <artifactId>testfx-core</artifactId>
@ -57,42 +57,42 @@
<artifactId>testfx-junit5</artifactId> <artifactId>testfx-junit5</artifactId>
<version>4.0.16-alpha</version> <version>4.0.16-alpha</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId> <artifactId>hamcrest</artifactId>
<version>2.2</version> <version>2.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<release>16</release> <release>16</release>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version> <version>3.0.0-M5</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.openjfx</groupId> <groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId> <artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version> <version>0.0.6</version>
<!-- Default configuration for running --> <!-- Default configuration for running -->
<!-- Usage: mvn javafx:run --> <!-- Usage: mvn javafx:run -->
<configuration> <configuration>
<mainClass>app.App</mainClass> <mainClass>app.App</mainClass>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -13,15 +13,15 @@ import java.io.IOException;
*/ */
public class App extends Application { public class App extends Application {
@Override @Override
public void start(Stage stage) throws IOException { public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("App.fxml")); FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("App.fxml"));
Parent parent = fxmlLoader.load(); Parent parent = fxmlLoader.load();
stage.setScene(new Scene(parent)); stage.setScene(new Scene(parent));
stage.show(); stage.show();
} }
public static void main(String[] args) { public static void main(String[] args) {
launch(); launch();
} }
} }

View File

@ -12,122 +12,122 @@ import javafx.scene.control.ListView;
public class AppController { public class AppController {
private Calc calc; private Calc calc;
public AppController() { public AppController() {
calc = new Calc(0.0, 0.0, 0.0); calc = new Calc(0.0, 0.0, 0.0);
}
public Calc getCalc() {
return calc;
}
public void setCalc(Calc calc) {
this.calc = calc;
updateOperandsView();
}
@FXML
private ListView<Double> operandsView;
@FXML
private Label operandView;
@FXML
void initialize() {
updateOperandsView();
}
private void updateOperandsView() {
List<Double> operands = operandsView.getItems();
operands.clear();
int elementCount = Math.min(calc.getOperandCount(), 3);
for (int i = 0; i < elementCount; i++) {
operands.add(calc.peekOperand(elementCount - i - 1));
} }
}
public Calc getCalc() { private String getOperandString() {
return calc; return operandView.getText();
}
private boolean hasOperand() {
return !getOperandString().isBlank();
}
private double getOperand() {
return Double.valueOf(operandView.getText());
}
private void setOperand(String operandString) {
operandView.setText(operandString);
}
@FXML
void handleEnter() {
if (hasOperand()) {
calc.pushOperand(getOperand());
} else {
calc.dup();
} }
setOperand("");
updateOperandsView();
}
public void setCalc(Calc calc) { private void appendToOperand(String s) {
this.calc = calc; // TODO
updateOperandsView(); }
@FXML
void handleDigit(ActionEvent ae) {
if (ae.getSource()instanceof Labeled l) {
// TODO append button label to operand
} }
}
@FXML @FXML
private ListView<Double> operandsView; void handlePoint() {
var operandString = getOperandString();
@FXML if (operandString.contains(".")) {
private Label operandView; // TODO remove characters after point
} else {
@FXML // TODO append point
void initialize() {
updateOperandsView();
} }
}
private void updateOperandsView() { @FXML
List<Double> operands = operandsView.getItems(); void handleClear() {
operands.clear(); // TODO clear operand
int elementCount = Math.min(calc.getOperandCount(), 3); }
for (int i = 0; i < elementCount; i++) {
operands.add(calc.peekOperand(elementCount - i - 1));
}
}
private String getOperandString() { @FXML
return operandView.getText(); void handleSwap() {
} // TODO clear operand
}
private boolean hasOperand() { private void performOperation(UnaryOperator<Double> op) {
return ! getOperandString().isBlank(); // TODO
} }
private double getOperand() { private void performOperation(boolean swap, BinaryOperator<Double> op) {
return Double.valueOf(operandView.getText()); if (hasOperand()) {
// TODO push operand first
} }
// TODO perform operation, but swap first if needed
}
private void setOperand(String operandString) { @FXML
operandView.setText(operandString); void handleOpAdd() {
} // TODO
}
@FXML @FXML
void handleEnter() { void handleOpSub() {
if (hasOperand()) { // TODO
calc.pushOperand(getOperand()); }
} else {
calc.dup();
}
setOperand("");
updateOperandsView();
}
private void appendToOperand(String s) { @FXML
// TODO void handleOpMult() {
} // TODO
}
@FXML
void handleDigit(ActionEvent ae) {
if (ae.getSource() instanceof Labeled l) {
// TODO append button label to operand
}
}
@FXML
void handlePoint() {
var operandString = getOperandString();
if (operandString.contains(".")) {
// TODO remove characters after point
} else {
// TODO append point
}
}
@FXML
void handleClear() {
// TODO clear operand
}
@FXML
void handleSwap() {
// TODO clear operand
}
private void performOperation(UnaryOperator<Double> op) {
// TODO
}
private void performOperation(boolean swap, BinaryOperator<Double> op) {
if (hasOperand()) {
// TODO push operand first
}
// TODO perform operation, but swap first if needed
}
@FXML
void handleOpAdd() {
// TODO
}
@FXML
void handleOpSub() {
// TODO
}
@FXML
void handleOpMult() {
// TODO
}
} }

View File

@ -7,110 +7,111 @@ import java.util.function.UnaryOperator;
public class Calc { public class Calc {
private final List<Double> operandStack; private final List<Double> operandStack;
public Calc(double... operands) { public Calc(double... operands) {
operandStack = new ArrayList<>(operands.length + 2); operandStack = new ArrayList<>(operands.length + 2);
for (var d : operands) { for (var d : operands) {
operandStack.add(d); operandStack.add(d);
}
} }
}
/** /**
* @return the number of operands on the stack * @return the number of operands on the stack
*/ */
public int getOperandCount() { public int getOperandCount() {
return operandStack.size(); return operandStack.size();
}
/**
* Pushes a new operand onto top of the stack.
*
* @param d the new operand
*/
public void pushOperand(double 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) {
if (n >= getOperandCount()) {
throw new IllegalArgumentException(
"Cannot peek at position " + n + " when the operand count is " + getOperandCount());
} }
return operandStack.get(getOperandCount() - n - 1);
}
/** /**
* Pushes a new operand onto top of the stack. * @return the top operand
* */
* @param d the new operand public double peekOperand() {
*/ return peekOperand(0);
public void pushOperand(double d) { }
operandStack.add(d);
/**
* Removes and returns the top operand.
*
* @return the top operand
* @throws IllegalStateException if the stack is empty
*/
public double popOperand() {
if (getOperandCount() == 0) {
throw new IllegalStateException("Cannot pop from an empty stack");
} }
return operandStack.remove(operandStack.size() - 1);
}
/** /**
* @param n the place (from the top) to peek * Performs the provided operation in the top operand, and replaces it with the
* @return the n'th operand from the top * result.
* @throws IllegalArgumentException if n is larger than the operand count *
*/ * @param op the operation to perform
public double peekOperand(int n) { * @return the result of performing the operation
if (n >= getOperandCount()) { * @throws IllegalStateException if the operand stack is empty
throw new IllegalArgumentException("Cannot peek at position " + n + " when the operand count is " + getOperandCount()); */
} public double performOperation(UnaryOperator<Double> op) throws IllegalStateException {
return operandStack.get(getOperandCount() - n - 1); // TODO
return 0.0;
}
/**
* Performs the provided operation in the two topmost operands, and 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) throws IllegalStateException {
if (getOperandCount() < 2) {
throw new IllegalStateException("Too few operands (" + getOperandCount() + ") on the stack");
} }
var op2 = popOperand();
var op1 = popOperand();
var result = op.apply(op1, op2);
pushOperand(result);
return result;
}
/** /**
* @return the top operand * Swaps the two topmost operands.
*/ *
public double peekOperand() { * @throws IllegalStateException if the operand count is less than two
return peekOperand(0); */
} public void swap() {
/** }
* Removes and returns the top operand.
*
* @return the top operand
* @throws IllegalStateException if the stack is empty
*/
public double popOperand() {
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 * Duplicates the top operand.
* replaces it with the result. *
* * @throws IllegalStateException if the operand stack is empty
* @param op the operation to perform */
* @return the result of performing the operation public void dup() {
* @throws IllegalStateException if the operand stack is empty // TODO
*/ }
public double performOperation(UnaryOperator<Double> op) throws IllegalStateException {
// TODO
return 0.0;
}
/**
* Performs the provided operation in the two topmost operands, and
* 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) throws IllegalStateException {
if (getOperandCount() < 2) {
throw new IllegalStateException("Too few operands (" + getOperandCount() + ") on the stack");
}
var op2 = popOperand();
var op1 = popOperand();
var result = op.apply(op1, op2);
pushOperand(result);
return result;
}
/**
* Swaps the two topmost operands.
*
* @throws IllegalStateException if the operand count is less than two
*/
public void swap() {
}
/**
* Duplicates the top operand.
*
* @throws IllegalStateException if the operand stack is empty
*/
public void dup() {
// TODO
}
} }

View File

@ -6,59 +6,59 @@
<?import javafx.scene.control.ListView?> <?import javafx.scene.control.ListView?>
<GridPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.AppController" <GridPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.AppController"
alignment="CENTER" hgap="10.0" vgap="10.0" > alignment="CENTER" hgap="10.0" vgap="10.0" >
<ListView fx:id="operandsView" prefHeight="80.0" <ListView fx:id="operandsView" prefHeight="80.0"
GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="4"/> GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="4"/>
<Label text="" fx:id="operandView" <Label text="" fx:id="operandView"
GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="4"/> GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="4"/>
<!-- multi-line button label with XML entity for newline --> <!-- multi-line button label with XML entity for newline -->
<Button text="E&#10;n&#10;t&#10;e&#10;r" onAction="#handleEnter" <Button text="E&#10;n&#10;t&#10;e&#10;r" onAction="#handleEnter"
GridPane.rowIndex="2" GridPane.columnIndex="3" GridPane.rowSpan="3"/> GridPane.rowIndex="2" GridPane.columnIndex="3" GridPane.rowSpan="3"/>
<Button text="7" onAction="#handleDigit" <Button text="7" onAction="#handleDigit"
GridPane.rowIndex="2" GridPane.columnIndex="0"/> GridPane.rowIndex="2" GridPane.columnIndex="0"/>
<Button text="8" onAction="#handleDigit" <Button text="8" onAction="#handleDigit"
GridPane.rowIndex="2" GridPane.columnIndex="1"/> GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<Button text="9" onAction="#handleDigit" <Button text="9" onAction="#handleDigit"
GridPane.rowIndex="2" GridPane.columnIndex="2"/> GridPane.rowIndex="2" GridPane.columnIndex="2"/>
<Button text="4" onAction="#handleDigit" <Button text="4" onAction="#handleDigit"
GridPane.rowIndex="3" GridPane.columnIndex="0"/> GridPane.rowIndex="3" GridPane.columnIndex="0"/>
<Button text="5" onAction="#handleDigit" <Button text="5" onAction="#handleDigit"
GridPane.rowIndex="3" GridPane.columnIndex="1"/> GridPane.rowIndex="3" GridPane.columnIndex="1"/>
<Button text="6" onAction="#handleDigit" <Button text="6" onAction="#handleDigit"
GridPane.rowIndex="3" GridPane.columnIndex="2"/> GridPane.rowIndex="3" GridPane.columnIndex="2"/>
<Button text="1" onAction="#handleDigit" <Button text="1" onAction="#handleDigit"
GridPane.rowIndex="4" GridPane.columnIndex="0"/> GridPane.rowIndex="4" GridPane.columnIndex="0"/>
<Button text="2" onAction="#handleDigit" <Button text="2" onAction="#handleDigit"
GridPane.rowIndex="4" GridPane.columnIndex="1"/> GridPane.rowIndex="4" GridPane.columnIndex="1"/>
<Button text="3" onAction="#handleDigit" <Button text="3" onAction="#handleDigit"
GridPane.rowIndex="4" GridPane.columnIndex="2"/> GridPane.rowIndex="4" GridPane.columnIndex="2"/>
<Button text="0" onAction="#handleDigit" <Button text="0" onAction="#handleDigit"
GridPane.rowIndex="5" GridPane.columnIndex="0"/> GridPane.rowIndex="5" GridPane.columnIndex="0"/>
<Button text="." onAction="#handlePoint" <Button text="." onAction="#handlePoint"
GridPane.rowIndex="5" GridPane.columnIndex="1"/> GridPane.rowIndex="5" GridPane.columnIndex="1"/>
<Button text="C" onAction="#handleClear" <Button text="C" onAction="#handleClear"
GridPane.rowIndex="5" GridPane.columnIndex="2"/> GridPane.rowIndex="5" GridPane.columnIndex="2"/>
<Button text="~" onAction="#handleSwap" <Button text="~" onAction="#handleSwap"
GridPane.rowIndex="5" GridPane.columnIndex="3"/> GridPane.rowIndex="5" GridPane.columnIndex="3"/>
<Button text="+" onAction="#handleOpAdd" <Button text="+" onAction="#handleOpAdd"
GridPane.rowIndex="6" GridPane.columnIndex="0"/> GridPane.rowIndex="6" GridPane.columnIndex="0"/>
<Button text="-" onAction="#handleOpSub" <Button text="-" onAction="#handleOpSub"
GridPane.rowIndex="6" GridPane.columnIndex="1"/> GridPane.rowIndex="6" GridPane.columnIndex="1"/>
<Button text="*" onAction="#handleOpMult" <Button text="*" onAction="#handleOpMult"
GridPane.rowIndex="6" GridPane.columnIndex="2"/> GridPane.rowIndex="6" GridPane.columnIndex="2"/>
<!-- TODO --> <!-- TODO -->
<Button text="/" <Button text="/"
GridPane.rowIndex="6" GridPane.columnIndex="3"/> GridPane.rowIndex="6" GridPane.columnIndex="3"/>
<Button text="√" <Button text="√"
GridPane.rowIndex="7" GridPane.columnIndex="0"/> GridPane.rowIndex="7" GridPane.columnIndex="0"/>
<Button text="π" <Button text="π"
GridPane.rowIndex="7" GridPane.columnIndex="1"/> GridPane.rowIndex="7" GridPane.columnIndex="1"/>
</GridPane> </GridPane>

View File

@ -24,107 +24,97 @@ import org.testfx.matcher.control.LabeledMatchers;
*/ */
public class AppTest extends ApplicationTest { public class AppTest extends ApplicationTest {
private AppController controller; private AppController controller;
private Parent root; private Parent root;
@Override @Override
public void start(Stage stage) throws IOException { public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("App.fxml")); FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("App.fxml"));
root = fxmlLoader.load(); root = fxmlLoader.load();
controller = fxmlLoader.getController(); controller = fxmlLoader.getController();
stage.setScene(new Scene(root)); stage.setScene(new Scene(root));
stage.show(); stage.show();
}
public Parent getRootNode() {
return root;
}
private String enterLabel = """
E
n
t
e
r
""".stripTrailing();
private void click(String... labels) {
for (var label : labels) {
clickOn(LabeledMatchers.hasText(label));
} }
}
public Parent getRootNode() { private String getOperandString() {
return root; return ((Label) getRootNode().lookup("#operandView")).getText();
}
private ListView<Double> getOperandsView() {
return (ListView<Double>) getRootNode().lookup("#operandsView");
}
private void checkView(double... operands) {
for (int i = 0; i < operands.length; i++) {
Assertions.assertEquals(operands[i], controller.getCalc().peekOperand(i),
"Wrong value at #" + i + " of operand stack");
} }
List<Double> viewItems = getOperandsView().getItems();
private String enterLabel = """ for (int i = 0; i < operands.length; i++) {
E Assertions.assertEquals(operands[i], viewItems.get(viewItems.size() - i - 1),
n "Wrong value at #" + i + " of operands view");
t
e
r
""".stripTrailing();
private void click(String... labels) {
for (var label : labels) {
clickOn(LabeledMatchers.hasText(label));
}
} }
}
private String getOperandString() { private void checkView(String operandString, double... operands) {
return ((Label) getRootNode().lookup("#operandView")).getText(); Assertions.assertEquals(operandString, getOperandString());
checkView(operands);
}
// see https://www.baeldung.com/parameterized-tests-junit-5
// about @ParameterizedTest
@ParameterizedTest
@MethodSource
public void testClicksOperand(String labels, String operandString) {
for (var label : labels.split(" ")) {
click(label);
} }
checkView(operandString);
}
private ListView<Double> getOperandsView() { private static Stream<Arguments> testClicksOperand() {
return (ListView<Double>) getRootNode().lookup("#operandsView"); return Stream.of(Arguments.of("2 7", "27"), Arguments.of("2 7 .", "27."), Arguments.of("2 7 . 5", "27.5"),
Arguments.of("2 7 . 5 .", "27."));
}
@ParameterizedTest
@MethodSource
public void testClicksOperands(String labels, String operandsString) {
for (var label : labels.split(" ")) {
click(label.equals("\n") ? enterLabel : label);
} }
checkView("", Stream.of(operandsString.split(" ")).mapToDouble(Double::valueOf).toArray());
}
private void checkView(double... operands) { private static Stream<Arguments> testClicksOperands() {
for (int i = 0; i < operands.length; i++) { return Stream.of(Arguments.of("2 7 . 5 \n", "27.5"), Arguments.of("2 7 \n", "27.0"),
Assertions.assertEquals(operands[i], controller.getCalc().peekOperand(i), "Wrong value at #" + i + " of operand stack"); Arguments.of("2 \n 7 \n 5 \n", "5.0", "7.0", "2.0"), Arguments.of("2 7 . \n", "27.0"),
} Arguments.of("2 7 . 5 \n", "27.5"), Arguments.of("2 \n 7 +", "9.0"), Arguments.of("2 \n 7 -", "-5.0"),
List<Double> viewItems = getOperandsView().getItems(); Arguments.of("2 \n 7 *", "14.0"), Arguments.of("6 \n 3 /", "2.0"), Arguments.of("2 5 \n √", "5.0"));
for (int i = 0; i < operands.length; i++) { }
Assertions.assertEquals(operands[i], viewItems.get(viewItems.size() - i - 1), "Wrong value at #" + i + " of operands view");
}
}
private void checkView(String operandString, double... operands) { @Test
Assertions.assertEquals(operandString, getOperandString()); public void testPi() {
checkView(operands); click("π");
} checkView("", Math.PI);
}
// see https://www.baeldung.com/parameterized-tests-junit-5
// about @ParameterizedTest
@ParameterizedTest
@MethodSource
public void testClicksOperand(String labels, String operandString) {
for (var label : labels.split(" ")) {
click(label);
}
checkView(operandString);
}
private static Stream<Arguments> testClicksOperand() {
return Stream.of(
Arguments.of("2 7", "27"),
Arguments.of("2 7 .", "27."),
Arguments.of("2 7 . 5", "27.5"),
Arguments.of("2 7 . 5 .", "27.")
);
}
@ParameterizedTest
@MethodSource
public void testClicksOperands(String labels, String operandsString) {
for (var label : labels.split(" ")) {
click(label.equals("\n") ? enterLabel : label);
}
checkView("", Stream.of(operandsString.split(" ")).mapToDouble(Double::valueOf).toArray());
}
private static Stream<Arguments> testClicksOperands() {
return Stream.of(
Arguments.of("2 7 . 5 \n", "27.5"),
Arguments.of("2 7 \n", "27.0"),
Arguments.of("2 \n 7 \n 5 \n", "5.0", "7.0", "2.0"),
Arguments.of("2 7 . \n", "27.0"),
Arguments.of("2 7 . 5 \n", "27.5"),
Arguments.of("2 \n 7 +", "9.0"),
Arguments.of("2 \n 7 -", "-5.0"),
Arguments.of("2 \n 7 *", "14.0"),
Arguments.of("6 \n 3 /", "2.0"),
Arguments.of("2 5 \n √", "5.0")
);
}
@Test
public void testPi() {
click("π");
checkView("", Math.PI);
}
} }

View File

@ -5,111 +5,110 @@ import org.junit.jupiter.api.Test;
public class CalcTest { public class CalcTest {
private static void checkCalc(Calc calc, double... operands) { private static void checkCalc(Calc calc, double... operands) {
Assertions.assertEquals(operands.length, calc.getOperandCount(), "Wrong operand count"); Assertions.assertEquals(operands.length, calc.getOperandCount(), "Wrong operand count");
for (int i = 0; i < operands.length; i++) { for (int i = 0; i < operands.length; i++) {
Assertions.assertEquals(operands[i], calc.peekOperand(i), "Wrong value at #" + i + " of operand stack"); Assertions.assertEquals(operands[i], calc.peekOperand(i), "Wrong value at #" + i + " of operand stack");
}
} }
}
@Test @Test
public void testCalc() { public void testCalc() {
checkCalc(new Calc()); checkCalc(new Calc());
checkCalc(new Calc(1.0), 1.0); checkCalc(new Calc(1.0), 1.0);
checkCalc(new Calc(3.14, 1.0), 1.0, 3.14); checkCalc(new Calc(3.14, 1.0), 1.0, 3.14);
} }
@Test @Test
public void testPushOperand() { public void testPushOperand() {
Calc calc = new Calc(); Calc calc = new Calc();
calc.pushOperand(1.0); calc.pushOperand(1.0);
checkCalc(calc, 1.0); checkCalc(calc, 1.0);
calc.pushOperand(3.14); calc.pushOperand(3.14);
checkCalc(calc, 3.14, 1.0); checkCalc(calc, 3.14, 1.0);
} }
@Test @Test
public void testPeekOperand() { public void testPeekOperand() {
Calc calc = new Calc(1.0, 3.14); Calc calc = new Calc(1.0, 3.14);
Assertions.assertEquals(3.14, calc.peekOperand()); Assertions.assertEquals(3.14, calc.peekOperand());
Assertions.assertThrows(IllegalArgumentException.class, () -> new Calc().peekOperand()); Assertions.assertThrows(IllegalArgumentException.class, () -> new Calc().peekOperand());
} }
@Test @Test
public void testPeekOperandN() { public void testPeekOperandN() {
Calc calc = new Calc(1.0, 3.14); Calc calc = new Calc(1.0, 3.14);
Assertions.assertEquals(3.14, calc.peekOperand(0)); Assertions.assertEquals(3.14, calc.peekOperand(0));
Assertions.assertEquals(1.0, calc.peekOperand(1)); Assertions.assertEquals(1.0, calc.peekOperand(1));
Assertions.assertThrows(IllegalArgumentException.class, () -> calc.peekOperand(2)); Assertions.assertThrows(IllegalArgumentException.class, () -> calc.peekOperand(2));
} }
@Test @Test
public void testPopOperand() { public void testPopOperand() {
Calc calc = new Calc(1.0, 3.14); Calc calc = new Calc(1.0, 3.14);
Assertions.assertEquals(3.14, calc.popOperand()); Assertions.assertEquals(3.14, calc.popOperand());
checkCalc(calc, 1.0); checkCalc(calc, 1.0);
Assertions.assertEquals(1.0, calc.popOperand()); Assertions.assertEquals(1.0, calc.popOperand());
checkCalc(calc); checkCalc(calc);
} }
@Test @Test
public void testPopOperand_emptyStack() { public void testPopOperand_emptyStack() {
Assertions.assertThrows(IllegalStateException.class, () -> new Calc().popOperand()); Assertions.assertThrows(IllegalStateException.class, () -> new Calc().popOperand());
} }
@Test @Test
public void testPerformOperation1() { public void testPerformOperation1() {
Calc calc = new Calc(1.0); Calc calc = new Calc(1.0);
Assertions.assertEquals(-1.0, calc.performOperation(n -> -n)); Assertions.assertEquals(-1.0, calc.performOperation(n -> -n));
checkCalc(calc, -1.0); checkCalc(calc, -1.0);
} }
@Test @Test
public void testPerformOperation1_emptyOperandStack() { public void testPerformOperation1_emptyOperandStack() {
Assertions.assertThrows(IllegalStateException.class, () -> new Calc().performOperation(n -> -n)); Assertions.assertThrows(IllegalStateException.class, () -> new Calc().performOperation(n -> -n));
} }
@Test
public void testPerformOperation2() {
Calc calc = new Calc(1.0, 3.0);
Assertions.assertEquals(-2.0, calc.performOperation((n1, n2) -> n1 - n2));
checkCalc(calc, -2.0);
}
@Test @Test
public void testPerformOperation2() { public void testPerformOperation2_lessThanTwoOperands() {
Calc calc = new Calc(1.0, 3.0); Assertions.assertThrows(IllegalStateException.class, () -> new Calc(1.0).performOperation((n1, n2) -> n1 - n2));
Assertions.assertEquals(-2.0, calc.performOperation((n1, n2) -> n1 - n2)); Assertions.assertThrows(IllegalStateException.class, () -> new Calc().performOperation((n1, n2) -> n1 - n2));
checkCalc(calc, -2.0); }
}
@Test @Test
public void testPerformOperation2_lessThanTwoOperands() { public void testSwap() {
Assertions.assertThrows(IllegalStateException.class, () -> new Calc(1.0).performOperation((n1, n2) -> n1 - n2)); Calc calc = new Calc(1.0, 3.14);
Assertions.assertThrows(IllegalStateException.class, () -> new Calc().performOperation((n1, n2) -> n1 - n2)); checkCalc(calc, 3.14, 1.0);
} calc.swap();
checkCalc(calc, 1.0, 3.14);
calc.swap();
checkCalc(calc, 3.14, 1.0);
}
@Test @Test
public void testSwap() { public void testSwap_lessThanTwoOperands() {
Calc calc = new Calc(1.0, 3.14); Assertions.assertThrows(IllegalStateException.class, () -> new Calc(1.0).swap());
checkCalc(calc, 3.14, 1.0); Assertions.assertThrows(IllegalStateException.class, () -> new Calc().swap());
calc.swap(); }
checkCalc(calc, 1.0, 3.14);
calc.swap();
checkCalc(calc, 3.14, 1.0);
}
@Test @Test
public void testSwap_lessThanTwoOperands() { public void testDup() {
Assertions.assertThrows(IllegalStateException.class, () -> new Calc(1.0).swap()); Calc calc = new Calc(1.0, 3.14);
Assertions.assertThrows(IllegalStateException.class, () -> new Calc().swap()); Assertions.assertEquals(3.14, calc.popOperand());
} checkCalc(calc, 1.0);
Assertions.assertEquals(1.0, calc.popOperand());
checkCalc(calc);
}
@Test @Test
public void testDup() { public void testDup_emptyOperandStack() {
Calc calc = new Calc(1.0, 3.14); Assertions.assertThrows(IllegalStateException.class, () -> new Calc().dup());
Assertions.assertEquals(3.14, calc.popOperand()); }
checkCalc(calc, 1.0);
Assertions.assertEquals(1.0, calc.popOperand());
checkCalc(calc);
}
@Test
public void testDup_emptyOperandStack() {
Assertions.assertThrows(IllegalStateException.class, () -> new Calc().dup());
}
} }