1 extern crate libtest_mimic;
2 
3 use libtest_mimic::{Arguments, Trial, Failed};
4 
5 use std::{
6     env,
7     error::Error,
8     ffi::OsStr,
9     fs,
10     path::Path,
11 };
12 
13 
main() -> Result<(), Box<dyn Error>>14 fn main() -> Result<(), Box<dyn Error>> {
15     let args = Arguments::from_args();
16     let tests = collect_tests()?;
17     libtest_mimic::run(&args, tests).exit();
18 }
19 
20 /// Creates one test for each `.rs` file in the current directory or
21 /// sub-directories of the current directory.
collect_tests() -> Result<Vec<Trial>, Box<dyn Error>>22 fn collect_tests() -> Result<Vec<Trial>, Box<dyn Error>> {
23     fn visit_dir(path: &Path, tests: &mut Vec<Trial>) -> Result<(), Box<dyn Error>> {
24         for entry in fs::read_dir(path)? {
25             let entry = entry?;
26             let file_type = entry.file_type()?;
27 
28             // Handle files
29             let path = entry.path();
30             if file_type.is_file() {
31                 if path.extension() == Some(OsStr::new("rs")) {
32                     let name = path
33                         .strip_prefix(env::current_dir()?)?
34                         .display()
35                         .to_string();
36 
37                     let test = Trial::test(name, move || check_file(&path))
38                         .with_kind("tidy");
39                     tests.push(test);
40                 }
41             } else if file_type.is_dir() {
42                 // Handle directories
43                 visit_dir(&path, tests)?;
44             }
45         }
46 
47         Ok(())
48     }
49 
50     // We recursively look for `.rs` files, starting from the current
51     // directory.
52     let mut tests = Vec::new();
53     let current_dir = env::current_dir()?;
54     visit_dir(&current_dir, &mut tests)?;
55 
56     Ok(tests)
57 }
58 
59 /// Performs a couple of tidy tests.
check_file(path: &Path) -> Result<(), Failed>60 fn check_file(path: &Path) -> Result<(), Failed> {
61     let content = fs::read(path).map_err(|e| format!("Cannot read file: {e}"))?;
62 
63     // Check that the file is valid UTF-8
64     let content = String::from_utf8(content)
65         .map_err(|_| "The file's contents are not a valid UTF-8 string!")?;
66 
67     // Check for `\r`: we only want `\n` line breaks!
68     if content.contains('\r') {
69         return Err("Contains '\\r' chars. Please use ' \\n' line breaks only!".into());
70     }
71 
72     // Check for tab characters `\t`
73     if content.contains('\t') {
74         return Err("Contains tab characters ('\\t'). Indent with four spaces!".into());
75     }
76 
77     // Check for too long lines
78     if content.lines().any(|line| line.chars().count() > 100) {
79         return Err("Contains lines longer than 100 codepoints!".into());
80     }
81 
82     Ok(())
83 }
84