From 170cd6e7ade8f0e8bf9cbaa56800de0101a8dcd1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 06:13:31 +0000 Subject: [PATCH 1/2] Link the integration suite once instead of 176 times MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rust gates were not slow because the runner was small. Two defects made every job rebuild work it had already cached. 1. One test binary per crate, not one per file. Cargo builds an executable for every `tests/*.rs`, and each one statically links the whole workspace under a `lto = "thin"` / `codegen-units = 1` release profile — the most expensive link settings there are, paid 176 times. Measured here: 8 of those targets rebuilt in 74.3s after touching deslop-core, so the full set is ~27 minutes, which matches the 19m54s "Compile release test binaries" step on CI. The suites are now modules of one binary per crate (`tests/suite.rs`), so the workspace is linked 4 times instead of 176. Every former test file is unchanged apart from its `mod common;` line: the shared helpers are declared once at the suite root, so `crate::common::…` still resolves. 2. The wire-model generator rewrote its output unconditionally. `crates/deslop-core/src/wire_generated.rs` is a source file of deslop-core, and cargo fingerprints local sources by mtime — so rewriting it with byte-identical content invalidated deslop-core and everything downstream. It is a prerequisite of `fmt`, `lint`, `test`, `test-shard`, `coverage` and `_vsix-build`, so each of those threw away the build the previous one had just produced. A no-op workspace rebuild is 0.13s; the same rebuild after one generator run was 1m30s. It now compares before writing, and `typediagram-gen.test.mjs` pins both halves — unchanged models leave the mtime alone, a clobbered file is still rewritten. Together, on the same 4 cores: rebuilding every test target after touching deslop-core goes from ~27 minutes to 1m23s. Also adds `[profile.release-test]` — `release` with the two shipping-only settings dropped, worth 2.9x on its own (74.3s to 26.0s over the same 8 targets). `make build`, `dup-gate` and `deployment-verify` still use `release`, so everything that ships stays fully optimised. `runs-on` for the Rust job now reads `vars.RUST_RUNNER`, defaulting to `ubuntu-latest`: one variable moves the Rust gates to a larger runner without hardcoding a label the org may not have provisioned. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CpWn82FwuJxjyrojMP8cT2 --- .github/workflows/ci.yml | 9 +- Cargo.toml | 18 ++ Makefile | 2 +- crates/deslop-core/Cargo.toml | 5 + .../tests/embedding_pass_observability.rs | 1 - crates/deslop-core/tests/issue_117.rs | 1 - .../issue_121_pytest_fixture_boilerplate.rs | 2 +- .../tests/issue_239_csharp_reparse.rs | 2 +- .../tests/issue_270_seed_language_drift.rs | 1 - .../issue_287_live_ingest_gitignore_parity.rs | 1 - .../issue_299_no_op_pass_skips_rerender.rs | 1 - .../tests/issue_45_observability.rs | 1 - .../issue_98_99_108_120_122_thresholds.rs | 2 +- crates/deslop-core/tests/live.rs | 1 - crates/deslop-core/tests/live_merge_plan.rs | 1 - .../deslop-core/tests/refactor_ast_access.rs | 1 - .../deslop-core/tests/refactor_consolidate.rs | 1 - .../tests/refactor_content_gate.rs | 1 - crates/deslop-core/tests/refactor_extract.rs | 1 - .../tests/refactor_extract_negative.rs | 1 - .../tests/refactor_extract_write_gate.rs | 1 - crates/deslop-core/tests/refactor_merge.rs | 1 - .../tests/refactor_merge_refusals.rs | 1 - crates/deslop-core/tests/suite.rs | 82 +++++++ crates/deslop-lsp/Cargo.toml | 5 + crates/deslop-lsp/tests/cli.rs | 1 - crates/deslop-lsp/tests/code_action.rs | 2 +- .../deslop-lsp/tests/code_action_refusal.rs | 2 +- crates/deslop-lsp/tests/cpu_throttle_knob.rs | 1 - .../deslop-lsp/tests/dependency_reactivity.rs | 2 +- .../tests/editor_non_interference.rs | 1 - .../tests/embedding_failure_progress.rs | 2 +- crates/deslop-lsp/tests/execute_command.rs | 1 - .../deslop-lsp/tests/history_determinism.rs | 2 +- .../tests/lsp_embedding_determinism.rs | 2 +- .../deslop-lsp/tests/lsp_workspace_scoping.rs | 2 +- crates/deslop-lsp/tests/notifications.rs | 1 - .../tests/observability_heartbeat.rs | 1 - crates/deslop-lsp/tests/ollama_fallback.rs | 2 +- crates/deslop-lsp/tests/state_file_and_ipc.rs | 2 +- crates/deslop-lsp/tests/suite.rs | 50 ++++ crates/deslop-lsp/tests/virtual_document.rs | 1 - crates/deslop-mcp/Cargo.toml | 5 + crates/deslop-mcp/tests/cli.rs | 2 +- .../tests/dart_generated_fp_over_mcp.rs | 2 +- .../tests/dart_language_label_over_mcp.rs | 2 +- .../tests/fsharp_language_label_over_mcp.rs | 2 +- .../tests/issue_135_rescan_generation.rs | 2 +- .../tests/issue_136_codex_payload_size.rs | 2 +- .../tests/issue_137_ipc_freshness.rs | 2 +- .../tests/issue_148_version_mismatch.rs | 2 +- .../tests/issue_149_ui_mcp_agreement.rs | 2 +- ...ue_151_socket_path_in_lsp_missing_error.rs | 2 +- .../tests/issue_153_rescan_freshness.rs | 2 +- .../issue_156_cluster_id_stale_offsets.rs | 2 +- ...issue_157_lsp_not_running_recovery_data.rs | 2 +- crates/deslop-mcp/tests/lsp_integration.rs | 2 +- crates/deslop-mcp/tests/merge_plan.rs | 2 +- crates/deslop-mcp/tests/orphan_exit.rs | 2 +- crates/deslop-mcp/tests/state_file_backend.rs | 2 +- crates/deslop-mcp/tests/suite.rs | 56 +++++ crates/deslop-mcp/tests/tcp_transport.rs | 2 +- crates/deslop/Cargo.toml | 5 + crates/deslop/tests/cache_blob_integrity.rs | 1 - .../tests/cache_key_lossy_utf8_collision.rs | 1 - crates/deslop/tests/cache_retention.rs | 1 - crates/deslop/tests/cli/bucket_groups.rs | 4 +- crates/deslop/tests/cli/cache_and_debug.rs | 2 +- crates/deslop/tests/cli/config.rs | 2 +- crates/deslop/tests/cli/detection.rs | 2 +- crates/deslop/tests/cli/embedding_ollama.rs | 4 +- crates/deslop/tests/cli/embedding_stub.rs | 4 +- crates/deslop/tests/cli/from_report.rs | 2 +- crates/deslop/tests/cli/invocation.rs | 2 +- crates/deslop/tests/cli/language_sections.rs | 2 +- crates/deslop/tests/cli/logging.rs | 4 +- crates/deslop/tests/cli/metrics.rs | 2 +- crates/deslop/tests/cli/report_css.rs | 2 +- crates/deslop/tests/cli/thresholds.rs | 2 +- .../tests/config_include_dependencies.rs | 1 - crates/deslop/tests/cross_cluster_collapse.rs | 1 - .../deslop/tests/cross_cluster_enclosure.rs | 1 - crates/deslop/tests/cross_language.rs | 1 - .../tests/csharp_issue_66_route_mapping.rs | 1 - .../csharp_type1_type2_distinct_buckets.rs | 1 - .../tests/csharp_unrelated_xunit_classes.rs | 1 - .../deslop/tests/dart_forwarding_fail_open.rs | 1 - .../dart_issue_119_embedding_role_mismatch.rs | 1 - ...t_issue_197_single_file_structural_only.rs | 1 - crates/deslop/tests/dart_signatures.rs | 1 - .../declaration_family_mixed_component.rs | 1 - .../tests/declaration_family_plurality.rs | 1 - crates/deslop/tests/diff_ingest_refusals.rs | 1 - crates/deslop/tests/diff_scoped_ingest.rs | 1 - crates/deslop/tests/diff_scoped_reporting.rs | 1 - .../deslop/tests/embedding_discovery_route.rs | 1 - crates/deslop/tests/embedding_non_finite.rs | 1 - crates/deslop/tests/embedding_perf.rs | 3 +- .../tests/embedding_route_invariance.rs | 1 - .../tests/fsharp_deep_match_stack_overflow.rs | 1 - .../fsharp_issue_336_data_table_category.rs | 1 - .../fsharp_issue_339_sibling_window_rename.rs | 1 - .../fsharp_issue_339_token_fallback_rename.rs | 1 - crates/deslop/tests/fused_golden_bands.rs | 1 - .../deslop/tests/fused_golden_invariants.rs | 1 - crates/deslop/tests/fused_score_bounds.rs | 1 - crates/deslop/tests/go_vendor_exclusion.rs | 1 - .../deslop/tests/incremental_equivalence.rs | 1 - .../tests/incremental_multilang_golden.rs | 1 - .../tests/incremental_multilang_matrix.rs | 1 - .../tests/issue_119_role_gate_exercised.rs | 1 - ...34_structural_only_not_nearly_identical.rs | 1 - .../tests/issue_165_dart_generated_header.rs | 1 - .../tests/issue_168_deep_nesting_no_crash.rs | 1 - .../tests/issue_169_dart_const_registry.rs | 1 - .../tests/issue_169_dart_filter_precision.rs | 1 - .../tests/issue_190_data_table_demote.rs | 1 - .../issue_331_336_shape_only_saturation.rs | 1 - ...e_342_scan_root_under_excluded_ancestor.rs | 1 - .../tests/issue_343_sum_clamp_saturation.rs | 1 - .../issue_372_identical_snippet_cosine.rs | 1 - crates/deslop/tests/js_language_features.rs | 1 - crates/deslop/tests/js_ts_clone_buckets.rs | 1 - crates/deslop/tests/js_ts_extensions.rs | 1 - .../tests/js_ts_false_positive_filters.rs | 1 - .../deslop/tests/js_ts_negative_controls.rs | 1 - crates/deslop/tests/js_ts_normalization.rs | 1 - crates/deslop/tests/js_ts_signatures.rs | 1 - crates/deslop/tests/jsx_tsx_components.rs | 1 - ...independent_verification_false_positive.rs | 1 - crates/deslop/tests/location_rendering.rs | 1 - .../deslop/tests/lsh_only_nearmiss_recall.rs | 1 - .../tests/metric_excludes_hidden_clusters.rs | 1 - .../deslop/tests/metric_language_agnostic.rs | 1 - crates/deslop/tests/metrics_folder_rollup.rs | 1 - crates/deslop/tests/ollama_failures.rs | 1 - crates/deslop/tests/pair_size_coherence.rs | 1 - .../tests/python_dict_assert_payload_proof.rs | 1 - .../deslop/tests/python_dict_assert_reach.rs | 1 - .../tests/python_dict_assert_rhs_logic.rs | 1 - .../tests/python_dict_false_positive.rs | 1 - ...ython_generated_template_false_positive.rs | 1 - .../tests/python_issue_100_kwargs_ctor.rs | 1 - .../tests/python_issue_104_module_preamble.rs | 1 - .../tests/python_issue_105_mapped_column.rs | 1 - .../python_issue_107_chained_dict_assert.rs | 1 - .../tests/python_issue_112_dict_fixture.rs | 1 - .../python_issue_115_pydantic_partial.rs | 1 - .../deslop/tests/python_issue_115_strenum.rs | 1 - ...ython_issue_119_embedding_role_mismatch.rs | 1 - .../tests/python_issue_133_constant_table.rs | 1 - .../tests/python_issue_69_abstract_method.rs | 1 - .../tests/python_issue_72_monkeypatch.rs | 1 - .../tests/python_issue_96_all_exports.rs | 1 - ...hon_issue_97_parametric_invariant_tests.rs | 1 - .../tests/python_literal_variation_calls.rs | 1 - crates/deslop/tests/python_signatures.rs | 1 - .../tests/rank_structural_only_policy.rs | 1 - .../tests/rename_literal_monotonicity.rs | 1 - crates/deslop/tests/report_golden.rs | 1 - crates/deslop/tests/rerun.rs | 1 - .../rust_issue_147_iter_collect_idiom.rs | 1 - .../tests/rust_issue_150_mod_declarations.rs | 1 - ...st_issue_154_structural_only_signatures.rs | 1 - .../tests/rust_issue_176_match_dispatch.rs | 1 - .../tests/rust_issue_224_struct_field_runs.rs | 1 - .../rust_issue_232_token_jaccard_identical.rs | 1 - .../rust_test_boilerplate_false_positive.rs | 1 - .../rust_trait_boilerplate_false_positive.rs | 1 - crates/deslop/tests/showstoppers.rs | 1 - crates/deslop/tests/signature_reuse.rs | 1 - crates/deslop/tests/suite.rs | 228 ++++++++++++++++++ .../deslop/tests/type2_rename_anchor_floor.rs | 1 - crates/deslop/tests/type3_enclosing_method.rs | 1 - crates/deslop/tests/typescript_features.rs | 1 - scripts/typediagram-gen.mjs | 37 ++- scripts/typediagram-gen.test.mjs | 95 ++++++++ 177 files changed, 637 insertions(+), 177 deletions(-) create mode 100644 crates/deslop-core/tests/suite.rs create mode 100644 crates/deslop-lsp/tests/suite.rs create mode 100644 crates/deslop-mcp/tests/suite.rs create mode 100644 crates/deslop/tests/suite.rs create mode 100644 scripts/typediagram-gen.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ecc0a46..4933f89e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,7 +81,14 @@ jobs: name: CI needs: changes if: needs.changes.outputs.code == 'true' - runs-on: ubuntu-latest + # [CI-RUNNER] The Rust gates are the only jobs whose cost is compile + # time, so they are the only ones sized up. `vars.RUST_RUNNER` is the + # single place the label lives: set it to a larger-runner label + # (`gh variable set RUST_RUNNER --body ubuntu-latest-16-cores`) and + # every Rust job moves together. It falls back to `ubuntu-latest`, + # because a `runs-on` label the org has not provisioned does not fail + # — it queues forever, which is worse than a slow run. + runs-on: ${{ vars.RUST_RUNNER || 'ubuntu-latest' }} # Covers a release clippy build, an instrumented coverage build, the # full workspace suite, the self-scan duplication gate and the # deployment gates. The previous 10 was sized against runs that diff --git a/Cargo.toml b/Cargo.toml index a73ea97e..b056ef5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,3 +94,21 @@ missing_docs_in_private_items = "deny" lto = "thin" codegen-units = 1 strip = "symbols" + +# [CI-RELEASE-BUILD] [TEST-PROFILE] The profile the test targets build under. +# +# Inherits `release` — same `opt-level`, same codegen, so the suites still +# exercise optimised code and never gate release artifacts on a debug build. +# It drops only the two settings that exist to squeeze the *shipped* binary +# and cost nothing but time on a test binary: whole-program ThinLTO and +# `codegen-units = 1`. Those are per-link costs, and a test target links the +# entire workspace. +# +# Measured on this tree, 8 test targets rebuilt after touching deslop-core: +# 74.3s under `release`, 26.0s under this profile — 2.9x. `make build`, +# `dup-gate` and `deployment-verify` still use `release`, so everything that +# ships is still fully optimised. +[profile.release-test] +inherits = "release" +lto = false +codegen-units = 16 diff --git a/Makefile b/Makefile index 9d0d3de9..a3a4d5f2 100644 --- a/Makefile +++ b/Makefile @@ -139,7 +139,7 @@ _coverage_check: ## before clippy parses the workspace on a fresh checkout. lint: typediagram-gen @echo "==> Linting..." - cargo clippy --release --all-targets --workspace -- -D warnings + cargo clippy --profile release-test --all-targets --workspace -- -D warnings @bash scripts/taxonomy-gate.sh @echo "==> VSIX harness + packaging script gates (unit)..." @node --test clients/vscode/scripts/*.test.mjs diff --git a/crates/deslop-core/Cargo.toml b/crates/deslop-core/Cargo.toml index dbcbfb3f..cde3b09b 100644 --- a/crates/deslop-core/Cargo.toml +++ b/crates/deslop-core/Cargo.toml @@ -6,6 +6,7 @@ rust-version.workspace = true license.workspace = true repository.workspace = true description = "Deslop analysis engine — AST fingerprinting, clustering, ranking, live incremental re-analysis. The shared core behind the LSP, MCP, and CLI surfaces." +autotests = false [features] default = [] @@ -60,3 +61,7 @@ tempfile.workspace = true [lints] workspace = true + +[[test]] +name = "suite" +path = "tests/suite.rs" diff --git a/crates/deslop-core/tests/embedding_pass_observability.rs b/crates/deslop-core/tests/embedding_pass_observability.rs index 4c3df87f..d8769cac 100644 --- a/crates/deslop-core/tests/embedding_pass_observability.rs +++ b/crates/deslop-core/tests/embedding_pass_observability.rs @@ -18,7 +18,6 @@ use deslop_core::{ EmbeddingProvider, EmbeddingSpec, ProviderError, }; -mod common; use crate::common::*; const VECTOR_DIMS: usize = 4; diff --git a/crates/deslop-core/tests/issue_117.rs b/crates/deslop-core/tests/issue_117.rs index 17f6cdce..883a5b95 100644 --- a/crates/deslop-core/tests/issue_117.rs +++ b/crates/deslop-core/tests/issue_117.rs @@ -10,7 +10,6 @@ use deslop_core::{ embedding::test_support::StubProvider, live::AnalysisSession, report::ReportCluster, }; -mod common; use crate::common::*; #[tokio::test(flavor = "multi_thread")] diff --git a/crates/deslop-core/tests/issue_121_pytest_fixture_boilerplate.rs b/crates/deslop-core/tests/issue_121_pytest_fixture_boilerplate.rs index abf20a78..52af2a70 100644 --- a/crates/deslop-core/tests/issue_121_pytest_fixture_boilerplate.rs +++ b/crates/deslop-core/tests/issue_121_pytest_fixture_boilerplate.rs @@ -3,7 +3,7 @@ //! //! Tests [CLONE-NOISE-PY-PYTEST-FIXTURE] -mod common; +use crate::common; use anyhow::Result; use common::ReportFixture; diff --git a/crates/deslop-core/tests/issue_239_csharp_reparse.rs b/crates/deslop-core/tests/issue_239_csharp_reparse.rs index d78d61f3..48520588 100644 --- a/crates/deslop-core/tests/issue_239_csharp_reparse.rs +++ b/crates/deslop-core/tests/issue_239_csharp_reparse.rs @@ -16,7 +16,7 @@ //! overshoots it by an order of magnitude while the cached path clears it //! several times over on debug, release, and coverage builds alike. -mod common; +use crate::common; use std::{fmt::Write as _, time::Instant}; diff --git a/crates/deslop-core/tests/issue_270_seed_language_drift.rs b/crates/deslop-core/tests/issue_270_seed_language_drift.rs index 1b021b84..bf7204c5 100644 --- a/crates/deslop-core/tests/issue_270_seed_language_drift.rs +++ b/crates/deslop-core/tests/issue_270_seed_language_drift.rs @@ -24,7 +24,6 @@ use deslop_core::{ EmbeddingProvider, }; -mod common; use crate::common::copy_fixture; #[test] diff --git a/crates/deslop-core/tests/issue_287_live_ingest_gitignore_parity.rs b/crates/deslop-core/tests/issue_287_live_ingest_gitignore_parity.rs index 3f6d5f8a..e32b61f0 100644 --- a/crates/deslop-core/tests/issue_287_live_ingest_gitignore_parity.rs +++ b/crates/deslop-core/tests/issue_287_live_ingest_gitignore_parity.rs @@ -21,7 +21,6 @@ use std::{fs, path::Path, sync::Arc}; use anyhow::{Context, Result}; use deslop_core::{embedding::test_support::StubProvider, live::AnalysisSession}; -mod common; use crate::common::*; /// C# that clusters with the fixture's `Alpha.cs`, so an admitted copy is diff --git a/crates/deslop-core/tests/issue_299_no_op_pass_skips_rerender.rs b/crates/deslop-core/tests/issue_299_no_op_pass_skips_rerender.rs index 7c83dfd0..a780dff0 100644 --- a/crates/deslop-core/tests/issue_299_no_op_pass_skips_rerender.rs +++ b/crates/deslop-core/tests/issue_299_no_op_pass_skips_rerender.rs @@ -43,7 +43,6 @@ use deslop_core::{ }; use tokio::sync::broadcast::{error::TryRecvError, Receiver}; -mod common; use crate::common::*; /// C# that clusters with the fixture's `Alpha.cs`, so if any gate were to diff --git a/crates/deslop-core/tests/issue_45_observability.rs b/crates/deslop-core/tests/issue_45_observability.rs index 54848f79..20a51b5a 100644 --- a/crates/deslop-core/tests/issue_45_observability.rs +++ b/crates/deslop-core/tests/issue_45_observability.rs @@ -8,7 +8,6 @@ use deslop_core::{ EmbeddingMode, }; -mod common; use crate::common::*; #[test] diff --git a/crates/deslop-core/tests/issue_98_99_108_120_122_thresholds.rs b/crates/deslop-core/tests/issue_98_99_108_120_122_thresholds.rs index 62532365..588afb91 100644 --- a/crates/deslop-core/tests/issue_98_99_108_120_122_thresholds.rs +++ b/crates/deslop-core/tests/issue_98_99_108_120_122_thresholds.rs @@ -1,7 +1,7 @@ //! Regression coverage for the low-structure fusion false positives //! tracked in GH #98, #99, #108, #120, and #122. -mod common; +use crate::common; use anyhow::Result; use common::ReportFixture; diff --git a/crates/deslop-core/tests/live.rs b/crates/deslop-core/tests/live.rs index adff7f99..89074a2b 100644 --- a/crates/deslop-core/tests/live.rs +++ b/crates/deslop-core/tests/live.rs @@ -25,7 +25,6 @@ use deslop_core::{ EmbeddingProvider, EmbeddingSpec, ExclusionConfig, ProviderError, }; -mod common; use tokio::sync::{Semaphore, SemaphorePermit}; use crate::common::*; diff --git a/crates/deslop-core/tests/live_merge_plan.rs b/crates/deslop-core/tests/live_merge_plan.rs index 4b8c93f7..e7025b67 100644 --- a/crates/deslop-core/tests/live_merge_plan.rs +++ b/crates/deslop-core/tests/live_merge_plan.rs @@ -3,7 +3,6 @@ //! `AnalysisSession`, gathers the in-memory inputs, and returns the //! mechanical plan — or a reasoned refusal, never a partial answer. -mod common; use std::sync::Arc; diff --git a/crates/deslop-core/tests/refactor_ast_access.rs b/crates/deslop-core/tests/refactor_ast_access.rs index 86ff99ee..0fc56d86 100644 --- a/crates/deslop-core/tests/refactor_ast_access.rs +++ b/crates/deslop-core/tests/refactor_ast_access.rs @@ -3,7 +3,6 @@ //! bytes are retrievable from the in-memory pipeline state through the //! public `deslop-core` API — never over the wire. -mod common; use anyhow::{ensure, Context, Result}; use deslop_core::ast::ByteRange; diff --git a/crates/deslop-core/tests/refactor_consolidate.rs b/crates/deslop-core/tests/refactor_consolidate.rs index 40bab8ca..d7452fbe 100644 --- a/crates/deslop-core/tests/refactor_consolidate.rs +++ b/crates/deslop-core/tests/refactor_consolidate.rs @@ -7,7 +7,6 @@ //! canonical, would-empty file, non-definition occurrences, non-Rust //! languages) must refuse with a reason. -mod common; use std::{ collections::HashMap, diff --git a/crates/deslop-core/tests/refactor_content_gate.rs b/crates/deslop-core/tests/refactor_content_gate.rs index df0084de..69a1ea99 100644 --- a/crates/deslop-core/tests/refactor_content_gate.rs +++ b/crates/deslop-core/tests/refactor_content_gate.rs @@ -14,7 +14,6 @@ //! Both directions are pinned here, because a gate that only ever //! refuses is as wrong as one that only ever allows. -mod common; use std::{ collections::HashMap, diff --git a/crates/deslop-core/tests/refactor_extract.rs b/crates/deslop-core/tests/refactor_extract.rs index 7221cba4..797c74ba 100644 --- a/crates/deslop-core/tests/refactor_extract.rs +++ b/crates/deslop-core/tests/refactor_extract.rs @@ -9,7 +9,6 @@ //! fully-applied buffer against golden snapshots shared with the LSP //! code-action tests. -mod common; use std::fs; diff --git a/crates/deslop-core/tests/refactor_extract_negative.rs b/crates/deslop-core/tests/refactor_extract_negative.rs index 7e5e664e..bbd84dc2 100644 --- a/crates/deslop-core/tests/refactor_extract_negative.rs +++ b/crates/deslop-core/tests/refactor_extract_negative.rs @@ -4,7 +4,6 @@ //! and non-exact-bucket clusters must all be silently refused — //! `Ok(None)`, never an error, never a partial plan. -mod common; use std::fs; diff --git a/crates/deslop-core/tests/refactor_extract_write_gate.rs b/crates/deslop-core/tests/refactor_extract_write_gate.rs index 27443a3f..4bc43b79 100644 --- a/crates/deslop-core/tests/refactor_extract_write_gate.rs +++ b/crates/deslop-core/tests/refactor_extract_write_gate.rs @@ -5,7 +5,6 @@ //! loss the type-safety backstop cannot catch. Writes to span-*bound* //! names stay extractable: they vacate with the span. -mod common; use anyhow::{anyhow, Result}; diff --git a/crates/deslop-core/tests/refactor_merge.rs b/crates/deslop-core/tests/refactor_merge.rs index 75450743..fe35ae86 100644 --- a/crates/deslop-core/tests/refactor_merge.rs +++ b/crates/deslop-core/tests/refactor_merge.rs @@ -8,7 +8,6 @@ //! with the LSP code-action suite. The fixtures a merge must *decline* //! live in `refactor_merge_refusals.rs`. -mod common; use std::fs; diff --git a/crates/deslop-core/tests/refactor_merge_refusals.rs b/crates/deslop-core/tests/refactor_merge_refusals.rs index f682c354..54cf2158 100644 --- a/crates/deslop-core/tests/refactor_merge_refusals.rs +++ b/crates/deslop-core/tests/refactor_merge_refusals.rs @@ -6,7 +6,6 @@ //! partial plan, because a partial merge silently changes behaviour //! while looking like a successful refactor. -mod common; use anyhow::{anyhow, ensure, Context, Result}; use deslop_core::wire_generated::MergeVerdict; diff --git a/crates/deslop-core/tests/suite.rs b/crates/deslop-core/tests/suite.rs new file mode 100644 index 00000000..a66a21b5 --- /dev/null +++ b/crates/deslop-core/tests/suite.rs @@ -0,0 +1,82 @@ +//! [CI-RELEASE-BUILD] [TEST-ONE-BINARY] The crate's whole integration +//! suite, linked once. +//! +//! Cargo builds one executable per `tests/*.rs`, and each one statically +//! links the entire workspace under the release profile. At 176 files that +//! was 176 whole-program links per CI run — the bulk of a 20-minute compile +//! that cancelled every Rust shard at its cap. Declaring the suites as +//! modules of a single binary links them once instead. +//! +//! Each module below is a former `tests/*.rs`, unchanged apart from its +//! `mod common;` line: the shared helpers are declared here, once, so +//! `crate::common::…` still resolves from every suite. + +/// Shared fixture helpers, declared once for every suite below. +mod common; + +#[path = "cluster_overlap_collapse.rs"] +mod cluster_overlap_collapse; +#[path = "cluster_subsumption.rs"] +mod cluster_subsumption; +#[path = "cross_language_threshold.rs"] +mod cross_language_threshold; +#[path = "diff_render_tags.rs"] +mod diff_render_tags; +#[path = "embedding_pairs.rs"] +mod embedding_pairs; +#[path = "embedding_pass_observability.rs"] +mod embedding_pass_observability; +#[path = "issue_117.rs"] +mod issue_117; +#[path = "issue_121_pytest_fixture_boilerplate.rs"] +mod issue_121_pytest_fixture_boilerplate; +#[path = "issue_124_node_count.rs"] +mod issue_124_node_count; +#[path = "issue_239_csharp_reparse.rs"] +mod issue_239_csharp_reparse; +#[path = "issue_270_seed_language_drift.rs"] +mod issue_270_seed_language_drift; +#[path = "issue_287_live_ingest_gitignore_parity.rs"] +mod issue_287_live_ingest_gitignore_parity; +#[path = "issue_299_no_op_pass_skips_rerender.rs"] +mod issue_299_no_op_pass_skips_rerender; +#[path = "issue_336_deep_ast_stack_overflow.rs"] +mod issue_336_deep_ast_stack_overflow; +#[path = "issue_45_observability.rs"] +mod issue_45_observability; +#[path = "issue_82_embedding_context_budget.rs"] +mod issue_82_embedding_context_budget; +#[path = "issue_91_embedding_roi.rs"] +mod issue_91_embedding_roi; +#[path = "issue_93_embedding_uniqueness.rs"] +mod issue_93_embedding_uniqueness; +#[path = "issue_98_99_108_120_122_thresholds.rs"] +mod issue_98_99_108_120_122_thresholds; +#[path = "lang_registry_vsix_parity.rs"] +mod lang_registry_vsix_parity; +#[path = "live.rs"] +mod live; +#[path = "live_merge_plan.rs"] +mod live_merge_plan; +#[path = "live_session_status.rs"] +mod live_session_status; +#[path = "pair_admission_bounded_max.rs"] +mod pair_admission_bounded_max; +#[path = "refactor_ast_access.rs"] +mod refactor_ast_access; +#[path = "refactor_consolidate.rs"] +mod refactor_consolidate; +#[path = "refactor_content_gate.rs"] +mod refactor_content_gate; +#[path = "refactor_extract.rs"] +mod refactor_extract; +#[path = "refactor_extract_negative.rs"] +mod refactor_extract_negative; +#[path = "refactor_extract_write_gate.rs"] +mod refactor_extract_write_gate; +#[path = "refactor_merge.rs"] +mod refactor_merge; +#[path = "refactor_merge_refusals.rs"] +mod refactor_merge_refusals; +#[path = "report_api.rs"] +mod report_api; diff --git a/crates/deslop-lsp/Cargo.toml b/crates/deslop-lsp/Cargo.toml index e25fb5d5..651ae5bd 100644 --- a/crates/deslop-lsp/Cargo.toml +++ b/crates/deslop-lsp/Cargo.toml @@ -6,6 +6,7 @@ rust-version.workspace = true license.workspace = true repository.workspace = true description = "Deslop LSP server — live duplicate-code analysis streamed to any LSP-capable editor as code is written." +autotests = false [[bin]] name = "deslop-lsp" @@ -47,3 +48,7 @@ tower-lsp.workspace = true [lints] workspace = true + +[[test]] +name = "suite" +path = "tests/suite.rs" diff --git a/crates/deslop-lsp/tests/cli.rs b/crates/deslop-lsp/tests/cli.rs index 114651b5..b8474655 100644 --- a/crates/deslop-lsp/tests/cli.rs +++ b/crates/deslop-lsp/tests/cli.rs @@ -3,7 +3,6 @@ //! Tests [LSP-TESTING] — spawns the real LSP binary and talks JSON-RPC //! over stdio against fixture workspaces; no mocked live session. -mod common; use std::{ path::Path, diff --git a/crates/deslop-lsp/tests/code_action.rs b/crates/deslop-lsp/tests/code_action.rs index 774ff7bb..753356de 100644 --- a/crates/deslop-lsp/tests/code_action.rs +++ b/crates/deslop-lsp/tests/code_action.rs @@ -7,7 +7,7 @@ //! `WorkspaceEdit` client-side, and asserts the resulting buffer //! matches the shared golden snapshot. -mod common; +use crate::common; use std::{ fs, diff --git a/crates/deslop-lsp/tests/code_action_refusal.rs b/crates/deslop-lsp/tests/code_action_refusal.rs index fbbf3c50..9da2afd0 100644 --- a/crates/deslop-lsp/tests/code_action_refusal.rs +++ b/crates/deslop-lsp/tests/code_action_refusal.rs @@ -7,7 +7,7 @@ //! announced with a `window/showMessage` warning, or the user's click //! silently does nothing. -mod common; +use crate::common; use anyhow::{anyhow, ensure, Context, Result}; use common::{ diff --git a/crates/deslop-lsp/tests/cpu_throttle_knob.rs b/crates/deslop-lsp/tests/cpu_throttle_knob.rs index 1cca2491..7d0cc774 100644 --- a/crates/deslop-lsp/tests/cpu_throttle_knob.rs +++ b/crates/deslop-lsp/tests/cpu_throttle_knob.rs @@ -8,7 +8,6 @@ //! configuration is covered at unit test level inside the LSP crate //! but the CLI contract is owned here. -mod common; use std::{ io::{BufRead, BufReader}, diff --git a/crates/deslop-lsp/tests/dependency_reactivity.rs b/crates/deslop-lsp/tests/dependency_reactivity.rs index 64980bd7..e3a4a1c7 100644 --- a/crates/deslop-lsp/tests/dependency_reactivity.rs +++ b/crates/deslop-lsp/tests/dependency_reactivity.rs @@ -2,7 +2,7 @@ //! [CONFIG-EXCLUDE-DEPENDENCIES]. The real filesystem watcher must honour //! the same opt-in as the cold pipeline scan. -mod common; +use crate::common; use std::{fs, path::Path, time::Duration}; diff --git a/crates/deslop-lsp/tests/editor_non_interference.rs b/crates/deslop-lsp/tests/editor_non_interference.rs index c9e228d9..2ba589b7 100644 --- a/crates/deslop-lsp/tests/editor_non_interference.rs +++ b/crates/deslop-lsp/tests/editor_non_interference.rs @@ -12,7 +12,6 @@ //! structural fix is to advertise none of the standard providers at all, //! which these tests pin. -mod common; use std::{path::Path, thread, time::Duration}; diff --git a/crates/deslop-lsp/tests/embedding_failure_progress.rs b/crates/deslop-lsp/tests/embedding_failure_progress.rs index 91595721..d528490f 100644 --- a/crates/deslop-lsp/tests/embedding_failure_progress.rs +++ b/crates/deslop-lsp/tests/embedding_failure_progress.rs @@ -30,7 +30,7 @@ #[path = "../../deslop/tests/cli/mock_ollama.rs"] mod mock_ollama; -mod common; +use crate::common; use std::{ io::BufReader, diff --git a/crates/deslop-lsp/tests/execute_command.rs b/crates/deslop-lsp/tests/execute_command.rs index 5a646c2f..278bfa02 100644 --- a/crates/deslop-lsp/tests/execute_command.rs +++ b/crates/deslop-lsp/tests/execute_command.rs @@ -4,7 +4,6 @@ //! client-bound `window/showDocument` requests so command handlers run //! through the same transport a real editor uses. -mod common; use std::process::{ChildStdin, ChildStdout}; diff --git a/crates/deslop-lsp/tests/history_determinism.rs b/crates/deslop-lsp/tests/history_determinism.rs index 6de950eb..ed355024 100644 --- a/crates/deslop-lsp/tests/history_determinism.rs +++ b/crates/deslop-lsp/tests/history_determinism.rs @@ -1,7 +1,7 @@ //! Real-LSP regression for [PIPELINE-DETERMINISM]. Returning to identical //! source and config bytes must return the identical ordered report. -mod common; +use crate::common; use std::{collections::BTreeMap, fs, path::Path, time::Duration}; diff --git a/crates/deslop-lsp/tests/lsp_embedding_determinism.rs b/crates/deslop-lsp/tests/lsp_embedding_determinism.rs index 9f3c2140..9f260d10 100644 --- a/crates/deslop-lsp/tests/lsp_embedding_determinism.rs +++ b/crates/deslop-lsp/tests/lsp_embedding_determinism.rs @@ -6,7 +6,7 @@ #[path = "../../deslop/tests/cli/mock_ollama.rs"] mod mock_ollama; -mod common; +use crate::common; use std::{ io::BufReader, diff --git a/crates/deslop-lsp/tests/lsp_workspace_scoping.rs b/crates/deslop-lsp/tests/lsp_workspace_scoping.rs index 81b2cb8f..bffe481e 100644 --- a/crates/deslop-lsp/tests/lsp_workspace_scoping.rs +++ b/crates/deslop-lsp/tests/lsp_workspace_scoping.rs @@ -2,7 +2,7 @@ //! live LSP admits into a workspace. Drives the real `deslop-lsp` binary //! over stdio; no pipeline internals are called. -mod common; +use crate::common; use std::{collections::BTreeSet, fs, path::Path}; diff --git a/crates/deslop-lsp/tests/notifications.rs b/crates/deslop-lsp/tests/notifications.rs index e04e8a44..7281c7d3 100644 --- a/crates/deslop-lsp/tests/notifications.rs +++ b/crates/deslop-lsp/tests/notifications.rs @@ -15,7 +15,6 @@ use std::{ use anyhow::{anyhow, ensure, Result}; -mod common; use crate::common::*; type FrameResult = std::result::Result; diff --git a/crates/deslop-lsp/tests/observability_heartbeat.rs b/crates/deslop-lsp/tests/observability_heartbeat.rs index 90ccc0e2..a370cebf 100644 --- a/crates/deslop-lsp/tests/observability_heartbeat.rs +++ b/crates/deslop-lsp/tests/observability_heartbeat.rs @@ -19,7 +19,6 @@ use anyhow::{anyhow, Result}; use serde_json::{json, Value}; use std::io::BufReader; -mod common; use crate::common::*; static NEXT_ID: AtomicI64 = AtomicI64::new(90_000); diff --git a/crates/deslop-lsp/tests/ollama_fallback.rs b/crates/deslop-lsp/tests/ollama_fallback.rs index 2260bbf5..6508d5b2 100644 --- a/crates/deslop-lsp/tests/ollama_fallback.rs +++ b/crates/deslop-lsp/tests/ollama_fallback.rs @@ -11,7 +11,7 @@ //! unreachable provider must degrade gracefully — a clean JSON-RPC reply and //! a live process — never a crash that loops the editor's restart logic. -mod common; +use crate::common; use std::{ thread, diff --git a/crates/deslop-lsp/tests/state_file_and_ipc.rs b/crates/deslop-lsp/tests/state_file_and_ipc.rs index 1c317050..c622a619 100644 --- a/crates/deslop-lsp/tests/state_file_and_ipc.rs +++ b/crates/deslop-lsp/tests/state_file_and_ipc.rs @@ -17,7 +17,7 @@ #![cfg(unix)] -mod common; +use crate::common; use std::{ fs, diff --git a/crates/deslop-lsp/tests/suite.rs b/crates/deslop-lsp/tests/suite.rs new file mode 100644 index 00000000..0c61f756 --- /dev/null +++ b/crates/deslop-lsp/tests/suite.rs @@ -0,0 +1,50 @@ +//! [CI-RELEASE-BUILD] [TEST-ONE-BINARY] The crate's whole integration +//! suite, linked once. +//! +//! Cargo builds one executable per `tests/*.rs`, and each one statically +//! links the entire workspace under the release profile. At 176 files that +//! was 176 whole-program links per CI run — the bulk of a 20-minute compile +//! that cancelled every Rust shard at its cap. Declaring the suites as +//! modules of a single binary links them once instead. +//! +//! Each module below is a former `tests/*.rs`, unchanged apart from its +//! `mod common;` line: the shared helpers are declared here, once, so +//! `crate::common::…` still resolves from every suite. + +/// Shared fixture helpers, declared once for every suite below. +mod common; + +#[path = "app.rs"] +mod app; +#[path = "cli.rs"] +mod cli; +#[path = "code_action.rs"] +mod code_action; +#[path = "code_action_refusal.rs"] +mod code_action_refusal; +#[path = "cpu_throttle_knob.rs"] +mod cpu_throttle_knob; +#[path = "dependency_reactivity.rs"] +mod dependency_reactivity; +#[path = "editor_non_interference.rs"] +mod editor_non_interference; +#[path = "embedding_failure_progress.rs"] +mod embedding_failure_progress; +#[path = "execute_command.rs"] +mod execute_command; +#[path = "history_determinism.rs"] +mod history_determinism; +#[path = "lsp_embedding_determinism.rs"] +mod lsp_embedding_determinism; +#[path = "lsp_workspace_scoping.rs"] +mod lsp_workspace_scoping; +#[path = "notifications.rs"] +mod notifications; +#[path = "observability_heartbeat.rs"] +mod observability_heartbeat; +#[path = "ollama_fallback.rs"] +mod ollama_fallback; +#[path = "state_file_and_ipc.rs"] +mod state_file_and_ipc; +#[path = "virtual_document.rs"] +mod virtual_document; diff --git a/crates/deslop-lsp/tests/virtual_document.rs b/crates/deslop-lsp/tests/virtual_document.rs index 2993af0b..288e6199 100644 --- a/crates/deslop-lsp/tests/virtual_document.rs +++ b/crates/deslop-lsp/tests/virtual_document.rs @@ -5,7 +5,6 @@ //! `deslop://schema`, `deslop://report`, `deslop://cluster/` — and //! returns a structured JSON-RPC error on malformed input. -mod common; use std::{path::Path, thread, time::Duration}; diff --git a/crates/deslop-mcp/Cargo.toml b/crates/deslop-mcp/Cargo.toml index eed29f4b..265a2763 100644 --- a/crates/deslop-mcp/Cargo.toml +++ b/crates/deslop-mcp/Cargo.toml @@ -6,6 +6,7 @@ rust-version.workspace = true license.workspace = true repository.workspace = true description = "Deslop MCP server — live duplicate-code tools over stdio for Claude, Cursor, Codex, Continue, and any MCP-capable AI coding agent. Query the running analysis mid-generation, before a copy-paste happens." +autotests = false [[bin]] name = "deslop-mcp" @@ -38,3 +39,7 @@ tempfile.workspace = true [lints] workspace = true + +[[test]] +name = "suite" +path = "tests/suite.rs" diff --git a/crates/deslop-mcp/tests/cli.rs b/crates/deslop-mcp/tests/cli.rs index 36a4e3fd..e2c50d12 100644 --- a/crates/deslop-mcp/tests/cli.rs +++ b/crates/deslop-mcp/tests/cli.rs @@ -23,7 +23,7 @@ use assert_cmd::cargo::cargo_bin; use serde_json::{json, Value}; use tempfile::TempDir; -mod common; +use crate::common; use common::{fixture_root, value_array, value_get}; #[cfg(unix)] use common::{pid_exists, read_mcp_pid, terminate_pid, wait_for_pid_exit, KILLABLE_PARENT_SCRIPT}; diff --git a/crates/deslop-mcp/tests/dart_generated_fp_over_mcp.rs b/crates/deslop-mcp/tests/dart_generated_fp_over_mcp.rs index 541b5704..c58f6fb9 100644 --- a/crates/deslop-mcp/tests/dart_generated_fp_over_mcp.rs +++ b/crates/deslop-mcp/tests/dart_generated_fp_over_mcp.rs @@ -13,7 +13,7 @@ use anyhow::{ensure, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{call_tool, copied_fixture_named, initialized_mcp, spawn_lsp_and_wait_for_socket}; /// File names of every occurrence across all returned clusters. diff --git a/crates/deslop-mcp/tests/dart_language_label_over_mcp.rs b/crates/deslop-mcp/tests/dart_language_label_over_mcp.rs index 919b5336..24574713 100644 --- a/crates/deslop-mcp/tests/dart_language_label_over_mcp.rs +++ b/crates/deslop-mcp/tests/dart_language_label_over_mcp.rs @@ -14,7 +14,7 @@ use anyhow::Result; -mod common; +use crate::common; use common::language_label::assert_language_label_over_mcp; #[test] diff --git a/crates/deslop-mcp/tests/fsharp_language_label_over_mcp.rs b/crates/deslop-mcp/tests/fsharp_language_label_over_mcp.rs index 7b2ef5f0..d366dec3 100644 --- a/crates/deslop-mcp/tests/fsharp_language_label_over_mcp.rs +++ b/crates/deslop-mcp/tests/fsharp_language_label_over_mcp.rs @@ -14,7 +14,7 @@ use anyhow::Result; -mod common; +use crate::common; use common::language_label::assert_language_label_over_mcp; #[test] diff --git a/crates/deslop-mcp/tests/issue_135_rescan_generation.rs b/crates/deslop-mcp/tests/issue_135_rescan_generation.rs index c437a62e..9666af02 100644 --- a/crates/deslop-mcp/tests/issue_135_rescan_generation.rs +++ b/crates/deslop-mcp/tests/issue_135_rescan_generation.rs @@ -11,7 +11,7 @@ use anyhow::{anyhow, ensure, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ copied_fixture, spawn_lsp_and_wait_for_socket, structured_content, wait_for_state_then_init_mcp, McpHandle, diff --git a/crates/deslop-mcp/tests/issue_136_codex_payload_size.rs b/crates/deslop-mcp/tests/issue_136_codex_payload_size.rs index c2b95054..c08e74c9 100644 --- a/crates/deslop-mcp/tests/issue_136_codex_payload_size.rs +++ b/crates/deslop-mcp/tests/issue_136_codex_payload_size.rs @@ -23,7 +23,7 @@ use std::{fs, path::Path}; use anyhow::{anyhow, ensure, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ copied_fixture, initialized_mcp, lsp_workspace_with_socket, spawn_lsp_and_wait_for_socket, structured_content, diff --git a/crates/deslop-mcp/tests/issue_137_ipc_freshness.rs b/crates/deslop-mcp/tests/issue_137_ipc_freshness.rs index 301487ea..c6f45777 100644 --- a/crates/deslop-mcp/tests/issue_137_ipc_freshness.rs +++ b/crates/deslop-mcp/tests/issue_137_ipc_freshness.rs @@ -13,7 +13,7 @@ use std::{fs, time::Duration}; use anyhow::{anyhow, ensure, Context, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ cluster_ids, copied_fixture, initialized_mcp, lsp_workspace_with_socket, spawn_lsp_and_wait_for_socket, structured_content, wait_for_path, McpHandle, SOCKET_TIMEOUT, diff --git a/crates/deslop-mcp/tests/issue_148_version_mismatch.rs b/crates/deslop-mcp/tests/issue_148_version_mismatch.rs index b6242988..52ea5c16 100644 --- a/crates/deslop-mcp/tests/issue_148_version_mismatch.rs +++ b/crates/deslop-mcp/tests/issue_148_version_mismatch.rs @@ -20,7 +20,7 @@ use anyhow::{ensure, Result}; use serde_json::{json, Value}; use tempfile::TempDir; -mod common; +use crate::common; use common::{error_and_message, initialized_mcp}; #[test] diff --git a/crates/deslop-mcp/tests/issue_149_ui_mcp_agreement.rs b/crates/deslop-mcp/tests/issue_149_ui_mcp_agreement.rs index b1e70687..22e5f8a7 100644 --- a/crates/deslop-mcp/tests/issue_149_ui_mcp_agreement.rs +++ b/crates/deslop-mcp/tests/issue_149_ui_mcp_agreement.rs @@ -16,7 +16,7 @@ use std::{ use anyhow::{anyhow, ensure, Context, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{initialized_mcp, lsp_workspace_with_socket, structured_content, McpHandle}; /// Lower bound for the slug shared with `clusterSlug()` in the VSIX diff --git a/crates/deslop-mcp/tests/issue_151_socket_path_in_lsp_missing_error.rs b/crates/deslop-mcp/tests/issue_151_socket_path_in_lsp_missing_error.rs index 7bf8f86f..d6c28468 100644 --- a/crates/deslop-mcp/tests/issue_151_socket_path_in_lsp_missing_error.rs +++ b/crates/deslop-mcp/tests/issue_151_socket_path_in_lsp_missing_error.rs @@ -14,7 +14,7 @@ use anyhow::{ensure, Result}; use serde_json::json; use tempfile::TempDir; -mod common; +use crate::common; use common::{error_and_message, expected_socket_fragment, initialized_mcp}; #[test] diff --git a/crates/deslop-mcp/tests/issue_153_rescan_freshness.rs b/crates/deslop-mcp/tests/issue_153_rescan_freshness.rs index 91aacf40..c3c95213 100644 --- a/crates/deslop-mcp/tests/issue_153_rescan_freshness.rs +++ b/crates/deslop-mcp/tests/issue_153_rescan_freshness.rs @@ -15,7 +15,7 @@ use anyhow::{anyhow, ensure, Context, Result}; use serde_json::Value; -mod common; +use crate::common; use common::{lsp_workspace_with_socket, rescan_call, wait_for_state_then_init_mcp}; /// One unique C# file body that shares no normalised subtrees with diff --git a/crates/deslop-mcp/tests/issue_156_cluster_id_stale_offsets.rs b/crates/deslop-mcp/tests/issue_156_cluster_id_stale_offsets.rs index c97db793..d1c583d5 100644 --- a/crates/deslop-mcp/tests/issue_156_cluster_id_stale_offsets.rs +++ b/crates/deslop-mcp/tests/issue_156_cluster_id_stale_offsets.rs @@ -16,7 +16,7 @@ use anyhow::{anyhow, ensure, Context, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{call_tool, lsp_workspace_with_socket, rescan_call, wait_for_state_then_init_mcp}; /// Issue #156: after rescanning, the cluster payload returned by diff --git a/crates/deslop-mcp/tests/issue_157_lsp_not_running_recovery_data.rs b/crates/deslop-mcp/tests/issue_157_lsp_not_running_recovery_data.rs index 9acbff2f..3674d496 100644 --- a/crates/deslop-mcp/tests/issue_157_lsp_not_running_recovery_data.rs +++ b/crates/deslop-mcp/tests/issue_157_lsp_not_running_recovery_data.rs @@ -13,7 +13,7 @@ use anyhow::{anyhow, ensure, Result}; use serde_json::{json, Value}; use tempfile::TempDir; -mod common; +use crate::common; use common::{error_and_message, expected_socket_fragment, initialized_mcp}; #[test] diff --git a/crates/deslop-mcp/tests/lsp_integration.rs b/crates/deslop-mcp/tests/lsp_integration.rs index 50e188e6..9cd8b3f1 100644 --- a/crates/deslop-mcp/tests/lsp_integration.rs +++ b/crates/deslop-mcp/tests/lsp_integration.rs @@ -18,7 +18,7 @@ use std::fs; use anyhow::{anyhow, ensure, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ copied_fixture, initialized_mcp, lsp_workspace_with_socket, spawn_lsp_and_wait_for_socket, structured_content, wait_for_state_then_init_mcp, McpHandle, diff --git a/crates/deslop-mcp/tests/merge_plan.rs b/crates/deslop-mcp/tests/merge_plan.rs index 494e5880..b9a45177 100644 --- a/crates/deslop-mcp/tests/merge_plan.rs +++ b/crates/deslop-mcp/tests/merge_plan.rs @@ -4,7 +4,7 @@ //! and the wire `WorkspaceEdit`. Unknown ids surface the stable //! `UnknownCluster` error. -mod common; +use crate::common; use anyhow::{anyhow, ensure, Context, Result}; use common::{ diff --git a/crates/deslop-mcp/tests/orphan_exit.rs b/crates/deslop-mcp/tests/orphan_exit.rs index 5f02f8ca..c5c0d2c7 100644 --- a/crates/deslop-mcp/tests/orphan_exit.rs +++ b/crates/deslop-mcp/tests/orphan_exit.rs @@ -13,7 +13,7 @@ use std::{ use anyhow::{anyhow, ensure, Context, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ fixture_root, pid_exists, read_mcp_pid, terminate_pid, value_get, wait_for_pid_exit, KILLABLE_PARENT_SCRIPT, diff --git a/crates/deslop-mcp/tests/state_file_backend.rs b/crates/deslop-mcp/tests/state_file_backend.rs index 6a4e9124..33540f88 100644 --- a/crates/deslop-mcp/tests/state_file_backend.rs +++ b/crates/deslop-mcp/tests/state_file_backend.rs @@ -26,7 +26,7 @@ use std::{fs, time::Duration}; use anyhow::{anyhow, ensure, Context, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ cluster_ids, copied_fixture, initialized_mcp, lsp_workspace_with_socket, spawn_lsp_and_wait_for_socket, structured_content, wait_for_path, SOCKET_TIMEOUT, diff --git a/crates/deslop-mcp/tests/suite.rs b/crates/deslop-mcp/tests/suite.rs new file mode 100644 index 00000000..3981fe9d --- /dev/null +++ b/crates/deslop-mcp/tests/suite.rs @@ -0,0 +1,56 @@ +//! [CI-RELEASE-BUILD] [TEST-ONE-BINARY] The crate's whole integration +//! suite, linked once. +//! +//! Cargo builds one executable per `tests/*.rs`, and each one statically +//! links the entire workspace under the release profile. At 176 files that +//! was 176 whole-program links per CI run — the bulk of a 20-minute compile +//! that cancelled every Rust shard at its cap. Declaring the suites as +//! modules of a single binary links them once instead. +//! +//! Each module below is a former `tests/*.rs`, unchanged apart from its +//! `mod common;` line: the shared helpers are declared here, once, so +//! `crate::common::…` still resolves from every suite. + +/// Shared fixture helpers, declared once for every suite below. +mod common; + +#[path = "cli.rs"] +mod cli; +#[path = "dart_generated_fp_over_mcp.rs"] +mod dart_generated_fp_over_mcp; +#[path = "dart_language_label_over_mcp.rs"] +mod dart_language_label_over_mcp; +#[path = "fsharp_language_label_over_mcp.rs"] +mod fsharp_language_label_over_mcp; +#[path = "issue_135_rescan_generation.rs"] +mod issue_135_rescan_generation; +#[path = "issue_136_codex_payload_size.rs"] +mod issue_136_codex_payload_size; +#[path = "issue_137_ipc_freshness.rs"] +mod issue_137_ipc_freshness; +#[path = "issue_148_version_mismatch.rs"] +mod issue_148_version_mismatch; +#[path = "issue_149_ui_mcp_agreement.rs"] +mod issue_149_ui_mcp_agreement; +#[path = "issue_151_socket_path_in_lsp_missing_error.rs"] +mod issue_151_socket_path_in_lsp_missing_error; +#[path = "issue_153_rescan_freshness.rs"] +mod issue_153_rescan_freshness; +#[path = "issue_156_cluster_id_stale_offsets.rs"] +mod issue_156_cluster_id_stale_offsets; +#[path = "issue_157_lsp_not_running_recovery_data.rs"] +mod issue_157_lsp_not_running_recovery_data; +#[path = "issue_255_language_enum_tracks_engine.rs"] +mod issue_255_language_enum_tracks_engine; +#[path = "lsp_integration.rs"] +mod lsp_integration; +#[path = "merge_plan.rs"] +mod merge_plan; +#[path = "orphan_exit.rs"] +mod orphan_exit; +#[path = "state_file_backend.rs"] +mod state_file_backend; +#[path = "tcp_transport.rs"] +mod tcp_transport; +#[path = "wrong_root.rs"] +mod wrong_root; diff --git a/crates/deslop-mcp/tests/tcp_transport.rs b/crates/deslop-mcp/tests/tcp_transport.rs index b6ddee23..384133eb 100644 --- a/crates/deslop-mcp/tests/tcp_transport.rs +++ b/crates/deslop-mcp/tests/tcp_transport.rs @@ -17,7 +17,7 @@ use std::{ use anyhow::{anyhow, ensure, Context, Result}; use serde_json::{json, Value}; -mod common; +use crate::common; use common::{ copied_fixture, initialized_mcp, spawn_lsp_with_args, structured_content, wait_for_path, ChildKillOnDrop, SOCKET_TIMEOUT, diff --git a/crates/deslop/Cargo.toml b/crates/deslop/Cargo.toml index 41d359fd..b70a4fbf 100644 --- a/crates/deslop/Cargo.toml +++ b/crates/deslop/Cargo.toml @@ -6,6 +6,7 @@ rust-version.workspace = true license.workspace = true repository.workspace = true description = "Deslop CLI — cold-cache entry point for the live duplicate-code analysis server. One-shot scans, CI gates, and report rendering (JSON / TXT / HTML)." +autotests = false [[bin]] name = "deslop" @@ -28,3 +29,7 @@ tempfile.workspace = true [lints] workspace = true + +[[test]] +name = "suite" +path = "tests/suite.rs" diff --git a/crates/deslop/tests/cache_blob_integrity.rs b/crates/deslop/tests/cache_blob_integrity.rs index 50637350..1e816030 100644 --- a/crates/deslop/tests/cache_blob_integrity.rs +++ b/crates/deslop/tests/cache_blob_integrity.rs @@ -26,7 +26,6 @@ use std::{ use anyhow::anyhow; -mod common; use crate::common::{incremental::*, multilang_warm::seed_twins, seeded::*, store::*, *}; /// Seeds the corpus and runs the store-filling cold pass, returning the diff --git a/crates/deslop/tests/cache_key_lossy_utf8_collision.rs b/crates/deslop/tests/cache_key_lossy_utf8_collision.rs index e3fcfb0d..32883e63 100644 --- a/crates/deslop/tests/cache_key_lossy_utf8_collision.rs +++ b/crates/deslop/tests/cache_key_lossy_utf8_collision.rs @@ -31,7 +31,6 @@ use std::{fs, path::Path}; use anyhow::Result; use serde_json::Value; -mod common; use crate::common::{incremental::*, *}; /// The clone body shared by both files. Seven lines, identical in each, diff --git a/crates/deslop/tests/cache_retention.rs b/crates/deslop/tests/cache_retention.rs index fbc2546c..5b36d4c0 100644 --- a/crates/deslop/tests/cache_retention.rs +++ b/crates/deslop/tests/cache_retention.rs @@ -13,7 +13,6 @@ //! scenario asserts the rendered report against the seeded truth — //! retention must never move a reported figure. -mod common; use std::{fs, path::Path}; diff --git a/crates/deslop/tests/cli/bucket_groups.rs b/crates/deslop/tests/cli/bucket_groups.rs index d54b1f95..2a8c9b5c 100644 --- a/crates/deslop/tests/cli/bucket_groups.rs +++ b/crates/deslop/tests/cli/bucket_groups.rs @@ -7,8 +7,8 @@ use deslop_test_support::write_dart_data_table_fixture; -use crate::language_sections::{RUST_A, RUST_B}; -use crate::support::*; +use super::language_sections::{RUST_A, RUST_B}; +use super::support::*; // Two byte-identical (Type-1) copies of one function — saturates both // the structural and token signals, routing to the `identical` bucket diff --git a/crates/deslop/tests/cli/cache_and_debug.rs b/crates/deslop/tests/cli/cache_and_debug.rs index 21613757..c2a49384 100644 --- a/crates/deslop/tests/cli/cache_and_debug.rs +++ b/crates/deslop/tests/cli/cache_and_debug.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; use std::fmt::Write as _; /// Runs a default (cache-on, [PIPELINE-INCREMENTAL]) pass over diff --git a/crates/deslop/tests/cli/config.rs b/crates/deslop/tests/cli/config.rs index dd01e679..ac8305eb 100644 --- a/crates/deslop/tests/cli/config.rs +++ b/crates/deslop/tests/cli/config.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; /// Returns the command scanning the `csharp-small` fixture with /// `--config /`, writing `body` there first when `Some` diff --git a/crates/deslop/tests/cli/detection.rs b/crates/deslop/tests/cli/detection.rs index 19452154..c82f279c 100644 --- a/crates/deslop/tests/cli/detection.rs +++ b/crates/deslop/tests/cli/detection.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; /// Runs the CLI against `fixture(fixture_name)` with `--min-nodes /// `, asserts the process succeeded, and returns the raw diff --git a/crates/deslop/tests/cli/embedding_ollama.rs b/crates/deslop/tests/cli/embedding_ollama.rs index 983d30f8..2e5330e3 100644 --- a/crates/deslop/tests/cli/embedding_ollama.rs +++ b/crates/deslop/tests/cli/embedding_ollama.rs @@ -1,5 +1,5 @@ -use crate::mock_ollama::{MockOllama, MOCK_CONTEXT_TOKENS}; -use crate::support::*; +use super::mock_ollama::{MockOllama, MOCK_CONTEXT_TOKENS}; +use super::support::*; // different default. Reports are parsed via `serde_json` so the // assertions are schema-aware rather than substring-guessing. diff --git a/crates/deslop/tests/cli/embedding_stub.rs b/crates/deslop/tests/cli/embedding_stub.rs index 7166a16c..9a203c6a 100644 --- a/crates/deslop/tests/cli/embedding_stub.rs +++ b/crates/deslop/tests/cli/embedding_stub.rs @@ -5,8 +5,8 @@ //! is no longer a production provider, so the same flows are now //! driven against an in-process mock Ollama HTTP server. -use crate::mock_ollama::MockOllama; -use crate::support::*; +use super::mock_ollama::MockOllama; +use super::support::*; /// Runs the full ollama embedding pass for `mode` (`required`/`auto`) /// against `scan_root`, writing to `output_prefix`, and asserts the CLI diff --git a/crates/deslop/tests/cli/from_report.rs b/crates/deslop/tests/cli/from_report.rs index cf8eca53..425904bf 100644 --- a/crates/deslop/tests/cli/from_report.rs +++ b/crates/deslop/tests/cli/from_report.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; /// Writes `report_body` to `/`, runs the CLI in /// `--from-report` replay mode over it (adding `--no-color` when diff --git a/crates/deslop/tests/cli/invocation.rs b/crates/deslop/tests/cli/invocation.rs index bf93a781..a8f7ea8d 100644 --- a/crates/deslop/tests/cli/invocation.rs +++ b/crates/deslop/tests/cli/invocation.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; use std::fmt::Write as _; #[test] diff --git a/crates/deslop/tests/cli/language_sections.rs b/crates/deslop/tests/cli/language_sections.rs index 11606741..4767c505 100644 --- a/crates/deslop/tests/cli/language_sections.rs +++ b/crates/deslop/tests/cli/language_sections.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; // Two Rust files that are renamed (Type-2) clones of one function: the // copy renames the function and its parameter but keeps the body's diff --git a/crates/deslop/tests/cli/logging.rs b/crates/deslop/tests/cli/logging.rs index 762866bf..79882d6e 100644 --- a/crates/deslop/tests/cli/logging.rs +++ b/crates/deslop/tests/cli/logging.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; /// Builds a `deslop` command against the `csharp-small` fixture writing /// its report under `/report`. Every logging test shares this scan @@ -255,7 +255,7 @@ fn technical_mode_surfaces_raw_cache_stats_line() -> Result<()> { // provider end-to-end without depending on a real install. #[test] fn technical_mode_surfaces_embedding_provenance_line() -> Result<()> { - let server = crate::mock_ollama::MockOllama::spawn()?; + let server = super::mock_ollama::MockOllama::spawn()?; let tmp = tempfile::tempdir()?; let scan_root = tmp.path().join("src"); seed_scan_root(&fixture("csharp-small"), &scan_root)?; diff --git a/crates/deslop/tests/cli/metrics.rs b/crates/deslop/tests/cli/metrics.rs index 5ce01266..4ed0bd2d 100644 --- a/crates/deslop/tests/cli/metrics.rs +++ b/crates/deslop/tests/cli/metrics.rs @@ -1,4 +1,4 @@ -use crate::support::*; +use super::support::*; /// Writes the cross-file clone-pair fixture into a fresh temp dir, runs /// `deslop` with the given `--min-nodes` value, asserts the run diff --git a/crates/deslop/tests/cli/report_css.rs b/crates/deslop/tests/cli/report_css.rs index f7c1c270..728f6b91 100644 --- a/crates/deslop/tests/cli/report_css.rs +++ b/crates/deslop/tests/cli/report_css.rs @@ -9,7 +9,7 @@ //! design-system CSS is inlined and that no unresolved `@import url(` //! leaks in its place. -use crate::support::*; +use super::support::*; // A renamed (Type-2) C# clone pair guarantees the report renders at // least one cluster card, so the `