summaryrefslogtreecommitdiff
path: root/src/test/java/org
diff options
context:
space:
mode:
authorAdrien Hopkins <ahopk127@my.yorku.ca>2021-03-27 16:36:39 -0500
committerAdrien Hopkins <ahopk127@my.yorku.ca>2021-03-27 16:36:39 -0500
commit2eee97c9e64dca79fc6b1614b304b398d25a7f4b (patch)
treef14d4237a3ce71d21d02b29719a5fb6595fe4091 /src/test/java/org
parentfe4135a68cfed92ef336eec663e9c42c2c97dcbc (diff)
Added automatic building with Gradle
Diffstat (limited to 'src/test/java/org')
-rw-r--r--src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java159
-rw-r--r--src/test/java/org/unitConverter/math/ExpressionParserTest.java52
-rw-r--r--src/test/java/org/unitConverter/math/ObjectProductTest.java78
-rw-r--r--src/test/java/org/unitConverter/unit/MultiUnitTest.java106
-rw-r--r--src/test/java/org/unitConverter/unit/UnitDatabaseTest.java309
-rw-r--r--src/test/java/org/unitConverter/unit/UnitTest.java146
6 files changed, 850 insertions, 0 deletions
diff --git a/src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java b/src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java
new file mode 100644
index 0000000..311ace5
--- /dev/null
+++ b/src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java
@@ -0,0 +1,159 @@
+/**
+ * Copyright (C) 2019 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 org.unitConverter.math;
+
+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.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+
+import org.junit.jupiter.api.Test;
+import org.unitConverter.math.ConditionalExistenceCollections.ConditionalExistenceIterator;
+
+/**
+ * Tests the {@link #ConditionalExistenceCollections}.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-10-16
+ */
+class ConditionalExistenceCollectionsTest {
+
+ /**
+ * The returned iterator ignores elements that don't start with "a".
+ *
+ * @return test iterator
+ * @since 2019-10-17
+ */
+ 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
+ .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
+ */
+ Map<String, Integer> getTestMap() {
+ final Map<String, Integer> map = new HashMap<>();
+ map.put("one", 1);
+ map.put("two", 2);
+ map.put("zero", 0);
+ map.put("ten", 10);
+ final Map<String, Integer> conditionalMap = ConditionalExistenceCollections.conditionalExistenceMap(map,
+ e -> !Integer.valueOf(0).equals(e.getValue()));
+ return conditionalMap;
+ }
+
+ /**
+ * Test method for {@link org.unitConverter.math.ZeroIsNullMap#containsKey(java.lang.Object)}.
+ */
+ @Test
+ void testContainsKeyObject() {
+ final Map<String, Integer> map = this.getTestMap();
+ assertTrue(map.containsKey("one"));
+ assertTrue(map.containsKey("ten"));
+ assertFalse(map.containsKey("five"));
+ assertFalse(map.containsKey("zero"));
+ }
+
+ /**
+ * Test method for {@link org.unitConverter.math.ZeroIsNullMap#containsValue(java.lang.Object)}.
+ */
+ @Test
+ void testContainsValueObject() {
+ final Map<String, Integer> map = this.getTestMap();
+ assertTrue(map.containsValue(1));
+ assertTrue(map.containsValue(10));
+ assertFalse(map.containsValue(5));
+ assertFalse(map.containsValue(0));
+ }
+
+ /**
+ * Test method for {@link org.unitConverter.math.ZeroIsNullMap#entrySet()}.
+ */
+ @Test
+ void testEntrySet() {
+ final Map<String, Integer> map = this.getTestMap();
+ for (final Entry<String, Integer> e : map.entrySet()) {
+ assertTrue(e.getValue() != 0);
+ }
+ }
+
+ /**
+ * Test method for {@link org.unitConverter.math.ZeroIsNullMap#get(java.lang.Object)}.
+ */
+ @Test
+ void testGetObject() {
+ final Map<String, Integer> map = this.getTestMap();
+ assertEquals(1, map.get("one"));
+ assertEquals(10, map.get("ten"));
+ assertEquals(null, map.get("five"));
+ assertEquals(null, map.get("zero"));
+ }
+
+ @Test
+ void testIterator() {
+ final ConditionalExistenceIterator<String> testIterator = this.getTestIterator();
+
+ assertTrue(testIterator.hasNext);
+ assertTrue(testIterator.hasNext());
+ assertEquals("aa", testIterator.nextElement);
+ assertEquals("aa", testIterator.next());
+
+ assertTrue(testIterator.hasNext);
+ assertTrue(testIterator.hasNext());
+ assertEquals("ab", testIterator.nextElement);
+ assertEquals("ab", testIterator.next());
+
+ assertFalse(testIterator.hasNext);
+ assertFalse(testIterator.hasNext());
+ assertEquals(null, testIterator.nextElement);
+ assertThrows(NoSuchElementException.class, testIterator::next);
+ }
+
+ /**
+ * Test method for {@link org.unitConverter.math.ZeroIsNullMap#keySet()}.
+ */
+ @Test
+ void testKeySet() {
+ final Map<String, Integer> map = this.getTestMap();
+ assertFalse(map.keySet().contains("zero"));
+ }
+
+ /**
+ * Test method for {@link org.unitConverter.math.ZeroIsNullMap#values()}.
+ */
+ @Test
+ void testValues() {
+ final Map<String, Integer> map = this.getTestMap();
+ assertFalse(map.values().contains(0));
+ }
+
+}
diff --git a/src/test/java/org/unitConverter/math/ExpressionParserTest.java b/src/test/java/org/unitConverter/math/ExpressionParserTest.java
new file mode 100644
index 0000000..f3180c1
--- /dev/null
+++ b/src/test/java/org/unitConverter/math/ExpressionParserTest.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2019 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 org.unitConverter.math;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * A test for the {@code ExpressionParser} class. This is NOT part of this program's public API.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-03-22
+ * @since v0.2.0
+ */
+class ExpressionParserTest {
+ private static final ExpressionParser<Integer> numberParser = new ExpressionParser.Builder<>(Integer::parseInt)
+ .addBinaryOperator("+", (o1, o2) -> o1 + o2, 0).addBinaryOperator("-", (o1, o2) -> o1 - o2, 0)
+ .addBinaryOperator("*", (o1, o2) -> o1 * o2, 1).addBinaryOperator("/", (o1, o2) -> o1 / o2, 1)
+ .addBinaryOperator("^", (o1, o2) -> (int) Math.pow(o1, o2), 2).build();
+
+ /**
+ * Test method for {@link org.unitConverter.math.ExpressionParser#parseExpression(java.lang.String)}.
+ */
+ @Test
+ public void testParseExpression() {
+ // test parsing of expressions
+ assertEquals((int) numberParser.parseExpression("1 + 2 ^ 5 * 3"), 97);
+ assertEquals((int) numberParser.parseExpression("(1 + 2) ^ 5 * 3"), 729);
+
+ // ensure it normally goes left to right
+ assertEquals((int) numberParser.parseExpression("1 + 2 + 3 + 4"), 10);
+ assertEquals((int) numberParser.parseExpression("12 - 4 - 3"), 5);
+ assertEquals((int) numberParser.parseExpression("12 - (4 - 3)"), 11);
+ assertEquals((int) numberParser.parseExpression("1 / 2 + 3"), 3);
+ }
+
+}
diff --git a/src/test/java/org/unitConverter/math/ObjectProductTest.java b/src/test/java/org/unitConverter/math/ObjectProductTest.java
new file mode 100644
index 0000000..afd18b7
--- /dev/null
+++ b/src/test/java/org/unitConverter/math/ObjectProductTest.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2018 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 org.unitConverter.math;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.unitConverter.unit.SI.Dimensions.AREA;
+import static org.unitConverter.unit.SI.Dimensions.ENERGY;
+import static org.unitConverter.unit.SI.Dimensions.LENGTH;
+import static org.unitConverter.unit.SI.Dimensions.MASS;
+import static org.unitConverter.unit.SI.Dimensions.MASS_DENSITY;
+import static org.unitConverter.unit.SI.Dimensions.QUANTITY;
+import static org.unitConverter.unit.SI.Dimensions.TIME;
+import static org.unitConverter.unit.SI.Dimensions.VOLUME;
+
+import org.junit.jupiter.api.Test;
+import org.unitConverter.unit.SI;
+
+/**
+ * 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
+ */
+class ObjectProductTest {
+ /**
+ * Tests {@link UnitDimension#equals}
+ *
+ * @since 2018-12-12
+ * @since v0.1.0
+ */
+ @Test
+ public void testEquals() {
+ assertEquals(LENGTH, LENGTH);
+ assertFalse(LENGTH.equals(QUANTITY));
+ }
+
+ /**
+ * Tests {@code UnitDimension}'s exponentiation
+ *
+ * @since 2019-01-15
+ * @since v0.1.0
+ */
+ @Test
+ public void testExponents() {
+ assertEquals(1, LENGTH.getExponent(SI.BaseDimensions.LENGTH));
+ assertEquals(3, VOLUME.getExponent(SI.BaseDimensions.LENGTH));
+ }
+
+ /**
+ * Tests {@code UnitDimension}'s multiplication and division.
+ *
+ * @since 2018-12-12
+ * @since v0.1.0
+ */
+ @Test
+ public void testMultiplicationAndDivision() {
+ assertEquals(AREA, LENGTH.times(LENGTH));
+ assertEquals(MASS_DENSITY, MASS.dividedBy(VOLUME));
+ assertEquals(ENERGY, AREA.times(MASS).dividedBy(TIME).dividedBy(TIME));
+ assertEquals(LENGTH, LENGTH.times(TIME).dividedBy(TIME));
+ }
+}
diff --git a/src/test/java/org/unitConverter/unit/MultiUnitTest.java b/src/test/java/org/unitConverter/unit/MultiUnitTest.java
new file mode 100644
index 0000000..5ea9d07
--- /dev/null
+++ b/src/test/java/org/unitConverter/unit/MultiUnitTest.java
@@ -0,0 +1,106 @@
+/**
+ * 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 org.unitConverter.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 {
+
+ @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(SI.METRE.withPrefix(SI.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 = SI.METRE.withPrefix(SI.MILLI)
+ .convertTo(footInch, millimetres);
+ assertEquals(feet, feetAndInches.get(0), 1e-10);
+ assertEquals(inches, feetAndInches.get(1), 1e-10);
+ }
+ }
+
+ /**
+ * Test method for
+ * {@link org.unitConverter.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 org.unitConverter.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/org/unitConverter/unit/UnitDatabaseTest.java b/src/test/java/org/unitConverter/unit/UnitDatabaseTest.java
new file mode 100644
index 0000000..f0ba8e5
--- /dev/null
+++ b/src/test/java/org/unitConverter/unit/UnitDatabaseTest.java
@@ -0,0 +1,309 @@
+/**
+ * Copyright (C) 2019 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 org.unitConverter.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.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * 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
+ */
+class UnitDatabaseTest {
+ // some linear units and one nonlinear
+ private static final Unit U = SI.METRE;
+ private static final Unit V = SI.KILOGRAM;
+ private static final Unit W = SI.SECOND;
+
+ // used for testing expressions
+ // J = U^2 * V / W^2
+ private static final LinearUnit J = SI.KILOGRAM.times(SI.METRE.toExponent(2))
+ .dividedBy(SI.SECOND.toExponent(2));
+ private static final LinearUnit K = SI.KELVIN;
+
+ private static final Unit NONLINEAR = Unit
+ .fromConversionFunctions(SI.METRE.getBase(), o -> o + 1, o -> o - 1);
+
+ // make the prefix values prime so I can tell which multiplications were made
+ private static final UnitPrefix A = UnitPrefix.valueOf(2)
+ .withName(NameSymbol.ofName("A"));
+ private static final UnitPrefix B = UnitPrefix.valueOf(3)
+ .withName(NameSymbol.ofName("B"));
+ private static final UnitPrefix C = UnitPrefix.valueOf(5)
+ .withName(NameSymbol.ofName("C"));
+ private static final UnitPrefix AB = UnitPrefix.valueOf(7);
+ private static final UnitPrefix BC = UnitPrefix.valueOf(11);
+
+ /**
+ * Confirms that operations that shouldn't function for infinite databases
+ * throw an {@code IllegalStateException}.
+ *
+ * @since 2019-05-03
+ */
+// @Test
+// @Timeout(value = 1, unit = TimeUnit.SECONDS)
+ public void testInfiniteSetExceptions() {
+ // load units
+ final UnitDatabase infiniteDatabase = new UnitDatabase();
+
+ infiniteDatabase.addUnit("J", J);
+ infiniteDatabase.addUnit("K", K);
+
+ infiniteDatabase.addPrefix("A", A);
+ infiniteDatabase.addPrefix("B", B);
+ infiniteDatabase.addPrefix("C", C);
+
+ final Set<Entry<String, Unit>> entrySet = infiniteDatabase.unitMap()
+ .entrySet();
+ final Set<String> keySet = infiniteDatabase.unitMap().keySet();
+ assertThrows(IllegalStateException.class, () -> entrySet.toArray());
+ assertThrows(IllegalStateException.class, () -> keySet.toArray());
+ }
+
+ /**
+ * Test that prefixes correctly apply to units.
+ *
+ * @since 2019-04-14
+ * @since v0.2.0
+ */
+ @Test
+ public void testPrefixes() {
+ final UnitDatabase database = new UnitDatabase();
+
+ database.addUnit("U", U);
+ database.addUnit("V", V);
+ database.addUnit("W", W);
+
+ database.addPrefix("A", A);
+ database.addPrefix("B", B);
+ database.addPrefix("C", C);
+
+ // test the getPrefixesFromName method
+ final List<UnitPrefix> expected = Arrays.asList(C, B, A);
+ assertEquals(expected, database.getPrefixesFromName("ABCU"));
+
+ // get the product
+ final Unit abcuNonlinear = database.getUnit("ABCU");
+ assert abcuNonlinear instanceof LinearUnit;
+
+ final LinearUnit abcu = (LinearUnit) abcuNonlinear;
+ assertEquals(A.getMultiplier() * B.getMultiplier() * C.getMultiplier(),
+ abcu.getConversionFactor(), 1e-15);
+ }
+
+ /**
+ * Tests the functionnalites of the prefixless unit map.
+ *
+ * <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();
+
+ database.addUnit("U", U);
+ database.addUnit("V", V);
+ database.addUnit("W", W);
+
+ // this should work because the map should be an auto-updating view
+ assertTrue(prefixlessUnits.containsKey("U"));
+ assertFalse(prefixlessUnits.containsKey("Z"));
+
+ assertTrue(prefixlessUnits.containsValue(U));
+ assertFalse(prefixlessUnits.containsValue(NONLINEAR));
+ }
+
+ /**
+ * Tests that the database correctly stores and retrieves units, ignoring
+ * prefixes.
+ *
+ * @since 2019-04-14
+ * @since v0.2.0
+ */
+ @Test
+ public void testPrefixlessUnits() {
+ final UnitDatabase database = new UnitDatabase();
+
+ database.addUnit("U", U);
+ database.addUnit("V", V);
+ database.addUnit("W", W);
+
+ assertTrue(database.containsUnitName("U"));
+ assertFalse(database.containsUnitName("Z"));
+
+ assertEquals(U, database.getUnit("U"));
+ assertThrows(NoSuchElementException.class, () -> database.getUnit("Z"));
+ }
+
+ /**
+ * Test 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();
+
+ database.addUnit("U", U);
+ database.addUnit("V", V);
+ database.addUnit("W", W);
+ database.addUnit("fj", J.times(5));
+ database.addUnit("ej", J.times(8));
+
+ database.addPrefix("A", A);
+ database.addPrefix("B", B);
+ database.addPrefix("C", C);
+
+ // first test - test prefixes and operations
+ final Unit expected1 = J.withPrefix(A).withPrefix(B).withPrefix(C)
+ .withPrefix(C);
+ final Unit actual1 = database.getUnitFromExpression("ABV * CU^2 / W / W");
+
+ assertEquals(expected1, actual1);
+
+ // second test - test addition and subtraction
+ final Unit expected2 = J.times(58);
+ final Unit actual2 = database.getUnitFromExpression("2 fj + 6 ej");
+
+ assertEquals(expected2, actual2);
+ }
+
+ /**
+ * 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();
+
+ database.addUnit("J", J);
+ database.addUnit("K", K);
+
+ database.addPrefix("A", A);
+ database.addPrefix("B", B);
+ database.addPrefix("C", C);
+
+ final int NUM_UNITS = database.unitMapPrefixless().size();
+ final int NUM_PREFIXES = database.prefixMap().size();
+
+ final Iterator<String> nameIterator = database.unitMap().keySet()
+ .iterator();
+ final Iterator<Entry<String, Unit>> entryIterator = database.unitMap()
+ .entrySet().iterator();
+
+ int expectedLength = 1;
+ int unitsWithThisLengthSoFar = 0;
+
+ // loop 1000 times
+ for (int i = 0; i < 1000; i++) {
+ // expected length of next
+ if (unitsWithThisLengthSoFar >= NUM_UNITS
+ * (int) Math.pow(NUM_PREFIXES, expectedLength - 1)) {
+ expectedLength++;
+ unitsWithThisLengthSoFar = 0;
+ }
+
+ // test that stuff is valid
+ final String nextName = nameIterator.next();
+ final Unit nextUnit = database.getUnit(nextName);
+ final Entry<String, Unit> nextEntry = entryIterator.next();
+
+ assertEquals(expectedLength, nextName.length());
+ assertEquals(nextName, nextEntry.getKey());
+ assertEquals(nextUnit, nextEntry.getValue());
+
+ unitsWithThisLengthSoFar++;
+ }
+
+ // test toString for consistency
+ final String entryIteratorString = entryIterator.toString();
+ for (int i = 0; i < 3; i++) {
+ assertEquals(entryIteratorString, entryIterator.toString());
+ }
+
+ final String nameIteratorString = nameIterator.toString();
+ for (int i = 0; i < 3; i++) {
+ assertEquals(nameIteratorString, nameIterator.toString());
+ }
+ }
+
+ /**
+ * Determine, given a unit name that could mean multiple things, which
+ * meaning is chosen.
+ * <p>
+ * 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();
+
+ database.addUnit("J", J);
+
+ database.addPrefix("A", A);
+ database.addPrefix("B", B);
+ database.addPrefix("C", C);
+ database.addPrefix("AB", AB);
+ database.addPrefix("BC", BC);
+
+ // test 1 - AB-C-J vs A-BC-J vs A-B-C-J
+ final Unit expected1 = J.withPrefix(AB).withPrefix(C);
+ final Unit actual1 = database.getUnit("ABCJ");
+
+ assertEquals(expected1, actual1);
+
+ // test 2 - ABC-J vs AB-CJ vs AB-C-J
+ database.addUnit("CJ", J.times(13));
+ database.addPrefix("ABC", UnitPrefix.valueOf(17));
+
+ final Unit expected2 = J.times(17);
+ final Unit actual2 = database.getUnit("ABCJ");
+
+ assertEquals(expected2, actual2);
+ }
+}
diff --git a/src/test/java/org/unitConverter/unit/UnitTest.java b/src/test/java/org/unitConverter/unit/UnitTest.java
new file mode 100644
index 0000000..3b594f2
--- /dev/null
+++ b/src/test/java/org/unitConverter/unit/UnitTest.java
@@ -0,0 +1,146 @@
+/**
+ * Copyright (C) 2018 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 org.unitConverter.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.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.junit.jupiter.api.Test;
+import org.unitConverter.math.DecimalComparison;
+
+/**
+ * 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
+ */
+class UnitTest {
+ /** A random number generator */
+ private static final Random rng = ThreadLocalRandom.current();
+
+ @Test
+ public void testAdditionAndSubtraction() {
+ final LinearUnit inch = SI.METRE.times(0.0254)
+ .withName(NameSymbol.of("inch", "in"));
+ final LinearUnit foot = SI.METRE.times(0.3048)
+ .withName(NameSymbol.of("foot", "ft"));
+
+ assertEquals(inch.plus(foot), SI.METRE.times(0.3302));
+ assertEquals(foot.minus(inch), SI.METRE.times(0.2794));
+
+ // test with LinearUnitValue
+ final LinearUnitValue value1 = LinearUnitValue.getExact(SI.METRE, 15);
+ final LinearUnitValue value2 = LinearUnitValue.getExact(foot, 120);
+ final LinearUnitValue value3 = LinearUnitValue.getExact(SI.METRE, 0.5);
+ final LinearUnitValue value4 = LinearUnitValue.getExact(SI.KILOGRAM, 60);
+
+ // make sure addition is done correctly
+ assertEquals(51.576, value1.plus(value2).getValueExact(), 0.001);
+ assertEquals(15.5, value1.plus(value3).getValueExact());
+ assertEquals(52.076, value1.plus(value2).plus(value3).getValueExact(),
+ 0.001);
+
+ // make sure addition uses the correct unit, and is still associative
+ // (ignoring floating-point rounding errors)
+ assertEquals(SI.METRE, value1.plus(value2).getUnit());
+ assertEquals(SI.METRE, value1.plus(value2).plus(value3).getUnit());
+ assertEquals(foot, value2.plus(value1).getUnit());
+ assertTrue(value1.plus(value2).equals(value2.plus(value1), true));
+
+ // make sure errors happen when they should
+ assertThrows(IllegalArgumentException.class, () -> value1.plus(value4));
+ }
+
+ @Test
+ public void testConversion() {
+ final LinearUnit metre = SI.METRE;
+ final Unit inch = metre.times(0.0254);
+
+ final UnitValue 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++) {
+ // initiate random values
+ final double conversionFactor = UnitTest.rng.nextDouble() * 1000000;
+ final double testValue = UnitTest.rng.nextDouble() * 1000000;
+ final double expected = testValue * conversionFactor;
+
+ // test
+ final Unit unit = SI.METRE.times(conversionFactor);
+ final double actual = unit.convertToBase(testValue);
+
+ assertEquals(actual, expected,
+ expected * DecimalComparison.DOUBLE_EPSILON);
+ }
+ }
+
+ @Test
+ public void testEquals() {
+ final LinearUnit metre = SI.METRE;
+ final Unit meter = SI.BaseUnits.METRE.asLinearUnit();
+
+ assertEquals(metre, meter);
+ }
+
+ @Test
+ public void testIsMetric() {
+ final Unit metre = SI.METRE;
+ final Unit megasecond = SI.SECOND.withPrefix(SI.MEGA);
+ final Unit hour = SI.HOUR;
+
+ assertTrue(metre.isMetric());
+ assertTrue(megasecond.isMetric());
+ assertFalse(hour.isMetric());
+ }
+
+ @Test
+ public void testMultiplicationAndDivision() {
+ // test unit-times-unit multiplication
+ final LinearUnit generatedJoule = SI.KILOGRAM
+ .times(SI.METRE.toExponent(2)).dividedBy(SI.SECOND.toExponent(2));
+ final LinearUnit actualJoule = SI.JOULE;
+
+ assertEquals(generatedJoule, actualJoule);
+
+ // test multiplication by conversion factors
+ final LinearUnit kilometre = SI.METRE.times(1000);
+ final LinearUnit hour = SI.SECOND.times(3600);
+ final LinearUnit generatedKPH = kilometre.dividedBy(hour);
+
+ final LinearUnit actualKPH = SI.METRE.dividedBy(SI.SECOND).dividedBy(3.6);
+
+ assertEquals(generatedKPH, actualKPH);
+ }
+
+ @Test
+ public void testPrefixes() {
+ final LinearUnit generatedKilometre = SI.METRE.withPrefix(SI.KILO);
+ final LinearUnit actualKilometre = SI.METRE.times(1000);
+
+ assertEquals(generatedKilometre, actualKilometre);
+ }
+}