]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/numbertest_permutation.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / test / intltest / numbertest_permutation.cpp
diff --git a/icuSources/test/intltest/numbertest_permutation.cpp b/icuSources/test/intltest/numbertest_permutation.cpp
new file mode 100644 (file)
index 0000000..85f32d5
--- /dev/null
@@ -0,0 +1,198 @@
+// © 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 -G option.
+ */
+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 */