ICU-21349 Add UnitsConverter.getConversionInfo(...)

See #1568
This commit is contained in:
younies 2021-02-10 11:48:35 +00:00 committed by Younies Mahmoud
parent 993e58a2c9
commit 916b9fad75
5 changed files with 211 additions and 0 deletions

View file

@ -593,6 +593,17 @@ double UnitsConverter::convertInverse(double inputValue) const {
return result;
}
ConversionInfo UnitsConverter::getConversionInfo() const {
ConversionInfo result;
result.conversionRate = conversionRate_.factorNum / conversionRate_.factorDen;
result.offset =
(conversionRate_.sourceOffset * (conversionRate_.factorNum / conversionRate_.factorDen)) -
conversionRate_.targetOffset;
result.reciprocal = conversionRate_.reciprocal;
return result;
}
} // namespace units
U_NAMESPACE_END

View file

@ -82,6 +82,12 @@ struct U_I18N_API Factor {
void substituteConstants();
};
struct U_I18N_API ConversionInfo {
double conversionRate;
double offset;
bool reciprocal;
};
/*
* Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
*/
@ -181,6 +187,8 @@ class U_I18N_API UnitsConverter : public UMemory {
*/
double convertInverse(double inputValue) const;
ConversionInfo getConversionInfo() const;
private:
ConversionRate conversionRate_;
};

View file

@ -45,6 +45,7 @@ class UnitsTest : public IntlTest {
void testUnitConstantFreshness();
void testExtractConvertibility();
void testConversionInfo();
void testConverterWithCLDRTests();
void testComplexUnitsConverter();
void testComplexUnitsConverterSorting();
@ -61,6 +62,7 @@ void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(testUnitConstantFreshness);
TESTCASE_AUTO(testExtractConvertibility);
TESTCASE_AUTO(testConversionInfo);
TESTCASE_AUTO(testConverterWithCLDRTests);
TESTCASE_AUTO(testComplexUnitsConverter);
TESTCASE_AUTO(testComplexUnitsConverterSorting);
@ -173,6 +175,94 @@ void UnitsTest::testExtractConvertibility() {
}
}
void UnitsTest::testConversionInfo() {
IcuTestErrorCode status(*this, "UnitsTest::testExtractConvertibility");
// Test Cases
struct TestCase {
const char *source;
const char *target;
const ConversionInfo expectedConversionInfo;
} testCases[]{
{
"meter",
"meter",
{1.0, 0, false},
},
{
"meter",
"foot",
{3.28084, 0, false},
},
{
"foot",
"meter",
{0.3048, 0, false},
},
{
"celsius",
"kelvin",
{1, 273.15, false},
},
{
"fahrenheit",
"kelvin",
{5.0 / 9.0, 255.372, false},
},
{
"fahrenheit",
"celsius",
{5.0 / 9.0, -17.7777777778, false},
},
{
"celsius",
"fahrenheit",
{9.0 / 5.0, 32, false},
},
{
"fahrenheit",
"fahrenheit",
{1.0, 0, false},
},
{
"mile-per-gallon",
"liter-per-100-kilometer",
{0.00425143707, 0, true},
},
};
ConversionRates rates(status);
for (const auto &testCase : testCases) {
auto sourceImpl = MeasureUnitImpl::forIdentifier(testCase.source, status);
auto targetImpl = MeasureUnitImpl::forIdentifier(testCase.target, status);
UnitsConverter unitsConverter(sourceImpl, targetImpl, rates, status);
if (status.errIfFailureAndReset()) {
continue;
}
ConversionInfo actualConversionInfo = unitsConverter.getConversionInfo();
UnicodeString message =
UnicodeString("testConverter: ") + testCase.source + " to " + testCase.target;
double maxDelta = 1e-6 * uprv_fabs(testCase.expectedConversionInfo.conversionRate);
if (testCase.expectedConversionInfo.conversionRate == 0) {
maxDelta = 1e-12;
}
assertEqualsNear(message + ", conversion rate: ", testCase.expectedConversionInfo.conversionRate,
actualConversionInfo.conversionRate, maxDelta);
maxDelta = 1e-6 * uprv_fabs(testCase.expectedConversionInfo.offset);
if (testCase.expectedConversionInfo.offset == 0) {
maxDelta = 1e-12;
}
assertEqualsNear(message + ", offset: ", testCase.expectedConversionInfo.offset, actualConversionInfo.offset,
maxDelta);
assertEquals(message + ", reciprocal: ", testCase.expectedConversionInfo.reciprocal,
actualConversionInfo.reciprocal);
}
}
void UnitsTest::testConverter() {
IcuTestErrorCode status(*this, "UnitsTest::testConverter");

View file

@ -127,6 +127,21 @@ public class UnitsConverter {
UNCONVERTIBLE,
}
public ConversionInfo getConversionInfo() {
ConversionInfo result = new ConversionInfo();
result.conversionRate = this.conversionRate;
result.offset = this.offset;
result.reciprocal = this.reciprocal;
return result;
}
public static class ConversionInfo {
public BigDecimal conversionRate;
public BigDecimal offset;
public boolean reciprocal;
}
/**
* Responsible for all the Factor operation
* NOTE:

View file

@ -271,6 +271,93 @@ public class UnitsTest {
}
}
@Test
public void testConversionInfo() {
class TestData {
String source;
String target;
UnitsConverter.ConversionInfo expected = new UnitsConverter.ConversionInfo();
public TestData(String source, String target, double conversionRate, double offset, Boolean reciprocal) {
this.source = source;
this.target = target;
this.expected.conversionRate = BigDecimal.valueOf(conversionRate);
this.expected.offset = BigDecimal.valueOf(offset);
this.expected.reciprocal = reciprocal;
}
}
TestData[] tests = {
new TestData(
"meter",
"meter",
1.0, 0, false),
new TestData(
"meter",
"foot",
3.28084, 0, false),
new TestData(
"foot",
"meter",
0.3048, 0, false),
new TestData(
"celsius",
"kelvin",
1, 273.15, false),
new TestData(
"fahrenheit",
"kelvin",
5.0 / 9.0, 255.372, false),
new TestData(
"fahrenheit",
"celsius",
5.0 / 9.0, -17.7777777778, false),
new TestData(
"celsius",
"fahrenheit",
9.0 / 5.0, 32, false),
new TestData(
"fahrenheit",
"fahrenheit",
1.0, 0, false),
new TestData(
"mile-per-gallon",
"liter-per-100-kilometer",
0.00425143707, 0, true),
};
ConversionRates conversionRates = new ConversionRates();
for (TestData test : tests) {
MeasureUnitImpl sourceImpl = MeasureUnitImpl.forIdentifier(test.source);
MeasureUnitImpl targetImpl = MeasureUnitImpl.forIdentifier(test.target);
UnitsConverter unitsConverter = new UnitsConverter(sourceImpl, targetImpl, conversionRates);
UnitsConverter.ConversionInfo actual = unitsConverter.getConversionInfo();
// Test conversion Rate
double maxDelta = 1e-6 * Math.abs(test.expected.conversionRate.doubleValue());
if (test.expected.conversionRate.doubleValue() == 0) {
maxDelta = 1e-12;
}
assertEquals("testConversionInfo for conversion rate: " + test.source + " to " + test.target,
test.expected.conversionRate.doubleValue(), actual.conversionRate.doubleValue(),
maxDelta);
// Test offset
maxDelta = 1e-6 * Math.abs(test.expected.offset.doubleValue());
if (test.expected.offset.doubleValue() == 0) {
maxDelta = 1e-12;
}
assertEquals("testConversionInfo for offset: " + test.source + " to " + test.target,
test.expected.offset.doubleValue(), actual.offset.doubleValue(),
maxDelta);
// Test Reciprocal
assertEquals("testConversionInfo for reciprocal: " + test.source + " to " + test.target,
test.expected.reciprocal, actual.reciprocal);
}
}
@Test
public void testConverter() {
class TestData {