513b0c20b0
Adds a test suite in C++ and Java to test many permutations of options in NumberFormatter.
199 lines
6.6 KiB
C++
199 lines
6.6 KiB
C++
// © 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 */
|