use std::fmt::{self, Write}; use crate::support::install::exe; use crate::support::paths::CargoPathExt; use crate::support::registry::Package; use crate::support::{basic_manifest, project}; use glob::glob; #[test] fn check_success() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("check").run(); } #[test] fn check_fail() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(42); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("check") .with_status(101) .with_stderr_contains("[..]this function takes 0 parameters but 1 parameter was supplied") .run(); } #[test] fn custom_derive() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate bar; trait B { fn b(&self); } #[derive(B)] struct A; fn main() { let a = A; a.b(); } "#, ) .build(); let _bar = project() .at("bar") .file( "Cargo.toml", r#" [package] name = "bar" version = "0.1.0" authors = [] [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(B)] pub fn derive(_input: TokenStream) -> TokenStream { format!("impl B for A {{ fn b(&self) {{}} }}").parse().unwrap() } "#, ) .build(); foo.cargo("check").run(); } #[test] fn check_build() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("check").run(); foo.cargo("build").run(); } #[test] fn build_check() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("build").run(); foo.cargo("check").run(); } // Checks that where a project has both a lib and a bin, the lib is only checked // not built. #[test] fn issue_3418() { let foo = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .build(); foo.cargo("check -v") .with_stderr_contains("[..] --emit=dep-info,metadata [..]") .run(); } // Some weirdness that seems to be caused by a crate being built as well as // checked, but in this case with a proc macro too. #[test] fn issue_3419() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies] rustc-serialize = "*" "#, ) .file( "src/lib.rs", r#" extern crate rustc_serialize; use rustc_serialize::Decodable; pub fn take() {} "#, ) .file( "src/main.rs", r#" extern crate rustc_serialize; extern crate foo; #[derive(RustcDecodable)] pub struct Foo; fn main() { foo::take::(); } "#, ) .build(); Package::new("rustc-serialize", "1.0.0") .file( "src/lib.rs", r#"pub trait Decodable: Sized { fn decode(d: &mut D) -> Result; } pub trait Decoder { type Error; fn read_struct(&mut self, s_name: &str, len: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result; } "#, ) .publish(); p.cargo("check").run(); } // Check on a dylib should have a different metadata hash than build. #[test] fn dylib_check_preserves_build_cache() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" authors = [] [lib] crate-type = ["dylib"] [dependencies] "#, ) .file("src/lib.rs", "") .build(); p.cargo("build") .with_stderr( "\ [..]Compiling foo v0.1.0 ([..]) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..] ", ) .run(); p.cargo("check").run(); p.cargo("build") .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]") .run(); } // test `cargo rustc --profile check` #[test] fn rustc_check() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::baz(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustc --profile check -- --emit=metadata").run(); } #[test] fn rustc_check_err() { let foo = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [dependencies.bar] path = "../bar" "#, ) .file( "src/main.rs", "extern crate bar; fn main() { ::bar::qux(); }", ) .build(); let _bar = project() .at("bar") .file("Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("src/lib.rs", "pub fn baz() {}") .build(); foo.cargo("rustc --profile check -- --emit=metadata") .with_status(101) .with_stderr_contains("[CHECKING] bar [..]") .with_stderr_contains("[CHECKING] foo [..]") .with_stderr_contains("[..]cannot find function `qux` in module `bar`") .run(); } #[test] fn check_all() { let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.0.1" authors = [] [workspace] [dependencies] b = { path = "b" } "#, ) .file("src/main.rs", "fn main() {}") .file("examples/a.rs", "fn main() {}") .file("tests/a.rs", "") .file("src/lib.rs", "") .file("b/Cargo.toml", &basic_manifest("b", "0.0.1")) .file("b/src/main.rs", "fn main() {}") .file("b/src/lib.rs", "") .build(); p.cargo("check --all -v") .with_stderr_contains("[..] --crate-name foo src/lib.rs [..]") .with_stderr_contains("[..] --crate-name foo src/main.rs [..]") .with_stderr_contains("[..] --crate-name b b/src/lib.rs [..]") .with_stderr_contains("[..] --crate-name b b/src/main.rs [..]") .run(); } #[test] fn check_virtual_all_implied() { let p = project() .file( "Cargo.toml", r#" [workspace] members = ["bar", "baz"] "#, ) .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) .file("bar/src/lib.rs", "pub fn bar() {}") .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0")) .file("baz/src/lib.rs", "pub fn baz() {}") .build(); p.cargo("check -v") .with_stderr_contains("[..] --crate-name bar bar/src/lib.rs [..]") .with_stderr_contains("[..] --crate-name baz baz/src/lib.rs [..]") .run(); } #[test] fn targets_selected_default() { let foo = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "pub fn smth() {}") .file("examples/example1.rs", "fn main() {}") .file("tests/test2.rs", "#[test] fn t() {}") .file("benches/bench3.rs", "") .build(); foo.cargo("check -v") .with_stderr_contains("[..] --crate-name foo src/lib.rs [..]") .with_stderr_contains("[..] --crate-name foo src/main.rs [..]") .with_stderr_does_not_contain("[..] --crate-name example1 examples/example1.rs [..]") .with_stderr_does_not_contain("[..] --crate-name test2 tests/test2.rs [..]") .with_stderr_does_not_contain("[..] --crate-name bench3 benches/bench3.rs [..]") .run(); } #[test] fn targets_selected_all() { let foo = project() .file("src/main.rs", "fn main() {}") .file("src/lib.rs", "pub fn smth() {}") .file("examples/example1.rs", "fn main() {}") .file("tests/test2.rs", "#[test] fn t() {}") .file("benches/bench3.rs", "") .build(); foo.cargo("check --all-targets -v") .with_stderr_contains("[..] --crate-name foo src/lib.rs [..]") .with_stderr_contains("[..] --crate-name foo src/main.rs [..]") .with_stderr_contains("[..] --crate-name example1 examples/example1.rs [..]") .with_stderr_contains("[..] --crate-name test2 tests/test2.rs [..]") .with_stderr_contains("[..] --crate-name bench3 benches/bench3.rs [..]") .run(); } #[test] fn check_unit_test_profile() { let foo = project() .file( "src/lib.rs", r#" #[cfg(test)] mod tests { #[test] fn it_works() { badtext } } "#, ) .build(); foo.cargo("check").run(); foo.cargo("check --profile test") .with_status(101) .with_stderr_contains("[..]badtext[..]") .run(); } // Verify what is checked with various command-line filters. #[test] fn check_filters() { let p = project() .file( "src/lib.rs", r#" fn unused_normal_lib() {} #[cfg(test)] mod tests { fn unused_unit_lib() {} } "#, ) .file( "src/main.rs", r#" fn main() {} fn unused_normal_bin() {} #[cfg(test)] mod tests { fn unused_unit_bin() {} } "#, ) .file( "tests/t1.rs", r#" fn unused_normal_t1() {} #[cfg(test)] mod tests { fn unused_unit_t1() {} } "#, ) .file( "examples/ex1.rs", r#" fn main() {} fn unused_normal_ex1() {} #[cfg(test)] mod tests { fn unused_unit_ex1() {} } "#, ) .file( "benches/b1.rs", r#" fn unused_normal_b1() {} #[cfg(test)] mod tests { fn unused_unit_b1() {} } "#, ) .build(); p.cargo("check") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_normal_bin[..]") .with_stderr_does_not_contain("[..]unused_normal_t1[..]") .with_stderr_does_not_contain("[..]unused_normal_ex1[..]") .with_stderr_does_not_contain("[..]unused_normal_b1[..]") .with_stderr_does_not_contain("[..]unused_unit_[..]") .run(); p.root().join("target").rm_rf(); p.cargo("check --tests -v") .with_stderr_contains("[..] --crate-name foo src/lib.rs [..] --test [..]") .with_stderr_contains("[..] --crate-name foo src/lib.rs [..] --crate-type lib [..]") .with_stderr_contains("[..] --crate-name foo src/main.rs [..] --test [..]") .with_stderr_contains("[..]unused_unit_lib[..]") .with_stderr_contains("[..]unused_unit_bin[..]") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_normal_bin[..]") .with_stderr_contains("[..]unused_unit_t1[..]") .with_stderr_does_not_contain("[..]unused_normal_ex1[..]") .with_stderr_does_not_contain("[..]unused_unit_ex1[..]") .with_stderr_does_not_contain("[..]unused_normal_b1[..]") .with_stderr_does_not_contain("[..]unused_unit_b1[..]") .with_stderr_does_not_contain("[..]--crate-type bin[..]") .run(); p.root().join("target").rm_rf(); p.cargo("check --test t1 -v") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_unit_t1[..]") .with_stderr_does_not_contain("[..]unused_unit_lib[..]") .with_stderr_does_not_contain("[..]unused_normal_bin[..]") .with_stderr_does_not_contain("[..]unused_unit_bin[..]") .with_stderr_does_not_contain("[..]unused_normal_ex1[..]") .with_stderr_does_not_contain("[..]unused_normal_b1[..]") .with_stderr_does_not_contain("[..]unused_unit_ex1[..]") .with_stderr_does_not_contain("[..]unused_unit_b1[..]") .run(); p.root().join("target").rm_rf(); p.cargo("check --all-targets -v") .with_stderr_contains("[..]unused_normal_lib[..]") .with_stderr_contains("[..]unused_normal_bin[..]") .with_stderr_contains("[..]unused_normal_t1[..]") .with_stderr_contains("[..]unused_normal_ex1[..]") .with_stderr_contains("[..]unused_normal_b1[..]") .with_stderr_contains("[..]unused_unit_b1[..]") .with_stderr_contains("[..]unused_unit_t1[..]") .with_stderr_contains("[..]unused_unit_lib[..]") .with_stderr_contains("[..]unused_unit_bin[..]") .with_stderr_does_not_contain("[..]unused_unit_ex1[..]") .run(); } #[test] fn check_artifacts() { // Verify which artifacts are created when running check (#4059). let p = project() .file("src/lib.rs", "") .file("src/main.rs", "fn main() {}") .file("tests/t1.rs", "") .file("examples/ex1.rs", "fn main() {}") .file("benches/b1.rs", "") .build(); let assert_glob = |path: &str, count: usize| { assert_eq!( glob(&p.root().join(path).to_str().unwrap()) .unwrap() .count(), count ); }; p.cargo("check").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_glob("target/debug/deps/libfoo-*.rmeta", 2); p.root().join("target").rm_rf(); p.cargo("check --lib").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_glob("target/debug/deps/libfoo-*.rmeta", 1); p.root().join("target").rm_rf(); p.cargo("check --bin foo").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_glob("target/debug/deps/libfoo-*.rmeta", 2); p.root().join("target").rm_rf(); p.cargo("check --test t1").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_glob("target/debug/t1-*", 0); assert_glob("target/debug/deps/libfoo-*.rmeta", 1); assert_glob("target/debug/deps/libt1-*.rmeta", 1); p.root().join("target").rm_rf(); p.cargo("check --example ex1").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p .root() .join("target/debug/examples") .join(exe("ex1")) .is_file()); assert_glob("target/debug/deps/libfoo-*.rmeta", 1); assert_glob("target/debug/examples/libex1-*.rmeta", 1); p.root().join("target").rm_rf(); p.cargo("check --bench b1").run(); assert!(!p.root().join("target/debug/libfoo.rmeta").is_file()); assert!(!p.root().join("target/debug/libfoo.rlib").is_file()); assert!(!p.root().join("target/debug").join(exe("foo")).is_file()); assert_glob("target/debug/b1-*", 0); assert_glob("target/debug/deps/libfoo-*.rmeta", 1); assert_glob("target/debug/deps/libb1-*.rmeta", 1); } #[test] fn short_message_format() { let foo = project() .file("src/lib.rs", "fn foo() { let _x: bool = 'a'; }") .build(); foo.cargo("check --message-format=short") .with_status(101) .with_stderr_contains( "\ src/lib.rs:1:27: error[E0308]: mismatched types error: aborting due to previous error error: Could not compile `foo`. ", ) .run(); } #[test] fn proc_macro() { let p = project() .file( "Cargo.toml", r#" [package] name = "demo" version = "0.0.1" [lib] proc-macro = true "#, ) .file( "src/lib.rs", r#" extern crate proc_macro; use proc_macro::TokenStream; #[proc_macro_derive(Foo)] pub fn demo(_input: TokenStream) -> TokenStream { "".parse().unwrap() } "#, ) .file( "src/main.rs", r#" #[macro_use] extern crate demo; #[derive(Foo)] struct A; fn main() {} "#, ) .build(); p.cargo("check -v").env("RUST_LOG", "cargo=trace").run(); } #[test] fn does_not_use_empty_rustc_wrapper() { let p = project().file("src/lib.rs", "").build(); p.cargo("check").env("RUSTC_WRAPPER", "").run(); } #[test] fn error_from_deep_recursion() -> Result<(), fmt::Error> { let mut big_macro = String::new(); writeln!(big_macro, "macro_rules! m {{")?; for i in 0..130 { writeln!(big_macro, "({}) => {{ m!({}); }};", i, i + 1)?; } writeln!(big_macro, "}}")?; writeln!(big_macro, "m!(0);")?; let p = project().file("src/lib.rs", &big_macro).build(); p.cargo("check --message-format=json") .with_status(101) .with_stdout_contains( "[..]\"message\":\"recursion limit reached while expanding the macro `m`\"[..]", ) .run(); Ok(()) }