summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdrien Hopkins <ahopk127@my.yorku.ca>2022-02-26 11:15:04 -0500
committerAdrien Hopkins <ahopk127@my.yorku.ca>2022-02-26 11:15:49 -0500
commit934213e08e85cc20bd994d0f39567426c21b89eb (patch)
treeb6a6ec78124e854246478f001fd0d816703e39ce /src
parent07c86e02be29aa3d3d878adce62c5c0a9a458e47 (diff)
Implemented expression conversion, tests now pass
Diffstat (limited to 'src')
-rw-r--r--src/main/java/sevenUnits/unit/UnitDatabase.java11
-rw-r--r--src/main/java/sevenUnits/utils/NameSymbol.java9
-rw-r--r--src/main/java/sevenUnits/utils/Nameable.java20
-rw-r--r--src/main/java/sevenUnits/utils/ObjectProduct.java6
-rw-r--r--src/main/java/sevenUnitsGUI/Presenter.java77
-rw-r--r--src/main/java/sevenUnitsGUI/TabbedView.java15
-rw-r--r--src/main/java/sevenUnitsGUI/UnitConversionView.java6
-rw-r--r--src/main/java/sevenUnitsGUI/ViewBot.java36
-rw-r--r--src/test/java/sevenUnitsGUI/PresenterTest.java104
9 files changed, 194 insertions, 90 deletions
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java
index b029539..bf6ae64 100644
--- a/src/main/java/sevenUnits/unit/UnitDatabase.java
+++ b/src/main/java/sevenUnits/unit/UnitDatabase.java
@@ -1478,6 +1478,17 @@ public final class UnitDatabase {
}
/**
+ * Removes all units, prefixes and dimensions from this database.
+ *
+ * @since 2022-02-26
+ */
+ public void clear() {
+ this.dimensions.clear();
+ this.prefixes.clear();
+ this.prefixlessUnits.clear();
+ }
+
+ /**
* Tests if the database has a unit dimension with this name.
*
* @param name name to test
diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java
index aea274b..255e82f 100644
--- a/src/main/java/sevenUnits/utils/NameSymbol.java
+++ b/src/main/java/sevenUnits/utils/NameSymbol.java
@@ -278,15 +278,6 @@ public final class NameSymbol {
return this.primaryName.isEmpty() && this.symbol.isEmpty();
}
- /**
- * @return a short version of this NameSymbol (defaults to symbol instead of
- * primary name)
- * @since 2022-02-26
- */
- public String shortName() {
- return this.symbol.or(this::getPrimaryName).orElse("EMPTY");
- }
-
@Override
public String toString() {
if (this.isEmpty())
diff --git a/src/main/java/sevenUnits/utils/Nameable.java b/src/main/java/sevenUnits/utils/Nameable.java
index 3cfc05a..e469d04 100644
--- a/src/main/java/sevenUnits/utils/Nameable.java
+++ b/src/main/java/sevenUnits/utils/Nameable.java
@@ -27,6 +27,16 @@ import java.util.Set;
*/
public interface Nameable {
/**
+ * @return a name for the object - if there's a primary name, it's that,
+ * otherwise the symbol, otherwise "Unnamed"
+ * @since 2022-02-26
+ */
+ default String getName() {
+ final NameSymbol ns = this.getNameSymbol();
+ return ns.getPrimaryName().or(ns::getSymbol).orElse("Unnamed");
+ }
+
+ /**
* @return a {@code NameSymbol} that contains this object's primary name,
* symbol and other names
* @since 2020-09-07
@@ -50,6 +60,16 @@ public interface Nameable {
}
/**
+ * @return a short name for the object - if there's a symbol, it's that,
+ * otherwise the symbol, otherwise "Unnamed"
+ * @since 2022-02-26
+ */
+ default String getShortName() {
+ final NameSymbol ns = this.getNameSymbol();
+ return ns.getSymbol().or(ns::getPrimaryName).orElse("Unnamed");
+ }
+
+ /**
* @return short symbol representing object
* @since 2020-09-07
*/
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index 926ce10..830f9d7 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.java
@@ -244,9 +244,9 @@ public class ObjectProduct<T> {
*/
@Override
public String toString() {
- return this.toString(o -> o instanceof Nameable
- ? ((Nameable) o).getNameSymbol().shortName()
- : o.toString());
+ return this
+ .toString(o -> o instanceof Nameable ? ((Nameable) o).getShortName()
+ : o.toString());
}
/**
diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java
index be02364..57d353d 100644
--- a/src/main/java/sevenUnitsGUI/Presenter.java
+++ b/src/main/java/sevenUnitsGUI/Presenter.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.Scanner;
@@ -34,6 +35,7 @@ import java.util.stream.Collectors;
import sevenUnits.ProgramInfo;
import sevenUnits.unit.BaseDimension;
import sevenUnits.unit.BritishImperial;
+import sevenUnits.unit.LinearUnitValue;
import sevenUnits.unit.Metric;
import sevenUnits.unit.Unit;
import sevenUnits.unit.UnitDatabase;
@@ -170,7 +172,7 @@ public final class Presenter {
/**
* The database that this presenter communicates with (effectively the model)
*/
- private final UnitDatabase database;
+ final UnitDatabase database;
/**
* The rule used for parsing input numbers. Any number-string inputted into
@@ -274,7 +276,58 @@ public final class Presenter {
* {@link ExpressionConversionView})
* @since 2021-12-15
*/
- public void convertExpressions() {}
+ public void convertExpressions() {
+ if (this.view instanceof ExpressionConversionView) {
+ final ExpressionConversionView xcview = (ExpressionConversionView) this.view;
+
+ final String fromExpression = xcview.getFromExpression();
+ final String toExpression = xcview.getToExpression();
+
+ // expressions must not be empty
+ if (fromExpression.isEmpty()) {
+ this.view.showErrorMessage("Parse Error",
+ "Please enter a unit expression in the From: box.");
+ return;
+ }
+ if (toExpression.isEmpty()) {
+ this.view.showErrorMessage("Parse Error",
+ "Please enter a unit expression in the To: box.");
+ return;
+ }
+
+ // evaluate expressions
+ final LinearUnitValue from;
+ final Unit to;
+ try {
+ from = this.database.evaluateUnitExpression(fromExpression);
+ } catch (final IllegalArgumentException | NoSuchElementException e) {
+ this.view.showErrorMessage("Parse Error",
+ "Could not recognize text in From entry: " + e.getMessage());
+ return;
+ }
+ try {
+ to = this.database.getUnitFromExpression(toExpression);
+ } catch (final IllegalArgumentException | NoSuchElementException e) {
+ this.view.showErrorMessage("Parse Error",
+ "Could not recognize text in To entry: " + e.getMessage());
+ return;
+ }
+
+ // convert and show output
+ if (from.getUnit().canConvertTo(to)) {
+ final double value = from.asUnitValue().convertTo(to).getValue();
+ xcview.showExpressionConversionOutput(fromExpression, toExpression,
+ value);
+ } else {
+ this.view.showErrorMessage("Conversion Error",
+ "Cannot convert between \"" + fromExpression + "\" and \""
+ + toExpression + "\".");
+ }
+
+ } else
+ throw new UnsupportedOperationException(
+ "This function can only be called when the view is an ExpressionConversionView");
+ }
/**
* Converts from the view's input unit to its output unit. Displays an error
@@ -326,8 +379,7 @@ public final class Presenter {
// convert!
final UnitValue initialValue = UnitValue.of(fromUnit, value);
final UnitValue converted = initialValue.convertTo(toUnit);
- ucview.showUnitConversionOutput(
- String.format("%s = %s", initialValue, converted));
+ ucview.showUnitConversionOutput(initialValue, converted);
} else
throw new UnsupportedOperationException(
"This function can only be called when the view is a UnitConversionView.");
@@ -365,23 +417,6 @@ public final class Presenter {
*/
public void saveSettings() {}
- /**
- * Returns true if and only if the unit represented by {@code unitName} has
- * the dimension represented by {@code dimensionName}.
- *
- * @param unitName name of unit to test
- * @param dimensionName name of dimension to test
- * @return whether unit has dimenision
- * @since 2019-04-13
- * @since v0.2.0
- */
- boolean unitMatchesDimension(String unitName, String dimensionName) {
- final Unit unit = this.database.getUnit(unitName);
- final ObjectProduct<BaseDimension> dimension = this.database
- .getDimension(dimensionName);
- return unit.getDimension().equals(dimension);
- }
-
void unitNameSelected() {}
/**
diff --git a/src/main/java/sevenUnitsGUI/TabbedView.java b/src/main/java/sevenUnitsGUI/TabbedView.java
index c3a05e2..1d40087 100644
--- a/src/main/java/sevenUnitsGUI/TabbedView.java
+++ b/src/main/java/sevenUnitsGUI/TabbedView.java
@@ -23,6 +23,7 @@ import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.text.DecimalFormat;
import java.text.NumberFormat;
+import java.text.ParseException;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Iterator;
@@ -59,6 +60,7 @@ import sevenUnits.ProgramInfo;
import sevenUnits.unit.BaseDimension;
import sevenUnits.unit.Unit;
import sevenUnits.unit.UnitPrefix;
+import sevenUnits.unit.UnitValue;
import sevenUnits.utils.NamedObjectProduct;
import sevenUnits.utils.ObjectProduct;
@@ -140,7 +142,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
/** The combo box that selects dimensions */
private final JComboBox<NamedObjectProduct<BaseDimension>> dimensionSelector;
/** The panel for inputting values in the dimension-based converter */
- private final JTextField valueInput;
+ private final JFormattedTextField valueInput;
/** The panel for "From" in the dimension-based converter */
private final SearchBoxList<Unit> fromSearch;
/** The panel for "To" in the dimension-based converter */
@@ -543,12 +545,13 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
@Override
public OptionalDouble getInputValue() {
- final String text = this.valueInput.getText();
try {
- return OptionalDouble.of(Double.parseDouble(text));
- } catch (final NumberFormatException e) {
+ this.valueInput.commitEdit();
+ } catch (final ParseException e) {
return OptionalDouble.empty();
}
+ return OptionalDouble
+ .of(((Number) this.valueInput.getValue()).doubleValue());
}
@Override
@@ -604,8 +607,8 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView {
}
@Override
- public void showUnitConversionOutput(String outputString) {
- this.unitOutput.setText(outputString);
+ public void showUnitConversionOutput(UnitValue input, UnitValue output) {
+ this.unitOutput.setText(input + " = " + output);
}
}
diff --git a/src/main/java/sevenUnitsGUI/UnitConversionView.java b/src/main/java/sevenUnitsGUI/UnitConversionView.java
index e411a44..67d3ddc 100644
--- a/src/main/java/sevenUnitsGUI/UnitConversionView.java
+++ b/src/main/java/sevenUnitsGUI/UnitConversionView.java
@@ -22,6 +22,7 @@ import java.util.Set;
import sevenUnits.unit.BaseDimension;
import sevenUnits.unit.Unit;
+import sevenUnits.unit.UnitValue;
import sevenUnits.utils.NamedObjectProduct;
import sevenUnits.utils.ObjectProduct;
@@ -94,8 +95,9 @@ public interface UnitConversionView extends View {
/**
* Shows the output of a unit conversion.
*
- * @param outputString string that shows output of conversion
+ * @param input input unit & value (obtained from this view)
+ * @param output output unit & value
* @since 2021-12-24
*/
- void showUnitConversionOutput(String outputString);
+ void showUnitConversionOutput(UnitValue input, UnitValue output);
}
diff --git a/src/main/java/sevenUnitsGUI/ViewBot.java b/src/main/java/sevenUnitsGUI/ViewBot.java
index bc5302b..43d73bb 100644
--- a/src/main/java/sevenUnitsGUI/ViewBot.java
+++ b/src/main/java/sevenUnitsGUI/ViewBot.java
@@ -16,6 +16,7 @@
*/
package sevenUnitsGUI;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -25,6 +26,7 @@ import java.util.Set;
import sevenUnits.unit.BaseDimension;
import sevenUnits.unit.Unit;
+import sevenUnits.unit.UnitValue;
import sevenUnits.utils.NamedObjectProduct;
import sevenUnits.utils.ObjectProduct;
@@ -59,8 +61,12 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
private Set<? extends Unit> fromUnits;
/** The units available in the To selection */
private Set<? extends Unit> toUnits;
+ /** Saved input values of all unit conversions */
+ private final List<UnitValue> unitConversionInputValues;
/** Saved output values of all unit conversions */
- private List<String> unitConversionOutputValues;
+ private final List<UnitValue> unitConversionOutputValues;
+ /** Saved outputs of all unit expressions */
+ private final List<String> expressionConversionOutputs;
/**
* Creates a new {@code ViewBot} with a new presenter.
@@ -69,6 +75,10 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
*/
public ViewBot() {
this.presenter = new Presenter(this);
+
+ this.unitConversionInputValues = new ArrayList<>();
+ this.unitConversionOutputValues = new ArrayList<>();
+ this.expressionConversionOutputs = new ArrayList<>();
}
/**
@@ -81,7 +91,7 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
}
public List<String> getExpressionConversionOutputs() {
- throw new UnsupportedOperationException("Not implemented yet");
+ return this.expressionConversionOutputs;
}
@Override
@@ -139,10 +149,18 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
}
/**
+ * @return the unitConversionInputValues
+ * @since 2022-02-26
+ */
+ public List<UnitValue> getUnitConversionInputValues() {
+ return this.unitConversionInputValues;
+ }
+
+ /**
* @return the unitConversionOutputValues
* @since 2022-02-10
*/
- public List<String> getUnitConversionOutputValues() {
+ public List<UnitValue> getUnitConversionOutputValues() {
return this.unitConversionOutputValues;
}
@@ -247,13 +265,17 @@ final class ViewBot implements UnitConversionView, ExpressionConversionView {
@Override
public void showExpressionConversionOutput(String fromExpression,
String toExpression, double value) {
- System.out.printf("Expression Conversion: %s = %d * (%s)%n",
- fromExpression, value, toExpression);
+ final String output = String.format("%s = %s %s", fromExpression, value,
+ toExpression);
+ this.expressionConversionOutputs.add(output);
+ System.out.println("Expression Conversion: " + output);
}
@Override
- public void showUnitConversionOutput(String outputString) {
- System.out.println("Unit conversion: " + outputString);
+ public void showUnitConversionOutput(UnitValue input, UnitValue output) {
+ this.unitConversionInputValues.add(input);
+ this.unitConversionOutputValues.add(output);
+ System.out.println("Unit conversion: " + input + " = " + output);
}
@Override
diff --git a/src/test/java/sevenUnitsGUI/PresenterTest.java b/src/test/java/sevenUnitsGUI/PresenterTest.java
index ff1450b..deb16d7 100644
--- a/src/test/java/sevenUnitsGUI/PresenterTest.java
+++ b/src/test/java/sevenUnitsGUI/PresenterTest.java
@@ -19,16 +19,19 @@ package sevenUnitsGUI;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.Set;
+import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import sevenUnits.unit.BaseDimension;
import sevenUnits.unit.Metric;
import sevenUnits.unit.Unit;
+import sevenUnits.unit.UnitValue;
import sevenUnits.utils.NameSymbol;
import sevenUnits.utils.NamedObjectProduct;
@@ -38,51 +41,20 @@ import sevenUnits.utils.NamedObjectProduct;
* @since 2022-02-10
*/
public final class PresenterTest {
+ private static final List<String> unitNames(
+ Collection<? extends Unit> units) {
+ return units.stream().map(Unit::getShortName)
+ .collect(Collectors.toList());
+ }
+
Set<Unit> testUnits = Set.of(Metric.METRE, Metric.KILOMETRE,
Metric.METRE_PER_SECOND, Metric.KILOMETRE_PER_HOUR);
+
Set<NamedObjectProduct<BaseDimension>> testDimensions = Set.of(
Metric.Dimensions.LENGTH.withName(NameSymbol.ofName("Length")),
Metric.Dimensions.VELOCITY.withName(NameSymbol.ofName("Velocity")));
/**
- * Test for {@link Presenter#updateView()}
- *
- * @since 2022-02-12
- */
- @Test
- void testUpdateView() {
- // setup
- final ViewBot viewBot = new ViewBot();
- final Presenter presenter = new Presenter(viewBot);
-
- viewBot.setFromUnits(this.testUnits);
- viewBot.setToUnits(this.testUnits);
- viewBot.setDimensions(this.testDimensions);
- viewBot.setSelectedDimension(
- Optional.of(this.testDimensions.iterator().next()));
-
- // filter to length units only, then get the filtered sets of units
- presenter.updateView();
- final Set<Unit> fromUnits = viewBot.getFromUnits();
- final Set<Unit> toUnits = viewBot.getToUnits();
-
- // test that fromUnits/toUnits is [METRE, KILOMETRE]
- // HOWEVER I don't care about the order so I'm testing it this way
- assertEquals(2, fromUnits.size(),
- "Invalid fromUnits (length != 2): " + fromUnits);
- assertEquals(2, toUnits.size(),
- "Invalid toUnits (length != 2): " + toUnits);
- assertTrue(fromUnits.contains(Metric.METRE),
- "Invaild fromUnits (METRE missing): " + fromUnits);
- assertTrue(toUnits.contains(Metric.METRE),
- "Invaild toUnits (METRE missing): " + toUnits);
- assertTrue(fromUnits.contains(Metric.KILOMETRE),
- "Invaild fromUnits (KILOMETRE missing): " + fromUnits);
- assertTrue(toUnits.contains(Metric.KILOMETRE),
- "Invaild toUnits (KILOMETRE missing): " + toUnits);
- }
-
- /**
* Test method for {@link Presenter#convertExpressions}
*
* @since 2022-02-12
@@ -129,10 +101,58 @@ public final class PresenterTest {
* here (that's for the backend tests), I'm just testing that it correctly
* calls the unit conversion system
*/
- final String expected = String
- .valueOf(Metric.METRE.convertTo(Metric.KILOMETRE, 10000.0));
+ final UnitValue expectedInput = UnitValue.of(Metric.METRE, 10000.0);
+ final UnitValue expectedOutput = expectedInput
+ .convertTo(Metric.KILOMETRE);
+
+ final List<UnitValue> inputs = viewBot.getUnitConversionInputValues();
+ final List<UnitValue> outputs = viewBot.getUnitConversionOutputValues();
+ assertEquals(expectedInput, inputs.get(inputs.size() - 1));
+ assertEquals(expectedOutput, outputs.get(outputs.size() - 1));
+ }
+
+ /**
+ * Test for {@link Presenter#updateView()}
+ *
+ * @since 2022-02-12
+ */
+ @Test
+ void testUpdateView() {
+ // setup
+ final ViewBot viewBot = new ViewBot();
+ final Presenter presenter = new Presenter(viewBot);
+
+ // override default database units
+ presenter.database.clear();
+ for (final Unit unit : this.testUnits) {
+ presenter.database.addUnit(unit.getPrimaryName().orElseThrow(), unit);
+ }
+
+ // set from and to units
+ viewBot.setFromUnits(this.testUnits);
+ viewBot.setToUnits(this.testUnits);
+ viewBot.setDimensions(this.testDimensions);
+ viewBot.setSelectedDimension(
+ Optional.of(this.testDimensions.iterator().next()));
+
+ // filter to length units only, then get the filtered sets of units
+ presenter.updateView();
+ final Set<Unit> fromUnits = viewBot.getFromUnits();
+ final Set<Unit> toUnits = viewBot.getToUnits();
- final List<String> outputs = viewBot.getUnitConversionOutputValues();
- assertEquals(expected, outputs.get(outputs.size() - 1));
+ // test that fromUnits/toUnits is [METRE, KILOMETRE]
+ // HOWEVER I don't care about the order so I'm testing it this way
+ assertEquals(2, fromUnits.size(),
+ "Invalid fromUnits (length != 2): " + unitNames(fromUnits));
+ assertEquals(2, toUnits.size(),
+ "Invalid toUnits (length != 2): " + unitNames(toUnits));
+ assertTrue(fromUnits.contains(Metric.METRE),
+ "Invaild fromUnits (METRE missing): " + unitNames(fromUnits));
+ assertTrue(toUnits.contains(Metric.METRE),
+ "Invaild toUnits (METRE missing): " + unitNames(toUnits));
+ assertTrue(fromUnits.contains(Metric.KILOMETRE),
+ "Invaild fromUnits (KILOMETRE missing): " + unitNames(fromUnits));
+ assertTrue(toUnits.contains(Metric.KILOMETRE),
+ "Invaild toUnits (KILOMETRE missing): " + unitNames(toUnits));
}
}