litcheck_filecheck/test/
result.rs

1use litcheck::diagnostics::FileName;
2
3use crate::common::*;
4
5/// Information about a successful test run
6#[derive(Debug)]
7pub struct TestResult {
8    /// The info for each positive match (i.e. does not include CHECK-NOT)
9    matches: Vec<MatchInfo<'static>>,
10    /// The number of checks that passed (includes both positive and negative assertions)
11    passed: usize,
12    /// If the test failed, this field contains the errors associated with that failure
13    error: TestFailed,
14}
15impl TestResult {
16    pub fn new<'input, 'context: 'input>(context: &MatchContext<'input, 'context>) -> Self {
17        let error = TestFailed::new(vec![], context);
18        Self {
19            matches: vec![],
20            passed: 0,
21            error,
22        }
23    }
24
25    pub fn from_matches<'input, 'context: 'input>(
26        matches: Matches<'_>,
27        context: &MatchContext<'input, 'context>,
28    ) -> Self {
29        let mut test_result = Self::new(context);
30        test_result.append(matches);
31        test_result
32    }
33
34    pub fn from_error(error: TestFailed) -> Self {
35        Self {
36            matches: vec![],
37            passed: 0,
38            error,
39        }
40    }
41
42    pub fn append(&mut self, matches: Matches<'_>) {
43        for result in matches.into_iter() {
44            match result {
45                Ok(Some(info)) => self.matched(info),
46                Ok(None) => self.passed(),
47                Err(err) => self.failed(err),
48            }
49        }
50    }
51
52    pub fn matched(&mut self, matched: MatchInfo<'_>) {
53        self.matches.push(matched.into_static());
54        self.passed += 1;
55    }
56
57    pub fn passed(&mut self) {
58        self.passed += 1;
59    }
60
61    pub fn failed(&mut self, error: CheckFailedError) {
62        self.error.errors.push(error);
63    }
64
65    pub fn is_ok(&self) -> bool {
66        self.error.errors.is_empty()
67    }
68
69    pub fn is_failed(&self) -> bool {
70        !self.error.errors.is_empty()
71    }
72
73    pub fn num_matched(&self) -> usize {
74        self.matches.len()
75    }
76
77    pub fn num_errors(&self) -> usize {
78        self.error.errors.len()
79    }
80
81    pub fn errors(&self) -> &[CheckFailedError] {
82        self.error.errors.as_slice()
83    }
84
85    pub fn last_match_end(&self) -> Option<usize> {
86        self.matches.iter().map(|mi| mi.span.end()).max()
87    }
88
89    pub fn into_result(mut self) -> Result<Vec<MatchInfo<'static>>, TestFailed> {
90        if self.is_ok() {
91            self.matches
92                .sort_by(|a, b| a.pattern_span.start().cmp(&b.pattern_span.start()));
93            Ok(self.matches)
94        } else {
95            Err(self.error)
96        }
97    }
98
99    pub fn unwrap_err(self) -> TestFailed {
100        if self.is_ok() {
101            self.error
102        } else {
103            panic!(
104                "attempted to unwrap error when test was successful: {:#?}",
105                self
106            );
107        }
108    }
109}
110
111#[derive(Debug)]
112pub struct TestInputType(pub FileName);
113impl fmt::Display for TestInputType {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        match &self.0 {
116            FileName::Stdin => f.write_str("test from standard input"),
117            FileName::Path(path) => write!(f, "test at {}", path.display()),
118            FileName::Virtual(name) => write!(f, "test '{name}'"),
119        }
120    }
121}