diff --git a/src/main/java/com/thealgorithms/conversions/UnitsConverter.java b/src/main/java/com/thealgorithms/conversions/UnitsConverter.java index 81c4d4562..00690b2c0 100644 --- a/src/main/java/com/thealgorithms/conversions/UnitsConverter.java +++ b/src/main/java/com/thealgorithms/conversions/UnitsConverter.java @@ -7,6 +7,43 @@ import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.lang3.tuple.Pair; +/** + * A class that handles unit conversions using affine transformations. + * + *

The {@code UnitsConverter} allows converting values between different units using + * pre-defined affine conversion formulas. Each conversion is represented by an + * {@link AffineConverter} that defines the scaling and offset for the conversion. + * + *

For each unit, both direct conversions (e.g., Celsius to Fahrenheit) and inverse + * conversions (e.g., Fahrenheit to Celsius) are generated automatically. It also computes + * transitive conversions (e.g., Celsius to Kelvin via Fahrenheit if both conversions exist). + * + *

Key features include: + *

+ * + *

Example Usage

+ *
+ * Map<Pair<String, String>, AffineConverter> basicConversions = Map.ofEntries(
+ *     entry(Pair.of("Celsius", "Fahrenheit"), new AffineConverter(9.0 / 5.0, 32.0)),
+ *     entry(Pair.of("Kelvin", "Celsius"), new AffineConverter(1.0, -273.15))
+ * );
+ *
+ * UnitsConverter converter = new UnitsConverter(basicConversions);
+ * double result = converter.convert("Celsius", "Fahrenheit", 100.0);
+ * // Output: 212.0 (Celsius to Fahrenheit conversion of 100°C)
+ * 
+ * + *

Exception Handling

+ * + */ public final class UnitsConverter { private final Map, AffineConverter> conversions; private final Set units; @@ -68,11 +105,29 @@ public final class UnitsConverter { return res; } + /** + * Constructor for {@code UnitsConverter}. + * + *

Accepts a map of basic conversions and automatically generates inverse and + * transitive conversions. + * + * @param basicConversions the initial set of unit conversions to add. + */ public UnitsConverter(final Map, AffineConverter> basicConversions) { conversions = computeAllConversions(basicConversions); units = extractUnits(conversions); } + /** + * Converts a value from one unit to another. + * + * @param inputUnit the unit of the input value. + * @param outputUnit the unit to convert the value into. + * @param value the value to convert. + * @return the converted value in the target unit. + * @throws IllegalArgumentException if inputUnit equals outputUnit. + * @throws NoSuchElementException if no conversion exists between the units. + */ public double convert(final String inputUnit, final String outputUnit, final double value) { if (inputUnit.equals(outputUnit)) { throw new IllegalArgumentException("inputUnit must be different from outputUnit."); @@ -81,6 +136,11 @@ public final class UnitsConverter { return conversions.computeIfAbsent(conversionKey, k -> { throw new NoSuchElementException("No converter for: " + k); }).convert(value); } + /** + * Retrieves the set of all units supported by this converter. + * + * @return a set of available units. + */ public Set availableUnits() { return units; } diff --git a/src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java b/src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java index 580a66bc0..0952129ef 100644 --- a/src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java +++ b/src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java @@ -1,10 +1,12 @@ package com.thealgorithms.conversions; import static java.util.Map.entry; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Set; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; @@ -24,4 +26,19 @@ public class UnitsConverterTest { assertThrows(NoSuchElementException.class, () -> someConverter.convert("X", "A", 20.0)); assertThrows(NoSuchElementException.class, () -> someConverter.convert("X", "Y", 20.0)); } + + @Test + void testAvailableUnits() { + final UnitsConverter someConverter = new UnitsConverter(Map.ofEntries(entry(Pair.of("Celsius", "Fahrenheit"), new AffineConverter(9.0 / 5.0, 32.0)), entry(Pair.of("Kelvin", "Celsius"), new AffineConverter(1.0, -273.15)))); + assertEquals(Set.of("Celsius", "Fahrenheit", "Kelvin"), someConverter.availableUnits()); + } + + @Test + void testInvertConversion() { + final UnitsConverter someConverter = new UnitsConverter(Map.ofEntries(entry(Pair.of("A", "B"), new AffineConverter(2.0, 5.0)))); + // Check conversion from A -> B + assertEquals(25.0, someConverter.convert("A", "B", 10.0), 0.0001); + // Check inverse conversion from B -> A + assertEquals(10.0, someConverter.convert("B", "A", 25.0), 0.0001); + } }