1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
8 #include "numbertest.h"
9 #include "number_microprops.h"
10 #include "number_patternmodifier.h"
11 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)12 void PatternModifierTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {
13     if (exec) {
14         logln("TestSuite PatternModifierTest: ");
15     }
16     TESTCASE_AUTO_BEGIN;
17         TESTCASE_AUTO(testBasic);
18         TESTCASE_AUTO(testPatternWithNoPlaceholder);
19         TESTCASE_AUTO(testMutableEqualsImmutable);
20     TESTCASE_AUTO_END;
21 }
22 
testBasic()23 void PatternModifierTest::testBasic() {
24     UErrorCode status = U_ZERO_ERROR;
25     MutablePatternModifier mod(false);
26     ParsedPatternInfo patternInfo;
27     PatternParser::parseToPatternInfo(u"a0b", patternInfo, status);
28     assertSuccess("Spot 1", status);
29     mod.setPatternInfo(&patternInfo);
30     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
31     DecimalFormatSymbols symbols(Locale::getEnglish(), status);
32     CurrencySymbols currencySymbols({u"USD", status}, "en", status);
33     if (!assertSuccess("Spot 2", status, true)) {
34         return;
35     }
36     mod.setSymbols(&symbols, &currencySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
37 
38     mod.setNumberProperties(1, StandardPlural::Form::COUNT);
39     assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
40     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
41     mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
42     assertEquals("Pattern a0b", u"+a", getPrefix(mod, status));
43     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
44     mod.setNumberProperties(0, StandardPlural::Form::COUNT);
45     assertEquals("Pattern a0b", u"+a", getPrefix(mod, status));
46     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
47     mod.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false);
48     assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
49     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
50     mod.setNumberProperties(-1, StandardPlural::Form::COUNT);
51     assertEquals("Pattern a0b", u"-a", getPrefix(mod, status));
52     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
53     mod.setPatternAttributes(UNUM_SIGN_NEVER, false);
54     assertEquals("Pattern a0b", u"a", getPrefix(mod, status));
55     assertEquals("Pattern a0b", u"b", getSuffix(mod, status));
56     assertSuccess("Spot 3", status);
57 
58     ParsedPatternInfo patternInfo2;
59     PatternParser::parseToPatternInfo(u"a0b;c-0d", patternInfo2, status);
60     assertSuccess("Spot 4", status);
61     mod.setPatternInfo(&patternInfo2);
62     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
63     mod.setNumberProperties(1, StandardPlural::Form::COUNT);
64     assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
65     assertEquals("Pattern a0b;c-0d", u"b", getSuffix(mod, status));
66     mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
67     assertEquals("Pattern a0b;c-0d", u"c+", getPrefix(mod, status));
68     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
69     mod.setNumberProperties(0, StandardPlural::Form::COUNT);
70     assertEquals("Pattern a0b;c-0d", u"c+", getPrefix(mod, status));
71     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
72     mod.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false);
73     assertEquals("Pattern a0b;c-0d", u"a", getPrefix(mod, status));
74     assertEquals("Pattern a0b;c-0d", u"b", getSuffix(mod, status));
75     mod.setNumberProperties(-1, StandardPlural::Form::COUNT);
76     assertEquals("Pattern a0b;c-0d", u"c-", getPrefix(mod, status));
77     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
78     mod.setPatternAttributes(UNUM_SIGN_NEVER, false);
79     // TODO: What should this behavior be?
80     assertEquals("Pattern a0b;c-0d", u"c-", getPrefix(mod, status));
81     assertEquals("Pattern a0b;c-0d", u"d", getSuffix(mod, status));
82     assertSuccess("Spot 5", status);
83 }
84 
testPatternWithNoPlaceholder()85 void PatternModifierTest::testPatternWithNoPlaceholder() {
86     UErrorCode status = U_ZERO_ERROR;
87     MutablePatternModifier mod(false);
88     ParsedPatternInfo patternInfo;
89     PatternParser::parseToPatternInfo(u"abc", patternInfo, status);
90     assertSuccess("Spot 1", status);
91     mod.setPatternInfo(&patternInfo);
92     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
93     DecimalFormatSymbols symbols(Locale::getEnglish(), status);
94     CurrencySymbols currencySymbols({u"USD", status}, "en", status);
95     if (!assertSuccess("Spot 2", status, true)) {
96         return;
97     }
98     mod.setSymbols(&symbols, &currencySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
99     mod.setNumberProperties(1, StandardPlural::Form::COUNT);
100 
101     // Unsafe Code Path
102     NumberStringBuilder nsb;
103     nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
104     assertSuccess("Spot 3", status);
105     mod.apply(nsb, 1, 4, status);
106     assertSuccess("Spot 4", status);
107     assertEquals("Unsafe Path", u"xabcy", nsb.toUnicodeString());
108 
109     // Safe Code Path
110     nsb.clear();
111     nsb.append(u"x123y", UNUM_FIELD_COUNT, status);
112     assertSuccess("Spot 5", status);
113     MicroProps micros;
114     LocalPointer<ImmutablePatternModifier> imod(mod.createImmutable(status), status);
115     if (U_FAILURE(status)) {
116       dataerrln("%s %d  Error in ImmutablePatternModifier creation",
117                 __FILE__, __LINE__);
118       assertSuccess("Spot 6", status);
119       return;
120     }
121     DecimalQuantity quantity;
122     imod->applyToMicros(micros, quantity);
123     micros.modMiddle->apply(nsb, 1, 4, status);
124     assertSuccess("Spot 7", status);
125     assertEquals("Safe Path", u"xabcy", nsb.toUnicodeString());
126 }
127 
testMutableEqualsImmutable()128 void PatternModifierTest::testMutableEqualsImmutable() {
129     UErrorCode status = U_ZERO_ERROR;
130     MutablePatternModifier mod(false);
131     ParsedPatternInfo patternInfo;
132     PatternParser::parseToPatternInfo("a0b;c-0d", patternInfo, status);
133     assertSuccess("Spot 1", status);
134     mod.setPatternInfo(&patternInfo);
135     mod.setPatternAttributes(UNUM_SIGN_AUTO, false);
136     DecimalFormatSymbols symbols(Locale::getEnglish(), status);
137     CurrencySymbols currencySymbols({u"USD", status}, "en", status);
138     assertSuccess("Spot 2", status);
139     if (U_FAILURE(status)) { return; }
140     mod.setSymbols(&symbols, &currencySymbols, UNUM_UNIT_WIDTH_SHORT, nullptr);
141     DecimalQuantity fq;
142     fq.setToInt(1);
143 
144     NumberStringBuilder nsb1;
145     MicroProps micros1;
146     mod.addToChain(&micros1);
147     mod.processQuantity(fq, micros1, status);
148     micros1.modMiddle->apply(nsb1, 0, 0, status);
149     assertSuccess("Spot 3", status);
150 
151     NumberStringBuilder nsb2;
152     MicroProps micros2;
153     LocalPointer<ImmutablePatternModifier> immutable(mod.createImmutable(status));
154     immutable->applyToMicros(micros2, fq);
155     micros2.modMiddle->apply(nsb2, 0, 0, status);
156     assertSuccess("Spot 4", status);
157 
158     NumberStringBuilder nsb3;
159     MicroProps micros3;
160     mod.addToChain(&micros3);
161     mod.setPatternAttributes(UNUM_SIGN_ALWAYS, false);
162     mod.processQuantity(fq, micros3, status);
163     micros3.modMiddle->apply(nsb3, 0, 0, status);
164     assertSuccess("Spot 5", status);
165 
166     assertTrue(nsb1.toUnicodeString() + " vs " + nsb2.toUnicodeString(), nsb1.contentEquals(nsb2));
167     assertFalse(nsb1.toUnicodeString() + " vs " + nsb3.toUnicodeString(), nsb1.contentEquals(nsb3));
168 }
169 
getPrefix(const MutablePatternModifier & mod,UErrorCode & status)170 UnicodeString PatternModifierTest::getPrefix(const MutablePatternModifier &mod, UErrorCode &status) {
171     NumberStringBuilder nsb;
172     mod.apply(nsb, 0, 0, status);
173     int32_t prefixLength = mod.getPrefixLength();
174     return UnicodeString(nsb.toUnicodeString(), 0, prefixLength);
175 }
176 
getSuffix(const MutablePatternModifier & mod,UErrorCode & status)177 UnicodeString PatternModifierTest::getSuffix(const MutablePatternModifier &mod, UErrorCode &status) {
178     NumberStringBuilder nsb;
179     mod.apply(nsb, 0, 0, status);
180     int32_t prefixLength = mod.getPrefixLength();
181     return UnicodeString(nsb.toUnicodeString(), prefixLength, nsb.length() - prefixLength);
182 }
183 
184 #endif /* #if !UCONFIG_NO_FORMATTING */
185