| // © 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 <fstream> |
| #include <iostream> |
| #include <vector> |
| |
| #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<std::vector<const char16_t*>>(); |
| auto currentSection = std::vector<const char16_t*>(); |
| 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<UnicodeString> 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 */ |