1use serde::Serialize;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum ScaffoldKind {
5 Requirement,
6 Verification,
7 Part,
8 Package,
9 UseCase,
10 Action,
11 State,
12 Interface,
13}
14
15impl std::str::FromStr for ScaffoldKind {
16 type Err = String;
17
18 fn from_str(s: &str) -> Result<Self, Self::Err> {
19 match s.to_lowercase().as_str() {
20 "requirement" | "req" => Ok(Self::Requirement),
21 "verification" | "verify" => Ok(Self::Verification),
22 "part" => Ok(Self::Part),
23 "package" | "pkg" => Ok(Self::Package),
24 "use-case" | "usecase" | "use_case" => Ok(Self::UseCase),
25 "action" => Ok(Self::Action),
26 "state" => Ok(Self::State),
27 "interface" => Ok(Self::Interface),
28 _ => Err(format!(
29 "Unknown scaffold kind: '{}'. Valid: requirement, verification, part, package, use-case, action, state, interface",
30 s
31 )),
32 }
33 }
34}
35
36#[derive(Debug, Clone, Serialize)]
37pub struct ScaffoldResult {
38 pub kind: String,
39 pub name: String,
40 pub sysml: String,
41}
42
43pub fn generate(kind: ScaffoldKind, name: &str) -> ScaffoldResult {
44 let sysml = match kind {
45 ScaffoldKind::Requirement => format!(
46 r#"requirement def {name} {{
47 doc /* TODO: describe requirement */
48
49 attribute id : String;
50 attribute text : String;
51}}"#
52 ),
53 ScaffoldKind::Verification => format!(
54 r#"verification def {name} {{
55 doc /* TODO: describe verification */
56
57 subject testSubject;
58
59 objective {{
60 doc /* TODO: verification objective */
61 }}
62}}"#
63 ),
64 ScaffoldKind::Part => format!(
65 r#"part def {name} {{
66 doc /* TODO: describe part */
67
68 attribute mass : Real;
69
70 port controlPort : ControlPort;
71}}"#
72 ),
73 ScaffoldKind::Package => format!(
74 r#"package {name} {{
75 doc /* TODO: package description */
76
77}}"#
78 ),
79 ScaffoldKind::UseCase => format!(
80 r#"use case def {name} {{
81 doc /* TODO: describe use case */
82
83 subject systemUnderTest;
84
85 objective {{
86 doc /* TODO: use case objective */
87 }}
88}}"#
89 ),
90 ScaffoldKind::Action => format!(
91 r#"action def {name} {{
92 doc /* TODO: describe action */
93
94 in item input;
95 out item output;
96}}"#
97 ),
98 ScaffoldKind::State => format!(
99 r#"state def {name} {{
100 doc /* TODO: describe state machine */
101
102 entry action entryAction;
103 exit action exitAction;
104}}"#
105 ),
106 ScaffoldKind::Interface => format!(
107 r#"interface def {name} {{
108 doc /* TODO: describe interface */
109
110 end port supplier;
111 end port consumer;
112}}"#
113 ),
114 };
115
116 ScaffoldResult {
117 kind: format!("{kind:?}"),
118 name: name.to_string(),
119 sysml,
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_scaffold_requirement() {
129 let result = generate(ScaffoldKind::Requirement, "MFRQ99");
130 assert!(result.sysml.contains("requirement def MFRQ99"));
131 assert!(result.sysml.contains("attribute id"));
132 }
133
134 #[test]
135 fn test_scaffold_part() {
136 let result = generate(ScaffoldKind::Part, "NewModule");
137 assert!(result.sysml.contains("part def NewModule"));
138 assert!(result.sysml.contains("port controlPort"));
139 }
140
141 #[test]
142 fn test_scaffold_package() {
143 let result = generate(ScaffoldKind::Package, "NewPkg");
144 assert!(result.sysml.contains("package NewPkg"));
145 }
146
147 #[test]
148 fn test_scaffold_verification() {
149 let result = generate(ScaffoldKind::Verification, "VerifyShield");
150 assert!(result.sysml.contains("verification def VerifyShield"));
151 assert!(result.sysml.contains("subject testSubject"));
152 }
153
154 #[test]
155 fn test_scaffold_use_case() {
156 let result = generate(ScaffoldKind::UseCase, "MiningOp");
157 assert!(result.sysml.contains("use case def MiningOp"));
158 }
159
160 #[test]
161 fn test_scaffold_action() {
162 let result = generate(ScaffoldKind::Action, "DetectThreat");
163 assert!(result.sysml.contains("action def DetectThreat"));
164 }
165
166 #[test]
167 fn test_scaffold_state() {
168 let result = generate(ScaffoldKind::State, "ShipStates");
169 assert!(result.sysml.contains("state def ShipStates"));
170 }
171
172 #[test]
173 fn test_scaffold_interface() {
174 let result = generate(ScaffoldKind::Interface, "PowerInterface");
175 assert!(result.sysml.contains("interface def PowerInterface"));
176 }
177
178 #[test]
179 fn test_parse_kind() {
180 assert_eq!(
181 "requirement".parse::<ScaffoldKind>().unwrap(),
182 ScaffoldKind::Requirement
183 );
184 assert_eq!(
185 "req".parse::<ScaffoldKind>().unwrap(),
186 ScaffoldKind::Requirement
187 );
188 assert_eq!(
189 "use-case".parse::<ScaffoldKind>().unwrap(),
190 ScaffoldKind::UseCase
191 );
192 assert!("invalid".parse::<ScaffoldKind>().is_err());
193 }
194
195 #[test]
196 fn test_scaffold_parseable() {
197 use nomograph_core::traits::Parser;
198 let parser = crate::parser::SysmlParser::new();
199 for kind in [
200 ScaffoldKind::Requirement,
201 ScaffoldKind::Part,
202 ScaffoldKind::Package,
203 ScaffoldKind::UseCase,
204 ScaffoldKind::Action,
205 ScaffoldKind::State,
206 ScaffoldKind::Interface,
207 ] {
208 let result = generate(kind, "TestName");
209 let parse_result = parser.parse(&result.sysml, std::path::Path::new("scaffold.sysml"));
210 assert!(
211 parse_result.is_ok(),
212 "Scaffold {:?} produced unparseable SysML: {}",
213 kind,
214 result.sysml
215 );
216 }
217 }
218}