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