diff options
| author | godosa <godosa@godosa.eu> | 2026-10-06 23:39:36 +0200 |
|---|---|---|
| committer | godosa <godosa@godosa.eu> | 2026-10-06 23:39:36 +0200 |
| commit | 39066900773e7857faf2d02e7ed51b71d219d97d (patch) | |
| tree | ffab8e4ddd971626776c3b1f4ce1da2c186c2187 /scripts/test_godosa_licenses.py | |
| download | godosa-engine-39066900773e7857faf2d02e7ed51b71d219d97d.tar.gz godosa-engine-39066900773e7857faf2d02e7ed51b71d219d97d.zip | |
godosa-engine: initial public history
Diffstat (limited to 'scripts/test_godosa_licenses.py')
| -rw-r--r-- | scripts/test_godosa_licenses.py | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/scripts/test_godosa_licenses.py b/scripts/test_godosa_licenses.py new file mode 100644 index 0000000..40e8387 --- /dev/null +++ b/scripts/test_godosa_licenses.py @@ -0,0 +1,116 @@ +"""python3 -m unittest discover -s scripts -p 'test_*.py'""" +import contextlib +import io +import json +import tempfile +import unittest +from pathlib import Path + +import godosa_licenses as gl + + +def nuspec(cache: Path, pid: str, ver: str, lic: str | None, copy: str = "© Someone"): + d = cache / pid.lower() / ver + d.mkdir(parents=True) + licel = f'<license type="expression">{lic}</license>' if lic else '<license type="file">LICENSE</license>' + (d / f"{pid.lower()}.nuspec").write_text( + f'<?xml version="1.0"?><package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">' + f"<metadata><id>{pid}</id><version>{ver}</version>{licel}<copyright>{copy}</copyright></metadata></package>") + + +def project(repo: Path, sln: str, rel: str, pkgs: dict[str, str]): + """pkgs: "Id/ver" -> "runtime" | "build" (analyzer, nothing in the output).""" + p = repo / rel + f = repo / sln + line = f'<Project Path="{rel}/{p.name}.csproj" />' + old = f.read_text() if f.exists() else "" + if line not in old: + f.write_text(old + line + "\n") + (p / "obj").mkdir(parents=True, exist_ok=True) + (p / f"{p.name}.csproj").write_text("<Project/>") + targets = {k: ({"type": "package", "runtime": {"lib/net10.0/X.dll": {}}} if kind == "runtime" + else {"type": "package", "runtime": {"lib/netstandard2.0/_._": {}}}) + for k, kind in pkgs.items()} + (p / "obj" / "project.assets.json").write_text(json.dumps({ + "targets": {"net10.0": targets}, + "libraries": {k: {"type": "package"} for k in pkgs}})) + + +class LicensesTest(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.repo = Path(self.tmp.name) / "repo" + self.cache = Path(self.tmp.name) / "cache" + self.repo.mkdir() + self.cache.mkdir() + self.cfg = gl.Config("Game.slnx", ("src/Game/",), "# Licences\n", + extra=[("runtime", "10", "MIT", "© R", "all")], + planned=[("Later", "2.0", "BSD|0", "managed", "nuspec")], + command="tool") + (self.repo / "Game.slnx").write_text("") + + def tearDown(self): + self.tmp.cleanup() + + def run_main(self, *argv) -> tuple[int, str]: + err = io.StringIO() + with contextlib.redirect_stderr(err): + code = gl.main(list(argv), self.cfg, self.repo, self.cache) + return code, err.getvalue() + + def test_write_then_check_is_clean_and_splits_shipped_from_test(self): + nuspec(self.cache, "Pack", "1.0.0", "MIT", "© P") + nuspec(self.cache, "xunit", "2.9.2", "Apache-2.0") + project(self.repo, "Game.slnx", "src/Game", {"Pack/1.0.0": "runtime"}) + project(self.repo, "Game.slnx", "src/Game.Tests", {"xunit/2.9.2": "runtime", "Pack/1.0.0": "runtime"}) + self.assertEqual(self.run_main("--write")[0], 0) + self.assertEqual(self.run_main(), (0, "")) + md = (self.repo / "licenses.md").read_text() + self.assertTrue(md.startswith("# Licences\n")) + shipped, rest = md.split("## Not a package") + self.assertIn("| Pack | 1.0.0 | MIT | © P | Game | |", shipped) + self.assertNotIn("xunit", shipped) + self.assertIn("| runtime | 10 | MIT | © R | all |", rest) + self.assertIn("| Later | 2.0 | BSD\\|0 | managed | nuspec |", rest) + self.assertIn("| xunit | 2.9.2 | Apache-2.0 | Game.Tests |", rest) + + def test_stale_names_the_command(self): + self.assertEqual(self.run_main(), (1, "licenses.md is stale: run tool --write\n")) + + def test_copyleft_ships_only_when_allowed(self): + nuspec(self.cache, "OpenAL.Native", "1.0.0", "LGPL-2.0-or-later") + project(self.repo, "Game.slnx", "src/Game.Tests", {"OpenAL.Native/1.0.0": "runtime"}) + self.assertEqual(self.run_main("--write")[0], 0) # test project: not shipped + project(self.repo, "Game.slnx", "src/Game", {"OpenAL.Native/1.0.0": "runtime"}) + self.assertEqual(self.run_main("--write"), (1, "NuGet OpenAL.Native 1.0.0: copyleft licence LGPL-2.0-or-later ships\n")) + self.cfg.allow_shipped["OpenAL.Native"] = "shared library" + self.assertEqual(self.run_main("--write")[0], 0) + self.assertIn("| shared library |", (self.repo / "licenses.md").read_text()) + + def test_build_only_package_is_not_shipped(self): + nuspec(self.cache, "Analyzer", "1.0.0", "GPL-3.0-only") + project(self.repo, "Game.slnx", "src/Game", {"Analyzer/1.0.0": "build"}) + self.assertEqual(self.run_main("--write")[0], 0) + + def test_unknown_licence_fails_until_overridden(self): + nuspec(self.cache, "FileLicensed", "1.0.0", None) + project(self.repo, "Game.slnx", "src/Game.Tests", {"FileLicensed/1.0.0": "runtime"}) + self.assertEqual(self.run_main("--write")[0], 1) + self.cfg.overrides["FileLicensed"] = "MIT" + self.assertEqual(self.run_main("--write")[0], 0) + + def test_projects_come_from_the_configured_solution(self): + nuspec(self.cache, "GplLib", "1.0.0", "GPL-3.0-only") + project(self.repo, "Other.slnx", "src/Game", {"GplLib/1.0.0": "runtime"}) + self.assertEqual(self.run_main("--write")[0], 0) + self.cfg.solution = "Other.slnx" + self.assertEqual(self.run_main("--write")[0], 1) + + def test_missing_assets_fails(self): + (self.repo / "src/Game").mkdir(parents=True) + (self.repo / "Game.slnx").write_text('<Project Path="src/Game/Game.csproj" />') + self.assertEqual(self.run_main("--write")[0], 1) + + +if __name__ == "__main__": + unittest.main() |
