blob: 8893da4df577decee9dda5d46402b127010ecaf8 [file] [log] [blame]
package org.unicode.cldr.unittest;
import com.google.common.base.Joiner;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
import com.ibm.icu.dev.test.TestFmwk;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import org.unicode.cldr.util.CLDRConfig;
import org.unicode.cldr.util.CLDRPaths;
import org.unicode.cldr.util.DtdData;
import org.unicode.cldr.util.DtdData.Attribute;
import org.unicode.cldr.util.DtdData.Element;
import org.unicode.cldr.util.DtdData.Element.ValueConstraint;
import org.unicode.cldr.util.DtdData.ElementType;
import org.unicode.cldr.util.DtdType;
import org.unicode.cldr.util.MatchValue;
import org.unicode.cldr.util.MatchValue.EnumParser;
import org.unicode.cldr.util.Pair;
import org.unicode.cldr.util.SupplementalDataInfo;
import org.unicode.cldr.util.Validity;
import org.unicode.cldr.util.Validity.Status;
import org.unicode.cldr.util.XMLFileReader;
import org.unicode.cldr.util.XPathParts;
public class TestDtdData extends TestFmwk {
private static final String COMMON_DIR = CLDRPaths.BASE_DIRECTORY + "common/";
static CLDRConfig testInfo = CLDRConfig.getInstance();
private static final SupplementalDataInfo SUPPLEMENTAL_DATA_INFO =
testInfo.getSupplementalDataInfo();
public static void main(String[] args) {
new TestDtdData().run(args);
}
public void TestRegularized() {
String[][] tests = {
/*
* TODO: re-enable the first test or something like it.
* It began to fail as a result of copying dtdData in XPathParts.cloneAsThawed rather than always making it null.
* Reference: https://unicode.org/cldr/trac/ticket/12007
*/
// has a value & value attribute
// { "//supplementalData/plurals/pluralRanges[@locales=\"id
// ja\"]/pluralRange[@start=\"a\"][@end=\"b\"][@result=\"c\"]",
//
// "//supplementalData/plurals/pluralRanges[@locales=\"id\"]/pluralRange[@end=\"b\"][@start=\"a\"]/_result==c",
//
// "//supplementalData/plurals/pluralRanges[@locales=\"ja\"]/pluralRange[@end=\"b\"][@start=\"a\"]/_result==c"
// },
{
"//supplementalData/plurals[@type=\"cardinal\"]/pluralRules[@locales=\"am as bn\"]/pluralRule[@count=\"other\"]",
"//supplementalData/plurals[@type=\"cardinal\"]/pluralRules[@locales=\"am\"]/pluralRule[@count=\"other\"]==VALUE",
"//supplementalData/plurals[@type=\"cardinal\"]/pluralRules[@locales=\"as\"]/pluralRule[@count=\"other\"]==VALUE",
"//supplementalData/plurals[@type=\"cardinal\"]/pluralRules[@locales=\"bn\"]/pluralRule[@count=\"other\"]==VALUE"
},
// no change
{
"//supplementalData/primaryZones/primaryZone[@iso3166=\"CL\"]",
"//supplementalData/primaryZones/primaryZone[@iso3166=\"CL\"]==VALUE"
},
// has only value attributes
{
"//supplementalData/version[@number=\"$Revision: 12197 $\"][@cldrVersion=\"29\"][@unicodeVersion=\"8.0.0\"]",
"//supplementalData/version/_cldrVersion==29",
"//supplementalData/version/_unicodeVersion==8.0.0"
},
// no change
{
"//ldml/identity/language[@type=\"af\"]",
"//ldml/identity/language[@type=\"af\"]==VALUE"
},
// // has a value & value attribute
// {"//ldml/annotations/annotation[@cp=\"[ߘ€]\"][@tts=\"grinnikende
// gesig\"]",
// "//ldml/annotations/annotation[@cp=\"[ߘ€]\"]",
// "//ldml/annotations/annotation_[@cp=\"[ߘ€]\"]/_tts"
// },
// has a value & value attribute
{
"//ldml/rbnf/rulesetGrouping[@type=\"SpelloutRules\"]/ruleset[@type=\"2d-year\"][@access=\"private\"]/rbnfrule[@value=\"0\"]",
"//ldml/rbnf/rulesetGrouping[@type=\"SpelloutRules\"]/ruleset[@type=\"2d-year\"]/_access==private",
"//ldml/rbnf/rulesetGrouping[@type=\"SpelloutRules\"]/ruleset[@type=\"2d-year\"]/rbnfrule==VALUE",
"//ldml/rbnf/rulesetGrouping[@type=\"SpelloutRules\"]/ruleset[@type=\"2d-year\"]/rbnfrule_/_value==0"
},
// has a value attribute
{
"//ldmlBCP47/version[@number=\"$Revision: 12232 $\"][@cldrVersion=\"29\"]",
"//ldmlBCP47/version/_cldrVersion==29"
},
// has a value & value attribute
{
"//ldmlBCP47/keyword/key[@name=\"ca\"][@description=\"Calendar algorithm key\"][@deprecated=\"false\"][@alias=\"calendar\"][@valueType=\"incremental\"]/type[@name=\"chinese\"][@description=\"Traditional Chinese calendar\"][@deprecated=\"false\"]",
"//ldmlBCP47/keyword/key[@name=\"ca\"]/_alias==calendar",
"//ldmlBCP47/keyword/key[@name=\"ca\"]/_description==Calendar algorithm key",
"//ldmlBCP47/keyword/key[@name=\"ca\"]/_valueType==incremental",
"//ldmlBCP47/keyword/key[@name=\"ca\"]/type[@name=\"chinese\"]/_description==Traditional Chinese calendar",
"//ldmlBCP47/keyword/key[@name=\"ca\"]/_deprecated==false",
"//ldmlBCP47/keyword/key[@name=\"ca\"]/type[@name=\"chinese\"]/_deprecated==false"
},
};
Multimap<String, String> extras = TreeMultimap.create();
for (String[] test : tests) {
final String path = test[0];
final Set<String> expected =
new TreeSet<>(Arrays.asList(test).subList(1, Arrays.asList(test).size()));
DtdData dtdData = DtdData.getInstance(DtdType.fromPath(path));
Set<String> actual = new TreeSet<>();
XPathParts parts = XPathParts.getFrozenInstance(path);
Set<String> pathForValues = dtdData.getRegularizedPaths(parts, extras);
for (Entry<String, Collection<String>> entry : extras.asMap().entrySet()) {
for (String value : entry.getValue()) {
actual.add(entry.getKey() + "==" + value);
}
}
if (pathForValues != null) {
for (String item : pathForValues) {
actual.add(item + "==VALUE");
}
}
TreeSet<String> temp = new TreeSet<>(actual);
temp.removeAll(expected);
assertEquals("too many, extra: " + path, Collections.emptySet(), temp);
temp.clear();
temp.addAll(expected);
temp.removeAll(actual);
assertEquals("too few, missing: " + path, Collections.emptySet(), temp);
}
}
public void TestDirectories() throws IOException {
for (File dir : new File(COMMON_DIR).listFiles()) {
if (dir.isDirectory() == false) {
continue;
}
int maxFiles = 5;
logln(dir.toString());
for (File file : dir.listFiles()) {
String name = file.getName();
if (!name.endsWith(".xml")) {
continue;
}
List<Pair<String, String>> data = new ArrayList<>();
for (Pair<String, String> pathValue :
XMLFileReader.loadPathValues(file.toString(), data, true)) {
DtdType dtdTypeFromPath = DtdType.fromPath(pathValue.getFirst());
if (!dtdTypeFromPath.directories.contains(dir.getName())) {
errln(
"Mismatch in "
+ file.toString()
+ ": "
+ dtdTypeFromPath
+ ", "
+ dtdTypeFromPath.directories);
} else {
logln("\t" + file.getName() + "\t" + dtdTypeFromPath);
}
break;
}
if (--maxFiles < 0) break;
}
}
}
public void TestValueAttributesWithChildren() {
Multimap<String, String> m = TreeMultimap.create();
for (DtdType type : DtdType.values()) {
if (type.getStatus() != DtdType.DtdStatus.active) {
continue;
}
if (type == DtdType.ldmlICU) {
continue;
}
DtdData dtdData = DtdData.getInstance(type);
Element special = dtdData.getElementFromName().get("special");
checkEmpty(
m,
type,
dtdData.ROOT,
special,
new HashSet<Element>(),
new ArrayList<>(Arrays.asList(dtdData.ROOT)));
}
Collection<String> items = m.get("error");
if (items != null) {
for (String item : items) {
errln(item);
}
}
if (isVerbose()) {
items = m.get("warn");
if (items != null) {
for (String item : items) {
warnln(item);
}
}
}
}
/**
* make sure that if the final element is empty, there is a value attribute required somewhere
* in the path
*
* @param m
* @param type
* @param seen
*/
private void checkEmpty(
Multimap<String, String> m,
DtdType type,
Element element,
Element special,
HashSet<Element> seen,
List<Element> parents) {
if (seen.contains(element)) {
return;
}
seen.add(element);
if (element.isDeprecated()) {
return;
}
HashSet<Attribute> valueAttributes = new LinkedHashSet<>();
HashSet<Attribute> distAttributes = new LinkedHashSet<>();
HashSet<Attribute> metadataAttributes =
new LinkedHashSet<>(); // TODO: not used currently, ignored
for (Attribute attribute : element.getAttributes().keySet()) {
if (attribute.isDeprecated()) continue;
switch (attribute.getStatus()) {
case value:
// if (attribute.mode == Mode.REQUIRED || attribute.mode == Mode.FIXED)
// {//strong test
valueAttributes.add(attribute);
break;
case distinguished:
distAttributes.add(attribute);
break;
case metadata:
metadataAttributes.add(attribute);
break;
}
}
ElementType elementType = element.getType();
switch (elementType) {
case EMPTY:
if (valueAttributes.isEmpty()) {
if (!distAttributes.isEmpty()) {
m.put(
"warn",
type
+ "\t||"
+ showPath(parents)
+ "||path has neither value NOR value attributes NOR dist. attrs.||");
} else {
if (!ALLOWED_EMPTY_NO_VALUE_PATHS.contains(showPath(parents))) {
m.put(
"error",
"\t||"
+ showPath(parents)
+ "||path has neither value NOR value attributes||");
}
}
}
break;
case ANY:
case PCDATA:
if (!valueAttributes.isEmpty()) {
m.put(
"warn",
"\t||"
+ showPath(parents)
+ "||path has both value AND value attributes||"
+ valueAttributes
+ "||");
}
break;
case CHILDREN:
// first remove deprecateds, and special
List<Element> children = new ArrayList<>(element.getChildren().keySet());
for (Iterator<Element> it = children.iterator(); it.hasNext(); ) {
Element child = it.next();
if (child.equals(special) || child.isDeprecated()) {
it.remove();
}
}
// if no children left, treat like EMPTY
if (children.isEmpty()) {
if (valueAttributes.isEmpty()) {
if (!ALLOWED_EMPTY_NO_VALUE_PATHS.contains(showPath(parents))) {
errln(
type
+ "\t|| "
+ showPath(parents)
+ "||DTD has neither value NOR value attributes (only special or deprecated children)||");
}
}
break;
}
if (!valueAttributes.isEmpty()) {
switch (element.getName()) {
case "ruleset":
logKnownIssue("cldrbug:8909", "waiting for RBNF to use data");
break;
case "key":
case "territory":
case "transform":
logKnownIssue("cldrbug:9982", "Lower priority fixes to bad xml");
break;
default:
m.put(
"error",
"\t||"
+ showPath(parents)
+ "||DTD has both children AND value attributes: tr35.md#XML_Format"
+ "||"
+ valueAttributes
+ "||"
+ children
+ "||");
break;
}
}
for (Element child : children) {
parents.add(child);
checkEmpty(m, type, child, special, seen, parents);
parents.remove(parents.size() - 1);
}
break;
}
}
private String showPath(List<Element> parents) {
return "!//" + Joiner.on("/").join(parents);
}
public void TestNewDtdData() {
for (DtdType type : DtdType.values()) {
if (type.getStatus() != DtdType.DtdStatus.active) {
continue;
}
if (type == DtdType.ldmlICU) {
continue;
}
DtdData dtdData = DtdData.getInstance(type);
for (Element element : dtdData.getElements()) {
boolean orderedNew = dtdData.isOrdered(element.name);
boolean orderedOld = isOrderedOld(element.name, type);
assertEquals(
"isOrdered " + type + ":" + element + " (old vs. DTD)",
orderedOld,
orderedNew);
boolean deprecatedNew = dtdData.isDeprecated(element.name, "*", "*");
boolean deprecatedOld =
SUPPLEMENTAL_DATA_INFO.isDeprecated(type, element.name, "*", "*");
assertEquals(
"isDeprecated " + type + ":" + element + " (old vs. DTD)",
deprecatedOld,
deprecatedNew);
for (Attribute attribute : element.getAttributes().keySet()) {
boolean distinguishedNew =
dtdData.isDistinguishing(element.name, attribute.name);
boolean distinguishedOld =
isDistinguishingOld(type, element.name, attribute.name);
if (!assertEquals(
"isDistinguished "
+ type
+ ": elementName.equals(\""
+ element.name
+ "\") && attribute.equals(\""
+ attribute.name
+ "\") (old vs. DTD)",
distinguishedOld,
distinguishedNew)) {
// for debugging
dtdData.isDistinguishing(element.name, attribute.name);
isDistinguishingOld(type, element.name, attribute.name);
}
deprecatedNew = dtdData.isDeprecated(element.name, attribute.name, "*");
deprecatedOld =
SUPPLEMENTAL_DATA_INFO.isDeprecated(
type, element.name, attribute.name, "*");
assertEquals(
"isDeprecated " + type + ":" + attribute + " (old vs. DTD)",
deprecatedOld,
deprecatedNew);
for (String value : attribute.values.keySet()) {
deprecatedNew = dtdData.isDeprecated(element.name, attribute.name, value);
deprecatedOld =
SUPPLEMENTAL_DATA_INFO.isDeprecated(
type, element.name, attribute.name, value);
assertEquals(
"isDeprecated "
+ type
+ ":"
+ attribute
+ ":"
+ value
+ " (old vs. DTD)",
deprecatedOld,
deprecatedNew);
}
}
}
}
}
// public void TestNonLeafValues() {
// for (DtdType type : DtdType.values()) {
// if (type == DtdType.ldmlICU) {
// continue;
// }
// DtdData dtdData = DtdData.getInstance(type);
// for (Element element : dtdData.getElements()) {
// if (element.isDeprecated()) {
// continue;
// }
// switch (element.getType()) {
// case PCDATA:
// case EMPTY: continue;
// case ANY:
// }
// for (Attribute attribute : element.getAttributes().keySet()) {
// if (attribute.isDeprecated()) {
// continue;
// }
// switch (attribute.getStatus()) {
// case value:
// errln(type + "\t" + element + "\t" + attribute + "\t");
// }
// }
// }
// }
//
// }
/** paths that can be empty elements. Each item starts with '!' because of showPath. */
static final Set<String> ALLOWED_EMPTY_NO_VALUE_PATHS =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList("!//keyboardTest3/tests/test/backspace")));
// TESTING CODE
static final Set<String> orderedElements =
Collections.unmodifiableSet(
new HashSet<>(
Arrays.asList(
// can prettyprint with TestAttributes
// DTD: ldml
// <collation> children
"base",
"optimize",
"rules",
"settings",
"suppress_contractions",
// <rules> children
"i",
"ic",
"p",
"pc",
"reset",
"s",
"sc",
"t",
"tc",
"x",
// <x> children
"context",
"extend",
"i",
"ic",
"p",
"pc",
"s",
"sc",
"t",
"tc",
"last_non_ignorable",
"last_secondary_ignorable",
"last_tertiary_ignorable",
// <variables> children
"variable",
// <rulesetGrouping> children
"ruleset",
// <ruleset> children
"rbnfrule",
// <exceptions> children (deprecated, use 'suppressions')
"exception",
// <suppressions> children
"suppression",
// DTD: supplementalData
// <territory> children
// "languagePopulation",
// <postalCodeData> children
// "postCodeRegex",
// <characters> children
// "character-fallback",
// <character-fallback> children
// "character",
// <character> children
"substitute", // may occur multiple times
// <transform> children
"comment",
"tRule",
// <validity> children
// both of these don't need to be ordered, but must delay
// changes until after isDistinguished always uses
// the dtd type
"attributeValues", // attribute values shouldn't need ordering,
// as long as these are distinguishing:
// elements="zoneItem" attributes="type"
"variable", // doesn't need to be ordered
// <pluralRules> children
"pluralRule",
// <codesByTerritory> children
// "telephoneCountryCode", // doesn't need ordering, as long as
// code is distinguishing, telephoneCountryCode
// code="376"
// <numberingSystems> children
// "numberingSystem", // doesn't need ordering, since id is
// distinguishing
// <metazoneInfo> children
// "timezone", // doesn't need ordering, since type is
// distinguishing
"attributes", // shouldn't need this in
// //supplementalData/metadata/suppress/attributes, except that
// the
// element is badly designed
"languageMatch",
"exception", // needed for new segmentations
"coverageLevel", // needed for supplemental/coverageLevel.xml
"coverageVariable", // needed for supplemental/coverageLevel.xml
"substitute", // needed for characters.xml
"unitPreference")));
static final Set<String> orderedKeyboardTestElements =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList("emit", "keystroke", "check", "backspace")));
static final Set<String> orderedKeyboardElements =
Collections.unmodifiableSet(
new HashSet<>(
Arrays.asList("name", "reorder", "row", "settings", "transform")));
public static boolean isOrderedOld(String element, DtdType type) {
switch (type) {
case keyboardTest3:
return orderedKeyboardTestElements.contains(element);
case keyboard3:
return orderedKeyboardElements.contains(element);
default:
// all others, above
return orderedElements.contains(element);
}
}
public boolean isDistinguishingOld(DtdType dtdType, String elementName, String attribute) {
switch (dtdType) {
case ldml:
return attribute.equals("_q")
|| attribute.equals("key")
|| attribute.equals("indexSource")
|| attribute.equals("request")
|| attribute.equals("count")
|| attribute.equals("id")
|| attribute.equals("registry")
|| attribute.equals("alt")
|| attribute.equals("mzone")
|| attribute.equals("from")
|| attribute.equals("to")
|| attribute.equals("value") && !elementName.equals("rbnfrule")
|| attribute.equals("yeartype")
|| attribute.equals("numberSystem")
|| attribute.equals("parent")
|| elementName.equals("annotation") && attribute.equals("cp")
|| (attribute.equals("type")
&& !elementName.equals("default")
&& !elementName.equals("measurementSystem")
&& !elementName.equals("mapping")
&& !elementName.equals("abbreviationFallback")
&& !elementName.equals("preferenceOrdering"))
|| (elementName.equals("parseLenients")
&& (attribute.equals("scope") || attribute.equals("level")))
|| (elementName.equals("parseLenient") && attribute.equals("sample"))
|| (elementName.equals("ordinalMinimalPairs")
&& attribute.equals("ordinal"))
|| (elementName.equals("styleName") && attribute.equals("subtype"))
|| (elementName.equals("unitPattern") && attribute.equals("case"))
|| (elementName.equals("compoundUnitPattern") && attribute.equals("case"))
|| (elementName.equals("compoundUnitPattern1")
&& (attribute.equals("case") || attribute.equals("gender")))
|| (elementName.equals("genderMinimalPairs") && attribute.equals("gender"))
|| (elementName.equals("caseMinimalPairs") && attribute.equals("case"))
|| (elementName.equals("nameOrderLocales") && attribute.equals("order"))
|| (elementName.equals("initialPattern") && attribute.equals("type"))
|| (elementName.equals("personName")
&& (attribute.equals("order")
|| attribute.equals("length")
|| attribute.equals("usage")
|| attribute.equals("formality")))
|| (elementName.equals("parameterDefault") && attribute.equals("parameter"))
|| (elementName.equals("sampleName") && attribute.equals("item"))
|| (elementName.equals("nameField") && attribute.equals("type"));
case ldmlBCP47:
return attribute.equals("_q")
// || attribute.equals("alias")
|| attribute.equals("name")
|| attribute.equals("extension");
case supplementalData:
return attribute.equals("_q")
|| (elementName.equals("matchVariable") && attribute.equals("id"))
|| attribute.equals("iso4217")
|| attribute.equals("iso3166")
|| attribute.equals("code") && elementName.equals("telephoneCountryCode")
|| (attribute.equals("type")
&& !elementName.equals("calendarSystem")
&& !elementName.equals("mapZone")
&& !elementName.equals("numberingSystem")
&& !elementName.equals("variable"))
|| attribute.equals("id") && elementName.equals("variable")
|| attribute.equals("alt")
|| attribute.equals("dtds")
|| attribute.equals("idStatus")
|| elementName.equals("deprecatedItems")
&& (attribute.equals("type")
|| attribute.equals("elements")
|| attribute.equals("attributes")
|| attribute.equals("values"))
|| elementName.equals("character") && attribute.equals("value")
|| elementName.equals("dayPeriodRules") && attribute.equals("locales")
|| elementName.equals("dayPeriodRule") && (attribute.equals("type"))
|| elementName.equals("metazones") && attribute.equals("type")
|| elementName.equals("subgroup") && attribute.equals("subtype")
|| elementName.equals("mapZone")
&& (attribute.equals("other") || attribute.equals("territory"))
|| elementName.equals("postCodeRegex") && attribute.equals("territoryId")
|| elementName.equals("calendarPreference")
&& attribute.equals("territories")
|| elementName.equals("minDays") && attribute.equals("count")
|| elementName.equals("firstDay") && attribute.equals("day")
|| elementName.equals("weekendStart") && attribute.equals("day")
|| elementName.equals("weekendEnd") && attribute.equals("day")
|| elementName.equals("measurementSystem") && attribute.equals("category")
|| elementName.equals("unitPreferences")
&& (attribute.equals("category")
|| attribute.equals("usage")
|| attribute.equals("scope"))
|| elementName.equals("unitPreference")
&& (attribute.equals("regions") || attribute.equals("geq"))
|| elementName.equals("distinguishingItems")
&& attribute.equals("attributes")
|| elementName.equals("codesByTerritory") && attribute.equals("territory")
|| elementName.equals("currency") && attribute.equals("iso4217")
|| elementName.equals("territoryAlias") && attribute.equals("type")
|| elementName.equals("territoryCodes") && attribute.equals("type")
|| elementName.equals("group")
&& (attribute.equals("status")) // || attribute.equals("grouping")
|| elementName.equals("plurals") && attribute.equals("type")
|| elementName.equals("pluralRules") && attribute.equals("locales")
|| elementName.equals("pluralRule") && attribute.equals("count")
|| elementName.equals("pluralRanges") && attribute.equals("locales")
|| elementName.equals("pluralRange")
&& (attribute.equals("start") || attribute.equals("end"))
|| elementName.equals("hours")
&& (attribute.equals("preferred") || attribute.equals("allowed"))
|| elementName.equals("personList") && attribute.equals("type")
|| elementName.equals("likelySubtag") && attribute.equals("from")
|| elementName.equals("rgPath") && attribute.equals("path")
|| elementName.equals("timezone") && attribute.equals("type")
|| (elementName.equals("metazoneId") && attribute.equals("shortId"))
|| elementName.equals("usesMetazone")
&& (attribute.equals("to")
|| attribute.equals("from")) // attribute.equals("mzone") ||
|| elementName.equals("numberingSystem") && attribute.equals("id")
|| elementName.equals("group") && attribute.equals("type")
|| elementName.equals("currency") && attribute.equals("from")
|| elementName.equals("currency") && attribute.equals("to")
|| elementName.equals("currency") && attribute.equals("iso4217")
|| elementName.equals("parentLocales") && attribute.equals("component")
|| (elementName.equals("parentLocale")
|| elementName.equals("languageGroup"))
&& attribute.equals("parent")
|| elementName.equals("currencyCodes") && attribute.equals("type")
|| elementName.equals("approvalRequirement")
&& (attribute.equals("locales") || attribute.equals("paths"))
|| elementName.equals("weekOfPreference") && attribute.equals("locales")
|| elementName.equals("coverageVariable") && attribute.equals("key")
|| elementName.equals("coverageLevel")
&& (attribute.equals("inLanguage")
|| attribute.equals("inScript")
|| attribute.equals("inTerritory")
|| attribute.equals("match"))
|| elementName.equals("languageMatch")
&& (attribute.equals("desired") || attribute.equals("supported"))
|| elementName.equals("pathMatch") && (attribute.equals("id"))
|| (elementName.equals("transform")
&& (attribute.equals("source")
|| attribute.equals("target")
|| attribute.equals("direction")
|| attribute.equals("variant")))
|| (elementName.equals("grammaticalFeatures")
&& (attribute.equals("locales") || attribute.equals("targets")))
|| (elementName.equals("grammaticalDefiniteness")
&& attribute.equals("scope"))
|| (elementName.equals("grammaticalCase") && attribute.equals("scope"))
|| (elementName.equals("grammaticalGender") && attribute.equals("scope"))
|| (elementName.equals("convertUnit")
&& (attribute.equals("source") || attribute.equals("target")))
|| (elementName.equals("unitConstant") && attribute.equals("constant"))
|| (elementName.equals("unitQuantity") && attribute.equals("baseUnit"))
|| attribute.equals("scope")
|| elementName.equals("deriveComponent")
&& (attribute.equals("feature") || attribute.equals("structure"))
|| elementName.equals("grammaticalDerivations")
&& attribute.equals("locales")
|| elementName.equals("deriveCompound")
&& (attribute.equals("feature") || attribute.equals("structure"))
|| (elementName.equals("nameOrderLocalesDefault")
&& attribute.equals("order"));
case keyboard3:
if (elementName.equals("keyboard3") && attribute.equals("locale")
|| elementName.equals("layers") && attribute.equals("formId")
|| elementName.equals("layers") && attribute.equals("minDeviceWidth")
|| elementName.equals("layer") && attribute.equals("modifiers")
|| elementName.equals("form") && attribute.equals("id")
|| elementName.equals("key") && attribute.equals("id")
|| elementName.equals("keyList") && attribute.equals("id")
|| elementName.equals("flick") && attribute.equals("id")
|| elementName.equals("import") && attribute.equals("path")
|| elementName.equals("locale") && attribute.equals("id")
|| elementName.equals("import") && attribute.equals("base")
|| elementName.equals("layer") && attribute.equals("id")
|| elementName.equals("string") && attribute.equals("id")
|| elementName.equals("set") && attribute.equals("id")
|| elementName.equals("uset") && attribute.equals("id")) {
return true;
}
// fall through to old keyboard
return attribute.equals("_q")
|| elementName.equals("keyboard3") && attribute.equals("locale")
|| elementName.equals("keyMap") && attribute.equals("modifiers")
|| elementName.equals("key") && attribute.equals("flickId")
|| elementName.equals("transforms") && attribute.equals("type")
|| elementName.equals("transform") && attribute.equals("after")
|| elementName.equals("flickSegment") && attribute.equals("directions")
|| elementName.equals("display") && attribute.equals("output")
|| elementName.equals("display") && attribute.equals("keyId")
|| elementName.equals("flick") && attribute.equals("id");
case keyboardTest3:
return elementName.equals("tests") && attribute.equals("name")
|| elementName.equals("test") && attribute.equals("name")
|| elementName.equals("repertoire") && attribute.equals("name")
|| elementName.equals("info") && attribute.equals("name");
case ldmlICU:
return false;
default:
throw new IllegalArgumentException(
"type missing from isDistinguishingOld(): " + dtdType);
}
// if (result != matches(distinguishingAttributeMap, new String[]{elementName, attribute},
// true)) {
// matches(distinguishingAttributeMap, new String[]{elementName, attribute}, true);
// throw new IllegalArgumentException("Failed: " + elementName + ", " + attribute);
// }
}
/**
* @deprecated
* @return
*/
@Deprecated
public static Set<String> getSerialElements() {
return orderedElements;
}
public static enum TestEnum {
a,
b,
c,
d
}
public void TestEnumParser() throws ClassNotFoundException {
Object[][] tests = {
{Status.class, "regular", Status.regular},
{Status.class, "regular deprecated", Validity.Status.regular, Status.deprecated},
{
Status.class,
"deprecated regular",
"regular deprecated",
Validity.Status.regular,
Status.deprecated
},
{TestEnum.class, "b a", "a b", TestEnum.a, TestEnum.b},
{TestEnum.class, "!c d", "a b", TestEnum.a, TestEnum.b},
};
for (Object[] test : tests) {
Class aClass = (Class<Enum>) test[0];
EnumParser parser = MatchValue.EnumParser.of(aClass);
final String inputText = (String) test[1];
int startOfValues = test[2] instanceof String ? 3 : 2;
String expectedFormat = startOfValues == 3 ? (String) test[2] : inputText;
Set<Enum> expected = new TreeSet<>();
for (Object item : Arrays.asList(test).subList(startOfValues, test.length)) {
expected.add((Enum) item);
}
Set<Enum> actual = parser.parse(inputText);
assertEquals("parse " + test[1], expected, actual);
String formatted = parser.format(expected);
assertEquals("format " + expected, expectedFormat, formatted);
}
}
public void TestMatchValue() {
String[][] tests = {{"validity/short-unit/deprecated", "inch-hg"}};
for (String[] test : tests) {
MatchValue matcher = MatchValue.of(test[0]);
final String toMatch = test[1];
boolean expectedValue = test.length < 3 ? true : Boolean.parseBoolean(test[2]);
final boolean actual = matcher.is(toMatch);
assertEquals(Arrays.asList(test).toString(), expectedValue, actual);
}
}
public void testGetAltMatch() {
DtdData dtdData = DtdData.getInstance(DtdType.ldml);
String[][] tests = {
/* Example
<!ELEMENT script ( #PCDATA ) >
<!ATTLIST script alt NMTOKENS #IMPLIED >
<!--@MATCH:literal/secondary, short, stand-alone, variant-->
*/
{"script", "alt", "secondary", "short", "stand-alone", "variant"},
/* Example
<!ELEMENT languages ( alias | ( language | special )* ) >
<!ATTLIST languages draft (approved | contributed | provisional | unconfirmed | true | false) #IMPLIED >
*/
{
"languages",
"draft",
"approved",
"contributed",
"provisional",
"unconfirmed",
"true",
"false"
},
};
for (String[] test : tests) {
Element element = dtdData.getElementFromName().get(test[0]);
Attribute attribute = element.getAttributeNamed(test[1]);
Set<String> expected = new HashSet<>(Arrays.asList(test).subList(2, test.length));
assertEquals(
"Match items for «" + test[0] + "@" + test[1] + "»",
expected,
attribute.getMatchLiterals());
}
}
public void testEmptyPcdata() {
String[][] tests = {
{"//ldml/personNames/nameOrderLocales[@order=\"givenFirst\"]", "any"},
{"//ldml/personNames/foreignSpaceReplacement", "any"},
{"//ldml/personNames/nativeSpaceReplacement", "any"},
{"//ldml/personNames/initialPattern[@type=\"initial\"]", "nonempty"},
};
for (String[] test : tests) {
String path = test[0];
ValueConstraint expected = ValueConstraint.valueOf(test[1]);
ValueConstraint actual = DtdData.getValueConstraint(path);
ValueConstraint check = DtdData.Element.ValueConstraint.nonempty;
assertEquals(path, expected, actual);
}
}
}