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