1 /*
2 *******************************************************************************
3 * Copyright (C) 2014-2016, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 *
7 * File SIMPLEPATTERNFORMATTERTEST.CPP
8 *
9 ********************************************************************************
10 */
11
12 #include "unicode/msgfmt.h"
13 #include "unicode/unistr.h"
14 #include "cstring.h"
15 #include "intltest.h"
16 #include "simplepatternformatter.h"
17
18 class SimplePatternFormatterTest : public IntlTest {
19 public:
SimplePatternFormatterTest()20 SimplePatternFormatterTest() {
21 }
22 void TestNoPlaceholders();
23 void TestSyntaxErrors();
24 void TestOnePlaceholder();
25 void TestBigPlaceholder();
26 void TestManyPlaceholders();
27 void TestTooFewPlaceholderValues();
28 void TestBadArguments();
29 void TestTextWithNoPlaceholders();
30 void TestFormatReplaceNoOptimization();
31 void TestFormatReplaceNoOptimizationLeadingText();
32 void TestFormatReplaceOptimization();
33 void TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice();
34 void TestFormatReplaceOptimizationNoOffsets();
35 void TestFormatReplaceNoOptimizationNoOffsets();
36 void TestQuotingLikeMessageFormat();
37 void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
38 private:
39 void verifyOffsets(
40 const int32_t *expected,
41 const int32_t *actual,
42 int32_t count);
43 };
44
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)45 void SimplePatternFormatterTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
46 TESTCASE_AUTO_BEGIN;
47 TESTCASE_AUTO(TestNoPlaceholders);
48 TESTCASE_AUTO(TestSyntaxErrors);
49 TESTCASE_AUTO(TestOnePlaceholder);
50 TESTCASE_AUTO(TestBigPlaceholder);
51 TESTCASE_AUTO(TestManyPlaceholders);
52 TESTCASE_AUTO(TestTooFewPlaceholderValues);
53 TESTCASE_AUTO(TestBadArguments);
54 TESTCASE_AUTO(TestTextWithNoPlaceholders);
55 TESTCASE_AUTO(TestFormatReplaceNoOptimization);
56 TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingText);
57 TESTCASE_AUTO(TestFormatReplaceOptimization);
58 TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice);
59 TESTCASE_AUTO(TestFormatReplaceOptimizationNoOffsets);
60 TESTCASE_AUTO(TestFormatReplaceNoOptimizationNoOffsets);
61 TESTCASE_AUTO(TestQuotingLikeMessageFormat);
62 TESTCASE_AUTO_END;
63 }
64
TestNoPlaceholders()65 void SimplePatternFormatterTest::TestNoPlaceholders() {
66 UErrorCode status = U_ZERO_ERROR;
67 SimplePatternFormatter fmt("This doesn''t have templates '{0}", status);
68 assertEquals("getPlaceholderCount", 0, fmt.getPlaceholderCount());
69 UnicodeString appendTo;
70 assertEquals(
71 "format",
72 "This doesn't have templates {0}",
73 fmt.format("unused", appendTo, status));
74 appendTo.remove();
75 int32_t offsets[] = { 0 };
76 assertEquals(
77 "formatAndAppend",
78 "This doesn't have templates {0}",
79 fmt.formatAndAppend(NULL, 0, appendTo, offsets, 1, status));
80 assertEquals("formatAndAppend offsets[0]", -1, offsets[0]);
81 assertEquals(
82 "formatAndReplace",
83 "This doesn't have templates {0}",
84 fmt.formatAndReplace(NULL, 0, appendTo, NULL, 0, status));
85 assertSuccess("Status", status);
86 }
87
TestSyntaxErrors()88 void SimplePatternFormatterTest::TestSyntaxErrors() {
89 UErrorCode status = U_ZERO_ERROR;
90 SimplePatternFormatter fmt("{}", status);
91 assertEquals("syntax error {}", U_ILLEGAL_ARGUMENT_ERROR, status);
92 status = U_ZERO_ERROR;
93 fmt.compile("{12d", status);
94 assertEquals("syntax error {12d", U_ILLEGAL_ARGUMENT_ERROR, status);
95 }
96
TestOnePlaceholder()97 void SimplePatternFormatterTest::TestOnePlaceholder() {
98 UErrorCode status = U_ZERO_ERROR;
99 SimplePatternFormatter fmt;
100 fmt.compile("{0} meter", status);
101 if (!assertSuccess("Status", status)) {
102 return;
103 }
104 assertEquals("PlaceholderCount", 1, fmt.getPlaceholderCount());
105 UnicodeString appendTo;
106 assertEquals(
107 "format",
108 "1 meter",
109 fmt.format("1", appendTo, status));
110
111 // assignment
112 SimplePatternFormatter s;
113 s = fmt;
114 appendTo.remove();
115 assertEquals(
116 "Assignment",
117 "1 meter",
118 s.format("1", appendTo, status));
119
120 // Copy constructor
121 SimplePatternFormatter r(fmt);
122 appendTo.remove();
123 assertEquals(
124 "Copy constructor",
125 "1 meter",
126 r.format("1", appendTo, status));
127 assertSuccess("Status", status);
128 }
129
TestBigPlaceholder()130 void SimplePatternFormatterTest::TestBigPlaceholder() {
131 UErrorCode status = U_ZERO_ERROR;
132 SimplePatternFormatter fmt("a{20}c", status);
133 if (!assertSuccess("Status", status)) {
134 return;
135 }
136 assertEquals("{20} count", 21, fmt.getPlaceholderCount());
137 UnicodeString b("b");
138 UnicodeString *values[] = {
139 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
140 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
141 &b
142 };
143 UnicodeString result;
144 assertEquals("{20}=b", "abc", fmt.formatAndAppend(values, 21, result, NULL, 0, status));
145 assertSuccess("Status", status);
146 }
147
TestManyPlaceholders()148 void SimplePatternFormatterTest::TestManyPlaceholders() {
149 UErrorCode status = U_ZERO_ERROR;
150 SimplePatternFormatter fmt;
151 fmt.compile(
152 "Templates {2}{1}{5} and {4} are out of order.", status);
153 if (!assertSuccess("Status", status)) {
154 return;
155 }
156 assertEquals("PlaceholderCount", 6, fmt.getPlaceholderCount());
157 UnicodeString values[] = {
158 "freddy", "tommy", "frog", "billy", "leg", "{0}"};
159 UnicodeString *params[] = {
160 &values[0], &values[1], &values[2], &values[3], &values[4], &values[5]};
161 int32_t offsets[6];
162 int32_t expectedOffsets[6] = {-1, 22, 18, -1, 35, 27};
163 UnicodeString appendTo("Prefix: ");
164 assertEquals(
165 "format",
166 "Prefix: Templates frogtommy{0} and leg are out of order.",
167 fmt.formatAndAppend(
168 params,
169 UPRV_LENGTHOF(params),
170 appendTo,
171 offsets,
172 UPRV_LENGTHOF(offsets),
173 status));
174 if (!assertSuccess("Status", status)) {
175 return;
176 }
177 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
178 appendTo.remove();
179
180 // Ensure we don't write to offsets array beyond its length.
181 status = U_ZERO_ERROR;
182 offsets[UPRV_LENGTHOF(offsets) - 1] = 289;
183 appendTo.remove();
184 fmt.formatAndAppend(
185 params,
186 UPRV_LENGTHOF(params),
187 appendTo,
188 offsets,
189 UPRV_LENGTHOF(offsets) - 1,
190 status);
191 assertEquals("Offsets buffer length", 289, offsets[UPRV_LENGTHOF(offsets) - 1]);
192
193 // Test assignment
194 SimplePatternFormatter s;
195 s = fmt;
196 appendTo.remove();
197 assertEquals(
198 "Assignment",
199 "Templates frogtommy{0} and leg are out of order.",
200 s.formatAndAppend(
201 params,
202 UPRV_LENGTHOF(params),
203 appendTo,
204 NULL,
205 0,
206 status));
207
208 // Copy constructor
209 SimplePatternFormatter r(fmt);
210 appendTo.remove();
211 assertEquals(
212 "Copy constructor",
213 "Templates frogtommy{0} and leg are out of order.",
214 r.formatAndAppend(
215 params,
216 UPRV_LENGTHOF(params),
217 appendTo,
218 NULL,
219 0,
220 status));
221 r.compile("{0} meter", status);
222 assertEquals("PlaceholderCount", 1, r.getPlaceholderCount());
223 appendTo.remove();
224 assertEquals(
225 "Replace with new compile",
226 "freddy meter",
227 r.format("freddy", appendTo, status));
228 r.compile("{0}, {1}", status);
229 assertEquals("PlaceholderCount", 2, r.getPlaceholderCount());
230 appendTo.remove();
231 assertEquals(
232 "2 arg",
233 "foo, bar",
234 r.format("foo", "bar", appendTo, status));
235 r.compile("{0}, {1} and {2}", status);
236 assertEquals("PlaceholderCount", 3, r.getPlaceholderCount());
237 appendTo.remove();
238 assertEquals(
239 "3 arg",
240 "foo, bar and baz",
241 r.format("foo", "bar", "baz", appendTo, status));
242 assertSuccess("Status", status);
243 }
244
TestTooFewPlaceholderValues()245 void SimplePatternFormatterTest::TestTooFewPlaceholderValues() {
246 UErrorCode status = U_ZERO_ERROR;
247 SimplePatternFormatter fmt("{0} and {1}", status);
248 UnicodeString appendTo;
249 UnicodeString firstValue;
250 UnicodeString *params[] = {&firstValue};
251
252 fmt.format(
253 firstValue, appendTo, status);
254 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
255 errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
256 }
257
258 status = U_ZERO_ERROR;
259 fmt.formatAndAppend(
260 params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
261 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
262 errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
263 }
264
265 status = U_ZERO_ERROR;
266 fmt.formatAndReplace(
267 params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
268 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
269 errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
270 }
271 }
272
TestBadArguments()273 void SimplePatternFormatterTest::TestBadArguments() {
274 UErrorCode status = U_ZERO_ERROR;
275 SimplePatternFormatter fmt("pickle", status);
276 UnicodeString appendTo;
277
278 // These succeed
279 fmt.formatAndAppend(
280 NULL, 0, appendTo, NULL, 0, status);
281 fmt.formatAndReplace(
282 NULL, 0, appendTo, NULL, 0, status);
283 assertSuccess("", status);
284 status = U_ZERO_ERROR;
285
286 // fails
287 fmt.formatAndAppend(
288 NULL, 1, appendTo, NULL, 0, status);
289 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
290 errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndAppend() values=NULL but length=1");
291 }
292 status = U_ZERO_ERROR;
293
294 // fails
295 fmt.formatAndAppend(
296 NULL, 0, appendTo, NULL, 1, status);
297 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
298 errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndAppend() offsets=NULL but length=1");
299 }
300 status = U_ZERO_ERROR;
301
302 // fails because appendTo used as a parameter value
303 SimplePatternFormatter fmt2("Placeholders {0} and {1}", status);
304 UnicodeString frog("frog");
305 const UnicodeString *params[] = { &appendTo, &frog };
306 fmt2.formatAndAppend(params, 2, appendTo, NULL, 0, status);
307 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
308 errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndAppend() value=appendTo");
309 }
310 status = U_ZERO_ERROR;
311
312
313 // fails
314 fmt.formatAndReplace(
315 NULL, 1, appendTo, NULL, 0, status);
316 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
317 errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndReplace() values=NULL but length=1");
318 }
319 status = U_ZERO_ERROR;
320
321 // fails
322 fmt.formatAndReplace(
323 NULL, 0, appendTo, NULL, 1, status);
324 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
325 errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndReplace() offsets=NULL but length=1");
326 }
327 }
328
TestTextWithNoPlaceholders()329 void SimplePatternFormatterTest::TestTextWithNoPlaceholders() {
330 UErrorCode status = U_ZERO_ERROR;
331 SimplePatternFormatter fmt("{0} has no {1} placeholders.", status);
332 assertEquals(
333 "", " has no placeholders.", fmt.getTextWithNoPlaceholders());
334 }
335
TestFormatReplaceNoOptimization()336 void SimplePatternFormatterTest::TestFormatReplaceNoOptimization() {
337 UErrorCode status = U_ZERO_ERROR;
338 SimplePatternFormatter fmt;
339 fmt.compile("{2}, {0}, {1} and {3}", status);
340 if (!assertSuccess("Status", status)) {
341 return;
342 }
343 UnicodeString result("original");
344 int offsets[4];
345 UnicodeString freddy("freddy");
346 UnicodeString frog("frog");
347 UnicodeString by("by");
348 const UnicodeString *params[] = {&result, &freddy, &frog, &by};
349 assertEquals(
350 "",
351 "frog, original, freddy and by",
352 fmt.formatAndReplace(
353 params,
354 UPRV_LENGTHOF(params),
355 result,
356 offsets,
357 UPRV_LENGTHOF(offsets),
358 status));
359 if (!assertSuccess("Status", status)) {
360 return;
361 }
362 int32_t expectedOffsets[] = {6, 16, 0, 27};
363 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
364 }
365
TestFormatReplaceNoOptimizationLeadingText()366 void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationLeadingText() {
367 UErrorCode status = U_ZERO_ERROR;
368 SimplePatternFormatter fmt;
369 fmt.compile("boo {2}, {0}, {1} and {3}", status);
370 if (!assertSuccess("Status", status)) {
371 return;
372 }
373 UnicodeString result("original");
374 int offsets[4];
375 UnicodeString freddy("freddy");
376 UnicodeString frog("frog");
377 UnicodeString by("by");
378 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
379 assertEquals(
380 "",
381 "boo original, freddy, frog and by",
382 fmt.formatAndReplace(
383 params,
384 UPRV_LENGTHOF(params),
385 result,
386 offsets,
387 UPRV_LENGTHOF(offsets),
388 status));
389 if (!assertSuccess("Status", status)) {
390 return;
391 }
392 int32_t expectedOffsets[] = {14, 22, 4, 31};
393 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
394 }
395
TestFormatReplaceOptimization()396 void SimplePatternFormatterTest::TestFormatReplaceOptimization() {
397 UErrorCode status = U_ZERO_ERROR;
398 SimplePatternFormatter fmt;
399 fmt.compile("{2}, {0}, {1} and {3}", status);
400 if (!assertSuccess("Status", status)) {
401 return;
402 }
403 UnicodeString result("original");
404 int offsets[4];
405 UnicodeString freddy("freddy");
406 UnicodeString frog("frog");
407 UnicodeString by("by");
408 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
409 assertEquals(
410 "",
411 "original, freddy, frog and by",
412 fmt.formatAndReplace(
413 params,
414 UPRV_LENGTHOF(params),
415 result,
416 offsets,
417 UPRV_LENGTHOF(offsets),
418 status));
419 if (!assertSuccess("Status", status)) {
420 return;
421 }
422 int32_t expectedOffsets[] = {10, 18, 0, 27};
423 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
424 }
425
TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice()426 void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice() {
427 UErrorCode status = U_ZERO_ERROR;
428 SimplePatternFormatter fmt;
429 fmt.compile("{2}, {0}, {1} and {3} {2}", status);
430 if (!assertSuccess("Status", status)) {
431 return;
432 }
433 UnicodeString result("original");
434 int offsets[4];
435 UnicodeString freddy("freddy");
436 UnicodeString frog("frog");
437 UnicodeString by("by");
438 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
439 assertEquals(
440 "",
441 "original, freddy, frog and by original",
442 fmt.formatAndReplace(
443 params,
444 UPRV_LENGTHOF(params),
445 result,
446 offsets,
447 UPRV_LENGTHOF(offsets),
448 status));
449 if (!assertSuccess("Status", status)) {
450 return;
451 }
452 int32_t expectedOffsets[] = {10, 18, 30, 27};
453 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
454 }
455
TestFormatReplaceOptimizationNoOffsets()456 void SimplePatternFormatterTest::TestFormatReplaceOptimizationNoOffsets() {
457 UErrorCode status = U_ZERO_ERROR;
458 SimplePatternFormatter fmt;
459 fmt.compile("{2}, {0}, {1} and {3}", status);
460 if (!assertSuccess("Status", status)) {
461 return;
462 }
463 UnicodeString result("original");
464 UnicodeString freddy("freddy");
465 UnicodeString frog("frog");
466 UnicodeString by("by");
467 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
468 assertEquals(
469 "",
470 "original, freddy, frog and by",
471 fmt.formatAndReplace(
472 params,
473 UPRV_LENGTHOF(params),
474 result,
475 NULL,
476 0,
477 status));
478 assertSuccess("Status", status);
479 }
480
TestFormatReplaceNoOptimizationNoOffsets()481 void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationNoOffsets() {
482 UErrorCode status = U_ZERO_ERROR;
483 SimplePatternFormatter fmt("Placeholders {0} and {1}", status);
484 UnicodeString result("previous:");
485 UnicodeString frog("frog");
486 const UnicodeString *params[] = {&result, &frog};
487 assertEquals(
488 "",
489 "Placeholders previous: and frog",
490 fmt.formatAndReplace(
491 params,
492 UPRV_LENGTHOF(params),
493 result,
494 NULL,
495 0,
496 status));
497 assertSuccess("Status", status);
498 }
499
TestQuotingLikeMessageFormat()500 void SimplePatternFormatterTest::TestQuotingLikeMessageFormat() {
501 UErrorCode status = U_ZERO_ERROR;
502 UnicodeString pattern = "{0} don't can''t '{5}''}{a' again '}'{1} to the '{end";
503 SimplePatternFormatter spf(pattern, status);
504 MessageFormat mf(pattern, Locale::getRoot(), status);
505 UnicodeString expected = "X don't can't {5}'}{a again }Y to the {end";
506 UnicodeString x("X"), y("Y");
507 Formattable values[] = { x, y };
508 UnicodeString result;
509 FieldPosition ignore(FieldPosition::DONT_CARE);
510 assertEquals("MessageFormat", expected, mf.format(values, 2, result, ignore, status));
511 assertEquals("SimplePatternFormatter", expected, spf.format(x, y, result.remove(), status));
512 }
513
verifyOffsets(const int32_t * expected,const int32_t * actual,int32_t count)514 void SimplePatternFormatterTest::verifyOffsets(
515 const int32_t *expected, const int32_t *actual, int32_t count) {
516 for (int32_t i = 0; i < count; ++i) {
517 if (expected[i] != actual[i]) {
518 errln("Expected %d, got %d", expected[i], actual[i]);
519 }
520 }
521 }
522
createSimplePatternFormatterTest()523 extern IntlTest *createSimplePatternFormatterTest() {
524 return new SimplePatternFormatterTest();
525 }
526