1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct DomainAgent {
28 pub id: String,
30 pub domain: String,
32 pub capabilities: Vec<DomainCapability>,
34 pub knowledge: DomainKnowledge,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct DomainCapability {
57 pub name: String,
59 pub description: String,
61 pub technologies: Vec<String>,
63 pub patterns: Vec<Pattern>,
65}
66
67#[derive(Debug, Clone, Default, Serialize, Deserialize)]
85pub struct DomainKnowledge {
86 pub best_practices: Vec<BestPractice>,
88 pub technology_recommendations: Vec<TechRecommendation>,
90 pub patterns: Vec<Pattern>,
92 pub anti_patterns: Vec<AntiPattern>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct TechRecommendation {
117 pub technology: String,
119 pub domain: String,
121 pub use_cases: Vec<String>,
123 pub pros: Vec<String>,
125 pub cons: Vec<String>,
127 pub alternatives: Vec<String>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct BestPractice {
151 pub title: String,
153 pub description: String,
155 pub domain: String,
157 pub technologies: Vec<String>,
159 pub implementation: String,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct Pattern {
183 pub name: String,
185 pub description: String,
187 pub domain: String,
189 pub technologies: Vec<String>,
191 pub use_cases: Vec<String>,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct AntiPattern {
215 pub name: String,
217 pub description: String,
219 pub domain: String,
221 pub why_avoid: String,
223 pub better_alternative: String,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct Recommendation {
247 pub domain: String,
249 pub category: String,
251 pub content: String,
253 pub technologies: Vec<String>,
255 pub rationale: String,
257}
258
259#[derive(Debug, Clone, Default, Serialize, Deserialize)]
278pub struct SharedContext {
279 pub project_type: String,
281 pub tech_stack: Vec<String>,
283 pub constraints: Vec<String>,
285 pub cross_domain_state: HashMap<String, serde_json::Value>,
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_domain_agent_creation() {
295 let agent = DomainAgent {
296 id: "web-agent".to_string(),
297 domain: "web".to_string(),
298 capabilities: vec![],
299 knowledge: DomainKnowledge::default(),
300 };
301
302 assert_eq!(agent.id, "web-agent");
303 assert_eq!(agent.domain, "web");
304 assert!(agent.capabilities.is_empty());
305 }
306
307 #[test]
308 fn test_domain_capability_creation() {
309 let capability = DomainCapability {
310 name: "Frontend Framework Selection".to_string(),
311 description: "Recommend frontend frameworks".to_string(),
312 technologies: vec!["React".to_string(), "Vue".to_string()],
313 patterns: vec![],
314 };
315
316 assert_eq!(capability.name, "Frontend Framework Selection");
317 assert_eq!(capability.technologies.len(), 2);
318 }
319
320 #[test]
321 fn test_tech_recommendation_creation() {
322 let recommendation = TechRecommendation {
323 technology: "React".to_string(),
324 domain: "web".to_string(),
325 use_cases: vec!["SPAs".to_string()],
326 pros: vec!["Large ecosystem".to_string()],
327 cons: vec!["Steep learning curve".to_string()],
328 alternatives: vec!["Vue".to_string()],
329 };
330
331 assert_eq!(recommendation.technology, "React");
332 assert_eq!(recommendation.domain, "web");
333 assert_eq!(recommendation.use_cases.len(), 1);
334 assert_eq!(recommendation.pros.len(), 1);
335 assert_eq!(recommendation.cons.len(), 1);
336 assert_eq!(recommendation.alternatives.len(), 1);
337 }
338
339 #[test]
340 fn test_best_practice_creation() {
341 let practice = BestPractice {
342 title: "Component-Based Architecture".to_string(),
343 description: "Use component-based architecture".to_string(),
344 domain: "web".to_string(),
345 technologies: vec!["React".to_string()],
346 implementation: "Break UI into components".to_string(),
347 };
348
349 assert_eq!(practice.title, "Component-Based Architecture");
350 assert_eq!(practice.domain, "web");
351 }
352
353 #[test]
354 fn test_pattern_creation() {
355 let pattern = Pattern {
356 name: "MVC Pattern".to_string(),
357 description: "Model-View-Controller pattern".to_string(),
358 domain: "backend".to_string(),
359 technologies: vec!["Django".to_string()],
360 use_cases: vec!["Web applications".to_string()],
361 };
362
363 assert_eq!(pattern.name, "MVC Pattern");
364 assert_eq!(pattern.domain, "backend");
365 }
366
367 #[test]
368 fn test_anti_pattern_creation() {
369 let anti_pattern = AntiPattern {
370 name: "God Object".to_string(),
371 description: "A class that does too much".to_string(),
372 domain: "backend".to_string(),
373 why_avoid: "Violates SRP".to_string(),
374 better_alternative: "Break into smaller classes".to_string(),
375 };
376
377 assert_eq!(anti_pattern.name, "God Object");
378 assert_eq!(anti_pattern.domain, "backend");
379 }
380
381 #[test]
382 fn test_recommendation_creation() {
383 let recommendation = Recommendation {
384 domain: "web".to_string(),
385 category: "framework".to_string(),
386 content: "Use React".to_string(),
387 technologies: vec!["React".to_string()],
388 rationale: "Well-suited for complex UIs".to_string(),
389 };
390
391 assert_eq!(recommendation.domain, "web");
392 assert_eq!(recommendation.category, "framework");
393 }
394
395 #[test]
396 fn test_shared_context_creation() {
397 let context = SharedContext {
398 project_type: "web-application".to_string(),
399 tech_stack: vec!["React".to_string(), "Node.js".to_string()],
400 constraints: vec!["Must support IE11".to_string()],
401 cross_domain_state: HashMap::new(),
402 };
403
404 assert_eq!(context.project_type, "web-application");
405 assert_eq!(context.tech_stack.len(), 2);
406 assert_eq!(context.constraints.len(), 1);
407 }
408
409 #[test]
410 fn test_domain_knowledge_default() {
411 let knowledge = DomainKnowledge::default();
412 assert!(knowledge.best_practices.is_empty());
413 assert!(knowledge.technology_recommendations.is_empty());
414 assert!(knowledge.patterns.is_empty());
415 assert!(knowledge.anti_patterns.is_empty());
416 }
417
418 #[test]
419 fn test_shared_context_default() {
420 let context = SharedContext::default();
421 assert!(context.project_type.is_empty());
422 assert!(context.tech_stack.is_empty());
423 assert!(context.constraints.is_empty());
424 assert!(context.cross_domain_state.is_empty());
425 }
426
427 #[test]
428 fn test_domain_agent_serialization() {
429 let agent = DomainAgent {
430 id: "web-agent".to_string(),
431 domain: "web".to_string(),
432 capabilities: vec![],
433 knowledge: DomainKnowledge::default(),
434 };
435
436 let json = serde_json::to_string(&agent).expect("serialization failed");
437 let deserialized: DomainAgent =
438 serde_json::from_str(&json).expect("deserialization failed");
439
440 assert_eq!(deserialized.id, agent.id);
441 assert_eq!(deserialized.domain, agent.domain);
442 }
443
444 #[test]
445 fn test_recommendation_serialization() {
446 let recommendation = Recommendation {
447 domain: "web".to_string(),
448 category: "framework".to_string(),
449 content: "Use React".to_string(),
450 technologies: vec!["React".to_string()],
451 rationale: "Well-suited".to_string(),
452 };
453
454 let json = serde_json::to_string(&recommendation).expect("serialization failed");
455 let deserialized: Recommendation =
456 serde_json::from_str(&json).expect("deserialization failed");
457
458 assert_eq!(deserialized.domain, recommendation.domain);
459 assert_eq!(deserialized.category, recommendation.category);
460 }
461
462 #[test]
463 fn test_shared_context_with_state() {
464 let mut context = SharedContext::default();
465 context
466 .cross_domain_state
467 .insert("key".to_string(), serde_json::json!("value"));
468
469 assert_eq!(context.cross_domain_state.len(), 1);
470 assert_eq!(
471 context.cross_domain_state.get("key").unwrap(),
472 &serde_json::json!("value")
473 );
474 }
475
476 #[test]
477 fn test_tech_recommendation_multiple_alternatives() {
478 let recommendation = TechRecommendation {
479 technology: "React".to_string(),
480 domain: "web".to_string(),
481 use_cases: vec!["SPAs".to_string(), "Complex UIs".to_string()],
482 pros: vec!["Ecosystem".to_string(), "Community".to_string()],
483 cons: vec!["Learning curve".to_string()],
484 alternatives: vec!["Vue".to_string(), "Angular".to_string(), "Svelte".to_string()],
485 };
486
487 assert_eq!(recommendation.use_cases.len(), 2);
488 assert_eq!(recommendation.pros.len(), 2);
489 assert_eq!(recommendation.alternatives.len(), 3);
490 }
491
492 #[test]
493 fn test_domain_capability_with_patterns() {
494 let patterns = vec![Pattern {
495 name: "Component Pattern".to_string(),
496 description: "Component-based architecture".to_string(),
497 domain: "web".to_string(),
498 technologies: vec!["React".to_string()],
499 use_cases: vec!["UI development".to_string()],
500 }];
501
502 let capability = DomainCapability {
503 name: "Frontend Framework".to_string(),
504 description: "Frontend framework selection".to_string(),
505 technologies: vec!["React".to_string()],
506 patterns,
507 };
508
509 assert_eq!(capability.patterns.len(), 1);
510 assert_eq!(capability.patterns[0].name, "Component Pattern");
511 }
512
513 #[test]
514 fn test_domain_knowledge_with_all_fields() {
515 let knowledge = DomainKnowledge {
516 best_practices: vec![BestPractice {
517 title: "Practice".to_string(),
518 description: "Description".to_string(),
519 domain: "web".to_string(),
520 technologies: vec!["React".to_string()],
521 implementation: "Implementation".to_string(),
522 }],
523 technology_recommendations: vec![TechRecommendation {
524 technology: "React".to_string(),
525 domain: "web".to_string(),
526 use_cases: vec!["SPAs".to_string()],
527 pros: vec!["Ecosystem".to_string()],
528 cons: vec!["Learning curve".to_string()],
529 alternatives: vec!["Vue".to_string()],
530 }],
531 patterns: vec![Pattern {
532 name: "Pattern".to_string(),
533 description: "Description".to_string(),
534 domain: "web".to_string(),
535 technologies: vec!["React".to_string()],
536 use_cases: vec!["UI".to_string()],
537 }],
538 anti_patterns: vec![AntiPattern {
539 name: "Anti-pattern".to_string(),
540 description: "Description".to_string(),
541 domain: "web".to_string(),
542 why_avoid: "Reason".to_string(),
543 better_alternative: "Alternative".to_string(),
544 }],
545 };
546
547 assert_eq!(knowledge.best_practices.len(), 1);
548 assert_eq!(knowledge.technology_recommendations.len(), 1);
549 assert_eq!(knowledge.patterns.len(), 1);
550 assert_eq!(knowledge.anti_patterns.len(), 1);
551 }
552}