use std::path::PathBuf;
use wrapc::{LibrarySearchPathKind, LinkLibKind, parse};
fn args<const N: usize>(a: [&str; N]) -> Vec<String> {
a.iter().map(|s| s.to_string()).collect()
}
#[test]
fn cargo_wrapper_protocol() {
let a = args([
"sccache",
"-",
"rustc",
"--crate-name",
"my_crate",
"src/main.rs",
]);
let info = parse(&a).unwrap();
assert_eq!(info.rustc, Some("rustc".to_string()));
assert_eq!(info.crate_name, Some("my_crate".to_string()));
assert_eq!(info.inputs, vec![PathBuf::from("src/main.rs")]);
}
#[test]
fn boolean_flags() {
let a = args([
"wrapc", "-", "rustc", "-h", "-V", "-v", "--test", "-O", "-g",
]);
let info = parse(&a).unwrap();
assert!(info.help);
assert!(info.version);
assert!(info.verbose);
assert!(info.test);
assert!(info.opt_level);
assert!(info.debug_info);
}
#[test]
fn equals_vs_space_syntax() {
let a1 = args(["wrapc", "-", "rustc", "--edition=2021", "--out-dir=target"]);
let a2 = args([
"wrapc",
"-",
"rustc",
"--edition",
"2021",
"--out-dir",
"target",
]);
let info1 = parse(&a1).unwrap();
let info2 = parse(&a2).unwrap();
assert_eq!(info1, info2);
assert_eq!(info1.edition, Some("2021".to_string()));
assert_eq!(info1.out_dir, Some(PathBuf::from("target")));
}
#[test]
fn lints_slugged_and_long() {
let a = args([
"wrapc",
"-",
"rustc",
"-Wunused",
"--allow",
"dead_code",
"-Dwarnings",
"--forbid=unsafe_code",
]);
let info = parse(&a).unwrap();
assert_eq!(info.warns, vec!["unused"]);
assert_eq!(info.allows, vec!["dead_code"]);
assert_eq!(info.denies, vec!["warnings"]);
assert_eq!(info.forbids, vec!["unsafe_code"]);
}
#[test]
fn codegen_and_z_flags() {
let a = args([
"wrapc",
"-",
"rustc",
"-Copt-level=3",
"-C",
"link-arg=-fuse-ld=lld",
"-Zmir-opt-level=3",
]);
let info = parse(&a).unwrap();
assert_eq!(
info.codegen_opts,
vec!["opt-level=3", "link-arg=-fuse-ld=lld"]
);
assert_eq!(info.z_opts, vec!["mir-opt-level=3"]);
}
#[test]
fn library_search_paths() {
let a = args([
"wrapc",
"-",
"rustc",
"-L",
"/usr/lib",
"-Lnative=/opt/lib",
"-Ldependency=target/deps",
]);
let info = parse(&a).unwrap();
assert_eq!(info.libpaths.len(), 3);
assert_eq!(info.libpaths[0].kind, LibrarySearchPathKind::All);
assert_eq!(info.libpaths[0].path, PathBuf::from("/usr/lib"));
assert_eq!(info.libpaths[1].kind, LibrarySearchPathKind::Native);
assert_eq!(info.libpaths[1].path, PathBuf::from("/opt/lib"));
assert_eq!(info.libpaths[2].kind, LibrarySearchPathKind::Dep);
assert_eq!(info.libpaths[2].path, PathBuf::from("target/deps"));
}
#[test]
fn link_libraries_complex() {
let a = args([
"wrapc",
"-",
"rustc",
"-lssl",
"-lstatic=crypto",
"-lstatic:+bundle,+whole-archive=mylib:renamed",
]);
let info = parse(&a).unwrap();
assert_eq!(info.links.len(), 3);
assert_eq!(info.links[0].name, "ssl");
assert_eq!(info.links[0].kind, None);
assert_eq!(info.links[1].name, "crypto");
assert_eq!(info.links[1].kind, Some(LinkLibKind::Static));
assert!(info.links[1].modifiers.is_empty());
let complex = &info.links[2];
assert_eq!(complex.name, "mylib");
assert_eq!(complex.rename, Some("renamed".to_string()));
assert_eq!(complex.kind, Some(LinkLibKind::Static));
assert_eq!(complex.modifiers, vec!["+bundle", "+whole-archive"]);
}
#[test]
fn emits_and_externs() {
let a = args([
"wrapc",
"-",
"rustc",
"--emit=link,dep-info=a.d",
"--extern",
"foo=libfoo.rlib",
"--extern=bar",
]);
let info = parse(&a).unwrap();
assert_eq!(info.emits.len(), 2);
assert_eq!(info.emits[0].kind, "link");
assert_eq!(info.emits[0].path, None);
assert_eq!(info.emits[1].kind, "dep-info");
assert_eq!(info.emits[1].path, Some(PathBuf::from("a.d")));
assert_eq!(info.externs.len(), 2);
assert_eq!(info.externs[0].name, "foo");
assert_eq!(info.externs[0].path, Some(PathBuf::from("libfoo.rlib")));
assert_eq!(info.externs[1].name, "bar");
assert_eq!(info.externs[1].path, None);
}
#[test]
fn double_dash_separator() {
let a = args([
"wrapc",
"-",
"rustc",
"--crate-name",
"foo",
"--",
"--ignored-flag",
"-some-thing",
]);
let info = parse(&a).unwrap();
assert_eq!(info.crate_name, Some("foo".to_string()));
assert_eq!(info.unknown, vec!["--", "--ignored-flag", "-some-thing"]);
}
#[test]
fn missing_value_fallback() {
let a = args(["wrapc", "-", "rustc", "--crate-name"]);
let info = parse(&a).unwrap();
assert_eq!(info.crate_name, None);
assert_eq!(info.unknown, vec!["--crate-name"]);
}
#[test]
fn stdin_as_input_with_wrapper() {
let a = args(["wrapc", "-", "rustc"]);
let info = parse(&a).unwrap();
assert_eq!(info.rustc, Some("rustc".to_string()));
assert_eq!(info.inputs, Vec::<PathBuf>::new());
}
#[test]
fn response_files() {
let a = args(["wrapc", "-", "rustc", "@args.txt", "src/main.rs"]);
let info = parse(&a).unwrap();
assert_eq!(info.unknown, vec!["@args.txt"]);
assert_eq!(info.inputs, vec![PathBuf::from("src/main.rs")]);
}
#[test]
fn roundtrip_reconstruction() {
let original_args = args([
"wrapc",
"-",
"rustc",
"--crate-name=my_crate",
"--edition=2021",
"-L",
"native=/usr/lib",
"-l",
"static:+bundle=mylib:renamed",
"--emit=link,dep-info=/tmp/dep.d",
"-Copt-level=3",
"-Wunused",
"src/main.rs",
]);
let info1 = parse(&original_args).unwrap();
let reconstructed_without_wrapper = info1.to_args();
let reconstructed = [
vec![
"wrapc".to_string(),
"-".to_string(),
info1.rustc.clone().unwrap(),
],
reconstructed_without_wrapper,
]
.concat();
let info2 = parse(&reconstructed).unwrap();
assert_eq!(info1, info2);
}