cli_testing_specialist/generator/
assert_cmd_generator.rs1use crate::error::Result;
2use crate::generator::test_generator_trait::TestGenerator as TestGeneratorTrait;
3use crate::types::analysis::CliAnalysis;
4use crate::types::test_case::TestCategory;
5use handlebars::Handlebars;
6use serde_json::json;
7
8pub struct AssertCmdGenerator {
29 handlebars: Handlebars<'static>,
30 cli_name: String,
31}
32
33impl AssertCmdGenerator {
34 pub fn new(analysis: &CliAnalysis) -> Result<Self> {
44 let mut handlebars = Handlebars::new();
45
46 Self::register_templates(&mut handlebars)?;
48
49 handlebars.set_strict_mode(true);
51
52 Ok(Self {
53 handlebars,
54 cli_name: analysis.binary_name.clone(),
55 })
56 }
57
58 fn register_templates(handlebars: &mut Handlebars) -> Result<()> {
60 handlebars
62 .register_template_string("basic", include_str!("../templates/assert_cmd/basic.hbs"))?;
63
64 handlebars.register_template_string(
66 "security",
67 include_str!("../templates/assert_cmd/security.hbs"),
68 )?;
69
70 handlebars
72 .register_template_string("help", include_str!("../templates/assert_cmd/help.hbs"))?;
73
74 handlebars
76 .register_template_string("path", include_str!("../templates/assert_cmd/path.hbs"))?;
77
78 handlebars.register_template_string(
80 "input_validation",
81 include_str!("../templates/assert_cmd/input_validation.hbs"),
82 )?;
83
84 handlebars.register_template_string(
86 "destructive_ops",
87 include_str!("../templates/assert_cmd/destructive_ops.hbs"),
88 )?;
89
90 handlebars.register_template_string(
92 "performance",
93 include_str!("../templates/assert_cmd/performance.hbs"),
94 )?;
95
96 handlebars.register_template_string(
98 "multi_shell",
99 include_str!("../templates/assert_cmd/multi_shell.hbs"),
100 )?;
101
102 Ok(())
103 }
104
105 pub fn sanitize_for_rust_string(input: &str) -> String {
123 input
124 .replace('\\', "\\\\") .replace('"', "\\\"") .replace('\n', "\\n") .replace('\r', "\\r") .replace('\t', "\\t") }
130}
131
132impl TestGeneratorTrait for AssertCmdGenerator {
133 fn generate(&self, analysis: &CliAnalysis, category: TestCategory) -> Result<String> {
134 let template_name = match category {
135 TestCategory::Basic => "basic",
136 TestCategory::Security => "security",
137 TestCategory::Help => "help",
138 TestCategory::Path => "path",
139 TestCategory::InputValidation => "input_validation",
140 TestCategory::DestructiveOps => "destructive_ops",
141 TestCategory::DirectoryTraversal => "security", TestCategory::Performance => "performance",
143 TestCategory::MultiShell => "multi_shell",
144 };
145
146 let data = json!({
148 "cli_name": Self::sanitize_for_rust_string(&self.cli_name),
149 "version": analysis.version.as_ref().map(|v| Self::sanitize_for_rust_string(v)),
150 "subcommands": analysis.subcommands.iter().map(|sc| {
151 json!({
152 "name": Self::sanitize_for_rust_string(&sc.name),
153 "description": sc.description.as_ref().map(|d| Self::sanitize_for_rust_string(d)),
154 })
155 }).collect::<Vec<_>>(),
156 });
157
158 let test_code = self.handlebars.render(template_name, &data)?;
160
161 Ok(test_code)
162 }
163
164 fn file_extension(&self) -> &str {
165 "rs"
166 }
167
168 fn name(&self) -> &str {
169 "assert_cmd"
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_sanitize_for_rust_string() {
179 assert_eq!(
180 AssertCmdGenerator::sanitize_for_rust_string("hello"),
181 "hello"
182 );
183 assert_eq!(
184 AssertCmdGenerator::sanitize_for_rust_string("hello\\world"),
185 "hello\\\\world"
186 );
187 assert_eq!(
188 AssertCmdGenerator::sanitize_for_rust_string("hello\"world"),
189 "hello\\\"world"
190 );
191 assert_eq!(
192 AssertCmdGenerator::sanitize_for_rust_string("hello\nworld"),
193 "hello\\nworld"
194 );
195 assert_eq!(
196 AssertCmdGenerator::sanitize_for_rust_string("test; rm -rf /"),
197 "test; rm -rf /"
198 );
199 }
200
201 #[test]
202 fn test_sanitize_complex_string() {
203 let input = "test\\path\"with\nnewline\tand\rtab";
204 let expected = "test\\\\path\\\"with\\nnewline\\tand\\rtab";
205 assert_eq!(
206 AssertCmdGenerator::sanitize_for_rust_string(input),
207 expected
208 );
209 }
210}