/** * 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 * 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 . */ 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.util.Random; import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.Test; import sevenUnits.utils.DecimalComparison; import sevenUnits.utils.NameSymbol; /** * 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 var inch = Metric.METRE.times(0.0254) .withName(NameSymbol.of("inch", "in")); final var foot = Metric.METRE.times(0.3048) .withName(NameSymbol.of("foot", "ft")); 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 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); 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(Metric.METRE, value1.plus(value2).getUnit()); assertEquals(Metric.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)); assertThrows(IllegalArgumentException.class, () -> value1.minus(value4)); } @Test public void testConversion() { final var metre = Metric.METRE; final Unit inch = metre.times(0.0254); 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 (var i = 0; i < 1000; i++) { // initiate random values 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 var actual = unit.convertToBase(testValue); assertEquals(actual, expected, expected * DecimalComparison.DOUBLE_EPSILON); } } @Test public void testEquals() { final var metre = Metric.METRE; final Unit meter = Metric.BaseUnits.METRE.asLinearUnit(); assertEquals(metre, meter); } @Test public void testIsMetric() { final Unit metre = Metric.METRE; final Unit megasecond = Metric.SECOND.withPrefix(Metric.MEGA); final Unit hour = Metric.HOUR; assertTrue(metre.isMetric()); assertTrue(megasecond.isMetric()); assertFalse(hour.isMetric()); } @Test public void testMultiplicationAndDivision() { // test unit-times-unit multiplication final var generatedJoule = Metric.KILOGRAM .times(Metric.METRE.toExponent(2)) .dividedBy(Metric.SECOND.toExponent(2)); final var actualJoule = Metric.JOULE; assertEquals(generatedJoule, actualJoule); // test multiplication by conversion factors final var kilometre = Metric.METRE.times(1000); final var hour = Metric.SECOND.times(3600); final var generatedKPH = kilometre.dividedBy(hour); final var actualKPH = Metric.METRE.dividedBy(Metric.SECOND) .dividedBy(3.6); assertEquals(generatedKPH, actualKPH); } @Test public void testPrefixes() { final var generatedKilometre = Metric.METRE.withPrefix(Metric.KILO); final var actualKilometre = Metric.METRE.times(1000); assertEquals(generatedKilometre, actualKilometre); } }