]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
b75a7d8f | 3 | /******************************************************************** |
729e4ab9 | 4 | * COPYRIGHT: |
2ca993e8 | 5 | * Copyright (c) 1997-2016, International Business Machines Corporation and |
729e4ab9 | 6 | * others. All Rights Reserved. |
46f4442e A |
7 | ******************************************************************** |
8 | * File TMSGFMT.CPP | |
9 | * | |
10 | * Modification History: | |
11 | * | |
12 | * Date Name Description | |
13 | * 03/24/97 helena Converted from Java. | |
14 | * 07/11/97 helena Updated to work on AIX. | |
15 | * 08/04/97 jfitz Updated to intltest | |
16 | *******************************************************************/ | |
b75a7d8f A |
17 | |
18 | #include "unicode/utypes.h" | |
19 | ||
20 | #if !UCONFIG_NO_FORMATTING | |
21 | ||
22 | #include "tmsgfmt.h" | |
b331163b | 23 | #include "cmemory.h" |
3d1f044b | 24 | #include "loctest.h" |
b75a7d8f A |
25 | |
26 | #include "unicode/format.h" | |
27 | #include "unicode/decimfmt.h" | |
51004dcb | 28 | #include "unicode/localpointer.h" |
b75a7d8f A |
29 | #include "unicode/locid.h" |
30 | #include "unicode/msgfmt.h" | |
31 | #include "unicode/numfmt.h" | |
32 | #include "unicode/choicfmt.h" | |
4388f060 | 33 | #include "unicode/messagepattern.h" |
729e4ab9 | 34 | #include "unicode/selfmt.h" |
b75a7d8f | 35 | #include "unicode/gregocal.h" |
f3c0d7a5 | 36 | #include "unicode/strenum.h" |
73c04bcf | 37 | #include <stdio.h> |
b75a7d8f A |
38 | |
39 | void | |
40 | TestMessageFormat::runIndexedTest(int32_t index, UBool exec, | |
41 | const char* &name, char* /*par*/) { | |
4388f060 A |
42 | TESTCASE_AUTO_BEGIN; |
43 | TESTCASE_AUTO(testBug1); | |
44 | TESTCASE_AUTO(testBug2); | |
45 | TESTCASE_AUTO(sample); | |
46 | TESTCASE_AUTO(PatternTest); | |
47 | TESTCASE_AUTO(testStaticFormat); | |
48 | TESTCASE_AUTO(testSimpleFormat); | |
49 | TESTCASE_AUTO(testMsgFormatChoice); | |
50 | TESTCASE_AUTO(testCopyConstructor); | |
51 | TESTCASE_AUTO(testAssignment); | |
52 | TESTCASE_AUTO(testClone); | |
53 | TESTCASE_AUTO(testEquals); | |
54 | TESTCASE_AUTO(testNotEquals); | |
55 | TESTCASE_AUTO(testSetLocale); | |
56 | TESTCASE_AUTO(testFormat); | |
57 | TESTCASE_AUTO(testParse); | |
58 | TESTCASE_AUTO(testAdopt); | |
59 | TESTCASE_AUTO(testCopyConstructor2); | |
60 | TESTCASE_AUTO(TestUnlimitedArgsAndSubformats); | |
61 | TESTCASE_AUTO(TestRBNF); | |
62 | TESTCASE_AUTO(TestTurkishCasing); | |
63 | TESTCASE_AUTO(testAutoQuoteApostrophe); | |
64 | TESTCASE_AUTO(testMsgFormatPlural); | |
65 | TESTCASE_AUTO(testMsgFormatSelect); | |
66 | TESTCASE_AUTO(testApostropheInPluralAndSelect); | |
67 | TESTCASE_AUTO(TestApostropheMode); | |
68 | TESTCASE_AUTO(TestCompatibleApostrophe); | |
69 | TESTCASE_AUTO(testCoverage); | |
51004dcb | 70 | TESTCASE_AUTO(testGetFormatNames); |
4388f060 | 71 | TESTCASE_AUTO(TestTrimArgumentName); |
51004dcb | 72 | TESTCASE_AUTO(TestSelectOrdinal); |
57a6839d | 73 | TESTCASE_AUTO(TestDecimals); |
2ca993e8 | 74 | TESTCASE_AUTO(TestArgIsPrefixOfAnother); |
0f5d89e8 | 75 | TESTCASE_AUTO(TestMessageFormatNumberSkeleton); |
3d1f044b A |
76 | TESTCASE_AUTO(TestMessageFormatDateSkeleton); |
77 | TESTCASE_AUTO(TestMessageFormatTimeSkeleton); | |
4388f060 | 78 | TESTCASE_AUTO_END; |
b75a7d8f A |
79 | } |
80 | ||
81 | void TestMessageFormat::testBug3() | |
82 | { | |
83 | double myNumber = -123456; | |
84 | DecimalFormat *form = 0; | |
85 | Locale locale[] = { | |
86 | Locale("ar", "", ""), | |
87 | Locale("be", "", ""), | |
88 | Locale("bg", "", ""), | |
89 | Locale("ca", "", ""), | |
90 | Locale("cs", "", ""), | |
91 | Locale("da", "", ""), | |
92 | Locale("de", "", ""), | |
93 | Locale("de", "AT", ""), | |
94 | Locale("de", "CH", ""), | |
95 | Locale("el", "", ""), // 10 | |
96 | Locale("en", "CA", ""), | |
97 | Locale("en", "GB", ""), | |
98 | Locale("en", "IE", ""), | |
99 | Locale("en", "US", ""), | |
100 | Locale("es", "", ""), | |
101 | Locale("et", "", ""), | |
102 | Locale("fi", "", ""), | |
103 | Locale("fr", "", ""), | |
104 | Locale("fr", "BE", ""), | |
105 | Locale("fr", "CA", ""), // 20 | |
106 | Locale("fr", "CH", ""), | |
107 | Locale("he", "", ""), | |
108 | Locale("hr", "", ""), | |
109 | Locale("hu", "", ""), | |
110 | Locale("is", "", ""), | |
111 | Locale("it", "", ""), | |
112 | Locale("it", "CH", ""), | |
113 | Locale("ja", "", ""), | |
114 | Locale("ko", "", ""), | |
115 | Locale("lt", "", ""), // 30 | |
116 | Locale("lv", "", ""), | |
117 | Locale("mk", "", ""), | |
118 | Locale("nl", "", ""), | |
119 | Locale("nl", "BE", ""), | |
120 | Locale("no", "", ""), | |
121 | Locale("pl", "", ""), | |
122 | Locale("pt", "", ""), | |
123 | Locale("ro", "", ""), | |
124 | Locale("ru", "", ""), | |
125 | Locale("sh", "", ""), // 40 | |
126 | Locale("sk", "", ""), | |
127 | Locale("sl", "", ""), | |
128 | Locale("sq", "", ""), | |
129 | Locale("sr", "", ""), | |
130 | Locale("sv", "", ""), | |
131 | Locale("tr", "", ""), | |
132 | Locale("uk", "", ""), | |
133 | Locale("zh", "", ""), | |
134 | Locale("zh", "TW", "") // 49 | |
135 | }; | |
136 | int32_t i; | |
137 | for (i= 0; i < 49; i++) { | |
138 | UnicodeString buffer; | |
139 | logln(locale[i].getDisplayName(buffer)); | |
140 | UErrorCode success = U_ZERO_ERROR; | |
141 | // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success); | |
142 | form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success); | |
143 | if (U_FAILURE(success)) { | |
144 | errln("Err: Number Format "); | |
145 | logln("Number format creation failed."); | |
146 | continue; | |
147 | } | |
148 | Formattable result; | |
f3c0d7a5 | 149 | FieldPosition pos(FieldPosition::DONT_CARE); |
b75a7d8f A |
150 | buffer.remove(); |
151 | form->format(myNumber, buffer, pos); | |
152 | success = U_ZERO_ERROR; | |
153 | ParsePosition parsePos; | |
154 | form->parse(buffer, result, parsePos); | |
374ca955 | 155 | logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]")); |
b75a7d8f A |
156 | if (U_FAILURE(success)) { |
157 | errln("Err: Number Format parse"); | |
158 | logln("Number format parse failed."); | |
159 | } | |
160 | delete form; | |
161 | } | |
162 | } | |
163 | ||
164 | void TestMessageFormat::testBug1() | |
165 | { | |
166 | const double limit[] = {0.0, 1.0, 2.0}; | |
167 | const UnicodeString formats[] = {"0.0<=Arg<1.0", | |
168 | "1.0<=Arg<2.0", | |
169 | "2.0<-Arg"}; | |
170 | ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3); | |
f3c0d7a5 | 171 | FieldPosition status(FieldPosition::DONT_CARE); |
b75a7d8f A |
172 | UnicodeString toAppendTo; |
173 | cf->format((int32_t)1, toAppendTo, status); | |
174 | if (toAppendTo != "1.0<=Arg<2.0") { | |
175 | errln("ChoiceFormat cmp in testBug1"); | |
176 | } | |
177 | logln(toAppendTo); | |
178 | delete cf; | |
179 | } | |
180 | ||
181 | void TestMessageFormat::testBug2() | |
182 | { | |
183 | UErrorCode status = U_ZERO_ERROR; | |
184 | UnicodeString result; | |
185 | // {sfb} use double format in pattern, so result will match (not strictly necessary) | |
46f4442e | 186 | const UnicodeString pattern = "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. "; |
b75a7d8f | 187 | logln("The input pattern : " + pattern); |
340931cb | 188 | LocalPointer<MessageFormat> fmt(new MessageFormat(pattern, status)); |
b75a7d8f | 189 | if (U_FAILURE(status)) { |
4388f060 | 190 | dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status)); |
b75a7d8f A |
191 | return; |
192 | } | |
193 | logln("The output pattern is : " + fmt->toPattern(result)); | |
194 | if (pattern != result) { | |
195 | errln("MessageFormat::toPattern() failed."); | |
196 | } | |
b75a7d8f A |
197 | } |
198 | ||
199 | #if 0 | |
0f5d89e8 | 200 | #if defined(_DEBUG) |
b75a7d8f A |
201 | //---------------------------------------------------- |
202 | // console I/O | |
203 | //---------------------------------------------------- | |
204 | ||
4388f060 A |
205 | #include <iostream> |
206 | std::ostream& operator<<(std::ostream& stream, const Formattable& obj); | |
b75a7d8f A |
207 | |
208 | #include "unicode/datefmt.h" | |
209 | #include <stdlib.h> | |
b75a7d8f A |
210 | #include <string.h> |
211 | ||
212 | IntlTest& | |
213 | operator<<( IntlTest& stream, | |
214 | const Formattable& obj) | |
215 | { | |
216 | static DateFormat *defDateFormat = 0; | |
217 | ||
218 | UnicodeString buffer; | |
219 | switch(obj.getType()) { | |
220 | case Formattable::kDate : | |
221 | if (defDateFormat == 0) { | |
222 | defDateFormat = DateFormat::createInstance(); | |
223 | } | |
224 | defDateFormat->format(obj.getDate(), buffer); | |
225 | stream << buffer; | |
226 | break; | |
227 | case Formattable::kDouble : | |
228 | char convert[20]; | |
229 | sprintf( convert, "%lf", obj.getDouble() ); | |
230 | stream << convert << "D"; | |
231 | break; | |
232 | case Formattable::kLong : | |
233 | stream << obj.getLong() << "L"; | |
234 | break; | |
235 | case Formattable::kString: | |
236 | stream << "\"" << obj.getString(buffer) << "\""; | |
237 | break; | |
238 | case Formattable::kArray: | |
239 | int32_t i, count; | |
240 | const Formattable* array; | |
241 | array = obj.getArray(count); | |
242 | stream << "["; | |
243 | for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " ); | |
244 | stream << "]"; | |
245 | break; | |
246 | default: | |
247 | stream << "INVALID_Formattable"; | |
248 | } | |
249 | return stream; | |
250 | } | |
0f5d89e8 | 251 | #endif /* defined(_DEBUG) */ |
b75a7d8f A |
252 | #endif |
253 | ||
254 | void TestMessageFormat::PatternTest() | |
255 | { | |
256 | Formattable testArgs[] = { | |
257 | Formattable(double(1)), Formattable(double(3456)), | |
258 | Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate) | |
259 | }; | |
260 | UnicodeString testCases[] = { | |
261 | "Quotes '', '{', 'a' {0} '{0}'", | |
262 | "Quotes '', '{', 'a' {0,number} '{0}'", | |
263 | "'{'1,number,'#',##} {1,number,'#',##}", | |
264 | "There are {1} files on {2} at {3}.", | |
265 | "On {2}, there are {1} files, with {0,number,currency}.", | |
266 | "'{1,number,percent}', {1,number,percent},", | |
267 | "'{1,date,full}', {1,date,full},", | |
268 | "'{3,date,full}', {3,date,full},", | |
269 | "'{1,number,#,##}' {1,number,#,##}", | |
270 | }; | |
271 | ||
4388f060 A |
272 | // ICU 4.8 returns the original pattern (testCases), |
273 | // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). | |
274 | /*UnicodeString testResultPatterns[] = { | |
b75a7d8f A |
275 | "Quotes '', '{', a {0} '{'0}", |
276 | "Quotes '', '{', a {0,number} '{'0}", | |
277 | "'{'1,number,#,##} {1,number,'#'#,##}", | |
278 | "There are {1} files on {2} at {3}.", | |
279 | "On {2}, there are {1} files, with {0,number,currency}.", | |
280 | "'{'1,number,percent}, {1,number,percent},", | |
281 | "'{'1,date,full}, {1,date,full},", | |
282 | "'{'3,date,full}, {3,date,full},", | |
283 | "'{'1,number,#,##} {1,number,#,##}" | |
4388f060 | 284 | };*/ |
b75a7d8f A |
285 | |
286 | UnicodeString testResultStrings[] = { | |
4388f060 A |
287 | "Quotes ', {, 'a' 1 {0}", |
288 | "Quotes ', {, 'a' 1 {0}", | |
289 | "{1,number,'#',##} #34,56", | |
51004dcb | 290 | "There are 3,456 files on Disk at 1/12/70, 5:46 AM.", |
b75a7d8f A |
291 | "On Disk, there are 3,456 files, with $1.00.", |
292 | "{1,number,percent}, 345,600%,", | |
293 | "{1,date,full}, Wednesday, December 31, 1969,", | |
294 | "{3,date,full}, Monday, January 12, 1970,", | |
295 | "{1,number,#,##} 34,56" | |
296 | }; | |
297 | ||
298 | ||
299 | for (int32_t i = 0; i < 9; ++i) { | |
300 | //it_out << "\nPat in: " << testCases[i]); | |
301 | ||
340931cb | 302 | LocalPointer<MessageFormat> form; |
b75a7d8f A |
303 | UErrorCode success = U_ZERO_ERROR; |
304 | UnicodeString buffer; | |
340931cb | 305 | form.adoptInstead(new MessageFormat(testCases[i], Locale::getUS(), success)); |
b75a7d8f | 306 | if (U_FAILURE(success)) { |
729e4ab9 | 307 | dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success)); |
b75a7d8f A |
308 | logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n"); |
309 | continue; | |
310 | } | |
4388f060 A |
311 | // ICU 4.8 returns the original pattern (testCases), |
312 | // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). | |
313 | if (form->toPattern(buffer) != testCases[i]) { | |
314 | // Note: An alternative test would be to build MessagePattern objects for | |
315 | // both the input and output patterns and compare them, taking SKIP_SYNTAX etc. | |
316 | // into account. | |
317 | // (Too much trouble...) | |
b75a7d8f A |
318 | errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i); |
319 | //form->toPattern(buffer); | |
320 | errln(((UnicodeString)" Orig: ") + testCases[i]); | |
4388f060 | 321 | errln(((UnicodeString)" Exp: ") + testCases[i]); |
b75a7d8f A |
322 | errln(((UnicodeString)" Got: ") + buffer); |
323 | } | |
324 | ||
325 | //it_out << "Pat out: " << form->toPattern(buffer)); | |
326 | UnicodeString result; | |
327 | int32_t count = 4; | |
f3c0d7a5 | 328 | FieldPosition fieldpos(FieldPosition::DONT_CARE); |
b75a7d8f A |
329 | form->format(testArgs, count, result, fieldpos, success); |
330 | if (U_FAILURE(success)) { | |
729e4ab9 | 331 | dataerrln("MessageFormat failed test #3 - %s", u_errorName(success)); |
b75a7d8f A |
332 | logln("TestMessageFormat::PatternTest failed test #3"); |
333 | continue; | |
334 | } | |
335 | if (result != testResultStrings[i]) { | |
336 | errln("TestMessageFormat::PatternTest failed test #4"); | |
337 | logln("TestMessageFormat::PatternTest failed #4."); | |
338 | logln(UnicodeString(" Result: ") + result ); | |
339 | logln(UnicodeString(" Expected: ") + testResultStrings[i] ); | |
340 | } | |
4388f060 | 341 | |
b75a7d8f A |
342 | |
343 | //it_out << "Result: " << result); | |
344 | #if 0 | |
345 | /* TODO: Look at this test and see if this is still a valid test */ | |
346 | logln("---------------- test parse ----------------"); | |
347 | ||
348 | form->toPattern(buffer); | |
349 | logln("MSG pattern for parse: " + buffer); | |
350 | ||
351 | int32_t parseCount = 0; | |
352 | Formattable* values = form->parse(result, parseCount, success); | |
353 | if (U_FAILURE(success)) { | |
354 | errln("MessageFormat failed test #5"); | |
355 | logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success); | |
356 | } else if (parseCount != count) { | |
357 | errln("MSG count not %d as expected. Got %d", count, parseCount); | |
358 | } | |
359 | UBool failed = FALSE; | |
360 | for (int32_t j = 0; j < parseCount; ++j) { | |
361 | if (values == 0 || testArgs[j] != values[j]) { | |
362 | errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j])); | |
363 | errln(((UnicodeString)"MSG values[") + j + "] : " + toString(values[j])); | |
364 | failed = TRUE; | |
365 | } | |
366 | } | |
367 | if (failed) | |
368 | errln("MessageFormat failed test #6"); | |
369 | #endif | |
b75a7d8f A |
370 | } |
371 | } | |
372 | ||
373 | void TestMessageFormat::sample() | |
374 | { | |
375 | MessageFormat *form = 0; | |
376 | UnicodeString buffer1, buffer2; | |
377 | UErrorCode success = U_ZERO_ERROR; | |
378 | form = new MessageFormat("There are {0} files on {1}", success); | |
379 | if (U_FAILURE(success)) { | |
380 | errln("Err: Message format creation failed"); | |
381 | logln("Sample message format creation failed."); | |
382 | return; | |
383 | } | |
384 | UnicodeString abc("abc"); | |
385 | UnicodeString def("def"); | |
386 | Formattable testArgs1[] = { abc, def }; | |
f3c0d7a5 | 387 | FieldPosition fieldpos(FieldPosition::DONT_CARE); |
374ca955 A |
388 | assertEquals("format", |
389 | "There are abc files on def", | |
390 | form->format(testArgs1, 2, buffer2, fieldpos, success)); | |
391 | assertSuccess("format", success); | |
b75a7d8f A |
392 | delete form; |
393 | } | |
394 | ||
374ca955 | 395 | void TestMessageFormat::testStaticFormat() |
b75a7d8f | 396 | { |
b75a7d8f | 397 | UErrorCode err = U_ZERO_ERROR; |
b75a7d8f A |
398 | Formattable arguments[] = { |
399 | (int32_t)7, | |
400 | Formattable(UDate(8.71068e+011), Formattable::kIsDate), | |
401 | "a disturbance in the Force" | |
402 | }; | |
403 | ||
404 | UnicodeString result; | |
405 | result = MessageFormat::format( | |
406 | "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", | |
407 | arguments, | |
408 | 3, | |
409 | result, | |
410 | err); | |
411 | ||
412 | if (U_FAILURE(err)) { | |
729e4ab9 | 413 | dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err)); |
b75a7d8f A |
414 | logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err); |
415 | return; | |
416 | } | |
417 | ||
418 | const UnicodeString expected( | |
419 | "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", ""); | |
420 | if (result != expected) { | |
421 | errln("TestMessageFormat::testStaticFormat failed on test"); | |
422 | logln( UnicodeString(" Result: ") + result ); | |
423 | logln( UnicodeString(" Expected: ") + expected ); | |
424 | } | |
425 | } | |
426 | ||
73c04bcf A |
427 | /* When the default locale is tr, make sure that the pattern can still be parsed. */ |
428 | void TestMessageFormat::TestTurkishCasing() | |
429 | { | |
430 | UErrorCode err = U_ZERO_ERROR; | |
431 | Locale saveDefaultLocale; | |
432 | Locale::setDefault( Locale("tr"), err ); | |
433 | ||
434 | Formattable arguments[] = { | |
435 | (int32_t)7, | |
436 | Formattable(UDate(8.71068e+011), Formattable::kIsDate), | |
437 | "a disturbance in the Force" | |
438 | }; | |
439 | ||
440 | UnicodeString result; | |
441 | result = MessageFormat::format( | |
442 | "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.", | |
443 | arguments, | |
444 | 3, | |
445 | result, | |
446 | err); | |
447 | ||
448 | if (U_FAILURE(err)) { | |
729e4ab9 | 449 | dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err)); |
73c04bcf A |
450 | return; |
451 | } | |
452 | ||
453 | const UnicodeString expected( | |
51004dcb | 454 | "At 12:20:00 on 8.08.1997, there was a disturbance in the Force on planet 7.", ""); |
73c04bcf A |
455 | if (result != expected) { |
456 | errln("TestTurkishCasing failed on test"); | |
457 | errln( UnicodeString(" Result: ") + result ); | |
458 | errln( UnicodeString(" Expected: ") + expected ); | |
459 | } | |
460 | Locale::setDefault( saveDefaultLocale, err ); | |
461 | } | |
b75a7d8f A |
462 | |
463 | void TestMessageFormat::testSimpleFormat(/* char* par */) | |
464 | { | |
465 | logln("running TestMessageFormat::testSimpleFormat"); | |
466 | ||
467 | UErrorCode err = U_ZERO_ERROR; | |
468 | ||
469 | Formattable testArgs1[] = {(int32_t)0, "MyDisk"}; | |
470 | Formattable testArgs2[] = {(int32_t)1, "MyDisk"}; | |
471 | Formattable testArgs3[] = {(int32_t)12, "MyDisk"}; | |
472 | ||
473 | MessageFormat* form = new MessageFormat( | |
474 | "The disk \"{1}\" contains {0} file(s).", err); | |
475 | ||
476 | UnicodeString string; | |
477 | FieldPosition ignore(FieldPosition::DONT_CARE); | |
478 | form->format(testArgs1, 2, string, ignore, err); | |
479 | if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") { | |
729e4ab9 | 480 | dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err)); |
b75a7d8f A |
481 | } |
482 | ||
483 | ignore.setField(FieldPosition::DONT_CARE); | |
484 | string.remove(); | |
485 | form->format(testArgs2, 2, string, ignore, err); | |
486 | if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") { | |
487 | logln(string); | |
729e4ab9 | 488 | dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string + " - " + u_errorName(err)); |
b75a7d8f A |
489 | } |
490 | ||
491 | ignore.setField(FieldPosition::DONT_CARE); | |
492 | string.remove(); | |
493 | form->format(testArgs3, 2, string, ignore, err); | |
494 | if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") { | |
729e4ab9 | 495 | dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string + " - " + u_errorName(err)); |
b75a7d8f A |
496 | } |
497 | ||
498 | delete form; | |
499 | } | |
500 | ||
501 | void TestMessageFormat::testMsgFormatChoice(/* char* par */) | |
502 | { | |
503 | logln("running TestMessageFormat::testMsgFormatChoice"); | |
504 | ||
505 | UErrorCode err = U_ZERO_ERROR; | |
506 | ||
507 | MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err); | |
508 | double filelimits[] = {0,1,2}; | |
509 | UnicodeString filepart[] = {"no files","one file","{0,number} files"}; | |
510 | ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3); | |
511 | form->setFormat(1,*fileform); // NOT zero, see below | |
512 | //is the format adopted? | |
513 | ||
514 | FieldPosition ignore(FieldPosition::DONT_CARE); | |
515 | UnicodeString string; | |
516 | Formattable testArgs1[] = {(int32_t)0, "MyDisk"}; | |
517 | form->format(testArgs1, 2, string, ignore, err); | |
518 | if (string != "The disk \"MyDisk\" contains no files.") { | |
519 | errln("TestMessageFormat::testMsgFormatChoice failed on test #1"); | |
520 | } | |
521 | ||
522 | ignore.setField(FieldPosition::DONT_CARE); | |
523 | string.remove(); | |
524 | Formattable testArgs2[] = {(int32_t)1, "MyDisk"}; | |
525 | form->format(testArgs2, 2, string, ignore, err); | |
526 | if (string != "The disk \"MyDisk\" contains one file.") { | |
527 | errln("TestMessageFormat::testMsgFormatChoice failed on test #2"); | |
528 | } | |
529 | ||
530 | ignore.setField(FieldPosition::DONT_CARE); | |
531 | string.remove(); | |
532 | Formattable testArgs3[] = {(int32_t)1273, "MyDisk"}; | |
533 | form->format(testArgs3, 2, string, ignore, err); | |
534 | if (string != "The disk \"MyDisk\" contains 1,273 files.") { | |
729e4ab9 | 535 | dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err)); |
b75a7d8f A |
536 | } |
537 | ||
538 | delete form; | |
539 | delete fileform; | |
540 | } | |
541 | ||
542 | ||
46f4442e A |
543 | void TestMessageFormat::testMsgFormatPlural(/* char* par */) |
544 | { | |
545 | logln("running TestMessageFormat::testMsgFormatPlural"); | |
546 | ||
547 | UErrorCode err = U_ZERO_ERROR; | |
548 | UnicodeString t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste."); | |
549 | UnicodeString t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste."); | |
550 | UnicodeString t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory."); | |
551 | UnicodeString t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory."); | |
4388f060 | 552 | UnicodeString t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste."); |
46f4442e A |
553 | MessageFormat* mfNum = new MessageFormat(t1, Locale("fr"), err); |
554 | if (U_FAILURE(err)) { | |
729e4ab9 | 555 | dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err)); |
46f4442e A |
556 | logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err); |
557 | return; | |
558 | } | |
559 | Formattable testArgs1((int32_t)0); | |
560 | FieldPosition ignore(FieldPosition::DONT_CARE); | |
561 | UnicodeString numResult1; | |
562 | mfNum->format(&testArgs1, 1, numResult1, ignore, err); | |
563 | ||
564 | MessageFormat* mfAlpha = new MessageFormat(t2, Locale("fr"), err); | |
565 | UnicodeString argName[] = {UnicodeString("argument")}; | |
566 | UnicodeString argNameResult; | |
567 | mfAlpha->format(argName, &testArgs1, 1, argNameResult, err); | |
568 | if (U_FAILURE(err)) { | |
4388f060 | 569 | dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err)); |
46f4442e A |
570 | logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err); |
571 | delete mfNum; | |
572 | return; | |
573 | } | |
574 | if ( numResult1 != argNameResult){ | |
575 | errln("TestMessageFormat::testMsgFormatPlural #1"); | |
576 | logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); | |
577 | } | |
578 | if ( numResult1 != UnicodeString("C\'est 0 fichier dans la liste.")) { | |
579 | errln("TestMessageFormat::testMsgFormatPlural #1"); | |
580 | logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); | |
581 | } | |
582 | err = U_ZERO_ERROR; | |
583 | ||
584 | delete mfNum; | |
585 | delete mfAlpha; | |
586 | ||
57a6839d | 587 | MessageFormat* mfNum2 = new MessageFormat(t3, Locale("uk"), err); |
46f4442e A |
588 | numResult1.remove(); |
589 | Formattable testArgs2((int32_t)4); | |
590 | mfNum2->format(&testArgs2, 1, numResult1, ignore, err); | |
57a6839d | 591 | MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("uk"), err); |
46f4442e A |
592 | argNameResult.remove(); |
593 | mfAlpha2->format(argName, &testArgs2, 1, argNameResult, err); | |
594 | ||
595 | if (U_FAILURE(err)) { | |
596 | errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName"); | |
597 | logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err); | |
598 | delete mfNum2; | |
599 | return; | |
600 | } | |
601 | if ( numResult1 != argNameResult){ | |
602 | errln("TestMessageFormat::testMsgFormatPlural #2"); | |
603 | logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); | |
604 | } | |
605 | if ( numResult1 != UnicodeString("There are 4,0 zavoda in the directory.")) { | |
606 | errln("TestMessageFormat::testMsgFormatPlural #2"); | |
607 | logln(UnicodeString("The results of argumentName and argumentIndex are not the same.")); | |
608 | } | |
609 | ||
610 | delete mfNum2; | |
611 | delete mfAlpha2; | |
612 | ||
613 | // nested formats | |
614 | err = U_ZERO_ERROR; | |
615 | MessageFormat* msgFmt = new MessageFormat(t5, Locale("fr"), err); | |
616 | if (U_FAILURE(err)) { | |
617 | errln("TestMessageFormat::test nested PluralFormat with argumentName"); | |
618 | logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err); | |
619 | delete msgFmt; | |
620 | return; | |
621 | } | |
622 | Formattable testArgs3((int32_t)0); | |
623 | argNameResult.remove(); | |
624 | msgFmt->format(&testArgs3, 1, argNameResult, ignore, err); | |
625 | if (U_FAILURE(err)) { | |
626 | errln("TestMessageFormat::test nested PluralFormat with argumentName"); | |
627 | } | |
628 | if ( argNameResult!= UnicodeString("C'est 0,0 fichier dans la liste.")) { | |
4388f060 | 629 | errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult); |
46f4442e A |
630 | logln(UnicodeString("The unexpected nested named PluralFormat.")); |
631 | } | |
632 | delete msgFmt; | |
633 | } | |
634 | ||
4388f060 A |
635 | void TestMessageFormat::testApostropheInPluralAndSelect() { |
636 | UErrorCode errorCode = U_ZERO_ERROR; | |
637 | MessageFormat msgFmt(UNICODE_STRING_SIMPLE( | |
638 | "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"), | |
639 | Locale::getEnglish(), | |
640 | errorCode); | |
641 | if (U_FAILURE(errorCode)) { | |
642 | errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode)); | |
643 | return; | |
644 | } | |
645 | UnicodeString expected = UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz"); | |
646 | Formattable args[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") }; | |
647 | internalFormat( | |
648 | &msgFmt, args, 2, expected, | |
649 | "MessageFormat with apostrophes in plural/select arguments failed:\n"); | |
650 | } | |
651 | ||
729e4ab9 A |
652 | void TestMessageFormat::internalFormat(MessageFormat* msgFmt , |
653 | Formattable* args , int32_t numOfArgs , | |
4388f060 | 654 | UnicodeString expected, const char* errMsg) |
729e4ab9 A |
655 | { |
656 | UnicodeString result; | |
657 | FieldPosition ignore(FieldPosition::DONT_CARE); | |
658 | UErrorCode status = U_ZERO_ERROR; | |
659 | ||
660 | //Format with passed arguments | |
661 | msgFmt->format( args , numOfArgs , result, ignore, status); | |
662 | if (U_FAILURE(status)) { | |
57a6839d | 663 | dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) ); |
729e4ab9 A |
664 | } |
665 | //Compare expected with obtained result | |
666 | if ( result!= expected ) { | |
667 | UnicodeString err = UnicodeString(errMsg); | |
668 | err+= UnicodeString(":Unexpected Result \n Expected: " + expected + "\n Obtained: " + result + "\n"); | |
669 | dataerrln(err); | |
670 | } | |
671 | } | |
672 | ||
673 | MessageFormat* TestMessageFormat::internalCreate( | |
674 | UnicodeString pattern ,Locale locale ,UErrorCode &status , char* errMsg) | |
675 | { | |
676 | //Create the MessageFormat with simple SelectFormat | |
340931cb | 677 | LocalPointer<MessageFormat> msgFmt(new MessageFormat(pattern, locale, status)); |
729e4ab9 | 678 | if (U_FAILURE(status)) { |
57a6839d | 679 | dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) ); |
729e4ab9 | 680 | logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status); |
340931cb | 681 | return nullptr; |
729e4ab9 | 682 | } |
340931cb | 683 | return msgFmt.orphan(); |
729e4ab9 A |
684 | } |
685 | ||
686 | void TestMessageFormat::testMsgFormatSelect(/* char* par */) | |
687 | { | |
688 | logln("running TestMessageFormat::testMsgFormatSelect"); | |
689 | ||
690 | UErrorCode err = U_ZERO_ERROR; | |
691 | //French Pattern | |
692 | UnicodeString t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."); | |
693 | ||
694 | err = U_ZERO_ERROR; | |
695 | //Create the MessageFormat with simple French pattern | |
696 | MessageFormat* msgFmt1 = internalCreate(t1.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t1"); | |
697 | if (!U_FAILURE(err)) { | |
698 | //Arguments | |
699 | Formattable testArgs10[] = {"Kirti","female"}; | |
700 | Formattable testArgs11[] = {"Victor","other"}; | |
701 | Formattable testArgs12[] = {"Ash","unknown"}; | |
702 | Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; | |
703 | UnicodeString exp[] = { | |
704 | "Kirti est all\\u00E9e \\u00E0 Paris." , | |
705 | "Victor est all\\u00E9 \\u00E0 Paris.", | |
706 | "Ash est all\\u00E9 \\u00E0 Paris."}; | |
707 | //Format | |
708 | for( int i=0; i< 3; i++){ | |
709 | internalFormat( msgFmt1 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1"); | |
710 | } | |
711 | } | |
712 | delete msgFmt1; | |
713 | ||
714 | //Quoted French Pattern | |
715 | UnicodeString t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris."); | |
716 | err = U_ZERO_ERROR; | |
717 | //Create the MessageFormat with Quoted French pattern | |
718 | MessageFormat* msgFmt2 = internalCreate(t2.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t2"); | |
719 | if (!U_FAILURE(err)) { | |
720 | //Arguments | |
721 | Formattable testArgs10[] = {"Kirti","female"}; | |
722 | Formattable testArgs11[] = {"Victor","other"}; | |
723 | Formattable testArgs12[] = {"Ash","male"}; | |
724 | Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; | |
725 | UnicodeString exp[] = { | |
726 | "Kirti est all\\u00E9e c'est \\u00E0 Paris." , | |
727 | "Victor est all\\u00E9 c'est \\u00E0 Paris.", | |
728 | "Ash est all\\u00E9 c'est \\u00E0 Paris."}; | |
729 | //Format | |
730 | for( int i=0; i< 3; i++){ | |
731 | internalFormat( msgFmt2 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2"); | |
732 | } | |
733 | } | |
734 | delete msgFmt2; | |
735 | ||
736 | //English Pattern | |
737 | UnicodeString t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books."); | |
738 | err = U_ZERO_ERROR; | |
739 | //Create the MessageFormat with English pattern | |
740 | MessageFormat* msgFmt3 = internalCreate(t3, Locale("en"),err,(char*)"From TestMessageFormat::TestSelectFormat create t3"); | |
741 | if (!U_FAILURE(err)) { | |
742 | //Arguments | |
743 | Formattable testArgs10[] = {"female"}; | |
744 | Formattable testArgs11[] = {"other"}; | |
745 | Formattable testArgs12[] = {"male"}; | |
746 | Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; | |
747 | UnicodeString exp[] = { | |
748 | "FEMALE FR company published new books." , | |
749 | "FR otherValue published new books.", | |
750 | "MALE FR company published new books."}; | |
751 | //Format | |
752 | for( int i=0; i< 3; i++){ | |
753 | internalFormat( msgFmt3 , testArgs[i], 1, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t3"); | |
754 | } | |
755 | } | |
756 | delete msgFmt3; | |
757 | ||
758 | //Nested patterns with plural, number ,choice ,select format etc. | |
759 | //Select Format with embedded number format | |
760 | UnicodeString t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."); | |
57a6839d | 761 | err = U_ZERO_ERROR; |
729e4ab9 A |
762 | //Create the MessageFormat with Select Format with embedded number format (nested pattern) |
763 | MessageFormat* msgFmt4 = internalCreate(t4.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t4"); | |
764 | if (!U_FAILURE(err)) { | |
765 | //Arguments | |
766 | Formattable testArgs10[] = {"Kirti","female",(int32_t)6}; | |
767 | Formattable testArgs11[] = {"Kirti","female",100.100}; | |
768 | Formattable testArgs12[] = {"Kirti","other",(int32_t)6}; | |
769 | Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12}; | |
770 | UnicodeString exp[] = { | |
771 | "Kirti est 6 all\\u00E9e \\u00E0 Paris." , | |
772 | "Kirti est 100 all\\u00E9e \\u00E0 Paris.", | |
773 | "Kirti est all\\u00E9 \\u00E0 Paris."}; | |
774 | //Format | |
775 | for( int i=0; i< 3; i++){ | |
776 | internalFormat( msgFmt4 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4"); | |
777 | } | |
778 | } | |
779 | delete msgFmt4; | |
780 | ||
729e4ab9 A |
781 | //Plural format with embedded select format |
782 | UnicodeString t5("{0} {1, plural, one {est {2, select, female {all\\u00E9e} other {all\\u00E9}}} other {sont {2, select, female {all\\u00E9es} other {all\\u00E9s}}}} \\u00E0 Paris."); | |
783 | err = U_ZERO_ERROR; | |
784 | //Create the MessageFormat with Plural format with embedded select format(nested pattern) | |
785 | MessageFormat* msgFmt5 = internalCreate(t5.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t5"); | |
f3c0d7a5 | 786 | // with no data the above should fail but it seems to construct an invalid MessageFormat with no reported error. See #13079 |
729e4ab9 A |
787 | if (!U_FAILURE(err)) { |
788 | //Arguments | |
789 | Formattable testArgs10[] = {"Kirti",(int32_t)6,"female"}; | |
790 | Formattable testArgs11[] = {"Kirti",(int32_t)1,"female"}; | |
791 | Formattable testArgs12[] = {"Ash",(int32_t)1,"other"}; | |
792 | Formattable testArgs13[] = {"Ash",(int32_t)5,"other"}; | |
793 | Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13}; | |
794 | UnicodeString exp[] = { | |
795 | "Kirti sont all\\u00E9es \\u00E0 Paris." , | |
796 | "Kirti est all\\u00E9e \\u00E0 Paris.", | |
797 | "Ash est all\\u00E9 \\u00E0 Paris.", | |
798 | "Ash sont all\\u00E9s \\u00E0 Paris."}; | |
799 | //Format | |
800 | for( int i=0; i< 4; i++){ | |
801 | internalFormat( msgFmt5 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5"); | |
802 | } | |
803 | } | |
804 | delete msgFmt5; | |
805 | ||
806 | err = U_ZERO_ERROR; | |
807 | //Select, plural, and number formats heavily nested | |
808 | UnicodeString t6("{0} und {1, select, female {{2, plural, one {{3, select, female {ihre Freundin} other {ihr Freund}} } other {ihre {2, number, integer} {3, select, female {Freundinnen} other {Freunde}} } }} other{{2, plural, one {{3, select, female {seine Freundin} other {sein Freund}}} other {seine {2, number, integer} {3, select, female {Freundinnen} other {Freunde}}}}} } gingen nach Paris."); | |
809 | //Create the MessageFormat with Select, plural, and number formats heavily nested | |
340931cb A |
810 | LocalPointer<MessageFormat> msgFmt6( |
811 | internalCreate(t6, Locale("de"),err,(char*)"From TestMessageFormat::TestSelectFormat create t6")); | |
729e4ab9 A |
812 | if (!U_FAILURE(err)) { |
813 | //Arguments | |
814 | Formattable testArgs10[] = {"Kirti","other",(int32_t)1,"other"}; | |
815 | Formattable testArgs11[] = {"Kirti","other",(int32_t)6,"other"}; | |
816 | Formattable testArgs12[] = {"Kirti","other",(int32_t)1,"female"}; | |
817 | Formattable testArgs13[] = {"Kirti","other",(int32_t)3,"female"}; | |
818 | Formattable testArgs14[] = {"Kirti","female",(int32_t)1,"female"}; | |
819 | Formattable testArgs15[] = {"Kirti","female",(int32_t)5,"female"}; | |
820 | Formattable testArgs16[] = {"Kirti","female",(int32_t)1,"other"}; | |
821 | Formattable testArgs17[] = {"Kirti","female",(int32_t)5,"other"}; | |
822 | Formattable testArgs18[] = {"Kirti","mixed",(int32_t)1,"mixed"}; | |
823 | Formattable testArgs19[] = {"Kirti","mixed",(int32_t)1,"other"}; | |
824 | Formattable testArgs20[] = {"Kirti","female",(int32_t)1,"mixed"}; | |
825 | Formattable testArgs21[] = {"Kirti","mixed",(int32_t)5,"mixed"}; | |
826 | Formattable testArgs22[] = {"Kirti","mixed",(int32_t)5,"other"}; | |
827 | Formattable testArgs23[] = {"Kirti","female",(int32_t)5,"mixed"}; | |
828 | Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13, | |
829 | testArgs14,testArgs15,testArgs16,testArgs17, | |
830 | testArgs18,testArgs19,testArgs20,testArgs21, | |
831 | testArgs22,testArgs23 }; | |
832 | UnicodeString exp[] = { | |
833 | "Kirti und sein Freund gingen nach Paris." , | |
834 | "Kirti und seine 6 Freunde gingen nach Paris." , | |
835 | "Kirti und seine Freundin gingen nach Paris.", | |
836 | "Kirti und seine 3 Freundinnen gingen nach Paris.", | |
837 | "Kirti und ihre Freundin gingen nach Paris.", | |
838 | "Kirti und ihre 5 Freundinnen gingen nach Paris.", | |
839 | "Kirti und ihr Freund gingen nach Paris.", | |
840 | "Kirti und ihre 5 Freunde gingen nach Paris.", | |
841 | "Kirti und sein Freund gingen nach Paris.", | |
842 | "Kirti und sein Freund gingen nach Paris.", | |
843 | "Kirti und ihr Freund gingen nach Paris.", | |
844 | "Kirti und seine 5 Freunde gingen nach Paris." , | |
845 | "Kirti und seine 5 Freunde gingen nach Paris." , | |
846 | "Kirti und ihre 5 Freunde gingen nach Paris." | |
847 | }; | |
848 | //Format | |
849 | for( int i=0; i< 14; i++){ | |
340931cb | 850 | internalFormat( msgFmt6.getAlias(), testArgs[i], 4, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t6"); |
729e4ab9 A |
851 | } |
852 | } | |
729e4ab9 | 853 | } |
46f4442e | 854 | |
b75a7d8f A |
855 | //--------------------------------- |
856 | // API Tests | |
857 | //--------------------------------- | |
858 | ||
859 | void TestMessageFormat::testCopyConstructor() | |
860 | { | |
b75a7d8f A |
861 | UErrorCode success = U_ZERO_ERROR; |
862 | MessageFormat *x = new MessageFormat("There are {0} files on {1}", success); | |
863 | MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success); | |
864 | MessageFormat *y = 0; | |
865 | y = new MessageFormat(*x); | |
866 | if ( (*x == *y) && | |
867 | (*x != *z) && | |
868 | (*y != *z) ) | |
869 | logln("First test (operator ==): Passed!"); | |
870 | else { | |
871 | errln("TestMessageFormat::testCopyConstructor failed #1"); | |
872 | logln("First test (operator ==): Failed!"); | |
873 | } | |
874 | if ( ((*x == *y) && (*y == *x)) && | |
875 | ((*x != *z) && (*z != *x)) && | |
876 | ((*y != *z) && (*z != *y)) ) | |
877 | logln("Second test (equals): Passed!"); | |
878 | else { | |
879 | errln("TestMessageFormat::testCopyConstructor failed #2"); | |
880 | logln("Second test (equals): Failed!"); | |
881 | } | |
882 | ||
883 | delete x; | |
884 | delete y; | |
885 | delete z; | |
886 | } | |
887 | ||
888 | ||
889 | void TestMessageFormat::testAssignment() | |
890 | { | |
b75a7d8f A |
891 | UErrorCode success = U_ZERO_ERROR; |
892 | MessageFormat *x = new MessageFormat("There are {0} files on {1}", success); | |
893 | MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success); | |
894 | MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success); | |
895 | *y = *x; | |
896 | if ( (*x == *y) && | |
897 | (*x != *z) && | |
898 | (*y != *z) ) | |
899 | logln("First test (operator ==): Passed!"); | |
900 | else { | |
901 | errln( "TestMessageFormat::testAssignment failed #1"); | |
902 | logln("First test (operator ==): Failed!"); | |
903 | } | |
904 | if ( ((*x == *y) && (*y == *x)) && | |
905 | ((*x != *z) && (*z != *x)) && | |
906 | ((*y != *z) && (*z != *y)) ) | |
907 | logln("Second test (equals): Passed!"); | |
908 | else { | |
909 | errln("TestMessageFormat::testAssignment failed #2"); | |
910 | logln("Second test (equals): Failed!"); | |
911 | } | |
912 | ||
913 | delete x; | |
914 | delete y; | |
915 | delete z; | |
916 | } | |
917 | ||
918 | void TestMessageFormat::testClone() | |
919 | { | |
b75a7d8f A |
920 | UErrorCode success = U_ZERO_ERROR; |
921 | MessageFormat *x = new MessageFormat("There are {0} files on {1}", success); | |
922 | MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success); | |
923 | MessageFormat *y = 0; | |
340931cb | 924 | y = x->clone(); |
b75a7d8f A |
925 | if ( (*x == *y) && |
926 | (*x != *z) && | |
927 | (*y != *z) ) | |
928 | logln("First test (operator ==): Passed!"); | |
929 | else { | |
930 | errln("TestMessageFormat::testClone failed #1"); | |
931 | logln("First test (operator ==): Failed!"); | |
932 | } | |
933 | if ( ((*x == *y) && (*y == *x)) && | |
934 | ((*x != *z) && (*z != *x)) && | |
935 | ((*y != *z) && (*z != *y)) ) | |
936 | logln("Second test (equals): Passed!"); | |
937 | else { | |
938 | errln("TestMessageFormat::testClone failed #2"); | |
939 | logln("Second test (equals): Failed!"); | |
940 | } | |
941 | ||
942 | delete x; | |
943 | delete y; | |
944 | delete z; | |
945 | } | |
946 | ||
947 | void TestMessageFormat::testEquals() | |
948 | { | |
b75a7d8f A |
949 | UErrorCode success = U_ZERO_ERROR; |
950 | MessageFormat x("There are {0} files on {1}", success); | |
951 | MessageFormat y("There are {0} files on {1}", success); | |
952 | if (!(x == y)) { | |
953 | errln( "TestMessageFormat::testEquals failed #1"); | |
954 | logln("First test (operator ==): Failed!"); | |
955 | } | |
956 | ||
957 | } | |
958 | ||
959 | void TestMessageFormat::testNotEquals() | |
960 | { | |
961 | UErrorCode success = U_ZERO_ERROR; | |
962 | MessageFormat x("There are {0} files on {1}", success); | |
963 | MessageFormat y(x); | |
964 | y.setLocale(Locale("fr")); | |
965 | if (!(x != y)) { | |
966 | errln( "TestMessageFormat::testEquals failed #1"); | |
967 | logln("First test (operator !=): Failed!"); | |
968 | } | |
969 | y = x; | |
970 | y.applyPattern("There are {0} files on {1} the disk", success); | |
971 | if (!(x != y)) { | |
972 | errln( "TestMessageFormat::testEquals failed #1"); | |
374ca955 | 973 | logln("Second test (operator !=): Failed!"); |
b75a7d8f A |
974 | } |
975 | } | |
976 | ||
977 | ||
978 | void TestMessageFormat::testSetLocale() | |
979 | { | |
980 | UErrorCode err = U_ZERO_ERROR; | |
981 | GregorianCalendar cal(err); | |
982 | Formattable arguments[] = { | |
983 | 456.83, | |
984 | Formattable(UDate(8.71068e+011), Formattable::kIsDate), | |
985 | "deposit" | |
986 | }; | |
987 | ||
988 | UnicodeString result; | |
989 | ||
990 | //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; | |
991 | UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}."; | |
992 | // {sfb} to get $, would need Locale::US, not Locale::ENGLISH | |
993 | // Just use unlocalized currency symbol. | |
994 | //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83."; | |
995 | UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of "; | |
996 | compareStrEng += (UChar) 0x00a4; | |
997 | compareStrEng += "456.83."; | |
998 | // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN | |
999 | // Just use unlocalized currency symbol. | |
1000 | //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM."; | |
1001 | UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of "; | |
46f4442e A |
1002 | compareStrGer += "456,83"; |
1003 | compareStrGer += (UChar) 0x00a0; | |
3d1f044b | 1004 | compareStrGer += "XXX."; |
b75a7d8f A |
1005 | |
1006 | MessageFormat msg( formatStr, err); | |
1007 | result = ""; | |
f3c0d7a5 | 1008 | FieldPosition pos(FieldPosition::DONT_CARE); |
b75a7d8f A |
1009 | result = msg.format( |
1010 | arguments, | |
1011 | 3, | |
1012 | result, | |
1013 | pos, | |
1014 | err); | |
1015 | ||
1016 | logln(result); | |
1017 | if (result != compareStrEng) { | |
3d1f044b A |
1018 | char bbuf[96]; |
1019 | result.extract(0, result.length(), bbuf, sizeof(bbuf)); | |
1020 | dataerrln("*** MSG format err. - %s; result was %s", u_errorName(err), bbuf); | |
b75a7d8f A |
1021 | } |
1022 | ||
1023 | msg.setLocale(Locale::getEnglish()); | |
1024 | UBool getLocale_ok = TRUE; | |
1025 | if (msg.getLocale() != Locale::getEnglish()) { | |
3d1f044b | 1026 | errln("*** MSG getLocale err."); |
b75a7d8f A |
1027 | getLocale_ok = FALSE; |
1028 | } | |
1029 | ||
1030 | msg.setLocale(Locale::getGerman()); | |
1031 | ||
1032 | if (msg.getLocale() != Locale::getGerman()) { | |
1033 | errln("*** MSG getLocal err."); | |
1034 | getLocale_ok = FALSE; | |
1035 | } | |
1036 | ||
1037 | msg.applyPattern( formatStr, err); | |
1038 | ||
1039 | pos.setField(0); | |
1040 | result = ""; | |
1041 | result = msg.format( | |
1042 | arguments, | |
1043 | 3, | |
1044 | result, | |
1045 | pos, | |
1046 | err); | |
1047 | ||
1048 | logln(result); | |
1049 | if (result == compareStrGer) { | |
1050 | logln("MSG setLocale tested."); | |
1051 | }else{ | |
729e4ab9 | 1052 | dataerrln( "*** MSG setLocale err. - %s", u_errorName(err)); |
b75a7d8f A |
1053 | } |
1054 | ||
1055 | if (getLocale_ok) { | |
1056 | logln("MSG getLocale tested."); | |
1057 | } | |
1058 | } | |
1059 | ||
1060 | void TestMessageFormat::testFormat() | |
1061 | { | |
1062 | UErrorCode err = U_ZERO_ERROR; | |
1063 | GregorianCalendar cal(err); | |
1064 | ||
1065 | const Formattable ftarray[] = | |
1066 | { | |
1067 | Formattable( UDate(8.71068e+011), Formattable::kIsDate ) | |
1068 | }; | |
2ca993e8 | 1069 | const int32_t ft_cnt = UPRV_LENGTHOF(ftarray); |
b75a7d8f A |
1070 | Formattable ft_arr( ftarray, ft_cnt ); |
1071 | ||
1072 | Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate); | |
1073 | ||
1074 | UnicodeString result; | |
1075 | ||
1076 | //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; | |
1077 | UnicodeString formatStr = "On {0,date}, it began."; | |
1078 | UnicodeString compareStr = "On Aug 8, 1997, it began."; | |
1079 | ||
1080 | err = U_ZERO_ERROR; | |
1081 | MessageFormat msg( formatStr, err); | |
f3c0d7a5 | 1082 | FieldPosition fp(FieldPosition::DONT_CARE); |
b75a7d8f A |
1083 | |
1084 | result = ""; | |
1085 | fp = 0; | |
1086 | result = msg.format( | |
1087 | *fmt, | |
1088 | result, | |
3d1f044b | 1089 | //FieldPosition(FieldPosition::DONT_CARE), |
b75a7d8f A |
1090 | fp, |
1091 | err); | |
1092 | ||
1093 | if (err != U_ILLEGAL_ARGUMENT_ERROR) { | |
729e4ab9 | 1094 | dataerrln("*** MSG format without expected error code. - %s", u_errorName(err)); |
b75a7d8f A |
1095 | } |
1096 | err = U_ZERO_ERROR; | |
1097 | ||
1098 | result = ""; | |
1099 | fp = 0; | |
1100 | result = msg.format( | |
1101 | ft_arr, | |
1102 | result, | |
3d1f044b | 1103 | //FieldPosition(FieldPosition::DONT_CARE), |
b75a7d8f A |
1104 | fp, |
1105 | err); | |
1106 | ||
1107 | logln("MSG format( Formattable&, ... ) expected:" + compareStr); | |
1108 | logln("MSG format( Formattable&, ... ) result:" + result); | |
1109 | if (result != compareStr) { | |
729e4ab9 | 1110 | dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err)); |
b75a7d8f A |
1111 | }else{ |
1112 | logln("MSG format( Formattable&, ... ) tested."); | |
1113 | } | |
1114 | ||
1115 | delete fmt; | |
1116 | ||
1117 | } | |
1118 | ||
1119 | void TestMessageFormat::testParse() | |
1120 | { | |
1121 | UErrorCode err = U_ZERO_ERROR; | |
1122 | int32_t count; | |
1123 | UnicodeString msgFormatString = "{0} =sep= {1}"; | |
1124 | MessageFormat msg( msgFormatString, err); | |
1125 | UnicodeString source = "abc =sep= def"; | |
1126 | UnicodeString tmp1, tmp2; | |
1127 | ||
1128 | Formattable* fmt_arr = msg.parse( source, count, err ); | |
1129 | if (U_FAILURE(err) || (!fmt_arr)) { | |
1130 | errln("*** MSG parse (ustring, count, err) error."); | |
1131 | }else{ | |
1132 | logln("MSG parse -- count: %d", count); | |
1133 | if (count != 2) { | |
1134 | errln("*** MSG parse (ustring, count, err) count err."); | |
1135 | }else{ | |
1136 | if ((fmt_arr[0].getType() == Formattable::kString) | |
1137 | && (fmt_arr[1].getType() == Formattable::kString) | |
1138 | && (fmt_arr[0].getString(tmp1) == "abc") | |
1139 | && (fmt_arr[1].getString(tmp2) == "def")) { | |
1140 | logln("MSG parse (ustring, count, err) tested."); | |
1141 | }else{ | |
1142 | errln("*** MSG parse (ustring, count, err) result err."); | |
1143 | } | |
1144 | } | |
1145 | } | |
1146 | delete[] fmt_arr; | |
1147 | ||
1148 | ParsePosition pp(0); | |
1149 | ||
1150 | fmt_arr = msg.parse( source, pp, count ); | |
1151 | if ((pp == 0) || (!fmt_arr)) { | |
1152 | errln("*** MSG parse (ustring, parsepos., count) error."); | |
1153 | }else{ | |
1154 | logln("MSG parse -- count: %d", count); | |
1155 | if (count != 2) { | |
1156 | errln("*** MSG parse (ustring, parsepos., count) count err."); | |
1157 | }else{ | |
1158 | if ((fmt_arr[0].getType() == Formattable::kString) | |
1159 | && (fmt_arr[1].getType() == Formattable::kString) | |
1160 | && (fmt_arr[0].getString(tmp1) == "abc") | |
1161 | && (fmt_arr[1].getString(tmp2) == "def")) { | |
1162 | logln("MSG parse (ustring, parsepos., count) tested."); | |
1163 | }else{ | |
1164 | errln("*** MSG parse (ustring, parsepos., count) result err."); | |
1165 | } | |
1166 | } | |
1167 | } | |
1168 | delete[] fmt_arr; | |
1169 | ||
1170 | pp = 0; | |
1171 | Formattable fmta; | |
1172 | ||
1173 | msg.parseObject( source, fmta, pp ); | |
1174 | if (pp == 0) { | |
1175 | errln("*** MSG parse (ustring, Formattable, parsepos ) error."); | |
1176 | }else{ | |
1177 | logln("MSG parse -- count: %d", count); | |
1178 | fmta.getArray(count); | |
1179 | if (count != 2) { | |
1180 | errln("*** MSG parse (ustring, Formattable, parsepos ) count err."); | |
1181 | }else{ | |
1182 | if ((fmta[0].getType() == Formattable::kString) | |
1183 | && (fmta[1].getType() == Formattable::kString) | |
1184 | && (fmta[0].getString(tmp1) == "abc") | |
1185 | && (fmta[1].getString(tmp2) == "def")) { | |
1186 | logln("MSG parse (ustring, Formattable, parsepos ) tested."); | |
1187 | }else{ | |
1188 | errln("*** MSG parse (ustring, Formattable, parsepos ) result err."); | |
1189 | } | |
1190 | } | |
1191 | } | |
1192 | } | |
1193 | ||
1194 | ||
1195 | void TestMessageFormat::testAdopt() | |
1196 | { | |
1197 | UErrorCode err = U_ZERO_ERROR; | |
1198 | ||
1199 | UnicodeString formatStr("{0,date},{1},{2,number}", ""); | |
1200 | UnicodeString formatStrChange("{0,number},{1,number},{2,date}", ""); | |
1201 | err = U_ZERO_ERROR; | |
1202 | MessageFormat msg( formatStr, err); | |
1203 | MessageFormat msgCmp( formatStr, err); | |
4388f060 A |
1204 | if (U_FAILURE(err)) { |
1205 | dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err)); | |
1206 | return; | |
1207 | } | |
b75a7d8f A |
1208 | int32_t count, countCmp; |
1209 | const Format** formats = msg.getFormats(count); | |
1210 | const Format** formatsCmp = msgCmp.getFormats(countCmp); | |
1211 | const Format** formatsChg = 0; | |
1212 | const Format** formatsAct = 0; | |
1213 | int32_t countAct; | |
1214 | const Format* a; | |
1215 | const Format* b; | |
1216 | UnicodeString patCmp; | |
1217 | UnicodeString patAct; | |
1218 | Format** formatsToAdopt; | |
1219 | ||
1220 | if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) { | |
729e4ab9 | 1221 | dataerrln("Error getting Formats"); |
b75a7d8f A |
1222 | return; |
1223 | } | |
1224 | ||
1225 | int32_t i; | |
1226 | ||
1227 | for (i = 0; i < count; i++) { | |
1228 | a = formats[i]; | |
1229 | b = formatsCmp[i]; | |
1230 | if ((a != NULL) && (b != NULL)) { | |
1231 | if (*a != *b) { | |
1232 | errln("a != b"); | |
1233 | return; | |
1234 | } | |
1235 | }else if ((a != NULL) || (b != NULL)) { | |
1236 | errln("(a != NULL) || (b != NULL)"); | |
1237 | return; | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | msg.applyPattern( formatStrChange, err ); //set msg formats to something different | |
1242 | int32_t countChg; | |
1243 | formatsChg = msg.getFormats(countChg); // tested function | |
1244 | if (!formatsChg || (countChg != count)) { | |
1245 | errln("Error getting Formats"); | |
1246 | return; | |
1247 | } | |
1248 | ||
1249 | UBool diff; | |
1250 | diff = TRUE; | |
1251 | for (i = 0; i < count; i++) { | |
1252 | a = formatsChg[i]; | |
1253 | b = formatsCmp[i]; | |
1254 | if ((a != NULL) && (b != NULL)) { | |
1255 | if (*a == *b) { | |
374ca955 | 1256 | logln("formatsChg == formatsCmp at index %d", i); |
b75a7d8f A |
1257 | diff = FALSE; |
1258 | } | |
1259 | } | |
1260 | } | |
1261 | if (!diff) { | |
1262 | errln("*** MSG getFormats diff err."); | |
1263 | return; | |
1264 | } | |
1265 | ||
1266 | logln("MSG getFormats tested."); | |
1267 | ||
1268 | msg.setFormats( formatsCmp, countCmp ); //tested function | |
1269 | ||
1270 | formatsAct = msg.getFormats(countAct); | |
1271 | if (!formatsAct || (countAct <=0) || (countAct != countCmp)) { | |
1272 | errln("Error getting Formats"); | |
1273 | return; | |
1274 | } | |
1275 | ||
374ca955 | 1276 | assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove())); |
4388f060 A |
1277 | // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). |
1278 | // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove())); | |
1279 | msg.toPattern(patCmp.remove()); | |
1280 | if (!patCmp.isBogus()) { | |
1281 | errln("msg.setFormat().toPattern() succeeds."); | |
1282 | } | |
b75a7d8f A |
1283 | |
1284 | for (i = 0; i < countAct; i++) { | |
1285 | a = formatsAct[i]; | |
1286 | b = formatsCmp[i]; | |
1287 | if ((a != NULL) && (b != NULL)) { | |
1288 | if (*a != *b) { | |
1289 | logln("formatsAct != formatsCmp at index %d", i); | |
1290 | errln("a != b"); | |
1291 | return; | |
1292 | } | |
1293 | }else if ((a != NULL) || (b != NULL)) { | |
1294 | errln("(a != NULL) || (b != NULL)"); | |
1295 | return; | |
1296 | } | |
1297 | } | |
1298 | logln("MSG setFormats tested."); | |
1299 | ||
b75a7d8f A |
1300 | //---- |
1301 | ||
1302 | msg.applyPattern( formatStrChange, err ); //set msg formats to something different | |
1303 | ||
1304 | formatsToAdopt = new Format* [countCmp]; | |
1305 | if (!formatsToAdopt) { | |
1306 | errln("memory allocation error"); | |
1307 | return; | |
1308 | } | |
1309 | ||
1310 | for (i = 0; i < countCmp; i++) { | |
1311 | if (formatsCmp[i] == NULL) { | |
1312 | formatsToAdopt[i] = NULL; | |
1313 | }else{ | |
1314 | formatsToAdopt[i] = formatsCmp[i]->clone(); | |
1315 | if (!formatsToAdopt[i]) { | |
1316 | errln("Can't clone format at index %d", i); | |
1317 | return; | |
1318 | } | |
1319 | } | |
1320 | } | |
1321 | msg.adoptFormats( formatsToAdopt, countCmp ); // function to test | |
1322 | delete[] formatsToAdopt; | |
1323 | ||
374ca955 | 1324 | assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove())); |
4388f060 A |
1325 | // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). |
1326 | // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove())); | |
b75a7d8f A |
1327 | |
1328 | formatsAct = msg.getFormats(countAct); | |
1329 | if (!formatsAct || (countAct <=0) || (countAct != countCmp)) { | |
1330 | errln("Error getting Formats"); | |
1331 | return; | |
1332 | } | |
1333 | ||
1334 | for (i = 0; i < countAct; i++) { | |
1335 | a = formatsAct[i]; | |
1336 | b = formatsCmp[i]; | |
1337 | if ((a != NULL) && (b != NULL)) { | |
1338 | if (*a != *b) { | |
1339 | errln("a != b"); | |
1340 | return; | |
1341 | } | |
1342 | }else if ((a != NULL) || (b != NULL)) { | |
1343 | errln("(a != NULL) || (b != NULL)"); | |
1344 | return; | |
1345 | } | |
1346 | } | |
1347 | logln("MSG adoptFormats tested."); | |
1348 | ||
1349 | //---- adoptFormat | |
1350 | ||
1351 | msg.applyPattern( formatStrChange, err ); //set msg formats to something different | |
1352 | ||
1353 | formatsToAdopt = new Format* [countCmp]; | |
1354 | if (!formatsToAdopt) { | |
1355 | errln("memory allocation error"); | |
1356 | return; | |
1357 | } | |
1358 | ||
1359 | for (i = 0; i < countCmp; i++) { | |
1360 | if (formatsCmp[i] == NULL) { | |
1361 | formatsToAdopt[i] = NULL; | |
1362 | }else{ | |
1363 | formatsToAdopt[i] = formatsCmp[i]->clone(); | |
1364 | if (!formatsToAdopt[i]) { | |
1365 | errln("Can't clone format at index %d", i); | |
1366 | return; | |
1367 | } | |
1368 | } | |
1369 | } | |
1370 | ||
1371 | for ( i = 0; i < countCmp; i++ ) { | |
1372 | msg.adoptFormat( i, formatsToAdopt[i] ); // function to test | |
1373 | } | |
1374 | delete[] formatsToAdopt; // array itself not needed in this case; | |
1375 | ||
374ca955 | 1376 | assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove())); |
4388f060 A |
1377 | // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). |
1378 | // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove())); | |
b75a7d8f A |
1379 | |
1380 | formatsAct = msg.getFormats(countAct); | |
1381 | if (!formatsAct || (countAct <=0) || (countAct != countCmp)) { | |
1382 | errln("Error getting Formats"); | |
1383 | return; | |
1384 | } | |
1385 | ||
1386 | for (i = 0; i < countAct; i++) { | |
1387 | a = formatsAct[i]; | |
1388 | b = formatsCmp[i]; | |
1389 | if ((a != NULL) && (b != NULL)) { | |
1390 | if (*a != *b) { | |
1391 | errln("a != b"); | |
1392 | return; | |
1393 | } | |
1394 | }else if ((a != NULL) || (b != NULL)) { | |
1395 | errln("(a != NULL) || (b != NULL)"); | |
1396 | return; | |
1397 | } | |
1398 | } | |
1399 | logln("MSG adoptFormat tested."); | |
1400 | } | |
1401 | ||
1402 | // This test is a regression test for a fixed bug in the copy constructor. | |
1403 | // It is kept as a global function rather than as a method since the test depends on memory values. | |
1404 | // (At least before the bug was fixed, whether it showed up or not depended on memory contents, | |
1405 | // which is probably why it didn't show up in the regular test for the copy constructor.) | |
1406 | // For this reason, the test isn't changed even though it contains function calls whose results are | |
1407 | // not tested and had no problems. Actually, the test failed by *crashing*. | |
1408 | static void _testCopyConstructor2() | |
1409 | { | |
1410 | UErrorCode status = U_ZERO_ERROR; | |
1411 | UnicodeString formatStr("Hello World on {0,date,full}", ""); | |
1412 | UnicodeString resultStr(" ", ""); | |
1413 | UnicodeString result; | |
f3c0d7a5 | 1414 | FieldPosition fp(FieldPosition::DONT_CARE); |
b75a7d8f A |
1415 | UDate d = Calendar::getNow(); |
1416 | const Formattable fargs( d, Formattable::kIsDate ); | |
1417 | ||
1418 | MessageFormat* fmt1 = new MessageFormat( formatStr, status ); | |
4388f060 A |
1419 | MessageFormat* fmt2 = NULL; |
1420 | MessageFormat* fmt3 = NULL; | |
1421 | MessageFormat* fmt4 = NULL; | |
b75a7d8f | 1422 | |
4388f060 A |
1423 | if (fmt1 == NULL) { |
1424 | it_err("testCopyConstructor2: (fmt1 != NULL)"); | |
1425 | goto cleanup; | |
1426 | } | |
b75a7d8f | 1427 | |
4388f060 | 1428 | fmt2 = new MessageFormat( *fmt1 ); |
b75a7d8f A |
1429 | result = fmt1->format( &fargs, 1, resultStr, fp, status ); |
1430 | ||
4388f060 A |
1431 | if (fmt2 == NULL) { |
1432 | it_err("testCopyConstructor2: (fmt2 != NULL)"); | |
1433 | goto cleanup; | |
1434 | } | |
b75a7d8f | 1435 | |
340931cb A |
1436 | fmt3 = fmt1->clone(); |
1437 | fmt4 = fmt2->clone(); | |
b75a7d8f | 1438 | |
4388f060 A |
1439 | if (fmt3 == NULL) { |
1440 | it_err("testCopyConstructor2: (fmt3 != NULL)"); | |
1441 | goto cleanup; | |
1442 | } | |
1443 | if (fmt4 == NULL) { | |
1444 | it_err("testCopyConstructor2: (fmt4 != NULL)"); | |
1445 | goto cleanup; | |
1446 | } | |
b75a7d8f A |
1447 | |
1448 | result = fmt1->format( &fargs, 1, resultStr, fp, status ); | |
1449 | result = fmt2->format( &fargs, 1, resultStr, fp, status ); | |
1450 | result = fmt3->format( &fargs, 1, resultStr, fp, status ); | |
1451 | result = fmt4->format( &fargs, 1, resultStr, fp, status ); | |
4388f060 A |
1452 | |
1453 | cleanup: | |
b75a7d8f A |
1454 | delete fmt1; |
1455 | delete fmt2; | |
1456 | delete fmt3; | |
1457 | delete fmt4; | |
1458 | } | |
1459 | ||
1460 | void TestMessageFormat::testCopyConstructor2() { | |
1461 | _testCopyConstructor2(); | |
1462 | } | |
1463 | ||
1464 | /** | |
1465 | * Verify that MessageFormat accomodates more than 10 arguments and | |
1466 | * more than 10 subformats. | |
1467 | */ | |
1468 | void TestMessageFormat::TestUnlimitedArgsAndSubformats() { | |
1469 | UErrorCode ec = U_ZERO_ERROR; | |
1470 | const UnicodeString pattern = | |
1471 | "On {0,date} (aka {0,date,short}, aka {0,date,long}) " | |
1472 | "at {0,time} (aka {0,time,short}, aka {0,time,long}) " | |
1473 | "there were {1,number} werjes " | |
1474 | "(a {3,number,percent} increase over {2,number}) " | |
1475 | "despite the {4}''s efforts " | |
1476 | "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}."; | |
1477 | MessageFormat msg(pattern, ec); | |
1478 | if (U_FAILURE(ec)) { | |
729e4ab9 | 1479 | dataerrln("FAIL: constructor failed - %s", u_errorName(ec)); |
b75a7d8f A |
1480 | return; |
1481 | } | |
1482 | ||
1483 | const Formattable ARGS[] = { | |
1484 | Formattable(UDate(1e13), Formattable::kIsDate), | |
1485 | Formattable((int32_t)1303), | |
1486 | Formattable((int32_t)1202), | |
1487 | Formattable(1303.0/1202 - 1), | |
1488 | Formattable("Glimmung"), | |
1489 | Formattable("the printers"), | |
1490 | Formattable("Nick"), | |
1491 | Formattable("his father"), | |
1492 | Formattable("his mother"), | |
1493 | Formattable("the spiddles"), | |
1494 | Formattable("of course"), | |
1495 | Formattable("Horace"), | |
1496 | }; | |
2ca993e8 | 1497 | const int32_t ARGS_LENGTH = UPRV_LENGTHOF(ARGS); |
b75a7d8f A |
1498 | Formattable ARGS_OBJ(ARGS, ARGS_LENGTH); |
1499 | ||
1500 | UnicodeString expected = | |
1501 | "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) " | |
1502 | "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) " | |
1503 | "there were 1,303 werjes " | |
1504 | "(a 8% increase over 1,202) " | |
1505 | "despite the Glimmung's efforts " | |
1506 | "and to delight of the printers, Nick, his father, " | |
1507 | "his mother, the spiddles, and of course Horace."; | |
1508 | UnicodeString result; | |
1509 | msg.format(ARGS_OBJ, result, ec); | |
1510 | if (result == expected) { | |
1511 | logln(result); | |
1512 | } else { | |
1513 | errln((UnicodeString)"FAIL: Got " + result + | |
1514 | ", expected " + expected); | |
1515 | } | |
1516 | } | |
1517 | ||
374ca955 A |
1518 | // test RBNF extensions to message format |
1519 | void TestMessageFormat::TestRBNF(void) { | |
1520 | // WARNING: this depends on the RBNF formats for en_US | |
1521 | Locale locale("en", "US", ""); | |
1522 | ||
1523 | UErrorCode ec = U_ZERO_ERROR; | |
1524 | ||
1525 | UnicodeString values[] = { | |
1526 | // decimal values do not format completely for ordinal or duration, and | |
1527 | // do not always parse, so do not include them | |
1528 | "0", "1", "12", "100", "123", "1001", "123,456", "-17", | |
1529 | }; | |
2ca993e8 | 1530 | int32_t values_count = UPRV_LENGTHOF(values); |
374ca955 A |
1531 | |
1532 | UnicodeString formats[] = { | |
1533 | "There are {0,spellout} files to search.", | |
1534 | "There are {0,spellout,%simplified} files to search.", | |
1535 | "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.", | |
2ca993e8 | 1536 | "This is the {0,ordinal} file to search.", |
374ca955 A |
1537 | "Searching this file will take {0,duration} to complete.", |
1538 | "Searching this file will take {0,duration,%with-words} to complete.", | |
1539 | }; | |
2ca993e8 | 1540 | int32_t formats_count = UPRV_LENGTHOF(formats); |
374ca955 A |
1541 | |
1542 | Formattable args[1]; | |
1543 | ||
1544 | NumberFormat* numFmt = NumberFormat::createInstance(locale, ec); | |
73c04bcf A |
1545 | if (U_FAILURE(ec)) { |
1546 | dataerrln("Error calling NumberFormat::createInstance()"); | |
1547 | return; | |
1548 | } | |
1549 | ||
374ca955 A |
1550 | for (int i = 0; i < formats_count; ++i) { |
1551 | MessageFormat* fmt = new MessageFormat(formats[i], locale, ec); | |
1552 | logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'"); | |
73c04bcf | 1553 | |
374ca955 A |
1554 | for (int j = 0; j < values_count; ++j) { |
1555 | ec = U_ZERO_ERROR; | |
1556 | numFmt->parse(values[j], args[0], ec); | |
1557 | if (U_FAILURE(ec)) { | |
1558 | errln((UnicodeString)"Failed to parse test argument " + values[j]); | |
1559 | } else { | |
f3c0d7a5 | 1560 | FieldPosition fp(FieldPosition::DONT_CARE); |
374ca955 A |
1561 | UnicodeString result; |
1562 | fmt->format(args, 1, result, fp, ec); | |
1563 | logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec)); | |
1564 | ||
2ca993e8 A |
1565 | int32_t count = 0; |
1566 | Formattable* parseResult = fmt->parse(result, count, ec); | |
1567 | if (count != 1) { | |
1568 | errln((UnicodeString)"parse returned " + count + " args"); | |
1569 | } else if (parseResult[0] != args[0]) { | |
1570 | errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0])); | |
374ca955 | 1571 | } |
2ca993e8 | 1572 | delete []parseResult; |
374ca955 A |
1573 | } |
1574 | } | |
1575 | delete fmt; | |
1576 | } | |
1577 | delete numFmt; | |
1578 | } | |
1579 | ||
4388f060 A |
1580 | UnicodeString TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern& pattern) { |
1581 | UnicodeString us(pattern.getPatternString()); | |
1582 | int count = pattern.countParts(); | |
1583 | for (int i = count; i > 0;) { | |
1584 | const MessagePattern::Part& part = pattern.getPart(--i); | |
1585 | if (part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) { | |
1586 | us.remove(part.getIndex(), part.getLimit() - part.getIndex()); | |
1587 | } | |
1588 | } | |
1589 | return us; | |
1590 | } | |
1591 | ||
1592 | void TestMessageFormat::TestApostropheMode() { | |
1593 | UErrorCode status = U_ZERO_ERROR; | |
1594 | MessagePattern *ado_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL, status); | |
1595 | MessagePattern *adr_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED, status); | |
1596 | if (ado_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) { | |
1597 | errln("wrong value from ado_mp->getApostropheMode()."); | |
1598 | } | |
1599 | if (adr_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) { | |
1600 | errln("wrong value from adr_mp->getApostropheMode()."); | |
1601 | } | |
1602 | ||
1603 | ||
1604 | UnicodeString tuples[] = { | |
1605 | // Desired output | |
1606 | // DOUBLE_OPTIONAL pattern | |
1607 | // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL) | |
1608 | "I see {many}", "I see '{many}'", "", | |
1609 | "I said {'Wow!'}", "I said '{''Wow!''}'", "", | |
1610 | "I dont know", "I dont know", "I don't know", | |
1611 | "I don't know", "I don't know", "I don''t know", | |
1612 | "I don't know", "I don''t know", "I don''t know" | |
1613 | }; | |
b331163b | 1614 | int32_t tuples_count = UPRV_LENGTHOF(tuples); |
4388f060 A |
1615 | |
1616 | for (int i = 0; i < tuples_count; i += 3) { | |
1617 | UnicodeString& desired = tuples[i]; | |
1618 | UnicodeString& ado_pattern = tuples[i + 1]; | |
1619 | UErrorCode status = U_ZERO_ERROR; | |
1620 | assertEquals("DOUBLE_OPTIONAL failure", | |
1621 | desired, | |
1622 | GetPatternAndSkipSyntax(ado_mp->parse(ado_pattern, NULL, status))); | |
1623 | UnicodeString& adr_pattern = tuples[i + 2].isEmpty() ? ado_pattern : tuples[i + 2]; | |
1624 | assertEquals("DOUBLE_REQUIRED failure", desired, | |
1625 | GetPatternAndSkipSyntax(adr_mp->parse(adr_pattern, NULL, status))); | |
1626 | } | |
1627 | delete adr_mp; | |
1628 | delete ado_mp; | |
1629 | } | |
1630 | ||
1631 | ||
1632 | // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode. | |
1633 | void TestMessageFormat::TestCompatibleApostrophe() { | |
1634 | // Message with choice argument which does not contain another argument. | |
1635 | // The JDK performs only one apostrophe-quoting pass on this pattern. | |
1636 | UnicodeString pattern = "ab{0,choice,0#1'2''3'''4''''.}yz"; | |
1637 | ||
1638 | UErrorCode ec = U_ZERO_ERROR; | |
1639 | MessageFormat compMsg("", Locale::getUS(), ec); | |
1640 | compMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, ec); | |
1641 | if (compMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) { | |
1642 | errln("wrong value from compMsg.getApostropheMode()."); | |
1643 | } | |
1644 | ||
1645 | MessageFormat icuMsg("", Locale::getUS(), ec); | |
1646 | icuMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_OPTIONAL, NULL, ec); | |
1647 | if (icuMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) { | |
1648 | errln("wrong value from icuMsg.getApostropheMode()."); | |
1649 | } | |
1650 | ||
1651 | Formattable zero0[] = { (int32_t)0 }; | |
f3c0d7a5 | 1652 | FieldPosition fieldpos(FieldPosition::DONT_CARE); |
4388f060 A |
1653 | UnicodeString buffer1, buffer2; |
1654 | assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", | |
1655 | "ab12'3'4''.yz", | |
1656 | compMsg.format(zero0, 1, buffer1, fieldpos, ec)); | |
1657 | assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", | |
1658 | "ab1'2'3''4''.yz", | |
1659 | icuMsg.format(zero0, 1, buffer2, fieldpos, ec)); | |
1660 | ||
1661 | // Message with choice argument which contains a nested simple argument. | |
1662 | // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes. | |
1663 | buffer1.remove(); | |
1664 | buffer2.remove(); | |
1665 | pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz"; | |
1666 | compMsg.applyPattern(pattern, ec); | |
1667 | icuMsg.applyPattern(pattern, ec); | |
1668 | if (U_FAILURE(ec)) { | |
1669 | dataerrln("Unable to applyPattern - %s", u_errorName(ec)); | |
1670 | } else { | |
1671 | assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", | |
1672 | "ab1234'.0xyz", | |
1673 | compMsg.format(zero0, 1, buffer1, fieldpos, ec)); | |
1674 | assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", | |
1675 | "ab1'2'3''4''.#x0yz", | |
1676 | icuMsg.format(zero0, 1, buffer2, fieldpos, ec)); | |
1677 | } | |
1678 | ||
1679 | // This part is copied over from Java tests but cannot be properly tested here | |
1680 | // because we do not have a live reference implementation with JDK behavior. | |
1681 | // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass. | |
1682 | /* | |
1683 | ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''."); | |
1684 | assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", | |
1685 | "12'3'4''.", | |
1686 | choice.format(0)); | |
1687 | choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}"); | |
1688 | assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", | |
1689 | "12'3'4''.{0,number,#x}", | |
1690 | choice.format(0)); | |
1691 | */ | |
1692 | } | |
1693 | ||
73c04bcf A |
1694 | void TestMessageFormat::testAutoQuoteApostrophe(void) { |
1695 | const char* patterns[] = { // pattern, expected pattern | |
1696 | "'", "''", | |
1697 | "''", "''", | |
1698 | "'{", "'{'", | |
1699 | "' {", "'' {", | |
1700 | "'a", "''a", | |
1701 | "'{'a", "'{'a", | |
1702 | "'{a'", "'{a'", | |
1703 | "'{}", "'{}'", | |
1704 | "{'", "{'", | |
1705 | "{'a", "{'a", | |
1706 | "{'a{}'a}'a", "{'a{}'a}''a", | |
1707 | "'}'", "'}'", | |
1708 | "'} '{'}'", "'} '{'}''", | |
1709 | "'} {{{''", "'} {{{'''", | |
1710 | }; | |
2ca993e8 | 1711 | int32_t pattern_count = UPRV_LENGTHOF(patterns); |
73c04bcf A |
1712 | |
1713 | for (int i = 0; i < pattern_count; i += 2) { | |
1714 | UErrorCode status = U_ZERO_ERROR; | |
1715 | UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status); | |
1716 | UnicodeString target(patterns[i+1]); | |
1717 | if (target != result) { | |
1718 | const int BUF2_LEN = 64; | |
1719 | char buf[256]; | |
1720 | char buf2[BUF2_LEN]; | |
1721 | int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN); | |
1722 | if (len >= BUF2_LEN) { | |
1723 | buf2[BUF2_LEN-1] = 0; | |
1724 | } | |
1725 | sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2); | |
1726 | errln(buf); | |
1727 | } | |
1728 | } | |
1729 | } | |
1730 | ||
729e4ab9 A |
1731 | void TestMessageFormat::testCoverage(void) { |
1732 | UErrorCode status = U_ZERO_ERROR; | |
1733 | UnicodeString testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste."); | |
1734 | MessageFormat *msgfmt = new MessageFormat(testformat, Locale("fr"), status); | |
1735 | if (msgfmt == NULL || U_FAILURE(status)) { | |
1736 | dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status)); | |
1737 | return; | |
1738 | } | |
1739 | if (!msgfmt->usesNamedArguments()) { | |
1740 | errln("FAIL: Unable to detect usage of named arguments."); | |
1741 | } | |
1742 | const double limit[] = {0.0, 1.0, 2.0}; | |
1743 | const UnicodeString formats[] = {"0.0<=Arg<1.0", | |
1744 | "1.0<=Arg<2.0", | |
1745 | "2.0<-Arg"}; | |
1746 | ChoiceFormat cf(limit, formats, 3); | |
1747 | ||
1748 | msgfmt->setFormat("set", cf, status); | |
1749 | ||
1750 | StringEnumeration *en = msgfmt->getFormatNames(status); | |
1751 | if (en == NULL || U_FAILURE(status)) { | |
1752 | errln("FAIL: Unable to get format names enumeration."); | |
1753 | } else { | |
1754 | int32_t count = 0; | |
1755 | en->reset(status); | |
1756 | count = en->count(status); | |
1757 | if (U_FAILURE(status)) { | |
1758 | errln("FAIL: Unable to get format name enumeration count."); | |
1759 | } else { | |
1760 | for (int32_t i = 0; i < count; i++) { | |
1761 | en->snext(status); | |
1762 | if (U_FAILURE(status)) { | |
1763 | errln("FAIL: Error enumerating through names."); | |
1764 | break; | |
1765 | } | |
1766 | } | |
1767 | } | |
1768 | } | |
1769 | ||
4388f060 A |
1770 | // adoptFormat() takes ownership of the input Format object. |
1771 | // We need to clone the stack-allocated cf so that we do not attempt to delete cf. | |
1772 | Format *cfClone = cf.clone(); | |
1773 | msgfmt->adoptFormat("adopt", cfClone, status); | |
729e4ab9 A |
1774 | |
1775 | delete en; | |
1776 | delete msgfmt; | |
1777 | ||
1778 | msgfmt = new MessageFormat("'", status); | |
1779 | if (msgfmt == NULL || U_FAILURE(status)) { | |
1780 | errln("FAIL: Unable to create MessageFormat."); | |
1781 | return; | |
1782 | } | |
1783 | if (msgfmt->usesNamedArguments()) { | |
1784 | errln("FAIL: Unable to detect usage of named arguments."); | |
1785 | } | |
1786 | ||
4388f060 A |
1787 | // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames() |
1788 | // on a MessageFormat without named arguments. | |
729e4ab9 | 1789 | msgfmt->setFormat("formatName", cf, status); |
4388f060 A |
1790 | if (U_FAILURE(status)) { |
1791 | errln("FAIL: Should work to setFormat(name, ...) regardless of pattern."); | |
729e4ab9 A |
1792 | } |
1793 | status = U_ZERO_ERROR; | |
1794 | en = msgfmt->getFormatNames(status); | |
4388f060 A |
1795 | if (U_FAILURE(status)) { |
1796 | errln("FAIL: Should work to get format names enumeration regardless of pattern."); | |
729e4ab9 A |
1797 | } |
1798 | ||
1799 | delete en; | |
1800 | delete msgfmt; | |
1801 | } | |
1802 | ||
51004dcb A |
1803 | void TestMessageFormat::testGetFormatNames() { |
1804 | IcuTestErrorCode errorCode(*this, "testGetFormatNames"); | |
1805 | MessageFormat msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode); | |
0f5d89e8 | 1806 | if(errorCode.errDataIfFailureAndReset("MessageFormat() failed")) { |
51004dcb A |
1807 | return; |
1808 | } | |
1809 | LocalPointer<StringEnumeration> names(msgfmt.getFormatNames(errorCode)); | |
0f5d89e8 | 1810 | if(errorCode.errIfFailureAndReset("msgfmt.getFormatNames() failed")) { |
51004dcb A |
1811 | return; |
1812 | } | |
1813 | const UnicodeString *name; | |
1814 | name = names->snext(errorCode); | |
1815 | if (name == NULL || errorCode.isFailure()) { | |
1816 | errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName()); | |
1817 | errorCode.reset(); | |
1818 | return; | |
1819 | } | |
1820 | if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) { | |
1821 | return; | |
1822 | } | |
1823 | name = names->snext(errorCode); | |
1824 | if (name == NULL || errorCode.isFailure()) { | |
1825 | errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName()); | |
1826 | errorCode.reset(); | |
1827 | return; | |
1828 | } | |
1829 | if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) { | |
1830 | return; | |
1831 | } | |
1832 | name = names->snext(errorCode); | |
1833 | if (name == NULL || errorCode.isFailure()) { | |
1834 | errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName()); | |
1835 | errorCode.reset(); | |
1836 | return; | |
1837 | } | |
1838 | if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) { | |
1839 | return; | |
1840 | } | |
1841 | name = names->snext(errorCode); | |
1842 | if (name != NULL) { | |
1843 | errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name); | |
1844 | return; | |
1845 | } | |
1846 | } | |
1847 | ||
4388f060 A |
1848 | void TestMessageFormat::TestTrimArgumentName() { |
1849 | // ICU 4.8 allows and ignores white space around argument names and numbers. | |
1850 | IcuTestErrorCode errorCode(*this, "TestTrimArgumentName"); | |
1851 | MessageFormat m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode); | |
0f5d89e8 | 1852 | if (errorCode.errDataIfFailureAndReset("Unable to instantiate MessageFormat")) { |
4388f060 A |
1853 | return; |
1854 | } | |
1855 | Formattable args[1] = { (int32_t)2 }; | |
f3c0d7a5 | 1856 | FieldPosition ignore(FieldPosition::DONT_CARE); |
4388f060 A |
1857 | UnicodeString result; |
1858 | assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z", | |
1859 | m.format(args, 1, result, ignore, errorCode)); | |
1860 | ||
1861 | m.applyPattern("x { _oOo_ , number , integer } y", errorCode); | |
1862 | UnicodeString argName = UNICODE_STRING_SIMPLE("_oOo_"); | |
1863 | args[0].setLong(3); | |
1864 | result.remove(); | |
1865 | assertEquals("trim-named-arg format() failed", "x 3 y", | |
1866 | m.format(&argName, args, 1, result, errorCode)); | |
1867 | } | |
1868 | ||
51004dcb A |
1869 | void TestMessageFormat::TestSelectOrdinal() { |
1870 | IcuTestErrorCode errorCode(*this, "TestSelectOrdinal"); | |
1871 | // Test plural & ordinal together, | |
1872 | // to make sure that we get the correct cached PluralSelector for each. | |
1873 | MessageFormat m( | |
1874 | "{0,plural,one{1 file}other{# files}}, " | |
1875 | "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}", | |
1876 | Locale::getEnglish(), errorCode); | |
0f5d89e8 | 1877 | if (errorCode.errDataIfFailureAndReset("Unable to instantiate MessageFormat")) { |
51004dcb A |
1878 | return; |
1879 | } | |
1880 | Formattable args[1] = { (int32_t)21 }; | |
f3c0d7a5 | 1881 | FieldPosition ignore(FieldPosition::DONT_CARE); |
51004dcb A |
1882 | UnicodeString result; |
1883 | assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file", | |
1884 | m.format(args, 1, result, ignore, errorCode), TRUE); | |
1885 | ||
1886 | args[0].setLong(2); | |
1887 | assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file", | |
1888 | m.format(args, 1, result.remove(), ignore, errorCode), TRUE); | |
1889 | ||
1890 | args[0].setLong(1); | |
1891 | assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file", | |
1892 | m.format(args, 1, result.remove(), ignore, errorCode), TRUE); | |
1893 | ||
1894 | args[0].setLong(3); | |
1895 | assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file", | |
1896 | m.format(args, 1, result.remove(), ignore, errorCode), TRUE); | |
1897 | ||
0f5d89e8 | 1898 | errorCode.errDataIfFailureAndReset(""); |
51004dcb A |
1899 | } |
1900 | ||
57a6839d A |
1901 | void TestMessageFormat::TestDecimals() { |
1902 | IcuTestErrorCode errorCode(*this, "TestDecimals"); | |
1903 | // Simple number replacement. | |
1904 | MessageFormat m( | |
1905 | "{0,plural,one{one meter}other{# meters}}", | |
1906 | Locale::getEnglish(), errorCode); | |
1907 | Formattable args[1] = { (int32_t)1 }; | |
1908 | FieldPosition ignore; | |
1909 | UnicodeString result; | |
1910 | assertEquals("simple format(1)", "one meter", | |
1911 | m.format(args, 1, result, ignore, errorCode), TRUE); | |
1912 | ||
1913 | args[0] = (double)1.5; | |
1914 | result.remove(); | |
1915 | assertEquals("simple format(1.5)", "1.5 meters", | |
1916 | m.format(args, 1, result, ignore, errorCode), TRUE); | |
1917 | ||
1918 | // Simple but explicit. | |
1919 | MessageFormat m0( | |
1920 | "{0,plural,one{one meter}other{{0} meters}}", | |
1921 | Locale::getEnglish(), errorCode); | |
1922 | args[0] = (int32_t)1; | |
1923 | result.remove(); | |
1924 | assertEquals("explicit format(1)", "one meter", | |
1925 | m0.format(args, 1, result, ignore, errorCode), TRUE); | |
1926 | ||
1927 | args[0] = (double)1.5; | |
1928 | result.remove(); | |
1929 | assertEquals("explicit format(1.5)", "1.5 meters", | |
1930 | m0.format(args, 1, result, ignore, errorCode), TRUE); | |
1931 | ||
1932 | // With offset and specific simple format with optional decimals. | |
1933 | MessageFormat m1( | |
1934 | "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}", | |
1935 | Locale::getEnglish(), errorCode); | |
1936 | args[0] = (int32_t)1; | |
1937 | result.remove(); | |
1938 | assertEquals("offset format(1)", "01 meters", | |
1939 | m1.format(args, 1, result, ignore, errorCode), TRUE); | |
1940 | ||
1941 | args[0] = (int32_t)2; | |
1942 | result.remove(); | |
1943 | assertEquals("offset format(1)", "another meter", | |
1944 | m1.format(args, 1, result, ignore, errorCode), TRUE); | |
1945 | ||
1946 | args[0] = (double)2.5; | |
1947 | result.remove(); | |
1948 | assertEquals("offset format(1)", "02.5 meters", | |
1949 | m1.format(args, 1, result, ignore, errorCode), TRUE); | |
1950 | ||
1951 | // With offset and specific simple format with forced decimals. | |
1952 | MessageFormat m2( | |
1953 | "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}", | |
1954 | Locale::getEnglish(), errorCode); | |
1955 | args[0] = (int32_t)1; | |
1956 | result.remove(); | |
1957 | assertEquals("offset-decimals format(1)", "1.0 meters", | |
1958 | m2.format(args, 1, result, ignore, errorCode), TRUE); | |
1959 | ||
1960 | args[0] = (int32_t)2; | |
1961 | result.remove(); | |
1962 | assertEquals("offset-decimals format(1)", "2.0 meters", | |
1963 | m2.format(args, 1, result, ignore, errorCode), TRUE); | |
1964 | ||
1965 | args[0] = (double)2.5; | |
1966 | result.remove(); | |
1967 | assertEquals("offset-decimals format(1)", "2.5 meters", | |
1968 | m2.format(args, 1, result, ignore, errorCode), TRUE); | |
1969 | errorCode.reset(); | |
1970 | } | |
1971 | ||
2ca993e8 A |
1972 | void TestMessageFormat::TestArgIsPrefixOfAnother() { |
1973 | IcuTestErrorCode errorCode(*this, "TestArgIsPrefixOfAnother"); | |
1974 | // Ticket #11952 | |
1975 | MessageFormat mf1("{0,select,a{A}ab{AB}abc{ABC}other{?}}", Locale::getEnglish(), errorCode); | |
1976 | Formattable args[3]; | |
1977 | FieldPosition ignore; | |
1978 | UnicodeString result; | |
1979 | args[0].setString("a"); | |
1980 | assertEquals("a", "A", mf1.format(args, 1, result, ignore, errorCode)); | |
1981 | args[0].setString("ab"); | |
1982 | assertEquals("ab", "AB", mf1.format(args, 1, result.remove(), ignore, errorCode)); | |
1983 | args[0].setString("abc"); | |
1984 | assertEquals("abc", "ABC", mf1.format(args, 1, result.remove(), ignore, errorCode)); | |
1985 | ||
1986 | // Ticket #12172 | |
1987 | MessageFormat mf2("{a} {aa} {aaa}", Locale::getEnglish(), errorCode); | |
1988 | UnicodeString argNames[3] = { "a", "aa", "aaa" }; | |
1989 | args[0].setString("A"); | |
1990 | args[1].setString("AB"); | |
1991 | args[2].setString("ABC"); | |
1992 | assertEquals("a aa aaa", "A AB ABC", mf2.format(argNames, args, 3, result.remove(), errorCode)); | |
1993 | ||
1994 | // Ticket #12172 | |
1995 | MessageFormat mf3("{aa} {aaa}", Locale::getEnglish(), errorCode); | |
1996 | assertEquals("aa aaa", "AB ABC", mf3.format(argNames + 1, args + 1, 2, result.remove(), errorCode)); | |
1997 | } | |
1998 | ||
0f5d89e8 A |
1999 | void TestMessageFormat::TestMessageFormatNumberSkeleton() { |
2000 | IcuTestErrorCode status(*this, "TestMessageFormatNumberSkeleton"); | |
2001 | ||
2002 | static const struct TestCase { | |
2003 | const char16_t* messagePattern; | |
2004 | const char* localeName; | |
2005 | double arg; | |
2006 | const char16_t* expected; | |
2007 | } cases[] = { | |
2008 | { u"{0,number,::percent}", "en", 50, u"50%" }, | |
2009 | { u"{0,number,::percent scale/100}", "en", 0.5, u"50%" }, | |
2010 | { u"{0,number, :: percent scale/100 }", "en", 0.5, u"50%" }, | |
2011 | { u"{0,number,::currency/USD}", "en", 23, u"$23.00" }, | |
2012 | { u"{0,number,::precision-integer}", "en", 514.23, u"514" }, | |
2013 | { u"{0,number,::.000}", "en", 514.23, u"514.230" }, | |
2014 | { u"{0,number,::.}", "en", 514.23, u"514" }, | |
2015 | { u"{0,number,::}", "fr", 514.23, u"514,23" }, | |
2016 | { u"Cost: {0,number,::currency/EUR}.", "en", 4.3, u"Cost: €4.30." }, | |
2017 | { u"{0,number,'::'0.00}", "en", 50, u"::50.00" }, // pattern literal | |
2018 | }; | |
2019 | ||
2020 | for (auto& cas : cases) { | |
2021 | status.setScope(cas.messagePattern); | |
2022 | MessageFormat msgf(cas.messagePattern, cas.localeName, status); | |
2023 | UnicodeString sb; | |
3d1f044b | 2024 | FieldPosition fpos(FieldPosition::DONT_CARE); |
0f5d89e8 A |
2025 | Formattable argsArray[] = {{cas.arg}}; |
2026 | Formattable args(argsArray, 1); | |
2027 | msgf.format(args, sb, status); | |
2028 | ||
2029 | assertEquals(cas.messagePattern, cas.expected, sb); | |
2030 | } | |
2031 | } | |
2032 | ||
3d1f044b A |
2033 | void TestMessageFormat::doTheRealDateTimeSkeletonTesting(UDate testDate, |
2034 | const char16_t* messagePattern, const char* localeName, const char16_t* expected, | |
2035 | IcuTestErrorCode& status) { | |
2036 | ||
2037 | status.setScope(messagePattern); | |
2038 | MessageFormat msgf(messagePattern, localeName, status); | |
2039 | UnicodeString sb; | |
2040 | FieldPosition fpos(FieldPosition::DONT_CARE); | |
2041 | Formattable argsArray[] = { Formattable(testDate, Formattable::kIsDate) }; | |
2042 | Formattable args(argsArray, 1); | |
2043 | msgf.format(args, sb, status); | |
2044 | ||
2045 | assertEquals(messagePattern, expected, sb); | |
2046 | } | |
2047 | ||
2048 | void TestMessageFormat::TestMessageFormatDateSkeleton() { | |
2049 | IcuTestErrorCode status(*this, "TestMessageFormatDateSkeleton"); | |
2050 | ||
2051 | UDate date = LocaleTest::date(2021-1900, UCAL_NOVEMBER, 23, 16, 42, 55); | |
2052 | ||
2053 | doTheRealDateTimeSkeletonTesting(date, u"{0,date,::MMMMd}", "en", u"November 23", status); | |
2054 | doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMdjm}", "en", u"November 23, 2021, 4:42 PM", status); | |
2055 | doTheRealDateTimeSkeletonTesting(date, u"{0,date, :: yMMMMd }", "en", u"November 23, 2021", status); | |
2056 | doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMd}", "fr", u"23 novembre 2021", status); | |
2057 | doTheRealDateTimeSkeletonTesting(date, u"Expiration: {0,date,::yMMM}!", "en", u"Expiration: Nov 2021!", status); | |
2058 | // pattern literal | |
2059 | doTheRealDateTimeSkeletonTesting(date, u"{0,date,'::'yMMMMd}", "en", u"::2021November23", status); | |
2060 | } | |
2061 | ||
2062 | void TestMessageFormat::TestMessageFormatTimeSkeleton() { | |
2063 | IcuTestErrorCode status(*this, "TestMessageFormatTimeSkeleton"); | |
2064 | ||
2065 | UDate date = LocaleTest::date(2021-1900, UCAL_NOVEMBER, 23, 16, 42, 55); | |
2066 | ||
2067 | doTheRealDateTimeSkeletonTesting(date, u"{0,time,::MMMMd}", "en", u"November 23", status); | |
2068 | doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMdjm}", "en", u"November 23, 2021, 4:42 PM", status); | |
2069 | doTheRealDateTimeSkeletonTesting(date, u"{0,time, :: yMMMMd }", "en", u"November 23, 2021", status); | |
2070 | doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMd}", "fr", u"23 novembre 2021", status); | |
2071 | doTheRealDateTimeSkeletonTesting(date, u"Expiration: {0,time,::yMMM}!", "en", u"Expiration: Nov 2021!", status); | |
2072 | // pattern literal | |
2073 | doTheRealDateTimeSkeletonTesting(date, u"{0,time,'::'yMMMMd}", "en", u"::2021November23", status); | |
2074 | } | |
2075 | ||
b75a7d8f | 2076 | #endif /* #if !UCONFIG_NO_FORMATTING */ |