blob: b60149a8e4ed282ecae97d1498d52824e31d9ee8 [file] [log] [blame]
// © 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.Locale;
import java.util.Map;
import java.util.Objects;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.message2.FormattedPlaceholder;
import com.ibm.icu.message2.Formatter;
import com.ibm.icu.message2.FormatterFactory;
import com.ibm.icu.message2.Mf2FunctionRegistry;
import com.ibm.icu.message2.PlainStringFormattedValue;
/**
* Showing a custom formatter for a user defined class.
*/
@RunWith(JUnit4.class)
@SuppressWarnings("javadoc")
public class CustomFormatterPersonTest extends TestFmwk {
public static class Person {
final String title;
final String firstName;
final String lastName;
public Person(String title, String firstName, String lastName) {
this.title = title;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return "Person {title='" + title + "', firstName='" + firstName + "', lastName='" + lastName + "'}";
}
}
public static class PersonNameFormatterFactory implements FormatterFactory {
@Override
public Formatter createFormatter(Locale locale, Map<String, Object> fixedOptions) {
return new PersonNameFormatterImpl(fixedOptions.get("formality"), fixedOptions.get("length"));
}
static class PersonNameFormatterImpl implements Formatter {
boolean useFormal = false;
final String length;
public PersonNameFormatterImpl(Object level, Object length) {
this.useFormal = "formal".equals(level);
this.length = Objects.toString(length);
}
@Override
public String formatToString(Object toFormat, Map<String, Object> variableOptions) {
return format(toFormat, variableOptions).toString();
}
// Very-very primitive implementation of the "CLDR Person Name Formatting" spec:
// https://docs.google.com/document/d/1uvv6gdkuFwtbNV26Pk7ddfZult4unYwR6DnnKYbujUo/
@Override
public FormattedPlaceholder format(Object toFormat, Map<String, Object> variableOptions) {
String result;
if (toFormat instanceof Person) {
Person person = (Person) toFormat;
switch (length) {
case "long":
result = person.title + " " + person.firstName + " " + person.lastName;
break;
case "medium":
result = useFormal
? person.firstName + " " + person.lastName
: person.title + " " + person.firstName;
break;
case "short": // intentional fall-through
default:
result = useFormal
? person.title + " " + person.lastName
: person.firstName;
}
} else {
result = Objects.toString(toFormat);
}
return new FormattedPlaceholder(toFormat, new PlainStringFormattedValue(result));
}
}
}
private static final Mf2FunctionRegistry CUSTOM_FUNCTION_REGISTRY = Mf2FunctionRegistry.builder()
.setFormatter("person", new PersonNameFormatterFactory())
.setDefaultFormatterNameForType(Person.class, "person")
.build();
@Test
public void testCustomFunctions() {
Person who = new Person("Mr.", "John", "Doe");
TestUtils.runTestCase(new TestCase.Builder()
.pattern("{Hello {$name :person formality=formal}}")
.arguments(Args.of("name", who))
.expected("Hello {$name}")
.errors("person function unknown when called without a custom registry")
.build());
TestUtils.runTestCase(new TestCase.Builder()
.pattern("{Hello {$name :person formality=informal}}")
.arguments(Args.of("name", who))
.expected("Hello {$name}")
.errors("person function unknown when called without a custom registry")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern("{Hello {$name :person formality=formal}}")
.arguments(Args.of("name", who))
.expected("Hello Mr. Doe")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern("{Hello {$name :person formality=informal}}")
.arguments(Args.of("name", who))
.expected("Hello John")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern("{Hello {$name :person formality=formal length=long}}")
.arguments(Args.of("name", who))
.expected("Hello Mr. John Doe")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern("{Hello {$name :person formality=formal length=medium}}")
.arguments(Args.of("name", who))
.expected("Hello John Doe")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern("{Hello {$name :person formality=formal length=short}}")
.arguments(Args.of("name", who))
.expected("Hello Mr. Doe")
.build());
}
@Test
public void testCustomFunctionsComplexMessage() {
Person femalePerson = new Person("Ms.", "Jane", "Doe");
Person malePerson = new Person("Mr.", "John", "Doe");
Person unknownPerson = new Person("Mr./Ms.", "Anonymous", "Doe");
String message = ""
+ "let $hostName = {$host :person length=long}\n"
+ "let $guestName = {$guest :person length=long}\n"
+ "let $guestsOther = {$guestCount :number offset=1}\n"
// + "\n"
+ "match {$hostGender :gender} {$guestCount :plural}\n"
// + "\n"
+ "when female 0 {{$hostName} does not give a party.}\n"
+ "when female 1 {{$hostName} invites {$guestName} to her party.}\n"
+ "when female 2 {{$hostName} invites {$guestName} and one other person to her party.}\n"
+ "when female * {{$hostName} invites {$guestName} and {$guestsOther} other people to her party.}\n"
// + "\n"
+ "when male 0 {{$hostName} does not give a party.}\n"
+ "when male 1 {{$hostName} invites {$guestName} to his party.}\n"
+ "when male 2 {{$hostName} invites {$guestName} and one other person to his party.}\n"
+ "when male * {{$hostName} invites {$guestName} and {$guestsOther} other people to his party.}\n"
// + "\n"
+ "when * 0 {{$hostName} does not give a party.}\n"
+ "when * 1 {{$hostName} invites {$guestName} to their party.}\n"
+ "when * 2 {{$hostName} invites {$guestName} and one other person to their party.}\n"
+ "when * * {{$hostName} invites {$guestName} and {$guestsOther} other people to their party.}\n";
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern(message)
.arguments(Args.of("hostGender", "female", "host", femalePerson, "guest", malePerson, "guestCount", 3))
.expected("Ms. Jane Doe invites Mr. John Doe and 2 other people to her party.")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern(message)
.arguments(Args.of("hostGender", "female", "host", femalePerson, "guest", malePerson, "guestCount", 2))
.expected("Ms. Jane Doe invites Mr. John Doe and one other person to her party.")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern(message)
.arguments(Args.of("hostGender", "female", "host", femalePerson, "guest", malePerson, "guestCount", 1))
.expected("Ms. Jane Doe invites Mr. John Doe to her party.")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern(message)
.arguments(Args.of("hostGender", "male", "host", malePerson, "guest", femalePerson, "guestCount", 3))
.expected("Mr. John Doe invites Ms. Jane Doe and 2 other people to his party.")
.build());
TestUtils.runTestCase(CUSTOM_FUNCTION_REGISTRY, new TestCase.Builder()
.pattern(message)
.arguments(Args.of("hostGender", "unknown", "host", unknownPerson, "guest", femalePerson, "guestCount", 2))
.expected("Mr./Ms. Anonymous Doe invites Ms. Jane Doe and one other person to their party.")
.build());
}
}