1 //! This test is a part of quality control and makes clippy eat what it produces. Awesome lints and
2 //! long error messages
4 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
6 // Dogfood cannot run on Windows
10 use std::lazy::SyncLazy;
11 use std::path::PathBuf;
12 use std::process::Command;
16 static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy"));
20 // run clippy on itself and fail the test if lint warnings are reported
21 if cargo::is_rustc_test_suite() {
24 let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
26 let mut command = Command::new(&*CLIPPY_PATH);
28 .current_dir(root_dir)
29 .env("CLIPPY_DOGFOOD", "1")
30 .env("CARGO_INCREMENTAL", "0")
33 .arg("--all-features")
35 .args(&["-D", "clippy::all"])
36 .args(&["-D", "clippy::pedantic"])
37 .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
39 // internal lints only exist if we build with the internal-lints feature
40 if cfg!(feature = "internal-lints") {
41 command.args(&["-D", "clippy::internal"]);
44 let output = command.output().unwrap();
46 println!("status: {}", output.status);
47 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
48 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
50 assert!(output.status.success());
53 fn test_no_deps_ignores_path_deps_in_workspaces() {
54 if cargo::is_rustc_test_suite() {
57 let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
58 let target_dir = root.join("target").join("dogfood");
59 let cwd = root.join("clippy_workspace_tests");
61 // Make sure we start with a clean state
64 .env("CARGO_TARGET_DIR", &target_dir)
66 .args(&["-p", "subcrate"])
67 .args(&["-p", "path_dep"])
71 // `path_dep` is a path dependency of `subcrate` that would trigger a denied lint.
72 // Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`.
73 let output = Command::new(&*CLIPPY_PATH)
75 .env("CLIPPY_DOGFOOD", "1")
76 .env("CARGO_INCREMENTAL", "0")
78 .args(&["-p", "subcrate"])
81 .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
82 .args(&["--cfg", r#"feature="primary_package_test""#])
85 println!("status: {}", output.status);
86 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
87 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
89 assert!(output.status.success());
91 let lint_path_dep = || {
92 // Test that without the `--no-deps` argument, `path_dep` is linted.
93 let output = Command::new(&*CLIPPY_PATH)
95 .env("CLIPPY_DOGFOOD", "1")
96 .env("CARGO_INCREMENTAL", "0")
98 .args(&["-p", "subcrate"])
100 .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
101 .args(&["--cfg", r#"feature="primary_package_test""#])
104 println!("status: {}", output.status);
105 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
106 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
108 assert!(!output.status.success());
110 String::from_utf8(output.stderr)
112 .contains("error: empty `loop {}` wastes CPU cycles")
116 // Make sure Cargo is aware of the removal of `--no-deps`.
119 let successful_build = || {
120 let output = Command::new(&*CLIPPY_PATH)
122 .env("CLIPPY_DOGFOOD", "1")
123 .env("CARGO_INCREMENTAL", "0")
125 .args(&["-p", "subcrate"])
127 .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
130 println!("status: {}", output.status);
131 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
132 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
134 assert!(output.status.success());
139 // Trigger a sucessful build, so Cargo would like to cache the build result.
142 // Make sure there's no spurious rebuild when nothing changes.
143 let stderr = String::from_utf8(successful_build().stderr).unwrap();
144 assert!(!stderr.contains("Compiling"));
145 assert!(!stderr.contains("Checking"));
146 assert!(stderr.contains("Finished"));
148 // Make sure Cargo is aware of the new `--cfg` flag.
153 fn dogfood_subprojects() {
154 // run clippy on remaining subprojects and fail the test if lint warnings are reported
155 if cargo::is_rustc_test_suite() {
159 // NOTE: `path_dep` crate is omitted on purpose here
161 "clippy_workspace_tests",
162 "clippy_workspace_tests/src",
163 "clippy_workspace_tests/subcrate",
164 "clippy_workspace_tests/subcrate/src",
170 run_clippy_for_project(project);
173 // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
174 // same time, so we test this immediately after the dogfood for workspaces.
175 test_no_deps_ignores_path_deps_in_workspaces();
180 #[cfg(feature = "metadata-collector-lint")]
181 fn run_metadata_collection_lint() {
183 use std::time::SystemTime;
185 // Setup for validation
186 let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
187 let start_time = SystemTime::now();
189 // Run collection as is
190 std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
191 run_clippy_for_project("clippy_lints");
193 // Check if cargo caching got in the way
194 if let Ok(file) = File::open(metadata_output_path) {
195 if let Ok(metadata) = file.metadata() {
196 if let Ok(last_modification) = metadata.modified() {
197 if last_modification > start_time {
198 // The output file has been modified. Most likely by a hungry
199 // metadata collection monster. So We'll return.
206 // Force cargo to invalidate the caches
207 filetime::set_file_mtime(
208 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
209 filetime::FileTime::now(),
213 // Running the collection again
214 run_clippy_for_project("clippy_lints");
217 fn run_clippy_for_project(project: &str) {
218 let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
220 let mut command = Command::new(&*CLIPPY_PATH);
223 .current_dir(root_dir.join(project))
224 .env("CLIPPY_DOGFOOD", "1")
225 .env("CARGO_INCREMENTAL", "0")
227 .arg("--all-targets")
228 .arg("--all-features")
230 .args(&["-D", "clippy::all"])
231 .args(&["-D", "clippy::pedantic"])
232 .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
234 // internal lints only exist if we build with the internal-lints feature
235 if cfg!(feature = "internal-lints") {
236 command.args(&["-D", "clippy::internal"]);
239 let output = command.output().unwrap();
241 println!("status: {}", output.status);
242 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
243 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
245 assert!(output.status.success());