From fbb2f4a997e7e7043a2bdf15303b88907f6bcbc6 Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Thu, 15 Aug 2024 16:47:24 -0500
Subject: Correct encoding of ±
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/test/java/sevenUnits/unit/UnitTest.java | 72 ++++++++++++++---------------
1 file changed, 36 insertions(+), 36 deletions(-)
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java
index c93043b..4fb26a3 100644
--- a/src/test/java/sevenUnits/unit/UnitTest.java
+++ b/src/test/java/sevenUnits/unit/UnitTest.java
@@ -42,17 +42,17 @@ import sevenUnits.utils.UncertainDouble;
class UnitTest {
/** A random number generator */
private static final Random rng = ThreadLocalRandom.current();
-
+
@Test
public void testAdditionAndSubtraction() {
final LinearUnit inch = Metric.METRE.times(0.0254)
.withName(NameSymbol.of("inch", "in"));
final LinearUnit 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));
-
+
// test with LinearUnitValue
final LinearUnitValue value1 = LinearUnitValue.getExact(Metric.METRE, 15);
final LinearUnitValue value2 = LinearUnitValue.getExact(foot, 120);
@@ -60,70 +60,70 @@ class UnitTest {
0.5);
final LinearUnitValue 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 LinearUnit metre = Metric.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 = Metric.METRE.times(conversionFactor);
final double actual = unit.convertToBase(testValue);
-
+
assertEquals(actual, expected,
expected * DecimalComparison.DOUBLE_EPSILON);
}
}
-
+
@Test
public void testEquals() {
final LinearUnit 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
@@ -131,29 +131,29 @@ class UnitTest {
.times(Metric.METRE.toExponent(2))
.dividedBy(Metric.SECOND.toExponent(2));
final LinearUnit 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 LinearUnit actualKPH = Metric.METRE.dividedBy(Metric.SECOND)
.dividedBy(3.6);
-
+
assertEquals(generatedKPH, actualKPH);
}
-
+
@Test
public void testPrefixes() {
final LinearUnit generatedKilometre = Metric.METRE
.withPrefix(Metric.KILO);
final LinearUnit actualKilometre = Metric.METRE.times(1000);
-
+
assertEquals(generatedKilometre, actualKilometre);
}
-
+
/**
* Tests converting an uncertain LinearUnitValue to a string.
*
@@ -163,13 +163,13 @@ class UnitTest {
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",
+
+ 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.
*
@@ -179,13 +179,13 @@ class UnitTest {
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",
+ 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.
*
@@ -196,11 +196,11 @@ class UnitTest {
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.
*
@@ -209,10 +209,10 @@ class UnitTest {
@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.
*
@@ -222,7 +222,7 @@ class UnitTest {
public void testValueToString5() {
final UnitValue value = UnitValue
.of(USCustomary.FAHRENHEIT.withName(NameSymbol.EMPTY), 50);
-
+
assertEquals("50.0 unnamed unit (= 283.15 K)", value.toString());
}
}
--
cgit v1.2.3
From ea3e2bf07939926e43c7abe3fd13a7c4e93f69d1 Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Thu, 22 Aug 2024 11:41:04 -0500
Subject: Show unit/dim file errors as popup
Previously, any error in the unit or dimension file(s) crashes the
program. Instead, 7Units now ignores any invalid lines, still parsing
the correct ones, and shows a popup in case any errors happen.
---
docs/roadmap.org | 3 +-
.../java/sevenUnits/unit/LoadingException.java | 96 +++++++++
src/main/java/sevenUnits/unit/UnitDatabase.java | 138 ++++++-------
src/main/java/sevenUnitsGUI/Presenter.java | 30 ++-
.../java/sevenUnits/unit/UnitDatabaseTest.java | 221 +++++++++++----------
src/test/java/sevenUnitsGUI/TabbedViewTest.java | 28 +--
6 files changed, 323 insertions(+), 193 deletions(-)
create mode 100644 src/main/java/sevenUnits/unit/LoadingException.java
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/docs/roadmap.org b/docs/roadmap.org
index bd0ccee..04ea0a5 100644
--- a/docs/roadmap.org
+++ b/docs/roadmap.org
@@ -5,9 +5,8 @@ These requirements are subject to change. I intend to finish version 1.0.0 by [
Feature Requirements:
- 7Units should be able to parse unit files from [[https://www.gnu.org/software/units/][GNU Units]], the program that inspired it.
- (It should not be required to handle features that aren't in 7Units; those definitions should be ignored with a warning)
- 7Units's expression converter should support most or all of the conversion features supported by GNU Units:
- - Converting to sums of units (it should also be possible to do this in the unit converter with preset combinations)
+ - (/Mostly Done/) Converting to sums of units (it should also be possible to do this in the unit converter with preset combinations)
- (/Optional/) Inverse nonlinear conversion with the tilde prefix
- (/Optional/) Nonlinear units should be specifiable in unit files.
- /Any other feature not listed should be considered optional./
diff --git a/src/main/java/sevenUnits/unit/LoadingException.java b/src/main/java/sevenUnits/unit/LoadingException.java
new file mode 100644
index 0000000..9376ed7
--- /dev/null
+++ b/src/main/java/sevenUnits/unit/LoadingException.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2024 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 java.nio.file.Path;
+import java.util.Optional;
+
+/**
+ * An exception that occurred when loading a file. This wrapper class adds more
+ * info about the error.
+ *
+ * @author Adrien Hopkins
+ * @since 2024-08-22
+ */
+public final class LoadingException extends RuntimeException {
+ public static enum FileType {
+ UNIT, DIMENSION
+ }
+
+ private static final long serialVersionUID = -8167971828216907607L;
+
+ private final long lineNumber;
+ private final String line;
+ private final Optional file;
+
+ private final FileType fileType;
+
+ private final RuntimeException problem;
+
+ public LoadingException(long lineNumber, String line, FileType fileType,
+ RuntimeException problem) {
+ super(problem);
+ this.lineNumber = lineNumber;
+ this.line = line;
+ this.file = Optional.empty();
+ this.fileType = fileType;
+ this.problem = problem;
+ }
+
+ public LoadingException(long lineNumber, String line, Path file,
+ FileType fileType, RuntimeException problem) {
+ super(problem);
+ this.lineNumber = lineNumber;
+ this.line = line;
+ this.file = Optional.of(file);
+ this.fileType = fileType;
+ this.problem = problem;
+ }
+
+ public Optional file() {
+ return this.file;
+ }
+
+ public FileType fileType() {
+ return this.fileType;
+ }
+
+ @Override
+ public String getMessage() {
+ return this.file
+ .map(f -> String.format(
+ "Error parsing line %d of %s file '%s' (\"%s\"): %s",
+ this.lineNumber, this.fileType.toString().toLowerCase(), f,
+ this.line, this.problem))
+ .orElse(String.format(
+ "Error parsing line %d of %s stream (\"%s\"): %s",
+ this.lineNumber, this.fileType.toString().toLowerCase(),
+ this.line, this.problem));
+ }
+
+ public String line() {
+ return this.line;
+ }
+
+ public long lineNumber() {
+ return this.lineNumber;
+ }
+
+ public RuntimeException problem() {
+ return this.problem;
+ }
+}
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java
index 514b27d..dc81aca 100644
--- a/src/main/java/sevenUnits/unit/UnitDatabase.java
+++ b/src/main/java/sevenUnits/unit/UnitDatabase.java
@@ -1364,16 +1364,7 @@ public final class UnitDatabase {
throw new IllegalArgumentException(String.format(
"! used but no dimension found (line %d).", lineCounter));
} else {
- // it's a unit, get the unit
- final ObjectProduct dimension;
- try {
- dimension = this.getDimensionFromExpression(expression);
- } catch (final IllegalArgumentException | NoSuchElementException e) {
- System.err.printf("Parsing error on line %d:%n", lineCounter);
- throw e;
- }
-
- this.addDimension(name, dimension);
+ this.addDimension(name, this.getDimensionFromExpression(expression));
}
}
@@ -1454,56 +1445,15 @@ public final class UnitDatabase {
.format("! used but no unit found (line %d).", lineCounter));
} else {
if (name.endsWith("-")) {
- final UnitPrefix prefix;
- try {
- prefix = this.getPrefixFromExpression(expression);
- } catch (final IllegalArgumentException
- | NoSuchElementException e) {
- System.err.printf("Parsing error on line %d:%n", lineCounter);
- throw e;
- }
final String prefixName = name.substring(0, name.length() - 1);
- this.addPrefix(prefixName, prefix);
+ this.addPrefix(prefixName,
+ this.getPrefixFromExpression(expression));
} else if (expression.contains(";")) {
// it's a multi-unit
- final String[] parts = expression.split(";");
- final List units = new ArrayList<>(parts.length);
- for (final String unitName : parts) {
- final Unit unit;
- try {
- unit = this.getUnitFromExpression(unitName.trim());
- } catch (final NoSuchElementException e) {
- System.err.printf("Parsing error on line %d:%n", lineCounter);
- throw e;
- }
-
- if (unit instanceof LinearUnit) {
- units.add((LinearUnit) unit);
- } else {
- System.err.printf("Parsing error on line %d:%n", lineCounter);
- throw new IllegalArgumentException(String.format(
- "Unit '%s' is in a unit-set expression, but is not linear.",
- unitName));
- }
- }
-
- try {
- this.addUnitSet(name, units);
- } catch (final IllegalArgumentException e) {
- System.err.printf("Parsing error on line %d:%n", lineCounter);
- throw e;
- }
+ this.addUnitSet(name, this.getUnitSetFromExpression(expression));
} else {
// it's a unit, get the unit
- final Unit unit;
- try {
- unit = this.getUnitFromExpression(expression);
- } catch (final IllegalArgumentException
- | NoSuchElementException e) {
- System.err.printf("Parsing error on line %d:%n", lineCounter);
- throw e;
- }
- this.addUnit(name, unit);
+ this.addUnit(name, this.getUnitFromExpression(expression));
}
}
}
@@ -1950,6 +1900,27 @@ public final class UnitDatabase {
return unitSet;
}
+ /**
+ * Parses a semicolon-separated expression to get the unit set being used.
+ *
+ * @since 2024-08-22
+ */
+ private List getUnitSetFromExpression(String expression) {
+ final String[] parts = expression.split(";");
+ final List units = new ArrayList<>(parts.length);
+ for (final String unitName : parts) {
+ final Unit unit = this.getUnitFromExpression(unitName.trim());
+
+ if (unit instanceof LinearUnit) {
+ units.add((LinearUnit) unit);
+ } else
+ throw new IllegalArgumentException(String.format(
+ "Unit '%s' is in a unit-set expression, but is not linear.",
+ unitName));
+ }
+ return units;
+ }
+
/**
* Adds all dimensions from a file, using data from the database to parse
* them.
@@ -1970,24 +1941,30 @@ public final class UnitDatabase {
*
*
* @param file file to read
- * @throws IllegalArgumentException if the file cannot be parsed, found or
- * read
- * @throws NullPointerException if file is null
+ * @throws NullPointerException if file is null
+ * @returns list of errors that happened when loading file
* @since 2019-01-13
* @since v0.1.0
*/
- public void loadDimensionFile(final Path file) {
+ public List loadDimensionFile(final Path file) {
Objects.requireNonNull(file, "file must not be null.");
+ final List errors = new ArrayList<>();
try {
long lineCounter = 0;
for (final String line : Files.readAllLines(file)) {
- this.addDimensionFromLine(line, ++lineCounter);
+ try {
+ this.addDimensionFromLine(line, ++lineCounter);
+ } catch (IllegalArgumentException | NoSuchElementException e) {
+ errors.add(new LoadingException(lineCounter, line, file,
+ LoadingException.FileType.DIMENSION, e));
+ }
}
} catch (final FileNotFoundException e) {
throw new IllegalArgumentException("Could not find file " + file, e);
} catch (final IOException e) {
throw new IllegalArgumentException("Could not read file " + file, e);
}
+ return errors;
}
/**
@@ -1997,13 +1974,22 @@ public final class UnitDatabase {
* @param stream stream to load from
* @since 2021-03-27
*/
- public void loadDimensionsFromStream(final InputStream stream) {
+ public List loadDimensionsFromStream(
+ final InputStream stream) {
+ final List errors = new ArrayList<>();
try (final Scanner scanner = new Scanner(stream)) {
long lineCounter = 0;
while (scanner.hasNextLine()) {
- this.addDimensionFromLine(scanner.nextLine(), ++lineCounter);
+ final String line = scanner.nextLine();
+ try {
+ this.addDimensionFromLine(line, ++lineCounter);
+ } catch (IllegalArgumentException | NoSuchElementException e) {
+ errors.add(new LoadingException(lineCounter, line,
+ LoadingException.FileType.DIMENSION, e));
+ }
}
}
+ return errors;
}
/**
@@ -2025,24 +2011,30 @@ public final class UnitDatabase {
*
*
* @param file file to read
- * @throws IllegalArgumentException if the file cannot be parsed, found or
- * read
- * @throws NullPointerException if file is null
+ * @throws NullPointerException if file is null
+ * @returns list of errors that happened when loading file
* @since 2019-01-13
* @since v0.1.0
*/
- public void loadUnitsFile(final Path file) {
+ public List loadUnitsFile(final Path file) {
Objects.requireNonNull(file, "file must not be null.");
+ final List errors = new ArrayList<>();
try {
long lineCounter = 0;
for (final String line : Files.readAllLines(file)) {
- this.addUnitOrPrefixFromLine(line, ++lineCounter);
+ try {
+ this.addUnitOrPrefixFromLine(line, ++lineCounter);
+ } catch (IllegalArgumentException | NoSuchElementException e) {
+ errors.add(new LoadingException(lineCounter, line, file,
+ LoadingException.FileType.UNIT, e));
+ }
}
} catch (final FileNotFoundException e) {
throw new IllegalArgumentException("Could not find file " + file, e);
} catch (final IOException e) {
throw new IllegalArgumentException("Could not read file " + file, e);
}
+ return errors;
}
/**
@@ -2052,13 +2044,21 @@ public final class UnitDatabase {
* @param stream stream to load from
* @since 2021-03-27
*/
- public void loadUnitsFromStream(InputStream stream) {
+ public List loadUnitsFromStream(InputStream stream) {
+ final List errors = new ArrayList<>();
try (final Scanner scanner = new Scanner(stream)) {
long lineCounter = 0;
while (scanner.hasNextLine()) {
- this.addUnitOrPrefixFromLine(scanner.nextLine(), ++lineCounter);
+ final String line = scanner.nextLine();
+ try {
+ this.addUnitOrPrefixFromLine(line, ++lineCounter);
+ } catch (IllegalArgumentException | NoSuchElementException e) {
+ errors.add(new LoadingException(lineCounter, line,
+ LoadingException.FileType.UNIT, e));
+ }
}
}
+ return errors;
}
/**
diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java
index 68f0fcb..4ff2d65 100644
--- a/src/main/java/sevenUnitsGUI/Presenter.java
+++ b/src/main/java/sevenUnitsGUI/Presenter.java
@@ -40,6 +40,7 @@ import sevenUnits.unit.BaseUnit;
import sevenUnits.unit.BritishImperial;
import sevenUnits.unit.LinearUnit;
import sevenUnits.unit.LinearUnitValue;
+import sevenUnits.unit.LoadingException;
import sevenUnits.unit.Metric;
import sevenUnits.unit.Unit;
import sevenUnits.unit.UnitDatabase;
@@ -311,7 +312,7 @@ public final class Presenter {
// load units and prefixes
try (final InputStream units = inputStream(DEFAULT_UNITS_FILEPATH)) {
- this.database.loadUnitsFromStream(units);
+ this.handleLoadErrors(this.database.loadUnitsFromStream(units));
} catch (final IOException e) {
throw new AssertionError("Loading of unitsfile.txt failed.", e);
}
@@ -319,7 +320,8 @@ public final class Presenter {
// load dimensions
try (final InputStream dimensions = inputStream(
DEFAULT_DIMENSIONS_FILEPATH)) {
- this.database.loadDimensionsFromStream(dimensions);
+ this.handleLoadErrors(
+ this.database.loadDimensionsFromStream(dimensions));
} catch (final IOException e) {
throw new AssertionError("Loading of dimensionfile.txt failed.", e);
}
@@ -771,6 +773,24 @@ public final class Presenter {
return this.view;
}
+ /**
+ * Accepts a list of errors. If that list is non-empty, prints an error
+ * message and alerts the user.
+ *
+ * @since 2024-08-22
+ */
+ private void handleLoadErrors(List errors) {
+ if (!errors.isEmpty()) {
+ final String errorMessage = String.format(
+ "%d error(s) happened while loading file:\n%s\n", errors.size(),
+ errors.stream().map(Throwable::getMessage)
+ .collect(Collectors.joining("\n")));
+ System.err.print(errorMessage);
+ this.view.showErrorMessage(errors.size() + "Loading Error(s)",
+ errorMessage);
+ }
+ }
+
/**
* @return whether or not the provided unit is semi-metric (i.e. an
* exception)
@@ -832,13 +852,15 @@ public final class Presenter {
// set manually to avoid the unnecessary saving of the non-manual
// methods
case "custom_dimension_file":
- this.database.loadDimensionFile(pathFromConfig(value));
+ this.handleLoadErrors(
+ this.database.loadDimensionFile(pathFromConfig(value)));
break;
case "custom_exception_file":
this.loadExceptionFile(pathFromConfig(value));
break;
case "custom_unit_file":
- this.database.loadUnitsFile(pathFromConfig(value));
+ this.handleLoadErrors(
+ this.database.loadUnitsFile(pathFromConfig(value)));
break;
case "number_display_rule":
this.setDisplayRuleFromString(value);
diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
index 9d650f0..e7f3ccf 100644
--- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
+++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
@@ -25,6 +25,7 @@ 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;
@@ -53,9 +54,9 @@ import sevenUnits.utils.UncertainDouble;
class UnitDatabaseTest {
private static final class SimpleEntry implements Map.Entry {
private final K key;
-
+
private V value;
-
+
/**
*
* @since 2021-10-07
@@ -64,7 +65,7 @@ class UnitDatabaseTest {
this.key = key;
this.value = value;
}
-
+
@Override
public boolean equals(Object obj) {
if (this == obj)
@@ -75,23 +76,23 @@ class UnitDatabaseTest {
return Objects.equals(this.key, other.getKey())
&& Objects.equals(this.value, other.getValue());
}
-
+
@Override
public K getKey() {
return this.key;
}
-
+
@Override
public V getValue() {
return this.value;
}
-
+
@Override
public int hashCode() {
return (this.key == null ? 0 : this.key.hashCode())
^ (this.value == null ? 0 : this.value.hashCode());
}
-
+
@Override
public V setValue(V value) {
final V oldValue = this.value;
@@ -99,20 +100,20 @@ class UnitDatabaseTest {
return oldValue;
}
}
-
+
// some linear units and one nonlinear
private static final Unit U = Metric.METRE;
private static final Unit V = Metric.KILOGRAM;
-
+
private static final Unit W = Metric.SECOND;
// used for testing expressions
// J = U^2 * V / W^2
private static final LinearUnit J = Metric.KILOGRAM
.times(Metric.METRE.toExponent(2))
.dividedBy(Metric.SECOND.toExponent(2));
-
+
private static final LinearUnit K = Metric.KELVIN;
-
+
private static final Unit NONLINEAR = Unit.fromConversionFunctions(
Metric.METRE.getBase(), o -> o + 1, o -> o - 1);
// make the prefix values prime so I can tell which multiplications were made
@@ -123,9 +124,9 @@ class UnitDatabaseTest {
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);
-
+
/**
* Gets a map entry.
*
@@ -139,41 +140,47 @@ class UnitDatabaseTest {
private static Map.Entry entry(K key, V value) {
return new SimpleEntry<>(key, value);
}
-
+
/**
* Loads the dimensionfile at src/test/resources/[path] to the database
* {@code loadTo}.
*
* @param loadTo database to load to
* @param path path of file to load
+ * @return exceptions returned by file loading
* @since 2021-10-04
*/
- private static void loadDimensionFile(UnitDatabase loadTo, String path) {
+ private static List loadDimensionFile(UnitDatabase loadTo,
+ String path) {
try (final InputStream 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();
}
}
-
+
/**
* Loads the unitfile at src/test/resources/[path] to the database
* {@code loadTo}.
*
* @param loadTo database to load to
* @param path path of file to load
+ * @return exceptions returned by file loading
* @since 2021-09-22
*/
- private static void loadUnitsFile(UnitDatabase loadTo, String path) {
+ private static List loadUnitsFile(UnitDatabase loadTo,
+ String path) {
try (final InputStream 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();
}
}
-
+
/**
* A test for the {@link UnitDatabase#evaluateUnitExpression(String)}
* function. Simple because the expression parser has its own test.
@@ -183,26 +190,26 @@ class UnitDatabaseTest {
@Test
public void testEvaluateExpression() {
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 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");
assertEquals(expected, actual);
-
+
// check that negation works properly
assertEquals(2,
database.evaluateUnitExpression("J - -1 * J").getValueExact());
}
-
+
/**
* Test for {@link UnitDatabase#getUnit}, {@link UnitDatabase#getLinearUnit}
* and {@link UnitDatabase#getLinearUnitValue}.
@@ -212,14 +219,14 @@ class UnitDatabaseTest {
@Test
public void testGetUnit() {
final UnitDatabase database = new UnitDatabase();
-
+
database.addUnit("m", Metric.METRE);
database.addUnit("meter", Metric.METRE);
database.addUnit("metre", Metric.METRE);
database.addUnit("badname", Metric.METRE);
database.addUnit("K", Metric.KELVIN);
database.addUnit("degC", Metric.CELSIUS);
-
+
// ensure getUnit returns units, regardless of whether the name is one of
// the unit's names
assertEquals(Metric.METRE, database.getUnit("m"));
@@ -228,14 +235,14 @@ class UnitDatabaseTest {
assertEquals(Metric.METRE, database.getUnit("badname"));
assertThrows(NoSuchElementException.class,
() -> database.getUnit("blabla"));
-
+
assertEquals(Metric.KELVIN, database.getLinearUnit("K"));
assertThrows(IllegalArgumentException.class,
() -> database.getLinearUnit("degC"));
assertEquals(Metric.KELVIN.times(373.15),
database.getLinearUnit("degC(100)"));
}
-
+
/**
* Confirms that operations that shouldn't function for infinite databases
* throw an {@code IllegalStateException}.
@@ -247,21 +254,21 @@ class UnitDatabaseTest {
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> entrySet = infiniteDatabase.unitMap()
.entrySet();
final Set keySet = infiniteDatabase.unitMap().keySet();
assertThrows(IllegalStateException.class, () -> entrySet.toArray());
assertThrows(IllegalStateException.class, () -> keySet.toArray());
}
-
+
/**
* A bunch of tests for invalid dimension files
*
@@ -277,12 +284,13 @@ class UnitDatabaseTest {
database.addDimension("TIME", Metric.Dimensions.TIME);
final String filename = String.format("/test-dimensionfile-invalid%d.txt",
num);
- final RuntimeException e = assertThrows(RuntimeException.class,
- () -> loadDimensionFile(database, filename));
+ final List errs = loadDimensionFile(database, filename);
+ assertFalse(errs.isEmpty(), "no error from invalid file " + filename);
+ final RuntimeException e = errs.get(0).problem();
assertTrue(e instanceof IllegalArgumentException
|| e instanceof NoSuchElementException);
}
-
+
/**
* A bunch of tests for invalid unit files
*
@@ -295,12 +303,13 @@ class UnitDatabaseTest {
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 List errs = loadUnitsFile(database, filename);
+ assertFalse(errs.isEmpty(), "no error from invalid file " + filename);
+ final RuntimeException e = errs.get(0).problem();
assertTrue(e instanceof IllegalArgumentException
|| e instanceof NoSuchElementException);
}
-
+
/**
* Tests loading a valid dimension-file with some derived dimensions.
*
@@ -312,13 +321,13 @@ class UnitDatabaseTest {
database.addDimension("LENGTH", Metric.Dimensions.LENGTH);
database.addDimension("MASS", Metric.Dimensions.MASS);
database.addDimension("TIME", Metric.Dimensions.TIME);
-
+
loadDimensionFile(database, "/test-dimensionfile-valid1.txt");
assertEquals(Metric.Dimensions.ENERGY, database.getDimension("ENERGY"));
assertEquals(Metric.Dimensions.POWER, database.getDimension("POWER"));
-
+
}
-
+
/**
* Tests loading a valid unitfile with some prefixes and no units.
*
@@ -327,13 +336,13 @@ class UnitDatabaseTest {
@Test
public void testLoadingValidPrefixes() {
final UnitDatabase 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());
}
-
+
/**
* Tests loading a valid unitfile with some units and preloaded prefixes
*
@@ -342,43 +351,43 @@ class UnitDatabaseTest {
@Test
public void testLoadingValidUnits() {
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);
-
+
loadUnitsFile(database, "/test-unitsfile-valid1.txt");
-
+
final Unit expected1 = ((LinearUnit) U).withPrefix(A).withPrefix(B)
.withPrefix(C);
final Unit 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");
assertEquals(expected2, actual2);
-
+
final Unit expected3 = ((LinearUnit) U)
.times(A.getMultiplier() + C.getMultiplier() - B.getMultiplier());
final Unit actual3 = database.getUnit("test3");
assertEquals(expected3, actual3);
-
+
final UnitValue expected4 = UnitValue.of(U, 1);
final UnitValue actual4 = database
.evaluateUnitExpression("-5 * U + -3 * U + 12 * U - 3 * U")
.asUnitValue();
assertEquals(expected4, actual4);
-
+
assertTrue(System.err.toString().length() > 0);
}
-
+
/**
* Tests the iterator of the prefixless unit map. These tests are simple, as
* the unit map iterator is simple.
@@ -388,16 +397,16 @@ class UnitDatabaseTest {
@Test
public void testPrefixedUnitMapIterator() {
final UnitDatabase database1 = new UnitDatabase();
-
+
database1.addUnit("U", U);
database1.addUnit("V", V);
database1.addUnit("W", W);
-
+
final Map map1 = database1.unitMap();
final Iterator keyIterator1 = map1.keySet().iterator();
final Iterator> entryIterator1 = map1.entrySet()
.iterator();
-
+
final Set expectedKeys = Set.of("U", "V", "W");
final Set actualKeys = new HashSet<>();
while (keyIterator1.hasNext()) {
@@ -405,7 +414,7 @@ class UnitDatabaseTest {
}
assertEquals(expectedKeys, actualKeys);
assertEquals(expectedKeys, map1.keySet());
-
+
final Set> expectedEntries = Set.of(entry("U", U),
entry("V", V), entry("W", W));
final Set> actualEntries = new HashSet<>();
@@ -415,7 +424,7 @@ class UnitDatabaseTest {
assertEquals(expectedEntries, actualEntries);
assertEquals(expectedEntries, map1.entrySet());
}
-
+
/**
* Test that prefixes correctly apply to units.
*
@@ -425,28 +434,28 @@ class UnitDatabaseTest {
@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 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.
*
@@ -462,19 +471,19 @@ class UnitDatabaseTest {
final UnitDatabase database = new UnitDatabase();
final Map prefixlessUnits = database
.unitMapPrefixless(true);
-
+
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.
@@ -485,18 +494,18 @@ class UnitDatabaseTest {
@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
public void testRemovableDuplicates() {
final Map unitMap = new HashMap<>();
@@ -504,7 +513,7 @@ class UnitDatabaseTest {
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,
@@ -514,28 +523,28 @@ class UnitDatabaseTest {
assertFalse(UnitDatabase.isRemovableDuplicate(unitMap,
entry("second", Metric.SECOND)));
}
-
+
@Test
public void testToString() {
final UnitDatabase 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.
*
@@ -546,37 +555,37 @@ class UnitDatabaseTest {
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);
-
+
// 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
*
@@ -587,25 +596,25 @@ class UnitDatabaseTest {
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(true).size();
final int NUM_PREFIXES = database.prefixMap(true).size();
-
+
final Iterator nameIterator = database.unitMap().keySet()
.iterator();
final Iterator> 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
@@ -614,31 +623,31 @@ class UnitDatabaseTest {
expectedLength++;
unitsWithThisLengthSoFar = 0;
}
-
+
// test that stuff is valid
final String nextName = nameIterator.next();
final Unit nextUnit = database.getUnit(nextName);
final Entry 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.
@@ -654,28 +663,28 @@ class UnitDatabaseTest {
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/sevenUnitsGUI/TabbedViewTest.java b/src/test/java/sevenUnitsGUI/TabbedViewTest.java
index 165718f..017e9ea 100644
--- a/src/test/java/sevenUnitsGUI/TabbedViewTest.java
+++ b/src/test/java/sevenUnitsGUI/TabbedViewTest.java
@@ -18,14 +18,18 @@ 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
*/
+@Timeout(value = 10, unit = TimeUnit.SECONDS)
class TabbedViewTest {
/**
* @return a view with all settings set to standard values
@@ -36,17 +40,17 @@ class TabbedViewTest {
private static final TabbedView setupView() {
final var view = new TabbedView();
final var presenter = view.getPresenter();
-
+
presenter.setNumberDisplayRule(StandardDisplayRules.uncertaintyBased());
presenter.setPrefixRepetitionRule(
DefaultPrefixRepetitionRule.NO_RESTRICTION);
presenter.setSearchRule(PrefixSearchRule.COMMON_PREFIXES);
presenter.setOneWayConversionEnabled(false);
presenter.setShowDuplicates(true);
-
+
return view;
}
-
+
/**
* Simulates an expression conversion operation, and ensures it works
* properly.
@@ -57,18 +61,18 @@ class TabbedViewTest {
@Test
void testExpressionConversion() {
final var view = setupView();
-
+
// prepare for unit conversion
view.masterPane.setSelectedIndex(1);
view.fromEntry.setText("250.0 inch");
view.toEntry.setText("metre");
-
+
view.convertExpressionButton.doClick();
-
+
// check result of conversion
assertEquals("250.0 inch = 6.350 metre", view.expressionOutput.getText());
}
-
+
/**
* Simulates a unit conversion operation, and ensures it works properly.
*
@@ -78,18 +82,18 @@ class TabbedViewTest {
@Test
void testUnitConversion() {
final var view = setupView();
-
+
// prepare for unit conversion
view.masterPane.setSelectedIndex(0);
view.dimensionSelector.setSelectedItem("Length");
view.fromSearch.getSearchList().setSelectedValue("inch", true);
view.toSearch.getSearchList().setSelectedValue("metre", true);
view.valueInput.setText("250.0");
-
+
view.convertUnitButton.doClick();
-
+
// check result of conversion
assertEquals("250.0 inch = 6.350 metre", view.unitOutput.getText());
}
-
+
}
--
cgit v1.2.3
From deb4a650caf9eb49d32810e573f22bbd77f0ca47 Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Fri, 7 Mar 2025 11:13:50 -0500
Subject: Add tests for LinearUnitValue
I specifically added tests for the methods that Jacoco says haven't been
tested:
- convertToMultiple
- equals
- equivalent
- hashCode
- operation methods
---
src/test/java/sevenUnits/unit/UnitTest.java | 74 --------
src/test/java/sevenUnits/unit/UnitValueTest.java | 214 +++++++++++++++++++++++
2 files changed, 214 insertions(+), 74 deletions(-)
create mode 100644 src/test/java/sevenUnits/unit/UnitValueTest.java
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java
index 4fb26a3..6ac0ebd 100644
--- a/src/test/java/sevenUnits/unit/UnitTest.java
+++ b/src/test/java/sevenUnits/unit/UnitTest.java
@@ -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,7 +28,6 @@ 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
@@ -153,76 +151,4 @@ class UnitTest {
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..69569ae
--- /dev/null
+++ b/src/test/java/sevenUnits/unit/UnitValueTest.java
@@ -0,0 +1,214 @@
+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;
+
+public final class UnitValueTest {
+ private static Stream 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 others, List 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
+ */
+ @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
+ */
+ @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
+ */
+ @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
+ */
+ @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
+ */
+ @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());
+ }
+}
--
cgit v1.2.3
From 4910b914392753986526bc28102ddef42e275e6c Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Wed, 30 Apr 2025 16:42:01 -0500
Subject: Add more UnitDatabase tests
---
src/main/java/sevenUnits/unit/UnitDatabase.java | 13 +-
.../java/sevenUnits/unit/UnitDatabaseTest.java | 460 +++++++++++++--------
2 files changed, 286 insertions(+), 187 deletions(-)
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java
index dc81aca..690430b 100644
--- a/src/main/java/sevenUnits/unit/UnitDatabase.java
+++ b/src/main/java/sevenUnits/unit/UnitDatabase.java
@@ -1905,18 +1905,23 @@ public final class UnitDatabase {
*
* @since 2024-08-22
*/
- private List getUnitSetFromExpression(String expression) {
+ List getUnitSetFromExpression(String expression) {
final String[] parts = expression.split(";");
final List units = new ArrayList<>(parts.length);
for (final String unitName : parts) {
final Unit unit = this.getUnitFromExpression(unitName.trim());
- if (unit instanceof LinearUnit) {
- units.add((LinearUnit) unit);
- } else
+ if (!(unit instanceof LinearUnit)) {
throw new IllegalArgumentException(String.format(
"Unit '%s' is in a unit-set expression, but is not linear.",
unitName));
+ } else if (units.size() > 0 && !unit.canConvertTo(units.get(0))) {
+ throw new IllegalArgumentException(String.format(
+ "Units in expression '%s' have different dimensions.",
+ expression));
+ }
+
+ units.add((LinearUnit) unit);
}
return units;
}
diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
index e7f3ccf..e55d6af 100644
--- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
+++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
@@ -23,21 +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;
@@ -46,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
@@ -54,18 +54,18 @@ import sevenUnits.utils.UncertainDouble;
class UnitDatabaseTest {
private static final class SimpleEntry implements Map.Entry {
private final K key;
-
+
private V value;
-
+
/**
- *
+ *
* @since 2021-10-07
*/
public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
-
+
@Override
public boolean equals(Object obj) {
if (this == obj)
@@ -76,44 +76,44 @@ class UnitDatabaseTest {
return Objects.equals(this.key, other.getKey())
&& Objects.equals(this.value, other.getValue());
}
-
+
@Override
public K getKey() {
return this.key;
}
-
+
@Override
public V getValue() {
return this.value;
}
-
+
@Override
public int hashCode() {
return (this.key == null ? 0 : this.key.hashCode())
^ (this.value == null ? 0 : this.value.hashCode());
}
-
+
@Override
public V setValue(V value) {
- final V oldValue = this.value;
+ final var oldValue = this.value;
this.value = value;
return oldValue;
}
}
-
+
// some linear units and one nonlinear
private static final Unit U = Metric.METRE;
private static final Unit V = Metric.KILOGRAM;
-
+
private static final Unit W = Metric.SECOND;
// used for testing expressions
// J = U^2 * V / W^2
private static final LinearUnit J = Metric.KILOGRAM
.times(Metric.METRE.toExponent(2))
.dividedBy(Metric.SECOND.toExponent(2));
-
+
private static final LinearUnit K = Metric.KELVIN;
-
+
private static final Unit NONLINEAR = Unit.fromConversionFunctions(
Metric.METRE.getBase(), o -> o + 1, o -> o - 1);
// make the prefix values prime so I can tell which multiplications were made
@@ -124,9 +124,9 @@ class UnitDatabaseTest {
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);
-
+
/**
* Gets a map entry.
*
@@ -140,7 +140,7 @@ class UnitDatabaseTest {
private static Map.Entry entry(K key, V value) {
return new SimpleEntry<>(key, value);
}
-
+
/**
* Loads the dimensionfile at src/test/resources/[path] to the database
* {@code loadTo}.
@@ -152,7 +152,7 @@ class UnitDatabaseTest {
*/
private static List loadDimensionFile(UnitDatabase loadTo,
String path) {
- try (final InputStream testFile = UnitDatabaseTest.class
+ try (final var testFile = UnitDatabaseTest.class
.getResourceAsStream(path)) {
return loadTo.loadDimensionsFromStream(testFile);
} catch (final IOException e) {
@@ -160,7 +160,7 @@ class UnitDatabaseTest {
return Collections.emptyList();
}
}
-
+
/**
* Loads the unitfile at src/test/resources/[path] to the database
* {@code loadTo}.
@@ -172,7 +172,7 @@ class UnitDatabaseTest {
*/
private static List loadUnitsFile(UnitDatabase loadTo,
String path) {
- try (final InputStream testFile = UnitDatabaseTest.class
+ try (final var testFile = UnitDatabaseTest.class
.getResourceAsStream(path)) {
return loadTo.loadUnitsFromStream(testFile);
} catch (final IOException e) {
@@ -180,53 +180,92 @@ class UnitDatabaseTest {
return Collections.emptyList();
}
}
-
+
+ private static final Stream testEvaluateExpressionInvalid() {
+ return Stream.of(Arguments.of("K^K"), Arguments.of("1 + K"));
+ }
+
+ private static final Stream testEvaluateExpressionValid() {
+ 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 - -1 * J",
+ LinearUnitValue.of(J, UncertainDouble.of(2, 1))),
+ Arguments.of("K^2",
+ LinearUnitValue.of(K.times(K), UncertainDouble.of(1, 0))));
+ }
+
+ /**
+ * 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
*/
- @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);
-
+
database.addPrefix("A", A);
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);
}
-
+
/**
* Test for {@link UnitDatabase#getUnit}, {@link UnitDatabase#getLinearUnit}
* and {@link UnitDatabase#getLinearUnitValue}.
- *
+ *
* @since 2021-10-07
*/
@Test
public void testGetUnit() {
- final UnitDatabase database = new UnitDatabase();
-
+ final var database = new UnitDatabase();
+
database.addUnit("m", Metric.METRE);
database.addUnit("meter", Metric.METRE);
database.addUnit("metre", Metric.METRE);
database.addUnit("badname", Metric.METRE);
database.addUnit("K", Metric.KELVIN);
database.addUnit("degC", Metric.CELSIUS);
-
+
// ensure getUnit returns units, regardless of whether the name is one of
// the unit's names
assertEquals(Metric.METRE, database.getUnit("m"));
@@ -235,40 +274,40 @@ class UnitDatabaseTest {
assertEquals(Metric.METRE, database.getUnit("badname"));
assertThrows(NoSuchElementException.class,
() -> database.getUnit("blabla"));
-
+
assertEquals(Metric.KELVIN, database.getLinearUnit("K"));
assertThrows(IllegalArgumentException.class,
() -> database.getLinearUnit("degC"));
assertEquals(Metric.KELVIN.times(373.15),
database.getLinearUnit("degC(100)"));
}
-
+
/**
* 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();
-
+ final var 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> entrySet = infiniteDatabase.unitMap()
+
+ final var entrySet = infiniteDatabase.unitMap()
.entrySet();
- final Set keySet = infiniteDatabase.unitMap().keySet();
+ final var keySet = infiniteDatabase.unitMap().keySet();
assertThrows(IllegalStateException.class, () -> entrySet.toArray());
assertThrows(IllegalStateException.class, () -> keySet.toArray());
}
-
+
/**
* A bunch of tests for invalid dimension files
*
@@ -278,19 +317,19 @@ class UnitDatabaseTest {
@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 List errs = loadDimensionFile(database, filename);
+ final var errs = loadDimensionFile(database, filename);
assertFalse(errs.isEmpty(), "no error from invalid file " + filename);
- final RuntimeException e = errs.get(0).problem();
+ final var e = errs.get(0).problem();
assertTrue(e instanceof IllegalArgumentException
|| e instanceof NoSuchElementException);
}
-
+
/**
* A bunch of tests for invalid unit files
*
@@ -300,113 +339,117 @@ class UnitDatabaseTest {
@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",
+ final var database = new UnitDatabase();
+ final var filename = String.format("/test-unitsfile-invalid%d.txt",
num);
- final List errs = loadUnitsFile(database, filename);
+ final var errs = loadUnitsFile(database, filename);
assertFalse(errs.isEmpty(), "no error from invalid file " + filename);
- final RuntimeException e = errs.get(0).problem();
+ 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
*/
@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);
-
+
loadDimensionFile(database, "/test-dimensionfile-valid1.txt");
assertEquals(Metric.Dimensions.ENERGY, database.getDimension("ENERGY"));
assertEquals(Metric.Dimensions.POWER, database.getDimension("POWER"));
-
+
}
-
+
/**
* Tests loading a valid unitfile with some prefixes and no units.
- *
+ *
* @since 2021-09-22
*/
@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
*/
@Test
public void testLoadingValidUnits() {
- final UnitDatabase database = new UnitDatabase();
-
+ 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);
-
+
loadUnitsFile(database, "/test-unitsfile-valid1.txt");
-
+
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);
-
+
assertTrue(System.err.toString().length() > 0);
}
-
+
/**
* Tests the iterator of the prefixless unit map. These tests are simple, as
* the unit map iterator is simple.
- *
+ *
* @since 2021-10-07
*/
@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 map1 = database1.unitMap();
- final Iterator keyIterator1 = map1.keySet().iterator();
- final Iterator> entryIterator1 = map1.entrySet()
+
+ final var map1 = database1.unitMap();
+ final var keyIterator1 = map1.keySet().iterator();
+ final var entryIterator1 = map1.entrySet()
.iterator();
-
+
final Set expectedKeys = Set.of("U", "V", "W");
final Set actualKeys = new HashSet<>();
while (keyIterator1.hasNext()) {
@@ -414,7 +457,7 @@ class UnitDatabaseTest {
}
assertEquals(expectedKeys, actualKeys);
assertEquals(expectedKeys, map1.keySet());
-
+
final Set> expectedEntries = Set.of(entry("U", U),
entry("V", V), entry("W", W));
final Set> actualEntries = new HashSet<>();
@@ -424,88 +467,88 @@ class UnitDatabaseTest {
assertEquals(expectedEntries, actualEntries);
assertEquals(expectedEntries, map1.entrySet());
}
-
+
/**
* 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);
database.addUnit("W", W);
-
+
database.addPrefix("A", A);
database.addPrefix("B", B);
database.addPrefix("C", C);
-
+
// test the getPrefixesFromName method
final List expected = Arrays.asList(C, B, A);
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.
- *
+ *
*
* The map should be an auto-updating view of the units in the database.
*
- *
+ *
* @since 2019-04-14
* @since v0.2.0
*/
@Test
public void testPrefixlessUnitMap() {
- final UnitDatabase database = new UnitDatabase();
- final Map prefixlessUnits = database
+ final var database = new UnitDatabase();
+ final var prefixlessUnits = database
.unitMapPrefixless(true);
-
+
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();
-
+ final var 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
public void testRemovableDuplicates() {
final Map unitMap = new HashMap<>();
@@ -513,7 +556,7 @@ class UnitDatabaseTest {
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,
@@ -523,131 +566,131 @@ class UnitDatabaseTest {
assertFalse(UnitDatabase.isRemovableDuplicate(unitMap,
entry("second", Metric.SECOND)));
}
-
+
@Test
public void testToString() {
- final UnitDatabase database = new UnitDatabase();
-
+ 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 UnitDatabase database = new UnitDatabase();
-
+ 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 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);
-
+
// 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 UnitDatabase database = new UnitDatabase();
-
+ 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 int NUM_UNITS = database.unitMapPrefixless(true).size();
- final int NUM_PREFIXES = database.prefixMap(true).size();
-
- final Iterator nameIterator = database.unitMap().keySet()
+
+ final var NUM_UNITS = database.unitMapPrefixless(true).size();
+ final var NUM_PREFIXES = database.prefixMap(true).size();
+
+ final var nameIterator = database.unitMap().keySet()
.iterator();
- final Iterator> entryIterator = database.unitMap()
+ 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)) {
expectedLength++;
unitsWithThisLengthSoFar = 0;
}
-
+
// test that stuff is valid
- final String nextName = nameIterator.next();
- final Unit nextUnit = database.getUnit(nextName);
- final Entry 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());
assertEquals(nextUnit, nextEntry.getValue());
-
+
unitsWithThisLengthSoFar++;
}
-
+
// 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());
}
}
-
+
/**
* Determine, given a unit name that could mean multiple things, which
* meaning is chosen.
@@ -655,36 +698,87 @@ 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.
*
- *
+ *
* @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);
-
+
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");
-
+ 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 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
+ */
+ @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
+ */
+ @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"));
+ }
+
}
--
cgit v1.2.3
From e86fb71e1665cb9e8511bafd54df0fb8cbca5adc Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Fri, 30 May 2025 19:48:42 -0500
Subject: Remove Unitlike/MultiUnit
I ended up never using this code - it was simpler to just use lists of
units and values. Making a whole new object for lists of units, and an
abstract class for things that convert things other than doubles, is
needlessly complicated, and doesn't solve any major issues. For
example, I still need to store each Unitlike type in a different
collection, because it will have a different type.
---
.../java/sevenUnits/unit/FunctionalUnitlike.java | 73 ------
src/main/java/sevenUnits/unit/LinearUnit.java | 9 -
src/main/java/sevenUnits/unit/MultiUnit.java | 161 -------------
src/main/java/sevenUnits/unit/Unit.java | 52 ----
src/main/java/sevenUnits/unit/UnitValue.java | 21 --
src/main/java/sevenUnits/unit/Unitlike.java | 262 ---------------------
src/main/java/sevenUnits/unit/UnitlikeValue.java | 176 --------------
src/test/java/sevenUnits/unit/MultiUnitTest.java | 110 ---------
8 files changed, 864 deletions(-)
delete mode 100644 src/main/java/sevenUnits/unit/FunctionalUnitlike.java
delete mode 100644 src/main/java/sevenUnits/unit/MultiUnit.java
delete mode 100644 src/main/java/sevenUnits/unit/Unitlike.java
delete mode 100644 src/main/java/sevenUnits/unit/UnitlikeValue.java
delete mode 100644 src/test/java/sevenUnits/unit/MultiUnitTest.java
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/main/java/sevenUnits/unit/FunctionalUnitlike.java b/src/main/java/sevenUnits/unit/FunctionalUnitlike.java
deleted file mode 100644
index e9b4d1f..0000000
--- a/src/main/java/sevenUnits/unit/FunctionalUnitlike.java
+++ /dev/null
@@ -1,73 +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 .
- */
-package sevenUnits.unit;
-
-import java.util.function.DoubleFunction;
-import java.util.function.ToDoubleFunction;
-
-import sevenUnits.utils.NameSymbol;
-import sevenUnits.utils.ObjectProduct;
-
-/**
- * A unitlike form that converts using two conversion functions.
- *
- * @since 2020-09-07
- */
-final class FunctionalUnitlike extends Unitlike {
- /**
- * A function that accepts a value in the unitlike form's base and returns a
- * value in the unitlike form.
- *
- * @since 2020-09-07
- */
- private final DoubleFunction converterFrom;
-
- /**
- * A function that accepts a value in the unitlike form and returns a value
- * in the unitlike form's base.
- */
- private final ToDoubleFunction converterTo;
-
- /**
- * Creates the {@code FunctionalUnitlike}.
- *
- * @param base unitlike form's base
- * @param converterFrom function that accepts a value in the unitlike form's
- * base and returns a value in the unitlike form.
- * @param converterTo function that accepts a value in the unitlike form
- * and returns a value in the unitlike form's base.
- * @throws NullPointerException if any argument is null
- * @since 2019-05-22
- */
- protected FunctionalUnitlike(ObjectProduct unitBase, NameSymbol ns,
- DoubleFunction converterFrom, ToDoubleFunction converterTo) {
- super(unitBase, ns);
- this.converterFrom = converterFrom;
- this.converterTo = converterTo;
- }
-
- @Override
- protected V convertFromBase(double value) {
- return this.converterFrom.apply(value);
- }
-
- @Override
- protected double convertToBase(V value) {
- return this.converterTo.applyAsDouble(value);
- }
-
-}
diff --git a/src/main/java/sevenUnits/unit/LinearUnit.java b/src/main/java/sevenUnits/unit/LinearUnit.java
index a230f28..3c3703c 100644
--- a/src/main/java/sevenUnits/unit/LinearUnit.java
+++ b/src/main/java/sevenUnits/unit/LinearUnit.java
@@ -74,15 +74,6 @@ public final class LinearUnit extends Unit {
return new LinearUnit(unit.getBase(), 1, NameSymbol.EMPTY);
}
- /**
- * @return the base unit associated with {@code unitlike}, as a
- * {@code LinearUnit}.
- * @since 2020-10-02
- */
- public static LinearUnit getBase(final Unitlike> unit) {
- return new LinearUnit(unit.getBase(), 1, NameSymbol.EMPTY);
- }
-
/**
* Gets a {@code LinearUnit} from a unit base and a conversion factor. In
* other words, gets the product of {@code unitBase} and
diff --git a/src/main/java/sevenUnits/unit/MultiUnit.java b/src/main/java/sevenUnits/unit/MultiUnit.java
deleted file mode 100644
index c6d3b97..0000000
--- a/src/main/java/sevenUnits/unit/MultiUnit.java
+++ /dev/null
@@ -1,161 +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 .
- */
-package sevenUnits.unit;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import sevenUnits.utils.NameSymbol;
-import sevenUnits.utils.ObjectProduct;
-
-/**
- * A combination of units, like "5 foot + 7 inch". All but the last units should
- * have a whole number value associated with them.
- *
- * @since 2020-10-02
- */
-public final class MultiUnit extends Unitlike> {
- /**
- * Creates a {@code MultiUnit} from its units. It will not have a name or
- * symbol.
- *
- * @since 2020-10-03
- */
- public static final MultiUnit of(LinearUnit... units) {
- return of(Arrays.asList(units));
- }
-
- /**
- * Creates a {@code MultiUnit} from its units. It will not have a name or
- * symbol.
- *
- * @since 2020-10-03
- */
- public static final MultiUnit of(List units) {
- if (units.size() < 1)
- throw new IllegalArgumentException("Must have at least one unit");
- final ObjectProduct unitBase = units.get(0).getBase();
- for (final LinearUnit unit : units) {
- if (!unitBase.equals(unit.getBase()))
- throw new IllegalArgumentException(
- "All units must have the same base.");
- }
- return new MultiUnit(new ArrayList<>(units), unitBase, NameSymbol.EMPTY);
- }
-
- /**
- * The units that make up this value.
- */
- private final List units;
-
- /**
- * Creates a {@code MultiUnit}.
- *
- * @since 2020-10-03
- */
- private MultiUnit(List units, ObjectProduct unitBase,
- NameSymbol ns) {
- super(unitBase, ns);
- this.units = units;
- }
-
- @Override
- protected List convertFromBase(double value) {
- final List values = new ArrayList<>(this.units.size());
- double temp = value;
-
- for (final LinearUnit unit : this.units.subList(0,
- this.units.size() - 1)) {
- values.add(Math.floor(temp / unit.getConversionFactor()));
- temp %= unit.getConversionFactor();
- }
-
- values.add(this.units.size() - 1,
- this.units.get(this.units.size() - 1).convertFromBase(temp));
-
- return values;
- }
-
- /**
- * Converts a value expressed in this unitlike form to a value expressed in
- * {@code other}.
- *
- * @implSpec If conversion is possible, this implementation returns
- * {@code other.convertFromBase(this.convertToBase(value))}.
- * Therefore, overriding either of those methods will change the
- * output of this method.
- *
- * @param other unit to convert to
- * @param values values to convert
- * @return converted value
- * @since 2020-10-03
- * @throws IllegalArgumentException if {@code other} is incompatible for
- * conversion with this unitlike form (as
- * tested by {@link Unit#canConvertTo}).
- * @throws NullPointerException if other is null
- */
- public final , V> V convertTo(U other,
- double... values) {
- final List valueList = new ArrayList<>(values.length);
- for (final double d : values) {
- valueList.add(d);
- }
-
- return this.convertTo(other, valueList);
- }
-
- /**
- * Converts a value expressed in this unitlike form to a value expressed in
- * {@code other}.
- *
- * @implSpec If conversion is possible, this implementation returns
- * {@code other.convertFromBase(this.convertToBase(value))}.
- * Therefore, overriding either of those methods will change the
- * output of this method.
- *
- * @param other unit to convert to
- * @param values values to convert
- * @return converted value
- * @since 2020-10-03
- * @throws IllegalArgumentException if {@code other} is incompatible for
- * conversion with this unitlike form (as
- * tested by {@link Unit#canConvertTo}).
- * @throws NullPointerException if other is null
- */
- public final double convertTo(Unit other, double... values) {
- final List valueList = new ArrayList<>(values.length);
- for (final double d : values) {
- valueList.add(d);
- }
-
- return this.convertTo(other, valueList);
- }
-
- @Override
- protected double convertToBase(List value) {
- if (value.size() != this.units.size())
- throw new IllegalArgumentException("Wrong number of values for "
- + this.units.size() + "-unit MultiUnit.");
-
- double baseValue = 0;
- for (int i = 0; i < this.units.size(); i++) {
- baseValue += value.get(i) * this.units.get(i).getConversionFactor();
- }
- return baseValue;
- }
-}
diff --git a/src/main/java/sevenUnits/unit/Unit.java b/src/main/java/sevenUnits/unit/Unit.java
index 59e928a..d25b362 100644
--- a/src/main/java/sevenUnits/unit/Unit.java
+++ b/src/main/java/sevenUnits/unit/Unit.java
@@ -136,15 +136,6 @@ public abstract class Unit implements Nameable {
this.nameSymbol = Objects.requireNonNull(ns, "ns may not be null");
}
- /**
- * @return this unit as a {@link Unitlike}
- * @since 2020-09-07
- */
- public final Unitlike asUnitlike() {
- return Unitlike.fromConversionFunctions(this.getBase(),
- this::convertFromBase, this::convertToBase, this.getNameSymbol());
- }
-
/**
* Checks if a value expressed in this unit can be converted to a value
* expressed in {@code other}
@@ -160,21 +151,6 @@ public abstract class Unit implements Nameable {
return Objects.equals(this.getBase(), other.getBase());
}
- /**
- * Checks if a value expressed in this unit can be converted to a value
- * expressed in {@code other}
- *
- * @param other unit or unitlike form to test with
- * @return true if they are compatible
- * @since 2019-01-13
- * @since v0.1.0
- * @throws NullPointerException if other is null
- */
- public final boolean canConvertTo(final Unitlike other) {
- Objects.requireNonNull(other, "other must not be null.");
- return Objects.equals(this.getBase(), other.getBase());
- }
-
/**
* Converts from a value expressed in this unit's base unit to a value
* expressed in this unit.
@@ -225,34 +201,6 @@ public abstract class Unit implements Nameable {
String.format("Cannot convert from %s to %s.", this, other));
}
- /**
- * Converts a value expressed in this unit to a value expressed in
- * {@code other}.
- *
- * @implSpec If conversion is possible, this implementation returns
- * {@code other.convertFromBase(this.convertToBase(value))}.
- * Therefore, overriding either of those methods will change the
- * output of this method.
- *
- * @param other unitlike form to convert to
- * @param value value to convert
- * @param type of value to convert to
- * @return converted value
- * @since 2020-09-07
- * @throws IllegalArgumentException if {@code other} is incompatible for
- * conversion with this unit (as tested by
- * {@link Unit#canConvertTo}).
- * @throws NullPointerException if other is null
- */
- public final W convertTo(final Unitlike other, final double value) {
- Objects.requireNonNull(other, "other must not be null.");
- if (this.canConvertTo(other))
- return other.convertFromBase(this.convertToBase(value));
- else
- throw new IllegalArgumentException(
- String.format("Cannot convert from %s to %s.", this, other));
- }
-
/**
* Converts from a value expressed in this unit to a value expressed in this
* unit's base unit.
diff --git a/src/main/java/sevenUnits/unit/UnitValue.java b/src/main/java/sevenUnits/unit/UnitValue.java
index 2d01831..9b485e3 100644
--- a/src/main/java/sevenUnits/unit/UnitValue.java
+++ b/src/main/java/sevenUnits/unit/UnitValue.java
@@ -63,27 +63,6 @@ public final class UnitValue {
return this.unit.canConvertTo(other);
}
- /**
- * @return true if this value can be converted to {@code other}.
- * @since 2020-10-01
- */
- public final boolean canConvertTo(Unitlike other) {
- return this.unit.canConvertTo(other);
- }
-
- /**
- * Returns a UnitlikeValue that represents the same value expressed in a
- * different unitlike form.
- *
- * @param other new unit to express value in
- * @return value expressed in {@code other}
- */
- public final , W> UnitlikeValue convertTo(
- U other) {
- return UnitlikeValue.of(other,
- this.unit.convertTo(other, this.getValue()));
- }
-
/**
* Returns a UnitValue that represents the same value expressed in a
* different unit
diff --git a/src/main/java/sevenUnits/unit/Unitlike.java b/src/main/java/sevenUnits/unit/Unitlike.java
deleted file mode 100644
index fef424e..0000000
--- a/src/main/java/sevenUnits/unit/Unitlike.java
+++ /dev/null
@@ -1,262 +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 .
- */
-package sevenUnits.unit;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.function.DoubleFunction;
-import java.util.function.ToDoubleFunction;
-
-import sevenUnits.utils.NameSymbol;
-import sevenUnits.utils.Nameable;
-import sevenUnits.utils.ObjectProduct;
-
-/**
- * An object that can convert a value between multiple forms (instances of the
- * object); like a unit but the "converted value" can be any type.
- *
- * @since 2020-09-07
- */
-public abstract class Unitlike implements Nameable {
- /**
- * Returns a unitlike form from its base and the functions it uses to convert
- * to and from its base.
- *
- * @param base unitlike form's base
- * @param converterFrom function that accepts a value expressed in the
- * unitlike form's base and returns that value expressed
- * in this unitlike form.
- * @param converterTo function that accepts a value expressed in the
- * unitlike form and returns that value expressed in the
- * unit's base.
- * @return a unitlike form that uses the provided functions to convert.
- * @since 2020-09-07
- * @throws NullPointerException if any argument is null
- */
- public static final Unitlike fromConversionFunctions(
- final ObjectProduct base,
- final DoubleFunction converterFrom,
- final ToDoubleFunction converterTo) {
- return new FunctionalUnitlike<>(base, NameSymbol.EMPTY, converterFrom,
- converterTo);
- }
-
- /**
- * Returns a unitlike form from its base and the functions it uses to convert
- * to and from its base.
- *
- * @param base unitlike form's base
- * @param converterFrom function that accepts a value expressed in the
- * unitlike form's base and returns that value expressed
- * in this unitlike form.
- * @param converterTo function that accepts a value expressed in the
- * unitlike form and returns that value expressed in the
- * unit's base.
- * @param ns names and symbol of unit
- * @return a unitlike form that uses the provided functions to convert.
- * @since 2020-09-07
- * @throws NullPointerException if any argument is null
- */
- public static final Unitlike fromConversionFunctions(
- final ObjectProduct base,
- final DoubleFunction converterFrom,
- final ToDoubleFunction converterTo, final NameSymbol ns) {
- return new FunctionalUnitlike<>(base, ns, converterFrom, converterTo);
- }
-
- /**
- * The combination of units that this unit is based on.
- *
- * @since 2019-10-16
- */
- private final ObjectProduct unitBase;
-
- /**
- * This unit's name(s) and symbol
- *
- * @since 2020-09-07
- */
- private final NameSymbol nameSymbol;
-
- /**
- * Cache storing the result of getDimension()
- *
- * @since 2019-10-16
- */
- private transient ObjectProduct dimension = null;
-
- /**
- * @param unitBase
- * @since 2020-09-07
- */
- protected Unitlike(ObjectProduct unitBase, NameSymbol ns) {
- this.unitBase = Objects.requireNonNull(unitBase,
- "unitBase may not be null");
- this.nameSymbol = Objects.requireNonNull(ns, "ns may not be null");
- }
-
- /**
- * Checks if a value expressed in this unitlike form can be converted to a
- * value expressed in {@code other}
- *
- * @param other unit or unitlike form to test with
- * @return true if they are compatible
- * @since 2019-01-13
- * @since v0.1.0
- * @throws NullPointerException if other is null
- */
- public final boolean canConvertTo(final Unit other) {
- Objects.requireNonNull(other, "other must not be null.");
- return Objects.equals(this.getBase(), other.getBase());
- }
-
- /**
- * Checks if a value expressed in this unitlike form can be converted to a
- * value expressed in {@code other}
- *
- * @param other unit or unitlike form to test with
- * @return true if they are compatible
- * @since 2019-01-13
- * @since v0.1.0
- * @throws NullPointerException if other is null
- */
- public final boolean canConvertTo(final Unitlike other) {
- Objects.requireNonNull(other, "other must not be null.");
- return Objects.equals(this.getBase(), other.getBase());
- }
-
- protected abstract V convertFromBase(double value);
-
- /**
- * Converts a value expressed in this unitlike form to a value expressed in
- * {@code other}.
- *
- * @implSpec If conversion is possible, this implementation returns
- * {@code other.convertFromBase(this.convertToBase(value))}.
- * Therefore, overriding either of those methods will change the
- * output of this method.
- *
- * @param other unit to convert to
- * @param value value to convert
- * @return converted value
- * @since 2019-05-22
- * @throws IllegalArgumentException if {@code other} is incompatible for
- * conversion with this unitlike form (as
- * tested by {@link Unit#canConvertTo}).
- * @throws NullPointerException if other is null
- */
- public final double convertTo(final Unit other, final V value) {
- Objects.requireNonNull(other, "other must not be null.");
- if (this.canConvertTo(other))
- return other.convertFromBase(this.convertToBase(value));
- else
- throw new IllegalArgumentException(
- String.format("Cannot convert from %s to %s.", this, other));
- }
-
- /**
- * Converts a value expressed in this unitlike form to a value expressed in
- * {@code other}.
- *
- * @implSpec If conversion is possible, this implementation returns
- * {@code other.convertFromBase(this.convertToBase(value))}.
- * Therefore, overriding either of those methods will change the
- * output of this method.
- *
- * @param other unitlike form to convert to
- * @param value value to convert
- * @param type of value to convert to
- * @return converted value
- * @since 2020-09-07
- * @throws IllegalArgumentException if {@code other} is incompatible for
- * conversion with this unitlike form (as
- * tested by {@link Unit#canConvertTo}).
- * @throws NullPointerException if other is null
- */
- public final W convertTo(final Unitlike other, final V value) {
- Objects.requireNonNull(other, "other must not be null.");
- if (this.canConvertTo(other))
- return other.convertFromBase(this.convertToBase(value));
- else
- throw new IllegalArgumentException(
- String.format("Cannot convert from %s to %s.", this, other));
- }
-
- protected abstract double convertToBase(V value);
-
- /**
- * @return combination of units that this unit is based on
- * @since 2018-12-22
- * @since v0.1.0
- */
- public final ObjectProduct getBase() {
- return this.unitBase;
- }
-
- /**
- * @return dimension measured by this unit
- * @since 2018-12-22
- * @since v0.1.0
- */
- public final ObjectProduct getDimension() {
- if (this.dimension == null) {
- final Map mapping = this.unitBase.exponentMap();
- final Map dimensionMap = new HashMap<>();
-
- for (final BaseUnit key : mapping.keySet()) {
- dimensionMap.put(key.getBaseDimension(), mapping.get(key));
- }
-
- this.dimension = ObjectProduct.fromExponentMapping(dimensionMap);
- }
- return this.dimension;
- }
-
- /**
- * @return the nameSymbol
- * @since 2020-09-07
- */
- @Override
- public final NameSymbol getNameSymbol() {
- return this.nameSymbol;
- }
-
- @Override
- public String toString() {
- return this.getPrimaryName().orElse("Unnamed unitlike form")
- + (this.getSymbol().isPresent()
- ? String.format(" (%s)", this.getSymbol().get())
- : "")
- + ", derived from "
- + this.getBase().toString(u -> u.getSymbol().get())
- + (this.getOtherNames().isEmpty() ? ""
- : ", also called " + String.join(", ", this.getOtherNames()));
- }
-
- /**
- * @param ns name(s) and symbol to use
- * @return a copy of this unitlike form with provided name(s) and symbol
- * @since 2020-09-07
- * @throws NullPointerException if ns is null
- */
- public Unitlike withName(final NameSymbol ns) {
- return fromConversionFunctions(this.getBase(), this::convertFromBase,
- this::convertToBase,
- Objects.requireNonNull(ns, "ns must not be null."));
- }
-}
diff --git a/src/main/java/sevenUnits/unit/UnitlikeValue.java b/src/main/java/sevenUnits/unit/UnitlikeValue.java
deleted file mode 100644
index ad0d1ea..0000000
--- a/src/main/java/sevenUnits/unit/UnitlikeValue.java
+++ /dev/null
@@ -1,176 +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 .
- */
-package sevenUnits.unit;
-
-import java.util.Optional;
-
-import sevenUnits.utils.NameSymbol;
-
-/**
- *
- * @since 2020-09-07
- */
-final class UnitlikeValue, V> {
- /**
- * Gets a {@code UnitlikeValue}.
- *
- * @since 2020-10-02
- */
- public static , V> UnitlikeValue of(T unitlike,
- V value) {
- return new UnitlikeValue<>(unitlike, value);
- }
-
- private final T unitlike;
- private final V value;
-
- /**
- * @param unitlike
- * @param value
- * @since 2020-09-07
- */
- private UnitlikeValue(T unitlike, V value) {
- this.unitlike = unitlike;
- this.value = value;
- }
-
- /**
- * @return true if this value can be converted to {@code other}.
- * @since 2020-10-01
- */
- public final boolean canConvertTo(Unit other) {
- return this.unitlike.canConvertTo(other);
- }
-
- /**
- * @return true if this value can be converted to {@code other}.
- * @since 2020-10-01
- */
- public final boolean canConvertTo(Unitlike other) {
- return this.unitlike.canConvertTo(other);
- }
-
- /**
- * Returns a UnitlikeValue that represents the same value expressed in a
- * different unitlike form.
- *
- * @param other new unit to express value in
- * @return value expressed in {@code other}
- */
- public final , W> UnitlikeValue convertTo(
- U other) {
- return UnitlikeValue.of(other,
- this.unitlike.convertTo(other, this.getValue()));
- }
-
- /**
- * Returns a UnitValue that represents the same value expressed in a
- * different unit
- *
- * @param other new unit to express value in
- * @return value expressed in {@code other}
- */
- public final UnitValue convertTo(Unit other) {
- return UnitValue.of(other,
- this.unitlike.convertTo(other, this.getValue()));
- }
-
- /**
- * Returns this unit value represented as a {@code LinearUnitValue} with this
- * unit's base unit as the base.
- *
- * @param ns name and symbol for the base unit, use NameSymbol.EMPTY if not
- * needed.
- * @since 2020-09-29
- */
- public final LinearUnitValue convertToBase(NameSymbol ns) {
- final LinearUnit base = LinearUnit.getBase(this.unitlike).withName(ns);
- return this.convertToLinear(base);
- }
-
- /**
- * @return a {@code LinearUnitValue} that is equivalent to this value. It
- * will have zero uncertainty.
- * @since 2020-09-29
- */
- public final LinearUnitValue convertToLinear(LinearUnit other) {
- return LinearUnitValue.getExact(other,
- this.getUnitlike().convertTo(other, this.getValue()));
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!(obj instanceof UnitlikeValue))
- return false;
- final UnitlikeValue, ?> other = (UnitlikeValue, ?>) obj;
- if (this.getUnitlike() == null) {
- if (other.getUnitlike() != null)
- return false;
- } else if (!this.getUnitlike().equals(other.getUnitlike()))
- return false;
- if (this.getValue() == null) {
- if (other.getValue() != null)
- return false;
- } else if (!this.getValue().equals(other.getValue()))
- return false;
- return true;
- }
-
- /**
- * @return the unitlike
- * @since 2020-09-29
- */
- public final Unitlike getUnitlike() {
- return this.unitlike;
- }
-
- /**
- * @return the value
- * @since 2020-09-29
- */
- public final V getValue() {
- return this.value;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + (this.getUnitlike() == null ? 0 : this.getUnitlike().hashCode());
- result = prime * result
- + (this.getValue() == null ? 0 : this.getValue().hashCode());
- return result;
- }
-
- @Override
- public String toString() {
- final Optional primaryName = this.getUnitlike().getPrimaryName();
- final Optional symbol = this.getUnitlike().getSymbol();
- if (primaryName.isEmpty() && symbol.isEmpty()) {
- final double baseValue = this.getUnitlike()
- .convertToBase(this.getValue());
- return String.format("%s unnamed unit (= %s %s)", this.getValue(),
- baseValue, this.getUnitlike().getBase());
- } else {
- final String unitName = symbol.orElse(primaryName.get());
- return this.getValue() + " " + unitName;
- }
- }
-}
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 .
- */
-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 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 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 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);
- }
- }
-}
--
cgit v1.2.3
From 7db19d307970b73559239ec343c92c7876510c2a Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Fri, 30 May 2025 20:10:09 -0500
Subject: Ensure LinearUnit&Prefix ==/hash obey contracts
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Previously, these classes' equals() and hashCode() methods did not obey
the contracts:
For equals(), I considered two values equal even if there was a very
small deviation, in order to avoid floating-point error. This equals
relation is not transitive (i.e. it is possible that a = b && b = c but
a ≠ c), violating the contract of equals.
This also makes it impossible to properly implement hashCode, as if two
values are equal, they must have the same hash code. The solution I had
provided is an ineffective hack, which could mess with hash maps and
sets.
I have changed the implementation to demand exact equality. I have also
provided equalsApproximately() methods to both classes that use the old
behaviour. Hash codes are only really used for hash maps, and the old
implementation doesn't even achieve its purpose, so I did not add a
method to return the old hash behaviour.
---
src/main/java/sevenUnits/unit/LinearUnit.java | 15 ++++++++++++++-
src/main/java/sevenUnits/unit/UnitPrefix.java | 18 +++++++++++++++++-
src/main/java/sevenUnits/utils/DecimalComparison.java | 15 ---------------
src/test/java/sevenUnits/unit/UnitTest.java | 8 ++++++--
4 files changed, 37 insertions(+), 19 deletions(-)
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/main/java/sevenUnits/unit/LinearUnit.java b/src/main/java/sevenUnits/unit/LinearUnit.java
index 3c3703c..d453a43 100644
--- a/src/main/java/sevenUnits/unit/LinearUnit.java
+++ b/src/main/java/sevenUnits/unit/LinearUnit.java
@@ -226,6 +226,19 @@ public final class LinearUnit extends Unit {
if (!(obj instanceof LinearUnit))
return false;
final LinearUnit other = (LinearUnit) obj;
+ return Objects.equals(this.getBase(), other.getBase())
+ && Double.compare(this.getConversionFactor(),
+ other.getConversionFactor()) == 0;
+ }
+
+ /**
+ * @return true iff this unit and other are equal,
+ * ignoring small differences caused by floating-point error.
+ *
+ * @apiNote This method is not transitive,
+ * so it cannot be used as an equals method.
+ */
+ public boolean equalsApproximately(final LinearUnit other) {
return Objects.equals(this.getBase(), other.getBase())
&& DecimalComparison.equals(this.getConversionFactor(),
other.getConversionFactor());
@@ -247,7 +260,7 @@ public final class LinearUnit extends Unit {
@Override
public int hashCode() {
return 31 * this.getBase().hashCode()
- + DecimalComparison.hash(this.getConversionFactor());
+ + Double.hashCode(this.getConversionFactor());
}
/**
diff --git a/src/main/java/sevenUnits/unit/UnitPrefix.java b/src/main/java/sevenUnits/unit/UnitPrefix.java
index 9035969..ec4be48 100644
--- a/src/main/java/sevenUnits/unit/UnitPrefix.java
+++ b/src/main/java/sevenUnits/unit/UnitPrefix.java
@@ -119,6 +119,22 @@ public final class UnitPrefix implements Nameable {
if (!(obj instanceof UnitPrefix))
return false;
final UnitPrefix other = (UnitPrefix) obj;
+ return Double.compare(this.getMultiplier(),
+ other.getMultiplier()) == 0;
+ }
+
+ /**
+ * @return true iff this prefix and other are equal,
+ * ignoring small differences caused by floating-point error.
+ *
+ * @apiNote This method is not transitive,
+ * so it cannot be used as an equals method.
+ */
+ public boolean equalsApproximately(final UnitPrefix other) {
+ if (this == other)
+ return true;
+ if (other == null)
+ return false;
return DecimalComparison.equals(this.getMultiplier(),
other.getMultiplier());
}
@@ -143,7 +159,7 @@ public final class UnitPrefix implements Nameable {
*/
@Override
public int hashCode() {
- return DecimalComparison.hash(this.getMultiplier());
+ return Double.hashCode(this.getMultiplier());
}
/**
diff --git a/src/main/java/sevenUnits/utils/DecimalComparison.java b/src/main/java/sevenUnits/utils/DecimalComparison.java
index 62c3720..03dd15b 100644
--- a/src/main/java/sevenUnits/utils/DecimalComparison.java
+++ b/src/main/java/sevenUnits/utils/DecimalComparison.java
@@ -69,7 +69,6 @@ public final class DecimalComparison {
* @return whether they are equal
* @since 2019-03-18
* @since v0.2.0
- * @see #hash(double)
*/
public static final boolean equals(final double a, final double b) {
return DecimalComparison.equals(a, b, DOUBLE_EPSILON);
@@ -194,7 +193,6 @@ public final class DecimalComparison {
* @param b second value to test
* @return whether they are equal
* @since 2020-09-07
- * @see #hash(double)
*/
public static final boolean equals(final UncertainDouble a,
final UncertainDouble b) {
@@ -236,19 +234,6 @@ public final class DecimalComparison {
epsilon);
}
- /**
- * Takes the hash code of doubles. Values that are equal according to
- * {@link #equals(double, double)} will probably have the same hash code.
- *
- * @param d double to hash
- * @return hash code of double
- * @since 2019-10-16
- */
- // TODO reconsider using this
- public static final int hash(final double d) {
- return Float.hashCode((float) d);
- }
-
// You may NOT get any DecimalComparison instances
private DecimalComparison() {
throw new AssertionError();
diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java
index 6ac0ebd..f8d3040 100644
--- a/src/test/java/sevenUnits/unit/UnitTest.java
+++ b/src/test/java/sevenUnits/unit/UnitTest.java
@@ -48,8 +48,12 @@ class UnitTest {
final LinearUnit 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);
--
cgit v1.2.3
From d80b80857e739eb32afd7625789944abd3afe376 Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Wed, 4 Jun 2025 18:58:15 -0500
Subject: Update copyright notices' years
I used the Git history for years after 2019, and only included 2019 or
2018 if they were already there. I also added copyright notices to all
code files that don't already have them.
---
src/main/java/sevenUnits/ProgramInfo.java | 2 +-
src/main/java/sevenUnits/package-info.java | 2 +-
src/main/java/sevenUnits/unit/BaseDimension.java | 2 +-
src/main/java/sevenUnits/unit/BaseUnit.java | 2 +-
src/main/java/sevenUnits/unit/BritishImperial.java | 2 +-
src/main/java/sevenUnits/unit/FunctionalUnit.java | 2 +-
src/main/java/sevenUnits/unit/LinearUnit.java | 2 +-
src/main/java/sevenUnits/unit/LinearUnitValue.java | 2 +-
src/main/java/sevenUnits/unit/LoadingException.java | 2 +-
src/main/java/sevenUnits/unit/Metric.java | 2 +-
src/main/java/sevenUnits/unit/USCustomary.java | 2 +-
src/main/java/sevenUnits/unit/Unit.java | 2 +-
src/main/java/sevenUnits/unit/UnitDatabase.java | 2 +-
src/main/java/sevenUnits/unit/UnitPrefix.java | 2 +-
src/main/java/sevenUnits/unit/UnitType.java | 2 +-
src/main/java/sevenUnits/unit/UnitValue.java | 2 +-
src/main/java/sevenUnits/unit/package-info.java | 2 +-
.../utils/ConditionalExistenceCollections.java | 2 +-
src/main/java/sevenUnits/utils/DecimalComparison.java | 2 +-
src/main/java/sevenUnits/utils/ExpressionParser.java | 2 +-
src/main/java/sevenUnits/utils/NameSymbol.java | 2 +-
src/main/java/sevenUnits/utils/Nameable.java | 2 +-
src/main/java/sevenUnits/utils/ObjectProduct.java | 2 +-
.../java/sevenUnits/utils/SemanticVersionNumber.java | 2 +-
src/main/java/sevenUnits/utils/UncertainDouble.java | 2 +-
src/main/java/sevenUnits/utils/package-info.java | 2 +-
.../java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java | 15 ++++++++++++++-
src/main/java/sevenUnitsGUI/DelegateListModel.java | 2 +-
.../java/sevenUnitsGUI/ExpressionConversionView.java | 2 +-
src/main/java/sevenUnitsGUI/FilterComparator.java | 2 +-
src/main/java/sevenUnitsGUI/GridBagBuilder.java | 2 +-
src/main/java/sevenUnitsGUI/Main.java | 2 +-
src/main/java/sevenUnitsGUI/PrefixSearchRule.java | 2 +-
src/main/java/sevenUnitsGUI/Presenter.java | 2 +-
src/main/java/sevenUnitsGUI/SearchBoxList.java | 2 +-
src/main/java/sevenUnitsGUI/StandardDisplayRules.java | 2 +-
src/main/java/sevenUnitsGUI/TabbedView.java | 2 +-
src/main/java/sevenUnitsGUI/UnitConversionRecord.java | 2 +-
src/main/java/sevenUnitsGUI/UnitConversionView.java | 2 +-
src/main/java/sevenUnitsGUI/View.java | 2 +-
src/main/java/sevenUnitsGUI/ViewBot.java | 2 +-
src/main/java/sevenUnitsGUI/package-info.java | 2 +-
src/test/java/sevenUnits/unit/UnitDatabaseTest.java | 2 +-
src/test/java/sevenUnits/unit/UnitTest.java | 2 +-
src/test/java/sevenUnits/unit/UnitValueTest.java | 16 ++++++++++++++++
.../utils/ConditionalExistenceCollectionsTest.java | 2 +-
src/test/java/sevenUnits/utils/ExpressionParserTest.java | 2 +-
src/test/java/sevenUnits/utils/NameSymbolTest.java | 16 ++++++++++++++++
src/test/java/sevenUnits/utils/ObjectProductTest.java | 2 +-
src/test/java/sevenUnits/utils/SemanticVersionTest.java | 2 +-
src/test/java/sevenUnits/utils/UncertainDoubleTest.java | 2 +-
src/test/java/sevenUnitsGUI/I18nTest.java | 16 ++++++++++++++++
src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java | 2 +-
src/test/java/sevenUnitsGUI/PrefixSearchTest.java | 2 +-
src/test/java/sevenUnitsGUI/PresenterTest.java | 2 +-
src/test/java/sevenUnitsGUI/RoundingTest.java | 2 +-
src/test/java/sevenUnitsGUI/TabbedViewTest.java | 2 +-
57 files changed, 115 insertions(+), 54 deletions(-)
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/main/java/sevenUnits/ProgramInfo.java b/src/main/java/sevenUnits/ProgramInfo.java
index 4fd4375..dda5d2c 100644
--- a/src/main/java/sevenUnits/ProgramInfo.java
+++ b/src/main/java/sevenUnits/ProgramInfo.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021-2024 Adrien Hopkins
+ * 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
diff --git a/src/main/java/sevenUnits/package-info.java b/src/main/java/sevenUnits/package-info.java
index 33b98fc..b90a5ea 100644
--- a/src/main/java/sevenUnits/package-info.java
+++ b/src/main/java/sevenUnits/package-info.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019-2021 Adrien Hopkins
+ * Copyright (C) 2019-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
diff --git a/src/main/java/sevenUnits/unit/BaseDimension.java b/src/main/java/sevenUnits/unit/BaseDimension.java
index 3f1f75f..cfa6af9 100644
--- a/src/main/java/sevenUnits/unit/BaseDimension.java
+++ b/src/main/java/sevenUnits/unit/BaseDimension.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019, 2022 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
diff --git a/src/main/java/sevenUnits/unit/BaseUnit.java b/src/main/java/sevenUnits/unit/BaseUnit.java
index 4781be9..0d375f8 100644
--- a/src/main/java/sevenUnits/unit/BaseUnit.java
+++ b/src/main/java/sevenUnits/unit/BaseUnit.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
diff --git a/src/main/java/sevenUnits/unit/BritishImperial.java b/src/main/java/sevenUnits/unit/BritishImperial.java
index 16255da..e327055 100644
--- a/src/main/java/sevenUnits/unit/BritishImperial.java
+++ b/src/main/java/sevenUnits/unit/BritishImperial.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
diff --git a/src/main/java/sevenUnits/unit/FunctionalUnit.java b/src/main/java/sevenUnits/unit/FunctionalUnit.java
index 8ca87b3..fb24629 100644
--- a/src/main/java/sevenUnits/unit/FunctionalUnit.java
+++ b/src/main/java/sevenUnits/unit/FunctionalUnit.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
diff --git a/src/main/java/sevenUnits/unit/LinearUnit.java b/src/main/java/sevenUnits/unit/LinearUnit.java
index 99bea96..6c1aba3 100644
--- a/src/main/java/sevenUnits/unit/LinearUnit.java
+++ b/src/main/java/sevenUnits/unit/LinearUnit.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
diff --git a/src/main/java/sevenUnits/unit/LinearUnitValue.java b/src/main/java/sevenUnits/unit/LinearUnitValue.java
index e4cc820..8d30907 100644
--- a/src/main/java/sevenUnits/unit/LinearUnitValue.java
+++ b/src/main/java/sevenUnits/unit/LinearUnitValue.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
diff --git a/src/main/java/sevenUnits/unit/LoadingException.java b/src/main/java/sevenUnits/unit/LoadingException.java
index 18630a4..b806147 100644
--- a/src/main/java/sevenUnits/unit/LoadingException.java
+++ b/src/main/java/sevenUnits/unit/LoadingException.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2024 Adrien Hopkins
+ * Copyright (C) 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
diff --git a/src/main/java/sevenUnits/unit/Metric.java b/src/main/java/sevenUnits/unit/Metric.java
index 16859bf..166cbcf 100644
--- a/src/main/java/sevenUnits/unit/Metric.java
+++ b/src/main/java/sevenUnits/unit/Metric.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
diff --git a/src/main/java/sevenUnits/unit/USCustomary.java b/src/main/java/sevenUnits/unit/USCustomary.java
index fa3f26e..1923d9e 100644
--- a/src/main/java/sevenUnits/unit/USCustomary.java
+++ b/src/main/java/sevenUnits/unit/USCustomary.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
diff --git a/src/main/java/sevenUnits/unit/Unit.java b/src/main/java/sevenUnits/unit/Unit.java
index 61a5dbf..5d67ed0 100644
--- a/src/main/java/sevenUnits/unit/Unit.java
+++ b/src/main/java/sevenUnits/unit/Unit.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
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java
index 95e953f..6cf794b 100644
--- a/src/main/java/sevenUnits/unit/UnitDatabase.java
+++ b/src/main/java/sevenUnits/unit/UnitDatabase.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2018-2024 Adrien Hopkins
+ * Copyright (C) 2018-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
diff --git a/src/main/java/sevenUnits/unit/UnitPrefix.java b/src/main/java/sevenUnits/unit/UnitPrefix.java
index be4d8fb..6ac9128 100644
--- a/src/main/java/sevenUnits/unit/UnitPrefix.java
+++ b/src/main/java/sevenUnits/unit/UnitPrefix.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
diff --git a/src/main/java/sevenUnits/unit/UnitType.java b/src/main/java/sevenUnits/unit/UnitType.java
index 6c0f7a9..d445418 100644
--- a/src/main/java/sevenUnits/unit/UnitType.java
+++ b/src/main/java/sevenUnits/unit/UnitType.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
diff --git a/src/main/java/sevenUnits/unit/UnitValue.java b/src/main/java/sevenUnits/unit/UnitValue.java
index aee836e..97b7e54 100644
--- a/src/main/java/sevenUnits/unit/UnitValue.java
+++ b/src/main/java/sevenUnits/unit/UnitValue.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
diff --git a/src/main/java/sevenUnits/unit/package-info.java b/src/main/java/sevenUnits/unit/package-info.java
index 6aedb9d..6d867d3 100644
--- a/src/main/java/sevenUnits/unit/package-info.java
+++ b/src/main/java/sevenUnits/unit/package-info.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019 Adrien Hopkins
+ * Copyright (C) 2019-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
diff --git a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
index cb3b8ce..b46e821 100644
--- a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
+++ b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.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
diff --git a/src/main/java/sevenUnits/utils/DecimalComparison.java b/src/main/java/sevenUnits/utils/DecimalComparison.java
index 03dd15b..4136818 100644
--- a/src/main/java/sevenUnits/utils/DecimalComparison.java
+++ b/src/main/java/sevenUnits/utils/DecimalComparison.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
diff --git a/src/main/java/sevenUnits/utils/ExpressionParser.java b/src/main/java/sevenUnits/utils/ExpressionParser.java
index 4f9cfa8..8ab6c95 100644
--- a/src/main/java/sevenUnits/utils/ExpressionParser.java
+++ b/src/main/java/sevenUnits/utils/ExpressionParser.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019, 2024 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
diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java
index a91009e..c0c8f94 100644
--- a/src/main/java/sevenUnits/utils/NameSymbol.java
+++ b/src/main/java/sevenUnits/utils/NameSymbol.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019 Adrien Hopkins
+ * Copyright (C) 2019, 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
diff --git a/src/main/java/sevenUnits/utils/Nameable.java b/src/main/java/sevenUnits/utils/Nameable.java
index 3959a64..15026b7 100644
--- a/src/main/java/sevenUnits/utils/Nameable.java
+++ b/src/main/java/sevenUnits/utils/Nameable.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2020 Adrien Hopkins
+ * Copyright (C) 2020, 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
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index 3861095..772ff5e 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.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
diff --git a/src/main/java/sevenUnits/utils/SemanticVersionNumber.java b/src/main/java/sevenUnits/utils/SemanticVersionNumber.java
index 937d474..bf198ae 100644
--- a/src/main/java/sevenUnits/utils/SemanticVersionNumber.java
+++ b/src/main/java/sevenUnits/utils/SemanticVersionNumber.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
diff --git a/src/main/java/sevenUnits/utils/UncertainDouble.java b/src/main/java/sevenUnits/utils/UncertainDouble.java
index c70574a..46803d1 100644
--- a/src/main/java/sevenUnits/utils/UncertainDouble.java
+++ b/src/main/java/sevenUnits/utils/UncertainDouble.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2020 Adrien Hopkins
+ * Copyright (C) 2020-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
diff --git a/src/main/java/sevenUnits/utils/package-info.java b/src/main/java/sevenUnits/utils/package-info.java
index 350c62d..6cae117 100644
--- a/src/main/java/sevenUnits/utils/package-info.java
+++ b/src/main/java/sevenUnits/utils/package-info.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2018-2020 Adrien Hopkins
+ * Copyright (C) 2018-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
diff --git a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
index ccc9f1c..fbf78a3 100644
--- a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
+++ b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
@@ -1,5 +1,18 @@
/**
- * @since 2020-08-26
+ * Copyright (C) 2020, 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 sevenUnitsGUI;
diff --git a/src/main/java/sevenUnitsGUI/DelegateListModel.java b/src/main/java/sevenUnitsGUI/DelegateListModel.java
index 798383b..4925197 100644
--- a/src/main/java/sevenUnitsGUI/DelegateListModel.java
+++ b/src/main/java/sevenUnitsGUI/DelegateListModel.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2018 Adrien Hopkins
+ * Copyright (C) 2018, 2022, 2024 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
diff --git a/src/main/java/sevenUnitsGUI/ExpressionConversionView.java b/src/main/java/sevenUnitsGUI/ExpressionConversionView.java
index 882c995..ead07c5 100644
--- a/src/main/java/sevenUnitsGUI/ExpressionConversionView.java
+++ b/src/main/java/sevenUnitsGUI/ExpressionConversionView.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
diff --git a/src/main/java/sevenUnitsGUI/FilterComparator.java b/src/main/java/sevenUnitsGUI/FilterComparator.java
index 484a98f..d7a59c4 100644
--- a/src/main/java/sevenUnitsGUI/FilterComparator.java
+++ b/src/main/java/sevenUnitsGUI/FilterComparator.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2018 Adrien Hopkins
+ * Copyright (C) 2018, 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
diff --git a/src/main/java/sevenUnitsGUI/GridBagBuilder.java b/src/main/java/sevenUnitsGUI/GridBagBuilder.java
index 95fc094..81d1e79 100644
--- a/src/main/java/sevenUnitsGUI/GridBagBuilder.java
+++ b/src/main/java/sevenUnitsGUI/GridBagBuilder.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2018 Adrien Hopkins
+ * Copyright (C) 2018, 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
diff --git a/src/main/java/sevenUnitsGUI/Main.java b/src/main/java/sevenUnitsGUI/Main.java
index ff61b3b..b573a09 100644
--- a/src/main/java/sevenUnitsGUI/Main.java
+++ b/src/main/java/sevenUnitsGUI/Main.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
diff --git a/src/main/java/sevenUnitsGUI/PrefixSearchRule.java b/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
index 69f09e6..1937fd2 100644
--- a/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
+++ b/src/main/java/sevenUnitsGUI/PrefixSearchRule.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
diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java
index 6dce39d..7c66d55 100644
--- a/src/main/java/sevenUnitsGUI/Presenter.java
+++ b/src/main/java/sevenUnitsGUI/Presenter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021-2022 Adrien Hopkins
+ * 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
diff --git a/src/main/java/sevenUnitsGUI/SearchBoxList.java b/src/main/java/sevenUnitsGUI/SearchBoxList.java
index 8fba459..1748083 100644
--- a/src/main/java/sevenUnitsGUI/SearchBoxList.java
+++ b/src/main/java/sevenUnitsGUI/SearchBoxList.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2019 Adrien Hopkins
+ * Copyright (C) 2019, 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
diff --git a/src/main/java/sevenUnitsGUI/StandardDisplayRules.java b/src/main/java/sevenUnitsGUI/StandardDisplayRules.java
index ff9c64e..a19b680 100644
--- a/src/main/java/sevenUnitsGUI/StandardDisplayRules.java
+++ b/src/main/java/sevenUnitsGUI/StandardDisplayRules.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
diff --git a/src/main/java/sevenUnitsGUI/TabbedView.java b/src/main/java/sevenUnitsGUI/TabbedView.java
index 9850aac..97b93dc 100644
--- a/src/main/java/sevenUnitsGUI/TabbedView.java
+++ b/src/main/java/sevenUnitsGUI/TabbedView.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
diff --git a/src/main/java/sevenUnitsGUI/UnitConversionRecord.java b/src/main/java/sevenUnitsGUI/UnitConversionRecord.java
index da1a9d2..6dde230 100644
--- a/src/main/java/sevenUnitsGUI/UnitConversionRecord.java
+++ b/src/main/java/sevenUnitsGUI/UnitConversionRecord.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
diff --git a/src/main/java/sevenUnitsGUI/UnitConversionView.java b/src/main/java/sevenUnitsGUI/UnitConversionView.java
index e3fb28f..a6cc399 100644
--- a/src/main/java/sevenUnitsGUI/UnitConversionView.java
+++ b/src/main/java/sevenUnitsGUI/UnitConversionView.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021-2022 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
diff --git a/src/main/java/sevenUnitsGUI/View.java b/src/main/java/sevenUnitsGUI/View.java
index 4140992..f934bb5 100644
--- a/src/main/java/sevenUnitsGUI/View.java
+++ b/src/main/java/sevenUnitsGUI/View.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021-2022 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
diff --git a/src/main/java/sevenUnitsGUI/ViewBot.java b/src/main/java/sevenUnitsGUI/ViewBot.java
index 60a8d7b..8e24e64 100644
--- a/src/main/java/sevenUnitsGUI/ViewBot.java
+++ b/src/main/java/sevenUnitsGUI/ViewBot.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
diff --git a/src/main/java/sevenUnitsGUI/package-info.java b/src/main/java/sevenUnitsGUI/package-info.java
index cff1ded..c0ccc1b 100644
--- a/src/main/java/sevenUnitsGUI/package-info.java
+++ b/src/main/java/sevenUnitsGUI/package-info.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021 Adrien Hopkins
+ * 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
diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
index e55d6af..56296b4 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
diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java
index f8d3040..4d9a103 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
diff --git a/src/test/java/sevenUnits/unit/UnitValueTest.java b/src/test/java/sevenUnits/unit/UnitValueTest.java
index 69569ae..6b80986 100644
--- a/src/test/java/sevenUnits/unit/UnitValueTest.java
+++ b/src/test/java/sevenUnits/unit/UnitValueTest.java
@@ -1,3 +1,19 @@
+/**
+ * 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 .
+ */
package sevenUnits.unit;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java b/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java
index 868385b..29675de 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
diff --git a/src/test/java/sevenUnits/utils/ExpressionParserTest.java b/src/test/java/sevenUnits/utils/ExpressionParserTest.java
index 15701ce..463880b 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
diff --git a/src/test/java/sevenUnits/utils/NameSymbolTest.java b/src/test/java/sevenUnits/utils/NameSymbolTest.java
index 327cd9f..55e09c4 100644
--- a/src/test/java/sevenUnits/utils/NameSymbolTest.java
+++ b/src/test/java/sevenUnits/utils/NameSymbolTest.java
@@ -1,3 +1,19 @@
+/**
+ * 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 .
+ */
package sevenUnits.utils;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/src/test/java/sevenUnits/utils/ObjectProductTest.java b/src/test/java/sevenUnits/utils/ObjectProductTest.java
index 8c6b353..584b3f3 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
diff --git a/src/test/java/sevenUnits/utils/SemanticVersionTest.java b/src/test/java/sevenUnits/utils/SemanticVersionTest.java
index 1e59ae3..295ad39 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
diff --git a/src/test/java/sevenUnits/utils/UncertainDoubleTest.java b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java
index b251b31..fe66e2d 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
diff --git a/src/test/java/sevenUnitsGUI/I18nTest.java b/src/test/java/sevenUnitsGUI/I18nTest.java
index 73bd727..2875db6 100644
--- a/src/test/java/sevenUnitsGUI/I18nTest.java
+++ b/src/test/java/sevenUnitsGUI/I18nTest.java
@@ -1,3 +1,19 @@
+/**
+ * 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 .
+ */
package sevenUnitsGUI;
import static org.junit.jupiter.api.Assertions.assertNotNull;
diff --git a/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java b/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java
index 476e407..ce75cca 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
diff --git a/src/test/java/sevenUnitsGUI/PrefixSearchTest.java b/src/test/java/sevenUnitsGUI/PrefixSearchTest.java
index 8790315..c7c652b 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
diff --git a/src/test/java/sevenUnitsGUI/PresenterTest.java b/src/test/java/sevenUnitsGUI/PresenterTest.java
index 1d9b45b..20d0c8a 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
diff --git a/src/test/java/sevenUnitsGUI/RoundingTest.java b/src/test/java/sevenUnitsGUI/RoundingTest.java
index f749f85..535167c 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
diff --git a/src/test/java/sevenUnitsGUI/TabbedViewTest.java b/src/test/java/sevenUnitsGUI/TabbedViewTest.java
index 017e9ea..7819452 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
--
cgit v1.2.3
From 79e1653caf5c30667877a158433cbcd766a135af Mon Sep 17 00:00:00 2001
From: Adrien Hopkins
Date: Wed, 4 Jun 2025 19:45:37 -0500
Subject: Add version numbers to all @since tags
Specifically, for every @since tag with a date, I added another that
contains the correspending version. I did not add date @since tags to
comments that do not have them, as that would be too tedious for what
it's worth. These dates could still be found by using git bisect
though.
---
src/main/java/sevenUnits/ProgramInfo.java | 2 +-
src/main/java/sevenUnits/unit/BaseDimension.java | 3 ++
src/main/java/sevenUnits/unit/BaseUnit.java | 6 +++
src/main/java/sevenUnits/unit/BritishImperial.java | 5 +++
src/main/java/sevenUnits/unit/FunctionalUnit.java | 5 +++
src/main/java/sevenUnits/unit/LinearUnit.java | 14 +++++++
src/main/java/sevenUnits/unit/LinearUnitValue.java | 23 +++++++++++
.../java/sevenUnits/unit/LoadingException.java | 1 +
src/main/java/sevenUnits/unit/Metric.java | 2 +
src/main/java/sevenUnits/unit/USCustomary.java | 5 +++
src/main/java/sevenUnits/unit/Unit.java | 14 +++++++
src/main/java/sevenUnits/unit/UnitDatabase.java | 24 +++++++++++
src/main/java/sevenUnits/unit/UnitPrefix.java | 11 +++++
src/main/java/sevenUnits/unit/UnitType.java | 2 +
src/main/java/sevenUnits/unit/UnitValue.java | 6 +++
.../utils/ConditionalExistenceCollections.java | 14 +++++++
.../java/sevenUnits/utils/DecimalComparison.java | 1 +
.../java/sevenUnits/utils/ExpressionParser.java | 2 +
src/main/java/sevenUnits/utils/NameSymbol.java | 14 ++++++-
src/main/java/sevenUnits/utils/Nameable.java | 7 ++++
src/main/java/sevenUnits/utils/ObjectProduct.java | 15 +++++++
.../sevenUnits/utils/SemanticVersionNumber.java | 48 +++++++++++-----------
.../java/sevenUnits/utils/UncertainDouble.java | 24 +++++++++++
.../sevenUnitsGUI/DefaultPrefixRepetitionRule.java | 1 +
src/main/java/sevenUnitsGUI/DelegateListModel.java | 1 +
.../sevenUnitsGUI/ExpressionConversionView.java | 8 ++--
src/main/java/sevenUnitsGUI/Main.java | 4 +-
src/main/java/sevenUnitsGUI/PrefixSearchRule.java | 12 +++---
src/main/java/sevenUnitsGUI/Presenter.java | 45 ++++++++++++++++++++
src/main/java/sevenUnitsGUI/SearchBoxList.java | 5 +++
.../java/sevenUnitsGUI/StandardDisplayRules.java | 20 +++++----
src/main/java/sevenUnitsGUI/TabbedView.java | 20 +++++----
.../java/sevenUnitsGUI/UnitConversionRecord.java | 17 ++++----
.../java/sevenUnitsGUI/UnitConversionView.java | 24 +++++------
src/main/java/sevenUnitsGUI/View.java | 20 ++++-----
src/main/java/sevenUnitsGUI/ViewBot.java | 26 +++++++++++-
src/main/java/sevenUnitsGUI/package-info.java | 1 +
.../java/sevenUnits/unit/UnitDatabaseTest.java | 15 +++++++
src/test/java/sevenUnits/unit/UnitValueTest.java | 10 +++++
.../utils/ConditionalExistenceCollectionsTest.java | 3 ++
.../sevenUnits/utils/ExpressionParserTest.java | 1 +
src/test/java/sevenUnits/utils/NameSymbolTest.java | 5 +++
.../java/sevenUnits/utils/SemanticVersionTest.java | 10 +++++
.../java/sevenUnits/utils/UncertainDoubleTest.java | 2 +
src/test/java/sevenUnitsGUI/I18nTest.java | 7 +++-
.../java/sevenUnitsGUI/PrefixRepetitionTest.java | 10 ++---
src/test/java/sevenUnitsGUI/PrefixSearchTest.java | 16 ++++----
src/test/java/sevenUnitsGUI/PresenterTest.java | 26 ++++++------
src/test/java/sevenUnitsGUI/RoundingTest.java | 23 ++++++-----
src/test/java/sevenUnitsGUI/TabbedViewTest.java | 8 ++--
50 files changed, 460 insertions(+), 128 deletions(-)
(limited to 'src/test/java/sevenUnits/unit')
diff --git a/src/main/java/sevenUnits/ProgramInfo.java b/src/main/java/sevenUnits/ProgramInfo.java
index dda5d2c..9b9832e 100644
--- a/src/main/java/sevenUnits/ProgramInfo.java
+++ b/src/main/java/sevenUnits/ProgramInfo.java
@@ -21,8 +21,8 @@ import sevenUnits.utils.SemanticVersionNumber;
/**
* Information about 7Units
*
- * @since 0.3.1
* @since 2021-06-28
+ * @since v0.3.1
*/
public final class ProgramInfo {
diff --git a/src/main/java/sevenUnits/unit/BaseDimension.java b/src/main/java/sevenUnits/unit/BaseDimension.java
index cfa6af9..fe7b772 100644
--- a/src/main/java/sevenUnits/unit/BaseDimension.java
+++ b/src/main/java/sevenUnits/unit/BaseDimension.java
@@ -26,6 +26,7 @@ import sevenUnits.utils.Nameable;
*
* @author Adrien Hopkins
* @since 2019-10-16
+ * @since v0.3.0
*/
public final class BaseDimension implements Nameable {
/**
@@ -35,6 +36,7 @@ public final class BaseDimension implements Nameable {
* @param symbol symbol used for dimension
* @return dimension
* @since 2019-10-16
+ * @since v0.3.0
*/
public static BaseDimension valueOf(final String name, final String symbol) {
return new BaseDimension(name, symbol);
@@ -57,6 +59,7 @@ public final class BaseDimension implements Nameable {
* @param symbol symbol of unit
* @throws NullPointerException if any argument is null
* @since 2019-10-16
+ * @since v0.3.0
*/
private BaseDimension(final String name, final String symbol) {
this.name = Objects.requireNonNull(name, "name must not be null.");
diff --git a/src/main/java/sevenUnits/unit/BaseUnit.java b/src/main/java/sevenUnits/unit/BaseUnit.java
index 0d375f8..2898de5 100644
--- a/src/main/java/sevenUnits/unit/BaseUnit.java
+++ b/src/main/java/sevenUnits/unit/BaseUnit.java
@@ -31,6 +31,7 @@ import sevenUnits.utils.NameSymbol;
*
* @author Adrien Hopkins
* @since 2019-10-16
+ * @since v0.3.0
*/
public final class BaseUnit extends Unit {
/**
@@ -41,6 +42,7 @@ public final class BaseUnit extends Unit {
* @param symbol symbol of unit
* @return base unit
* @since 2019-10-16
+ * @since v0.3.0
*/
public static BaseUnit valueOf(final BaseDimension dimension,
final String name, final String symbol) {
@@ -56,6 +58,7 @@ public final class BaseUnit extends Unit {
* @param otherNames other possible names of unit
* @return base unit
* @since 2019-10-21
+ * @since v0.3.0
*/
public static BaseUnit valueOf(final BaseDimension dimension,
final String name, final String symbol, final Set otherNames) {
@@ -75,6 +78,7 @@ public final class BaseUnit extends Unit {
* @param symbol symbol of unit
* @throws NullPointerException if any argument is null
* @since 2019-10-16
+ * @since v0.3.0
*/
private BaseUnit(final BaseDimension dimension, final String primaryName,
final String symbol, final Set otherNames) {
@@ -90,6 +94,7 @@ public final class BaseUnit extends Unit {
*
* @return this unit as a {@code LinearUnit}
* @since 2019-10-16
+ * @since v0.3.0
*/
public LinearUnit asLinearUnit() {
return LinearUnit.valueOf(this.getBase(), 1);
@@ -108,6 +113,7 @@ public final class BaseUnit extends Unit {
/**
* @return dimension
* @since 2019-10-16
+ * @since v0.3.0
*/
public final BaseDimension getBaseDimension() {
return this.dimension;
diff --git a/src/main/java/sevenUnits/unit/BritishImperial.java b/src/main/java/sevenUnits/unit/BritishImperial.java
index e327055..a6fd43f 100644
--- a/src/main/java/sevenUnits/unit/BritishImperial.java
+++ b/src/main/java/sevenUnits/unit/BritishImperial.java
@@ -23,6 +23,7 @@ import sevenUnits.utils.NameSymbol;
*
* @author Adrien Hopkins
* @since 2019-10-21
+ * @since v0.3.0
*/
// this class is just constants, most of which are obvious from the variable name
// so no need to check for missing values
@@ -33,6 +34,7 @@ public final class BritishImperial {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Area {
public static final LinearUnit SQUARE_FOOT = Length.FOOT.toExponent(2);
@@ -48,6 +50,7 @@ public final class BritishImperial {
*
* @author Adrien Hopkins
* @since 2019-10-28
+ * @since v0.3.0
*/
public static final class Length {
/**
@@ -81,6 +84,7 @@ public final class BritishImperial {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Mass {
public static final LinearUnit POUND = Metric.GRAM.times(453.59237);
@@ -99,6 +103,7 @@ public final class BritishImperial {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Volume {
public static final LinearUnit FLUID_OUNCE = Metric.LITRE
diff --git a/src/main/java/sevenUnits/unit/FunctionalUnit.java b/src/main/java/sevenUnits/unit/FunctionalUnit.java
index fb24629..41db164 100644
--- a/src/main/java/sevenUnits/unit/FunctionalUnit.java
+++ b/src/main/java/sevenUnits/unit/FunctionalUnit.java
@@ -27,6 +27,7 @@ import sevenUnits.utils.ObjectProduct;
*
* @author Adrien Hopkins
* @since 2019-05-22
+ * @since v0.3.0
*/
final class FunctionalUnit extends Unit {
/**
@@ -34,6 +35,7 @@ final class FunctionalUnit extends Unit {
* that value expressed in this unit.
*
* @since 2019-05-22
+ * @since v0.3.0
*/
private final DoubleUnaryOperator converterFrom;
@@ -42,6 +44,7 @@ final class FunctionalUnit extends Unit {
* value expressed in the unit's base.
*
* @since 2019-05-22
+ * @since v0.3.0
*/
private final DoubleUnaryOperator converterTo;
@@ -55,6 +58,7 @@ final class FunctionalUnit extends Unit {
* and returns that value expressed in the unit's base.
* @throws NullPointerException if any argument is null
* @since 2019-05-22
+ * @since v0.3.0
*/
public FunctionalUnit(final ObjectProduct base,
final DoubleUnaryOperator converterFrom,
@@ -77,6 +81,7 @@ final class FunctionalUnit extends Unit {
* @param ns name and symbol of resulting unit
* @throws NullPointerException if any argument is null
* @since 2019-05-22
+ * @since v0.3.0
*/
public FunctionalUnit(final ObjectProduct base,
final DoubleUnaryOperator converterFrom,
diff --git a/src/main/java/sevenUnits/unit/LinearUnit.java b/src/main/java/sevenUnits/unit/LinearUnit.java
index 6c1aba3..7191196 100644
--- a/src/main/java/sevenUnits/unit/LinearUnit.java
+++ b/src/main/java/sevenUnits/unit/LinearUnit.java
@@ -29,6 +29,7 @@ import sevenUnits.utils.UncertainDouble;
*
* @author Adrien Hopkins
* @since 2019-10-16
+ * @since v0.3.0
*/
public final class LinearUnit extends Unit {
/**
@@ -39,6 +40,7 @@ public final class LinearUnit extends Unit {
* @param value value to convert
* @return value expressed as a {@code LinearUnit}
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if unit is null
*/
public static LinearUnit fromUnitValue(final Unit unit, final double value) {
@@ -56,6 +58,7 @@ public final class LinearUnit extends Unit {
* @param ns name(s) and symbol of unit
* @return value expressed as a {@code LinearUnit}
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if unit or ns is null
*/
public static LinearUnit fromUnitValue(final Unit unit, final double value,
@@ -70,6 +73,7 @@ public final class LinearUnit extends Unit {
* @return the base unit associated with {@code unit}, as a
* {@code LinearUnit}.
* @since 2020-10-02
+ * @since v0.3.0
*/
public static LinearUnit getBase(final Unit unit) {
return new LinearUnit(unit.getBase(), 1, NameSymbol.EMPTY);
@@ -84,6 +88,7 @@ public final class LinearUnit extends Unit {
* @param conversionFactor number to multiply base by
* @return product of base and conversion factor
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if unitBase is null
*/
public static LinearUnit valueOf(final ObjectProduct unitBase,
@@ -101,6 +106,7 @@ public final class LinearUnit extends Unit {
* @param ns name(s) and symbol of unit
* @return product of base and conversion factor
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if unitBase is null
*/
public static LinearUnit valueOf(final ObjectProduct unitBase,
@@ -116,6 +122,7 @@ public final class LinearUnit extends Unit {
*
*
* @since 2019-10-16
+ * @since v0.3.0
*/
private final double conversionFactor;
@@ -125,6 +132,7 @@ public final class LinearUnit extends Unit {
* @param unitBase base of linear unit
* @param conversionFactor conversion factor between base and unit
* @since 2019-10-16
+ * @since v0.3.0
*/
private LinearUnit(final ObjectProduct unitBase,
final double conversionFactor, final NameSymbol ns) {
@@ -150,6 +158,7 @@ public final class LinearUnit extends Unit {
* @param value value to convert
* @return converted value
* @since 2019-09-07
+ * @since v0.3.0
* @throws IllegalArgumentException if {@code other} is incompatible for
* conversion with this unit (as tested by
* {@link Unit#canConvertTo}).
@@ -181,6 +190,7 @@ public final class LinearUnit extends Unit {
* Converts an {@code UncertainDouble} to the base unit.
*
* @since 2020-09-07
+ * @since v0.3.0
*/
UncertainDouble convertToBase(final UncertainDouble value) {
return value.timesExact(this.getConversionFactor());
@@ -249,6 +259,7 @@ public final class LinearUnit extends Unit {
/**
* @return conversion factor
* @since 2019-10-16
+ * @since v0.3.0
*/
public double getConversionFactor() {
return this.conversionFactor;
@@ -270,6 +281,7 @@ public final class LinearUnit extends Unit {
* is a {@code BaseUnit b} where
* {@code b.asLinearUnit().equals(this)} returns {@code true}.)
* @since 2019-10-16
+ * @since v0.3.0
*/
public boolean isBase() {
return this.isCoherent() && this.getBase().isSingleObject();
@@ -278,6 +290,7 @@ public final class LinearUnit extends Unit {
/**
* @return whether this unit is coherent (i.e. has conversion factor 1)
* @since 2019-10-16
+ * @since v0.3.0
*/
public boolean isCoherent() {
return this.getConversionFactor() == 1;
@@ -403,6 +416,7 @@ public final class LinearUnit extends Unit {
* @param exponent exponent to raise unit to
* @return result of rounded exponentation
* @since 2024-08-22
+ * @since v1.0.0
* @see ObjectProduct#toExponentRounded
*/
public LinearUnit toExponentRounded(final double exponent) {
diff --git a/src/main/java/sevenUnits/unit/LinearUnitValue.java b/src/main/java/sevenUnits/unit/LinearUnitValue.java
index 8d30907..86520d7 100644
--- a/src/main/java/sevenUnits/unit/LinearUnitValue.java
+++ b/src/main/java/sevenUnits/unit/LinearUnitValue.java
@@ -34,6 +34,7 @@ import sevenUnits.utils.UncertainDouble;
*
* @author Adrien Hopkins
* @since 2020-07-26
+ * @since v0.3.0
*/
public final class LinearUnitValue {
/** The value 1 as a LinearUnitValue. */
@@ -46,6 +47,7 @@ public final class LinearUnitValue {
* @param value value to express
* @return exact {@code LinearUnitValue} instance
* @since 2020-07-26
+ * @since v0.3.0
*/
public static final LinearUnitValue getExact(final LinearUnit unit,
final double value) {
@@ -61,6 +63,7 @@ public final class LinearUnitValue {
* @param value value to express
* @return uncertain {@code LinearUnitValue} instance
* @since 2020-07-26
+ * @since v0.3.0
*/
public static final LinearUnitValue of(final LinearUnit unit,
final UncertainDouble value) {
@@ -77,6 +80,7 @@ public final class LinearUnitValue {
* @param unit unit to express as
* @param value value to express
* @since 2020-07-26
+ * @since v0.3.0
*/
private LinearUnitValue(final LinearUnit unit, final UncertainDouble value) {
this.unit = unit;
@@ -87,6 +91,7 @@ public final class LinearUnitValue {
* @return this value as a {@code UnitValue}. All uncertainty information is
* removed from the returned value.
* @since 2020-08-04
+ * @since v0.3.0
*/
public final UnitValue asUnitValue() {
return UnitValue.of(this.unit, this.value.value());
@@ -96,6 +101,7 @@ public final class LinearUnitValue {
* @param other a {@code LinearUnit}
* @return true iff this value can be represented with {@code other}.
* @since 2020-07-26
+ * @since v0.3.0
*/
public final boolean canConvertTo(final LinearUnit other) {
return this.unit.canConvertTo(other);
@@ -108,6 +114,7 @@ public final class LinearUnitValue {
* @param other new unit to express value in
* @return value expressed in {@code other}
* @since 2020-07-26
+ * @since v0.3.0
*/
public final LinearUnitValue convertTo(final LinearUnit other) {
return LinearUnitValue.of(other, this.unit.convertTo(other, this.value));
@@ -122,6 +129,7 @@ public final class LinearUnitValue {
* @throws IllegalArgumentException if no units are provided or units
* provided have incompatible bases
* @since 2024-08-15
+ * @since v1.0.0
*/
public final List convertToMultiple(
final List others) {
@@ -155,6 +163,7 @@ public final class LinearUnitValue {
* @param divisor value to divide by
* @return multiplied value
* @since 2020-07-28
+ * @since v0.3.0
*/
public LinearUnitValue dividedBy(final double divisor) {
return LinearUnitValue.of(this.unit, this.value.dividedByExact(divisor));
@@ -166,6 +175,7 @@ public final class LinearUnitValue {
* @param divisor value to multiply by
* @return quotient
* @since 2020-07-28
+ * @since v0.3.0
*/
public LinearUnitValue dividedBy(final LinearUnitValue divisor) {
return LinearUnitValue.of(this.unit.dividedBy(divisor.unit),
@@ -178,6 +188,7 @@ public final class LinearUnitValue {
* km) returns true.
*
* @since 2020-07-26
+ * @since v0.3.0
* @see #equals(Object, boolean)
*/
@Override
@@ -202,6 +213,7 @@ public final class LinearUnitValue {
* @return true iff this and obj are equal
*
* @since 2020-07-28
+ * @since v0.3.0
*/
public boolean equals(final Object obj, final boolean avoidFPErrors) {
if (!avoidFPErrors)
@@ -219,6 +231,7 @@ public final class LinearUnitValue {
* @return true iff this and other are within each other's uncertainty range
*
* @since 2020-07-26
+ * @since v0.3.0
*/
public boolean equivalent(final LinearUnitValue other) {
if (other == null
@@ -234,6 +247,7 @@ public final class LinearUnitValue {
/**
* @return the unit
* @since 2020-09-29
+ * @since v0.3.0
*/
public final LinearUnit getUnit() {
return this.unit;
@@ -242,6 +256,7 @@ public final class LinearUnitValue {
/**
* @return the value
* @since 2020-09-29
+ * @since v0.3.0
*/
public final UncertainDouble getValue() {
return this.value;
@@ -250,6 +265,7 @@ public final class LinearUnitValue {
/**
* @return the exact value
* @since 2020-09-07
+ * @since v0.3.0
*/
public final double getValueExact() {
return this.value.value();
@@ -270,6 +286,7 @@ public final class LinearUnitValue {
* @throws IllegalArgumentException if {@code subtrahend} has a unit that is
* not compatible for addition
* @since 2020-07-26
+ * @since v0.3.0
*/
public LinearUnitValue minus(final LinearUnitValue subtrahend) {
Objects.requireNonNull(subtrahend, "subtrahend may not be null");
@@ -292,6 +309,7 @@ public final class LinearUnitValue {
* @throws IllegalArgumentException if {@code addend} has a unit that is not
* compatible for addition
* @since 2020-07-26
+ * @since v0.3.0
*/
public LinearUnitValue plus(final LinearUnitValue addend) {
Objects.requireNonNull(addend, "addend may not be null");
@@ -312,6 +330,7 @@ public final class LinearUnitValue {
* @param multiplier value to multiply by
* @return multiplied value
* @since 2020-07-28
+ * @since v0.3.0
*/
public LinearUnitValue times(final double multiplier) {
return LinearUnitValue.of(this.unit, this.value.timesExact(multiplier));
@@ -323,6 +342,7 @@ public final class LinearUnitValue {
* @param multiplier value to multiply by
* @return product
* @since 2020-07-28
+ * @since v0.3.0
*/
public LinearUnitValue times(final LinearUnitValue multiplier) {
return LinearUnitValue.of(this.unit.times(multiplier.unit),
@@ -335,6 +355,7 @@ public final class LinearUnitValue {
* @param exponent exponent to raise to
* @return result of exponentiation
* @since 2020-07-28
+ * @since v0.3.0
*/
public LinearUnitValue toExponent(final int exponent) {
return LinearUnitValue.of(this.unit.toExponent(exponent),
@@ -348,6 +369,7 @@ public final class LinearUnitValue {
* @return result of exponentation
*
* @since 2024-08-22
+ * @since v1.0.0
* @see ObjectProduct#toExponentRounded
*/
public LinearUnitValue toExponentRounded(final double exponent) {
@@ -375,6 +397,7 @@ public final class LinearUnitValue {
* @return string representing this value
*
* @since 2020-07-26
+ * @since v0.3.0
*/
public String toString(final boolean showUncertainty,
RoundingMode roundingMode) {
diff --git a/src/main/java/sevenUnits/unit/LoadingException.java b/src/main/java/sevenUnits/unit/LoadingException.java
index b806147..7b3d708 100644
--- a/src/main/java/sevenUnits/unit/LoadingException.java
+++ b/src/main/java/sevenUnits/unit/LoadingException.java
@@ -25,6 +25,7 @@ import java.util.Optional;
*
* @author Adrien Hopkins
* @since 2024-08-22
+ * @since v1.0.0
*/
public final class LoadingException extends RuntimeException {
/** The type of file that was being loaded. */
diff --git a/src/main/java/sevenUnits/unit/Metric.java b/src/main/java/sevenUnits/unit/Metric.java
index 166cbcf..34fd0b8 100644
--- a/src/main/java/sevenUnits/unit/Metric.java
+++ b/src/main/java/sevenUnits/unit/Metric.java
@@ -36,6 +36,7 @@ import sevenUnits.utils.ObjectProduct;
*
* @author Adrien Hopkins
* @since 2019-10-16
+ * @since v0.3.0
*/
// this class is just constants, most of which are obvious from the variable name
// so no need to check for missing values
@@ -109,6 +110,7 @@ public final class Metric {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Constants {
public static final LinearUnit EARTH_GRAVITY = METRE.dividedBy(SECOND)
diff --git a/src/main/java/sevenUnits/unit/USCustomary.java b/src/main/java/sevenUnits/unit/USCustomary.java
index 1923d9e..be8c5e2 100644
--- a/src/main/java/sevenUnits/unit/USCustomary.java
+++ b/src/main/java/sevenUnits/unit/USCustomary.java
@@ -21,6 +21,7 @@ package sevenUnits.unit;
*
* @author Adrien Hopkins
* @since 2019-10-21
+ * @since v0.3.0
*/
// this class is just constants, most of which are obvious from the variable name
// so no need to check for missing values
@@ -31,6 +32,7 @@ public final class USCustomary {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Area {
public static final LinearUnit SQUARE_SURVEY_FOOT = Length.SURVEY_FOOT
@@ -49,6 +51,7 @@ public final class USCustomary {
*
* @author Adrien Hopkins
* @since 2019-10-28
+ * @since v0.3.0
*/
public static final class Length {
public static final LinearUnit FOOT = BritishImperial.Length.FOOT;
@@ -79,6 +82,7 @@ public final class USCustomary {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Mass {
public static final LinearUnit GRAIN = BritishImperial.Mass.GRAIN;
@@ -99,6 +103,7 @@ public final class USCustomary {
*
* @author Adrien Hopkins
* @since 2019-11-08
+ * @since v0.3.0
*/
public static final class Volume {
public static final LinearUnit CUBIC_INCH = Length.INCH.toExponent(3);
diff --git a/src/main/java/sevenUnits/unit/Unit.java b/src/main/java/sevenUnits/unit/Unit.java
index 5d67ed0..d651fe2 100644
--- a/src/main/java/sevenUnits/unit/Unit.java
+++ b/src/main/java/sevenUnits/unit/Unit.java
@@ -31,6 +31,7 @@ import sevenUnits.utils.ObjectProduct;
*
* @author Adrien Hopkins
* @since 2019-10-16
+ * @since v0.3.0
*/
public abstract class Unit implements Nameable {
/**
@@ -51,6 +52,7 @@ public abstract class Unit implements Nameable {
* and returns that value expressed in the unit's base.
* @return a unit that uses the provided functions to convert.
* @since 2019-05-22
+ * @since v0.3.0
* @throws NullPointerException if any argument is null
*/
public static final Unit fromConversionFunctions(
@@ -79,6 +81,7 @@ public abstract class Unit implements Nameable {
* @param ns names and symbol of unit
* @return a unit that uses the provided functions to convert.
* @since 2019-05-22
+ * @since v0.3.0
* @throws NullPointerException if any argument is null
*/
public static final Unit fromConversionFunctions(
@@ -92,6 +95,7 @@ public abstract class Unit implements Nameable {
* The combination of units that this unit is based on.
*
* @since 2019-10-16
+ * @since v0.3.0
*/
private final ObjectProduct unitBase;
@@ -99,6 +103,7 @@ public abstract class Unit implements Nameable {
* This unit's name(s) and symbol
*
* @since 2020-09-07
+ * @since v0.3.0
*/
private final NameSymbol nameSymbol;
@@ -106,6 +111,7 @@ public abstract class Unit implements Nameable {
* Cache storing the result of getDimension()
*
* @since 2019-10-16
+ * @since v0.3.0
*/
private transient ObjectProduct dimension = null;
@@ -113,6 +119,7 @@ public abstract class Unit implements Nameable {
* A constructor that constructs {@code BaseUnit} instances.
*
* @since 2019-10-16
+ * @since v0.3.0
*/
Unit(final NameSymbol nameSymbol) {
if (this instanceof BaseUnit) {
@@ -128,6 +135,7 @@ public abstract class Unit implements Nameable {
* @param unitBase base of unit
* @param ns names and symbol of unit
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if unitBase or ns is null
*/
protected Unit(ObjectProduct unitBase, NameSymbol ns) {
@@ -187,6 +195,7 @@ public abstract class Unit implements Nameable {
* @param value value to convert
* @return converted value
* @since 2019-05-22
+ * @since v0.3.0
* @throws IllegalArgumentException if {@code other} is incompatible for
* conversion with this unit (as tested by
* {@link Unit#canConvertTo}).
@@ -255,6 +264,7 @@ public abstract class Unit implements Nameable {
/**
* @return the nameSymbol
* @since 2020-09-07
+ * @since v0.3.0
*/
@Override
public final NameSymbol getNameSymbol() {
@@ -281,6 +291,7 @@ public abstract class Unit implements Nameable {
* @return true iff this unit is metric.
*
* @since 2020-08-27
+ * @since v0.3.0
*/
public final boolean isMetric() {
// first condition - check that it is a linear unit
@@ -302,6 +313,7 @@ public abstract class Unit implements Nameable {
/**
* @return a string representing this unit's definition
* @since 2022-03-10
+ * @since v0.3.0
*/
public String toDefinitionString() {
if (!this.unitBase.getNameSymbol().isEmpty())
@@ -314,6 +326,7 @@ public abstract class Unit implements Nameable {
/**
* @return a string containing both this unit's name and its definition
* @since 2022-03-10
+ * @since v0.3.0
*/
public final String toFullString() {
return this.toString() + " (" + this.toDefinitionString() + ")";
@@ -333,6 +346,7 @@ public abstract class Unit implements Nameable {
* @param ns name(s) and symbol to use
* @return a copy of this unit with provided name(s) and symbol
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if ns is null
*/
public Unit withName(final NameSymbol ns) {
diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java
index 6cf794b..b0d026f 100644
--- a/src/main/java/sevenUnits/unit/UnitDatabase.java
+++ b/src/main/java/sevenUnits/unit/UnitDatabase.java
@@ -138,6 +138,7 @@ public final class UnitDatabase {
/**
* @since 2019-05-03
+ * @since v0.3.0
*/
@Override
public boolean equals(final Object o) {
@@ -160,6 +161,7 @@ public final class UnitDatabase {
/**
* @since 2019-05-03
+ * @since v0.3.0
*/
@Override
public int hashCode() {
@@ -181,6 +183,7 @@ public final class UnitDatabase {
* value.
*
* @since 2019-05-03
+ * @since v0.3.0
*/
@Override
public String toString() {
@@ -307,6 +310,7 @@ public final class UnitDatabase {
* @return the next element in the iterator, without iterating over
* it
* @since 2019-05-03
+ * @since v0.3.0
*/
private Entry peek() {
if (!this.hasNext())
@@ -333,6 +337,7 @@ public final class UnitDatabase {
* of the representation are unspecified and subject to change.
*
* @since 2019-05-03
+ * @since v0.3.0
*/
@Override
public String toString() {
@@ -622,6 +627,7 @@ public final class UnitDatabase {
* @return the next element in the iterator, without iterating over
* it
* @since 2019-05-03
+ * @since v0.3.0
*/
private String peek() {
if (!this.hasNext())
@@ -645,6 +651,7 @@ public final class UnitDatabase {
* of the representation are unspecified and subject to change.
*
* @since 2019-05-03
+ * @since v0.3.0
*/
@Override
public String toString() {
@@ -1136,6 +1143,7 @@ public final class UnitDatabase {
* @param exponentUnit exponent
* @return result
* @since 2020-08-04
+ * @since v0.3.0
*/
private static final LinearUnitValue exponentiateUnitValues(
final LinearUnitValue base, final LinearUnitValue exponentValue) {
@@ -1151,6 +1159,7 @@ public final class UnitDatabase {
/**
* @return true if entry represents a removable duplicate entry of map.
* @since 2021-05-22
+ * @since v0.3.0
*/
static boolean isRemovableDuplicate(Map map,
Entry entry) {
@@ -1236,6 +1245,7 @@ public final class UnitDatabase {
* A parser that can parse unit value expressions.
*
* @since 2020-08-04
+ * @since v0.3.0
*/
private final ExpressionParser unitValueExpressionParser = new ExpressionParser.Builder<>(
this::getLinearUnitValue)
@@ -1297,6 +1307,7 @@ public final class UnitDatabase {
* @param prefixRepetitionRule the rule that determines when prefix
* repetition is allowed
* @since 2020-08-26
+ * @since v0.3.0
*/
public UnitDatabase(Predicate> prefixRepetitionRule) {
this.prefixlessUnits = new HashMap<>();
@@ -1468,6 +1479,7 @@ public final class UnitDatabase {
* @param name name of unit set
* @param value unit set to add
* @since 2024-08-16
+ * @since v1.0.0
*/
public void addUnitSet(String name, List value) {
if (value.isEmpty())
@@ -1486,6 +1498,7 @@ public final class UnitDatabase {
* Removes all units, unit sets, prefixes and dimensions from this database.
*
* @since 2022-02-26
+ * @since v0.4.0
*/
public void clear() {
this.dimensions.clear();
@@ -1538,6 +1551,7 @@ public final class UnitDatabase {
* @return true iff there is a unit set with this name
*
* @since 2024-08-16
+ * @since v1.0.0
*/
public boolean containsUnitSetName(String name) {
return this.unitSets.containsKey(name);
@@ -1559,6 +1573,7 @@ public final class UnitDatabase {
* @param expression expression to parse
* @return {@code LinearUnitValue} representing value of expression
* @since 2020-08-04
+ * @since v0.3.0
*/
public LinearUnitValue evaluateUnitExpression(final String expression) {
Objects.requireNonNull(expression, "expression must not be null.");
@@ -1697,6 +1712,7 @@ public final class UnitDatabase {
* @param name name of unit
* @return {@code LinearUnitValue} instance
* @since 2020-08-04
+ * @since v0.3.0
*/
LinearUnitValue getLinearUnitValue(final String name) {
try {
@@ -1735,6 +1751,7 @@ public final class UnitDatabase {
* @param unitName name of unit
* @return prefixes
* @since 2020-08-26
+ * @since v0.3.0
*/
List getPrefixesFromName(final String unitName) {
final List prefixes = new ArrayList<>();
@@ -1800,6 +1817,7 @@ public final class UnitDatabase {
/**
* @return the prefixRepetitionRule
* @since 2020-08-26
+ * @since v0.3.0
*/
public final Predicate> getPrefixRepetitionRule() {
return this.prefixRepetitionRule;
@@ -1904,6 +1922,7 @@ public final class UnitDatabase {
* @return unit set with that name
*
* @since 2024-08-16
+ * @since v1.0.0
*/
public List getUnitSet(String name) {
final List unitSet = this.unitSets.get(name);
@@ -1916,6 +1935,7 @@ public final class UnitDatabase {
* Parses a semicolon-separated expression to get the unit set being used.
*
* @since 2024-08-22
+ * @since v1.0.0
*/
List getUnitSetFromExpression(String expression) {
final String[] parts = expression.split(";");
@@ -1991,6 +2011,7 @@ public final class UnitDatabase {
* @param stream stream to load from
* @return list of all errors that happened loading the stream
* @since 2021-03-27
+ * @since v0.3.0
*/
public List loadDimensionsFromStream(
final InputStream stream) {
@@ -2062,6 +2083,7 @@ public final class UnitDatabase {
* @param stream stream to load from
* @return list of all errors that happened loading the stream
* @since 2021-03-27
+ * @since v0.3.0
*/
public List loadUnitsFromStream(InputStream stream) {
final List errors = new ArrayList<>();
@@ -2098,6 +2120,7 @@ public final class UnitDatabase {
/**
* @param prefixRepetitionRule the prefixRepetitionRule to set
* @since 2020-08-26
+ * @since v0.3.0
*/
public final void setPrefixRepetitionRule(
Predicate> prefixRepetitionRule) {
@@ -2169,6 +2192,7 @@ public final class UnitDatabase {
/**
* @return an unmodifiable map mapping names to unit sets
* @since 2024-08-16
+ * @since v1.0.0
*/
public Map> unitSetMap() {
return Collections.unmodifiableMap(this.unitSets);
diff --git a/src/main/java/sevenUnits/unit/UnitPrefix.java b/src/main/java/sevenUnits/unit/UnitPrefix.java
index 6ac9128..0fd3421 100644
--- a/src/main/java/sevenUnits/unit/UnitPrefix.java
+++ b/src/main/java/sevenUnits/unit/UnitPrefix.java
@@ -28,6 +28,7 @@ import sevenUnits.utils.Nameable;
*
* @author Adrien Hopkins
* @since 2019-10-16
+ * @since v0.3.0
*/
public final class UnitPrefix implements Nameable {
/**
@@ -36,6 +37,7 @@ public final class UnitPrefix implements Nameable {
* @param multiplier multiplier of prefix
* @return prefix
* @since 2019-10-16
+ * @since v0.3.0
*/
public static UnitPrefix valueOf(final double multiplier) {
return new UnitPrefix(multiplier, NameSymbol.EMPTY);
@@ -48,6 +50,7 @@ public final class UnitPrefix implements Nameable {
* @param ns name(s) and symbol of prefix
* @return prefix
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if ns is null
*/
public static UnitPrefix valueOf(final double multiplier,
@@ -60,6 +63,7 @@ public final class UnitPrefix implements Nameable {
* This prefix's name(s) and symbol.
*
* @since 2022-04-16
+ * @since v0.4.0
*/
private final NameSymbol nameSymbol;
@@ -67,6 +71,7 @@ public final class UnitPrefix implements Nameable {
* The number that this prefix multiplies units by
*
* @since 2019-10-16
+ * @since v0.3.0
*/
private final double multiplier;
@@ -88,6 +93,7 @@ public final class UnitPrefix implements Nameable {
* @param divisor number to divide by
* @return quotient of prefix and scalar
* @since 2019-10-16
+ * @since v0.3.0
*/
public UnitPrefix dividedBy(final double divisor) {
return valueOf(this.getMultiplier() / divisor);
@@ -143,6 +149,7 @@ public final class UnitPrefix implements Nameable {
/**
* @return prefix's multiplier
* @since 2019-11-26
+ * @since v0.3.0
*/
public double getMultiplier() {
return this.multiplier;
@@ -169,6 +176,7 @@ public final class UnitPrefix implements Nameable {
* @param multiplicand number to multiply by
* @return product of prefix and scalar
* @since 2019-10-16
+ * @since v0.3.0
*/
public UnitPrefix times(final double multiplicand) {
return valueOf(this.getMultiplier() * multiplicand);
@@ -180,6 +188,7 @@ public final class UnitPrefix implements Nameable {
* @return sum of prefixes
*
* @since 2024-03-03
+ * @since v0.5.0
*/
public UnitPrefix plus(final UnitPrefix other) {
return valueOf(this.getMultiplier() + other.getMultiplier());
@@ -191,6 +200,7 @@ public final class UnitPrefix implements Nameable {
* @return difference of prefixes
*
* @since 2024-03-03
+ * @since v0.5.0
*/
public UnitPrefix minus(final UnitPrefix other) {
return valueOf(this.getMultiplier() - other.getMultiplier());
@@ -239,6 +249,7 @@ public final class UnitPrefix implements Nameable {
* @param ns name(s) and symbol to use
* @return copy of this prefix with provided name(s) and symbol
* @since 2019-11-26
+ * @since v0.3.0
* @throws NullPointerException if ns is null
*/
public UnitPrefix withName(final NameSymbol ns) {
diff --git a/src/main/java/sevenUnits/unit/UnitType.java b/src/main/java/sevenUnits/unit/UnitType.java
index d445418..a331d3d 100644
--- a/src/main/java/sevenUnits/unit/UnitType.java
+++ b/src/main/java/sevenUnits/unit/UnitType.java
@@ -30,6 +30,7 @@ import java.util.function.Predicate;
*
*
* @since 2022-04-10
+ * @since v0.4.0
*/
public enum UnitType {
/** Units that pass {@link Unit#isMetric} */
@@ -51,6 +52,7 @@ public enum UnitType {
* @param isSemiMetric predicate to determine if a unit is semi-metric
* @return type of unit
* @since 2022-04-18
+ * @since v0.4.0
*/
public static final UnitType getType(Unit u, Predicate isSemiMetric) {
if (isSemiMetric.test(u))
diff --git a/src/main/java/sevenUnits/unit/UnitValue.java b/src/main/java/sevenUnits/unit/UnitValue.java
index 97b7e54..4003c17 100644
--- a/src/main/java/sevenUnits/unit/UnitValue.java
+++ b/src/main/java/sevenUnits/unit/UnitValue.java
@@ -29,6 +29,7 @@ import sevenUnits.utils.NameSymbol;
*
* @author Adrien Hopkins
* @since 2020-07-26
+ * @since v0.3.0
*/
public final class UnitValue {
/**
@@ -59,6 +60,7 @@ public final class UnitValue {
* @param other unit to try to convert to
* @return true if this value can be converted to {@code other}.
* @since 2020-10-01
+ * @since v0.3.0
*/
public final boolean canConvertTo(Unit other) {
return this.unit.canConvertTo(other);
@@ -84,6 +86,7 @@ public final class UnitValue {
* needed.
* @return this unit as a {@link LinearUnitValue}
* @since 2020-09-29
+ * @since v0.3.0
*/
public final LinearUnitValue convertToBase(NameSymbol ns) {
final LinearUnit base = LinearUnit.getBase(this.unit).withName(ns);
@@ -95,6 +98,7 @@ public final class UnitValue {
* @return a {@code LinearUnitValue} that is equivalent to this value. It
* will have zero uncertainty.
* @since 2020-09-29
+ * @since v0.3.0
*/
public final LinearUnitValue convertToLinear(LinearUnit newUnit) {
return LinearUnitValue.getExact(newUnit,
@@ -121,6 +125,7 @@ public final class UnitValue {
/**
* @return the unit
* @since 2020-09-29
+ * @since v0.3.0
*/
public final Unit getUnit() {
return this.unit;
@@ -129,6 +134,7 @@ public final class UnitValue {
/**
* @return the value
* @since 2020-09-29
+ * @since v0.3.0
*/
public final double getValue() {
return this.value;
diff --git a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
index b46e821..dd21a22 100644
--- a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
+++ b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
@@ -53,6 +53,7 @@ import java.util.function.Predicate;
*
* @author Adrien Hopkins
* @since 2019-10-17
+ * @since v0.3.0
*/
public final class ConditionalExistenceCollections {
/**
@@ -60,6 +61,7 @@ public final class ConditionalExistenceCollections {
*
* @author Adrien Hopkins
* @since 2019-10-17
+ * @since v0.3.0
* @param type of element in collection
*/
static final class ConditionalExistenceCollection
@@ -73,6 +75,7 @@ public final class ConditionalExistenceCollections {
* @param collection
* @param existenceCondition
* @since 2019-10-17
+ * @since v0.3.0
*/
private ConditionalExistenceCollection(final Collection collection,
final Predicate existenceCondition) {
@@ -149,6 +152,7 @@ public final class ConditionalExistenceCollections {
*
* @author Adrien Hopkins
* @since 2019-10-17
+ * @since v0.3.0
* @param type of elements in iterator
*/
static final class ConditionalExistenceIterator implements Iterator {
@@ -163,6 +167,7 @@ public final class ConditionalExistenceCollections {
* @param iterator
* @param condition
* @since 2019-10-17
+ * @since v0.3.0
*/
private ConditionalExistenceIterator(final Iterator iterator,
final Predicate condition) {
@@ -175,6 +180,7 @@ public final class ConditionalExistenceCollections {
* Gets the next element, and sets nextElement and hasNext accordingly.
*
* @since 2019-10-17
+ * @since v0.3.0
*/
private void getAndSetNextElement() {
do {
@@ -214,6 +220,7 @@ public final class ConditionalExistenceCollections {
*
* @author Adrien Hopkins
* @since 2019-10-17
+ * @since v0.3.0
* @param key type
* @param value type
*/
@@ -227,6 +234,7 @@ public final class ConditionalExistenceCollections {
* @param map
* @param entryExistenceCondition
* @since 2019-10-17
+ * @since v0.3.0
*/
private ConditionalExistenceMap(final Map map,
final Predicate> entryExistenceCondition) {
@@ -313,6 +321,7 @@ public final class ConditionalExistenceCollections {
*
* @author Adrien Hopkins
* @since 2019-10-17
+ * @since v0.3.0
* @param type of element in set
*/
static final class ConditionalExistenceSet extends AbstractSet {
@@ -325,6 +334,7 @@ public final class ConditionalExistenceCollections {
* @param set set to use
* @param existenceCondition condition where element exists
* @since 2019-10-17
+ * @since v0.3.0
*/
private ConditionalExistenceSet(final Set set,
final Predicate existenceCondition) {
@@ -410,6 +420,7 @@ public final class ConditionalExistenceCollections {
* @param existenceCondition elements only exist if this returns true
* @return wrapper collection
* @since 2019-10-17
+ * @since v0.3.0
*/
public static final Collection conditionalExistenceCollection(
final Collection collection,
@@ -427,6 +438,7 @@ public final class ConditionalExistenceCollections {
* @param existenceCondition elements only exist if this returns true
* @return wrapper iterator
* @since 2019-10-17
+ * @since v0.3.0
*/
public static final Iterator conditionalExistenceIterator(
final Iterator iterator, final Predicate existenceCondition) {
@@ -443,6 +455,7 @@ public final class ConditionalExistenceCollections {
* @param entryExistenceCondition mappings only exist if this returns true
* @return wrapper map
* @since 2019-10-17
+ * @since v0.3.0
*/
public static final Map conditionalExistenceMap(
final Map map,
@@ -459,6 +472,7 @@ public final class ConditionalExistenceCollections {
* @param existenceCondition elements only exist if this returns true
* @return wrapper set
* @since 2019-10-17
+ * @since v0.3.0
*/
public static final Set conditionalExistenceSet(final Set set,
final Predicate existenceCondition) {
diff --git a/src/main/java/sevenUnits/utils/DecimalComparison.java b/src/main/java/sevenUnits/utils/DecimalComparison.java
index 4136818..c7564c4 100644
--- a/src/main/java/sevenUnits/utils/DecimalComparison.java
+++ b/src/main/java/sevenUnits/utils/DecimalComparison.java
@@ -193,6 +193,7 @@ public final class DecimalComparison {
* @param b second value to test
* @return whether they are equal
* @since 2020-09-07
+ * @since v0.3.0
*/
public static final boolean equals(final UncertainDouble a,
final UncertainDouble b) {
diff --git a/src/main/java/sevenUnits/utils/ExpressionParser.java b/src/main/java/sevenUnits/utils/ExpressionParser.java
index 8ab6c95..1c8df9f 100644
--- a/src/main/java/sevenUnits/utils/ExpressionParser.java
+++ b/src/main/java/sevenUnits/utils/ExpressionParser.java
@@ -87,6 +87,7 @@ public final class ExpressionParser {
* A map mapping operator strings to numeric functions.
*
* @since 2024-03-23
+ * @since v0.5.0
*/
private final Map> numericOperators;
@@ -526,6 +527,7 @@ public final class ExpressionParser {
* A map mapping operator strings to numeric functions.
*
* @since 2024-03-23
+ * @since v0.5.0
*/
private final Map> numericOperators;
diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java
index c0c8f94..ebb1e8b 100644
--- a/src/main/java/sevenUnits/utils/NameSymbol.java
+++ b/src/main/java/sevenUnits/utils/NameSymbol.java
@@ -29,6 +29,7 @@ import java.util.Set;
*
* @author Adrien Hopkins
* @since 2019-10-21
+ * @since v0.3.0
*/
public final class NameSymbol {
/** The {@code NameSymbol} with all fields empty. */
@@ -67,6 +68,7 @@ public final class NameSymbol {
* @param symbol symbol to use
* @return NameSymbol instance
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if name or symbol is null
*/
public static final NameSymbol of(final String name, final String symbol) {
@@ -83,6 +85,7 @@ public final class NameSymbol {
* @param otherNames other names to use
* @return NameSymbol instance
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if any argument is null
*/
public static final NameSymbol of(final String name, final String symbol,
@@ -101,6 +104,7 @@ public final class NameSymbol {
* @param otherNames other names to use
* @return NameSymbol instance
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if any argument is null
*/
public static final NameSymbol of(final String name, final String symbol,
@@ -117,6 +121,7 @@ public final class NameSymbol {
* @param name name to use
* @return NameSymbol instance
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if name is null
*/
public static final NameSymbol ofName(final String name) {
@@ -140,6 +145,7 @@ public final class NameSymbol {
* @param otherNames other names to use
* @return NameSymbol instance
* @since 2019-11-26
+ * @since v0.3.0
*/
public static final NameSymbol ofNullable(final String name,
final String symbol, final Set otherNames) {
@@ -163,6 +169,7 @@ public final class NameSymbol {
* @param otherNames other names to use
* @return NameSymbol instance
* @since 2019-11-26
+ * @since v0.3.0
*/
public static final NameSymbol ofNullable(final String name,
final String symbol, final String... otherNames) {
@@ -176,6 +183,7 @@ public final class NameSymbol {
* @param symbol symbol to use
* @return NameSymbol instance
* @since 2019-10-21
+ * @since v0.3.0
* @throws NullPointerException if symbol is null
*/
public static final NameSymbol ofSymbol(final String symbol) {
@@ -196,6 +204,7 @@ public final class NameSymbol {
* @param otherNames other names and/or spellings, should be a mutable copy
* of the argument
* @since 2019-10-21
+ * @since v0.3.0
*/
NameSymbol(final Optional primaryName,
final Optional symbol, final Set otherNames) {
@@ -241,6 +250,7 @@ public final class NameSymbol {
/**
* @return otherNames
* @since 2019-10-21
+ * @since v0.3.0
*/
public final Set getOtherNames() {
return this.otherNames;
@@ -249,6 +259,7 @@ public final class NameSymbol {
/**
* @return primaryName
* @since 2019-10-21
+ * @since v0.3.0
*/
public final Optional getPrimaryName() {
return this.primaryName;
@@ -257,6 +268,7 @@ public final class NameSymbol {
/**
* @return symbol
* @since 2019-10-21
+ * @since v0.3.0
*/
public final Optional getSymbol() {
return this.symbol;
@@ -302,8 +314,8 @@ public final class NameSymbol {
* @param name additional name to add
* @return copy of this NameSymbol with the additional name
*
- * @since v0.4.0
* @since 2022-04-19
+ * @since v0.4.0
*/
public final NameSymbol withExtraName(String name) {
if (this.primaryName.isPresent()) {
diff --git a/src/main/java/sevenUnits/utils/Nameable.java b/src/main/java/sevenUnits/utils/Nameable.java
index 15026b7..efd1ab8 100644
--- a/src/main/java/sevenUnits/utils/Nameable.java
+++ b/src/main/java/sevenUnits/utils/Nameable.java
@@ -24,12 +24,14 @@ import java.util.Set;
* and symbol data should be immutable.
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public interface Nameable {
/**
* @return a name for the object - if there's a primary name, it's that,
* otherwise the symbol, otherwise "Unnamed"
* @since 2022-02-26
+ * @since v0.4.0
*/
default String getName() {
final NameSymbol ns = this.getNameSymbol();
@@ -40,12 +42,14 @@ public interface Nameable {
* @return a {@code NameSymbol} that contains this object's primary name,
* symbol and other names
* @since 2020-09-07
+ * @since v0.3.0
*/
NameSymbol getNameSymbol();
/**
* @return set of alternate names
* @since 2020-09-07
+ * @since v0.3.0
*/
default Set getOtherNames() {
return this.getNameSymbol().getOtherNames();
@@ -54,6 +58,7 @@ public interface Nameable {
/**
* @return preferred name of object
* @since 2020-09-07
+ * @since v0.3.0
*/
default Optional getPrimaryName() {
return this.getNameSymbol().getPrimaryName();
@@ -63,6 +68,7 @@ public interface Nameable {
* @return a short name for the object - if there's a symbol, it's that,
* otherwise the symbol, otherwise "Unnamed"
* @since 2022-02-26
+ * @since v0.4.0
*/
default String getShortName() {
final NameSymbol ns = this.getNameSymbol();
@@ -72,6 +78,7 @@ public interface Nameable {
/**
* @return short symbol representing object
* @since 2020-09-07
+ * @since v0.3.0
*/
default Optional getSymbol() {
return this.getNameSymbol().getSymbol();
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index 772ff5e..1b8832e 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.java
@@ -33,6 +33,7 @@ import java.util.function.Function;
* @author Adrien Hopkins
* @param type of object that is being multiplied
* @since 2019-10-16
+ * @since v0.3.0
*/
public class ObjectProduct implements Nameable {
/**
@@ -47,6 +48,7 @@ public class ObjectProduct implements Nameable {
* @param type of objects that can be multiplied
* @return empty product
* @since 2019-10-16
+ * @since v0.3.0
*/
public static final ObjectProduct empty() {
return new ObjectProduct<>(new HashMap<>());
@@ -59,6 +61,7 @@ public class ObjectProduct implements Nameable {
* @param map map mapping objects to exponents
* @return object product
* @since 2019-10-16
+ * @since v0.3.0
*/
public static final ObjectProduct fromExponentMapping(
final Map map) {
@@ -73,6 +76,7 @@ public class ObjectProduct implements Nameable {
* @param type of object contained in returned ObjectProduct
* @return product
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if object is null
*/
public static final ObjectProduct oneOf(final T object) {
@@ -87,6 +91,7 @@ public class ObjectProduct implements Nameable {
* treats zero as null, and is immutable.
*
* @since 2019-10-16
+ * @since v0.3.0
*/
final Map exponents;
@@ -100,6 +105,7 @@ public class ObjectProduct implements Nameable {
*
* @param exponents objects that make up this product
* @since 2019-10-16
+ * @since v0.3.0
*/
ObjectProduct(final Map exponents) {
this(exponents, NameSymbol.EMPTY);
@@ -111,6 +117,7 @@ public class ObjectProduct implements Nameable {
* @param exponents objects that make up this product
* @param nameSymbol name and symbol of object product
* @since 2019-10-16
+ * @since v0.3.0
*/
ObjectProduct(final Map exponents, NameSymbol nameSymbol) {
this.exponents = Collections.unmodifiableMap(
@@ -125,6 +132,7 @@ public class ObjectProduct implements Nameable {
* @param other other product
* @return quotient of two products
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if other is null
*/
public ObjectProduct dividedBy(final ObjectProduct other) {
@@ -158,6 +166,7 @@ public class ObjectProduct implements Nameable {
/**
* @return immutable map mapping objects to exponents
* @since 2019-10-16
+ * @since v0.3.0
*/
public Map exponentMap() {
return this.exponents;
@@ -209,6 +218,7 @@ public class ObjectProduct implements Nameable {
* @return true if this product is a single object, i.e. it has one exponent
* of one and no other nonzero exponents
* @since 2019-10-16
+ * @since v0.3.0
*/
public boolean isSingleObject() {
int oneCount = 0;
@@ -229,6 +239,7 @@ public class ObjectProduct implements Nameable {
* @param other other product
* @return product of two products
* @since 2019-10-16
+ * @since v0.3.0
* @throws NullPointerException if other is null
*/
public ObjectProduct times(final ObjectProduct other) {
@@ -254,6 +265,7 @@ public class ObjectProduct implements Nameable {
* @param exponent exponent
* @return result of exponentiation
* @since 2019-10-16
+ * @since v0.3.0
*/
public ObjectProduct toExponent(final int exponent) {
final Map map = new HashMap<>(this.exponents);
@@ -274,6 +286,7 @@ public class ObjectProduct implements Nameable {
* @return result of exponentiation
*
* @since 2024-08-22
+ * @since v0.3.0
*/
public ObjectProduct toExponentRounded(final double exponent) {
final Map map = new HashMap<>(this.exponents);
@@ -315,6 +328,7 @@ public class ObjectProduct implements Nameable {
* @param objectToString function to convert objects to strings
* @return string representation of product
* @since 2019-10-16
+ * @since v0.3.0
*/
public String toString(final Function objectToString) {
final List positiveStringComponents = new ArrayList<>();
@@ -347,6 +361,7 @@ public class ObjectProduct implements Nameable {
* @return named version of this {@code ObjectProduct}, using data from
* {@code nameSymbol}
* @since 2021-12-15
+ * @since v0.3.0
*/
public ObjectProduct withName(NameSymbol nameSymbol) {
return new ObjectProduct<>(this.exponents, nameSymbol);
diff --git a/src/main/java/sevenUnits/utils/SemanticVersionNumber.java b/src/main/java/sevenUnits/utils/SemanticVersionNumber.java
index bf198ae..cde3d37 100644
--- a/src/main/java/sevenUnits/utils/SemanticVersionNumber.java
+++ b/src/main/java/sevenUnits/utils/SemanticVersionNumber.java
@@ -39,8 +39,8 @@ import java.util.regex.Pattern;
* are made
*
*
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public final class SemanticVersionNumber
implements Comparable {
@@ -52,8 +52,8 @@ public final class SemanticVersionNumber
* throw NullPointerExceptions, everything else throws
* IllegalArgumentException.
*
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public static final class Builder {
private final int major;
@@ -69,8 +69,8 @@ public final class SemanticVersionNumber
* @param major major version number of final version
* @param minor minor version number of final version
* @param patch patch version number of final version
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
private Builder(int major, int minor, int patch) {
this.major = major;
@@ -82,8 +82,8 @@ public final class SemanticVersionNumber
/**
* @return version number created by this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public SemanticVersionNumber build() {
return new SemanticVersionNumber(this.major, this.minor, this.patch,
@@ -95,8 +95,8 @@ public final class SemanticVersionNumber
*
* @param identifiers build metadata
* @return this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public Builder buildMetadata(List identifiers) {
Objects.requireNonNull(identifiers, "identifiers may not be null");
@@ -115,8 +115,8 @@ public final class SemanticVersionNumber
*
* @param identifiers build metadata
* @return this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public Builder buildMetadata(String... identifiers) {
Objects.requireNonNull(identifiers, "identifiers may not be null");
@@ -154,8 +154,8 @@ public final class SemanticVersionNumber
*
* @param identifiers pre-release identifier(s) to add
* @return this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public Builder preRelease(int... identifiers) {
Objects.requireNonNull(identifiers, "identifiers may not be null");
@@ -173,8 +173,8 @@ public final class SemanticVersionNumber
*
* @param identifiers pre-release identifier(s) to add
* @return this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public Builder preRelease(List identifiers) {
Objects.requireNonNull(identifiers, "identifiers may not be null");
@@ -193,8 +193,8 @@ public final class SemanticVersionNumber
*
* @param identifiers pre-release identifier(s) to add
* @return this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public Builder preRelease(String... identifiers) {
Objects.requireNonNull(identifiers, "identifiers may not be null");
@@ -214,8 +214,8 @@ public final class SemanticVersionNumber
* @param identifier1 first identifier
* @param identifier2 second identifier
* @return this builder
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public Builder preRelease(String identifier1, int identifier2) {
Objects.requireNonNull(identifier1, "identifier1 may not be null");
@@ -280,8 +280,8 @@ public final class SemanticVersionNumber
* @param patch patch version number of final version
* @return version number builder
* @throws IllegalArgumentException if any argument is negative
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public static final SemanticVersionNumber.Builder builder(int major,
int minor, int patch) {
@@ -304,8 +304,8 @@ public final class SemanticVersionNumber
* @param b second list
* @return result of comparison as in a comparator
* @see Comparator
- * @since v0.4.0
* @since 2022-02-20
+ * @since v0.4.0
*/
private static final int compareIdentifiers(List a, List b) {
// test pre-release size
@@ -365,8 +365,8 @@ public final class SemanticVersionNumber
*
* @param versionString string to parse
* @return {@code SemanticVersionNumber} instance
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
* @see #toString
*/
public static final SemanticVersionNumber fromString(String versionString) {
@@ -409,8 +409,8 @@ public final class SemanticVersionNumber
*
* @param versionString string to test
* @return true iff string is valid
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public static final boolean isValidVersionString(String versionString) {
return VERSION_NUMBER.matcher(versionString).matches();
@@ -429,8 +429,8 @@ public final class SemanticVersionNumber
* @throws IllegalArgumentException if any argument is negative or if the
* preReleaseType is null, empty or not
* alphanumeric (0-9, A-Z, a-z, - only)
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public static final SemanticVersionNumber preRelease(int major, int minor,
int patch, String preReleaseType, int preReleaseNumber) {
@@ -467,8 +467,8 @@ public final class SemanticVersionNumber
* @param patch patch version number
* @return {@code SemanticVersionNumber} instance
* @throws IllegalArgumentException if any argument is negative
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public static final SemanticVersionNumber stableVersion(int major, int minor,
int patch) {
@@ -500,8 +500,8 @@ public final class SemanticVersionNumber
* @param patch patch version number
* @param preReleaseIdentifiers pre-release version data
* @param buildMetadata build metadata
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
private SemanticVersionNumber(int major, int minor, int patch,
List preReleaseIdentifiers, List buildMetadata) {
@@ -514,8 +514,8 @@ public final class SemanticVersionNumber
/**
* @return build metadata (empty if there is none)
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public List buildMetadata() {
return Collections.unmodifiableList(this.buildMetadata);
@@ -585,8 +585,8 @@ public final class SemanticVersionNumber
* @param other version to compare with
* @return true if you can definitely upgrade to {@code other} without
* changing code
- * @since v0.4.0
* @since 2022-02-20
+ * @since v0.4.0
*/
public boolean compatibleWith(SemanticVersionNumber other) {
Objects.requireNonNull(other, "other may not be null");
@@ -639,8 +639,8 @@ public final class SemanticVersionNumber
/**
* @return true iff this version is stable (major version > 0 and not a
* pre-release)
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public boolean isStable() {
return this.major > 0 && this.preReleaseIdentifiers.isEmpty();
@@ -649,8 +649,8 @@ public final class SemanticVersionNumber
/**
* @return the MAJOR version number, incremented when you make backwards
* incompatible API changes
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public int majorVersion() {
return this.major;
@@ -659,8 +659,8 @@ public final class SemanticVersionNumber
/**
* @return the MINOR version number, incremented when you add backwards
* compatible functionality
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public int minorVersion() {
return this.minor;
@@ -669,8 +669,8 @@ public final class SemanticVersionNumber
/**
* @return the PATCH version number, incremented when you make backwards
* compatible bug fixes
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public int patchVersion() {
return this.patch;
@@ -679,8 +679,8 @@ public final class SemanticVersionNumber
/**
* @return identifiers describing this pre-release (empty if not a
* pre-release)
- * @since v0.4.0
* @since 2022-02-19
+ * @since v0.4.0
*/
public List preReleaseIdentifiers() {
return Collections.unmodifiableList(this.preReleaseIdentifiers);
diff --git a/src/main/java/sevenUnits/utils/UncertainDouble.java b/src/main/java/sevenUnits/utils/UncertainDouble.java
index 46803d1..f700454 100644
--- a/src/main/java/sevenUnits/utils/UncertainDouble.java
+++ b/src/main/java/sevenUnits/utils/UncertainDouble.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
* arguments is null.
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final class UncertainDouble implements Comparable {
/**
@@ -56,6 +57,7 @@ public final class UncertainDouble implements Comparable {
* @throws NumberFormatException if the argument is not a number
*
* @since 2022-04-18
+ * @since v0.4.0
*/
public static final UncertainDouble fromRoundedString(String s) {
final BigDecimal value = new BigDecimal(s);
@@ -75,6 +77,7 @@ public final class UncertainDouble implements Comparable {
* @return {@code UncertainDouble} instance
* @throws IllegalArgumentException if the string is invalid
* @since 2020-09-07
+ * @since v0.3.0
*/
public static final UncertainDouble fromString(String s) {
Objects.requireNonNull(s, "s may not be null");
@@ -116,6 +119,7 @@ public final class UncertainDouble implements Comparable {
* @return {@code UncertainDouble} instance with these parameters
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public static final UncertainDouble of(double value, double uncertainty) {
return new UncertainDouble(value, uncertainty);
@@ -132,6 +136,7 @@ public final class UncertainDouble implements Comparable {
* @return {@code UncertainDouble} instance with these parameters
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public static final UncertainDouble ofRelative(double value,
double relativeUncertainty) {
@@ -146,6 +151,7 @@ public final class UncertainDouble implements Comparable {
* @param value
* @param uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
private UncertainDouble(double value, double uncertainty) {
this.value = value;
@@ -178,6 +184,7 @@ public final class UncertainDouble implements Comparable {
* @return quotient
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble dividedBy(UncertainDouble other) {
Objects.requireNonNull(other, "other may not be null");
@@ -192,6 +199,7 @@ public final class UncertainDouble implements Comparable {
* @return quotient
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble dividedByExact(double other) {
return UncertainDouble.of(this.value / other, this.uncertainty / other);
@@ -216,6 +224,7 @@ public final class UncertainDouble implements Comparable {
* @return true iff this and {@code other} are within each other's
* uncertainty range.
* @since 2020-09-07
+ * @since v0.3.0
*/
public final boolean equivalent(UncertainDouble other) {
Objects.requireNonNull(other, "other may not be null");
@@ -227,6 +236,7 @@ public final class UncertainDouble implements Comparable {
* Gets the preferred scale for rounding a value for toString.
*
* @since 2020-09-07
+ * @since v0.3.0
*/
private final int getDisplayScale() {
// round based on uncertainty
@@ -263,6 +273,7 @@ public final class UncertainDouble implements Comparable {
* @return true iff the value has no uncertainty
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final boolean isExact() {
return this.uncertainty == 0;
@@ -275,6 +286,7 @@ public final class UncertainDouble implements Comparable {
* @return result of subtraction
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble minus(UncertainDouble other) {
Objects.requireNonNull(other, "other may not be null");
@@ -289,6 +301,7 @@ public final class UncertainDouble implements Comparable {
* @return result of subtraction
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble minusExact(double other) {
return UncertainDouble.of(this.value - other, this.uncertainty);
@@ -301,6 +314,7 @@ public final class UncertainDouble implements Comparable {
* @return result of addition
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble plus(UncertainDouble other) {
Objects.requireNonNull(other, "other may not be null");
@@ -315,6 +329,7 @@ public final class UncertainDouble implements Comparable {
* @return result of addition
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble plusExact(double other) {
return UncertainDouble.of(this.value + other, this.uncertainty);
@@ -323,6 +338,7 @@ public final class UncertainDouble implements Comparable {
/**
* @return relative uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
public final double relativeUncertainty() {
return this.uncertainty / this.value;
@@ -335,6 +351,7 @@ public final class UncertainDouble implements Comparable {
* @return product
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble times(UncertainDouble other) {
Objects.requireNonNull(other, "other may not be null");
@@ -349,6 +366,7 @@ public final class UncertainDouble implements Comparable {
* @return product
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble timesExact(double other) {
return UncertainDouble.of(this.value * other, this.uncertainty * other);
@@ -361,6 +379,7 @@ public final class UncertainDouble implements Comparable {
* @return result of exponentation
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble toExponent(UncertainDouble other) {
Objects.requireNonNull(other, "other may not be null");
@@ -381,6 +400,7 @@ public final class UncertainDouble implements Comparable {
* @return result of exponentation
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final UncertainDouble toExponentExact(double other) {
return UncertainDouble.ofRelative(Math.pow(this.value, other),
@@ -404,6 +424,7 @@ public final class UncertainDouble implements Comparable {
*
*
* @since 2020-09-07
+ * @since v0.3.0
*/
@Override
public final String toString() {
@@ -441,6 +462,7 @@ public final class UncertainDouble implements Comparable {
* @return string representation of this {@code UncertainDouble}
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final String toString(boolean showUncertainty,
RoundingMode roundingMode) {
@@ -473,6 +495,7 @@ public final class UncertainDouble implements Comparable {
/**
* @return absolute uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
public final double uncertainty() {
return this.uncertainty;
@@ -481,6 +504,7 @@ public final class UncertainDouble implements Comparable {
/**
* @return value without uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
public final double value() {
return this.value;
diff --git a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
index fbf78a3..97df107 100644
--- a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
+++ b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java
@@ -26,6 +26,7 @@ import sevenUnits.unit.UnitPrefix;
* A rule that specifies whether prefix repetition is allowed
*
* @since 2020-08-26
+ * @since v0.3.0
*/
public enum DefaultPrefixRepetitionRule implements Predicate> {
/** Prefix repetition is never allowed; only one prefix may be used. */
diff --git a/src/main/java/sevenUnitsGUI/DelegateListModel.java b/src/main/java/sevenUnitsGUI/DelegateListModel.java
index 4925197..200eee2 100644
--- a/src/main/java/sevenUnitsGUI/DelegateListModel.java
+++ b/src/main/java/sevenUnitsGUI/DelegateListModel.java
@@ -56,6 +56,7 @@ final class DelegateListModel extends AbstractListModel
* Creates an empty {@code DelegateListModel}.
*
* @since 2019-04-13
+ * @since v0.2.0
*/
public DelegateListModel() {
this(new ArrayList<>());
diff --git a/src/main/java/sevenUnitsGUI/ExpressionConversionView.java b/src/main/java/sevenUnitsGUI/ExpressionConversionView.java
index ead07c5..20eb23c 100644
--- a/src/main/java/sevenUnitsGUI/ExpressionConversionView.java
+++ b/src/main/java/sevenUnitsGUI/ExpressionConversionView.java
@@ -20,21 +20,21 @@ package sevenUnitsGUI;
* A View that can convert unit expressions
*
* @author Adrien Hopkins
- * @since v0.4.0
* @since 2021-12-15
+ * @since v0.4.0
*/
public interface ExpressionConversionView extends View {
/**
* @return unit expression to convert from
- * @since v0.4.0
* @since 2021-12-15
+ * @since v0.4.0
*/
String getFromExpression();
/**
* @return unit expression to convert to
- * @since v0.4.0
* @since 2021-12-15
+ * @since v0.4.0
*/
String getToExpression();
@@ -42,8 +42,8 @@ public interface ExpressionConversionView extends View {
* Shows the output of an expression conversion to the user.
*
* @param uc unit conversion to show
- * @since v0.4.0
* @since 2021-12-15
+ * @since v0.4.0
*/
void showExpressionConversionOutput(UnitConversionRecord uc);
}
diff --git a/src/main/java/sevenUnitsGUI/Main.java b/src/main/java/sevenUnitsGUI/Main.java
index b573a09..3ff2fd9 100644
--- a/src/main/java/sevenUnitsGUI/Main.java
+++ b/src/main/java/sevenUnitsGUI/Main.java
@@ -19,8 +19,8 @@ package sevenUnitsGUI;
/**
* The main code for the 7Units GUI
*
- * @since v0.4.0
* @since 2022-04-19
+ * @since v0.4.0
*/
public final class Main {
@@ -28,8 +28,8 @@ public final class Main {
* The main method that starts 7Units
*
* @param args commandline arguments
- * @since v0.4.0
* @since 2022-04-19
+ * @since v0.4.0
*/
public static void main(String[] args) {
View.createTabbedView();
diff --git a/src/main/java/sevenUnitsGUI/PrefixSearchRule.java b/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
index 1937fd2..2ea0923 100644
--- a/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
+++ b/src/main/java/sevenUnitsGUI/PrefixSearchRule.java
@@ -34,8 +34,8 @@ import sevenUnits.unit.UnitPrefix;
* A search rule that applies a certain set of prefixes to a unit. It always
* includes the original unit in the output map.
*
- * @since v0.4.0
* @since 2022-07-06
+ * @since v0.4.0
*/
public final class PrefixSearchRule implements
Function, Map> {
@@ -70,8 +70,8 @@ public final class PrefixSearchRule implements
*
* @param prefixes prefixes to apply
* @return prefix rule
- * @since v0.4.0
* @since 2022-07-06
+ * @since v0.4.0
*/
public static final PrefixSearchRule getCoherentOnlyRule(
Set prefixes) {
@@ -84,8 +84,8 @@ public final class PrefixSearchRule implements
*
* @param prefixes prefixes to apply
* @return prefix rule
- * @since v0.4.0
* @since 2022-07-06
+ * @since v0.4.0
*/
public static final PrefixSearchRule getUniversalRule(
Set prefixes) {
@@ -106,8 +106,8 @@ public final class PrefixSearchRule implements
* @param prefixes prefixes to add to units
* @param prefixableUnitRule function that determines which units get
* prefixes
- * @since v0.4.0
* @since 2022-07-06
+ * @since v0.4.0
*/
public PrefixSearchRule(Set prefixes,
Predicate prefixableUnitRule) {
@@ -143,8 +143,8 @@ public final class PrefixSearchRule implements
/**
* @return rule that determines which units get prefixes
- * @since v0.4.0
* @since 2022-07-09
+ * @since v0.4.0
*/
public Predicate getPrefixableUnitRule() {
return this.prefixableUnitRule;
@@ -152,8 +152,8 @@ public final class PrefixSearchRule implements
/**
* @return the prefixes that are applied by this rule
- * @since v0.4.0
* @since 2022-07-06
+ * @since v0.4.0
*/
public Set getPrefixes() {
return this.prefixes;
diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java
index 7c66d55..ff7e23c 100644
--- a/src/main/java/sevenUnitsGUI/Presenter.java
+++ b/src/main/java/sevenUnitsGUI/Presenter.java
@@ -60,6 +60,7 @@ import sevenUnitsGUI.StandardDisplayRules.UncertaintyBased;
*
* @author Adrien Hopkins
* @since 2021-12-15
+ * @since v0.4.0
*/
public final class Presenter {
/**
@@ -139,6 +140,7 @@ public final class Presenter {
* {@code maxLineLength}. If no good spot is found, returns -1.
*
* @since 2024-08-22
+ * @since v1.0.0
*/
private static int findLineSplit(String toWrap, int maxLineLength) {
for (var i = maxLineLength - 1; i >= 0; i--) {
@@ -155,6 +157,7 @@ public final class Presenter {
* @param filename filename to get resource from
* @return contents of file
* @since 2021-03-27
+ * @since v0.3.0
*/
private static List getLinesFromResource(String filename) {
final List lines = new ArrayList<>();
@@ -178,6 +181,7 @@ public final class Presenter {
* @param filepath file to use as resource
* @return obtained Path
* @since 2021-03-27
+ * @since v0.3.0
*/
private static InputStream inputStream(String filepath) {
return Presenter.class.getResourceAsStream(filepath);
@@ -188,6 +192,7 @@ public final class Presenter {
* the nearest integer.
*
* @since 2024-08-16
+ * @since v1.0.0
*/
private static String linearUnitValueIntToString(LinearUnitValue uv) {
return Long.toString(Math.round(uv.getValueExact())) + " " + uv.getUnit();
@@ -227,6 +232,7 @@ public final class Presenter {
/**
* @return true iff a and b have any elements in common
* @since 2022-04-19
+ * @since v0.4.0
*/
private static boolean sharesAnyElements(Set> a, Set> b) {
for (final Object e : a) {
@@ -254,6 +260,7 @@ public final class Presenter {
/**
* @return {@code line} with any comments removed.
* @since 2021-03-13
+ * @since v0.3.0
*/
private static String withoutComments(String line) {
final var index = line.indexOf('#');
@@ -264,6 +271,7 @@ public final class Presenter {
* Wraps a string, ensuring no line is longer than {@code maxLineLength}.
*
* @since 2024-08-22
+ * @since v1.0.0
*/
private static String wrapString(String toWrap, int maxLineLength) {
final var wrapped = new StringBuilder(toWrap.length());
@@ -366,6 +374,7 @@ public final class Presenter {
*
* @param view the view that this presenter communicates with
* @since 2021-12-15
+ * @since v0.4.0
*/
public Presenter(View view) {
this.view = view;
@@ -449,6 +458,7 @@ public final class Presenter {
* @param e entry
* @return stream of entries, ready for flat-mapping
* @since 2022-07-06
+ * @since v0.4.0
*/
private Stream> applySearchRule(
Map.Entry e) {
@@ -472,6 +482,7 @@ public final class Presenter {
* not implement
* {@link ExpressionConversionView})
* @since 2021-12-15
+ * @since v0.4.0
*/
public void convertExpressions() {
if (!(this.view instanceof ExpressionConversionView))
@@ -515,6 +526,7 @@ public final class Presenter {
* returned.
*
* @since 2024-08-15
+ * @since v1.0.0
*/
private Optional convertExpressionToExpression(
String fromExpression, String toExpression) {
@@ -567,6 +579,7 @@ public final class Presenter {
* the view and Optional.empty() is returned.
*
* @since 2024-08-15
+ * @since v1.0.0
*/
private Optional convertExpressionToMultiUnit(
String fromExpression, String[] toExpressions) {
@@ -617,6 +630,7 @@ public final class Presenter {
* error happened, it is shown to the view and Optional.empty() is returned.
*
* @since 2024-08-15
+ * @since v1.0.0
*/
private Optional convertExpressionToNamedMultiUnit(
String fromExpression, String toName) {
@@ -653,6 +667,7 @@ public final class Presenter {
* implement
* {@link UnitConversionView})
* @since 2021-12-15
+ * @since v0.4.0
*/
public void convertUnits() {
if (!(this.view instanceof UnitConversionView))
@@ -770,6 +785,7 @@ public final class Presenter {
/**
* @return true iff duplicate units are shown in unit lists
* @since 2022-03-30
+ * @since v0.4.0
*/
public boolean duplicatesShown() {
return this.showDuplicates;
@@ -778,6 +794,7 @@ public final class Presenter {
/**
* @return text in About file
* @since 2022-02-19
+ * @since v0.4.0
*/
public String getAboutText() {
final Path customFilepath = Presenter.pathFromConfig(
@@ -809,6 +826,7 @@ public final class Presenter {
/**
* @return set of all locales available to select
* @since 2025-02-21
+ * @since v1.0.0
*/
public Set getAvailableLocales() {
return this.locales.keySet();
@@ -820,6 +838,7 @@ public final class Presenter {
* @param dimension dimension to name
* @return name of dimension
* @since 2022-04-16
+ * @since v0.4.0
*/
String getDimensionName(ObjectProduct dimension) {
// find this dimension in the database and get its name
@@ -847,6 +866,7 @@ public final class Presenter {
* @return the rule that is used by this presenter to convert numbers into
* strings
* @since 2022-04-10
+ * @since v0.4.0
*/
public Function getNumberDisplayRule() {
return this.numberDisplayRule;
@@ -856,6 +876,7 @@ public final class Presenter {
* @return the rule that is used by this presenter to convert strings into
* numbers
* @since 2022-04-10
+ * @since v0.4.0
*/
@SuppressWarnings("unused") // not implemented yet
private Function getNumberParsingRule() {
@@ -865,6 +886,7 @@ public final class Presenter {
/**
* @return the rule that determines whether a set of prefixes is valid
* @since 2022-04-19
+ * @since v0.4.0
*/
public Predicate> getPrefixRepetitionRule() {
return this.prefixRepetitionRule;
@@ -873,6 +895,7 @@ public final class Presenter {
/**
* @return the rule that determines which units are prefixed
* @since 2022-07-08
+ * @since v0.4.0
*/
public Function, Map> getSearchRule() {
return this.searchRule;
@@ -881,6 +904,7 @@ public final class Presenter {
/**
* @return a search rule that shows all single prefixes
* @since 2022-07-08
+ * @since v0.4.0
*/
public Function, Map> getUniversalSearchRule() {
return PrefixSearchRule.getCoherentOnlyRule(
@@ -890,6 +914,7 @@ public final class Presenter {
/**
* @return user's selected locale
* @since 2025-02-21
+ * @since v1.0.0
*/
public String getUserLocale() {
return userLocale;
@@ -898,6 +923,7 @@ public final class Presenter {
/**
* @return the view associated with this presenter
* @since 2022-04-19
+ * @since v0.4.0
*/
public View getView() {
return this.view;
@@ -908,6 +934,7 @@ public final class Presenter {
* message and alerts the user.
*
* @since 2024-08-22
+ * @since v1.0.0
*/
private void handleLoadErrors(List errors) {
if (!errors.isEmpty()) {
@@ -925,6 +952,7 @@ public final class Presenter {
* @return whether or not the provided unit is semi-metric (i.e. an
* exception)
* @since 2022-04-16
+ * @since v0.4.0
*/
boolean isSemiMetric(Unit u) {
// determine if u is an exception
@@ -944,6 +972,7 @@ public final class Presenter {
* number display rule.
*
* @since 2024-08-16
+ * @since v1.0.0
*/
private String linearUnitValueSumToString(List values) {
final var integerPart = values.subList(0, values.size() - 1).stream()
@@ -1018,6 +1047,7 @@ public final class Presenter {
*
* @param settingsFile file settings should be loaded from
* @since 2021-12-15
+ * @since v0.4.0
*/
void loadSettings(Path settingsFile) {
this.customDimensionFiles.clear();
@@ -1086,6 +1116,7 @@ public final class Presenter {
/**
* @return a message showing how much stuff has been loaded
* @since 2024-08-22
+ * @since v1.0.0
*/
private String loadStatMsg() {
return this.getLocalizedText("load_stat_msg")
@@ -1107,6 +1138,7 @@ public final class Presenter {
* unit list and imperial/USC units removed from the To unit list)
*
* @since 2022-03-30
+ * @since v0.4.0
*/
public boolean oneWayConversionEnabled() {
return this.oneWayConversionEnabled;
@@ -1118,6 +1150,7 @@ public final class Presenter {
* they depend on are not created yet.
*
* @since 2022-02-26
+ * @since v0.4.0
*/
public void postViewInitialize() {
// unit conversion specific stuff
@@ -1148,6 +1181,7 @@ public final class Presenter {
*
* @return false iff the presenter could not write to the file
* @since 2022-04-19
+ * @since v0.4.0
*/
public boolean saveSettings() {
final var configDir = CONFIG_FILE.getParent();
@@ -1187,6 +1221,7 @@ public final class Presenter {
* @param numberDisplayRule the new rule that will be used by this presenter
* to convert numbers into strings
* @since 2022-04-10
+ * @since v0.4.0
*/
public void setNumberDisplayRule(
Function numberDisplayRule) {
@@ -1197,6 +1232,7 @@ public final class Presenter {
* @param numberParsingRule the new rule that will be used by this presenter
* to convert strings into numbers
* @since 2022-04-10
+ * @since v0.4.0
*/
@SuppressWarnings("unused") // not implemented yet
private void setNumberParsingRule(
@@ -1208,6 +1244,7 @@ public final class Presenter {
* @param oneWayConversionEnabled whether not one-way conversion should be
* enabled
* @since 2022-03-30
+ * @since v0.4.0
* @see #oneWayConversionEnabled
*/
public void setOneWayConversionEnabled(boolean oneWayConversionEnabled) {
@@ -1219,6 +1256,7 @@ public final class Presenter {
* @param prefixRepetitionRule the rule that determines whether a set of
* prefixes is valid
* @since 2022-04-19
+ * @since v0.4.0
*/
public void setPrefixRepetitionRule(
Predicate