--- /dev/null
+/*
+*******************************************************************************
+* 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();
+}