]>
Commit | Line | Data |
---|---|---|
0a29b90c FG |
1 | //! Tests for internal code checks. |
2 | ||
3 | #![allow(clippy::all)] | |
4 | ||
5 | use std::fs; | |
6 | ||
7 | #[test] | |
8 | fn check_forbidden_code() { | |
9 | // Do not use certain macros, functions, etc. | |
10 | if !cargo_util::is_ci() { | |
11 | // Only check these on CI, otherwise it could be annoying. | |
12 | use std::io::Write; | |
13 | writeln!( | |
14 | std::io::stderr(), | |
15 | "\nSkipping check_forbidden_code test, set CI=1 to enable" | |
16 | ) | |
17 | .unwrap(); | |
18 | return; | |
19 | } | |
20 | let root_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src"); | |
21 | for entry in walkdir::WalkDir::new(&root_path) | |
22 | .into_iter() | |
23 | .filter_entry(|e| e.path() != root_path.join("doc")) | |
24 | .filter_map(|e| e.ok()) | |
25 | { | |
26 | let path = entry.path(); | |
27 | if !entry | |
28 | .file_name() | |
29 | .to_str() | |
30 | .map(|s| s.ends_with(".rs")) | |
31 | .unwrap_or(false) | |
32 | { | |
33 | continue; | |
34 | } | |
35 | eprintln!("checking {}", path.display()); | |
36 | let c = fs::read_to_string(path).unwrap(); | |
37 | for (line_index, line) in c.lines().enumerate() { | |
38 | if line.trim().starts_with("//") { | |
39 | continue; | |
40 | } | |
41 | if line_has_print(line) { | |
42 | if entry.file_name().to_str().unwrap() == "cargo_new.rs" && line.contains("Hello") { | |
43 | // An exception. | |
44 | continue; | |
45 | } | |
46 | panic!( | |
47 | "found print macro in {}:{}\n\n{}\n\n\ | |
48 | print! macros should not be used in Cargo because they can panic.\n\ | |
49 | Use one of the drop_print macros instead.\n\ | |
50 | ", | |
51 | path.display(), | |
52 | line_index, | |
53 | line | |
54 | ); | |
55 | } | |
56 | if line_has_macro(line, "dbg") { | |
57 | panic!( | |
58 | "found dbg! macro in {}:{}\n\n{}\n\n\ | |
59 | dbg! should not be used outside of debugging.", | |
60 | path.display(), | |
61 | line_index, | |
62 | line | |
63 | ); | |
64 | } | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | fn line_has_print(line: &str) -> bool { | |
70 | line_has_macro(line, "print") | |
71 | || line_has_macro(line, "eprint") | |
72 | || line_has_macro(line, "println") | |
73 | || line_has_macro(line, "eprintln") | |
74 | } | |
75 | ||
76 | #[test] | |
77 | fn line_has_print_works() { | |
78 | assert!(line_has_print("print!")); | |
79 | assert!(line_has_print("println!")); | |
80 | assert!(line_has_print("eprint!")); | |
81 | assert!(line_has_print("eprintln!")); | |
82 | assert!(line_has_print("(print!(\"hi!\"))")); | |
83 | assert!(!line_has_print("print")); | |
84 | assert!(!line_has_print("i like to print things")); | |
85 | assert!(!line_has_print("drop_print!")); | |
86 | assert!(!line_has_print("drop_println!")); | |
87 | assert!(!line_has_print("drop_eprint!")); | |
88 | assert!(!line_has_print("drop_eprintln!")); | |
89 | } | |
90 | ||
91 | fn line_has_macro(line: &str, mac: &str) -> bool { | |
92 | for (i, _) in line.match_indices(mac) { | |
93 | if line.get(i + mac.len()..i + mac.len() + 1) != Some("!") { | |
94 | continue; | |
95 | } | |
96 | if i == 0 { | |
97 | return true; | |
98 | } | |
99 | // Check for identifier boundary start. | |
100 | let prev1 = line.get(i - 1..i).unwrap().chars().next().unwrap(); | |
101 | if prev1.is_alphanumeric() || prev1 == '_' { | |
102 | continue; | |
103 | } | |
104 | return true; | |
105 | } | |
106 | false | |
107 | } |