summaryrefslogtreecommitdiff
path: root/icu4j/main/common_tests/src/test/java/com/ibm/icu/dev/test/message2/Mf2FeaturesTest.java
blob: 6d4fa23fafc0cd3cb6769912c997fe5d797ce279 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
// © 2022 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html

package com.ibm.icu.dev.test.message2;

import java.util.Date;
import java.util.Locale;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.ibm.icu.dev.test.CoreTestFmwk;
import com.ibm.icu.math.BigDecimal;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.CurrencyAmount;

/**
 * Trying to show off most of the features in one place.
 *
 * <p>It covers the examples in the
 * <a href="https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md">spec document</a>,
 * except for the custom formatters ones, which are too verbose and were moved to separate test classes.</p>
 * </p>
 */
@RunWith(JUnit4.class)
@SuppressWarnings("javadoc")
public class Mf2FeaturesTest extends CoreTestFmwk {

    // November 23, 2022 at 7:42:37.123 PM
    static final Date TEST_DATE = new Date(1669261357123L);

    @Test
    public void testEmptyMessage() {
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{}")
                .arguments(Args.NONE)
                .expected("")
                .build());
    }

    @Test
    public void testPlainText() {
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Hello World!}")
                .arguments(Args.NONE)
                .expected("Hello World!")
                .build());
    }

    @Test
    public void testPlaceholders() {
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Hello, {$userName}!}")
                .arguments(Args.of("userName", "John"))
                .expected("Hello, John!")
                .build());
    }

    @Test
    public void testArgumentMissing() {
        // Test to check what happens if an argument name from the placeholder is not found
        // We do what the old ICU4J MessageFormat does.
        String message = "{Hello {$name}, today is {$today :datetime skeleton=yMMMMdEEEE}.}";

        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("name", "John", "today", TEST_DATE))
                .expected("Hello John, today is Wednesday, November 23, 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("name", "John"))
                .expected("Hello John, today is {$today}.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("today", TEST_DATE))
                .expected("Hello {$name}, today is Wednesday, November 23, 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.NONE)
                .expected("Hello {$name}, today is {$today}.")
                .build());
    }

    @Test
    public void testDefaultLocale() {
        String message = "{Date: {$date :datetime skeleton=yMMMMdEEEE}.}";
        String expectedEn = "Date: Wednesday, November 23, 2022.";
        String expectedRo = "Date: miercuri, 23 noiembrie 2022.";
        Map<String, Object> arguments = Args.of("date", TEST_DATE);

        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(arguments)
                .expected(expectedEn)
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(arguments)
                .locale("ro")
                .expected(expectedRo)
                .build());

        Locale originalLocale = Locale.getDefault();
        Locale.setDefault(Locale.forLanguageTag("ro"));
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(arguments)
                .locale("en-US")
                .expected(expectedEn)
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(arguments)
                .expected(expectedRo)
                .build());
        Locale.setDefault(originalLocale);
    }

    @Test
    public void testAllKindOfDates() {
        // Default function
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date}.}")
                .locale("ro")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 23.11.2022, 19:42.")
                .build());
        // Default options
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime}.}")
                .locale("ro")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 23.11.2022, 19:42.")
                .build());

        // Skeleton
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime skeleton=yMMMMd}.}")
                .locale("ro-RO")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 23 noiembrie 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime skeleton=jm}.}")
                .locale("ro-RO")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 19:42.")
                .build());

        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime skeleton=yMMMd}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: Nov 23, 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime skeleton=yMMMdjms}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: Nov 23, 2022, 7:42:37\u202FPM.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime skeleton=jm}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 7:42\u202FPM.")
                .build());

        // Style
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime datestyle=long}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: November 23, 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(
                "{Testing date formatting: {$date :datetime datestyle=medium}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: Nov 23, 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime datestyle=short}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 11/23/22.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime timestyle=long}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 7:42:37\u202FPM PST.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime timestyle=medium}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 7:42:37\u202FPM.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(
                "{Testing date formatting: {$date :datetime timestyle=short}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 7:42\u202FPM.")
                .build());

        // Pattern
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime pattern=(d 'of' MMMM, y 'at' HH:mm)}.}")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 23 of November, 2022 at 19:42.")
                .build());
    }

    @Test
    public void testAllKindOfNumbers() {
        double value = 1234567890.97531;

        // From literal values
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{From literal: {(123456789) :number}!}")
                .locale("ro")
                .arguments(Args.of("val", value))
                .expected("From literal: 123.456.789!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{From literal: {(123456789.531) :number}!}")
                .locale("ro")
                .arguments(Args.of("val", value))
                .expected("From literal: 123.456.789,531!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{From literal: {(123456789.531) :number}!}")
                .locale("my")
                .arguments(Args.of("val", value))
                .expected("From literal: \u1041\u1042\u1043,\u1044\u1045\u1046,\u1047\u1048\u1049.\u1045\u1043\u1041!")
                .build());

        // Testing that the detection works for various types (without specifying :number)
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Default double: {$val}!}")
                .locale("en-IN")
                .arguments(Args.of("val", value))
                .expected("Default double: 1,23,45,67,890.97531!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Default double: {$val}!}")
                .locale("ro")
                .arguments(Args.of("val", value))
                .expected("Default double: 1.234.567.890,97531!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Default float: {$val}!}")
                .locale("ro")
                .arguments(Args.of("val", 3.1415926535))
                .expected("Default float: 3,141593!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Default long: {$val}!}")
                .locale("ro")
                .arguments(Args.of("val", 1234567890123456789L))
                .expected("Default long: 1.234.567.890.123.456.789!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Default number: {$val}!}")
                .locale("ro")
                .arguments(Args.of("val", new BigDecimal("1234567890123456789.987654321")))
                .expected("Default number: 1.234.567.890.123.456.789,987654!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Price: {$val}}")
                .locale("de")
                .arguments(Args.of("val", new CurrencyAmount(1234.56, Currency.getInstance("EUR"))))
                .expected("Price: 1.234,56\u00A0\u20AC")
                .build());

        // Various skeletons
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Skeletons, minFraction: {$val :number skeleton=(.00000000*)}!}")
                .locale("ro")
                .arguments(Args.of("val", value))
                .expected("Skeletons, minFraction: 1.234.567.890,97531000!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Skeletons, maxFraction: {$val :number skeleton=(.###)}!}")
                .locale("ro")
                .arguments(Args.of("val", value))
                .expected("Skeletons, maxFraction: 1.234.567.890,975!")
                .build());
        // Currency
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Skeletons, currency: {$val :number skeleton=(currency/EUR)}!}")
                .locale("de")
                .arguments(Args.of("val", value))
                .expected("Skeletons, currency: 1.234.567.890,98\u00A0\u20AC!")
                .build());
        // Currency as a parameter
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Skeletons, currency: {$val :number skeleton=$skel}!}")
                .locale("de")
                .arguments(Args.of("val", value, "skel", "currency/EUR"))
                .expected("Skeletons, currency: 1.234.567.890,98\u00A0\u20AC!")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Skeletons, currency: {$val :number skeleton=$skel}!}")
                .locale("de")
                .arguments(Args.of("val", value, "skel", "currency/JPY"))
                .expected("Skeletons, currency: 1.234.567.891\u00A0\u00A5!")
                .build());

        // Various measures
        double celsius = 27;
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(""
                        + "let $intl = {$valC :number skeleton=(unit/celsius)}\n"
                        + "let $us = {$valF :number skeleton=(unit/fahrenheit)}\n"
                        + "{Temperature: {$intl} ({$us})}")
                .locale("ro")
                .arguments(Args.of("valC", celsius, "valF", celsius * 9 / 5 + 32))
                .expected("Temperature: 27 \u00B0C (80,6 \u00B0F)")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Height: {$len :number skeleton=(unit/meter)}}")
                .locale("ro")
                .arguments(Args.of("len", 1.75))
                .expected("Height: 1,75 m")
                .build());

        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Skeletons, currency: {$val :number skeleton=(currency/EUR)}!}")
                .locale("de")
                .arguments(Args.of("val", value))
                .expected("Skeletons, currency: 1.234.567.890,98\u00A0\u20AC!")
                .build());
    }

    @Test
    public void testSpecialPluralWithDecimals() {
        String message;
        message = "let $amount = {$count :number}\n"
                + "match {$amount :plural}\n"
                + "  when 1 {I have {$amount} dollar.}\n"
                + "  when * {I have {$amount} dollars.}\n";
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .locale("en-US")
                .arguments(Args.of("count", 1))
                .expected("I have 1 dollar.")
                .build());
        message = "let $amount = {$count :number skeleton=(.00*)}\n"
                + "match {$amount :plural skeleton=(.00*)}\n"
                + "  when 1 {I have {$amount} dollar.}\n"
                + "  when * {I have {$amount} dollars.}\n";
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .locale("en-US")
                .arguments(Args.of("count", 1))
                .expected("I have 1.00 dollars.")
                .build());
    }

    @Test
    public void testDefaultFunctionAndOptions() {
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date}.}")
                .locale("ro")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 23.11.2022, 19:42.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern("{Testing date formatting: {$date :datetime}.}")
                .locale("ro")
                .arguments(Args.of("date", TEST_DATE))
                .expected("Testing date formatting: 23.11.2022, 19:42.")
                .build());
    }

    @Test
    public void testSimpleSelection() {
        String message = "match {$count :plural}\n"
                + " when 1 {You have one notification.}\n"
                + " when * {You have {$count} notifications.}\n";

        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("count", 1))
                .expected("You have one notification.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("count", 42))
                .expected("You have 42 notifications.")
                .build());
    }

    @Test
    public void testComplexSelection() {
        String message = ""
                + "match {$photoCount :plural} {$userGender :select}\n"
                + " when 1 masculine {{$userName} added a new photo to his album.}\n"
                + " when 1 feminine {{$userName} added a new photo to her album.}\n"
                + " when 1 * {{$userName} added a new photo to their album.}\n"
                + " when * masculine {{$userName} added {$photoCount} photos to his album.}\n"
                + " when * feminine {{$userName} added {$photoCount} photos to her album.}\n"
                + " when * * {{$userName} added {$photoCount} photos to their album.}";

        TestUtils.runTestCase(new TestCase.Builder().pattern(message)
                .arguments(Args.of("photoCount", 1, "userGender", "masculine", "userName", "John"))
                .expected("John added a new photo to his album.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder().pattern(message)
                .arguments(Args.of("photoCount", 1, "userGender", "feminine", "userName", "Anna"))
                .expected("Anna added a new photo to her album.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder().pattern(message)
                .arguments(Args.of("photoCount", 1, "userGender", "unknown", "userName", "Anonymous"))
                .expected("Anonymous added a new photo to their album.")
                .build());

        TestUtils.runTestCase(new TestCase.Builder().pattern(message)
                .arguments(Args.of("photoCount", 13, "userGender", "masculine", "userName", "John"))
                .expected("John added 13 photos to his album.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder().pattern(message)
                .arguments(Args.of("photoCount", 13, "userGender", "feminine", "userName", "Anna"))
                .expected("Anna added 13 photos to her album.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder().pattern(message)
                .arguments(Args.of("photoCount", 13, "userGender", "unknown", "userName", "Anonymous"))
                .expected("Anonymous added 13 photos to their album.")
                .build());
    }

    // Local Variables

    @Test
    public void testSimpleLocaleVariable() {
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(""
                        + "let $expDate = {$expDate :datetime skeleton=yMMMdE}\n"
                        + "{Your tickets expire on {$expDate}.}")
                .arguments(Args.of("count", 1, "expDate", TEST_DATE))
                .expected("Your tickets expire on Wed, Nov 23, 2022.")
                .build());
    }

    @Test
    public void testLocaleVariableWithSelect() {
        String message = ""
                + "let $expDate = {$expDate :datetime skeleton=yMMMdE}\n"
                + "match {$count :plural}\n"
                + " when 1 {Your ticket expires on {$expDate}.}\n"
                + " when * {Your {$count} tickets expire on {$expDate}.}\n";

        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("count", 1, "expDate", TEST_DATE))
                .expected("Your ticket expires on Wed, Nov 23, 2022.")
                .build());
        TestUtils.runTestCase(new TestCase.Builder()
                .pattern(message)
                .arguments(Args.of("count", 3, "expDate", TEST_DATE))
                .expected("Your 3 tickets expire on Wed, Nov 23, 2022.")
                .build());
    }

}