]> granicus.if.org Git - icu/commitdiff
Read and fprintf unitsTest.txt data-driven unit tests
authorHugo van der Merwe <17109322+hugovdm@users.noreply.github.com>
Thu, 5 Mar 2020 15:34:03 +0000 (16:34 +0100)
committerHugo van der Merwe <17109322+hugovdm@users.noreply.github.com>
Thu, 5 Mar 2020 15:34:03 +0000 (16:34 +0100)
icu4c/source/test/intltest/unitstest.cpp

index 05a02f73cbf55c7c54d30b8d4d43600710aea886..0f564174ef3a605ff425bdec41a7b6240023f53d 100644 (file)
@@ -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 */