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.expect("Lifetime analysis should succeed with valid test data");
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.expect("Memory analysis should succeed with empty data");
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 =
980 lifetime_result.expect("Lifetime analysis should succeed with empty data");
981 assert_eq!(lifetime_data.metadata.total_allocations, 0);
982
983 let performance_result = engine.create_performance_analysis(&empty_allocations);
984 assert!(performance_result.is_ok());
985 let performance_data =
986 performance_result.expect("Performance analysis should succeed with empty data");
987 assert_eq!(performance_data.metadata.total_allocations, 0);
988
989 let complex_types_result = engine.create_complex_types_analysis(&empty_allocations);
990 assert!(complex_types_result.is_ok());
991 let complex_types_data =
992 complex_types_result.expect("Complex types analysis should succeed with empty data");
993 assert_eq!(complex_types_data.metadata.total_allocations, 0);
994 }
995
996 fn create_multiple_test_allocations() -> Vec<AllocationInfo> {
997 vec![
998 AllocationInfo {
999 ptr: 0x1000,
1000 size: 1024,
1001 var_name: Some("buffer".to_string()),
1002 type_name: Some("Vec<u8>".to_string()),
1003 scope_name: Some("main".to_string()),
1004 timestamp_alloc: 1234567890,
1005 timestamp_dealloc: Some(1234567990),
1006 thread_id: "main".to_string(),
1007 borrow_count: 0,
1008 stack_trace: Some(vec!["main".to_string(), "allocate".to_string()]),
1009 is_leaked: false,
1010 lifetime_ms: Some(100),
1011 borrow_info: None,
1012 clone_info: None,
1013 ownership_history_available: false,
1014 smart_pointer_info: None,
1015 memory_layout: None,
1016 generic_info: None,
1017 dynamic_type_info: None,
1018 runtime_state: None,
1019 stack_allocation: None,
1020 temporary_object: None,
1021 fragmentation_analysis: None,
1022 generic_instantiation: None,
1023 type_relationships: None,
1024 type_usage: None,
1025 function_call_tracking: None,
1026 lifecycle_tracking: None,
1027 access_tracking: None,
1028 drop_chain_analysis: None,
1029 },
1030 AllocationInfo {
1031 ptr: 0x2000,
1032 size: 512,
1033 var_name: None, type_name: None, scope_name: Some("function".to_string()),
1036 timestamp_alloc: 1234567900,
1037 timestamp_dealloc: None,
1038 thread_id: "worker".to_string(),
1039 borrow_count: 2,
1040 stack_trace: None,
1041 is_leaked: true,
1042 lifetime_ms: None,
1043 borrow_info: None,
1044 clone_info: None,
1045 ownership_history_available: false,
1046 smart_pointer_info: None,
1047 memory_layout: None,
1048 generic_info: None,
1049 dynamic_type_info: None,
1050 runtime_state: None,
1051 stack_allocation: None,
1052 temporary_object: None,
1053 fragmentation_analysis: None,
1054 generic_instantiation: None,
1055 type_relationships: None,
1056 type_usage: None,
1057 function_call_tracking: None,
1058 lifecycle_tracking: None,
1059 access_tracking: None,
1060 drop_chain_analysis: None,
1061 },
1062 AllocationInfo {
1063 ptr: 0x3000,
1064 size: 8,
1065 var_name: Some("counter".to_string()),
1066 type_name: Some("HashMap<String, i32>".to_string()),
1067 scope_name: None, timestamp_alloc: 1234567910,
1069 timestamp_dealloc: Some(1234567950),
1070 thread_id: "main".to_string(),
1071 borrow_count: 1,
1072 stack_trace: Some(vec!["main".to_string()]),
1073 is_leaked: false,
1074 lifetime_ms: Some(40),
1075 borrow_info: None,
1076 clone_info: None,
1077 ownership_history_available: false,
1078 smart_pointer_info: None,
1079 memory_layout: None,
1080 generic_info: None,
1081 dynamic_type_info: None,
1082 runtime_state: None,
1083 stack_allocation: None,
1084 temporary_object: None,
1085 fragmentation_analysis: None,
1086 generic_instantiation: None,
1087 type_relationships: None,
1088 type_usage: None,
1089 function_call_tracking: None,
1090 lifecycle_tracking: None,
1091 access_tracking: None,
1092 drop_chain_analysis: None,
1093 },
1094 ]
1095 }
1096
1097 #[test]
1098 fn test_multiple_allocations_analysis() {
1099 let engine = StandardAnalysisEngine::new();
1100 let allocations = create_multiple_test_allocations();
1101
1102 let memory_result = engine.create_memory_analysis(&allocations);
1104 assert!(memory_result.is_ok());
1105 let memory_data = memory_result.unwrap();
1106 assert_eq!(memory_data.metadata.total_allocations, 3);
1107
1108 let summary = memory_data.data.get("summary").unwrap();
1110 assert_eq!(
1111 summary.get("total_allocations").unwrap().as_u64().unwrap(),
1112 3
1113 );
1114 assert_eq!(summary.get("total_memory").unwrap().as_u64().unwrap(), 1544); assert_eq!(summary.get("leaked_count").unwrap().as_u64().unwrap(), 1);
1116 assert_eq!(summary.get("max_size").unwrap().as_u64().unwrap(), 1024);
1117 assert_eq!(summary.get("min_size").unwrap().as_u64().unwrap(), 8);
1118 }
1119
1120 #[test]
1121 fn test_lifetime_analysis_with_multiple_allocations() {
1122 let engine = StandardAnalysisEngine::new();
1123 let allocations = create_multiple_test_allocations();
1124
1125 let result = engine.create_lifetime_analysis(&allocations);
1126 assert!(result.is_ok());
1127 let analysis_data = result.unwrap();
1128
1129 let events = analysis_data
1131 .data
1132 .get("lifecycle_events")
1133 .unwrap()
1134 .as_array()
1135 .unwrap();
1136 assert_eq!(events.len(), 5); let scope_analysis = analysis_data
1140 .data
1141 .get("scope_analysis")
1142 .unwrap()
1143 .as_object()
1144 .unwrap();
1145 assert!(scope_analysis.contains_key("main"));
1146 assert!(scope_analysis.contains_key("function"));
1147 assert!(scope_analysis.contains_key("global"));
1148 }
1149
1150 #[test]
1151 fn test_performance_analysis_with_multiple_threads() {
1152 let engine = StandardAnalysisEngine::new();
1153 let allocations = create_multiple_test_allocations();
1154
1155 let result = engine.create_performance_analysis(&allocations);
1156 assert!(result.is_ok());
1157 let analysis_data = result.unwrap();
1158
1159 let thread_analysis = analysis_data
1161 .data
1162 .get("thread_analysis")
1163 .unwrap()
1164 .as_object()
1165 .unwrap();
1166 assert!(thread_analysis.contains_key("main"));
1167 assert!(thread_analysis.contains_key("worker"));
1168
1169 let main_stats = thread_analysis.get("main").unwrap();
1171 assert_eq!(
1172 main_stats
1173 .get("allocation_count")
1174 .unwrap()
1175 .as_u64()
1176 .unwrap(),
1177 2
1178 );
1179 assert_eq!(
1180 main_stats.get("total_size").unwrap().as_u64().unwrap(),
1181 1032
1182 ); let worker_stats = thread_analysis.get("worker").unwrap();
1186 assert_eq!(
1187 worker_stats
1188 .get("allocation_count")
1189 .unwrap()
1190 .as_u64()
1191 .unwrap(),
1192 1
1193 );
1194 assert_eq!(
1195 worker_stats.get("total_size").unwrap().as_u64().unwrap(),
1196 512
1197 );
1198 }
1199
1200 #[test]
1201 fn test_complex_types_categorization() {
1202 let engine = StandardAnalysisEngine::new();
1203 let allocations = create_multiple_test_allocations();
1204
1205 let result = engine.create_complex_types_analysis(&allocations);
1206 assert!(result.is_ok());
1207 let analysis_data = result.unwrap();
1208
1209 let categorized = analysis_data
1211 .data
1212 .get("categorized_types")
1213 .unwrap()
1214 .as_object()
1215 .unwrap();
1216 assert!(categorized.contains_key("generic")); assert!(categorized.contains_key("primitive")); let generic_types = analysis_data
1221 .data
1222 .get("generic_types")
1223 .unwrap()
1224 .as_object()
1225 .unwrap();
1226 assert!(generic_types.contains_key("Vec<u8>"));
1227 assert!(generic_types.contains_key("HashMap<String, i32>"));
1228 }
1229
1230 #[test]
1231 fn test_type_name_inference() {
1232 let engine = StandardAnalysisEngine::new();
1233
1234 let test_cases = vec![
1236 (0, "ZeroSizedType"),
1237 (1, "u8_or_bool"),
1238 (2, "u16_or_char"),
1239 (4, "u32_or_f32_or_i32"),
1240 (8, "u64_or_f64_or_i64_or_usize"),
1241 (16, "u128_or_i128_or_complex_struct"),
1242 (24, "Vec_or_String_header"),
1243 (32, "HashMap_or_BTreeMap_header"),
1244 (1024, "LargeAllocation_1024bytes"),
1245 (48, "AlignedStruct_48bytes"), (33, "CustomType_33bytes"), ];
1248
1249 for (size, expected_prefix) in test_cases {
1250 let alloc = AllocationInfo {
1251 ptr: 0x1000,
1252 size,
1253 var_name: None,
1254 type_name: None, scope_name: None,
1256 timestamp_alloc: 0,
1257 timestamp_dealloc: None,
1258 thread_id: "test".to_string(),
1259 borrow_count: 0,
1260 stack_trace: None,
1261 is_leaked: false,
1262 lifetime_ms: None,
1263 borrow_info: None,
1264 clone_info: None,
1265 ownership_history_available: false,
1266 smart_pointer_info: None,
1267 memory_layout: None,
1268 generic_info: None,
1269 dynamic_type_info: None,
1270 runtime_state: None,
1271 stack_allocation: None,
1272 temporary_object: None,
1273 fragmentation_analysis: None,
1274 generic_instantiation: None,
1275 type_relationships: None,
1276 type_usage: None,
1277 function_call_tracking: None,
1278 lifecycle_tracking: None,
1279 access_tracking: None,
1280 drop_chain_analysis: None,
1281 };
1282
1283 let inferred_type = engine.infer_type_name(&alloc);
1284 assert_eq!(inferred_type, expected_prefix);
1285 }
1286 }
1287
1288 #[test]
1289 fn test_var_name_inference() {
1290 let engine = StandardAnalysisEngine::new();
1291
1292 let test_cases = vec![
1293 (0, "zero_sized_var"),
1294 (4, "primitive_var"),
1295 (16, "small_struct_var"),
1296 (128, "medium_struct_var"),
1297 (512, "large_struct_var"),
1298 (2048, "heap_allocated_var"),
1299 ];
1300
1301 for (size, expected_prefix) in test_cases {
1302 let alloc = AllocationInfo {
1303 ptr: 0x1234,
1304 size,
1305 var_name: None, type_name: Some("TestType".to_string()),
1307 scope_name: None,
1308 timestamp_alloc: 0,
1309 timestamp_dealloc: None,
1310 thread_id: "test".to_string(),
1311 borrow_count: 0,
1312 stack_trace: None,
1313 is_leaked: false,
1314 lifetime_ms: None,
1315 borrow_info: None,
1316 clone_info: None,
1317 ownership_history_available: false,
1318 smart_pointer_info: None,
1319 memory_layout: None,
1320 generic_info: None,
1321 dynamic_type_info: None,
1322 runtime_state: None,
1323 stack_allocation: None,
1324 temporary_object: None,
1325 fragmentation_analysis: None,
1326 generic_instantiation: None,
1327 type_relationships: None,
1328 type_usage: None,
1329 function_call_tracking: None,
1330 lifecycle_tracking: None,
1331 access_tracking: None,
1332 drop_chain_analysis: None,
1333 };
1334
1335 let inferred_var = engine.infer_var_name(&alloc);
1336 assert!(inferred_var.starts_with(expected_prefix));
1337 assert!(inferred_var.contains("1234")); }
1339 }
1340
1341 #[test]
1342 fn test_optimization_levels() {
1343 let levels = vec![
1345 OptimizationLevel::Low,
1346 OptimizationLevel::Medium,
1347 OptimizationLevel::High,
1348 OptimizationLevel::Maximum,
1349 ];
1350
1351 for level in levels {
1352 let config = AnalysisConfig {
1353 optimization_level: level.clone(),
1354 parallel_processing: true,
1355 enhanced_ffi_analysis: true,
1356 security_analysis: false,
1357 batch_size: 1000,
1358 };
1359
1360 let engine = StandardAnalysisEngine::with_config(config);
1361 let allocations = create_test_allocations();
1362
1363 let memory_result = engine.create_memory_analysis(&allocations);
1365 assert!(memory_result.is_ok());
1366 let memory_data = memory_result.unwrap();
1367 assert_eq!(
1368 memory_data.metadata.optimization_level,
1369 format!("{:?}", level)
1370 );
1371
1372 let lifetime_result = engine.create_lifetime_analysis(&allocations);
1373 assert!(lifetime_result.is_ok());
1374
1375 let performance_result = engine.create_performance_analysis(&allocations);
1376 assert!(performance_result.is_ok());
1377
1378 let complex_types_result = engine.create_complex_types_analysis(&allocations);
1379 assert!(complex_types_result.is_ok());
1380 }
1381 }
1382
1383 #[test]
1384 fn test_analysis_error_display() {
1385 let processing_error = AnalysisError::ProcessingError("Test processing error".to_string());
1386 assert_eq!(
1387 processing_error.to_string(),
1388 "Processing error: Test processing error"
1389 );
1390
1391 let serialization_error =
1392 AnalysisError::SerializationError("Test serialization error".to_string());
1393 assert_eq!(
1394 serialization_error.to_string(),
1395 "Serialization error: Test serialization error"
1396 );
1397
1398 let invalid_data_error = AnalysisError::InvalidData("Test invalid data".to_string());
1399 assert_eq!(
1400 invalid_data_error.to_string(),
1401 "Invalid data: Test invalid data"
1402 );
1403 }
1404
1405 #[test]
1406 fn test_analysis_error_debug() {
1407 let error = AnalysisError::ProcessingError("Debug test".to_string());
1408 let debug_str = format!("{:?}", error);
1409 assert!(debug_str.contains("ProcessingError"));
1410 assert!(debug_str.contains("Debug test"));
1411 }
1412
1413 #[test]
1414 fn test_analysis_data_debug_and_clone() {
1415 let metadata = AnalysisMetadata {
1416 analysis_type: "test_analysis".to_string(),
1417 timestamp: 1234567890,
1418 total_allocations: 10,
1419 optimization_level: "High".to_string(),
1420 };
1421
1422 let data = AnalysisData {
1423 data: serde_json::json!({"test": "value"}),
1424 metadata: metadata.clone(),
1425 };
1426
1427 let debug_str = format!("{:?}", data);
1429 assert!(debug_str.contains("AnalysisData"));
1430 assert!(debug_str.contains("test_analysis"));
1431
1432 let cloned_data = data.clone();
1434 assert_eq!(
1435 cloned_data.metadata.analysis_type,
1436 data.metadata.analysis_type
1437 );
1438 assert_eq!(cloned_data.metadata.timestamp, data.metadata.timestamp);
1439 assert_eq!(
1440 cloned_data.metadata.total_allocations,
1441 data.metadata.total_allocations
1442 );
1443 }
1444
1445 #[test]
1446 fn test_analysis_metadata_debug_and_clone() {
1447 let metadata = AnalysisMetadata {
1448 analysis_type: "test_metadata".to_string(),
1449 timestamp: 9876543210,
1450 total_allocations: 42,
1451 optimization_level: "Maximum".to_string(),
1452 };
1453
1454 let debug_str = format!("{:?}", metadata);
1456 assert!(debug_str.contains("AnalysisMetadata"));
1457 assert!(debug_str.contains("test_metadata"));
1458 assert!(debug_str.contains("42"));
1459
1460 let cloned_metadata = metadata.clone();
1462 assert_eq!(cloned_metadata.analysis_type, metadata.analysis_type);
1463 assert_eq!(cloned_metadata.timestamp, metadata.timestamp);
1464 assert_eq!(
1465 cloned_metadata.total_allocations,
1466 metadata.total_allocations
1467 );
1468 assert_eq!(
1469 cloned_metadata.optimization_level,
1470 metadata.optimization_level
1471 );
1472 }
1473
1474 #[test]
1475 fn test_analysis_config_debug_and_clone() {
1476 let config = AnalysisConfig {
1477 optimization_level: OptimizationLevel::Medium,
1478 parallel_processing: false,
1479 enhanced_ffi_analysis: true,
1480 security_analysis: true,
1481 batch_size: 2000,
1482 };
1483
1484 let debug_str = format!("{:?}", config);
1486 assert!(debug_str.contains("AnalysisConfig"));
1487 assert!(debug_str.contains("Medium"));
1488 assert!(debug_str.contains("2000"));
1489
1490 let cloned_config = config.clone();
1492 assert_eq!(cloned_config.optimization_level, config.optimization_level);
1493 assert_eq!(
1494 cloned_config.parallel_processing,
1495 config.parallel_processing
1496 );
1497 assert_eq!(
1498 cloned_config.enhanced_ffi_analysis,
1499 config.enhanced_ffi_analysis
1500 );
1501 assert_eq!(cloned_config.security_analysis, config.security_analysis);
1502 assert_eq!(cloned_config.batch_size, config.batch_size);
1503 }
1504
1505 #[test]
1506 fn test_optimization_level_equality() {
1507 assert_eq!(OptimizationLevel::Low, OptimizationLevel::Low);
1508 assert_eq!(OptimizationLevel::Medium, OptimizationLevel::Medium);
1509 assert_eq!(OptimizationLevel::High, OptimizationLevel::High);
1510 assert_eq!(OptimizationLevel::Maximum, OptimizationLevel::Maximum);
1511
1512 assert_ne!(OptimizationLevel::Low, OptimizationLevel::Medium);
1513 assert_ne!(OptimizationLevel::Medium, OptimizationLevel::High);
1514 assert_ne!(OptimizationLevel::High, OptimizationLevel::Maximum);
1515 }
1516
1517 #[test]
1518 fn test_convert_to_export_options() {
1519 let engine = StandardAnalysisEngine::new();
1520 let export_options = engine.convert_to_export_options();
1521
1522 assert_eq!(export_options.batch_size, 1000);
1525 assert!(export_options.parallel_processing);
1526 }
1527}