From 1abe5853482a01f9f97f6cb133300666ee1c7ec6 Mon Sep 17 00:00:00 2001 From: Mihai Nita Date: Sun, 22 Sep 2024 15:49:10 -0700 Subject: [PATCH] ICU-22908 MF2 ICU4J: Update spec tests and update implementation for recent spec changes --- .../dev/test/message2/Mf2FeaturesTest.java | 14 +- .../icu/message2/MFDataModelValidator.java | 7 +- .../java/com/ibm/icu/message2/MFParser.java | 25 +-- .../com/ibm/icu/message2/MFSerializer.java | 10 +- .../icu/message2/NumberFormatterFactory.java | 9 +- .../ibm/icu/dev/test/message2/CoreTest.java | 64 +++---- .../CustomFormatterMessageRefTest.java | 6 +- .../message2/CustomFormatterPersonTest.java | 4 +- .../test/message2/DefaultTestProperties.java | 26 ++- .../dev/test/message2/MessageFormat2Test.java | 27 +-- .../ibm/icu/dev/test/message2/Mf2IcuTest.java | 3 +- .../dev/test/message2/SerializationTest.java | 21 +-- .../ibm/icu/dev/test/message2/TestUtils.java | 6 +- .../com/ibm/icu/dev/test/message2/Unit.java | 5 +- .../message2/alias-selector-annotations.json | 4 +- .../message2/icu-test-previous-release.json | 24 +-- testdata/message2/icu-test-selectors.json | 78 +++++--- testdata/message2/matches-whitespace.json | 27 +-- testdata/message2/more-data-model-errors.json | 26 +-- testdata/message2/resolution-errors.json | 4 +- testdata/message2/runtime-errors.json | 6 +- testdata/message2/spec/data-model-errors.json | 25 +-- testdata/message2/spec/functions/date.json | 3 +- .../message2/spec/functions/datetime.json | 3 +- testdata/message2/spec/functions/integer.json | 2 +- testdata/message2/spec/functions/number.json | 169 +----------------- testdata/message2/spec/functions/string.json | 11 +- testdata/message2/spec/functions/time.json | 3 +- testdata/message2/spec/pattern-selection.json | 120 +++++++++++++ testdata/message2/spec/syntax-errors.json | 110 +++++++++--- testdata/message2/spec/syntax.json | 61 +++++-- testdata/message2/valid-tests.json | 2 +- 32 files changed, 514 insertions(+), 391 deletions(-) create mode 100644 testdata/message2/spec/pattern-selection.json diff --git a/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/message2/Mf2FeaturesTest.java b/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/message2/Mf2FeaturesTest.java index 77c0fa3604d7..bf53948aae6f 100644 --- a/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/message2/Mf2FeaturesTest.java +++ b/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/message2/Mf2FeaturesTest.java @@ -328,7 +328,7 @@ public void testAllKindOfNumbers() { public void testSpecialPluralWithDecimals() { String message; message = ".local $amount = {$count :number}\n" - + ".match {$amount :number}\n" + + ".match $amount\n" + " 1 {{I have {$amount} dollar.}}\n" + " * {{I have {$amount} dollars.}}"; TestUtils.runTestCase(new TestCase.Builder() @@ -338,7 +338,7 @@ public void testSpecialPluralWithDecimals() { .expected("I have 1 dollar.") .build()); message = ".local $amount = {$count :number minimumFractionDigits=2}\n" - + ".match {$amount :number minimumFractionDigits=2}\n" + + ".match $amount\n" + " one {{I have {$amount} dollar.}}\n" + " * {{I have {$amount} dollars.}}"; TestUtils.runTestCase(new TestCase.Builder() @@ -367,7 +367,8 @@ public void testDefaultFunctionAndOptions() { @Test public void testSimpleSelection() { - String message = ".match {$count :number}\n" + String message = ".input {$count :number}\n" + + ".match $count\n" + " 1 {{You have one notification.}}\n" + " * {{You have {$count} notifications.}}"; @@ -386,7 +387,9 @@ public void testSimpleSelection() { @Test public void testComplexSelection() { String message = "" - + ".match {$photoCount :number} {$userGender :string}\n" + + ".input {$photoCount :number}\n" + + ".input {$userGender :string}\n" + + ".match $photoCount $userGender\n" + " 1 masculine {{{$userName} added a new photo to his album.}}\n" + " 1 feminine {{{$userName} added a new photo to her album.}}\n" + " 1 * {{{$userName} added a new photo to their album.}}\n" @@ -437,8 +440,9 @@ public void testSimpleLocaleVariable() { @Test public void testLocaleVariableWithSelect() { String message = "" + + ".input {$count :number}\n" + ".local $exp = {$expDate :date year=numeric month=short day=numeric weekday=short}\n" - + ".match {$count :number}\n" + + ".match $count\n" + " 1 {{Your ticket expires on {$exp}.}}\n" + " * {{Your {$count} tickets expire on {$exp}.}}"; diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFDataModelValidator.java b/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFDataModelValidator.java index a17728434b34..a66d2e24c7ec 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFDataModelValidator.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFDataModelValidator.java @@ -140,6 +140,7 @@ private boolean validateDeclarations(List declarations) throws MFPa private void validateExpression(Expression expression, boolean fromInput) throws MFParseException { String argName = null; + boolean wasLiteral = false; Annotation annotation = null; if (expression instanceof Literal) { // ...{foo}... or ...{|foo|}... or ...{123}... @@ -148,6 +149,7 @@ private void validateExpression(Expression expression, boolean fromInput) LiteralExpression le = (LiteralExpression) expression; argName = le.arg.value; annotation = le.annotation; + wasLiteral = true; } else if (expression instanceof VariableExpression) { VariableExpression ve = (VariableExpression) expression; // ...{$foo :bar opt1=|str| opt2=$x opt3=$y}... @@ -184,7 +186,10 @@ private void validateExpression(Expression expression, boolean fromInput) addVariableDeclaration(argName); } else { // Remember that we've seen it, to complain if there is a declaration later - declaredVars.add(argName); + if (!wasLiteral) { + // We don't consider {|bar| :func} to be a declaration of a "bar" variable + declaredVars.add(argName); + } } } } diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFParser.java b/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFParser.java index 61d18ffde8a4..a628d0062c51 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFParser.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFParser.java @@ -559,9 +559,9 @@ private MFDataModel.Message getComplexMessage() throws MFParseException { } } - // abnf: matcher = match-statement 1*([s] variant) - // abnf: match-statement = match 1*([s] selector) - // abnf: selector = expression + // abnf: matcher = match-statement s variant *([s] variant) + // abnf: match-statement = match 1*(s selector) + // abnf: selector = variable // abnf: variant = key *(s key) [s] quoted-pattern // abnf: key = literal / "*" // abnf: match = %s".match" @@ -571,17 +571,18 @@ private MFDataModel.SelectMessage getMatch(List declara // Look for selectors List expressions = new ArrayList<>(); while (true) { - // Whitespace not required between selectors: - // match 1*([s] selector) - // Whitespace not required before first variant: - // matcher = match-statement 1*([s] variant) - skipOptionalWhitespaces(); - MFDataModel.Expression expression = getPlaceholder(); - if (expression == null) { + // Whitespace required between selectors but not required before first variant. + skipMandatoryWhitespaces(); + int cp = input.peekChar(); + if (cp != '$') { break; } - checkCondition( - !(expression instanceof MFDataModel.Markup), "Cannot do selection on markup"); + MFDataModel.VariableRef variableRef = getVariableRef(); + if (variableRef == null) { + break; + } + MFDataModel.Expression expression = + new MFDataModel.VariableExpression(variableRef, null, new ArrayList<>()); expressions.add(expression); } diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFSerializer.java b/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFSerializer.java index 4ce31109f4f2..1e29fc5c09ba 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFSerializer.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/message2/MFSerializer.java @@ -79,7 +79,15 @@ private void selectMessageToString(SelectMessage message) { result.append(".match"); for (Expression selector : message.selectors) { result.append(' '); - expressionToString(selector); + if (selector instanceof VariableExpression) { + VariableExpression ve = (VariableExpression) selector; + literalOrVariableRefToString(ve.arg); + } else { + // TODO: we have a (valid?) data model, so do we really want to fail? + // It is very close to release, so I am a bit reluctant to add a throw. + // I tried, and none of the unit tests fail (as expected). But still feels unsafe. + expressionToString(selector); + } } for (Variant variant : message.variants) { variantToString(variant); diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/message2/NumberFormatterFactory.java b/icu4j/main/core/src/main/java/com/ibm/icu/message2/NumberFormatterFactory.java index 6cb6c56c45eb..28451b0bda82 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/message2/NumberFormatterFactory.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/message2/NumberFormatterFactory.java @@ -163,14 +163,16 @@ public FormattedPlaceholder format(Object toFormat, Map variable private static class PluralSelectorImpl implements Selector { private static final String NO_MATCH = "\uFFFDNO_MATCH\uFFFE"; // Unlikely to show in a key private final PluralRules rules; - private Map fixedOptions; - private LocalizedNumberFormatter icuFormatter; + private final Map fixedOptions; + private final LocalizedNumberFormatter icuFormatter; + private final String kind; private PluralSelectorImpl( Locale locale, PluralRules rules, Map fixedOptions, String kind) { this.rules = rules; this.fixedOptions = fixedOptions; this.icuFormatter = formatterForOptions(locale, fixedOptions, kind); + this.kind = kind; } /** @@ -252,6 +254,9 @@ private boolean matches(Object value, String key, Map variableOp } else { return false; } + if ("integer".equals(kind)) { + valToCheck = valToCheck.intValue(); + } Number keyNrVal = OptUtils.asNumber(key); if (keyNrVal != null && valToCheck.doubleValue() == keyNrVal.doubleValue()) { diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CoreTest.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CoreTest.java index 63e3eefddf1d..0c9878a8dd3a 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CoreTest.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CoreTest.java @@ -14,37 +14,39 @@ @SuppressWarnings({"static-method", "javadoc"}) @RunWith(JUnit4.class) public class CoreTest extends CoreTestFmwk { - private static final String[] JSON_FILES = {"alias-selector-annotations.json", - "duplicate-declarations.json", - "icu-parser-tests.json", - "icu-test-functions.json", - "icu-test-previous-release.json", - "icu-test-selectors.json", - "invalid-number-literals-diagnostics.json", - "invalid-options.json", - "markup.json", - "matches-whitespace.json", - "more-data-model-errors.json", - "more-functions.json", - "resolution-errors.json", - "runtime-errors.json", - "spec/data-model-errors.json", - "spec/syntax-errors.json", - "spec/syntax.json", - "spec/functions/date.json", - "spec/functions/datetime.json", - "spec/functions/integer.json", - "spec/functions/number.json", - "spec/functions/string.json", - "spec/functions/time.json", - "syntax-errors-diagnostics.json", - "syntax-errors-diagnostics-multiline.json", - "syntax-errors-end-of-input.json", - "syntax-errors-reserved.json", - "tricky-declarations.json", - "unsupported-expressions.json", - "unsupported-statements.json", - "valid-tests.json"}; + private static final String[] JSON_FILES = { + "alias-selector-annotations.json", + "duplicate-declarations.json", + "icu-parser-tests.json", + "icu-test-functions.json", + "icu-test-previous-release.json", + "icu-test-selectors.json", + "invalid-number-literals-diagnostics.json", + "invalid-options.json", + "markup.json", + "matches-whitespace.json", + "more-data-model-errors.json", + "more-functions.json", + "resolution-errors.json", + "runtime-errors.json", + "spec/data-model-errors.json", + "spec/syntax-errors.json", + "spec/syntax.json", + "spec/functions/date.json", + "spec/functions/datetime.json", + "spec/functions/integer.json", + "spec/functions/number.json", + "spec/functions/string.json", + "spec/functions/time.json", + "syntax-errors-diagnostics.json", + "syntax-errors-diagnostics-multiline.json", + "syntax-errors-end-of-input.json", + "syntax-errors-reserved.json", + "tricky-declarations.json", + "unsupported-expressions.json", + "unsupported-statements.json", + "valid-tests.json" + }; @Test public void test() throws Exception { diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterMessageRefTest.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterMessageRefTest.java index 362ff351e170..524ede919d8c 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterMessageRefTest.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterMessageRefTest.java @@ -79,9 +79,9 @@ public String formatToString(Object toFormat, Map variableOption @BeforeClass public static void beforeClass() { - PROPERTIES.put("firefox", ".match {$gcase :string} genitive {{Firefoxin}} * {{Firefox}}"); - PROPERTIES.put("chrome", ".match {$gcase :string} genitive {{Chromen}} * {{Chrome}}"); - PROPERTIES.put("safari", ".match {$gcase :string} genitive {{Safarin}} * {{Safari}}"); + PROPERTIES.put("firefox", ".input {$gcase :string} .match $gcase genitive {{Firefoxin}} * {{Firefox}}"); + PROPERTIES.put("chrome", ".input {$gcase :string} .match $gcase genitive {{Chromen}} * {{Chrome}}"); + PROPERTIES.put("safari", ".input {$gcase :string} .match $gcase genitive {{Safarin}} * {{Safari}}"); } @Test diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterPersonTest.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterPersonTest.java index 97dcfb3f287d..93baa18cc5b8 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterPersonTest.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/CustomFormatterPersonTest.java @@ -146,11 +146,13 @@ public void testCustomFunctionsComplexMessage() { Person malePerson = new Person("Mr.", "John", "Doe"); Person unknownPerson = new Person("Mr./Ms.", "Anonymous", "Doe"); String message = "" + + ".input {$hostGender :string}\n" + + ".input {$guestCount :number}\n" + ".local $hostName = {$host :person length=long}\n" + ".local $guestName = {$guest :person length=long}\n" + ".local $guestsOther = {$guestCount :number icu:offset=1}\n" // + "\n" - + ".match {$hostGender :icu:gender} {$guestCount :number}\n" + + ".match $hostGender $guestCount\n" // + "\n" + " female 0 {{{$hostName} does not give a party.}}\n" + " female 1 {{{$hostName} invites {$guestName} to her party.}}\n" diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/DefaultTestProperties.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/DefaultTestProperties.java index 21cc5a363a32..fc11256bc1d2 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/DefaultTestProperties.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/DefaultTestProperties.java @@ -3,17 +3,37 @@ package com.ibm.icu.dev.test.message2; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + // See https://github.com/unicode-org/conformance/blob/main/schema/message_fmt2/testgen_schema.json // Class corresponding to the json test files. // Since this is serialized by Gson, the field names should match the keys in the .json files. class DefaultTestProperties { + private static final Object[] NO_ERRORS = {}; // Unused fields ignored - final String locale; - final Object[] expErrors; + private final String locale; + private final JsonElement expErrors; - DefaultTestProperties(String locale, Object[] expErrors) { + DefaultTestProperties(String locale, JsonElement expErrors) { this.locale = locale; this.expErrors = expErrors; } + + String getLocale() { + return this.locale; + } + + Object[] getExpErrors() { + if (expErrors == null || !expErrors.isJsonArray()) { + return NO_ERRORS; + } + JsonArray arr = expErrors.getAsJsonArray(); + Object [] result = new Object[arr.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = arr.get(i); + } + return result; + } } diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/MessageFormat2Test.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/MessageFormat2Test.java index 08cc9f0e1de9..cfe8722857d8 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/MessageFormat2Test.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/MessageFormat2Test.java @@ -129,7 +129,8 @@ public void testDateFormat() { @Test public void testPlural() { String message = "" - + ".match {$count :number}\n" + + ".input {$count :number}\n" + + ".match $count\n" + " 1 {{You have one notification.}}\n" + " * {{You have {$count} notifications.}}"; @@ -147,7 +148,8 @@ public void testPlural() { @Test public void testPluralOrdinal() { String message = "" - + ".match {$place :number select=ordinal}\n" + + ".input {$place :number select=ordinal}\n" + + ".match $place\n" + " 1 {{You got the gold medal}}\n" + " 2 {{You got the silver medal}}\n" + " 3 {{You got the bronze medal}}\n" @@ -332,7 +334,8 @@ public void testFormatterIsCreatedOnce() { @Test public void testPluralWithOffset() { String message = "" - + ".match {$count :number icu:offset=2}\n" + + ".input {$count :number icu:offset=2}\n" + + ".match $count\n" + " 1 {{Anna}}\n" + " 2 {{Anna and Bob}}\n" + " one {{Anna, Bob, and {$count :number icu:offset=2} other guest}}\n" @@ -361,7 +364,7 @@ public void testPluralWithOffset() { public void testPluralWithOffsetAndLocalVar() { String message = "" + ".local $foo = {$count :number icu:offset=2}" - + ".match {$foo :number}\n" // should "inherit" the offset + + ".match $foo\n" // should "inherit" the offset + " 1 {{Anna}}\n" + " 2 {{Anna and Bob}}\n" + " one {{Anna, Bob, and {$foo} other guest}}\n" @@ -390,7 +393,7 @@ public void testPluralWithOffsetAndLocalVar() { public void testPluralWithOffsetAndLocalVar2() { String message = "" + ".local $foo = {$amount :number icu:skeleton=|.00/w|}\n" - + ".match {$foo :number}\n" // should "inherit" the offset + + ".match $foo\n" // should "inherit" the offset + " 1 {{Last dollar}}\n" + " one {{{$foo} dollar}}\n" + " * {{{$foo} dollars}}"; @@ -412,7 +415,7 @@ public void testPluralWithOffsetAndLocalVar2() { public void testPluralWithOffsetAndLocalVar2Options() { String message = "" + ".local $foo = {$amount :number minumumFractionalDigits=2}\n" - + ".match {$foo :number}\n" // should "inherit" the offset + + ".match $foo\n" // should "inherit" the offset + " 1 {{Last dollar}}\n" + " one {{{$foo} dollar}}\n" + " * {{{$foo} dollars}}"; @@ -447,7 +450,8 @@ public void testLoopOnLocalVars() { @Test public void testVariableOptionsInSelector() { String messageVar = "" - + ".match {$count :number icu:offset=$delta}\n" + + ".input {$count :number icu:offset=$delta}\n" + + ".match $count\n" + " 1 {{A}}\n" + " 2 {{A and B}}\n" + " one {{A, B, and {$count :number icu:offset=$delta} more character}}\n" @@ -465,7 +469,8 @@ public void testVariableOptionsInSelector() { mfVar.formatToString(Args.of("count", 7, "delta", 2))); String messageVar2 = "" - + ".match {$count :number icu:offset=$delta}\n" + + ".input {$count :number icu:offset=$delta}\n" + + ".match $count\n" + " 1 {{Exactly 1}}\n" + " 2 {{Exactly 2}}\n" + " * {{Count = {$count :number icu:offset=$delta} and delta={$delta}.}}"; @@ -505,7 +510,7 @@ public void testVariableOptionsInSelector() { public void testVariableOptionsInSelectorWithLocalVar() { String messageFix = "" + ".local $offCount = {$count :number icu:offset=2}" - + ".match {$offCount :number}\n" + + ".match $offCount\n" + " 1 {{A}}\n" + " 2 {{A and B}}\n" + " one {{A, B, and {$offCount} more character}}\n" @@ -520,7 +525,7 @@ public void testVariableOptionsInSelectorWithLocalVar() { String messageVar = "" + ".local $offCount = {$count :number icu:offset=$delta}" - + ".match {$offCount :number}\n" + + ".match $offCount\n" + " 1 {{A}}\n" + " 2 {{A and B}}\n" + " one {{A, B, and {$offCount} more character}}\n" @@ -539,7 +544,7 @@ public void testVariableOptionsInSelectorWithLocalVar() { String messageVar2 = "" + ".local $offCount = {$count :number icu:offset=$delta}" - + ".match {$offCount :number}\n" + + ".match $offCount\n" + " 1 {{Exactly 1}}\n" + " 2 {{Exactly 2}}\n" + " * {{Count = {$count}, OffCount = {$offCount}, and delta={$delta}.}}"; diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Mf2IcuTest.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Mf2IcuTest.java index b72f4db0a6cc..915c08436d50 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Mf2IcuTest.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Mf2IcuTest.java @@ -74,7 +74,8 @@ public void testSimpleFormat() { @Test public void testSelectFormatToPattern() { String pattern = "" - + ".match {$userGender :string}\n" + + ".input {$userGender :string}\n" + + ".match $userGender\n" + " female {{{$userName} est all\u00E9e \u00E0 Paris.}}" + " * {{{$userName} est all\u00E9 \u00E0 Paris.}}" ; diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/SerializationTest.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/SerializationTest.java index 465b7cae8131..4cc18ec11c84 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/SerializationTest.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/SerializationTest.java @@ -28,13 +28,13 @@ public void test() throws Exception { ".input {$a :number} {{Hello world!}}", ".local $b = {$a :number} {{Hello world!}}", ".local $c = {1 :number} {{Hello {userName}}}", - ".match {$count :number}\n" + ".input {$count :number} .match $count\n" + "one {{You deleted {$count} file}}\n" + "* {{You deleted {$count} files}}", - ".match {$count :number}\n" + ".input {$count :number} .match $count\n" + "one {{You deleted {$count} file}}\n" + "* {{You deleted {$count} files}}", - ".match {$place :number select=ordinal}\n" + ".input {$place :number select=ordinal} .match $place\n" + "* {{You fininshed in the {$place}th place}}\n" + "two {{You fininshed in the {$place}nd place}}\n" + "one {{You fininshed in the {$place}st place}}\n" @@ -42,7 +42,8 @@ public void test() throws Exception { + "2 {{You got the silver medal}}\n" + "3 {{You got the bronze medal}}\n" + "few {{You fininshed in the {$place}rd place}}", - ".match {$fileCount :number} {$folderCount :number}\n" + ".input {$fileCount :number}\n.input {$folderCount :number}\n" + + ".match $fileCount $folderCount\n" + "* * {{You deleted {$fileCount} files in {$folderCount} folders}}\n" + "one one {{You deleted {$fileCount} file in {$folderCount} folder}}\n" + "one * {{You deleted {$fileCount} file in {$folderCount} folders}}\n" @@ -52,26 +53,26 @@ public void test() throws Exception { "{|3.1415| :number minimumFractionDigits=5} dollars", "{|3.1415| :number maximumFractionDigits=2} dollars", ".local $c = {$count :number minimumFractionDigits=2}\n" - + ".match {$c}\n" + + ".match $c\n" + "one {{{$c} dollar}}\n" + "* {{{$c} dollars}}", ".local $c = {1 :number minimumFractionDigits=2}\n" - + ".match {$c}\n" + + ".match $c\n" + "one {{{$c} dollar}}\n" + "* {{{$c} dollars}}", ".local $c = {1 :number}\n" - + ".match {$c}\n" + + ".match $c\n" + "one {{{$c} dollar}}\n" + "* {{{$c} dollars}}", ".local $c = {1.25 :number}\n" - + ".match {$c}\n" + + ".match $c\n" + "one {{{$c} dollar}}\n" + "* {{{$c} dollars}}", ".local $c = {1.25 :number maximumFractionDigits=0}\n" - + ".match {$c}\n" + + ".match $c\n" + "one {{{$c} dollar}}\n" + "* {{{$c} dollars}}", - ".match {$count :number} 1 {{one}} * {{other}}", + ".input {$count :number} .match $count 1 {{one}} * {{other}}", }; for (String test : testStrings) { checkOneString(test); diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/TestUtils.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/TestUtils.java index 7bfcf65dc56d..6774baeeb568 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/TestUtils.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/TestUtils.java @@ -129,7 +129,7 @@ static Map paramsToMap(Param[] params) { static boolean expectsErrors(DefaultTestProperties defaults, Unit unit) { return (unit.expErrors != null && !unit.expErrors.isEmpty()) - || (defaults.expErrors != null && defaults.expErrors.length > 0); + || (defaults.getExpErrors().length > 0); } static void runTestCase(DefaultTestProperties defaults, Unit unit) { @@ -154,8 +154,8 @@ static void runTestCase(DefaultTestProperties defaults, Unit unit, Param[] param MessageFormatter.builder().setPattern(pattern.toString()); if (unit.locale != null && !unit.locale.isEmpty()) { mfBuilder.setLocale(Locale.forLanguageTag(unit.locale)); - } else if (defaults.locale != null) { - mfBuilder.setLocale(Locale.forLanguageTag(defaults.locale)); + } else if (defaults.getLocale() != null) { + mfBuilder.setLocale(Locale.forLanguageTag(defaults.getLocale())); } else { mfBuilder.setLocale(Locale.US); } diff --git a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Unit.java b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Unit.java index ff90ce0ccf9a..0349edb2ee67 100644 --- a/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Unit.java +++ b/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2/Unit.java @@ -32,7 +32,7 @@ class Unit { this.expErrors = expErrors; } - class Error { + static class Error { final String name; final String type; @@ -62,6 +62,9 @@ public String toString() { if (exp != null) { result.add("exp=" + escapeString(exp)); } + if (ignoreJava != null) { + result.add("ignoreJava=" + ignoreJava); + } return result.toString(); } diff --git a/testdata/message2/alias-selector-annotations.json b/testdata/message2/alias-selector-annotations.json index c064d40d4c82..d5307c5b1192 100644 --- a/testdata/message2/alias-selector-annotations.json +++ b/testdata/message2/alias-selector-annotations.json @@ -6,11 +6,11 @@ }, "tests": [ { - "src": ".local $one = {|The one| :string}\n .match {$one}\n 1 {{Value is one}}\n * {{Value is not one}}", + "src": ".local $one = {|The one| :string}\n .match $one\n 1 {{Value is one}}\n * {{Value is not one}}", "exp": "Value is not one" }, { - "src": ".local $one = {|The one| :string}\n .local $two = {$one}\n .match {$two}\n 1 {{Value is one}}\n * {{Value is not one}}", + "src": ".local $one = {|The one| :string}\n .local $two = {$one}\n .match $two\n 1 {{Value is one}}\n * {{Value is not one}}", "exp": "Value is not one" } ] diff --git a/testdata/message2/icu-test-previous-release.json b/testdata/message2/icu-test-previous-release.json index 0a1e27dff6e2..74fc41fdfcea 100644 --- a/testdata/message2/icu-test-previous-release.json +++ b/testdata/message2/icu-test-previous-release.json @@ -31,50 +31,50 @@ "exp": "bar foo" }, { - "src": ".match {$foo :number} 1 {{one}} * {{other}}", + "src": ".input {$foo :number} .match $foo 1 {{one}} * {{other}}", "params": [{ "name": "foo", "value": "1" }], "exp": "one", "ignoreJava": "See ICU-22809" }, { - "src": ".match {$foo :string} 1 {{one}} * {{other}}", + "src": ".input {$foo :string} .match $foo 1 {{one}} * {{other}}", "params": [{ "name": "foo", "value": "1" }], "exp": "one" }, { - "src": ".match {$foo :number} 1 {{one}} * {{other}}", + "src": ".input {$foo :number} .match $foo 1 {{one}} * {{other}}", "params": [{ "name": "foo", "value": 1 }], "exp": "one" }, { "ignoreJava": "Can't pass null in a map", "ignoreCpp": "Same as Java", - "src": ".match {$foo} 1 {{one}} * {{other}}", + "src": ".match $foo 1 {{one}} * {{other}}", "params": [{ "name": "foo", "value": null }], "exp": "other" }, { - "src": ".match {$foo :number} 1 {{one}} * {{other}}", + "src": ".input {$foo :number} .match $foo 1 {{one}} * {{other}}", "exp": "other", "expErrors": [{ "type": "unresolved-variable" }] }, { - "src": ".local $foo = {$bar} .match {$foo :number} one {{one}} * {{other}}", + "src": ".local $foo = {$bar :number} .match $foo one {{one}} * {{other}}", "params": [{ "name": "bar", "value": 1 }], "exp": "one" }, { - "src": ".local $foo = {$bar} .match {$foo :number} one {{one}} * {{other}}", + "src": ".local $foo = {$bar :number} .match $foo one {{one}} * {{other}}", "params": [{ "name": "bar", "value": 2 }], "exp": "other" }, { - "src": ".local $bar = {$none} .match {$foo :number} one {{one}} * {{{$bar}}}", + "src": ".local $bar = {$none} .input {$foo :number} .match $foo one {{one}} * {{{$bar}}}", "params": [{ "name": "foo", "value": 1 }, {"name": "none", "value": "" }], "exp": "one" }, { - "src": ".local $bar = {$none :number} .match {$foo :string} one {{one}} * {{{$bar}}}", + "src": ".local $bar = {$none :number} .input {$foo :string} .match $foo one {{one}} * {{{$bar}}}", "params": [{ "name": "foo", "value": 2 }], "exp": "{$none}", "expErrors": [{ "type": "unresolved-variable" }], @@ -120,17 +120,17 @@ "ignoreCpp": "Fallback is unclear. See https://github.com/unicode-org/message-format-wg/issues/703" }, { - "src": ".match {|foo| :string} *{{foo}}", + "src": ".local $f = {|foo| :string} .match $f *{{foo}}", "exp": "foo" }, { - "src": ".match {$foo :string} * * {{foo}}", + "src": ".input {$foo :string} .match $foo * * {{foo}}", "exp": "foo", "expErrors": [{ "type": "variant-key-mismatch" }, { "type": "unresolved-variable" }], "ignoreCpp": "Fallback is unclear. See https://github.com/unicode-org/message-format-wg/issues/735" }, { - "src": ".match {$foo :string} {$bar :string} * {{foo}}", + "src": ".input {$foo :string} .input {$bar :string} .match $foo $bar * {{foo}}", "exp": "foo", "expErrors": [{ "type": "variant-key-mismatch" }, { "type": "unresolved-variable" }], "ignoreCpp": "Fallback is unclear. See https://github.com/unicode-org/message-format-wg/issues/735" diff --git a/testdata/message2/icu-test-selectors.json b/testdata/message2/icu-test-selectors.json index 102bdfd88f50..7998f1359fb2 100644 --- a/testdata/message2/icu-test-selectors.json +++ b/testdata/message2/icu-test-selectors.json @@ -8,7 +8,8 @@ { "comment": "Testing simple plural", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", "one {{{$count} file}}\n", " * {{{$count} files}}" ], @@ -18,7 +19,8 @@ { "comment": "Testing simple plural", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", "one {{{$count} file}}\n", " * {{{$count} files}}" ], @@ -28,7 +30,8 @@ { "comment": "Testing simple plural", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", "one {{{$count} file}}\n", " * {{{$count} files}}" ], @@ -39,7 +42,8 @@ "comment": "Testing simple plural", "locale": "fr", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", "one {{{$count} file}}\n", " * {{{$count} files}}" ], @@ -50,7 +54,8 @@ "comment": "Testing simple plural", "locale": "fr", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", "one {{{$count} file}}\n", " * {{{$count} files}}" ], @@ -61,7 +66,8 @@ "comment": "Testing simple plural", "locale": "fr", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", "one {{{$count} file}}\n", " * {{{$count} files}}" ], @@ -71,7 +77,8 @@ { "comment": "Testing simple plural, but swap variant order", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", " * {{You deleted {$count} files}}\n", "one {{You deleted {$count} file}}" ], @@ -81,7 +88,8 @@ { "comment": "Testing simple plural, but swap variant order", "src": [ - ".match {$count :number}\n", + ".input {$count :number}\n", + ".match $count\n", " * {{You deleted {$count} files}}\n", "one {{You deleted {$count} file}}" ], @@ -91,7 +99,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -106,7 +115,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -121,7 +131,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -136,7 +147,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -151,7 +163,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -166,7 +179,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -181,7 +195,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -196,7 +211,8 @@ { "comment": "Ordinal, with mixed order and exact matches", "src": [ - ".match {$place :number select=ordinal}\n", + ".input {$place :number select=ordinal}\n", + ".match $place\n", "* {{You finished in the {$place}th place}}\n", "two {{You finished in the {$place}nd place}}\n", "one {{You finished in the {$place}st place}}\n", @@ -211,7 +227,8 @@ { "comment": "Plural combinations, mixed order", "src": [ - ".match {$fileCount :number} {$folderCount :number}\n", + ".input {$fileCount :number} .input {$folderCount :number}\n", + ".match $fileCount $folderCount\n", " * * {{You found {$fileCount} files in {$folderCount} folders}}\n", " one one {{You found {$fileCount} file in {$folderCount} folder}}\n", " one * {{You found {$fileCount} file in {$folderCount} folders}}\n", @@ -224,7 +241,8 @@ { "comment": "Plural combinations, mixed order", "src": [ - ".match {$fileCount :number} {$folderCount :number}\n", + ".input {$fileCount :number} .input {$folderCount :number}\n", + ".match $fileCount $folderCount\n", " * * {{You found {$fileCount} files in {$folderCount} folders}}\n", " one one {{You found {$fileCount} file in {$folderCount} folder}}\n", " one * {{You found {$fileCount} file in {$folderCount} folders}}\n", @@ -237,7 +255,8 @@ { "comment": "Plural combinations, mixed order", "src": [ - ".match {$fileCount :number} {$folderCount :number}\n", + ".input {$fileCount :number} .input {$folderCount :number}\n", + ".match $fileCount $folderCount\n", " * * {{You found {$fileCount} files in {$folderCount} folders}}\n", " one one {{You found {$fileCount} file in {$folderCount} folder}}\n", " one * {{You found {$fileCount} file in {$folderCount} folders}}\n", @@ -250,7 +269,8 @@ { "comment": "Plural combinations, mixed order", "src": [ - ".match {$fileCount :number} {$folderCount :number}\n", + ".input {$fileCount :number} .input {$folderCount :number}\n", + ".match $fileCount $folderCount\n", " * * {{You found {$fileCount} files in {$folderCount} folders}}\n", " one one {{You found {$fileCount} file in {$folderCount} folder}}\n", " one * {{You found {$fileCount} file in {$folderCount} folders}}\n", @@ -264,7 +284,7 @@ "comment": "Test that the selection honors the formatting option (`1.00 dollars`)", "src": [ ".local $c = {$price :number minimumFractionDigits=$minF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -276,7 +296,7 @@ "comment": "Test that the selection honors the formatting option (`1.00 dollars`)", "src": [ ".local $c = {$price :number minimumFractionDigits=$minF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -288,7 +308,7 @@ "comment": "Test that the selection honors the formatting option (`1.00 dollars`)", "src": [ ".local $c = {$price :number maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -300,7 +320,7 @@ "comment": "Test that the selection honors the formatting option (`1.00 dollars`)", "src": [ ".local $c = {$price :number maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -312,7 +332,7 @@ "comment": "Test that the selection honors the `:integer` over options", "src": [ ".local $c = {$price :integer maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -324,7 +344,7 @@ "comment": "Test that the selection honors the `:integer` over options", "src": [ ".local $c = {$price :integer maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -336,7 +356,7 @@ "comment": "Test that the selection honors the `:integer` over options", "src": [ ".local $c = {$price :integer maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -348,7 +368,7 @@ "comment": "Test that the selection honors the `:integer` over options", "src": [ ".local $c = {$price :integer maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], @@ -360,7 +380,7 @@ "comment": "Test that the selection honors the `:integer` over options", "src": [ ".local $c = {$price :integer maximumFractionDigits=$maxF}\n", - ".match {$c}\n", + ".match $c\n", " one {{{$c} dollar}}\n", " * {{{$c} dollars}}" ], diff --git a/testdata/message2/matches-whitespace.json b/testdata/message2/matches-whitespace.json index a0af4c4d143e..b87eb526beae 100644 --- a/testdata/message2/matches-whitespace.json +++ b/testdata/message2/matches-whitespace.json @@ -5,30 +5,19 @@ "locale": "en-US" }, "tests": [ - { "src": ".match {one :string} {bar :string} one * {{one}} * * {{other}}", - "exp": "one" }, - { "src": ".match {foo :string} {bar :string}one * {{one}} * * {{other}}", - "exp": "other" - }, - { "src": ".match {foo :string}{bar :string} one * {{one}} * * {{other}}", - "exp": "other" - }, - { "src": ".match {one :string}{bar :string}one * {{one}} * * {{other}}", - "exp": "one" + { "src": ".local $one = {1 :string} .local $bar = {bar :string} .match $one $bar one * {{one}} * * {{other}}", + "exp": "one", + "ignoreJava": "Unclear why this would be an error?" }, - { "src": ".match{foo :string} {bar :string} one * {{one}} * * {{other}}", + { "src": ".local $foo = {foo :string} .local $bar = {bar :string} .match $foo $bar one * {{one}}* * {{other}}", "exp": "other" }, - { "src": ".match {foo :string} {bar :string} one * {{one}}* * {{other}}", - "exp": "other" }, - { "src": ".match {foo :string} {bar :string}one * {{one}}* * {{other}}", - "exp": "other" - }, - { "src": ".match {foo :string} {bar :string} one *{{one}} * * {{foo}}", + { "src": ".local $foo = {foo :string} .local $bar = {bar :string} .match $foo $bar one *{{one}} * * {{foo}}", "exp": "foo" }, - { "src": ".match {foo :string} {bar :string} one * {{one}} * * {{foo}}", - "exp": "foo" } + { "src": ".local $foo = {foo :string} .local $bar = {bar :string} .match $foo $bar one * {{one}} * * {{foo}}", + "exp": "foo" + } ] } diff --git a/testdata/message2/more-data-model-errors.json b/testdata/message2/more-data-model-errors.json index 32744083af1c..36b528bc2715 100644 --- a/testdata/message2/more-data-model-errors.json +++ b/testdata/message2/more-data-model-errors.json @@ -5,7 +5,7 @@ }, "tests": [ { - "src": ".match {$foo :number} {$bar :number} one{{one}}", + "src": ".input {$foo :number} .input {$bar :number} .match $foo $bar one{{one}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -14,7 +14,7 @@ }, { - "src": ".match {$foo :number} {$bar :number} one {{one}}", + "src": ".input {$foo :number} .input {$bar :number} .match $foo $bar one {{one}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -23,7 +23,7 @@ }, { - "src": ".match {$foo :number} {$bar :number} one {{one}}", + "src": ".input {$foo :number} .input {$bar :number} .match $foo $bar one {{one}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -32,7 +32,7 @@ }, { - "src": ".match {$foo :number} * * {{foo}}", + "src": ".input {$foo :number} .match $foo * * {{foo}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -41,7 +41,7 @@ }, { - "src": ".match {$one :number}\n 1 2 {{Too many}}\n * {{Otherwise}}", + "src": ".input {$one :number} .match $one\n 1 2 {{Too many}}\n * {{Otherwise}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -50,7 +50,7 @@ }, { - "src": ".match {$one :number} {$two :number}\n 1 2 {{Two keys}}\n * {{Missing a key}}\n * * {{Otherwise}}", + "src": ".input {$one :number} .input {$two :number} .match $one $two \n 1 2 {{Two keys}}\n * {{Missing a key}}\n * * {{Otherwise}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -59,7 +59,7 @@ }, { - "src": ".match {$foo :x} {$bar :x} * {{foo}}", + "src": ".input {$foo :x} .input {$bar :X} .match $foo $bar * {{foo}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -68,7 +68,7 @@ }, { - "src": ".match {$one :number}\n 1 {{Value is one}}\n 2 {{Value is two}}", + "src": ".input {$one :number} .match $one\n 1 {{Value is one}}\n 2 {{Value is two}}", "expErrors": [ { "type": "missing-fallback-variant" @@ -77,7 +77,7 @@ }, { - "src": ".match {$one :number} {$two :number}\n 1 * {{First is one}}\n * 1 {{Second is one}}", + "src": ".input {$one :number} .input {$two :number} .match $one $two\n 1 * {{First is one}}\n * 1 {{Second is one}}", "expErrors": [ { "type": "missing-fallback-variant" @@ -86,7 +86,7 @@ }, { - "src": ".match {$one}\n 1 {{Value is one}}\n * {{Value is not one}}", + "src": ".match $one\n 1 {{Value is one}}\n * {{Value is not one}}", "expErrors": [ { "type": "missing-selector-annotation" @@ -95,7 +95,7 @@ }, { - "src": ".local $one = {|The one|}\n .match {$one}\n 1 {{Value is one}}\n * {{Value is not one}}", + "src": ".local $one = {|The one|}\n .match $one\n 1 {{Value is one}}\n * {{Value is not one}}", "expErrors": [ { "type": "missing-selector-annotation" @@ -103,7 +103,7 @@ ] }, { - "src": ".input {$foo} .match {$foo} one {{one}} * {{other}}", + "src": ".input {$foo} .match $foo one {{one}} * {{other}}", "expErrors": [ { "type": "missing-selector-annotation" @@ -112,7 +112,7 @@ }, { - "src": ".local $foo = {$bar} .match {$foo} one {{one}} * {{other}}", + "src": ".local $foo = {$bar} .match $foo one {{one}} * {{other}}", "expErrors": [ { "type": "missing-selector-annotation" diff --git a/testdata/message2/resolution-errors.json b/testdata/message2/resolution-errors.json index 8f1ac2fb9364..736e1cb64f05 100644 --- a/testdata/message2/resolution-errors.json +++ b/testdata/message2/resolution-errors.json @@ -7,8 +7,8 @@ "tests": [ { "src": "{$oops}", "exp": "{$oops}", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "ICU4J doesn't signal unresolved variable errors?"}, { "src": ".input {$x :number} {{{$x}}}", "exp": "{$x}", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"}, - { "src": ".local $foo = {$bar} .match {$foo :number} one {{one}} * {{other}}", "exp": "other", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"}, - { "src": ".local $bar = {$none :number} .match {$foo :string} one {{one}} * {{{$bar}}}", "exp": "{$none}", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"}, + { "src": ".local $foo = {$bar} .local $f = {$foo :number} .match $f one {{one}} * {{other}}", "exp": "other", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"}, + { "src": ".local $bar = {$none :number} .local $f = {$foo :string} .match $f one {{one}} * {{{$bar}}}", "exp": "{$none}", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"}, { "src": "The value is {horse :func}.", "exp": "The value is {|horse|}.", "expErrors": [{ "type": "unknown-function" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"} ] } diff --git a/testdata/message2/runtime-errors.json b/testdata/message2/runtime-errors.json index b1bb0cd491a0..ffeb081fab0d 100644 --- a/testdata/message2/runtime-errors.json +++ b/testdata/message2/runtime-errors.json @@ -6,19 +6,19 @@ }, "tests": [ { - "src": ".match {|horse| :date}\n 1 {{The value is one.}}\n * {{Formatter used as selector.}}", + "src": ".local $h = {|horse| :date} .match $h\n 1 {{The value is one.}}\n * {{Formatter used as selector.}}", "exp": "Formatter used as selector.", "expErrors": [{"type": "bad-selector"}], "ignoreJava": "ICU4J doesn't signal runtime errors?" }, { - "src": ".match {|horse| :number}\n 1 {{The value is one.}}\n * {{horse is not a number.}}", + "src": ".local $h = {|horse| :number} .match $h\n 1 {{The value is one.}}\n * {{horse is not a number.}}", "exp": "horse is not a number.", "expErrors": [{"type": "bad-selector"}], "ignoreJava": "ICU4J doesn't signal runtime errors?" }, { - "src": ".local $sel = {|horse| :number}\n .match {$sel}\n 1 {{The value is one.}}\n * {{horse is not a number.}}", + "src": ".local $sel = {|horse| :number}\n .match $sel\n 1 {{The value is one.}}\n * {{horse is not a number.}}", "exp": "horse is not a number.", "expErrors": [{"type": "bad-selector"}], "ignoreJava": "ICU4J doesn't signal runtime errors?" diff --git a/testdata/message2/spec/data-model-errors.json b/testdata/message2/spec/data-model-errors.json index 86a674c43961..3c23be5fbec6 100644 --- a/testdata/message2/spec/data-model-errors.json +++ b/testdata/message2/spec/data-model-errors.json @@ -6,7 +6,7 @@ }, "tests": [ { - "src": ".match {$foo :x} * * {{foo}}", + "src": ".input {$foo :x} .match $foo * * {{foo}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -14,7 +14,7 @@ ] }, { - "src": ".match {$foo :x} {$bar :x} * {{foo}}", + "src": ".input {$foo :x} .input {$bar :x} .match $foo $bar * {{foo}}", "expErrors": [ { "type": "variant-key-mismatch" @@ -22,7 +22,7 @@ ] }, { - "src": ".match {:foo} 1 {{_}}", + "src": ".input {$foo :x} .match $foo 1 {{_}}", "expErrors": [ { "type": "missing-fallback-variant" @@ -30,7 +30,7 @@ ] }, { - "src": ".match {:foo} other {{_}}", + "src": ".input {$foo :x} .match $foo other {{_}}", "expErrors": [ { "type": "missing-fallback-variant" @@ -38,7 +38,7 @@ ] }, { - "src": ".match {:foo} {:bar} * 1 {{_}} 1 * {{_}}", + "src": ".input {$foo :x} .input {$bar :x} .match $foo $bar * 1 {{_}} 1 * {{_}}", "expErrors": [ { "type": "missing-fallback-variant" @@ -46,7 +46,7 @@ ] }, { - "src": ".match {$foo} one {{one}} * {{other}}", + "src": ".input {$foo} .match $foo one {{one}} * {{other}}", "expErrors": [ { "type": "missing-selector-annotation" @@ -54,7 +54,7 @@ ] }, { - "src": ".input {$foo} .match {$foo} one {{one}} * {{other}}", + "src": ".local $foo = {$bar} .match $foo one {{one}} * {{other}}", "expErrors": [ { "type": "missing-selector-annotation" @@ -62,7 +62,7 @@ ] }, { - "src": ".local $foo = {$bar} .match {$foo} one {{one}} * {{other}}", + "src": ".input {$bar} .local $foo = {$bar} .match $foo one {{one}} * {{other}}", "expErrors": [ { "type": "missing-selector-annotation" @@ -166,7 +166,7 @@ ] }, { - "src": ".match {$var :string} * {{The first default}} * {{The second default}}", + "src": ".input {$var :string} .match $var * {{The first default}} * {{The second default}}", "expErrors": [ { "type": "duplicate-variant" @@ -174,12 +174,17 @@ ] }, { - "src": ".match {$x :string} {$y :string} * foo {{The first foo variant}} bar * {{The bar variant}} * |foo| {{The second foo variant}} * * {{The default variant}}", + "src": ".input {$x :string} .input {$y :string} .match $x $y * foo {{The first foo variant}} bar * {{The bar variant}} * |foo| {{The second foo variant}} * * {{The default variant}}", "expErrors": [ { "type": "duplicate-variant" } ] + }, + { + "src": ".local $star = {star :string} .match $star |*| {{Literal star}} * {{The default}}", + "exp": "The default", + "ignoreJava": "Unclear why would this be an error?" } ] } diff --git a/testdata/message2/spec/functions/date.json b/testdata/message2/spec/functions/date.json index dd14e6785fb6..76ce510dffd3 100644 --- a/testdata/message2/spec/functions/date.json +++ b/testdata/message2/spec/functions/date.json @@ -1,9 +1,10 @@ { + "$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json", "scenario": "Date function", "description": "The built-in formatter for dates.", "defaultTestProperties": { "locale": "en-US", - "expErrors": [] + "expErrors": false }, "tests": [ { diff --git a/testdata/message2/spec/functions/datetime.json b/testdata/message2/spec/functions/datetime.json index bdfea3096cda..f3a8e4f3c939 100644 --- a/testdata/message2/spec/functions/datetime.json +++ b/testdata/message2/spec/functions/datetime.json @@ -1,9 +1,10 @@ { + "$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json", "scenario": "Datetime function", "description": "The built-in formatter for datetimes.", "defaultTestProperties": { "locale": "en-US", - "expErrors": [] + "expErrors": false }, "tests": [ { diff --git a/testdata/message2/spec/functions/integer.json b/testdata/message2/spec/functions/integer.json index c8e75077a221..4ea96941e179 100644 --- a/testdata/message2/spec/functions/integer.json +++ b/testdata/message2/spec/functions/integer.json @@ -19,7 +19,7 @@ "exp": "hello 4" }, { - "src": ".match {$foo :integer} one {{one}} * {{other}}", + "src": ".input {$foo :integer} .match $foo 1 {{one}} * {{other}}", "params": [ { "name": "foo", diff --git a/testdata/message2/spec/functions/number.json b/testdata/message2/spec/functions/number.json index 1b81c705622b..ff62f830b5b5 100644 --- a/testdata/message2/spec/functions/number.json +++ b/testdata/message2/spec/functions/number.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json", "scenario": "Number function", "description": "The built-in formatter for numbers.", "defaultTestProperties": { @@ -219,174 +220,6 @@ ], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }, - { - "src": ".match {$foo :number} one {{one}} * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".match {$foo :number} 1 {{=1}} one {{one}} * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "=1" - }, - { - "src": ".match {$foo :number} one {{one}} 1 {{=1}} * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "=1" - }, - { - "src": ".match {$foo :number} {$bar :number} one one {{one one}} one * {{one other}} * * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - }, - { - "name": "bar", - "value": 1 - } - ], - "exp": "one one" - }, - { - "src": ".match {$foo :number} {$bar :number} one one {{one one}} one * {{one other}} * * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - }, - { - "name": "bar", - "value": 2 - } - ], - "exp": "one other" - }, - { - "src": ".match {$foo :number} {$bar :number} one one {{one one}} one * {{one other}} * * {{other}}", - "params": [ - { - "name": "foo", - "value": 2 - }, - { - "name": "bar", - "value": 2 - } - ], - "exp": "other" - }, - { - "src": ".input {$foo :number} .match {$foo} one {{one}} * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".local $foo = {$bar :number} .match {$foo} one {{one}} * {{other}}", - "params": [ - { - "name": "bar", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".input {$foo :number} .local $bar = {$foo} .match {$bar} one {{one}} * {{other}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".input {$bar :number} .match {$bar} one {{one}} * {{other}}", - "params": [ - { - "name": "bar", - "value": 2 - } - ], - "exp": "other" - }, - { - "src": ".input {$bar} .match {$bar :number} one {{one}} * {{other}}", - "params": [ - { - "name": "bar", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".input {$bar} .match {$bar :number} one {{one}} * {{other}}", - "params": [ - { - "name": "bar", - "value": 2 - } - ], - "exp": "other" - }, - { - "src": ".input {$none} .match {$foo :number} one {{one}} * {{{$none}}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".local $bar = {$none} .match {$foo :number} one {{one}} * {{{$bar}}}", - "params": [ - { - "name": "foo", - "value": 1 - } - ], - "exp": "one" - }, - { - "src": ".local $bar = {$none} .match {$foo :number} one {{one}} * {{{$bar}}}", - "params": [ - { - "name": "foo", - "value": 2 - } - ], - "exp": "{$none}", - "expErrors": [ - { - "type": "unresolved-variable" - } - ], - "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" - }, { "src": "{42 :number @foo @bar=13}", "exp": "42", diff --git a/testdata/message2/spec/functions/string.json b/testdata/message2/spec/functions/string.json index 5858079b99a6..73cbfd55eb1d 100644 --- a/testdata/message2/spec/functions/string.json +++ b/testdata/message2/spec/functions/string.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json", "scenario": "String function", "description": "The built-in formatter for strings.", "defaultTestProperties": { @@ -6,7 +7,7 @@ }, "tests": [ { - "src": ".match {$foo :string} |1| {{one}} * {{other}}", + "src": ".input {$foo :string} .match $foo |1| {{one}} * {{other}}", "params": [ { "name": "foo", @@ -16,7 +17,7 @@ "exp": "one" }, { - "src": ".match {$foo :string} 1 {{one}} * {{other}}", + "src": ".input {$foo :string} .match $foo 1 {{one}} * {{other}}", "params": [ { "name": "foo", @@ -27,7 +28,7 @@ "ignoreJava": ":string doesn't stringify numbers?" }, { - "src": ".match {$foo :string} 1 {{one}} * {{other}}", + "src": ".input {$foo :string} .match $foo 1 {{one}} * {{other}}", "params": [ { "name": "foo", @@ -35,10 +36,10 @@ } ], "exp": "other", - "ignoreCpp": "Can't handle null value for input variable" + "ignoreCpp": "Explicit null doesn't work" }, { - "src": ".match {$foo :string} 1 {{one}} * {{other}}", + "src": ".input {$foo :string} .match $foo 1 {{one}} * {{other}}", "exp": "other", "expErrors": [ { diff --git a/testdata/message2/spec/functions/time.json b/testdata/message2/spec/functions/time.json index 845934a5e16a..89adf5fb79d3 100644 --- a/testdata/message2/spec/functions/time.json +++ b/testdata/message2/spec/functions/time.json @@ -1,9 +1,10 @@ { + "$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json", "scenario": "Time function", "description": "The built-in formatter for times.", "defaultTestProperties": { "locale": "en-US", - "expErrors": [] + "expErrors": false }, "tests": [ { diff --git a/testdata/message2/spec/pattern-selection.json b/testdata/message2/spec/pattern-selection.json new file mode 100644 index 000000000000..29dc146c1907 --- /dev/null +++ b/testdata/message2/spec/pattern-selection.json @@ -0,0 +1,120 @@ +{ + "$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json", + "scenario": "Pattern selection", + "description": "Tests for pattern selection", + "defaultTestProperties": { + "locale": "und" + }, + "tests": [ + { + "src": ".local $x = {1 :test:select} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "1" + }, + { + "src": ".local $x = {0 :test:select} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "other" + }, + { + "src": ".input {$x :test:select} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "params": [{ "name": "x", "value": 1 }], + "exp": "1" + }, + { + "src": ".input {$x :test:select} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "params": [{ "name": "x", "value": 2 }], + "exp": "other" + }, + { + "src": ".input {$x :test:select} .local $y = {$x} .match $y 1.0 {{1.0}} 1 {{1}} * {{other}}", + "params": [{ "name": "x", "value": 1 }], + "exp": "1" + }, + { + "src": ".input {$x :test:select} .local $y = {$x} .match $y 1.0 {{1.0}} 1 {{1}} * {{other}}", + "params": [{ "name": "x", "value": 2 }], + "exp": "other" + }, + { + "src": ".local $x = {1 :test:select decimalPlaces=1} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "1.0" + }, + { + "src": ".local $x = {1 :test:select decimalPlaces=1} .match $x 1 {{1}} 1.0 {{1.0}} * {{other}}", + "exp": "1.0" + }, + { + "src": ".local $x = {1 :test:select decimalPlaces=9} .match $x 1.0 {{1.0}} 1 {{1}} * {{bad-option-value}}", + "exp": "bad-option-value", + "expErrors": [{ "type": "bad-option" }, { "type": "bad-selector" }] + }, + { + "src": ".input {$x :test:select} .local $y = {$x :test:select decimalPlaces=1} .match $y 1.0 {{1.0}} 1 {{1}} * {{other}}", + "params": [{ "name": "x", "value": 1 }], + "exp": "1.0" + }, + { + "src": ".input {$x :test:select decimalPlaces=1} .local $y = {$x :test:select} .match $y 1.0 {{1.0}} 1 {{1}} * {{other}}", + "params": [{ "name": "x", "value": 1 }], + "exp": "1.0" + }, + { + "src": ".input {$x :test:select decimalPlaces=9} .local $y = {$x :test:select decimalPlaces=1} .match $y 1.0 {{1.0}} 1 {{1}} * {{bad-option-value}}", + "params": [{ "name": "x", "value": 1 }], + "exp": "bad-option-value", + "expErrors": [ + { "type": "bad-option" }, + { "type": "bad-operand" }, + { "type": "bad-selector" } + ] + }, + { + "src": ".local $x = {1 :test:select fails=select} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "other", + "expErrors": [{ "type": "bad-selector" }] + }, + { + "src": ".local $x = {1 :test:select fails=format} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "1" + }, + { + "src": ".local $x = {1 :test:format} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "other", + "expErrors": [{ "type": "bad-selector" }] + }, + { + "src": ".input {$x :test:select} .match $x 1.0 {{1.0}} 1 {{1}} * {{other}}", + "exp": "other", + "expErrors": [ + { "type": "unresolved-variable" }, + { "type": "bad-operand" }, + { "type": "bad-selector" } + ] + }, + { + "src": ".local $x = {1 :test:select} .local $y = {1 :test:select} .match $x $y 1 1 {{1,1}} 1 * {{1,*}} * 1 {{*,1}} * * {{*,*}}", + "exp": "1,1" + }, + { + "src": ".local $x = {1 :test:select} .local $y = {0 :test:select} .match $x $y 1 1 {{1,1}} 1 * {{1,*}} * 1 {{*,1}} * * {{*,*}}", + "exp": "1,*" + }, + { + "src": ".local $x = {0 :test:select} .local $y = {1 :test:select} .match $x $y 1 1 {{1,1}} 1 * {{1,*}} * 1 {{*,1}} * * {{*,*}}", + "exp": "*,1" + }, + { + "src": ".local $x = {0 :test:select} .local $y = {0 :test:select} .match $x $y 1 1 {{1,1}} 1 * {{1,*}} * 1 {{*,1}} * * {{*,*}}", + "exp": "*,*" + }, + { + "src": ".local $x = {1 :test:select fails=select} .local $y = {1 :test:select} .match $x $y 1 1 {{1,1}} 1 * {{1,*}} * 1 {{*,1}} * * {{*,*}}", + "exp": "*,1", + "expErrors": [{ "type": "bad-selector" }] + }, + { + "src": ".local $x = {1 :test:select} .local $y = {1 :test:format} .match $x $y 1 1 {{1,1}} 1 * {{1,*}} * 1 {{*,1}} * * {{*,*}}", + "exp": "1,*", + "expErrors": [{ "type": "bad-selector" }] + } + ] +} diff --git a/testdata/message2/spec/syntax-errors.json b/testdata/message2/spec/syntax-errors.json index 34d9aa484572..ecaab10ea761 100644 --- a/testdata/message2/spec/syntax-errors.json +++ b/testdata/message2/spec/syntax-errors.json @@ -122,6 +122,10 @@ { "src": "bad {:placeholder @attribute=@foo}" }, + { + "src": "bad {:placeholder @attribute=$foo}", + "ignoreJava": "Unclear why would this be an error?" + }, { "src": "{ @misplaced = attribute }" }, @@ -155,26 +159,90 @@ { "src": ".local $bar = |foo| {{_}}" }, - { - "src": ".match {#foo} * {{foo}}" - }, - { - "src": ".match {} * {{foo}}" - }, - { - "src": ".match {|foo| :x} {|bar| :x} ** {{foo}}" - }, - { - "src": ".match * {{foo}}" - }, - { - "src": ".match {|x| :x} * foo" - }, - { - "src": ".match {|x| :x} * {{foo}} extra" - }, - { - "src": ".match |x| * {{foo}}" - } + { "src": ".match {{foo}}" }, + { "src": ".match * {{foo}}" }, + { "src": ".match x * {{foo}}" }, + { "src": ".match |x| * {{foo}}" }, + { "src": ".match :x * {{foo}}" }, + { "src": ".match {$foo} * {{foo}}" }, + { "src": ".match {#foo} * {{foo}}" }, + { "src": ".input {$x :x} .match {$x} * {{foo}}" }, + { "src": ".input {$x :x} .match$x * {{foo}}" }, + { "src": ".input {$x :x} .match $x* {{foo}}" }, + { "src": ".input {$x :x} .match $x|x| {{foo}} * {{foo}}" }, + { "src": ".input {$x :x} .local $y = {y :y} .match $x$y * * {{foo}}" }, + { "src": ".input {$x :x} .local $y = {y :y} .match $x $y ** {{foo}}" }, + { "src": ".input {$x :x} .match $x" }, + { "src": ".input {$x :x} .match $x *" }, + { "src": ".input {$x :x} .match $x * foo" }, + { "src": ".input {$x :x} .match $x * {{foo}} extra" }, + { "src": ".n{a}{{}}" }, + { "src": "{^}" }, + { "src": "{!}" }, + { "src": ".n .{a}{{}}" }, + { "src": ".n. {a}{{}}" }, + { "src": ".n.{a}{b}{{}}" }, + { "src": "{!.}" }, + { "src": "{! .}" }, + { "src": "{%}" }, + { "src": "{*}" }, + { "src": "{+}" }, + { "src": "{<}" }, + { "src": "{>}" }, + { "src": "{?}" }, + { "src": "{~}" }, + { "src": "{^.}" }, + { "src": "{^ .}" }, + { "src": "{&}" }, + { "src": "{!.\\{}" }, + { "src": "{!. \\{}" }, + { "src": "{!|a|}" }, + { "src": "foo {+reserved}" }, + { "src": "foo {&private}" }, + { "src": "foo {?reserved @a @b=c}" }, + { "src": ".foo {42} {{bar}}" }, + { "src": ".foo{42}{{bar}}" }, + { "src": ".foo |}lit{| {42}{{bar}}" }, + { "src": ".i {1} {{}}" }, + { "src": ".l $y = {|bar|} {{}}" }, + { "src": ".l $x.y = {|bar|} {{}}" }, + { "src": "hello {|4.2| %number}" }, + { "src": "hello {|4.2| %n|um|ber}" }, + { "src": "{+42}" }, + { "src": "hello {|4.2| &num|be|r}" }, + { "src": "hello {|4.2| ^num|be|r}" }, + { "src": "hello {|4.2| +num|be|r}" }, + { "src": "hello {|4.2| ?num|be||r|s}" }, + { "src": "hello {|foo| !number}" }, + { "src": "hello {|foo| *number}" }, + { "src": "hello {?number}" }, + { "src": "{xyzz }" }, + { "src": "hello {$foo ~xyzz }" }, + { "src": "hello {$x xyzz }" }, + { "src": "{ !xyzz }" }, + { "src": "{~xyzz }" }, + { "src": "{ num x \\\\ abcde |aaa||3.14||42| r }" }, + { "src": "hello {$foo >num x \\\\ abcde |aaa||3.14| |42| r }" }, + { "src" : ".input{ $n ~ }{{{$n}}}" } ] } diff --git a/testdata/message2/spec/syntax.json b/testdata/message2/spec/syntax.json index 558fc64062b4..436146df4749 100644 --- a/testdata/message2/spec/syntax.json +++ b/testdata/message2/spec/syntax.json @@ -26,6 +26,11 @@ "src": "\\\\", "exp": "\\" }, + { + "description": "message -> simple-message -> simple-start pattern -> 1*escaped-char", + "src": "\\\\\\{\\|\\}", + "exp": "\\{|}" + }, { "description": "message -> simple-message -> simple-start pattern -> simple-start-char pattern -> ... -> simple-start-char *text-char placeholder", "src": "hello {world}", @@ -173,8 +178,8 @@ "exp": "" }, { - "description": "message -> complex-message -> complex-body -> matcher -> match-statement variant -> match selector key quoted-pattern -> \".match\" expression literal quoted-pattern", - "src": ".match{a :f}a{{}}*{{}}", + "description": "message -> complex-message -> complex-body -> ... -> matcher -> match-statement variant -> match selector key quoted-pattern -> \".match\" variable literal quoted-pattern", + "src": ".local $a={a :f}.match $a a{{}}*{{}}", "exp": "", "expErrors": [ { "type": "unknown-function" } ], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" @@ -199,39 +204,61 @@ "src": ".local $x = {a}{{}}", "exp": "" }, + { + "description": "input-declaration-like content in complex-message", + "src": "{{.input {$x}}}", + "params": [{ "name": "x", "value": "X" }], + "exp": ".input X" + }, + { + "description": "local-declaration-like content in complex-message with leading whitespace", + "src": "{{ .local $x = {$y}}}", + "params": [{ "name": "y", "value": "Y" }], + "exp": " .local $x = Y" + }, { "description": "... matcher -> match-statement [s] variant -> match 1*([s] selector) variant -> match selector selector variant -> match selector selector variant key s key quoted-pattern", - "src": ".match{a :f}{b :f}a b{{}}* *{{}}", + "src": ".local $a={a :f}.local $b={b :f}.match $a $b a b{{}}* *{{}}", "exp": "", - "expErrors": [ { "type": "unknown-function" } ], + "expErrors": [ + { "type": "unknown-function" }, + { "type": "bad-selector" }, + { "type": "unknown-function" }, + { "type": "bad-selector" } + ], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }, { "description": "... matcher -> match-statement [s] variant -> match 1*([s] selector) variant -> match selector variant variant ...", - "src": ".match{a :f}a{{}}b{{}}*{{}}", + "src": ".local $a={a :f}.match $a a{{}}b{{}}*{{}}", "exp": "", - "expErrors": [ { "type": "unknown-function" } ], + "expErrors": [{ "type": "unknown-function" }, { "type": "bad-selector" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }, { "description": "... variant -> key s quoted-pattern -> ...", - "src": ".match{a :f}a {{}}*{{}}", + "src": ".local $a={a :f}.match $a a {{}}*{{}}", "exp": "", - "expErrors": [ { "type": "unknown-function" } ], + "expErrors": [{ "type": "unknown-function" }, { "type": "bad-selector" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }, { "description": "... variant -> key s key s quoted-pattern -> ...", - "src": ".match{a :f}{b :f}a b {{}}* *{{}}", + "src": ".local $a={a :f}.local $b={b :f}.match $a $b a b {{}}* *{{}}", "exp": "", - "expErrors": [ { "type": "unknown-function" } ], + "expErrors": [ + { "type": "unknown-function" }, + { "type": "bad-selector" }, + { "type": "unknown-function" }, + { "type": "bad-selector" } + ], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }, { "description": "... key -> \"*\" ...", - "src": ".match{a :f}*{{}}", + "src": ".local $a={a :f}.match $a *{{}}", "exp": "", - "expErrors": [ { "type": "unknown-function" } ], + "expErrors": [{ "type": "unknown-function" }, { "type": "bad-selector" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }, { @@ -405,8 +432,8 @@ "exp": "a" }, { - "description": "... attribute -> \"@\" identifier s \"=\" s variable ...", - "src": "{42 @foo=$bar}", + "description": "... attribute -> \"@\" identifier s \"=\" s quoted-literal ...", + "src": "{42 @foo=|bar|}", "exp": "42", "expParts": [ { @@ -432,9 +459,9 @@ "exp": "\\" }, { - "description": "... quoted-literal -> \"|\" quoted-char escaped-char \"|\"", - "src": "{|a\\\\|}", - "exp": "a\\" + "description": "... quoted-literal -> \"|\" quoted-char 1*escaped-char \"|\"", + "src": "{|a\\\\\\{\\|\\}|}", + "exp": "a\\{|}" }, { "description": "... unquoted-literal -> number-literal -> %x30", diff --git a/testdata/message2/valid-tests.json b/testdata/message2/valid-tests.json index 4b1ce8d67fb6..0f062116b733 100644 --- a/testdata/message2/valid-tests.json +++ b/testdata/message2/valid-tests.json @@ -141,7 +141,7 @@ }, { "comment": "Trailing whitespace after match is valid", - "src": ".match {1 :string} * {{}} ", + "src": ".local $x = {1 :string} .match $x * {{}} ", "exp": "" }, {