summaryrefslogtreecommitdiff
path: root/tools/tests
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 18:36:54 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 18:36:54 +0200
commitf466977249d9ac10fe8b75180c30cb90dbcc22ca (patch)
treef346500d39d077aaaeb350e0e99647a4d6e6367c /tools/tests
parent479d7ba2e843d5ea93979f2eed68f4d38d146c25 (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.py108
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)]) == []