11//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
2- //! `core` or `alloc` .
2+ //! of the standard library .
33//!
44//! `core` and `alloc` cannot be tested directly due to duplicating lang items.
55//! All tests and benchmarks must be written externally in
66//! `{coretests,alloctests}/{tests,benches}`.
77//!
8- //! Outside of `core` and `alloc` , tests and benchmarks should be outlined into
9- //! separate files named `tests.rs` or `benches.rs`, or directories named
8+ //! Outside of the standard library , tests and benchmarks should be outlined
9+ //! into separate files named `tests.rs` or `benches.rs`, or directories named
1010//! `tests` or `benches` unconfigured during normal build.
1111
1212use std:: path:: Path ;
1313
1414use crate :: walk:: { filter_dirs, walk} ;
1515
16- pub fn check ( root_path : & Path , bad : & mut bool ) {
17- let core = root_path. join ( "core" ) ;
18- let core_copy = core. clone ( ) ;
19- let is_core = move |path : & Path | path. starts_with ( & core) ;
20- let alloc = root_path. join ( "alloc" ) ;
21- let alloc_copy = alloc. clone ( ) ;
22- let is_alloc = move |path : & Path | path. starts_with ( & alloc) ;
23-
16+ pub fn check ( root_path : & Path , stdlib : bool , bad : & mut bool ) {
2417 let skip = move |path : & Path , is_dir| {
2518 let file_name = path. file_name ( ) . unwrap_or_default ( ) ;
19+
20+ // Skip excluded directories and non-rust files
2621 if is_dir {
27- filter_dirs ( path)
28- || path. ends_with ( "src/doc" )
29- || ( file_name == "tests" || file_name == "benches" )
30- && !is_core ( path)
31- && !is_alloc ( path)
22+ if filter_dirs ( path) || path. ends_with ( "src/doc" ) {
23+ return true ;
24+ }
3225 } else {
3326 let extension = path. extension ( ) . unwrap_or_default ( ) ;
34- extension != "rs"
35- || ( file_name == "tests.rs" || file_name == "benches.rs" )
36- && !is_core ( path)
37- && !is_alloc ( path)
38- // Tests which use non-public internals and, as such, need to
39- // have the types in the same crate as the tests themselves. See
40- // the comment in alloctests/lib.rs.
41- || path. ends_with ( "library/alloc/src/collections/btree/borrow/tests.rs" )
27+ if extension != "rs" {
28+ return true ;
29+ }
30+ }
31+
32+ // Tests in a separate package are always allowed
33+ if is_dir && file_name != "tests" && file_name. as_encoded_bytes ( ) . ends_with ( b"tests" ) {
34+ return true ;
35+ }
36+
37+ if !stdlib {
38+ // Outside of the standard library tests may also be in separate files in the same crate
39+ if is_dir {
40+ if file_name == "tests" || file_name == "benches" {
41+ return true ;
42+ }
43+ } else {
44+ if file_name == "tests.rs" || file_name == "benches.rs" {
45+ return true ;
46+ }
47+ }
48+ }
49+
50+ if is_dir {
51+ // FIXME remove those exceptions once no longer necessary
52+ file_name == "std_detect" || file_name == "std" || file_name == "test"
53+ } else {
54+ // Tests which use non-public internals and, as such, need to
55+ // have the types in the same crate as the tests themselves. See
56+ // the comment in alloctests/lib.rs.
57+ path. ends_with ( "library/alloc/src/collections/btree/borrow/tests.rs" )
4258 || path. ends_with ( "library/alloc/src/collections/btree/map/tests.rs" )
4359 || path. ends_with ( "library/alloc/src/collections/btree/node/tests.rs" )
4460 || path. ends_with ( "library/alloc/src/collections/btree/set/tests.rs" )
@@ -50,22 +66,29 @@ pub fn check(root_path: &Path, bad: &mut bool) {
5066
5167 walk ( root_path, skip, & mut |entry, contents| {
5268 let path = entry. path ( ) ;
53- let is_core = path. starts_with ( & core_copy) ;
54- let is_alloc = path. starts_with ( & alloc_copy) ;
69+ let package = path
70+ . strip_prefix ( root_path)
71+ . unwrap ( )
72+ . components ( )
73+ . next ( )
74+ . unwrap ( )
75+ . as_os_str ( )
76+ . to_str ( )
77+ . unwrap ( ) ;
5578 for ( i, line) in contents. lines ( ) . enumerate ( ) {
5679 let line = line. trim ( ) ;
5780 let is_test = || line. contains ( "#[test]" ) && !line. contains ( "`#[test]" ) ;
5881 let is_bench = || line. contains ( "#[bench]" ) && !line. contains ( "`#[bench]" ) ;
59- let manual_skip = line. contains ( "//tidy:skip" ) ;
60- if !line. starts_with ( "//" ) && ( is_test ( ) || is_bench ( ) ) && !manual_skip {
61- let explanation = if is_core {
62- "`core` unit tests and benchmarks must be placed into `coretests`"
63- } else if is_alloc {
64- "`alloc` unit tests and benchmarks must be placed into `alloctests`"
82+ if !line. starts_with ( "//" ) && ( is_test ( ) || is_bench ( ) ) {
83+ let explanation = if stdlib {
84+ format ! (
85+ "`{package}` unit tests and benchmarks must be placed into `{package}tests`"
86+ )
6587 } else {
6688 "unit tests and benchmarks must be placed into \
6789 separate files or directories named \
6890 `tests.rs`, `benches.rs`, `tests` or `benches`"
91+ . to_owned ( )
6992 } ;
7093 let name = if is_test ( ) { "test" } else { "bench" } ;
7194 tidy_error ! (
0 commit comments