diff options
author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2025-06-15 19:42:01 -0500 |
---|---|---|
committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2025-06-15 19:42:01 -0500 |
commit | 2fdbc084fd1d78f0b7633db34460b1195de264f3 (patch) | |
tree | 4c908950d9b049394f8160b8159b498aec586ecc /src/test | |
parent | ed53492243ecad8d975401a97f5b634328ad2c71 (diff) | |
parent | bccb5b5e3452421c81c1fb58f83391ba6584807c (diff) |
See the tag 'v1.0.0' or the changelog for more information about this
release.
Diffstat (limited to 'src/test')
16 files changed, 1023 insertions, 557 deletions
diff --git a/src/test/java/sevenUnits/unit/MultiUnitTest.java b/src/test/java/sevenUnits/unit/MultiUnitTest.java deleted file mode 100644 index 949a1f1..0000000 --- a/src/test/java/sevenUnits/unit/MultiUnitTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright (C) 2020 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.unit; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; - -import org.junit.jupiter.api.Test; - -/** - * Tests related to the {@code MultiUnit}. - * - * @since 2020-10-03 - */ -class MultiUnitTest { - - /** - * Ensures that the {@code MultiUnit} can convert properly. - */ - @Test - final void testConvert() { - final Random rng = ThreadLocalRandom.current(); - final MultiUnit footInch = MultiUnit.of(BritishImperial.Length.FOOT, - BritishImperial.Length.INCH); - - assertEquals(1702.0, - footInch.convertTo(Metric.METRE.withPrefix(Metric.MILLI), - Arrays.asList(5.0, 7.0)), - 1.0); - - for (int i = 0; i < 1000; i++) { - final double feet = rng.nextInt(1000); - final double inches = rng.nextDouble() * 12; - final double millimetres = feet * 304.8 + inches * 25.4; - - final List<Double> feetAndInches = Metric.METRE - .withPrefix(Metric.MILLI).convertTo(footInch, millimetres); - assertEquals(feet, feetAndInches.get(0), 1e-10); - assertEquals(inches, feetAndInches.get(1), 1e-10); - } - } - - /** - * Test method for {@link sevenUnits.unit.MultiUnit#convertFromBase(double)}. - */ - @Test - final void testConvertFromBase() { - final Random rng = ThreadLocalRandom.current(); - final MultiUnit footInch = MultiUnit.of(BritishImperial.Length.FOOT, - BritishImperial.Length.INCH); - - // 1.7 m =~ 5' + 7" - final List<Double> values = footInch.convertFromBase(1.7018); - - assertEquals(5, values.get(0)); - assertEquals(7, values.get(1), 1e-12); - - for (int i = 0; i < 1000; i++) { - final double feet = rng.nextInt(1000); - final double inches = rng.nextDouble() * 12; - final double metres = feet * 0.3048 + inches * 0.0254; - - final List<Double> feetAndInches = footInch.convertFromBase(metres); - assertEquals(feet, feetAndInches.get(0), 1e-10); - assertEquals(inches, feetAndInches.get(1), 1e-10); - } - } - - /** - * Test method for - * {@link sevenUnits.unit.MultiUnit#convertToBase(java.util.List)}. - */ - @Test - final void testConvertToBase() { - final Random rng = ThreadLocalRandom.current(); - final MultiUnit footInch = MultiUnit.of(BritishImperial.Length.FOOT, - BritishImperial.Length.INCH); - - // 1.7 m =~ 5' + 7" - assertEquals(1.7018, footInch.convertToBase(Arrays.asList(5.0, 7.0)), - 1e-12); - - for (int i = 0; i < 1000; i++) { - final double feet = rng.nextInt(1000); - final double inches = rng.nextDouble() * 12; - final double metres = feet * 0.3048 + inches * 0.0254; - - assertEquals(metres, - footInch.convertToBase(Arrays.asList(feet, inches)), 1e-12); - } - } -} diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java index 9d650f0..3d6d663 100644 --- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java +++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Adrien Hopkins + * Copyright (C) 2019, 2021, 2022, 2024, 2025 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 @@ -23,20 +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; @@ -45,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 @@ -57,8 +58,8 @@ class UnitDatabaseTest { private V value; /** - * * @since 2021-10-07 + * @since v0.3.2 */ public SimpleEntry(K key, V value) { this.key = key; @@ -94,7 +95,7 @@ class UnitDatabaseTest { @Override public V setValue(V value) { - final V oldValue = this.value; + final var oldValue = this.value; this.value = value; return oldValue; } @@ -135,6 +136,7 @@ class UnitDatabaseTest { * @param value value in entry * @return entry * @since 2021-10-07 + * @since v0.3.2 */ private static <K, V> Map.Entry<K, V> entry(K key, V value) { return new SimpleEntry<>(key, value); @@ -146,14 +148,18 @@ class UnitDatabaseTest { * * @param loadTo database to load to * @param path path of file to load + * @return exceptions returned by file loading * @since 2021-10-04 + * @since v0.3.2 */ - private static void loadDimensionFile(UnitDatabase loadTo, String path) { - try (final InputStream testFile = UnitDatabaseTest.class + private static List<LoadingException> loadDimensionFile(UnitDatabase loadTo, + String path) { + try (final var 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(); } } @@ -163,26 +169,89 @@ class UnitDatabaseTest { * * @param loadTo database to load to * @param path path of file to load + * @return exceptions returned by file loading * @since 2021-09-22 + * @since v0.3.2 */ - private static void loadUnitsFile(UnitDatabase loadTo, String path) { - try (final InputStream testFile = UnitDatabaseTest.class + private static List<LoadingException> loadUnitsFile(UnitDatabase loadTo, + String path) { + try (final var 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(); } } + private static final Stream<Arguments> testEvaluateExpressionInvalid() { + return Stream.of(Arguments.of("K^K"), Arguments.of("1 + K")); + } + + private static final Stream<Arguments> testEvaluateExpressionValid() { + final var uncertainTwoThirds = UncertainDouble.of(2.0, 1.0) + .dividedBy(UncertainDouble.of(3.0, 1.0)); + 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 + 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))), + Arguments.of("2 J / 3 J", + LinearUnitValue.of(J.dividedBy(J), uncertainTwoThirds))); + } + + private static final Stream<Arguments> testFormatExpression() { + return Stream.of(Arguments.of("1*2", "1 * 2"), + Arguments.of("1/2", "1 / 2"), Arguments.of("1|2", "1 | 2"), + Arguments.of("1^2", "1 ^ 2"), Arguments.of("1 * 2", "1 * 2"), + Arguments.of("+1", "+1"), Arguments.of("-1", "-1"), + Arguments.of("1.1e+5", "1.1e+5"), + Arguments.of("1.25e-5", "1.25e-5")); + } + + /** + * 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 + * @since v0.3.2 */ - @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); @@ -191,27 +260,30 @@ class UnitDatabaseTest { 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); + } + + @ParameterizedTest + @MethodSource + public void testFormatExpression(String expression, String expected) { + assertEquals(expected, UnitDatabase.formatExpression(expression)); } /** * Test for {@link UnitDatabase#getUnit}, {@link UnitDatabase#getLinearUnit} * and {@link UnitDatabase#getLinearUnitValue}. - * + * * @since 2021-10-07 + * @since v0.3.2 */ @Test public void testGetUnit() { - final UnitDatabase database = new UnitDatabase(); + final var database = new UnitDatabase(); database.addUnit("m", Metric.METRE); database.addUnit("meter", Metric.METRE); @@ -239,14 +311,15 @@ class UnitDatabaseTest { /** * Confirms that operations that shouldn't function for infinite databases * throw an {@code IllegalStateException}. - * + * * @since 2019-05-03 + * @since v0.3.0 */ // @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); @@ -255,9 +328,8 @@ class UnitDatabaseTest { infiniteDatabase.addPrefix("B", B); infiniteDatabase.addPrefix("C", C); - final Set<Entry<String, Unit>> entrySet = infiniteDatabase.unitMap() - .entrySet(); - final Set<String> keySet = infiniteDatabase.unitMap().keySet(); + final var entrySet = infiniteDatabase.unitMap().entrySet(); + final var keySet = infiniteDatabase.unitMap().keySet(); assertThrows(IllegalStateException.class, () -> entrySet.toArray()); assertThrows(IllegalStateException.class, () -> keySet.toArray()); } @@ -267,18 +339,20 @@ class UnitDatabaseTest { * * @param num which file to test * @since 2021-10-04 + * @since v0.3.2 */ @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 RuntimeException e = assertThrows(RuntimeException.class, - () -> loadDimensionFile(database, filename)); + final var errs = loadDimensionFile(database, filename); + assertFalse(errs.isEmpty(), "no error from invalid file " + filename); + final var e = errs.get(0).problem(); assertTrue(e instanceof IllegalArgumentException || e instanceof NoSuchElementException); } @@ -288,27 +362,29 @@ class UnitDatabaseTest { * * @param num which file to test * @since 2021-09-27 + * @since v0.3.2 */ @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)); + final var database = new UnitDatabase(); + final var filename = String.format("/test-unitsfile-invalid%d.txt", num); + final var errs = loadUnitsFile(database, filename); + assertFalse(errs.isEmpty(), "no error from invalid file " + filename); + 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 + * @since v0.3.2 */ @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); @@ -321,27 +397,33 @@ class UnitDatabaseTest { /** * Tests loading a valid unitfile with some prefixes and no units. - * + * * @since 2021-09-22 + * @since v0.3.2 */ @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 + * @since v0.3.2 */ @Test public void testLoadingValidUnits() { - final UnitDatabase database = new UnitDatabase(); + final var database = new UnitDatabase(); database.addUnit("U", U); database.addUnit("V", V); @@ -357,21 +439,21 @@ class UnitDatabaseTest { 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); @@ -382,21 +464,21 @@ class UnitDatabaseTest { /** * Tests the iterator of the prefixless unit map. These tests are simple, as * the unit map iterator is simple. - * + * * @since 2021-10-07 + * @since v0.3.2 */ @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() - .iterator(); + 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<>(); @@ -418,13 +500,13 @@ class UnitDatabaseTest { /** * 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); @@ -439,29 +521,28 @@ class UnitDatabaseTest { 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 - .unitMapPrefixless(true); + final var database = new UnitDatabase(); + final var prefixlessUnits = database.unitMapPrefixless(true); database.addUnit("U", U); database.addUnit("V", V); @@ -478,13 +559,13 @@ class UnitDatabaseTest { /** * 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); @@ -517,7 +598,7 @@ class UnitDatabaseTest { @Test public void testToString() { - final UnitDatabase database = new UnitDatabase(); + final var database = new UnitDatabase(); database.addUnit("J", J); database.addUnit("K", J); @@ -538,14 +619,14 @@ class UnitDatabaseTest { /** * 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); @@ -560,13 +641,13 @@ class UnitDatabaseTest { // 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); @@ -579,14 +660,14 @@ class UnitDatabaseTest { /** * 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); @@ -595,19 +676,17 @@ class UnitDatabaseTest { 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 var NUM_UNITS = database.unitMapPrefixless(true).size(); + final var NUM_PREFIXES = database.prefixMap(true).size(); - final Iterator<String> nameIterator = database.unitMap().keySet() - .iterator(); - final Iterator<Entry<String, Unit>> entryIterator = database.unitMap() - .entrySet().iterator(); + final var nameIterator = database.unitMap().keySet().iterator(); + 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)) { @@ -616,9 +695,9 @@ class UnitDatabaseTest { } // 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()); @@ -628,13 +707,13 @@ class UnitDatabaseTest { } // 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()); } } @@ -646,14 +725,14 @@ 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); @@ -665,7 +744,7 @@ class UnitDatabaseTest { // 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); @@ -674,8 +753,61 @@ class UnitDatabaseTest { 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 + * @since v1.0.0 + */ + @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 + * @since v1.0.0 + */ + @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")); + } + } diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java index c93043b..fb21723 100644 --- a/src/test/java/sevenUnits/unit/UnitTest.java +++ b/src/test/java/sevenUnits/unit/UnitTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018 Adrien Hopkins + * Copyright (C) 2018, 2021, 2022, 2024, 2025 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 @@ -21,7 +21,6 @@ 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 java.math.RoundingMode; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; @@ -29,12 +28,11 @@ import org.junit.jupiter.api.Test; import sevenUnits.utils.DecimalComparison; import sevenUnits.utils.NameSymbol; -import sevenUnits.utils.UncertainDouble; /** * Testing the various Unit classes. This is NOT part of this program's public * API. - * + * * @author Adrien Hopkins * @since 2018-12-22 * @since v0.1.0 @@ -45,21 +43,25 @@ class UnitTest { @Test public void testAdditionAndSubtraction() { - final LinearUnit inch = Metric.METRE.times(0.0254) + final var inch = Metric.METRE.times(0.0254) .withName(NameSymbol.of("inch", "in")); - final LinearUnit foot = Metric.METRE.times(0.3048) + final var foot = Metric.METRE.times(0.3048) .withName(NameSymbol.of("foot", "ft")); - assertEquals(inch.plus(foot), Metric.METRE.times(0.3302)); - assertEquals(foot.minus(inch), Metric.METRE.times(0.2794)); + assertTrue( + inch.plus(foot).equalsApproximately(Metric.METRE.times(0.3302)), + String.format("Expected: %s, Actual: %s", inch.plus(foot), + Metric.METRE.times(0.3302))); + assertTrue( + foot.minus(inch).equalsApproximately(Metric.METRE.times(0.2794)), + String.format("Expected: %s, Actual: %s", foot.minus(inch), + Metric.METRE.times(0.2794))); // 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 var value1 = LinearUnitValue.getExact(Metric.METRE, 15); + final var value2 = LinearUnitValue.getExact(foot, 120); + final var value3 = LinearUnitValue.getExact(Metric.METRE, 0.5); + final var value4 = LinearUnitValue.getExact(Metric.KILOGRAM, 60); // make sure addition is done correctly assertEquals(51.576, value1.plus(value2).getValueExact(), 0.001); @@ -81,24 +83,24 @@ class UnitTest { @Test public void testConversion() { - final LinearUnit metre = Metric.METRE; + final var metre = Metric.METRE; final Unit inch = metre.times(0.0254); - final UnitValue value = UnitValue.of(inch, 75); + final var value = UnitValue.of(inch, 75); assertEquals(1.9, inch.convertTo(metre, 75), 0.01); assertEquals(1.9, value.convertTo(metre).getValue(), 0.01); // try random stuff - for (int i = 0; i < 1000; i++) { + for (var i = 0; i < 1000; i++) { // initiate random values - final double conversionFactor = UnitTest.rng.nextDouble() * 1000000; - final double testValue = UnitTest.rng.nextDouble() * 1000000; - final double expected = testValue * conversionFactor; + final var conversionFactor = UnitTest.rng.nextDouble() * 1000000; + final var testValue = UnitTest.rng.nextDouble() * 1000000; + final var expected = testValue * conversionFactor; // test final Unit unit = Metric.METRE.times(conversionFactor); - final double actual = unit.convertToBase(testValue); + final var actual = unit.convertToBase(testValue); assertEquals(actual, expected, expected * DecimalComparison.DOUBLE_EPSILON); @@ -107,7 +109,7 @@ class UnitTest { @Test public void testEquals() { - final LinearUnit metre = Metric.METRE; + final var metre = Metric.METRE; final Unit meter = Metric.BaseUnits.METRE.asLinearUnit(); assertEquals(metre, meter); @@ -127,19 +129,19 @@ class UnitTest { @Test public void testMultiplicationAndDivision() { // test unit-times-unit multiplication - final LinearUnit generatedJoule = Metric.KILOGRAM + final var generatedJoule = Metric.KILOGRAM .times(Metric.METRE.toExponent(2)) .dividedBy(Metric.SECOND.toExponent(2)); - final LinearUnit actualJoule = Metric.JOULE; + final var actualJoule = Metric.JOULE; assertEquals(generatedJoule, actualJoule); // test multiplication by conversion factors - final LinearUnit kilometre = Metric.METRE.times(1000); - final LinearUnit hour = Metric.SECOND.times(3600); - final LinearUnit generatedKPH = kilometre.dividedBy(hour); + final var kilometre = Metric.METRE.times(1000); + final var hour = Metric.SECOND.times(3600); + final var generatedKPH = kilometre.dividedBy(hour); - final LinearUnit actualKPH = Metric.METRE.dividedBy(Metric.SECOND) + final var actualKPH = Metric.METRE.dividedBy(Metric.SECOND) .dividedBy(3.6); assertEquals(generatedKPH, actualKPH); @@ -147,82 +149,9 @@ class UnitTest { @Test public void testPrefixes() { - final LinearUnit generatedKilometre = Metric.METRE - .withPrefix(Metric.KILO); - final LinearUnit actualKilometre = Metric.METRE.times(1000); + final var generatedKilometre = Metric.METRE.withPrefix(Metric.KILO); + final var 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, RoundingMode.HALF_EVEN)); - assertEquals("10.0 m", value.toString(false, RoundingMode.HALF_EVEN)); - } - - /** - * 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, RoundingMode.HALF_EVEN)); - assertEquals("10.0 m", value.toString(false, RoundingMode.HALF_EVEN)); - } - - /** - * 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, RoundingMode.HALF_EVEN)); - } - - /** - * 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/unit/UnitValueTest.java b/src/test/java/sevenUnits/unit/UnitValueTest.java new file mode 100644 index 0000000..3679703 --- /dev/null +++ b/src/test/java/sevenUnits/unit/UnitValueTest.java @@ -0,0 +1,240 @@ +/** + * Copyright (C) 2021, 2025 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.unit; + +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 java.math.RoundingMode; +import java.util.List; +import java.util.Objects; +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 sevenUnits.utils.NameSymbol; +import sevenUnits.utils.UncertainDouble; + +/** + * Tests for the UnitValue and LinearUnitValue classes + * + * @since v1.0.0 + */ +public final class UnitValueTest { + private static Stream<Arguments> testConvertToMultiple() { + return Stream.of( + Arguments.of( + LinearUnitValue.getExact(BritishImperial.Length.INCH, 64), + List.of(BritishImperial.Length.FOOT, + BritishImperial.Length.INCH), + List.of(5.0, 4.0)), + Arguments.of(LinearUnitValue.getExact(Metric.SECOND, 44102.5), + List.of(Metric.HOUR, Metric.MINUTE, Metric.SECOND), + List.of(12.0, 15.0, 2.5))); + } + + @ParameterizedTest + @MethodSource + public void testConvertToMultiple(LinearUnitValue valFrom, + List<LinearUnit> others, List<Double> expectedValues) { + final var actual = valFrom.convertToMultiple(others); + assertEquals(others.size(), expectedValues.size(), String.format( + "%s converted to %s had the wrong number of resulting units (expected: %d, actual: %d).", + valFrom, others, others.size(), actual.size())); + + for (var i = 0; i < others.size(); i++) { + final var expectedValue = LinearUnitValue.getExact(others.get(i), + expectedValues.get(i)); + assertTrue(expectedValue.equivalent(actual.get(i)), + String.format("Value %d: expected %s, actual %s.", i, + expectedValue, actual.get(i))); + } + } + + @Test + public void testConvertToMultipleErrors() { + assertThrows(IllegalArgumentException.class, + () -> LinearUnitValue.ONE.convertToMultiple(List.of())); + assertThrows(IllegalArgumentException.class, + () -> LinearUnitValue.ONE.convertToMultiple(List.of(Metric.METRE))); + } + + // I am intentionally testing whether or not equals gracefully returns false + // when it gets an argument of the wrong type + @SuppressWarnings("unlikely-arg-type") + @Test + public void testEqualsHashCode() { + final var v1 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(1.0, 0.01)); + final var v2 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(1.0, 0.01)); + final var v3 = LinearUnitValue.of(Metric.MILLIMETRE, + UncertainDouble.of(1000.0, 10.0)); + final var v4 = LinearUnitValue.of(Metric.MILLIMETRE, + UncertainDouble.of(1000.0, 20.0)); + + assertTrue(Objects.equals(v1, v2), + "Two identical values are not equal()"); + assertTrue(Objects.equals(v1.hashCode(), v2.hashCode()), + "Two identical values have different hash codes."); + assertTrue(Objects.equals(v1, v3), + "Two values with the same value but different units are not equal()"); + assertTrue(Objects.equals(v1.hashCode(), v3.hashCode()), + "Two values with the same value but different units have different hash codes."); + assertFalse(Objects.equals(v1, v4), + "Two values with the same value but different uncertainties are equal()"); + assertFalse(Objects.equals(v1, "Hello")); + assertFalse(v1.equals("Hello", true)); + } + + @Test + public void testEqualsNoFP() { + final var v1 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(1.0, 0.01)); + final var v2 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(1.0, 0.01)); + final var v3 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(1.0 + 5e-16, 0.01)); + assertTrue(v1.equals(v2, false)); + assertFalse(v1.equals(v3, false)); + assertTrue(v1.equals(v3, true)); + } + + @Test + public void testOperations() { + final var v1 = LinearUnitValue.getExact(Metric.METRE, 2.0); + final var v2 = LinearUnitValue.getExact(Metric.METRE, 4.0); + + assertEquals(v2, v1.times(2)); + assertEquals(v1, v2.dividedBy(2)); + assertEquals(LinearUnitValue.getExact(Metric.SQUARE_METRE, 8.0), + v1.times(v2)); + assertEquals(LinearUnitValue.getExact(Metric.ONE, 0.5), v1.dividedBy(v2)); + assertEquals(LinearUnitValue.getExact(Metric.SQUARE_METRE, 4.0), + v1.toExponent(2)); + assertEquals(LinearUnitValue.getExact(Metric.SQUARE_METRE, 4.0), + v1.toExponentRounded(2.0)); + } + + @Test + public void testValueEquivalent() { + final var v1 = LinearUnitValue.of(BritishImperial.Length.INCH, + UncertainDouble.of(1.0, 0.0)); + final var v2 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(0.0255, 0.0)); + assertFalse(v1.equivalent(v2)); + + final var v3 = LinearUnitValue.of(BritishImperial.Length.INCH, + UncertainDouble.of(1.0, 1.0)); + final var v4 = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(0.0255, 0.025)); + assertTrue(v3.equivalent(v4)); + } + + @Test + public void testValueEquivalentErrors() { + final var v1 = LinearUnitValue.of(BritishImperial.Length.INCH, + UncertainDouble.of(1.0, 0.0)); + final var v2 = LinearUnitValue.of(BritishImperial.CALORIE, + UncertainDouble.of(1.0, 0.0)); + assertFalse(v1.equivalent(v2)); + + assertFalse(v1.equivalent(null)); + } + + /** + * Tests converting an uncertain LinearUnitValue to a string. + * + * @since 2021-11-04 + * @since v0.3.2 + */ + @Test + public void testValueToString1() { + final var 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, RoundingMode.HALF_EVEN)); + assertEquals("10.0 m", value.toString(false, RoundingMode.HALF_EVEN)); + } + + /** + * Tests converting a certain LinearUnitValue to a string. + * + * @since 2021-11-04 + * @since v0.3.2 + */ + @Test + public void testValueToString2() { + final var value = LinearUnitValue.of(Metric.METRE, + UncertainDouble.of(10, 0)); + + assertEquals("10.0 m", value.toString()); + assertEquals("(10.0 ± 0.0) m", + value.toString(true, RoundingMode.HALF_EVEN)); + assertEquals("10.0 m", value.toString(false, RoundingMode.HALF_EVEN)); + } + + /** + * Tests converting an unnamed LinearUnitValue to a string. + * + * @since 2021-11-04 + * @since v0.3.2 + */ + @Test + public void testValueToString3() { + final var value = LinearUnitValue.of( + Metric.METRE.withName(NameSymbol.EMPTY), + UncertainDouble.of(10, 0.24)); + + assertEquals("10.0 unnamed unit (= 10.0 m)", + value.toString(false, RoundingMode.HALF_EVEN)); + } + + /** + * Tests converting a named UnitValue to a string. + * + * @since 2021-11-04 + * @since v0.3.2 + */ + @Test + public void testValueToString4() { + final var value = UnitValue.of(BritishImperial.FAHRENHEIT, 80); + + assertEquals("80.0 \u00B0F", value.toString()); + } + + /** + * Tests converting an unnamed UnitValue to a string. + * + * @since 2021-11-04 + * @since v0.3.2 + */ + @Test + public void testValueToString5() { + final var 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 868385b..8711847 100644 --- a/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java +++ b/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Adrien Hopkins + * Copyright (C) 2019, 2021, 2022, 2024, 2025 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 @@ -23,7 +23,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -38,31 +37,34 @@ import sevenUnits.utils.ConditionalExistenceCollections.ConditionalExistenceIter * normal operations on conditional existence collections and ensures that * elements that do not pass the existence condition are not included in the * results. - * + * * @author Adrien Hopkins * @since 2019-10-16 + * @since v0.3.0 */ class ConditionalExistenceCollectionsTest { /** * The returned iterator ignores elements that don't start with "a". - * + * * @return test iterator * @since 2019-10-17 + * @since v0.3.0 */ ConditionalExistenceIterator<String> getTestIterator() { final List<String> items = Arrays.asList("aa", "ab", "ba"); - final Iterator<String> it = items.iterator(); - final ConditionalExistenceIterator<String> cit = (ConditionalExistenceIterator<String>) ConditionalExistenceCollections + final var it = items.iterator(); + final var cit = (ConditionalExistenceIterator<String>) ConditionalExistenceCollections .conditionalExistenceIterator(it, s -> s.startsWith("a")); return cit; } /** * The returned map ignores mappings where the value is zero. - * + * * @return map to be used for test data * @since 2019-10-16 + * @since v0.3.0 */ Map<String, Integer> getTestMap() { final Map<String, Integer> map = new HashMap<>(); @@ -76,60 +78,49 @@ class ConditionalExistenceCollectionsTest { return conditionalMap; } - /** - * Test method for the ConditionalExistenceMap's containsKey method. - */ + /** Test method for the ConditionalExistenceMap's containsKey method. */ @Test void testContainsKeyObject() { - final Map<String, Integer> map = this.getTestMap(); + final var map = this.getTestMap(); assertTrue(map.containsKey("one")); assertTrue(map.containsKey("ten")); assertFalse(map.containsKey("five")); assertFalse(map.containsKey("zero")); } - /** - * Test method for the ConditionalExistenceMap's containsValue method. - */ + /** Test method for the ConditionalExistenceMap's containsValue method. */ @Test void testContainsValueObject() { - final Map<String, Integer> map = this.getTestMap(); + final var map = this.getTestMap(); assertTrue(map.containsValue(1)); assertTrue(map.containsValue(10)); assertFalse(map.containsValue(5)); assertFalse(map.containsValue(0)); } - /** - * Test method for the ConditionalExistenceMap's entrySet method. - */ + /** Test method for the ConditionalExistenceMap's entrySet method. */ @Test void testEntrySet() { - final Map<String, Integer> map = this.getTestMap(); + final var map = this.getTestMap(); for (final Entry<String, Integer> e : map.entrySet()) { assertTrue(e.getValue() != 0); } } - /** - * Test method for the ConditionalExistenceMap's get method. - */ + /** Test method for the ConditionalExistenceMap's get method. */ @Test void testGetObject() { - final Map<String, Integer> map = this.getTestMap(); + final var map = this.getTestMap(); assertEquals(1, map.get("one")); assertEquals(10, map.get("ten")); assertEquals(null, map.get("five")); assertEquals(null, map.get("zero")); } - /** - * Test method for the ConditionalExistenceCollection's iterator. - */ + /** Test method for the ConditionalExistenceCollection's iterator. */ @Test void testIterator() { - final ConditionalExistenceIterator<String> testIterator = this - .getTestIterator(); + final var testIterator = this.getTestIterator(); assertTrue(testIterator.hasNext); assertTrue(testIterator.hasNext()); @@ -147,22 +138,18 @@ class ConditionalExistenceCollectionsTest { assertThrows(NoSuchElementException.class, testIterator::next); } - /** - * Test method for the ConditionalExistenceMap's keySet operation. - */ + /** Test method for the ConditionalExistenceMap's keySet operation. */ @Test void testKeySet() { - final Map<String, Integer> map = this.getTestMap(); - assertFalse(map.keySet().contains("zero")); + final var map = this.getTestMap(); + assertFalse(map.containsKey("zero")); } - /** - * Test method for the ConditionalExistenceMap's values operation. - */ + /** Test method for the ConditionalExistenceMap's values operation. */ @Test void testValues() { - final Map<String, Integer> map = this.getTestMap(); - assertFalse(map.values().contains(0)); + final var map = this.getTestMap(); + assertFalse(map.containsValue(0)); } } diff --git a/src/test/java/sevenUnits/utils/ExpressionParserTest.java b/src/test/java/sevenUnits/utils/ExpressionParserTest.java index 3a95285..2e0b4b0 100644 --- a/src/test/java/sevenUnits/utils/ExpressionParserTest.java +++ b/src/test/java/sevenUnits/utils/ExpressionParserTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2019 Adrien Hopkins + * Copyright (C) 2019, 2021, 2024, 2025 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 @@ -17,6 +17,7 @@ package sevenUnits.utils; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.List; import java.util.stream.IntStream; @@ -26,11 +27,10 @@ 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. - * + * * @author Adrien Hopkins * @since 2019-03-22 * @since v0.2.0 @@ -39,13 +39,13 @@ 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(); + .addUnaryOperator("neg", o1 -> -o1, 1) + .addBinaryOperator("*", (o1, o2) -> o1 * o2, 2) + .addBinaryOperator("/", (o1, o2) -> o1 / o2, 2) + .addUnaryOperator("recip", o1 -> 1 / o1, 3) + .addBinaryOperator("^", (o1, o2) -> (int) Math.pow(o1, o2), 4).build(); - /** - * The expressions used in the expression parsing tests - */ + /** The expressions used in the expression parsing tests */ private static final List<String> TEST_EXPRESSIONS = List.of( // test parsing of expressions "1 + 2 ^ 5 * 3", "(1 + 2) ^ 5 * 3", @@ -54,21 +54,81 @@ class ExpressionParserTest { // 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 - */ + /** The expected results for evaluating these expressions */ private static final int[] RESULTS = { 97, 729, 133, 10, 5, 11, 3 }; + private static final Stream<Arguments> testConvertExpressionToRPN() { + return Stream.of(Arguments.of("1 + 2 ^ 5 * 3", "1 2 5 ^ 3 * +"), + Arguments.of("(1 + 2) ^ 5 * 3", "1 2 + 5 ^ 3 *"), + Arguments.of("12 * 5 + (3 ^ (2 * 3) - 72) / (3 + 3 * 2)", + "12 5 * 3 2 3 * ^ 72 - 3 3 2 * + / +"), + Arguments.of("1 + 2 + 3 + 4", "1 2 + 3 + 4 +"), + Arguments.of("12 - 4 - 3", "12 4 - 3 -"), + Arguments.of("12 - (4 - 3)", "12 4 3 - -"), + Arguments.of("1 / 2 + 3", "1 2 / 3 +"), Arguments.of("12", "12"), + Arguments.of("2 * 3 + 4", "2 3 * 4 +"), + Arguments.of("(2 * 3) + 4", "2 3 * 4 +"), + Arguments.of("2 * 3 - 4", "2 3 * 4 -"), + Arguments.of("(2 * 3) - 4", "2 3 * 4 -"), + Arguments.of("2 * (3 + 4)", "2 3 4 + *"), + Arguments.of("2 * (3 - 4)", "2 3 4 - *"), + Arguments.of("neg 2", "2 neg"), + Arguments.of("1 + neg 2", "1 2 neg +")); + } + + private static final Stream<String> testInvalidExpression() { + return Stream.of("+", "1 +", "1 + * 2", "1 (+ 1)", "neg"); + } + + private static final Stream<String> testInvalidRPN() { + return Stream.of("+", "1 +", "1 + * 2", "1 * 2", "1 2", "neg"); + } + /** * @return A stream of objects, where each one is an expression and the * expected result * @since 2021-09-27 + * @since v0.3.2 */ private static final Stream<Arguments> testParseExpressionData() { return IntStream.range(0, TEST_EXPRESSIONS.size()) .mapToObj(i -> Arguments.of(TEST_EXPRESSIONS.get(i), RESULTS[i])); } + private static final Stream<Arguments> testParseRPN() { + return Stream.of(Arguments.of("1 2 5 ^ 3 * +", 97), + Arguments.of("1 2 + 5 ^ 3 *", 729), + Arguments.of("12 5 * 3 2 3 * ^ 72 - 3 3 2 * + / +", 133), + Arguments.of("1 2 + 3 + 4 +", 10), Arguments.of("12 4 - 3 -", 5), + Arguments.of("12 4 3 - -", 11), Arguments.of("1 2 / 3 +", 3), + Arguments.of("12", 12), Arguments.of("2 3 * 4 +", 10), + Arguments.of("2 3 * 4 -", 2), Arguments.of("2 3 4 + *", 14), + Arguments.of("2 3 4 - *", -2), Arguments.of("2 neg", -2), + Arguments.of("1 2 neg +", -1)); + } + + @ParameterizedTest + @MethodSource + public void testConvertExpressionToRPN(String expression, + String expectedRPN) { + assertEquals(expectedRPN, + numberParser.convertExpressionToReversePolish(expression)); + } + + @ParameterizedTest + @MethodSource + public void testInvalidExpression(String expression) { + assertThrows(RuntimeException.class, + () -> numberParser.convertExpressionToReversePolish(expression)); + } + + @ParameterizedTest + @MethodSource + public void testInvalidRPN(String expressionRPN) { + assertThrows(RuntimeException.class, + () -> numberParser.parseReversePolishExpression(expressionRPN)); + } + /** * Test method for * {@link sevenUnits.utils.ExpressionParser#parseExpression(java.lang.String)}. @@ -78,4 +138,11 @@ class ExpressionParserTest { public void testParseExpression(String expression, int value) { assertEquals(value, numberParser.parseExpression(expression)); } + + @ParameterizedTest + @MethodSource + public void testParseRPN(String expressionRPN, int value) { + assertEquals(value, + numberParser.parseReversePolishExpression(expressionRPN)); + } } diff --git a/src/test/java/sevenUnits/utils/NameSymbolTest.java b/src/test/java/sevenUnits/utils/NameSymbolTest.java new file mode 100644 index 0000000..f8843e0 --- /dev/null +++ b/src/test/java/sevenUnits/utils/NameSymbolTest.java @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2025 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.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +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; + +/** + * Tests for the {@link NameSymbol} class. + * + * @since v1.0.0 + */ +class NameSymbolTest { + private static Stream<Arguments> testEqualsHashCode() { + return Stream.of( + Arguments.of(NameSymbol.ofName("test"), NameSymbol.ofName("test"), + true), + Arguments.of(NameSymbol.ofName("a"), NameSymbol.ofName("b"), false), + Arguments.of(NameSymbol.ofSymbol("test"), + NameSymbol.ofSymbol("test"), true), + Arguments.of(NameSymbol.ofSymbol("a"), NameSymbol.ofSymbol("b"), + false), + Arguments.of(NameSymbol.ofName("test"), NameSymbol.ofSymbol("test"), + false), + Arguments.of(NameSymbol.of("main", "s"), NameSymbol.of("main", "s"), + true), + Arguments.of(NameSymbol.of("main", "s"), + NameSymbol.of("main", "s", "m"), false), + Arguments.of(new NameSymbol(null, null, new HashSet<>()), + new NameSymbol(null, null, new HashSet<>()), true), + Arguments.of( + new NameSymbol(Optional.of("main"), Optional.of("s"), + new HashSet<>()), + new NameSymbol(null, null, new HashSet<>()), false), + Arguments.of(new NameSymbol(null, null, new HashSet<>()), + new NameSymbol(Optional.of("main"), Optional.of("s"), + new HashSet<>()), + false), + Arguments.of( + new NameSymbol(Optional.of("main"), null, new HashSet<>()), + new NameSymbol(Optional.of("main"), Optional.of("s"), + new HashSet<>()), + false)); + } + + @Test + public void testCreate() { + final Set<String> names = Set.of("a", "b", "c"); + final var ns = NameSymbol.ofNullable(null, null, names); + assertTrue(ns.getPrimaryName().isPresent(), + "NameSymbol created without primary name."); + assertTrue(names.contains(ns.getPrimaryName().orElseThrow()), + String.format("Primary name (%s) was not obtained from names set.", + ns.getPrimaryName())); + assertFalse( + ns.getOtherNames().contains(ns.getPrimaryName().orElseThrow()), + String.format("Primary name (%s) was included in other names set.", + ns.getPrimaryName())); + assertEquals(Set.of("a", "b", "c"), names, + "names input was changed by ofNullable()"); + } + + /** + * Tests that two NameSymbols are or are not equal. If they are equal, also + * ensures they have the same hash code. + * + * @param a first NameSymbol to test + * @param b second NameSymbol to test + * @param equal true iff a should be equal to be, otherwise false + */ + @ParameterizedTest + @MethodSource + public void testEqualsHashCode(NameSymbol a, NameSymbol b, boolean equal) { + if (equal) { + assertTrue(Objects.equals(a, b)); + assertEquals(a.hashCode(), b.hashCode(), + "Equal NameSymbol instances have different hash codes."); + } else { + assertFalse(Objects.equals(a, b)); + } + } +} diff --git a/src/test/java/sevenUnits/utils/ObjectProductTest.java b/src/test/java/sevenUnits/utils/ObjectProductTest.java index 8c6b353..7c5df88 100644 --- a/src/test/java/sevenUnits/utils/ObjectProductTest.java +++ b/src/test/java/sevenUnits/utils/ObjectProductTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018 Adrien Hopkins + * Copyright (C) 2018, 2021, 2024, 2025 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 @@ -34,7 +34,7 @@ import sevenUnits.unit.Metric; /** * Tests for {@link ObjectProduct} using BaseDimension as a test object. This is * NOT part of this program's public API. - * + * * @author Adrien Hopkins * @since 2018-12-12 * @since v0.1.0 @@ -42,7 +42,7 @@ import sevenUnits.unit.Metric; class ObjectProductTest { /** * Tests {@link UnitDimension#equals} - * + * * @since 2018-12-12 * @since v0.1.0 */ @@ -54,7 +54,7 @@ class ObjectProductTest { /** * Tests {@code UnitDimension}'s exponentiation - * + * * @since 2019-01-15 * @since v0.1.0 */ @@ -66,7 +66,7 @@ class ObjectProductTest { /** * Tests {@code UnitDimension}'s multiplication and division. - * + * * @since 2018-12-12 * @since v0.1.0 */ diff --git a/src/test/java/sevenUnits/utils/SemanticVersionTest.java b/src/test/java/sevenUnits/utils/SemanticVersionTest.java index 1e59ae3..5b74812 100644 --- a/src/test/java/sevenUnits/utils/SemanticVersionTest.java +++ b/src/test/java/sevenUnits/utils/SemanticVersionTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 Adrien Hopkins + * Copyright (C) 2022, 2024, 2025 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 @@ -35,12 +35,14 @@ import org.junit.jupiter.api.Test; * Tests for {@link SemanticVersionNumber} * * @since 2022-02-19 + * @since v0.4.0 */ public final class SemanticVersionTest { /** * Test for {@link SemanticVersionNumber#compatible} - * + * * @since 2022-02-20 + * @since v0.4.0 */ @Test public void testCompatibility() { @@ -64,38 +66,37 @@ public final class SemanticVersionTest { /** * Tests {@link SemanticVersionNumber#toString} for complex version numbers - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testComplexToString() { - final SemanticVersionNumber v1 = builder(1, 2, 3).preRelease(1, 2, 3) - .build(); + final var v1 = builder(1, 2, 3).preRelease(1, 2, 3).build(); assertEquals("1.2.3-1.2.3", v1.toString()); - final SemanticVersionNumber v2 = builder(4, 5, 6).preRelease("abc", 123) + final var v2 = builder(4, 5, 6).preRelease("abc", 123) .buildMetadata("2022-02-19").build(); assertEquals("4.5.6-abc.123+2022-02-19", v2.toString()); - final SemanticVersionNumber v3 = builder(1, 0, 0) - .preRelease("x-y-z", "--").build(); + final var v3 = builder(1, 0, 0).preRelease("x-y-z", "--").build(); assertEquals("1.0.0-x-y-z.--", v3.toString()); } /** * Tests that complex version can be created and their parts read - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testComplexVersions() { - final SemanticVersionNumber v1 = builder(1, 2, 3).preRelease(1, 2, 3) - .build(); + final var v1 = builder(1, 2, 3).preRelease(1, 2, 3).build(); assertEquals(1, v1.majorVersion()); assertEquals(2, v1.minorVersion()); assertEquals(3, v1.patchVersion()); assertEquals(List.of("1", "2", "3"), v1.preReleaseIdentifiers()); assertEquals(List.of(), v1.buildMetadata()); - final SemanticVersionNumber v2 = builder(4, 5, 6).preRelease("abc", 123) + final var v2 = builder(4, 5, 6).preRelease("abc", 123) .buildMetadata("2022-02-19").build(); assertEquals(4, v2.majorVersion()); assertEquals(5, v2.minorVersion()); @@ -103,8 +104,7 @@ public final class SemanticVersionTest { assertEquals(List.of("abc", "123"), v2.preReleaseIdentifiers()); assertEquals(List.of("2022-02-19"), v2.buildMetadata()); - final SemanticVersionNumber v3 = builder(1, 0, 0) - .preRelease("x-y-z", "--").build(); + final var v3 = builder(1, 0, 0).preRelease("x-y-z", "--").build(); assertEquals(1, v3.majorVersion()); assertEquals(0, v3.minorVersion()); assertEquals(0, v3.patchVersion()); @@ -114,8 +114,9 @@ public final class SemanticVersionTest { /** * Test that semantic version strings can be parsed correctly - * + * * @since 2022-02-19 + * @since v0.4.0 * @see SemanticVersionNumber#fromString * @see SemanticVersionNumber#isValidVersionString */ @@ -153,9 +154,7 @@ public final class SemanticVersionTest { "Could not parse 1.2.3-abc.56.def+2022abc99"); } - /** - * Ensures it is impossible to create invalid version numbers - */ + /** Ensures it is impossible to create invalid version numbers */ @Test public void testInvalidVersionNumbers() { // stableVersion() @@ -199,7 +198,7 @@ public final class SemanticVersionTest { assertThrows(IllegalArgumentException.class, () -> builder(-3, 0, 7), "Negative major version number tolerated by builder"); - final SemanticVersionNumber.Builder testBuilder = builder(1, 2, 3); + final var testBuilder = builder(1, 2, 3); // note: builder.buildMetadata(null) doesn't even compile lol // builder.buildMetadata assertThrows(NullPointerException.class, @@ -265,8 +264,9 @@ public final class SemanticVersionTest { /** * Test for {@link SemanticVersionNumber#isStable} - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testIsStable() { @@ -288,29 +288,27 @@ public final class SemanticVersionTest { * {@link SemanticVersionNumber#compareTo} according to official rules. Tests * all of the versions compared in section 11 of the SemVer 2.0.0 document * and some more. - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testOrder() { - final SemanticVersionNumber v100a = builder(1, 0, 0).preRelease("alpha") - .build(); // 1.0.0-alpha - final SemanticVersionNumber v100a1 = preRelease(1, 0, 0, "alpha", 1); // 1.0.0-alpha.1 - final SemanticVersionNumber v100ab = builder(1, 0, 0) - .preRelease("alpha", "beta").build(); // 1.0.0-alpha.beta - final SemanticVersionNumber v100b = builder(1, 0, 0).preRelease("beta") - .build(); // 1.0.0-alpha - final SemanticVersionNumber v100b2 = preRelease(1, 0, 0, "beta", 2); // 1.0.0-beta.2 - final SemanticVersionNumber v100b11 = preRelease(1, 0, 0, "beta", 11); // 1.0.0-beta.11 - final SemanticVersionNumber v100rc1 = preRelease(1, 0, 0, "rc", 1); // 1.0.0-rc.1 - final SemanticVersionNumber v100 = stableVersion(1, 0, 0); - final SemanticVersionNumber v100plus = builder(1, 0, 0) + final var v100a = builder(1, 0, 0).preRelease("alpha").build(); // 1.0.0-alpha + final var v100a1 = preRelease(1, 0, 0, "alpha", 1); // 1.0.0-alpha.1 + final var v100ab = builder(1, 0, 0).preRelease("alpha", "beta").build(); // 1.0.0-alpha.beta + final var v100b = builder(1, 0, 0).preRelease("beta").build(); // 1.0.0-alpha + final var v100b2 = preRelease(1, 0, 0, "beta", 2); // 1.0.0-beta.2 + final var v100b11 = preRelease(1, 0, 0, "beta", 11); // 1.0.0-beta.11 + final var v100rc1 = preRelease(1, 0, 0, "rc", 1); // 1.0.0-rc.1 + final var v100 = stableVersion(1, 0, 0); + final var v100plus = builder(1, 0, 0) .buildMetadata("blah", "blah", "blah").build(); // 1.0.0+blah.blah.blah - final SemanticVersionNumber v200 = stableVersion(2, 0, 0); - final SemanticVersionNumber v201 = stableVersion(2, 0, 1); - final SemanticVersionNumber v210 = stableVersion(2, 1, 0); - final SemanticVersionNumber v211 = stableVersion(2, 1, 1); - final SemanticVersionNumber v300 = stableVersion(3, 0, 0); + final var v200 = stableVersion(2, 0, 0); + final var v201 = stableVersion(2, 0, 1); + final var v210 = stableVersion(2, 1, 0); + final var v211 = stableVersion(2, 1, 1); + final var v300 = stableVersion(3, 0, 0); // test order of version numbers assertTrue(v100a.compareTo(v100a1) < 0, "1.0.0-alpha >= 1.0.0-alpha.1"); @@ -348,17 +346,18 @@ public final class SemanticVersionTest { /** * Tests that simple stable versions can be created and their parts read - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testSimpleStableVersions() { - final SemanticVersionNumber v100 = stableVersion(1, 0, 0); + final var v100 = stableVersion(1, 0, 0); assertEquals(1, v100.majorVersion()); assertEquals(0, v100.minorVersion()); assertEquals(0, v100.patchVersion()); - final SemanticVersionNumber v925 = stableVersion(9, 2, 5); + final var v925 = stableVersion(9, 2, 5); assertEquals(9, v925.majorVersion()); assertEquals(2, v925.minorVersion()); assertEquals(5, v925.patchVersion()); @@ -367,26 +366,28 @@ public final class SemanticVersionTest { /** * Tests that {@link SemanticVersionNumber#toString} works for simple version * numbers - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testSimpleToString() { - final SemanticVersionNumber v100 = stableVersion(1, 0, 0); + final var v100 = stableVersion(1, 0, 0); assertEquals("1.0.0", v100.toString()); - final SemanticVersionNumber v845a1 = preRelease(8, 4, 5, "alpha", 1); + final var v845a1 = preRelease(8, 4, 5, "alpha", 1); assertEquals("8.4.5-alpha.1", v845a1.toString()); } /** * Tests that simple unstable versions can be created and their parts read - * + * * @since 2022-02-19 + * @since v0.4.0 */ @Test public void testSimpleUnstableVersions() { - final SemanticVersionNumber v350a1 = preRelease(3, 5, 0, "alpha", 1); + final var v350a1 = preRelease(3, 5, 0, "alpha", 1); assertEquals(3, v350a1.majorVersion(), "Incorrect major version for v3.5.0a1"); assertEquals(5, v350a1.minorVersion(), diff --git a/src/test/java/sevenUnits/utils/UncertainDoubleTest.java b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java index 36b373b..733a308 100644 --- a/src/test/java/sevenUnits/utils/UncertainDoubleTest.java +++ b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2021 Adrien Hopkins + * Copyright (C) 2021, 2022, 2024, 2025 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 @@ -32,11 +32,10 @@ import org.junit.jupiter.api.Test; * * @author Adrien Hopkins * @since 2021-11-29 + * @since v0.3.2 */ class UncertainDoubleTest { - /** - * Ensures that the compareTo function behaves correctly. - */ + /** Ensures that the compareTo function behaves correctly. */ @Test final void testCompareTo() { assertTrue(of(2.0, 0.5).compareTo(of(2.0, 0.1)) == 0); @@ -44,23 +43,18 @@ class UncertainDoubleTest { assertTrue(of(2.0, 0.5).compareTo(of(3.0, 0.1)) < 0); } - /** - * Tests the ___exact operations - */ + /** Tests the ___exact operations */ @Test final void testExactOperations() { - final UncertainDouble x = UncertainDouble.of(Math.PI, 0.1); + final var 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); + final var x1 = UncertainDouble.of(Math.PI + Math.E - Math.E, 0.1); + final var 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); + final var result1 = x.plusExact(Math.E).minusExact(Math.E); + final var result2 = x.timesExact(Math.E).dividedByExact(Math.E); // test that these operations work & don't change uncertainty assertEquals(x1, result1); @@ -75,36 +69,35 @@ class UncertainDoubleTest { /** * Test for {@link UncertainDouble#fromRoundedString} - * + * * @since 2022-04-18 + * @since v0.4.0 */ @Test final void testFromRoundedString() { assertEquals(of(12345.678, 0.001), fromRoundedString("12345.678")); } - /** - * Test for {@link UncertainDouble#fromString} - */ + /** Test for {@link UncertainDouble#fromString} */ @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.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")) { + 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 ± 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()); + assertEquals(of(2.0, 0.5).hashCode(), fromString("2.0 ± 0.5").hashCode()); } } diff --git a/src/test/java/sevenUnitsGUI/I18nTest.java b/src/test/java/sevenUnitsGUI/I18nTest.java new file mode 100644 index 0000000..2f90d76 --- /dev/null +++ b/src/test/java/sevenUnitsGUI/I18nTest.java @@ -0,0 +1,95 @@ +/** + * Copyright (C) 2025 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 sevenUnitsGUI; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +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; + +/** + * Tests for the internationalization system. + * + * @since v1.0.0 + */ +class I18nTest { + private static final Stream<String> testLocaleSupported() { + return Stream.of("en", "fr"); + } + + private static final Stream<Arguments> testLocalization() { + return Stream.of(Arguments.of("tv.title", "en", "7Units [v]"), + Arguments.of("tv.title", "fr", "7Unités [v]"), + Arguments.of("tv.convert_units.title", "en", "Convert Units"), + Arguments.of("tv.convert_units.title", "fr", "Convertir Unités")); + } + + /** + * Tests that the default locale is supported. + * + * @since v1.0.0 + * @see Presenter#DEFAULT_LOCALE + */ + @Test + void testDefaultLocaleSupported() { + final var p = new Presenter(new ViewBot()); + assertNotNull(p.locales.get(Presenter.DEFAULT_LOCALE), + "Default locale is not supported."); + } + + /** + * Ensures that the system supports the provided locale. + * + * @param localeName locale to test for support + * + * @since 2025-06-04 + * @since v1.0.0 + */ + @ParameterizedTest + @MethodSource + void testLocaleSupported(String localeName) { + final var p = new Presenter(new ViewBot()); + assertNotNull(p.locales.get(localeName), + "Locale \"" + localeName + "\" is not supported."); + } + + /** + * Tests that the system can correctly localize text, using the default + * locales. + * + * @param key key of text to localize + * @param locale locale to use + * @param expected expected value of output text + * + * @since 2025-06-04 + * @since v1.0.0 + */ + @ParameterizedTest + @MethodSource + void testLocalization(String key, String locale, String expected) { + final var p = new Presenter(new ViewBot()); + p.setUserLocale(locale); + final var actual = p.getLocalizedText(key); + assertEquals(expected, actual); + } + +} diff --git a/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java b/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java index 476e407..ead5f4a 100644 --- a/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java +++ b/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 Adrien Hopkins + * Copyright (C) 2022, 2024, 2025 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 @@ -31,15 +31,15 @@ import sevenUnits.unit.Metric; /** * Tests for the default prefix repetition rules. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ class PrefixRepetitionTest { /** * Ensures that the complex repetition rule disallows invalid prefix lists. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testInvalidComplexRepetition() { @@ -57,9 +57,9 @@ class PrefixRepetitionTest { /** * Tests the {@code NO_REPETITION} rule. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testNoRepetition() { @@ -71,9 +71,9 @@ class PrefixRepetitionTest { /** * Tests the {@code NO_RESTRICTION} rule. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testNoRestriction() { @@ -85,9 +85,9 @@ class PrefixRepetitionTest { /** * Ensures that the complex repetition rule allows valid prefix lists. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testValidComplexRepetition() { diff --git a/src/test/java/sevenUnitsGUI/PrefixSearchTest.java b/src/test/java/sevenUnitsGUI/PrefixSearchTest.java index 305d0d7..00dd960 100644 --- a/src/test/java/sevenUnitsGUI/PrefixSearchTest.java +++ b/src/test/java/sevenUnitsGUI/PrefixSearchTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 Adrien Hopkins + * Copyright (C) 2022, 2024, 2025 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 @@ -18,6 +18,7 @@ package sevenUnitsGUI; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static sevenUnitsGUI.PrefixSearchRule.COMMON_PREFIXES; import static sevenUnitsGUI.PrefixSearchRule.NO_PREFIXES; import static sevenUnitsGUI.PrefixSearchRule.getCoherentOnlyRule; @@ -35,13 +36,11 @@ import sevenUnits.unit.Metric; /** * Tests for {@link PrefixSearchRule} * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ class PrefixSearchTest { - /** - * A method that creates duplicate copies of the common prefix rule. - */ + /** A method that creates duplicate copies of the common prefix rule. */ private static final PrefixSearchRule getCommonRuleCopy() { return getCoherentOnlyRule(Set.of(Metric.KILO, Metric.MILLI)); } @@ -51,8 +50,8 @@ class PrefixSearchTest { * {@link sevenUnitsGUI.PrefixSearchRule#apply(java.util.Map.Entry)}, for a * coherent unit and {@link PrefixSearchRule#COMMON_PREFIXES}. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @Test final void testCoherentPrefixSearch() { @@ -69,8 +68,8 @@ class PrefixSearchTest { * Test method for * {@link sevenUnitsGUI.PrefixSearchRule#equals(java.lang.Object)}. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @Test final void testEquals() { @@ -84,8 +83,8 @@ class PrefixSearchTest { /** * Test method for {@link sevenUnitsGUI.PrefixSearchRule#getPrefixes()}. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @Test final void testGetPrefixes() { @@ -97,8 +96,8 @@ class PrefixSearchTest { /** * Test method for {@link sevenUnitsGUI.PrefixSearchRule#hashCode()}. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @Test final void testHashCode() { @@ -109,9 +108,9 @@ class PrefixSearchTest { /** * Tests prefix searching for a non-coherent unit and * {@link PrefixSearchRule#COMMON_PREFIXES}. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test final void testNonCoherentPrefixSearch() { @@ -124,9 +123,9 @@ class PrefixSearchTest { /** * Tests that {@link PrefixSearchRule#NO_PREFIXES} returns the original unit. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testNoPrefixes() { @@ -145,14 +144,17 @@ class PrefixSearchTest { /** * Test method for {@link sevenUnitsGUI.PrefixSearchRule#toString()}. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @Test final void testToString() { - assertEquals( - "Apply the following prefixes: [kilo (\u00D7 1000.0), milli (\u00D7 0.001)]", - COMMON_PREFIXES.toString()); + final var toString = COMMON_PREFIXES.toString(); + final var valid1 = "Apply the following prefixes: [kilo (\u00D7 1000.0), milli (\u00D7 0.001)]"; + final var valid2 = "Apply the following prefixes: [milli (\u00D7 0.001), kilo (\u00D7 1000.0)]"; + + assertTrue(valid1.equals(toString) || valid2.equals(toString), + "COMMON_PREFIXES.toString invalid (was \"" + toString + "\")."); } } diff --git a/src/test/java/sevenUnitsGUI/PresenterTest.java b/src/test/java/sevenUnitsGUI/PresenterTest.java index 9e25a08..9ac5b84 100644 --- a/src/test/java/sevenUnitsGUI/PresenterTest.java +++ b/src/test/java/sevenUnitsGUI/PresenterTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 Adrien Hopkins + * Copyright (C) 2022-2025 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 @@ -17,13 +17,12 @@ package sevenUnitsGUI; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue; -import java.math.RoundingMode; import java.nio.file.Path; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; @@ -32,12 +31,12 @@ 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 sevenUnits.unit.BaseDimension; import sevenUnits.unit.BritishImperial; import sevenUnits.unit.LinearUnit; -import sevenUnits.unit.LinearUnitValue; import sevenUnits.unit.Metric; import sevenUnits.unit.Unit; import sevenUnits.unit.UnitDatabase; @@ -53,11 +52,11 @@ import sevenUnits.utils.UncertainDouble; * <em>Note: this test outputs a lot to the standard output, because creating a * {@link UnitDatabase} and converting with a {@link ViewBot} both trigger * println statements.</em> - * + * * @author Adrien Hopkins * - * @since v0.4.0 * @since 2022-02-10 + * @since v0.4.0 */ public final class PresenterTest { private static final Path TEST_SETTINGS = Path.of("src", "test", "resources", @@ -74,10 +73,10 @@ public final class PresenterTest { /** * @return rounding rules used by {@link #testRoundingRules} - * @since v0.4.0 * @since 2022-04-16 + * @since v0.4.0 */ - private static final Stream<Function<UncertainDouble, String>> getRoundingRules() { + private static Stream<Function<UncertainDouble, String>> getRoundingRules() { final var SCIENTIFIC_ROUNDING = StandardDisplayRules.uncertaintyBased(); final var INTEGER_ROUNDING = StandardDisplayRules.fixedDecimals(0); final var SIG_FIG_ROUNDING = StandardDisplayRules.fixedPrecision(4); @@ -85,81 +84,99 @@ public final class PresenterTest { return Stream.of(SCIENTIFIC_ROUNDING, INTEGER_ROUNDING, SIG_FIG_ROUNDING); } - private static final Stream<Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>>> getSearchRules() { + private static Stream<Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>>> getSearchRules() { return SEARCH_RULES; } - private static final Set<String> names(Set<? extends Nameable> units) { + private static Set<String> names(Set<? extends Nameable> units) { return units.stream().map(Nameable::getName).collect(Collectors.toSet()); } + private static Stream<Arguments> testConvertExpressions() { + return Stream.of( + Arguments.of("10000.0 m", "km", "10000.0 m = 10.00000 km"), + Arguments.of("1.0 m", "ft; in", "1.0 m = 3 ft + 3 in"), + Arguments.of("1.0 m", "ftin", "1.0 m = 3 ft + 3 in")); + } + + private static Stream<Arguments> testConvertUnits() { + return Stream.of( + Arguments.of("m", "km", 10000.0, "10000.0 m = 10.00000 km"), + Arguments.of("m", "ftin", 1.0, "1.0 m = 3 ft + 3 in")); + } + /** * Test method for {@link Presenter#convertExpressions} - * - * @since v0.4.0 + * * @since 2022-02-12 + * @since v0.4.0 */ - @Test - void testConvertExpressions() { + @ParameterizedTest + @MethodSource + void testConvertExpressions(String from, String to, String expectedOutput) { // setup - final ViewBot viewBot = new ViewBot(); - final Presenter presenter = new Presenter(viewBot); + final var viewBot = new ViewBot(); + final var presenter = new Presenter(viewBot); - viewBot.setFromExpression("10000.0 m"); - viewBot.setToExpression("km"); + viewBot.setFromExpression(from); + viewBot.setToExpression(to); // convert expression presenter.convertExpressions(); // test result - final List<UnitConversionRecord> outputs = viewBot - .expressionConversionList(); - assertEquals("10000.0 m = 10.00000 km", - outputs.get(outputs.size() - 1).toString()); + final var outputs = viewBot.expressionConversionList(); + assertEquals(expectedOutput, outputs.get(outputs.size() - 1).toString()); } /** - * Tests that unit-conversion Views can correctly convert units - * - * @since v0.4.0 + * Test method for {@link Presenter#convertUnits} + * * @since 2022-02-12 + * @since v0.4.0 */ - @Test - void testConvertUnits() { + @ParameterizedTest + @MethodSource + void testConvertUnits(String from, String to, double value, + String expectedOutput) { // setup - final ViewBot viewBot = new ViewBot(); - final Presenter presenter = new Presenter(viewBot); + final var viewBot = new ViewBot(); + final var presenter = new Presenter(viewBot); - viewBot.setFromUnitNames(names(testUnits)); - viewBot.setToUnitNames(names(testUnits)); - viewBot.setFromSelection("metre"); - viewBot.setToSelection("kilometre"); - viewBot.setInputValue("10000.0"); + viewBot.setFromSelection(from); + viewBot.setToSelection(to); + viewBot.setInputValue(Double.toString(value)); - // convert units + // convert expression presenter.convertUnits(); - /* - * use result from system as expected - I'm not testing unit conversion - * here (that's for the backend tests), I'm just testing that it correctly - * calls the unit conversion system - */ - final LinearUnitValue expectedInput = LinearUnitValue.of(Metric.METRE, - UncertainDouble.fromRoundedString("10000.0")); - final LinearUnitValue expectedOutput = expectedInput - .convertTo(Metric.KILOMETRE); - final UnitConversionRecord expectedUC = UnitConversionRecord.valueOf( - expectedInput.getUnit().getName(), - expectedOutput.getUnit().getName(), "10000.0", - expectedOutput.getValue().toString(false, RoundingMode.HALF_EVEN)); - assertEquals(List.of(expectedUC), viewBot.unitConversionList()); + // test result + final var outputs = viewBot.unitConversionList(); + assertEquals(expectedOutput, outputs.get(outputs.size() - 1).toString()); + } + + /** + * Ensures that the default unitfile can be disabled. + * + * @since 2025-02-23 + * @since v1.0.0 + */ + @Test + void testDisableDefault() { + final var viewBot = new ViewBot(); + final var presenter = new Presenter(viewBot); + assumeTrue(presenter.database.containsUnitName("joule"), + "Attempted to test disabling default on unit not in default file."); + presenter.setUseDefaultDatafiles(false); + assertFalse(presenter.database.containsUnitName("joule"), + "Presenter disabled default datafiles, but still contains the joule."); } /** * Tests that duplicate units are successfully removed, if that is asked for - * - * @since v0.4.0 + * * @since 2022-04-16 + * @since v0.4.0 */ @Test void testDuplicateUnits() { @@ -190,9 +207,9 @@ public final class PresenterTest { /** * Tests that one-way conversion correctly filters From and To units - * - * @since v0.4.0 + * * @since 2022-04-16 + * @since v0.4.0 */ @Test void testOneWayConversion() { @@ -224,9 +241,9 @@ public final class PresenterTest { /** * Tests the prefix-viewing functionality. - * - * @since v0.4.0 + * * @since 2022-04-16 + * @since v0.4.0 */ @Test void testPrefixViewing() { @@ -254,9 +271,9 @@ public final class PresenterTest { /** * Tests that rounding rules are used correctly. - * - * @since v0.4.0 + * * @since 2022-04-16 + * @since v0.4.0 */ @ParameterizedTest @MethodSource("getRoundingRules") @@ -273,9 +290,9 @@ public final class PresenterTest { presenter.convertUnits(); // test the result of the rounding - final String expectedOutputString = roundingRule + final var expectedOutputString = roundingRule .apply(UncertainDouble.fromRoundedString("12.3456789")); - final String actualOutputString = viewBot.unitConversionList().get(0) + final var actualOutputString = viewBot.unitConversionList().get(0) .outputValueString(); assertEquals(expectedOutputString, actualOutputString); } @@ -284,8 +301,8 @@ public final class PresenterTest { * Tests that the Presenter correctly applies search rules. * * @param searchRule search rule to test - * @since v0.4.0 * @since 2022-07-08 + * @since v0.4.0 */ @ParameterizedTest @MethodSource("getSearchRules") @@ -309,7 +326,7 @@ public final class PresenterTest { .apply(Map.entry("inch", BritishImperial.Length.INCH)).keySet()); expectedOutput.addAll( searchRule.apply(Map.entry("metre", Metric.METRE)).keySet()); - final Set<String> actualOutput = viewBot.getFromUnitNames(); + final var actualOutput = viewBot.getFromUnitNames(); // test output assertEquals(expectedOutput, actualOutput); @@ -317,9 +334,9 @@ public final class PresenterTest { /** * Tests that settings can be saved to and loaded from a file. - * - * @since v0.4.0 + * * @since 2022-04-16 + * @since v0.4.0 */ @Test void testSettingsSaving() { @@ -351,9 +368,9 @@ public final class PresenterTest { /** * Ensures the Presenter generates the correct data upon a unit-viewing. - * - * @since v0.4.0 + * * @since 2022-04-16 + * @since v0.4.0 */ @Test void testUnitViewing() { @@ -385,15 +402,15 @@ public final class PresenterTest { /** * Test for {@link Presenter#updateView()} - * - * @since v0.4.0 + * * @since 2022-02-12 + * @since v0.4.0 */ @Test void testUpdateView() { // setup - final ViewBot viewBot = new ViewBot(); - final Presenter presenter = new Presenter(viewBot); + final var viewBot = new ViewBot(); + final var presenter = new Presenter(viewBot); presenter.setOneWayConversionEnabled(false); presenter.setSearchRule(PrefixSearchRule.NO_PREFIXES); @@ -415,8 +432,8 @@ public final class PresenterTest { // filter to length units only, then get the filtered sets of units presenter.updateView(); - final Set<String> fromUnits = viewBot.getFromUnitNames(); - final Set<String> toUnits = viewBot.getToUnitNames(); + final var fromUnits = viewBot.getFromUnitNames(); + final var toUnits = viewBot.getToUnitNames(); // test that fromUnits/toUnits is [METRE, KILOMETRE] assertEquals(Set.of("metre", "kilometre"), fromUnits); diff --git a/src/test/java/sevenUnitsGUI/RoundingTest.java b/src/test/java/sevenUnitsGUI/RoundingTest.java index f749f85..589b8d0 100644 --- a/src/test/java/sevenUnitsGUI/RoundingTest.java +++ b/src/test/java/sevenUnitsGUI/RoundingTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 Adrien Hopkins + * Copyright (C) 2022, 2024, 2025 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 @@ -41,8 +41,8 @@ import sevenUnitsGUI.StandardDisplayRules.UncertaintyBased; /** * Tests that ensure the rounding rules work as intended. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ class RoundingTest { // rounding rules to test @@ -69,8 +69,8 @@ class RoundingTest { /** * @return arguments for * {@link #testFixedDecimalRounding(UncertainDouble, String, String, String)} - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ private static final Stream<Arguments> fixedDecimalRoundingExamples() { // input, zero decimal string, two decimal string, six decimal string @@ -83,8 +83,8 @@ class RoundingTest { /** * @return arguments for * {@link #testFixedPrecisionRounding(UncertainDouble, String, String, String)} - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ private static final Stream<Arguments> fixedPrecisionRoundingExamples() { // input, one sig fig string, three s.f. string, six s.f. string @@ -97,8 +97,8 @@ class RoundingTest { /** * @return arguments for * {@link #testUncertaintyRounding(UncertainDouble, String)} - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ private static final Stream<Arguments> uncertaintyRoundingExamples() { // input, uncertainty rounding string @@ -112,8 +112,8 @@ class RoundingTest { * Test for {@link FixedDecimals#decimalPlaces()} and * {@link FixedPrecision#significantFigures()}. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @Test void testDataMethods() { @@ -137,9 +137,9 @@ class RoundingTest { /** * Tests that the rounding methods' equals() methods work. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testEquals() { @@ -161,7 +161,7 @@ class RoundingTest { // test that FixedDecimals is never equal to FixedPrecision // this unlikely argument is the test - the equals should return false! @SuppressWarnings("unlikely-arg-type") - final boolean differentRulesEqual = Objects.equals(fixedDecimals(4), + final var differentRulesEqual = Objects.equals(fixedDecimals(4), fixedPrecision(4)); assertFalse(differentRulesEqual, "fixedDecimals(4) == fixedPrecision(4)"); } @@ -174,6 +174,7 @@ class RoundingTest { * @param twoDecimalString expected string for two decimal places * @param sixDecimalString expected string for six decimal places * @since 2022-07-17 + * @since v0.4.0 */ @ParameterizedTest @MethodSource("fixedDecimalRoundingExamples") @@ -200,8 +201,8 @@ class RoundingTest { * @param oneSigFigString expected string for one significant figure * @param threeSigFigString expected string for three significant figures * @param twelveSigFigString expected string for twelve significant figures - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @ParameterizedTest @MethodSource("fixedPrecisionRoundingExamples") @@ -225,9 +226,9 @@ class RoundingTest { /** * Tests that {@link StandardDisplayRules#getStandardRule} gets rounding * rules as intended. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testGetStandardRule() { @@ -243,9 +244,9 @@ class RoundingTest { /** * Tests that the rounding methods' equals() methods work. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testHashCode() { @@ -257,9 +258,9 @@ class RoundingTest { /** * Tests that the {@code toString()} methods of the three rounding rule * classes work correctly. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testToString() { @@ -273,8 +274,8 @@ class RoundingTest { * * @param input input number * @param output expected output string - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ @ParameterizedTest @MethodSource("uncertaintyRoundingExamples") diff --git a/src/test/java/sevenUnitsGUI/TabbedViewTest.java b/src/test/java/sevenUnitsGUI/TabbedViewTest.java index 165718f..b32579c 100644 --- a/src/test/java/sevenUnitsGUI/TabbedViewTest.java +++ b/src/test/java/sevenUnitsGUI/TabbedViewTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2022 Adrien Hopkins + * Copyright (C) 2022, 2024, 2025 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 @@ -18,20 +18,24 @@ package sevenUnitsGUI; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.concurrent.TimeUnit; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; /** - * Test for the TabbedView + * Test for the TabbedView. * - * @since v0.4.0 * @since 2022-07-17 + * @since v0.4.0 */ +@Timeout(value = 10, unit = TimeUnit.SECONDS) class TabbedViewTest { /** * @return a view with all settings set to standard values - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ private static final TabbedView setupView() { final var view = new TabbedView(); @@ -50,9 +54,9 @@ class TabbedViewTest { /** * Simulates an expression conversion operation, and ensures it works * properly. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testExpressionConversion() { @@ -71,9 +75,9 @@ class TabbedViewTest { /** * Simulates a unit conversion operation, and ensures it works properly. - * - * @since v0.4.0 + * * @since 2022-07-17 + * @since v0.4.0 */ @Test void testUnitConversion() { |