#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum RequirementKind {
#[default]
Requirement,
Functional,
Interface,
Performance,
Physical,
DesignConstraint,
}
impl RequirementKind {
pub fn label(self) -> &'static str {
match self {
RequirementKind::Requirement => "requirement",
RequirementKind::Functional => "functionalRequirement",
RequirementKind::Interface => "interfaceRequirement",
RequirementKind::Performance => "performanceRequirement",
RequirementKind::Physical => "physicalRequirement",
RequirementKind::DesignConstraint => "designConstraint",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Risk {
Low,
Medium,
High,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerifyMethod {
Analysis,
Inspection,
Test,
Demonstration,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelationshipKind {
Contains,
Copies,
Derives,
Satisfies,
Verifies,
Refines,
Traces,
}
impl RelationshipKind {
pub fn label(self) -> &'static str {
match self {
RelationshipKind::Contains => "contains",
RelationshipKind::Copies => "copies",
RelationshipKind::Derives => "derives",
RelationshipKind::Satisfies => "satisfies",
RelationshipKind::Verifies => "verifies",
RelationshipKind::Refines => "refines",
RelationshipKind::Traces => "traces",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Requirement {
pub kind: RequirementKind,
pub name: String,
pub id: String,
pub text: String,
pub risk: Option<Risk>,
pub verify_method: Option<VerifyMethod>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
pub name: String,
pub kind: String,
pub docref: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RequirementRelationship {
pub source: String,
pub target: String,
pub kind: RelationshipKind,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct RequirementDiagram {
pub requirements: Vec<Requirement>,
pub elements: Vec<Element>,
pub relationships: Vec<RequirementRelationship>,
}
impl RequirementDiagram {
pub fn total_items(&self) -> usize {
self.requirements.len() + self.elements.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_diagram_is_empty() {
let d = RequirementDiagram::default();
assert!(d.requirements.is_empty());
assert!(d.elements.is_empty());
assert!(d.relationships.is_empty());
assert_eq!(d.total_items(), 0);
}
#[test]
fn total_items_counts_requirements_and_elements() {
let d = RequirementDiagram {
requirements: vec![
Requirement {
kind: RequirementKind::Requirement,
name: "req1".to_string(),
id: "1".to_string(),
text: "some text".to_string(),
risk: Some(Risk::High),
verify_method: Some(VerifyMethod::Test),
},
Requirement {
kind: RequirementKind::Functional,
name: "req2".to_string(),
id: "2".to_string(),
text: "other text".to_string(),
risk: None,
verify_method: None,
},
],
elements: vec![Element {
name: "elem1".to_string(),
kind: "simulation".to_string(),
docref: Some("docs/elem1".to_string()),
}],
relationships: vec![RequirementRelationship {
source: "elem1".to_string(),
target: "req1".to_string(),
kind: RelationshipKind::Satisfies,
}],
};
assert_eq!(d.total_items(), 3); assert_eq!(d.relationships.len(), 1);
}
#[test]
fn equality_holds_for_identical_diagrams() {
let a = RequirementDiagram {
requirements: vec![Requirement {
kind: RequirementKind::Performance,
name: "perf_req".to_string(),
id: "3".to_string(),
text: "perf text".to_string(),
risk: Some(Risk::Medium),
verify_method: Some(VerifyMethod::Demonstration),
}],
elements: vec![],
relationships: vec![],
};
let b = a.clone();
assert_eq!(a, b);
let c = RequirementDiagram {
requirements: vec![Requirement {
kind: RequirementKind::Interface,
name: "other".to_string(),
id: "4".to_string(),
text: "interface text".to_string(),
risk: None,
verify_method: Some(VerifyMethod::Analysis),
}],
elements: vec![],
relationships: vec![],
};
assert_ne!(a, c);
}
}