// © 2022 and later: Unicode, Inc. and others. // License & terms of use: https://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. * *

It covers the examples in the * spec document, * except for the custom formatters ones, which are too verbose and were moved to separate test classes.

*

*/ @RunWith(JUnit4.class) @SuppressWarnings({"static-method", "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 year=numeric month=long day=numeric weekday=long}."; 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 :date year=numeric month=long day=numeric weekday=long}."; String expectedEn = "Date: Wednesday, November 23, 2022."; String expectedRo = "Date: miercuri, 23 noiembrie 2022."; Map 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 :date year=numeric month=long day=numeric}.") .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 hour=numeric minute=numeric}.") .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 :date year=numeric month=short day=numeric}.") .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 icu: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 hour=numeric minute=numeric}.") .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()); } @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("Option, minFraction: {$val :number minimumFractionDigits=8}!") .locale("ro") .arguments(Args.of("val", value)) .expected("Option, minFraction: 1.234.567.890,97531000!") .build()); TestUtils.runTestCase(new TestCase.Builder() .pattern("Option, maxFraction: {$val :number maximumFractionDigits=3}!") .locale("ro") .arguments(Args.of("val", value)) .expected("Option, maxFraction: 1.234.567.890,975!") .build()); // Currency TestUtils.runTestCase(new TestCase.Builder() .pattern("Skeletons, currency: {$val :number icu: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 icu: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 icu: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("" + ".local $intl = {$valC :number icu:skeleton=|unit/celsius|}\n" + ".local $us = {$valF :number icu: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 icu: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 icu: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 = ".local $amount = {$count :number}\n" + ".match {$amount :number}\n" + " 1 {{I have {$amount} dollar.}}\n" + " * {{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 = ".local $amount = {$count :number minimumFractionDigits=2}\n" + ".match {$amount :number minimumFractionDigits=2}\n" + " one {{I have {$amount} dollar.}}\n" + " * {{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 :number}\n" + " 1 {{You have one notification.}}\n" + " * {{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 :number} {$userGender :string}\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" + " * masculine {{{$userName} added {$photoCount} photos to his album.}}\n" + " * feminine {{{$userName} added {$photoCount} photos to her album.}}\n" + " * * {{{$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("" + ".local $exp = {$expDate :datetime year=numeric month=short day=numeric weekday=short}\n" + "{{Your tickets expire on {$exp}.}}") .arguments(Args.of("count", 1, "expDate", TEST_DATE)) .expected("Your tickets expire on Wed, Nov 23, 2022.") .build()); } @Test public void testLocaleVariableWithSelect() { String message = "" + ".local $exp = {$expDate :date year=numeric month=short day=numeric weekday=short}\n" + ".match {$count :number}\n" + " 1 {{Your ticket expires on {$exp}.}}\n" + " * {{Your {$count} tickets expire on {$exp}.}}\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()); } }