ricecoder_refactoring/patterns/
validator.rs1use crate::error::{RefactoringError, Result};
4use super::RefactoringPattern;
5
6pub struct PatternValidator;
8
9impl PatternValidator {
10 pub fn validate(pattern: &RefactoringPattern) -> Result<()> {
12 if pattern.name.is_empty() {
14 return Err(RefactoringError::InvalidConfiguration(
15 "Pattern name cannot be empty".to_string(),
16 ));
17 }
18
19 if pattern.template.is_empty() {
21 return Err(RefactoringError::InvalidConfiguration(
22 "Pattern template cannot be empty".to_string(),
23 ));
24 }
25
26 let template_placeholders = Self::extract_placeholders(&pattern.template);
28 let parameter_placeholders: std::collections::HashSet<_> =
29 pattern.parameters.iter().map(|p| p.placeholder.clone()).collect();
30
31 for placeholder in template_placeholders {
32 if !parameter_placeholders.contains(&placeholder) {
33 return Err(RefactoringError::InvalidConfiguration(format!(
34 "Template uses placeholder {} but no parameter defined",
35 placeholder
36 )));
37 }
38 }
39
40 for param in &pattern.parameters {
42 if !pattern.template.contains(¶m.placeholder) {
43 return Err(RefactoringError::InvalidConfiguration(format!(
44 "Parameter {} is defined but not used in template",
45 param.name
46 )));
47 }
48 }
49
50 Ok(())
51 }
52
53 fn extract_placeholders(template: &str) -> Vec<String> {
55 let mut placeholders = vec![];
56 let mut chars = template.chars().peekable();
57
58 while let Some(ch) = chars.next() {
59 if ch == '{' && chars.peek() == Some(&'{') {
60 chars.next(); let mut placeholder = String::from("{{");
62
63 while let Some(ch) = chars.next() {
64 placeholder.push(ch);
65 if ch == '}' && chars.peek() == Some(&'}') {
66 chars.next(); placeholder.push('}');
68 placeholders.push(placeholder);
69 break;
70 }
71 }
72 }
73 }
74
75 placeholders
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::patterns::{RefactoringPattern, PatternParameter, PatternScope};
83
84 #[test]
85 fn test_validate_valid_pattern() -> Result<()> {
86 let pattern = RefactoringPattern {
87 name: "test".to_string(),
88 description: "Test pattern".to_string(),
89 template: "fn {{old_name}}() -> fn {{new_name}}()".to_string(),
90 parameters: vec![
91 PatternParameter {
92 name: "old_name".to_string(),
93 placeholder: "{{old_name}}".to_string(),
94 description: "Old name".to_string(),
95 },
96 PatternParameter {
97 name: "new_name".to_string(),
98 placeholder: "{{new_name}}".to_string(),
99 description: "New name".to_string(),
100 },
101 ],
102 scope: PatternScope::Global,
103 };
104
105 PatternValidator::validate(&pattern)?;
106 Ok(())
107 }
108
109 #[test]
110 fn test_validate_empty_name() {
111 let pattern = RefactoringPattern {
112 name: "".to_string(),
113 description: "Test pattern".to_string(),
114 template: "template".to_string(),
115 parameters: vec![],
116 scope: PatternScope::Global,
117 };
118
119 assert!(PatternValidator::validate(&pattern).is_err());
120 }
121
122 #[test]
123 fn test_validate_empty_template() {
124 let pattern = RefactoringPattern {
125 name: "test".to_string(),
126 description: "Test pattern".to_string(),
127 template: "".to_string(),
128 parameters: vec![],
129 scope: PatternScope::Global,
130 };
131
132 assert!(PatternValidator::validate(&pattern).is_err());
133 }
134
135 #[test]
136 fn test_validate_unused_placeholder() {
137 let pattern = RefactoringPattern {
138 name: "test".to_string(),
139 description: "Test pattern".to_string(),
140 template: "fn {{old_name}}()".to_string(),
141 parameters: vec![
142 PatternParameter {
143 name: "old_name".to_string(),
144 placeholder: "{{old_name}}".to_string(),
145 description: "Old name".to_string(),
146 },
147 PatternParameter {
148 name: "new_name".to_string(),
149 placeholder: "{{new_name}}".to_string(),
150 description: "New name".to_string(),
151 },
152 ],
153 scope: PatternScope::Global,
154 };
155
156 assert!(PatternValidator::validate(&pattern).is_err());
157 }
158
159 #[test]
160 fn test_extract_placeholders() {
161 let template = "fn {{old_name}}() -> fn {{new_name}}()";
162 let placeholders = PatternValidator::extract_placeholders(template);
163
164 assert_eq!(placeholders.len(), 2);
165 assert!(placeholders.contains(&"{{old_name}}".to_string()));
166 assert!(placeholders.contains(&"{{new_name}}".to_string()));
167 }
168}