use std::collections::{BTreeMap, BTreeSet};
mod runner;
pub use runner::{
ConformanceCheckReport, ConformanceCheckResult, ConformanceFailure, ConformanceRunner,
conformance,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ConformanceLevel {
DeterministicTrace = 1,
ScopeResourceLifecycle = 2,
MaterializedOutput = 3,
FullRecomputeOracle = 4,
GeneratedModelSequences = 5,
PerformanceSmoke = 6,
}
impl ConformanceLevel {
pub const ALL: [Self; 6] = [
Self::DeterministicTrace,
Self::ScopeResourceLifecycle,
Self::MaterializedOutput,
Self::FullRecomputeOracle,
Self::GeneratedModelSequences,
Self::PerformanceSmoke,
];
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ConformanceReport {
supported: BTreeSet<ConformanceLevel>,
unsupported: BTreeSet<ConformanceLevel>,
unsupported_reasons: BTreeMap<ConformanceLevel, Vec<String>>,
checks: Vec<ConformanceCheckReport>,
}
impl ConformanceReport {
pub fn new() -> Self {
Self::default()
}
pub fn support(mut self, level: ConformanceLevel) -> Self {
self.unsupported.remove(&level);
self.unsupported_reasons.remove(&level);
self.supported.insert(level);
self
}
pub fn unsupported(mut self, level: ConformanceLevel) -> Self {
self.unsupported_reasons
.entry(level)
.or_default()
.push("explicitly unsupported".to_owned());
self.supported.remove(&level);
self.unsupported.insert(level);
self
}
pub fn unsupported_with_reason(
mut self,
level: ConformanceLevel,
reason: impl Into<String>,
) -> Self {
self.supported.remove(&level);
self.unsupported.insert(level);
self.unsupported_reasons
.entry(level)
.or_default()
.push(reason.into());
self
}
pub fn record_check(mut self, check: ConformanceCheckReport) -> Self {
self.checks.push(check);
self
}
pub fn supported_levels(&self) -> &BTreeSet<ConformanceLevel> {
&self.supported
}
pub fn unsupported_levels(&self) -> &BTreeSet<ConformanceLevel> {
&self.unsupported
}
pub fn unsupported_reasons(&self) -> &BTreeMap<ConformanceLevel, Vec<String>> {
&self.unsupported_reasons
}
pub fn check_results(&self) -> &[ConformanceCheckReport] {
&self.checks
}
pub fn supports(&self, level: ConformanceLevel) -> bool {
self.supported.contains(&level)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConformanceSuite {
required: BTreeSet<ConformanceLevel>,
}
impl ConformanceSuite {
pub fn new() -> Self {
Self {
required: BTreeSet::new(),
}
}
pub fn all() -> Self {
let mut suite = Self::new();
for level in ConformanceLevel::ALL {
suite = suite.require(level);
}
suite
}
pub fn require(mut self, level: ConformanceLevel) -> Self {
self.required.insert(level);
self
}
pub fn required_levels(&self) -> &BTreeSet<ConformanceLevel> {
&self.required
}
pub fn report(&self, supported: &[ConformanceLevel]) -> ConformanceReport {
let mut report = ConformanceReport::new();
let supported = supported.iter().copied().collect::<BTreeSet<_>>();
for level in &self.required {
if supported.contains(level) {
report = report.support(*level);
} else {
report = report.unsupported(*level);
}
}
report
}
pub fn runner(self) -> ConformanceRunner {
ConformanceRunner::new(self)
}
}
impl Default for ConformanceSuite {
fn default() -> Self {
Self::new()
}
}