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