1#![allow(dead_code)]
2use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum StackLayer {
15 Primitives,
17 MlAlgorithms,
19 MlPipeline,
21 Transpilers,
23 Orchestration,
25 Quality,
27 Data,
29}
30
31impl StackLayer {
32 pub fn index(&self) -> u8 {
34 match self {
35 StackLayer::Primitives => 0,
36 StackLayer::MlAlgorithms => 1,
37 StackLayer::MlPipeline => 2,
38 StackLayer::Transpilers => 3,
39 StackLayer::Orchestration => 4,
40 StackLayer::Quality => 5,
41 StackLayer::Data => 6,
42 }
43 }
44
45 pub fn all() -> Vec<StackLayer> {
47 vec![
48 StackLayer::Primitives,
49 StackLayer::MlAlgorithms,
50 StackLayer::MlPipeline,
51 StackLayer::Transpilers,
52 StackLayer::Orchestration,
53 StackLayer::Quality,
54 StackLayer::Data,
55 ]
56 }
57}
58
59impl std::fmt::Display for StackLayer {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 match self {
62 StackLayer::Primitives => write!(f, "Compute Primitives"),
63 StackLayer::MlAlgorithms => write!(f, "ML Algorithms"),
64 StackLayer::MlPipeline => write!(f, "Training & Inference"),
65 StackLayer::Transpilers => write!(f, "Transpilers"),
66 StackLayer::Orchestration => write!(f, "Orchestration"),
67 StackLayer::Quality => write!(f, "Quality & Profiling"),
68 StackLayer::Data => write!(f, "Data Loading"),
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
79pub enum CapabilityCategory {
80 Compute,
81 Storage,
82 MachineLearning,
83 Transpilation,
84 Validation,
85 Profiling,
86 Distribution,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
91pub struct Capability {
92 pub name: String,
93 pub category: CapabilityCategory,
94 pub description: Option<String>,
95}
96
97impl Capability {
98 pub fn new(name: impl Into<String>, category: CapabilityCategory) -> Self {
99 Self {
100 name: name.into(),
101 category,
102 description: None,
103 }
104 }
105
106 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
107 self.description = Some(desc.into());
108 self
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct StackComponent {
119 pub name: String,
121 pub version: String,
123 pub layer: StackLayer,
125 pub description: String,
127 pub capabilities: Vec<Capability>,
129 pub crate_name: Option<String>,
131 pub references: Vec<Citation>,
133}
134
135impl StackComponent {
136 pub fn new(
137 name: impl Into<String>,
138 version: impl Into<String>,
139 layer: StackLayer,
140 description: impl Into<String>,
141 ) -> Self {
142 Self {
143 name: name.into(),
144 version: version.into(),
145 layer,
146 description: description.into(),
147 capabilities: Vec::new(),
148 crate_name: None,
149 references: Vec::new(),
150 }
151 }
152
153 pub fn with_capability(mut self, cap: Capability) -> Self {
154 self.capabilities.push(cap);
155 self
156 }
157
158 pub fn with_capabilities(mut self, caps: Vec<Capability>) -> Self {
159 self.capabilities.extend(caps);
160 self
161 }
162
163 pub fn has_capability(&self, name: &str) -> bool {
164 self.capabilities.iter().any(|c| c.name == name)
165 }
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct Citation {
171 pub id: u32,
172 pub authors: String,
173 pub year: u16,
174 pub title: String,
175 pub venue: Option<String>,
176}
177
178#[derive(Debug, Clone, Default, Serialize, Deserialize)]
184pub struct HardwareSpec {
185 pub has_gpu: bool,
186 pub gpu_memory_gb: Option<f32>,
187 pub cpu_cores: Option<u32>,
188 pub ram_gb: Option<f32>,
189 pub is_distributed: bool,
190 pub node_count: Option<u32>,
191}
192
193impl HardwareSpec {
194 pub fn cpu_only() -> Self {
195 Self {
196 has_gpu: false,
197 ..Default::default()
198 }
199 }
200
201 pub fn with_gpu(memory_gb: f32) -> Self {
202 Self {
203 has_gpu: true,
204 gpu_memory_gb: Some(memory_gb),
205 ..Default::default()
206 }
207 }
208
209 pub fn has_gpu(&self) -> bool {
210 self.has_gpu
211 }
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
216pub enum DataSize {
217 Samples(u64),
219 Bytes(u64),
221 Unknown,
223}
224
225impl DataSize {
226 pub fn samples(n: u64) -> Self {
227 DataSize::Samples(n)
228 }
229
230 pub fn bytes(n: u64) -> Self {
231 DataSize::Bytes(n)
232 }
233
234 pub fn as_samples(&self) -> Option<u64> {
236 match self {
237 DataSize::Samples(n) => Some(*n),
238 _ => None,
239 }
240 }
241
242 pub fn is_large(&self) -> bool {
244 match self {
245 DataSize::Samples(n) => *n > 100_000,
246 DataSize::Bytes(n) => *n > 1_000_000_000,
247 DataSize::Unknown => false,
248 }
249 }
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
254pub enum OptimizationTarget {
255 #[default]
257 Speed,
258 Memory,
260 Power,
262 Balanced,
264}
265
266#[derive(Debug, Clone, Default, Serialize, Deserialize)]
268pub struct QueryConstraints {
269 pub max_latency_ms: Option<u64>,
271 pub data_size: Option<DataSize>,
273 pub sovereign_only: bool,
275 pub eu_compliant: bool,
277 pub hardware: HardwareSpec,
279}
280
281#[derive(Debug, Clone, Default, Serialize, Deserialize)]
283pub struct QueryPreferences {
284 pub optimize_for: OptimizationTarget,
286 pub simplicity_weight: f32,
288 pub existing_components: Vec<String>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct OracleQuery {
295 pub description: String,
297 pub constraints: QueryConstraints,
299 pub preferences: QueryPreferences,
301}
302
303impl OracleQuery {
304 pub fn new(description: impl Into<String>) -> Self {
305 Self {
306 description: description.into(),
307 constraints: QueryConstraints::default(),
308 preferences: QueryPreferences::default(),
309 }
310 }
311
312 pub fn with_constraints(mut self, constraints: QueryConstraints) -> Self {
313 self.constraints = constraints;
314 self
315 }
316
317 pub fn with_preferences(mut self, preferences: QueryPreferences) -> Self {
318 self.preferences = preferences;
319 self
320 }
321
322 pub fn with_data_size(mut self, size: DataSize) -> Self {
323 self.constraints.data_size = Some(size);
324 self
325 }
326
327 pub fn with_hardware(mut self, hardware: HardwareSpec) -> Self {
328 self.constraints.hardware = hardware;
329 self
330 }
331
332 pub fn sovereign_only(mut self) -> Self {
333 self.constraints.sovereign_only = true;
334 self
335 }
336
337 pub fn eu_compliant(mut self) -> Self {
338 self.constraints.eu_compliant = true;
339 self
340 }
341}
342
343#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
349#[allow(clippy::upper_case_acronyms)]
350pub enum Backend {
351 Scalar,
352 SIMD,
353 GPU,
354 Distributed,
355}
356
357impl std::fmt::Display for Backend {
358 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
359 match self {
360 Backend::Scalar => write!(f, "Scalar"),
361 Backend::SIMD => write!(f, "SIMD"),
362 Backend::GPU => write!(f, "GPU"),
363 Backend::Distributed => write!(f, "Distributed"),
364 }
365 }
366}
367
368#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
370pub enum OpComplexity {
371 Low,
373 Medium,
375 High,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct ComputeRecommendation {
382 pub backend: Backend,
383 pub rationale: String,
384}
385
386#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct DistributionRecommendation {
389 pub tool: Option<String>,
390 pub needed: bool,
391 pub rationale: String,
392 pub node_count: Option<u32>,
393}
394
395#[derive(Debug, Clone, Serialize, Deserialize)]
397pub struct ComponentRecommendation {
398 pub component: String,
400 pub path: Option<String>,
402 pub confidence: f32,
404 pub rationale: String,
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize)]
410pub struct OracleResponse {
411 pub problem_class: String,
413 pub algorithm: Option<String>,
415 pub primary: ComponentRecommendation,
417 pub supporting: Vec<ComponentRecommendation>,
419 pub compute: ComputeRecommendation,
421 pub distribution: DistributionRecommendation,
423 pub code_example: Option<String>,
425 pub related_queries: Vec<String>,
427}
428
429impl OracleResponse {
430 pub fn new(problem_class: impl Into<String>, primary: ComponentRecommendation) -> Self {
431 Self {
432 problem_class: problem_class.into(),
433 algorithm: None,
434 primary,
435 supporting: Vec::new(),
436 compute: ComputeRecommendation {
437 backend: Backend::SIMD,
438 rationale: "Default SIMD backend".into(),
439 },
440 distribution: DistributionRecommendation {
441 tool: None,
442 needed: false,
443 rationale: "Single-node sufficient".into(),
444 node_count: None,
445 },
446 code_example: None,
447 related_queries: Vec::new(),
448 }
449 }
450
451 pub fn with_algorithm(mut self, algo: impl Into<String>) -> Self {
452 self.algorithm = Some(algo.into());
453 self
454 }
455
456 pub fn with_supporting(mut self, rec: ComponentRecommendation) -> Self {
457 self.supporting.push(rec);
458 self
459 }
460
461 pub fn with_compute(mut self, compute: ComputeRecommendation) -> Self {
462 self.compute = compute;
463 self
464 }
465
466 pub fn with_distribution(mut self, dist: DistributionRecommendation) -> Self {
467 self.distribution = dist;
468 self
469 }
470
471 pub fn with_code_example(mut self, code: impl Into<String>) -> Self {
472 self.code_example = Some(code.into());
473 self
474 }
475}
476
477#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
483pub enum ProblemDomain {
484 SupervisedLearning,
486 UnsupervisedLearning,
487 DeepLearning,
488 Inference,
489 LinearAlgebra,
491 VectorSearch,
492 GraphAnalytics,
493 PythonMigration,
495 CMigration,
496 ShellMigration,
497 DistributedCompute,
499 DataPipeline,
500 ModelServing,
501 Testing,
503 Profiling,
504 Validation,
505}
506
507impl std::fmt::Display for ProblemDomain {
508 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
509 match self {
510 ProblemDomain::SupervisedLearning => write!(f, "Supervised Learning"),
511 ProblemDomain::UnsupervisedLearning => write!(f, "Unsupervised Learning"),
512 ProblemDomain::DeepLearning => write!(f, "Deep Learning"),
513 ProblemDomain::Inference => write!(f, "Model Inference"),
514 ProblemDomain::LinearAlgebra => write!(f, "Linear Algebra"),
515 ProblemDomain::VectorSearch => write!(f, "Vector Search"),
516 ProblemDomain::GraphAnalytics => write!(f, "Graph Analytics"),
517 ProblemDomain::PythonMigration => write!(f, "Python Migration"),
518 ProblemDomain::CMigration => write!(f, "C/C++ Migration"),
519 ProblemDomain::ShellMigration => write!(f, "Shell Migration"),
520 ProblemDomain::DistributedCompute => write!(f, "Distributed Computing"),
521 ProblemDomain::DataPipeline => write!(f, "Data Pipeline"),
522 ProblemDomain::ModelServing => write!(f, "Model Serving"),
523 ProblemDomain::Testing => write!(f, "Testing"),
524 ProblemDomain::Profiling => write!(f, "Profiling"),
525 ProblemDomain::Validation => write!(f, "Validation"),
526 }
527 }
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize)]
536pub struct IntegrationPattern {
537 pub from: String,
538 pub to: String,
539 pub pattern_name: String,
540 pub description: String,
541 pub code_template: Option<String>,
542}
543
544#[cfg(test)]
549mod tests {
550 use super::*;
551
552 #[test]
557 fn test_stack_layer_index() {
558 assert_eq!(StackLayer::Primitives.index(), 0);
559 assert_eq!(StackLayer::MlAlgorithms.index(), 1);
560 assert_eq!(StackLayer::MlPipeline.index(), 2);
561 assert_eq!(StackLayer::Transpilers.index(), 3);
562 assert_eq!(StackLayer::Orchestration.index(), 4);
563 assert_eq!(StackLayer::Quality.index(), 5);
564 assert_eq!(StackLayer::Data.index(), 6);
565 }
566
567 #[test]
568 fn test_stack_layer_all() {
569 let layers = StackLayer::all();
570 assert_eq!(layers.len(), 7);
571 assert_eq!(layers[0], StackLayer::Primitives);
572 assert_eq!(layers[6], StackLayer::Data);
573 }
574
575 #[test]
576 fn test_stack_layer_display() {
577 assert_eq!(StackLayer::Primitives.to_string(), "Compute Primitives");
578 assert_eq!(StackLayer::MlAlgorithms.to_string(), "ML Algorithms");
579 assert_eq!(StackLayer::Transpilers.to_string(), "Transpilers");
580 }
581
582 #[test]
583 fn test_stack_layer_serialization() {
584 let layer = StackLayer::MlAlgorithms;
585 let json = serde_json::to_string(&layer).unwrap();
586 let parsed: StackLayer = serde_json::from_str(&json).unwrap();
587 assert_eq!(layer, parsed);
588 }
589
590 #[test]
595 fn test_capability_new() {
596 let cap = Capability::new("simd", CapabilityCategory::Compute);
597 assert_eq!(cap.name, "simd");
598 assert_eq!(cap.category, CapabilityCategory::Compute);
599 assert!(cap.description.is_none());
600 }
601
602 #[test]
603 fn test_capability_with_description() {
604 let cap = Capability::new("vector_ops", CapabilityCategory::Compute)
605 .with_description("SIMD-accelerated vector operations");
606 assert_eq!(
607 cap.description.as_deref(),
608 Some("SIMD-accelerated vector operations")
609 );
610 }
611
612 #[test]
613 fn test_capability_equality() {
614 let cap1 = Capability::new("simd", CapabilityCategory::Compute);
615 let cap2 = Capability::new("simd", CapabilityCategory::Compute);
616 let cap3 = Capability::new("gpu", CapabilityCategory::Compute);
617 assert_eq!(cap1, cap2);
618 assert_ne!(cap1, cap3);
619 }
620
621 #[test]
626 fn test_stack_component_new() {
627 let comp = StackComponent::new(
628 "trueno",
629 "0.7.3",
630 StackLayer::Primitives,
631 "SIMD-accelerated tensor operations",
632 );
633 assert_eq!(comp.name, "trueno");
634 assert_eq!(comp.version, "0.7.3");
635 assert_eq!(comp.layer, StackLayer::Primitives);
636 assert!(comp.capabilities.is_empty());
637 }
638
639 #[test]
640 fn test_stack_component_with_capability() {
641 let comp = StackComponent::new("trueno", "0.7.3", StackLayer::Primitives, "SIMD tensors")
642 .with_capability(Capability::new("simd", CapabilityCategory::Compute))
643 .with_capability(Capability::new("gpu", CapabilityCategory::Compute));
644 assert_eq!(comp.capabilities.len(), 2);
645 assert!(comp.has_capability("simd"));
646 assert!(comp.has_capability("gpu"));
647 assert!(!comp.has_capability("tpu"));
648 }
649
650 #[test]
651 fn test_stack_component_with_capabilities() {
652 let caps = vec![
653 Capability::new("vector_ops", CapabilityCategory::Compute),
654 Capability::new("matrix_ops", CapabilityCategory::Compute),
655 ];
656 let comp = StackComponent::new("trueno", "0.7.3", StackLayer::Primitives, "SIMD tensors")
657 .with_capabilities(caps);
658 assert_eq!(comp.capabilities.len(), 2);
659 }
660
661 #[test]
662 fn test_stack_component_serialization() {
663 let comp =
664 StackComponent::new("aprender", "0.12.0", StackLayer::MlAlgorithms, "ML library")
665 .with_capability(Capability::new(
666 "random_forest",
667 CapabilityCategory::MachineLearning,
668 ));
669 let json = serde_json::to_string(&comp).unwrap();
670 let parsed: StackComponent = serde_json::from_str(&json).unwrap();
671 assert_eq!(comp.name, parsed.name);
672 assert_eq!(comp.version, parsed.version);
673 assert_eq!(comp.capabilities.len(), parsed.capabilities.len());
674 }
675
676 #[test]
681 fn test_hardware_spec_default() {
682 let hw = HardwareSpec::default();
683 assert!(!hw.has_gpu);
684 assert!(hw.gpu_memory_gb.is_none());
685 assert!(!hw.is_distributed);
686 }
687
688 #[test]
689 fn test_hardware_spec_cpu_only() {
690 let hw = HardwareSpec::cpu_only();
691 assert!(!hw.has_gpu());
692 }
693
694 #[test]
695 fn test_hardware_spec_with_gpu() {
696 let hw = HardwareSpec::with_gpu(16.0);
697 assert!(hw.has_gpu());
698 assert_eq!(hw.gpu_memory_gb, Some(16.0));
699 }
700
701 #[test]
706 fn test_data_size_samples() {
707 let size = DataSize::samples(1_000_000);
708 assert_eq!(size.as_samples(), Some(1_000_000));
709 assert!(size.is_large());
710 }
711
712 #[test]
713 fn test_data_size_bytes() {
714 let size = DataSize::bytes(2_000_000_000);
715 assert!(size.is_large());
716 assert!(size.as_samples().is_none());
717 }
718
719 #[test]
720 fn test_data_size_small() {
721 let size = DataSize::samples(1000);
722 assert!(!size.is_large());
723 }
724
725 #[test]
726 fn test_data_size_unknown() {
727 let size = DataSize::Unknown;
728 assert!(!size.is_large());
729 assert!(size.as_samples().is_none());
730 }
731
732 #[test]
737 fn test_oracle_query_new() {
738 let query = OracleQuery::new("Train a random forest on 1M samples");
739 assert_eq!(query.description, "Train a random forest on 1M samples");
740 assert!(!query.constraints.sovereign_only);
741 assert!(!query.constraints.eu_compliant);
742 }
743
744 #[test]
745 fn test_oracle_query_with_data_size() {
746 let query =
747 OracleQuery::new("classification task").with_data_size(DataSize::samples(1_000_000));
748 assert_eq!(
749 query.constraints.data_size,
750 Some(DataSize::Samples(1_000_000))
751 );
752 }
753
754 #[test]
755 fn test_oracle_query_sovereign_only() {
756 let query = OracleQuery::new("GDPR compliant training").sovereign_only();
757 assert!(query.constraints.sovereign_only);
758 }
759
760 #[test]
761 fn test_oracle_query_eu_compliant() {
762 let query = OracleQuery::new("EU AI Act compliant").eu_compliant();
763 assert!(query.constraints.eu_compliant);
764 }
765
766 #[test]
767 fn test_oracle_query_with_hardware() {
768 let query = OracleQuery::new("GPU training").with_hardware(HardwareSpec::with_gpu(24.0));
769 assert!(query.constraints.hardware.has_gpu());
770 }
771
772 #[test]
773 fn test_oracle_query_serialization() {
774 let query = OracleQuery::new("Test query")
775 .with_data_size(DataSize::samples(10000))
776 .sovereign_only();
777 let json = serde_json::to_string(&query).unwrap();
778 let parsed: OracleQuery = serde_json::from_str(&json).unwrap();
779 assert_eq!(query.description, parsed.description);
780 assert_eq!(
781 query.constraints.sovereign_only,
782 parsed.constraints.sovereign_only
783 );
784 }
785
786 #[test]
791 fn test_backend_display() {
792 assert_eq!(Backend::Scalar.to_string(), "Scalar");
793 assert_eq!(Backend::SIMD.to_string(), "SIMD");
794 assert_eq!(Backend::GPU.to_string(), "GPU");
795 assert_eq!(Backend::Distributed.to_string(), "Distributed");
796 }
797
798 #[test]
799 fn test_backend_serialization() {
800 let backend = Backend::GPU;
801 let json = serde_json::to_string(&backend).unwrap();
802 let parsed: Backend = serde_json::from_str(&json).unwrap();
803 assert_eq!(backend, parsed);
804 }
805
806 #[test]
811 fn test_oracle_response_new() {
812 let rec = ComponentRecommendation {
813 component: "aprender".into(),
814 path: Some("aprender::tree::RandomForest".into()),
815 confidence: 0.95,
816 rationale: "Random forest is ideal for tabular data".into(),
817 };
818 let response = OracleResponse::new("supervised_learning", rec);
819 assert_eq!(response.problem_class, "supervised_learning");
820 assert_eq!(response.primary.component, "aprender");
821 assert!(!response.distribution.needed);
822 }
823
824 #[test]
825 fn test_oracle_response_with_algorithm() {
826 let rec = ComponentRecommendation {
827 component: "aprender".into(),
828 path: None,
829 confidence: 0.9,
830 rationale: "Test".into(),
831 };
832 let response = OracleResponse::new("ml", rec).with_algorithm("random_forest");
833 assert_eq!(response.algorithm.as_deref(), Some("random_forest"));
834 }
835
836 #[test]
837 fn test_oracle_response_with_supporting() {
838 let primary = ComponentRecommendation {
839 component: "aprender".into(),
840 path: None,
841 confidence: 0.9,
842 rationale: "Primary".into(),
843 };
844 let supporting = ComponentRecommendation {
845 component: "trueno".into(),
846 path: None,
847 confidence: 0.8,
848 rationale: "Backend compute".into(),
849 };
850 let response = OracleResponse::new("ml", primary).with_supporting(supporting);
851 assert_eq!(response.supporting.len(), 1);
852 assert_eq!(response.supporting[0].component, "trueno");
853 }
854
855 #[test]
856 fn test_oracle_response_with_code_example() {
857 let rec = ComponentRecommendation {
858 component: "aprender".into(),
859 path: None,
860 confidence: 0.9,
861 rationale: "Test".into(),
862 };
863 let code = r#"use aprender::tree::RandomForest;
864let model = RandomForest::new();"#;
865 let response = OracleResponse::new("ml", rec).with_code_example(code);
866 assert!(response.code_example.is_some());
867 assert!(response.code_example.unwrap().contains("RandomForest"));
868 }
869
870 #[test]
875 fn test_problem_domain_display() {
876 assert_eq!(
877 ProblemDomain::SupervisedLearning.to_string(),
878 "Supervised Learning"
879 );
880 assert_eq!(
881 ProblemDomain::PythonMigration.to_string(),
882 "Python Migration"
883 );
884 assert_eq!(ProblemDomain::GraphAnalytics.to_string(), "Graph Analytics");
885 }
886
887 #[test]
888 fn test_problem_domain_serialization() {
889 let domain = ProblemDomain::DeepLearning;
890 let json = serde_json::to_string(&domain).unwrap();
891 let parsed: ProblemDomain = serde_json::from_str(&json).unwrap();
892 assert_eq!(domain, parsed);
893 }
894
895 #[test]
900 fn test_optimization_target_default() {
901 let target = OptimizationTarget::default();
902 assert_eq!(target, OptimizationTarget::Speed);
903 }
904
905 #[test]
906 fn test_optimization_target_serialization() {
907 let target = OptimizationTarget::Memory;
908 let json = serde_json::to_string(&target).unwrap();
909 let parsed: OptimizationTarget = serde_json::from_str(&json).unwrap();
910 assert_eq!(target, parsed);
911 }
912
913 #[test]
918 fn test_query_constraints_default() {
919 let constraints = QueryConstraints::default();
920 assert!(constraints.max_latency_ms.is_none());
921 assert!(constraints.data_size.is_none());
922 assert!(!constraints.sovereign_only);
923 assert!(!constraints.eu_compliant);
924 }
925
926 #[test]
931 fn test_query_preferences_default() {
932 let prefs = QueryPreferences::default();
933 assert_eq!(prefs.optimize_for, OptimizationTarget::Speed);
934 assert_eq!(prefs.simplicity_weight, 0.0);
935 assert!(prefs.existing_components.is_empty());
936 }
937
938 #[test]
943 fn test_integration_pattern() {
944 let pattern = IntegrationPattern {
945 from: "aprender".into(),
946 to: "realizar".into(),
947 pattern_name: "model_export".into(),
948 description: "Export trained model for serving".into(),
949 code_template: Some("model.export_apr(\"model.apr\")".into()),
950 };
951 assert_eq!(pattern.from, "aprender");
952 assert_eq!(pattern.to, "realizar");
953 assert!(pattern.code_template.is_some());
954 }
955
956 #[test]
957 fn test_integration_pattern_serialization() {
958 let pattern = IntegrationPattern {
959 from: "depyler".into(),
960 to: "aprender".into(),
961 pattern_name: "sklearn_convert".into(),
962 description: "Convert sklearn to aprender".into(),
963 code_template: None,
964 };
965 let json = serde_json::to_string(&pattern).unwrap();
966 let parsed: IntegrationPattern = serde_json::from_str(&json).unwrap();
967 assert_eq!(pattern.from, parsed.from);
968 assert_eq!(pattern.to, parsed.to);
969 }
970}