| package org.unicode.cldr.unittest; |
| |
| 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.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; |
| |
| 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; |
| |
| 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 == 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 { |
| 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()) { |
| errln(type + "\t|| " + showPath(parents) + "||path has neither value NOR value attributes||"); |
| } |
| 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 == 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, orderedOld, orderedNew); |
| boolean deprecatedNew = dtdData.isDeprecated(element.name, "*", "*"); |
| boolean deprecatedOld = SUPPLEMENTAL_DATA_INFO.isDeprecated(type, element.name, "*", "*"); |
| assertEquals("isDeprecated " + type + ":" + element, deprecatedOld, deprecatedNew); |
| |
| for (Attribute attribute : element.getAttributes().keySet()) { |
| boolean distinguishedNew = dtdData.isDistinguishing(element.name, attribute.name); |
| boolean distinguishedOld = isDistinguishingOld(type, element.name, attribute.name); |
| assertEquals("isDistinguished " + type |
| + ": elementName.equals(\"" + element.name + "\") && attribute.equals(\"" + attribute.name + "\")", distinguishedOld, distinguishedNew); |
| deprecatedNew = dtdData.isDeprecated(element.name, attribute.name, "*"); |
| deprecatedOld = SUPPLEMENTAL_DATA_INFO.isDeprecated(type, element.name, attribute.name, "*"); |
| assertEquals("isDeprecated " + type + ":" + attribute, 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, 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"); |
| // } |
| // } |
| // } |
| // } |
| // |
| // } |
| |
| // 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" |
| ))); |
| |
| public static boolean isOrderedOld(String element, DtdType type) { |
| 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("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") |
| || (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("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 keyboard: |
| return attribute.equals("_q") |
| || elementName.equals("keyboard") && attribute.equals("locale") |
| || elementName.equals("keyMap") && attribute.equals("modifiers") |
| || elementName.equals("map") && attribute.equals("iso") |
| || elementName.equals("map") && attribute.equals("optional") |
| || elementName.equals("map") && attribute.equals("longpress-status") |
| || elementName.equals("transforms") && attribute.equals("type") |
| || elementName.equals("transform") && attribute.equals("from") |
| || elementName.equals("import") && attribute.equals("path") |
| || elementName.equals("reorder") && attribute.equals("before") |
| || elementName.equals("reorder") && attribute.equals("from") |
| || elementName.equals("reorder") && attribute.equals("after") |
| || elementName.equals("layer") && attribute.equals("modifier") |
| || elementName.equals("switch") && attribute.equals("iso") |
| || elementName.equals("transform") && attribute.equals("before") |
| || elementName.equals("transform") && attribute.equals("after") |
| || elementName.equals("backspace") && attribute.equals("before") |
| || elementName.equals("backspace") && attribute.equals("from") |
| || elementName.equals("backspace") && attribute.equals("after") |
| || elementName.equals("vkeys") && attribute.equals("type") |
| || elementName.equals("flick") && attribute.equals("directions") |
| || elementName.equals("row") && attribute.equals("keys") |
| || elementName.equals("vkey") && attribute.equals("iso") |
| || elementName.equals("display") && attribute.equals("to") |
| || elementName.equals("flicks") && attribute.equals("iso"); |
| |
| case platform: |
| return attribute.equals("_q") |
| || elementName.equals("platform") && attribute.equals("id") |
| || elementName.equals("map") && attribute.equals("keycode"); |
| case ldmlICU: |
| return false; |
| default: |
| throw new IllegalArgumentException("Type is wrong: " + 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() { |
| Object[][] tests = { |
| {"validity/short-unit/deprecated", "inch-hg"} |
| }; |
| for (Object[] test : tests) { |
| MatchValue matcher = MatchValue.of((String)test[0]); |
| final String toMatch = (String)test[1]; |
| boolean expectedValue = test.length < 3 ? true : Boolean.valueOf((String)test[2]); |
| |
| final boolean actual = matcher.is(toMatch); |
| assertEquals(Arrays.asList(test).toString(), expectedValue, actual); |
| } |
| } |
| } |