C++程序  |  526行  |  17.54 KB

/*
*******************************************************************************
* Copyright (C) 2014-2016, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
* File SIMPLEPATTERNFORMATTERTEST.CPP
*
********************************************************************************
*/

#include "unicode/msgfmt.h"
#include "unicode/unistr.h"
#include "cstring.h"
#include "intltest.h"
#include "simplepatternformatter.h"

class SimplePatternFormatterTest : public IntlTest {
public:
    SimplePatternFormatterTest() {
    }
    void TestNoPlaceholders();
    void TestSyntaxErrors();
    void TestOnePlaceholder();
    void TestBigPlaceholder();
    void TestManyPlaceholders();
    void TestTooFewPlaceholderValues();
    void TestBadArguments();
    void TestTextWithNoPlaceholders();
    void TestFormatReplaceNoOptimization();
    void TestFormatReplaceNoOptimizationLeadingText();
    void TestFormatReplaceOptimization();
    void TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice();
    void TestFormatReplaceOptimizationNoOffsets();
    void TestFormatReplaceNoOptimizationNoOffsets();
    void TestQuotingLikeMessageFormat();
    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
private:
    void verifyOffsets(
            const int32_t *expected,
            const int32_t *actual,
            int32_t count);
};

void SimplePatternFormatterTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
  TESTCASE_AUTO_BEGIN;
  TESTCASE_AUTO(TestNoPlaceholders);
  TESTCASE_AUTO(TestSyntaxErrors);
  TESTCASE_AUTO(TestOnePlaceholder);
  TESTCASE_AUTO(TestBigPlaceholder);
  TESTCASE_AUTO(TestManyPlaceholders);
  TESTCASE_AUTO(TestTooFewPlaceholderValues);
  TESTCASE_AUTO(TestBadArguments);
  TESTCASE_AUTO(TestTextWithNoPlaceholders);
  TESTCASE_AUTO(TestFormatReplaceNoOptimization);
  TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingText);
  TESTCASE_AUTO(TestFormatReplaceOptimization);
  TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice);
  TESTCASE_AUTO(TestFormatReplaceOptimizationNoOffsets);
  TESTCASE_AUTO(TestFormatReplaceNoOptimizationNoOffsets);
  TESTCASE_AUTO(TestQuotingLikeMessageFormat);
  TESTCASE_AUTO_END;
}

void SimplePatternFormatterTest::TestNoPlaceholders() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("This doesn''t have templates '{0}", status);
    assertEquals("getPlaceholderCount", 0, fmt.getPlaceholderCount());
    UnicodeString appendTo;
    assertEquals(
            "format",
            "This doesn't have templates {0}", 
            fmt.format("unused", appendTo, status));
    appendTo.remove();
    int32_t offsets[] = { 0 };
    assertEquals(
            "formatAndAppend",
            "This doesn't have templates {0}", 
            fmt.formatAndAppend(NULL, 0, appendTo, offsets, 1, status));
    assertEquals("formatAndAppend offsets[0]", -1, offsets[0]);
    assertEquals(
            "formatAndReplace",
            "This doesn't have templates {0}", 
            fmt.formatAndReplace(NULL, 0, appendTo, NULL, 0, status));
    assertSuccess("Status", status);
}

void SimplePatternFormatterTest::TestSyntaxErrors() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("{}", status);
    assertEquals("syntax error {}", U_ILLEGAL_ARGUMENT_ERROR, status);
    status = U_ZERO_ERROR;
    fmt.compile("{12d", status);
    assertEquals("syntax error {12d", U_ILLEGAL_ARGUMENT_ERROR, status);
}

void SimplePatternFormatterTest::TestOnePlaceholder() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile("{0} meter", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    assertEquals("PlaceholderCount", 1, fmt.getPlaceholderCount());
    UnicodeString appendTo;
    assertEquals(
            "format",
            "1 meter",
            fmt.format("1", appendTo, status));

    // assignment
    SimplePatternFormatter s;
    s = fmt;
    appendTo.remove();
    assertEquals(
            "Assignment",
            "1 meter",
            s.format("1", appendTo, status));

    // Copy constructor
    SimplePatternFormatter r(fmt);
    appendTo.remove();
    assertEquals(
            "Copy constructor",
            "1 meter",
            r.format("1", appendTo, status));
    assertSuccess("Status", status);
}

void SimplePatternFormatterTest::TestBigPlaceholder() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("a{20}c", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    assertEquals("{20} count", 21, fmt.getPlaceholderCount());
    UnicodeString b("b");
    UnicodeString *values[] = {
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        &b
    };
    UnicodeString result;
    assertEquals("{20}=b", "abc", fmt.formatAndAppend(values, 21, result, NULL, 0, status));
    assertSuccess("Status", status);
}

void SimplePatternFormatterTest::TestManyPlaceholders() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile(
            "Templates {2}{1}{5} and {4} are out of order.", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    assertEquals("PlaceholderCount", 6, fmt.getPlaceholderCount());
    UnicodeString values[] = {
            "freddy", "tommy", "frog", "billy", "leg", "{0}"};
    UnicodeString *params[] = {
           &values[0], &values[1], &values[2], &values[3], &values[4], &values[5]}; 
    int32_t offsets[6];
    int32_t expectedOffsets[6] = {-1, 22, 18, -1, 35, 27};
    UnicodeString appendTo("Prefix: ");
    assertEquals(
            "format",
            "Prefix: Templates frogtommy{0} and leg are out of order.",
            fmt.formatAndAppend(
                    params,
                    UPRV_LENGTHOF(params),
                    appendTo,
                    offsets,
                    UPRV_LENGTHOF(offsets),
                    status));
    if (!assertSuccess("Status", status)) {
        return;
    }
    verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
    appendTo.remove();

    // Ensure we don't write to offsets array beyond its length.
    status = U_ZERO_ERROR;
    offsets[UPRV_LENGTHOF(offsets) - 1] = 289;
    appendTo.remove();
    fmt.formatAndAppend(
            params,
            UPRV_LENGTHOF(params),
            appendTo,
            offsets,
            UPRV_LENGTHOF(offsets) - 1,
            status);
    assertEquals("Offsets buffer length", 289, offsets[UPRV_LENGTHOF(offsets) - 1]);

    // Test assignment
    SimplePatternFormatter s;
    s = fmt;
    appendTo.remove();
    assertEquals(
            "Assignment",
            "Templates frogtommy{0} and leg are out of order.",
            s.formatAndAppend(
                    params,
                    UPRV_LENGTHOF(params),
                    appendTo,
                    NULL,
                    0,
                    status));

    // Copy constructor
    SimplePatternFormatter r(fmt);
    appendTo.remove();
    assertEquals(
            "Copy constructor",
            "Templates frogtommy{0} and leg are out of order.",
            r.formatAndAppend(
                    params,
                    UPRV_LENGTHOF(params),
                    appendTo,
                    NULL,
                    0,
                    status));
    r.compile("{0} meter", status);
    assertEquals("PlaceholderCount", 1, r.getPlaceholderCount());
    appendTo.remove();
    assertEquals(
            "Replace with new compile",
            "freddy meter",
            r.format("freddy", appendTo, status));
    r.compile("{0}, {1}", status);
    assertEquals("PlaceholderCount", 2, r.getPlaceholderCount());
    appendTo.remove();
    assertEquals(
            "2 arg",
            "foo, bar",
            r.format("foo", "bar", appendTo, status));
    r.compile("{0}, {1} and {2}", status);
    assertEquals("PlaceholderCount", 3, r.getPlaceholderCount());
    appendTo.remove();
    assertEquals(
            "3 arg",
            "foo, bar and baz",
            r.format("foo", "bar", "baz", appendTo, status));
    assertSuccess("Status", status);
}

void SimplePatternFormatterTest::TestTooFewPlaceholderValues() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("{0} and {1}", status);
    UnicodeString appendTo;
    UnicodeString firstValue;
    UnicodeString *params[] = {&firstValue};

    fmt.format(
            firstValue, appendTo, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
    }

    status = U_ZERO_ERROR;
    fmt.formatAndAppend(
            params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
    }

    status = U_ZERO_ERROR;
    fmt.formatAndReplace(
            params, UPRV_LENGTHOF(params), appendTo, NULL, 0, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
    }
}

void SimplePatternFormatterTest::TestBadArguments() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("pickle", status);
    UnicodeString appendTo;

    // These succeed
    fmt.formatAndAppend(
            NULL, 0, appendTo, NULL, 0, status);
    fmt.formatAndReplace(
            NULL, 0, appendTo, NULL, 0, status);
    assertSuccess("", status);
    status = U_ZERO_ERROR;

    // fails
    fmt.formatAndAppend(
            NULL, 1, appendTo, NULL, 0, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndAppend() values=NULL but length=1");
    }
    status = U_ZERO_ERROR;
   
    // fails
    fmt.formatAndAppend(
            NULL, 0, appendTo, NULL, 1, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndAppend() offsets=NULL but length=1");
    }
    status = U_ZERO_ERROR;

    // fails because appendTo used as a parameter value
    SimplePatternFormatter fmt2("Placeholders {0} and {1}", status);
    UnicodeString frog("frog");
    const UnicodeString *params[] = { &appendTo, &frog };
    fmt2.formatAndAppend(params, 2, appendTo, NULL, 0, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndAppend() value=appendTo");
    }
    status = U_ZERO_ERROR;

   
    // fails
    fmt.formatAndReplace(
            NULL, 1, appendTo, NULL, 0, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndReplace() values=NULL but length=1");
    }
    status = U_ZERO_ERROR;
   
    // fails
    fmt.formatAndReplace(
            NULL, 0, appendTo, NULL, 1, status);
    if (status != U_ILLEGAL_ARGUMENT_ERROR) {
        errln("Expected U_ILLEGAL_ARGUMENT_ERROR: formatAndReplace() offsets=NULL but length=1");
    }
}

void SimplePatternFormatterTest::TestTextWithNoPlaceholders() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("{0} has no {1} placeholders.", status);
    assertEquals(
            "", " has no  placeholders.", fmt.getTextWithNoPlaceholders());
}

void SimplePatternFormatterTest::TestFormatReplaceNoOptimization() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile("{2}, {0}, {1} and {3}", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    UnicodeString result("original");
    int offsets[4];
    UnicodeString freddy("freddy");
    UnicodeString frog("frog");
    UnicodeString by("by");
    const UnicodeString *params[] = {&result, &freddy, &frog, &by};
    assertEquals(
            "",
            "frog, original, freddy and by",
            fmt.formatAndReplace(
                    params,
                    UPRV_LENGTHOF(params),
                    result,
                    offsets,
                    UPRV_LENGTHOF(offsets),
                    status));
    if (!assertSuccess("Status", status)) {
        return;
    }
    int32_t expectedOffsets[] = {6, 16, 0, 27};
    verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
}

void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationLeadingText() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile("boo {2}, {0}, {1} and {3}", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    UnicodeString result("original");
    int offsets[4];
    UnicodeString freddy("freddy");
    UnicodeString frog("frog");
    UnicodeString by("by");
    const UnicodeString *params[] = {&freddy, &frog, &result, &by};
    assertEquals(
            "",
            "boo original, freddy, frog and by",
            fmt.formatAndReplace(
                    params,
                    UPRV_LENGTHOF(params),
                    result,
                    offsets,
                    UPRV_LENGTHOF(offsets),
                    status));
    if (!assertSuccess("Status", status)) {
        return;
    }
    int32_t expectedOffsets[] = {14, 22, 4, 31};
    verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
}

void SimplePatternFormatterTest::TestFormatReplaceOptimization() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile("{2}, {0}, {1} and {3}", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    UnicodeString result("original");
    int offsets[4];
    UnicodeString freddy("freddy");
    UnicodeString frog("frog");
    UnicodeString by("by");
    const UnicodeString *params[] = {&freddy, &frog, &result, &by};
    assertEquals(
            "",
            "original, freddy, frog and by",
            fmt.formatAndReplace(
                    params,
                    UPRV_LENGTHOF(params),
                    result,
                    offsets,
                    UPRV_LENGTHOF(offsets),
                    status));
    if (!assertSuccess("Status", status)) {
        return;
    }
    int32_t expectedOffsets[] = {10, 18, 0, 27};
    verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
}

void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationLeadingPlaceholderUsedTwice() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile("{2}, {0}, {1} and {3} {2}", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    UnicodeString result("original");
    int offsets[4];
    UnicodeString freddy("freddy");
    UnicodeString frog("frog");
    UnicodeString by("by");
    const UnicodeString *params[] = {&freddy, &frog, &result, &by};
    assertEquals(
            "",
            "original, freddy, frog and by original",
            fmt.formatAndReplace(
                    params,
                    UPRV_LENGTHOF(params),
                    result,
                    offsets,
                    UPRV_LENGTHOF(offsets),
                    status));
    if (!assertSuccess("Status", status)) {
        return;
    }
    int32_t expectedOffsets[] = {10, 18, 30, 27};
    verifyOffsets(expectedOffsets, offsets, UPRV_LENGTHOF(expectedOffsets));
}

void SimplePatternFormatterTest::TestFormatReplaceOptimizationNoOffsets() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt;
    fmt.compile("{2}, {0}, {1} and {3}", status);
    if (!assertSuccess("Status", status)) {
        return;
    }
    UnicodeString result("original");
    UnicodeString freddy("freddy");
    UnicodeString frog("frog");
    UnicodeString by("by");
    const UnicodeString *params[] = {&freddy, &frog, &result, &by};
    assertEquals(
            "",
            "original, freddy, frog and by",
            fmt.formatAndReplace(
                    params,
                    UPRV_LENGTHOF(params),
                    result,
                    NULL,
                    0,
                    status));
    assertSuccess("Status", status);
}

void SimplePatternFormatterTest::TestFormatReplaceNoOptimizationNoOffsets() {
    UErrorCode status = U_ZERO_ERROR;
    SimplePatternFormatter fmt("Placeholders {0} and {1}", status);
    UnicodeString result("previous:");
    UnicodeString frog("frog");
    const UnicodeString *params[] = {&result, &frog};
    assertEquals(
            "",
            "Placeholders previous: and frog",
            fmt.formatAndReplace(
                    params,
                    UPRV_LENGTHOF(params),
                    result,
                    NULL,
                    0,
                    status));
    assertSuccess("Status", status);
}

void SimplePatternFormatterTest::TestQuotingLikeMessageFormat() {
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString pattern = "{0} don't can''t '{5}''}{a' again '}'{1} to the '{end";
    SimplePatternFormatter spf(pattern, status);
    MessageFormat mf(pattern, Locale::getRoot(), status);
    UnicodeString expected = "X don't can't {5}'}{a again }Y to the {end";
    UnicodeString x("X"), y("Y");
    Formattable values[] = { x, y };
    UnicodeString result;
    FieldPosition ignore(FieldPosition::DONT_CARE);
    assertEquals("MessageFormat", expected, mf.format(values, 2, result, ignore, status));
    assertEquals("SimplePatternFormatter", expected, spf.format(x, y, result.remove(), status));
}

void SimplePatternFormatterTest::verifyOffsets(
        const int32_t *expected, const int32_t *actual, int32_t count) {
    for (int32_t i = 0; i < count; ++i) {
        if (expected[i] != actual[i]) {
            errln("Expected %d, got %d", expected[i], actual[i]);
        }
    }
}

extern IntlTest *createSimplePatternFormatterTest() {
    return new SimplePatternFormatterTest();
}