diff options
Diffstat (limited to 'src/test/java')
7 files changed, 594 insertions, 49 deletions
diff --git a/src/test/java/sevenUnits/unit/MultiUnitTest.java b/src/test/java/sevenUnits/unit/MultiUnitTest.java index d632118..39ee21c 100644 --- a/src/test/java/sevenUnits/unit/MultiUnitTest.java +++ b/src/test/java/sevenUnits/unit/MultiUnitTest.java @@ -25,10 +25,6 @@ import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.Test; -import sevenUnits.unit.BritishImperial; -import sevenUnits.unit.MultiUnit; -import sevenUnits.unit.Metric; - /** * Tests related to the {@code MultiUnit}. * diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java index 1d5e503..2276d7c 100644 --- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java +++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java @@ -20,23 +20,26 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; 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.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 org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; -import sevenUnits.unit.LinearUnit; -import sevenUnits.unit.NameSymbol; -import sevenUnits.unit.Metric; -import sevenUnits.unit.Unit; -import sevenUnits.unit.UnitDatabase; -import sevenUnits.unit.UnitPrefix; +import sevenUnits.utils.UncertainDouble; /** * A test for the {@link UnitDatabase} class. This is NOT part of this program's @@ -47,20 +50,70 @@ import sevenUnits.unit.UnitPrefix; * @since v0.2.0 */ 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) + return true; + if (!(obj instanceof Map.Entry<?, ?>)) + return false; + final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj; + 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; + 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; + 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)) + 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); + 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 private static final UnitPrefix A = UnitPrefix.valueOf(2) .withName(NameSymbol.ofName("A")); @@ -69,9 +122,120 @@ 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. + * + * @param <K> type of key + * @param <V> type of value + * @param key key in entry + * @param value value in entry + * @return entry + * @since 2021-10-07 + */ + 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 + * @since 2021-10-04 + */ + private static void loadDimensionFile(UnitDatabase loadTo, String path) { + try (final InputStream testFile = UnitDatabaseTest.class + .getResourceAsStream(path)) { + loadTo.loadDimensionsFromStream(testFile); + } catch (final IOException e) { + fail(e.getClass() + " occurred upon loading file \"" + path + "\"."); + } + } + + /** + * 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 + * @since 2021-09-22 + */ + private static void loadUnitsFile(UnitDatabase loadTo, String path) { + try (final InputStream testFile = UnitDatabaseTest.class + .getResourceAsStream(path)) { + loadTo.loadUnitsFromStream(testFile); + } catch (final IOException e) { + fail(e.getClass() + " occurred upon loading file \"" + path + "\"."); + } + } + + /** + * 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(); + + 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}. + * + * @since 2021-10-07 + */ + @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")); + assertEquals(Metric.METRE, database.getUnit("metre")); + assertEquals(Metric.METRE, database.getUnit("meter")); + 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}. * @@ -98,6 +262,160 @@ class UnitDatabaseTest { } /** + * A bunch of tests for invalid dimension files + * + * @param num which file to test + * @since 2021-10-04 + */ + @ParameterizedTest + @ValueSource(ints = { 1, 2, 3 }) + public void testLoadingInvalidDimensionFile(int num) { + final UnitDatabase 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", + num); + final RuntimeException e = assertThrows(RuntimeException.class, + () -> loadDimensionFile(database, filename)); + assertTrue(e instanceof IllegalArgumentException + || e instanceof NoSuchElementException); + } + + /** + * A bunch of tests for invalid unit files + * + * @param num which file to test + * @since 2021-09-27 + */ + @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", + num); + final RuntimeException e = assertThrows(RuntimeException.class, + () -> loadUnitsFile(database, filename)); + 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(); + 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(); + + 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 + * + * @since 2021-09-22 + */ + @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. + * + * @since 2021-10-07 + */ + @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()) { + actualKeys.add(keyIterator1.next()); + } + 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<>(); + while (entryIterator1.hasNext()) { + actualEntries.add(entryIterator1.next()); + } + assertEquals(expectedEntries, actualEntries); + assertEquals(expectedEntries, map1.entrySet()); + } + + /** * Test that prefixes correctly apply to units. * * @since 2019-04-14 @@ -178,6 +496,45 @@ class UnitDatabaseTest { assertThrows(NoSuchElementException.class, () -> database.getUnit("Z")); } + @Test + public void testRemovableDuplicates() { + final Map<String, Unit> unitMap = new HashMap<>(); + unitMap.put("meter", Metric.METRE); + 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, + entry("meter", Metric.METRE))); + assertFalse(UnitDatabase.isRemovableDuplicate(unitMap, + entry("metre", Metric.METRE))); + 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. * @@ -211,6 +568,12 @@ class UnitDatabaseTest { 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")); } /** diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java index a980054..bb2e6a4 100644 --- a/src/test/java/sevenUnits/unit/UnitTest.java +++ b/src/test/java/sevenUnits/unit/UnitTest.java @@ -26,13 +26,8 @@ import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.Test; -import sevenUnits.unit.LinearUnit; -import sevenUnits.unit.LinearUnitValue; -import sevenUnits.unit.NameSymbol; -import sevenUnits.unit.Metric; -import sevenUnits.unit.Unit; -import sevenUnits.unit.UnitValue; import sevenUnits.utils.DecimalComparison; +import sevenUnits.utils.UncertainDouble; /** * Testing the various Unit classes. This is NOT part of this program's public @@ -59,8 +54,10 @@ class UnitTest { // test with LinearUnitValue final LinearUnitValue value1 = LinearUnitValue.getExact(Metric.METRE, 15); final LinearUnitValue value2 = LinearUnitValue.getExact(foot, 120); - final LinearUnitValue value3 = LinearUnitValue.getExact(Metric.METRE, 0.5); - final LinearUnitValue value4 = LinearUnitValue.getExact(Metric.KILOGRAM, 60); + final LinearUnitValue value3 = LinearUnitValue.getExact(Metric.METRE, + 0.5); + final LinearUnitValue value4 = LinearUnitValue.getExact(Metric.KILOGRAM, + 60); // make sure addition is done correctly assertEquals(51.576, value1.plus(value2).getValueExact(), 0.001); @@ -77,6 +74,7 @@ class UnitTest { // make sure errors happen when they should assertThrows(IllegalArgumentException.class, () -> value1.plus(value4)); + assertThrows(IllegalArgumentException.class, () -> value1.minus(value4)); } @Test @@ -128,7 +126,8 @@ class UnitTest { public void testMultiplicationAndDivision() { // test unit-times-unit multiplication final LinearUnit generatedJoule = Metric.KILOGRAM - .times(Metric.METRE.toExponent(2)).dividedBy(Metric.SECOND.toExponent(2)); + .times(Metric.METRE.toExponent(2)) + .dividedBy(Metric.SECOND.toExponent(2)); final LinearUnit actualJoule = Metric.JOULE; assertEquals(generatedJoule, actualJoule); @@ -138,16 +137,87 @@ class UnitTest { final LinearUnit hour = Metric.SECOND.times(3600); final LinearUnit generatedKPH = kilometre.dividedBy(hour); - final LinearUnit actualKPH = Metric.METRE.dividedBy(Metric.SECOND).dividedBy(3.6); + final LinearUnit actualKPH = Metric.METRE.dividedBy(Metric.SECOND) + .dividedBy(3.6); assertEquals(generatedKPH, actualKPH); } @Test public void testPrefixes() { - final LinearUnit generatedKilometre = Metric.METRE.withPrefix(Metric.KILO); + final LinearUnit generatedKilometre = Metric.METRE + .withPrefix(Metric.KILO); final LinearUnit actualKilometre = Metric.METRE.times(1000); assertEquals(generatedKilometre, actualKilometre); } + + /** + * Tests converting an uncertain LinearUnitValue to a string. + * + * @since 2021-11-04 + */ + @Test + public void testValueToString1() { + final LinearUnitValue value = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(10, 0.24)); + + assertEquals("(10.0 ± 0.2) m", value.toString()); + assertEquals("(10.0 ± 0.2) m", value.toString(true)); + assertEquals("10.0 m", value.toString(false)); + } + + /** + * Tests converting a certain LinearUnitValue to a string. + * + * @since 2021-11-04 + */ + @Test + public void testValueToString2() { + final LinearUnitValue value = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(10, 0)); + + assertEquals("10.0 m", value.toString()); + assertEquals("(10.0 ± 0.0) m", value.toString(true)); + assertEquals("10.0 m", value.toString(false)); + } + + /** + * Tests converting an unnamed LinearUnitValue to a string. + * + * @since 2021-11-04 + */ + @Test + public void testValueToString3() { + final LinearUnitValue value = LinearUnitValue.of( + Metric.METRE.withName(NameSymbol.EMPTY), + UncertainDouble.of(10, 0.24)); + + assertEquals("10.0 unnamed unit (= 10.0 m)", value.toString(false)); + } + + /** + * Tests converting a named UnitValue to a string. + * + * @since 2021-11-04 + */ + @Test + public void testValueToString4() { + final UnitValue value = UnitValue.of(BritishImperial.FAHRENHEIT, 80); + + assertEquals("80.0 \u00B0F", value.toString()); + } + + /** + * Tests converting an unnamed UnitValue to a string. + * + * @since 2021-11-04 + */ + @Test + public void testValueToString5() { + final UnitValue value = UnitValue + .of(USCustomary.FAHRENHEIT.withName(NameSymbol.EMPTY), 50); + + assertEquals("50.0 unnamed unit (= 283.15 K)", value.toString()); + } } diff --git a/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java b/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java index 46afe77..d653848 100644 --- a/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java +++ b/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java @@ -31,7 +31,6 @@ import java.util.NoSuchElementException; import org.junit.jupiter.api.Test; -import sevenUnits.utils.ConditionalExistenceCollections; import sevenUnits.utils.ConditionalExistenceCollections.ConditionalExistenceIterator; /** diff --git a/src/test/java/sevenUnits/utils/ExpressionParserTest.java b/src/test/java/sevenUnits/utils/ExpressionParserTest.java index 29648ee..a954b12 100644 --- a/src/test/java/sevenUnits/utils/ExpressionParserTest.java +++ b/src/test/java/sevenUnits/utils/ExpressionParserTest.java @@ -18,37 +18,65 @@ package sevenUnits.utils; import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; -import sevenUnits.utils.ExpressionParser; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +// TODO add tests for expression-to-RPN and RPN-to-result /** - * A test for the {@code ExpressionParser} class. This is NOT part of this program's public API. + * A test for the {@code ExpressionParser} class. This is NOT part of this + * program's public API. * * @author Adrien Hopkins * @since 2019-03-22 * @since v0.2.0 */ class ExpressionParserTest { - private static final ExpressionParser<Integer> numberParser = new ExpressionParser.Builder<>(Integer::parseInt) - .addBinaryOperator("+", (o1, o2) -> o1 + o2, 0).addBinaryOperator("-", (o1, o2) -> o1 - o2, 0) - .addBinaryOperator("*", (o1, o2) -> o1 * o2, 1).addBinaryOperator("/", (o1, o2) -> o1 / o2, 1) - .addBinaryOperator("^", (o1, o2) -> (int) Math.pow(o1, o2), 2).build(); - + private static final ExpressionParser<Integer> numberParser = new ExpressionParser.Builder<>( + Integer::parseInt).addBinaryOperator("+", (o1, o2) -> o1 + o2, 0) + .addBinaryOperator("-", (o1, o2) -> o1 - o2, 0) + .addBinaryOperator("*", (o1, o2) -> o1 * o2, 1) + .addBinaryOperator("/", (o1, o2) -> o1 / o2, 1) + .addBinaryOperator("^", (o1, o2) -> (int) Math.pow(o1, o2), 2) + .build(); + /** - * Test method for {@link sevenUnits.utils.ExpressionParser#parseExpression(java.lang.String)}. + * The expressions used in the expression parsing tests */ - @Test - public void testParseExpression() { - // test parsing of expressions - assertEquals((int) numberParser.parseExpression("1 + 2 ^ 5 * 3"), 97); - assertEquals((int) numberParser.parseExpression("(1 + 2) ^ 5 * 3"), 729); - - // ensure it normally goes left to right - assertEquals((int) numberParser.parseExpression("1 + 2 + 3 + 4"), 10); - assertEquals((int) numberParser.parseExpression("12 - 4 - 3"), 5); - assertEquals((int) numberParser.parseExpression("12 - (4 - 3)"), 11); - assertEquals((int) numberParser.parseExpression("1 / 2 + 3"), 3); + private static final List<String> TEST_EXPRESSIONS = List.of( + // test parsing of expressions + "1 + 2 ^ 5 * 3", "(1 + 2) ^ 5 * 3", + "12 * 5 + (3 ^ (2 * 3) - 72) / (3 + 3 * 2)", + + // ensure it normally goes from left to right + "1 + 2 + 3 + 4", "12 - 4 - 3", "12 - (4 - 3)", "1 / 2 + 3"); + + /** + * The expected results for evaluating these expressions + */ + private static final int[] RESULTS = { 97, 729, 133, 10, 5, 11, 3 }; + + /** + * @return A stream of objects, where each one is an expression and the + * expected result + * @since 2021-09-27 + */ + private static final Stream<Arguments> testParseExpressionData() { + return IntStream.range(0, TEST_EXPRESSIONS.size()) + .mapToObj(i -> Arguments.of(TEST_EXPRESSIONS.get(i), RESULTS[i])); + } + + /** + * Test method for + * {@link sevenUnits.utils.ExpressionParser#parseExpression(java.lang.String)}. + */ + @ParameterizedTest + @MethodSource("testParseExpressionData") + public void testParseExpression(String expression, int value) { + assertEquals(value, numberParser.parseExpression(expression)); } - } diff --git a/src/test/java/sevenUnits/utils/ObjectProductTest.java b/src/test/java/sevenUnits/utils/ObjectProductTest.java index 13fd7ec..15ff277 100644 --- a/src/test/java/sevenUnits/utils/ObjectProductTest.java +++ b/src/test/java/sevenUnits/utils/ObjectProductTest.java @@ -30,7 +30,6 @@ import static sevenUnits.unit.Metric.Dimensions.VOLUME; import org.junit.jupiter.api.Test; import sevenUnits.unit.Metric; -import sevenUnits.utils.ObjectProduct; /** * Tests for {@link ObjectProduct} using BaseDimension as a test object. This is NOT part of this program's public API. diff --git a/src/test/java/sevenUnits/utils/UncertainDoubleTest.java b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java new file mode 100644 index 0000000..c891f20 --- /dev/null +++ b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java @@ -0,0 +1,90 @@ +/** + * Copyright (C) 2021 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package sevenUnits.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static sevenUnits.utils.UncertainDouble.fromString; +import static sevenUnits.utils.UncertainDouble.of; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +/** + * Tests for the UncertainDouble + * + * @author Adrien Hopkins + * @since 2021-11-29 + */ +class UncertainDoubleTest { + @Test + final void testCompareTo() { + assertTrue(of(2.0, 0.5).compareTo(of(2.0, 0.1)) == 0); + assertTrue(of(2.0, 0.5).compareTo(of(1.0, 0.1)) > 0); + assertTrue(of(2.0, 0.5).compareTo(of(3.0, 0.1)) < 0); + } + + @Test + final void testExactOperations() { + final UncertainDouble x = UncertainDouble.of(Math.PI, 0.1); + + // slightly different because roundoff errors + final UncertainDouble x1 = UncertainDouble.of(Math.PI + Math.E - Math.E, + 0.1); + final UncertainDouble x2 = UncertainDouble.of(Math.PI * Math.E / Math.E, + 0.1); + + // get results + final UncertainDouble result1 = x.plusExact(Math.E).minusExact(Math.E); + final UncertainDouble result2 = x.timesExact(Math.E) + .dividedByExact(Math.E); + + // test that these operations work & don't change uncertainty + assertEquals(x1, result1); + assertTrue(x.equivalent(result1)); + assertEquals(x2, result2); + assertTrue(x.equivalent(result2)); + + // exponents are different + assertEquals(Math.pow(Math.PI, Math.E), + x.toExponentExact(Math.E).value()); + } + + @Test + final void testFromString() { + // valid strings + assertEquals(of(2.0, 0.5), fromString("2.0 ± 0.5")); + assertEquals(of(2.0, 0.5), fromString("2.0 +- 0.5")); + assertEquals(of(2.0, 0.0), fromString("2.0")); + + // invalid strings + for (final String s : List.of("2.A", "A", "2.0 ± .", "± 3.5")) { + assertThrows(IllegalArgumentException.class, () -> fromString(s)); + } + + // back and forth + assertEquals("2.0 ± 0.5", of(2.0, 0.5).toString()); + assertEquals("2.0", of(2.0, 0).toString()); + } + + @Test + final void testHashCode() { + assertEquals(of(2.0, 0.5).hashCode(), fromString("2.0 ± 0.5").hashCode()); + } +} |