• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2022 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 package com.ibm.icu.dev.test.message2;
5 
6 import org.junit.Test;
7 import org.junit.runner.RunWith;
8 import org.junit.runners.JUnit4;
9 
10 import com.ibm.icu.dev.test.TestFmwk;
11 
12 /**
13  * These tests come from the test suite created for the JavaScript implementation of MessageFormat v2.
14  *
15  * <p>Original JSON file
16  * <a href="https://github.com/messageformat/messageformat/blob/master/packages/mf2-messageformat/src/__fixtures/test-messages.json">here</a>.</p>
17  */
18 @RunWith(JUnit4.class)
19 @SuppressWarnings("javadoc")
20 public class FromJsonTest extends TestFmwk {
21 
22     static final TestCase[] TEST_CASES = {
23             new TestCase.Builder()
24                 .pattern("{hello}")
25                 .expected("hello")
26                 .build(),
27             new TestCase.Builder()
28                 .pattern("{hello {(world)}}")
29                 .expected("hello world")
30                 .build(),
31             new TestCase.Builder()
32                 .pattern("{hello {()}}")
33                 .expected("hello ")
34                 .build(),
35             new TestCase.Builder()
36                 .pattern("{hello {$place}}")
37                 .arguments(Args.of("place", "world"))
38                 .expected("hello world")
39                 .build(),
40             new TestCase.Builder()
41                 .pattern("{hello {$place}}")
42                 .expected("hello {$place}")
43                 // errorsJs: ["missing-var"]
44                 .build(),
45             new TestCase.Builder()
46                 .pattern("{{$one} and {$two}}")
47                 .arguments(Args.of("one", 1.3, "two", 4.2))
48                 .expected("1.3 and 4.2")
49                 .build(),
50             new TestCase.Builder()
51                 .pattern("{{$one} et {$two}}")
52                 .locale("fr")
53                 .arguments(Args.of("one", 1.3, "two", 4.2))
54                 .expected("1,3 et 4,2")
55                 .build(),
56             new TestCase.Builder()
57                 .pattern("{hello {(4.2) :number}}")
58                 .expected("hello 4.2")
59                 .build(),
60             new TestCase.Builder() // not in the original JSON
61                 .locale("ar-EG")
62                 .pattern("{hello {(4.2) :number}}")
63                 .expected("hello \u0664\u066B\u0662")
64                 .build(),
65             new TestCase.Builder()
66                 .pattern("{hello {(foo) :number}}")
67                 .expected("hello NaN")
68                 .build(),
69             new TestCase.Builder()
70                 .pattern("{hello {:number}}")
71                 .expected("hello NaN")
72                 // This is different from JS, should be an error.
73                 .errors("ICU4J: exception.")
74                 .build(),
75             new TestCase.Builder()
76                 .pattern("{hello {(4.2) :number minimumFractionDigits=2}}")
77                 .expected("hello 4.20")
78                 .build(),
79             new TestCase.Builder()
80                 .pattern("{hello {(4.2) :number minimumFractionDigits=(2)}}")
81                 .expected("hello 4.20")
82                 .build(),
83             new TestCase.Builder()
84                 .pattern("{hello {(4.2) :number minimumFractionDigits=$foo}}")
85                 .arguments(Args.of("foo", 2f))
86                 .expected("hello 4.20")
87                 .build(),
88             new TestCase.Builder()
89                 .pattern("{hello {(4.2) :number minimumFractionDigits=$foo}}")
90                 .arguments(Args.of("foo", "2"))
91                 .expected("hello 4.20")
92                 // errorsJs: ["invalid-type"]
93                 .build(),
94             new TestCase.Builder()
95                 .pattern("let $foo = {(bar)} {bar {$foo}}")
96                 .expected("bar bar")
97                 .build(),
98             new TestCase.Builder()
99                 .pattern("let $foo = {(bar)} {bar {$foo}}")
100                 .arguments(Args.of("foo", "foo"))
101                 // expectedJs: "bar foo"
102                 // It is undefined if we allow arguments to override local variables, or it is an error.
103                 // And undefined who wins if that happens, the local variable of the argument.
104                 .expected("bar bar")
105                 .build(),
106             new TestCase.Builder()
107                 .pattern("let $foo = {$bar} {bar {$foo}}")
108                 .arguments(Args.of("bar", "foo"))
109                 .expected("bar foo")
110                 .build(),
111             new TestCase.Builder()
112                 .pattern("let $foo = {$bar :number} {bar {$foo}}")
113                 .arguments(Args.of("bar", 4.2))
114                 .expected("bar 4.2")
115                 .build(),
116             new TestCase.Builder()
117                 .pattern("let $foo = {$bar :number minimumFractionDigits=2} {bar {$foo}}")
118                 .arguments(Args.of("bar", 4.2))
119                 .expected("bar 4.20")
120                 .build(),
121             new TestCase.Builder().ignore("Maybe") // Because minimumFractionDigits=foo
122                 .pattern("let $foo = {$bar :number minimumFractionDigits=foo} {bar {$foo}}")
123                 .arguments(Args.of("bar", 4.2))
124                 .expected("bar 4.2")
125                 .errors("invalid-type")
126                 .build(),
127             new TestCase.Builder().ignore("Maybe. Function specific behavior.")
128                 .pattern("let $foo = {$bar :number} {bar {$foo}}")
129                 .arguments(Args.of("bar", "foo"))
130                 .expected("bar NaN")
131                 .build(),
132             new TestCase.Builder()
133                 .pattern("let $foo = {$bar} let $bar = {$baz} {bar {$foo}}")
134                 .arguments(Args.of("baz", "foo"))
135                 // expectedJs: "bar foo"
136                 // It is currently undefined if a local variable (like $foo)
137                 // can reference a local variable that was not yet defined (like $bar).
138                 // That is called hoisting and it is valid in JavaScript or Python.
139                 // Not allowing that would prevent circular references.
140                 // https://github.com/unicode-org/message-format-wg/issues/292
141                 .expected("bar {$bar}")
142                 .build(),
143             new TestCase.Builder()
144                 .patternJs("match {$foo} when (1) {one} when * {other}")
145                 .pattern("match {$foo :select} when (1) {one} when * {other}")
146                 .arguments(Args.of("foo", "1"))
147                 .expected("one")
148                 .build(),
149             new TestCase.Builder()
150                 .pattern("match {$foo :plural} when 1 {one} when * {other}")
151                 .arguments(Args.of("foo", "1")) // Should this be error? Plural on string?
152                 // expectedJs: "one"
153                 .expected("other")
154                 .build(),
155             new TestCase.Builder()
156                 .pattern("match {$foo :select} when (1) {one} when * {other}")
157                 .arguments(Args.of("foo", "1"))
158                 .expected("one")
159                 .build(),
160             new TestCase.Builder()
161                 .patternJs("match {$foo} when 1 {one} when * {other}")
162                 .pattern("match {$foo :plural} when 1 {one} when * {other}")
163                 .arguments(Args.of("foo", 1))
164                 .expected("one")
165                 .build(),
166             new TestCase.Builder()
167                 .pattern("match {$foo :plural} when 1 {one} when * {other}")
168                 .arguments(Args.of("foo", 1))
169                 .expected("one")
170                 .build(),
171             new TestCase.Builder().ignore("not possible to put a null in a map")
172                 .pattern("match {$foo} when 1 {one} when * {other}")
173                 .arguments(Args.of("foo", null))
174                 .expected("other")
175                 .build(),
176             new TestCase.Builder()
177                 .patternJs("match {$foo} when 1 {one} when * {other}")
178                 .pattern("match {$foo :plural} when 1 {one} when * {other}")
179                 .expected("other")
180                 .errors("missing-var")
181                 .build(),
182             new TestCase.Builder()
183                 .patternJs("match {$foo} when one {one} when * {other}")
184                 .pattern("match {$foo :plural} when one {one} when * {other}")
185                 .arguments(Args.of("foo", 1))
186                 .expected("one")
187                 .build(),
188             new TestCase.Builder()
189                 .patternJs("match {$foo} when 1 {=1} when one {one} when * {other}")
190                 .pattern("match {$foo :plural} when 1 {=1} when one {one} when * {other}")
191                 .arguments(Args.of("foo", 1))
192                 .expected("=1")
193                 .build(),
194             new TestCase.Builder()
195                 .patternJs("match {$foo} when one {one} when 1 {=1} when * {other}")
196                 .pattern("match {$foo :plural} when one {one} when 1 {=1} when * {other}")
197                 .arguments(Args.of("foo", 1))
198                 .expected("one")
199                 .build(),
200             new TestCase.Builder()
201                 .patternJs("match {$foo} {$bar} when one one {one one} when one * {one other} when * * {other}")
202                 .pattern("match {$foo :plural} {$bar :plural} when one one {one one} when one * {one other} when * * {other}")
203                 .arguments(Args.of("foo", 1, "bar", 1))
204                 .expected("one one")
205                 .build(),
206             new TestCase.Builder()
207                 .patternJs("match {$foo} {$bar} when one one {one one} when one * {one other} when * * {other}")
208                 .pattern("match {$foo :plural} {$bar :plural} when one one {one one} when one * {one other} when * * {other}")
209                 .arguments(Args.of("foo", 1, "bar", 2))
210                 .expected("one other")
211                 .build(),
212             new TestCase.Builder()
213                 .patternJs("match {$foo} {$bar} when one one {one one} when one * {one other} when * * {other}")
214                 .pattern("match {$foo :plural} {$bar :plural} when one one {one one} when one * {one other} when * * {other}")
215                 .arguments(Args.of("foo", 2, "bar", 2))
216                 .expected("other")
217                 .build(),
218             new TestCase.Builder()
219                 .patternJs("let $foo = {$bar} match {$foo} when one {one} when * {other}")
220                 .pattern("let $foo = {$bar} match {$foo :plural} when one {one} when * {other}")
221                 .arguments(Args.of("bar", 1))
222                 .expected("one")
223                 .build(),
224             new TestCase.Builder()
225                 .patternJs("let $foo = {$bar} match {$foo} when one {one} when * {other}")
226                 .pattern("let $foo = {$bar} match {$foo :plural} when one {one} when * {other}")
227                 .arguments(Args.of("bar", 2))
228                 .expected("other")
229                 .build(),
230             new TestCase.Builder()
231                 .patternJs("let $bar = {$none} match {$foo} when one {one} when * {{$bar}}")
232                 .pattern("let $bar = {$none} match {$foo :plural} when one {one} when * {{$bar}}")
233                 .arguments(Args.of("foo", 1))
234                 .expected("one")
235                 .build(),
236             new TestCase.Builder()
237                 .patternJs("let $bar = {$none} match {$foo} when one {one} when * {{$bar}}")
238                 .pattern("let $bar = {$none :plural} match {$foo} when one {one} when * {{$bar}}")
239                 .arguments(Args.of("foo", 2))
240                 .expected("{$bar}")
241                 .errors("missing-var")
242                 .build(),
243             new TestCase.Builder()
244                 .pattern("let bar = {(foo)} {{$bar}}")
245                 .expected("{$bar}")
246                 .errors("missing-char", "missing-var")
247                 .build(),
248             new TestCase.Builder()
249                 .pattern("let $bar {(foo)} {{$bar}}")
250                 .expected("foo")
251                 .errors("missing-char")
252                 .build(),
253             new TestCase.Builder()
254                 .pattern("let $bar = (foo) {{$bar}}")
255                 .expected("{$bar}")
256                 .errors("missing-char", "junk-element")
257                 .build(),
258             new TestCase.Builder().ignore("no markup support")
259                 .pattern("{{+tag}}")
260                 .expected("{+tag}")
261                 .build(),
262             new TestCase.Builder().ignore("no markup support")
263                 .pattern("{{+tag}content}")
264                 .expected("{+tag}content")
265                 .build(),
266             new TestCase.Builder().ignore("no markup support")
267                 .pattern("{{+tag}content{-tag}}")
268                 .expected("{+tag}content{-tag}")
269                 .build(),
270             new TestCase.Builder().ignore("no markup support")
271                 .pattern("{{-tag}content}")
272                 .expected("{-tag}content")
273                 .build(),
274             new TestCase.Builder().ignore("no markup support")
275                 .pattern("{{+tag foo=bar}}")
276                 .expected("{+tag foo=bar}")
277                 .build(),
278             new TestCase.Builder().ignore("no markup support")
279                 .pattern("{{+tag foo=(foo) bar=$bar}}")
280                 .arguments(Args.of("bar", "b a r"))
281                 .expected("{+tag foo=foo bar=(b a r)}")
282                 .build(),
283             new TestCase.Builder()
284                 .pattern("{bad {(foo) +markup}}")
285                 .expected("bad {+markup}")
286                 .errors("extra-content")
287                 .build(),
288             new TestCase.Builder()
289                 .pattern("{{-tag foo=bar}}")
290                 .expected("{-tag}")
291                 .errors("extra-content")
292                 .build(),
293             new TestCase.Builder()
294                 .pattern("no braces")
295                 .expected("{no braces}")
296                 .errors("parse-error", "junk-element")
297                 .build(),
298             new TestCase.Builder()
299                 .pattern("no braces {$foo}")
300                 .arguments(Args.of("foo", 2))
301                 .expected("{no braces {$foo}}")
302                 .errors("parse-error", "junk-element")
303                 .build(),
304             new TestCase.Builder().ignore("infinite loop!")
305                 .pattern("{missing end brace")
306                 .expected("missing end brace")
307                 .errors("missing-char")
308                 .build(),
309             new TestCase.Builder()
310                 .pattern("{missing end {$brace")
311                 .expected("missing end {$brace}")
312                 .errors("missing-char", "missing-char", "missing-var")
313                 .build(),
314             new TestCase.Builder()
315                 .pattern("{extra} content")
316                 .expected("extra")
317                 .errors("extra-content")
318                 .build(),
319             new TestCase.Builder()
320                 .pattern("{empty { }}")
321                 .expected("empty ")
322                 // errorsJs: ["parse-error", "junk-element"]
323                 .build(),
324             new TestCase.Builder()
325                 .pattern("{bad {:}}")
326                 .expected("bad {:}")
327                 .errors("empty-token", "missing-func")
328                 .build(),
329             new TestCase.Builder()
330                 .pattern("{bad {placeholder}}")
331                 .expected("bad {placeholder}")
332                 .errors("parse-error", "extra-content", "junk-element")
333                 .build(),
334             new TestCase.Builder()
335                 .pattern("{no-equal {(42) :number minimumFractionDigits 2}}")
336                 .expected( "no-equal 42.00")
337                 .errors("missing-char")
338                 .build(),
339             new TestCase.Builder()
340                 .pattern("{bad {:placeholder option=}}")
341                 .expected("bad {:placeholder}")
342                 .errors("empty-token", "missing-func")
343                 .build(),
344             new TestCase.Builder()
345                 .pattern("{bad {:placeholder option value}}")
346                 .expected("bad {:placeholder}")
347                 .errors("missing-char", "missing-func")
348                 .build(),
349             new TestCase.Builder()
350                 .pattern("{bad {:placeholder option}}")
351                 .expected("bad {:placeholder}")
352                 .errors("missing-char", "empty-token", "missing-func")
353                 .build(),
354             new TestCase.Builder()
355                 .pattern("{bad {$placeholder option}}")
356                 .expected("bad {$placeholder}")
357                 .errors("extra-content", "extra-content", "missing-var")
358                 .build(),
359             new TestCase.Builder()
360                 .pattern("{no {$placeholder end}")
361                 .expected("no {$placeholder}")
362                 .errors("extra-content", "missing-var")
363                 .build(),
364             new TestCase.Builder()
365                 .pattern("match {} when * {foo}")
366                 .expected("foo")
367                 .errors("parse-error", "bad-selector", "junk-element")
368                 .build(),
369             new TestCase.Builder()
370                 .pattern("match {+foo} when * {foo}")
371                 .expected("foo")
372                 .errors("bad-selector")
373                 .build(),
374             new TestCase.Builder()
375                 .pattern("match {(foo)} when*{foo}")
376                 .expected("foo")
377                 .errors("missing-char")
378                 .build(),
379             new TestCase.Builder()
380                 .pattern("match when * {foo}")
381                 .expected("foo")
382                 .errors("empty-token")
383                 .build(),
384             new TestCase.Builder()
385                 .pattern("match {(x)} when * foo")
386                 .expected("")
387                 .errors("key-mismatch", "missing-char")
388                 .build(),
389             new TestCase.Builder()
390                 .pattern("match {(x)} when * {foo} extra")
391                 .expected("foo")
392                 .errors("extra-content")
393                 .build(),
394             new TestCase.Builder()
395                 .pattern("match (x) when * {foo}")
396                 .expected("")
397                 .errors("empty-token", "extra-content")
398                 .build(),
399             new TestCase.Builder()
400                 .pattern("match {$foo} when * * {foo}")
401                 .expected("foo")
402                 .errors("key-mismatch", "missing-var")
403                 .build(),
404             new TestCase.Builder()
405                 .pattern("match {$foo} {$bar} when * {foo}")
406                 .expected("foo")
407                 .errors("key-mismatch", "missing-var", "missing-var")
408                 .build()
409     };
410 
411     @Test
test()412     public void test() {
413         int ignoreCount = 0;
414         for (TestCase testCase : TEST_CASES) {
415             if (testCase.ignore)
416                 ignoreCount++;
417             TestUtils.runTestCase(testCase);
418         }
419         System.out.printf("Executed %d test cases out of %d, skipped %d%n",
420                 TEST_CASES.length - ignoreCount, TEST_CASES.length, ignoreCount);
421     }
422 }
423