diff --git a/.vscode/java-formatter.xml b/.vscode/java-formatter.xml new file mode 100644 index 0000000..7a5d23d --- /dev/null +++ b/.vscode/java-formatter.xml @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b00d5c6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "java.format.settings.url": ".vscode/java-formatter.xml", + "java.configuration.updateBuildConfiguration": "interactive" +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index e0a6fc4..3dc14f7 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,12 @@ plugins { id 'application' } +java { + toolchain { + languageVersion = JavaLanguageVersion.of(25) + } +} + repositories { // Use Maven Central for resolving dependencies. mavenCentral() diff --git a/src/main/java/htw/berlin/prog2/ha1/Calculator.java b/src/main/java/htw/berlin/prog2/ha1/Calculator.java index 84c04f2..c3c3461 100644 --- a/src/main/java/htw/berlin/prog2/ha1/Calculator.java +++ b/src/main/java/htw/berlin/prog2/ha1/Calculator.java @@ -1,10 +1,11 @@ package htw.berlin.prog2.ha1; /** - * Eine Klasse, die das Verhalten des Online Taschenrechners imitiert, welcher auf - * https://www.online-calculator.com/ aufgerufen werden kann (ohne die Memory-Funktionen) - * und dessen Bildschirm bis zu zehn Ziffern plus einem Dezimaltrennzeichen darstellen kann. - * Enthält mit Absicht noch diverse Bugs oder unvollständige Funktionen. + * Eine Klasse, die das Verhalten des Online Taschenrechners imitiert, welcher + * auf https://www.online-calculator.com/ aufgerufen werden kann (ohne die + * Memory-Funktionen) und dessen Bildschirm bis zu zehn Ziffern plus einem + * Dezimaltrennzeichen darstellen kann. Enthält mit Absicht noch diverse Bugs + * oder unvollständige Funktionen. */ public class Calculator { @@ -12,6 +13,12 @@ public class Calculator { private double latestValue; + private String lastValue = ""; + + private int operationCount = 0; + + private int equalsCount = 0; + private String latestOperation = ""; /** @@ -22,27 +29,39 @@ public String readScreen() { } /** - * Empfängt den Wert einer gedrückten Zifferntaste. Da man nur eine Taste auf einmal - * drücken kann muss der Wert positiv und einstellig sein und zwischen 0 und 9 liegen. - * Führt in jedem Fall dazu, dass die gerade gedrückte Ziffer auf dem Bildschirm angezeigt - * oder rechts an die zuvor gedrückte Ziffer angehängt angezeigt wird. + * Empfängt den Wert einer gedrückten Zifferntaste. Da man nur eine Taste + * auf einmal drücken kann muss der Wert positiv und einstellig sein und + * zwischen 0 und 9 liegen. Führt in jedem Fall dazu, dass die gerade + * gedrückte Ziffer auf dem Bildschirm angezeigt oder rechts an die zuvor + * gedrückte Ziffer angehängt angezeigt wird. + * + * Hinweise / Seiteneffekte: - Der interne Bildschirminhalt ({@code screen}) + * wird geändert. - Die zuletzt eingegebene Ziffernfolge wird in + * {@code lastValue} gespeichert und kann beim erneuten Drücken von "=" + * relevant sein. + * * @param digit Die Ziffer, deren Taste gedrückt wurde */ public void pressDigitKey(int digit) { - if(digit > 9 || digit < 0) throw new IllegalArgumentException(); - - if(screen.equals("0") || latestValue == Double.parseDouble(screen)) screen = ""; + if (digit > 9 || digit < 0) { + throw new IllegalArgumentException(); + } + if (screen.equals("0") || latestValue == Double.parseDouble(screen)) { + screen = ""; + } + lastValue = screen + digit; screen = screen + digit; } /** * Empfängt den Befehl der C- bzw. CE-Taste (Clear bzw. Clear Entry). - * Einmaliges Drücken der Taste löscht die zuvor eingegebenen Ziffern auf dem Bildschirm - * so dass "0" angezeigt wird, jedoch ohne zuvor zwischengespeicherte Werte zu löschen. - * Wird daraufhin noch einmal die Taste gedrückt, dann werden auch zwischengespeicherte - * Werte sowie der aktuelle Operationsmodus zurückgesetzt, so dass der Rechner wieder - * im Ursprungszustand ist. + * Einmaliges Drücken der Taste löscht die zuvor eingegebenen Ziffern auf + * dem Bildschirm so dass "0" angezeigt wird, jedoch ohne zuvor + * zwischengespeicherte Werte zu löschen. Wird daraufhin noch einmal die + * Taste gedrückt, dann werden auch zwischengespeicherte Werte sowie der + * aktuelle Operationsmodus zurückgesetzt, so dass der Rechner wieder im + * Ursprungszustand ist. */ public void pressClearKey() { screen = "0"; @@ -51,83 +70,142 @@ public void pressClearKey() { } /** - * Empfängt den Wert einer gedrückten binären Operationstaste, also eine der vier Operationen - * Addition, Substraktion, Division, oder Multiplikation, welche zwei Operanden benötigen. - * Beim ersten Drücken der Taste wird der Bildschirminhalt nicht verändert, sondern nur der - * Rechner in den passenden Operationsmodus versetzt. - * Beim zweiten Drücken nach Eingabe einer weiteren Zahl wird direkt des aktuelle Zwischenergebnis - * auf dem Bildschirm angezeigt. Falls hierbei eine Division durch Null auftritt, wird "Error" angezeigt. - * @param operation "+" für Addition, "-" für Substraktion, "x" für Multiplikation, "/" für Division + * Empfängt den Wert einer gedrückten binären Operationstaste, also eine der + * vier Operationen Addition, Substraktion, Division, oder Multiplikation, + * welche zwei Operanden benötigen. Beim ersten Drücken der Taste wird der + * Bildschirminhalt nicht verändert, sondern nur der Rechner in den + * passenden Operationsmodus versetzt. Beim zweiten Drücken nach Eingabe + * einer weiteren Zahl wird direkt des aktuelle Zwischenergebnis auf dem + * Bildschirm angezeigt. Falls hierbei eine Division durch Null auftritt, + * wird "Error" angezeigt. + * + * Verhalten / Seiteneffekte: - Speichert den aktuellen {@code screen}-Wert + * in {@code latestValue} als linken Operanden. - Setzt + * {@code latestOperation} auf die übergebene Operation. - Falls bereits + * eine vorherige Operation gesetzt war, wird {@link #pressEqualsKey()} + * aufgerufen, um das Zwischenergebnis anzuzeigen. + * + * @param operation "+" für Addition, "-" für Substraktion, "x" für + * Multiplikation, "/" für Division */ - public void pressBinaryOperationKey(String operation) { + public void pressBinaryOperationKey(String operation) { + operationCount++; + if (!latestOperation.isEmpty()) { + pressEqualsKey(); + } latestValue = Double.parseDouble(screen); latestOperation = operation; + } /** - * Empfängt den Wert einer gedrückten unären Operationstaste, also eine der drei Operationen - * Quadratwurzel, Prozent, Inversion, welche nur einen Operanden benötigen. - * Beim Drücken der Taste wird direkt die Operation auf den aktuellen Zahlenwert angewendet und - * der Bildschirminhalt mit dem Ergebnis aktualisiert. - * @param operation "√" für Quadratwurzel, "%" für Prozent, "1/x" für Inversion + * Empfängt den Wert einer gedrückten unären Operationstaste, also eine der + * drei Operationen Quadratwurzel, Prozent, Inversion, welche nur einen + * Operanden benötigen. Beim Drücken der Taste wird direkt die Operation auf + * den aktuellen Zahlenwert angewendet und der Bildschirminhalt mit dem + * Ergebnis aktualisiert. + * + * @param operation "√" für Quadratwurzel, "%" für Prozent, "1/x" für + * Inversion */ public void pressUnaryOperationKey(String operation) { latestValue = Double.parseDouble(screen); latestOperation = operation; - var result = switch(operation) { - case "√" -> Math.sqrt(Double.parseDouble(screen)); - case "%" -> Double.parseDouble(screen) / 100; - case "1/x" -> 1 / Double.parseDouble(screen); - default -> throw new IllegalArgumentException(); + Double result = switch (operation) { + case "√" -> + Math.sqrt(Double.parseDouble(screen)); + case "%" -> + Double.parseDouble(screen) / 100; + case "1/x" -> + 1 / Double.parseDouble(screen); + default -> + throw new IllegalArgumentException(); }; screen = Double.toString(result); - if(screen.equals("NaN")) screen = "Error"; - if(screen.contains(".") && screen.length() > 11) screen = screen.substring(0, 10); + if (screen.equals("NaN")) { + screen = "Error"; + } + if (screen.contains(".") && screen.length() > 11) { + screen = screen.substring(0, 10); + } } /** - * Empfängt den Befehl der gedrückten Dezimaltrennzeichentaste, im Englischen üblicherweise "." - * Fügt beim ersten Mal Drücken dem aktuellen Bildschirminhalt das Trennzeichen auf der rechten - * Seite hinzu und aktualisiert den Bildschirm. Daraufhin eingegebene Zahlen werden rechts vom - * Trennzeichen angegeben und daher als Dezimalziffern interpretiert. - * Beim zweimaligem Drücken, oder wenn bereits ein Trennzeichen angezeigt wird, passiert nichts. + * Empfängt den Befehl der gedrückten Dezimaltrennzeichentaste, im + * Englischen üblicherweise "." Fügt beim ersten Mal Drücken dem aktuellen + * Bildschirminhalt das Trennzeichen auf der rechten Seite hinzu und + * aktualisiert den Bildschirm. Daraufhin eingegebene Zahlen werden rechts + * vom Trennzeichen angegeben und daher als Dezimalziffern interpretiert. + * Beim zweimaligem Drücken, oder wenn bereits ein Trennzeichen angezeigt + * wird, passiert nichts. */ public void pressDotKey() { - if(!screen.contains(".")) screen = screen + "."; + if (!screen.contains(".")) { + screen = screen + "."; + } } /** - * Empfängt den Befehl der gedrückten Vorzeichenumkehrstaste ("+/-"). - * Zeigt der Bildschirm einen positiven Wert an, so wird ein "-" links angehängt, der Bildschirm - * aktualisiert und die Inhalt fortan als negativ interpretiert. - * Zeigt der Bildschirm bereits einen negativen Wert mit führendem Minus an, dann wird dieses - * entfernt und der Inhalt fortan als positiv interpretiert. + * Empfängt den Befehl der gedrückten Vorzeichenumkehrstaste ("+/-"). Zeigt + * der Bildschirm einen positiven Wert an, so wird ein "-" links angehängt, + * der Bildschirm aktualisiert und die Inhalt fortan als negativ + * interpretiert. Zeigt der Bildschirm bereits einen negativen Wert mit + * führendem Minus an, dann wird dieses entfernt und der Inhalt fortan als + * positiv interpretiert. */ public void pressNegativeKey() { screen = screen.startsWith("-") ? screen.substring(1) : "-" + screen; } /** - * Empfängt den Befehl der gedrückten "="-Taste. - * Wurde zuvor keine Operationstaste gedrückt, passiert nichts. - * Wurde zuvor eine binäre Operationstaste gedrückt und zwei Operanden eingegeben, wird das - * Ergebnis der Operation angezeigt. Falls hierbei eine Division durch Null auftritt, wird "Error" angezeigt. - * Wird die Taste weitere Male gedrückt (ohne andere Tasten dazwischen), so wird die letzte - * Operation (ggf. inklusive letztem Operand) erneut auf den aktuellen Bildschirminhalt angewandt - * und das Ergebnis direkt angezeigt. + * Empfängt den Befehl der gedrückten "="-Taste. Wurde zuvor keine + * Operationstaste gedrückt, passiert nichts. Wurde zuvor eine binäre + * Operationstaste gedrückt und zwei Operanden eingegeben, wird das Ergebnis + * der Operation angezeigt. Falls hierbei eine Division durch Null auftritt, + * wird "Error" angezeigt. Wird die Taste weitere Male gedrückt (ohne andere + * Tasten dazwischen), so wird die letzte Operation (ggf. inklusive letztem + * Operand) erneut auf den aktuellen Bildschirminhalt angewandt und das + * Ergebnis direkt angezeigt. + * + * Ergänzende Hinweise: - Beim ersten Anwenden wird {@code latestValue} + * (linker Operand) mit dem aktuellen {@code screen} (rechter Operand) + * kombiniert. - Bei wiederholtem Drücken ohne neue Eingaben wird + * {@code lastValue} als rechter Operand wiederverwendet (gesteuert über + * {@code equalsCount} und {@code operationCount}). - Das Ergebnis ersetzt + * den Bildschirminhalt und wird in {@code latestValue} gespeichert. + * Ganzzahlige Ergebnisse verlieren die Nachkommastelle ".0" in der Anzeige. + * + * @throws IllegalArgumentException wenn keine gültige vorherige Operation + * gesetzt ist oder die Operation nicht erkannt wird */ public void pressEqualsKey() { - var result = switch(latestOperation) { - case "+" -> latestValue + Double.parseDouble(screen); - case "-" -> latestValue - Double.parseDouble(screen); - case "x" -> latestValue * Double.parseDouble(screen); - case "/" -> latestValue / Double.parseDouble(screen); - default -> throw new IllegalArgumentException(); + equalsCount++; + if (equalsCount > operationCount) { + screen = lastValue; + } + Double result = switch (latestOperation) { + case "+" -> + latestValue + Double.parseDouble(screen); + case "-" -> + latestValue - Double.parseDouble(screen); + case "x" -> + latestValue * Double.parseDouble(screen); + case "/" -> + latestValue / Double.parseDouble(screen); + default -> + throw new IllegalArgumentException(); }; screen = Double.toString(result); - if(screen.equals("Infinity")) screen = "Error"; - if(screen.endsWith(".0")) screen = screen.substring(0,screen.length()-2); - if(screen.contains(".") && screen.length() > 11) screen = screen.substring(0, 10); + latestValue = result; + if (screen.equals("Infinity")) { + screen = "Error"; + } + if (screen.endsWith(".0")) { + screen = screen.substring(0, screen.length() - 2); + } + if (screen.contains(".") && screen.length() > 11) { + screen = screen.substring(0, 10); + } } } diff --git a/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java b/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java index ddff0da..c7dd89f 100644 --- a/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java +++ b/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java @@ -88,7 +88,75 @@ void testMultipleDecimalDots() { assertEquals(expected, actual); } + @Test + @DisplayName("should display resume after substrakt two positive numbers") + void testSubstraktion() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(7); + calc.pressBinaryOperationKey("-"); + calc.pressDigitKey(3); + calc.pressEqualsKey(); + + String expected = "4"; + String actual = calc.readScreen(); + + assertEquals(expected, actual); + } + + @Test + @DisplayName("should display devisor after adding two positive division-digit numbers") + void testDivisiorByTheSameNumber() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(7); + calc.pressBinaryOperationKey("/"); + calc.pressDigitKey(7); + calc.pressEqualsKey(); + + String expected = "1"; + String actual = calc.readScreen(); + + assertEquals(expected, actual); + } + + @Test + @DisplayName("should display result after adding two positive numbers again using the equals key") + void testPositiveAdditionNextPressEqualsAgain() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(7); + calc.pressBinaryOperationKey("+"); + calc.pressDigitKey(5); + calc.pressEqualsKey(); + calc.pressEqualsKey(); + calc.pressEqualsKey(); + + String expected = "22"; + String actual = calc.readScreen(); + + assertEquals(expected, actual); + } + + @Test + @DisplayName("should display result after adding two positive numbers again using the equals key") + void testPlusMinusOperator() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(7); + calc.pressBinaryOperationKey("+"); + calc.pressDigitKey(5); + calc.pressBinaryOperationKey("-"); + calc.pressDigitKey(4); + calc.pressBinaryOperationKey("-"); + calc.pressDigitKey(2); + calc.pressEqualsKey(); + + String expected = "6"; + String actual = calc.readScreen(); + + assertEquals(expected, actual); + } //TODO hier weitere Tests erstellen } -