1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2014-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
9 * simpleformattertest.cpp
11 ********************************************************************************
14 #include "unicode/msgfmt.h"
15 #include "unicode/unistr.h"
18 #include "unicode/simpleformatter.h"
20 class SimpleFormatterTest : public IntlTest {
22 SimpleFormatterTest() {
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);
42 const int32_t *expected,
43 const int32_t *actual,
47 void SimpleFormatterTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
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);
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;
74 "This doesn't have templates {0}",
75 fmt.format("unused", appendTo, status));
77 int32_t offsets[] = { 0 };
80 "This doesn't have templates {0}",
81 fmt.formatAndAppend(NULL, 0, appendTo, offsets, 1, status));
82 assertEquals("formatAndAppend offsets[0]", -1, offsets[0]);
85 "This doesn't have templates {0}",
86 fmt.formatAndReplace(NULL, 0, appendTo, NULL, 0, status));
87 assertSuccess("Status", status);
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);
99 void SimpleFormatterTest::TestOneArgument() {
100 UErrorCode status = U_ZERO_ERROR;
102 fmt.applyPattern("{0} meter", status);
103 if (!assertSuccess("Status", status)) {
106 assertEquals("getArgumentLimit", 1, fmt.getArgumentLimit());
107 UnicodeString appendTo;
111 fmt.format("1", appendTo, status));
120 s.format("1", appendTo, status));
123 SimpleFormatter r(fmt);
128 r.format("1", appendTo, status));
129 assertSuccess("Status", status);
132 void SimpleFormatterTest::TestBigArgument() {
133 UErrorCode status = U_ZERO_ERROR;
134 SimpleFormatter fmt("a{20}c", status);
135 if (!assertSuccess("Status", status)) {
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,
145 UnicodeString result;
146 assertEquals("{20}=b", "abc", fmt.formatAndAppend(values, 21, result, NULL, 0, status));
147 assertSuccess("Status", status);
150 void SimpleFormatterTest::TestManyArguments() {
151 UErrorCode status = U_ZERO_ERROR;
154 "Templates {2}{1}{5} and {4} are out of order.", status);
155 if (!assertSuccess("Status", status)) {
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]};
164 int32_t expectedOffsets[6] = {-1, 22, 18, -1, 35, 27};
165 UnicodeString appendTo("Prefix: ");
168 "Prefix: Templates frogtommy{0} and leg are out of order.",
171 UPRV_LENGTHOF(params),
174 UPRV_LENGTHOF(offsets),
176 if (!assertSuccess("Status", status)) {
179 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
182 // Ensure we don't write to offsets array beyond its length.
183 status = U_ZERO_ERROR;
184 offsets[UPRV_LENGTHOF(offsets) - 1] = 289;
188 UPRV_LENGTHOF(params),
191 UPRV_LENGTHOF(offsets) - 1,
193 assertEquals("Offsets buffer length", 289, offsets[UPRV_LENGTHOF(offsets) - 1]);
201 "Templates frogtommy{0} and leg are out of order.",
204 UPRV_LENGTHOF(params),
211 SimpleFormatter r(fmt);
215 "Templates frogtommy{0} and leg are out of order.",
218 UPRV_LENGTHOF(params),
223 r.applyPattern("{0} meter", status);
224 assertEquals("getArgumentLimit", 1, r.getArgumentLimit());
227 "Replace with new applyPattern",
229 r.format("freddy", appendTo, status));
230 r.applyPattern("{0}, {1}", status);
231 assertEquals("getArgumentLimit", 2, r.getArgumentLimit());
236 r.format("foo", "bar", appendTo, status));
237 r.applyPattern("{0}, {1} and {2}", status);
238 assertEquals("getArgumentLimit", 3, r.getArgumentLimit());
243 r.format("foo", "bar", "baz", appendTo, status));
244 assertSuccess("Status", status);
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};
255 firstValue, appendTo, status);
256 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
257 errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
260 status = U_ZERO_ERROR;
262 params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
263 if (status != U_ILLEGAL_ARGUMENT_ERROR) {
264 errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
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");
275 void SimpleFormatterTest::TestBadArguments() {
276 UErrorCode status = U_ZERO_ERROR;
277 SimpleFormatter fmt("pickle", status);
278 UnicodeString appendTo;
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;
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");
294 status = U_ZERO_ERROR;
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");
302 status = U_ZERO_ERROR;
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");
312 status = U_ZERO_ERROR;
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");
321 status = U_ZERO_ERROR;
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");
331 void SimpleFormatterTest::TestTextWithNoArguments() {
332 UErrorCode status = U_ZERO_ERROR;
333 SimpleFormatter fmt("{0} has no {1} arguments.", status);
335 "", " has no arguments.", fmt.getTextWithNoArguments());
338 void SimpleFormatterTest::TestFormatReplaceNoOptimization() {
339 UErrorCode status = U_ZERO_ERROR;
341 fmt.applyPattern("{2}, {0}, {1} and {3}", status);
342 if (!assertSuccess("Status", status)) {
345 UnicodeString result("original");
347 UnicodeString freddy("freddy");
348 UnicodeString frog("frog");
349 UnicodeString by("by");
350 const UnicodeString *params[] = {&result, &freddy, &frog, &by};
353 "frog, original, freddy and by",
354 fmt.formatAndReplace(
356 UPRV_LENGTHOF(params),
359 UPRV_LENGTHOF(offsets),
361 if (!assertSuccess("Status", status)) {
364 int32_t expectedOffsets[] = {6, 16, 0, 27};
365 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
368 void SimpleFormatterTest::TestFormatReplaceNoOptimizationLeadingText() {
369 UErrorCode status = U_ZERO_ERROR;
371 fmt.applyPattern("boo {2}, {0}, {1} and {3}", status);
372 if (!assertSuccess("Status", status)) {
375 UnicodeString result("original");
377 UnicodeString freddy("freddy");
378 UnicodeString frog("frog");
379 UnicodeString by("by");
380 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
383 "boo original, freddy, frog and by",
384 fmt.formatAndReplace(
386 UPRV_LENGTHOF(params),
389 UPRV_LENGTHOF(offsets),
391 if (!assertSuccess("Status", status)) {
394 int32_t expectedOffsets[] = {14, 22, 4, 31};
395 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
398 void SimpleFormatterTest::TestFormatReplaceOptimization() {
399 UErrorCode status = U_ZERO_ERROR;
401 fmt.applyPattern("{2}, {0}, {1} and {3}", status);
402 if (!assertSuccess("Status", status)) {
405 UnicodeString result("original");
407 UnicodeString freddy("freddy");
408 UnicodeString frog("frog");
409 UnicodeString by("by");
410 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
413 "original, freddy, frog and by",
414 fmt.formatAndReplace(
416 UPRV_LENGTHOF(params),
419 UPRV_LENGTHOF(offsets),
421 if (!assertSuccess("Status", status)) {
424 int32_t expectedOffsets[] = {10, 18, 0, 27};
425 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
428 void SimpleFormatterTest::TestFormatReplaceNoOptimizationLeadingArgumentUsedTwice() {
429 UErrorCode status = U_ZERO_ERROR;
431 fmt.applyPattern("{2}, {0}, {1} and {3} {2}", status);
432 if (!assertSuccess("Status", status)) {
435 UnicodeString result("original");
437 UnicodeString freddy("freddy");
438 UnicodeString frog("frog");
439 UnicodeString by("by");
440 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
443 "original, freddy, frog and by original",
444 fmt.formatAndReplace(
446 UPRV_LENGTHOF(params),
449 UPRV_LENGTHOF(offsets),
451 if (!assertSuccess("Status", status)) {
454 int32_t expectedOffsets[] = {10, 18, 30, 27};
455 verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
458 void SimpleFormatterTest::TestFormatReplaceOptimizationNoOffsets() {
459 UErrorCode status = U_ZERO_ERROR;
461 fmt.applyPattern("{2}, {0}, {1} and {3}", status);
462 if (!assertSuccess("Status", status)) {
465 UnicodeString result("original");
466 UnicodeString freddy("freddy");
467 UnicodeString frog("frog");
468 UnicodeString by("by");
469 const UnicodeString *params[] = {&freddy, &frog, &result, &by};
472 "original, freddy, frog and by",
473 fmt.formatAndReplace(
475 UPRV_LENGTHOF(params),
480 assertSuccess("Status", status);
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};
491 "Arguments previous: and frog",
492 fmt.formatAndReplace(
494 UPRV_LENGTHOF(params),
499 assertSuccess("Status", status);
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 */
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]);
527 extern IntlTest *createSimpleFormatterTest() {
528 return new SimpleFormatterTest();