1#[cfg(test)]
7mod tests {
8 use crate::domain::{KnowledgeBase, AgentFactory};
9 use crate::domain::factory::{
10 AgentConfig, CapabilityConfig, BestPracticeConfig, TechRecommendationConfig,
11 PatternConfig, AntiPatternConfig,
12 };
13
14 fn create_agent_config_with_knowledge(
16 domain: &str,
17 name: &str,
18 capabilities: Vec<(&str, Vec<&str>)>,
19 tech_recommendations: Vec<(&str, Vec<&str>)>,
20 best_practices: Vec<(&str, Vec<&str>)>,
21 patterns: Vec<(&str, Vec<&str>)>,
22 anti_patterns: Vec<(&str, &str)>,
23 ) -> AgentConfig {
24 AgentConfig {
25 domain: domain.to_string(),
26 name: name.to_string(),
27 description: format!("Agent for {} development", domain),
28 capabilities: capabilities
29 .into_iter()
30 .map(|(cap_name, techs)| CapabilityConfig {
31 name: cap_name.to_string(),
32 description: format!("Capability: {}", cap_name),
33 technologies: techs.into_iter().map(|t| t.to_string()).collect(),
34 })
35 .collect(),
36 best_practices: best_practices
37 .into_iter()
38 .map(|(title, techs)| BestPracticeConfig {
39 title: title.to_string(),
40 description: format!("Best practice: {}", title),
41 technologies: techs.into_iter().map(|t| t.to_string()).collect(),
42 implementation: "Implementation guidance".to_string(),
43 })
44 .collect(),
45 technology_recommendations: tech_recommendations
46 .into_iter()
47 .map(|(tech, use_cases)| TechRecommendationConfig {
48 technology: tech.to_string(),
49 use_cases: use_cases.into_iter().map(|u| u.to_string()).collect(),
50 pros: vec!["Pro 1".to_string()],
51 cons: vec!["Con 1".to_string()],
52 alternatives: vec![],
53 })
54 .collect(),
55 patterns: patterns
56 .into_iter()
57 .map(|(name, techs)| PatternConfig {
58 name: name.to_string(),
59 description: format!("Pattern: {}", name),
60 technologies: techs.into_iter().map(|t| t.to_string()).collect(),
61 use_cases: vec!["Use case 1".to_string()],
62 })
63 .collect(),
64 anti_patterns: anti_patterns
65 .into_iter()
66 .map(|(name, reason)| AntiPatternConfig {
67 name: name.to_string(),
68 description: format!("Anti-pattern: {}", name),
69 why_avoid: reason.to_string(),
70 better_alternative: "Better approach".to_string(),
71 })
72 .collect(),
73 }
74 }
75
76 #[test]
87 fn property_knowledge_relevance_web_domain() {
88 let factory = AgentFactory::new();
89 let kb = KnowledgeBase::new();
90
91 let web_config = create_agent_config_with_knowledge(
93 "web",
94 "Web Development Agent",
95 vec![
96 ("Frontend Framework Selection", vec!["React", "Vue", "Angular"]),
97 ("Styling Guidance", vec!["CSS", "Tailwind CSS", "styled-components"]),
98 ("Build Configuration", vec!["Vite", "Webpack"]),
99 ("Testing Strategy", vec!["Jest", "Vitest", "Playwright"]),
100 ],
101 vec![
102 ("React", vec!["Single Page Applications", "Complex UIs"]),
103 ("Vue", vec!["Progressive enhancement", "Rapid prototyping"]),
104 ("Angular", vec!["Enterprise applications"]),
105 ("Vite", vec!["Modern web development"]),
106 ("Webpack", vec!["Complex bundling scenarios"]),
107 ("Jest", vec!["JavaScript testing"]),
108 ("Vitest", vec!["Vite projects"]),
109 ("Playwright", vec!["E2E testing"]),
110 ],
111 vec![
112 ("Component-Based Architecture", vec!["React", "Vue"]),
113 ("Performance Optimization", vec!["React", "Vue", "Angular"]),
114 ],
115 vec![
116 ("MVC Pattern", vec!["React", "Vue"]),
117 ("Singleton Pattern", vec!["JavaScript"]),
118 ],
119 vec![
120 ("God Component", "Component that does too much"),
121 ("Tight Coupling", "Components tightly coupled"),
122 ],
123 );
124
125 let web_agent = factory.create_agent("web", &web_config).unwrap();
127
128 for practice in &web_agent.knowledge.best_practices {
130 kb.add_best_practice("web", practice.clone()).unwrap();
131 }
132
133 for recommendation in &web_agent.knowledge.technology_recommendations {
134 kb.add_tech_recommendation("web", recommendation.clone()).unwrap();
135 }
136
137 for pattern in &web_agent.knowledge.patterns {
138 kb.add_pattern("web", pattern.clone()).unwrap();
139 }
140
141 for anti_pattern in &web_agent.knowledge.anti_patterns {
142 kb.add_anti_pattern("web", anti_pattern.clone()).unwrap();
143 }
144
145 let practices = kb.get_best_practices("web").unwrap();
147 assert!(!practices.is_empty());
148 for practice in &practices {
149 assert_eq!(practice.domain, "web");
150 for tech in &practice.technologies {
152 assert!(
153 vec!["React", "Vue", "Angular", "CSS", "Tailwind CSS", "styled-components"]
154 .contains(&tech.as_str()),
155 "Technology {} is not web-related",
156 tech
157 );
158 }
159 }
160
161 let tech_recs = kb.get_tech_recommendations("web").unwrap();
163 assert!(!tech_recs.is_empty());
164 for rec in &tech_recs {
165 assert_eq!(rec.domain, "web");
166 assert!(
168 vec!["React", "Vue", "Angular", "Vite", "Webpack", "Jest", "Vitest", "Playwright"]
169 .contains(&rec.technology.as_str()),
170 "Technology {} is not web-related",
171 rec.technology
172 );
173 assert!(!rec.use_cases.is_empty());
175 assert!(!rec.pros.is_empty());
177 assert!(!rec.cons.is_empty());
178 }
179
180 let patterns = kb.get_patterns("web").unwrap();
182 assert!(!patterns.is_empty());
183 for pattern in &patterns {
184 assert_eq!(pattern.domain, "web");
185 for tech in &pattern.technologies {
187 assert!(
188 vec!["React", "Vue", "Angular", "JavaScript"]
189 .contains(&tech.as_str()),
190 "Technology {} is not web-related",
191 tech
192 );
193 }
194 }
195
196 let anti_patterns = kb.get_anti_patterns("web").unwrap();
198 assert!(!anti_patterns.is_empty());
199 for anti_pattern in &anti_patterns {
200 assert_eq!(anti_pattern.domain, "web");
201 assert!(!anti_pattern.why_avoid.is_empty());
203 assert!(!anti_pattern.better_alternative.is_empty());
205 }
206
207 let tech_names: Vec<_> = tech_recs.iter().map(|t| &t.technology).collect();
209 assert!(tech_names.contains(&&"React".to_string()));
210 assert!(tech_names.contains(&&"Vue".to_string()));
211 assert!(tech_names.contains(&&"Vite".to_string()));
212 assert!(tech_names.contains(&&"Jest".to_string()));
213 }
214
215 #[test]
226 fn property_knowledge_relevance_backend_domain() {
227 let factory = AgentFactory::new();
228 let kb = KnowledgeBase::new();
229
230 let backend_config = create_agent_config_with_knowledge(
232 "backend",
233 "Backend Development Agent",
234 vec![
235 ("API Design", vec!["REST", "GraphQL", "gRPC"]),
236 ("Architecture Guidance", vec!["Microservices", "Monolithic", "Serverless"]),
237 ("Database Design", vec!["PostgreSQL", "MongoDB", "Neo4j"]),
238 ("Scalability", vec!["Redis", "Memcached", "Load Balancers"]),
239 ("Security", vec!["OAuth 2.0", "JWT", "TLS"]),
240 ("Observability", vec!["ELK Stack", "Prometheus", "Jaeger"]),
241 ],
242 vec![
243 ("REST", vec!["Web APIs", "Microservices"]),
244 ("GraphQL", vec!["Flexible APIs", "Real-time data"]),
245 ("gRPC", vec!["High-performance APIs"]),
246 ("PostgreSQL", vec!["Relational data", "ACID transactions"]),
247 ("MongoDB", vec!["Document storage", "Flexible schema"]),
248 ("Redis", vec!["Caching", "Session storage"]),
249 ("OAuth 2.0", vec!["Authentication"]),
250 ("JWT", vec!["Token-based auth"]),
251 ],
252 vec![
253 ("API Versioning", vec!["REST", "GraphQL"]),
254 ("Database Indexing", vec!["PostgreSQL", "MongoDB"]),
255 ],
256 vec![
257 ("MVC Pattern", vec!["Django", "Rails"]),
258 ("Repository Pattern", vec!["Java", "C#"]),
259 ],
260 vec![
261 ("God Object", "Class that does too much"),
262 ("Tight Coupling", "Services tightly coupled"),
263 ],
264 );
265
266 let backend_agent = factory.create_agent("backend", &backend_config).unwrap();
268
269 for practice in &backend_agent.knowledge.best_practices {
271 kb.add_best_practice("backend", practice.clone()).unwrap();
272 }
273
274 for recommendation in &backend_agent.knowledge.technology_recommendations {
275 kb.add_tech_recommendation("backend", recommendation.clone()).unwrap();
276 }
277
278 for pattern in &backend_agent.knowledge.patterns {
279 kb.add_pattern("backend", pattern.clone()).unwrap();
280 }
281
282 for anti_pattern in &backend_agent.knowledge.anti_patterns {
283 kb.add_anti_pattern("backend", anti_pattern.clone()).unwrap();
284 }
285
286 let practices = kb.get_best_practices("backend").unwrap();
288 assert!(!practices.is_empty());
289 for practice in &practices {
290 assert_eq!(practice.domain, "backend");
291 for tech in &practice.technologies {
293 assert!(
294 vec!["REST", "GraphQL", "PostgreSQL", "MongoDB"]
295 .contains(&tech.as_str()),
296 "Technology {} is not backend-related",
297 tech
298 );
299 }
300 }
301
302 let tech_recs = kb.get_tech_recommendations("backend").unwrap();
304 assert!(!tech_recs.is_empty());
305 for rec in &tech_recs {
306 assert_eq!(rec.domain, "backend");
307 assert!(
309 vec!["REST", "GraphQL", "gRPC", "PostgreSQL", "MongoDB", "Redis", "OAuth 2.0", "JWT"]
310 .contains(&rec.technology.as_str()),
311 "Technology {} is not backend-related",
312 rec.technology
313 );
314 assert!(!rec.use_cases.is_empty());
316 assert!(!rec.pros.is_empty());
318 assert!(!rec.cons.is_empty());
319 }
320
321 let patterns = kb.get_patterns("backend").unwrap();
323 assert!(!patterns.is_empty());
324 for pattern in &patterns {
325 assert_eq!(pattern.domain, "backend");
326 for tech in &pattern.technologies {
328 assert!(
329 vec!["Django", "Rails", "Java", "C#"]
330 .contains(&tech.as_str()),
331 "Technology {} is not backend-related",
332 tech
333 );
334 }
335 }
336
337 let anti_patterns = kb.get_anti_patterns("backend").unwrap();
339 assert!(!anti_patterns.is_empty());
340 for anti_pattern in &anti_patterns {
341 assert_eq!(anti_pattern.domain, "backend");
342 assert!(!anti_pattern.why_avoid.is_empty());
344 assert!(!anti_pattern.better_alternative.is_empty());
346 }
347
348 let tech_names: Vec<_> = tech_recs.iter().map(|t| &t.technology).collect();
350 assert!(tech_names.contains(&&"REST".to_string()));
351 assert!(tech_names.contains(&&"GraphQL".to_string()));
352 assert!(tech_names.contains(&&"PostgreSQL".to_string()));
353 assert!(tech_names.contains(&&"MongoDB".to_string()));
354 }
355
356 #[test]
368 fn property_knowledge_relevance_devops_domain() {
369 let factory = AgentFactory::new();
370 let kb = KnowledgeBase::new();
371
372 let devops_config = create_agent_config_with_knowledge(
374 "devops",
375 "DevOps Agent",
376 vec![
377 ("CI/CD Pipeline Setup", vec!["GitHub Actions", "GitLab CI", "Jenkins"]),
378 ("Infrastructure as Code", vec!["Terraform", "CloudFormation", "Ansible"]),
379 ("Containerization", vec!["Docker", "Kubernetes"]),
380 ("Observability Infrastructure", vec!["Prometheus", "Grafana", "ELK Stack"]),
381 ("Security Scanning", vec!["Trivy", "Snyk", "SonarQube"]),
382 ("Auto-Scaling", vec!["Kubernetes", "AWS Auto Scaling", "Docker Swarm"]),
383 ],
384 vec![
385 ("GitHub Actions", vec!["CI/CD pipelines"]),
386 ("GitLab CI", vec!["CI/CD pipelines"]),
387 ("Jenkins", vec!["CI/CD pipelines"]),
388 ("Terraform", vec!["Infrastructure as Code"]),
389 ("CloudFormation", vec!["Infrastructure as Code"]),
390 ("Ansible", vec!["Infrastructure as Code"]),
391 ("Docker", vec!["Containerization"]),
392 ("Kubernetes", vec!["Container orchestration"]),
393 ("Prometheus", vec!["Monitoring"]),
394 ("Grafana", vec!["Visualization"]),
395 ],
396 vec![
397 ("Infrastructure as Code", vec!["Terraform", "CloudFormation"]),
398 ("Monitoring and Alerting", vec!["Prometheus", "Grafana"]),
399 ],
400 vec![
401 ("Blue-Green Deployment", vec!["Kubernetes", "Docker"]),
402 ("Canary Deployment", vec!["Kubernetes"]),
403 ],
404 vec![
405 ("Manual Infrastructure", "Infrastructure managed manually"),
406 ("No Monitoring", "No monitoring or alerting"),
407 ],
408 );
409
410 let devops_agent = factory.create_agent("devops", &devops_config).unwrap();
412
413 for practice in &devops_agent.knowledge.best_practices {
415 kb.add_best_practice("devops", practice.clone()).unwrap();
416 }
417
418 for recommendation in &devops_agent.knowledge.technology_recommendations {
419 kb.add_tech_recommendation("devops", recommendation.clone()).unwrap();
420 }
421
422 for pattern in &devops_agent.knowledge.patterns {
423 kb.add_pattern("devops", pattern.clone()).unwrap();
424 }
425
426 for anti_pattern in &devops_agent.knowledge.anti_patterns {
427 kb.add_anti_pattern("devops", anti_pattern.clone()).unwrap();
428 }
429
430 let practices = kb.get_best_practices("devops").unwrap();
432 assert!(!practices.is_empty());
433 for practice in &practices {
434 assert_eq!(practice.domain, "devops");
435 for tech in &practice.technologies {
437 assert!(
438 vec!["Terraform", "CloudFormation", "Prometheus", "Grafana"]
439 .contains(&tech.as_str()),
440 "Technology {} is not DevOps-related",
441 tech
442 );
443 }
444 }
445
446 let tech_recs = kb.get_tech_recommendations("devops").unwrap();
448 assert!(!tech_recs.is_empty());
449 for rec in &tech_recs {
450 assert_eq!(rec.domain, "devops");
451 assert!(
453 vec!["GitHub Actions", "GitLab CI", "Jenkins", "Terraform", "CloudFormation", "Ansible", "Docker", "Kubernetes", "Prometheus", "Grafana"]
454 .contains(&rec.technology.as_str()),
455 "Technology {} is not DevOps-related",
456 rec.technology
457 );
458 assert!(!rec.use_cases.is_empty());
460 assert!(!rec.pros.is_empty());
462 assert!(!rec.cons.is_empty());
463 }
464
465 let patterns = kb.get_patterns("devops").unwrap();
467 assert!(!patterns.is_empty());
468 for pattern in &patterns {
469 assert_eq!(pattern.domain, "devops");
470 for tech in &pattern.technologies {
472 assert!(
473 vec!["Kubernetes", "Docker"]
474 .contains(&tech.as_str()),
475 "Technology {} is not DevOps-related",
476 tech
477 );
478 }
479 }
480
481 let anti_patterns = kb.get_anti_patterns("devops").unwrap();
483 assert!(!anti_patterns.is_empty());
484 for anti_pattern in &anti_patterns {
485 assert_eq!(anti_pattern.domain, "devops");
486 assert!(!anti_pattern.why_avoid.is_empty());
488 assert!(!anti_pattern.better_alternative.is_empty());
490 }
491
492 let tech_names: Vec<_> = tech_recs.iter().map(|t| &t.technology).collect();
494 assert!(tech_names.contains(&&"GitHub Actions".to_string()));
495 assert!(tech_names.contains(&&"Terraform".to_string()));
496 assert!(tech_names.contains(&&"Docker".to_string()));
497 assert!(tech_names.contains(&&"Kubernetes".to_string()));
498 }
499
500 #[test]
504 fn property_knowledge_retrieval_accuracy() {
505 let factory = AgentFactory::new();
506 let kb = KnowledgeBase::new();
507
508 let domains = vec!["web", "backend", "devops"];
510
511 for domain in &domains {
512 let config = create_agent_config_with_knowledge(
513 domain,
514 &format!("{} Agent", domain),
515 vec![("Capability", vec!["Tech"])],
516 vec![("Tech", vec!["Use case"])],
517 vec![("Practice", vec!["Tech"])],
518 vec![("Pattern", vec!["Tech"])],
519 vec![("Anti-pattern", "Reason")],
520 );
521
522 let agent = factory.create_agent(domain, &config).unwrap();
523
524 for practice in &agent.knowledge.best_practices {
525 kb.add_best_practice(domain, practice.clone()).unwrap();
526 }
527
528 for recommendation in &agent.knowledge.technology_recommendations {
529 kb.add_tech_recommendation(domain, recommendation.clone()).unwrap();
530 }
531
532 for pattern in &agent.knowledge.patterns {
533 kb.add_pattern(domain, pattern.clone()).unwrap();
534 }
535
536 for anti_pattern in &agent.knowledge.anti_patterns {
537 kb.add_anti_pattern(domain, anti_pattern.clone()).unwrap();
538 }
539 }
540
541 for domain in &domains {
543 let practices = kb.get_best_practices(domain).unwrap();
544 for practice in &practices {
545 assert_eq!(practice.domain, *domain);
546 }
547
548 let tech_recs = kb.get_tech_recommendations(domain).unwrap();
549 for rec in &tech_recs {
550 assert_eq!(rec.domain, *domain);
551 }
552
553 let patterns = kb.get_patterns(domain).unwrap();
554 for pattern in &patterns {
555 assert_eq!(pattern.domain, *domain);
556 }
557
558 let anti_patterns = kb.get_anti_patterns(domain).unwrap();
559 for anti_pattern in &anti_patterns {
560 assert_eq!(anti_pattern.domain, *domain);
561 }
562 }
563 }
564
565 #[test]
568 fn property_technology_recommendation_completeness() {
569 let factory = AgentFactory::new();
570 let kb = KnowledgeBase::new();
571
572 let config = create_agent_config_with_knowledge(
574 "web",
575 "Web Agent",
576 vec![("Framework", vec!["React", "Vue"])],
577 vec![
578 ("React", vec!["SPAs", "Complex UIs"]),
579 ("Vue", vec!["Progressive enhancement"]),
580 ],
581 vec![],
582 vec![],
583 vec![],
584 );
585
586 let agent = factory.create_agent("web", &config).unwrap();
587
588 for recommendation in &agent.knowledge.technology_recommendations {
589 kb.add_tech_recommendation("web", recommendation.clone()).unwrap();
590 }
591
592 let tech_recs = kb.get_tech_recommendations("web").unwrap();
594 for rec in &tech_recs {
595 assert!(!rec.use_cases.is_empty(), "Technology {} has no use cases", rec.technology);
597 assert!(!rec.pros.is_empty(), "Technology {} has no pros", rec.technology);
599 assert!(!rec.cons.is_empty(), "Technology {} has no cons", rec.technology);
601 }
602 }
603
604 #[test]
607 fn property_best_practice_applicability() {
608 let factory = AgentFactory::new();
609 let kb = KnowledgeBase::new();
610
611 let config = create_agent_config_with_knowledge(
613 "web",
614 "Web Agent",
615 vec![("Framework", vec!["React"])],
616 vec![],
617 vec![
618 ("Component-Based Architecture", vec!["React", "Vue"]),
619 ("Performance Optimization", vec!["React"]),
620 ],
621 vec![],
622 vec![],
623 );
624
625 let agent = factory.create_agent("web", &config).unwrap();
626
627 for practice in &agent.knowledge.best_practices {
628 kb.add_best_practice("web", practice.clone()).unwrap();
629 }
630
631 let practices = kb.get_best_practices("web").unwrap();
633 for practice in &practices {
634 assert!(
635 !practice.technologies.is_empty(),
636 "Best practice {} has no applicable technologies",
637 practice.title
638 );
639 }
640 }
641
642 #[test]
645 fn property_anti_pattern_guidance() {
646 let factory = AgentFactory::new();
647 let kb = KnowledgeBase::new();
648
649 let config = create_agent_config_with_knowledge(
651 "web",
652 "Web Agent",
653 vec![("Framework", vec!["React"])],
654 vec![],
655 vec![],
656 vec![],
657 vec![
658 ("God Component", "Component does too much"),
659 ("Tight Coupling", "Components are tightly coupled"),
660 ],
661 );
662
663 let agent = factory.create_agent("web", &config).unwrap();
664
665 for anti_pattern in &agent.knowledge.anti_patterns {
666 kb.add_anti_pattern("web", anti_pattern.clone()).unwrap();
667 }
668
669 let anti_patterns = kb.get_anti_patterns("web").unwrap();
671 for anti_pattern in &anti_patterns {
672 assert!(
673 !anti_pattern.why_avoid.is_empty(),
674 "Anti-pattern {} has no guidance on why to avoid it",
675 anti_pattern.name
676 );
677 assert!(
678 !anti_pattern.better_alternative.is_empty(),
679 "Anti-pattern {} has no better alternative",
680 anti_pattern.name
681 );
682 }
683 }
684}