diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-20 18:36:54 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-20 18:36:54 +0200 |
| commit | f466977249d9ac10fe8b75180c30cb90dbcc22ca (patch) | |
| tree | f346500d39d077aaaeb350e0e99647a4d6e6367c /tools/tests | |
| parent | 479d7ba2e843d5ea93979f2eed68f4d38d146c25 (diff) | |
build(lint): validate resource XML against the SDK schema and cross-check the settings form
tools/check_resources.py checks every resource file against the SDK's
resources.xsd and that settings, properties and strings agree. Adds the
pure-Python, MIT-licensed xmlschema to the dev image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/tests')
| -rw-r--r-- | tools/tests/test_check_resources.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tools/tests/test_check_resources.py b/tools/tests/test_check_resources.py new file mode 100644 index 0000000..3f0f946 --- /dev/null +++ b/tools/tests/test_check_resources.py @@ -0,0 +1,108 @@ +# Author: cirakg & claude ai +# Summary: Tests for tools/check_resources.py (schema validation and the settings cross-check). +"""Tests for tools/check_resources.py.""" + +from __future__ import annotations + +from pathlib import Path + +import check_resources as cr +import xmlschema + +TINY_XSD = """<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="strings"> + <xs:complexType><xs:sequence> + <xs:element name="string" maxOccurs="unbounded"> + <xs:complexType><xs:simpleContent><xs:extension base="xs:string"> + <xs:attribute name="id" type="xs:string" use="required"/> + </xs:extension></xs:simpleContent></xs:complexType> + </xs:element> + </xs:sequence></xs:complexType> + </xs:element> +</xs:schema> +""" + +PROPERTIES = """<properties> + <property id="kind" type="number">1</property> + <property id="status" type="string"></property> + <property id="count" type="number">0</property> + <property id="orphan" type="string"></property> +</properties> +""" + +SETTINGS = """<settings> + <group id="g" title="@Strings.Title"> + <setting propertyKey="@Properties.kind" title="@Strings.Kind"> + <settingConfig type="list"> + <listEntry value="0">@Strings.Zero</listEntry> + <listEntry value="2">@Strings.Missing</listEntry> + </settingConfig> + </setting> + <setting propertyKey="@Properties.status" title="@Strings.Title"> + <settingConfig type="alphaNumeric" readonly="true" /> + </setting> + <setting propertyKey="@Properties.count" title="@Strings.Title"> + <settingConfig type="numeric" readonly="true" /> + </setting> + <setting propertyKey="@Properties.count" title="@Strings.Title"> + <settingConfig type="numeric" /> + </setting> + <setting propertyKey="@Properties.ghost" title="@Strings.Title"> + <settingConfig type="boolean" /> + </setting> + </group> +</settings> +""" + +STRINGS = '<strings><string id="Title">T</string><string id="Kind">K</string><string id="Zero">0</string></strings>' + + +def write(folder: Path, name: str, text: str) -> Path: + path = folder / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text, encoding="utf-8") + return path + + +def test_cross_check_finds_every_kind_of_mismatch(tmp_path: Path) -> None: + settings = write(tmp_path, "settings.xml", SETTINGS) + properties = write(tmp_path, "properties.xml", PROPERTIES) + strings = write(tmp_path, "strings.xml", STRINGS) + problems = cr.cross_check(settings, properties, [strings]) + assert problems == [ + "settings.xml: @Strings.Missing is not defined", + "settings.xml: @Properties.ghost is not defined in properties.xml", + "kind: default '1' is not one of the list values ['0', '2']", + "count: read-only settings must be string properties, not number", + "settings.xml: count appears 2 times", + "properties.xml: orphan is not in the settings form", + ] + + +def test_validate_reports_schema_errors(tmp_path: Path) -> None: + schema = xmlschema.XMLSchema(TINY_XSD) + good = write(tmp_path, "resources/strings/strings.xml", STRINGS) + bad = write(tmp_path, "resources/strings/bad.xml", "<strings><string>no id</string></strings>") + assert cr.resource_files(tmp_path) == [bad, good] + problems = cr.validate(schema, [bad, good], tmp_path) + assert len(problems) == 1 + assert problems[0].startswith("resources/strings/bad.xml: ") + assert "id" in problems[0] + + +def test_main_needs_the_schema(tmp_path: Path) -> None: + assert cr.main([str(tmp_path), "--xsd", str(tmp_path / "missing.xsd")]) == cr.EXIT_NO_SCHEMA + + +def test_cross_check_accepts_a_consistent_form(tmp_path: Path) -> None: + properties = write( + tmp_path, "properties.xml", '<properties><property id="kind" type="number">0</property></properties>' + ) + settings = write( + tmp_path, + "settings.xml", + '<settings><setting propertyKey="@Properties.kind" title="@Strings.Kind"><settingConfig type="list">' + '<listEntry value="0">@Strings.Zero</listEntry></settingConfig></setting></settings>', + ) + assert cr.cross_check(settings, properties, [write(tmp_path, "strings.xml", STRINGS)]) == [] |
