icu/testdata/message2/spec/syntax.json
Tim Chevalier d0e30acc68 ICU-23059 ICU4C MF2: Spec test updates
Update spec tests to current version from message-format-wg

  - Update parser for changed name-start grammar rule
  - Validate number literals in :number implementation (since parser no longer does this)
  - Disallow `:number`/`:integer` select option set from variable

    See https://github.com/unicode-org/message-format-wg/pull/1016

    As part of this, un-skip tests where the `bad-option` error is
    expected, and implement validating digit size options
    (pending PR https://github.com/unicode-org/icu/pull/2973 is intended
    to do this more fully)
2025-03-27 15:20:49 -07:00

775 lines
22 KiB
JSON

{
"$schema": "https://raw.githubusercontent.com/unicode-org/message-format-wg/main/test/schemas/v0/tests.schema.json",
"scenario": "Syntax",
"description": "Test cases that do not depend on any registry definitions.",
"defaultTestProperties": {
"bidiIsolation": "none",
"locale": "en-US"
},
"tests": [
{
"description": "message -> simple-message -> <empty>",
"src": "",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> simple-start-char",
"src": "a",
"exp": "a"
},
{
"description": "message -> simple-message -> simple-start pattern -> simple-start-char pattern -> ...",
"src": "hello",
"exp": "hello"
},
{
"description": "message -> simple-message -> simple-start pattern -> escaped-char",
"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}",
"exp": "hello world"
},
{
"description": "message -> simple-message -> simple-start pattern -> simple-start-char pattern -> ... -> simple-start-char *text-char placeholder",
"src": "hello {|world|}",
"exp": "hello world"
},
{
"description": "message -> simple-message -> s simple-start pattern -> s simple-start-char pattern -> ...",
"src": "\n hello\t",
"exp": "\n hello\t"
},
{
"src": "hello {$place}",
"params": [
{
"name": "place",
"value": "world"
}
],
"exp": "hello world"
},
{
"src": "hello {$place-.}",
"params": [
{
"name": "place-.",
"value": "world"
}
],
"exp": "hello world"
},
{
"src": "hello {$place}",
"expErrors": [
{
"type": "unresolved-variable"
}
],
"exp": "hello {$place}"
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> expression -> literal-expression -> \"{\" literal \"}\"",
"src": "{a}",
"exp": "a"
},
{
"description": "... -> literal-expression -> \"{\" literal s annotation \"}\" -> \"{\" literal s function \"}\" -> \"{\" literal s \":\" identifier \"}\" -> \"{\" literal s \":\" name \"}\"",
"src": "{a :f}",
"exp": "{|a|}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... -> \"{\" literal s \":\" namespace \":\" name \"}\"",
"src": "{a :u:f}",
"exp": "{|a|}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> expression -> variable-expression -> \"{\" variable \"}\"",
"src": "{$x}",
"exp": "{$x}",
"expErrors": [{ "type": "unresolved-variable" }]
},
{
"description": "... -> variable-expression -> \"{\" variable s annotation \"}\" -> \"{\" variable s function \"}\" -> \"{\" variable s \":\" identifier \"}\" -> \"{\" variable s \":\" name \"}\"",
"src": "{$x :f}",
"exp": "{$x}",
"expErrors": [{ "type": "unresolved-variable" }, { "type": "unknown-function" }]
},
{
"description": "... -> \"{\" variable s \":\" namespace \":\" name \"}\"",
"src": "{$x :u:f}",
"exp": "{$x}",
"expErrors": [{ "type": "unresolved-variable" }, { "type": "unknown-function" }]
},
{
"description": "... -> annotation-expression -> function -> \"{\" \":\" namespace \":\" name \"}\"",
"src": "{:u:f}",
"exp": "{:u:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... -> annotation-expression -> function -> \"{\" \":\" name \"}\"",
"src": "{:f}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "message -> complex-message -> complex-body -> quoted-pattern -> \"{{\" pattern \"}}\" -> \"{{\"\"}}\"",
"src": "{{}}",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"#\" identifier \"}\"",
"src": "{#tag}",
"exp": "",
"expParts": [
{
"type": "markup",
"kind": "open",
"name": "tag"
}
]
},
{
"description": "message -> complex-message -> *(declaration [s]) complex-body -> declaration complex-body -> input-declaration complex-body -> input variable-expression complex-body",
"src": ".input{$x}{{}}",
"exp": ""
},
{
"description": "message -> complex-message -> s *(declaration [s]) complex-body s -> s declaration complex-body s -> s input-declaration complex-body s -> s input variable-expression complex-body s",
"src": "\t.input{$x}{{}}\n",
"exp": ""
},
{
"description": "message -> complex-message -> *(declaration [s]) complex-body -> declaration declaration complex-body -> input-declaration input-declaration complex-body -> input variable-expression input variable-expression complex-body",
"src": ".input{$x}.input{$y}{{}}",
"exp": ""
},
{
"description": "message -> complex-message -> *(declaration [s]) complex-body -> declaration s declaration complex-body -> input-declaration s input-declaration complex-body -> input variable-expression s input variable-expression complex-body",
"src": ".input{$x} .input{$y}{{}}",
"exp": ""
},
{
"description": "message -> complex-message -> s *(declaration [s]) complex-body s -> s complex-body s",
"src": " {{}} ",
"exp": ""
},
{
"description": "message -> complex-message -> *(declaration [s]) complex-body -> declaration declaration complex-body -> local-declaration input-declaration complex-body -> local s variable [s] \"=\" [s] expression input variable-expression complex-body",
"src": ".local $x ={a}.input{$y}{{}}",
"exp": ""
},
{
"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" }, { "type": "bad-selector" }]
},
{
"description": "... input-declaration -> input s variable-expression ...",
"src": ".input {$x}{{}}",
"exp": ""
},
{
"description": "... local-declaration -> local s variable s \"=\" expression ...",
"src": ".local $x ={a}{{}}",
"exp": ""
},
{
"description": "... local-declaration -> local s variable \"=\" s expression ...",
"src": ".local $x= {a}{{}}",
"exp": ""
},
{
"description": "... local-declaration -> local s variable s \"=\" expression ...",
"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": ".local $a={a :f}.local $b={b :f}.match $a $b a b{{}}* *{{}}",
"exp": "",
"expErrors": [
{ "type": "unknown-function" },
{ "type": "bad-selector" },
{ "type": "unknown-function" },
{ "type": "bad-selector" }
]
},
{
"description": "... matcher -> match-statement [s] variant -> match 1*([s] selector) variant -> match selector variant variant ...",
"src": ".local $a={a :f}.match $a a{{}}b{{}}*{{}}",
"exp": "",
"expErrors": [{ "type": "unknown-function" }, { "type": "bad-selector" }]
},
{
"description": "... variant -> key s quoted-pattern -> ...",
"src": ".local $a={a :f}.match $a a {{}}*{{}}",
"exp": "",
"expErrors": [{ "type": "unknown-function" }, { "type": "bad-selector" }]
},
{
"description": "... variant -> key s key s quoted-pattern -> ...",
"src": ".local $a={a :f}.local $b={b :f}.match $a $b a b {{}}* *{{}}",
"exp": "",
"expErrors": [
{ "type": "unknown-function" },
{ "type": "bad-selector" },
{ "type": "unknown-function" },
{ "type": "bad-selector" }
]
},
{
"description": "... key -> \"*\" ...",
"src": ".local $a={a :f}.match $a *{{}}",
"exp": "",
"expErrors": [{ "type": "unknown-function" }, { "type": "bad-selector" }]
},
{
"description": "simple-message -> simple-start pattern -> placeholder -> expression -> literal-expression -> \"{\" s literal \"}\"",
"src": "{ a}",
"exp": "a"
},
{
"description": "... literal-expression -> \"{\" literal s attribute \"}\" -> \"{\" literal s \"@\" identifier \"}\"",
"src": "{a @c}",
"exp": "a"
},
{
"description": "... -> literal-expression -> \"{\" literal s \"}\"",
"src": "{a }",
"exp": "a"
},
{
"description": "simple-message -> simple-start pattern -> placeholder -> expression -> variable-expression -> \"{\" s variable \"}\"",
"src": "{ $x}",
"exp": "{$x}",
"expErrors": [{ "type": "unresolved-variable" }]
},
{
"description": "... variable-expression -> \"{\" variable s attribute \"}\" -> \"{\" variable s \"@\" identifier \"}\"",
"src": "{$x @c}",
"exp": "{$x}",
"expErrors": [{ "type": "unresolved-variable" }]
},
{
"description": "... -> variable-expression -> \"{\" variable s \"}\"",
"src": "{$x }",
"exp": "{$x}",
"expErrors": [{ "type": "unresolved-variable" }]
},
{
"description": "simple-message -> simple-start pattern -> placeholder -> expression -> annotation-expression -> \"{\" s annotation \"}\"",
"src": "{ :f}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... annotation-expression -> \"{\" annotation s attribute \"}\" -> \"{\" annotation s \"@\" identifier \"}\"",
"src": "{:f @c}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... -> annotation-expression -> \"{\" annotation s \"}\"",
"src": "{:f }",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" s \"#\" identifier \"}\"",
"src": "{ #a}",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"#\" identifier option \"}\" -> \"{\" \"#\" identifier identifier \"=\" literal \"}\"",
"src": "{#tag foo=bar}",
"exp": "",
"expParts": [
{
"type": "markup",
"kind": "open",
"name": "tag",
"options": {
"foo": "bar"
}
}
]
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"#\" identifier attribute \"}\" -> \"{\" \"#\" identifier identifier \"=\" literal \"}\"",
"src": "{#a @c}",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"#\" identifier s \"}\" -> \"{\" \"#\" identifier identifier \"=\" literal \"}\"",
"src": "{#a }",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"#\" identifier \"/\" \"}\" -> \"{\" \"#\" identifier identifier \"=\" literal \"}\"",
"src": "{#a/}",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"/\" identifier \"}\"",
"src": "{/a}",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" s \"/\" identifier \"}\"",
"src": "{ /a}",
"exp": ""
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"/\" identifier option \"}\"",
"src": "{/tag foo=bar}",
"exp": "",
"expParts": [
{
"type": "markup",
"kind": "close",
"name": "tag",
"options": {
"foo": "bar"
}
}
]
},
{
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" \"/\" identifier s \"}\"",
"src": "{/a }",
"exp": ""
},
{
"description": "... annotation-expression -> function -> \":\" identifier option",
"src": "{:f k=v}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... option -> identifier s \"=\" literal",
"src": "{:f k =v}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... option -> identifier \"=\" s literal",
"src": "{:f k= v}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... option -> identifier s \"=\" s literal",
"src": "{:f k = v}",
"exp": "{:f}",
"expErrors": [{ "type": "unknown-function" }]
},
{
"description": "... attribute -> \"@\" identifier \"=\" literal ...",
"src": "{a @c=d}",
"exp": "a"
},
{
"description": "... attribute -> \"@\" identifier s \"=\" literal ...",
"src": "{a @c =d}",
"exp": "a"
},
{
"description": "... attribute -> \"@\" identifier \"=\" s literal ...",
"src": "{a @c= d}",
"exp": "a"
},
{
"description": "... attribute -> \"@\" identifier s \"=\" s literal ...",
"src": "{a @c = d}",
"exp": "a"
},
{
"description": "... attribute -> \"@\" identifier s \"=\" s quoted-literal ...",
"src": "{42 @foo=|bar|}",
"exp": "42",
"expParts": [
{
"type": "string",
"source": "|42|",
"value": "42"
}
]
},
{
"description": "... quoted-literal",
"src": "{||}",
"exp": ""
},
{
"description": "... quoted-literal",
"src": "{|a|}",
"exp": "a"
},
{
"description": "... quoted-literal",
"src": "{|\\\\|}",
"exp": "\\"
},
{
"description": "... quoted-literal",
"src": "{|a\\\\\\{\\|\\}|}",
"exp": "a\\{|}"
},
{
"description": "... unquoted-literal",
"src": "{0}",
"exp": "0"
},
{
"description": "... unquoted-literal",
"src": "{-0}",
"exp": "-0"
},
{
"description": "... unquoted-literal",
"src": "{1}",
"exp": "1"
},
{
"description": "... unquoted-literal",
"src": "{11}",
"exp": "11"
},
{
"description": "... unquoted-literal",
"src": "{0.1}",
"exp": "0.1"
},
{
"description": "... unquoted-literal",
"src": "{0.12}",
"exp": "0.12"
},
{
"description": "... unquoted-literal",
"src": "{0e1}",
"exp": "0e1"
},
{
"description": "... unquoted-literal",
"src": "{0E1}",
"exp": "0E1"
},
{
"description": "... unquoted-literal",
"src": "{0E-1}",
"exp": "0E-1"
},
{
"description": "... unquoted-literal",
"src": "{0E-1}",
"exp": "0E-1"
},
{
"description": "+ as unquoted-literal",
"src": "{+}",
"exp": "+"
},
{
"description": "- as unquoted-literal",
"src": "{-}",
"exp": "-"
},
{
"description": ". as unquoted-literal",
"src": "{·}",
"exp": "·"
},
{
"description": "emoji as unquoted-literal",
"src": "{🥔}",
"exp": "🥔"
},
{
"description": "emoji above U+FFFF as unquoted-literal, ",
"src": "{🀄️}",
"exp": "🀄️"
},
{
"description": "multi-code-point emoji as unquoted-literal",
"src": "{🏳️‍🌈}",
"exp": "🏳️‍🌈"
},
{
"description": "various characters as unquoted-literal",
"src": "{\u00a1\u061d\u1681\u200b\u2010\u2030\u2060\u206a\u3001\ue000\ufdf0}",
"exp": "\u00a1\u061d\u1681\u200b\u2010\u2030\u2060\u206a\u3001\ue000\ufdf0"
},
{
"src": "hello { world\t\n}",
"exp": "hello world"
},
{
"src": "hello {\u3000world\r}",
"exp": "hello world"
},
{
"src": "{$one} and {$two}",
"params": [
{
"name": "one",
"value": 1.3
},
{
"name": "two",
"value": 4.2
}
],
"exp": "1.3 and 4.2"
},
{
"src": "{$one} et {$two}",
"locale": "fr",
"params": [
{
"name": "one",
"value": 1.3
},
{
"name": "two",
"value": 4.2
}
],
"exp": "1,3 et 4,2"
},
{
"src": ".local $foo = {bar} {{bar {$foo}}}",
"exp": "bar bar"
},
{
"src": ".local $foo = {|bar|} {{bar {$foo}}}",
"exp": "bar bar"
},
{
"src": ".local $foo = {|bar|} {{bar {$foo}}}",
"params": [
{
"name": "foo",
"value": "foo"
}
],
"exp": "bar bar"
},
{
"src": ".local $foo = {$bar} {{bar {$foo}}}",
"params": [
{
"name": "bar",
"value": "foo"
}
],
"exp": "bar foo"
},
{
"src": ".local $foo = {$baz} .local $bar = {$foo} {{bar {$bar}}}",
"params": [
{
"name": "baz",
"value": "foo"
}
],
"exp": "bar foo"
},
{
"src": ".input {$foo} {{bar {$foo}}}",
"params": [
{
"name": "foo",
"value": "foo"
}
],
"exp": "bar foo"
},
{
"src": ".input {$foo} .local $bar = {$foo} {{bar {$bar}}}",
"params": [
{
"name": "foo",
"value": "foo"
}
],
"exp": "bar foo"
},
{
"src": ".local $foo = {$baz} .local $bar = {$foo} {{bar {$bar}}}",
"params": [
{
"name": "baz",
"value": "foo"
}
],
"exp": "bar foo"
},
{
"src": ".local $x = {42} .local $y = {$x} {{{$x} {$y}}}",
"exp": "42 42"
},
{
"src": "{#tag}content",
"exp": "content",
"expParts": [
{
"type": "markup",
"kind": "open",
"name": "tag"
},
{
"type": "literal",
"value": "content"
}
]
},
{
"src": "{#ns:tag}content{/ns:tag}",
"exp": "content",
"expParts": [
{
"type": "markup",
"kind": "open",
"name": "ns:tag"
},
{
"type": "literal",
"value": "content"
},
{
"type": "markup",
"kind": "close",
"name": "ns:tag"
}
]
},
{
"src": "{/tag}content",
"exp": "content",
"expParts": [
{
"type": "markup",
"kind": "close",
"name": "tag"
},
{
"type": "literal",
"value": "content"
}
]
},
{
"src": "{#tag foo=bar/}",
"exp": "",
"expParts": [
{
"type": "markup",
"kind": "standalone",
"name": "tag",
"options": {
"foo": "bar"
}
}
]
},
{
"src": "{#tag a:foo=|foo| b:bar=$bar}",
"params": [
{
"name": "bar",
"value": "b a r"
}
],
"exp": "",
"expParts": [
{
"type": "markup",
"kind": "open",
"name": "tag",
"options": {
"a:foo": "foo",
"b:bar": "b a r"
}
}
]
},
{
"src": "{42 @foo @bar=13}",
"exp": "42",
"expParts": [
{
"type": "string",
"source": "|42|",
"value": "42"
}
]
},
{
"src": "{{trailing whitespace}} \n",
"exp": "trailing whitespace"
},
{
"description": "NFC: text is not normalized",
"src": "\u1E0A\u0323",
"exp": "\u1E0A\u0323"
},
{
"description": "NFC: variables are compared to each other as-if normalized; decl is non-normalized, use is",
"src": ".local $\u0044\u0323\u0307 = {foo} {{{$\u1E0c\u0307}}}",
"exp": "foo"
},
{
"description": "NFC: variables are compared to each other as-if normalized; decl is normalized, use isn't",
"src": ".local $\u1E0c\u0307 = {foo} {{{$\u0044\u0323\u0307}}}",
"exp": "foo"
},
{
"description": "NFC: variables are compared to each other as-if normalized; decl is normalized, use isn't",
"src": ".input {$\u1E0c\u0307} {{{$\u0044\u0323\u0307}}}",
"params": [{"name": "\u1E0c\u0307", "value": "foo"}],
"exp": "foo"
},
{
"description": "NFC: variables are compared to each other as-if normalized; decl is non-normalized, use is",
"src": ".input {$\u0044\u0323\u0307} {{{$\u1E0c\u0307}}}",
"params": [{"name": "\u0044\u0323\u0307", "value": "foo"}],
"exp": "foo"
},
{
"description": "NFC: variables are compared to each other as-if normalized; decl is non-normalized, use is; reordering",
"src": ".local $\u0044\u0307\u0323 = {foo} {{{$\u1E0c\u0307}}}",
"exp": "foo"
},
{
"description": "NFC: variables are compared to each other as-if normalized; decl is non-normalized, use is; special case mapping",
"src": ".local $\u0041\u030A\u0301 = {foo} {{{$\u01FA}}}",
"exp": "foo"
}
]
}