Files
allwpilib/wpiunits/src/test/java/org/wpilib/units/MeasureTest.java
2025-11-07 23:09:21 -08:00

333 lines
10 KiB
Java

// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package org.wpilib.units;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.wpilib.units.measure.Angle;
import org.wpilib.units.measure.AngularMomentum;
import org.wpilib.units.measure.Distance;
import org.wpilib.units.measure.LinearVelocity;
import org.wpilib.units.measure.Per;
import org.wpilib.units.measure.Time;
class MeasureTest {
@Test
void testBasics() {
DistanceUnit unit = Units.Feet;
double magnitude = 10;
Distance m = unit.of(magnitude);
assertEquals(unit, m.unit(), "Wrong units");
assertEquals(magnitude, m.magnitude(), 0, "Wrong magnitude");
}
@Test
void testMultiply() {
Distance m = Units.Feet.of(1);
Distance m2 = m.times(10);
assertEquals(10, m2.in(Units.Feet), 1e-12);
assertNotSame(m2, m); // make sure state wasn't changed
}
@Test
void testTimesConversionFactor() {
Distance m = Units.Feet.of(10);
Per<AngleUnit, DistanceUnit> conversion = Units.Degrees.of(10).div(Units.Feet.of(1));
Angle result = m.timesConversionFactor(conversion);
assertEquals(Units.Degrees.of(100), result);
}
@Test
void testTimesConversionFactorComplex() {
Distance m = Units.Feet.of(1);
// Using a complex compound unit here
// (Per<Mult<Mult<Mass, Per<Distance, Time>>, Distance>, Distance>)
Per<AngularMomentumUnit, DistanceUnit> conversion =
Units.KilogramMetersSquaredPerSecond.of(1).div(Units.Foot.one());
AngularMomentum result = m.timesConversionFactor(conversion);
assertEquals(Units.KilogramMetersSquaredPerSecond.of(1), result);
}
@Test
void testTimesVelocityConversionFactor() {
Time m = Units.Seconds.of(10);
LinearVelocity conversion = Units.MetersPerSecond.of(10);
Distance result = m.timesConversionFactor(conversion);
assertEquals(Units.Meters.of(100), result);
}
@Test
void testDivide() {
Distance m = Units.Meters.of(1);
Distance m2 = m.div(10);
assertEquals(0.1, m2.magnitude(), 0);
assertNotSame(m2, m);
}
@Test
void testAdd() {
Distance m1 = Units.Feet.of(1);
Distance m2 = Units.Inches.of(2);
assertTrue(m1.plus(m2).isEquivalent(Units.Feet.of(1 + 2 / 12d)));
assertTrue(m2.plus(m1).isEquivalent(Units.Inches.of(14)));
}
@Test
void testSubtract() {
Distance m1 = Units.Feet.of(1);
Distance m2 = Units.Inches.of(2);
assertTrue(m1.minus(m2).isEquivalent(Units.Feet.of(1 - 2 / 12d)));
assertTrue(m2.minus(m1).isEquivalent(Units.Inches.of(-10)));
}
@Test
void testUnaryMinus() {
Distance m = Units.Feet.of(123);
Distance negated = m.unaryMinus();
assertEquals(-123, negated.in(Units.Feet), 1e-12);
assertEquals(Units.Feet, negated.unit());
}
@Test
void testEquivalency() {
Distance inches = Units.Inches.of(12);
Distance feet = Units.Feet.of(1);
assertTrue(inches.isEquivalent(feet));
assertTrue(feet.isEquivalent(inches));
}
@Test
void testAs() {
Distance m = Units.Inches.of(12);
assertEquals(1, m.in(Units.Feet), Measure.EQUIVALENCE_THRESHOLD);
}
@Test
void testPerMeasureTime() {
var measure = Units.Kilograms.of(144);
var dt = Units.Milliseconds.of(53);
// 144 Kg / (53 ms) = (1000 / 53) * 144 Kg/s = (144,000 / 53) Kg/s
var result = measure.div(dt);
assertEquals(144_000.0 / 53, result.baseUnitMagnitude(), 1e-5);
assertEquals(Units.Kilograms.per(Units.Milliseconds), result.unit());
}
@Test
void testPerUnitTime() {
var measure = Units.Kilograms.of(144);
var result = measure.per(Units.Millisecond);
assertEquals(VelocityUnit.class, result.unit().getClass());
assertEquals(144_000.0, result.baseUnitMagnitude(), 1e-5);
assertEquals(Units.Kilograms.per(Units.Milliseconds), result.unit());
}
@Test
void testDivideMeasure() {
// Dimensionless divide
var m1 = Units.Meters.of(6);
var m2 = Units.Value.of(3);
var result = m1.div(m2);
assertEquals(2, m1.div(m2).magnitude());
assertEquals(Units.Meters, result.unit());
// Velocity divide
var m3 = Units.Meters.of(8);
var m4 = Units.Meters.per(Units.Second).of(4);
var time = m3.div(m4);
assertEquals(2, time.magnitude());
assertEquals(Units.Second, time.unit());
// PerUnit divide
var m5 = Units.Volts.of(6);
var m6 = Units.Volts.per(Units.Meter).of(2);
// Voltage/(Voltage/Distance) -> Voltage * Distance/Voltage -> Distance
var dist = m5.div(m6);
assertEquals(3, dist.magnitude());
assertEquals(Units.Meter, dist.unit());
}
@Test
void testToShortString() {
var measure = Units.Volts.of(343);
assertEquals("3.430e+02 V", measure.toShortString());
}
@Test
void testToLongString() {
var measure = Units.Volts.of(343);
assertEquals("343.0 Volt", measure.toLongString());
assertEquals("343.0001 Volt", Units.Volts.of(343.0001).toLongString());
assertEquals("1.2345678912345678E8 Volt", Units.Volts.of(123456789.12345678).toLongString());
}
@Test
void testOfBaseUnits() {
var unit = new ExampleUnit(16);
var measure = unit.ofBaseUnits(1);
assertEquals(unit, measure.unit());
assertEquals(1, measure.baseUnitMagnitude());
assertEquals(1 / 16.0, measure.magnitude());
}
@Test
@SuppressWarnings("SelfComparison")
void testCompare() {
var unit = new ExampleUnit(7);
var base = unit.of(1);
var less = unit.of(0.5);
var more = unit.of(2);
assertEquals(0, base.compareTo(base));
assertEquals(-1, base.compareTo(more));
assertEquals(1, base.compareTo(less));
// lt, lte, gt, gte helper functions
assertTrue(base.lt(more));
assertTrue(base.lte(more));
assertFalse(base.gt(more));
assertFalse(base.gte(more));
assertTrue(base.gt(less));
assertTrue(base.gte(less));
assertFalse(base.lt(less));
assertFalse(base.lte(less));
assertTrue(base.lte(base));
assertTrue(base.gte(base));
assertFalse(base.lt(base));
assertFalse(base.gt(base));
}
@Test
void testMinNoArgs() {
var min = Measure.min();
assertNull(min);
}
@Test
void testMin() {
var unit = new ExampleUnit(56.1);
var one = unit.of(1);
var two = unit.of(2);
var zero = unit.of(0);
var veryNegative = unit.of(-12839712);
var min = Measure.min(one, two, zero, veryNegative);
assertSame(veryNegative, min);
}
@Test
void testMaxNoArgs() {
var min = Measure.max();
assertNull(min);
}
@Test
void testMax() {
var unit = new ExampleUnit(6.551);
var one = unit.of(1);
var two = unit.of(2);
var zero = unit.of(0);
var veryLarge = unit.of(8217234);
var max = Measure.max(one, two, zero, veryLarge);
assertSame(veryLarge, max);
}
@Test
void testIsNearVarianceThreshold() {
var unit = new ExampleUnit(92);
var measureA = unit.of(1.21);
var measureB = unit.ofBaseUnits(64);
// A = 1.21 * 92 base units, or 111.32
// B = 64 base units
// ratio = 111.32 / 64 = 1.739375 = 173.9375%
assertTrue(measureA.isNear(measureA, 0));
assertTrue(measureB.isNear(measureB, 0));
assertFalse(measureA.isNear(measureB, 0));
assertFalse(measureA.isNear(measureB, 0.50));
assertFalse(measureA.isNear(measureB, 0.739370));
assertTrue(measureA.isNear(measureB, 0.739375));
assertTrue(measureA.isNear(measureB, 100)); // some stupidly large range +/- 10000%
var measureC = unit.of(-1.21);
var measureD = unit.ofBaseUnits(-64);
assertTrue(measureC.isNear(measureC, 0));
assertTrue(measureD.isNear(measureD, 0));
assertFalse(measureC.isNear(measureD, 0));
assertFalse(measureC.isNear(measureD, 0.50));
assertFalse(measureC.isNear(measureD, 0.739370));
assertTrue(measureC.isNear(measureD, 0.739375));
assertTrue(measureC.isNear(measureD, 100)); // some stupidly large range +/- 10000%
var measureE = Units.Meters.of(1);
var measureF = Units.Feet.of(-3.28084);
assertTrue(measureE.isNear(measureF, 2.01));
assertFalse(measureE.isNear(measureF, 1.99));
assertTrue(measureF.isNear(measureE, 2.01));
assertFalse(measureF.isNear(measureE, 1.99));
assertTrue(Units.Feet.zero().isNear(Units.Millimeters.zero(), 0.001));
assertFalse(Units.Feet.of(2).isNear(Units.Millimeters.of(0), 0.001));
}
@Test
void testIsNearMeasureTolerance() {
var measureCompared = Units.Meters.of(1);
var measureComparing = Units.Meters.of(1.2);
// Positive value with positive tolerance
assertTrue(measureCompared.isNear(measureComparing, Units.Millimeters.of(300)));
assertFalse(measureCompared.isNear(measureComparing, Units.Centimeters.of(10)));
measureCompared = measureCompared.unaryMinus();
measureComparing = measureComparing.unaryMinus();
// Negative value with positive tolerance
assertTrue(measureCompared.isNear(measureComparing, Units.Millimeters.of(300)));
assertFalse(measureCompared.isNear(measureComparing, Units.Centimeters.of(10)));
measureCompared = measureCompared.unaryMinus();
measureComparing = measureComparing.unaryMinus();
// Positive value with negative tolerance
assertTrue(measureCompared.isNear(measureComparing, Units.Millimeters.of(-300)));
assertFalse(measureCompared.isNear(measureComparing, Units.Centimeters.of(-10)));
measureCompared = measureCompared.unaryMinus();
measureComparing = measureComparing.unaryMinus();
// Negative value with negative tolerance.
assertTrue(measureCompared.isNear(measureComparing, Units.Millimeters.of(-300)));
assertFalse(measureCompared.isNear(measureComparing, Units.Centimeters.of(-10)));
measureCompared = measureCompared.unaryMinus();
measureComparing = measureComparing.unaryMinus();
// Tolerance exact difference between measures.
assertTrue(measureCompared.isNear(measureComparing, Units.Millimeters.of(200)));
assertTrue(measureCompared.isNear(measureComparing, Units.Centimeters.of(-20)));
}
}