summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorM Hickford <mirth.hickford@gmail.com>2022-01-27 21:51:03 +0000
committerPeter Hutterer <peter.hutterer@who-t.net>2022-01-27 21:51:03 +0000
commit297bb51556bf72c26acc26b411cfab8116376d6e (patch)
treee14c1e8d5f844e534c3061f3a190041921041cb9 /tests
parent175077ece6506bf3fc89f4b17b4a84bf39847a26 (diff)
downloadxkeyboard-config-297bb51556bf72c26acc26b411cfab8116376d6e.tar.gz
Test that each layout has at least one country and language associated
Diffstat (limited to 'tests')
-rw-r--r--tests/test_rules_xml.py91
1 files changed, 71 insertions, 20 deletions
diff --git a/tests/test_rules_xml.py b/tests/test_rules_xml.py
index 85ad717..3d36ecf 100644
--- a/tests/test_rules_xml.py
+++ b/tests/test_rules_xml.py
@@ -36,6 +36,14 @@ def iterate_layouts_variants(rules_xml):
for variant in layout.iter('variant'):
yield layout, variant
+def iterate_config_items(rules_xml):
+ '''
+ Return an iterator of configItem elements
+ '''
+ tree = ET.parse(rules_xml)
+ root = tree.getroot()
+ return root.iter('configItem')
+
def pytest_generate_tests(metafunc):
# for any test_foo function with an argument named rules_xml,
@@ -54,6 +62,17 @@ def pytest_generate_tests(metafunc):
for l, v in iterate_layouts_variants(f):
layouts.append(Layout(f, l, v))
metafunc.parametrize('layout', layouts)
+ elif 'config_item' in metafunc.fixturenames:
+ rules_xml = list(_xkb_config_root().glob('rules/*.xml'))
+ assert rules_xml
+ config_items = []
+ for f in rules_xml:
+ for item in iterate_config_items(f):
+ item = ConfigItem.from_elem(item)
+ item.rulesfile = f
+ config_items.append(item)
+ metafunc.parametrize('config_item', config_items)
+
@@ -72,23 +91,29 @@ class Layout:
else:
self.name = f"{self.layout.name}"
- def _fetch(self, name):
- parent = self.variant or self.layout
- elements = parent.findall(name)
- if elements is None:
- return None
- elif len(elements) > 1:
- return elements
- else:
- return elements[0]
-
@property
def iso3166(self):
- return (self.variant or self.layout).iso3166
+ if self.variant and self.variant.iso3166 is not None:
+ return self.variant.iso3166 or []
+ # inherit from parent
+ return self.layout.iso3166 or []
@property
def iso639(self):
- return (self.variant or self.layout).iso639
+ if self.variant and self.variant.iso639 is not None:
+ return self.variant.iso639 or []
+ # inherit from parent
+ return self.layout.iso639 or []
+
+ @property
+ def popularity(self):
+ return self.variant.popularity if self.variant else self.layout.popularity
+
+ @property
+ def shortDescription(self):
+ if self.variant and self.variant.shortDescription:
+ return self.variant.shortDescription
+ return self.layout.shortDescription
def prettyxml(element):
@@ -100,8 +125,9 @@ class ConfigItem:
self.name = name
self.shortDescription = shortDescription
self.description = description
- self.iso639 = []
- self.iso3166 = []
+ self.iso639 = None
+ self.iso3166 = None
+ self.popularity = None
@classmethod
def _fetch_subelement(cls, parent, name):
@@ -126,17 +152,14 @@ class ConfigItem:
@classmethod
def from_elem(cls, elem):
try:
- ci_element = cls._fetch_subelement(elem, 'configItem')
+ ci_element = elem if elem.tag == "configItem" else cls._fetch_subelement(elem, 'configItem')
name = cls._fetch_text(ci_element, 'name')
assert name is not None
# shortDescription and description are optional
sdesc = cls._fetch_text(ci_element, 'shortDescription')
desc = cls._fetch_text(ci_element, 'description')
ci = ConfigItem(name, sdesc, desc)
-
- langlist = cls._fetch_subelement(ci_element, 'languageList')
- if langlist:
- ci.iso639 = cls._fetch_subelement_text(langlist, 'iso639Id')
+ ci.popularity = ci_element.attrib.get('popularity')
langlist = cls._fetch_subelement(ci_element, 'languageList')
if langlist:
@@ -144,7 +167,7 @@ class ConfigItem:
countrylist = cls._fetch_subelement(ci_element, 'countryList')
if countrylist:
- ci.iso3166 = cls._fetch_subelement_text(countrylist, 'iso3166')
+ ci.iso3166 = cls._fetch_subelement_text(countrylist, 'iso3166Id')
return ci
except AssertionError as e:
@@ -180,15 +203,39 @@ def test_duplicate_models(rules_xml):
models[ci.name] = True
+def test_exotic(config_item):
+ """All items in extras should be marked exotic"""
+ if config_item.rulesfile.stem.endswith('extras'):
+ assert config_item.popularity == "exotic", f"{config_item.rulesfile}: item {config_item.name} does not have popularity exotic"
+ else:
+ assert config_item.popularity != "exotic", f"{config_item.rulesfile}: item {config_item.name} has popularity exotic"
+
+
+def test_short_description(layout):
+ assert layout.shortDescription, f'{layout.rulesfile}: layout {layout.name} missing shortDescription'
+
+
def test_iso3166(layout):
+ """Typically layouts should specify at least one country code"""
pycountry = pytest.importorskip('pycountry')
country_codes = [c.alpha_2 for c in pycountry.countries]
+ expected_without_country = [
+ "apl", # programming
+ "brai", # Braille not specific to any country
+ "custom",
+ "epo", # Esperanto not native to any country
+ "trans", # international
+ ]
+
for code in layout.iso3166:
assert code in country_codes, \
f'{layout.rulesfile}: unknown country code "{code}" in {layout.name}'
+ assert layout.iso3166 or layout.layout.name in expected_without_country, f"{layout.rulesfile}: layout {layout.name} has no countries associated"
+
def test_iso639(layout):
+ """Typically layouts should should specify at least one language code"""
pycountry = pytest.importorskip('pycountry')
# A list of languages not in pycountry, so we need to special-case them
@@ -200,6 +247,10 @@ def test_iso639(layout):
'ovd', # Elfdalian, https://iso639-3.sil.org/code/ovd
]
language_codes = [c.alpha_3 for c in pycountry.languages] + special_langs
+ expected_without_language = ["brai", "custom", "trans"]
+
for code in layout.iso639:
assert code in language_codes, \
f'{layout.rulesfile}: unknown language code "{code}" in {layout.name}'
+
+ assert layout.iso639 or layout.layout.name in expected_without_language, f"{layout.rulesfile}: layout {layout.name} has no languages associated"