@@ -427,13 +427,13 @@ fn test_with_features(
427427 // Write modified TOML
428428 std:: fs:: write ( workspace_toml_path, doc. to_string ( ) ) ?;
429429
430- // OPTIMIZATION: Check only affected members instead of whole workspace
431- let check_passed = run_cargo_check_targeted ( used_by_members, ctx. workspace_root ( ) ) ?;
430+ // OPTIMIZATION: Build + test only affected members instead of whole workspace
431+ let build_and_test_passed = run_cargo_build_and_test_targeted ( used_by_members, ctx. workspace_root ( ) ) ?;
432432
433433 // Always restore original content
434434 std:: fs:: write ( workspace_toml_path, original_content) ?;
435435
436- Ok ( check_passed )
436+ Ok ( build_and_test_passed )
437437}
438438
439439/// Set dependency features in workspace.dependencies to exact list
@@ -480,38 +480,72 @@ fn set_dependency_features(doc: &mut toml_edit::DocumentMut, dep_name: &str, fea
480480 Ok ( false )
481481}
482482
483- /// Run cargo check for SPECIFIC workspace members (graph-aware optimization)
483+ /// Run cargo build + test for SPECIFIC workspace members (graph-aware optimization)
484484///
485485/// **HUGE PERFORMANCE WIN:**
486- /// Instead of `cargo check --workspace` (checks all 50+ crates),
486+ /// Instead of `cargo build --workspace` (checks all 50+ crates),
487487/// we check only the 2-3 crates that actually use this dependency.
488- fn run_cargo_check_targeted ( members : & [ String ] , workspace_root : & Path ) -> RailResult < bool > {
489- let mut cmd = Command :: new ( "cargo" ) ;
490- cmd. arg ( "check" ) ;
491-
492- // OPTIMIZATION: Check only affected members
488+ ///
489+ /// **Why build instead of check:**
490+ /// - `cargo check` allows some code that fails during actual compilation/linking
491+ /// - Features may affect codegen, proc-macros, or linking behavior
492+ /// - More accurate validation at slight performance cost
493+ ///
494+ /// **Why also run tests:**
495+ /// - Some features only affect runtime behavior (e.g., serde's preserve_order)
496+ /// - Tests catch functional regressions that compilation doesn't
497+ fn run_cargo_build_and_test_targeted ( members : & [ String ] , workspace_root : & Path ) -> RailResult < bool > {
498+ // Step 1: Build with all targets
499+ let mut build_cmd = Command :: new ( "cargo" ) ;
500+ build_cmd. arg ( "build" ) ;
501+
502+ // OPTIMIZATION: Build only affected members
493503 if members. len ( ) <= 5 {
494- // Small number of members - check them explicitly
504+ // Small number of members - build them explicitly
495505 for member in members {
496- cmd . arg ( "-p" ) . arg ( member) ;
506+ build_cmd . arg ( "-p" ) . arg ( member) ;
497507 }
498508 } else {
499- // Many members use this dep - check whole workspace (rare case)
500- cmd . arg ( "--workspace" ) ;
509+ // Many members use this dep - build whole workspace (rare case)
510+ build_cmd . arg ( "--workspace" ) ;
501511 }
502512
503- // CRITICAL FIX: Check all targets (tests, examples, benches)
513+ // CRITICAL: Build all targets (tests, examples, benches)
504514 // This prevents removing features that are only used in tests/examples
505- cmd . arg ( "--all-targets" ) ;
515+ build_cmd . arg ( "--all-targets" ) ;
506516
507- cmd . current_dir ( workspace_root) ;
517+ build_cmd . current_dir ( workspace_root) ;
508518
509519 // Suppress output - we only care about exit status
510- cmd. stdout ( std:: process:: Stdio :: null ( ) ) ;
511- cmd. stderr ( std:: process:: Stdio :: null ( ) ) ;
520+ build_cmd. stdout ( std:: process:: Stdio :: null ( ) ) ;
521+ build_cmd. stderr ( std:: process:: Stdio :: null ( ) ) ;
522+
523+ let build_output = build_cmd. output ( ) ?;
524+ if !build_output. status . success ( ) {
525+ return Ok ( false ) ;
526+ }
527+
528+ // Step 2: Run tests to ensure functionality
529+ let mut test_cmd = Command :: new ( "cargo" ) ;
530+ test_cmd. arg ( "test" ) ;
531+
532+ // Test same members
533+ if members. len ( ) <= 5 {
534+ for member in members {
535+ test_cmd. arg ( "-p" ) . arg ( member) ;
536+ }
537+ } else {
538+ test_cmd. arg ( "--workspace" ) ;
539+ }
540+
541+ test_cmd. current_dir ( workspace_root) ;
542+
543+ // Suppress output
544+ test_cmd. stdout ( std:: process:: Stdio :: null ( ) ) ;
545+ test_cmd. stderr ( std:: process:: Stdio :: null ( ) ) ;
512546
513- let output = cmd . output ( ) ?;
514- Ok ( output . status . success ( ) )
547+ let test_output = test_cmd . output ( ) ?;
548+ Ok ( test_output . status . success ( ) )
515549}
516550
517551#[ cfg( test) ]
0 commit comments