+47
-1
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
@@ -69,6 +70,49 @@ class upload_packages_test(unittest.TestCase):
|
||||
completed = subprocess.run(command, cwd=repo, check=False)
|
||||
self.assertEqual(completed.returncode, 0)
|
||||
|
||||
def test_project_root_build_is_rejected(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = pathlib.Path(directory)
|
||||
context = self.context(root)
|
||||
context.config["tooling"]["targets"]["native"]["build_dir"] = "."
|
||||
with self.assertRaisesRegex(modulus.config.config_error, "project and source roots"):
|
||||
modulus.cli.build_context(root, context.config)
|
||||
|
||||
def test_configure_and_lsp_refresh_project_editor_settings(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = pathlib.Path(directory)
|
||||
fragments = [
|
||||
{"CompileFlags": {"CompilationDatabase": "build/native"}},
|
||||
{"If": {"PathMatch": "src/pico/.*"}, "CompileFlags": {"CompilationDatabase": "build/pico"}},
|
||||
]
|
||||
config = {"package": {"name": "sample"}, "tooling": {"editor": {"clangd": fragments}}}
|
||||
(root / "modulus.json").write_text(json.dumps(config), encoding="utf-8")
|
||||
with unittest.mock.patch.object(modulus.cli, "find_repo_root", return_value=root):
|
||||
for command in ("configure", "lsp"):
|
||||
with self.subTest(command=command), unittest.mock.patch.object(modulus.cli, command, return_value=0):
|
||||
(root / ".clangd").write_text("stale", encoding="utf-8")
|
||||
self.assertEqual(modulus.cli.main(command), 0)
|
||||
content = (root / ".clangd").read_text(encoding="utf-8").split("\n", 1)[1]
|
||||
self.assertEqual([json.loads(part) for part in content.split("\n---\n")], fragments)
|
||||
before = {name: (root / name).stat().st_mtime_ns for name in modulus.export.editor_files.values()}
|
||||
self.assertEqual(modulus.cli.main(command), 0)
|
||||
self.assertEqual(before, {name: (root / name).stat().st_mtime_ns for name in before})
|
||||
|
||||
def test_lsp_rejects_source_root_before_cache_cleanup(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = pathlib.Path(directory)
|
||||
context = self.context(root)
|
||||
cache = root / "CMakeCache.txt"
|
||||
cache.write_text("keep", encoding="utf-8")
|
||||
with unittest.mock.patch.object(modulus.cli, "clear_lsp_cmake_cache") as clear:
|
||||
for build_dir in (".", "alias", "subproject"):
|
||||
if build_dir == "alias":
|
||||
(root / "alias").symlink_to(root, target_is_directory=True)
|
||||
with self.subTest(build_dir=build_dir), self.assertRaises(modulus.config.config_error):
|
||||
modulus.cli.configure_lsp_database(context, {"source_dir": "subproject", "build_dir": build_dir})
|
||||
clear.assert_not_called()
|
||||
self.assertEqual(cache.read_text(encoding="utf-8"), "keep")
|
||||
|
||||
@unittest.mock.patch.object(modulus.cli, "upload_all_packages", return_value=37)
|
||||
@unittest.mock.patch.object(modulus.cli, "configure_conan_remote", return_value=0)
|
||||
def test_failed_upload_does_not_force_by_default(self, configure, upload):
|
||||
@@ -511,7 +555,9 @@ class upload_packages_test(unittest.TestCase):
|
||||
@unittest.mock.patch.object(modulus.cli, "run", return_value=0)
|
||||
@unittest.mock.patch.object(modulus.cli, "in_docker", return_value=True)
|
||||
def test_build_can_target_one_cmake_target(self, docker, run):
|
||||
context = self.context()
|
||||
directory = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(directory.cleanup)
|
||||
context = self.context(pathlib.Path(directory.name))
|
||||
context.default_target.build_dir.mkdir(parents=True, exist_ok=True)
|
||||
(context.default_target.build_dir / "CMakeCache.txt").write_text("", encoding="utf-8")
|
||||
(context.default_target.build_dir / "build.ninja").write_text("", encoding="utf-8")
|
||||
|
||||
+46
-22
@@ -31,7 +31,6 @@ class modulus_export_test(unittest.TestCase):
|
||||
for directory in (
|
||||
"modulus",
|
||||
"tools/docker",
|
||||
"tools/editor",
|
||||
"include/modulus",
|
||||
"tests",
|
||||
"lib/cmake/modulus",
|
||||
@@ -48,9 +47,6 @@ class modulus_export_test(unittest.TestCase):
|
||||
(package / "tools" / "lsp.py").write_text("#!/usr/bin/env python3\n", encoding="utf-8")
|
||||
(package / "tools" / "run.py").write_text("#!/usr/bin/env python3\n", encoding="utf-8")
|
||||
(package / "tools" / "docker" / "Dockerfile").write_text("FROM scratch\n", encoding="utf-8")
|
||||
(package / "tools" / "editor" / "clangd.yaml").write_text("CompileFlags: {}\n", encoding="utf-8")
|
||||
(package / "tools" / "editor" / "clang-format").write_text("DisableFormat: true\n", encoding="utf-8")
|
||||
(package / "tools" / "editor" / "pyrightconfig.json").write_text("{}\n", encoding="utf-8")
|
||||
(package / "include" / "modulus" / "types.hpp").write_text("", encoding="utf-8")
|
||||
(package / "tests" / "test.cpp").write_text("", encoding="utf-8")
|
||||
(package / "lib" / "cmake" / "modulus" / "modulus-config.cmake").write_text("", encoding="utf-8")
|
||||
@@ -224,8 +220,8 @@ class modulus_export_test(unittest.TestCase):
|
||||
self.assertTrue((repo / "build" / "build_tools" / "docker" / "Dockerfile").is_file())
|
||||
self.assertFalse((repo / "build" / "build_tools" / "docs").exists())
|
||||
self.assertFalse((repo / "build" / "build_tools" / "lsp").exists())
|
||||
for source_name, destination_name in modulus.export.editor_files.items():
|
||||
self.assertEqual((repo / destination_name).read_text(encoding="utf-8"), (package / "tools" / "editor" / source_name).read_text(encoding="utf-8"))
|
||||
for destination in modulus.export.editor_files.values():
|
||||
self.assertTrue((repo / destination).is_file())
|
||||
runtime = repo / "build" / "build_common" / "modulus"
|
||||
self.assertTrue((runtime / "modulus" / "cli.py").is_file())
|
||||
self.assertTrue((runtime / "modulus" / "config.py").is_file())
|
||||
@@ -244,23 +240,51 @@ class modulus_export_test(unittest.TestCase):
|
||||
self.assertFalse((runtime / "share").exists())
|
||||
self.assertFalse((runtime / "bin").exists())
|
||||
|
||||
def test_root_editor_files_match_export_templates(self):
|
||||
root = pathlib.Path(__file__).resolve().parents[1]
|
||||
for source_name, destination_name in modulus.export.editor_files.items():
|
||||
self.assertEqual((root / destination_name).read_text(encoding="utf-8"), (root / "tools" / "editor" / source_name).read_text(encoding="utf-8"))
|
||||
|
||||
def test_clangd_template_uses_default_target_compile_database_and_disables_clang_tidy(self):
|
||||
root = pathlib.Path(__file__).resolve().parents[1]
|
||||
def test_editor_defaults_use_configured_target(self):
|
||||
config = modulus.config.normalize(self.config())
|
||||
default_target = config["tooling"]["targets"][config["tooling"]["default_target"]]
|
||||
template = (root / "tools" / "editor" / "clangd.yaml").read_text(encoding="utf-8")
|
||||
self.assertIn(f"CompilationDatabase: {default_target['build_dir']}", template)
|
||||
self.assertIn("Diagnostics:", template)
|
||||
self.assertIn("ClangTidy:", template)
|
||||
self.assertIn("Remove: ['*']", template)
|
||||
self.assertNotIn("bugprone-*", template)
|
||||
self.assertNotIn("performance-*", template)
|
||||
self.assertNotIn("readability-*", template)
|
||||
config["tooling"].pop("editor")
|
||||
config["tooling"]["targets"][config["tooling"]["default_target"]]["build_dir"] = "build/custom"
|
||||
config = modulus.config.normalize(config)
|
||||
editor = config["tooling"]["editor"]
|
||||
self.assertEqual(editor["clangd"][0]["CompileFlags"]["CompilationDatabase"], "build/custom")
|
||||
self.assertEqual(editor["clangd"][0]["Diagnostics"]["ClangTidy"]["Remove"], ["*"])
|
||||
self.assertIn("conanfile.py", editor["pyright"]["include"])
|
||||
self.assertNotIn("package/conanfile.py", editor["pyright"]["include"])
|
||||
|
||||
def test_editor_replacements_and_refresh_are_idempotent(self):
|
||||
config = self.config()
|
||||
editor = {
|
||||
"clangd": [
|
||||
{"CompileFlags": {"CompilationDatabase": "build/native"}},
|
||||
{"If": {"PathMatch": "src/pico/.*"}, "CompileFlags": {"CompilationDatabase": "build/pico"}},
|
||||
],
|
||||
"clang_format": {"BasedOnStyle": "LLVM", "IndentWidth": 2},
|
||||
"pyright": {"include": ["generator"]},
|
||||
}
|
||||
config["tooling"] = {"editor": editor}
|
||||
normalized = modulus.config.normalize(config)
|
||||
self.assertEqual(normalized["tooling"]["editor"], editor)
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = pathlib.Path(directory)
|
||||
modulus.export.sync_editor_files(root, normalized)
|
||||
for name, filename in modulus.export.editor_files.items():
|
||||
path = root / filename
|
||||
content = path.read_text(encoding="utf-8")
|
||||
if name != "pyright":
|
||||
content = content.split("\n", 1)[1]
|
||||
documents = [json.loads(part) for part in content.split("\n---\n")]
|
||||
self.assertEqual(documents if name == "clangd" else documents[0], editor[name])
|
||||
before = {path.name: path.stat().st_mtime_ns for path in root.iterdir()}
|
||||
modulus.export.sync_editor_files(root, normalized)
|
||||
self.assertEqual(before, {path.name: path.stat().st_mtime_ns for path in root.iterdir()})
|
||||
|
||||
def test_editor_config_rejects_invalid_shapes(self):
|
||||
for editor in (None, [], {"unknown": {}}, {"clangd": {}}, {"clangd": []}, {"clangd": ["bad"]}, {"pyright": []}, {"clang_format": None}, {"pyright": {"value": float("nan")}}):
|
||||
with self.subTest(editor=editor):
|
||||
config = self.config()
|
||||
config["tooling"] = {"editor": editor}
|
||||
with self.assertRaises(modulus.config.config_error):
|
||||
modulus.config.normalize(config)
|
||||
|
||||
def test_export_requires_packaged_tools(self):
|
||||
with tempfile.TemporaryDirectory() as repo_dir, tempfile.TemporaryDirectory() as package_dir:
|
||||
|
||||
Reference in New Issue
Block a user