1use crate::core::types::AllocationInfo;
7use serde_json::Value;
8use std::error::Error;
9use std::fmt;
10
11#[derive(Debug, Clone)]
13pub struct AnalysisData {
14 pub data: Value,
16 pub metadata: AnalysisMetadata,
18}
19
20#[derive(Debug, Clone)]
22pub struct AnalysisMetadata {
23 pub analysis_type: String,
25 pub timestamp: u64,
27 pub total_allocations: usize,
29 pub optimization_level: String,
31}
32
33#[derive(Debug)]
35pub enum AnalysisError {
36 ProcessingError(String),
38 SerializationError(String),
40 InvalidData(String),
42}
43
44impl fmt::Display for AnalysisError {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match self {
47 AnalysisError::ProcessingError(msg) => write!(f, "Processing error: {msg}"),
48 AnalysisError::SerializationError(msg) => write!(f, "Serialization error: {msg}"),
49 AnalysisError::InvalidData(msg) => write!(f, "Invalid data: {msg}"),
50 }
51 }
52}
53
54impl Error for AnalysisError {}
55
56pub trait AnalysisEngine {
61 fn create_memory_analysis(
65 &self,
66 allocations: &[AllocationInfo],
67 ) -> Result<AnalysisData, AnalysisError>;
68
69 fn create_lifetime_analysis(
73 &self,
74 allocations: &[AllocationInfo],
75 ) -> Result<AnalysisData, AnalysisError>;
76
77 fn create_performance_analysis(
81 &self,
82 allocations: &[AllocationInfo],
83 ) -> Result<AnalysisData, AnalysisError>;
84
85 fn create_unsafe_ffi_analysis(
89 &self,
90 allocations: &[AllocationInfo],
91 ) -> Result<AnalysisData, AnalysisError>;
92
93 fn create_complex_types_analysis(
97 &self,
98 allocations: &[AllocationInfo],
99 ) -> Result<AnalysisData, AnalysisError>;
100
101 fn get_config(&self) -> &AnalysisConfig;
103}
104
105#[derive(Debug, Clone)]
107pub struct AnalysisConfig {
108 pub optimization_level: OptimizationLevel,
110 pub parallel_processing: bool,
112 pub enhanced_ffi_analysis: bool,
114 pub security_analysis: bool,
116 pub batch_size: usize,
118}
119
120#[derive(Debug, Clone, PartialEq)]
122pub enum OptimizationLevel {
123 Low,
125 Medium,
127 High,
129 Maximum,
131}
132
133impl Default for AnalysisConfig {
134 fn default() -> Self {
135 Self {
136 optimization_level: OptimizationLevel::High,
137 parallel_processing: true,
138 enhanced_ffi_analysis: true,
139 security_analysis: false,
140 batch_size: 1000,
141 }
142 }
143}
144
145pub struct StandardAnalysisEngine {
150 config: AnalysisConfig,
151}
152
153impl StandardAnalysisEngine {
154 pub fn new() -> Self {
156 Self {
157 config: AnalysisConfig::default(),
158 }
159 }
160
161 pub fn with_config(config: AnalysisConfig) -> Self {
163 Self { config }
164 }
165}
166
167impl Default for StandardAnalysisEngine {
168 fn default() -> Self {
169 Self::new()
170 }
171}
172
173impl AnalysisEngine for StandardAnalysisEngine {
174 fn create_memory_analysis(
175 &self,
176 allocations: &[AllocationInfo],
177 ) -> Result<AnalysisData, AnalysisError> {
178 let total_size: usize = allocations.iter().map(|a| a.size).sum();
181 let avg_size = if !allocations.is_empty() {
182 total_size / allocations.len()
183 } else {
184 0
185 };
186 let max_size = allocations.iter().map(|a| a.size).max().unwrap_or(0);
187 let min_size = allocations.iter().map(|a| a.size).min().unwrap_or(0);
188
189 let allocations_data: Vec<serde_json::Value> = allocations
190 .iter()
191 .map(|alloc| {
192 serde_json::json!({
193 "ptr": alloc.ptr,
194 "size": alloc.size,
195 "var_name": self.infer_var_name(alloc),
196 "type_name": self.infer_type_name(alloc),
197 "scope_name": alloc.scope_name.as_deref().unwrap_or("global"),
198 "thread_id": alloc.thread_id,
199 "timestamp_alloc": alloc.timestamp_alloc,
200 "timestamp_dealloc": alloc.timestamp_dealloc.unwrap_or(0),
201 "is_leaked": alloc.is_leaked,
202 "borrow_count": alloc.borrow_count,
203 "lifetime_ms": alloc.lifetime_ms.unwrap_or(0),
204 "stack_trace": alloc.stack_trace.as_ref().map(|st| st.join(" -> ")).unwrap_or_else(|| "no_stack_trace".to_string())
205 })
206 })
207 .collect();
208
209 let data = serde_json::json!({
210 "allocations": allocations_data,
211 "metadata": {
212 "analysis_type": "integrated_memory_analysis",
213 "export_version": "2.0",
214 "optimization_level": format!("{:?}", self.config.optimization_level),
215 "timestamp": std::time::SystemTime::now()
216 .duration_since(std::time::UNIX_EPOCH)
217 .unwrap_or_default()
218 .as_secs(),
219 "total_allocations_analyzed": allocations.len(),
220 "pipeline_features": {
221 "enhanced_ffi_analysis": self.config.enhanced_ffi_analysis,
222 "parallel_processing": self.config.parallel_processing,
223 "security_analysis": self.config.security_analysis
224 }
225 },
226 "summary": {
227 "total_allocations": allocations.len(),
228 "total_memory": total_size,
229 "average_size": avg_size,
230 "max_size": max_size,
231 "min_size": min_size,
232 "leaked_count": allocations.iter().filter(|a| a.is_leaked).count()
233 }
234 });
235
236 Ok(AnalysisData {
237 data,
238 metadata: AnalysisMetadata {
239 analysis_type: "integrated_memory_analysis".to_string(),
240 timestamp: std::time::SystemTime::now()
241 .duration_since(std::time::UNIX_EPOCH)
242 .unwrap_or_default()
243 .as_secs(),
244 total_allocations: allocations.len(),
245 optimization_level: format!("{:?}", self.config.optimization_level),
246 },
247 })
248 }
249
250 fn create_lifetime_analysis(
251 &self,
252 allocations: &[AllocationInfo],
253 ) -> Result<AnalysisData, AnalysisError> {
254 let mut lifecycle_events = Vec::new();
256 let mut scope_analysis = std::collections::HashMap::new();
257
258 for alloc in allocations {
259 lifecycle_events.push(serde_json::json!({
261 "event": "allocation",
262 "ptr": format!("0x{:x}", alloc.ptr),
263 "size": alloc.size,
264 "timestamp": alloc.timestamp_alloc,
265 "var_name": self.infer_var_name(alloc),
266 "type_name": self.infer_type_name(alloc),
267 "scope": alloc.scope_name.as_deref().unwrap_or("global")
268 }));
269
270 if let Some(dealloc_time) = alloc.timestamp_dealloc {
272 lifecycle_events.push(serde_json::json!({
273 "event": "deallocation",
274 "ptr": format!("0x{:x}", alloc.ptr),
275 "timestamp": dealloc_time,
276 "var_name": self.infer_var_name(alloc),
277 "scope": alloc.scope_name.as_deref().unwrap_or("global")
278 }));
279 }
280
281 let scope = alloc.scope_name.as_deref().unwrap_or("global");
283 let entry = scope_analysis
284 .entry(scope.to_string())
285 .or_insert((0, 0, Vec::new()));
286 entry.0 += 1; entry.1 += alloc.size; entry.2.push(alloc.size); }
290
291 let scope_stats: std::collections::HashMap<String, serde_json::Value> = scope_analysis
293 .into_iter()
294 .map(|(scope, (count, total_size, sizes))| {
295 let avg_size = if count > 0 { total_size / count } else { 0 };
296 (
297 scope,
298 serde_json::json!({
299 "allocation_count": count,
300 "total_size": total_size,
301 "average_size": avg_size,
302 "sizes": sizes
303 }),
304 )
305 })
306 .collect();
307
308 let data = serde_json::json!({
309 "lifecycle_events": lifecycle_events,
310 "scope_analysis": scope_stats,
311 "variable_lifetimes": {},
312 "metadata": {
313 "analysis_type": "integrated_lifetime_analysis",
314 "export_version": "2.0",
315 "optimization_level": format!("{:?}", self.config.optimization_level),
316 "timestamp": std::time::SystemTime::now()
317 .duration_since(std::time::UNIX_EPOCH)
318 .unwrap_or_default()
319 .as_secs(),
320 "total_allocations_analyzed": allocations.len(),
321 "pipeline_features": {
322 "enhanced_ffi_analysis": self.config.enhanced_ffi_analysis,
323 "parallel_processing": self.config.parallel_processing
324 }
325 },
326 "summary": {
327 "total_allocations": allocations.len(),
328 "unique_scopes": scope_stats.len(),
329 "total_events": lifecycle_events.len(),
330 "leaked_count": allocations.iter().filter(|a| a.is_leaked).count()
331 }
332 });
333
334 Ok(AnalysisData {
335 data,
336 metadata: AnalysisMetadata {
337 analysis_type: "integrated_lifetime_analysis".to_string(),
338 timestamp: std::time::SystemTime::now()
339 .duration_since(std::time::UNIX_EPOCH)
340 .unwrap_or_default()
341 .as_secs(),
342 total_allocations: allocations.len(),
343 optimization_level: format!("{:?}", self.config.optimization_level),
344 },
345 })
346 }
347
348 fn create_performance_analysis(
349 &self,
350 allocations: &[AllocationInfo],
351 ) -> Result<AnalysisData, AnalysisError> {
352 let total_size: usize = allocations.iter().map(|a| a.size).sum();
354 let avg_size = if !allocations.is_empty() {
355 total_size / allocations.len()
356 } else {
357 0
358 };
359 let max_size = allocations.iter().map(|a| a.size).max().unwrap_or(0);
360 let min_size = allocations.iter().map(|a| a.size).min().unwrap_or(0);
361
362 let mut thread_stats = std::collections::HashMap::new();
364 for alloc in allocations {
365 let entry = thread_stats
366 .entry(alloc.thread_id.clone())
367 .or_insert((0, 0));
368 entry.0 += 1; entry.1 += alloc.size; }
371
372 let thread_analysis: std::collections::HashMap<String, serde_json::Value> = thread_stats
373 .into_iter()
374 .map(|(thread_id, (count, total_size))| {
375 (
376 thread_id,
377 serde_json::json!({
378 "allocation_count": count,
379 "total_size": total_size,
380 "average_size": if count > 0 { total_size / count } else { 0 }
381 }),
382 )
383 })
384 .collect();
385
386 let allocations_data: Vec<serde_json::Value> = allocations
387 .iter()
388 .map(|alloc| {
389 serde_json::json!({
390 "ptr": alloc.ptr,
391 "size": alloc.size,
392 "timestamp_alloc": alloc.timestamp_alloc,
393 "thread_id": alloc.thread_id,
394 "borrow_count": alloc.borrow_count,
395 "var_name": self.infer_var_name(alloc),
396 "type_name": self.infer_type_name(alloc),
397 "scope_name": alloc.scope_name.as_deref().unwrap_or("global"),
398 "is_leaked": alloc.is_leaked,
399 "lifetime_ms": alloc.lifetime_ms.unwrap_or(0),
400 "fragmentation_score": 0.0 })
402 })
403 .collect();
404
405 let data = serde_json::json!({
406 "allocations": allocations_data,
407 "thread_analysis": thread_analysis,
408 "metadata": {
409 "analysis_type": "integrated_performance_analysis",
410 "export_version": "2.0",
411 "optimization_level": format!("{:?}", self.config.optimization_level),
412 "timestamp": std::time::SystemTime::now()
413 .duration_since(std::time::UNIX_EPOCH)
414 .unwrap_or_default()
415 .as_secs(),
416 "total_allocations_analyzed": allocations.len(),
417 "pipeline_features": {
418 "parallel_processing": self.config.parallel_processing,
419 "batch_size": self.config.batch_size
420 }
421 },
422 "summary": {
423 "total_allocations": allocations.len(),
424 "total_memory": total_size,
425 "average_size": avg_size,
426 "max_size": max_size,
427 "min_size": min_size,
428 "unique_threads": thread_analysis.len()
429 }
430 });
431
432 Ok(AnalysisData {
433 data,
434 metadata: AnalysisMetadata {
435 analysis_type: "integrated_performance_analysis".to_string(),
436 timestamp: std::time::SystemTime::now()
437 .duration_since(std::time::UNIX_EPOCH)
438 .unwrap_or_default()
439 .as_secs(),
440 total_allocations: allocations.len(),
441 optimization_level: format!("{:?}", self.config.optimization_level),
442 },
443 })
444 }
445
446 fn create_unsafe_ffi_analysis(
447 &self,
448 _allocations: &[AllocationInfo],
449 ) -> Result<AnalysisData, AnalysisError> {
450 use crate::analysis::unsafe_ffi_tracker::get_global_unsafe_ffi_tracker;
451
452 let tracker = get_global_unsafe_ffi_tracker();
454 let enhanced_allocations = tracker.get_enhanced_allocations().map_err(|e| {
455 AnalysisError::ProcessingError(format!("Failed to get enhanced allocations: {e}"))
456 })?;
457
458 let user_enhanced_allocations = enhanced_allocations;
461
462 let data = serde_json::to_value(&user_enhanced_allocations).map_err(|e| {
464 AnalysisError::SerializationError(format!(
465 "Failed to serialize enhanced allocations: {e}"
466 ))
467 })?;
468
469 Ok(AnalysisData {
470 data,
471 metadata: AnalysisMetadata {
472 analysis_type: "unsafe_ffi_analysis".to_string(),
473 timestamp: std::time::SystemTime::now()
474 .duration_since(std::time::UNIX_EPOCH)
475 .unwrap_or_default()
476 .as_secs(),
477 total_allocations: user_enhanced_allocations.len(),
478 optimization_level: format!("{:?}", self.config.optimization_level),
479 },
480 })
481 }
482
483 fn create_complex_types_analysis(
484 &self,
485 allocations: &[AllocationInfo],
486 ) -> Result<AnalysisData, AnalysisError> {
487 let mut categorized_types = std::collections::HashMap::new();
489 let mut generic_types = std::collections::HashMap::new();
490
491 for alloc in allocations {
492 let type_name = self.infer_type_name(alloc);
493
494 let category = if type_name.contains('<') && type_name.contains('>') {
496 "generic"
497 } else if type_name.starts_with("Vec") || type_name.starts_with("HashMap") {
498 "collection"
499 } else if type_name.contains("::") {
500 "module_type"
501 } else {
502 "primitive"
503 };
504
505 let entry = categorized_types
506 .entry(category.to_string())
507 .or_insert(Vec::new());
508 if alloc.memory_layout.is_some() {
510 tracing::debug!(
511 "AllocationInfo has memory_layout for {}",
512 self.infer_var_name(alloc)
513 );
514 }
515 if alloc.generic_info.is_some() {
516 tracing::debug!(
517 "AllocationInfo has generic_info for {}",
518 self.infer_var_name(alloc)
519 );
520 }
521
522 let mut json_obj = serde_json::Map::new();
524 json_obj.insert(
525 "ptr".to_string(),
526 serde_json::Value::String(format!("0x{:x}", alloc.ptr)),
527 );
528 json_obj.insert(
529 "size".to_string(),
530 serde_json::Value::Number(serde_json::Number::from(alloc.size)),
531 );
532 json_obj.insert(
533 "var_name".to_string(),
534 serde_json::Value::String(self.infer_var_name(alloc)),
535 );
536 json_obj.insert(
537 "type_name".to_string(),
538 serde_json::Value::String(type_name.to_string()),
539 );
540
541 json_obj.insert(
543 "smart_pointer_info".to_string(),
544 if let Some(ref info) = alloc.smart_pointer_info {
545 serde_json::to_value(info)
546 .unwrap_or_else(|_| serde_json::json!({"type": "unknown", "ref_count": 0}))
547 } else {
548 serde_json::json!({"type": "none", "ref_count": 0})
549 },
550 );
551
552 json_obj.insert(
553 "memory_layout".to_string(),
554 if let Some(ref layout) = alloc.memory_layout {
555 match serde_json::to_value(layout) {
556 Ok(value) => {
557 tracing::debug!(
558 "Successfully serialized memory_layout for {}",
559 self.infer_var_name(alloc)
560 );
561 value
562 }
563 Err(e) => {
564 tracing::debug!(
565 "Failed to serialize memory_layout for {}: {}",
566 self.infer_var_name(alloc),
567 e
568 );
569 serde_json::json!({"layout_type": "unknown", "size": alloc.size, "alignment": 1})
570 }
571 }
572 } else {
573 serde_json::json!({"layout_type": "default", "size": alloc.size, "alignment": 1})
574 },
575 );
576
577 json_obj.insert(
578 "generic_info".to_string(),
579 if let Some(ref info) = alloc.generic_info {
580 match serde_json::to_value(info) {
581 Ok(value) => {
582 tracing::debug!(
583 "Successfully serialized generic_info for {}",
584 self.infer_var_name(alloc)
585 );
586 value
587 }
588 Err(e) => {
589 tracing::debug!(
590 "Failed to serialize generic_info for {}: {}",
591 self.infer_var_name(alloc),
592 e
593 );
594 serde_json::json!({"generic_type": "none", "type_parameters": []})
595 }
596 }
597 } else {
598 serde_json::json!({"generic_type": "none", "type_parameters": []})
599 },
600 );
601
602 json_obj.insert(
603 "dynamic_type_info".to_string(),
604 if let Some(ref info) = alloc.dynamic_type_info {
605 serde_json::to_value(info).unwrap_or_else(|_| serde_json::json!({"type": "static", "runtime_type": "unknown"}))
606 } else {
607 serde_json::json!({"type": "static", "runtime_type": self.infer_type_name(alloc)})
608 },
609 );
610
611 json_obj.insert(
612 "generic_instantiation".to_string(),
613 if let Some(ref info) = alloc.generic_instantiation {
614 serde_json::to_value(info).unwrap_or_else(
615 |_| serde_json::json!({"instantiation": "none", "parameters": []}),
616 )
617 } else {
618 serde_json::json!({"instantiation": "none", "parameters": []})
619 },
620 );
621
622 json_obj.insert(
623 "type_relationships".to_string(),
624 if let Some(ref info) = alloc.type_relationships {
625 serde_json::to_value(info).unwrap_or_else(
626 |_| serde_json::json!({"relationships": [], "inheritance": "none"}),
627 )
628 } else {
629 serde_json::json!({"relationships": [], "inheritance": "none"})
630 },
631 );
632
633 json_obj.insert(
634 "type_usage".to_string(),
635 if let Some(ref info) = alloc.type_usage {
636 serde_json::to_value(info).unwrap_or_else(
637 |_| serde_json::json!({"usage_count": 1, "usage_pattern": "single"}),
638 )
639 } else {
640 serde_json::json!({"usage_count": 1, "usage_pattern": "single"})
641 },
642 );
643
644 entry.push(serde_json::Value::Object(json_obj));
645
646 if category == "generic" {
648 let entry = generic_types.entry(type_name.to_string()).or_insert((0, 0));
649 entry.0 += 1; entry.1 += alloc.size; }
652 }
653
654 let generic_stats: std::collections::HashMap<String, serde_json::Value> = generic_types
655 .into_iter()
656 .map(|(type_name, (count, total_size))| {
657 (
658 type_name,
659 serde_json::json!({
660 "instantiation_count": count,
661 "total_size": total_size,
662 "average_size": if count > 0 { total_size / count } else { 0 }
663 }),
664 )
665 })
666 .collect();
667
668 let data = serde_json::json!({
669 "categorized_types": categorized_types,
670 "generic_types": generic_stats,
671 "metadata": {
672 "analysis_type": "integrated_complex_types_analysis",
673 "export_version": "2.0",
674 "optimization_level": format!("{:?}", self.config.optimization_level),
675 "timestamp": std::time::SystemTime::now()
676 .duration_since(std::time::UNIX_EPOCH)
677 .unwrap_or_default()
678 .as_secs(),
679 "total_allocations_analyzed": allocations.len(),
680 "pipeline_features": {
681 "type_categorization": true,
682 "generic_analysis": true,
683 "memory_layout_analysis": true
684 }
685 },
686 "summary": {
687 "total_allocations": allocations.len(),
688 "type_categories": categorized_types.len(),
689 "generic_types": generic_stats.len(),
690 "complex_type_ratio": if !allocations.is_empty() {
691 (categorized_types.get("generic").map(|v| v.len()).unwrap_or(0) as f64 / allocations.len() as f64) * 100.0
692 } else { 0.0 }
693 }
694 });
695
696 Ok(AnalysisData {
697 data,
698 metadata: AnalysisMetadata {
699 analysis_type: "integrated_complex_types_analysis".to_string(),
700 timestamp: std::time::SystemTime::now()
701 .duration_since(std::time::UNIX_EPOCH)
702 .unwrap_or_default()
703 .as_secs(),
704 total_allocations: allocations.len(),
705 optimization_level: format!("{:?}", self.config.optimization_level),
706 },
707 })
708 }
709
710 fn get_config(&self) -> &AnalysisConfig {
711 &self.config
712 }
713}
714
715impl StandardAnalysisEngine {
716 #[allow(dead_code)]
718 fn convert_to_export_options(
719 &self,
720 ) -> crate::export::optimized_json_export::OptimizedExportOptions {
721 use crate::export::optimized_json_export::{
722 OptimizationLevel as ExportOptLevel, OptimizedExportOptions,
723 };
724
725 let export_opt_level = match self.config.optimization_level {
726 OptimizationLevel::Low => ExportOptLevel::Low,
727 OptimizationLevel::Medium => ExportOptLevel::Medium,
728 OptimizationLevel::High => ExportOptLevel::High,
729 OptimizationLevel::Maximum => ExportOptLevel::Maximum,
730 };
731
732 OptimizedExportOptions::with_optimization_level(export_opt_level)
733 .parallel_processing(self.config.parallel_processing)
734 .batch_size(self.config.batch_size)
735 }
736
737 fn infer_type_name(&self, alloc: &AllocationInfo) -> String {
740 match alloc.type_name.as_deref() {
741 Some(name) => name.to_string(),
742 None => {
743 match alloc.size {
745 0 => "ZeroSizedType".to_string(),
746 1 => "u8_or_bool".to_string(),
747 2 => "u16_or_char".to_string(),
748 4 => "u32_or_f32_or_i32".to_string(),
749 8 => "u64_or_f64_or_i64_or_usize".to_string(),
750 16 => "u128_or_i128_or_complex_struct".to_string(),
751 24 => "Vec_or_String_header".to_string(),
752 32 => "HashMap_or_BTreeMap_header".to_string(),
753 size if size >= 1024 => format!("LargeAllocation_{size}bytes"),
754 size if size % 8 == 0 => format!("AlignedStruct_{size}bytes"),
755 size => format!("CustomType_{size}bytes"),
756 }
757 }
758 }
759 }
760
761 fn infer_var_name(&self, alloc: &AllocationInfo) -> String {
764 match alloc.var_name.as_deref() {
765 Some(name) => name.to_string(),
766 None => {
767 let type_hint = match alloc.size {
769 0 => "zero_sized_var",
770 1..=8 => "primitive_var",
771 9..=32 => "small_struct_var",
772 33..=256 => "medium_struct_var",
773 257..=1024 => "large_struct_var",
774 _ => "heap_allocated_var",
775 };
776
777 format!("{}_{:x}", type_hint, alloc.ptr)
779 }
780 }
781 }
782}
783
784#[cfg(test)]
785mod tests {
786 use super::*;
787 use crate::core::types::AllocationInfo;
788
789 fn create_test_allocations() -> Vec<AllocationInfo> {
790 vec![AllocationInfo {
791 ptr: 0x1000,
792 size: 1024,
793 var_name: Some("buffer".to_string()),
794 type_name: Some("Vec<u8>".to_string()),
795 scope_name: Some("main".to_string()),
796 timestamp_alloc: 1234567890,
797 timestamp_dealloc: None,
798 thread_id: "main".to_string(),
799 borrow_count: 0,
800 stack_trace: None,
801 is_leaked: false,
802 lifetime_ms: Some(100),
803 borrow_info: None,
804 clone_info: None,
805 ownership_history_available: false,
806 smart_pointer_info: None,
807 memory_layout: None,
808 generic_info: None,
809 dynamic_type_info: None,
810 runtime_state: None,
811 stack_allocation: None,
812 temporary_object: None,
813 fragmentation_analysis: None,
814 generic_instantiation: None,
815 type_relationships: None,
816 type_usage: None,
817 function_call_tracking: None,
818 lifecycle_tracking: None,
819 access_tracking: None,
820 drop_chain_analysis: None,
821 }]
822 }
823
824 #[test]
825 fn test_standard_analysis_engine_creation() {
826 let engine = StandardAnalysisEngine::new();
827 assert_eq!(
828 engine.get_config().optimization_level,
829 OptimizationLevel::High
830 );
831 }
832
833 #[test]
834 fn test_memory_analysis() {
835 let engine = StandardAnalysisEngine::new();
836 let allocations = create_test_allocations();
837
838 let result = engine.create_memory_analysis(&allocations);
839 assert!(result.is_ok());
840
841 let analysis_data = result.expect("Failed to get analysis data");
842 assert_eq!(
843 analysis_data.metadata.analysis_type,
844 "integrated_memory_analysis"
845 );
846 assert_eq!(analysis_data.metadata.total_allocations, 1);
847 }
848
849 #[test]
850 fn test_standard_analysis_engine_with_config() {
851 let config = AnalysisConfig {
852 optimization_level: OptimizationLevel::Low,
853 parallel_processing: false,
854 enhanced_ffi_analysis: false,
855 security_analysis: true,
856 batch_size: 500,
857 };
858 let engine = StandardAnalysisEngine::with_config(config);
859
860 assert_eq!(
861 engine.get_config().optimization_level,
862 OptimizationLevel::Low
863 );
864 assert!(!engine.get_config().parallel_processing);
865 assert!(!engine.get_config().enhanced_ffi_analysis);
866 assert!(engine.get_config().security_analysis);
867 assert_eq!(engine.get_config().batch_size, 500);
868 }
869
870 #[test]
871 fn test_standard_analysis_engine_default() {
872 let engine1 = StandardAnalysisEngine::new();
873 let engine2 = StandardAnalysisEngine::default();
874
875 assert_eq!(
876 engine1.get_config().optimization_level,
877 engine2.get_config().optimization_level
878 );
879 assert_eq!(
880 engine1.get_config().parallel_processing,
881 engine2.get_config().parallel_processing
882 );
883 assert_eq!(
884 engine1.get_config().batch_size,
885 engine2.get_config().batch_size
886 );
887 }
888
889 #[test]
890 fn test_analysis_config_default() {
891 let config = AnalysisConfig::default();
892
893 assert_eq!(config.optimization_level, OptimizationLevel::High);
894 assert!(config.parallel_processing);
895 assert!(config.enhanced_ffi_analysis);
896 assert!(!config.security_analysis);
897 assert_eq!(config.batch_size, 1000);
898 }
899
900 #[test]
901 fn test_lifetime_analysis() {
902 let engine = StandardAnalysisEngine::new();
903 let allocations = create_test_allocations();
904
905 let result = engine.create_lifetime_analysis(&allocations);
906 assert!(result.is_ok());
907
908 let analysis_data = result.unwrap();
909 assert_eq!(
910 analysis_data.metadata.analysis_type,
911 "integrated_lifetime_analysis"
912 );
913 assert_eq!(analysis_data.metadata.total_allocations, 1);
914
915 let data = &analysis_data.data;
917 assert!(data.get("lifecycle_events").is_some());
918 assert!(data.get("scope_analysis").is_some());
919 assert!(data.get("summary").is_some());
920 }
921
922 #[test]
923 fn test_performance_analysis() {
924 let engine = StandardAnalysisEngine::new();
925 let allocations = create_test_allocations();
926
927 let result = engine.create_performance_analysis(&allocations);
928 assert!(result.is_ok());
929
930 let analysis_data = result.unwrap();
931 assert_eq!(
932 analysis_data.metadata.analysis_type,
933 "integrated_performance_analysis"
934 );
935 assert_eq!(analysis_data.metadata.total_allocations, 1);
936
937 let data = &analysis_data.data;
939 assert!(data.get("allocations").is_some());
940 assert!(data.get("thread_analysis").is_some());
941 assert!(data.get("summary").is_some());
942 }
943
944 #[test]
945 fn test_complex_types_analysis() {
946 let engine = StandardAnalysisEngine::new();
947 let allocations = create_test_allocations();
948
949 let result = engine.create_complex_types_analysis(&allocations);
950 assert!(result.is_ok());
951
952 let analysis_data = result.unwrap();
953 assert_eq!(
954 analysis_data.metadata.analysis_type,
955 "integrated_complex_types_analysis"
956 );
957 assert_eq!(analysis_data.metadata.total_allocations, 1);
958
959 let data = &analysis_data.data;
961 assert!(data.get("categorized_types").is_some());
962 assert!(data.get("generic_types").is_some());
963 assert!(data.get("summary").is_some());
964 }
965
966 #[test]
967 fn test_empty_allocations() {
968 let engine = StandardAnalysisEngine::new();
969 let empty_allocations = vec![];
970
971 let memory_result = engine.create_memory_analysis(&empty_allocations);
973 assert!(memory_result.is_ok());
974 let memory_data = memory_result.unwrap();
975 assert_eq!(memory_data.metadata.total_allocations, 0);
976
977 let lifetime_result = engine.create_lifetime_analysis(&empty_allocations);
978 assert!(lifetime_result.is_ok());
979 let lifetime_data = lifetime_result.unwrap();
980 assert_eq!(lifetime_data.metadata.total_allocations, 0);
981
982 let performance_result = engine.create_performance_analysis(&empty_allocations);
983 assert!(performance_result.is_ok());
984 let performance_data = performance_result.unwrap();
985 assert_eq!(performance_data.metadata.total_allocations, 0);
986
987 let complex_types_result = engine.create_complex_types_analysis(&empty_allocations);
988 assert!(complex_types_result.is_ok());
989 let complex_types_data = complex_types_result.unwrap();
990 assert_eq!(complex_types_data.metadata.total_allocations, 0);
991 }
992
993 fn create_multiple_test_allocations() -> Vec<AllocationInfo> {
994 vec![
995 AllocationInfo {
996 ptr: 0x1000,
997 size: 1024,
998 var_name: Some("buffer".to_string()),
999 type_name: Some("Vec<u8>".to_string()),
1000 scope_name: Some("main".to_string()),
1001 timestamp_alloc: 1234567890,
1002 timestamp_dealloc: Some(1234567990),
1003 thread_id: "main".to_string(),
1004 borrow_count: 0,
1005 stack_trace: Some(vec!["main".to_string(), "allocate".to_string()]),
1006 is_leaked: false,
1007 lifetime_ms: Some(100),
1008 borrow_info: None,
1009 clone_info: None,
1010 ownership_history_available: false,
1011 smart_pointer_info: None,
1012 memory_layout: None,
1013 generic_info: None,
1014 dynamic_type_info: None,
1015 runtime_state: None,
1016 stack_allocation: None,
1017 temporary_object: None,
1018 fragmentation_analysis: None,
1019 generic_instantiation: None,
1020 type_relationships: None,
1021 type_usage: None,
1022 function_call_tracking: None,
1023 lifecycle_tracking: None,
1024 access_tracking: None,
1025 drop_chain_analysis: None,
1026 },
1027 AllocationInfo {
1028 ptr: 0x2000,
1029 size: 512,
1030 var_name: None, type_name: None, scope_name: Some("function".to_string()),
1033 timestamp_alloc: 1234567900,
1034 timestamp_dealloc: None,
1035 thread_id: "worker".to_string(),
1036 borrow_count: 2,
1037 stack_trace: None,
1038 is_leaked: true,
1039 lifetime_ms: None,
1040 borrow_info: None,
1041 clone_info: None,
1042 ownership_history_available: false,
1043 smart_pointer_info: None,
1044 memory_layout: None,
1045 generic_info: None,
1046 dynamic_type_info: None,
1047 runtime_state: None,
1048 stack_allocation: None,
1049 temporary_object: None,
1050 fragmentation_analysis: None,
1051 generic_instantiation: None,
1052 type_relationships: None,
1053 type_usage: None,
1054 function_call_tracking: None,
1055 lifecycle_tracking: None,
1056 access_tracking: None,
1057 drop_chain_analysis: None,
1058 },
1059 AllocationInfo {
1060 ptr: 0x3000,
1061 size: 8,
1062 var_name: Some("counter".to_string()),
1063 type_name: Some("HashMap<String, i32>".to_string()),
1064 scope_name: None, timestamp_alloc: 1234567910,
1066 timestamp_dealloc: Some(1234567950),
1067 thread_id: "main".to_string(),
1068 borrow_count: 1,
1069 stack_trace: Some(vec!["main".to_string()]),
1070 is_leaked: false,
1071 lifetime_ms: Some(40),
1072 borrow_info: None,
1073 clone_info: None,
1074 ownership_history_available: false,
1075 smart_pointer_info: None,
1076 memory_layout: None,
1077 generic_info: None,
1078 dynamic_type_info: None,
1079 runtime_state: None,
1080 stack_allocation: None,
1081 temporary_object: None,
1082 fragmentation_analysis: None,
1083 generic_instantiation: None,
1084 type_relationships: None,
1085 type_usage: None,
1086 function_call_tracking: None,
1087 lifecycle_tracking: None,
1088 access_tracking: None,
1089 drop_chain_analysis: None,
1090 },
1091 ]
1092 }
1093
1094 #[test]
1095 fn test_multiple_allocations_analysis() {
1096 let engine = StandardAnalysisEngine::new();
1097 let allocations = create_multiple_test_allocations();
1098
1099 let memory_result = engine.create_memory_analysis(&allocations);
1101 assert!(memory_result.is_ok());
1102 let memory_data = memory_result.unwrap();
1103 assert_eq!(memory_data.metadata.total_allocations, 3);
1104
1105 let summary = memory_data.data.get("summary").unwrap();
1107 assert_eq!(
1108 summary.get("total_allocations").unwrap().as_u64().unwrap(),
1109 3
1110 );
1111 assert_eq!(summary.get("total_memory").unwrap().as_u64().unwrap(), 1544); assert_eq!(summary.get("leaked_count").unwrap().as_u64().unwrap(), 1);
1113 assert_eq!(summary.get("max_size").unwrap().as_u64().unwrap(), 1024);
1114 assert_eq!(summary.get("min_size").unwrap().as_u64().unwrap(), 8);
1115 }
1116
1117 #[test]
1118 fn test_lifetime_analysis_with_multiple_allocations() {
1119 let engine = StandardAnalysisEngine::new();
1120 let allocations = create_multiple_test_allocations();
1121
1122 let result = engine.create_lifetime_analysis(&allocations);
1123 assert!(result.is_ok());
1124 let analysis_data = result.unwrap();
1125
1126 let events = analysis_data
1128 .data
1129 .get("lifecycle_events")
1130 .unwrap()
1131 .as_array()
1132 .unwrap();
1133 assert_eq!(events.len(), 5); let scope_analysis = analysis_data
1137 .data
1138 .get("scope_analysis")
1139 .unwrap()
1140 .as_object()
1141 .unwrap();
1142 assert!(scope_analysis.contains_key("main"));
1143 assert!(scope_analysis.contains_key("function"));
1144 assert!(scope_analysis.contains_key("global"));
1145 }
1146
1147 #[test]
1148 fn test_performance_analysis_with_multiple_threads() {
1149 let engine = StandardAnalysisEngine::new();
1150 let allocations = create_multiple_test_allocations();
1151
1152 let result = engine.create_performance_analysis(&allocations);
1153 assert!(result.is_ok());
1154 let analysis_data = result.unwrap();
1155
1156 let thread_analysis = analysis_data
1158 .data
1159 .get("thread_analysis")
1160 .unwrap()
1161 .as_object()
1162 .unwrap();
1163 assert!(thread_analysis.contains_key("main"));
1164 assert!(thread_analysis.contains_key("worker"));
1165
1166 let main_stats = thread_analysis.get("main").unwrap();
1168 assert_eq!(
1169 main_stats
1170 .get("allocation_count")
1171 .unwrap()
1172 .as_u64()
1173 .unwrap(),
1174 2
1175 );
1176 assert_eq!(
1177 main_stats.get("total_size").unwrap().as_u64().unwrap(),
1178 1032
1179 ); let worker_stats = thread_analysis.get("worker").unwrap();
1183 assert_eq!(
1184 worker_stats
1185 .get("allocation_count")
1186 .unwrap()
1187 .as_u64()
1188 .unwrap(),
1189 1
1190 );
1191 assert_eq!(
1192 worker_stats.get("total_size").unwrap().as_u64().unwrap(),
1193 512
1194 );
1195 }
1196
1197 #[test]
1198 fn test_complex_types_categorization() {
1199 let engine = StandardAnalysisEngine::new();
1200 let allocations = create_multiple_test_allocations();
1201
1202 let result = engine.create_complex_types_analysis(&allocations);
1203 assert!(result.is_ok());
1204 let analysis_data = result.unwrap();
1205
1206 let categorized = analysis_data
1208 .data
1209 .get("categorized_types")
1210 .unwrap()
1211 .as_object()
1212 .unwrap();
1213 assert!(categorized.contains_key("generic")); assert!(categorized.contains_key("primitive")); let generic_types = analysis_data
1218 .data
1219 .get("generic_types")
1220 .unwrap()
1221 .as_object()
1222 .unwrap();
1223 assert!(generic_types.contains_key("Vec<u8>"));
1224 assert!(generic_types.contains_key("HashMap<String, i32>"));
1225 }
1226
1227 #[test]
1228 fn test_type_name_inference() {
1229 let engine = StandardAnalysisEngine::new();
1230
1231 let test_cases = vec![
1233 (0, "ZeroSizedType"),
1234 (1, "u8_or_bool"),
1235 (2, "u16_or_char"),
1236 (4, "u32_or_f32_or_i32"),
1237 (8, "u64_or_f64_or_i64_or_usize"),
1238 (16, "u128_or_i128_or_complex_struct"),
1239 (24, "Vec_or_String_header"),
1240 (32, "HashMap_or_BTreeMap_header"),
1241 (1024, "LargeAllocation_1024bytes"),
1242 (48, "AlignedStruct_48bytes"), (33, "CustomType_33bytes"), ];
1245
1246 for (size, expected_prefix) in test_cases {
1247 let alloc = AllocationInfo {
1248 ptr: 0x1000,
1249 size,
1250 var_name: None,
1251 type_name: None, scope_name: None,
1253 timestamp_alloc: 0,
1254 timestamp_dealloc: None,
1255 thread_id: "test".to_string(),
1256 borrow_count: 0,
1257 stack_trace: None,
1258 is_leaked: false,
1259 lifetime_ms: None,
1260 borrow_info: None,
1261 clone_info: None,
1262 ownership_history_available: false,
1263 smart_pointer_info: None,
1264 memory_layout: None,
1265 generic_info: None,
1266 dynamic_type_info: None,
1267 runtime_state: None,
1268 stack_allocation: None,
1269 temporary_object: None,
1270 fragmentation_analysis: None,
1271 generic_instantiation: None,
1272 type_relationships: None,
1273 type_usage: None,
1274 function_call_tracking: None,
1275 lifecycle_tracking: None,
1276 access_tracking: None,
1277 drop_chain_analysis: None,
1278 };
1279
1280 let inferred_type = engine.infer_type_name(&alloc);
1281 assert_eq!(inferred_type, expected_prefix);
1282 }
1283 }
1284
1285 #[test]
1286 fn test_var_name_inference() {
1287 let engine = StandardAnalysisEngine::new();
1288
1289 let test_cases = vec![
1290 (0, "zero_sized_var"),
1291 (4, "primitive_var"),
1292 (16, "small_struct_var"),
1293 (128, "medium_struct_var"),
1294 (512, "large_struct_var"),
1295 (2048, "heap_allocated_var"),
1296 ];
1297
1298 for (size, expected_prefix) in test_cases {
1299 let alloc = AllocationInfo {
1300 ptr: 0x1234,
1301 size,
1302 var_name: None, type_name: Some("TestType".to_string()),
1304 scope_name: None,
1305 timestamp_alloc: 0,
1306 timestamp_dealloc: None,
1307 thread_id: "test".to_string(),
1308 borrow_count: 0,
1309 stack_trace: None,
1310 is_leaked: false,
1311 lifetime_ms: None,
1312 borrow_info: None,
1313 clone_info: None,
1314 ownership_history_available: false,
1315 smart_pointer_info: None,
1316 memory_layout: None,
1317 generic_info: None,
1318 dynamic_type_info: None,
1319 runtime_state: None,
1320 stack_allocation: None,
1321 temporary_object: None,
1322 fragmentation_analysis: None,
1323 generic_instantiation: None,
1324 type_relationships: None,
1325 type_usage: None,
1326 function_call_tracking: None,
1327 lifecycle_tracking: None,
1328 access_tracking: None,
1329 drop_chain_analysis: None,
1330 };
1331
1332 let inferred_var = engine.infer_var_name(&alloc);
1333 assert!(inferred_var.starts_with(expected_prefix));
1334 assert!(inferred_var.contains("1234")); }
1336 }
1337
1338 #[test]
1339 fn test_optimization_levels() {
1340 let levels = vec![
1342 OptimizationLevel::Low,
1343 OptimizationLevel::Medium,
1344 OptimizationLevel::High,
1345 OptimizationLevel::Maximum,
1346 ];
1347
1348 for level in levels {
1349 let config = AnalysisConfig {
1350 optimization_level: level.clone(),
1351 parallel_processing: true,
1352 enhanced_ffi_analysis: true,
1353 security_analysis: false,
1354 batch_size: 1000,
1355 };
1356
1357 let engine = StandardAnalysisEngine::with_config(config);
1358 let allocations = create_test_allocations();
1359
1360 let memory_result = engine.create_memory_analysis(&allocations);
1362 assert!(memory_result.is_ok());
1363 let memory_data = memory_result.unwrap();
1364 assert_eq!(
1365 memory_data.metadata.optimization_level,
1366 format!("{:?}", level)
1367 );
1368
1369 let lifetime_result = engine.create_lifetime_analysis(&allocations);
1370 assert!(lifetime_result.is_ok());
1371
1372 let performance_result = engine.create_performance_analysis(&allocations);
1373 assert!(performance_result.is_ok());
1374
1375 let complex_types_result = engine.create_complex_types_analysis(&allocations);
1376 assert!(complex_types_result.is_ok());
1377 }
1378 }
1379
1380 #[test]
1381 fn test_analysis_error_display() {
1382 let processing_error = AnalysisError::ProcessingError("Test processing error".to_string());
1383 assert_eq!(
1384 processing_error.to_string(),
1385 "Processing error: Test processing error"
1386 );
1387
1388 let serialization_error =
1389 AnalysisError::SerializationError("Test serialization error".to_string());
1390 assert_eq!(
1391 serialization_error.to_string(),
1392 "Serialization error: Test serialization error"
1393 );
1394
1395 let invalid_data_error = AnalysisError::InvalidData("Test invalid data".to_string());
1396 assert_eq!(
1397 invalid_data_error.to_string(),
1398 "Invalid data: Test invalid data"
1399 );
1400 }
1401
1402 #[test]
1403 fn test_analysis_error_debug() {
1404 let error = AnalysisError::ProcessingError("Debug test".to_string());
1405 let debug_str = format!("{:?}", error);
1406 assert!(debug_str.contains("ProcessingError"));
1407 assert!(debug_str.contains("Debug test"));
1408 }
1409
1410 #[test]
1411 fn test_analysis_data_debug_and_clone() {
1412 let metadata = AnalysisMetadata {
1413 analysis_type: "test_analysis".to_string(),
1414 timestamp: 1234567890,
1415 total_allocations: 10,
1416 optimization_level: "High".to_string(),
1417 };
1418
1419 let data = AnalysisData {
1420 data: serde_json::json!({"test": "value"}),
1421 metadata: metadata.clone(),
1422 };
1423
1424 let debug_str = format!("{:?}", data);
1426 assert!(debug_str.contains("AnalysisData"));
1427 assert!(debug_str.contains("test_analysis"));
1428
1429 let cloned_data = data.clone();
1431 assert_eq!(
1432 cloned_data.metadata.analysis_type,
1433 data.metadata.analysis_type
1434 );
1435 assert_eq!(cloned_data.metadata.timestamp, data.metadata.timestamp);
1436 assert_eq!(
1437 cloned_data.metadata.total_allocations,
1438 data.metadata.total_allocations
1439 );
1440 }
1441
1442 #[test]
1443 fn test_analysis_metadata_debug_and_clone() {
1444 let metadata = AnalysisMetadata {
1445 analysis_type: "test_metadata".to_string(),
1446 timestamp: 9876543210,
1447 total_allocations: 42,
1448 optimization_level: "Maximum".to_string(),
1449 };
1450
1451 let debug_str = format!("{:?}", metadata);
1453 assert!(debug_str.contains("AnalysisMetadata"));
1454 assert!(debug_str.contains("test_metadata"));
1455 assert!(debug_str.contains("42"));
1456
1457 let cloned_metadata = metadata.clone();
1459 assert_eq!(cloned_metadata.analysis_type, metadata.analysis_type);
1460 assert_eq!(cloned_metadata.timestamp, metadata.timestamp);
1461 assert_eq!(
1462 cloned_metadata.total_allocations,
1463 metadata.total_allocations
1464 );
1465 assert_eq!(
1466 cloned_metadata.optimization_level,
1467 metadata.optimization_level
1468 );
1469 }
1470
1471 #[test]
1472 fn test_analysis_config_debug_and_clone() {
1473 let config = AnalysisConfig {
1474 optimization_level: OptimizationLevel::Medium,
1475 parallel_processing: false,
1476 enhanced_ffi_analysis: true,
1477 security_analysis: true,
1478 batch_size: 2000,
1479 };
1480
1481 let debug_str = format!("{:?}", config);
1483 assert!(debug_str.contains("AnalysisConfig"));
1484 assert!(debug_str.contains("Medium"));
1485 assert!(debug_str.contains("2000"));
1486
1487 let cloned_config = config.clone();
1489 assert_eq!(cloned_config.optimization_level, config.optimization_level);
1490 assert_eq!(
1491 cloned_config.parallel_processing,
1492 config.parallel_processing
1493 );
1494 assert_eq!(
1495 cloned_config.enhanced_ffi_analysis,
1496 config.enhanced_ffi_analysis
1497 );
1498 assert_eq!(cloned_config.security_analysis, config.security_analysis);
1499 assert_eq!(cloned_config.batch_size, config.batch_size);
1500 }
1501
1502 #[test]
1503 fn test_optimization_level_equality() {
1504 assert_eq!(OptimizationLevel::Low, OptimizationLevel::Low);
1505 assert_eq!(OptimizationLevel::Medium, OptimizationLevel::Medium);
1506 assert_eq!(OptimizationLevel::High, OptimizationLevel::High);
1507 assert_eq!(OptimizationLevel::Maximum, OptimizationLevel::Maximum);
1508
1509 assert_ne!(OptimizationLevel::Low, OptimizationLevel::Medium);
1510 assert_ne!(OptimizationLevel::Medium, OptimizationLevel::High);
1511 assert_ne!(OptimizationLevel::High, OptimizationLevel::Maximum);
1512 }
1513
1514 #[test]
1515 fn test_convert_to_export_options() {
1516 let engine = StandardAnalysisEngine::new();
1517 let export_options = engine.convert_to_export_options();
1518
1519 assert_eq!(export_options.batch_size, 1000);
1522 assert!(export_options.parallel_processing);
1523 }
1524}