ricecoder_storage/markdown_config/
validation.rs1use crate::markdown_config::error::{MarkdownConfigError, MarkdownConfigResult};
4use crate::markdown_config::types::{AgentConfig, CommandConfig, ModeConfig, Parameter};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct ValidationResult {
9 pub errors: Vec<String>,
11}
12
13impl ValidationResult {
14 pub fn new() -> Self {
16 Self {
17 errors: Vec::new(),
18 }
19 }
20
21 pub fn add_error(&mut self, error: impl Into<String>) {
23 self.errors.push(error.into());
24 }
25
26 pub fn is_valid(&self) -> bool {
28 self.errors.is_empty()
29 }
30
31 pub fn error_count(&self) -> usize {
33 self.errors.len()
34 }
35
36 pub fn to_error(self) -> Option<MarkdownConfigError> {
38 if self.errors.is_empty() {
39 None
40 } else {
41 let message = self.errors.join("; ");
42 Some(MarkdownConfigError::validation_error(message))
43 }
44 }
45}
46
47impl Default for ValidationResult {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53pub fn validate_agent_config(config: &AgentConfig) -> ValidationResult {
60 let mut result = ValidationResult::new();
61
62 if config.name.is_empty() {
64 result.add_error("Agent name is required and cannot be empty");
65 }
66
67 if config.prompt.is_empty() {
68 result.add_error("Agent prompt is required and cannot be empty");
69 }
70
71 if let Some(temp) = config.temperature {
73 if !(0.0..=2.0).contains(&temp) {
74 result.add_error(format!(
75 "Agent temperature must be between 0.0 and 2.0, got {}",
76 temp
77 ));
78 }
79 }
80
81 if let Some(tokens) = config.max_tokens {
82 if tokens == 0 {
83 result.add_error("Agent max_tokens must be greater than 0");
84 }
85 }
86
87 result
88}
89
90pub fn validate_agent_config_strict(config: &AgentConfig) -> MarkdownConfigResult<()> {
92 let result = validate_agent_config(config);
93 result.to_error().map_or(Ok(()), Err)
94}
95
96pub fn validate_mode_config(config: &ModeConfig) -> ValidationResult {
103 let mut result = ValidationResult::new();
104
105 if config.name.is_empty() {
107 result.add_error("Mode name is required and cannot be empty");
108 }
109
110 if config.prompt.is_empty() {
111 result.add_error("Mode prompt is required and cannot be empty");
112 }
113
114 result
115}
116
117pub fn validate_mode_config_strict(config: &ModeConfig) -> MarkdownConfigResult<()> {
119 let result = validate_mode_config(config);
120 result.to_error().map_or(Ok(()), Err)
121}
122
123pub fn validate_command_config(config: &CommandConfig) -> ValidationResult {
130 let mut result = ValidationResult::new();
131
132 if config.name.is_empty() {
134 result.add_error("Command name is required and cannot be empty");
135 }
136
137 if config.template.is_empty() {
138 result.add_error("Command template is required and cannot be empty");
139 }
140
141 for (idx, param) in config.parameters.iter().enumerate() {
143 let param_errors = validate_parameter(param);
144 for error in param_errors.errors {
145 result.add_error(format!("Parameter[{}]: {}", idx, error));
146 }
147 }
148
149 result
150}
151
152pub fn validate_command_config_strict(config: &CommandConfig) -> MarkdownConfigResult<()> {
154 let result = validate_command_config(config);
155 result.to_error().map_or(Ok(()), Err)
156}
157
158pub fn validate_parameter(param: &Parameter) -> ValidationResult {
165 let mut result = ValidationResult::new();
166
167 if param.name.is_empty() {
169 result.add_error("Parameter name is required and cannot be empty");
170 }
171
172 result
173}
174
175pub fn validate_parameter_strict(param: &Parameter) -> MarkdownConfigResult<()> {
177 let result = validate_parameter(param);
178 result.to_error().map_or(Ok(()), Err)
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 fn create_test_agent(name: &str) -> AgentConfig {
186 AgentConfig {
187 name: name.to_string(),
188 description: Some("Test agent".to_string()),
189 prompt: "You are a helpful assistant".to_string(),
190 model: Some("gpt-4".to_string()),
191 temperature: Some(0.7),
192 max_tokens: Some(2000),
193 tools: vec![],
194 }
195 }
196
197 fn create_test_mode(name: &str) -> ModeConfig {
198 ModeConfig {
199 name: name.to_string(),
200 description: Some("Test mode".to_string()),
201 prompt: "Focus on the task".to_string(),
202 keybinding: Some("C-f".to_string()),
203 enabled: true,
204 }
205 }
206
207 fn create_test_command(name: &str) -> CommandConfig {
208 CommandConfig {
209 name: name.to_string(),
210 description: Some("Test command".to_string()),
211 template: "echo {{message}}".to_string(),
212 parameters: vec![],
213 keybinding: Some("C-t".to_string()),
214 }
215 }
216
217 #[test]
220 fn test_validation_result_new() {
221 let result = ValidationResult::new();
222 assert!(result.is_valid());
223 assert_eq!(result.error_count(), 0);
224 }
225
226 #[test]
227 fn test_validation_result_add_error() {
228 let mut result = ValidationResult::new();
229 result.add_error("Test error");
230 assert!(!result.is_valid());
231 assert_eq!(result.error_count(), 1);
232 }
233
234 #[test]
235 fn test_validation_result_multiple_errors() {
236 let mut result = ValidationResult::new();
237 result.add_error("Error 1");
238 result.add_error("Error 2");
239 result.add_error("Error 3");
240 assert!(!result.is_valid());
241 assert_eq!(result.error_count(), 3);
242 }
243
244 #[test]
245 fn test_validation_result_to_error_valid() {
246 let result = ValidationResult::new();
247 assert!(result.to_error().is_none());
248 }
249
250 #[test]
251 fn test_validation_result_to_error_invalid() {
252 let mut result = ValidationResult::new();
253 result.add_error("Test error");
254 assert!(result.to_error().is_some());
255 }
256
257 #[test]
260 fn test_validate_agent_config_valid() {
261 let agent = create_test_agent("test-agent");
262 let result = validate_agent_config(&agent);
263 assert!(result.is_valid());
264 }
265
266 #[test]
267 fn test_validate_agent_config_empty_name() {
268 let mut agent = create_test_agent("test");
269 agent.name = String::new();
270 let result = validate_agent_config(&agent);
271 assert!(!result.is_valid());
272 assert!(result.errors.iter().any(|e| e.contains("name")));
273 }
274
275 #[test]
276 fn test_validate_agent_config_empty_prompt() {
277 let mut agent = create_test_agent("test");
278 agent.prompt = String::new();
279 let result = validate_agent_config(&agent);
280 assert!(!result.is_valid());
281 assert!(result.errors.iter().any(|e| e.contains("prompt")));
282 }
283
284 #[test]
285 fn test_validate_agent_config_invalid_temperature_too_high() {
286 let mut agent = create_test_agent("test");
287 agent.temperature = Some(3.0);
288 let result = validate_agent_config(&agent);
289 assert!(!result.is_valid());
290 assert!(result.errors.iter().any(|e| e.contains("temperature")));
291 }
292
293 #[test]
294 fn test_validate_agent_config_invalid_temperature_negative() {
295 let mut agent = create_test_agent("test");
296 agent.temperature = Some(-0.5);
297 let result = validate_agent_config(&agent);
298 assert!(!result.is_valid());
299 assert!(result.errors.iter().any(|e| e.contains("temperature")));
300 }
301
302 #[test]
303 fn test_validate_agent_config_invalid_max_tokens() {
304 let mut agent = create_test_agent("test");
305 agent.max_tokens = Some(0);
306 let result = validate_agent_config(&agent);
307 assert!(!result.is_valid());
308 assert!(result.errors.iter().any(|e| e.contains("max_tokens")));
309 }
310
311 #[test]
312 fn test_validate_agent_config_multiple_errors() {
313 let mut agent = create_test_agent("test");
314 agent.name = String::new();
315 agent.prompt = String::new();
316 agent.temperature = Some(3.0);
317 let result = validate_agent_config(&agent);
318 assert!(!result.is_valid());
319 assert_eq!(result.error_count(), 3);
320 }
321
322 #[test]
323 fn test_validate_agent_config_strict_valid() {
324 let agent = create_test_agent("test");
325 assert!(validate_agent_config_strict(&agent).is_ok());
326 }
327
328 #[test]
329 fn test_validate_agent_config_strict_invalid() {
330 let mut agent = create_test_agent("test");
331 agent.name = String::new();
332 assert!(validate_agent_config_strict(&agent).is_err());
333 }
334
335 #[test]
338 fn test_validate_mode_config_valid() {
339 let mode = create_test_mode("test-mode");
340 let result = validate_mode_config(&mode);
341 assert!(result.is_valid());
342 }
343
344 #[test]
345 fn test_validate_mode_config_empty_name() {
346 let mut mode = create_test_mode("test");
347 mode.name = String::new();
348 let result = validate_mode_config(&mode);
349 assert!(!result.is_valid());
350 assert!(result.errors.iter().any(|e| e.contains("name")));
351 }
352
353 #[test]
354 fn test_validate_mode_config_empty_prompt() {
355 let mut mode = create_test_mode("test");
356 mode.prompt = String::new();
357 let result = validate_mode_config(&mode);
358 assert!(!result.is_valid());
359 assert!(result.errors.iter().any(|e| e.contains("prompt")));
360 }
361
362 #[test]
363 fn test_validate_mode_config_strict_valid() {
364 let mode = create_test_mode("test");
365 assert!(validate_mode_config_strict(&mode).is_ok());
366 }
367
368 #[test]
369 fn test_validate_mode_config_strict_invalid() {
370 let mut mode = create_test_mode("test");
371 mode.name = String::new();
372 assert!(validate_mode_config_strict(&mode).is_err());
373 }
374
375 #[test]
378 fn test_validate_command_config_valid() {
379 let command = create_test_command("test-command");
380 let result = validate_command_config(&command);
381 assert!(result.is_valid());
382 }
383
384 #[test]
385 fn test_validate_command_config_empty_name() {
386 let mut command = create_test_command("test");
387 command.name = String::new();
388 let result = validate_command_config(&command);
389 assert!(!result.is_valid());
390 assert!(result.errors.iter().any(|e| e.contains("name")));
391 }
392
393 #[test]
394 fn test_validate_command_config_empty_template() {
395 let mut command = create_test_command("test");
396 command.template = String::new();
397 let result = validate_command_config(&command);
398 assert!(!result.is_valid());
399 assert!(result.errors.iter().any(|e| e.contains("template")));
400 }
401
402 #[test]
403 fn test_validate_command_config_with_parameters() {
404 let mut command = create_test_command("test");
405 command.parameters = vec![
406 Parameter {
407 name: "param1".to_string(),
408 description: Some("First parameter".to_string()),
409 required: true,
410 default: None,
411 },
412 Parameter {
413 name: "param2".to_string(),
414 description: None,
415 required: false,
416 default: Some("default".to_string()),
417 },
418 ];
419 let result = validate_command_config(&command);
420 assert!(result.is_valid());
421 }
422
423 #[test]
424 fn test_validate_command_config_invalid_parameter() {
425 let mut command = create_test_command("test");
426 command.parameters = vec![Parameter {
427 name: String::new(),
428 description: None,
429 required: false,
430 default: None,
431 }];
432 let result = validate_command_config(&command);
433 assert!(!result.is_valid());
434 assert!(result.errors.iter().any(|e| e.contains("Parameter")));
435 }
436
437 #[test]
438 fn test_validate_command_config_strict_valid() {
439 let command = create_test_command("test");
440 assert!(validate_command_config_strict(&command).is_ok());
441 }
442
443 #[test]
444 fn test_validate_command_config_strict_invalid() {
445 let mut command = create_test_command("test");
446 command.name = String::new();
447 assert!(validate_command_config_strict(&command).is_err());
448 }
449
450 #[test]
453 fn test_validate_parameter_valid() {
454 let param = Parameter {
455 name: "test-param".to_string(),
456 description: Some("Test parameter".to_string()),
457 required: true,
458 default: None,
459 };
460 let result = validate_parameter(¶m);
461 assert!(result.is_valid());
462 }
463
464 #[test]
465 fn test_validate_parameter_empty_name() {
466 let param = Parameter {
467 name: String::new(),
468 description: None,
469 required: false,
470 default: None,
471 };
472 let result = validate_parameter(¶m);
473 assert!(!result.is_valid());
474 assert!(result.errors.iter().any(|e| e.contains("name")));
475 }
476
477 #[test]
478 fn test_validate_parameter_strict_valid() {
479 let param = Parameter {
480 name: "test".to_string(),
481 description: None,
482 required: false,
483 default: None,
484 };
485 assert!(validate_parameter_strict(¶m).is_ok());
486 }
487
488 #[test]
489 fn test_validate_parameter_strict_invalid() {
490 let param = Parameter {
491 name: String::new(),
492 description: None,
493 required: false,
494 default: None,
495 };
496 assert!(validate_parameter_strict(¶m).is_err());
497 }
498}