Home | History | Annotate | Download | only in intltest
      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:
     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 }
    530