1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::{config, LightContext, SourceFile, Span};
use anyhow::Result;
use indexmap::IndexMap;
use std::{
    collections::{BTreeMap, BTreeSet},
    path::Path,
};
use subprocess::{Exec, Popen};

mod auto;
pub use auto::Auto;

mod empty;
pub use empty::Empty;

mod union;
pub use union::Union;

#[allow(dead_code)]
type AutoUnion<T, U> = Auto<Union<T, U>>;

pub trait Applicable {
    fn applicable(&self, context: &LightContext) -> Result<bool>;
}

pub trait ToImplementation {
    fn to_implementation(&self, context: &LightContext) -> Result<Option<Box<dyn Interface>>>;
}

pub trait Interface: Parse + Run {}

pub type TestFileTestSpanMap = BTreeMap<SourceFile, TestSpanMap>;

pub type TestSpanMap = IndexMap<String, BTreeSet<Span>>;

pub trait Parse {
    fn parse(
        &mut self,
        context: &LightContext,
        config: &config::Toml,
        test_files: &[&Path],
    ) -> Result<TestFileTestSpanMap>;
}

pub type Postprocess = dyn Fn(&LightContext, Popen) -> Result<bool>;

pub trait Run {
    fn dry_run(&self, context: &LightContext, test_file: &Path) -> Result<()>;
    fn exec(
        &self,
        context: &LightContext,
        test_name: &str,
        span: &Span,
    ) -> Result<Option<(Exec, Option<Box<Postprocess>>)>>;
}

pub trait AsParse {
    fn as_parse(&self) -> &dyn Parse;
    fn as_parse_mut(&mut self) -> &mut dyn Parse;
}

pub trait AsRun {
    fn as_run(&self) -> &dyn Run;
}

impl<T: AsParse> Parse for T {
    #[cfg_attr(dylint_lib = "general", allow(non_local_effect_before_error_return))]
    fn parse(
        &mut self,
        context: &LightContext,
        config: &config::Toml,
        test_files: &[&Path],
    ) -> Result<TestFileTestSpanMap> {
        self.as_parse_mut().parse(context, config, test_files)
    }
}

impl<T: AsRun> Run for T {
    fn dry_run(&self, context: &LightContext, test_file: &Path) -> Result<()> {
        self.as_run().dry_run(context, test_file)
    }
    fn exec(
        &self,
        context: &LightContext,
        test_name: &str,
        span: &Span,
    ) -> Result<Option<(Exec, Option<Box<Postprocess>>)>> {
        self.as_run().exec(context, test_name, span)
    }
}