diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-18 21:10:37 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-18 21:10:37 +0200 |
| commit | 2292bf700d28ade39cf2d64b45509e6db21034bc (patch) | |
| tree | ef455320d39ebe51db236219dbbda2b148dcbe18 /tools/tests/test_lint_project.py | |
| parent | 85f1ecabd7f58f306b2a042376209ac8cf49ab9b (diff) | |
test(tools): add screenshot, budget and product checks; enforce file headers
- sim_screenshot.py finds the device drawing in the simulator window,
crops the screen and compares it with approved golden images.
- check_budgets.py reads key=value DIAG/HARNESS lines (the simulator
console escapes quotes, so JSON was dropped).
- ciq_test_report.py accepts SDK 9.2.0's real summary line
`PASSED (passed=N, failed=N, errors=N)`; a captured log is a fixture.
- gen_products.py checks all manifest products are watches with
API 5.0+ and at least 512 KB for apps.
- lint_project.py rule HDR001: every file carries the Author/Summary
header (JSON keys, PNG text chunks; generated package-lock exempt).
- make_icon.py --all draws one icon per launcher size in use.
- Golden screenshots for fr255s, venusq2, fr70 and fr965.
- 44 tests, warnings as errors, ruff and mypy --strict clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/tests/test_lint_project.py')
| -rw-r--r-- | tools/tests/test_lint_project.py | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/tools/tests/test_lint_project.py b/tools/tests/test_lint_project.py index be0151e..31f8125 100644 --- a/tools/tests/test_lint_project.py +++ b/tools/tests/test_lint_project.py @@ -1,11 +1,16 @@ +# Author: cirakg & claude ai +# Summary: Tests for tools/lint_project.py, the project policy linter. """Tests for tools/lint_project.py, the project policy linter.""" from __future__ import annotations +import json from pathlib import Path import lint_project as lp from conftest import PROJECT_ROOT +from PIL import Image +from PIL.PngImagePlugin import PngInfo GOOD_MANIFEST = "<iq:manifest><iq:permissions/></iq:manifest>\n" @@ -19,7 +24,8 @@ def make_project(tmp_path: Path, files: dict[str, str]) -> Path: def codes(root: Path) -> list[tuple[str, str, int]]: - return [(str(p.path), p.code, p.line) for p in lp.lint(root)] + """Findings of the code rules (MC001-MC005) only.""" + return [(str(p.path), p.code, p.line) for p in sorted(lp.lint_code(root))] def test_clean_project_passes(tmp_path: Path) -> None: @@ -76,6 +82,41 @@ def test_manifest_permissions_are_rejected(tmp_path: Path) -> None: assert codes(root) == [("manifest.xml", "MC005", 2)] +HEADER = "# Author: cirakg & claude ai\n# Summary: A file with a proper header.\n" + + +def header_findings(root: Path) -> list[str]: + return sorted(str(p.path) for p in lp.lint_headers(root)) + + +def save_png(path: Path, author: str | None) -> None: + info = PngInfo() + if author is not None: + info.add_text("Author", author) + info.add_text("Description", "test image") + path.parent.mkdir(parents=True, exist_ok=True) + Image.new("RGB", (4, 4)).save(path, pnginfo=info) + + +def test_headers_are_required_in_every_file_type(tmp_path: Path) -> None: + files = { + "ok.sh": "#!/bin/sh\n" + HEADER, + "late.txt": "\n" * 20 + HEADER, # too far down + "none.md": "# Title\n", + "data/ok.json": json.dumps({"_author": lp.AUTHOR, "_summary": "x"}), + "data/bad.json": json.dumps({"author": "someone else", "description": "x"}), + "docker/docs/package-lock.json": "{}", # generated, exempt + "build/out.txt": "ignored folder", + } + for name, text in files.items(): + path = tmp_path / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text, encoding="utf-8") + save_png(tmp_path / "img/ok.png", lp.AUTHOR) + save_png(tmp_path / "img/anon.png", None) + assert header_findings(tmp_path) == ["data/bad.json", "img/anon.png", "late.txt", "none.md"] + + def test_project_passes_its_own_rules() -> None: problems = lp.lint(PROJECT_ROOT) assert problems == [], "\n".join(map(str, problems)) |
