]> git.lizzy.rs Git - rust.git/blob - tests/dogfood.rs
Auto merge of #7596 - lengyijun:option_needless_deref, r=llogiq
[rust.git] / tests / dogfood.rs
1 //! This test is a part of quality control and makes clippy eat what it produces. Awesome lints and
2 //! long error messages
3 //!
4 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
5
6 // Dogfood cannot run on Windows
7 #![cfg(not(windows))]
8 #![feature(once_cell)]
9
10 use std::lazy::SyncLazy;
11 use std::path::PathBuf;
12 use std::process::Command;
13
14 mod cargo;
15
16 static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy"));
17
18 #[test]
19 fn dogfood_clippy() {
20     // run clippy on itself and fail the test if lint warnings are reported
21     if cargo::is_rustc_test_suite() {
22         return;
23     }
24     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
25
26     let mut command = Command::new(&*CLIPPY_PATH);
27     command
28         .current_dir(root_dir)
29         .env("CLIPPY_DOGFOOD", "1")
30         .env("CARGO_INCREMENTAL", "0")
31         .arg("clippy")
32         .arg("--all-targets")
33         .arg("--all-features")
34         .arg("--")
35         .args(&["-D", "clippy::all"])
36         .args(&["-D", "clippy::pedantic"])
37         .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
38
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"]);
42     }
43
44     let output = command.output().unwrap();
45
46     println!("status: {}", output.status);
47     println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
48     println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
49
50     assert!(output.status.success());
51 }
52
53 fn test_no_deps_ignores_path_deps_in_workspaces() {
54     if cargo::is_rustc_test_suite() {
55         return;
56     }
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");
60
61     // Make sure we start with a clean state
62     Command::new("cargo")
63         .current_dir(&cwd)
64         .env("CARGO_TARGET_DIR", &target_dir)
65         .arg("clean")
66         .args(&["-p", "subcrate"])
67         .args(&["-p", "path_dep"])
68         .output()
69         .unwrap();
70
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)
74         .current_dir(&cwd)
75         .env("CLIPPY_DOGFOOD", "1")
76         .env("CARGO_INCREMENTAL", "0")
77         .arg("clippy")
78         .args(&["-p", "subcrate"])
79         .arg("--no-deps")
80         .arg("--")
81         .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
82         .args(&["--cfg", r#"feature="primary_package_test""#])
83         .output()
84         .unwrap();
85     println!("status: {}", output.status);
86     println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
87     println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
88
89     assert!(output.status.success());
90
91     let lint_path_dep = || {
92         // Test that without the `--no-deps` argument, `path_dep` is linted.
93         let output = Command::new(&*CLIPPY_PATH)
94             .current_dir(&cwd)
95             .env("CLIPPY_DOGFOOD", "1")
96             .env("CARGO_INCREMENTAL", "0")
97             .arg("clippy")
98             .args(&["-p", "subcrate"])
99             .arg("--")
100             .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
101             .args(&["--cfg", r#"feature="primary_package_test""#])
102             .output()
103             .unwrap();
104         println!("status: {}", output.status);
105         println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
106         println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
107
108         assert!(!output.status.success());
109         assert!(
110             String::from_utf8(output.stderr)
111                 .unwrap()
112                 .contains("error: empty `loop {}` wastes CPU cycles")
113         );
114     };
115
116     // Make sure Cargo is aware of the removal of `--no-deps`.
117     lint_path_dep();
118
119     let successful_build = || {
120         let output = Command::new(&*CLIPPY_PATH)
121             .current_dir(&cwd)
122             .env("CLIPPY_DOGFOOD", "1")
123             .env("CARGO_INCREMENTAL", "0")
124             .arg("clippy")
125             .args(&["-p", "subcrate"])
126             .arg("--")
127             .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
128             .output()
129             .unwrap();
130         println!("status: {}", output.status);
131         println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
132         println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
133
134         assert!(output.status.success());
135
136         output
137     };
138
139     // Trigger a sucessful build, so Cargo would like to cache the build result.
140     successful_build();
141
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"));
147
148     // Make sure Cargo is aware of the new `--cfg` flag.
149     lint_path_dep();
150 }
151
152 #[test]
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() {
156         return;
157     }
158
159     // NOTE: `path_dep` crate is omitted on purpose here
160     for project in &[
161         "clippy_workspace_tests",
162         "clippy_workspace_tests/src",
163         "clippy_workspace_tests/subcrate",
164         "clippy_workspace_tests/subcrate/src",
165         "clippy_dev",
166         "clippy_lints",
167         "clippy_utils",
168         "rustc_tools_util",
169     ] {
170         run_clippy_for_project(project);
171     }
172
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();
176 }
177
178 #[test]
179 #[ignore]
180 #[cfg(feature = "metadata-collector-lint")]
181 fn run_metadata_collection_lint() {
182     use std::fs::File;
183     use std::time::SystemTime;
184
185     // Setup for validation
186     let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json");
187     let start_time = SystemTime::now();
188
189     // Run collection as is
190     std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
191     run_clippy_for_project("clippy_lints");
192
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.
200                     return;
201                 }
202             }
203         }
204     }
205
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(),
210     )
211     .unwrap();
212
213     // Running the collection again
214     run_clippy_for_project("clippy_lints");
215 }
216
217 fn run_clippy_for_project(project: &str) {
218     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
219
220     let mut command = Command::new(&*CLIPPY_PATH);
221
222     command
223         .current_dir(root_dir.join(project))
224         .env("CLIPPY_DOGFOOD", "1")
225         .env("CARGO_INCREMENTAL", "0")
226         .arg("clippy")
227         .arg("--all-targets")
228         .arg("--all-features")
229         .arg("--")
230         .args(&["-D", "clippy::all"])
231         .args(&["-D", "clippy::pedantic"])
232         .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
233
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"]);
237     }
238
239     let output = command.output().unwrap();
240
241     println!("status: {}", output.status);
242     println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
243     println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
244
245     assert!(output.status.success());
246 }