blob: b12bd0bd0d7ac1dc5a42a818a1e8d37c58fe7639 [file] [log] [blame]
// © 2020 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
package org.unicode.icu.tool.cldrtoicu.localedistance;
import static com.google.common.truth.Truth.assertThat;
import static org.unicode.icu.tool.cldrtoicu.testing.AssertUtils.assertThrows;
import org.junit.Test;
import com.google.common.collect.ImmutableMap;
import com.ibm.icu.util.BytesTrie;
// NOTE: Remember that here, "region" is synonymous with a "partition group ID".
public class DistanceTableTest {
@Test
public void testSimpleMapping() {
DistanceTable.Builder builder = defaultTable();
// You need at least one non default mapping.
builder.addDistance(23, true, "en", "en");
DistanceTable table = builder.build();
assertThat(getTrieTable(table)).containsExactly("en-en", 23);
assertThat(table.getDefaultDistances()).asList().containsExactly(80, 50, 4, 4).inOrder();
}
@Test
public void testReverseMapping() {
DistanceTable.Builder builder = defaultTable();
// You need at least one non default mapping.
builder.addDistance(1, false, "no", "nb");
DistanceTable table = builder.build();
assertThat(getTrieTable(table))
.containsExactly(
"nb-no", 1,
"no-nb", 1)
.inOrder();
}
@Test
public void testMinRegionDistance() {
DistanceTable.Builder builder = defaultTable();
// You need at least one non default mapping.
builder.addDistance(2, true, "zh", "zh", "Hant", "Hant", "1", "1");
builder.addDistance(4, true, "zh", "zh", "Hant", "Hant", "2", "2");
builder.addDistance(6, true, "zh", "zh", "Hant", "Hant", "*", "*");
DistanceTable table = builder.build();
assertThat(getTrieTable(table))
.containsExactly(
// Inferred mappings for "parent" locales.
"zh-zh", 0, // Equal locales have zero distance.
"zh-zh-*-*", 50, // Default unknown script distance
"zh-zh-Hant-Hant", 0,
// Trie ordering prefers "*" mapping at the front.
"zh-zh-Hant-Hant-*-*", 6,
"zh-zh-Hant-Hant-1-1", 2,
"zh-zh-Hant-Hant-2-2", 4)
.inOrder();
// Minimum region distance is recorded successfully (last value).
assertThat(table.getDefaultDistances()).asList().containsExactly(80, 50, 4, 2).inOrder();
}
@Test
public void testSkipScript() {
DistanceTable.Builder builder = defaultTable();
// You need at least one non default mapping.
builder.addDistance(2, true, "en", "en", "*", "*", "1", "1");
builder.addDistance(4, true, "en", "en", "*", "*", "*", "*");
DistanceTable table = builder.build();
assertThat(getTrieTable(table))
.containsExactly(
// "en-en" is marked for "skip script" so the remaining "en-en-..."
// mappings are correctly interpretted as "language-region".
"en-en", 128,
"en-en-*-*", 4,
"en-en-1-1", 2)
.inOrder();
}
@Test
public void testFirstOneWins() {
DistanceTable.Builder builder = defaultTable();
// Duplicate mappings are only expected for "region" where different rules can
// produce duplicate mappings by virtue of having non-disjoint region partitions.
builder.addDistance(2, true, "en", "en", "*", "*", "1", "1");
builder.addDistance(4, true, "en", "en", "*", "*", "1", "1"); // ignored
builder.addDistance(6, true, "en", "en", "*", "*", "*", "*");
DistanceTable table = builder.build();
assertThat(getTrieTable(table))
.containsExactly(
"en-en", 128,
"en-en-*-*", 6,
"en-en-1-1", 2)
.inOrder();
}
@Test
public void testBadDistance() {
IllegalArgumentException e = assertThrows(
IllegalArgumentException.class,
() -> defaultTable().addDistance(123, true, "en", "fr"));
assertThat(e).hasMessageThat().contains("distance");
assertThat(e).hasMessageThat().contains("123");
}
@Test
public void testBadParameters() {
IllegalArgumentException e = assertThrows(
IllegalArgumentException.class,
() -> defaultTable().addDistance(1, true, "en", "en", "*"));
assertThat(e).hasMessageThat().contains("invalid number of arguments");
}
@Test
public void testBadKeys() {
IllegalArgumentException e = assertThrows(
IllegalArgumentException.class,
() -> defaultTable().addDistance(1, true, "en", "*"));
assertThat(e).hasMessageThat().contains("invalid mapping key");
assertThat(e).hasMessageThat().contains("en");
assertThat(e).hasMessageThat().contains("�");
}
private static DistanceTable.Builder defaultTable() {
DistanceTable.Builder table = DistanceTable.builder();
// Defaults (which are necessary to add, but should always be trimmed from results).
// The actual distances don't matter (and are copied to the distance array).
table.addDistance(80, false, "*", "*");
table.addDistance(50, false, "*", "*", "*", "*");
table.addDistance(4, false, "*", "*", "*", "*", "*", "*");
return table;
}
@Test
public void testNoDefaultLanguage() {
// Don't get the default table, since we need to test without defaults.
DistanceTable.Builder builder = DistanceTable.builder();
IllegalStateException e = assertThrows(IllegalStateException.class, builder::build);
assertThat(e).hasMessageThat().contains("missing default language");
}
@Test
public void testNoDefaultScript() {
// Don't get the default table, since we need to test without defaults.
DistanceTable.Builder builder = DistanceTable.builder();
builder.addDistance(80, false, "*", "*");
IllegalStateException e = assertThrows(IllegalStateException.class, builder::build);
assertThat(e).hasMessageThat().contains("missing default script");
}
@Test
public void testNoDefaultRegion() {
// Don't get the default table, since we need to test without defaults.
DistanceTable.Builder builder = DistanceTable.builder();
builder.addDistance(80, false, "*", "*");
builder.addDistance(50, false, "*", "*", "*", "*");
IllegalStateException e = assertThrows(IllegalStateException.class, builder::build);
assertThat(e).hasMessageThat().contains("missing default region");
}
// VisibleForTesting
public ImmutableMap<String, Integer> getTrieTable(DistanceTable table) {
// We rebuild the Trie from the byte[] data.
return TestData.getTrieTable(new BytesTrie(table.getTrie().toByteArray(), 0), "*-*", i -> i);
}
}