--- /dev/null
+// © 2017 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 "numbertest.h"
+#include "number_patternstring.h"
+
+void PatternStringTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
+ if (exec) {
+ logln("TestSuite PatternStringTest: ");
+ }
+ TESTCASE_AUTO_BEGIN;
+ TESTCASE_AUTO(testLocalized);
+ TESTCASE_AUTO(testToPatternSimple);
+ TESTCASE_AUTO(testExceptionOnInvalid);
+ TESTCASE_AUTO(testBug13117);
+ TESTCASE_AUTO_END;
+}
+
+void PatternStringTest::testLocalized() {
+ IcuTestErrorCode status(*this, "testLocalized");
+ DecimalFormatSymbols symbols(Locale::getEnglish(), status);
+ if (status.isFailure()) { return; }
+ symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"a", status);
+ symbols.setSymbol(DecimalFormatSymbols::kPercentSymbol, u"b", status);
+ symbols.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u".", status);
+ symbols.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"'", status);
+
+ UnicodeString standard = u"+-abcb''a''#,##0.0%'a%'";
+ UnicodeString localized = u"’.'ab'c'b''a'''#,##0a0b'a%'";
+ UnicodeString toStandard = u"+-'ab'c'b''a'''#,##0.0%'a%'";
+
+ assertEquals(
+ "standard to localized",
+ localized,
+ PatternStringUtils::convertLocalized(standard, symbols, true, status));
+ assertEquals(
+ "localized to standard",
+ toStandard,
+ PatternStringUtils::convertLocalized(localized, symbols, false, status));
+}
+
+void PatternStringTest::testToPatternSimple() {
+ const char16_t* cases[][2] = {{u"#", u"0"},
+ {u"0", u"0"},
+ {u"#0", u"0"},
+ {u"###", u"0"},
+ {u"0.##", u"0.##"},
+ {u"0.00", u"0.00"},
+ {u"0.00#", u"0.00#"},
+ {u"0.05", u"0.05"},
+ {u"#E0", u"#E0"},
+ {u"0E0", u"0E0"},
+ {u"#00E00", u"#00E00"},
+ {u"#,##0", u"#,##0"},
+ {u"#;#", u"0;0"},
+ // ignore a negative prefix pattern of '-' since that is the default:
+ {u"#;-#", u"0"},
+ {u"pp#,000;(#)", u"pp#,000;(#,000)"},
+ {u"**##0", u"**##0"},
+ {u"*'x'##0", u"*x##0"},
+ {u"a''b0", u"a''b0"},
+ {u"*''##0", u"*''##0"},
+ {u"*📺##0", u"*'📺'##0"},
+ {u"*'நி'##0", u"*'நி'##0"},};
+
+ UErrorCode status = U_ZERO_ERROR;
+ for (const char16_t** cas : cases) {
+ UnicodeString input(cas[0]);
+ UnicodeString output(cas[1]);
+
+ DecimalFormatProperties properties = PatternParser::parseToProperties(
+ input, IGNORE_ROUNDING_NEVER, status);
+ assertSuccess(input, status);
+ UnicodeString actual = PatternStringUtils::propertiesToPatternString(properties, status);
+ assertEquals(input, output, actual);
+ }
+}
+
+void PatternStringTest::testExceptionOnInvalid() {
+ static const char16_t* invalidPatterns[] = {
+ u"#.#.#",
+ u"0#",
+ u"0#.",
+ u".#0",
+ u"0#.#0",
+ u"@0",
+ u"0@",
+ u"0,",
+ u"0,,",
+ u"0,,0",
+ u"0,,0,",
+ u"#,##0E0"};
+
+ for (auto pattern : invalidPatterns) {
+ UErrorCode status = U_ZERO_ERROR;
+ ParsedPatternInfo patternInfo;
+ PatternParser::parseToPatternInfo(pattern, patternInfo, status);
+ assertTrue(pattern, U_FAILURE(status));
+ }
+}
+
+void PatternStringTest::testBug13117() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatProperties expected = PatternParser::parseToProperties(
+ u"0", IGNORE_ROUNDING_NEVER, status);
+ DecimalFormatProperties actual = PatternParser::parseToProperties(
+ u"0;", IGNORE_ROUNDING_NEVER, status);
+ assertSuccess("Spot 1", status);
+ assertTrue("Should not consume negative subpattern", expected == actual);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */