diff --git a/app/src/main/java/htw/berlin/prog2/ha1/Calculator.java b/app/src/main/java/htw/berlin/prog2/ha1/Calculator.java index 84c04f2..cecb1bc 100644 --- a/app/src/main/java/htw/berlin/prog2/ha1/Calculator.java +++ b/app/src/main/java/htw/berlin/prog2/ha1/Calculator.java @@ -1,133 +1,171 @@ -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. - */ -public class Calculator { - - private String screen = "0"; - - private double latestValue; - - private String latestOperation = ""; - - /** - * @return den aktuellen Bildschirminhalt als String - */ - public String readScreen() { - return screen; - } - - /** - * 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. - * @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 = ""; - - 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. - */ - public void pressClearKey() { - screen = "0"; - latestOperation = ""; - latestValue = 0.0; - } - - /** - * 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 - */ - public void pressBinaryOperationKey(String operation) { - 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 - */ - 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(); - }; - screen = Double.toString(result); - 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. - */ - public void pressDotKey() { - 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. - */ - 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. - */ - 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(); - }; - 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); - } -} +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. + */ +public class Calculator { + + private String screen = "0"; + + private double latestValue; + + private String latestOperation = ""; + + /** + * @return den aktuellen Bildschirminhalt als String + */ + public String readScreen() { + return screen; + } + + /** + * 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. + * @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 = ""; + + 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. + */ + public void pressClearKey() { + screen = "0"; + latestOperation = ""; + latestValue = 0.0; + } + + /** + * 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 + */ + public void pressBinaryOperationKey(String operation) { + 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 + */ + public void pressUnaryOperationKey(String operation) { + // Überprüfung: Bildschirmwertes null bevor ausgeführt (operation) wird + if (operation.equals("1/x") && screen.equals("0")) { + screen = "Error"; // Fehler bei Division durch null + return; // Methode verlassen + } + + // Übernehmen des aktuellen Wertes und der Ausführung + latestValue = Double.parseDouble(screen); + latestOperation = operation; + + // die Durchführung der berechnungen + double result = switch (operation) { + case "√" -> Math.sqrt(latestValue); + case "%" -> latestValue / 100; + case "1/x" -> 1 / latestValue; + default -> throw new IllegalArgumentException("Ungültige Operation"); + }; + + // Ergebnisses auf den Bildschirm setzen + screen = Double.toString(result); + if (screen.equals("NaN") || screen.equals("Infinity")) { + screen = "Error"; + } + if (screen.contains(".") && screen.length() > 11) { + screen = screen.substring(0, 10); // Begrenzung auf 10 Zeichen + } + } + + + /** + * 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 + "."; + } + + /** + * 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. + */ + public void pressEqualsKey() { + // Überprüfung - ob eine Operation ausgewählt wurde + if (latestOperation.isEmpty()) { + return; // Wenn keine Operation vorhanden ist passiert nichts + } + + double result; + double divisor = Double.parseDouble(screen); + + // Durchführung der Berechnung + switch(latestOperation) { + case "+" -> result = latestValue + divisor; + case "-" -> result = latestValue - divisor; + case "x" -> result = latestValue * divisor; + case "/" -> { + if (divisor == 0) { // Division durch Null + screen = "Error"; + return; // Methode verlassen + } + result = latestValue / divisor; + } + default -> throw new IllegalArgumentException("Ungültige Operation"); + } + + // Ergebnis auf den Bildschirm setzen + screen = Double.toString(result); + + // Formatierung des Bildschirms + if (screen.endsWith(".0")) { + screen = screen.substring(0, screen.length() - 2); // Entfernt .0 + } + if (screen.contains(".") && screen.length() > 11) { + screen = screen.substring(0, 10); // Begrenzung auf 10 Zeichen + } //commit 2-5 - 2 rote tests mit bugfixes -p + } + +} \ No newline at end of file diff --git a/app/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java b/app/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java index ddff0da..251600d 100644 --- a/app/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java +++ b/app/src/test/java/htw/berlin/prog2/ha1/CalculatorTest.java @@ -90,5 +90,48 @@ void testMultipleDecimalDots() { //TODO hier weitere Tests erstellen -} + @Test + @DisplayName ("soll den Bildschirm auf 0 zurücksetzen, wenn die Clear-Taste = 0 gedrückt wird") + void testClearScreen() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(1);//1 eingeben + calc.pressDigitKey(6);//6 eingeben und dann clear taste drücken + calc.pressClearKey();// clear taste drücken + + String expected = "0";// ergebnis ist 0 + String actual = calc.readScreen(); //commit 1 - + + assertEquals(expected, actual); + } + @Test + @DisplayName ("soll 'Error' anzeigen, wenn ein negativer Wert durch Null geteilt wird") + void testNegativeDivisionByZero() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(9);// 9 eingeben + calc.pressNegativeKey(); // -9 eingeben + calc.pressBinaryOperationKey("/");// geteilt eingeben + calc.pressDigitKey(0); // geteilt 0 eingeben + calc.pressEqualsKey(); // ergebnis berechnen = error + + String expected = "Error"; //zeigt error an + String actual = calc.readScreen(); //commit 2 - 1/2 - + + assertEquals(expected, actual); + } + @Test + @DisplayName ("soll 'Error' ausgeben, wenn der Kehrwert von 0 ermittelt wird") + void testInverseWithoutValue() { + Calculator calc = new Calculator(); + + calc.pressDigitKey(0); // 0 eingeben + calc.pressUnaryOperationKey("1/x"); // 1/x taste drücken = 1 durch 0 ist nicht definiert + + String expected = "Error"; // zeigt error an + String actual = calc.readScreen(); //commit 2 - 2/2 p + + assertEquals(expected, actual); + } +} \ No newline at end of file