summaryrefslogtreecommitdiff
path: root/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
diff options
context:
space:
mode:
authorAdrien Hopkins <adrien.p.hopkins@gmail.com>2024-08-22 11:41:04 -0500
committerAdrien Hopkins <adrien.p.hopkins@gmail.com>2024-08-22 11:45:37 -0500
commitea3e2bf07939926e43c7abe3fd13a7c4e93f69d1 (patch)
tree958c97f05c2830aefef45f6882ba688694480b55 /src/test/java/sevenUnits/unit/UnitDatabaseTest.java
parent43e3b70003fdda6f2ccdd2471e3ee3f97ad50ada (diff)
Show unit/dim file errors as popup
Previously, any error in the unit or dimension file(s) crashes the program. Instead, 7Units now ignores any invalid lines, still parsing the correct ones, and shows a popup in case any errors happen.
Diffstat (limited to 'src/test/java/sevenUnits/unit/UnitDatabaseTest.java')
-rw-r--r--src/test/java/sevenUnits/unit/UnitDatabaseTest.java221
1 files changed, 115 insertions, 106 deletions
diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
index 9d650f0..e7f3ccf 100644
--- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
+++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
@@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -53,9 +54,9 @@ import sevenUnits.utils.UncertainDouble;
class UnitDatabaseTest {
private static final class SimpleEntry<K, V> implements Map.Entry<K, V> {
private final K key;
-
+
private V value;
-
+
/**
*
* @since 2021-10-07
@@ -64,7 +65,7 @@ class UnitDatabaseTest {
this.key = key;
this.value = value;
}
-
+
@Override
public boolean equals(Object obj) {
if (this == obj)
@@ -75,23 +76,23 @@ class UnitDatabaseTest {
return Objects.equals(this.key, other.getKey())
&& Objects.equals(this.value, other.getValue());
}
-
+
@Override
public K getKey() {
return this.key;
}
-
+
@Override
public V getValue() {
return this.value;
}
-
+
@Override
public int hashCode() {
return (this.key == null ? 0 : this.key.hashCode())
^ (this.value == null ? 0 : this.value.hashCode());
}
-
+
@Override
public V setValue(V value) {
final V oldValue = this.value;
@@ -99,20 +100,20 @@ class UnitDatabaseTest {
return oldValue;
}
}
-
+
// some linear units and one nonlinear
private static final Unit U = Metric.METRE;
private static final Unit V = Metric.KILOGRAM;
-
+
private static final Unit W = Metric.SECOND;
// used for testing expressions
// J = U^2 * V / W^2
private static final LinearUnit J = Metric.KILOGRAM
.times(Metric.METRE.toExponent(2))
.dividedBy(Metric.SECOND.toExponent(2));
-
+
private static final LinearUnit K = Metric.KELVIN;
-
+
private static final Unit NONLINEAR = Unit.fromConversionFunctions(
Metric.METRE.getBase(), o -> o + 1, o -> o - 1);
// make the prefix values prime so I can tell which multiplications were made
@@ -123,9 +124,9 @@ class UnitDatabaseTest {
private static final UnitPrefix C = UnitPrefix.valueOf(5)
.withName(NameSymbol.ofName("C"));
private static final UnitPrefix AB = UnitPrefix.valueOf(7);
-
+
private static final UnitPrefix BC = UnitPrefix.valueOf(11);
-
+
/**
* Gets a map entry.
*
@@ -139,41 +140,47 @@ class UnitDatabaseTest {
private static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new SimpleEntry<>(key, value);
}
-
+
/**
* Loads the dimensionfile at src/test/resources/[path] to the database
* {@code loadTo}.
*
* @param loadTo database to load to
* @param path path of file to load
+ * @return exceptions returned by file loading
* @since 2021-10-04
*/
- private static void loadDimensionFile(UnitDatabase loadTo, String path) {
+ private static List<LoadingException> loadDimensionFile(UnitDatabase loadTo,
+ String path) {
try (final InputStream testFile = UnitDatabaseTest.class
.getResourceAsStream(path)) {
- loadTo.loadDimensionsFromStream(testFile);
+ return loadTo.loadDimensionsFromStream(testFile);
} catch (final IOException e) {
fail(e.getClass() + " occurred upon loading file \"" + path + "\".");
+ return Collections.emptyList();
}
}
-
+
/**
* Loads the unitfile at src/test/resources/[path] to the database
* {@code loadTo}.
*
* @param loadTo database to load to
* @param path path of file to load
+ * @return exceptions returned by file loading
* @since 2021-09-22
*/
- private static void loadUnitsFile(UnitDatabase loadTo, String path) {
+ private static List<LoadingException> loadUnitsFile(UnitDatabase loadTo,
+ String path) {
try (final InputStream testFile = UnitDatabaseTest.class
.getResourceAsStream(path)) {
- loadTo.loadUnitsFromStream(testFile);
+ return loadTo.loadUnitsFromStream(testFile);
} catch (final IOException e) {
fail(e.getClass() + " occurred upon loading file \"" + path + "\".");
+ return Collections.emptyList();
}
}
-
+
/**
* A test for the {@link UnitDatabase#evaluateUnitExpression(String)}
* function. Simple because the expression parser has its own test.
@@ -183,26 +190,26 @@ class UnitDatabaseTest {
@Test
public void testEvaluateExpression() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("J", J);
database.addUnit("K", K);
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
final LinearUnitValue expected = LinearUnitValue.of(J,
UncertainDouble.of(12, Math.sqrt(14.625)));
// note: units are exact, each number has an uncertainty of 1
final LinearUnitValue actual = database
.evaluateUnitExpression("J + (2 * 3) J + (20 / 4) J");
assertEquals(expected, actual);
-
+
// check that negation works properly
assertEquals(2,
database.evaluateUnitExpression("J - -1 * J").getValueExact());
}
-
+
/**
* Test for {@link UnitDatabase#getUnit}, {@link UnitDatabase#getLinearUnit}
* and {@link UnitDatabase#getLinearUnitValue}.
@@ -212,14 +219,14 @@ class UnitDatabaseTest {
@Test
public void testGetUnit() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("m", Metric.METRE);
database.addUnit("meter", Metric.METRE);
database.addUnit("metre", Metric.METRE);
database.addUnit("badname", Metric.METRE);
database.addUnit("K", Metric.KELVIN);
database.addUnit("degC", Metric.CELSIUS);
-
+
// ensure getUnit returns units, regardless of whether the name is one of
// the unit's names
assertEquals(Metric.METRE, database.getUnit("m"));
@@ -228,14 +235,14 @@ class UnitDatabaseTest {
assertEquals(Metric.METRE, database.getUnit("badname"));
assertThrows(NoSuchElementException.class,
() -> database.getUnit("blabla"));
-
+
assertEquals(Metric.KELVIN, database.getLinearUnit("K"));
assertThrows(IllegalArgumentException.class,
() -> database.getLinearUnit("degC"));
assertEquals(Metric.KELVIN.times(373.15),
database.getLinearUnit("degC(100)"));
}
-
+
/**
* Confirms that operations that shouldn't function for infinite databases
* throw an {@code IllegalStateException}.
@@ -247,21 +254,21 @@ class UnitDatabaseTest {
public void testInfiniteSetExceptions() {
// load units
final UnitDatabase infiniteDatabase = new UnitDatabase();
-
+
infiniteDatabase.addUnit("J", J);
infiniteDatabase.addUnit("K", K);
-
+
infiniteDatabase.addPrefix("A", A);
infiniteDatabase.addPrefix("B", B);
infiniteDatabase.addPrefix("C", C);
-
+
final Set<Entry<String, Unit>> entrySet = infiniteDatabase.unitMap()
.entrySet();
final Set<String> keySet = infiniteDatabase.unitMap().keySet();
assertThrows(IllegalStateException.class, () -> entrySet.toArray());
assertThrows(IllegalStateException.class, () -> keySet.toArray());
}
-
+
/**
* A bunch of tests for invalid dimension files
*
@@ -277,12 +284,13 @@ class UnitDatabaseTest {
database.addDimension("TIME", Metric.Dimensions.TIME);
final String filename = String.format("/test-dimensionfile-invalid%d.txt",
num);
- final RuntimeException e = assertThrows(RuntimeException.class,
- () -> loadDimensionFile(database, filename));
+ final List<LoadingException> errs = loadDimensionFile(database, filename);
+ assertFalse(errs.isEmpty(), "no error from invalid file " + filename);
+ final RuntimeException e = errs.get(0).problem();
assertTrue(e instanceof IllegalArgumentException
|| e instanceof NoSuchElementException);
}
-
+
/**
* A bunch of tests for invalid unit files
*
@@ -295,12 +303,13 @@ class UnitDatabaseTest {
final UnitDatabase database = new UnitDatabase();
final String filename = String.format("/test-unitsfile-invalid%d.txt",
num);
- final RuntimeException e = assertThrows(RuntimeException.class,
- () -> loadUnitsFile(database, filename));
+ final List<LoadingException> errs = loadUnitsFile(database, filename);
+ assertFalse(errs.isEmpty(), "no error from invalid file " + filename);
+ final RuntimeException e = errs.get(0).problem();
assertTrue(e instanceof IllegalArgumentException
|| e instanceof NoSuchElementException);
}
-
+
/**
* Tests loading a valid dimension-file with some derived dimensions.
*
@@ -312,13 +321,13 @@ class UnitDatabaseTest {
database.addDimension("LENGTH", Metric.Dimensions.LENGTH);
database.addDimension("MASS", Metric.Dimensions.MASS);
database.addDimension("TIME", Metric.Dimensions.TIME);
-
+
loadDimensionFile(database, "/test-dimensionfile-valid1.txt");
assertEquals(Metric.Dimensions.ENERGY, database.getDimension("ENERGY"));
assertEquals(Metric.Dimensions.POWER, database.getDimension("POWER"));
-
+
}
-
+
/**
* Tests loading a valid unitfile with some prefixes and no units.
*
@@ -327,13 +336,13 @@ class UnitDatabaseTest {
@Test
public void testLoadingValidPrefixes() {
final UnitDatabase database = new UnitDatabase();
-
+
loadUnitsFile(database, "/test-unitsfile-valid2.txt");
assertEquals(7, database.getPrefix("A").getMultiplier());
assertEquals(11, database.getPrefix("B").getMultiplier());
assertEquals(13, database.getPrefix("C").getMultiplier());
}
-
+
/**
* Tests loading a valid unitfile with some units and preloaded prefixes
*
@@ -342,43 +351,43 @@ class UnitDatabaseTest {
@Test
public void testLoadingValidUnits() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("U", U);
database.addUnit("V", V);
database.addUnit("W", W);
database.addUnit("fj", J.times(5));
database.addUnit("ej", J.times(8));
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
loadUnitsFile(database, "/test-unitsfile-valid1.txt");
-
+
final Unit expected1 = ((LinearUnit) U).withPrefix(A).withPrefix(B)
.withPrefix(C);
final Unit actual1 = database.getUnit("test1");
assertEquals(expected1, actual1);
-
+
final Unit expected2 = ((LinearUnit) W).withPrefix(B)
.times(((LinearUnit) V).withPrefix(C));
final Unit actual2 = database.getUnit("test2");
assertEquals(expected2, actual2);
-
+
final Unit expected3 = ((LinearUnit) U)
.times(A.getMultiplier() + C.getMultiplier() - B.getMultiplier());
final Unit actual3 = database.getUnit("test3");
assertEquals(expected3, actual3);
-
+
final UnitValue expected4 = UnitValue.of(U, 1);
final UnitValue actual4 = database
.evaluateUnitExpression("-5 * U + -3 * U + 12 * U - 3 * U")
.asUnitValue();
assertEquals(expected4, actual4);
-
+
assertTrue(System.err.toString().length() > 0);
}
-
+
/**
* Tests the iterator of the prefixless unit map. These tests are simple, as
* the unit map iterator is simple.
@@ -388,16 +397,16 @@ class UnitDatabaseTest {
@Test
public void testPrefixedUnitMapIterator() {
final UnitDatabase database1 = new UnitDatabase();
-
+
database1.addUnit("U", U);
database1.addUnit("V", V);
database1.addUnit("W", W);
-
+
final Map<String, Unit> map1 = database1.unitMap();
final Iterator<String> keyIterator1 = map1.keySet().iterator();
final Iterator<Map.Entry<String, Unit>> entryIterator1 = map1.entrySet()
.iterator();
-
+
final Set<String> expectedKeys = Set.of("U", "V", "W");
final Set<String> actualKeys = new HashSet<>();
while (keyIterator1.hasNext()) {
@@ -405,7 +414,7 @@ class UnitDatabaseTest {
}
assertEquals(expectedKeys, actualKeys);
assertEquals(expectedKeys, map1.keySet());
-
+
final Set<Map.Entry<String, Unit>> expectedEntries = Set.of(entry("U", U),
entry("V", V), entry("W", W));
final Set<Map.Entry<String, Unit>> actualEntries = new HashSet<>();
@@ -415,7 +424,7 @@ class UnitDatabaseTest {
assertEquals(expectedEntries, actualEntries);
assertEquals(expectedEntries, map1.entrySet());
}
-
+
/**
* Test that prefixes correctly apply to units.
*
@@ -425,28 +434,28 @@ class UnitDatabaseTest {
@Test
public void testPrefixes() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("U", U);
database.addUnit("V", V);
database.addUnit("W", W);
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
// test the getPrefixesFromName method
final List<UnitPrefix> expected = Arrays.asList(C, B, A);
assertEquals(expected, database.getPrefixesFromName("ABCU"));
-
+
// get the product
final Unit abcuNonlinear = database.getUnit("ABCU");
assert abcuNonlinear instanceof LinearUnit;
-
+
final LinearUnit abcu = (LinearUnit) abcuNonlinear;
assertEquals(A.getMultiplier() * B.getMultiplier() * C.getMultiplier(),
abcu.getConversionFactor(), 1e-15);
}
-
+
/**
* Tests the functionnalites of the prefixless unit map.
*
@@ -462,19 +471,19 @@ class UnitDatabaseTest {
final UnitDatabase database = new UnitDatabase();
final Map<String, Unit> prefixlessUnits = database
.unitMapPrefixless(true);
-
+
database.addUnit("U", U);
database.addUnit("V", V);
database.addUnit("W", W);
-
+
// this should work because the map should be an auto-updating view
assertTrue(prefixlessUnits.containsKey("U"));
assertFalse(prefixlessUnits.containsKey("Z"));
-
+
assertTrue(prefixlessUnits.containsValue(U));
assertFalse(prefixlessUnits.containsValue(NONLINEAR));
}
-
+
/**
* Tests that the database correctly stores and retrieves units, ignoring
* prefixes.
@@ -485,18 +494,18 @@ class UnitDatabaseTest {
@Test
public void testPrefixlessUnits() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("U", U);
database.addUnit("V", V);
database.addUnit("W", W);
-
+
assertTrue(database.containsUnitName("U"));
assertFalse(database.containsUnitName("Z"));
-
+
assertEquals(U, database.getUnit("U"));
assertThrows(NoSuchElementException.class, () -> database.getUnit("Z"));
}
-
+
@Test
public void testRemovableDuplicates() {
final Map<String, Unit> unitMap = new HashMap<>();
@@ -504,7 +513,7 @@ class UnitDatabaseTest {
unitMap.put("metre", Metric.METRE);
unitMap.put("m", Metric.METRE);
unitMap.put("second", Metric.SECOND);
-
+
assertTrue(UnitDatabase.isRemovableDuplicate(unitMap,
entry("m", Metric.METRE)));
assertTrue(UnitDatabase.isRemovableDuplicate(unitMap,
@@ -514,28 +523,28 @@ class UnitDatabaseTest {
assertFalse(UnitDatabase.isRemovableDuplicate(unitMap,
entry("second", Metric.SECOND)));
}
-
+
@Test
public void testToString() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("J", J);
database.addUnit("K", J);
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
if ("Unit Database with 1 units, 3 unit prefixes and 0 dimensions"
.equals(database.toString())) {
fail("Database counts by number of units, not number of unit names.");
}
-
+
assertEquals(
"Unit Database with 2 units, 3 unit prefixes and 0 dimensions",
database.toString());
}
-
+
/**
* Test that unit expressions return the correct value.
*
@@ -546,37 +555,37 @@ class UnitDatabaseTest {
public void testUnitExpressions() {
// load units
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("U", U);
database.addUnit("V", V);
database.addUnit("W", W);
database.addUnit("fj", J.times(5));
database.addUnit("ej", J.times(8));
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
// first test - test prefixes and operations
final Unit expected1 = J.withPrefix(A).withPrefix(B).withPrefix(C)
.withPrefix(C);
final Unit actual1 = database.getUnitFromExpression("ABV * CU^2 / W / W");
-
+
assertEquals(expected1, actual1);
-
+
// second test - test addition and subtraction
final Unit expected2 = J.times(58);
final Unit actual2 = database.getUnitFromExpression("2 fj + 6 ej");
-
+
assertEquals(expected2, actual2);
-
+
// test incorrect expressions
assertThrows(IllegalArgumentException.class,
() -> database.getUnitFromExpression("U + V"));
assertThrows(IllegalArgumentException.class,
() -> database.getUnitFromExpression("U - V"));
}
-
+
/**
* Tests both the unit name iterator and the name-unit entry iterator
*
@@ -587,25 +596,25 @@ class UnitDatabaseTest {
public void testUnitIterator() {
// load units
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("J", J);
database.addUnit("K", K);
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
final int NUM_UNITS = database.unitMapPrefixless(true).size();
final int NUM_PREFIXES = database.prefixMap(true).size();
-
+
final Iterator<String> nameIterator = database.unitMap().keySet()
.iterator();
final Iterator<Entry<String, Unit>> entryIterator = database.unitMap()
.entrySet().iterator();
-
+
int expectedLength = 1;
int unitsWithThisLengthSoFar = 0;
-
+
// loop 1000 times
for (int i = 0; i < 1000; i++) {
// expected length of next
@@ -614,31 +623,31 @@ class UnitDatabaseTest {
expectedLength++;
unitsWithThisLengthSoFar = 0;
}
-
+
// test that stuff is valid
final String nextName = nameIterator.next();
final Unit nextUnit = database.getUnit(nextName);
final Entry<String, Unit> nextEntry = entryIterator.next();
-
+
assertEquals(expectedLength, nextName.length());
assertEquals(nextName, nextEntry.getKey());
assertEquals(nextUnit, nextEntry.getValue());
-
+
unitsWithThisLengthSoFar++;
}
-
+
// test toString for consistency
final String entryIteratorString = entryIterator.toString();
for (int i = 0; i < 3; i++) {
assertEquals(entryIteratorString, entryIterator.toString());
}
-
+
final String nameIteratorString = nameIterator.toString();
for (int i = 0; i < 3; i++) {
assertEquals(nameIteratorString, nameIterator.toString());
}
}
-
+
/**
* Determine, given a unit name that could mean multiple things, which
* meaning is chosen.
@@ -654,28 +663,28 @@ class UnitDatabaseTest {
public void testUnitPrefixCombinations() {
// load units
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("J", J);
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
database.addPrefix("AB", AB);
database.addPrefix("BC", BC);
-
+
// test 1 - AB-C-J vs A-BC-J vs A-B-C-J
final Unit expected1 = J.withPrefix(AB).withPrefix(C);
final Unit actual1 = database.getUnit("ABCJ");
-
+
assertEquals(expected1, actual1);
-
+
// test 2 - ABC-J vs AB-CJ vs AB-C-J
database.addUnit("CJ", J.times(13));
database.addPrefix("ABC", UnitPrefix.valueOf(17));
-
+
final Unit expected2 = J.times(17);
final Unit actual2 = database.getUnit("ABCJ");
-
+
assertEquals(expected2, actual2);
}
}