12e5b6d6dSopenharmony_ci// © 2017 and later: Unicode, Inc. and others. 22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 32e5b6d6dSopenharmony_ci 42e5b6d6dSopenharmony_ci#include "unicode/utypes.h" 52e5b6d6dSopenharmony_ci 62e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING 72e5b6d6dSopenharmony_ci 82e5b6d6dSopenharmony_ci#include "unicode/dcfmtsym.h" 92e5b6d6dSopenharmony_ci 102e5b6d6dSopenharmony_ci#include "cstr.h" 112e5b6d6dSopenharmony_ci#include "numbertest.h" 122e5b6d6dSopenharmony_ci#include "number_utils.h" 132e5b6d6dSopenharmony_ci#include "number_skeletons.h" 142e5b6d6dSopenharmony_ci#include "putilimp.h" 152e5b6d6dSopenharmony_ci 162e5b6d6dSopenharmony_ciusing namespace icu::number::impl; 172e5b6d6dSopenharmony_ci 182e5b6d6dSopenharmony_ci 192e5b6d6dSopenharmony_civoid NumberSkeletonTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) { 202e5b6d6dSopenharmony_ci if (exec) { 212e5b6d6dSopenharmony_ci logln("TestSuite AffixUtilsTest: "); 222e5b6d6dSopenharmony_ci } 232e5b6d6dSopenharmony_ci TESTCASE_AUTO_BEGIN; 242e5b6d6dSopenharmony_ci TESTCASE_AUTO(validTokens); 252e5b6d6dSopenharmony_ci TESTCASE_AUTO(invalidTokens); 262e5b6d6dSopenharmony_ci TESTCASE_AUTO(unknownTokens); 272e5b6d6dSopenharmony_ci TESTCASE_AUTO(unexpectedTokens); 282e5b6d6dSopenharmony_ci TESTCASE_AUTO(duplicateValues); 292e5b6d6dSopenharmony_ci TESTCASE_AUTO(stemsRequiringOption); 302e5b6d6dSopenharmony_ci TESTCASE_AUTO(defaultTokens); 312e5b6d6dSopenharmony_ci TESTCASE_AUTO(flexibleSeparators); 322e5b6d6dSopenharmony_ci TESTCASE_AUTO(wildcardCharacters); 332e5b6d6dSopenharmony_ci TESTCASE_AUTO(perUnitInArabic); 342e5b6d6dSopenharmony_ci TESTCASE_AUTO(perUnitToSkeleton); 352e5b6d6dSopenharmony_ci TESTCASE_AUTO_END; 362e5b6d6dSopenharmony_ci} 372e5b6d6dSopenharmony_ci 382e5b6d6dSopenharmony_civoid NumberSkeletonTest::validTokens() { 392e5b6d6dSopenharmony_ci IcuTestErrorCode status(*this, "validTokens"); 402e5b6d6dSopenharmony_ci 412e5b6d6dSopenharmony_ci // This tests only if the tokens are valid, not their behavior. 422e5b6d6dSopenharmony_ci // Most of these are from the design doc. 432e5b6d6dSopenharmony_ci static const char16_t* cases[] = { 442e5b6d6dSopenharmony_ci u"precision-integer", 452e5b6d6dSopenharmony_ci u"precision-unlimited", 462e5b6d6dSopenharmony_ci u"@@@##", 472e5b6d6dSopenharmony_ci u"@@*", 482e5b6d6dSopenharmony_ci u"@@+", 492e5b6d6dSopenharmony_ci u"@@+/w", 502e5b6d6dSopenharmony_ci u".000##", 512e5b6d6dSopenharmony_ci u".00*", 522e5b6d6dSopenharmony_ci u".00+", 532e5b6d6dSopenharmony_ci u".", 542e5b6d6dSopenharmony_ci u"./w", 552e5b6d6dSopenharmony_ci u".*", 562e5b6d6dSopenharmony_ci u".+", 572e5b6d6dSopenharmony_ci u".+/w", 582e5b6d6dSopenharmony_ci u".######", 592e5b6d6dSopenharmony_ci u".00/@@*", 602e5b6d6dSopenharmony_ci u".00/@@+", 612e5b6d6dSopenharmony_ci u".00/@##", 622e5b6d6dSopenharmony_ci u".00/@##/w", 632e5b6d6dSopenharmony_ci u".00/@", 642e5b6d6dSopenharmony_ci u".00/@r", 652e5b6d6dSopenharmony_ci u".00/@@s", 662e5b6d6dSopenharmony_ci u".00/@@#r", 672e5b6d6dSopenharmony_ci u"precision-increment/3.14", 682e5b6d6dSopenharmony_ci u"precision-increment/3.14/w", 692e5b6d6dSopenharmony_ci u"precision-currency-standard", 702e5b6d6dSopenharmony_ci u"precision-currency-standard/w", 712e5b6d6dSopenharmony_ci u"precision-integer rounding-mode-half-up", 722e5b6d6dSopenharmony_ci u".00# rounding-mode-ceiling", 732e5b6d6dSopenharmony_ci u".00/@@* rounding-mode-floor", 742e5b6d6dSopenharmony_ci u".00/@@+ rounding-mode-floor", 752e5b6d6dSopenharmony_ci u"scientific", 762e5b6d6dSopenharmony_ci u"scientific/*ee", 772e5b6d6dSopenharmony_ci u"scientific/+ee", 782e5b6d6dSopenharmony_ci u"scientific/sign-always", 792e5b6d6dSopenharmony_ci u"scientific/*ee/sign-always", 802e5b6d6dSopenharmony_ci u"scientific/+ee/sign-always", 812e5b6d6dSopenharmony_ci u"scientific/sign-always/*ee", 822e5b6d6dSopenharmony_ci u"scientific/sign-always/+ee", 832e5b6d6dSopenharmony_ci u"scientific/sign-except-zero", 842e5b6d6dSopenharmony_ci u"engineering", 852e5b6d6dSopenharmony_ci u"engineering/*eee", 862e5b6d6dSopenharmony_ci u"engineering/+eee", 872e5b6d6dSopenharmony_ci u"compact-short", 882e5b6d6dSopenharmony_ci u"compact-long", 892e5b6d6dSopenharmony_ci u"notation-simple", 902e5b6d6dSopenharmony_ci u"percent", 912e5b6d6dSopenharmony_ci u"permille", 922e5b6d6dSopenharmony_ci u"measure-unit/length-meter", 932e5b6d6dSopenharmony_ci u"measure-unit/area-square-meter", 942e5b6d6dSopenharmony_ci u"measure-unit/energy-joule per-measure-unit/length-meter", 952e5b6d6dSopenharmony_ci u"unit/square-meter-per-square-meter", 962e5b6d6dSopenharmony_ci u"currency/XXX", 972e5b6d6dSopenharmony_ci u"currency/ZZZ", 982e5b6d6dSopenharmony_ci u"currency/usd", 992e5b6d6dSopenharmony_ci u"group-off", 1002e5b6d6dSopenharmony_ci u"group-min2", 1012e5b6d6dSopenharmony_ci u"group-auto", 1022e5b6d6dSopenharmony_ci u"group-on-aligned", 1032e5b6d6dSopenharmony_ci u"group-thousands", 1042e5b6d6dSopenharmony_ci u"integer-width/00", 1052e5b6d6dSopenharmony_ci u"integer-width/#0", 1062e5b6d6dSopenharmony_ci u"integer-width/*00", 1072e5b6d6dSopenharmony_ci u"integer-width/+00", 1082e5b6d6dSopenharmony_ci u"sign-always", 1092e5b6d6dSopenharmony_ci u"sign-auto", 1102e5b6d6dSopenharmony_ci u"sign-never", 1112e5b6d6dSopenharmony_ci u"sign-accounting", 1122e5b6d6dSopenharmony_ci u"sign-accounting-always", 1132e5b6d6dSopenharmony_ci u"sign-except-zero", 1142e5b6d6dSopenharmony_ci u"sign-accounting-except-zero", 1152e5b6d6dSopenharmony_ci u"unit-width-narrow", 1162e5b6d6dSopenharmony_ci u"unit-width-short", 1172e5b6d6dSopenharmony_ci u"unit-width-iso-code", 1182e5b6d6dSopenharmony_ci u"unit-width-full-name", 1192e5b6d6dSopenharmony_ci u"unit-width-hidden", 1202e5b6d6dSopenharmony_ci u"decimal-auto", 1212e5b6d6dSopenharmony_ci u"decimal-always", 1222e5b6d6dSopenharmony_ci u"scale/5.2", 1232e5b6d6dSopenharmony_ci u"scale/-5.2", 1242e5b6d6dSopenharmony_ci u"scale/100", 1252e5b6d6dSopenharmony_ci u"scale/1E2", 1262e5b6d6dSopenharmony_ci u"scale/1", 1272e5b6d6dSopenharmony_ci u"latin", 1282e5b6d6dSopenharmony_ci u"numbering-system/arab", 1292e5b6d6dSopenharmony_ci u"numbering-system/latn", 1302e5b6d6dSopenharmony_ci u"precision-integer/@##", 1312e5b6d6dSopenharmony_ci u"precision-integer rounding-mode-ceiling", 1322e5b6d6dSopenharmony_ci u"precision-currency-cash rounding-mode-ceiling", 1332e5b6d6dSopenharmony_ci u"0", 1342e5b6d6dSopenharmony_ci u"00", 1352e5b6d6dSopenharmony_ci u"000", 1362e5b6d6dSopenharmony_ci u"E0", 1372e5b6d6dSopenharmony_ci u"E00", 1382e5b6d6dSopenharmony_ci u"E000", 1392e5b6d6dSopenharmony_ci u"EE0", 1402e5b6d6dSopenharmony_ci u"EE00", 1412e5b6d6dSopenharmony_ci u"EE+?0", 1422e5b6d6dSopenharmony_ci u"EE+?00", 1432e5b6d6dSopenharmony_ci u"EE+!0", 1442e5b6d6dSopenharmony_ci u"EE+!00", 1452e5b6d6dSopenharmony_ci }; 1462e5b6d6dSopenharmony_ci 1472e5b6d6dSopenharmony_ci for (auto& cas : cases) { 1482e5b6d6dSopenharmony_ci UnicodeString skeletonString(cas); 1492e5b6d6dSopenharmony_ci status.setScope(skeletonString); 1502e5b6d6dSopenharmony_ci UParseError perror; 1512e5b6d6dSopenharmony_ci NumberFormatter::forSkeleton(skeletonString, perror, status); 1522e5b6d6dSopenharmony_ci assertSuccess(CStr(skeletonString)(), status, true); 1532e5b6d6dSopenharmony_ci assertEquals(skeletonString, -1, perror.offset); 1542e5b6d6dSopenharmony_ci status.errIfFailureAndReset(); 1552e5b6d6dSopenharmony_ci } 1562e5b6d6dSopenharmony_ci} 1572e5b6d6dSopenharmony_ci 1582e5b6d6dSopenharmony_civoid NumberSkeletonTest::invalidTokens() { 1592e5b6d6dSopenharmony_ci static const char16_t* cases[] = { 1602e5b6d6dSopenharmony_ci u".00x", 1612e5b6d6dSopenharmony_ci u".00i", 1622e5b6d6dSopenharmony_ci u".00/x", 1632e5b6d6dSopenharmony_ci u".00/ww", 1642e5b6d6dSopenharmony_ci u".00##0", 1652e5b6d6dSopenharmony_ci u".##*", 1662e5b6d6dSopenharmony_ci u".00##*", 1672e5b6d6dSopenharmony_ci u".0#*", 1682e5b6d6dSopenharmony_ci u"@#*", 1692e5b6d6dSopenharmony_ci u".##+", 1702e5b6d6dSopenharmony_ci u".00##+", 1712e5b6d6dSopenharmony_ci u".0#+", 1722e5b6d6dSopenharmony_ci u"@#+", 1732e5b6d6dSopenharmony_ci u"@@x", 1742e5b6d6dSopenharmony_ci u"@@##0", 1752e5b6d6dSopenharmony_ci u".00/@@", 1762e5b6d6dSopenharmony_ci u".00/@@x", 1772e5b6d6dSopenharmony_ci u".00/@@#", 1782e5b6d6dSopenharmony_ci u".00/@@#*", 1792e5b6d6dSopenharmony_ci u".00/floor/@@*", // wrong order 1802e5b6d6dSopenharmony_ci u".00/@@#+", 1812e5b6d6dSopenharmony_ci u".00/@@@+r", 1822e5b6d6dSopenharmony_ci u".00/floor/@@+", // wrong order 1832e5b6d6dSopenharmony_ci u"precision-increment/français", // non-invariant characters for C++ 1842e5b6d6dSopenharmony_ci u"scientific/ee", 1852e5b6d6dSopenharmony_ci u"precision-increment/xxx", 1862e5b6d6dSopenharmony_ci u"precision-increment/NaN", 1872e5b6d6dSopenharmony_ci u"precision-increment/Infinity", 1882e5b6d6dSopenharmony_ci u"precision-increment/0.1.2", 1892e5b6d6dSopenharmony_ci u"scale/xxx", 1902e5b6d6dSopenharmony_ci u"scale/NaN", 1912e5b6d6dSopenharmony_ci u"scale/Infinity", 1922e5b6d6dSopenharmony_ci u"scale/0.1.2", 1932e5b6d6dSopenharmony_ci u"scale/français", // non-invariant characters for C++ 1942e5b6d6dSopenharmony_ci u"currency/dummy", 1952e5b6d6dSopenharmony_ci u"currency/ççç", // three characters but not ASCII 1962e5b6d6dSopenharmony_ci u"measure-unit/foo", 1972e5b6d6dSopenharmony_ci u"integer-width/xxx", 1982e5b6d6dSopenharmony_ci u"integer-width/0*", 1992e5b6d6dSopenharmony_ci u"integer-width/*0#", 2002e5b6d6dSopenharmony_ci u"integer-width/*#", 2012e5b6d6dSopenharmony_ci u"integer-width/*#0", 2022e5b6d6dSopenharmony_ci u"integer-width/0+", 2032e5b6d6dSopenharmony_ci u"integer-width/+0#", 2042e5b6d6dSopenharmony_ci u"integer-width/+#", 2052e5b6d6dSopenharmony_ci u"integer-width/+#0", 2062e5b6d6dSopenharmony_ci u"scientific/foo", 2072e5b6d6dSopenharmony_ci u"E", 2082e5b6d6dSopenharmony_ci u"E1", 2092e5b6d6dSopenharmony_ci u"E+", 2102e5b6d6dSopenharmony_ci u"E+?", 2112e5b6d6dSopenharmony_ci u"E+!", 2122e5b6d6dSopenharmony_ci u"E+0", 2132e5b6d6dSopenharmony_ci u"EE", 2142e5b6d6dSopenharmony_ci u"EE+", 2152e5b6d6dSopenharmony_ci u"EEE", 2162e5b6d6dSopenharmony_ci u"EEE0", 2172e5b6d6dSopenharmony_ci u"001", 2182e5b6d6dSopenharmony_ci u"00*", 2192e5b6d6dSopenharmony_ci u"00+", 2202e5b6d6dSopenharmony_ci }; 2212e5b6d6dSopenharmony_ci 2222e5b6d6dSopenharmony_ci expectedErrorSkeleton(cases, UPRV_LENGTHOF(cases)); 2232e5b6d6dSopenharmony_ci} 2242e5b6d6dSopenharmony_ci 2252e5b6d6dSopenharmony_civoid NumberSkeletonTest::unknownTokens() { 2262e5b6d6dSopenharmony_ci static const char16_t* cases[] = { 2272e5b6d6dSopenharmony_ci u"maesure-unit", 2282e5b6d6dSopenharmony_ci u"measure-unit/foo-bar", 2292e5b6d6dSopenharmony_ci u"numbering-system/dummy", 2302e5b6d6dSopenharmony_ci u"français", 2312e5b6d6dSopenharmony_ci u"measure-unit/français-français", // non-invariant characters for C++ 2322e5b6d6dSopenharmony_ci u"numbering-system/français", // non-invariant characters for C++ 2332e5b6d6dSopenharmony_ci u"currency-USD"}; 2342e5b6d6dSopenharmony_ci 2352e5b6d6dSopenharmony_ci expectedErrorSkeleton(cases, UPRV_LENGTHOF(cases)); 2362e5b6d6dSopenharmony_ci} 2372e5b6d6dSopenharmony_ci 2382e5b6d6dSopenharmony_civoid NumberSkeletonTest::unexpectedTokens() { 2392e5b6d6dSopenharmony_ci static const char16_t* cases[] = { 2402e5b6d6dSopenharmony_ci u".00/w/w", 2412e5b6d6dSopenharmony_ci u"group-thousands/foo", 2422e5b6d6dSopenharmony_ci u"precision-integer//@## group-off", 2432e5b6d6dSopenharmony_ci u"precision-integer//@## group-off", 2442e5b6d6dSopenharmony_ci u"precision-integer/ group-off", 2452e5b6d6dSopenharmony_ci u"precision-integer// group-off"}; 2462e5b6d6dSopenharmony_ci 2472e5b6d6dSopenharmony_ci expectedErrorSkeleton(cases, UPRV_LENGTHOF(cases)); 2482e5b6d6dSopenharmony_ci} 2492e5b6d6dSopenharmony_ci 2502e5b6d6dSopenharmony_civoid NumberSkeletonTest::duplicateValues() { 2512e5b6d6dSopenharmony_ci static const char16_t* cases[] = { 2522e5b6d6dSopenharmony_ci u"precision-integer precision-integer", 2532e5b6d6dSopenharmony_ci u"precision-integer .00+", 2542e5b6d6dSopenharmony_ci u"precision-integer precision-unlimited", 2552e5b6d6dSopenharmony_ci u"precision-integer @@@", 2562e5b6d6dSopenharmony_ci u"scientific engineering", 2572e5b6d6dSopenharmony_ci u"engineering compact-long", 2582e5b6d6dSopenharmony_ci u"sign-auto sign-always"}; 2592e5b6d6dSopenharmony_ci 2602e5b6d6dSopenharmony_ci expectedErrorSkeleton(cases, UPRV_LENGTHOF(cases)); 2612e5b6d6dSopenharmony_ci} 2622e5b6d6dSopenharmony_ci 2632e5b6d6dSopenharmony_civoid NumberSkeletonTest::stemsRequiringOption() { 2642e5b6d6dSopenharmony_ci static const char16_t* stems[] = { 2652e5b6d6dSopenharmony_ci u"precision-increment", 2662e5b6d6dSopenharmony_ci u"measure-unit", 2672e5b6d6dSopenharmony_ci u"per-measure-unit", 2682e5b6d6dSopenharmony_ci u"currency", 2692e5b6d6dSopenharmony_ci u"integer-width", 2702e5b6d6dSopenharmony_ci u"numbering-system", 2712e5b6d6dSopenharmony_ci u"scale"}; 2722e5b6d6dSopenharmony_ci static const char16_t* suffixes[] = {u"", u"/@##", u" scientific", u"/@## scientific"}; 2732e5b6d6dSopenharmony_ci 2742e5b6d6dSopenharmony_ci for (auto& stem : stems) { 2752e5b6d6dSopenharmony_ci for (auto& suffix : suffixes) { 2762e5b6d6dSopenharmony_ci UnicodeString skeletonString = UnicodeString(stem) + suffix; 2772e5b6d6dSopenharmony_ci UErrorCode status = U_ZERO_ERROR; 2782e5b6d6dSopenharmony_ci UParseError perror; 2792e5b6d6dSopenharmony_ci NumberFormatter::forSkeleton(skeletonString, perror, status); 2802e5b6d6dSopenharmony_ci assertEquals(skeletonString, U_NUMBER_SKELETON_SYNTAX_ERROR, status); 2812e5b6d6dSopenharmony_ci 2822e5b6d6dSopenharmony_ci // Check the UParseError for integrity. 2832e5b6d6dSopenharmony_ci // If an option is present, the option is wrong; error offset is at the start of the option 2842e5b6d6dSopenharmony_ci // If an option is not present, the error offset is at the token separator (end of stem) 2852e5b6d6dSopenharmony_ci int32_t expectedOffset = u_strlen(stem) + ((suffix[0] == u'/') ? 1 : 0); 2862e5b6d6dSopenharmony_ci assertEquals(skeletonString, expectedOffset, perror.offset); 2872e5b6d6dSopenharmony_ci UnicodeString expectedPreContext = skeletonString.tempSubString(0, expectedOffset); 2882e5b6d6dSopenharmony_ci if (expectedPreContext.length() >= U_PARSE_CONTEXT_LEN - 1) { 2892e5b6d6dSopenharmony_ci expectedPreContext = expectedPreContext.tempSubString(expectedOffset - U_PARSE_CONTEXT_LEN + 1); 2902e5b6d6dSopenharmony_ci } 2912e5b6d6dSopenharmony_ci assertEquals(skeletonString, expectedPreContext, perror.preContext); 2922e5b6d6dSopenharmony_ci UnicodeString expectedPostContext = skeletonString.tempSubString(expectedOffset); 2932e5b6d6dSopenharmony_ci // None of the postContext strings in this test exceed U_PARSE_CONTEXT_LEN 2942e5b6d6dSopenharmony_ci assertEquals(skeletonString, expectedPostContext, perror.postContext); 2952e5b6d6dSopenharmony_ci } 2962e5b6d6dSopenharmony_ci } 2972e5b6d6dSopenharmony_ci} 2982e5b6d6dSopenharmony_ci 2992e5b6d6dSopenharmony_civoid NumberSkeletonTest::defaultTokens() { 3002e5b6d6dSopenharmony_ci IcuTestErrorCode status(*this, "defaultTokens"); 3012e5b6d6dSopenharmony_ci 3022e5b6d6dSopenharmony_ci static const char16_t* cases[] = { 3032e5b6d6dSopenharmony_ci u"notation-simple", 3042e5b6d6dSopenharmony_ci u"base-unit", 3052e5b6d6dSopenharmony_ci u"group-auto", 3062e5b6d6dSopenharmony_ci u"integer-width/+0", 3072e5b6d6dSopenharmony_ci u"sign-auto", 3082e5b6d6dSopenharmony_ci u"unit-width-short", 3092e5b6d6dSopenharmony_ci u"decimal-auto"}; 3102e5b6d6dSopenharmony_ci 3112e5b6d6dSopenharmony_ci for (auto& cas : cases) { 3122e5b6d6dSopenharmony_ci UnicodeString skeletonString(cas); 3132e5b6d6dSopenharmony_ci status.setScope(skeletonString); 3142e5b6d6dSopenharmony_ci UnicodeString normalized = NumberFormatter::forSkeleton( 3152e5b6d6dSopenharmony_ci skeletonString, status).toSkeleton(status); 3162e5b6d6dSopenharmony_ci // Skeleton should become empty when normalized 3172e5b6d6dSopenharmony_ci assertEquals(skeletonString, u"", normalized); 3182e5b6d6dSopenharmony_ci status.errIfFailureAndReset(); 3192e5b6d6dSopenharmony_ci } 3202e5b6d6dSopenharmony_ci} 3212e5b6d6dSopenharmony_ci 3222e5b6d6dSopenharmony_civoid NumberSkeletonTest::flexibleSeparators() { 3232e5b6d6dSopenharmony_ci IcuTestErrorCode status(*this, "flexibleSeparators"); 3242e5b6d6dSopenharmony_ci 3252e5b6d6dSopenharmony_ci static struct TestCase { 3262e5b6d6dSopenharmony_ci const char16_t* skeleton; 3272e5b6d6dSopenharmony_ci const char16_t* expected; 3282e5b6d6dSopenharmony_ci } cases[] = {{u"precision-integer group-off", u"5142"}, 3292e5b6d6dSopenharmony_ci {u"precision-integer group-off", u"5142"}, 3302e5b6d6dSopenharmony_ci {u"precision-integer/@## group-off", u"5140"}, 3312e5b6d6dSopenharmony_ci {u"precision-integer/@## group-off", u"5140"}}; 3322e5b6d6dSopenharmony_ci 3332e5b6d6dSopenharmony_ci for (auto& cas : cases) { 3342e5b6d6dSopenharmony_ci UnicodeString skeletonString(cas.skeleton); 3352e5b6d6dSopenharmony_ci UnicodeString expected(cas.expected); 3362e5b6d6dSopenharmony_ci status.setScope(skeletonString); 3372e5b6d6dSopenharmony_ci UnicodeString actual = NumberFormatter::forSkeleton(skeletonString, status).locale("en") 3382e5b6d6dSopenharmony_ci .formatDouble(5142.3, status) 3392e5b6d6dSopenharmony_ci .toString(status); 3402e5b6d6dSopenharmony_ci if (!status.errDataIfFailureAndReset()) { 3412e5b6d6dSopenharmony_ci assertEquals(skeletonString, expected, actual); 3422e5b6d6dSopenharmony_ci } 3432e5b6d6dSopenharmony_ci status.errIfFailureAndReset(); 3442e5b6d6dSopenharmony_ci } 3452e5b6d6dSopenharmony_ci} 3462e5b6d6dSopenharmony_ci 3472e5b6d6dSopenharmony_civoid NumberSkeletonTest::wildcardCharacters() { 3482e5b6d6dSopenharmony_ci IcuTestErrorCode status(*this, "wildcardCharacters"); 3492e5b6d6dSopenharmony_ci 3502e5b6d6dSopenharmony_ci struct TestCase { 3512e5b6d6dSopenharmony_ci const char16_t* star; 3522e5b6d6dSopenharmony_ci const char16_t* plus; 3532e5b6d6dSopenharmony_ci } cases[] = { 3542e5b6d6dSopenharmony_ci { u".00*", u".00+" }, 3552e5b6d6dSopenharmony_ci { u"@@*", u"@@+" }, 3562e5b6d6dSopenharmony_ci { u"scientific/*ee", u"scientific/+ee" }, 3572e5b6d6dSopenharmony_ci { u"integer-width/*00", u"integer-width/+00" }, 3582e5b6d6dSopenharmony_ci }; 3592e5b6d6dSopenharmony_ci 3602e5b6d6dSopenharmony_ci for (const auto& cas : cases) { 3612e5b6d6dSopenharmony_ci UnicodeString star(cas.star); 3622e5b6d6dSopenharmony_ci UnicodeString plus(cas.plus); 3632e5b6d6dSopenharmony_ci status.setScope(star); 3642e5b6d6dSopenharmony_ci 3652e5b6d6dSopenharmony_ci UnicodeString normalized = NumberFormatter::forSkeleton(plus, status) 3662e5b6d6dSopenharmony_ci .toSkeleton(status); 3672e5b6d6dSopenharmony_ci assertEquals("Plus should normalize to star", star, normalized); 3682e5b6d6dSopenharmony_ci status.errIfFailureAndReset(); 3692e5b6d6dSopenharmony_ci } 3702e5b6d6dSopenharmony_ci} 3712e5b6d6dSopenharmony_ci 3722e5b6d6dSopenharmony_ci// In C++, there is no distinguishing between "invalid", "unknown", and "unexpected" tokens. 3732e5b6d6dSopenharmony_civoid NumberSkeletonTest::expectedErrorSkeleton(const char16_t** cases, int32_t casesLen) { 3742e5b6d6dSopenharmony_ci for (int32_t i = 0; i < casesLen; i++) { 3752e5b6d6dSopenharmony_ci UnicodeString skeletonString(cases[i]); 3762e5b6d6dSopenharmony_ci UErrorCode status = U_ZERO_ERROR; 3772e5b6d6dSopenharmony_ci NumberFormatter::forSkeleton(skeletonString, status); 3782e5b6d6dSopenharmony_ci assertEquals(skeletonString, U_NUMBER_SKELETON_SYNTAX_ERROR, status); 3792e5b6d6dSopenharmony_ci } 3802e5b6d6dSopenharmony_ci} 3812e5b6d6dSopenharmony_ci 3822e5b6d6dSopenharmony_civoid NumberSkeletonTest::perUnitInArabic() { 3832e5b6d6dSopenharmony_ci IcuTestErrorCode status(*this, "perUnitInArabic"); 3842e5b6d6dSopenharmony_ci 3852e5b6d6dSopenharmony_ci struct TestCase { 3862e5b6d6dSopenharmony_ci const char16_t* type; 3872e5b6d6dSopenharmony_ci const char16_t* subtype; 3882e5b6d6dSopenharmony_ci } cases[] = { 3892e5b6d6dSopenharmony_ci {u"area", u"acre"}, 3902e5b6d6dSopenharmony_ci {u"digital", u"bit"}, 3912e5b6d6dSopenharmony_ci {u"digital", u"byte"}, 3922e5b6d6dSopenharmony_ci {u"temperature", u"celsius"}, 3932e5b6d6dSopenharmony_ci {u"length", u"centimeter"}, 3942e5b6d6dSopenharmony_ci {u"duration", u"day"}, 3952e5b6d6dSopenharmony_ci {u"angle", u"degree"}, 3962e5b6d6dSopenharmony_ci {u"temperature", u"fahrenheit"}, 3972e5b6d6dSopenharmony_ci {u"volume", u"fluid-ounce"}, 3982e5b6d6dSopenharmony_ci {u"length", u"foot"}, 3992e5b6d6dSopenharmony_ci {u"volume", u"gallon"}, 4002e5b6d6dSopenharmony_ci {u"digital", u"gigabit"}, 4012e5b6d6dSopenharmony_ci {u"digital", u"gigabyte"}, 4022e5b6d6dSopenharmony_ci {u"mass", u"gram"}, 4032e5b6d6dSopenharmony_ci {u"area", u"hectare"}, 4042e5b6d6dSopenharmony_ci {u"duration", u"hour"}, 4052e5b6d6dSopenharmony_ci {u"length", u"inch"}, 4062e5b6d6dSopenharmony_ci {u"digital", u"kilobit"}, 4072e5b6d6dSopenharmony_ci {u"digital", u"kilobyte"}, 4082e5b6d6dSopenharmony_ci {u"mass", u"kilogram"}, 4092e5b6d6dSopenharmony_ci {u"length", u"kilometer"}, 4102e5b6d6dSopenharmony_ci {u"volume", u"liter"}, 4112e5b6d6dSopenharmony_ci {u"digital", u"megabit"}, 4122e5b6d6dSopenharmony_ci {u"digital", u"megabyte"}, 4132e5b6d6dSopenharmony_ci {u"length", u"meter"}, 4142e5b6d6dSopenharmony_ci {u"length", u"mile"}, 4152e5b6d6dSopenharmony_ci {u"length", u"mile-scandinavian"}, 4162e5b6d6dSopenharmony_ci {u"volume", u"milliliter"}, 4172e5b6d6dSopenharmony_ci {u"length", u"millimeter"}, 4182e5b6d6dSopenharmony_ci {u"duration", u"millisecond"}, 4192e5b6d6dSopenharmony_ci {u"duration", u"minute"}, 4202e5b6d6dSopenharmony_ci {u"duration", u"month"}, 4212e5b6d6dSopenharmony_ci {u"mass", u"ounce"}, 4222e5b6d6dSopenharmony_ci {u"concentr", u"percent"}, 4232e5b6d6dSopenharmony_ci {u"digital", u"petabyte"}, 4242e5b6d6dSopenharmony_ci {u"mass", u"pound"}, 4252e5b6d6dSopenharmony_ci {u"duration", u"second"}, 4262e5b6d6dSopenharmony_ci {u"mass", u"stone"}, 4272e5b6d6dSopenharmony_ci {u"digital", u"terabit"}, 4282e5b6d6dSopenharmony_ci {u"digital", u"terabyte"}, 4292e5b6d6dSopenharmony_ci {u"duration", u"week"}, 4302e5b6d6dSopenharmony_ci {u"length", u"yard"}, 4312e5b6d6dSopenharmony_ci {u"duration", u"year"}, 4322e5b6d6dSopenharmony_ci }; 4332e5b6d6dSopenharmony_ci 4342e5b6d6dSopenharmony_ci for (const auto& cas1 : cases) { 4352e5b6d6dSopenharmony_ci for (const auto& cas2 : cases) { 4362e5b6d6dSopenharmony_ci UnicodeString skeleton(u"measure-unit/"); 4372e5b6d6dSopenharmony_ci skeleton += cas1.type; 4382e5b6d6dSopenharmony_ci skeleton += u"-"; 4392e5b6d6dSopenharmony_ci skeleton += cas1.subtype; 4402e5b6d6dSopenharmony_ci skeleton += u" "; 4412e5b6d6dSopenharmony_ci skeleton += u"per-measure-unit/"; 4422e5b6d6dSopenharmony_ci skeleton += cas2.type; 4432e5b6d6dSopenharmony_ci skeleton += u"-"; 4442e5b6d6dSopenharmony_ci skeleton += cas2.subtype; 4452e5b6d6dSopenharmony_ci 4462e5b6d6dSopenharmony_ci status.setScope(skeleton); 4472e5b6d6dSopenharmony_ci UnicodeString actual = NumberFormatter::forSkeleton(skeleton, status).locale("ar") 4482e5b6d6dSopenharmony_ci .formatDouble(5142.3, status) 4492e5b6d6dSopenharmony_ci .toString(status); 4502e5b6d6dSopenharmony_ci status.errIfFailureAndReset(); 4512e5b6d6dSopenharmony_ci } 4522e5b6d6dSopenharmony_ci } 4532e5b6d6dSopenharmony_ci} 4542e5b6d6dSopenharmony_ci 4552e5b6d6dSopenharmony_civoid NumberSkeletonTest::perUnitToSkeleton() { 4562e5b6d6dSopenharmony_ci IcuTestErrorCode status(*this, "perUnitToSkeleton"); 4572e5b6d6dSopenharmony_ci struct TestCase { 4582e5b6d6dSopenharmony_ci const char16_t* type; 4592e5b6d6dSopenharmony_ci const char16_t* subtype; 4602e5b6d6dSopenharmony_ci } cases[] = { 4612e5b6d6dSopenharmony_ci {u"area", u"acre"}, 4622e5b6d6dSopenharmony_ci {u"concentr", u"percent"}, 4632e5b6d6dSopenharmony_ci {u"concentr", u"permille"}, 4642e5b6d6dSopenharmony_ci {u"concentr", u"permillion"}, 4652e5b6d6dSopenharmony_ci {u"concentr", u"permyriad"}, 4662e5b6d6dSopenharmony_ci {u"digital", u"bit"}, 4672e5b6d6dSopenharmony_ci {u"length", u"yard"}, 4682e5b6d6dSopenharmony_ci }; 4692e5b6d6dSopenharmony_ci 4702e5b6d6dSopenharmony_ci for (const auto& cas1 : cases) { 4712e5b6d6dSopenharmony_ci for (const auto& cas2 : cases) { 4722e5b6d6dSopenharmony_ci UnicodeString skeleton(u"measure-unit/"); 4732e5b6d6dSopenharmony_ci skeleton += cas1.type; 4742e5b6d6dSopenharmony_ci skeleton += u"-"; 4752e5b6d6dSopenharmony_ci skeleton += cas1.subtype; 4762e5b6d6dSopenharmony_ci skeleton += u" "; 4772e5b6d6dSopenharmony_ci skeleton += u"per-measure-unit/"; 4782e5b6d6dSopenharmony_ci skeleton += cas2.type; 4792e5b6d6dSopenharmony_ci skeleton += u"-"; 4802e5b6d6dSopenharmony_ci skeleton += cas2.subtype; 4812e5b6d6dSopenharmony_ci 4822e5b6d6dSopenharmony_ci status.setScope(skeleton); 4832e5b6d6dSopenharmony_ci if (cas1.type != cas2.type && cas1.subtype != cas2.subtype) { 4842e5b6d6dSopenharmony_ci UnicodeString toSkeleton = NumberFormatter::forSkeleton( 4852e5b6d6dSopenharmony_ci skeleton, status).toSkeleton(status); 4862e5b6d6dSopenharmony_ci if (status.errIfFailureAndReset()) { 4872e5b6d6dSopenharmony_ci continue; 4882e5b6d6dSopenharmony_ci } 4892e5b6d6dSopenharmony_ci // Ensure both subtype are in the toSkeleton. 4902e5b6d6dSopenharmony_ci UnicodeString msg; 4912e5b6d6dSopenharmony_ci msg.append(toSkeleton) 4922e5b6d6dSopenharmony_ci .append(" should contain '") 4932e5b6d6dSopenharmony_ci .append(UnicodeString(cas1.subtype)) 4942e5b6d6dSopenharmony_ci .append("' when constructed from ") 4952e5b6d6dSopenharmony_ci .append(skeleton); 4962e5b6d6dSopenharmony_ci assertTrue(msg, toSkeleton.indexOf(cas1.subtype) >= 0); 4972e5b6d6dSopenharmony_ci 4982e5b6d6dSopenharmony_ci msg.remove(); 4992e5b6d6dSopenharmony_ci msg.append(toSkeleton) 5002e5b6d6dSopenharmony_ci .append(" should contain '") 5012e5b6d6dSopenharmony_ci .append(UnicodeString(cas2.subtype)) 5022e5b6d6dSopenharmony_ci .append("' when constructed from ") 5032e5b6d6dSopenharmony_ci .append(skeleton); 5042e5b6d6dSopenharmony_ci assertTrue(msg, toSkeleton.indexOf(cas2.subtype) >= 0); 5052e5b6d6dSopenharmony_ci } 5062e5b6d6dSopenharmony_ci } 5072e5b6d6dSopenharmony_ci } 5082e5b6d6dSopenharmony_ci} 5092e5b6d6dSopenharmony_ci 5102e5b6d6dSopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */ 511