From 0167a0faceeed73d08f5649bc290836e4bde2b12 Mon Sep 17 00:00:00 2001 From: Pascal Date: Wed, 24 Jun 2026 09:59:45 +0200 Subject: [PATCH 1/2] test: reduce registry manifest test repetition Assisted-by: Codex (model: GPT-5, autonomous) --- tests/integrations/test_registry.py | 89 ++++++++++++++++------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/tests/integrations/test_registry.py b/tests/integrations/test_registry.py index 0110e19ec7..7408c98a36 100644 --- a/tests/integrations/test_registry.py +++ b/tests/integrations/test_registry.py @@ -48,6 +48,11 @@ def _multi_install_safe_pairs() -> list[tuple[str, str]]: ] +def _multi_install_safe_orders() -> list[list[str]]: + safe_keys = _multi_install_safe_keys() + return [safe_keys, list(reversed(safe_keys))] + + def _posix_path(value: str | None) -> str | None: if not value: return None @@ -230,60 +235,62 @@ def test_safe_context_files_do_not_overlap_other_command_dirs(self, first, secon f"commands directory {_integration_commands_dir(first)!r}" ) - @pytest.mark.parametrize(("first", "second"), _multi_install_safe_pairs()) + @pytest.mark.parametrize( + "ordered_keys", + _multi_install_safe_orders(), + ids=["forward", "reverse"], + ) def test_safe_integrations_have_disjoint_manifests( self, tmp_path, - first, - second, + ordered_keys, ): - for initial, additional in ((first, second), (second, first)): - project_root = tmp_path / f"project-{initial}-{additional}" - project_root.mkdir() - runner = CliRunner() - - original_cwd = os.getcwd() - try: - os.chdir(project_root) - init_result = runner.invoke( - app, - [ - "init", - "--here", - "--integration", - initial, - "--script", - "sh", - "--ignore-agent-tools", - ], - catch_exceptions=False, - ) - assert init_result.exit_code == 0, init_result.output + project_root = tmp_path / "project" + project_root.mkdir() + runner = CliRunner() + # Install every safe integration once per order, then assert pairwise + # manifest isolation from the resulting manifests. + original_cwd = os.getcwd() + try: + os.chdir(project_root) + init_result = runner.invoke( + app, + [ + "init", + "--here", + "--integration", + ordered_keys[0], + "--script", + "sh", + "--ignore-agent-tools", + ], + catch_exceptions=False, + ) + assert init_result.exit_code == 0, init_result.output + + for key in ordered_keys[1:]: install_result = runner.invoke( app, - ["integration", "install", additional, "--script", "sh"], + ["integration", "install", key, "--script", "sh"], catch_exceptions=False, ) assert install_result.exit_code == 0, install_result.output - finally: - os.chdir(original_cwd) + finally: + os.chdir(original_cwd) - initial_manifest = json.loads( + manifests = {} + for key in ordered_keys: + manifest = json.loads( ( - project_root / ".specify" / "integrations" / f"{initial}.manifest.json" + project_root / ".specify" / "integrations" / f"{key}.manifest.json" ).read_text(encoding="utf-8") ) - additional_manifest = json.loads( - ( - project_root / ".specify" / "integrations" / f"{additional}.manifest.json" - ).read_text(encoding="utf-8") - ) - - initial_files = set(initial_manifest.get("files", {})) - additional_files = set(additional_manifest.get("files", {})) + manifests[key] = set(manifest.get("files", {})) - assert initial_files.isdisjoint(additional_files), ( - f"{initial} and {additional} are declared multi-install safe but both manage " - f"these files: {sorted(initial_files & additional_files)}" + for first, second in _multi_install_safe_pairs(): + overlap = manifests[first] & manifests[second] + assert not overlap, ( + f"{first} and {second} are declared multi-install safe but both manage " + f"these files: {sorted(overlap)}" ) From ca07e0e781399920e2546c561dbdcb90c041ad30 Mon Sep 17 00:00:00 2001 From: Pascal Date: Wed, 24 Jun 2026 10:36:00 +0200 Subject: [PATCH 2/2] test: clarify disjoint-manifest order rationale and guard safe set Add a >=2 precondition, explain why two install orders are tested (manifests are order-independent; the orders only vary the init path), and build the manifest map with a comprehension. --- tests/integrations/test_registry.py | 32 +++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tests/integrations/test_registry.py b/tests/integrations/test_registry.py index 7408c98a36..9bcb4b2c44 100644 --- a/tests/integrations/test_registry.py +++ b/tests/integrations/test_registry.py @@ -245,12 +245,25 @@ def test_safe_integrations_have_disjoint_manifests( tmp_path, ordered_keys, ): + # The pairwise disjointness contract is only meaningful with at least + # two safe integrations. Guard so a shrunken registry fails loudly here + # rather than passing vacuously (or tripping over ordered_keys[0] below). + assert len(ordered_keys) >= 2, ( + f"expected at least two multi-install-safe integrations, got {ordered_keys}" + ) + project_root = tmp_path / "project" project_root.mkdir() runner = CliRunner() - # Install every safe integration once per order, then assert pairwise - # manifest isolation from the resulting manifests. + # Install every safe integration once into a single project, then assert + # pairwise manifest isolation. Each safe integration writes only to its + # own (disjoint) directories and always records what it writes, so a + # manifest's contents are independent of install order and of which other + # integrations are co-installed. The two parametrized orders therefore + # produce the same manifests; their purpose is to route a different + # integration through the `init` path versus `integration install` + # (forward installs the first key via init, reverse the last). original_cwd = os.getcwd() try: os.chdir(project_root) @@ -279,14 +292,15 @@ def test_safe_integrations_have_disjoint_manifests( finally: os.chdir(original_cwd) - manifests = {} - for key in ordered_keys: - manifest = json.loads( - ( - project_root / ".specify" / "integrations" / f"{key}.manifest.json" - ).read_text(encoding="utf-8") + integrations_dir = project_root / ".specify" / "integrations" + manifests = { + key: set( + json.loads( + (integrations_dir / f"{key}.manifest.json").read_text(encoding="utf-8") + ).get("files", {}) ) - manifests[key] = set(manifest.get("files", {})) + for key in ordered_keys + } for first, second in _multi_install_safe_pairs(): overlap = manifests[first] & manifests[second]