diff options
author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2025-04-30 16:42:01 -0500 |
---|---|---|
committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2025-04-30 16:42:01 -0500 |
commit | 4910b914392753986526bc28102ddef42e275e6c (patch) | |
tree | c3c6e748584cef92660ed3cfce4a33a30491a150 | |
parent | d1335dd378a7e302e4853c2695f2931c244b8863 (diff) |
Add more UnitDatabase tests
-rw-r--r-- | src/main/java/sevenUnits/unit/UnitDatabase.java | 13 | ||||
-rw-r--r-- | src/test/java/sevenUnits/unit/UnitDatabaseTest.java | 460 |
2 files changed, 286 insertions, 187 deletions
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java index dc81aca..690430b 100644 --- a/src/main/java/sevenUnits/unit/UnitDatabase.java +++ b/src/main/java/sevenUnits/unit/UnitDatabase.java @@ -1905,18 +1905,23 @@ public final class UnitDatabase { * * @since 2024-08-22 */ - private List<LinearUnit> getUnitSetFromExpression(String expression) { + List<LinearUnit> getUnitSetFromExpression(String expression) { final String[] parts = expression.split(";"); final List<LinearUnit> units = new ArrayList<>(parts.length); for (final String unitName : parts) { final Unit unit = this.getUnitFromExpression(unitName.trim()); - if (unit instanceof LinearUnit) { - units.add((LinearUnit) unit); - } else + if (!(unit instanceof LinearUnit)) { throw new IllegalArgumentException(String.format( "Unit '%s' is in a unit-set expression, but is not linear.", unitName)); + } else if (units.size() > 0 && !unit.canConvertTo(units.get(0))) { + throw new IllegalArgumentException(String.format( + "Units in expression '%s' have different dimensions.", + expression)); + } + + units.add((LinearUnit) unit); } return units; } diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java index e7f3ccf..e55d6af 100644 --- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java +++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java @@ -23,21 +23,21 @@ import static org.junit.jupiter.api.Assertions.assertTrue; 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; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import sevenUnits.utils.NameSymbol; @@ -46,7 +46,7 @@ import sevenUnits.utils.UncertainDouble; /** * A test for the {@link UnitDatabase} class. This is NOT part of this program's * public API. - * + * * @author Adrien Hopkins * @since 2019-04-14 * @since v0.2.0 @@ -54,18 +54,18 @@ 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 */ public SimpleEntry(K key, V value) { this.key = key; this.value = value; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -76,44 +76,44 @@ 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; + final var oldValue = this.value; this.value = value; 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 @@ -124,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. * @@ -140,7 +140,7 @@ 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}. @@ -152,7 +152,7 @@ class UnitDatabaseTest { */ private static List<LoadingException> loadDimensionFile(UnitDatabase loadTo, String path) { - try (final InputStream testFile = UnitDatabaseTest.class + try (final var testFile = UnitDatabaseTest.class .getResourceAsStream(path)) { return loadTo.loadDimensionsFromStream(testFile); } catch (final IOException e) { @@ -160,7 +160,7 @@ class UnitDatabaseTest { return Collections.emptyList(); } } - + /** * Loads the unitfile at src/test/resources/[path] to the database * {@code loadTo}. @@ -172,7 +172,7 @@ class UnitDatabaseTest { */ private static List<LoadingException> loadUnitsFile(UnitDatabase loadTo, String path) { - try (final InputStream testFile = UnitDatabaseTest.class + try (final var testFile = UnitDatabaseTest.class .getResourceAsStream(path)) { return loadTo.loadUnitsFromStream(testFile); } catch (final IOException e) { @@ -180,53 +180,92 @@ class UnitDatabaseTest { return Collections.emptyList(); } } - + + private static final Stream<Arguments> testEvaluateExpressionInvalid() { + return Stream.of(Arguments.of("K^K"), Arguments.of("1 + K")); + } + + private static final Stream<Arguments> testEvaluateExpressionValid() { + return Stream.of( + Arguments.of("J + (2 * 3) J + (20 / 4) J", + LinearUnitValue.of(J, + UncertainDouble.of(12, Math.sqrt(14.625)))), + Arguments.of("J - -1 * J", + LinearUnitValue.of(J, UncertainDouble.of(2, 1))), + Arguments.of("K^2", + LinearUnitValue.of(K.times(K), UncertainDouble.of(1, 0)))); + } + + /** + * Tests expressions that are valid to the parser, but semantically invalid + * (e.g. adding different dimensions) + * + * @param expression expression to test - should throw + * {@link IllegalArgumentException} + */ + @ParameterizedTest + @MethodSource + public void testEvaluateExpressionInvalid(String expression) { + final var database = new UnitDatabase(); + + database.addUnit("J", J); + database.addUnit("K", K); + + database.addPrefix("A", A); + database.addPrefix("B", B); + database.addPrefix("C", C); + + assertThrows(IllegalArgumentException.class, + () -> database.getUnitFromExpression(expression)); + assertThrows(IllegalArgumentException.class, + () -> database.evaluateUnitExpression(expression)); + } + /** * A test for the {@link UnitDatabase#evaluateUnitExpression(String)} * function. Simple because the expression parser has its own test. - * + * * @since 2021-09-27 */ - @Test - public void testEvaluateExpression() { - final UnitDatabase database = new UnitDatabase(); - + @ParameterizedTest + @MethodSource + public void testEvaluateExpressionValid(String expression, + LinearUnitValue expected) { + final var 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"); + + final var actual = database + .evaluateUnitExpression(expression); assertEquals(expected, actual); - - // check that negation works properly - assertEquals(2, - database.evaluateUnitExpression("J - -1 * J").getValueExact()); + + final var expectedU = expected.getUnit().times(expected.getValueExact()); + final var actualU = database.getUnitFromExpression(expression); + assertEquals(expectedU, actualU); } - + /** * Test for {@link UnitDatabase#getUnit}, {@link UnitDatabase#getLinearUnit} * and {@link UnitDatabase#getLinearUnitValue}. - * + * * @since 2021-10-07 */ @Test public void testGetUnit() { - final UnitDatabase database = new UnitDatabase(); - + final var 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")); @@ -235,40 +274,40 @@ 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}. - * + * * @since 2019-05-03 */ // @Test // @Timeout(value = 1, unit = TimeUnit.SECONDS) public void testInfiniteSetExceptions() { // load units - final UnitDatabase infiniteDatabase = new UnitDatabase(); - + final var 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() + + final var entrySet = infiniteDatabase.unitMap() .entrySet(); - final Set<String> keySet = infiniteDatabase.unitMap().keySet(); + final var keySet = infiniteDatabase.unitMap().keySet(); assertThrows(IllegalStateException.class, () -> entrySet.toArray()); assertThrows(IllegalStateException.class, () -> keySet.toArray()); } - + /** * A bunch of tests for invalid dimension files * @@ -278,19 +317,19 @@ class UnitDatabaseTest { @ParameterizedTest @ValueSource(ints = { 1, 2, 3 }) public void testLoadingInvalidDimensionFile(int num) { - final UnitDatabase database = new UnitDatabase(); + final var database = new UnitDatabase(); database.addDimension("LENGTH", Metric.Dimensions.LENGTH); database.addDimension("MASS", Metric.Dimensions.MASS); database.addDimension("TIME", Metric.Dimensions.TIME); - final String filename = String.format("/test-dimensionfile-invalid%d.txt", + final var filename = String.format("/test-dimensionfile-invalid%d.txt", num); - final List<LoadingException> errs = loadDimensionFile(database, filename); + final var errs = loadDimensionFile(database, filename); assertFalse(errs.isEmpty(), "no error from invalid file " + filename); - final RuntimeException e = errs.get(0).problem(); + final var e = errs.get(0).problem(); assertTrue(e instanceof IllegalArgumentException || e instanceof NoSuchElementException); } - + /** * A bunch of tests for invalid unit files * @@ -300,113 +339,117 @@ class UnitDatabaseTest { @ParameterizedTest @ValueSource(ints = { 1, 2, 3, 4, 5 }) public void testLoadingInvalidUnitFile(int num) { - final UnitDatabase database = new UnitDatabase(); - final String filename = String.format("/test-unitsfile-invalid%d.txt", + final var database = new UnitDatabase(); + final var filename = String.format("/test-unitsfile-invalid%d.txt", num); - final List<LoadingException> errs = loadUnitsFile(database, filename); + final var errs = loadUnitsFile(database, filename); assertFalse(errs.isEmpty(), "no error from invalid file " + filename); - final RuntimeException e = errs.get(0).problem(); + final var e = errs.get(0).problem(); assertTrue(e instanceof IllegalArgumentException || e instanceof NoSuchElementException); } - + /** * Tests loading a valid dimension-file with some derived dimensions. - * + * * @since 2021-10-04 */ @Test public void testLoadingValidDimensions() { - final UnitDatabase database = new UnitDatabase(); + final var database = new UnitDatabase(); 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. - * + * * @since 2021-09-22 */ @Test public void testLoadingValidPrefixes() { - final UnitDatabase database = new UnitDatabase(); - + final var 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()); + + // test invalid prefixes + assertThrows(NoSuchElementException.class, + () -> database.getPrefix("N/A")); } - + /** * Tests loading a valid unitfile with some units and preloaded prefixes - * + * * @since 2021-09-22 */ @Test public void testLoadingValidUnits() { - final UnitDatabase database = new UnitDatabase(); - + final var 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"); + final var 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"); + final var 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"); + final var actual3 = database.getUnit("test3"); assertEquals(expected3, actual3); - - final UnitValue expected4 = UnitValue.of(U, 1); - final UnitValue actual4 = database + + final var expected4 = UnitValue.of(U, 1); + final var 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. - * + * * @since 2021-10-07 */ @Test public void testPrefixedUnitMapIterator() { - final UnitDatabase database1 = new UnitDatabase(); - + final var 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() + + final var map1 = database1.unitMap(); + final var keyIterator1 = map1.keySet().iterator(); + final var entryIterator1 = map1.entrySet() .iterator(); - + final Set<String> expectedKeys = Set.of("U", "V", "W"); final Set<String> actualKeys = new HashSet<>(); while (keyIterator1.hasNext()) { @@ -414,7 +457,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<>(); @@ -424,88 +467,88 @@ class UnitDatabaseTest { assertEquals(expectedEntries, actualEntries); assertEquals(expectedEntries, map1.entrySet()); } - + /** * Test that prefixes correctly apply to units. - * + * * @since 2019-04-14 * @since v0.2.0 */ @Test public void testPrefixes() { - final UnitDatabase database = new UnitDatabase(); - + final var 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"); + final var abcuNonlinear = database.getUnit("ABCU"); assert abcuNonlinear instanceof LinearUnit; - - final LinearUnit abcu = (LinearUnit) abcuNonlinear; + + final var abcu = (LinearUnit) abcuNonlinear; assertEquals(A.getMultiplier() * B.getMultiplier() * C.getMultiplier(), abcu.getConversionFactor(), 1e-15); } - + /** * Tests the functionnalites of the prefixless unit map. - * + * * <p> * The map should be an auto-updating view of the units in the database. * </p> - * + * * @since 2019-04-14 * @since v0.2.0 */ @Test public void testPrefixlessUnitMap() { - final UnitDatabase database = new UnitDatabase(); - final Map<String, Unit> prefixlessUnits = database + final var database = new UnitDatabase(); + final var 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. - * + * * @since 2019-04-14 * @since v0.2.0 */ @Test public void testPrefixlessUnits() { - final UnitDatabase database = new UnitDatabase(); - + final var 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<>(); @@ -513,7 +556,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, @@ -523,131 +566,131 @@ class UnitDatabaseTest { assertFalse(UnitDatabase.isRemovableDuplicate(unitMap, entry("second", Metric.SECOND))); } - + @Test public void testToString() { - final UnitDatabase database = new UnitDatabase(); - + final var 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. - * + * * @since 2019-04-14 * @since v0.2.0 */ @Test public void testUnitExpressions() { // load units - final UnitDatabase database = new UnitDatabase(); - + final var 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"); - + final var 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"); - + final var 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 - * + * * @since 2019-04-14 * @since v0.2.0 */ @Test public void testUnitIterator() { // load units - final UnitDatabase database = new UnitDatabase(); - + final var 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() + + final var NUM_UNITS = database.unitMapPrefixless(true).size(); + final var NUM_PREFIXES = database.prefixMap(true).size(); + + final var nameIterator = database.unitMap().keySet() .iterator(); - final Iterator<Entry<String, Unit>> entryIterator = database.unitMap() + final var entryIterator = database.unitMap() .entrySet().iterator(); - - int expectedLength = 1; - int unitsWithThisLengthSoFar = 0; - + + var expectedLength = 1; + var unitsWithThisLengthSoFar = 0; + // loop 1000 times - for (int i = 0; i < 1000; i++) { + for (var i = 0; i < 1000; i++) { // expected length of next if (unitsWithThisLengthSoFar >= NUM_UNITS * (int) Math.pow(NUM_PREFIXES, expectedLength - 1)) { 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(); - + final var nextName = nameIterator.next(); + final var nextUnit = database.getUnit(nextName); + final var 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++) { + final var entryIteratorString = entryIterator.toString(); + for (var i = 0; i < 3; i++) { assertEquals(entryIteratorString, entryIterator.toString()); } - - final String nameIteratorString = nameIterator.toString(); - for (int i = 0; i < 3; i++) { + + final var nameIteratorString = nameIterator.toString(); + for (var i = 0; i < 3; i++) { assertEquals(nameIteratorString, nameIterator.toString()); } } - + /** * Determine, given a unit name that could mean multiple things, which * meaning is chosen. @@ -655,36 +698,87 @@ class UnitDatabaseTest { * For example, "ABCU" could mean "A-B-C-U", "AB-C-U", or "A-BC-U". In this * case, "AB-C-U" is the correct choice. * </p> - * + * * @since 2019-04-14 * @since v0.2.0 */ @Test public void testUnitPrefixCombinations() { // load units - final UnitDatabase database = new UnitDatabase(); - + final var 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"); - + final var 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"); - + final var actual2 = database.getUnit("ABCJ"); + assertEquals(expected2, actual2); } + + /** + * Tests the ability to create, read, and delete unit sets. + * + * @since 2025-04-30 + */ + @Test + void testUnitSetsInvalid() { + final List<LinearUnit> units = List.of(Metric.SECOND, + BritishImperial.Length.INCH); + + final var database = new UnitDatabase(); + + assertThrows(IllegalArgumentException.class, + () -> database.addUnitSet("badtest", units)); + assertThrows(NoSuchElementException.class, + () -> database.getUnitSet("badtest")); + + database.addUnit("ft", BritishImperial.Length.FOOT); + database.addUnit("s", Metric.SECOND); + database.addUnit("dC", Metric.CELSIUS); + database.addUnit("K", Metric.KELVIN); + + assertThrows(IllegalArgumentException.class, + () -> database.getUnitSetFromExpression("K; dC"), + "getUnitSetFromExpression allowed nonlinear unit."); + assertThrows(IllegalArgumentException.class, + () -> database.getUnitSetFromExpression("ft; s"), + "getUnitSetFromExpression allowed units of different dimension."); + } + + /** + * Tests the ability to create, read, and delete unit sets. + * + * @since 2025-04-30 + */ + @Test + void testUnitSetsValid() { + final List<LinearUnit> units = List.of(BritishImperial.Length.FOOT, + BritishImperial.Length.INCH); + + final var database = new UnitDatabase(); + + database.addUnitSet("ftintest", units); + assertEquals(units, database.getUnitSet("ftintest")); + + database.addUnit("ft", BritishImperial.Length.FOOT); + database.addUnit("in", BritishImperial.Length.INCH); + assertEquals(units, database.getUnitSetFromExpression("ft; in")); + } + } |