@@ -7,55 +7,20 @@ use std::fs;
7
7
use std:: io:: Write ;
8
8
use std:: path:: { Path , PathBuf } ;
9
9
10
- const EXPECTED_TEST_FILE_EXTENSIONS : & [ & str ] = & [
11
- "rs" , // test source files
12
- "stderr" , // expected stderr file, corresponds to a rs file
13
- "svg" , // expected svg file, corresponds to a rs file, equivalent to stderr
14
- "stdout" , // expected stdout file, corresponds to a rs file
15
- "fixed" , // expected source file after applying fixes
16
- "md" , // test directory descriptions
17
- "ftl" , // translation tests
18
- ] ;
19
-
20
- const EXTENSION_EXCEPTION_PATHS : & [ & str ] = & [
21
- "tests/ui/asm/named-asm-labels.s" , // loading an external asm file to test named labels lint
22
- "tests/ui/codegen/mismatched-data-layout.json" , // testing mismatched data layout w/ custom targets
23
- "tests/ui/check-cfg/my-awesome-platform.json" , // testing custom targets with cfgs
24
- "tests/ui/argfile/commandline-argfile-badutf8.args" , // passing args via a file
25
- "tests/ui/argfile/commandline-argfile.args" , // passing args via a file
26
- "tests/ui/crate-loading/auxiliary/libfoo.rlib" , // testing loading a manually created rlib
27
- "tests/ui/include-macros/data.bin" , // testing including data with the include macros
28
- "tests/ui/include-macros/file.txt" , // testing including data with the include macros
29
- "tests/ui/macros/macro-expanded-include/file.txt" , // testing including data with the include macros
30
- "tests/ui/macros/not-utf8.bin" , // testing including data with the include macros
31
- "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment" , // more include
32
- "tests/ui/proc-macro/auxiliary/included-file.txt" , // more include
33
- "tests/ui/unpretty/auxiliary/data.txt" , // more include
34
- "tests/ui/invalid/foo.natvis.xml" , // sample debugger visualizer
35
- "tests/ui/sanitizer/dataflow-abilist.txt" , // dataflow sanitizer ABI list file
36
- "tests/ui/shell-argfiles/shell-argfiles.args" , // passing args via a file
37
- "tests/ui/shell-argfiles/shell-argfiles-badquotes.args" , // passing args via a file
38
- "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args" , // passing args via a file
39
- "tests/ui/shell-argfiles/shell-argfiles-via-argfile.args" , // passing args via a file
40
- "tests/ui/std/windows-bat-args1.bat" , // tests escaping arguments through batch files
41
- "tests/ui/std/windows-bat-args2.bat" , // tests escaping arguments through batch files
42
- "tests/ui/std/windows-bat-args3.bat" , // tests escaping arguments through batch files
43
- ] ;
44
-
45
- pub fn check ( root_path : & Path , bless : bool , bad : & mut bool ) {
46
- let issues_txt_header = r#"============================================================
10
+ const ISSUES_TXT_HEADER : & str = r#"============================================================
47
11
⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️
48
12
============================================================
49
13
"# ;
50
14
15
+ pub fn check ( root_path : & Path , bless : bool , bad : & mut bool ) {
51
16
let path = & root_path. join ( "tests" ) ;
52
17
53
18
// the list of files in ui tests that are allowed to start with `issue-XXXX`
54
19
// BTreeSet because we would like a stable ordering so --bless works
55
20
let mut prev_line = "" ;
56
21
let mut is_sorted = true ;
57
22
let allowed_issue_names: BTreeSet < _ > = include_str ! ( "issues.txt" )
58
- . strip_prefix ( issues_txt_header )
23
+ . strip_prefix ( ISSUES_TXT_HEADER )
59
24
. unwrap ( )
60
25
. lines ( )
61
26
. inspect ( |& line| {
@@ -75,73 +40,9 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
75
40
) ;
76
41
}
77
42
78
- let mut remaining_issue_names: BTreeSet < & str > = allowed_issue_names. clone ( ) ;
79
-
80
- let ( ui, ui_fulldeps) = ( path. join ( "ui" ) , path. join ( "ui-fulldeps" ) ) ;
81
- let paths = [ ui. as_path ( ) , ui_fulldeps. as_path ( ) ] ;
82
- crate :: walk:: walk_no_read ( & paths, |_, _| false , & mut |entry| {
83
- let file_path = entry. path ( ) ;
84
- if let Some ( ext) = file_path. extension ( ) . and_then ( OsStr :: to_str) {
85
- // files that are neither an expected extension or an exception should not exist
86
- // they're probably typos or not meant to exist
87
- if !( EXPECTED_TEST_FILE_EXTENSIONS . contains ( & ext)
88
- || EXTENSION_EXCEPTION_PATHS . iter ( ) . any ( |path| file_path. ends_with ( path) ) )
89
- {
90
- tidy_error ! ( bad, "file {} has unexpected extension {}" , file_path. display( ) , ext) ;
91
- }
92
-
93
- // NB: We do not use file_stem() as some file names have multiple `.`s and we
94
- // must strip all of them.
95
- let testname =
96
- file_path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . split_once ( '.' ) . unwrap ( ) . 0 ;
97
- if ext == "stderr" || ext == "stdout" || ext == "fixed" {
98
- // Test output filenames have one of the formats:
99
- // ```
100
- // $testname.stderr
101
- // $testname.$mode.stderr
102
- // $testname.$revision.stderr
103
- // $testname.$revision.$mode.stderr
104
- // ```
105
- //
106
- // For now, just make sure that there is a corresponding
107
- // `$testname.rs` file.
108
-
109
- if !file_path. with_file_name ( testname) . with_extension ( "rs" ) . exists ( )
110
- && !testname. contains ( "ignore-tidy" )
111
- {
112
- tidy_error ! ( bad, "Stray file with UI testing output: {:?}" , file_path) ;
113
- }
114
-
115
- if let Ok ( metadata) = fs:: metadata ( file_path)
116
- && metadata. len ( ) == 0
117
- {
118
- tidy_error ! ( bad, "Empty file with UI testing output: {:?}" , file_path) ;
119
- }
120
- }
43
+ deny_new_top_level_ui_tests ( bad, & path. join ( "ui" ) ) ;
121
44
122
- if ext == "rs"
123
- && let Some ( test_name) = static_regex ! ( r"^issues?[-_]?(\d{3,})" ) . captures ( testname)
124
- {
125
- // these paths are always relative to the passed `path` and always UTF8
126
- let stripped_path = file_path
127
- . strip_prefix ( path)
128
- . unwrap ( )
129
- . to_str ( )
130
- . unwrap ( )
131
- . replace ( std:: path:: MAIN_SEPARATOR_STR , "/" ) ;
132
-
133
- if !remaining_issue_names. remove ( stripped_path. as_str ( ) )
134
- && !stripped_path. starts_with ( "ui/issues/" )
135
- {
136
- tidy_error ! (
137
- bad,
138
- "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`" ,
139
- issue_n = & test_name[ 1 ] ,
140
- ) ;
141
- }
142
- }
143
- }
144
- } ) ;
45
+ let remaining_issue_names = recursively_check_ui_tests ( bad, path, & allowed_issue_names) ;
145
46
146
47
// if there are any file names remaining, they were moved on the fs.
147
48
// our data must remain up to date, so it must be removed from issues.txt
@@ -152,7 +53,7 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
152
53
// so we don't bork things on panic or a contributor using Ctrl+C
153
54
let blessed_issues_path = tidy_src. join ( "issues_blessed.txt" ) ;
154
55
let mut blessed_issues_txt = fs:: File :: create ( & blessed_issues_path) . unwrap ( ) ;
155
- blessed_issues_txt. write_all ( issues_txt_header . as_bytes ( ) ) . unwrap ( ) ;
56
+ blessed_issues_txt. write_all ( ISSUES_TXT_HEADER . as_bytes ( ) ) . unwrap ( ) ;
156
57
// If we changed paths to use the OS separator, reassert Unix chauvinism for blessing.
157
58
for filename in allowed_issue_names. difference ( & remaining_issue_names) {
158
59
writeln ! ( blessed_issues_txt, "{filename}" ) . unwrap ( ) ;
@@ -171,3 +72,170 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
171
72
}
172
73
}
173
74
}
75
+
76
+ fn deny_new_top_level_ui_tests ( bad : & mut bool , tests_path : & Path ) {
77
+ // See <https://github.com/rust-lang/compiler-team/issues/902> where we propose banning adding
78
+ // new ui tests *directly* under `tests/ui/`. For more context, see:
79
+ //
80
+ // - <https://github.com/rust-lang/rust/issues/73494>
81
+ // - <https://github.com/rust-lang/rust/issues/133895>
82
+
83
+ let top_level_ui_tests = walkdir:: WalkDir :: new ( tests_path)
84
+ . min_depth ( 1 )
85
+ . max_depth ( 1 )
86
+ . follow_links ( false )
87
+ . same_file_system ( true )
88
+ . into_iter ( )
89
+ . flatten ( )
90
+ . filter ( |e| {
91
+ let file_name = e. file_name ( ) ;
92
+ file_name != ".gitattributes" && file_name != "README.md"
93
+ } )
94
+ . filter ( |e| !e. file_type ( ) . is_dir ( ) ) ;
95
+ for entry in top_level_ui_tests {
96
+ tidy_error ! (
97
+ bad,
98
+ "ui tests should be added under meaningful subdirectories: `{}`" ,
99
+ entry. path( ) . display( )
100
+ )
101
+ }
102
+ }
103
+
104
+ fn recursively_check_ui_tests < ' issues > (
105
+ bad : & mut bool ,
106
+ path : & Path ,
107
+ allowed_issue_names : & ' issues BTreeSet < & ' issues str > ,
108
+ ) -> BTreeSet < & ' issues str > {
109
+ let mut remaining_issue_names: BTreeSet < & str > = allowed_issue_names. clone ( ) ;
110
+
111
+ let ( ui, ui_fulldeps) = ( path. join ( "ui" ) , path. join ( "ui-fulldeps" ) ) ;
112
+ let paths = [ ui. as_path ( ) , ui_fulldeps. as_path ( ) ] ;
113
+ crate :: walk:: walk_no_read ( & paths, |_, _| false , & mut |entry| {
114
+ let file_path = entry. path ( ) ;
115
+ if let Some ( ext) = file_path. extension ( ) . and_then ( OsStr :: to_str) {
116
+ check_unexpected_extension ( bad, file_path, ext) ;
117
+
118
+ // NB: We do not use file_stem() as some file names have multiple `.`s and we
119
+ // must strip all of them.
120
+ let testname =
121
+ file_path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . split_once ( '.' ) . unwrap ( ) . 0 ;
122
+ if ext == "stderr" || ext == "stdout" || ext == "fixed" {
123
+ check_stray_output_snapshot ( bad, file_path, testname) ;
124
+ check_empty_output_snapshot ( bad, file_path) ;
125
+ }
126
+
127
+ deny_new_nondescriptive_test_names (
128
+ bad,
129
+ path,
130
+ & mut remaining_issue_names,
131
+ file_path,
132
+ testname,
133
+ ext,
134
+ ) ;
135
+ }
136
+ } ) ;
137
+ remaining_issue_names
138
+ }
139
+
140
+ fn check_unexpected_extension ( bad : & mut bool , file_path : & Path , ext : & str ) {
141
+ const EXPECTED_TEST_FILE_EXTENSIONS : & [ & str ] = & [
142
+ "rs" , // test source files
143
+ "stderr" , // expected stderr file, corresponds to a rs file
144
+ "svg" , // expected svg file, corresponds to a rs file, equivalent to stderr
145
+ "stdout" , // expected stdout file, corresponds to a rs file
146
+ "fixed" , // expected source file after applying fixes
147
+ "md" , // test directory descriptions
148
+ "ftl" , // translation tests
149
+ ] ;
150
+
151
+ const EXTENSION_EXCEPTION_PATHS : & [ & str ] = & [
152
+ "tests/ui/asm/named-asm-labels.s" , // loading an external asm file to test named labels lint
153
+ "tests/ui/codegen/mismatched-data-layout.json" , // testing mismatched data layout w/ custom targets
154
+ "tests/ui/check-cfg/my-awesome-platform.json" , // testing custom targets with cfgs
155
+ "tests/ui/argfile/commandline-argfile-badutf8.args" , // passing args via a file
156
+ "tests/ui/argfile/commandline-argfile.args" , // passing args via a file
157
+ "tests/ui/crate-loading/auxiliary/libfoo.rlib" , // testing loading a manually created rlib
158
+ "tests/ui/include-macros/data.bin" , // testing including data with the include macros
159
+ "tests/ui/include-macros/file.txt" , // testing including data with the include macros
160
+ "tests/ui/macros/macro-expanded-include/file.txt" , // testing including data with the include macros
161
+ "tests/ui/macros/not-utf8.bin" , // testing including data with the include macros
162
+ "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment" , // more include
163
+ "tests/ui/proc-macro/auxiliary/included-file.txt" , // more include
164
+ "tests/ui/unpretty/auxiliary/data.txt" , // more include
165
+ "tests/ui/invalid/foo.natvis.xml" , // sample debugger visualizer
166
+ "tests/ui/sanitizer/dataflow-abilist.txt" , // dataflow sanitizer ABI list file
167
+ "tests/ui/shell-argfiles/shell-argfiles.args" , // passing args via a file
168
+ "tests/ui/shell-argfiles/shell-argfiles-badquotes.args" , // passing args via a file
169
+ "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args" , // passing args via a file
170
+ "tests/ui/shell-argfiles/shell-argfiles-via-argfile.args" , // passing args via a file
171
+ "tests/ui/std/windows-bat-args1.bat" , // tests escaping arguments through batch files
172
+ "tests/ui/std/windows-bat-args2.bat" , // tests escaping arguments through batch files
173
+ "tests/ui/std/windows-bat-args3.bat" , // tests escaping arguments through batch files
174
+ ] ;
175
+
176
+ // files that are neither an expected extension or an exception should not exist
177
+ // they're probably typos or not meant to exist
178
+ if !( EXPECTED_TEST_FILE_EXTENSIONS . contains ( & ext)
179
+ || EXTENSION_EXCEPTION_PATHS . iter ( ) . any ( |path| file_path. ends_with ( path) ) )
180
+ {
181
+ tidy_error ! ( bad, "file {} has unexpected extension {}" , file_path. display( ) , ext) ;
182
+ }
183
+ }
184
+
185
+ fn check_stray_output_snapshot ( bad : & mut bool , file_path : & Path , testname : & str ) {
186
+ // Test output filenames have one of the formats:
187
+ // ```
188
+ // $testname.stderr
189
+ // $testname.$mode.stderr
190
+ // $testname.$revision.stderr
191
+ // $testname.$revision.$mode.stderr
192
+ // ```
193
+ //
194
+ // For now, just make sure that there is a corresponding
195
+ // `$testname.rs` file.
196
+
197
+ if !file_path. with_file_name ( testname) . with_extension ( "rs" ) . exists ( )
198
+ && !testname. contains ( "ignore-tidy" )
199
+ {
200
+ tidy_error ! ( bad, "Stray file with UI testing output: {:?}" , file_path) ;
201
+ }
202
+ }
203
+
204
+ fn check_empty_output_snapshot ( bad : & mut bool , file_path : & Path ) {
205
+ if let Ok ( metadata) = fs:: metadata ( file_path)
206
+ && metadata. len ( ) == 0
207
+ {
208
+ tidy_error ! ( bad, "Empty file with UI testing output: {:?}" , file_path) ;
209
+ }
210
+ }
211
+
212
+ fn deny_new_nondescriptive_test_names (
213
+ bad : & mut bool ,
214
+ path : & Path ,
215
+ remaining_issue_names : & mut BTreeSet < & str > ,
216
+ file_path : & Path ,
217
+ testname : & str ,
218
+ ext : & str ,
219
+ ) {
220
+ if ext == "rs"
221
+ && let Some ( test_name) = static_regex ! ( r"^issues?[-_]?(\d{3,})" ) . captures ( testname)
222
+ {
223
+ // these paths are always relative to the passed `path` and always UTF8
224
+ let stripped_path = file_path
225
+ . strip_prefix ( path)
226
+ . unwrap ( )
227
+ . to_str ( )
228
+ . unwrap ( )
229
+ . replace ( std:: path:: MAIN_SEPARATOR_STR , "/" ) ;
230
+
231
+ if !remaining_issue_names. remove ( stripped_path. as_str ( ) )
232
+ && !stripped_path. starts_with ( "ui/issues/" )
233
+ {
234
+ tidy_error ! (
235
+ bad,
236
+ "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`" ,
237
+ issue_n = & test_name[ 1 ] ,
238
+ ) ;
239
+ }
240
+ }
241
+ }
0 commit comments