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