diff options
author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2024-03-24 13:14:11 -0500 |
---|---|---|
committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2024-03-24 13:14:11 -0500 |
commit | 26291e672b0e683edc9d57710a9a9d96ca199c45 (patch) | |
tree | df88f3d3f110e50f38b8a2752d55df4a0c777677 | |
parent | cc45a65c78c578eb404d8773b22e5b046917621f (diff) |
Format source code & set explicit UTF-8
56 files changed, 1639 insertions, 1600 deletions
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/<project>=UTF-8 diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 0000000..5a0ad22 --- /dev/null +++ b/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/src/main/java/sevenUnits/ProgramInfo.java b/src/main/java/sevenUnits/ProgramInfo.java index d94347b..017fce9 100644 --- a/src/main/java/sevenUnits/ProgramInfo.java +++ b/src/main/java/sevenUnits/ProgramInfo.java @@ -25,15 +25,15 @@ import sevenUnits.utils.SemanticVersionNumber; * @since 2021-06-28 */ public final class ProgramInfo { - + /** The version number (0.5.0-alpha.2) */ public static final SemanticVersionNumber VERSION = SemanticVersionNumber .preRelease(0, 5, 0, "alpha", 2); - + private ProgramInfo() { // this class is only for static variables, you shouldn't be able to // construct an instance throw new AssertionError(); } - + } diff --git a/src/main/java/sevenUnits/unit/BaseDimension.java b/src/main/java/sevenUnits/unit/BaseDimension.java index 820d48c..3f1f75f 100644 --- a/src/main/java/sevenUnits/unit/BaseDimension.java +++ b/src/main/java/sevenUnits/unit/BaseDimension.java @@ -39,7 +39,7 @@ public final class BaseDimension implements Nameable { public static BaseDimension valueOf(final String name, final String symbol) { return new BaseDimension(name, symbol); } - + /** * The name of the dimension. */ @@ -49,7 +49,7 @@ public final class BaseDimension implements Nameable { * or two characters. */ private final String symbol; - + /** * Creates the {@code BaseDimension}. * @@ -62,7 +62,7 @@ public final class BaseDimension implements Nameable { this.name = Objects.requireNonNull(name, "name must not be null."); this.symbol = Objects.requireNonNull(symbol, "symbol must not be null."); } - + /** * @since v0.4.0 */ @@ -70,7 +70,7 @@ public final class BaseDimension implements Nameable { public NameSymbol getNameSymbol() { return NameSymbol.of(this.name, this.symbol); } - + @Override public String toString() { return String.format("%s (%s)", this.name, this.symbol); diff --git a/src/main/java/sevenUnits/unit/BaseUnit.java b/src/main/java/sevenUnits/unit/BaseUnit.java index dba7f52..fe85a7b 100644 --- a/src/main/java/sevenUnits/unit/BaseUnit.java +++ b/src/main/java/sevenUnits/unit/BaseUnit.java @@ -46,7 +46,7 @@ public final class BaseUnit extends Unit { final String name, final String symbol) { return new BaseUnit(dimension, name, symbol, new HashSet<>()); } - + /** * Gets a base unit from the dimension it measures, its name and its symbol. * @@ -60,12 +60,12 @@ public final class BaseUnit extends Unit { final String name, final String symbol, final Set<String> otherNames) { return new BaseUnit(dimension, name, symbol, otherNames); } - + /** * The dimension measured by this base unit. */ private final BaseDimension dimension; - + /** * Creates the {@code BaseUnit}. * @@ -81,7 +81,7 @@ public final class BaseUnit extends Unit { this.dimension = Objects.requireNonNull(dimension, "dimension must not be null."); } - + /** * Returns a {@code LinearUnit} with this unit as a base and a conversion * factor of 1. This operation must be done in order to allow units to be @@ -93,17 +93,17 @@ public final class BaseUnit extends Unit { public LinearUnit asLinearUnit() { return LinearUnit.valueOf(this.getBase(), 1); } - + @Override protected double convertFromBase(final double value) { return value; } - + @Override protected double convertToBase(final double value) { return value; } - + /** * @return dimension * @since 2019-10-16 @@ -111,7 +111,7 @@ public final class BaseUnit extends Unit { public final BaseDimension getBaseDimension() { return this.dimension; } - + @Override public String toString() { return this.getPrimaryName().orElse("Unnamed unit") @@ -119,7 +119,7 @@ public final class BaseUnit extends Unit { ? String.format(" (%s)", this.getSymbol().get()) : ""); } - + @Override public BaseUnit withName(final NameSymbol ns) { Objects.requireNonNull(ns, "ns must not be null."); diff --git a/src/main/java/sevenUnits/unit/BritishImperial.java b/src/main/java/sevenUnits/unit/BritishImperial.java index 0ecba6d..69a3c05 100644 --- a/src/main/java/sevenUnits/unit/BritishImperial.java +++ b/src/main/java/sevenUnits/unit/BritishImperial.java @@ -39,7 +39,7 @@ public final class BritishImperial { public static final LinearUnit ROOD = Length.ROD.times(Length.FURLONG); public static final LinearUnit ACRE = Length.FURLONG.times(Length.CHAIN); } - + /** * Imperial units that measure length * @@ -59,15 +59,15 @@ public final class BritishImperial { public static final LinearUnit FURLONG = CHAIN.times(10); public static final LinearUnit MILE = FURLONG.times(8); public static final LinearUnit LEAGUE = MILE.times(3); - + public static final LinearUnit NAUTICAL_MILE = Metric.METRE.times(1852); public static final LinearUnit CABLE = NAUTICAL_MILE.dividedBy(10); public static final LinearUnit FATHOM = CABLE.dividedBy(100); - + public static final LinearUnit ROD = YARD.times(5.5); public static final LinearUnit LINK = ROD.dividedBy(25); } - + /** * British Imperial units that measure mass. * @@ -85,7 +85,7 @@ public final class BritishImperial { public static final LinearUnit LONG_TON = HUNDREDWEIGHT.times(20); public static final LinearUnit SLUG = Metric.KILOGRAM.times(14.59390294); } - + /** * British Imperial units that measure volume * @@ -101,23 +101,23 @@ public final class BritishImperial { public static final LinearUnit GALLON = QUART.times(4); public static final LinearUnit PECK = GALLON.times(2); public static final LinearUnit BUSHEL = PECK.times(4); - + public static final LinearUnit CUBIC_INCH = Length.INCH.toExponent(3); public static final LinearUnit CUBIC_FOOT = Length.FOOT.toExponent(3); public static final LinearUnit CUBIC_YARD = Length.YARD.toExponent(3); public static final LinearUnit ACRE_FOOT = Area.ACRE.times(Length.FOOT); } - + public static final LinearUnit OUNCE_FORCE = Mass.OUNCE .times(Metric.Constants.EARTH_GRAVITY); public static final LinearUnit POUND_FORCE = Mass.POUND .times(Metric.Constants.EARTH_GRAVITY); - + public static final LinearUnit BRITISH_THERMAL_UNIT = Metric.JOULE .times(1055.06); public static final LinearUnit CALORIE = Metric.JOULE.times(4.184); public static final LinearUnit KILOCALORIE = Metric.JOULE.times(4184); - + public static final Unit FAHRENHEIT = Unit .fromConversionFunctions(Metric.KELVIN.getBase(), tempK -> tempK * 1.8 - 459.67, tempF -> (tempF + 459.67) / 1.8) diff --git a/src/main/java/sevenUnits/unit/FunctionalUnit.java b/src/main/java/sevenUnits/unit/FunctionalUnit.java index 720b0af..6de446f 100644 --- a/src/main/java/sevenUnits/unit/FunctionalUnit.java +++ b/src/main/java/sevenUnits/unit/FunctionalUnit.java @@ -30,14 +30,16 @@ import sevenUnits.utils.ObjectProduct; */ final class FunctionalUnit extends Unit { /** - * A function that accepts a value expressed in the unit's base and returns that value expressed in this unit. + * A function that accepts a value expressed in the unit's base and returns + * that value expressed in this unit. * * @since 2019-05-22 */ private final DoubleUnaryOperator converterFrom; /** - * A function that accepts a value expressed in the unit and returns that value expressed in the unit's base. + * A function that accepts a value expressed in the unit and returns that + * value expressed in the unit's base. * * @since 2019-05-22 */ @@ -46,45 +48,43 @@ final class FunctionalUnit extends Unit { /** * Creates the {@code FunctionalUnit}. * - * @param base - * unit's base - * @param converterFrom - * function that accepts a value expressed in the unit's base and returns that value expressed in this - * unit. - * @param converterTo - * function that accepts a value expressed in the unit and returns that value expressed in the unit's - * base. - * @throws NullPointerException - * if any argument is null + * @param base unit's base + * @param converterFrom function that accepts a value expressed in the unit's + * base and returns that value expressed in this unit. + * @param converterTo function that accepts a value expressed in the unit + * and returns that value expressed in the unit's base. + * @throws NullPointerException if any argument is null * @since 2019-05-22 */ - public FunctionalUnit(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, + public FunctionalUnit(final ObjectProduct<BaseUnit> base, + final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo) { super(base, NameSymbol.EMPTY); - this.converterFrom = Objects.requireNonNull(converterFrom, "converterFrom must not be null."); - this.converterTo = Objects.requireNonNull(converterTo, "converterTo must not be null."); + this.converterFrom = Objects.requireNonNull(converterFrom, + "converterFrom must not be null."); + this.converterTo = Objects.requireNonNull(converterTo, + "converterTo must not be null."); } /** * Creates the {@code FunctionalUnit}. * - * @param base - * unit's base - * @param converterFrom - * function that accepts a value expressed in the unit's base and returns that value expressed in this - * unit. - * @param converterTo - * function that accepts a value expressed in the unit and returns that value expressed in the unit's - * base. - * @throws NullPointerException - * if any argument is null + * @param base unit's base + * @param converterFrom function that accepts a value expressed in the unit's + * base and returns that value expressed in this unit. + * @param converterTo function that accepts a value expressed in the unit + * and returns that value expressed in the unit's base. + * @throws NullPointerException if any argument is null * @since 2019-05-22 */ - public FunctionalUnit(final ObjectProduct<BaseUnit> base, final DoubleUnaryOperator converterFrom, + public FunctionalUnit(final ObjectProduct<BaseUnit> base, + final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo, final NameSymbol ns) { super(base, ns); - this.converterFrom = Objects.requireNonNull(converterFrom, "converterFrom must not be null."); - this.converterTo = Objects.requireNonNull(converterTo, "converterTo must not be null."); + this.converterFrom = Objects.requireNonNull(converterFrom, + "converterFrom must not be null."); + this.converterTo = Objects.requireNonNull(converterTo, + "converterTo must not be null."); } /** diff --git a/src/main/java/sevenUnits/unit/FunctionalUnitlike.java b/src/main/java/sevenUnits/unit/FunctionalUnitlike.java index d6046c0..e9b4d1f 100644 --- a/src/main/java/sevenUnits/unit/FunctionalUnitlike.java +++ b/src/main/java/sevenUnits/unit/FunctionalUnitlike.java @@ -35,13 +35,13 @@ final class FunctionalUnitlike<V> extends Unitlike<V> { * @since 2020-09-07 */ private final DoubleFunction<V> converterFrom; - + /** * A function that accepts a value in the unitlike form and returns a value * in the unitlike form's base. */ private final ToDoubleFunction<V> converterTo; - + /** * Creates the {@code FunctionalUnitlike}. * @@ -59,15 +59,15 @@ final class FunctionalUnitlike<V> extends Unitlike<V> { 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 103b7f6..6489229 100644 --- a/src/main/java/sevenUnits/unit/LinearUnit.java +++ b/src/main/java/sevenUnits/unit/LinearUnit.java @@ -46,7 +46,7 @@ public final class LinearUnit extends Unit { Objects.requireNonNull(unit, "unit must not be null.").getBase(), unit.convertToBase(value), NameSymbol.EMPTY); } - + /** * Gets a {@code LinearUnit} from a unit and a value. For example, converts * '59 °F' to a linear unit with the value of '288.15 K' @@ -64,7 +64,7 @@ public final class LinearUnit extends Unit { Objects.requireNonNull(unit, "unit must not be null.").getBase(), unit.convertToBase(value), ns); } - + /** * @return the base unit associated with {@code unit}, as a * {@code LinearUnit}. @@ -73,7 +73,7 @@ public final class LinearUnit extends Unit { public static LinearUnit getBase(final Unit unit) { return new LinearUnit(unit.getBase(), 1, NameSymbol.EMPTY); } - + /** * @return the base unit associated with {@code unitlike}, as a * {@code LinearUnit}. @@ -82,7 +82,7 @@ public final class LinearUnit extends Unit { 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 @@ -98,7 +98,7 @@ public final class LinearUnit extends Unit { final double conversionFactor) { return new LinearUnit(unitBase, conversionFactor, NameSymbol.EMPTY); } - + /** * Gets a {@code LinearUnit} from a unit base and a conversion factor. In * other words, gets the product of {@code unitBase} and @@ -115,7 +115,7 @@ public final class LinearUnit extends Unit { final double conversionFactor, final NameSymbol ns) { return new LinearUnit(unitBase, conversionFactor, ns); } - + /** * The value of this unit as represented in its base form. Mathematically, * @@ -126,7 +126,7 @@ public final class LinearUnit extends Unit { * @since 2019-10-16 */ private final double conversionFactor; - + /** * Creates the {@code LinearUnit}. * @@ -139,7 +139,7 @@ public final class LinearUnit extends Unit { super(unitBase, ns); this.conversionFactor = conversionFactor; } - + /** * {@inheritDoc} * @@ -149,7 +149,7 @@ public final class LinearUnit extends Unit { protected double convertFromBase(final double value) { return value / this.getConversionFactor(); } - + /** * Converts an {@code UncertainDouble} value expressed in this unit to an * {@code UncertainValue} value expressed in {@code other}. @@ -172,9 +172,9 @@ public final class LinearUnit extends Unit { else throw new IllegalArgumentException( String.format("Cannot convert from %s to %s.", this, other)); - + } - + /** * {@inheritDoc} * @@ -184,7 +184,7 @@ public final class LinearUnit extends Unit { protected double convertToBase(final double value) { return value * this.getConversionFactor(); } - + /** * Converts an {@code UncertainDouble} to the base unit. * @@ -193,7 +193,7 @@ public final class LinearUnit extends Unit { UncertainDouble convertToBase(final UncertainDouble value) { return value.timesExact(this.getConversionFactor()); } - + /** * Divides this unit by a scalar. * @@ -205,7 +205,7 @@ public final class LinearUnit extends Unit { public LinearUnit dividedBy(final double divisor) { return valueOf(this.getBase(), this.getConversionFactor() / divisor); } - + /** * Returns the quotient of this unit and another. * @@ -217,14 +217,14 @@ public final class LinearUnit extends Unit { */ public LinearUnit dividedBy(final LinearUnit divisor) { Objects.requireNonNull(divisor, "other must not be null"); - + // divide the units final ObjectProduct<BaseUnit> base = this.getBase() .dividedBy(divisor.getBase()); return valueOf(base, this.getConversionFactor() / divisor.getConversionFactor()); } - + /** * {@inheritDoc} * @@ -239,7 +239,7 @@ public final class LinearUnit extends Unit { && DecimalComparison.equals(this.getConversionFactor(), other.getConversionFactor()); } - + /** * @return conversion factor * @since 2019-10-16 @@ -247,7 +247,7 @@ public final class LinearUnit extends Unit { public double getConversionFactor() { return this.conversionFactor; } - + /** * {@inheritDoc} * @@ -258,7 +258,7 @@ public final class LinearUnit extends Unit { return 31 * this.getBase().hashCode() + DecimalComparison.hash(this.getConversionFactor()); } - + /** * @return whether this unit is equivalent to a {@code BaseUnit} (i.e. there * is a {@code BaseUnit b} where @@ -268,7 +268,7 @@ public final class LinearUnit extends Unit { public boolean isBase() { return this.isCoherent() && this.getBase().isSingleObject(); } - + /** * @return whether this unit is coherent (i.e. has conversion factor 1) * @since 2019-10-16 @@ -276,7 +276,7 @@ public final class LinearUnit extends Unit { public boolean isCoherent() { return this.getConversionFactor() == 1; } - + /** * Returns the difference of this unit and another. * <p> @@ -296,18 +296,18 @@ public final class LinearUnit extends Unit { */ public LinearUnit minus(final LinearUnit subtrahend) { Objects.requireNonNull(subtrahend, "addend must not be null."); - + // reject subtrahends that cannot be added to this unit if (!this.getBase().equals(subtrahend.getBase())) throw new IllegalArgumentException(String.format( "Incompatible units for subtraction \"%s\" and \"%s\".", this, subtrahend)); - + // subtract the units return valueOf(this.getBase(), this.getConversionFactor() - subtrahend.getConversionFactor()); } - + /** * Returns the sum of this unit and another. * <p> @@ -327,18 +327,18 @@ public final class LinearUnit extends Unit { */ public LinearUnit plus(final LinearUnit addend) { Objects.requireNonNull(addend, "addend must not be null."); - + // reject addends that cannot be added to this unit if (!this.getBase().equals(addend.getBase())) throw new IllegalArgumentException(String.format( "Incompatible units for addition \"%s\" and \"%s\".", this, addend)); - + // add the units return valueOf(this.getBase(), this.getConversionFactor() + addend.getConversionFactor()); } - + /** * Multiplies this unit by a scalar. * @@ -350,7 +350,7 @@ public final class LinearUnit extends Unit { public LinearUnit times(final double multiplier) { return valueOf(this.getBase(), this.getConversionFactor() * multiplier); } - + /** * Returns the product of this unit and another. * @@ -362,21 +362,21 @@ public final class LinearUnit extends Unit { */ public LinearUnit times(final LinearUnit multiplier) { Objects.requireNonNull(multiplier, "other must not be null"); - + // multiply the units final ObjectProduct<BaseUnit> base = this.getBase() .times(multiplier.getBase()); return valueOf(base, this.getConversionFactor() * multiplier.getConversionFactor()); } - + @Override public String toDefinitionString() { return Double.toString(this.conversionFactor) + (this.getBase().equals(ObjectProduct.empty()) ? "" : " " + this.getBase().toString(BaseUnit::getShortName)); } - + /** * Returns this unit but to an exponent. * @@ -389,12 +389,12 @@ public final class LinearUnit extends Unit { return valueOf(this.getBase().toExponent(exponent), Math.pow(this.conversionFactor, exponent)); } - + @Override public LinearUnit withName(final NameSymbol ns) { return valueOf(this.getBase(), this.getConversionFactor(), ns); } - + /** * Returns the result of applying {@code prefix} to this unit. * <p> @@ -413,7 +413,7 @@ public final class LinearUnit extends Unit { */ public LinearUnit withPrefix(final UnitPrefix prefix) { final LinearUnit unit = this.times(prefix.getMultiplier()); - + // create new name and symbol, if possible final String name; if (this.getPrimaryName().isPresent() @@ -422,14 +422,14 @@ public final class LinearUnit extends Unit { } else { name = null; } - + final String symbol; if (this.getSymbol().isPresent() && prefix.getSymbol().isPresent()) { symbol = prefix.getSymbol().get() + this.getSymbol().get(); } else { symbol = null; } - + return unit.withName(NameSymbol.ofNullable(name, symbol)); } } diff --git a/src/main/java/sevenUnits/unit/LinearUnitValue.java b/src/main/java/sevenUnits/unit/LinearUnitValue.java index f91d30b..3a9428b 100644 --- a/src/main/java/sevenUnits/unit/LinearUnitValue.java +++ b/src/main/java/sevenUnits/unit/LinearUnitValue.java @@ -34,7 +34,7 @@ import sevenUnits.utils.UncertainDouble; */ public final class LinearUnitValue { public static final LinearUnitValue ONE = getExact(Metric.ONE, 1); - + /** * Gets an exact {@code LinearUnitValue} * @@ -49,7 +49,7 @@ public final class LinearUnitValue { Objects.requireNonNull(unit, "unit must not be null"), UncertainDouble.of(value, 0)); } - + /** * Gets an uncertain {@code LinearUnitValue} * @@ -65,11 +65,11 @@ public final class LinearUnitValue { Objects.requireNonNull(unit, "unit must not be null"), Objects.requireNonNull(value, "value may not be null")); } - + private final LinearUnit unit; - + private final UncertainDouble value; - + /** * @param unit unit to express as * @param value value to express @@ -79,7 +79,7 @@ public final class LinearUnitValue { this.unit = unit; this.value = value; } - + /** * @return this value as a {@code UnitValue}. All uncertainty information is * removed from the returned value. @@ -88,7 +88,7 @@ public final class LinearUnitValue { public final UnitValue asUnitValue() { return UnitValue.of(this.unit, this.value.value()); } - + /** * @param other a {@code LinearUnit} * @return true iff this value can be represented with {@code other}. @@ -97,7 +97,7 @@ public final class LinearUnitValue { public final boolean canConvertTo(final LinearUnit other) { return this.unit.canConvertTo(other); } - + /** * Returns a LinearUnitValue that represents the same value expressed in a * different unit @@ -109,7 +109,7 @@ public final class LinearUnitValue { public final LinearUnitValue convertTo(final LinearUnit other) { return LinearUnitValue.of(other, this.unit.convertTo(other, this.value)); } - + /** * Divides this value by a scalar * @@ -120,7 +120,7 @@ public final class LinearUnitValue { public LinearUnitValue dividedBy(final double divisor) { return LinearUnitValue.of(this.unit, this.value.dividedByExact(divisor)); } - + /** * Divides this value by another value * @@ -132,7 +132,7 @@ public final class LinearUnitValue { return LinearUnitValue.of(this.unit.dividedBy(divisor.unit), this.value.dividedBy(divisor.value)); } - + /** * Returns true if this and obj represent the same value, regardless of * whether or not they are expressed in the same unit. So (1000 m).equals(1 @@ -150,7 +150,7 @@ public final class LinearUnitValue { && this.unit.convertToBase(this.value) .equals(other.unit.convertToBase(other.value)); } - + /** * Returns true if this and obj represent the same value, regardless of * whether or not they are expressed in the same unit. So (1000 m).equals(1 @@ -171,7 +171,7 @@ public final class LinearUnitValue { && DecimalComparison.equals(this.unit.convertToBase(this.value), other.unit.convertToBase(other.value)); } - + /** * @param other another {@code LinearUnitValue} * @return true iff this and other are within each other's uncertainty range @@ -185,10 +185,10 @@ public final class LinearUnitValue { final LinearUnit base = LinearUnit.valueOf(this.unit.getBase(), 1); final LinearUnitValue thisBase = this.convertTo(base); final LinearUnitValue otherBase = other.convertTo(base); - + return thisBase.value.equivalent(otherBase.value); } - + /** * @return the unit * @since 2020-09-29 @@ -196,7 +196,7 @@ public final class LinearUnitValue { public final LinearUnit getUnit() { return this.unit; } - + /** * @return the value * @since 2020-09-29 @@ -204,7 +204,7 @@ public final class LinearUnitValue { public final UncertainDouble getValue() { return this.value; } - + /** * @return the exact value * @since 2020-09-07 @@ -212,13 +212,13 @@ public final class LinearUnitValue { public final double getValueExact() { return this.value.value(); } - + @Override public int hashCode() { return Objects.hash(this.unit.getBase(), this.unit.convertToBase(this.getValue())); } - + /** * Returns the difference of this value and another, expressed in this * value's unit @@ -231,17 +231,17 @@ public final class LinearUnitValue { */ public LinearUnitValue minus(final LinearUnitValue subtrahend) { Objects.requireNonNull(subtrahend, "subtrahend may not be null"); - + if (!this.canConvertTo(subtrahend.unit)) throw new IllegalArgumentException(String.format( "Incompatible units for subtraction \"%s\" and \"%s\".", this.unit, subtrahend.unit)); - + final LinearUnitValue otherConverted = subtrahend.convertTo(this.unit); return LinearUnitValue.of(this.unit, this.value.minus(otherConverted.value)); } - + /** * Returns the sum of this value and another, expressed in this value's unit * @@ -253,17 +253,17 @@ public final class LinearUnitValue { */ public LinearUnitValue plus(final LinearUnitValue addend) { Objects.requireNonNull(addend, "addend may not be null"); - + if (!this.canConvertTo(addend.unit)) throw new IllegalArgumentException(String.format( "Incompatible units for addition \"%s\" and \"%s\".", this.unit, addend.unit)); - + final LinearUnitValue otherConverted = addend.convertTo(this.unit); return LinearUnitValue.of(this.unit, this.value.plus(otherConverted.value)); } - + /** * Multiplies this value by a scalar * @@ -274,7 +274,7 @@ public final class LinearUnitValue { public LinearUnitValue times(final double multiplier) { return LinearUnitValue.of(this.unit, this.value.timesExact(multiplier)); } - + /** * Multiplies this value by another value * @@ -286,7 +286,7 @@ public final class LinearUnitValue { return LinearUnitValue.of(this.unit.times(multiplier.unit), this.value.times(multiplier.value)); } - + /** * Raises a value to an exponent * @@ -298,18 +298,18 @@ public final class LinearUnitValue { return LinearUnitValue.of(this.unit.toExponent(exponent), this.value.toExponentExact(exponent)); } - + @Override public String toString() { return this.toString(!this.value.isExact(), RoundingMode.HALF_EVEN); } - + /** * Returns a string representing the object. <br> * If the attached unit has a name or symbol, the string looks like "12 km". * Otherwise, it looks like "13 unnamed unit (= 2 m/s)". * <p> - * If showUncertainty is true, strings like "35 ± 8" are shown instead of + * If showUncertainty is true, strings like "35 � 8" are shown instead of * single numbers. * <p> * Non-exact values are rounded intelligently based on their uncertainty. @@ -321,9 +321,9 @@ public final class LinearUnitValue { final Optional<String> primaryName = this.unit.getPrimaryName(); final Optional<String> symbol = this.unit.getSymbol(); final String chosenName = symbol.orElse(primaryName.orElse(null)); - + final UncertainDouble baseValue = this.unit.convertToBase(this.value); - + // get rounded strings // if showUncertainty is true, add brackets around the string final String valueString = (showUncertainty ? "(" : "") @@ -332,7 +332,7 @@ public final class LinearUnitValue { final String baseValueString = (showUncertainty ? "(" : "") + baseValue.toString(showUncertainty, roundingMode) + (showUncertainty ? ")" : ""); - + // create string if (chosenName == null) return String.format("%s unnamed unit (= %s %s)", valueString, diff --git a/src/main/java/sevenUnits/unit/Metric.java b/src/main/java/sevenUnits/unit/Metric.java index 05e82ba..7841987 100644 --- a/src/main/java/sevenUnits/unit/Metric.java +++ b/src/main/java/sevenUnits/unit/Metric.java @@ -59,13 +59,13 @@ public final class Metric { .valueOf("Information", "Info"); // non-SI public static final BaseDimension CURRENCY = BaseDimension .valueOf("Currency", "$$"); // non-SI - + // You may NOT get SI.BaseDimensions instances! private BaseDimensions() { throw new AssertionError(); } } - + /// base units of the SI // suppressing warnings since these are the same object, but in a different /// form (class) @@ -89,16 +89,16 @@ public final class Metric { .valueOf(BaseDimensions.INFORMATION, "bit", "b"); public static final BaseUnit DOLLAR = BaseUnit .valueOf(BaseDimensions.CURRENCY, "dollar", "$"); - + public static final Set<BaseUnit> BASE_UNITS = Set.of(METRE, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA, BIT); - + // You may NOT get SI.BaseUnits instances! private BaseUnits() { throw new AssertionError(); } } - + /** * Constants that relate to the SI or other systems. * @@ -109,7 +109,7 @@ public final class Metric { public static final LinearUnit EARTH_GRAVITY = METRE.dividedBy(SECOND) .dividedBy(SECOND).times(9.80665); } - + // dimensions used in the SI, as ObjectProducts public static final class Dimensions { public static final ObjectProduct<BaseDimension> EMPTY = ObjectProduct @@ -139,7 +139,7 @@ public final class Metric { public static final ObjectProduct<BaseDimension> CURRENCY = ObjectProduct .oneOf(BaseDimensions.CURRENCY) .withName(NameSymbol.ofName("Currency")); - + // derived dimensions without named SI units public static final ObjectProduct<BaseDimension> AREA = LENGTH .times(LENGTH); @@ -175,7 +175,7 @@ public final class Metric { .dividedBy(LENGTH); public static final ObjectProduct<BaseDimension> SOLID_ANGLE = AREA .dividedBy(AREA); - + // derived dimensions with named SI units public static final ObjectProduct<BaseDimension> FREQUENCY = EMPTY .dividedBy(TIME); @@ -209,17 +209,17 @@ public final class Metric { .dividedBy(MASS); public static final ObjectProduct<BaseDimension> CATALYTIC_ACTIVITY = QUANTITY .dividedBy(TIME); - + // You may NOT get SI.Dimension instances! private Dimensions() { throw new AssertionError(); } } - + /// The units of the SI public static final LinearUnit ONE = LinearUnit .valueOf(ObjectProduct.empty(), 1); - + public static final LinearUnit METRE = BaseUnits.METRE.asLinearUnit() .withName(NameSymbol.of("metre", "m", "meter")); public static final LinearUnit KILOGRAM = BaseUnits.KILOGRAM.asLinearUnit() @@ -241,7 +241,7 @@ public final class Metric { // Non-base units public static final LinearUnit RADIAN = METRE.dividedBy(METRE) .withName(NameSymbol.of("radian", "rad")); - + public static final LinearUnit STERADIAN = RADIAN.times(RADIAN) .withName(NameSymbol.of("steradian", "sr")); public static final LinearUnit HERTZ = ONE.dividedBy(SECOND) @@ -290,7 +290,7 @@ public final class Metric { // common derived units included for convenience public static final LinearUnit GRAM = KILOGRAM.dividedBy(1000) .withName(NameSymbol.of("gram", "g")); - + public static final LinearUnit SQUARE_METRE = METRE.toExponent(2) .withName(NameSymbol.of("square metre", "m^2", "square meter", "metre squared", "meter squared")); @@ -305,7 +305,7 @@ public final class Metric { .fromConversionFunctions(KELVIN.getBase(), tempK -> tempK - 273.15, tempC -> tempC + 273.15) .withName(NameSymbol.of("degree Celsius", "\u00B0C")); - + public static final LinearUnit MINUTE = SECOND.times(60) .withName(NameSymbol.of("minute", "min")); public static final LinearUnit HOUR = MINUTE.times(60) @@ -349,7 +349,7 @@ public final class Metric { .fromConversionFunctions(ONE.getBase(), pr -> 10 * Math.log10(pr), dB -> Math.pow(10, dB / 10)) .withName(NameSymbol.of("decibel", "dB")); - + /// The prefixes of the SI // expanding decimal prefixes public static final UnitPrefix KILO = UnitPrefix.valueOf(1e3) @@ -368,7 +368,7 @@ public final class Metric { .withName(NameSymbol.of("zetta", "Z")); public static final UnitPrefix YOTTA = UnitPrefix.valueOf(1e24) .withName(NameSymbol.of("yotta", "Y")); - + // contracting decimal prefixes public static final UnitPrefix MILLI = UnitPrefix.valueOf(1e-3) .withName(NameSymbol.of("milli", "m")); @@ -386,7 +386,7 @@ public final class Metric { .withName(NameSymbol.of("zepto", "z")); public static final UnitPrefix YOCTO = UnitPrefix.valueOf(1e-24) .withName(NameSymbol.of("yocto", "y")); - + // prefixes that don't match the pattern of thousands public static final UnitPrefix DEKA = UnitPrefix.valueOf(1e1) .withName(NameSymbol.of("deka", "da", "deca", "D")); @@ -408,7 +408,7 @@ public final class Metric { .withName(NameSymbol.of("pebi", "Pi")); public static final UnitPrefix EXBI = PEBI.times(1024) .withName(NameSymbol.of("exbi", "Ei")); - + // a few prefixed units public static final LinearUnit MICROMETRE = Metric.METRE .withPrefix(Metric.MICRO); @@ -418,7 +418,7 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGAMETRE = Metric.METRE .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROLITRE = Metric.LITRE .withPrefix(Metric.MICRO); public static final LinearUnit MILLILITRE = Metric.LITRE @@ -427,7 +427,7 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGALITRE = Metric.LITRE .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROSECOND = Metric.SECOND .withPrefix(Metric.MICRO); public static final LinearUnit MILLISECOND = Metric.SECOND @@ -436,14 +436,14 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGASECOND = Metric.SECOND .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROGRAM = Metric.GRAM .withPrefix(Metric.MICRO); public static final LinearUnit MILLIGRAM = Metric.GRAM .withPrefix(Metric.MILLI); public static final LinearUnit MEGAGRAM = Metric.GRAM .withPrefix(Metric.MEGA); - + public static final LinearUnit MICRONEWTON = Metric.NEWTON .withPrefix(Metric.MICRO); public static final LinearUnit MILLINEWTON = Metric.NEWTON @@ -452,7 +452,7 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGANEWTON = Metric.NEWTON .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROJOULE = Metric.JOULE .withPrefix(Metric.MICRO); public static final LinearUnit MILLIJOULE = Metric.JOULE @@ -461,7 +461,7 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGAJOULE = Metric.JOULE .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROWATT = Metric.WATT .withPrefix(Metric.MICRO); public static final LinearUnit MILLIWATT = Metric.WATT @@ -470,7 +470,7 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGAWATT = Metric.WATT .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROCOULOMB = Metric.COULOMB .withPrefix(Metric.MICRO); public static final LinearUnit MILLICOULOMB = Metric.COULOMB @@ -479,12 +479,12 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGACOULOMB = Metric.COULOMB .withPrefix(Metric.MEGA); - + public static final LinearUnit MICROAMPERE = Metric.AMPERE .withPrefix(Metric.MICRO); public static final LinearUnit MILLIAMPERE = Metric.AMPERE .withPrefix(Metric.MILLI); - + public static final LinearUnit MICROVOLT = Metric.VOLT .withPrefix(Metric.MICRO); public static final LinearUnit MILLIVOLT = Metric.VOLT @@ -493,16 +493,16 @@ public final class Metric { .withPrefix(Metric.KILO); public static final LinearUnit MEGAVOLT = Metric.VOLT .withPrefix(Metric.MEGA); - + public static final LinearUnit KILOOHM = Metric.OHM.withPrefix(Metric.KILO); public static final LinearUnit MEGAOHM = Metric.OHM.withPrefix(Metric.MEGA); - + // sets of prefixes public static final Set<UnitPrefix> ALL_PREFIXES = Set.of(DEKA, HECTO, KILO, MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, DECI, CENTI, MILLI, MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO, KIBI, MEBI, GIBI, TEBI, PEBI, EXBI); - + public static final Set<UnitPrefix> DECIMAL_PREFIXES = Set.of(DEKA, HECTO, KILO, MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, DECI, CENTI, MILLI, MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO); @@ -514,7 +514,7 @@ public final class Metric { TEBI, PEBI, EXBI); public static final Set<UnitPrefix> REDUCING_PREFIXES = Set.of(DECI, CENTI, MILLI, MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO); - + // You may NOT get SI instances! private Metric() { throw new AssertionError(); diff --git a/src/main/java/sevenUnits/unit/MultiUnit.java b/src/main/java/sevenUnits/unit/MultiUnit.java index bc240e3..950c547 100644 --- a/src/main/java/sevenUnits/unit/MultiUnit.java +++ b/src/main/java/sevenUnits/unit/MultiUnit.java @@ -39,7 +39,7 @@ public final class MultiUnit extends Unitlike<List<Double>> { 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. @@ -57,12 +57,12 @@ public final class MultiUnit extends Unitlike<List<Double>> { } return new MultiUnit(new ArrayList<>(units), unitBase, NameSymbol.EMPTY); } - + /** * The units that make up this value. */ private final List<LinearUnit> units; - + /** * Creates a {@code MultiUnit}. * @@ -73,24 +73,24 @@ public final class MultiUnit extends Unitlike<List<Double>> { super(unitBase, ns); this.units = units; } - + @Override protected List<Double> convertFromBase(double value) { final List<Double> 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}. @@ -99,7 +99,7 @@ public final class MultiUnit extends Unitlike<List<Double>> { * {@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 @@ -115,10 +115,10 @@ public final class MultiUnit extends Unitlike<List<Double>> { 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}. @@ -127,7 +127,7 @@ public final class MultiUnit extends Unitlike<List<Double>> { * {@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 @@ -142,16 +142,16 @@ public final class MultiUnit extends Unitlike<List<Double>> { for (final double d : values) { valueList.add(d); } - + return this.convertTo(other, valueList); } - + @Override protected double convertToBase(List<Double> 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(); diff --git a/src/main/java/sevenUnits/unit/USCustomary.java b/src/main/java/sevenUnits/unit/USCustomary.java index 459071f..fce829e 100644 --- a/src/main/java/sevenUnits/unit/USCustomary.java +++ b/src/main/java/sevenUnits/unit/USCustomary.java @@ -30,10 +30,14 @@ public final class USCustomary { * @since 2019-11-08 */ public static final class Area { - public static final LinearUnit SQUARE_SURVEY_FOOT = Length.SURVEY_FOOT.times(Length.SURVEY_FOOT); - public static final LinearUnit SQUARE_CHAIN = Length.SURVEY_CHAIN.times(Length.SURVEY_CHAIN); - public static final LinearUnit ACRE = Length.SURVEY_CHAIN.times(Length.SURVEY_FURLONG); - public static final LinearUnit SECTION = Length.SURVEY_MILE.times(Length.SURVEY_MILE); + public static final LinearUnit SQUARE_SURVEY_FOOT = Length.SURVEY_FOOT + .times(Length.SURVEY_FOOT); + public static final LinearUnit SQUARE_CHAIN = Length.SURVEY_CHAIN + .times(Length.SURVEY_CHAIN); + public static final LinearUnit ACRE = Length.SURVEY_CHAIN + .times(Length.SURVEY_FURLONG); + public static final LinearUnit SECTION = Length.SURVEY_MILE + .times(Length.SURVEY_MILE); public static final LinearUnit SURVEY_TOWNSHIP = SECTION.times(36); } @@ -52,8 +56,10 @@ public final class USCustomary { public static final LinearUnit YARD = BritishImperial.Length.YARD; public static final LinearUnit MILE = BritishImperial.Length.MILE; - public static final LinearUnit SURVEY_FOOT = Metric.METRE.times(1200.0 / 3937.0); - public static final LinearUnit SURVEY_LINK = SURVEY_FOOT.times(33.0 / 50.0); + public static final LinearUnit SURVEY_FOOT = Metric.METRE + .times(1200.0 / 3937.0); + public static final LinearUnit SURVEY_LINK = SURVEY_FOOT + .times(33.0 / 50.0); public static final LinearUnit SURVEY_ROD = SURVEY_FOOT.times(16.5); public static final LinearUnit SURVEY_CHAIN = SURVEY_ROD.times(4); public static final LinearUnit SURVEY_FURLONG = SURVEY_CHAIN.times(10); @@ -97,7 +103,8 @@ public final class USCustomary { public static final LinearUnit CUBIC_YARD = Length.YARD.toExponent(3); public static final LinearUnit ACRE_FOOT = Area.ACRE.times(Length.FOOT); - public static final LinearUnit MINIM = Metric.LITRE.withPrefix(Metric.MICRO).times(61.611519921875); + public static final LinearUnit MINIM = Metric.LITRE + .withPrefix(Metric.MICRO).times(61.611519921875); public static final LinearUnit FLUID_DRAM = MINIM.times(60); public static final LinearUnit TEASPOON = MINIM.times(80); public static final LinearUnit TABLESPOON = TEASPOON.times(3); @@ -112,7 +119,8 @@ public final class USCustomary { public static final LinearUnit OIL_BARREL = GALLON.times(42); public static final LinearUnit HOGSHEAD = GALLON.times(63); - public static final LinearUnit DRY_PINT = Metric.LITRE.times(0.5506104713575); + public static final LinearUnit DRY_PINT = Metric.LITRE + .times(0.5506104713575); public static final LinearUnit DRY_QUART = DRY_PINT.times(2); public static final LinearUnit DRY_GALLON = DRY_QUART.times(4); public static final LinearUnit PECK = DRY_GALLON.times(2); @@ -128,8 +136,10 @@ public final class USCustomary { public static final LinearUnit KILOCALORIE = BritishImperial.KILOCALORIE; public static final LinearUnit FOOT_POUND = POUND_FORCE.times(Length.FOOT); - public static final LinearUnit HORSEPOWER = Length.FOOT.times(POUND_FORCE).dividedBy(Metric.MINUTE).times(33000); - public static final LinearUnit POUND_PER_SQUARE_INCH = POUND_FORCE.dividedBy(Length.INCH.toExponent(2)); + public static final LinearUnit HORSEPOWER = Length.FOOT.times(POUND_FORCE) + .dividedBy(Metric.MINUTE).times(33000); + public static final LinearUnit POUND_PER_SQUARE_INCH = POUND_FORCE + .dividedBy(Length.INCH.toExponent(2)); public static final Unit FAHRENHEIT = BritishImperial.FAHRENHEIT; } diff --git a/src/main/java/sevenUnits/unit/Unit.java b/src/main/java/sevenUnits/unit/Unit.java index 14478ba..59e928a 100644 --- a/src/main/java/sevenUnits/unit/Unit.java +++ b/src/main/java/sevenUnits/unit/Unit.java @@ -59,7 +59,7 @@ public abstract class Unit implements Nameable { final DoubleUnaryOperator converterTo) { return new FunctionalUnit(base, converterFrom, converterTo); } - + /** * Returns a unit from its base and the functions it uses to convert to and * from its base. @@ -87,28 +87,28 @@ public abstract class Unit implements Nameable { final DoubleUnaryOperator converterTo, final NameSymbol ns) { return new FunctionalUnit(base, converterFrom, converterTo, ns); } - + /** * The combination of units that this unit is based on. * * @since 2019-10-16 */ private final ObjectProduct<BaseUnit> 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<BaseDimension> dimension = null; - + /** * A constructor that constructs {@code BaseUnit} instances. * @@ -121,7 +121,7 @@ public abstract class Unit implements Nameable { throw new AssertionError(); this.nameSymbol = nameSymbol; } - + /** * Creates the {@code Unit}. * @@ -135,7 +135,7 @@ public abstract class Unit implements Nameable { "unitBase may not be null"); this.nameSymbol = Objects.requireNonNull(ns, "ns may not be null"); } - + /** * @return this unit as a {@link Unitlike} * @since 2020-09-07 @@ -144,7 +144,7 @@ public abstract class Unit implements Nameable { 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} @@ -159,7 +159,7 @@ public abstract class Unit implements Nameable { Objects.requireNonNull(other, "other must not be null."); 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} @@ -174,7 +174,7 @@ public abstract class Unit implements Nameable { 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. @@ -190,14 +190,14 @@ public abstract class Unit implements Nameable { * * @implSpec This method is used by {@link #convertTo}, and its behaviour * affects the behaviour of {@code convertTo}. - * + * * @param value value expressed in <b>base</b> unit * @return value expressed in <b>this</b> unit * @since 2018-12-22 * @since v0.1.0 */ protected abstract double convertFromBase(double value); - + /** * Converts a value expressed in this unit to a value expressed in * {@code other}. @@ -206,7 +206,7 @@ public abstract class Unit implements Nameable { * {@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 @@ -224,7 +224,7 @@ public abstract class Unit implements Nameable { throw new IllegalArgumentException( String.format("Cannot convert from %s to %s.", this, other)); } - + /** * Converts a value expressed in this unit to a value expressed in * {@code other}. @@ -252,7 +252,7 @@ public abstract class Unit implements Nameable { 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. @@ -268,14 +268,14 @@ public abstract class Unit implements Nameable { * * @implSpec This method is used by {@link #convertTo}, and its behaviour * affects the behaviour of {@code convertTo}. - * + * * @param value value expressed in <b>this</b> unit * @return value expressed in <b>base</b> unit * @since 2018-12-22 * @since v0.1.0 */ protected abstract double convertToBase(double value); - + /** * @return combination of units that this unit is based on * @since 2018-12-22 @@ -284,7 +284,7 @@ public abstract class Unit implements Nameable { public final ObjectProduct<BaseUnit> getBase() { return this.unitBase; } - + /** * @return dimension measured by this unit * @since 2018-12-22 @@ -294,16 +294,16 @@ public abstract class Unit implements Nameable { if (this.dimension == null) { final Map<BaseUnit, Integer> mapping = this.unitBase.exponentMap(); final Map<BaseDimension, Integer> 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 @@ -312,7 +312,7 @@ public abstract class Unit implements Nameable { public final NameSymbol getNameSymbol() { return this.nameSymbol; } - + /** * Returns true iff this unit is metric. * <p> @@ -337,18 +337,18 @@ public abstract class Unit implements Nameable { if (!(this instanceof LinearUnit)) return false; final LinearUnit linear = (LinearUnit) this; - + // second condition - check that for (final BaseUnit b : linear.getBase().getBaseSet()) { if (!Metric.BaseUnits.BASE_UNITS.contains(b)) return false; } - + // third condition - check that conversion factor is a power of 10 return DecimalComparison .equals(Math.log10(linear.getConversionFactor()) % 1.0, 0); } - + /** * @return a string representing this unit's definition * @since 2022-03-10 @@ -360,7 +360,7 @@ public abstract class Unit implements Nameable { return "derived from " + this.getBase().toString(BaseUnit::getShortName); } - + /** * @return a string containing both this unit's name and its definition * @since 2022-03-10 @@ -368,7 +368,7 @@ public abstract class Unit implements Nameable { public final String toFullString() { return this.toString() + " (" + this.toDefinitionString() + ")"; } - + @Override public String toString() { if (this.nameSymbol.getPrimaryName().isPresent() @@ -378,7 +378,7 @@ public abstract class Unit implements Nameable { else return this.getName(); } - + /** * @param ns name(s) and symbol to use * @return a copy of this unit with provided name(s) and symbol diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java index d738b78..0120067 100644 --- a/src/main/java/sevenUnits/unit/UnitDatabase.java +++ b/src/main/java/sevenUnits/unit/UnitDatabase.java @@ -123,7 +123,7 @@ public final class UnitDatabase { implements Entry<String, Unit> { private final String key; private final Unit value; - + /** * Creates the {@code PrefixedUnitEntry}. * @@ -136,7 +136,7 @@ public final class UnitDatabase { this.key = key; this.value = value; } - + /** * @since 2019-05-03 */ @@ -148,17 +148,17 @@ public final class UnitDatabase { return Objects.equals(this.getKey(), other.getKey()) && Objects.equals(this.getValue(), other.getValue()); } - + @Override public String getKey() { return this.key; } - + @Override public Unit getValue() { return this.value; } - + /** * @since 2019-05-03 */ @@ -168,13 +168,13 @@ public final class UnitDatabase { ^ (this.getValue() == null ? 0 : this.getValue().hashCode()); } - + @Override public Unit setValue(final Unit value) { throw new UnsupportedOperationException( "Cannot set value in an immutable entry"); } - + /** * Returns a string representation of the entry. The format of the * string is the string representation of the key, then the equals @@ -188,7 +188,7 @@ public final class UnitDatabase { return this.getKey() + "=" + this.getValue(); } } - + /** * An iterator that iterates over the units of a * {@code PrefixedUnitNameSet}. @@ -203,12 +203,12 @@ public final class UnitDatabase { private int unitNamePosition = 0; // the indices of the prefixes attached to the current unit private final List<Integer> prefixCoordinates = new ArrayList<>(); - + // values from the unit entry set private final Map<String, Unit> map; private transient final List<String> unitNames; private transient final List<String> prefixNames; - + /** * Creates the * {@code UnitsDatabase.PrefixedUnitMap.PrefixedUnitNameSet.PrefixedUnitNameIterator}. @@ -221,7 +221,7 @@ public final class UnitDatabase { this.unitNames = new ArrayList<>(map.units.keySet()); this.prefixNames = new ArrayList<>(map.prefixes.keySet()); } - + /** * @return current unit name * @since 2019-04-14 @@ -233,10 +233,10 @@ public final class UnitDatabase { unitName.append(this.prefixNames.get(i)); } unitName.append(this.unitNames.get(this.unitNamePosition)); - + return unitName.toString(); } - + @Override public boolean hasNext() { if (this.unitNames.isEmpty()) @@ -249,7 +249,7 @@ public final class UnitDatabase { return true; } } - + /** * Changes this iterator's position to the next available one. * @@ -258,11 +258,11 @@ public final class UnitDatabase { */ private void incrementPosition() { this.unitNamePosition++; - + if (this.unitNamePosition >= this.unitNames.size()) { // we have used all of our units, go to a different prefix this.unitNamePosition = 0; - + // if the prefix coordinates are empty, then set it to [0] if (this.prefixCoordinates.isEmpty()) { this.prefixCoordinates.add(0, 0); @@ -271,7 +271,7 @@ public final class UnitDatabase { int i = this.prefixCoordinates.size() - 1; this.prefixCoordinates.set(i, this.prefixCoordinates.get(i) + 1); - + // fix any carrying errors while (i >= 0 && this.prefixCoordinates .get(i) >= this.prefixNames.size()) { @@ -279,7 +279,7 @@ public final class UnitDatabase { this.prefixCoordinates.set(i--, 0); // null and // decrement at the // same time - + if (i < 0) { // we need to add a new coordinate this.prefixCoordinates.add(0, 0); } else { // increment an existing one @@ -290,18 +290,18 @@ public final class UnitDatabase { } } } - + @Override public Entry<String, Unit> next() { // get next element final Entry<String, Unit> nextEntry = this.peek(); - + // iterate to next position this.incrementPosition(); - + return nextEntry; } - + /** * @return the next element in the iterator, without iterating over * it @@ -310,7 +310,7 @@ public final class UnitDatabase { private Entry<String, Unit> peek() { if (!this.hasNext()) throw new NoSuchElementException("No units left!"); - + // if I have prefixes, ensure I'm not using a nonlinear unit // since all of the unprefixed stuff is done, just remove // nonlinear units @@ -321,12 +321,12 @@ public final class UnitDatabase { this.unitNames.remove(this.unitNamePosition); } } - + final String nextName = this.getCurrentUnitName(); - + return new PrefixedUnitEntry(nextName, this.map.get(nextName)); } - + /** * Returns a string representation of the object. The exact details * of the representation are unspecified and subject to change. @@ -340,10 +340,10 @@ public final class UnitDatabase { this.peek()); } } - + // the map that created this set private final PrefixedUnitMap map; - + /** * Creates the {@code PrefixedUnitNameSet}. * @@ -354,31 +354,31 @@ public final class UnitDatabase { public PrefixedUnitEntrySet(final PrefixedUnitMap map) { this.map = map; } - + @Override public boolean add(final Map.Entry<String, Unit> e) { throw new UnsupportedOperationException( "Cannot add to an immutable set"); } - + @Override public boolean addAll( final Collection<? extends Map.Entry<String, Unit>> c) { throw new UnsupportedOperationException( "Cannot add to an immutable set"); } - + @Override public void clear() { throw new UnsupportedOperationException( "Cannot clear an immutable set"); } - + @Override public boolean contains(final Object o) { // get the entry final Entry<String, Unit> entry; - + try { // This is OK because I'm in a try-catch block, catching the // exact exception that would be thrown. @@ -389,11 +389,11 @@ public final class UnitDatabase { throw new IllegalArgumentException( "Attempted to test for an entry using a non-entry."); } - + return this.map.containsKey(entry.getKey()) && this.map.get(entry.getKey()).equals(entry.getValue()); } - + @Override public boolean containsAll(final Collection<?> c) { for (final Object o : c) @@ -401,42 +401,42 @@ public final class UnitDatabase { return false; return true; } - + @Override public boolean isEmpty() { return this.map.isEmpty(); } - + @Override public Iterator<Entry<String, Unit>> iterator() { return new PrefixedUnitEntryIterator(this.map); } - + @Override public boolean remove(final Object o) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public boolean removeAll(final Collection<?> c) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public boolean removeIf( final Predicate<? super Entry<String, Unit>> filter) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public boolean retainAll(final Collection<?> c) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public int size() { if (this.map.units.isEmpty()) @@ -449,7 +449,7 @@ public final class UnitDatabase { return Integer.MAX_VALUE; } } - + /** * @throws IllegalStateException if the set is infinite in size */ @@ -462,7 +462,7 @@ public final class UnitDatabase { throw new IllegalStateException( "Cannot make an infinite set into an array."); } - + /** * @throws IllegalStateException if the set is infinite in size */ @@ -475,7 +475,7 @@ public final class UnitDatabase { throw new IllegalStateException( "Cannot make an infinite set into an array."); } - + @Override public String toString() { if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) @@ -486,7 +486,7 @@ public final class UnitDatabase { this.map.units, this.map.prefixes); } } - + /** * The class used for unit name sets. * @@ -518,12 +518,12 @@ public final class UnitDatabase { private int unitNamePosition = 0; // the indices of the prefixes attached to the current unit private final List<Integer> prefixCoordinates = new ArrayList<>(); - + // values from the unit name set private final Map<String, Unit> map; private transient final List<String> unitNames; private transient final List<String> prefixNames; - + /** * Creates the * {@code UnitsDatabase.PrefixedUnitMap.PrefixedUnitNameSet.PrefixedUnitNameIterator}. @@ -536,7 +536,7 @@ public final class UnitDatabase { this.unitNames = new ArrayList<>(map.units.keySet()); this.prefixNames = new ArrayList<>(map.prefixes.keySet()); } - + /** * @return current unit name * @since 2019-04-14 @@ -548,10 +548,10 @@ public final class UnitDatabase { unitName.append(this.prefixNames.get(i)); } unitName.append(this.unitNames.get(this.unitNamePosition)); - + return unitName.toString(); } - + @Override public boolean hasNext() { if (this.unitNames.isEmpty()) @@ -564,7 +564,7 @@ public final class UnitDatabase { return true; } } - + /** * Changes this iterator's position to the next available one. * @@ -573,11 +573,11 @@ public final class UnitDatabase { */ private void incrementPosition() { this.unitNamePosition++; - + if (this.unitNamePosition >= this.unitNames.size()) { // we have used all of our units, go to a different prefix this.unitNamePosition = 0; - + // if the prefix coordinates are empty, then set it to [0] if (this.prefixCoordinates.isEmpty()) { this.prefixCoordinates.add(0, 0); @@ -586,7 +586,7 @@ public final class UnitDatabase { int i = this.prefixCoordinates.size() - 1; this.prefixCoordinates.set(i, this.prefixCoordinates.get(i) + 1); - + // fix any carrying errors while (i >= 0 && this.prefixCoordinates .get(i) >= this.prefixNames.size()) { @@ -594,7 +594,7 @@ public final class UnitDatabase { this.prefixCoordinates.set(i--, 0); // null and // decrement at the // same time - + if (i < 0) { // we need to add a new coordinate this.prefixCoordinates.add(0, 0); } else { // increment an existing one @@ -605,16 +605,16 @@ public final class UnitDatabase { } } } - + @Override public String next() { final String nextName = this.peek(); - + this.incrementPosition(); - + return nextName; } - + /** * @return the next element in the iterator, without iterating over * it @@ -633,10 +633,10 @@ public final class UnitDatabase { this.unitNames.remove(this.unitNamePosition); } } - + return this.getCurrentUnitName(); } - + /** * Returns a string representation of the object. The exact details * of the representation are unspecified and subject to change. @@ -650,10 +650,10 @@ public final class UnitDatabase { this.peek()); } } - + // the map that created this set private final PrefixedUnitMap map; - + /** * Creates the {@code PrefixedUnitNameSet}. * @@ -664,30 +664,30 @@ public final class UnitDatabase { public PrefixedUnitNameSet(final PrefixedUnitMap map) { this.map = map; } - + @Override public boolean add(final String e) { throw new UnsupportedOperationException( "Cannot add to an immutable set"); } - + @Override public boolean addAll(final Collection<? extends String> c) { throw new UnsupportedOperationException( "Cannot add to an immutable set"); } - + @Override public void clear() { throw new UnsupportedOperationException( "Cannot clear an immutable set"); } - + @Override public boolean contains(final Object o) { return this.map.containsKey(o); } - + @Override public boolean containsAll(final Collection<?> c) { for (final Object o : c) @@ -695,41 +695,41 @@ public final class UnitDatabase { return false; return true; } - + @Override public boolean isEmpty() { return this.map.isEmpty(); } - + @Override public Iterator<String> iterator() { return new PrefixedUnitNameIterator(this.map); } - + @Override public boolean remove(final Object o) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public boolean removeAll(final Collection<?> c) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public boolean removeIf(final Predicate<? super String> filter) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public boolean retainAll(final Collection<?> c) { throw new UnsupportedOperationException( "Cannot remove from an immutable set"); } - + @Override public int size() { if (this.map.units.isEmpty()) @@ -742,7 +742,7 @@ public final class UnitDatabase { return Integer.MAX_VALUE; } } - + /** * @throws IllegalStateException if the set is infinite in size */ @@ -754,9 +754,9 @@ public final class UnitDatabase { // infinite set throw new IllegalStateException( "Cannot make an infinite set into an array."); - + } - + /** * @throws IllegalStateException if the set is infinite in size */ @@ -769,7 +769,7 @@ public final class UnitDatabase { throw new IllegalStateException( "Cannot make an infinite set into an array."); } - + @Override public String toString() { if (this.map.units.isEmpty() || this.map.prefixes.isEmpty()) @@ -780,7 +780,7 @@ public final class UnitDatabase { this.map.units, this.map.prefixes); } } - + /** * The units stored in this collection, without prefixes. * @@ -788,7 +788,7 @@ public final class UnitDatabase { * @since v0.2.0 */ private final Map<String, Unit> units; - + /** * The available prefixes for use. * @@ -796,12 +796,12 @@ public final class UnitDatabase { * @since v0.2.0 */ private final Map<String, UnitPrefix> prefixes; - + // caches private transient Collection<Unit> values = null; private transient Set<String> keySet = null; private transient Set<Entry<String, Unit>> entrySet = null; - + /** * Creates the {@code PrefixedUnitMap}. * @@ -817,50 +817,50 @@ public final class UnitDatabase { this.units = Collections.unmodifiableMap(units); this.prefixes = Collections.unmodifiableMap(prefixes); } - + @Override public void clear() { throw new UnsupportedOperationException( "Cannot clear an immutable map"); } - + @Override public Unit compute(final String key, final BiFunction<? super String, ? super Unit, ? extends Unit> remappingFunction) { throw new UnsupportedOperationException( "Cannot edit an immutable map"); } - + @Override public Unit computeIfAbsent(final String key, final Function<? super String, ? extends Unit> mappingFunction) { throw new UnsupportedOperationException( "Cannot edit an immutable map"); } - + @Override public Unit computeIfPresent(final String key, final BiFunction<? super String, ? super Unit, ? extends Unit> remappingFunction) { throw new UnsupportedOperationException( "Cannot edit an immutable map"); } - + @Override public boolean containsKey(final Object key) { // First, test if there is a unit with the key if (this.units.containsKey(key)) return true; - + // Next, try to cast it to String if (!(key instanceof String)) throw new IllegalArgumentException( "Attempted to test for a unit using a non-string name."); final String unitName = (String) key; - + // Then, look for the longest prefix that is attached to a valid unit String longestPrefix = null; int longestLength = 0; - + for (final String prefixName : this.prefixes.keySet()) { // a prefix name is valid if: // - it is prefixed (i.e. the unit name starts with it) @@ -879,10 +879,10 @@ public final class UnitDatabase { } } } - + return longestPrefix != null; } - + /** * {@inheritDoc} * @@ -895,7 +895,7 @@ public final class UnitDatabase { public boolean containsValue(final Object value) { return this.units.containsValue(value); } - + @Override public Set<Entry<String, Unit>> entrySet() { if (this.entrySet == null) { @@ -903,23 +903,23 @@ public final class UnitDatabase { } return this.entrySet; } - + @Override public Unit get(final Object key) { // First, test if there is a unit with the key if (this.units.containsKey(key)) return this.units.get(key); - + // Next, try to cast it to String if (!(key instanceof String)) throw new IllegalArgumentException( "Attempted to obtain a unit using a non-string name."); final String unitName = (String) key; - + // Then, look for the longest prefix that is attached to a valid unit String longestPrefix = null; int longestLength = 0; - + for (final String prefixName : this.prefixes.keySet()) { // a prefix name is valid if: // - it is prefixed (i.e. the unit name starts with it) @@ -938,7 +938,7 @@ public final class UnitDatabase { } } } - + // if none found, returns null if (longestPrefix == null) return null; @@ -949,16 +949,16 @@ public final class UnitDatabase { // before selecting this prefix final LinearUnit unit = (LinearUnit) this.get(rest); final UnitPrefix prefix = this.prefixes.get(longestPrefix); - + return unit.withPrefix(prefix); } } - + @Override public boolean isEmpty() { return this.units.isEmpty(); } - + @Override public Set<String> keySet() { if (this.keySet == null) { @@ -966,64 +966,64 @@ public final class UnitDatabase { } return this.keySet; } - + @Override public Unit merge(final String key, final Unit value, final BiFunction<? super Unit, ? super Unit, ? extends Unit> remappingFunction) { throw new UnsupportedOperationException( "Cannot merge into an immutable map"); } - + @Override public Unit put(final String key, final Unit value) { throw new UnsupportedOperationException( "Cannot add entries to an immutable map"); } - + @Override public void putAll(final Map<? extends String, ? extends Unit> m) { throw new UnsupportedOperationException( "Cannot add entries to an immutable map"); } - + @Override public Unit putIfAbsent(final String key, final Unit value) { throw new UnsupportedOperationException( "Cannot add entries to an immutable map"); } - + @Override public Unit remove(final Object key) { throw new UnsupportedOperationException( "Cannot remove entries from an immutable map"); } - + @Override public boolean remove(final Object key, final Object value) { throw new UnsupportedOperationException( "Cannot remove entries from an immutable map"); } - + @Override public Unit replace(final String key, final Unit value) { throw new UnsupportedOperationException( "Cannot replace entries in an immutable map"); } - + @Override public boolean replace(final String key, final Unit oldValue, final Unit newValue) { throw new UnsupportedOperationException( "Cannot replace entries in an immutable map"); } - + @Override public void replaceAll( final BiFunction<? super String, ? super Unit, ? extends Unit> function) { throw new UnsupportedOperationException( "Cannot replace entries in an immutable map"); } - + @Override public int size() { if (this.units.isEmpty()) @@ -1036,7 +1036,7 @@ public final class UnitDatabase { return Integer.MAX_VALUE; } } - + @Override public String toString() { if (this.units.isEmpty() || this.prefixes.isEmpty()) @@ -1046,7 +1046,7 @@ public final class UnitDatabase { "Infinite map of name-unit entries created from units %s and prefixes %s", this.units, this.prefixes); } - + /** * {@inheritDoc} * @@ -1064,12 +1064,12 @@ public final class UnitDatabase { return this.values; } } - + /** * Replacements done to *all* expression types */ private static final Map<Pattern, String> EXPRESSION_REPLACEMENTS = new HashMap<>(); - + // add data to expression replacements static { // add spaces around operators @@ -1077,7 +1077,7 @@ public final class UnitDatabase { EXPRESSION_REPLACEMENTS.put(Pattern.compile(operator), " " + operator + " "); } - + // replace multiple spaces with a single space EXPRESSION_REPLACEMENTS.put(Pattern.compile(" +"), " "); // place brackets around any expression of the form "number unit", with or @@ -1092,20 +1092,20 @@ public final class UnitDatabase { // "1e3") ), "\\($1 $2\\)"); } - + /** * A regular expression that separates names and expressions in unit files. */ private static final Pattern NAME_EXPRESSION = Pattern .compile("(\\S+)\\s+(\\S.*)"); - + /** * Like normal string comparisons, but shorter strings are always less than * longer strings. */ private static final Comparator<String> lengthFirstComparator = Comparator .comparingInt(String::length).thenComparing(Comparator.naturalOrder()); - + /** * The exponent operator * @@ -1132,7 +1132,7 @@ public final class UnitDatabase { // not a number throw new IllegalArgumentException("Exponents must be numbers."); } - + /** * The exponent operator * @@ -1158,7 +1158,7 @@ public final class UnitDatabase { // not a number throw new IllegalArgumentException("Exponents must be numbers."); } - + /** * @return true if entry represents a removable duplicate entry of map. * @since 2021-05-22 @@ -1174,7 +1174,7 @@ public final class UnitDatabase { } return false; } - + /** * The units in this system, excluding prefixes. * @@ -1182,7 +1182,7 @@ public final class UnitDatabase { * @since v0.1.0 */ private final Map<String, Unit> prefixlessUnits; - + /** * The unit prefixes in this system. * @@ -1190,7 +1190,7 @@ public final class UnitDatabase { * @since v0.1.0 */ private final Map<String, UnitPrefix> prefixes; - + /** * The dimensions in this system. * @@ -1198,7 +1198,7 @@ public final class UnitDatabase { * @since v0.2.0 */ private final Map<String, ObjectProduct<BaseDimension>> dimensions; - + /** * A map mapping strings to units (including prefixes) * @@ -1206,7 +1206,7 @@ public final class UnitDatabase { * @since v0.2.0 */ private final Map<String, Unit> units; - + /** * The rule that specifies when prefix repetition is allowed. It takes in one * argument: a list of the prefixes being applied to the unit @@ -1218,7 +1218,7 @@ public final class UnitDatabase { * {@code prefixRepetitionRule.test(Arrays.asList(giga, mega, kilo))} */ private Predicate<List<UnitPrefix>> prefixRepetitionRule; - + /** * A parser that can parse unit expressions. * @@ -1227,14 +1227,13 @@ public final class UnitDatabase { */ private final ExpressionParser<LinearUnit> unitExpressionParser = new ExpressionParser.Builder<>( this::getLinearUnit).addBinaryOperator("+", (o1, o2) -> o1.plus(o2), 0) - .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) - .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1) - .addSpaceFunction("*") - .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) - .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 3) - .addBinaryOperator("^", UnitDatabase::exponentiateUnits, 2) - .build(); - + .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) + .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1) + .addSpaceFunction("*") + .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) + .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 3) + .addBinaryOperator("^", UnitDatabase::exponentiateUnits, 2).build(); + /** * A parser that can parse unit value expressions. * @@ -1242,15 +1241,15 @@ public final class UnitDatabase { */ private final ExpressionParser<LinearUnitValue> unitValueExpressionParser = new ExpressionParser.Builder<>( this::getLinearUnitValue) - .addBinaryOperator("+", (o1, o2) -> o1.plus(o2), 0) - .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) - .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1) - .addSpaceFunction("*") - .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) - .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 3) - .addBinaryOperator("^", UnitDatabase::exponentiateUnitValues, 2) - .build(); - + .addBinaryOperator("+", (o1, o2) -> o1.plus(o2), 0) + .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) + .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1) + .addSpaceFunction("*") + .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) + .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 3) + .addBinaryOperator("^", UnitDatabase::exponentiateUnitValues, 2) + .build(); + /** * A parser that can parse unit prefix expressions * @@ -1259,15 +1258,15 @@ public final class UnitDatabase { */ private final ExpressionParser<UnitPrefix> prefixExpressionParser = new ExpressionParser.Builder<>( this::getPrefix).addBinaryOperator("+", (o1, o2) -> o1.plus(o2), 0) - .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) - .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1) - .addSpaceFunction("*") - .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) - .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 3) - .addBinaryOperator("^", - (o1, o2) -> o1.toExponent(o2.getMultiplier()), 2) - .build(); - + .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) + .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1) + .addSpaceFunction("*") + .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) + .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 3) + .addBinaryOperator("^", (o1, o2) -> o1.toExponent(o2.getMultiplier()), + 2) + .build(); + /** * A parser that can parse unit dimension expressions. * @@ -1276,14 +1275,14 @@ public final class UnitDatabase { */ private final ExpressionParser<ObjectProduct<BaseDimension>> unitDimensionParser = new ExpressionParser.Builder<>( this::getDimension).addBinaryOperator("*", (o1, o2) -> o1.times(o2), 0) - .addSpaceFunction("*") - .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 0) - .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 2) - .addNumericOperator("^", (o1, o2) -> { - int exponent = (int) Math.round(o2.value()); - return o1.toExponent(exponent); - }, 1).build(); - + .addSpaceFunction("*") + .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 0) + .addBinaryOperator("|", (o1, o2) -> o1.dividedBy(o2), 2) + .addNumericOperator("^", (o1, o2) -> { + int exponent = (int) Math.round(o2.value()); + return o1.toExponent(exponent); + }, 1).build(); + /** * Creates the {@code UnitsDatabase}. * @@ -1293,7 +1292,7 @@ public final class UnitDatabase { public UnitDatabase() { this(prefixes -> true); } - + /** * Creates the {@code UnitsDatabase} * @@ -1311,7 +1310,7 @@ public final class UnitDatabase { entry -> this.prefixRepetitionRule .test(this.getPrefixesFromName(entry.getKey()))); } - + /** * Adds a unit dimension to the database. * @@ -1329,7 +1328,7 @@ public final class UnitDatabase { .withName(dimension.getNameSymbol().withExtraName(name)); this.dimensions.put(name, namedDimension); } - + /** * Adds to the list from a line in a unit dimension file. * @@ -1348,7 +1347,7 @@ public final class UnitDatabase { lineCounter); return; } - + // divide line into name and expression final Matcher lineMatcher = NAME_EXPRESSION.matcher(line); if (!lineMatcher.matches()) @@ -1357,12 +1356,12 @@ public final class UnitDatabase { lineCounter)); final String name = lineMatcher.group(1); final String expression = lineMatcher.group(2); - + // if (name.endsWith(" ")) { // System.err.printf("Warning - line %d's dimension name ends in a space", // lineCounter); // } - + // if expression is "!", search for an existing dimension // if no unit found, throw an error if (expression.equals("!")) { @@ -1378,11 +1377,11 @@ public final class UnitDatabase { System.err.printf("Parsing error on line %d:%n", lineCounter); throw e; } - + this.addDimension(name, dimension); } } - + /** * Adds a unit prefix to the database. * @@ -1399,7 +1398,7 @@ public final class UnitDatabase { this.prefixes.put(Objects.requireNonNull(name, "name must not be null."), namedPrefix); } - + /** * Adds a unit to the database. * @@ -1416,7 +1415,7 @@ public final class UnitDatabase { this.prefixlessUnits.put( Objects.requireNonNull(name, "name must not be null."), namedUnit); } - + /** * Adds to the list from a line in a unit file. * @@ -1435,7 +1434,7 @@ public final class UnitDatabase { lineCounter); return; } - + // divide line into name and expression final Matcher lineMatcher = NAME_EXPRESSION.matcher(line); if (!lineMatcher.matches()) @@ -1443,15 +1442,15 @@ public final class UnitDatabase { "Error at line %d: Lines of a unit file must consist of a unit name, then spaces or tabs, then a unit expression.", lineCounter)); final String name = lineMatcher.group(1); - + final String expression = lineMatcher.group(2); - + // this code should never occur // if (name.endsWith(" ")) { // System.err.printf("Warning - line %d's unit name ends in a space", // lineCounter); // } - + // if expression is "!", search for an existing unit // if no unit found, throw an error if (expression.equals("!")) { @@ -1484,7 +1483,7 @@ public final class UnitDatabase { } } } - + /** * Removes all units, prefixes and dimensions from this database. * @@ -1495,7 +1494,7 @@ public final class UnitDatabase { this.prefixes.clear(); this.prefixlessUnits.clear(); } - + /** * Tests if the database has a unit dimension with this name. * @@ -1507,7 +1506,7 @@ public final class UnitDatabase { public boolean containsDimensionName(final String name) { return this.dimensions.containsKey(name); } - + /** * Tests if the database has a unit prefix with this name. * @@ -1519,7 +1518,7 @@ public final class UnitDatabase { public boolean containsPrefixName(final String name) { return this.prefixes.containsKey(name); } - + /** * Tests if the database has a unit with this name, taking prefixes into * consideration @@ -1532,7 +1531,7 @@ public final class UnitDatabase { public boolean containsUnitName(final String name) { return this.units.containsKey(name); } - + /** * @return a map mapping dimension names to dimensions * @since 2019-04-13 @@ -1541,7 +1540,7 @@ public final class UnitDatabase { public Map<String, ObjectProduct<BaseDimension>> dimensionMap() { return Collections.unmodifiableMap(this.dimensions); } - + /** * Evaluates a unit expression, following the same rules as * {@link #getUnitFromExpression}. @@ -1552,23 +1551,23 @@ public final class UnitDatabase { */ public LinearUnitValue evaluateUnitExpression(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); - + // attempt to get a unit as an alias, or a number with precision first if (this.containsUnitName(expression)) return this.getLinearUnitValue(expression); - + // force operators to have spaces String modifiedExpression = expression; modifiedExpression = modifiedExpression.replaceAll("\\+", " \\+ "); modifiedExpression = modifiedExpression.replaceAll("-", " - "); - + // format expression for (final Entry<Pattern, String> replacement : EXPRESSION_REPLACEMENTS .entrySet()) { modifiedExpression = replacement.getKey().matcher(modifiedExpression) .replaceAll(replacement.getValue()); } - + // the previous operation breaks negative numbers, fix them! // (i.e. -2 becomes - 2) // FIXME the previous operaton also breaks stuff like "1e-5" @@ -1581,10 +1580,10 @@ public final class UnitDatabase { + modifiedExpression.substring(i + 2); } } - + return this.unitValueExpressionParser.parseExpression(modifiedExpression); } - + /** * Gets a unit dimension from the database using its name. * @@ -1595,15 +1594,14 @@ public final class UnitDatabase { */ public ObjectProduct<BaseDimension> getDimension(final String name) { Objects.requireNonNull(name, "name must not be null."); - final ObjectProduct<BaseDimension> dimension = this.dimensions - .get(name); + final ObjectProduct<BaseDimension> dimension = this.dimensions.get(name); if (dimension == null) throw new NoSuchElementException( "No dimension with name \"" + name + "\"."); else return dimension; } - + /** * Uses the database's data to parse an expression into a unit dimension * <p> @@ -1626,24 +1624,24 @@ public final class UnitDatabase { public ObjectProduct<BaseDimension> getDimensionFromExpression( final String expression) { Objects.requireNonNull(expression, "expression must not be null."); - + // attempt to get a dimension as an alias first if (this.containsDimensionName(expression)) return this.getDimension(expression); - + // force operators to have spaces String modifiedExpression = expression; - + // format expression for (final Entry<Pattern, String> replacement : EXPRESSION_REPLACEMENTS .entrySet()) { modifiedExpression = replacement.getKey().matcher(modifiedExpression) .replaceAll(replacement.getValue()); } - + return this.unitDimensionParser.parseExpression(modifiedExpression); } - + /** * Gets a unit. If it is linear, cast it to a LinearUnit and return it. * Otherwise, throw an {@code IllegalArgumentException}. @@ -1662,7 +1660,7 @@ public final class UnitDatabase { if (parts.size() != 2) throw new IllegalArgumentException( "Format nonlinear units like: unit(value)."); - + // solve the function final Unit unit = this.getUnit(parts.get(0)); final double value = Double.parseDouble( @@ -1671,7 +1669,7 @@ public final class UnitDatabase { } else { // get a linear unit final Unit unit = this.getUnit(name); - + if (unit instanceof LinearUnit) return (LinearUnit) unit; else @@ -1679,7 +1677,7 @@ public final class UnitDatabase { String.format("%s is not a linear unit.", name)); } } - + /** * Gets a {@code LinearUnitValue} from a unit name. Nonlinear units will be * converted to their base units. @@ -1697,7 +1695,7 @@ public final class UnitDatabase { return LinearUnitValue.getExact(this.getLinearUnit(name), 1); } } - + /** * Gets a unit prefix from the database from its name * @@ -1718,7 +1716,7 @@ public final class UnitDatabase { return prefix; } } - + /** * Gets all of the prefixes that are on a unit name, in application order. * @@ -1729,12 +1727,12 @@ public final class UnitDatabase { List<UnitPrefix> getPrefixesFromName(final String unitName) { final List<UnitPrefix> prefixes = new ArrayList<>(); String name = unitName; - + while (!this.prefixlessUnits.containsKey(name)) { // find the longest prefix String longestPrefixName = null; int longestLength = name.length(); - + while (longestPrefixName == null) { longestLength--; if (longestLength <= 0) @@ -1744,7 +1742,7 @@ public final class UnitDatabase { longestPrefixName = name.substring(0, longestLength); } } - + // longest prefix found! final UnitPrefix prefix = this.getPrefix(longestPrefixName); prefixes.add(0, prefix); @@ -1752,7 +1750,7 @@ public final class UnitDatabase { } return prefixes; } - + /** * Gets a unit prefix from a prefix expression * <p> @@ -1769,24 +1767,24 @@ public final class UnitDatabase { */ public UnitPrefix getPrefixFromExpression(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); - + // attempt to get a unit as an alias first if (this.containsUnitName(expression)) return this.getPrefix(expression); - + // force operators to have spaces String modifiedExpression = expression; - + // format expression for (final Entry<Pattern, String> replacement : EXPRESSION_REPLACEMENTS .entrySet()) { modifiedExpression = replacement.getKey().matcher(modifiedExpression) .replaceAll(replacement.getValue()); } - + return this.prefixExpressionParser.parseExpression(modifiedExpression); } - + /** * @return the prefixRepetitionRule * @since 2020-08-26 @@ -1794,7 +1792,7 @@ public final class UnitDatabase { public final Predicate<List<UnitPrefix>> getPrefixRepetitionRule() { return this.prefixRepetitionRule; } - + /** * Gets a unit from the database from its name, looking for prefixes. * @@ -1827,9 +1825,9 @@ public final class UnitDatabase { } else return unit; } - + } - + /** * Uses the database's unit data to parse an expression into a unit * <p> @@ -1853,23 +1851,23 @@ public final class UnitDatabase { */ public Unit getUnitFromExpression(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); - + // attempt to get a unit as an alias first if (this.containsUnitName(expression)) return this.getUnit(expression); - + // force operators to have spaces String modifiedExpression = expression; modifiedExpression = modifiedExpression.replaceAll("\\+", " \\+ "); modifiedExpression = modifiedExpression.replaceAll("-", " - "); - + // format expression for (final Entry<Pattern, String> replacement : EXPRESSION_REPLACEMENTS .entrySet()) { modifiedExpression = replacement.getKey().matcher(modifiedExpression) .replaceAll(replacement.getValue()); } - + // the previous operation breaks negative numbers, fix them! // (i.e. -2 becomes - 2) for (int i = 0; i < modifiedExpression.length(); i++) { @@ -1881,10 +1879,10 @@ public final class UnitDatabase { + modifiedExpression.substring(i + 2); } } - + return this.unitExpressionParser.parseExpression(modifiedExpression); } - + /** * Adds all dimensions from a file, using data from the database to parse * them. @@ -1924,7 +1922,7 @@ public final class UnitDatabase { throw new IllegalArgumentException("Could not read file " + file, e); } } - + /** * Adds all dimensions from a {@code InputStream}. Otherwise, works like * {@link #loadDimensionFile}. @@ -1940,7 +1938,7 @@ public final class UnitDatabase { } } } - + /** * Adds all units from a file, using data from the database to parse them. * <p> @@ -1979,7 +1977,7 @@ public final class UnitDatabase { throw new IllegalArgumentException("Could not read file " + file, e); } } - + /** * Adds all units from a {@code InputStream}. Otherwise, works like * {@link #loadUnitsFile}. @@ -1995,7 +1993,7 @@ public final class UnitDatabase { } } } - + /** * @param includeDuplicates if false, duplicates are removed from the map * @return a map mapping prefix names to prefixes @@ -2010,7 +2008,7 @@ public final class UnitDatabase { .conditionalExistenceMap(this.prefixes, entry -> !isRemovableDuplicate(this.prefixes, entry))); } - + /** * @param prefixRepetitionRule the prefixRepetitionRule to set * @since 2020-08-26 @@ -2019,7 +2017,7 @@ public final class UnitDatabase { Predicate<List<UnitPrefix>> prefixRepetitionRule) { this.prefixRepetitionRule = prefixRepetitionRule; } - + /** * @return a string stating the number of units, prefixes and dimensions in * the database @@ -2031,7 +2029,7 @@ public final class UnitDatabase { this.prefixlessUnits.size(), this.prefixes.size(), this.dimensions.size()); } - + /** * Returns a map mapping unit names to units, including units with prefixes. * <p> @@ -2063,7 +2061,7 @@ public final class UnitDatabase { return this.units; // PrefixedUnitMap is immutable so I don't need to make // an unmodifiable map. } - + /** * @param includeDuplicates if true, duplicate units will all exist in the * map; if false, only one of each unit will exist, diff --git a/src/main/java/sevenUnits/unit/UnitPrefix.java b/src/main/java/sevenUnits/unit/UnitPrefix.java index 824f60b..9035969 100644 --- a/src/main/java/sevenUnits/unit/UnitPrefix.java +++ b/src/main/java/sevenUnits/unit/UnitPrefix.java @@ -40,7 +40,7 @@ public final class UnitPrefix implements Nameable { public static UnitPrefix valueOf(final double multiplier) { return new UnitPrefix(multiplier, NameSymbol.EMPTY); } - + /** * Gets a {@code UnitPrefix} from a multiplier and a name * @@ -55,21 +55,21 @@ public final class UnitPrefix implements Nameable { return new UnitPrefix(multiplier, Objects.requireNonNull(ns, "ns must not be null.")); } - + /** * This prefix's name(s) and symbol. * * @since 2022-04-16 */ private final NameSymbol nameSymbol; - + /** * The number that this prefix multiplies units by * * @since 2019-10-16 */ private final double multiplier; - + /** * Creates the {@code DefaultUnitPrefix}. * @@ -81,7 +81,7 @@ public final class UnitPrefix implements Nameable { this.multiplier = multiplier; this.nameSymbol = ns; } - + /** * Divides this prefix by a scalar * @@ -92,7 +92,7 @@ public final class UnitPrefix implements Nameable { public UnitPrefix dividedBy(final double divisor) { return valueOf(this.getMultiplier() / divisor); } - + /** * Divides this prefix by {@code other}. * @@ -104,7 +104,7 @@ public final class UnitPrefix implements Nameable { public UnitPrefix dividedBy(final UnitPrefix other) { return valueOf(this.getMultiplier() / other.getMultiplier()); } - + /** * {@inheritDoc} * @@ -122,7 +122,7 @@ public final class UnitPrefix implements Nameable { return DecimalComparison.equals(this.getMultiplier(), other.getMultiplier()); } - + /** * @return prefix's multiplier * @since 2019-11-26 @@ -130,12 +130,12 @@ public final class UnitPrefix implements Nameable { public double getMultiplier() { return this.multiplier; } - + @Override public NameSymbol getNameSymbol() { return this.nameSymbol; } - + /** * {@inheritDoc} * @@ -145,7 +145,7 @@ public final class UnitPrefix implements Nameable { public int hashCode() { return DecimalComparison.hash(this.getMultiplier()); } - + /** * Multiplies this prefix by a scalar * @@ -156,9 +156,10 @@ public final class UnitPrefix implements Nameable { public UnitPrefix times(final double multiplicand) { return valueOf(this.getMultiplier() * multiplicand); } - + /** * Adds {@code other} to this prefix and returns the result. + * * @since 2024-03-03 */ public UnitPrefix plus(final UnitPrefix other) { @@ -167,6 +168,7 @@ public final class UnitPrefix implements Nameable { /** * Subtracts {@code other} from this prefix and returns the result. + * * @since 2024-03-03 */ public UnitPrefix minus(final UnitPrefix other) { @@ -184,7 +186,7 @@ public final class UnitPrefix implements Nameable { public UnitPrefix times(final UnitPrefix other) { return valueOf(this.getMultiplier() * other.getMultiplier()); } - + /** * Raises this prefix to an exponent. * @@ -196,7 +198,7 @@ public final class UnitPrefix implements Nameable { public UnitPrefix toExponent(final double exponent) { return valueOf(Math.pow(this.getMultiplier(), exponent)); } - + /** * @return a string describing the prefix and its multiplier */ @@ -211,7 +213,7 @@ public final class UnitPrefix implements Nameable { else return String.format("Unit Prefix (\u00D7 %s)", this.multiplier); } - + /** * @param ns name(s) and symbol to use * @return copy of this prefix with provided name(s) and symbol diff --git a/src/main/java/sevenUnits/unit/UnitType.java b/src/main/java/sevenUnits/unit/UnitType.java index 7cebf2d..9a87288 100644 --- a/src/main/java/sevenUnits/unit/UnitType.java +++ b/src/main/java/sevenUnits/unit/UnitType.java @@ -33,7 +33,7 @@ import java.util.function.Predicate; */ public enum UnitType { METRIC, SEMI_METRIC, NON_METRIC; - + /** * Determines which type a unit is. The type will be: * <ul> diff --git a/src/main/java/sevenUnits/unit/UnitValue.java b/src/main/java/sevenUnits/unit/UnitValue.java index 339263d..2d01831 100644 --- a/src/main/java/sevenUnits/unit/UnitValue.java +++ b/src/main/java/sevenUnits/unit/UnitValue.java @@ -42,10 +42,10 @@ public final class UnitValue { return new UnitValue( Objects.requireNonNull(unit, "unit must not be null"), value); } - + private final Unit unit; private final double value; - + /** * @param unit the unit being used * @param value the value being represented @@ -54,7 +54,7 @@ public final class UnitValue { this.unit = unit; this.value = value; } - + /** * @return true if this value can be converted to {@code other}. * @since 2020-10-01 @@ -62,7 +62,7 @@ public final class UnitValue { public final boolean canConvertTo(Unit other) { return this.unit.canConvertTo(other); } - + /** * @return true if this value can be converted to {@code other}. * @since 2020-10-01 @@ -70,7 +70,7 @@ public final class UnitValue { public final <W> boolean canConvertTo(Unitlike<W> other) { return this.unit.canConvertTo(other); } - + /** * Returns a UnitlikeValue that represents the same value expressed in a * different unitlike form. @@ -83,7 +83,7 @@ public final class UnitValue { return UnitlikeValue.of(other, this.unit.convertTo(other, this.getValue())); } - + /** * Returns a UnitValue that represents the same value expressed in a * different unit @@ -95,7 +95,7 @@ public final class UnitValue { return UnitValue.of(other, this.getUnit().convertTo(other, this.getValue())); } - + /** * Returns this unit value represented as a {@code LinearUnitValue} with this * unit's base unit as the base. @@ -108,7 +108,7 @@ public final class UnitValue { final LinearUnit base = LinearUnit.getBase(this.unit).withName(ns); return this.convertToLinear(base); } - + /** * @return a {@code LinearUnitValue} that is equivalent to this value. It * will have zero uncertainty. @@ -118,7 +118,7 @@ public final class UnitValue { return LinearUnitValue.getExact(other, this.getUnit().convertTo(other, this.getValue())); } - + /** * Returns true if this and obj represent the same value, regardless of * whether or not they are expressed in the same unit. So (1000 m).equals(1 @@ -135,7 +135,7 @@ public final class UnitValue { .doubleToLongBits( other.getUnit().convertToBase(other.getValue())); } - + /** * @return the unit * @since 2020-09-29 @@ -143,7 +143,7 @@ public final class UnitValue { public final Unit getUnit() { return this.unit; } - + /** * @return the value * @since 2020-09-29 @@ -151,13 +151,13 @@ public final class UnitValue { public final double getValue() { return this.value; } - + @Override public int hashCode() { return Objects.hash(this.getUnit().getBase(), this.getUnit().convertFromBase(this.getValue())); } - + @Override public String toString() { final Optional<String> primaryName = this.getUnit().getPrimaryName(); diff --git a/src/main/java/sevenUnits/unit/Unitlike.java b/src/main/java/sevenUnits/unit/Unitlike.java index 68de2c2..fef424e 100644 --- a/src/main/java/sevenUnits/unit/Unitlike.java +++ b/src/main/java/sevenUnits/unit/Unitlike.java @@ -55,7 +55,7 @@ public abstract class Unitlike<V> implements Nameable { 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. @@ -78,28 +78,28 @@ public abstract class Unitlike<V> implements Nameable { final ToDoubleFunction<W> 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<BaseUnit> 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<BaseDimension> dimension = null; - + /** * @param unitBase * @since 2020-09-07 @@ -109,7 +109,7 @@ public abstract class Unitlike<V> implements Nameable { "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} @@ -124,7 +124,7 @@ public abstract class Unitlike<V> implements Nameable { 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} @@ -139,9 +139,9 @@ public abstract class Unitlike<V> implements Nameable { 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}. @@ -150,7 +150,7 @@ public abstract class Unitlike<V> implements Nameable { * {@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 @@ -168,7 +168,7 @@ public abstract class Unitlike<V> implements Nameable { 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}. @@ -196,9 +196,9 @@ public abstract class Unitlike<V> implements Nameable { 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 @@ -207,7 +207,7 @@ public abstract class Unitlike<V> implements Nameable { public final ObjectProduct<BaseUnit> getBase() { return this.unitBase; } - + /** * @return dimension measured by this unit * @since 2018-12-22 @@ -217,16 +217,16 @@ public abstract class Unitlike<V> implements Nameable { if (this.dimension == null) { final Map<BaseUnit, Integer> mapping = this.unitBase.exponentMap(); final Map<BaseDimension, Integer> 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 @@ -235,7 +235,7 @@ public abstract class Unitlike<V> implements Nameable { public final NameSymbol getNameSymbol() { return this.nameSymbol; } - + @Override public String toString() { return this.getPrimaryName().orElse("Unnamed unitlike form") @@ -247,7 +247,7 @@ public abstract class Unitlike<V> implements Nameable { + (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 diff --git a/src/main/java/sevenUnits/unit/UnitlikeValue.java b/src/main/java/sevenUnits/unit/UnitlikeValue.java index 26354b1..ad0d1ea 100644 --- a/src/main/java/sevenUnits/unit/UnitlikeValue.java +++ b/src/main/java/sevenUnits/unit/UnitlikeValue.java @@ -34,10 +34,10 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { V value) { return new UnitlikeValue<>(unitlike, value); } - + private final T unitlike; private final V value; - + /** * @param unitlike * @param value @@ -47,7 +47,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { this.unitlike = unitlike; this.value = value; } - + /** * @return true if this value can be converted to {@code other}. * @since 2020-10-01 @@ -55,7 +55,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { 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 @@ -63,7 +63,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { public final <W> boolean canConvertTo(Unitlike<W> other) { return this.unitlike.canConvertTo(other); } - + /** * Returns a UnitlikeValue that represents the same value expressed in a * different unitlike form. @@ -76,7 +76,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { return UnitlikeValue.of(other, this.unitlike.convertTo(other, this.getValue())); } - + /** * Returns a UnitValue that represents the same value expressed in a * different unit @@ -88,7 +88,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { 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. @@ -101,7 +101,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { 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. @@ -111,7 +111,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { return LinearUnitValue.getExact(other, this.getUnitlike().convertTo(other, this.getValue())); } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -131,7 +131,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { return false; return true; } - + /** * @return the unitlike * @since 2020-09-29 @@ -139,7 +139,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { public final Unitlike<V> getUnitlike() { return this.unitlike; } - + /** * @return the value * @since 2020-09-29 @@ -147,7 +147,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { public final V getValue() { return this.value; } - + @Override public int hashCode() { final int prime = 31; @@ -158,7 +158,7 @@ final class UnitlikeValue<T extends Unitlike<V>, V> { + (this.getValue() == null ? 0 : this.getValue().hashCode()); return result; } - + @Override public String toString() { final Optional<String> primaryName = this.getUnitlike().getPrimaryName(); diff --git a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java index bee4dd1..b71a4e0 100644 --- a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java +++ b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java @@ -67,7 +67,7 @@ public final class ConditionalExistenceCollections { extends AbstractCollection<E> { final Collection<E> collection; final Predicate<E> existenceCondition; - + /** * Creates the {@code ConditionalExistenceCollection}. * @@ -80,38 +80,38 @@ public final class ConditionalExistenceCollections { this.collection = collection; this.existenceCondition = existenceCondition; } - + @Override public boolean add(final E e) { return this.collection.add(e) && this.existenceCondition.test(e); } - + @Override public void clear() { this.collection.clear(); } - + @Override public boolean contains(final Object o) { if (!this.collection.contains(o)) return false; - + // this collection can only contain instances of E // since the object is in the collection, we know that it must be an // instance of E // therefore this cast will always work @SuppressWarnings("unchecked") final E e = (E) o; - + return this.existenceCondition.test(e); } - + @Override public Iterator<E> iterator() { return conditionalExistenceIterator(this.collection.iterator(), this.existenceCondition); } - + @Override public boolean remove(final Object o) { // remove() must be first in the && statement, otherwise it may not @@ -119,32 +119,32 @@ public final class ConditionalExistenceCollections { final boolean containedObject = this.contains(o); return this.collection.remove(o) && containedObject; } - + @Override public int size() { return (int) this.collection.stream().filter(this.existenceCondition) .count(); } - + @Override public Object[] toArray() { // ensure the toArray operation is supported this.collection.toArray(); - + // if it works, do it for real return super.toArray(); } - + @Override public <T> T[] toArray(T[] a) { // ensure the toArray operation is supported this.collection.toArray(); - + // if it works, do it for real return super.toArray(a); } } - + /** * Elements in this wrapper iterator only exist if they pass a condition. * @@ -157,7 +157,7 @@ public final class ConditionalExistenceCollections { final Predicate<E> existenceCondition; E nextElement; boolean hasNext; - + /** * Creates the {@code ConditionalExistenceIterator}. * @@ -171,7 +171,7 @@ public final class ConditionalExistenceCollections { this.existenceCondition = condition; this.getAndSetNextElement(); } - + /** * Gets the next element, and sets nextElement and hasNext accordingly. * @@ -188,12 +188,12 @@ public final class ConditionalExistenceCollections { } while (!this.existenceCondition.test(this.nextElement)); this.hasNext = true; } - + @Override public boolean hasNext() { return this.hasNext; } - + @Override public E next() { if (this.hasNext()) { @@ -203,13 +203,13 @@ public final class ConditionalExistenceCollections { } else throw new NoSuchElementException(); } - + @Override public void remove() { this.iterator.remove(); } } - + /** * Mappings in this map only exist if the entry passes some condition. * @@ -221,7 +221,7 @@ public final class ConditionalExistenceCollections { static final class ConditionalExistenceMap<K, V> extends AbstractMap<K, V> { Map<K, V> map; Predicate<Entry<K, V>> entryExistenceCondition; - + /** * Creates the {@code ConditionalExistenceMap}. * @@ -234,81 +234,81 @@ public final class ConditionalExistenceCollections { this.map = map; this.entryExistenceCondition = entryExistenceCondition; } - + @Override public boolean containsKey(final Object key) { if (!this.map.containsKey(key)) return false; - + // only instances of K have mappings in the backing map // since we know that key is a valid key, it must be an instance of K @SuppressWarnings("unchecked") final K keyAsK = (K) key; - + // get and test entry final V value = this.map.get(key); final Entry<K, V> entry = new SimpleEntry<>(keyAsK, value); return this.entryExistenceCondition.test(entry); } - + @Override public Set<Entry<K, V>> entrySet() { return conditionalExistenceSet(this.map.entrySet(), this.entryExistenceCondition); } - + @Override public V get(final Object key) { return this.containsKey(key) ? this.map.get(key) : null; } - + private final Entry<K, V> getEntry(K key) { return new Entry<>() { @Override public K getKey() { return key; } - + @Override public V getValue() { return ConditionalExistenceMap.this.map.get(key); } - + @Override public V setValue(V value) { return ConditionalExistenceMap.this.map.put(key, value); } }; } - + @Override public Set<K> keySet() { return conditionalExistenceSet(this.map.keySet(), k -> this.entryExistenceCondition.test(this.getEntry(k))); } - + @Override public V put(final K key, final V value) { final V oldValue = this.map.put(key, value); - + // get and test entry final Entry<K, V> entry = new SimpleEntry<>(key, oldValue); return this.entryExistenceCondition.test(entry) ? oldValue : null; } - + @Override public V remove(final Object key) { final V oldValue = this.map.remove(key); return this.containsKey(key) ? oldValue : null; } - + @Override public Collection<V> values() { // maybe change this to use ConditionalExistenceCollection return super.values(); } } - + /** * Elements in this set only exist if a certain condition is true. * @@ -319,7 +319,7 @@ public final class ConditionalExistenceCollections { static final class ConditionalExistenceSet<E> extends AbstractSet<E> { private final Set<E> set; private final Predicate<E> existenceCondition; - + /** * Creates the {@code ConditionalNonexistenceSet}. * @@ -332,7 +332,7 @@ public final class ConditionalExistenceCollections { this.set = set; this.existenceCondition = existenceCondition; } - + /** * {@inheritDoc} * <p> @@ -343,33 +343,33 @@ public final class ConditionalExistenceCollections { public boolean add(final E e) { return this.set.add(e) && this.existenceCondition.test(e); } - + @Override public void clear() { this.set.clear(); } - + @Override public boolean contains(final Object o) { if (!this.set.contains(o)) return false; - + // this set can only contain instances of E // since the object is in the set, we know that it must be an instance // of E // therefore this cast will always work @SuppressWarnings("unchecked") final E e = (E) o; - + return this.existenceCondition.test(e); } - + @Override public Iterator<E> iterator() { return conditionalExistenceIterator(this.set.iterator(), this.existenceCondition); } - + @Override public boolean remove(final Object o) { // remove() must be first in the && statement, otherwise it may not @@ -377,31 +377,31 @@ public final class ConditionalExistenceCollections { final boolean containedObject = this.contains(o); return this.set.remove(o) && containedObject; } - + @Override public int size() { return (int) this.set.stream().filter(this.existenceCondition).count(); } - + @Override public Object[] toArray() { // ensure the toArray operation is supported this.set.toArray(); - + // if it works, do it for real return super.toArray(); } - + @Override public <T> T[] toArray(T[] a) { // ensure the toArray operation is supported this.set.toArray(); - + // if it works, do it for real return super.toArray(a); } } - + /** * Elements in the returned wrapper collection are ignored if they don't pass * a condition. @@ -418,7 +418,7 @@ public final class ConditionalExistenceCollections { return new ConditionalExistenceCollection<>(collection, existenceCondition); } - + /** * Elements in the returned wrapper iterator are ignored if they don't pass a * condition. @@ -433,7 +433,7 @@ public final class ConditionalExistenceCollections { final Iterator<E> iterator, final Predicate<E> existenceCondition) { return new ConditionalExistenceIterator<>(iterator, existenceCondition); } - + /** * Mappings in the returned wrapper map are ignored if the corresponding * entry doesn't pass a condition @@ -450,7 +450,7 @@ public final class ConditionalExistenceCollections { final Predicate<Entry<K, V>> entryExistenceCondition) { return new ConditionalExistenceMap<>(map, entryExistenceCondition); } - + /** * Elements in the returned wrapper set are ignored if they don't pass a * condition. diff --git a/src/main/java/sevenUnits/utils/DecimalComparison.java b/src/main/java/sevenUnits/utils/DecimalComparison.java index a5cbbaa..0515b6b 100644 --- a/src/main/java/sevenUnits/utils/DecimalComparison.java +++ b/src/main/java/sevenUnits/utils/DecimalComparison.java @@ -34,7 +34,7 @@ public final class DecimalComparison { * @since v0.2.0 */ public static final double DOUBLE_EPSILON = 1.0e-15; - + /** * The value used for float comparison. If two float values are within this * value multiplied by the larger value, they are considered equal. @@ -43,7 +43,7 @@ public final class DecimalComparison { * @since v0.2.0 */ public static final float FLOAT_EPSILON = 1.0e-6f; - + /** * Tests for equality of double values using {@link #DOUBLE_EPSILON}. * <p> @@ -74,7 +74,7 @@ public final class DecimalComparison { public static final boolean equals(final double a, final double b) { return DecimalComparison.equals(a, b, DOUBLE_EPSILON); } - + /** * Tests for double equality using a custom epsilon value. * @@ -106,7 +106,7 @@ public final class DecimalComparison { final double epsilon) { return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b)); } - + /** * Tests for equality of float values using {@link #FLOAT_EPSILON}. * @@ -136,7 +136,7 @@ public final class DecimalComparison { public static final boolean equals(final float a, final float b) { return DecimalComparison.equals(a, b, FLOAT_EPSILON); } - + /** * Tests for float equality using a custom epsilon value. * @@ -168,7 +168,7 @@ public final class DecimalComparison { final float epsilon) { return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b)); } - + /** * Tests for equality of {@code UncertainDouble} values using * {@link #DOUBLE_EPSILON}. @@ -201,7 +201,7 @@ public final class DecimalComparison { return DecimalComparison.equals(a.value(), b.value()) && DecimalComparison.equals(a.uncertainty(), b.uncertainty()); } - + /** * Tests for {@code UncertainDouble} equality using a custom epsilon value. * @@ -235,7 +235,7 @@ public final class DecimalComparison { && DecimalComparison.equals(a.uncertainty(), b.uncertainty(), epsilon); } - + /** * Takes the hash code of doubles. Values that are equal according to * {@link #equals(double, double)} will have the same hash code. @@ -247,10 +247,10 @@ public final class DecimalComparison { 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/main/java/sevenUnits/utils/ExpressionParser.java b/src/main/java/sevenUnits/utils/ExpressionParser.java index a41f37d..e248ff0 100644 --- a/src/main/java/sevenUnits/utils/ExpressionParser.java +++ b/src/main/java/sevenUnits/utils/ExpressionParser.java @@ -56,7 +56,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final Function<String, ? extends T> objectObtainer; - + /** * The function of the space as an operator (like 3 x y) * @@ -64,7 +64,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private String spaceFunction = null; - + /** * A map mapping operator strings to operator functions, for unary * operators. @@ -73,7 +73,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final Map<String, PriorityUnaryOperator<T>> unaryOperators; - + /** * A map mapping operator strings to operator functions, for binary * operators. @@ -82,14 +82,14 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final Map<String, PriorityBinaryOperator<T>> binaryOperators; - + /** * A map mapping operator strings to numeric functions. * * @since 2024-03-23 */ private final Map<String, PriorityBiFunction<T, UncertainDouble, T>> numericOperators; - + /** * Creates the {@code Builder}. * @@ -106,7 +106,7 @@ public final class ExpressionParser<T> { this.binaryOperators = new HashMap<>(); this.numericOperators = new HashMap<>(); } - + /** * Adds a binary operator to the builder. * @@ -124,7 +124,7 @@ public final class ExpressionParser<T> { final BinaryOperator<T> operator, final int priority) { Objects.requireNonNull(text, "text must not be null."); Objects.requireNonNull(operator, "operator must not be null."); - + // Unfortunately, I cannot use a lambda because the // PriorityBinaryOperator requires arguments. final PriorityBinaryOperator<T> priorityOperator = new PriorityBinaryOperator<>( @@ -133,24 +133,28 @@ public final class ExpressionParser<T> { public T apply(final T t, final T u) { return operator.apply(t, u); } - + }; this.binaryOperators.put(text, priorityOperator); return this; } - + /** - * Adds a two-argument operator where the second operator is a number. This is used for operations like vector scaling and exponentation. + * Adds a two-argument operator where the second operator is a number. + * This is used for operations like vector scaling and exponentation. + * * @param text text used to reference the operator, like '^' * @param operator operator to add * @param priority operator's priority, which determines which operators * are applied first * @return this builder */ - public Builder<T> addNumericOperator(final String text, final BiFunction<T, UncertainDouble, T> operator, final int priority) { + public Builder<T> addNumericOperator(final String text, + final BiFunction<T, UncertainDouble, T> operator, + final int priority) { Objects.requireNonNull(text, "text must not be null."); Objects.requireNonNull(operator, "operator must not be null."); - + // Unfortunately, I cannot use a lambda because the // PriorityBinaryOperator requires arguments. final PriorityBiFunction<T, UncertainDouble, T> priorityOperator = new PriorityBiFunction<>( @@ -159,12 +163,12 @@ public final class ExpressionParser<T> { public T apply(final T t, final UncertainDouble u) { return operator.apply(t, u); } - + }; this.numericOperators.put(text, priorityOperator); return this; } - + /** * Adds a function for spaces. You must use the text of an existing binary * operator. @@ -176,15 +180,15 @@ public final class ExpressionParser<T> { */ public Builder<T> addSpaceFunction(final String operator) { Objects.requireNonNull(operator, "operator must not be null."); - + if (!this.binaryOperators.containsKey(operator)) throw new IllegalArgumentException(String .format("Could not find binary operator '%s'", operator)); - + this.spaceFunction = operator; return this; } - + /** * Adds a unary operator to the builder. * @@ -202,7 +206,7 @@ public final class ExpressionParser<T> { final UnaryOperator<T> operator, final int priority) { Objects.requireNonNull(text, "text must not be null."); Objects.requireNonNull(operator, "operator must not be null."); - + // Unfortunately, I cannot use a lambda because the // PriorityUnaryOperator requires arguments. final PriorityUnaryOperator<T> priorityOperator = new PriorityUnaryOperator<>( @@ -215,7 +219,7 @@ public final class ExpressionParser<T> { this.unaryOperators.put(text, priorityOperator); return this; } - + /** * @return an {@code ExpressionParser<T>} instance with the properties * given to this builder @@ -227,7 +231,7 @@ public final class ExpressionParser<T> { this.binaryOperators, this.numericOperators, this.spaceFunction); } } - + /** * A binary operator with a priority field that determines which operators * apply first. @@ -247,7 +251,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final int priority; - + /** * Creates the {@code PriorityBinaryOperator}. * @@ -258,7 +262,7 @@ public final class ExpressionParser<T> { public PriorityBinaryOperator(final int priority) { this.priority = priority; } - + /** * Compares this object to another by priority. * @@ -278,7 +282,7 @@ public final class ExpressionParser<T> { else return 0; } - + /** * @return priority * @since 2019-03-22 @@ -298,8 +302,8 @@ public final class ExpressionParser<T> { * @since 2019-03-17 * @since v0.2.0 */ - private static abstract class PriorityBiFunction<T, U, R> - implements BiFunction<T, U, R>, Comparable<PriorityBiFunction<T, U, R>> { + private static abstract class PriorityBiFunction<T, U, R> implements + BiFunction<T, U, R>, Comparable<PriorityBiFunction<T, U, R>> { /** * The operator's priority. Higher-priority operators are applied before * lower-priority operators @@ -308,7 +312,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final int priority; - + /** * Creates the {@code PriorityBinaryOperator}. * @@ -319,7 +323,7 @@ public final class ExpressionParser<T> { public PriorityBiFunction(final int priority) { this.priority = priority; } - + /** * Compares this object to another by priority. * @@ -339,7 +343,7 @@ public final class ExpressionParser<T> { else return 0; } - + /** * @return priority * @since 2019-03-22 @@ -349,7 +353,7 @@ public final class ExpressionParser<T> { return this.priority; } } - + /** * A unary operator with a priority field that determines which operators * apply first. @@ -369,7 +373,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final int priority; - + /** * Creates the {@code PriorityUnaryOperator}. * @@ -380,7 +384,7 @@ public final class ExpressionParser<T> { public PriorityUnaryOperator(final int priority) { this.priority = priority; } - + /** * Compares this object to another by priority. * @@ -400,7 +404,7 @@ public final class ExpressionParser<T> { else return 0; } - + /** * @return priority * @since 2019-03-22 @@ -410,7 +414,7 @@ public final class ExpressionParser<T> { return this.priority; } } - + /** * The types of tokens that are available. * @@ -421,7 +425,7 @@ public final class ExpressionParser<T> { private static enum TokenType { OBJECT, UNARY_OPERATOR, BINARY_OPERATOR, NUMERIC_OPERATOR; } - + /** * The opening bracket. * @@ -429,7 +433,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ public static final char OPENING_BRACKET = '('; - + /** * The closing bracket. * @@ -437,7 +441,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ public static final char CLOSING_BRACKET = ')'; - + /** * Finds the other bracket in a pair of brackets, given the position of one. * @@ -451,9 +455,9 @@ public final class ExpressionParser<T> { private static int findBracketPair(final String string, final int bracketPosition) { Objects.requireNonNull(string, "string must not be null."); - + final char openingBracket = string.charAt(bracketPosition); - + // figure out what closing bracket to look for final char closingBracket; switch (openingBracket) { @@ -470,16 +474,16 @@ public final class ExpressionParser<T> { throw new IllegalArgumentException( String.format("Invalid bracket '%s'", openingBracket)); } - + // level of brackets. every opening bracket increments this; every closing // bracket decrements it int bracketLevel = 0; - + // iterate over the string to find the closing bracket for (int currentPosition = bracketPosition; currentPosition < string .length(); currentPosition++) { final char currentCharacter = string.charAt(currentPosition); - + if (currentCharacter == openingBracket) { bracketLevel++; } else if (currentCharacter == closingBracket) { @@ -488,10 +492,10 @@ public final class ExpressionParser<T> { return currentPosition; } } - + throw new IllegalArgumentException("No matching bracket found."); } - + /** * A function that obtains a parseable object from a string. For example, an * integer {@code ExpressionParser} would use {@code Integer::parseInt}. @@ -500,7 +504,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final Function<String, ? extends T> objectObtainer; - + /** * A map mapping operator strings to operator functions, for unary operators. * @@ -508,7 +512,7 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final Map<String, PriorityUnaryOperator<T>> unaryOperators; - + /** * A map mapping operator strings to operator functions, for binary * operators. @@ -524,7 +528,7 @@ public final class ExpressionParser<T> { * @since 2024-03-23 */ private final Map<String, PriorityBiFunction<T, UncertainDouble, T>> numericOperators; - + /** * The operator for space, or null if spaces have no function. * @@ -532,15 +536,15 @@ public final class ExpressionParser<T> { * @since v0.2.0 */ private final String spaceOperator; - + /** * Creates the {@code ExpressionParser}. * - * @param objectObtainer function to get objects from strings - * @param unaryOperators unary operators available to the parser - * @param binaryOperators binary operators available to the parser + * @param objectObtainer function to get objects from strings + * @param unaryOperators unary operators available to the parser + * @param binaryOperators binary operators available to the parser * @param numericOperators numeric operators available to the parser - * @param spaceOperator operator used by spaces + * @param spaceOperator operator used by spaces * @since 2019-03-14 * @since v0.2.0 */ @@ -555,7 +559,7 @@ public final class ExpressionParser<T> { this.numericOperators = numericOperators; this.spaceOperator = spaceOperator; } - + /** * Converts a given mathematical expression to reverse Polish notation * (operators after operands). @@ -574,19 +578,19 @@ public final class ExpressionParser<T> { */ String convertExpressionToReversePolish(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); - + final List<String> components = new ArrayList<>(); - + // the part of the expression remaining to parse String partialExpression = expression; - + // find and deal with brackets while (partialExpression.indexOf(OPENING_BRACKET) != -1) { final int openingBracketPosition = partialExpression .indexOf(OPENING_BRACKET); final int closingBracketPosition = findBracketPair(partialExpression, openingBracketPosition); - + // check for function if (openingBracketPosition > 0 && partialExpression.charAt(openingBracketPosition - 1) != ' ') { @@ -616,15 +620,15 @@ public final class ExpressionParser<T> { .substring(closingBracketPosition + 1); } } - + // add everything else components.addAll(Arrays.asList(partialExpression.split(" "))); - + // remove empty entries while (components.contains("")) { components.remove(""); } - + // deal with space multiplication (x y) if (this.spaceOperator != null) { for (int i = 0; i < components.size() - 1; i++) { @@ -634,7 +638,7 @@ public final class ExpressionParser<T> { } } } - + // turn the expression into reverse Polish while (true) { final int highestPriorityOperatorPosition = this @@ -642,7 +646,7 @@ public final class ExpressionParser<T> { if (highestPriorityOperatorPosition == -1) { break; } - + // swap components based on what kind of operator there is // 1 + 2 becomes 2 1 + // - 1 becomes 1 - @@ -677,11 +681,11 @@ public final class ExpressionParser<T> { throw new AssertionError("Expected operator, found non-operator."); } } - + // join all of the components together, then ensure there is only one // space in a row String expressionRPN = String.join(" ", components).replaceAll(" +", " "); - + while (expressionRPN.charAt(0) == ' ') { expressionRPN = expressionRPN.substring(1); } @@ -690,7 +694,7 @@ public final class ExpressionParser<T> { } return expressionRPN; } - + /** * Finds the position of the highest-priority operator in a list * @@ -708,18 +712,18 @@ public final class ExpressionParser<T> { // find highest priority int maxPriority = Integer.MIN_VALUE; int maxPriorityPosition = -1; - + // go over components one by one // if it is an operator, test its priority to see if it's max // if it is, update maxPriority and maxPriorityPosition for (int i = 0; i < components.size(); i++) { - + switch (this.getTokenType(components.get(i))) { case UNARY_OPERATOR: final PriorityUnaryOperator<T> unaryOperator = this.unaryOperators .get(components.get(i)); final int unaryPriority = unaryOperator.getPriority(); - + if (unaryPriority > maxPriority) { maxPriority = unaryPriority; maxPriorityPosition = i; @@ -729,7 +733,7 @@ public final class ExpressionParser<T> { final PriorityBinaryOperator<T> binaryOperator = this.binaryOperators .get(components.get(i)); final int binaryPriority = binaryOperator.getPriority(); - + if (binaryPriority > maxPriority) { maxPriority = binaryPriority; maxPriorityPosition = i; @@ -739,7 +743,7 @@ public final class ExpressionParser<T> { final PriorityBiFunction<T, UncertainDouble, T> numericOperator = this.numericOperators .get(components.get(i)); final int numericPriority = numericOperator.getPriority(); - + if (numericPriority > maxPriority) { maxPriority = numericPriority; maxPriorityPosition = i; @@ -749,11 +753,11 @@ public final class ExpressionParser<T> { break; } } - + // max priority position found return maxPriorityPosition; } - + /** * Determines whether an inputted string is an object or an operator * @@ -765,7 +769,7 @@ public final class ExpressionParser<T> { */ private TokenType getTokenType(final String token) { Objects.requireNonNull(token, "token must not be null."); - + if (this.unaryOperators.containsKey(token)) return TokenType.UNARY_OPERATOR; else if (this.binaryOperators.containsKey(token)) @@ -775,7 +779,7 @@ public final class ExpressionParser<T> { else return TokenType.OBJECT; } - + /** * Parses an expression. * @@ -789,7 +793,7 @@ public final class ExpressionParser<T> { return this.parseReversePolishExpression( this.convertExpressionToReversePolish(expression)); } - + /** * Parses an expression expressed in reverse Polish notation. * @@ -801,42 +805,43 @@ public final class ExpressionParser<T> { */ T parseReversePolishExpression(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); - + final Deque<T> stack = new ArrayDeque<>(); final Deque<UncertainDouble> doubleStack = new ArrayDeque<>(); - + // iterate over every item in the expression, then for (final String item : expression.split(" ")) { // choose a path based on what kind of thing was just read switch (this.getTokenType(item)) { - + case BINARY_OPERATOR: if (stack.size() < 2) throw new IllegalStateException(String.format( "Attempted to call binary operator %s with only %d arguments.", item, stack.size())); - + // get two arguments and operator, then apply! final T o1 = stack.pop(); final T o2 = stack.pop(); final BinaryOperator<T> binaryOperator = this.binaryOperators .get(item); - + stack.push(binaryOperator.apply(o1, o2)); break; - + case NUMERIC_OPERATOR: if (stack.size() < 1 || doubleStack.size() < 1) throw new IllegalStateException(String.format( "Attempted to call binary operator %s with insufficient arguments.", item)); - + final T ot = stack.pop(); final UncertainDouble on = doubleStack.pop(); - final BiFunction<T, UncertainDouble, T> op = this.numericOperators.get(item); + final BiFunction<T, UncertainDouble, T> op = this.numericOperators + .get(item); stack.push(op.apply(ot, on)); break; - + case OBJECT: // just add it to the stack // these try-catch statements are necessary @@ -850,35 +855,36 @@ public final class ExpressionParser<T> { doubleStack.push(UncertainDouble.fromString(item)); } catch (IllegalArgumentException e2) { try { - doubleStack.push(UncertainDouble.of(Double.parseDouble(item), 0)); + doubleStack.push( + UncertainDouble.of(Double.parseDouble(item), 0)); } catch (NumberFormatException e3) { throw e; } } } break; - + case UNARY_OPERATOR: if (stack.size() < 1) throw new IllegalStateException(String.format( "Attempted to call unary operator %s with only %d arguments.", item, stack.size())); - + // get one argument and operator, then apply! final T o = stack.pop(); final UnaryOperator<T> unaryOperator = this.unaryOperators .get(item); - + stack.push(unaryOperator.apply(o)); break; default: throw new AssertionError( String.format("Internal error: Invalid token type %s.", this.getTokenType(item))); - + } } - + // return answer, or throw an exception if I can't if (stack.size() > 1) throw new IllegalStateException( diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java index 9388f63..49c44fa 100644 --- a/src/main/java/sevenUnits/utils/NameSymbol.java +++ b/src/main/java/sevenUnits/utils/NameSymbol.java @@ -33,7 +33,7 @@ import java.util.Set; public final class NameSymbol { public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(), Optional.empty(), new HashSet<>()); - + /** * Creates a {@code NameSymbol}, ensuring that if primaryName is null and * otherNames is not empty, one name is moved from otherNames to primaryName @@ -43,7 +43,7 @@ public final class NameSymbol { private static final NameSymbol create(final String name, final String symbol, final Set<String> otherNames) { final Optional<String> primaryName; - + if (name == null && !otherNames.isEmpty()) { // get primary name and remove it from savedNames final Iterator<String> it = otherNames.iterator(); @@ -53,11 +53,11 @@ public final class NameSymbol { } else { primaryName = Optional.ofNullable(name); } - + return new NameSymbol(primaryName, Optional.ofNullable(symbol), otherNames); } - + /** * Gets a {@code NameSymbol} with a primary name, a symbol and no other * names. @@ -72,7 +72,7 @@ public final class NameSymbol { return new NameSymbol(Optional.of(name), Optional.of(symbol), new HashSet<>()); } - + /** * Gets a {@code NameSymbol} with a primary name, a symbol and additional * names. @@ -90,7 +90,7 @@ public final class NameSymbol { new HashSet<>(Objects.requireNonNull(otherNames, "otherNames must not be null."))); } - + /** * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional * names. @@ -108,7 +108,7 @@ public final class NameSymbol { new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames, "otherNames must not be null.")))); } - + /** * Gets a {@code NameSymbol} with a primary name, no symbol, and no other * names. @@ -122,7 +122,7 @@ public final class NameSymbol { return new NameSymbol(Optional.of(name), Optional.empty(), new HashSet<>()); } - + /** * Gets a {@code NameSymbol} with a primary name, a symbol and additional * names. @@ -145,7 +145,7 @@ public final class NameSymbol { return NameSymbol.create(name, symbol, otherNames == null ? new HashSet<>() : new HashSet<>(otherNames)); } - + /** * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional * names. @@ -168,7 +168,7 @@ public final class NameSymbol { return create(name, symbol, otherNames == null ? new HashSet<>() : new HashSet<>(Arrays.asList(otherNames))); } - + /** * Gets a {@code NameSymbol} with a symbol and no names. * @@ -181,12 +181,12 @@ public final class NameSymbol { return new NameSymbol(Optional.empty(), Optional.of(symbol), new HashSet<>()); } - + private final Optional<String> primaryName; private final Optional<String> symbol; - + private final Set<String> otherNames; - + /** * Creates the {@code NameSymbol}. * @@ -202,12 +202,12 @@ public final class NameSymbol { this.symbol = symbol; otherNames.remove(null); this.otherNames = Collections.unmodifiableSet(otherNames); - + if (this.primaryName.isEmpty()) { assert this.otherNames.isEmpty(); } } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -232,7 +232,7 @@ public final class NameSymbol { return false; return true; } - + /** * @return otherNames * @since 2019-10-21 @@ -240,7 +240,7 @@ public final class NameSymbol { public final Set<String> getOtherNames() { return this.otherNames; } - + /** * @return primaryName * @since 2019-10-21 @@ -248,7 +248,7 @@ public final class NameSymbol { public final Optional<String> getPrimaryName() { return this.primaryName; } - + /** * @return symbol * @since 2019-10-21 @@ -256,7 +256,7 @@ public final class NameSymbol { public final Optional<String> getSymbol() { return this.symbol; } - + @Override public int hashCode() { final int prime = 31; @@ -269,7 +269,7 @@ public final class NameSymbol { + (this.symbol == null ? 0 : this.symbol.hashCode()); return result; } - + /** * @return true iff this {@code NameSymbol} contains no names or symbols. */ @@ -277,7 +277,7 @@ public final class NameSymbol { // if primaryName is empty, otherNames must also be empty return this.primaryName.isEmpty() && this.symbol.isEmpty(); } - + @Override public String toString() { if (this.isEmpty()) @@ -288,7 +288,7 @@ public final class NameSymbol { else return this.primaryName.orElseGet(this.symbol::orElseThrow); } - + /** * Creates and returns a copy of this {@code NameSymbol} with the provided * extra name. If this {@code NameSymbol} has a primary name, the provided diff --git a/src/main/java/sevenUnits/utils/Nameable.java b/src/main/java/sevenUnits/utils/Nameable.java index e469d04..3959a64 100644 --- a/src/main/java/sevenUnits/utils/Nameable.java +++ b/src/main/java/sevenUnits/utils/Nameable.java @@ -35,14 +35,14 @@ public interface Nameable { final NameSymbol ns = this.getNameSymbol(); return ns.getPrimaryName().or(ns::getSymbol).orElse("Unnamed"); } - + /** * @return a {@code NameSymbol} that contains this object's primary name, * symbol and other names * @since 2020-09-07 */ NameSymbol getNameSymbol(); - + /** * @return set of alternate names * @since 2020-09-07 @@ -50,7 +50,7 @@ public interface Nameable { default Set<String> getOtherNames() { return this.getNameSymbol().getOtherNames(); } - + /** * @return preferred name of object * @since 2020-09-07 @@ -58,7 +58,7 @@ public interface Nameable { default Optional<String> getPrimaryName() { return this.getNameSymbol().getPrimaryName(); } - + /** * @return a short name for the object - if there's a symbol, it's that, * otherwise the symbol, otherwise "Unnamed" @@ -68,7 +68,7 @@ public interface Nameable { final NameSymbol ns = this.getNameSymbol(); return ns.getSymbol().or(ns::getPrimaryName).orElse("Unnamed"); } - + /** * @return short symbol representing object * @since 2020-09-07 diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java index 66bb773..5a29d79 100644 --- a/src/main/java/sevenUnits/utils/ObjectProduct.java +++ b/src/main/java/sevenUnits/utils/ObjectProduct.java @@ -44,7 +44,7 @@ public class ObjectProduct<T> implements Nameable { public static final <T> ObjectProduct<T> empty() { return new ObjectProduct<>(new HashMap<>()); } - + /** * Gets an {@code ObjectProduct} from an object-to-integer mapping * @@ -57,7 +57,7 @@ public class ObjectProduct<T> implements Nameable { final Map<T, Integer> map) { return new ObjectProduct<>(new HashMap<>(map)); } - + /** * Gets an ObjectProduct that has one of the inputted argument, and nothing * else. @@ -73,7 +73,7 @@ public class ObjectProduct<T> implements Nameable { map.put(object, 1); return new ObjectProduct<>(map); } - + /** * The objects that make up the product, mapped to their exponents. This map * treats zero as null, and is immutable. @@ -81,12 +81,12 @@ public class ObjectProduct<T> implements Nameable { * @since 2019-10-16 */ final Map<T, Integer> exponents; - + /** * The object's name and symbol */ private final NameSymbol nameSymbol; - + /** * Creates a {@code ObjectProduct} without a name/symbol. * @@ -96,7 +96,7 @@ public class ObjectProduct<T> implements Nameable { ObjectProduct(final Map<T, Integer> exponents) { this(exponents, NameSymbol.EMPTY); } - + /** * Creates the {@code ObjectProduct}. * @@ -110,7 +110,7 @@ public class ObjectProduct<T> implements Nameable { e -> !Integer.valueOf(0).equals(e.getValue()))); this.nameSymbol = nameSymbol; } - + /** * Calculates the quotient of two products * @@ -125,17 +125,17 @@ public class ObjectProduct<T> implements Nameable { final Set<T> objects = new HashSet<>(); objects.addAll(this.getBaseSet()); objects.addAll(other.getBaseSet()); - + // get a list of all exponents final Map<T, Integer> map = new HashMap<>(objects.size()); for (final T key : objects) { map.put(key, this.getExponent(key) - other.getExponent(key)); } - + // create the product return new ObjectProduct<>(map); } - + // this method relies on the use of ZeroIsNullMap @Override public boolean equals(final Object obj) { @@ -146,7 +146,7 @@ public class ObjectProduct<T> implements Nameable { final ObjectProduct<?> other = (ObjectProduct<?>) obj; return Objects.equals(this.exponents, other.exponents); } - + /** * @return immutable map mapping objects to exponents * @since 2019-10-16 @@ -154,7 +154,7 @@ public class ObjectProduct<T> implements Nameable { public Map<T, Integer> exponentMap() { return this.exponents; } - + /** * @return a set of all of the base objects with non-zero exponents that make * up this dimension. @@ -163,7 +163,7 @@ public class ObjectProduct<T> implements Nameable { */ public final Set<T> getBaseSet() { final Set<T> dimensions = new HashSet<>(); - + // add all dimensions with a nonzero exponent - zero exponents shouldn't // be there in the first place for (final T dimension : this.exponents.keySet()) { @@ -171,10 +171,10 @@ public class ObjectProduct<T> implements Nameable { dimensions.add(dimension); } } - + return dimensions; } - + /** * Gets the exponent for a specific dimension. * @@ -186,17 +186,17 @@ public class ObjectProduct<T> implements Nameable { public int getExponent(final T dimension) { return this.exponents.getOrDefault(dimension, 0); } - + @Override public NameSymbol getNameSymbol() { return this.nameSymbol; } - + @Override public int hashCode() { return Objects.hash(this.exponents); } - + /** * @return true if this product is a single object, i.e. it has one exponent * of one and no other nonzero exponents @@ -214,7 +214,7 @@ public class ObjectProduct<T> implements Nameable { } return oneCount == 1 && !twoOrMore; } - + /** * Multiplies this product by another * @@ -229,17 +229,17 @@ public class ObjectProduct<T> implements Nameable { final Set<T> objects = new HashSet<>(); objects.addAll(this.getBaseSet()); objects.addAll(other.getBaseSet()); - + // get a list of all exponents final Map<T, Integer> map = new HashMap<>(objects.size()); for (final T key : objects) { map.put(key, this.getExponent(key) + other.getExponent(key)); } - + // create the product return new ObjectProduct<>(map); } - + /** * Returns this product, but to an exponent * @@ -254,7 +254,7 @@ public class ObjectProduct<T> implements Nameable { } return new ObjectProduct<>(map); } - + /** * Converts this product to a string using the objects' * {@link Object#toString()} method (or {@link Nameable#getShortName} if @@ -271,7 +271,7 @@ public class ObjectProduct<T> implements Nameable { .toString(o -> o instanceof Nameable ? ((Nameable) o).getShortName() : o.toString()); } - + /** * Converts this product to a string. The objects that make up this product * are represented by {@code objectToString} @@ -283,7 +283,7 @@ public class ObjectProduct<T> implements Nameable { public String toString(final Function<T, String> objectToString) { final List<String> positiveStringComponents = new ArrayList<>(); final List<String> negativeStringComponents = new ArrayList<>(); - + // for each base object that makes up this object, add it and its exponent for (final T object : this.getBaseSet()) { final int exponent = this.exponents.get(object); @@ -297,15 +297,15 @@ public class ObjectProduct<T> implements Nameable { objectToString.apply(object), -exponent)); } } - + final String positiveString = positiveStringComponents.isEmpty() ? "1" : String.join(" * ", positiveStringComponents); final String negativeString = negativeStringComponents.isEmpty() ? "" : " / " + String.join(" * ", negativeStringComponents); - + return positiveString + negativeString; } - + /** * @return named version of this {@code ObjectProduct}, using data from * {@code nameSymbol} diff --git a/src/main/java/sevenUnits/utils/SemanticVersionNumber.java b/src/main/java/sevenUnits/utils/SemanticVersionNumber.java index e80e16e..fc47baa 100644 --- a/src/main/java/sevenUnits/utils/SemanticVersionNumber.java +++ b/src/main/java/sevenUnits/utils/SemanticVersionNumber.java @@ -61,7 +61,7 @@ public final class SemanticVersionNumber private final int patch; private final List<String> preReleaseIdentifiers; private final List<String> buildMetadata; - + /** * Creates a builder which can be used to create a * {@code SemanticVersionNumber} @@ -79,7 +79,7 @@ public final class SemanticVersionNumber this.preReleaseIdentifiers = new ArrayList<>(); this.buildMetadata = new ArrayList<>(); } - + /** * @return version number created by this builder * @since v0.4.0 @@ -89,7 +89,7 @@ public final class SemanticVersionNumber return new SemanticVersionNumber(this.major, this.minor, this.patch, this.preReleaseIdentifiers, this.buildMetadata); } - + /** * Adds one or more build metadata identifiers * @@ -109,7 +109,7 @@ public final class SemanticVersionNumber } return this; } - + /** * Adds one or more build metadata identifiers * @@ -129,7 +129,7 @@ public final class SemanticVersionNumber } return this; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -142,13 +142,13 @@ public final class SemanticVersionNumber && this.patch == other.patch && Objects.equals( this.preReleaseIdentifiers, other.preReleaseIdentifiers); } - + @Override public int hashCode() { return Objects.hash(this.buildMetadata, this.major, this.minor, this.patch, this.preReleaseIdentifiers); } - + /** * Adds one or more numeric identifiers to the version number * @@ -167,7 +167,7 @@ public final class SemanticVersionNumber } return this; } - + /** * Adds one or more pre-release identifier(s) to the version number * @@ -187,7 +187,7 @@ public final class SemanticVersionNumber } return this; } - + /** * Adds one or more pre-release identifier(s) to the version number * @@ -207,7 +207,7 @@ public final class SemanticVersionNumber } return this; } - + /** * Adds a string identifier and an integer identifer to pre-release data * @@ -229,13 +229,13 @@ public final class SemanticVersionNumber this.preReleaseIdentifiers.add(Integer.toString(identifier2)); return this; } - + @Override public String toString() { return "Semantic Version Builder: " + this.build().toString(); } } - + /** * An alternative comparison method for version numbers. This uses the * version's natural order, but the build metadata will be compared (using @@ -257,21 +257,21 @@ public final class SemanticVersionNumber return naturalComparison; }; }; - + /** The alphanumeric pattern all identifiers must follow */ private static final Pattern VALID_IDENTIFIER = Pattern .compile("[0-9A-Za-z-]+"); - + /** The numeric pattern which causes special behaviour */ private static final Pattern NUMERIC_IDENTIFER = Pattern.compile("[0-9]+"); - + /** The pattern for a version number */ private static final Pattern VERSION_NUMBER = Pattern .compile("(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)" // main // version + "(?:-([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?" // pre-release + "(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?"); // build data - + /** * Creates a builder that can be used to create a version number * @@ -296,7 +296,7 @@ public final class SemanticVersionNumber "Patch version must be non-negative."); return new SemanticVersionNumber.Builder(major, minor, patch); } - + /** * Compares two lists of strings based on SemVer's precedence rules * @@ -311,24 +311,24 @@ public final class SemanticVersionNumber // test pre-release size final int aSize = a.size(); final int bSize = b.size(); - + // no identifiers is greater than any identifiers if (aSize != 0 && bSize == 0) return -1; else if (aSize == 0 && bSize != 0) return 1; - + // test identifiers one by one for (int i = 0; i < Math.min(aSize, bSize); i++) { final String aElement = a.get(i); final String bElement = b.get(i); - + if (NUMERIC_IDENTIFER.matcher(aElement).matches()) { if (NUMERIC_IDENTIFER.matcher(bElement).matches()) { // both are numbers, compare them final int aNumber = Integer.parseInt(aElement); final int bNumber = Integer.parseInt(bElement); - + if (aNumber < bNumber) return -1; else if (aNumber > bNumber) @@ -350,7 +350,7 @@ public final class SemanticVersionNumber } } } - + // we just tested the stuff that's in common, maybe someone has more if (aSize < bSize) return -1; @@ -359,7 +359,7 @@ public final class SemanticVersionNumber else return 0; } - + /** * Gets a version number from a string in the official format * @@ -377,12 +377,12 @@ public final class SemanticVersionNumber throw new IllegalArgumentException( String.format("Provided string \"%s\" is not a version number", versionString)); - + // main parts final int major = Integer.parseInt(m.group(1)); final int minor = Integer.parseInt(m.group(2)); final int patch = Integer.parseInt(m.group(3)); - + // pre release final List<String> preRelease; if (m.group(4) == null) { @@ -390,7 +390,7 @@ public final class SemanticVersionNumber } else { preRelease = Arrays.asList(m.group(4).split("\\.")); } - + // build metadata final List<String> buildMetadata; if (m.group(5) == null) { @@ -398,12 +398,12 @@ public final class SemanticVersionNumber } else { buildMetadata = Arrays.asList(m.group(5).split("\\.")); } - + // return number return new SemanticVersionNumber(major, minor, patch, preRelease, buildMetadata); } - + /** * Tests whether a string is a valid Semantic Version string * @@ -415,7 +415,7 @@ public final class SemanticVersionNumber public static final boolean isValidVersionString(String versionString) { return VERSION_NUMBER.matcher(versionString).matches(); } - + /** * Creates a simple pre-release version number of the form * MAJOR.MINOR.PATH-TYPE.NUMBER (e.g. 1.2.3-alpha.4). @@ -454,7 +454,7 @@ public final class SemanticVersionNumber List.of(preReleaseType, Integer.toString(preReleaseNumber)), List.of()); } - + /** * Creates a {@code SemanticVersionNumber} instance without pre-release * identifiers or build metadata. @@ -484,14 +484,14 @@ public final class SemanticVersionNumber return new SemanticVersionNumber(major, minor, patch, List.of(), List.of()); } - + // parts of the version number private final int major; private final int minor; private final int patch; private final List<String> preReleaseIdentifiers; private final List<String> buildMetadata; - + /** * Creates a version number * @@ -511,7 +511,7 @@ public final class SemanticVersionNumber this.preReleaseIdentifiers = preReleaseIdentifiers; this.buildMetadata = buildMetadata; } - + /** * @return build metadata (empty if there is none) * @since v0.4.0 @@ -520,7 +520,7 @@ public final class SemanticVersionNumber public List<String> buildMetadata() { return Collections.unmodifiableList(this.buildMetadata); } - + /** * Compares two version numbers according to the official Semantic Versioning * order. @@ -538,23 +538,23 @@ public final class SemanticVersionNumber return -1; else if (this.major > o.major) return 1; - + if (this.minor < o.minor) return -1; else if (this.minor > o.minor) return 1; - + if (this.patch < o.patch) return -1; else if (this.patch > o.patch) return 1; - + // now we just compare pre-release identifiers // (remember: build metadata is ignored) return SemanticVersionNumber.compareIdentifiers( this.preReleaseIdentifiers, o.preReleaseIdentifiers); } - + /** * Determines the compatibility of code written for this version to * {@code other}. More specifically: @@ -590,11 +590,11 @@ public final class SemanticVersionNumber */ public boolean compatibleWith(SemanticVersionNumber other) { Objects.requireNonNull(other, "other may not be null"); - + return this.compareTo(other) == 0 || this.major != 0 && this.major == other.major && this.compareTo(other) < 0; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -621,7 +621,7 @@ public final class SemanticVersionNumber return false; return true; } - + @Override public int hashCode() { final int prime = 31; @@ -635,7 +635,7 @@ public final class SemanticVersionNumber : this.preReleaseIdentifiers.hashCode()); return result; } - + /** * @return true iff this version is stable (major version > 0 and not a * pre-release) @@ -645,7 +645,7 @@ public final class SemanticVersionNumber public boolean isStable() { return this.major > 0 && this.preReleaseIdentifiers.isEmpty(); } - + /** * @return the MAJOR version number, incremented when you make backwards * incompatible API changes @@ -655,7 +655,7 @@ public final class SemanticVersionNumber public int majorVersion() { return this.major; } - + /** * @return the MINOR version number, incremented when you add backwards * compatible functionality @@ -665,7 +665,7 @@ public final class SemanticVersionNumber public int minorVersion() { return this.minor; } - + /** * @return the PATCH version number, incremented when you make backwards * compatible bug fixes @@ -675,7 +675,7 @@ public final class SemanticVersionNumber public int patchVersion() { return this.patch; } - + /** * @return identifiers describing this pre-release (empty if not a * pre-release) @@ -685,7 +685,7 @@ public final class SemanticVersionNumber public List<String> preReleaseIdentifiers() { return Collections.unmodifiableList(this.preReleaseIdentifiers); } - + /** * Converts a version number to a string using the official SemVer format. * The core of a version is MAJOR.MINOR.PATCH, without zero-padding. If diff --git a/src/main/java/sevenUnits/utils/UncertainDouble.java b/src/main/java/sevenUnits/utils/UncertainDouble.java index ac523b3..66d8103 100644 --- a/src/main/java/sevenUnits/utils/UncertainDouble.java +++ b/src/main/java/sevenUnits/utils/UncertainDouble.java @@ -23,7 +23,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * A double with an associated uncertainty value. For example, 3.2 ± 0.2. + * A double with an associated uncertainty value. For example, 3.2 � 0.2. * <p> * All methods in this class throw a NullPointerException if any of their * arguments is null. @@ -35,20 +35,20 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { * The exact value 0 */ public static final UncertainDouble ZERO = UncertainDouble.of(0, 0); - + static final String NUMBER_REGEX = "(\\d+(?:[\\.,]\\d+))"; - + /** * A regular expression that can recognize toString forms */ static final Pattern TO_STRING = Pattern.compile(NUMBER_REGEX - // optional "± [number]" - + "(?:\\s*(?:±|\\+-)\\s*" + NUMBER_REGEX + ")?"); - + // optional "� [number]" + + "(?:\\s*(?:�|\\+-)\\s*" + NUMBER_REGEX + ")?"); + /** * Gets an UncertainDouble from a double string. The uncertainty of the * double will be one of the lowest decimal place of the number. For example, - * "12345.678" will become 12345.678 ± 0.001. + * "12345.678" will become 12345.678 � 0.001. * * @throws NumberFormatException if the argument is not a number * @@ -59,13 +59,13 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { final double uncertainty = Math.pow(10, -value.scale()); return UncertainDouble.of(value.doubleValue(), uncertainty); } - + /** * Parses a string in the form of {@link UncertainDouble#toString(boolean)} * and returns the corresponding {@code UncertainDouble} instance. * <p> * This method allows some alternative forms of the string representation, - * such as using "+-" instead of "±". + * such as using "+-" instead of "�". * * @param s string to parse * @return {@code UncertainDouble} instance @@ -75,11 +75,11 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public static final UncertainDouble fromString(String s) { Objects.requireNonNull(s, "s may not be null"); final Matcher matcher = TO_STRING.matcher(s); - + if (!matcher.matches()) throw new IllegalArgumentException( "Could not parse stirng \"" + s + "\"."); - + double value, uncertainty; try { value = Double.parseDouble(matcher.group(1)); @@ -87,7 +87,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { throw new IllegalArgumentException( "String " + s + " not in correct format."); } - + final String uncertaintyString = matcher.group(2); if (uncertaintyString == null) { uncertainty = 0; @@ -99,10 +99,10 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { "String " + s + " not in correct format."); } } - + return UncertainDouble.of(value, uncertainty); } - + /** * Gets an {@code UncertainDouble} from its value and <b>absolute</b> * uncertainty. @@ -112,7 +112,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public static final UncertainDouble of(double value, double uncertainty) { return new UncertainDouble(value, uncertainty); } - + /** * Gets an {@code UncertainDouble} from its value and <b>relative</b> * uncertainty. @@ -123,11 +123,11 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { double relativeUncertainty) { return new UncertainDouble(value, value * relativeUncertainty); } - + private final double value; - + private final double uncertainty; - + /** * @param value * @param uncertainty @@ -138,13 +138,13 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { // uncertainty should only ever be positive this.uncertainty = Math.abs(uncertainty); } - + /** * Compares this {@code UncertainDouble} with another * {@code UncertainDouble}. * <p> - * This method only compares the values, not the uncertainties. So 3.1 ± 0.5 - * is considered less than 3.2 ± 0.5, even though they are equivalent. + * This method only compares the values, not the uncertainties. So 3.1 � 0.5 + * is considered less than 3.2 � 0.5, even though they are equivalent. * <p> * <b>Note:</b> The natural ordering of this class is inconsistent with * equals. Specifically, if two {@code UncertainDouble} instances {@code a} @@ -156,7 +156,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final int compareTo(UncertainDouble o) { return Double.compare(this.value, o.value); } - + /** * Returns the quotient of {@code this} and {@code other}. * @@ -167,7 +167,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return UncertainDouble.ofRelative(this.value / other.value, Math .hypot(this.relativeUncertainty(), other.relativeUncertainty())); } - + /** * Returns the quotient of {@code this} and the exact value {@code other}. * @@ -176,7 +176,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final UncertainDouble dividedByExact(double other) { return UncertainDouble.of(this.value / other, this.uncertainty / other); } - + @Override public final boolean equals(Object obj) { if (this == obj) @@ -190,7 +190,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return false; return true; } - + /** * @param other another {@code UncertainDouble} * @return true iff this and {@code other} are within each other's @@ -202,7 +202,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return Math.abs(this.value - other.value) <= Math.min(this.uncertainty, other.uncertainty); } - + /** * Gets the preferred scale for rounding a value for toString. * @@ -217,19 +217,19 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { // the value is rounded to the same number of decimal places as the // uncertainty. final BigDecimal bigUncertainty = BigDecimal.valueOf(this.uncertainty); - + // the scale that will give the uncertainty two decimal places final int twoDecimalPlacesScale = bigUncertainty.scale() - bigUncertainty.precision() + 2; final BigDecimal roundedUncertainty = bigUncertainty .setScale(twoDecimalPlacesScale, RoundingMode.HALF_EVEN); - + if (roundedUncertainty.unscaledValue().intValue() >= 20) return twoDecimalPlacesScale - 1; // one decimal place else return twoDecimalPlacesScale; } - + @Override public final int hashCode() { final int prime = 31; @@ -238,7 +238,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { result = prime * result + Double.hashCode(this.uncertainty); return result; } - + /** * @return true iff the value has no uncertainty * @@ -247,7 +247,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final boolean isExact() { return this.uncertainty == 0; } - + /** * Returns the difference of {@code this} and {@code other}. * @@ -258,7 +258,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return UncertainDouble.of(this.value - other.value, Math.hypot(this.uncertainty, other.uncertainty)); } - + /** * Returns the difference of {@code this} and the exact value {@code other}. * @@ -267,7 +267,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final UncertainDouble minusExact(double other) { return UncertainDouble.of(this.value - other, this.uncertainty); } - + /** * Returns the sum of {@code this} and {@code other}. * @@ -278,7 +278,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return UncertainDouble.of(this.value + other.value, Math.hypot(this.uncertainty, other.uncertainty)); } - + /** * Returns the sum of {@code this} and the exact value {@code other}. * @@ -287,7 +287,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final UncertainDouble plusExact(double other) { return UncertainDouble.of(this.value + other, this.uncertainty); } - + /** * @return relative uncertainty * @since 2020-09-07 @@ -295,7 +295,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final double relativeUncertainty() { return this.uncertainty / this.value; } - + /** * Returns the product of {@code this} and {@code other}. * @@ -306,7 +306,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return UncertainDouble.ofRelative(this.value * other.value, Math .hypot(this.relativeUncertainty(), other.relativeUncertainty())); } - + /** * Returns the product of {@code this} and the exact value {@code other}. * @@ -315,7 +315,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final UncertainDouble timesExact(double other) { return UncertainDouble.of(this.value * other, this.uncertainty * other); } - + /** * Returns the result of {@code this} raised to the exponent {@code other}. * @@ -323,15 +323,15 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { */ public final UncertainDouble toExponent(UncertainDouble other) { Objects.requireNonNull(other, "other may not be null"); - + final double result = Math.pow(this.value, other.value); final double relativeUncertainty = Math.hypot( other.value * this.relativeUncertainty(), Math.log(this.value) * other.uncertainty); - + return UncertainDouble.ofRelative(result, relativeUncertainty); } - + /** * Returns the result of {@code this} raised the exact exponent * {@code other}. @@ -342,7 +342,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { return UncertainDouble.ofRelative(Math.pow(this.value, other), this.relativeUncertainty() * other); } - + /** * Returns a string representation of this {@code UncertainDouble}. * <p> @@ -354,8 +354,8 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { * Examples: * * <pre> - * UncertainDouble.of(3.27, 0.22).toString() = "3.3 ± 0.2" - * UncertainDouble.of(3.27, 0.13).toString() = "3.27 ± 0.13" + * UncertainDouble.of(3.27, 0.22).toString() = "3.3 � 0.2" + * UncertainDouble.of(3.27, 0.13).toString() = "3.27 � 0.13" * UncertainDouble.of(-5.01, 0).toString() = "-5.01" * </pre> * @@ -365,12 +365,12 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final String toString() { return this.toString(!this.isExact(), RoundingMode.HALF_EVEN); } - + /** * Returns a string representation of this {@code UncertainDouble}. * <p> * If {@code showUncertainty} is true, the string will be of the form "VALUE - * ± UNCERTAINTY", and if it is false the string will be of the form "VALUE" + * � UNCERTAINTY", and if it is false the string will be of the form "VALUE" * <p> * VALUE represents a string representation of this {@code UncertainDouble}'s * value. If the uncertainty is non-zero, the string will be rounded to the @@ -385,11 +385,11 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { * * <pre> * UncertainDouble.of(3.27, 0.22).toString(false) = "3.3" - * UncertainDouble.of(3.27, 0.22).toString(true) = "3.3 ± 0.2" + * UncertainDouble.of(3.27, 0.22).toString(true) = "3.3 � 0.2" * UncertainDouble.of(3.27, 0.13).toString(false) = "3.27" - * UncertainDouble.of(3.27, 0.13).toString(true) = "3.27 ± 0.13" + * UncertainDouble.of(3.27, 0.13).toString(true) = "3.27 � 0.13" * UncertainDouble.of(-5.01, 0).toString(false) = "-5.01" - * UncertainDouble.of(-5.01, 0).toString(true) = "-5.01 ± 0.0" + * UncertainDouble.of(-5.01, 0).toString(true) = "-5.01 � 0.0" * </pre> * * @since 2020-09-07 @@ -397,31 +397,31 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final String toString(boolean showUncertainty, RoundingMode roundingMode) { String valueString, uncertaintyString; - + // generate the string representation of value and uncertainty if (this.isExact()) { uncertaintyString = "0.0"; valueString = Double.toString(this.value); - + } else { // round the value and uncertainty according to getDisplayScale() final BigDecimal bigValue = BigDecimal.valueOf(this.value); final BigDecimal bigUncertainty = BigDecimal.valueOf(this.uncertainty); - + final int displayScale = this.getDisplayScale(); final BigDecimal roundedUncertainty = bigUncertainty .setScale(displayScale, roundingMode); final BigDecimal roundedValue = bigValue.setScale(displayScale, roundingMode); - + valueString = roundedValue.toString(); uncertaintyString = roundedUncertainty.toString(); } - - // return "value" or "value ± uncertainty" depending on showUncertainty - return valueString + (showUncertainty ? " ± " + uncertaintyString : ""); + + // return "value" or "value � uncertainty" depending on showUncertainty + return valueString + (showUncertainty ? " � " + uncertaintyString : ""); } - + /** * @return absolute uncertainty * @since 2020-09-07 @@ -429,7 +429,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { public final double uncertainty() { return this.uncertainty; } - + /** * @return value without uncertainty * @since 2020-09-07 diff --git a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java index b56356d..1fb2709 100644 --- a/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java +++ b/src/main/java/sevenUnitsGUI/DefaultPrefixRepetitionRule.java @@ -45,16 +45,16 @@ public enum DefaultPrefixRepetitionRule implements Predicate<List<UnitPrefix>> { } else { magnifying = false; } - + // if the first prefix is non-metric (including binary prefixes), // assume we are using non-metric prefixes // non-metric prefixes are allowed, but can't be repeated. if (!Metric.DECIMAL_PREFIXES.contains(prefixes.get(0))) return NO_REPETITION.test(prefixes); - + int part = 0; // 0=yotta/yoctos, 1=kilo-zetta/milli-zepto, // 2=deka,hecto,deci,centi - + for (final UnitPrefix prefix : prefixes) { // check that the current prefix is metric and appropriately // magnifying/reducing @@ -62,7 +62,7 @@ public enum DefaultPrefixRepetitionRule implements Predicate<List<UnitPrefix>> { return false; if (magnifying != prefix.getMultiplier() > 1) return false; - + // check if the current prefix is correct // since part is set *after* this check, part designates the state // of the *previous* prefix @@ -79,7 +79,7 @@ public enum DefaultPrefixRepetitionRule implements Predicate<List<UnitPrefix>> { // deka/hecto must be the last prefix, so this is always invalid return false; } - + // set part if (Metric.YOTTA.equals(prefix) || Metric.YOCTO.equals(prefix)) { part = 0; diff --git a/src/main/java/sevenUnitsGUI/DelegateListModel.java b/src/main/java/sevenUnitsGUI/DelegateListModel.java index 5938b59..798383b 100644 --- a/src/main/java/sevenUnitsGUI/DelegateListModel.java +++ b/src/main/java/sevenUnitsGUI/DelegateListModel.java @@ -27,15 +27,17 @@ import javax.swing.AbstractListModel; /** * A list model that delegates to a list. * <p> - * It is recommended to use the delegate methods in DelegateListModel instead of the delegated list's methods because - * the delegate methods handle updating the list. + * It is recommended to use the delegate methods in DelegateListModel instead of + * the delegated list's methods because the delegate methods handle updating the + * list. * </p> * * @author Adrien Hopkins * @since 2019-01-14 * @since v0.1.0 */ -final class DelegateListModel<E> extends AbstractListModel<E> implements List<E> { +final class DelegateListModel<E> extends AbstractListModel<E> + implements List<E> { /** * @since 2019-01-14 * @since v0.1.0 @@ -62,8 +64,7 @@ final class DelegateListModel<E> extends AbstractListModel<E> implements List<E> /** * Creates the {@code DelegateListModel}. * - * @param delegate - * list to delegate + * @param delegate list to delegate * @since 2019-01-14 * @since v0.1.0 */ @@ -101,7 +102,8 @@ final class DelegateListModel<E> extends AbstractListModel<E> implements List<E> for (final E e : c) { this.add(index, e); } - return !c.isEmpty(); // Since this is a list, it will always change if c has elements. + return !c.isEmpty(); // Since this is a list, it will always change if c + // has elements. } @Override diff --git a/src/main/java/sevenUnitsGUI/ExpressionConversionView.java b/src/main/java/sevenUnitsGUI/ExpressionConversionView.java index 5c39788..882c995 100644 --- a/src/main/java/sevenUnitsGUI/ExpressionConversionView.java +++ b/src/main/java/sevenUnitsGUI/ExpressionConversionView.java @@ -30,14 +30,14 @@ public interface ExpressionConversionView extends View { * @since 2021-12-15 */ String getFromExpression(); - + /** * @return unit expression to convert <em>to</em> * @since v0.4.0 * @since 2021-12-15 */ String getToExpression(); - + /** * Shows the output of an expression conversion to the user. * diff --git a/src/main/java/sevenUnitsGUI/FilterComparator.java b/src/main/java/sevenUnitsGUI/FilterComparator.java index c0a67e8..484a98f 100644 --- a/src/main/java/sevenUnitsGUI/FilterComparator.java +++ b/src/main/java/sevenUnitsGUI/FilterComparator.java @@ -50,7 +50,7 @@ final class FilterComparator<T> implements Comparator<T> { * @since v0.2.0 */ private final boolean caseSensitive; - + /** * Creates the {@code FilterComparator}. * @@ -61,7 +61,7 @@ final class FilterComparator<T> implements Comparator<T> { public FilterComparator(final String filter) { this(filter, null); } - + /** * Creates the {@code FilterComparator}. * @@ -76,7 +76,7 @@ final class FilterComparator<T> implements Comparator<T> { final Comparator<T> comparator) { this(filter, comparator, false); } - + /** * Creates the {@code FilterComparator}. * @@ -95,7 +95,7 @@ final class FilterComparator<T> implements Comparator<T> { this.comparator = comparator; this.caseSensitive = caseSensitive; } - + /** * Compares two objects according to whether or not they match a filter. * Objects whose string representation starts with the filter's text go @@ -114,19 +114,19 @@ final class FilterComparator<T> implements Comparator<T> { str0 = arg0.toString().toLowerCase(); str1 = arg1.toString().toLowerCase(); } - + // elements that start with the filter always go first if (str0.startsWith(this.filter) && !str1.startsWith(this.filter)) return -1; else if (!str0.startsWith(this.filter) && str1.startsWith(this.filter)) return 1; - + // elements that contain the filter but don't start with them go next if (str0.contains(this.filter) && !str1.contains(this.filter)) return -1; else if (!str0.contains(this.filter) && !str1.contains(this.filter)) return 1; - + // other elements go last if (this.comparator == null) return str0.compareTo(str1); diff --git a/src/main/java/sevenUnitsGUI/GridBagBuilder.java b/src/main/java/sevenUnitsGUI/GridBagBuilder.java index 32e94d7..fdbaee7 100644 --- a/src/main/java/sevenUnitsGUI/GridBagBuilder.java +++ b/src/main/java/sevenUnitsGUI/GridBagBuilder.java @@ -30,13 +30,16 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code gridx} property. * <p> - * Specifies the cell containing the leading edge of the component's display area, where the first cell in a row has - * <code>gridx=0</code>. The leading edge of a component's display area is its left edge for a horizontal, - * left-to-right container and its right edge for a horizontal, right-to-left container. The value - * <code>RELATIVE</code> specifies that the component be placed immediately following the component that was added - * to the container just before this component was added. + * Specifies the cell containing the leading edge of the component's display + * area, where the first cell in a row has <code>gridx=0</code>. The leading + * edge of a component's display area is its left edge for a horizontal, + * left-to-right container and its right edge for a horizontal, right-to-left + * container. The value <code>RELATIVE</code> specifies that the component be + * placed immediately following the component that was added to the container + * just before this component was added. * <p> - * The default value is <code>RELATIVE</code>. <code>gridx</code> should be a non-negative value. + * The default value is <code>RELATIVE</code>. <code>gridx</code> should be a + * non-negative value. * * @serial * @see #clone() @@ -48,11 +51,13 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code gridy} property. * <p> - * Specifies the cell at the top of the component's display area, where the topmost cell has <code>gridy=0</code>. - * The value <code>RELATIVE</code> specifies that the component be placed just below the component that was added to - * the container just before this component was added. + * Specifies the cell at the top of the component's display area, where the + * topmost cell has <code>gridy=0</code>. The value <code>RELATIVE</code> + * specifies that the component be placed just below the component that was + * added to the container just before this component was added. * <p> - * The default value is <code>RELATIVE</code>. <code>gridy</code> should be a non-negative value. + * The default value is <code>RELATIVE</code>. <code>gridy</code> should be a + * non-negative value. * * @serial * @see #clone() @@ -65,9 +70,10 @@ final class GridBagBuilder { * <p> * Specifies the number of cells in a row for the component's display area. * <p> - * Use <code>REMAINDER</code> to specify that the component's display area will be from <code>gridx</code> to the - * last cell in the row. Use <code>RELATIVE</code> to specify that the component's display area will be from - * <code>gridx</code> to the next to the last one in its row. + * Use <code>REMAINDER</code> to specify that the component's display area + * will be from <code>gridx</code> to the last cell in the row. Use + * <code>RELATIVE</code> to specify that the component's display area will be + * from <code>gridx</code> to the next to the last one in its row. * <p> * <code>gridwidth</code> should be non-negative and the default value is 1. * @@ -80,13 +86,16 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code gridheight} property. * <p> - * Specifies the number of cells in a column for the component's display area. + * Specifies the number of cells in a column for the component's display + * area. * <p> - * Use <code>REMAINDER</code> to specify that the component's display area will be from <code>gridy</code> to the - * last cell in the column. Use <code>RELATIVE</code> to specify that the component's display area will be from - * <code>gridy</code> to the next to the last one in its column. + * Use <code>REMAINDER</code> to specify that the component's display area + * will be from <code>gridy</code> to the last cell in the column. Use + * <code>RELATIVE</code> to specify that the component's display area will be + * from <code>gridy</code> to the next to the last one in its column. * <p> - * <code>gridheight</code> should be a non-negative value and the default value is 1. + * <code>gridheight</code> should be a non-negative value and the default + * value is 1. * * @serial * @see #clone() @@ -99,15 +108,17 @@ final class GridBagBuilder { * <p> * Specifies how to distribute extra horizontal space. * <p> - * The grid bag layout manager calculates the weight of a column to be the maximum <code>weightx</code> of all the - * components in a column. If the resulting layout is smaller horizontally than the area it needs to fill, the extra - * space is distributed to each column in proportion to its weight. A column that has a weight of zero receives no - * extra space. + * The grid bag layout manager calculates the weight of a column to be the + * maximum <code>weightx</code> of all the components in a column. If the + * resulting layout is smaller horizontally than the area it needs to fill, + * the extra space is distributed to each column in proportion to its weight. + * A column that has a weight of zero receives no extra space. * <p> - * If all the weights are zero, all the extra space appears between the grids of the cell and the left and right - * edges. + * If all the weights are zero, all the extra space appears between the grids + * of the cell and the left and right edges. * <p> - * The default value of this field is <code>0</code>. <code>weightx</code> should be a non-negative value. + * The default value of this field is <code>0</code>. <code>weightx</code> + * should be a non-negative value. * * @serial * @see #clone() @@ -120,15 +131,17 @@ final class GridBagBuilder { * <p> * Specifies how to distribute extra vertical space. * <p> - * The grid bag layout manager calculates the weight of a row to be the maximum <code>weighty</code> of all the - * components in a row. If the resulting layout is smaller vertically than the area it needs to fill, the extra - * space is distributed to each row in proportion to its weight. A row that has a weight of zero receives no extra - * space. + * The grid bag layout manager calculates the weight of a row to be the + * maximum <code>weighty</code> of all the components in a row. If the + * resulting layout is smaller vertically than the area it needs to fill, the + * extra space is distributed to each row in proportion to its weight. A row + * that has a weight of zero receives no extra space. * <p> - * If all the weights are zero, all the extra space appears between the grids of the cell and the top and bottom - * edges. + * If all the weights are zero, all the extra space appears between the grids + * of the cell and the top and bottom edges. * <p> - * The default value of this field is <code>0</code>. <code>weighty</code> should be a non-negative value. + * The default value of this field is <code>0</code>. <code>weighty</code> + * should be a non-negative value. * * @serial * @see #clone() @@ -139,20 +152,26 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code anchor} property. * <p> - * This field is used when the component is smaller than its display area. It determines where, within the display - * area, to place the component. + * This field is used when the component is smaller than its display area. It + * determines where, within the display area, to place the component. * <p> - * There are three kinds of possible values: orientation relative, baseline relative and absolute. Orientation - * relative values are interpreted relative to the container's component orientation property, baseline relative - * values are interpreted relative to the baseline and absolute values are not. The absolute values are: - * <code>CENTER</code>, <code>NORTH</code>, <code>NORTHEAST</code>, <code>EAST</code>, <code>SOUTHEAST</code>, - * <code>SOUTH</code>, <code>SOUTHWEST</code>, <code>WEST</code>, and <code>NORTHWEST</code>. The orientation - * relative values are: <code>PAGE_START</code>, <code>PAGE_END</code>, <code>LINE_START</code>, - * <code>LINE_END</code>, <code>FIRST_LINE_START</code>, <code>FIRST_LINE_END</code>, <code>LAST_LINE_START</code> - * and <code>LAST_LINE_END</code>. The baseline relative values are: <code>BASELINE</code>, - * <code>BASELINE_LEADING</code>, <code>BASELINE_TRAILING</code>, <code>ABOVE_BASELINE</code>, - * <code>ABOVE_BASELINE_LEADING</code>, <code>ABOVE_BASELINE_TRAILING</code>, <code>BELOW_BASELINE</code>, - * <code>BELOW_BASELINE_LEADING</code>, and <code>BELOW_BASELINE_TRAILING</code>. The default value is + * There are three kinds of possible values: orientation relative, baseline + * relative and absolute. Orientation relative values are interpreted + * relative to the container's component orientation property, baseline + * relative values are interpreted relative to the baseline and absolute + * values are not. The absolute values are: <code>CENTER</code>, + * <code>NORTH</code>, <code>NORTHEAST</code>, <code>EAST</code>, + * <code>SOUTHEAST</code>, <code>SOUTH</code>, <code>SOUTHWEST</code>, + * <code>WEST</code>, and <code>NORTHWEST</code>. The orientation relative + * values are: <code>PAGE_START</code>, <code>PAGE_END</code>, + * <code>LINE_START</code>, <code>LINE_END</code>, + * <code>FIRST_LINE_START</code>, <code>FIRST_LINE_END</code>, + * <code>LAST_LINE_START</code> and <code>LAST_LINE_END</code>. The baseline + * relative values are: <code>BASELINE</code>, <code>BASELINE_LEADING</code>, + * <code>BASELINE_TRAILING</code>, <code>ABOVE_BASELINE</code>, + * <code>ABOVE_BASELINE_LEADING</code>, <code>ABOVE_BASELINE_TRAILING</code>, + * <code>BELOW_BASELINE</code>, <code>BELOW_BASELINE_LEADING</code>, and + * <code>BELOW_BASELINE_TRAILING</code>. The default value is * <code>CENTER</code>. * * @serial @@ -164,17 +183,18 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code fill} property. * <p> - * This field is used when the component's display area is larger than the component's requested size. It determines - * whether to resize the component, and if so, how. + * This field is used when the component's display area is larger than the + * component's requested size. It determines whether to resize the component, + * and if so, how. * <p> * The following values are valid for <code>fill</code>: * * <ul> * <li><code>NONE</code>: Do not resize the component. - * <li><code>HORIZONTAL</code>: Make the component wide enough to fill its display area horizontally, but do not - * change its height. - * <li><code>VERTICAL</code>: Make the component tall enough to fill its display area vertically, but do not change - * its width. + * <li><code>HORIZONTAL</code>: Make the component wide enough to fill its + * display area horizontally, but do not change its height. + * <li><code>VERTICAL</code>: Make the component tall enough to fill its + * display area vertically, but do not change its width. * <li><code>BOTH</code>: Make the component fill its display area entirely. * </ul> * <p> @@ -188,8 +208,8 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code insets} property. * <p> - * This field specifies the external padding of the component, the minimum amount of space between the component and - * the edges of its display area. + * This field specifies the external padding of the component, the minimum + * amount of space between the component and the edges of its display area. * <p> * The default value is <code>new Insets(0, 0, 0, 0)</code>. * @@ -201,8 +221,9 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code ipadx} property. * <p> - * This field specifies the internal padding of the component, how much space to add to the minimum width of the - * component. The width of the component is at least its minimum width plus <code>ipadx</code> pixels. + * This field specifies the internal padding of the component, how much space + * to add to the minimum width of the component. The width of the component + * is at least its minimum width plus <code>ipadx</code> pixels. * <p> * The default value is <code>0</code>. * @@ -215,8 +236,9 @@ final class GridBagBuilder { /** * The built {@code GridBagConstraints}'s {@code ipady} property. * <p> - * This field specifies the internal padding, that is, how much space to add to the minimum height of the component. - * The height of the component is at least its minimum height plus <code>ipady</code> pixels. + * This field specifies the internal padding, that is, how much space to add + * to the minimum height of the component. The height of the component is at + * least its minimum height plus <code>ipady</code> pixels. * <p> * The default value is 0. * @@ -227,10 +249,8 @@ final class GridBagBuilder { private int ipady; /** - * @param gridx - * x position - * @param gridy - * y position + * @param gridx x position + * @param gridy y position * @since 2018-11-30 * @since v0.1.0 */ @@ -239,31 +259,25 @@ final class GridBagBuilder { } /** - * @param gridx - * x position - * @param gridy - * y position - * @param gridwidth - * number of cells occupied horizontally - * @param gridheight - * number of cells occupied vertically + * @param gridx x position + * @param gridy y position + * @param gridwidth number of cells occupied horizontally + * @param gridheight number of cells occupied vertically * @since 2018-11-30 * @since v0.1.0 */ - public GridBagBuilder(final int gridx, final int gridy, final int gridwidth, final int gridheight) { - this(gridx, gridy, gridwidth, gridheight, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, + public GridBagBuilder(final int gridx, final int gridy, final int gridwidth, + final int gridheight) { + this(gridx, gridy, gridwidth, gridheight, 0.0, 0.0, + GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0); } /** - * @param gridx - * x position - * @param gridy - * y position - * @param gridwidth - * number of cells occupied horizontally - * @param gridheight - * number of cells occupied vertically + * @param gridx x position + * @param gridy y position + * @param gridwidth number of cells occupied horizontally + * @param gridheight number of cells occupied vertically * @param weightx * @param weighty * @param anchor @@ -274,9 +288,10 @@ final class GridBagBuilder { * @since 2018-11-30 * @since v0.1.0 */ - private GridBagBuilder(final int gridx, final int gridy, final int gridwidth, final int gridheight, - final double weightx, final double weighty, final int anchor, final int fill, final Insets insets, - final int ipadx, final int ipady) { + private GridBagBuilder(final int gridx, final int gridy, final int gridwidth, + final int gridheight, final double weightx, final double weighty, + final int anchor, final int fill, final Insets insets, final int ipadx, + final int ipady) { super(); this.gridx = gridx; this.gridy = gridy; @@ -297,8 +312,9 @@ final class GridBagBuilder { * @since v0.1.0 */ public GridBagConstraints build() { - return new GridBagConstraints(this.gridx, this.gridy, this.gridwidth, this.gridheight, this.weightx, - this.weighty, this.anchor, this.fill, this.insets, this.ipadx, this.ipady); + return new GridBagConstraints(this.gridx, this.gridy, this.gridwidth, + this.gridheight, this.weightx, this.weighty, this.anchor, this.fill, + this.insets, this.ipadx, this.ipady); } /** @@ -401,8 +417,7 @@ final class GridBagBuilder { } /** - * @param anchor - * anchor to set + * @param anchor anchor to set * @since 2018-11-30 * @since v0.1.0 */ @@ -412,8 +427,7 @@ final class GridBagBuilder { } /** - * @param fill - * fill to set + * @param fill fill to set * @since 2018-11-30 * @since v0.1.0 */ @@ -423,8 +437,7 @@ final class GridBagBuilder { } /** - * @param insets - * insets to set + * @param insets insets to set * @since 2018-11-30 * @since v0.1.0 */ @@ -434,8 +447,7 @@ final class GridBagBuilder { } /** - * @param ipadx - * ipadx to set + * @param ipadx ipadx to set * @since 2018-11-30 * @since v0.1.0 */ @@ -445,8 +457,7 @@ final class GridBagBuilder { } /** - * @param ipady - * ipady to set + * @param ipady ipady to set * @since 2018-11-30 * @since v0.1.0 */ @@ -456,8 +467,7 @@ final class GridBagBuilder { } /** - * @param weightx - * weightx to set + * @param weightx weightx to set * @since 2018-11-30 * @since v0.1.0 */ @@ -467,8 +477,7 @@ final class GridBagBuilder { } /** - * @param weighty - * weighty to set + * @param weighty weighty to set * @since 2018-11-30 * @since v0.1.0 */ diff --git a/src/main/java/sevenUnitsGUI/Main.java b/src/main/java/sevenUnitsGUI/Main.java index 998b373..ff61b3b 100644 --- a/src/main/java/sevenUnitsGUI/Main.java +++ b/src/main/java/sevenUnitsGUI/Main.java @@ -23,7 +23,7 @@ package sevenUnitsGUI; * @since 2022-04-19 */ public final class Main { - + /** * The main method that starts 7Units * @@ -34,5 +34,5 @@ public final class Main { 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 a5034c9..69f09e6 100644 --- a/src/main/java/sevenUnitsGUI/PrefixSearchRule.java +++ b/src/main/java/sevenUnitsGUI/PrefixSearchRule.java @@ -46,7 +46,7 @@ public final class PrefixSearchRule implements */ public static final PrefixSearchRule NO_PREFIXES = getUniversalRule( Set.of()); - + /** * A rule that gives every unit a common set of prefixes. * @@ -54,7 +54,7 @@ public final class PrefixSearchRule implements */ public static final PrefixSearchRule COMMON_PREFIXES = getCoherentOnlyRule( Set.of(Metric.MILLI, Metric.KILO)); - + /** * A rule that gives every unit all metric prefixes. * @@ -62,7 +62,7 @@ public final class PrefixSearchRule implements */ public static final PrefixSearchRule ALL_METRIC_PREFIXES = getCoherentOnlyRule( Metric.ALL_PREFIXES); - + /** * Gets a rule that applies the provided prefixes to coherent units only (as * defined by {@link LinearUnit#isCoherent}), except the kilogram @@ -78,7 +78,7 @@ public final class PrefixSearchRule implements return new PrefixSearchRule(prefixes, u -> u.isCoherent() && !u.getName().equals("kilogram")); } - + /** * Gets a rule that applies the provided prefixes to all units. * @@ -91,17 +91,17 @@ public final class PrefixSearchRule implements Set<UnitPrefix> prefixes) { return new PrefixSearchRule(prefixes, u -> true); } - + /** * The set of prefixes that will be applied to the unit. */ private final Set<UnitPrefix> prefixes; - + /** * Determines which units are given prefixes. */ private final Predicate<LinearUnit> prefixableUnitRule; - + /** * @param prefixes prefixes to add to units * @param prefixableUnitRule function that determines which units get @@ -114,7 +114,7 @@ public final class PrefixSearchRule implements this.prefixes = Collections.unmodifiableSet(new HashSet<>(prefixes)); this.prefixableUnitRule = prefixableUnitRule; } - + @Override public Map<String, LinearUnit> apply(Entry<String, LinearUnit> t) { final Map<String, LinearUnit> outputUnits = new HashMap<>(); @@ -129,7 +129,7 @@ public final class PrefixSearchRule implements } return Collections.unmodifiableMap(outputUnits); } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -140,7 +140,7 @@ public final class PrefixSearchRule implements return Objects.equals(this.prefixableUnitRule, other.prefixableUnitRule) && Objects.equals(this.prefixes, other.prefixes); } - + /** * @return rule that determines which units get prefixes * @since v0.4.0 @@ -149,7 +149,7 @@ public final class PrefixSearchRule implements public Predicate<LinearUnit> getPrefixableUnitRule() { return this.prefixableUnitRule; } - + /** * @return the prefixes that are applied by this rule * @since v0.4.0 @@ -158,12 +158,12 @@ public final class PrefixSearchRule implements public Set<UnitPrefix> getPrefixes() { return this.prefixes; } - + @Override public int hashCode() { return Objects.hash(this.prefixableUnitRule, this.prefixes); } - + @Override public String toString() { return "Apply the following prefixes: " + this.prefixes; diff --git a/src/main/java/sevenUnitsGUI/Presenter.java b/src/main/java/sevenUnitsGUI/Presenter.java index b129d95..eba8438 100644 --- a/src/main/java/sevenUnitsGUI/Presenter.java +++ b/src/main/java/sevenUnitsGUI/Presenter.java @@ -61,17 +61,18 @@ import sevenUnitsGUI.StandardDisplayRules.UncertaintyBased; */ public final class Presenter { /** - * The place where settings are stored. - * Both this path and its parent directory may not exist. + * The place where settings are stored. Both this path and its parent + * directory may not exist. */ - private static final Path CONFIG_FILE = userConfigDir().resolve("SevenUnits").resolve("config.txt"); + private static final Path CONFIG_FILE = userConfigDir().resolve("SevenUnits") + .resolve("config.txt"); /** The default place where units are stored. */ private static final String DEFAULT_UNITS_FILEPATH = "/unitsfile.txt"; /** The default place where dimensions are stored. */ private static final String DEFAULT_DIMENSIONS_FILEPATH = "/dimensionfile.txt"; /** The default place where exceptions are stored. */ private static final String DEFAULT_EXCEPTIONS_FILEPATH = "/metric_exceptions.txt"; - + private static final Path userConfigDir() { if (System.getProperty("os.name").startsWith("Windows")) { final String envFolder = System.getenv("LOCALAPPDATA"); @@ -116,14 +117,14 @@ public final class Presenter { // nonlinear units - must be loaded manually database.addUnit("tempCelsius", Metric.CELSIUS); database.addUnit("tempFahrenheit", BritishImperial.FAHRENHEIT); - + // load initial dimensions database.addDimension("Length", Metric.Dimensions.LENGTH); database.addDimension("Mass", Metric.Dimensions.MASS); database.addDimension("Time", Metric.Dimensions.TIME); database.addDimension("Temperature", Metric.Dimensions.TEMPERATURE); } - + /** * @return text in About file * @since 2022-02-19 @@ -133,7 +134,7 @@ public final class Presenter { .map(Presenter::withoutComments).collect(Collectors.joining("\n")) .replaceAll("\\[VERSION\\]", ProgramInfo.VERSION.toString()); } - + /** * Gets the text of a resource file as a set of strings (each one is one line * of the text). @@ -144,7 +145,7 @@ public final class Presenter { */ private static final List<String> getLinesFromResource(String filename) { final List<String> lines = new ArrayList<>(); - + try (InputStream stream = inputStream(filename); Scanner scanner = new Scanner(stream)) { while (scanner.hasNextLine()) { @@ -154,10 +155,10 @@ public final class Presenter { throw new AssertionError( "Error occurred while loading file " + filename, e); } - + return lines; } - + /** * Gets an input stream for a resource file. * @@ -168,7 +169,7 @@ public final class Presenter { private static final InputStream inputStream(String filepath) { return Presenter.class.getResourceAsStream(filepath); } - + /** * @return true iff a and b have any elements in common * @since 2022-04-19 @@ -180,7 +181,7 @@ public final class Presenter { } return false; } - + /** * @return {@code line} with any comments removed. * @since 2021-03-13 @@ -189,25 +190,25 @@ public final class Presenter { final int index = line.indexOf('#'); return index == -1 ? line : line.substring(0, index); } - + // ====== SETTINGS ====== - + /** * The view that this presenter communicates with */ private final View view; - + /** * The database that this presenter communicates with (effectively the model) */ final UnitDatabase database; - + /** * The rule used for parsing input numbers. Any number-string inputted into * this program will be parsed using this method. <b>Not implemented yet.</b> */ private Function<String, UncertainDouble> numberParsingRule; - + /** * The rule used for displaying the results of unit conversions. The result * of unit conversions will be put into this function, and the resulting @@ -215,41 +216,41 @@ public final class Presenter { */ private Function<UncertainDouble, String> numberDisplayRule = StandardDisplayRules .uncertaintyBased(); - + /** * A predicate that determines whether or not a certain combination of * prefixes is allowed. If it returns false, a combination of prefixes will * not be allowed. Prefixes are put in the list from right to left. */ private Predicate<List<UnitPrefix>> prefixRepetitionRule = DefaultPrefixRepetitionRule.NO_RESTRICTION; - + /** * A rule that accepts a prefixless name-unit pair and returns a map mapping * names to prefixed versions of that unit (including the unit itself) that * should be searchable. */ private Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> searchRule = PrefixSearchRule.NO_PREFIXES; - + /** * The set of units that is considered neither metric nor nonmetric for the * purposes of the metric-imperial one-way conversion. These units are * included in both From and To, even if One Way Conversion is enabled. */ private final Set<String> metricExceptions; - + /** * If this is true, views that show units as a list will have metric units * removed from the From unit list and imperial/USC units removed from the To * unit list. */ private boolean oneWayConversionEnabled = false; - + /** * If this is false, duplicate units and prefixes will be removed from the * unit view in views that show units as a list to choose from. */ private boolean showDuplicates = false; - + /** * Creates a Presenter * @@ -260,14 +261,14 @@ public final class Presenter { this.view = view; this.database = new UnitDatabase(); addDefaults(this.database); - + // load units and prefixes try (final InputStream units = inputStream(DEFAULT_UNITS_FILEPATH)) { this.database.loadUnitsFromStream(units); } catch (final IOException e) { throw new AssertionError("Loading of unitsfile.txt failed.", e); } - + // load dimensions try (final InputStream dimensions = inputStream( DEFAULT_DIMENSIONS_FILEPATH)) { @@ -275,7 +276,7 @@ public final class Presenter { } catch (final IOException e) { throw new AssertionError("Loading of dimensionfile.txt failed.", e); } - + // load metric exceptions try { this.metricExceptions = new HashSet<>(); @@ -293,16 +294,16 @@ public final class Presenter { throw new AssertionError("Loading of metric_exceptions.txt failed.", e); } - + // set default settings temporarily if (Files.exists(CONFIG_FILE)) { this.loadSettings(CONFIG_FILE); } - + // a Predicate that returns true iff the argument is a full base unit final Predicate<Unit> isFullBase = unit -> unit instanceof LinearUnit && ((LinearUnit) unit).isBase(); - + // print out unit counts System.out.printf( "Successfully loaded %d units with %d unit names (%d base units).%n", @@ -311,7 +312,7 @@ public final class Presenter { this.database.unitMapPrefixless(false).values().stream() .filter(isFullBase).count()); } - + /** * Applies a search rule to an entry in a name-unit map. * @@ -331,7 +332,7 @@ public final class Presenter { } else return Stream.of(e); } - + /** * Converts from the view's input expression to its output expression. * Displays an error message if any of the required fields are invalid. @@ -345,10 +346,10 @@ public final class Presenter { public void convertExpressions() { if (this.view instanceof ExpressionConversionView) { final ExpressionConversionView xcview = (ExpressionConversionView) this.view; - + final String fromExpression = xcview.getFromExpression(); final String toExpression = xcview.getToExpression(); - + // expressions must not be empty if (fromExpression.isEmpty()) { this.view.showErrorMessage("Parse Error", @@ -360,7 +361,7 @@ public final class Presenter { "Please enter a unit expression in the To: box."); return; } - + // evaluate expressions final LinearUnitValue from; final Unit to; @@ -378,11 +379,11 @@ public final class Presenter { "Could not recognize text in To entry: " + e.getMessage()); return; } - + // convert and show output if (from.getUnit().canConvertTo(to)) { final UncertainDouble uncertainValue; - + // uncertainty is meaningless for non-linear units, so we will have // to erase uncertainty information for them if (to instanceof LinearUnit) { @@ -392,7 +393,7 @@ public final class Presenter { final double value = from.asUnitValue().convertTo(to).getValue(); uncertainValue = UncertainDouble.of(value, 0); } - + final UnitConversionRecord uc = UnitConversionRecord.valueOf( fromExpression, toExpression, "", this.numberDisplayRule.apply(uncertainValue)); @@ -402,12 +403,12 @@ public final class Presenter { "Cannot convert between \"" + fromExpression + "\" and \"" + toExpression + "\"."); } - + } else throw new UnsupportedOperationException( "This function can only be called when the view is an ExpressionConversionView"); } - + /** * Converts from the view's input unit to its output unit. Displays an error * message if any of the required fields are invalid. @@ -421,11 +422,11 @@ public final class Presenter { public void convertUnits() { if (this.view instanceof UnitConversionView) { final UnitConversionView ucview = (UnitConversionView) this.view; - + final Optional<String> fromUnitOptional = ucview.getFromSelection(); final Optional<String> toUnitOptional = ucview.getToSelection(); final String inputValueString = ucview.getInputValue(); - + // extract values from optionals final String fromUnitString, toUnitString; if (fromUnitOptional.isPresent()) { @@ -442,11 +443,11 @@ public final class Presenter { "Please specify a To unit"); return; } - + // convert strings to data, checking if anything is invalid final Unit fromUnit, toUnit; final UncertainDouble uncertainValue; - + if (this.database.containsUnitName(fromUnitString)) { fromUnit = this.database.getUnit(fromUnitString); } else @@ -463,11 +464,11 @@ public final class Presenter { "Invalid value " + inputValueString); return; } - + if (!fromUnit.canConvertTo(toUnit)) throw this.viewError("Could not convert between %s and %s", fromUnit, toUnit); - + // convert - we will need to erase uncertainty for non-linear units, so // we need to treat linear and non-linear units differently final String outputValueString; @@ -477,18 +478,18 @@ public final class Presenter { final LinearUnitValue initialValue = LinearUnitValue.of(fromLinear, uncertainValue); final LinearUnitValue converted = initialValue.convertTo(toLinear); - + outputValueString = this.numberDisplayRule .apply(converted.getValue()); } else { final UnitValue initialValue = UnitValue.of(fromUnit, uncertainValue.value()); final UnitValue converted = initialValue.convertTo(toUnit); - + outputValueString = this.numberDisplayRule .apply(UncertainDouble.of(converted.getValue(), 0)); } - + ucview.showUnitConversionOutput( UnitConversionRecord.valueOf(fromUnitString, toUnitString, inputValueString, outputValueString)); @@ -496,7 +497,7 @@ public final class Presenter { throw new UnsupportedOperationException( "This function can only be called when the view is a UnitConversionView."); } - + /** * @return true iff duplicate units are shown in unit lists * @since 2022-03-30 @@ -504,7 +505,7 @@ public final class Presenter { public boolean duplicatesShown() { return this.showDuplicates; } - + /** * Gets a name for this dimension using the database * @@ -519,7 +520,7 @@ public final class Presenter { .filter(d -> d.equals(dimension)).findAny().map(Nameable::getName) .orElse(dimension.toString(Nameable::getName)); } - + /** * @return the rule that is used by this presenter to convert numbers into * strings @@ -528,7 +529,7 @@ public final class Presenter { public Function<UncertainDouble, String> getNumberDisplayRule() { return this.numberDisplayRule; } - + /** * @return the rule that is used by this presenter to convert strings into * numbers @@ -538,7 +539,7 @@ public final class Presenter { private Function<String, UncertainDouble> getNumberParsingRule() { return this.numberParsingRule; } - + /** * @return the rule that determines whether a set of prefixes is valid * @since 2022-04-19 @@ -546,7 +547,7 @@ public final class Presenter { public Predicate<List<UnitPrefix>> getPrefixRepetitionRule() { return this.prefixRepetitionRule; } - + /** * @return the rule that determines which units are prefixed * @since 2022-07-08 @@ -554,7 +555,7 @@ public final class Presenter { public Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> getSearchRule() { return this.searchRule; } - + /** * @return a search rule that shows all single prefixes * @since 2022-07-08 @@ -563,7 +564,7 @@ public final class Presenter { return PrefixSearchRule.getCoherentOnlyRule( new HashSet<>(this.database.prefixMap(true).values())); } - + /** * @return the view associated with this presenter * @since 2022-04-19 @@ -571,7 +572,7 @@ public final class Presenter { public View getView() { return this.view; } - + /** * @return whether or not the provided unit is semi-metric (i.e. an * exception) @@ -587,7 +588,7 @@ public final class Presenter { && this.metricExceptions.contains(symbol.orElseThrow()) || sharesAnyElements(this.metricExceptions, u.getOtherNames()); } - + /** * Loads settings from the user's settings file and applies them to the * presenter. @@ -616,7 +617,7 @@ public final class Presenter { break; case "prefix_rule": this.prefixRepetitionRule = DefaultPrefixRepetitionRule - .valueOf(value); + .valueOf(value); this.database.setPrefixRepetitionRule(this.prefixRepetitionRule); break; case "one_way": @@ -643,10 +644,11 @@ public final class Presenter { private List<Map.Entry<String, String>> settingsFromFile(Path settingsFile) { try (Stream<String> lines = Files.lines(settingsFile)) { return lines.map(Presenter::withoutComments) - .filter(line -> !line.isBlank()) - .map(Presenter::parseSettingLine).toList(); + .filter(line -> !line.isBlank()).map(Presenter::parseSettingLine) + .toList(); } catch (final IOException e) { - this.view.showErrorMessage("Settings Loading Error", "Error loading settings file. Using default settings."); + this.view.showErrorMessage("Settings Loading Error", + "Error loading settings file. Using default settings."); return null; } } @@ -662,7 +664,7 @@ public final class Presenter { return Map.entry(param, value); } - + private void setSearchRuleFromString(String ruleString) { switch (ruleString) { case "NO_PREFIXES": @@ -675,7 +677,9 @@ public final class Presenter { this.searchRule = PrefixSearchRule.ALL_METRIC_PREFIXES; break; default: - System.err.printf("Warning: unrecognized value for search_prefix_rule: %s\n", ruleString); + System.err.printf( + "Warning: unrecognized value for search_prefix_rule: %s\n", + ruleString); } } @@ -694,7 +698,8 @@ public final class Presenter { this.numberDisplayRule = StandardDisplayRules.uncertaintyBased(); break; default: - this.numberDisplayRule = StandardDisplayRules.getStandardRule(ruleString); + this.numberDisplayRule = StandardDisplayRules + .getStandardRule(ruleString); break; } } @@ -706,8 +711,7 @@ public final class Presenter { } catch (IOException e) { this.view.showErrorMessage("File Load Error", "Error loading configured metric exception file \"" - + exceptionFile + "\": " - + e.getLocalizedMessage()); + + exceptionFile + "\": " + e.getLocalizedMessage()); } } @@ -721,7 +725,7 @@ public final class Presenter { public boolean oneWayConversionEnabled() { return this.oneWayConversionEnabled; } - + /** * Completes creation of the presenter. This part of the initialization * depends on the view's functions, so it cannot be run if the components @@ -735,10 +739,10 @@ public final class Presenter { final UnitConversionView ucview = (UnitConversionView) this.view; ucview.setDimensionNames(this.database.dimensionMap().keySet()); } - + this.updateView(); } - + void prefixSelected() { final Optional<String> selectedPrefixName = this.view .getViewedPrefixName(); @@ -750,10 +754,10 @@ public final class Presenter { .ifPresent(prefix -> this.view.showPrefix(prefix.getNameSymbol(), String.valueOf(prefix.getMultiplier()))); } - + /** - * Saves the presenter's current settings to the config file, - * creating it if it doesn't exist. + * Saves the presenter's current settings to the config file, creating it if + * it doesn't exist. * * @return false iff the presenter could not write to the file * @since 2022-04-19 @@ -770,7 +774,7 @@ public final class Presenter { return this.writeSettings(CONFIG_FILE); } - + /** * Saves the presenter's settings to the user settings file. * @@ -798,8 +802,9 @@ public final class Presenter { return false; } } - - private static String searchRuleToString(Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> searchRule) { + + private static String searchRuleToString( + Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> searchRule) { if (PrefixSearchRule.NO_PREFIXES.equals(searchRule)) { return "NO_PREFIXES"; } else if (PrefixSearchRule.COMMON_PREFIXES.equals(searchRule)) { @@ -810,10 +815,11 @@ public final class Presenter { return searchRule.toString(); } - private static String displayRuleToString(Function<UncertainDouble, String> numberDisplayRule) { + private static String displayRuleToString( + Function<UncertainDouble, String> numberDisplayRule) { if (numberDisplayRule instanceof FixedDecimals) { return String.format("FIXED_DECIMALS %d", - ((FixedDecimals) numberDisplayRule) .decimalPlaces()); + ((FixedDecimals) numberDisplayRule).decimalPlaces()); } else if (numberDisplayRule instanceof FixedPrecision) { return String.format("FIXED_PRECISION %d", ((FixedPrecision) numberDisplayRule).significantFigures()); @@ -832,7 +838,7 @@ public final class Presenter { Function<UncertainDouble, String> numberDisplayRule) { this.numberDisplayRule = numberDisplayRule; } - + /** * @param numberParsingRule the new rule that will be used by this presenter * to convert strings into numbers @@ -843,7 +849,7 @@ public final class Presenter { Function<String, UncertainDouble> numberParsingRule) { this.numberParsingRule = numberParsingRule; } - + /** * @param oneWayConversionEnabled whether not one-way conversion should be * enabled @@ -854,7 +860,7 @@ public final class Presenter { this.oneWayConversionEnabled = oneWayConversionEnabled; this.updateView(); } - + /** * @param prefixRepetitionRule the rule that determines whether a set of * prefixes is valid @@ -865,7 +871,7 @@ public final class Presenter { this.prefixRepetitionRule = prefixRepetitionRule; this.database.setPrefixRepetitionRule(prefixRepetitionRule); } - + /** * @param searchRule A rule that accepts a prefixless name-unit pair and * returns a map mapping names to prefixed versions of that @@ -877,7 +883,7 @@ public final class Presenter { Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>> searchRule) { this.searchRule = searchRule; } - + /** * @param showDuplicateUnits whether or not duplicate units should be shown * @since 2022-03-30 @@ -886,7 +892,7 @@ public final class Presenter { this.showDuplicates = showDuplicateUnits; this.updateView(); } - + /** * Shows a unit in the unit viewer * @@ -902,7 +908,7 @@ public final class Presenter { final var unitType = UnitType.getType(u, this::isSemiMetric); this.view.showUnit(nameSymbol, definition, dimensionString, unitType); } - + /** * Runs whenever a unit name is selected in the unit viewer. Gets the * description of a unit and displays it. @@ -918,7 +924,7 @@ public final class Presenter { : null); selectedUnit.ifPresent(this::showUnit); } - + /** * Updates the view's From and To units, if it has some * @@ -928,19 +934,19 @@ public final class Presenter { if (this.view instanceof UnitConversionView) { final UnitConversionView ucview = (UnitConversionView) this.view; final var selectedDimensionName = ucview.getSelectedDimensionName(); - + // load units & prefixes into viewers this.view.setViewableUnitNames( this.database.unitMapPrefixless(this.showDuplicates).keySet()); this.view.setViewablePrefixNames( this.database.prefixMap(this.showDuplicates).keySet()); - + // get From and To units var fromUnits = this.database.unitMapPrefixless(this.showDuplicates) .entrySet().stream(); var toUnits = this.database.unitMapPrefixless(this.showDuplicates) .entrySet().stream(); - + // filter by dimension, if one is selected if (selectedDimensionName.isPresent()) { final var viewDimension = this.database @@ -950,7 +956,7 @@ public final class Presenter { toUnits = toUnits.filter( u -> viewDimension.equals(u.getValue().getDimension())); } - + // filter by unit type, if desired if (this.oneWayConversionEnabled) { fromUnits = fromUnits.filter(u -> UnitType.getType(u.getValue(), @@ -958,7 +964,7 @@ public final class Presenter { toUnits = toUnits.filter(u -> UnitType.getType(u.getValue(), this::isSemiMetric) != UnitType.NON_METRIC); } - + // set unit names ucview.setFromUnitNames(fromUnits.flatMap(this::applySearchRule) .map(Map.Entry::getKey).collect(Collectors.toSet())); @@ -966,7 +972,7 @@ public final class Presenter { .map(Map.Entry::getKey).collect(Collectors.toSet())); } } - + /** * @param message message to add * @param args string formatting arguments for message diff --git a/src/main/java/sevenUnitsGUI/SearchBoxList.java b/src/main/java/sevenUnitsGUI/SearchBoxList.java index 9b41601..8fba459 100644 --- a/src/main/java/sevenUnitsGUI/SearchBoxList.java +++ b/src/main/java/sevenUnitsGUI/SearchBoxList.java @@ -40,13 +40,13 @@ import javax.swing.JTextField; * @since v0.2.0 */ final class SearchBoxList<E> extends JPanel { - + /** * @since 2019-04-13 * @since v0.2.0 */ private static final long serialVersionUID = 6226930279415983433L; - + /** * The text to place in an empty search box. * @@ -54,7 +54,7 @@ final class SearchBoxList<E> extends JPanel { * @since v0.2.0 */ private static final String EMPTY_TEXT = "Search..."; - + /** * The color to use for an empty foreground. * @@ -62,24 +62,24 @@ final class SearchBoxList<E> extends JPanel { * @since v0.2.0 */ private static final Color EMPTY_FOREGROUND = new Color(192, 192, 192); - + // the components private final Collection<E> itemsToFilter; private final DelegateListModel<E> listModel; private final JTextField searchBox; private final JList<E> searchItems; - + private boolean searchBoxEmpty = true; - + // I need to do this because, for some reason, Swing is auto-focusing my // search box without triggering a focus // event. private boolean searchBoxFocused = false; - + private Predicate<E> customSearchFilter = o -> true; private final Comparator<E> defaultOrdering; private final boolean caseSensitive; - + /** * Creates an empty SearchBoxList * @@ -88,7 +88,7 @@ final class SearchBoxList<E> extends JPanel { public SearchBoxList() { this(List.of(), null, false); } - + /** * Creates the {@code SearchBoxList}. * @@ -98,7 +98,7 @@ final class SearchBoxList<E> extends JPanel { public SearchBoxList(final Collection<E> itemsToFilter) { this(itemsToFilter, null, false); } - + /** * Creates the {@code SearchBoxList}. * @@ -116,35 +116,35 @@ final class SearchBoxList<E> extends JPanel { this.itemsToFilter = new ArrayList<>(itemsToFilter); this.defaultOrdering = defaultOrdering; this.caseSensitive = caseSensitive; - + // create the components this.listModel = new DelegateListModel<>(new ArrayList<>(itemsToFilter)); this.searchItems = new JList<>(this.listModel); - + this.searchBox = new JTextField(EMPTY_TEXT); this.searchBox.setForeground(EMPTY_FOREGROUND); - + // add them to the panel this.add(this.searchBox, BorderLayout.PAGE_START); this.add(new JScrollPane(this.searchItems), BorderLayout.CENTER); - + // set up the search box this.searchBox.addFocusListener(new FocusListener() { @Override public void focusGained(final FocusEvent e) { SearchBoxList.this.searchBoxFocusGained(e); } - + @Override public void focusLost(final FocusEvent e) { SearchBoxList.this.searchBoxFocusLost(e); } }); - + this.searchBox.addCaretListener(e -> this.searchBoxTextChanged()); this.searchBoxEmpty = true; } - + /** * Adds an additional filter for searching. * @@ -155,7 +155,7 @@ final class SearchBoxList<E> extends JPanel { public void addSearchFilter(final Predicate<E> filter) { this.customSearchFilter = this.customSearchFilter.and(filter); } - + /** * Resets the search filter. * @@ -165,7 +165,7 @@ final class SearchBoxList<E> extends JPanel { public void clearSearchFilters() { this.customSearchFilter = o -> true; } - + /** * @return items available in search list, including items that are hidden by * the search filter @@ -174,7 +174,7 @@ final class SearchBoxList<E> extends JPanel { public Collection<E> getItems() { return Collections.unmodifiableCollection(this.itemsToFilter); } - + /** * @return this component's search box component * @since 2019-04-14 @@ -183,7 +183,7 @@ final class SearchBoxList<E> extends JPanel { public final JTextField getSearchBox() { return this.searchBox; } - + /** * @param searchText text to search for * @return a filter that filters out that text, based on this list's case @@ -198,7 +198,7 @@ final class SearchBoxList<E> extends JPanel { return item -> item.toString().toLowerCase() .contains(searchText.toLowerCase()); } - + /** * @return this component's list component * @since 2019-04-14 @@ -207,7 +207,7 @@ final class SearchBoxList<E> extends JPanel { public final JList<E> getSearchList() { return this.searchItems; } - + /** * @return index selected in item list, -1 if no selection * @since 2019-04-14 @@ -216,7 +216,7 @@ final class SearchBoxList<E> extends JPanel { public int getSelectedIndex() { return this.searchItems.getSelectedIndex(); } - + /** * @return value selected in item list * @since 2019-04-13 @@ -225,7 +225,7 @@ final class SearchBoxList<E> extends JPanel { public Optional<E> getSelectedValue() { return Optional.ofNullable(this.searchItems.getSelectedValue()); } - + /** * Re-applies the filters. * @@ -238,21 +238,21 @@ final class SearchBoxList<E> extends JPanel { final FilterComparator<E> comparator = new FilterComparator<>(searchText, this.defaultOrdering, this.caseSensitive); final Predicate<E> searchFilter = this.getSearchFilter(searchText); - + this.listModel.clear(); this.itemsToFilter.forEach(item -> { if (searchFilter.test(item)) { this.listModel.add(item); } }); - + // applies the custom filters this.listModel.removeIf(this.customSearchFilter.negate()); - + // sorts the remaining items this.listModel.sort(comparator); } - + /** * Runs whenever the search box gains focus. * @@ -267,7 +267,7 @@ final class SearchBoxList<E> extends JPanel { this.searchBox.setForeground(Color.BLACK); } } - + /** * Runs whenever the search box loses focus. * @@ -282,7 +282,7 @@ final class SearchBoxList<E> extends JPanel { this.searchBox.setForeground(EMPTY_FOREGROUND); } } - + /** * Runs whenever the text in the search box is changed. * <p> @@ -301,7 +301,7 @@ final class SearchBoxList<E> extends JPanel { final FilterComparator<E> comparator = new FilterComparator<>(searchText, this.defaultOrdering, this.caseSensitive); final Predicate<E> searchFilter = this.getSearchFilter(searchText); - + // initialize list with items that match the filter then sort this.listModel.clear(); this.itemsToFilter.forEach(string -> { @@ -309,14 +309,14 @@ final class SearchBoxList<E> extends JPanel { this.listModel.add(string); } }); - + // applies the custom filters this.listModel.removeIf(this.customSearchFilter.negate()); - + // sorts the remaining items this.listModel.sort(comparator); } - + /** * Resets the search box list's contents to the provided items, removing any * old items @@ -329,7 +329,7 @@ final class SearchBoxList<E> extends JPanel { this.itemsToFilter.addAll(newItems); this.reapplyFilter(); } - + /** * Manually updates the search box's item list. * diff --git a/src/main/java/sevenUnitsGUI/StandardDisplayRules.java b/src/main/java/sevenUnitsGUI/StandardDisplayRules.java index cc69d31..d00263b 100644 --- a/src/main/java/sevenUnitsGUI/StandardDisplayRules.java +++ b/src/main/java/sevenUnitsGUI/StandardDisplayRules.java @@ -46,7 +46,7 @@ public final class StandardDisplayRules { * The number of places to round to. */ private final int decimalPlaces; - + /** * @param decimalPlaces * @since 2022-04-18 @@ -54,14 +54,14 @@ public final class StandardDisplayRules { private FixedDecimals(int decimalPlaces) { this.decimalPlaces = decimalPlaces; } - + @Override public String apply(UncertainDouble t) { final var toRound = new BigDecimal(t.value()); return toRound.setScale(this.decimalPlaces, RoundingMode.HALF_EVEN) .toPlainString(); } - + /** * @return the number of decimal places this rule rounds to * @since 2022-04-18 @@ -69,7 +69,7 @@ public final class StandardDisplayRules { public int decimalPlaces() { return this.decimalPlaces; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -81,18 +81,18 @@ public final class StandardDisplayRules { return false; return true; } - + @Override public int hashCode() { return 31 + this.decimalPlaces; } - + @Override public String toString() { return "Round to " + this.decimalPlaces + " decimal places"; } } - + /** * A rule that rounds to a fixed number of significant digits. * @@ -103,12 +103,12 @@ public final class StandardDisplayRules { implements Function<UncertainDouble, String> { public static final Pattern TO_STRING_PATTERN = Pattern .compile("Round to (\\d+) significant figures"); - + /** * The number of significant figures to round to. */ private final MathContext mathContext; - + /** * @param significantFigures * @since 2022-04-18 @@ -117,13 +117,13 @@ public final class StandardDisplayRules { this.mathContext = new MathContext(significantFigures, RoundingMode.HALF_EVEN); } - + @Override public String apply(UncertainDouble t) { final var toRound = new BigDecimal(t.value()); return toRound.round(this.mathContext).toString(); } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -138,13 +138,13 @@ public final class StandardDisplayRules { return false; return true; } - + @Override public int hashCode() { return 127 + (this.mathContext == null ? 0 : this.mathContext.hashCode()); } - + /** * @return the number of significant figures this rule rounds to * @since 2022-04-18 @@ -152,14 +152,14 @@ public final class StandardDisplayRules { public int significantFigures() { return this.mathContext.getPrecision(); } - + @Override public String toString() { return "Round to " + this.mathContext.getPrecision() + " significant figures"; } } - + /** * A rounding rule that rounds based on UncertainDouble's toString method. * This means the output will have around as many significant figures as the @@ -170,25 +170,26 @@ public final class StandardDisplayRules { */ public static final class UncertaintyBased implements Function<UncertainDouble, String> { - private UncertaintyBased() {} - + private UncertaintyBased() { + } + @Override public String apply(UncertainDouble t) { return t.toString(false, RoundingMode.HALF_EVEN); } - + @Override public String toString() { return "Uncertainty-Based Rounding"; } } - + /** * For now, I want this to be a singleton. I might want to add a parameter * later, so I won't make it an enum. */ private static final UncertaintyBased UNCERTAINTY_BASED_ROUNDING_RULE = new UncertaintyBased(); - + /** * @param decimalPlaces decimal places to round to * @return a rounding rule that rounds to fixed number of decimal places @@ -198,7 +199,7 @@ public final class StandardDisplayRules { public static final FixedDecimals fixedDecimals(int decimalPlaces) { return new FixedDecimals(decimalPlaces); } - + /** * @param significantFigures significant figures to round to * @return a rounding rule that rounds to a fixed number of significant @@ -209,7 +210,7 @@ public final class StandardDisplayRules { public static final FixedPrecision fixedPrecision(int significantFigures) { return new FixedPrecision(significantFigures); } - + /** * Gets one of the standard rules from its string representation. * @@ -224,23 +225,23 @@ public final class StandardDisplayRules { String ruleToString) { if (UNCERTAINTY_BASED_ROUNDING_RULE.toString().equals(ruleToString)) return UNCERTAINTY_BASED_ROUNDING_RULE; - + // test if it is a fixed-places rule final var placesMatch = FixedDecimals.TO_STRING_PATTERN .matcher(ruleToString); if (placesMatch.matches()) return new FixedDecimals(Integer.valueOf(placesMatch.group(1))); - + // test if it is a fixed-sig-fig rule final var sigFigMatch = FixedPrecision.TO_STRING_PATTERN .matcher(ruleToString); if (sigFigMatch.matches()) return new FixedPrecision(Integer.valueOf(sigFigMatch.group(1))); - + throw new IllegalArgumentException( "Provided string does not match any given rules."); } - + /** * @return an UncertainDouble-based rounding rule * @since v0.4.0 @@ -249,6 +250,7 @@ public final class StandardDisplayRules { public static final UncertaintyBased uncertaintyBased() { return UNCERTAINTY_BASED_ROUNDING_RULE; } - - private StandardDisplayRules() {} + + private StandardDisplayRules() { + } } diff --git a/src/main/java/sevenUnitsGUI/TabbedView.java b/src/main/java/sevenUnitsGUI/TabbedView.java index 6181eae..997acc3 100644 --- a/src/main/java/sevenUnitsGUI/TabbedView.java +++ b/src/main/java/sevenUnitsGUI/TabbedView.java @@ -78,7 +78,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { */ private static final class JComboBoxItemSet<E> extends AbstractSet<E> { private final JComboBox<E> comboBox; - + /** * @param comboBox combo box to get items from * @since 2022-02-19 @@ -86,17 +86,17 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { public JComboBoxItemSet(JComboBox<E> comboBox) { this.comboBox = comboBox; } - + @Override public Iterator<E> iterator() { return new Iterator<>() { private int index = 0; - + @Override public boolean hasNext() { return this.index < JComboBoxItemSet.this.size(); } - + @Override public E next() { if (this.hasNext()) @@ -107,14 +107,14 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { } }; } - + @Override public int size() { return this.comboBox.getItemCount(); } - + } - + /** * The standard types of rounding, corresponding to the options on the * TabbedView's settings panel. @@ -139,7 +139,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { */ UNCERTAINTY; } - + /** * Creates a TabbedView. * @@ -153,14 +153,14 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { @SuppressWarnings("unused") final View view = new TabbedView(); } - + /** The Presenter that handles this View */ final Presenter presenter; /** The frame that this view lives on */ final JFrame frame; /** The tabbed pane that contains all of the components */ final JTabbedPane masterPane; - + // DIMENSION-BASED CONVERTER /** The combo box that selects dimensions */ final JComboBox<String> dimensionSelector; @@ -174,7 +174,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { final JButton convertUnitButton; /** The output area in the dimension-based converter */ final JTextArea unitOutput; - + // EXPRESSION-BASED CONVERTER /** The "From" entry in the conversion panel */ final JTextField fromEntry; @@ -184,7 +184,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { final JButton convertExpressionButton; /** The output area in the conversion panel */ final JTextArea expressionOutput; - + // UNIT AND PREFIX VIEWERS /** The searchable list of unit names in the unit viewer */ private final SearchBoxList<String> unitNameList; @@ -194,11 +194,11 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { private final JTextArea unitTextBox; /** The text box for prefix data in the prefix viewer */ private final JTextArea prefixTextBox; - + // SETTINGS STUFF private StandardRoundingType roundingType; private int precision; - + /** * Creates the view and makes it visible to the user * @@ -215,161 +215,161 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { System.err.println("Failed to enable system look-and-feel."); e.printStackTrace(); } - + // initialize important components this.presenter = new Presenter(this); this.frame = new JFrame("7Units " + ProgramInfo.VERSION); this.frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - + // master components (those that contain everything else within them) this.masterPane = new JTabbedPane(); this.frame.add(this.masterPane); - + // ============ UNIT CONVERSION TAB ============ final JPanel convertUnitPanel = new JPanel(); this.masterPane.addTab("Convert Units", convertUnitPanel); this.masterPane.setMnemonicAt(0, KeyEvent.VK_U); convertUnitPanel.setLayout(new BorderLayout()); - + { // panel for input part final JPanel inputPanel = new JPanel(); convertUnitPanel.add(inputPanel, BorderLayout.CENTER); inputPanel.setLayout(new GridLayout(1, 3)); inputPanel.setBorder(new EmptyBorder(6, 6, 3, 6)); - + this.fromSearch = new SearchBoxList<>(); inputPanel.add(this.fromSearch); - + final JPanel inBetweenPanel = new JPanel(); inputPanel.add(inBetweenPanel); inBetweenPanel.setLayout(new BorderLayout()); - + this.dimensionSelector = new JComboBox<>(); inBetweenPanel.add(this.dimensionSelector, BorderLayout.PAGE_START); this.dimensionSelector .addItemListener(e -> this.presenter.updateView()); - + final JLabel arrowLabel = new JLabel("-->"); inBetweenPanel.add(arrowLabel, BorderLayout.CENTER); arrowLabel.setHorizontalAlignment(SwingConstants.CENTER); - + this.toSearch = new SearchBoxList<>(); inputPanel.add(this.toSearch); } - + { // panel for submit and output, and also value entry final JPanel outputPanel = new JPanel(); convertUnitPanel.add(outputPanel, BorderLayout.PAGE_END); outputPanel.setLayout(new BorderLayout()); outputPanel.setBorder(new EmptyBorder(3, 6, 6, 6)); - + final JLabel valuePrompt = new JLabel("Value to convert: "); outputPanel.add(valuePrompt, BorderLayout.LINE_START); - + this.valueInput = new JTextField(); outputPanel.add(this.valueInput, BorderLayout.CENTER); - + // conversion button this.convertUnitButton = new JButton("Convert"); outputPanel.add(this.convertUnitButton, BorderLayout.LINE_END); this.convertUnitButton .addActionListener(e -> this.presenter.convertUnits()); this.convertUnitButton.setMnemonic(KeyEvent.VK_ENTER); - + // conversion output this.unitOutput = new JTextArea(2, 32); outputPanel.add(this.unitOutput, BorderLayout.PAGE_END); this.unitOutput.setEditable(false); } - + // ============ EXPRESSION CONVERSION TAB ============ final JPanel convertExpressionPanel = new JPanel(); this.masterPane.addTab("Convert Unit Expressions", convertExpressionPanel); this.masterPane.setMnemonicAt(1, KeyEvent.VK_E); convertExpressionPanel.setLayout(new GridLayout(4, 1)); - + // from and to expressions this.fromEntry = new JTextField(); convertExpressionPanel.add(this.fromEntry); this.fromEntry.setBorder(BorderFactory.createTitledBorder("From")); - + this.toEntry = new JTextField(); convertExpressionPanel.add(this.toEntry); this.toEntry.setBorder(BorderFactory.createTitledBorder("To")); - + // button to convert this.convertExpressionButton = new JButton("Convert"); convertExpressionPanel.add(this.convertExpressionButton); - + this.convertExpressionButton .addActionListener(e -> this.presenter.convertExpressions()); this.convertExpressionButton.setMnemonic(KeyEvent.VK_ENTER); - + // output of conversion this.expressionOutput = new JTextArea(2, 32); convertExpressionPanel.add(this.expressionOutput); this.expressionOutput .setBorder(BorderFactory.createTitledBorder("Output")); this.expressionOutput.setEditable(false); - + // =========== UNIT VIEWER =========== final JPanel unitLookupPanel = new JPanel(); this.masterPane.addTab("Unit Viewer", unitLookupPanel); this.masterPane.setMnemonicAt(2, KeyEvent.VK_V); unitLookupPanel.setLayout(new GridLayout()); - + this.unitNameList = new SearchBoxList<>(); unitLookupPanel.add(this.unitNameList); this.unitNameList.getSearchList() .addListSelectionListener(e -> this.presenter.unitNameSelected()); - + // the text box for unit's toString this.unitTextBox = new JTextArea(); unitLookupPanel.add(this.unitTextBox); this.unitTextBox.setEditable(false); this.unitTextBox.setLineWrap(true); - + // ============ PREFIX VIEWER ============= final JPanel prefixLookupPanel = new JPanel(); this.masterPane.addTab("Prefix Viewer", prefixLookupPanel); this.masterPane.setMnemonicAt(3, KeyEvent.VK_P); prefixLookupPanel.setLayout(new GridLayout(1, 2)); - + this.prefixNameList = new SearchBoxList<>(); prefixLookupPanel.add(this.prefixNameList); this.prefixNameList.getSearchList() .addListSelectionListener(e -> this.presenter.prefixSelected()); - + // the text box for prefix's toString this.prefixTextBox = new JTextArea(); prefixLookupPanel.add(this.prefixTextBox); this.prefixTextBox.setEditable(false); this.prefixTextBox.setLineWrap(true); - + // ============ INFO PANEL ============ - + final JPanel infoPanel = new JPanel(); this.masterPane.addTab("\uD83D\uDEC8", // info (i) character new JScrollPane(infoPanel)); - + final JTextArea infoTextArea = new JTextArea(); infoTextArea.setEditable(false); infoTextArea.setOpaque(false); infoPanel.add(infoTextArea); infoTextArea.setText(Presenter.getAboutText()); - + // ============ SETTINGS PANEL ============ this.masterPane.addTab("\u2699", new JScrollPane(this.createSettingsPanel())); this.masterPane.setMnemonicAt(5, KeyEvent.VK_S); - + // ============ FINALIZE CREATION OF VIEW ============ this.presenter.postViewInitialize(); this.frame.pack(); this.frame.setVisible(true); } - + /** * Creates and returns the settings panel (in its own function to make this * code more organized, as this function is massive!) @@ -378,28 +378,28 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { */ private JPanel createSettingsPanel() { final JPanel settingsPanel = new JPanel(); - + settingsPanel .setLayout(new BoxLayout(settingsPanel, BoxLayout.PAGE_AXIS)); - + // ============ ROUNDING SETTINGS ============ { final JPanel roundingPanel = new JPanel(); settingsPanel.add(roundingPanel); roundingPanel.setBorder(new TitledBorder("Rounding Settings")); roundingPanel.setLayout(new GridBagLayout()); - + // rounding rule selection final ButtonGroup roundingRuleButtons = new ButtonGroup(); this.roundingType = this.getPresenterRoundingType() .orElseThrow(() -> new AssertionError( "Presenter loaded non-standard rounding rule")); this.precision = this.getPresenterPrecision().orElse(6); - + final JLabel roundingRuleLabel = new JLabel("Rounding Rule:"); roundingPanel.add(roundingRuleLabel, new GridBagBuilder(0, 0) .setAnchor(GridBagConstraints.LINE_START).build()); - + // sigDigSlider needs to be first so that the rounding-type buttons can // show and hide it final JLabel sliderLabel = new JLabel("Precision:"); @@ -407,26 +407,26 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { this.roundingType != StandardRoundingType.UNCERTAINTY); roundingPanel.add(sliderLabel, new GridBagBuilder(0, 4) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JSlider sigDigSlider = new JSlider(0, 12); roundingPanel.add(sigDigSlider, new GridBagBuilder(0, 5) .setAnchor(GridBagConstraints.LINE_START).build()); - + sigDigSlider.setMajorTickSpacing(4); sigDigSlider.setMinorTickSpacing(1); sigDigSlider.setSnapToTicks(true); sigDigSlider.setPaintTicks(true); sigDigSlider.setPaintLabels(true); - + sigDigSlider.setVisible( this.roundingType != StandardRoundingType.UNCERTAINTY); sigDigSlider.setValue(this.precision); - + sigDigSlider.addChangeListener(e -> { this.precision = sigDigSlider.getValue(); this.updatePresenterRoundingRule(); }); - + // significant digit rounding final JRadioButton fixedPrecision = new JRadioButton( "Fixed Precision"); @@ -442,7 +442,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { roundingRuleButtons.add(fixedPrecision); roundingPanel.add(fixedPrecision, new GridBagBuilder(0, 1) .setAnchor(GridBagConstraints.LINE_START).build()); - + // decimal place rounding final JRadioButton fixedDecimals = new JRadioButton( "Fixed Decimal Places"); @@ -458,7 +458,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { roundingRuleButtons.add(fixedDecimals); roundingPanel.add(fixedDecimals, new GridBagBuilder(0, 2) .setAnchor(GridBagConstraints.LINE_START).build()); - + // scientific rounding final JRadioButton relativePrecision = new JRadioButton( "Uncertainty-Based Rounding"); @@ -475,7 +475,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { roundingPanel.add(relativePrecision, new GridBagBuilder(0, 3) .setAnchor(GridBagConstraints.LINE_START).build()); } - + // ============ PREFIX REPETITION SETTINGS ============ { final JPanel prefixRepetitionPanel = new JPanel(); @@ -483,14 +483,14 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { prefixRepetitionPanel .setBorder(new TitledBorder("Prefix Repetition Settings")); prefixRepetitionPanel.setLayout(new GridBagLayout()); - + final var prefixRule = this.getPresenterPrefixRule() .orElseThrow(() -> new AssertionError( "Presenter loaded non-standard prefix rule")); - + // prefix rules final ButtonGroup prefixRuleButtons = new ButtonGroup(); - + final JRadioButton noRepetition = new JRadioButton("No Repetition"); if (prefixRule == DefaultPrefixRepetitionRule.NO_REPETITION) { noRepetition.setSelected(true); @@ -503,7 +503,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { prefixRuleButtons.add(noRepetition); prefixRepetitionPanel.add(noRepetition, new GridBagBuilder(0, 0) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JRadioButton noRestriction = new JRadioButton("No Restriction"); if (prefixRule == DefaultPrefixRepetitionRule.NO_RESTRICTION) { noRestriction.setSelected(true); @@ -516,7 +516,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { prefixRuleButtons.add(noRestriction); prefixRepetitionPanel.add(noRestriction, new GridBagBuilder(0, 1) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JRadioButton customRepetition = new JRadioButton( "Complex Repetition"); if (prefixRule == DefaultPrefixRepetitionRule.COMPLEX_REPETITION) { @@ -531,19 +531,19 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { prefixRepetitionPanel.add(customRepetition, new GridBagBuilder(0, 2) .setAnchor(GridBagConstraints.LINE_START).build()); } - + // ============ SEARCH SETTINGS ============ { final JPanel searchingPanel = new JPanel(); settingsPanel.add(searchingPanel); searchingPanel.setBorder(new TitledBorder("Search Settings")); searchingPanel.setLayout(new GridBagLayout()); - + // searching rules final ButtonGroup searchRuleButtons = new ButtonGroup(); - + final var searchRule = this.presenter.getSearchRule(); - + final JRadioButton noPrefixes = new JRadioButton( "Never Include Prefixed Units"); noPrefixes.addActionListener(e -> { @@ -554,7 +554,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { searchRuleButtons.add(noPrefixes); searchingPanel.add(noPrefixes, new GridBagBuilder(0, 0) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JRadioButton commonPrefixes = new JRadioButton( "Include Common Prefixes"); commonPrefixes.addActionListener(e -> { @@ -565,7 +565,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { searchRuleButtons.add(commonPrefixes); searchingPanel.add(commonPrefixes, new GridBagBuilder(0, 1) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JRadioButton alwaysInclude = new JRadioButton( "Include All Single Prefixes"); alwaysInclude.addActionListener(e -> { @@ -577,7 +577,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { searchRuleButtons.add(alwaysInclude); searchingPanel.add(alwaysInclude, new GridBagBuilder(0, 3) .setAnchor(GridBagConstraints.LINE_START).build()); - + if (PrefixSearchRule.NO_PREFIXES.equals(searchRule)) { noPrefixes.setSelected(true); } else if (PrefixSearchRule.COMMON_PREFIXES.equals(searchRule)) { @@ -589,13 +589,13 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { this.presenter.saveSettings(); } } - + // ============ OTHER SETTINGS ============ { final JPanel miscPanel = new JPanel(); settingsPanel.add(miscPanel); miscPanel.setLayout(new GridBagLayout()); - + final JCheckBox oneWay = new JCheckBox("Convert One Way Only"); oneWay.setSelected(this.presenter.oneWayConversionEnabled()); oneWay.addItemListener(e -> { @@ -605,7 +605,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { }); miscPanel.add(oneWay, new GridBagBuilder(0, 0) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JCheckBox showAllVariations = new JCheckBox( "Show Duplicate Units & Prefixes"); showAllVariations.setSelected(this.presenter.duplicatesShown()); @@ -616,49 +616,49 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { }); miscPanel.add(showAllVariations, new GridBagBuilder(0, 1) .setAnchor(GridBagConstraints.LINE_START).build()); - + final JButton unitFileButton = new JButton("Manage Unit Data Files"); unitFileButton.setEnabled(false); miscPanel.add(unitFileButton, new GridBagBuilder(0, 2) .setAnchor(GridBagConstraints.LINE_START).build()); } - + return settingsPanel; } - + @Override public Set<String> getDimensionNames() { return Collections .unmodifiableSet(new JComboBoxItemSet<>(this.dimensionSelector)); } - + @Override public String getFromExpression() { return this.fromEntry.getText(); } - + @Override public Optional<String> getFromSelection() { return this.fromSearch.getSelectedValue(); } - + @Override public Set<String> getFromUnitNames() { // this should work because the only way I can mutate the item list is // with setFromUnits which only accepts a Set return new HashSet<>(this.fromSearch.getItems()); } - + @Override public String getInputValue() { return this.valueInput.getText(); } - + @Override public Presenter getPresenter() { return this.presenter; } - + /** * @return the precision of the presenter's rounding rule, if that is * meaningful @@ -678,7 +678,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { else return OptionalInt.empty(); } - + /** * @return presenter's prefix repetition rule * @since v0.4.0 @@ -690,7 +690,7 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { ? Optional.of((DefaultPrefixRepetitionRule) prefixRule) : Optional.empty(); } - + /** * Determines which rounding type the presenter is currently using, if any. * @@ -709,41 +709,41 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { else return Optional.empty(); } - + @Override public Optional<String> getSelectedDimensionName() { final String selectedItem = (String) this.dimensionSelector .getSelectedItem(); return Optional.ofNullable(selectedItem); } - + @Override public String getToExpression() { return this.toEntry.getText(); } - + @Override public Optional<String> getToSelection() { return this.toSearch.getSelectedValue(); } - + @Override public Set<String> getToUnitNames() { // this should work because the only way I can mutate the item list is // with setToUnits which only accepts a Set return new HashSet<>(this.toSearch.getItems()); } - + @Override public Optional<String> getViewedPrefixName() { return this.prefixNameList.getSelectedValue(); } - + @Override public Optional<String> getViewedUnitName() { return this.unitNameList.getSelectedValue(); } - + @Override public void setDimensionNames(Set<String> dimensionNames) { this.dimensionSelector.removeAllItems(); @@ -751,45 +751,45 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { this.dimensionSelector.addItem(d); } } - + @Override public void setFromUnitNames(Set<String> units) { this.fromSearch.setItems(units); } - + @Override public void setToUnitNames(Set<String> units) { this.toSearch.setItems(units); } - + @Override public void setViewablePrefixNames(Set<String> prefixNames) { this.prefixNameList.setItems(prefixNames); } - + @Override public void setViewableUnitNames(Set<String> unitNames) { this.unitNameList.setItems(unitNames); } - + @Override public void showErrorMessage(String title, String message) { JOptionPane.showMessageDialog(this.frame, message, title, JOptionPane.ERROR_MESSAGE); } - + @Override public void showExpressionConversionOutput(UnitConversionRecord uc) { this.expressionOutput.setText(String.format("%s = %s %s", uc.fromName(), uc.outputValueString(), uc.toName())); } - + @Override public void showPrefix(NameSymbol name, String multiplierString) { this.prefixTextBox.setText( String.format("%s%nMultiplier: %s", name, multiplierString)); } - + @Override public void showUnit(NameSymbol name, String definition, String dimensionName, UnitType type) { @@ -797,12 +797,12 @@ final class TabbedView implements ExpressionConversionView, UnitConversionView { String.format("%s%nDefinition: %s%nDimension: %s%nType: %s", name, definition, dimensionName, type)); } - + @Override public void showUnitConversionOutput(UnitConversionRecord uc) { this.unitOutput.setText(uc.toString()); } - + /** * Sets the presenter's rounding rule to the one specified by the current * settings diff --git a/src/main/java/sevenUnitsGUI/UnitConversionRecord.java b/src/main/java/sevenUnitsGUI/UnitConversionRecord.java index fa64ee9..43a62e6 100644 --- a/src/main/java/sevenUnitsGUI/UnitConversionRecord.java +++ b/src/main/java/sevenUnitsGUI/UnitConversionRecord.java @@ -44,7 +44,7 @@ public final class UnitConversionRecord { input.getValue().toString(false, RoundingMode.HALF_EVEN), output.getValue().toString(false, RoundingMode.HALF_EVEN)); } - + /** * Gets a {@code UnitConversionRecord} from two unit values * @@ -60,7 +60,7 @@ public final class UnitConversionRecord { output.getUnit().getName(), String.valueOf(input.getValue()), String.valueOf(output.getValue())); } - + /** * Gets a {@code UnitConversionRecord} * @@ -78,7 +78,7 @@ public final class UnitConversionRecord { return new UnitConversionRecord(fromName, toName, inputValueString, outputValueString); } - + /** * The name of the unit or expression that was converted from */ @@ -87,7 +87,7 @@ public final class UnitConversionRecord { * The name of the unit or expression that was converted to */ private final String toName; - + /** * A string representing the input value. It doesn't need to be the same as * the input value's string representation; it could be rounded, for example. @@ -98,7 +98,7 @@ public final class UnitConversionRecord { * the input value's string representation; it could be rounded, for example. */ private final String outputValueString; - + /** * @param fromName name of unit or expression that was converted * from @@ -114,7 +114,7 @@ public final class UnitConversionRecord { this.inputValueString = inputValueString; this.outputValueString = outputValueString; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -144,7 +144,7 @@ public final class UnitConversionRecord { return false; return true; } - + /** * @return name of unit or expression that was converted from * @since v0.4.0 @@ -153,7 +153,7 @@ public final class UnitConversionRecord { public String fromName() { return this.fromName; } - + @Override public int hashCode() { final int prime = 31; @@ -168,7 +168,7 @@ public final class UnitConversionRecord { + (this.toName == null ? 0 : this.toName.hashCode()); return result; } - + /** * @return string representing input value * @since v0.4.0 @@ -177,7 +177,7 @@ public final class UnitConversionRecord { public String inputValueString() { return this.inputValueString; } - + /** * @return string representing output value * @since v0.4.0 @@ -186,7 +186,7 @@ public final class UnitConversionRecord { public String outputValueString() { return this.outputValueString; } - + /** * @return name of unit or expression that was converted to * @since v0.4.0 @@ -195,7 +195,7 @@ public final class UnitConversionRecord { public String toName() { return this.toName; } - + @Override public String toString() { final String inputString = this.inputValueString.isBlank() ? this.fromName diff --git a/src/main/java/sevenUnitsGUI/UnitConversionView.java b/src/main/java/sevenUnitsGUI/UnitConversionView.java index 0d07823..b9077f7 100644 --- a/src/main/java/sevenUnitsGUI/UnitConversionView.java +++ b/src/main/java/sevenUnitsGUI/UnitConversionView.java @@ -33,21 +33,21 @@ public interface UnitConversionView extends View { * @since 2022-01-29 */ Set<String> getDimensionNames(); - + /** * @return name of unit to convert <em>from</em> * @since v0.4.0 * @since 2021-12-15 */ Optional<String> getFromSelection(); - + /** * @return list of names of units available to convert from * @since v0.4.0 * @since 2022-03-30 */ Set<String> getFromUnitNames(); - + /** * @return value to convert between the units (specifically, the numeric * string provided by the user) @@ -55,28 +55,28 @@ public interface UnitConversionView extends View { * @since 2021-12-15 */ String getInputValue(); - + /** * @return selected dimension * @since v0.4.0 * @since 2021-12-15 */ Optional<String> getSelectedDimensionName(); - + /** * @return name of unit to convert <em>to</em> * @since v0.4.0 * @since 2021-12-15 */ Optional<String> getToSelection(); - + /** * @return list of names of units available to convert to * @since v0.4.0 * @since 2022-03-30 */ Set<String> getToUnitNames(); - + /** * Sets the available dimensions for filtering. * @@ -85,7 +85,7 @@ public interface UnitConversionView extends View { * @since 2021-12-15 */ void setDimensionNames(Set<String> dimensionNames); - + /** * Sets the available units to convert from. {@link #getFromSelection} is not * required to use one of these units; this method is to be used for views @@ -96,7 +96,7 @@ public interface UnitConversionView extends View { * @since 2021-12-15 */ void setFromUnitNames(Set<String> unitNames); - + /** * Sets the available units to convert to. {@link #getToSelection} is not * required to use one of these units; this method is to be used for views @@ -107,7 +107,7 @@ public interface UnitConversionView extends View { * @since 2021-12-15 */ void setToUnitNames(Set<String> unitNames); - + /** * Shows the output of a unit conversion. * diff --git a/src/main/java/sevenUnitsGUI/View.java b/src/main/java/sevenUnitsGUI/View.java index bb810ec..7dd0c44 100644 --- a/src/main/java/sevenUnitsGUI/View.java +++ b/src/main/java/sevenUnitsGUI/View.java @@ -38,28 +38,28 @@ public interface View { static View createTabbedView() { return new TabbedView(); } - + /** * @return the presenter associated with this view * @since v0.4.0 * @since 2022-04-19 */ Presenter getPresenter(); - + /** * @return name of prefix currently being viewed * @since v0.4.0 * @since 2022-04-10 */ Optional<String> getViewedPrefixName(); - + /** * @return name of unit currently being viewed * @since v0.4.0 * @since 2022-04-10 */ Optional<String> getViewedUnitName(); - + /** * Sets the list of prefixes that are available to be viewed in a prefix * viewer @@ -69,7 +69,7 @@ public interface View { * @since 2022-04-10 */ void setViewablePrefixNames(Set<String> prefixNames); - + /** * Sets the list of units that are available to be viewed in a unit viewer * @@ -78,7 +78,7 @@ public interface View { * @since 2022-04-10 */ void setViewableUnitNames(Set<String> unitNames); - + /** * Shows an error message. * @@ -89,7 +89,7 @@ public interface View { * @since 2021-12-15 */ void showErrorMessage(String title, String message); - + /** * Shows information about a prefix to the user. * @@ -99,7 +99,7 @@ public interface View { * @since 2022-04-10 */ void showPrefix(NameSymbol name, String multiplierString); - + /** * Shows information about a unit to the user. * diff --git a/src/main/java/sevenUnitsGUI/ViewBot.java b/src/main/java/sevenUnitsGUI/ViewBot.java index e7304c4..e6593fb 100644 --- a/src/main/java/sevenUnitsGUI/ViewBot.java +++ b/src/main/java/sevenUnitsGUI/ViewBot.java @@ -46,7 +46,7 @@ public final class ViewBot public static final class PrefixViewingRecord implements Nameable { private final NameSymbol nameSymbol; private final String multiplierString; - + /** * @param nameSymbol * @param multiplierString @@ -57,7 +57,7 @@ public final class ViewBot this.nameSymbol = nameSymbol; this.multiplierString = multiplierString; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -68,25 +68,25 @@ public final class ViewBot return Objects.equals(this.multiplierString, other.multiplierString) && Objects.equals(this.nameSymbol, other.nameSymbol); } - + @Override public NameSymbol getNameSymbol() { return this.nameSymbol; } - + @Override public int hashCode() { return Objects.hash(this.multiplierString, this.nameSymbol); } - + public String multiplierString() { return this.multiplierString; } - + public NameSymbol nameSymbol() { return this.nameSymbol; } - + @Override public String toString() { final StringBuilder builder = new StringBuilder(); @@ -98,7 +98,7 @@ public final class ViewBot return builder.toString(); } } - + /** * A record of the parameters given to * {@link View#showUnit(NameSymbol, String, String, UnitType)}, for testing. @@ -110,7 +110,7 @@ public final class ViewBot private final String definition; private final String dimensionName; private final UnitType unitType; - + /** * @since 2022-04-16 */ @@ -121,7 +121,7 @@ public final class ViewBot this.dimensionName = dimensionName; this.unitType = unitType; } - + /** * @return the definition * @since 2022-04-16 @@ -129,7 +129,7 @@ public final class ViewBot public String definition() { return this.definition; } - + /** * @return the dimensionName * @since 2022-04-16 @@ -137,7 +137,7 @@ public final class ViewBot public String dimensionName() { return this.dimensionName; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -150,7 +150,7 @@ public final class ViewBot && Objects.equals(this.nameSymbol, other.nameSymbol) && this.unitType == other.unitType; } - + /** * @return the nameSymbol * @since 2022-04-16 @@ -159,17 +159,17 @@ public final class ViewBot public NameSymbol getNameSymbol() { return this.nameSymbol; } - + @Override public int hashCode() { return Objects.hash(this.definition, this.dimensionName, this.nameSymbol, this.unitType); } - + public NameSymbol nameSymbol() { return this.nameSymbol; } - + @Override public String toString() { final StringBuilder builder = new StringBuilder(); @@ -184,7 +184,7 @@ public final class ViewBot builder.append("]"); return builder.toString(); } - + /** * @return the unitType * @since 2022-04-16 @@ -193,10 +193,10 @@ public final class ViewBot return this.unitType; } } - + /** The presenter that works with this ViewBot */ private final Presenter presenter; - + /** The dimensions available to select from */ private Set<String> dimensionNames = Set.of(); /** The expression in the From field */ @@ -217,12 +217,12 @@ public final class ViewBot private Set<String> fromUnits = Set.of(); /** The units available in the To selection */ private Set<String> toUnits = Set.of(); - + /** The selected unit in the unit viewer */ private Optional<String> unitViewerSelection = Optional.empty(); /** The selected unit in the prefix viewer */ private Optional<String> prefixViewerSelection = Optional.empty(); - + /** Saved outputs of all unit conversions */ private final List<UnitConversionRecord> unitConversions; /** Saved outputs of all unit expressions */ @@ -231,7 +231,7 @@ public final class ViewBot private final List<UnitViewingRecord> unitViewingRecords; /** Saved outputs of all prefix viewings */ private final List<PrefixViewingRecord> prefixViewingRecords; - + /** * Creates a new {@code ViewBot} with a new presenter. * @@ -239,13 +239,13 @@ public final class ViewBot */ public ViewBot() { this.presenter = new Presenter(this); - + this.unitConversions = new ArrayList<>(); this.expressionConversions = new ArrayList<>(); this.unitViewingRecords = new ArrayList<>(); this.prefixViewingRecords = new ArrayList<>(); } - + /** * @return list of records of expression conversions done by this bot * @since 2022-04-09 @@ -253,7 +253,7 @@ public final class ViewBot public List<UnitConversionRecord> expressionConversionList() { return Collections.unmodifiableList(this.expressionConversions); } - + /** * @return the available dimensions * @since 2022-01-29 @@ -262,17 +262,17 @@ public final class ViewBot public Set<String> getDimensionNames() { return this.dimensionNames; } - + @Override public String getFromExpression() { return this.fromExpression; } - + @Override public Optional<String> getFromSelection() { return this.fromSelection; } - + /** * @return the units available for selection in From * @since 2022-01-29 @@ -281,12 +281,12 @@ public final class ViewBot public Set<String> getFromUnitNames() { return Collections.unmodifiableSet(this.fromUnits); } - + @Override public String getInputValue() { return this.inputValue; } - + /** * @return the presenter associated with tihs view * @since 2022-01-29 @@ -295,22 +295,22 @@ public final class ViewBot public Presenter getPresenter() { return this.presenter; } - + @Override public Optional<String> getSelectedDimensionName() { return this.selectedDimensionName; } - + @Override public String getToExpression() { return this.toExpression; } - + @Override public Optional<String> getToSelection() { return this.toSelection; } - + /** * @return the units available for selection in To * @since 2022-01-29 @@ -319,17 +319,17 @@ public final class ViewBot public Set<String> getToUnitNames() { return Collections.unmodifiableSet(this.toUnits); } - + @Override public Optional<String> getViewedPrefixName() { return this.prefixViewerSelection; } - + @Override public Optional<String> getViewedUnitName() { return this.unitViewerSelection; } - + /** * @return list of records of this viewBot's prefix views * @since 2022-04-16 @@ -337,13 +337,13 @@ public final class ViewBot public List<PrefixViewingRecord> prefixViewList() { return Collections.unmodifiableList(this.prefixViewingRecords); } - + @Override public void setDimensionNames(Set<String> dimensionNames) { this.dimensionNames = Objects.requireNonNull(dimensionNames, "dimensions may not be null"); } - + /** * Sets the From expression (as in {@link #getFromExpression}). * @@ -355,7 +355,7 @@ public final class ViewBot this.fromExpression = Objects.requireNonNull(fromExpression, "fromExpression cannot be null."); } - + /** * @param fromSelection the fromSelection to set * @since 2022-01-29 @@ -364,7 +364,7 @@ public final class ViewBot this.fromSelection = Objects.requireNonNull(fromSelection, "fromSelection cannot be null"); } - + /** * @param fromSelection the fromSelection to set * @since 2022-02-10 @@ -372,12 +372,12 @@ public final class ViewBot public void setFromSelection(String fromSelection) { this.setFromSelection(Optional.of(fromSelection)); } - + @Override public void setFromUnitNames(Set<String> units) { this.fromUnits = Objects.requireNonNull(units, "units may not be null"); } - + /** * @param inputValue the inputValue to set * @since 2022-01-29 @@ -385,7 +385,7 @@ public final class ViewBot public void setInputValue(String inputValue) { this.inputValue = inputValue; } - + /** * @param selectedDimension the selectedDimension to set * @since 2022-01-29 @@ -394,11 +394,11 @@ public final class ViewBot Optional<String> selectedDimensionName) { this.selectedDimensionName = selectedDimensionName; } - + public void setSelectedDimensionName(String selectedDimensionName) { this.setSelectedDimensionName(Optional.of(selectedDimensionName)); } - + /** * Sets the To expression (as in {@link #getToExpression}). * @@ -410,7 +410,7 @@ public final class ViewBot this.toExpression = Objects.requireNonNull(toExpression, "toExpression cannot be null."); } - + /** * @param toSelection the toSelection to set * @since 2022-01-29 @@ -419,77 +419,77 @@ public final class ViewBot this.toSelection = Objects.requireNonNull(toSelection, "toSelection cannot be null."); } - + public void setToSelection(String toSelection) { this.setToSelection(Optional.of(toSelection)); } - + @Override public void setToUnitNames(Set<String> units) { this.toUnits = Objects.requireNonNull(units, "units may not be null"); } - + @Override public void setViewablePrefixNames(Set<String> prefixNames) { // do nothing, ViewBot supports selecting any prefix } - + @Override public void setViewableUnitNames(Set<String> unitNames) { // do nothing, ViewBot supports selecting any unit } - + public void setViewedPrefixName(Optional<String> viewedPrefixName) { this.prefixViewerSelection = viewedPrefixName; } - + public void setViewedPrefixName(String viewedPrefixName) { this.setViewedPrefixName(Optional.of(viewedPrefixName)); } - + public void setViewedUnitName(Optional<String> viewedUnitName) { this.unitViewerSelection = viewedUnitName; } - + public void setViewedUnitName(String viewedUnitName) { this.setViewedUnitName(Optional.of(viewedUnitName)); } - + @Override public void showErrorMessage(String title, String message) { System.err.printf("%s: %s%n", title, message); } - + @Override public void showExpressionConversionOutput(UnitConversionRecord uc) { this.expressionConversions.add(uc); System.out.println("Expression Conversion: " + uc); } - + @Override public void showPrefix(NameSymbol name, String multiplierString) { this.prefixViewingRecords .add(new PrefixViewingRecord(name, multiplierString)); } - + @Override public void showUnit(NameSymbol name, String definition, String dimensionName, UnitType type) { this.unitViewingRecords .add(new UnitViewingRecord(name, definition, dimensionName, type)); } - + @Override public void showUnitConversionOutput(UnitConversionRecord uc) { this.unitConversions.add(uc); System.out.println("Unit Conversion: " + uc); } - + @Override public String toString() { return super.toString() + String.format("[presenter=%s]", this.presenter); } - + /** * @return list of records of every unit conversion made by this bot * @since 2022-04-09 @@ -497,7 +497,7 @@ public final class ViewBot public List<UnitConversionRecord> unitConversionList() { return Collections.unmodifiableList(this.unitConversions); } - + /** * @return list of records of unit viewings made by this bot * @since 2022-04-16 diff --git a/src/test/java/sevenUnits/unit/MultiUnitTest.java b/src/test/java/sevenUnits/unit/MultiUnitTest.java index 30f2941..949a1f1 100644 --- a/src/test/java/sevenUnits/unit/MultiUnitTest.java +++ b/src/test/java/sevenUnits/unit/MultiUnitTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test; * @since 2020-10-03 */ class MultiUnitTest { - + /** * Ensures that the {@code MultiUnit} can convert properly. */ @@ -40,24 +40,24 @@ class MultiUnitTest { 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<Double> 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)}. */ @@ -66,24 +66,24 @@ class MultiUnitTest { final Random rng = ThreadLocalRandom.current(); final MultiUnit footInch = MultiUnit.of(BritishImperial.Length.FOOT, BritishImperial.Length.INCH); - + // 1.7 m =~ 5' + 7" final List<Double> values = footInch.convertFromBase(1.7018); - + assertEquals(5, values.get(0)); assertEquals(7, values.get(1), 1e-12); - + for (int i = 0; i < 1000; i++) { final double feet = rng.nextInt(1000); final double inches = rng.nextDouble() * 12; final double metres = feet * 0.3048 + inches * 0.0254; - + final List<Double> feetAndInches = footInch.convertFromBase(metres); assertEquals(feet, feetAndInches.get(0), 1e-10); assertEquals(inches, feetAndInches.get(1), 1e-10); } } - + /** * Test method for * {@link sevenUnits.unit.MultiUnit#convertToBase(java.util.List)}. @@ -93,16 +93,16 @@ class MultiUnitTest { final Random rng = ThreadLocalRandom.current(); final MultiUnit footInch = MultiUnit.of(BritishImperial.Length.FOOT, BritishImperial.Length.INCH); - + // 1.7 m =~ 5' + 7" assertEquals(1.7018, footInch.convertToBase(Arrays.asList(5.0, 7.0)), 1e-12); - + for (int i = 0; i < 1000; i++) { final double feet = rng.nextInt(1000); final double inches = rng.nextDouble() * 12; final double metres = feet * 0.3048 + inches * 0.0254; - + assertEquals(metres, footInch.convertToBase(Arrays.asList(feet, inches)), 1e-12); } diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java index 4be33dd..9d650f0 100644 --- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java +++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java @@ -53,9 +53,9 @@ import sevenUnits.utils.UncertainDouble; class UnitDatabaseTest { private static final class SimpleEntry<K, V> implements Map.Entry<K, V> { private final K key; - + private V value; - + /** * * @since 2021-10-07 @@ -64,7 +64,7 @@ class UnitDatabaseTest { this.key = key; this.value = value; } - + @Override public boolean equals(Object obj) { if (this == obj) @@ -75,23 +75,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 +99,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 +123,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,7 +139,7 @@ class UnitDatabaseTest { private static <K, V> Map.Entry<K, V> entry(K key, V value) { return new SimpleEntry<>(key, value); } - + /** * Loads the dimensionfile at src/test/resources/[path] to the database * {@code loadTo}. @@ -156,7 +156,7 @@ class UnitDatabaseTest { fail(e.getClass() + " occurred upon loading file \"" + path + "\"."); } } - + /** * Loads the unitfile at src/test/resources/[path] to the database * {@code loadTo}. @@ -173,7 +173,7 @@ class UnitDatabaseTest { fail(e.getClass() + " occurred upon loading file \"" + path + "\"."); } } - + /** * A test for the {@link UnitDatabase#evaluateUnitExpression(String)} * function. Simple because the expression parser has its own test. @@ -183,26 +183,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 +212,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 +228,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 +247,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<Entry<String, Unit>> entrySet = infiniteDatabase.unitMap() .entrySet(); final Set<String> keySet = infiniteDatabase.unitMap().keySet(); assertThrows(IllegalStateException.class, () -> entrySet.toArray()); assertThrows(IllegalStateException.class, () -> keySet.toArray()); } - + /** * A bunch of tests for invalid dimension files * @@ -282,7 +282,7 @@ class UnitDatabaseTest { assertTrue(e instanceof IllegalArgumentException || e instanceof NoSuchElementException); } - + /** * A bunch of tests for invalid unit files * @@ -300,7 +300,7 @@ class UnitDatabaseTest { assertTrue(e instanceof IllegalArgumentException || e instanceof NoSuchElementException); } - + /** * Tests loading a valid dimension-file with some derived dimensions. * @@ -312,13 +312,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 +327,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 +342,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 +388,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<String, Unit> map1 = database1.unitMap(); final Iterator<String> keyIterator1 = map1.keySet().iterator(); final Iterator<Map.Entry<String, Unit>> entryIterator1 = map1.entrySet() .iterator(); - + final Set<String> expectedKeys = Set.of("U", "V", "W"); final Set<String> actualKeys = new HashSet<>(); while (keyIterator1.hasNext()) { @@ -405,7 +405,7 @@ class UnitDatabaseTest { } assertEquals(expectedKeys, actualKeys); assertEquals(expectedKeys, map1.keySet()); - + final Set<Map.Entry<String, Unit>> expectedEntries = Set.of(entry("U", U), entry("V", V), entry("W", W)); final Set<Map.Entry<String, Unit>> actualEntries = new HashSet<>(); @@ -415,7 +415,7 @@ class UnitDatabaseTest { assertEquals(expectedEntries, actualEntries); assertEquals(expectedEntries, map1.entrySet()); } - + /** * Test that prefixes correctly apply to units. * @@ -425,28 +425,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<UnitPrefix> expected = Arrays.asList(C, B, A); assertEquals(expected, database.getPrefixesFromName("ABCU")); - + // get the product final Unit abcuNonlinear = database.getUnit("ABCU"); assert abcuNonlinear instanceof LinearUnit; - + final LinearUnit abcu = (LinearUnit) abcuNonlinear; assertEquals(A.getMultiplier() * B.getMultiplier() * C.getMultiplier(), abcu.getConversionFactor(), 1e-15); } - + /** * Tests the functionnalites of the prefixless unit map. * @@ -462,19 +462,19 @@ class UnitDatabaseTest { final UnitDatabase database = new UnitDatabase(); final Map<String, Unit> 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 +485,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<String, Unit> unitMap = new HashMap<>(); @@ -504,7 +504,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 +514,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 +546,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 +587,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<String> nameIterator = database.unitMap().keySet() .iterator(); final Iterator<Entry<String, Unit>> entryIterator = database.unitMap() .entrySet().iterator(); - + int expectedLength = 1; int unitsWithThisLengthSoFar = 0; - + // loop 1000 times for (int i = 0; i < 1000; i++) { // expected length of next @@ -614,31 +614,31 @@ class UnitDatabaseTest { expectedLength++; unitsWithThisLengthSoFar = 0; } - + // test that stuff is valid final String nextName = nameIterator.next(); final Unit nextUnit = database.getUnit(nextName); final Entry<String, Unit> nextEntry = entryIterator.next(); - + assertEquals(expectedLength, nextName.length()); assertEquals(nextName, nextEntry.getKey()); assertEquals(nextUnit, nextEntry.getValue()); - + unitsWithThisLengthSoFar++; } - + // test toString for consistency final String entryIteratorString = entryIterator.toString(); for (int i = 0; i < 3; i++) { assertEquals(entryIteratorString, entryIterator.toString()); } - + final String nameIteratorString = nameIterator.toString(); for (int i = 0; i < 3; i++) { assertEquals(nameIteratorString, nameIterator.toString()); } } - + /** * Determine, given a unit name that could mean multiple things, which * meaning is chosen. @@ -654,28 +654,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/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java index d3699ca..c93043b 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()); } } diff --git a/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java b/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java index 6b5f9cf..868385b 100644 --- a/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java +++ b/src/test/java/sevenUnits/utils/ConditionalExistenceCollectionsTest.java @@ -43,7 +43,7 @@ import sevenUnits.utils.ConditionalExistenceCollections.ConditionalExistenceIter * @since 2019-10-16 */ class ConditionalExistenceCollectionsTest { - + /** * The returned iterator ignores elements that don't start with "a". * @@ -57,7 +57,7 @@ class ConditionalExistenceCollectionsTest { .conditionalExistenceIterator(it, s -> s.startsWith("a")); return cit; } - + /** * The returned map ignores mappings where the value is zero. * @@ -75,7 +75,7 @@ class ConditionalExistenceCollectionsTest { e -> !Integer.valueOf(0).equals(e.getValue())); return conditionalMap; } - + /** * Test method for the ConditionalExistenceMap's containsKey method. */ @@ -87,7 +87,7 @@ class ConditionalExistenceCollectionsTest { assertFalse(map.containsKey("five")); assertFalse(map.containsKey("zero")); } - + /** * Test method for the ConditionalExistenceMap's containsValue method. */ @@ -99,7 +99,7 @@ class ConditionalExistenceCollectionsTest { assertFalse(map.containsValue(5)); assertFalse(map.containsValue(0)); } - + /** * Test method for the ConditionalExistenceMap's entrySet method. */ @@ -110,7 +110,7 @@ class ConditionalExistenceCollectionsTest { assertTrue(e.getValue() != 0); } } - + /** * Test method for the ConditionalExistenceMap's get method. */ @@ -122,7 +122,7 @@ class ConditionalExistenceCollectionsTest { assertEquals(null, map.get("five")); assertEquals(null, map.get("zero")); } - + /** * Test method for the ConditionalExistenceCollection's iterator. */ @@ -130,23 +130,23 @@ class ConditionalExistenceCollectionsTest { void testIterator() { final ConditionalExistenceIterator<String> testIterator = this .getTestIterator(); - + assertTrue(testIterator.hasNext); assertTrue(testIterator.hasNext()); assertEquals("aa", testIterator.nextElement); assertEquals("aa", testIterator.next()); - + assertTrue(testIterator.hasNext); assertTrue(testIterator.hasNext()); assertEquals("ab", testIterator.nextElement); assertEquals("ab", testIterator.next()); - + assertFalse(testIterator.hasNext); assertFalse(testIterator.hasNext()); assertEquals(null, testIterator.nextElement); assertThrows(NoSuchElementException.class, testIterator::next); } - + /** * Test method for the ConditionalExistenceMap's keySet operation. */ @@ -155,7 +155,7 @@ class ConditionalExistenceCollectionsTest { final Map<String, Integer> map = this.getTestMap(); assertFalse(map.keySet().contains("zero")); } - + /** * Test method for the ConditionalExistenceMap's values operation. */ @@ -164,5 +164,5 @@ class ConditionalExistenceCollectionsTest { final Map<String, Integer> map = this.getTestMap(); assertFalse(map.values().contains(0)); } - + } diff --git a/src/test/java/sevenUnits/utils/ExpressionParserTest.java b/src/test/java/sevenUnits/utils/ExpressionParserTest.java index a954b12..3a95285 100644 --- a/src/test/java/sevenUnits/utils/ExpressionParserTest.java +++ b/src/test/java/sevenUnits/utils/ExpressionParserTest.java @@ -38,12 +38,11 @@ import org.junit.jupiter.params.provider.MethodSource; class ExpressionParserTest { private static final ExpressionParser<Integer> numberParser = new ExpressionParser.Builder<>( Integer::parseInt).addBinaryOperator("+", (o1, o2) -> o1 + o2, 0) - .addBinaryOperator("-", (o1, o2) -> o1 - o2, 0) - .addBinaryOperator("*", (o1, o2) -> o1 * o2, 1) - .addBinaryOperator("/", (o1, o2) -> o1 / o2, 1) - .addBinaryOperator("^", (o1, o2) -> (int) Math.pow(o1, o2), 2) - .build(); - + .addBinaryOperator("-", (o1, o2) -> o1 - o2, 0) + .addBinaryOperator("*", (o1, o2) -> o1 * o2, 1) + .addBinaryOperator("/", (o1, o2) -> o1 / o2, 1) + .addBinaryOperator("^", (o1, o2) -> (int) Math.pow(o1, o2), 2).build(); + /** * The expressions used in the expression parsing tests */ @@ -51,15 +50,15 @@ class ExpressionParserTest { // test parsing of expressions "1 + 2 ^ 5 * 3", "(1 + 2) ^ 5 * 3", "12 * 5 + (3 ^ (2 * 3) - 72) / (3 + 3 * 2)", - + // ensure it normally goes from left to right "1 + 2 + 3 + 4", "12 - 4 - 3", "12 - (4 - 3)", "1 / 2 + 3"); - + /** * The expected results for evaluating these expressions */ private static final int[] RESULTS = { 97, 729, 133, 10, 5, 11, 3 }; - + /** * @return A stream of objects, where each one is an expression and the * expected result @@ -69,7 +68,7 @@ class ExpressionParserTest { return IntStream.range(0, TEST_EXPRESSIONS.size()) .mapToObj(i -> Arguments.of(TEST_EXPRESSIONS.get(i), RESULTS[i])); } - + /** * Test method for * {@link sevenUnits.utils.ExpressionParser#parseExpression(java.lang.String)}. diff --git a/src/test/java/sevenUnits/utils/ObjectProductTest.java b/src/test/java/sevenUnits/utils/ObjectProductTest.java index 15ff277..8c6b353 100644 --- a/src/test/java/sevenUnits/utils/ObjectProductTest.java +++ b/src/test/java/sevenUnits/utils/ObjectProductTest.java @@ -32,7 +32,8 @@ import org.junit.jupiter.api.Test; import sevenUnits.unit.Metric; /** - * Tests for {@link ObjectProduct} using BaseDimension as a test object. This is NOT part of this program's public API. + * Tests for {@link ObjectProduct} using BaseDimension as a test object. This is + * NOT part of this program's public API. * * @author Adrien Hopkins * @since 2018-12-12 diff --git a/src/test/java/sevenUnits/utils/SemanticVersionTest.java b/src/test/java/sevenUnits/utils/SemanticVersionTest.java index 877b258..1e59ae3 100644 --- a/src/test/java/sevenUnits/utils/SemanticVersionTest.java +++ b/src/test/java/sevenUnits/utils/SemanticVersionTest.java @@ -48,20 +48,20 @@ public final class SemanticVersionTest { "1.0.0 not compatible with 1.0.5"); assertTrue(stableVersion(1, 3, 1).compatibleWith(stableVersion(1, 4, 0)), "1.3.1 not compatible with 1.4.0"); - + // 0.y.z should not be compatible with any other version assertFalse(stableVersion(0, 4, 0).compatibleWith(stableVersion(0, 4, 1)), "0.4.0 compatible with 0.4.1 (0.y.z versions should be treated as unstable/incompatbile)"); - + // upgrading major version should = incompatible assertFalse(stableVersion(1, 0, 0).compatibleWith(stableVersion(2, 0, 0)), "1.0.0 compatible with 2.0.0"); - + // dowgrade should = incompatible assertFalse(stableVersion(1, 1, 0).compatibleWith(stableVersion(1, 0, 0)), "1.1.0 compatible with 1.0.0"); } - + /** * Tests {@link SemanticVersionNumber#toString} for complex version numbers * @@ -79,7 +79,7 @@ public final class SemanticVersionTest { .preRelease("x-y-z", "--").build(); assertEquals("1.0.0-x-y-z.--", v3.toString()); } - + /** * Tests that complex version can be created and their parts read * @@ -94,7 +94,7 @@ public final class SemanticVersionTest { assertEquals(3, v1.patchVersion()); assertEquals(List.of("1", "2", "3"), v1.preReleaseIdentifiers()); assertEquals(List.of(), v1.buildMetadata()); - + final SemanticVersionNumber v2 = builder(4, 5, 6).preRelease("abc", 123) .buildMetadata("2022-02-19").build(); assertEquals(4, v2.majorVersion()); @@ -102,7 +102,7 @@ public final class SemanticVersionTest { assertEquals(6, v2.patchVersion()); assertEquals(List.of("abc", "123"), v2.preReleaseIdentifiers()); assertEquals(List.of("2022-02-19"), v2.buildMetadata()); - + final SemanticVersionNumber v3 = builder(1, 0, 0) .preRelease("x-y-z", "--").build(); assertEquals(1, v3.majorVersion()); @@ -111,7 +111,7 @@ public final class SemanticVersionTest { assertEquals(List.of("x-y-z", "--"), v3.preReleaseIdentifiers()); assertEquals(List.of(), v3.buildMetadata()); } - + /** * Test that semantic version strings can be parsed correctly * @@ -132,7 +132,7 @@ public final class SemanticVersionTest { "1.0.0+abc is treated as invalid"); assertTrue(isValidVersionString("1.0.0-abc+def"), "1.0.0-abc+def is treated as invalid"); - + // test that invalid versions don't match assertFalse(isValidVersionString("1.0"), "1.0 is treated as valid (patch should be required)"); @@ -142,7 +142,7 @@ public final class SemanticVersionTest { "1.0.0- is treated as valid (pre-release must not be empty)"); assertFalse(isValidVersionString("1.0.0+"), "1.0.0+ is treated as valid (build metadata must not be empty)"); - + // test that versions can be parsed assertEquals(stableVersion(1, 0, 0), fromString("1.0.0"), "Could not parse 1.0.0"); @@ -152,7 +152,7 @@ public final class SemanticVersionTest { fromString("1.2.3-abc.56.def+2022abc99"), "Could not parse 1.2.3-abc.56.def+2022abc99"); } - + /** * Ensures it is impossible to create invalid version numbers */ @@ -168,7 +168,7 @@ public final class SemanticVersionTest { assertThrows(IllegalArgumentException.class, () -> stableVersion(-3, 0, 7), "Negative major version number tolerated by stableVersion"); - + // preRelease() assertThrows(IllegalArgumentException.class, () -> preRelease(1, 0, -1, "test", 2), @@ -190,7 +190,7 @@ public final class SemanticVersionTest { assertThrows(IllegalArgumentException.class, () -> preRelease(1, 0, 0, "abc+cde", 1), "Invalid string tolerated by preRelease"); - + // builder() assertThrows(IllegalArgumentException.class, () -> builder(1, 0, -1), "Negative patch tolerated by builder"); @@ -198,7 +198,7 @@ public final class SemanticVersionTest { "Negative minor version number tolerated by builder"); assertThrows(IllegalArgumentException.class, () -> builder(-3, 0, 7), "Negative major version number tolerated by builder"); - + final SemanticVersionNumber.Builder testBuilder = builder(1, 2, 3); // note: builder.buildMetadata(null) doesn't even compile lol // builder.buildMetadata @@ -220,7 +220,7 @@ public final class SemanticVersionTest { assertThrows(IllegalArgumentException.class, () -> testBuilder.buildMetadata(List.of("")), "Invalid string tolerated by builder.buildMetadata(List<String>)"); - + // builder.preRelease assertThrows(NullPointerException.class, () -> testBuilder.preRelease(null, "abc"), @@ -240,7 +240,7 @@ public final class SemanticVersionTest { assertThrows(IllegalArgumentException.class, () -> testBuilder.preRelease(List.of("")), "Invalid string tolerated by builder.preRelease(List<String>)"); - + // the overloadings that accept numeric arguments assertThrows(IllegalArgumentException.class, () -> testBuilder.preRelease(-1), @@ -257,12 +257,12 @@ public final class SemanticVersionTest { assertThrows(IllegalArgumentException.class, () -> testBuilder.preRelease("#$#c", 1), "Invalid string tolerated by builder.preRelease(String, int)"); - + // ensure all these attempts didn't change the builder assertEquals(builder(1, 2, 3), testBuilder, "Attempts at making invalid version number succeeded despite throwing errors"); } - + /** * Test for {@link SemanticVersionNumber#isStable} * @@ -282,7 +282,7 @@ public final class SemanticVersionTest { .isStable(), "9.9.99+lots-of-metadata.abc123.2022 should be stable but is not"); } - + /** * Tests that the versions are ordered by * {@link SemanticVersionNumber#compareTo} according to official rules. Tests @@ -311,7 +311,7 @@ public final class SemanticVersionTest { final SemanticVersionNumber v210 = stableVersion(2, 1, 0); final SemanticVersionNumber v211 = stableVersion(2, 1, 1); final SemanticVersionNumber v300 = stableVersion(3, 0, 0); - + // test order of version numbers assertTrue(v100a.compareTo(v100a1) < 0, "1.0.0-alpha >= 1.0.0-alpha.1"); assertTrue(v100a1.compareTo(v100ab) < 0, @@ -327,25 +327,25 @@ public final class SemanticVersionTest { assertTrue(v201.compareTo(v210) < 0, "2.0.1 >= 2.1.0"); assertTrue(v210.compareTo(v211) < 0, "2.1.0 >= 2.1.1"); assertTrue(v211.compareTo(v300) < 0, "2.1.1 >= 3.0.0"); - + // test symmetry - assume previous tests passed assertTrue(v100a1.compareTo(v100a) > 0, "1.0.0-alpha.1 <= 1.0.0-alpha"); assertTrue(v100.compareTo(v100rc1) > 0, "1.0.0 <= 1.0.0-rc.1"); assertTrue(v300.compareTo(v211) > 0, "3.0.0 <= 2.1.1"); - + // test transitivity assertTrue(v100a.compareTo(v100b11) < 0, "1.0.0-alpha >= 1.0.0-beta.11"); assertTrue(v100b.compareTo(v200) < 0, "1.0.0-beta >= 2.0.0"); assertTrue(v100.compareTo(v300) < 0, "1.0.0 >= 3.0.0"); assertTrue(v100a.compareTo(v300) < 0, "1.0.0-alpha >= 3.0.0"); - + // test metadata is ignored assertEquals(0, v100.compareTo(v100plus), "Build metadata not ignored"); // test metadata is NOT ignored by alternative comparator assertTrue(BUILD_METADATA_COMPARATOR.compare(v100, v100plus) > 0, "Build metadata ignored by BUILD_METADATA_COMPARATOR"); } - + /** * Tests that simple stable versions can be created and their parts read * @@ -357,13 +357,13 @@ public final class SemanticVersionTest { assertEquals(1, v100.majorVersion()); assertEquals(0, v100.minorVersion()); assertEquals(0, v100.patchVersion()); - + final SemanticVersionNumber v925 = stableVersion(9, 2, 5); assertEquals(9, v925.majorVersion()); assertEquals(2, v925.minorVersion()); assertEquals(5, v925.patchVersion()); } - + /** * Tests that {@link SemanticVersionNumber#toString} works for simple version * numbers @@ -374,11 +374,11 @@ public final class SemanticVersionTest { public void testSimpleToString() { final SemanticVersionNumber v100 = stableVersion(1, 0, 0); assertEquals("1.0.0", v100.toString()); - + final SemanticVersionNumber v845a1 = preRelease(8, 4, 5, "alpha", 1); assertEquals("8.4.5-alpha.1", v845a1.toString()); } - + /** * Tests that simple unstable versions can be created and their parts read * diff --git a/src/test/java/sevenUnits/utils/UncertainDoubleTest.java b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java index 5ccef28..36b373b 100644 --- a/src/test/java/sevenUnits/utils/UncertainDoubleTest.java +++ b/src/test/java/sevenUnits/utils/UncertainDoubleTest.java @@ -43,36 +43,36 @@ class UncertainDoubleTest { assertTrue(of(2.0, 0.5).compareTo(of(1.0, 0.1)) > 0); assertTrue(of(2.0, 0.5).compareTo(of(3.0, 0.1)) < 0); } - + /** * Tests the ___exact operations */ @Test final void testExactOperations() { final UncertainDouble x = UncertainDouble.of(Math.PI, 0.1); - + // slightly different because roundoff errors final UncertainDouble x1 = UncertainDouble.of(Math.PI + Math.E - Math.E, 0.1); final UncertainDouble x2 = UncertainDouble.of(Math.PI * Math.E / Math.E, 0.1); - + // get results final UncertainDouble result1 = x.plusExact(Math.E).minusExact(Math.E); final UncertainDouble result2 = x.timesExact(Math.E) .dividedByExact(Math.E); - + // test that these operations work & don't change uncertainty assertEquals(x1, result1); assertTrue(x.equivalent(result1)); assertEquals(x2, result2); assertTrue(x.equivalent(result2)); - + // exponents are different assertEquals(Math.pow(Math.PI, Math.E), x.toExponentExact(Math.E).value()); } - + /** * Test for {@link UncertainDouble#fromRoundedString} * @@ -82,29 +82,29 @@ class UncertainDoubleTest { final void testFromRoundedString() { assertEquals(of(12345.678, 0.001), fromRoundedString("12345.678")); } - + /** * Test for {@link UncertainDouble#fromString} */ @Test final void testFromString() { // valid strings - assertEquals(of(2.0, 0.5), fromString("2.0 ± 0.5")); + assertEquals(of(2.0, 0.5), fromString("2.0 � 0.5")); assertEquals(of(2.0, 0.5), fromString("2.0 +- 0.5")); assertEquals(of(2.0, 0.0), fromString("2.0")); - + // invalid strings - for (final String s : List.of("2.A", "A", "2.0 ± .", "± 3.5")) { + for (final String s : List.of("2.A", "A", "2.0 � .", "� 3.5")) { assertThrows(IllegalArgumentException.class, () -> fromString(s)); } - + // back and forth - assertEquals("2.0 ± 0.5", of(2.0, 0.5).toString()); + assertEquals("2.0 � 0.5", of(2.0, 0.5).toString()); assertEquals("2.0", of(2.0, 0).toString()); } - + @Test final void testHashCode() { - assertEquals(of(2.0, 0.5).hashCode(), fromString("2.0 ± 0.5").hashCode()); + assertEquals(of(2.0, 0.5).hashCode(), fromString("2.0 � 0.5").hashCode()); } } diff --git a/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java b/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java index 8ea3fd0..476e407 100644 --- a/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java +++ b/src/test/java/sevenUnitsGUI/PrefixRepetitionTest.java @@ -54,7 +54,7 @@ class PrefixRepetitionTest { assertFalse(COMPLEX_REPETITION.test(List.of(Metric.YOTTA, Metric.MILLI)), "Complex repetition does not factor direction of prefixes"); } - + /** * Tests the {@code NO_REPETITION} rule. * @@ -68,7 +68,7 @@ class PrefixRepetitionTest { assertTrue(NO_REPETITION.test(List.of(Metric.MILLI))); assertTrue(NO_REPETITION.test(List.of()), "Empty list yields false"); } - + /** * Tests the {@code NO_RESTRICTION} rule. * @@ -82,7 +82,7 @@ class PrefixRepetitionTest { assertTrue(NO_RESTRICTION.test(List.of(Metric.MILLI))); assertTrue(NO_RESTRICTION.test(List.of())); } - + /** * Ensures that the complex repetition rule allows valid prefix lists. * @@ -95,7 +95,7 @@ class PrefixRepetitionTest { assertTrue(COMPLEX_REPETITION.test(List.of(Metric.KILO)), "Single prefix not allowed"); assertTrue(COMPLEX_REPETITION.test(List.of()), "No prefixes not allowed"); - + // valid complex repetition assertTrue(COMPLEX_REPETITION.test(List.of(Metric.YOTTA, Metric.KILO)), "Valid complex repetition (kiloyotta) not allowed"); @@ -109,7 +109,7 @@ class PrefixRepetitionTest { COMPLEX_REPETITION.test(List.of(Metric.YOTTA, Metric.YOTTA, Metric.KILO, Metric.DEKA)), "Valid complex repetition (dekakiloyottayotta) not allowed"); - + // valid with negative prefixes assertTrue(COMPLEX_REPETITION.test(List.of(Metric.YOCTO, Metric.MILLI)), "Valid complex repetition (milliyocto) not allowed"); diff --git a/src/test/java/sevenUnitsGUI/PrefixSearchTest.java b/src/test/java/sevenUnitsGUI/PrefixSearchTest.java index ca238fe..305d0d7 100644 --- a/src/test/java/sevenUnitsGUI/PrefixSearchTest.java +++ b/src/test/java/sevenUnitsGUI/PrefixSearchTest.java @@ -45,7 +45,7 @@ class PrefixSearchTest { private static final PrefixSearchRule getCommonRuleCopy() { return getCoherentOnlyRule(Set.of(Metric.KILO, Metric.MILLI)); } - + /** * Test method for * {@link sevenUnitsGUI.PrefixSearchRule#apply(java.util.Map.Entry)}, for a @@ -60,11 +60,11 @@ class PrefixSearchTest { Metric.KILOMETRE, "millimetre", Metric.MILLIMETRE); final var actual = COMMON_PREFIXES .apply(Map.entry("metre", Metric.METRE)); - + assertEquals(expected, actual, "Prefixes not correctly applied to coherent unit."); } - + /** * Test method for * {@link sevenUnitsGUI.PrefixSearchRule#equals(java.lang.Object)}. @@ -76,11 +76,11 @@ class PrefixSearchTest { final void testEquals() { assertEquals(getCommonRuleCopy(), getCommonRuleCopy(), "equals considers something other than prefixes/rule"); - + assertNotEquals(getCoherentOnlyRule(Set.of()), getUniversalRule(Set.of()), "equals ignores rule"); } - + /** * Test method for {@link sevenUnitsGUI.PrefixSearchRule#getPrefixes()}. * @@ -93,7 +93,7 @@ class PrefixSearchTest { assertEquals(Metric.ALL_PREFIXES, PrefixSearchRule.ALL_METRIC_PREFIXES.getPrefixes()); } - + /** * Test method for {@link sevenUnitsGUI.PrefixSearchRule#hashCode()}. * @@ -105,7 +105,7 @@ class PrefixSearchTest { assertEquals(getCommonRuleCopy().hashCode(), getCommonRuleCopy().hashCode()); } - + /** * Tests prefix searching for a non-coherent unit and * {@link PrefixSearchRule#COMMON_PREFIXES}. @@ -118,10 +118,10 @@ class PrefixSearchTest { final var input = Map.entry("inch", BritishImperial.Length.INCH); final var expected = Map.ofEntries(input); final var actual = COMMON_PREFIXES.apply(input); - + assertEquals(expected, actual, "Prefixes applied to non-coherent unit."); } - + /** * Tests that {@link PrefixSearchRule#NO_PREFIXES} returns the original unit. * @@ -141,7 +141,7 @@ class PrefixSearchTest { } } } - + /** * Test method for {@link sevenUnitsGUI.PrefixSearchRule#toString()}. * @@ -154,5 +154,5 @@ class PrefixSearchTest { "Apply the following prefixes: [kilo (\u00D7 1000.0), milli (\u00D7 0.001)]", COMMON_PREFIXES.toString()); } - + } diff --git a/src/test/java/sevenUnitsGUI/PresenterTest.java b/src/test/java/sevenUnitsGUI/PresenterTest.java index 5755701..9e25a08 100644 --- a/src/test/java/sevenUnitsGUI/PresenterTest.java +++ b/src/test/java/sevenUnitsGUI/PresenterTest.java @@ -64,14 +64,14 @@ public final class PresenterTest { "test-settings.txt"); static final Set<Unit> testUnits = Set.of(Metric.METRE, Metric.KILOMETRE, Metric.METRE_PER_SECOND, Metric.KILOMETRE_PER_HOUR); - + static final Set<ObjectProduct<BaseDimension>> testDimensions = Set .of(Metric.Dimensions.LENGTH, Metric.Dimensions.VELOCITY); - + private static final Stream<Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>>> SEARCH_RULES = Stream .of(PrefixSearchRule.NO_PREFIXES, PrefixSearchRule.COMMON_PREFIXES, PrefixSearchRule.ALL_METRIC_PREFIXES); - + /** * @return rounding rules used by {@link #testRoundingRules} * @since v0.4.0 @@ -81,18 +81,18 @@ public final class PresenterTest { final var SCIENTIFIC_ROUNDING = StandardDisplayRules.uncertaintyBased(); final var INTEGER_ROUNDING = StandardDisplayRules.fixedDecimals(0); final var SIG_FIG_ROUNDING = StandardDisplayRules.fixedPrecision(4); - + return Stream.of(SCIENTIFIC_ROUNDING, INTEGER_ROUNDING, SIG_FIG_ROUNDING); } - + private static final Stream<Function<Map.Entry<String, LinearUnit>, Map<String, LinearUnit>>> getSearchRules() { return SEARCH_RULES; } - + private static final Set<String> names(Set<? extends Nameable> units) { return units.stream().map(Nameable::getName).collect(Collectors.toSet()); } - + /** * Test method for {@link Presenter#convertExpressions} * @@ -104,20 +104,20 @@ public final class PresenterTest { // setup final ViewBot viewBot = new ViewBot(); final Presenter presenter = new Presenter(viewBot); - + viewBot.setFromExpression("10000.0 m"); viewBot.setToExpression("km"); - + // convert expression presenter.convertExpressions(); - + // test result final List<UnitConversionRecord> outputs = viewBot .expressionConversionList(); assertEquals("10000.0 m = 10.00000 km", outputs.get(outputs.size() - 1).toString()); } - + /** * Tests that unit-conversion Views can correctly convert units * @@ -129,16 +129,16 @@ public final class PresenterTest { // setup final ViewBot viewBot = new ViewBot(); final Presenter presenter = new Presenter(viewBot); - + viewBot.setFromUnitNames(names(testUnits)); viewBot.setToUnitNames(names(testUnits)); viewBot.setFromSelection("metre"); viewBot.setToSelection("kilometre"); viewBot.setInputValue("10000.0"); - + // convert units presenter.convertUnits(); - + /* * use result from system as expected - I'm not testing unit conversion * here (that's for the backend tests), I'm just testing that it correctly @@ -154,7 +154,7 @@ public final class PresenterTest { expectedOutput.getValue().toString(false, RoundingMode.HALF_EVEN)); assertEquals(List.of(expectedUC), viewBot.unitConversionList()); } - + /** * Tests that duplicate units are successfully removed, if that is asked for * @@ -165,7 +165,7 @@ public final class PresenterTest { void testDuplicateUnits() { final var metre = Metric.METRE; final var meter = Metric.METRE.withName(NameSymbol.of("meter", "m")); - + // load 2 duplicate units final var viewBot = new ViewBot(); final var presenter = new Presenter(viewBot); @@ -174,20 +174,20 @@ public final class PresenterTest { presenter.database.addUnit("meter", meter); presenter.setOneWayConversionEnabled(false); presenter.setSearchRule(PrefixSearchRule.NO_PREFIXES); - + // test that only one of them is included if duplicate units disabled presenter.setShowDuplicates(false); presenter.updateView(); assertEquals(1, viewBot.getFromUnitNames().size()); assertEquals(1, viewBot.getToUnitNames().size()); - + // test that both of them is included if duplicate units enabled presenter.setShowDuplicates(true); presenter.updateView(); assertEquals(2, viewBot.getFromUnitNames().size()); assertEquals(2, viewBot.getToUnitNames().size()); } - + /** * Tests that one-way conversion correctly filters From and To units * @@ -200,7 +200,7 @@ public final class PresenterTest { final var allNames = Set.of("metre", "inch", "tempC"); final var metricNames = Set.of("metre", "tempC"); final var nonMetricNames = Set.of("inch", "tempC"); - + // load view with one metric and one non-metric unit final var viewBot = new ViewBot(); final var presenter = new Presenter(viewBot); @@ -209,19 +209,19 @@ public final class PresenterTest { presenter.database.addUnit("inch", BritishImperial.Length.INCH); presenter.database.addUnit("tempC", Metric.CELSIUS); presenter.setSearchRule(PrefixSearchRule.NO_PREFIXES); - + // test that units are removed from each side when one-way conversion is // enabled presenter.setOneWayConversionEnabled(true); assertEquals(nonMetricNames, viewBot.getFromUnitNames()); assertEquals(metricNames, viewBot.getToUnitNames()); - + // test that units are kept when one-way conversion is disabled presenter.setOneWayConversionEnabled(false); assertEquals(allNames, viewBot.getFromUnitNames()); assertEquals(allNames, viewBot.getToUnitNames()); } - + /** * Tests the prefix-viewing functionality. * @@ -235,23 +235,23 @@ public final class PresenterTest { final var presenter = new Presenter(viewBot); viewBot.setViewablePrefixNames(Set.of("kilo", "milli")); presenter.setNumberDisplayRule(UncertainDouble::toString); - + // view prefix viewBot.setViewedPrefixName("kilo"); presenter.prefixSelected(); // just in case - + // get correct values final var expectedNameSymbol = presenter.database.getPrefix("kilo") .getNameSymbol(); final var expectedMultiplierString = String .valueOf(Metric.KILO.getMultiplier()); - + // test that presenter's values are correct final var prefixRecord = viewBot.prefixViewList().get(0); assertEquals(expectedNameSymbol, prefixRecord.getNameSymbol()); assertEquals(expectedMultiplierString, prefixRecord.multiplierString()); } - + /** * Tests that rounding rules are used correctly. * @@ -265,13 +265,13 @@ public final class PresenterTest { final var viewBot = new ViewBot(); final var presenter = new Presenter(viewBot); presenter.setNumberDisplayRule(roundingRule); - + // convert and round viewBot.setInputValue("12345.6789"); viewBot.setFromSelection("metre"); viewBot.setToSelection("kilometre"); presenter.convertUnits(); - + // test the result of the rounding final String expectedOutputString = roundingRule .apply(UncertainDouble.fromRoundedString("12.3456789")); @@ -279,7 +279,7 @@ public final class PresenterTest { .outputValueString(); assertEquals(expectedOutputString, actualOutputString); } - + /** * Tests that the Presenter correctly applies search rules. * @@ -294,15 +294,15 @@ public final class PresenterTest { // setup final var viewBot = new ViewBot(); final var presenter = new Presenter(viewBot); - + presenter.setSearchRule(searchRule); presenter.setOneWayConversionEnabled(false); - + presenter.database.clear(); presenter.database.addUnit("metre", Metric.METRE); presenter.database.addUnit("inch", BritishImperial.Length.INCH); presenter.updateView(); - + // create expected output based on rule final Set<String> expectedOutput = new HashSet<>(); expectedOutput.addAll(searchRule @@ -310,11 +310,11 @@ public final class PresenterTest { expectedOutput.addAll( searchRule.apply(Map.entry("metre", Metric.METRE)).keySet()); final Set<String> actualOutput = viewBot.getFromUnitNames(); - + // test output assertEquals(expectedOutput, actualOutput); } - + /** * Tests that settings can be saved to and loaded from a file. * @@ -326,7 +326,7 @@ public final class PresenterTest { // setup final var viewBot = new ViewBot(); final var presenter = new Presenter(viewBot); - + // set and save custom settings presenter.setOneWayConversionEnabled(true); presenter.setShowDuplicates(true); @@ -335,12 +335,12 @@ public final class PresenterTest { DefaultPrefixRepetitionRule.COMPLEX_REPETITION); assumeTrue(presenter.writeSettings(TEST_SETTINGS), "Could not write to settings file."); - + // overwrite custom settings presenter.setOneWayConversionEnabled(false); presenter.setShowDuplicates(false); presenter.setNumberDisplayRule(StandardDisplayRules.uncertaintyBased()); - + // load settings & test that they're the same presenter.loadSettings(TEST_SETTINGS); assertTrue(presenter.oneWayConversionEnabled()); @@ -348,7 +348,7 @@ public final class PresenterTest { assertEquals(StandardDisplayRules.fixedPrecision(11), presenter.getNumberDisplayRule()); } - + /** * Ensures the Presenter generates the correct data upon a unit-viewing. * @@ -361,12 +361,12 @@ public final class PresenterTest { final var viewBot = new ViewBot(); final var presenter = new Presenter(viewBot); viewBot.setViewableUnitNames(names(testUnits)); - + // view unit viewBot.setViewedUnitName("metre"); presenter.unitNameSelected(); // just in case this isn't triggered // automatically - + // get correct values final var expectedNameSymbol = presenter.database.getUnit("metre") .getNameSymbol(); @@ -374,7 +374,7 @@ public final class PresenterTest { final var expectedDimensionName = presenter .getDimensionName(Metric.METRE.getDimension()); final var expectedUnitType = UnitType.METRIC; - + // test for correctness final var viewRecord = viewBot.unitViewList().get(0); assertEquals(expectedNameSymbol, viewRecord.getNameSymbol()); @@ -382,7 +382,7 @@ public final class PresenterTest { assertEquals(expectedDimensionName, viewRecord.dimensionName()); assertEquals(expectedUnitType, viewRecord.unitType()); } - + /** * Test for {@link Presenter#updateView()} * @@ -396,7 +396,7 @@ public final class PresenterTest { final Presenter presenter = new Presenter(viewBot); presenter.setOneWayConversionEnabled(false); presenter.setSearchRule(PrefixSearchRule.NO_PREFIXES); - + // override default database units presenter.database.clear(); for (final Unit unit : testUnits) { @@ -406,18 +406,18 @@ public final class PresenterTest { presenter.database.addDimension( dimension.getPrimaryName().orElseThrow(), dimension); } - + // set from and to units viewBot.setFromUnitNames(names(testUnits)); viewBot.setToUnitNames(names(testUnits)); viewBot.setDimensionNames(names(testDimensions)); viewBot.setSelectedDimensionName(Metric.Dimensions.LENGTH.getName()); - + // filter to length units only, then get the filtered sets of units presenter.updateView(); final Set<String> fromUnits = viewBot.getFromUnitNames(); final Set<String> toUnits = viewBot.getToUnitNames(); - + // test that fromUnits/toUnits is [METRE, KILOMETRE] assertEquals(Set.of("metre", "kilometre"), fromUnits); assertEquals(Set.of("metre", "kilometre"), toUnits); diff --git a/src/test/java/sevenUnitsGUI/RoundingTest.java b/src/test/java/sevenUnitsGUI/RoundingTest.java index ca1a272..f749f85 100644 --- a/src/test/java/sevenUnitsGUI/RoundingTest.java +++ b/src/test/java/sevenUnitsGUI/RoundingTest.java @@ -49,13 +49,13 @@ class RoundingTest { private static final FixedDecimals ZERO_DECIMALS = fixedDecimals(0); private static final FixedDecimals TWO_DECIMALS = fixedDecimals(2); private static final FixedDecimals SIX_DECIMALS = fixedDecimals(6); - + private static final FixedPrecision ONE_SIG_FIG = fixedPrecision(1); private static final FixedPrecision THREE_SIG_FIGS = fixedPrecision(3); private static final FixedPrecision TWELVE_SIG_FIGS = fixedPrecision(12); - + private static final UncertaintyBased UNCERTAINTY_BASED = uncertaintyBased(); - + // numbers to test rounding with private static final UncertainDouble INPUT1 = UncertainDouble.of(12.3456789, 0.0); @@ -65,7 +65,7 @@ class RoundingTest { 0.0); private static final UncertainDouble INPUT4 = UncertainDouble.of(0.00001234, 0.000001); - + /** * @return arguments for * {@link #testFixedDecimalRounding(UncertainDouble, String, String, String)} @@ -79,7 +79,7 @@ class RoundingTest { Arguments.of(INPUT3, "12345432", "12345432.10", "12345432.100000"), Arguments.of(INPUT4, "0", "0.00", "0.000012")); } - + /** * @return arguments for * {@link #testFixedPrecisionRounding(UncertainDouble, String, String, String)} @@ -93,7 +93,7 @@ class RoundingTest { Arguments.of(INPUT3, "1E+7", "1.23E+7", "12345432.1000"), Arguments.of(INPUT4, "0.00001", "0.0000123", "0.0000123400000000")); } - + /** * @return arguments for * {@link #testUncertaintyRounding(UncertainDouble, String)} @@ -107,7 +107,7 @@ class RoundingTest { Arguments.of(INPUT3, "1.23454321E7"), Arguments.of(INPUT4, "0.0000123")); } - + /** * Test for {@link FixedDecimals#decimalPlaces()} and * {@link FixedPrecision#significantFigures()}. @@ -124,7 +124,7 @@ class RoundingTest { "TWO_DECIMALS has " + TWO_DECIMALS.decimalPlaces() + " decimals"); assertEquals(6, SIX_DECIMALS.decimalPlaces(), "SIX_DECIMALS has " + SIX_DECIMALS.decimalPlaces() + " decimals"); - + // ensure # of sig figs can be accessed assertEquals(1, ONE_SIG_FIG.significantFigures(), "ONE_SIG_FIG has " + ONE_SIG_FIG.significantFigures() + " significant figures"); @@ -134,7 +134,7 @@ class RoundingTest { "TWELVE_SIG_FIGS has " + TWELVE_SIG_FIGS.significantFigures() + " significant figures"); } - + /** * Tests that the rounding methods' equals() methods work. * @@ -150,14 +150,14 @@ class RoundingTest { "TWO_DECIMALS == SIX_DECIMALS"); assertTrue(Objects.equals(fixedDecimals(0), fixedDecimals(0)), "FixedDecimals.equals() depends on something other than decimal places."); - + assertTrue(ONE_SIG_FIG.equals(ONE_SIG_FIG), "ONE_SIG_FIG does not equal itself"); assertFalse(THREE_SIG_FIGS.equals(TWELVE_SIG_FIGS), "THREE_SIG_FIGS == TWELVE_SIG_FIGS"); assertTrue(Objects.equals(fixedPrecision(1), fixedPrecision(1)), "FixedPrecision.equals() depends on something other than significant figures."); - + // test that FixedDecimals is never equal to FixedPrecision // this unlikely argument is the test - the equals should return false! @SuppressWarnings("unlikely-arg-type") @@ -165,7 +165,7 @@ class RoundingTest { fixedPrecision(4)); assertFalse(differentRulesEqual, "fixedDecimals(4) == fixedPrecision(4)"); } - + /** * Ensures that fixed decimal rounding works as expected * @@ -192,7 +192,7 @@ class RoundingTest { "TWO_DECIMALS rounded " + input + " as " + SIX_DECIMALS.apply(input) + " (should be " + sixDecimalString + ")"); } - + /** * Ensures that fixed precision rounding works as expected * @@ -221,7 +221,7 @@ class RoundingTest { + TWELVE_SIG_FIGS.apply(input) + " (should be " + twelveSigFigString + ")"); } - + /** * Tests that {@link StandardDisplayRules#getStandardRule} gets rounding * rules as intended. @@ -236,11 +236,11 @@ class RoundingTest { getStandardRule("Round to 3 significant figures")); assertEquals(UNCERTAINTY_BASED, getStandardRule("Uncertainty-Based Rounding")); - + assertThrows(IllegalArgumentException.class, () -> getStandardRule("Not a rounding rule")); } - + /** * Tests that the rounding methods' equals() methods work. * @@ -253,7 +253,7 @@ class RoundingTest { assertEquals(ONE_SIG_FIG.hashCode(), ONE_SIG_FIG.hashCode()); assertEquals(UNCERTAINTY_BASED.hashCode(), UNCERTAINTY_BASED.hashCode()); } - + /** * Tests that the {@code toString()} methods of the three rounding rule * classes work correctly. @@ -267,7 +267,7 @@ class RoundingTest { assertEquals("Round to 3 significant figures", THREE_SIG_FIGS.toString()); assertEquals("Uncertainty-Based Rounding", UNCERTAINTY_BASED.toString()); } - + /** * Tests that Uncertainty Rounding works as expected * diff --git a/src/test/java/sevenUnitsGUI/TabbedViewTest.java b/src/test/java/sevenUnitsGUI/TabbedViewTest.java index 00092a4..165718f 100644 --- a/src/test/java/sevenUnitsGUI/TabbedViewTest.java +++ b/src/test/java/sevenUnitsGUI/TabbedViewTest.java @@ -36,17 +36,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 +57,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 +78,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()); } - + } |