// © 2019 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include #include #include #include "numbertest.h" #include "ucbuf.h" #include "unicode/numberformatter.h" void NumberPermutationTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) { if (exec) { logln("TestSuite NumberPermutationTest: "); } TESTCASE_AUTO_BEGIN; TESTCASE_AUTO(testPermutations); TESTCASE_AUTO_END; } static const char16_t* kSkeletonParts[] = { // Notation u"compact-short", u"scientific/+ee/sign-always", nullptr, // Unit u"percent", u"currency/EUR", u"measure-unit/length-furlong", nullptr, // Unit Width u"unit-width-narrow", u"unit-width-full-name", nullptr, // Precision u"precision-integer", u".000", u".##/@@@+", u"@@", nullptr, // Rounding Mode u"rounding-mode-floor", nullptr, // Integer Width u"integer-width/##00", nullptr, // Scale u"scale/0.5", nullptr, // Grouping u"group-on-aligned", nullptr, // Symbols u"latin", nullptr, // Sign Display u"sign-accounting-except-zero", nullptr, // Decimal Separator Display u"decimal-always", nullptr, }; static const double kNumbersToTest[]{0, 91827.3645, -0.22222}; /** * Test permutations of 3 orthogonal skeleton parts from the list above. * Compare the results against the golden data file: * numberpermutationtest.txt * To regenerate that file, run intltest with the -e and -G options. * On Linux, from icu4c/source: * make -j8 tests && (cd test/intltest && LD_LIBRARY_PATH=../../lib:../../tools/ctestfw ./intltest -e -G format/NumberTest/NumberPermutationTest) * After re-generating the file, copy it into icu4j: * cp test/testdata/numberpermutationtest.txt ../../icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberpermutationtest.txt */ void NumberPermutationTest::testPermutations() { IcuTestErrorCode status(*this, "testPermutations"); const struct LocaleData { Locale locale; const char16_t* ustring; } localesToTest[] = { {"es-MX", u"es-MX"}, {"zh-TW", u"zh-TW"}, {"bn-BD", u"bn-BD"}, }; // Convert kSkeletonParts to a more convenient data structure auto skeletonParts = std::vector>(); auto currentSection = std::vector(); for (int32_t i = 0; i < UPRV_LENGTHOF(kSkeletonParts); i++) { const char16_t* skeletonPart = kSkeletonParts[i]; if (skeletonPart == nullptr) { skeletonParts.push_back(currentSection); currentSection.clear(); } else { currentSection.push_back(skeletonPart); } } // Build up the golden data string as we evaluate all permutations std::vector resultLines; resultLines.push_back(u"# © 2019 and later: Unicode, Inc. and others."); resultLines.push_back(u"# License & terms of use: http://www.unicode.org/copyright.html"); resultLines.push_back(UnicodeString()); // Take combinations of 3 orthogonal options for (size_t i = 0; i < skeletonParts.size() - 2; i++) { const auto& skeletons1 = skeletonParts[i]; for (size_t j = i + 1; j < skeletonParts.size() - 1; j++) { const auto& skeletons2 = skeletonParts[j]; for (size_t k = j + 1; k < skeletonParts.size(); k++) { const auto& skeletons3 = skeletonParts[k]; // Evaluate all combinations of skeletons for these options for (const auto& skel1 : skeletons1) { for (const auto& skel2 : skeletons2) { for (const auto& skel3 : skeletons3) { // Compute the skeleton UnicodeString skeleton; skeleton .append(skel1) // .append(u' ') // .append(skel2) // .append(u' ') // .append(skel3); resultLines.push_back(skeleton); // Check several locales and several numbers in each locale for (const auto& locData : localesToTest) { auto lnf = NumberFormatter::forSkeleton(skeleton, status) .locale(locData.locale); resultLines.push_back(UnicodeString(u" ").append(locData.ustring)); for (const auto& input : kNumbersToTest) { resultLines.push_back(UnicodeString(u" ").append( lnf.formatDouble(input, status).toTempString(status))); } } resultLines.push_back(UnicodeString()); } } } } // Quick mode: test all fields at least once but stop early. if (quick) { infoln(u"Quick mode: stopped after " + Int64ToUnicodeString(resultLines.size()) + u" lines"); goto outerEnd; } } } outerEnd: void(); CharString goldenFilePath(getSourceTestData(status), status); goldenFilePath.appendPathPart("numberpermutationtest.txt", status); // Compare it to the golden file const char* codePage = "UTF-8"; LocalUCHARBUFPointer f(ucbuf_open(goldenFilePath.data(), &codePage, TRUE, FALSE, status)); if (!assertSuccess("Can't open data file", status)) { return; } int32_t lineNumber = 1; int32_t lineLength; for (const auto& actualLine : resultLines) { const UChar* lineBuf = ucbuf_readline(f.getAlias(), &lineLength, status); if (lineBuf == nullptr) { errln("More lines generated than are in the data file!"); break; } UnicodeString expectedLine(lineBuf, lineLength - 1); assertEquals(u"Line #" + Int64ToUnicodeString(lineNumber) + u" differs", // expectedLine, actualLine); lineNumber++; } // Quick mode: test all fields at least once but stop early. if (!quick && ucbuf_readline(f.getAlias(), &lineLength, status) != nullptr) { errln("Fewer lines generated than are in the data file!"); } // Overwrite the golden data if requested if (write_golden_data) { std::ofstream outFile; outFile.open(goldenFilePath.data()); for (const auto& uniLine : resultLines) { std::string byteLine; uniLine.toUTF8String(byteLine); outFile << byteLine << std::endl; } outFile.close(); } } #endif /* #if !UCONFIG_NO_FORMATTING */