1 //! File tests.
2 //!
3 //! This crate contains the main test driver as well as implementations of the
4 //! available filetest commands.
5 
6 #![deny(missing_docs)]
7 
8 pub use crate::function_runner::TestFileCompiler;
9 use crate::runner::TestRunner;
10 use cranelift_reader::TestCommand;
11 use std::path::Path;
12 
13 mod concurrent;
14 pub mod function_runner;
15 mod match_directive;
16 mod runner;
17 mod runone;
18 mod subtest;
19 
20 mod test_alias_analysis;
21 mod test_cat;
22 mod test_compile;
23 mod test_domtree;
24 mod test_inline;
25 mod test_interpret;
26 mod test_legalizer;
27 mod test_optimize;
28 mod test_print_cfg;
29 mod test_run;
30 mod test_safepoint;
31 mod test_unwind;
32 mod test_verifier;
33 
34 /// Main entry point for `clif-util test`.
35 ///
36 /// Take a list of filenames which can be either `.clif` files or directories.
37 ///
38 /// Files are interpreted as test cases and executed immediately.
39 ///
40 /// Directories are scanned recursively for test cases ending in `.clif`. These test cases are
41 /// executed on background threads.
42 ///
run(verbose: bool, report_times: bool, files: &[String]) -> anyhow::Result<()>43 pub fn run(verbose: bool, report_times: bool, files: &[String]) -> anyhow::Result<()> {
44     let mut runner = TestRunner::new(verbose, report_times);
45 
46     for path in files.iter().map(Path::new) {
47         if path.is_file() {
48             runner.push_test(path);
49         } else {
50             runner.push_dir(path);
51         }
52     }
53 
54     runner.start_threads();
55     runner.run()
56 }
57 
58 /// Used for 'pass' subcommand.
59 /// Commands are interpreted as test and executed.
60 ///
61 /// Directories are scanned recursively for test cases ending in `.clif`.
62 ///
run_passes( verbose: bool, report_times: bool, passes: &[String], target: &str, file: &str, ) -> anyhow::Result<()>63 pub fn run_passes(
64     verbose: bool,
65     report_times: bool,
66     passes: &[String],
67     target: &str,
68     file: &str,
69 ) -> anyhow::Result<()> {
70     let mut runner = TestRunner::new(verbose, report_times);
71 
72     let path = Path::new(file);
73     if path == Path::new("-") || path.is_file() {
74         runner.push_test(path);
75     } else {
76         runner.push_dir(path);
77     }
78 
79     runner.start_threads();
80     runner.run_passes(passes, target)
81 }
82 
83 /// Create a new subcommand trait object to match `parsed.command`.
84 ///
85 /// This function knows how to create all of the possible `test <foo>` commands that can appear in
86 /// a `.clif` test file.
new_subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn subtest::SubTest>>87 fn new_subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn subtest::SubTest>> {
88     match parsed.command {
89         "alias-analysis" => test_alias_analysis::subtest(parsed),
90         "cat" => test_cat::subtest(parsed),
91         "compile" => test_compile::subtest(parsed),
92         "domtree" => test_domtree::subtest(parsed),
93         "inline" => test_inline::subtest(parsed),
94         "interpret" => test_interpret::subtest(parsed),
95         "legalizer" => test_legalizer::subtest(parsed),
96         "optimize" => test_optimize::subtest(parsed),
97         "print-cfg" => test_print_cfg::subtest(parsed),
98         "run" => test_run::subtest(parsed),
99         "safepoint" => test_safepoint::subtest(parsed),
100         "unwind" => test_unwind::subtest(parsed),
101         "verifier" => test_verifier::subtest(parsed),
102         _ => anyhow::bail!("unknown test command '{}'", parsed.command),
103     }
104 }
105 
pretty_anyhow_error( func: &cranelift_codegen::ir::Function, err: cranelift_codegen::CodegenError, ) -> anyhow::Error106 fn pretty_anyhow_error(
107     func: &cranelift_codegen::ir::Function,
108     err: cranelift_codegen::CodegenError,
109 ) -> anyhow::Error {
110     let s = cranelift_codegen::print_errors::pretty_error(func, err);
111     anyhow::anyhow!("{s}")
112 }
113