From 4464997b955984445d1f44029151f707054f0e8e Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Costa Date: Mon, 23 Mar 2026 17:23:09 +0000 Subject: [PATCH] buildRustCrate: name tests//main.rs binaries as to match cargo build_bin_test_file derives the test binary name by replacing `/` with `_`, stripping the `tests_` prefix and `.rs` suffix. For the subdirectory integration-test layout `tests//main.rs`, this produces `_main`, but cargo names that binary `` per its auto-discovery rules. Tools that expect the cargo convention (cargo-nextest binaries-metadata, IDE test runners) cannot find the binaries. Strip the trailing `_main` when the source file is `*/main.rs`. The guard is needed so a flat-style `tests/_main.rs` keeps its suffix. Add `expectedTestBinaries` to the test harness so binary naming can be asserted, and cover both the subdir case (suffix stripped) and the flat case with a literal `_main` in the filename (suffix kept). Also fix a typo in `removeAttrs` that leaked `expectedTestOutputs` into the crate args. --- .../rust/build-rust-crate/lib.sh | 6 ++++ .../rust/build-rust-crate/test/default.nix | 34 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/pkgs/build-support/rust/build-rust-crate/lib.sh b/pkgs/build-support/rust/build-rust-crate/lib.sh index 5fa9b2f21154..09731f29f0c3 100644 --- a/pkgs/build-support/rust/build-rust-crate/lib.sh +++ b/pkgs/build-support/rust/build-rust-crate/lib.sh @@ -87,6 +87,12 @@ build_bin_test_file() { # above. derived_crate_name=${derived_crate_name#"tests_"} derived_crate_name="${derived_crate_name%.rs}" + # Cargo names tests//main.rs as , not _main — strip the + # trailing _main that the `/`→`_` substitution produced. Guarded so + # a flat-style tests/_main.rs keeps its _main suffix. + if [[ "$file" == */main.rs ]]; then + derived_crate_name="${derived_crate_name%_main}" + fi build_bin_test "$derived_crate_name" "$file" } diff --git a/pkgs/build-support/rust/build-rust-crate/test/default.nix b/pkgs/build-support/rust/build-rust-crate/test/default.nix index d5c56858c6a4..b9ab9b8c31c8 100644 --- a/pkgs/build-support/rust/build-rust-crate/test/default.nix +++ b/pkgs/build-support/rust/build-rust-crate/test/default.nix @@ -91,9 +91,15 @@ let mkTest = crateArgs: let - crate = mkHostCrate (removeAttrs crateArgs [ "expectedTestOutput" ]); + crate = mkHostCrate ( + removeAttrs crateArgs [ + "expectedTestOutputs" + "expectedTestBinaries" + ] + ); hasTests = crateArgs.buildTests or false; expectedTestOutputs = crateArgs.expectedTestOutputs or null; + expectedTestBinaries = crateArgs.expectedTestBinaries or [ ]; binaries = map (v: lib.escapeShellArg v.name) (crateArgs.crateBin or [ ]); isLib = crateArgs ? libName || crateArgs ? libPath; crateName = crateArgs.crateName or "nixtestcrate"; @@ -134,6 +140,10 @@ let '' else if stdenv.hostPlatform == stdenv.buildPlatform then '' + ${lib.concatMapStringsSep "\n" ( + b: + "test -x ${crate}/tests/${lib.escapeShellArg b} || { echo 'expected test binary \"${b}\" not found in:'; ls ${crate}/tests; exit 23; }" + ) expectedTestBinaries} for file in ${crate}/tests/*; do $file 2>&1 >> $out done @@ -419,12 +429,34 @@ rec { ]; }; buildTests = true; + # Cargo names tests//main.rs as , not _main. + expectedTestBinaries = [ + "foo" + "bar" + ]; expectedTestOutputs = [ "test src_main ... ok" "test tests_foo ... ok" "test tests_bar ... ok" ]; }; + rustBinTestsFlatMainSuffix = { + # A flat-style test whose name happens to end in _main must keep + # its suffix — only tests//main.rs gets the _main stripped. + src = symlinkJoin { + name = "rust-bin-tests-flat-main-suffix"; + paths = [ + (mkTestFileWithMain "src/main.rs" "src_main") + (mkTestFile "tests/foo_main.rs" "flat_test") + ]; + }; + buildTests = true; + expectedTestBinaries = [ "foo_main" ]; + expectedTestOutputs = [ + "test src_main ... ok" + "test flat_test ... ok" + ]; + }; linkAgainstRlibCrate = { crateName = "foo"; src = mkFile "src/main.rs" ''