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