Skip to main content

litcheck_filecheck/test/
mod.rs

1mod result;
2#[cfg(test)]
3pub(crate) mod testing;
4
5pub(crate) use self::result::TestInputType;
6pub use self::result::TestResult;
7#[cfg(test)]
8pub use self::testing::TestContext;
9
10use std::path::Path;
11
12use litcheck::diagnostics::SourceManagerExt;
13
14use crate::{check::Checker, common::*, parse};
15
16#[macro_export]
17macro_rules! source_file {
18    ($config:ident, $content:expr) => {
19        $config.source_manager().load(
20            litcheck::diagnostics::SourceLanguage::Unknown,
21            litcheck::diagnostics::FileName::from(format!("{}{}", file!(), line!())),
22            $content.into(),
23        )
24    };
25
26    ($config:expr, $content:expr) => {
27        $config.source_manager().load(
28            litcheck::diagnostics::SourceLanguage::Unknown,
29            litcheck::diagnostics::FileName::from(format!("{}{}", file!(), line!())),
30            $content.into(),
31        )
32    };
33
34    ($config:ident, $name:expr, $content:expr) => {
35        $config.source_manager().load(
36            litcheck::diagnostics::SourceLanguage::Unknown,
37            litcheck::diagnostics::FileName::from($name),
38            $content.into(),
39        )
40    };
41
42    ($config:expr, $name:expr, $content:expr) => {
43        $config.source_manager().load(
44            litcheck::diagnostics::SourceLanguage::Unknown,
45            litcheck::diagnostics::FileName::from($name),
46            $content.into(),
47        )
48    };
49}
50
51/// This struct represents a single FileCheck test which
52/// can be run against one or more input files for verification.
53///
54/// This is the primary entrypoint for running FileCheck tests.
55pub struct Test<'a> {
56    config: &'a Config,
57    match_file: Arc<SourceFile>,
58}
59impl<'a> Test<'a> {
60    /// Create a new test from the given match file (containing CHECKs) and configuration
61    ///
62    /// This function does not compile the actual test file until verification is requested.
63    pub fn new(match_file: Arc<SourceFile>, config: &'a Config) -> Self {
64        Self { config, match_file }
65    }
66
67    /// Create a test from a file path containing CHECKs
68    pub fn from_file(match_file: impl AsRef<Path>, config: &'a Config) -> Self {
69        let match_file = config
70            .source_manager
71            .load_file(match_file.as_ref())
72            .expect("could not load match file");
73        Self::new(match_file, config)
74    }
75
76    /// Verify the file at the given path passes this test.
77    ///
78    /// See [Self::verify] for details.
79    pub fn verify_file(
80        &mut self,
81        input_file: impl AsRef<Path>,
82    ) -> DiagResult<Vec<MatchInfo<'static>>> {
83        let input_file = self
84            .config
85            .source_manager
86            .load_file(input_file.as_ref())
87            .map_err(Report::from_err)?;
88        self.verify(input_file)
89    }
90
91    /// Verify the given input file passes this test.
92    ///
93    /// First, it parses the check file for rules, post-processes them, and then
94    /// applies the parsed rules to the input file, to determine if the file matches
95    /// or fails to match.
96    pub fn verify(&mut self, input_file: Arc<SourceFile>) -> DiagResult<Vec<MatchInfo<'static>>> {
97        // Parse the check file
98        let mut parser = parse::CheckFileParser::new(self.config);
99
100        let match_file = parser
101            .parse(self.match_file.id(), self.match_file.as_str())
102            .map_err(|err| Report::new(err).with_source_code(self.match_file.clone()))?;
103
104        // Compile the check rules, and raise an error if any are invalid
105        let program = match_file.compile(self.config)?;
106
107        // Apply the checks
108        let mut checker = Checker::new(self.config, program, self.match_file.clone());
109        checker
110            .check_input(input_file)
111            .into_result()
112            .map_err(Report::new)
113    }
114}