import importlib.util import json import re import tempfile import unittest from pathlib import Path SCRIPT = Path(__file__).resolve().parents[1] / "scripts/check-versions.py" spec = importlib.util.spec_from_file_location("check_versions", SCRIPT) checker = importlib.util.module_from_spec(spec) spec.loader.exec_module(checker) class VersionChecks(unittest.TestCase): def test_numeric_comparison(self): self.assertEqual(checker.compare("1.2.9", "1.2.10"), "newer") self.assertEqual(checker.compare("2.0", "2.0.0"), "current") self.assertEqual(checker.compare("2.1", "2.0"), "behind") self.assertEqual(checker.compare("1.0", "2.0rc1"), "incomparable") self.assertEqual(checker.compare("0_pre20260803", "1.0"), "incomparable") def test_recipes_and_coverage(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) package = root / "packages/app-misc/example" package.mkdir(parents=True) (package / "example-0_pre20260803.exheres-0").touch() found, problems = checker.recipes(root) self.assertEqual(found, {"app-misc/example": "0_pre20260803"}) self.assertEqual(problems, []) text, failed = checker.report(root, {}, "", 0) self.assertTrue(failed) self.assertIn("unmapped recipe: app-misc/example", text) (package / "example-1.0.exheres-0").touch() _, problems = checker.recipes(root) self.assertIn("multiple versions for app-misc/example", problems) def test_result_events(self): output = "\n".join([ json.dumps({"event": "updated", "name": "a/b", "version": "1.2", "level": "info"}), json.dumps({"event": "no-result", "name": "c/d", "level": "error"}), ]) self.assertEqual(checker.results(output), ({"a/b": "1.2"}, {"c/d": "no-result"})) def test_failed_and_proxy_results(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) for name in ("net-im/viber", "dev-python/structlog"): category, package = name.split("/") path = root / "packages" / category / package path.mkdir(parents=True) (path / f"{package}-1.0.exheres-0").touch() config = {name: {"source": "aur"} for name in ("net-im/viber", "dev-python/structlog")} output = json.dumps({"event": "updated", "name": "net-im/viber", "version": "1.2", "level": "info"}) text, failed = checker.report(root, config, output, 3) self.assertTrue(failed) self.assertIn("proxy-newer", text) self.assertIn("no version returned", text) self.assertIn("failed=1", text) def test_aur_proxies(self): import tomllib with (SCRIPT.parents[1] / "nvchecker.toml").open("rb") as file: config = tomllib.load(file) for name, aur in (("app-misc/ente-auth", "ente-auth"), ("sys-kernel/kernel-cachyos", "linux-cachyos")): with self.subTest(name=name): self.assertNotIn(name, checker.UNSUPPORTED) self.assertIn(name, checker.PROXIES) self.assertEqual(config[name]["source"], "aur") self.assertEqual(config[name]["aur"], aur) self.assertTrue(config["app-misc/ente-auth"]["strip_release"]) self.assertNotIn("strip_release", config["sys-kernel/kernel-cachyos"]) def test_kernel_release_proxy(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory) package = root / "packages/sys-kernel/kernel-cachyos" package.mkdir(parents=True) recipe = package / "kernel-cachyos-7.2.8.exheres-0" recipe.write_text('MY_RELEASE="${PV}-1"\n') config = {"sys-kernel/kernel-cachyos": {"source": "aur"}} for version, expected in (("7.2.8-1", "proxy-current"), ("7.2.8-2", "proxy-newer"), ("7.2.8", "failed")): with self.subTest(version=version): output = json.dumps({"event": "updated", "name": "sys-kernel/kernel-cachyos", "version": version}) text, failed = checker.report(root, config, output, 0) self.assertIn(f"{expected:14} sys-kernel/kernel-cachyos", text) self.assertIn(f"failed={int(expected == 'failed')}", text) recipe.write_text('MY_RELEASE="${PV}-${REL}"\n') output = json.dumps({"event": "updated", "name": "sys-kernel/kernel-cachyos", "version": "7.2.8-1"}) text, failed = checker.report(root, config, output, 0) self.assertTrue(failed) self.assertIn("unrecognized recipe release", text) def test_tarball_feeds(self): import tomllib with (SCRIPT.parents[1] / "nvchecker.toml").open("rb") as file: config = tomllib.load(file) examples = { "media-libs/zita-convolver": ( 'https://kokkinizita.linuxaudio.org/linuxaudio/downloads/', '', "4.0.3", ), "net-firewall/ufw": ( 'https://launchpad.net/ufw/+download', '', "0.36.2", ), } for name, (url, html, version) in examples.items(): with self.subTest(name=name): self.assertNotIn(name, checker.UNSUPPORTED) self.assertEqual(config[name]["source"], "regex") self.assertEqual(config[name]["url"], url) self.assertEqual(re.findall(config[name]["regex"], html), [version]) def test_zoom_feed(self): import tomllib with (SCRIPT.parents[1] / "nvchecker.toml").open("rb") as file: config = tomllib.load(file) entry = config["net-im/zoom"] self.assertEqual(entry["source"], "regex") self.assertEqual(entry["url"], "https://zoom.us/rest/download?os=linux") response = '{"downloadVO":{"zoom":{"version":"7.2.1.5760"},"zoomX86":{"version":"5.4.53391.1108"}}}' self.assertEqual(re.findall(entry["regex"], response), ["7.2.1.5760"]) self.assertEqual(checker.compare("7.2.1.5760", "7.2.1.5760"), "current") def test_repository_coverage(self): import tomllib root = SCRIPT.parents[1] with (root / "nvchecker.toml").open("rb") as file: config = tomllib.load(file) found, problems = checker.recipes(root) self.assertEqual(problems, []) self.assertEqual(set(found), (set(config) - {"__config__"}) | set(checker.UNSUPPORTED)) self.assertFalse((set(config) - {"__config__"}) & set(checker.UNSUPPORTED)) if __name__ == "__main__": unittest.main()