aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/scripts/test_godosa_licenses.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/test_godosa_licenses.py')
-rw-r--r--scripts/test_godosa_licenses.py116
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()