X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/a0b4f637ba1a6c3c5651b61a69303b029bacf7d3..2ca993e82fb37b597a3c73ecd1586a139a6579c5:/icuSources/test/intltest/simpleformattertest.cpp diff --git a/icuSources/test/intltest/simpleformattertest.cpp b/icuSources/test/intltest/simpleformattertest.cpp new file mode 100644 index 00000000..efe030c9 --- /dev/null +++ b/icuSources/test/intltest/simpleformattertest.cpp @@ -0,0 +1,527 @@ +/* +******************************************************************************* +* Copyright (C) 2014-2016, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +* +* simpleformattertest.cpp +* +******************************************************************************** +*/ + +#include "unicode/msgfmt.h" +#include "unicode/unistr.h" +#include "cstring.h" +#include "intltest.h" +#include "unicode/simpleformatter.h" + +class SimpleFormatterTest : public IntlTest { +public: + SimpleFormatterTest() { + } + void TestNoArguments(); + void TestSyntaxErrors(); + void TestOneArgument(); + void TestBigArgument(); + void TestManyArguments(); + void TestTooFewArgumentValues(); + void TestBadArguments(); + void TestTextWithNoArguments(); + void TestFormatReplaceNoOptimization(); + void TestFormatReplaceNoOptimizationLeadingText(); + void TestFormatReplaceOptimization(); + void TestFormatReplaceNoOptimizationLeadingArgumentUsedTwice(); + 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 SimpleFormatterTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) { + TESTCASE_AUTO_BEGIN; + TESTCASE_AUTO(TestNoArguments); + TESTCASE_AUTO(TestSyntaxErrors); + TESTCASE_AUTO(TestOneArgument); + TESTCASE_AUTO(TestBigArgument); + TESTCASE_AUTO(TestManyArguments); + TESTCASE_AUTO(TestTooFewArgumentValues); + TESTCASE_AUTO(TestBadArguments); + TESTCASE_AUTO(TestTextWithNoArguments); + TESTCASE_AUTO(TestFormatReplaceNoOptimization); + TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingText); + TESTCASE_AUTO(TestFormatReplaceOptimization); + TESTCASE_AUTO(TestFormatReplaceNoOptimizationLeadingArgumentUsedTwice); + TESTCASE_AUTO(TestFormatReplaceOptimizationNoOffsets); + TESTCASE_AUTO(TestFormatReplaceNoOptimizationNoOffsets); + TESTCASE_AUTO(TestQuotingLikeMessageFormat); + TESTCASE_AUTO_END; +} + +void SimpleFormatterTest::TestNoArguments() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt("This doesn''t have templates '{0}", status); + assertEquals("getArgumentLimit", 0, fmt.getArgumentLimit()); + 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 SimpleFormatterTest::TestSyntaxErrors() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt("{}", status); + assertEquals("syntax error {}", U_ILLEGAL_ARGUMENT_ERROR, status); + status = U_ZERO_ERROR; + fmt.applyPattern("{12d", status); + assertEquals("syntax error {12d", U_ILLEGAL_ARGUMENT_ERROR, status); +} + +void SimpleFormatterTest::TestOneArgument() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern("{0} meter", status); + if (!assertSuccess("Status", status)) { + return; + } + assertEquals("getArgumentLimit", 1, fmt.getArgumentLimit()); + UnicodeString appendTo; + assertEquals( + "format", + "1 meter", + fmt.format("1", appendTo, status)); + + // assignment + SimpleFormatter s; + s = fmt; + appendTo.remove(); + assertEquals( + "Assignment", + "1 meter", + s.format("1", appendTo, status)); + + // Copy constructor + SimpleFormatter r(fmt); + appendTo.remove(); + assertEquals( + "Copy constructor", + "1 meter", + r.format("1", appendTo, status)); + assertSuccess("Status", status); +} + +void SimpleFormatterTest::TestBigArgument() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt("a{20}c", status); + if (!assertSuccess("Status", status)) { + return; + } + assertEquals("{20} count", 21, fmt.getArgumentLimit()); + 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 SimpleFormatterTest::TestManyArguments() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern( + "Templates {2}{1}{5} and {4} are out of order.", status); + if (!assertSuccess("Status", status)) { + return; + } + assertEquals("getArgumentLimit", 6, fmt.getArgumentLimit()); + 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 + SimpleFormatter 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 + SimpleFormatter 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.applyPattern("{0} meter", status); + assertEquals("getArgumentLimit", 1, r.getArgumentLimit()); + appendTo.remove(); + assertEquals( + "Replace with new applyPattern", + "freddy meter", + r.format("freddy", appendTo, status)); + r.applyPattern("{0}, {1}", status); + assertEquals("getArgumentLimit", 2, r.getArgumentLimit()); + appendTo.remove(); + assertEquals( + "2 arg", + "foo, bar", + r.format("foo", "bar", appendTo, status)); + r.applyPattern("{0}, {1} and {2}", status); + assertEquals("getArgumentLimit", 3, r.getArgumentLimit()); + appendTo.remove(); + assertEquals( + "3 arg", + "foo, bar and baz", + r.format("foo", "bar", "baz", appendTo, status)); + assertSuccess("Status", status); +} + +void SimpleFormatterTest::TestTooFewArgumentValues() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter 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 SimpleFormatterTest::TestBadArguments() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter 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 + SimpleFormatter fmt2("Arguments {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 SimpleFormatterTest::TestTextWithNoArguments() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt("{0} has no {1} arguments.", status); + assertEquals( + "", " has no arguments.", fmt.getTextWithNoArguments()); +} + +void SimpleFormatterTest::TestFormatReplaceNoOptimization() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern("{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 SimpleFormatterTest::TestFormatReplaceNoOptimizationLeadingText() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern("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 SimpleFormatterTest::TestFormatReplaceOptimization() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern("{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 SimpleFormatterTest::TestFormatReplaceNoOptimizationLeadingArgumentUsedTwice() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern("{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 SimpleFormatterTest::TestFormatReplaceOptimizationNoOffsets() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt; + fmt.applyPattern("{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 SimpleFormatterTest::TestFormatReplaceNoOptimizationNoOffsets() { + UErrorCode status = U_ZERO_ERROR; + SimpleFormatter fmt("Arguments {0} and {1}", status); + UnicodeString result("previous:"); + UnicodeString frog("frog"); + const UnicodeString *params[] = {&result, &frog}; + assertEquals( + "", + "Arguments previous: and frog", + fmt.formatAndReplace( + params, + UPRV_LENGTHOF(params), + result, + NULL, + 0, + status)); + assertSuccess("Status", status); +} + +void SimpleFormatterTest::TestQuotingLikeMessageFormat() { +#if !UCONFIG_NO_FORMATTING + UErrorCode status = U_ZERO_ERROR; + UnicodeString pattern = "{0} don't can''t '{5}''}{a' again '}'{1} to the '{end"; + SimpleFormatter 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("SimpleFormatter", expected, spf.format(x, y, result.remove(), status)); +#endif /* !UCONFIG_NO_FORMATTING */ +} + +void SimpleFormatterTest::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 *createSimpleFormatterTest() { + return new SimpleFormatterTest(); +}