1 // © 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 IcuTestErrorCode
status(*this, "TestTextWithNoArguments");
333 SimpleFormatter
fmt("{0} has no {1} arguments.", status
);
334 assertEquals("String output 1",
335 " has no arguments.", fmt
.getTextWithNoArguments());
337 // Test offset positions
339 assertEquals("String output 2",
340 u
" has no arguments.", fmt
.getTextWithNoArguments(offsets
, 3));
341 assertEquals("Offset at 0",
343 assertEquals("Offset at 1",
345 assertEquals("Offset at 2",
349 void SimpleFormatterTest::TestFormatReplaceNoOptimization() {
350 UErrorCode status
= U_ZERO_ERROR
;
352 fmt
.applyPattern("{2}, {0}, {1} and {3}", status
);
353 if (!assertSuccess("Status", status
)) {
356 UnicodeString
result("original");
358 UnicodeString
freddy("freddy");
359 UnicodeString
frog("frog");
360 UnicodeString
by("by");
361 const UnicodeString
*params
[] = {&result
, &freddy
, &frog
, &by
};
364 "frog, original, freddy and by",
365 fmt
.formatAndReplace(
367 UPRV_LENGTHOF(params
),
370 UPRV_LENGTHOF(offsets
),
372 if (!assertSuccess("Status", status
)) {
375 int32_t expectedOffsets
[] = {6, 16, 0, 27};
376 verifyOffsets(expectedOffsets
, offsets
, UPRV_LENGTHOF(expectedOffsets
));
379 void SimpleFormatterTest::TestFormatReplaceNoOptimizationLeadingText() {
380 UErrorCode status
= U_ZERO_ERROR
;
382 fmt
.applyPattern("boo {2}, {0}, {1} and {3}", status
);
383 if (!assertSuccess("Status", status
)) {
386 UnicodeString
result("original");
388 UnicodeString
freddy("freddy");
389 UnicodeString
frog("frog");
390 UnicodeString
by("by");
391 const UnicodeString
*params
[] = {&freddy
, &frog
, &result
, &by
};
394 "boo original, freddy, frog and by",
395 fmt
.formatAndReplace(
397 UPRV_LENGTHOF(params
),
400 UPRV_LENGTHOF(offsets
),
402 if (!assertSuccess("Status", status
)) {
405 int32_t expectedOffsets
[] = {14, 22, 4, 31};
406 verifyOffsets(expectedOffsets
, offsets
, UPRV_LENGTHOF(expectedOffsets
));
409 void SimpleFormatterTest::TestFormatReplaceOptimization() {
410 UErrorCode status
= U_ZERO_ERROR
;
412 fmt
.applyPattern("{2}, {0}, {1} and {3}", status
);
413 if (!assertSuccess("Status", status
)) {
416 UnicodeString
result("original");
418 UnicodeString
freddy("freddy");
419 UnicodeString
frog("frog");
420 UnicodeString
by("by");
421 const UnicodeString
*params
[] = {&freddy
, &frog
, &result
, &by
};
424 "original, freddy, frog and by",
425 fmt
.formatAndReplace(
427 UPRV_LENGTHOF(params
),
430 UPRV_LENGTHOF(offsets
),
432 if (!assertSuccess("Status", status
)) {
435 int32_t expectedOffsets
[] = {10, 18, 0, 27};
436 verifyOffsets(expectedOffsets
, offsets
, UPRV_LENGTHOF(expectedOffsets
));
439 void SimpleFormatterTest::TestFormatReplaceNoOptimizationLeadingArgumentUsedTwice() {
440 UErrorCode status
= U_ZERO_ERROR
;
442 fmt
.applyPattern("{2}, {0}, {1} and {3} {2}", status
);
443 if (!assertSuccess("Status", status
)) {
446 UnicodeString
result("original");
448 UnicodeString
freddy("freddy");
449 UnicodeString
frog("frog");
450 UnicodeString
by("by");
451 const UnicodeString
*params
[] = {&freddy
, &frog
, &result
, &by
};
454 "original, freddy, frog and by original",
455 fmt
.formatAndReplace(
457 UPRV_LENGTHOF(params
),
460 UPRV_LENGTHOF(offsets
),
462 if (!assertSuccess("Status", status
)) {
465 int32_t expectedOffsets
[] = {10, 18, 30, 27};
466 verifyOffsets(expectedOffsets
, offsets
, UPRV_LENGTHOF(expectedOffsets
));
469 void SimpleFormatterTest::TestFormatReplaceOptimizationNoOffsets() {
470 UErrorCode status
= U_ZERO_ERROR
;
472 fmt
.applyPattern("{2}, {0}, {1} and {3}", status
);
473 if (!assertSuccess("Status", status
)) {
476 UnicodeString
result("original");
477 UnicodeString
freddy("freddy");
478 UnicodeString
frog("frog");
479 UnicodeString
by("by");
480 const UnicodeString
*params
[] = {&freddy
, &frog
, &result
, &by
};
483 "original, freddy, frog and by",
484 fmt
.formatAndReplace(
486 UPRV_LENGTHOF(params
),
491 assertSuccess("Status", status
);
494 void SimpleFormatterTest::TestFormatReplaceNoOptimizationNoOffsets() {
495 UErrorCode status
= U_ZERO_ERROR
;
496 SimpleFormatter
fmt("Arguments {0} and {1}", status
);
497 UnicodeString
result("previous:");
498 UnicodeString
frog("frog");
499 const UnicodeString
*params
[] = {&result
, &frog
};
502 "Arguments previous: and frog",
503 fmt
.formatAndReplace(
505 UPRV_LENGTHOF(params
),
510 assertSuccess("Status", status
);
513 void SimpleFormatterTest::TestQuotingLikeMessageFormat() {
514 #if !UCONFIG_NO_FORMATTING
515 UErrorCode status
= U_ZERO_ERROR
;
516 UnicodeString pattern
= "{0} don't can''t '{5}''}{a' again '}'{1} to the '{end";
517 SimpleFormatter
spf(pattern
, status
);
518 MessageFormat
mf(pattern
, Locale::getRoot(), status
);
519 UnicodeString expected
= "X don't can't {5}'}{a again }Y to the {end";
520 UnicodeString
x("X"), y("Y");
521 Formattable values
[] = { x
, y
};
522 UnicodeString result
;
523 FieldPosition
ignore(FieldPosition::DONT_CARE
);
524 assertEquals("MessageFormat", expected
, mf
.format(values
, 2, result
, ignore
, status
));
525 assertEquals("SimpleFormatter", expected
, spf
.format(x
, y
, result
.remove(), status
));
526 #endif /* !UCONFIG_NO_FORMATTING */
529 void SimpleFormatterTest::verifyOffsets(
530 const int32_t *expected
, const int32_t *actual
, int32_t count
) {
531 for (int32_t i
= 0; i
< count
; ++i
) {
532 if (expected
[i
] != actual
[i
]) {
533 errln("Expected %d, got %d", expected
[i
], actual
[i
]);
538 extern IntlTest
*createSimpleFormatterTest() {
539 return new SimpleFormatterTest();