litcheck_lit/formats/
executable.rs

1use std::{path::Path, time::Duration};
2
3use litcheck::diagnostics::DiagResult;
4use serde::Deserialize;
5
6use crate::{
7    config::BooleanExpr,
8    format::TestFormat,
9    test::{DefaultTestRegistry, Test, TestRegistry, TestResult, TestStatus},
10    Config,
11};
12
13#[derive(Default, Clone, Debug, Deserialize)]
14pub struct ExecutableTest {
15    /// When non-empty, this specifies a set of boolean expressions which
16    /// are evaluated like the UNSUPPORTED directive in `ShTest`. If any
17    /// expression evaluates to true, the test is considered unsupported.
18    #[serde(default)]
19    unsupported: Vec<BooleanExpr>,
20}
21impl TestFormat for ExecutableTest {
22    #[inline(always)]
23    fn name(&self) -> &'static str {
24        "executable"
25    }
26
27    #[inline(always)]
28    fn registry(&self) -> &dyn TestRegistry {
29        &DefaultTestRegistry
30    }
31
32    fn execute(&self, test: &Test, config: &Config) -> DiagResult<TestResult> {
33        const ARGV: &[&Path] = &[];
34
35        if let Some(unsupported_features) = test.config.unsupported_features(&self.unsupported) {
36            return Ok(TestResult::new(TestStatus::Unsupported)
37                .with_stderr(unsupported_features.into_bytes()));
38        }
39
40        if config.no_execute {
41            return Ok(TestResult::new(TestStatus::Pass));
42        }
43
44        let mut command = crate::utils::ShellCommand::new(test.source_path());
45        command
46            .args(ARGV)
47            .current_dir(test.suite.working_dir())
48            .envs(test.config.env.iter().map(|(k, v)| (&**k, &**v)))
49            .paths(config.search_paths.as_slice())?;
50
51        Ok(command.wait_with_timeout(
52            config
53                .timeout
54                .map(Duration::from_secs)
55                .unwrap_or(Duration::ZERO),
56        ))
57    }
58}