use super::super::{detect_family, parse_invocation, CompilerFamily, ParsedInvocation};
use super::args;
use crate::core::NormalizedPath;
#[test]
fn detect_rustc_family() {
assert_eq!(detect_family("rustc"), CompilerFamily::Rustc);
assert_eq!(detect_family("/usr/bin/rustc"), CompilerFamily::Rustc);
assert_eq!(detect_family("rustc.exe"), CompilerFamily::Rustc);
assert_eq!(
detect_family("C:\\rustup\\rustc.exe"),
CompilerFamily::Rustc
);
}
#[test]
fn rustc_no_depfile_support() {
assert!(!CompilerFamily::Rustc.supports_depfile());
}
#[test]
fn rustc_no_pch_extension() {
assert_eq!(CompilerFamily::Rustc.pch_extension(), None);
}
#[test]
fn rustc_lib_crate_is_cacheable() {
let result = parse_invocation(
"rustc",
&args(&[
"--edition",
"2021",
"--crate-type",
"lib",
"--emit=dep-info,metadata,link",
"-C",
"opt-level=2",
"src/lib.rs",
]),
);
match result {
ParsedInvocation::Cacheable(c) => {
assert_eq!(c.family, CompilerFamily::Rustc);
assert_eq!(c.source_file, NormalizedPath::new("src/lib.rs"));
}
other => panic!("expected cacheable, got: {other:?}"),
}
}
#[test]
fn rustc_rlib_crate_is_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "rlib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_staticlib_crate_is_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "staticlib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_bin_crate_is_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "bin", "src/main.rs"]));
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_bin_primary_output_uses_executable_extension() {
let result = parse_invocation(
"rustc",
&args(&[
"--crate-name",
"build_script_build",
"--crate-type",
"bin",
"--out-dir",
"/tmp/build/foo-abc",
"-C",
"extra-filename=-abc",
"/path/to/build.rs",
]),
);
let cc = match result {
ParsedInvocation::Cacheable(c) => c,
other => panic!("expected cacheable, got: {other:?}"),
};
let out = cc.output_file.to_string_lossy();
if cfg!(target_os = "windows") {
assert!(
out.ends_with("build_script_build-abc.exe"),
"expected bin .exe, got {out}"
);
} else {
assert!(
out.ends_with("build_script_build-abc"),
"expected bin executable, got {out}"
);
assert!(!out.ends_with(".rlib"), "bin must not get .rlib, got {out}");
}
}
#[test]
fn rustc_dylib_is_non_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "dylib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::NonCacheable { .. }));
}
#[test]
fn rustc_proc_macro_is_cacheable() {
let result = parse_invocation(
"rustc",
&args(&["--crate-type", "proc-macro", "src/lib.rs"]),
);
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_proc_macro_primary_output_uses_dylib_extension() {
let result = parse_invocation(
"rustc",
&args(&[
"--crate-name",
"serde_derive",
"--crate-type",
"proc-macro",
"--out-dir",
"/tmp/deps",
"-C",
"extra-filename=-abc123",
"/path/to/src/lib.rs",
]),
);
let cc = match result {
ParsedInvocation::Cacheable(c) => c,
other => panic!("expected cacheable, got: {other:?}"),
};
let out = cc.output_file.to_string_lossy();
if cfg!(target_os = "windows") {
assert!(
out.ends_with("serde_derive-abc123.dll"),
"expected proc-macro .dll, got {out}"
);
} else if cfg!(target_os = "macos") {
assert!(
out.ends_with("libserde_derive-abc123.dylib"),
"expected proc-macro .dylib, got {out}"
);
} else {
assert!(
out.ends_with("libserde_derive-abc123.so"),
"expected proc-macro .so, got {out}"
);
}
}
#[test]
fn rustc_cdylib_is_non_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "cdylib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::NonCacheable { .. }));
}
#[test]
fn rustc_no_crate_type_defaults_to_bin_cacheable() {
let result = parse_invocation("rustc", &args(&["src/main.rs"]));
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_incremental_is_cacheable() {
let result = parse_invocation(
"rustc",
&args(&[
"--crate-type",
"lib",
"-C",
"incremental=/tmp/incr",
"src/lib.rs",
]),
);
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_no_source_is_non_cacheable() {
let result = parse_invocation("rustc", &args(&["--version"]));
assert!(matches!(result, ParsedInvocation::NonCacheable { .. }));
}
#[test]
fn rustc_emit_metadata_is_cacheable() {
let result = parse_invocation(
"rustc",
&args(&["--crate-type", "lib", "--emit=metadata", "src/lib.rs"]),
);
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_output_with_explicit_o() {
let result = parse_invocation(
"rustc",
&args(&["--crate-type", "lib", "src/lib.rs", "-o", "libfoo.rlib"]),
);
match result {
ParsedInvocation::Cacheable(c) => {
assert_eq!(c.output_file, NormalizedPath::new("libfoo.rlib"));
}
other => panic!("expected cacheable, got: {other:?}"),
}
}
#[test]
fn rustc_metadata_only_output_is_rmeta() {
let result = parse_invocation(
"rustc",
&args(&[
"--crate-type",
"lib",
"--crate-name",
"mylib",
"--emit=dep-info,metadata",
"--out-dir",
"/target/debug/deps",
"-C",
"extra-filename=-abc123",
"src/lib.rs",
]),
);
match result {
ParsedInvocation::Cacheable(c) => {
assert_eq!(
c.output_file,
NormalizedPath::new("/target/debug/deps/libmylib-abc123.rmeta")
);
}
other => panic!("expected cacheable, got: {other:?}"),
}
}
#[test]
fn rustc_output_from_out_dir() {
let result = parse_invocation(
"rustc",
&args(&[
"--crate-type",
"lib",
"--crate-name",
"mylib",
"--out-dir",
"/target/debug/deps",
"-C",
"extra-filename=-abc123",
"src/lib.rs",
]),
);
match result {
ParsedInvocation::Cacheable(c) => {
assert_eq!(
c.output_file,
NormalizedPath::new("/target/debug/deps/libmylib-abc123.rlib")
);
}
other => panic!("expected cacheable, got: {other:?}"),
}
}
#[test]
fn rustc_full_cargo_invocation_cacheable() {
let result = parse_invocation(
"rustc",
&args(&[
"--edition",
"2021",
"--crate-type",
"lib",
"--crate-name",
"serde",
"--emit=dep-info,metadata,link",
"-C",
"opt-level=2",
"-C",
"metadata=abc123def",
"-C",
"extra-filename=-abc123def",
"--out-dir",
"/target/release/deps",
"-L",
"dependency=/target/release/deps",
"--extern",
"serde_derive=/target/release/deps/libserde_derive-xyz.so",
"--cap-lints",
"allow",
"--cfg",
"feature=\"derive\"",
"--cfg",
"feature=\"std\"",
"src/lib.rs",
]),
);
match result {
ParsedInvocation::Cacheable(c) => {
assert_eq!(c.family, CompilerFamily::Rustc);
assert_eq!(c.source_file, NormalizedPath::new("src/lib.rs"));
assert_eq!(
c.output_file,
NormalizedPath::new("/target/release/deps/libserde-abc123def.rlib")
);
}
other => panic!("expected cacheable, got: {other:?}"),
}
}
#[test]
fn rustc_original_args_preserved() {
let input = args(&["--edition", "2021", "--crate-type", "lib", "src/lib.rs"]);
let result = parse_invocation("rustc", &input);
match result {
ParsedInvocation::Cacheable(c) => {
assert_eq!(*c.original_args, *input);
}
other => panic!("expected cacheable, got: {other:?}"),
}
}
#[test]
fn rustc_equal_form_crate_type() {
let result = parse_invocation("rustc", &args(&["--crate-type=lib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_concatenated_c_incremental_is_cacheable() {
let result = parse_invocation(
"rustc",
&args(&["--crate-type", "lib", "-Cincremental=/tmp", "src/lib.rs"]),
);
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_comma_separated_crate_type_all_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "lib,rlib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_comma_separated_crate_type_mixed_non_cacheable() {
let result = parse_invocation("rustc", &args(&["--crate-type", "lib,dylib", "src/lib.rs"]));
assert!(matches!(result, ParsedInvocation::NonCacheable { .. }));
}
#[test]
fn rustc_comma_separated_crate_type_equals_form() {
let result = parse_invocation(
"rustc",
&args(&["--crate-type=lib,staticlib", "src/lib.rs"]),
);
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}
#[test]
fn rustc_test_flag_makes_non_cacheable() {
let result = parse_invocation(
"rustc",
&args(&["--crate-type", "lib", "--test", "src/lib.rs"]),
);
assert!(matches!(result, ParsedInvocation::Cacheable(_)));
}