@@ -118,7 +118,7 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
118118 ) ;
119119 }
120120
121- let contains_tests = file_buf . contains ( "#[test] \n " ) ;
121+ let contains_tests = exercise_has_tests ( & file_buf ) ;
122122 if exercise_info. test {
123123 if !contains_tests {
124124 bail ! (
@@ -139,6 +139,13 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
139139 Ok ( paths)
140140}
141141
142+ // Check if the exercise contains `#[test]`-annotated tests.
143+ // CRLF line endings are normalized first so that the check doesn't fail
144+ // on files with Windows line endings (e.g. `#[test]\r\n`).
145+ fn exercise_has_tests ( file_content : & str ) -> bool {
146+ file_content. replace ( "\r \n " , "\n " ) . contains ( "#[test]\n " )
147+ }
148+
142149// Check `dir` for unexpected files.
143150// Only Rust files in `allowed_rust_files` and `README.md` files are allowed.
144151// Only one level of directory nesting is allowed.
@@ -396,3 +403,21 @@ pub fn check(require_solutions: bool) -> Result<()> {
396403}
397404
398405const SKIP_CHECK_UNSOLVED_HINT : & str = "If this is an introduction exercise that is intended to be already solved, add `skip_check_unsolved = true` to the exercise's metadata in the `info.toml` file" ;
406+
407+ #[ cfg( test) ]
408+ mod tests {
409+ use super :: * ;
410+
411+ #[ test]
412+ fn detects_tests_in_files_with_crlf_line_endings ( ) {
413+ let content = "fn main() {}\r \n \r \n #[cfg(test)]\r \n mod tests {\r \n #[test]\r \n fn it_works() {}\r \n }\r \n " ;
414+ assert ! ( exercise_has_tests( content) ) ;
415+ }
416+
417+ #[ test]
418+ fn detects_tests_in_files_with_lf_line_endings ( ) {
419+ let content =
420+ "fn main() {}\n \n #[cfg(test)]\n mod tests {\n #[test]\n fn it_works() {}\n }\n " ;
421+ assert ! ( exercise_has_tests( content) ) ;
422+ }
423+ }
0 commit comments