Skip to content

Commit 2a624c2

Browse files
committedOct 7, 2019
Add new test to heck if all error codes have tests
1 parent 4ac4809 commit 2a624c2

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed
 
+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//! Checks that all error codes have at least one test to prevent having error
2+
//! codes that are silently not thrown by the compiler anymore.
3+
4+
use std::collections::HashMap;
5+
use std::ffi::OsStr;
6+
use std::path::Path;
7+
8+
// A few of those error codes can't be tested but all the others can and *should* be tested!
9+
const WHITELIST: &[&str] = &[
10+
"E0183",
11+
"E0227",
12+
"E0279",
13+
"E0280",
14+
"E0311",
15+
"E0313",
16+
"E0314",
17+
"E0315",
18+
"E0377",
19+
"E0456",
20+
"E0461",
21+
"E0462",
22+
"E0464",
23+
"E0465",
24+
"E0472",
25+
"E0473",
26+
"E0474",
27+
"E0475",
28+
"E0476",
29+
"E0479",
30+
"E0480",
31+
"E0481",
32+
"E0482",
33+
"E0483",
34+
"E0484",
35+
"E0485",
36+
"E0486",
37+
"E0487",
38+
"E0488",
39+
"E0489",
40+
"E0514",
41+
"E0519",
42+
"E0523",
43+
"E0526",
44+
"E0554",
45+
"E0570",
46+
"E0629",
47+
"E0630",
48+
"E0640",
49+
"E0717",
50+
"E0727",
51+
"E0729",
52+
];
53+
54+
fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>) {
55+
let mut reached_no_explanation = false;
56+
let mut last_error_code = None;
57+
58+
for line in f.lines() {
59+
let s = line.trim();
60+
if s.starts_with('E') && s.ends_with(": r##\"") {
61+
if let Some(err_code) = s.splitn(2, ':').next() {
62+
let err_code = err_code.to_owned();
63+
last_error_code = Some(err_code.clone());
64+
if !error_codes.contains_key(&err_code) {
65+
error_codes.insert(err_code, false);
66+
}
67+
}
68+
} else if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') {
69+
if let Some(err_code) = s.splitn(2, 'E').skip(1).next() {
70+
if let Some(err_code) = err_code.splitn(2, ',').next() {
71+
let nb = error_codes.entry(format!("E{}", err_code)).or_insert(false);
72+
*nb = true;
73+
}
74+
}
75+
} else if s == ";" {
76+
reached_no_explanation = true;
77+
} else if reached_no_explanation && s.starts_with('E') {
78+
if let Some(err_code) = s.splitn(2, ',').next() {
79+
let err_code = err_code.to_owned();
80+
if !error_codes.contains_key(&err_code) { // this check should *never* fail!
81+
error_codes.insert(err_code, false);
82+
}
83+
}
84+
} else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") {
85+
if let Some(last) = last_error_code {
86+
error_codes.get_mut(&last).map(|x| *x = true);
87+
}
88+
last_error_code = None;
89+
}
90+
}
91+
}
92+
93+
fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, bool>) {
94+
for line in f.lines() {
95+
let s = line.trim();
96+
if s.starts_with("error[E") || s.starts_with("warning[E") {
97+
if let Some(err_code) = s.splitn(2, ']').next() {
98+
if let Some(err_code) = err_code.splitn(2, '[').skip(1).next() {
99+
let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
100+
*nb = true;
101+
}
102+
}
103+
}
104+
}
105+
}
106+
107+
pub fn check(path: &Path, bad: &mut bool) {
108+
println!("Checking which error codes lack tests...");
109+
let mut error_codes: HashMap<String, bool> = HashMap::new();
110+
super::walk(path,
111+
&mut |path| super::filter_dirs(path),
112+
&mut |entry, contents| {
113+
let file_name = entry.file_name();
114+
if file_name == "error_codes.rs" {
115+
extract_error_codes(contents, &mut error_codes);
116+
} else if entry.path().extension() == Some(OsStr::new("stderr")) {
117+
extract_error_codes_from_tests(contents, &mut error_codes);
118+
}
119+
});
120+
println!("Found {} error codes", error_codes.len());
121+
122+
let mut errors = Vec::new();
123+
for (err_code, nb) in &error_codes {
124+
if !*nb && !WHITELIST.contains(&err_code.as_str()) {
125+
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
126+
}
127+
}
128+
errors.sort();
129+
for err in &errors {
130+
eprintln!("{}", err);
131+
}
132+
println!("Found {} error codes with no tests", errors.len());
133+
if !errors.is_empty() {
134+
*bad = true;
135+
}
136+
println!("Done!");
137+
}

‎src/tools/tidy/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub mod extdeps;
4141
pub mod ui_tests;
4242
pub mod unit_tests;
4343
pub mod unstable_book;
44+
pub mod error_codes_check;
4445

4546
fn filter_dirs(path: &Path) -> bool {
4647
let skip = [

‎src/tools/tidy/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ fn main() {
3535
deps::check_whitelist(&path, &cargo, &mut bad);
3636
extdeps::check(&path, &mut bad);
3737
ui_tests::check(&path, &mut bad);
38+
error_codes_check::check(&path, &mut bad);
3839

3940
if bad {
4041
eprintln!("some tidy checks failed");

0 commit comments

Comments
 (0)
Please sign in to comment.