{ lib, buildRustCrate, runCommand, writeTextFile, symlinkJoin, callPackage }: let mkCrate = args: let p = { crateName = "nixtestcrate"; version = "0.1.0"; authors = [ "Test " ]; } // args; in buildRustCrate p; mkFile = destination: text: writeTextFile { name = "src"; destination = "/${destination}"; inherit text; }; mkBin = name: mkFile name '' use std::env; fn main() { let name: String = env::args().nth(0).unwrap(); println!("executed {}", name); } ''; mkBinExtern = name: extern: mkFile name '' extern crate ${extern}; fn main() { assert_eq!(${extern}::test(), 23); } ''; mkLib = name: mkFile name "pub fn test() -> i32 { return 23; }"; mkTest = crateArgs: let crate = mkCrate crateArgs; binaries = map (v: ''"${v.name}"'') (crateArgs.crateBin or []); isLib = crateArgs ? libName || crateArgs ? libPath; crateName = crateArgs.crateName or "nixtestcrate"; libName = crateArgs.libName or crateName; libTestBinary = if !isLib then null else mkCrate { crateName = "run-test-${crateName}"; dependencies = [ crate ]; src = mkBinExtern "src/main.rs" libName; }; in runCommand "run-buildRustCrate-${crateName}-test" { nativeBuildInputs = [ crate ]; } '' ${lib.concatStringsSep "\n" binaries} ${lib.optionalString isLib '' test -e ${crate}/lib/*.rlib || exit 1 ${libTestBinary}/bin/run-test-${crateName} ''} touch $out ''; in rec { tests = let cases = { libPath = { libPath = "src/my_lib.rs"; src = mkLib "src/my_lib.rs"; }; srcLib = { src = mkLib "src/lib.rs"; }; customLibName = { libName = "test_lib"; src = mkLib "src/test_lib.rs"; }; customLibNameAndLibPath = { libName = "test_lib"; libPath = "src/best-lib.rs"; src = mkLib "src/best-lib.rs"; }; crateBinWithPath = { crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }]; src = mkBin "src/foobar.rs"; }; crateBinNoPath1 = { crateBin = [{ name = "my-binary2"; }]; src = mkBin "src/my_binary2.rs"; }; crateBinNoPath2 = { crateBin = [{ name = "my-binary3"; } { name = "my-binary4"; }]; src = symlinkJoin { name = "buildRustCrateMultipleBinariesCase"; paths = [ (mkBin "src/bin/my_binary3.rs") (mkBin "src/bin/my_binary4.rs") ]; }; }; crateBinNoPath3 = { crateBin = [{ name = "my-binary5"; }]; src = mkBin "src/bin/main.rs"; }; crateBinNoPath4 = { crateBin = [{ name = "my-binary6"; }]; src = mkBin "src/main.rs";}; crateBinRename1 = { crateBin = [{ name = "my-binary-rename1"; }]; src = mkBinExtern "src/main.rs" "foo_renamed"; dependencies = [ (mkCrate { crateName = "foo"; src = mkLib "src/lib.rs"; }) ]; crateRenames = { "foo" = "foo_renamed"; }; }; crateBinRename2 = { crateBin = [{ name = "my-binary-rename2"; }]; src = mkBinExtern "src/main.rs" "foo_renamed"; dependencies = [ (mkCrate { crateName = "foo"; libName = "foolib"; src = mkLib "src/lib.rs"; }) ]; crateRenames = { "foo" = "foo_renamed"; }; }; }; brotliCrates = (callPackage ./brotli-crates.nix {}); in lib.mapAttrs (key: value: mkTest (value // lib.optionalAttrs (!value?crateName) { crateName = key; })) cases // { brotliTest = let pkg = brotliCrates.brotli_2_5_0 {}; in runCommand "run-brotli-test-cmd" { nativeBuildInputs = [ pkg ]; } '' ${pkg}/bin/brotli -c ${pkg}/bin/brotli > /dev/null && touch $out ''; allocNoStdLibTest = let pkg = brotliCrates.alloc_no_stdlib_1_3_0 {}; in runCommand "run-alloc-no-stdlib-test-cmd" { nativeBuildInputs = [ pkg ]; } '' test -e ${pkg}/bin/example && touch $out ''; brotliDecompressorTest = let pkg = brotliCrates.brotli_decompressor_1_3_1 {}; in runCommand "run-brotli-decompressor-test-cmd" { nativeBuildInputs = [ pkg ]; } '' test -e ${pkg}/bin/brotli-decompressor && touch $out ''; }; test = runCommand "run-buildRustCrate-tests" { nativeBuildInputs = builtins.attrValues tests; } " touch $out "; }