From afafaf91deab10d8080ca8de1cc43febdfb9441e Mon Sep 17 00:00:00 2001 From: Hugo van der Merwe <17109322+hugovdm@users.noreply.github.com> Date: Thu, 5 Mar 2020 16:34:03 +0100 Subject: [PATCH] Read and fprintf unitsTest.txt data-driven unit tests --- icu4c/source/test/intltest/unitstest.cpp | 106 ++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/icu4c/source/test/intltest/unitstest.cpp b/icu4c/source/test/intltest/unitstest.cpp index 05a02f73cbf..0f564174ef3 100644 --- a/icu4c/source/test/intltest/unitstest.cpp +++ b/icu4c/source/test/intltest/unitstest.cpp @@ -5,9 +5,13 @@ #if !UCONFIG_NO_FORMATTING - #include "intltest.h" +#include "charstr.h" +#include "unicode/ctest.h" +#include "unicode/measunit.h" #include "unicode/unistr.h" +#include "unicode/unum.h" +#include "uparse.h" class UnitsTest : public IntlTest { public: @@ -15,6 +19,7 @@ class UnitsTest : public IntlTest { void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = NULL); + void testConversions(); void testBasic(); void testSiPrefixes(); void testMass(); @@ -29,6 +34,7 @@ void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha logln("TestSuite UnitsTest: "); } TESTCASE_AUTO_BEGIN; + TESTCASE_AUTO(testConversions); TESTCASE_AUTO(testBasic); TESTCASE_AUTO(testSiPrefixes); TESTCASE_AUTO(testMass); @@ -160,4 +166,102 @@ void UnitsTest::testArea() { } } +/** + * Returns a StringPiece pointing at the given field with space prefixes and + * postfixes trimmed off. + */ +StringPiece trimField(char *(&field)[2]) { + char *start = field[0]; + while (start < field[1] && (start[0]) == ' ') { + start++; + } + int32_t length = (int32_t)(field[1] - start); + while (length > 0 && (start[length - 1]) == ' ') { + length--; + } + return StringPiece(start, length); +} + +/** + * WIP(hugovdm): deals with a single data-driven unit test for unit conversions. + * This is a UParseLineFn as required by u_parseDelimitedFile. + */ +static void U_CALLCONV unitsTestDataLineFn(void *context, char *fields[][2], + int32_t fieldCount, + UErrorCode *pErrorCode) { + (void)fieldCount; // unused UParseLineFn variable + IcuTestErrorCode status(*(UnitsTest *)context, "unitsTestDatalineFn"); + + StringPiece quantity = trimField(fields[0]); + StringPiece x = trimField(fields[1]); + StringPiece y = trimField(fields[2]); + StringPiece commentConversionFormula = trimField(fields[3]); + StringPiece utf8Expected = trimField(fields[4]); + + UNumberFormat *nf = + unum_open(UNUM_DEFAULT, NULL, -1, "en_US", NULL, pErrorCode); + UnicodeString uExpected = UnicodeString::fromUTF8(utf8Expected); + double expected = unum_parseDouble(nf, uExpected.getBuffer(), + uExpected.length(), 0, pErrorCode); + unum_close(nf); + + MeasureUnit sourceUnit = MeasureUnit::forIdentifier(x, status); + if (status.errIfFailureAndReset("forIdentifier(\"%.*s\")", x.length(), + x.data())) { + return; + } + + MeasureUnit targetUnit = MeasureUnit::forIdentifier(y, status); + if (status.errIfFailureAndReset("forIdentifier(\"%.*s\")", y.length(), + y.data())) { + return; + } + + // WIP(hugovdm): hook this up to actual tests. + // + // Possible after merging in younies/tryingdouble: + // UnitConverter converter(sourceUnit, targetUnit, *pErrorCode); + // double got = converter.convert(1000, *pErrorCode); + // ((UnitsTest*)context)->assertEqualsNear(quantity.data(), expected, got, 0.0001); + // + // In the meantime, printing to stderr. + fprintf(stderr, + "Quantity (Category): \"%.*s\", " + "Expected value of \"1000 %.*s in %.*s\": %f, " + "commentConversionFormula: \"%.*s\", " + "expected field: \"%.*s\"\n", + quantity.length(), quantity.data(), + x.length(), x.data(), y.length(), y.data(), expected, + commentConversionFormula.length(), commentConversionFormula.data(), + utf8Expected.length(), utf8Expected.data()); +} + +/** + * Runs data-driven unit tests for unit conversion. It looks for the test cases + * in source/test/testdata/units/unitsTest.txt, which originates in CLDR. + */ +void UnitsTest::testConversions() { + const char *filename = "unitsTest.txt"; + const int32_t kNumFields = 5; + char *fields[kNumFields][2]; + + IcuTestErrorCode errorCode(*this, "UnitsTest::testConversions"); + const char *sourceTestDataPath = getSourceTestData(errorCode); + if (errorCode.errIfFailureAndReset("unable to find the source/test/testdata " + "folder (getSourceTestData())")) { + return; + } + + CharString path(sourceTestDataPath, errorCode); + path.appendPathPart("units", errorCode); + path.appendPathPart("unitsTest.txt", errorCode); + + u_parseDelimitedFile(path.data(), ';', fields, kNumFields, + unitsTestDataLineFn, this, errorCode); + if (U_FAILURE(errorCode)) { + log_err_status(errorCode, "error parsing %s: %s\n", filename, + u_errorName(errorCode)); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ -- 2.40.0