#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::assertions_on_constants)] #![feature(path_file_prefix)] use std::cmp::Ordering; use std::ffi::OsStr; use std::fs::{self, DirEntry}; use std::path::Path; #[test] fn test_missing_tests() { let missing_files = explore_directory(Path::new("./tests")); if !missing_files.is_empty() { assert!( false, "Didn't see a test file for the following files:\n\n{}\n", missing_files .iter() .map(|s| format!("\t{s}")) .collect::>() .join("\n") ); } } // Test for missing files. fn explore_directory(dir: &Path) -> Vec { let mut missing_files: Vec = Vec::new(); let mut current_file = String::new(); let mut files: Vec = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect(); files.sort_by(|x, y| { match x.path().file_prefix().cmp(&y.path().file_prefix()) { Ordering::Equal => (), ord => return ord, } // Sort rs files before the others if they share the same prefix. So when we see // the file prefix for the first time and it's not a rust file, it means the rust // file has to be missing. match ( x.path().extension().and_then(OsStr::to_str), y.path().extension().and_then(OsStr::to_str), ) { (Some("rs" | "toml"), _) => Ordering::Less, (_, Some("rs" | "toml")) => Ordering::Greater, _ => Ordering::Equal, } }); for entry in &files { let path = entry.path(); if path.is_dir() { missing_files.extend(explore_directory(&path)); } else { let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string(); if let Some(ext) = path.extension() { match ext.to_str().unwrap() { "rs" | "toml" => current_file = file_prefix.clone(), "stderr" | "stdout" => { if file_prefix != current_file { missing_files.push(path.to_str().unwrap().to_string()); } }, _ => continue, }; } } } missing_files }