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