Skip to content

test: ✅ Add end-to-end completion-handler test for relationship-hop wiring (#219) - #223

Merged
mikebronner merged 1 commit into
mainfrom
chore/219-add-an-end-to-end-completion-handler-test-for-the-
Jun 18, 2026
Merged

mikebronner merged 1 commit into
mainfrom
chore/219-add-an-end-to-end-completion-handler-test-for-the-

Conversation

@mikebronner

Copy link
Copy Markdown
Contributor

Summary

Implements #219 — an end-to-end completion-handler regression test for the
relationship-hop wiring that #211 / PR #215 left covered only indirectly.

The unit tests exercise apply_relation_method_hops + columns_for_collection
directly with a hand-built ChainContext, and the diagnostics path is covered
end-to-end through chain_diagnostics. The glue in
main.rs::try_query_chain_completion that dispatches apply_relation_method_hops
inside the real textDocument/completion flow had no regression guard — a
bad re-wire (wrong call order, missing dispatch, lost effective_model) would
have slipped past every existing test. These tests close that gap, mirroring the
diagnostics-side end-to-end fixtures from PR #215.

Changes

  • New test file laravel-lsp/src/tests/query_chain_completion_handler.rs,
    registered in laravel-lsp/src/tests/mod.rs. Builds a real
    LaravelLanguageServer via LspService::new(LaravelLanguageServer::new),
    primes initialized_root with a tempdir of User/Competition models and
    database_schema with a seeded provider, then drives the real
    try_query_chain_completion with $user->competitions->where('|').
    • property_receiver_hop_offers_related_table_columns — asserts the
      competitions column type is offered.
    • property_receiver_hop_excludes_parent_only_columns — asserts the
      users-only column email is not offered, proving the hop advanced
      effective_model from User to Competition.
  • laravel-lsp/src/database.rs — DatabaseSchemaProvider::set_test_schema
    is now #[doc(hidden)] pub instead of #[cfg(test)]. ⚠️ Reviewer note:
    this is the one production-lib change. Cargo does not enable cfg(test) on a
    library consumed as a dependency, so a #[cfg(test)] seam is invisible to the
    binary's src/tests/ crate — the AC requires priming database_schema from
    there. #[doc(hidden)] keeps it off the documented public surface while making
    it reachable cross-crate. The schema mutation itself is unchanged.

Acceptance Criteria

  • New test file laravel-lsp/src/tests/query_chain_completion_handler.rs
    created and registered in laravel-lsp/src/tests/mod.rs.
  • Harness builds a real LaravelLanguageServer via
    tower_lsp::LspService::new(LaravelLanguageServer::new), primes
    initialized_root with a tempdir holding User.php (a competitions hasMany
    to Competition::class) and Competition.php, and primes database_schema
    with a DatabaseSchemaProvider whose competitions table carries a column
    (type) absent from users.
  • property_receiver_hop_offers_related_table_columns calls
    try_query_chain_completion with /** @var User $user */ and
    $user->competitions->where('|'), cursor inside the where string argument,
    and asserts the competitions column type is among the returned items.
  • A companion test asserts a users-only column (email) is not among
    the returned items, confirming the hop advanced effective_model from User
    to Competition.
  • Both tests fail when the apply_relation_method_hops dispatch block in
    main.rs is commented out (verified locally: completion returns
    ["id", "email"], so type is missing and email leaks).
  • cargo test passes with no new warnings from the test file.

Test Plan

  • cargo fmt --check — clean.
  • cargo clippy --all-targets — no warnings (CI runs -D warnings).
  • cargo test — full unit suite green (lib 1894 + bin 418, including the 2
    new tests).
  • Reverse check — neutralized the apply_relation_method_hops dispatch
    block and confirmed both new tests fail, then restored it.
  • ℹ️ The integration_tests target needs the CI-only fixture bootstrap
    (cp test-project/.env.example test-project/.env + composer install); those
    pre-existing, environment-dependent tests are untouched by this change and
    pass in CI.

Fixes #219

…iring.

Cover the main.rs `try_query_chain_completion` dispatch of
`apply_relation_method_hops`, which was only exercised indirectly: the
unit tests hit the hop and collection-column functions directly, and the
diagnostics path is covered end-to-end, but the completion glue had no
regression guard. A bad re-wire (wrong order, missing dispatch, lost
`effective_model`) would have slipped through every existing test.

Drive the real completion entry point with the property-access receiver
shape `$user->competitions->where('|')`, priming a genuine backend's
`initialized_root` (User/Competition models) and `database_schema` (a
seeded provider where `type` lives only on `competitions` and `email`
only on `users`). One test asserts `type` is offered; the mirror asserts
`email` is not — together proving the hop advanced the effective model
from User to Competition. Both fail when the dispatch block is removed.

Expose `DatabaseSchemaProvider::set_test_schema` as `#[doc(hidden)] pub`
rather than `#[cfg(test)]`: Cargo does not enable `cfg(test)` on a library
consumed as a dependency, so the bin test crate could not otherwise reach
the schema-seeding seam.

Fixes: #219

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@mr-sherlock-holmes mr-sherlock-holmes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved

Review Summary

A tight, well-documented test-only PR that closes the exact gap #219 named: the main.rs::try_query_chain_completion glue dispatching apply_relation_method_hops had no end-to-end regression guard. Reviewed via four blind lens passes (AC conformance, correctness, security, test honesty) over the PR checkout; CI is green (LSP test/fmt/clippy, 3m9s).

Acceptance criteria — all 6 met:

  1. ✅ New file tests/query_chain_completion_handler.rs registered in tests/mod.rs:31 (alphabetical).
  2. ✅ Real backend via LspService::new(LaravelLanguageServer::new); initialized_root primed with a tempdir of User.php (hasMany competitions) + Competition.php; database_schema seeded so type lives on competitions but not users.
  3. ✅ property_receiver_hop_offers_related_table_columns drives try_query_chain_completion with /** @var User $user */ + $user->competitions->where('◊')->get() and asserts type is offered. (Divergence, fine: a trailing ->get() completes the chain shape; cursor is still inside the where string arg.)
  4. ✅ Companion property_receiver_hop_excludes_parent_only_columns asserts email (users-only) is absent.
  5. ✅ Genuine regression guard, not coverage theatre — confirmed by code logic and your documented reverse check (["id","email"] with the dispatch neutralized). Without the hop, effective_model stays User → users table → type missing (test 1 fails) and email leaks (test 2 fails). The asymmetric schema catches the missing hop from both directions, and the positive assertion rules out a vacuous pass (.expect() on None, empty-vec both fail).
  6. ✅ cargo test + clippy -D warnings green in CI.

What's Good

  • The asymmetric fixture (type only on competitions, email only on users) is a sharp design — both assertions can pass only if the hop advanced the model. That's a real guard.
  • Hermetic and deterministic: set_test_schema seeds the in-memory cache, no live DB or network, tempdir RAII-cleaned.
  • You flagged the one production-lib change yourself in the PR body. Concur with the call: the test must live in the binary crate (crate::LaravelLanguageServer), which consumes the lib without cfg(test), so a #[cfg(test)] seam is invisible cross-crate. #[doc(hidden)] pub is the right pragmatic fit here — it mirrors the already-pub invalidate_cache cache-mutator (database.rs:522), and the feature-flag alternative would be strictly worse in this same-package bin-test topology (it'd break plain cargo test in CI). Well-documented rationale on both sides of the seam.

📋 Non-blocking follow-ups

  • None.

Ready for @mikebronner to merge.

@mikebronner
mikebronner merged commit 596f604 into main Jun 18, 2026
5 checks passed
@mikebronner
mikebronner deleted the chore/219-add-an-end-to-end-completion-handler-test-for-the- branch June 18, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an end-to-end completion-handler test for the relationship-hop wiring (main.rs dispatch of apply_relation_method_hops)

1 participant