unitMap = new HashMap<>();
unitMap.put("meter", Metric.METRE);
unitMap.put("metre", Metric.METRE);
unitMap.put("m", Metric.METRE);
unitMap.put("second", Metric.SECOND);
assertTrue(UnitDatabase.isRemovableDuplicate(unitMap,
entry("m", Metric.METRE)));
assertTrue(UnitDatabase.isRemovableDuplicate(unitMap,
entry("meter", Metric.METRE)));
assertFalse(UnitDatabase.isRemovableDuplicate(unitMap,
entry("metre", Metric.METRE)));
assertFalse(UnitDatabase.isRemovableDuplicate(unitMap,
entry("second", Metric.SECOND)));
}
@Test
public void testToString() {
final var database = new UnitDatabase();
database.addUnit("J", J);
database.addUnit("K", J);
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
if ("Unit Database with 1 units, 3 unit prefixes and 0 dimensions"
.equals(database.toString())) {
fail("Database counts by number of units, not number of unit names.");
}
assertEquals(
"Unit Database with 2 units, 3 unit prefixes and 0 dimensions",
database.toString());
}
/**
* Test that unit expressions return the correct value.
*
* @since 2019-04-14
* @since v0.2.0
*/
@Test
public void testUnitExpressions() {
// load units
final var database = new UnitDatabase();
database.addUnit("U", U);
database.addUnit("V", V);
database.addUnit("W", W);
database.addUnit("fj", J.times(5));
database.addUnit("ej", J.times(8));
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
// first test - test prefixes and operations
final Unit expected1 = J.withPrefix(A).withPrefix(B).withPrefix(C)
.withPrefix(C);
final 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 var actual2 = database.getUnitFromExpression("2 fj + 6 ej");
assertEquals(expected2, actual2);
// test incorrect expressions
assertThrows(IllegalArgumentException.class,
() -> database.getUnitFromExpression("U + V"));
assertThrows(IllegalArgumentException.class,
() -> database.getUnitFromExpression("U - V"));
}
/**
* Tests both the unit name iterator and the name-unit entry iterator
*
* @since 2019-04-14
* @since v0.2.0
*/
@Test
public void testUnitIterator() {
// load units
final var database = new UnitDatabase();
database.addUnit("J", J);
database.addUnit("K", K);
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
final var NUM_UNITS = database.unitMapPrefixless(true).size();
final var NUM_PREFIXES = database.prefixMap(true).size();
final var nameIterator = database.unitMap().keySet().iterator();
final var entryIterator = database.unitMap().entrySet().iterator();
var expectedLength = 1;
var unitsWithThisLengthSoFar = 0;
// loop 1000 times
for (var i = 0; i < 1000; i++) {
// expected length of next
if (unitsWithThisLengthSoFar >= NUM_UNITS
* (int) Math.pow(NUM_PREFIXES, expectedLength - 1)) {
expectedLength++;
unitsWithThisLengthSoFar = 0;
}
// test that stuff is valid
final var nextName = nameIterator.next();
final var nextUnit = database.getUnit(nextName);
final var nextEntry = entryIterator.next();
assertEquals(expectedLength, nextName.length());
assertEquals(nextName, nextEntry.getKey());
assertEquals(nextUnit, nextEntry.getValue());
unitsWithThisLengthSoFar++;
}
// test toString for consistency
final var entryIteratorString = entryIterator.toString();
for (var i = 0; i < 3; i++) {
assertEquals(entryIteratorString, entryIterator.toString());
}
final var nameIteratorString = nameIterator.toString();
for (var i = 0; i < 3; i++) {
assertEquals(nameIteratorString, nameIterator.toString());
}
}
/**
* Determine, given a unit name that could mean multiple things, which
* meaning is chosen.
*
* 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.
*
*
* @since 2019-04-14
* @since v0.2.0
*/
@Test
public void testUnitPrefixCombinations() {
// load units
final var database = new UnitDatabase();
database.addUnit("J", J);
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
database.addPrefix("AB", AB);
database.addPrefix("BC", BC);
// test 1 - AB-C-J vs A-BC-J vs A-B-C-J
final Unit expected1 = J.withPrefix(AB).withPrefix(C);
final var actual1 = database.getUnit("ABCJ");
assertEquals(expected1, actual1);
// test 2 - ABC-J vs AB-CJ vs AB-C-J
database.addUnit("CJ", J.times(13));
database.addPrefix("ABC", UnitPrefix.valueOf(17));
final Unit expected2 = J.times(17);
final 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 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 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"));
}
}