use crate::support::{is_nightly, process, project, registry::Package}; use std::path::Path; fn as_str(bytes: &[u8]) -> &str { std::str::from_utf8(bytes).expect("valid utf-8") } #[test] fn simple() { if !is_nightly() { // --json-rendered is unstable return; } // A simple example that generates two warnings (unused functions). let p = project() .file( "src/lib.rs", " fn a() {} fn b() {} ", ) .build(); let agnostic_path = Path::new("src").join("lib.rs"); let agnostic_path_s = agnostic_path.to_str().unwrap(); // Capture what rustc actually emits. This is done to avoid relying on the // exact message formatting in rustc. let rustc_output = process("rustc") .cwd(p.root()) .args(&["--crate-type=lib", agnostic_path_s]) .exec_with_output() .expect("rustc to run"); assert!(rustc_output.stdout.is_empty()); assert!(rustc_output.status.success()); // -q so the output is the same as rustc (no "Compiling" or "Finished"). let cargo_output1 = p .cargo("check -Zcache-messages -q --color=never") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); assert_eq!(as_str(&rustc_output.stderr), as_str(&cargo_output1.stderr)); assert!(cargo_output1.stdout.is_empty()); // Check that the cached version is exactly the same. let cargo_output2 = p .cargo("check -Zcache-messages -q") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); assert_eq!(as_str(&rustc_output.stderr), as_str(&cargo_output2.stderr)); assert!(cargo_output2.stdout.is_empty()); } #[test] fn color() { if !is_nightly() { // --json-rendered is unstable return; } // Check enabling/disabling color. let p = project().file("src/lib.rs", "fn a() {}").build(); let agnostic_path = Path::new("src").join("lib.rs"); let agnostic_path_s = agnostic_path.to_str().unwrap(); // Capture the original color output. let rustc_output = process("rustc") .cwd(p.root()) .args(&["--crate-type=lib", agnostic_path_s, "--color=always"]) .exec_with_output() .expect("rustc to run"); assert!(rustc_output.status.success()); let rustc_color = as_str(&rustc_output.stderr); assert!(rustc_color.contains("\x1b[")); // Capture the original non-color output. let rustc_output = process("rustc") .cwd(p.root()) .args(&["--crate-type=lib", agnostic_path_s]) .exec_with_output() .expect("rustc to run"); let rustc_nocolor = as_str(&rustc_output.stderr); assert!(!rustc_nocolor.contains("\x1b[")); // First pass, non-cached, with color, should be the same. let cargo_output1 = p .cargo("check -Zcache-messages -q --color=always") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); assert_eq!(rustc_color, as_str(&cargo_output1.stderr)); // Replay cached, with color. let cargo_output2 = p .cargo("check -Zcache-messages -q --color=always") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); assert_eq!(rustc_color, as_str(&cargo_output2.stderr)); // Replay cached, no color. let cargo_output_nocolor = p .cargo("check -Zcache-messages -q --color=never") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); assert_eq!(rustc_nocolor, as_str(&cargo_output_nocolor.stderr)); } #[test] fn cached_as_json() { if !is_nightly() { // --json-rendered is unstable return; } // Check that cached JSON output is the same. let p = project().file("src/lib.rs", "fn a() {}").build(); // Grab the non-cached output, feature disabled. // NOTE: When stabilizing, this will need to be redone. let cargo_output = p .cargo("check --message-format=json") .exec_with_output() .expect("cargo to run"); assert!(cargo_output.status.success()); let orig_cargo_out = as_str(&cargo_output.stdout); assert!(orig_cargo_out.contains("compiler-message")); p.cargo("clean").run(); // Check JSON output, not fresh. let cargo_output1 = p .cargo("check -Zcache-messages --message-format=json") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); assert_eq!(as_str(&cargo_output1.stdout), orig_cargo_out); // Check JSON output, fresh. let cargo_output2 = p .cargo("check -Zcache-messages --message-format=json") .masquerade_as_nightly_cargo() .exec_with_output() .expect("cargo to run"); // The only difference should be this field. let fix_fresh = as_str(&cargo_output2.stdout).replace("\"fresh\":true", "\"fresh\":false"); assert_eq!(fix_fresh, orig_cargo_out); } #[test] fn clears_cache_after_fix() { if !is_nightly() { // --json-rendered is unstable return; } // Make sure the cache is invalidated when there is no output. let p = project().file("src/lib.rs", "fn asdf() {}").build(); // Fill the cache. p.cargo("check -Zcache-messages") .masquerade_as_nightly_cargo() .with_stderr_contains("[..]asdf[..]") .run(); let cpath = p .glob("target/debug/.fingerprint/foo-*/output") .next() .unwrap() .unwrap(); assert!(std::fs::read_to_string(cpath).unwrap().contains("asdf")); // Fix it. p.change_file("src/lib.rs", ""); p.cargo("check -Zcache-messages") .masquerade_as_nightly_cargo() .with_stdout("") .with_stderr( "\ [CHECKING] foo [..] [FINISHED] [..] ", ) .run(); assert_eq!(p.glob("target/debug/.fingerprint/foo-*/output").count(), 0); // And again, check the cache is correct. p.cargo("check -Zcache-messages") .masquerade_as_nightly_cargo() .with_stdout("") .with_stderr( "\ [FINISHED] [..] ", ) .run(); } #[test] fn rustdoc() { if !is_nightly() { // --json-rendered is unstable return; } // Create a warning in rustdoc. let p = project() .file( "src/lib.rs", " #![warn(private_doc_tests)] /// asdf /// ``` /// let x = 1; /// ``` fn f() {} ", ) .build(); // At this time, rustdoc does not support --json-rendered=termcolor. So it // will always be uncolored with -Zcache-messages. let rustdoc_output = p .cargo("doc -Zcache-messages -q") .masquerade_as_nightly_cargo() .exec_with_output() .expect("rustdoc to run"); assert!(rustdoc_output.status.success()); let rustdoc_stderr = as_str(&rustdoc_output.stderr); assert!(rustdoc_stderr.contains("private")); // Invert this when --json-rendered is added. assert!(!rustdoc_stderr.contains("\x1b[")); assert_eq!(p.glob("target/debug/.fingerprint/foo-*/output").count(), 1); // Check the cached output. let rustdoc_output = p .cargo("doc -Zcache-messages -q") .masquerade_as_nightly_cargo() .exec_with_output() .expect("rustdoc to run"); assert_eq!(as_str(&rustdoc_output.stderr), rustdoc_stderr); } #[test] fn clippy() { if !is_nightly() { // --json-rendered is unstable return; } if let Err(e) = process("clippy-driver").arg("-V").exec_with_output() { eprintln!("clippy-driver not available, skipping clippy test"); eprintln!("{:?}", e); return; } // Caching clippy output. // This is just a random clippy lint (assertions_on_constants) that // hopefully won't change much in the future. let p = project() .file("src/lib.rs", "pub fn f() { assert!(true); }") .build(); p.cargo("clippy-preview -Zunstable-options -Zcache-messages") .masquerade_as_nightly_cargo() .with_stderr_contains("[..]assert!(true)[..]") .run(); // Again, reading from the cache. p.cargo("clippy-preview -Zunstable-options -Zcache-messages") .masquerade_as_nightly_cargo() .with_stderr_contains("[..]assert!(true)[..]") .run(); // FIXME: Unfortunately clippy is sharing the same hash with check. This // causes the cache to be reused when it shouldn't. p.cargo("check -Zcache-messages") .masquerade_as_nightly_cargo() .with_stderr_contains("[..]assert!(true)[..]") // This should not be here. .run(); } #[test] fn fix() { if !is_nightly() { // --json-rendered is unstable return; } // Make sure `fix` is not broken by caching. let p = project().file("src/lib.rs", "pub fn try() {}").build(); p.cargo("fix --edition --allow-no-vcs -Zcache-messages") .masquerade_as_nightly_cargo() .run(); assert_eq!(p.read_file("src/lib.rs"), "pub fn r#try() {}"); } #[test] fn very_verbose() { if !is_nightly() { // --json-rendered is unstable return; } // Handle cap-lints in dependencies. Package::new("bar", "1.0.0") .file("src/lib.rs", "fn not_used() {}") .publish(); let p = project() .file( "Cargo.toml", r#" [package] name = "foo" version = "0.1.0" [dependencies] bar = "1.0" "#, ) .file("src/lib.rs", "") .build(); p.cargo("check -Zcache-messages -vv") .masquerade_as_nightly_cargo() .with_stderr_contains("[..]not_used[..]") .run(); p.cargo("check -Zcache-messages") .masquerade_as_nightly_cargo() .with_stderr("[FINISHED] [..]") .run(); p.cargo("check -Zcache-messages -vv") .masquerade_as_nightly_cargo() .with_stderr_contains("[..]not_used[..]") .run(); } #[test] fn short_incompatible() { let p = project().file("src/lib.rs", "").build(); p.cargo("check -Zcache-messages --message-format=short") .masquerade_as_nightly_cargo() .with_stderr( "[ERROR] currently `--message-format short` is incompatible with cached output", ) .with_status(101) .run(); }