use std::collections::BTreeMap;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::model::serde_util::{is_false, is_zero};
use crate::app_src::AppSrcSpec;
use crate::model::names::{ApplicationName, ModuleName};
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SuiteRef {
pub application: ApplicationName,
pub module: ModuleName,
pub path: PathBuf,
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SuiteInclusionReason {
TestModified { path: PathBuf },
UnitOrPropSweep {
application: ApplicationName,
triggering_modules: Vec<ModuleName>,
},
SameAppCaller {
application: ApplicationName,
module: ModuleName,
},
CrossAppCaller {
library_application: ApplicationName,
module: ModuleName,
},
ConfiguredRule {
rule_name: String,
triggering_path: PathBuf,
},
BehaviourImplementerSweep {
behaviour: ModuleName,
implementer: ModuleName,
},
}
#[derive(Debug, Clone, Default)]
pub struct PlanInput {
pub repo_root: PathBuf,
pub modified_paths: Vec<PathBuf>,
pub apps: Vec<AppSrcSpec>,
pub library_apps: Vec<ApplicationName>,
pub extra_rules: Vec<ExtraRule>,
pub implementer_index: BTreeMap<ModuleName, Vec<ModuleName>>,
pub dep_module_index: BTreeMap<String, Vec<ModuleName>>,
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SuitePlanEntry {
pub suite: SuiteRef,
pub reasons: Vec<SuiteInclusionReason>,
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UncoveredApplication {
pub application: ApplicationName,
pub modified_modules: usize,
pub discovered_suites: usize,
pub suites: Vec<ModuleName>,
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BroadImpactModule {
pub module: ModuleName,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub application: Option<ApplicationName>,
pub suite_fanout: usize,
pub total_suites: usize,
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct SuitePlan {
pub entries: Vec<SuitePlanEntry>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub uncovered: Vec<UncoveredApplication>,
#[serde(default, skip_serializing_if = "is_zero")]
pub unattributed_paths: usize,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub broad_impact: Vec<BroadImpactModule>,
}
impl SuitePlan {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn len(&self) -> usize {
self.entries.len()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExtraRule {
pub name: String,
pub trigger: ExtraRuleTrigger,
#[serde(default)]
pub include_suites: Vec<SuiteRefSpec>,
#[serde(default)]
pub include_suite_templates: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub line_match: Option<LineMatch>,
#[serde(default, skip_serializing_if = "is_false")]
pub include_suite_for_dep_modules: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LineMatch {
pub pattern: String,
#[serde(default)]
pub captures: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
#[allow(clippy::enum_variant_names)]
pub enum ExtraRuleTrigger {
PathSuffix { suffix: String },
PathContains { fragment: String },
PathRegex {
pattern: String,
#[serde(default)]
captures: Vec<String>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SuiteRefSpec {
pub application: ApplicationName,
pub module: ModuleName,
}