memscope_rs/cli/commands/html_from_json/
direct_json_template.rs

1use serde_json::Value;
2use std::collections::HashMap;
3use std::error::Error;
4
5use super::html::{get_embedded_styles_css, get_html_template};
6use super::js::get_embedded_script_js;
7
8/// Generate HTML directly from raw JSON data
9pub fn generate_direct_html(json_data: &HashMap<String, Value>) -> Result<String, Box<dyn Error>> {
10    tracing::info!("🎨 Generating enhanced HTML with embedded JSON data...");
11
12    // Validate that we have essential data
13    if json_data.is_empty() {
14        return Err("No JSON data provided for HTML generation".into());
15    }
16
17    // Log what data we have
18    for (key, value) in json_data {
19        tracing::info!(
20            "📊 Found data: {} ({} bytes)",
21            key,
22            serde_json::to_string(value).unwrap_or_default().len()
23        );
24    }
25
26    // Transform the data structure to match JavaScript expectations
27    let transformed_data = transform_json_data_structure(json_data)?;
28
29    // Generate safety risk data from the transformed allocations
30    let safety_risk_data = generate_safety_risk_data_from_json(&transformed_data)?;
31
32    // Serialize the transformed JSON data for embedding with proper escaping
33    let json_data_str = serde_json::to_string(&transformed_data)
34        .map_err(|e| format!("Failed to serialize JSON data: {e}"))?;
35
36    // Debug: Log data serialization info
37    tracing::info!(
38        "📊 JSON data serialized: {} characters",
39        json_data_str.len()
40    );
41    if let Some(memory_analysis) = transformed_data.get("memory_analysis") {
42        if let Some(allocations) = memory_analysis.get("allocations") {
43            if let Some(allocs_array) = allocations.as_array() {
44                tracing::info!(
45                    "📊 Memory analysis allocations: {} items",
46                    allocs_array.len()
47                );
48            }
49        }
50    }
51
52    // Log data structure for debugging
53    if let Some(unsafe_ffi_data) = json_data.get("basic_usage_snapshot_unsafe_ffi") {
54        if let Some(summary) = unsafe_ffi_data.get("summary") {
55            tracing::info!("📊 Unsafe/FFI Summary: {summary}");
56        }
57    }
58
59    // Try multiple possible paths for the template files - prioritize the original dashboard.html
60
61    // Use embedded template to avoid external file dependency
62    let template_content = get_html_template().to_string();
63
64    // Use embedded CSS to avoid external file dependency
65    let css_content = get_embedded_styles_css().to_string();
66
67    // Use embedded JavaScript to avoid external file dependency
68    let js_content = get_embedded_script_js().to_string();
69
70    // Replace placeholders in the template with proper escaping
71    let mut html = template_content
72        .replace("{{ json_data }}", &json_data_str) // with spaces
73        .replace("{{json_data}}", &json_data_str) // without spaces
74        .replace("{{CSS_CONTENT}}", &css_content)
75        .replace("{{JS_CONTENT}}", &js_content)
76        .replace("{{DATA_PLACEHOLDER}}", &json_data_str)
77        .replace(
78            "{\n        {\n        CSS_CONTENT\n      }\n    }",
79            &css_content,
80        ); // fix CSS format issues - match exact template spacing
81
82    // Inject safety risk data into the HTML
83    html = inject_safety_risk_data_into_html(html, &safety_risk_data)?;
84
85    tracing::info!(
86        "✅ Generated HTML with {} bytes of embedded JSON data",
87        json_data_str.len()
88    );
89
90    Ok(html)
91}
92
93/// Transform the raw JSON data structure to match JavaScript expectations
94/// This function preprocesses data in Rust to create visualization-ready structures
95fn transform_json_data_structure(
96    json_data: &HashMap<String, Value>,
97) -> Result<serde_json::Map<String, Value>, Box<dyn Error>> {
98    let mut transformed = serde_json::Map::new();
99
100    // Process each JSON file and map it to the expected structure
101    for (file_key, file_data) in json_data {
102        // Extract the data type from the filename
103        if file_key.contains("memory_analysis") {
104            let enhanced_memory_data = enhance_memory_analysis_data(file_data)?;
105            transformed.insert("memory_analysis".to_string(), enhanced_memory_data);
106        } else if file_key.contains("lifetime") {
107            let enhanced_lifetime_data = enhance_lifetime_data(file_data)?;
108            transformed.insert("lifetime".to_string(), enhanced_lifetime_data);
109        } else if file_key.contains("complex_types") {
110            transformed.insert("complex_types".to_string(), file_data.clone());
111        } else if file_key.contains("performance") {
112            transformed.insert("performance".to_string(), file_data.clone());
113        } else if file_key.contains("unsafe_ffi") {
114            let enhanced_ffi_data = enhance_ffi_data(file_data)?;
115            transformed.insert("unsafe_ffi".to_string(), enhanced_ffi_data);
116            // Also add it with the specific key that JavaScript expects
117            transformed.insert(file_key.clone(), file_data.clone());
118        } else if file_key.contains("security_violations") {
119            transformed.insert("security_violations".to_string(), file_data.clone());
120        } else if file_key.contains("variable_relationships") {
121            transformed.insert("variable_relationships".to_string(), file_data.clone());
122        } else {
123            // Keep any other data with its original key
124            transformed.insert(file_key.clone(), file_data.clone());
125        }
126    }
127
128    // Ensure we have all expected data structures, even if empty
129    if !transformed.contains_key("memory_analysis") {
130        transformed.insert(
131            "memory_analysis".to_string(),
132            serde_json::json!({
133                "allocations": [],
134                "stats": {
135                    "total_allocations": 0,
136                    "active_allocations": 0,
137                    "total_memory": 0,
138                    "active_memory": 0
139                }
140            }),
141        );
142    }
143
144    if !transformed.contains_key("lifetime") {
145        transformed.insert(
146            "lifetime".to_string(),
147            serde_json::json!({
148                "lifecycle_events": []
149            }),
150        );
151    }
152
153    if !transformed.contains_key("complex_types") {
154        transformed.insert(
155            "complex_types".to_string(),
156            serde_json::json!({
157                "categorized_types": {
158                    "generic_types": [],
159                    "collections": [],
160                    "smart_pointers": [],
161                    "trait_objects": []
162                },
163                "summary": {
164                    "total_complex_types": 0,
165                    "generic_type_count": 0
166                }
167            }),
168        );
169    }
170
171    if !transformed.contains_key("performance") {
172        transformed.insert(
173            "performance".to_string(),
174            serde_json::json!({
175                "memory_performance": {
176                    "active_memory": 0,
177                    "peak_memory": 0,
178                    "total_allocated": 0
179                },
180                "allocation_distribution": {
181                    "tiny": 0,
182                    "small": 0,
183                    "medium": 0,
184                    "large": 0,
185                    "massive": 0
186                }
187            }),
188        );
189    }
190
191    if !transformed.contains_key("unsafe_ffi") {
192        transformed.insert(
193            "unsafe_ffi".to_string(),
194            serde_json::json!({
195                "summary": {
196                    "total_risk_items": 0,
197                    "unsafe_count": 0,
198                    "ffi_count": 0,
199                    "safety_violations": 0
200                },
201                "enhanced_ffi_data": [],
202                "safety_violations": []
203            }),
204        );
205    }
206
207    if !transformed.contains_key("security_violations") {
208        transformed.insert(
209            "security_violations".to_string(),
210            serde_json::json!({
211                "metadata": {
212                    "total_violations": 0
213                },
214                "violation_reports": [],
215                "security_summary": {
216                    "security_analysis_summary": {
217                        "total_violations": 0,
218                        "severity_breakdown": {
219                            "critical": 0,
220                            "high": 0,
221                            "medium": 0,
222                            "low": 0,
223                            "info": 0
224                        }
225                    }
226                }
227            }),
228        );
229    }
230
231    tracing::info!(
232        "🔄 Transformed data structure with keys: {:?}",
233        transformed.keys().collect::<Vec<_>>()
234    );
235
236    Ok(transformed)
237}
238
239/// Enhance memory analysis data with visualization-ready structures
240fn enhance_memory_analysis_data(data: &Value) -> Result<Value, Box<dyn Error>> {
241    let mut enhanced = data.clone();
242
243    if let Some(allocations) = data.get("allocations").and_then(|a| a.as_array()) {
244        // Add memory fragmentation analysis
245        let fragmentation_data = analyze_memory_fragmentation(allocations);
246
247        // Add memory growth trends
248        let growth_trends = analyze_memory_growth_trends(allocations);
249
250        // Create enhanced structure
251        if let Some(obj) = enhanced.as_object_mut() {
252            obj.insert("fragmentation_analysis".to_string(), fragmentation_data);
253            obj.insert("growth_trends".to_string(), growth_trends);
254            obj.insert("visualization_ready".to_string(), serde_json::json!(true));
255        }
256    }
257
258    Ok(enhanced)
259}
260
261/// Enhance lifetime data with colorful progress bar information
262fn enhance_lifetime_data(data: &Value) -> Result<Value, Box<dyn Error>> {
263    let mut enhanced = data.clone();
264
265    if let Some(events) = data.get("lifecycle_events").and_then(|e| e.as_array()) {
266        // Filter for user-defined variables
267        let user_variables: Vec<&Value> = events
268            .iter()
269            .filter(|event| {
270                event
271                    .get("var_name")
272                    .and_then(|v| v.as_str())
273                    .is_some_and(|s| s != "unknown")
274                    && event
275                        .get("type_name")
276                        .and_then(|v| v.as_str())
277                        .is_some_and(|s| s != "unknown")
278            })
279            .collect();
280
281        // Group by variable name and add color information
282        let mut variable_groups = std::collections::HashMap::new();
283        for (index, event) in user_variables.iter().enumerate() {
284            if let Some(var_name) = event.get("var_name").and_then(|v| v.as_str()) {
285                let color_index = index % 10; // 10 colors in palette
286                let color = get_progress_color(color_index);
287
288                let group = variable_groups
289                    .entry(var_name.to_string())
290                    .or_insert_with(|| {
291                        serde_json::json!({
292                            "var_name": var_name,
293                            "type_name": event.get("type_name"),
294                            "color": color,
295                            "color_index": color_index,
296                            "events": []
297                        })
298                    });
299
300                if let Some(events_array) = group.get_mut("events").and_then(|e| e.as_array_mut()) {
301                    events_array.push((*event).clone());
302                }
303            }
304        }
305
306        // Convert to array and add to enhanced data
307        let grouped_variables: Vec<Value> = variable_groups.into_values().collect();
308
309        if let Some(obj) = enhanced.as_object_mut() {
310            obj.insert(
311                "variable_groups".to_string(),
312                serde_json::json!(grouped_variables),
313            );
314            obj.insert(
315                "user_variables_count".to_string(),
316                serde_json::json!(user_variables.len()),
317            );
318            obj.insert("visualization_ready".to_string(), serde_json::json!(true));
319        }
320    }
321
322    Ok(enhanced)
323}
324
325/// Enhance FFI data with comprehensive analysis and SVG-inspired visualization data
326fn enhance_ffi_data(data: &Value) -> Result<Value, Box<dyn Error>> {
327    let mut enhanced = data.clone();
328
329    let empty_vec = vec![];
330    // Use the actual allocations field from the JSON data
331    let allocations = data
332        .get("allocations")
333        .and_then(|d| d.as_array())
334        .unwrap_or(&empty_vec);
335
336    // Fallback to enhanced_ffi_data if allocations is not found
337    let enhanced_data = if allocations.is_empty() {
338        data.get("enhanced_ffi_data")
339            .and_then(|d| d.as_array())
340            .unwrap_or(&empty_vec)
341    } else {
342        allocations
343    };
344
345    let boundary_events = data
346        .get("boundary_events")
347        .and_then(|d| d.as_array())
348        .unwrap_or(&empty_vec);
349
350    tracing::info!(
351        "🔍 FFI data enhancement - allocations: {}, enhanced_data: {}, boundary_events: {}",
352        allocations.len(),
353        enhanced_data.len(),
354        boundary_events.len()
355    );
356
357    // Calculate comprehensive statistics using the actual allocations
358    let stats = calculate_ffi_statistics_from_allocations(enhanced_data, boundary_events);
359
360    // Analyze language interactions
361    let language_interactions = analyze_language_interactions(boundary_events);
362
363    // Safety analysis using actual allocations
364    let safety_analysis = analyze_safety_metrics_from_allocations(enhanced_data);
365
366    // Create SVG-inspired dashboard metrics
367    let dashboard_metrics = create_ffi_dashboard_metrics(enhanced_data, boundary_events);
368
369    // Create memory hotspots analysis
370    let memory_hotspots = analyze_memory_hotspots(enhanced_data);
371
372    // Create cross-language memory flow analysis
373    let memory_flow = analyze_cross_language_memory_flow(enhanced_data, boundary_events);
374
375    // Create risk assessment
376    let risk_assessment = create_ffi_risk_assessment(enhanced_data);
377
378    if let Some(obj) = enhanced.as_object_mut() {
379        obj.insert("comprehensive_stats".to_string(), stats);
380        obj.insert("language_interactions".to_string(), language_interactions);
381        obj.insert("safety_analysis".to_string(), safety_analysis);
382        obj.insert("dashboard_metrics".to_string(), dashboard_metrics);
383        obj.insert("memory_hotspots".to_string(), memory_hotspots);
384        obj.insert("memory_flow".to_string(), memory_flow);
385        obj.insert("risk_assessment".to_string(), risk_assessment);
386        obj.insert("visualization_ready".to_string(), serde_json::json!(true));
387        // Ensure allocations are preserved in the enhanced data
388        if !allocations.is_empty() {
389            obj.insert("allocations".to_string(), serde_json::json!(allocations));
390        }
391    }
392
393    Ok(enhanced)
394}
395
396/// Analyze memory fragmentation from allocations
397fn analyze_memory_fragmentation(allocations: &[Value]) -> Value {
398    let mut sorted_allocs: Vec<_> = allocations
399        .iter()
400        .filter_map(|alloc| {
401            let ptr_str = alloc.get("ptr")?.as_str()?;
402            let size = alloc.get("size")?.as_u64()? as usize;
403            let address = u64::from_str_radix(ptr_str.trim_start_matches("0x"), 16).ok()?;
404            Some((address, size))
405        })
406        .collect();
407
408    sorted_allocs.sort_by_key(|&(addr, _)| addr);
409
410    let mut gaps = 0;
411    let mut total_gap_size = 0u64;
412
413    for i in 1..sorted_allocs.len() {
414        let (prev_addr, prev_size) = sorted_allocs[i - 1];
415        let (curr_addr, _) = sorted_allocs[i];
416        let prev_end = prev_addr + prev_size as u64;
417
418        if curr_addr > prev_end {
419            gaps += 1;
420            total_gap_size += curr_addr - prev_end;
421        }
422    }
423
424    let total_memory: u64 = sorted_allocs.iter().map(|(_, size)| *size as u64).sum();
425    let fragmentation_score = if total_memory > 0 {
426        ((total_gap_size as f64 / (total_memory + total_gap_size) as f64) * 100.0) as u32
427    } else {
428        0
429    };
430
431    let largest_block = sorted_allocs
432        .iter()
433        .map(|(_, size)| *size)
434        .max()
435        .unwrap_or(0);
436
437    serde_json::json!({
438        "total_blocks": sorted_allocs.len(),
439        "fragmentation_score": fragmentation_score,
440        "largest_block": largest_block,
441        "gaps": gaps,
442        "total_gap_size": total_gap_size,
443        "analysis": get_fragmentation_analysis(fragmentation_score)
444    })
445}
446
447/// Analyze memory growth trends
448fn analyze_memory_growth_trends(allocations: &[Value]) -> Value {
449    let mut sorted_allocs: Vec<_> = allocations
450        .iter()
451        .filter_map(|alloc| {
452            let timestamp = alloc.get("timestamp_alloc")?.as_u64()?;
453            let size = alloc.get("size")?.as_u64()? as usize;
454            Some((timestamp, size))
455        })
456        .collect();
457
458    sorted_allocs.sort_by_key(|&(timestamp, _)| timestamp);
459
460    let mut cumulative_memory = 0;
461    let time_points: Vec<_> = sorted_allocs
462        .iter()
463        .enumerate()
464        .map(|(index, &(timestamp, size))| {
465            cumulative_memory += size;
466            serde_json::json!({
467                "timestamp": timestamp,
468                "memory": cumulative_memory,
469                "index": index
470            })
471        })
472        .take(100) // Limit for performance
473        .collect();
474
475    let peak_memory = time_points
476        .iter()
477        .filter_map(|p| p.get("memory")?.as_u64())
478        .max()
479        .unwrap_or(0);
480
481    let current_memory = time_points
482        .last()
483        .and_then(|p| p.get("memory")?.as_u64())
484        .unwrap_or(0);
485
486    let start_memory = time_points
487        .first()
488        .and_then(|p| p.get("memory")?.as_u64())
489        .unwrap_or(0);
490
491    let growth_rate = if start_memory > 0 {
492        ((current_memory as f64 - start_memory as f64) / start_memory as f64 * 100.0) as i32
493    } else {
494        0
495    };
496
497    let time_span = if time_points.len() > 1 {
498        let start_time = time_points[0]
499            .get("timestamp")
500            .and_then(|t| t.as_u64())
501            .unwrap_or(0);
502        let end_time = time_points
503            .last()
504            .and_then(|p| p.get("timestamp"))
505            .and_then(|t| t.as_u64())
506            .unwrap_or(0);
507        if end_time > start_time {
508            (end_time - start_time) / 1_000_000_000 // Convert to seconds
509        } else {
510            1
511        }
512    } else {
513        1
514    };
515
516    let allocation_rate = if time_span > 0 {
517        allocations.len() as u64 / time_span
518    } else {
519        0
520    };
521
522    serde_json::json!({
523        "peak_memory": peak_memory,
524        "current_memory": current_memory,
525        "growth_rate": growth_rate,
526        "allocation_rate": allocation_rate,
527        "time_points": time_points,
528        "analysis": get_trend_analysis(growth_rate)
529    })
530}
531
532/// Calculate comprehensive FFI statistics from allocations
533fn calculate_ffi_statistics_from_allocations(
534    allocations: &[Value],
535    boundary_events: &[Value],
536) -> Value {
537    let ffi_tracked_allocations = allocations
538        .iter()
539        .filter(|item| {
540            item.get("ffi_tracked")
541                .and_then(|f| f.as_bool())
542                .unwrap_or(false)
543        })
544        .count();
545
546    let non_ffi_allocations = allocations.len() - ffi_tracked_allocations;
547
548    let boundary_crossings = boundary_events.len();
549
550    // Count safety violations from arrays
551    let safety_violations = allocations
552        .iter()
553        .map(|item| {
554            item.get("safety_violations")
555                .and_then(|s| s.as_array())
556                .map(|arr| arr.len() as u64)
557                .unwrap_or(0)
558        })
559        .sum::<u64>();
560
561    // Count borrow conflicts
562    let borrow_conflicts = allocations
563        .iter()
564        .filter(|item| {
565            if let Some(borrow_info) = item.get("borrow_info") {
566                let immutable = borrow_info
567                    .get("immutable_borrows")
568                    .and_then(|v| v.as_u64())
569                    .unwrap_or(0);
570                let mutable = borrow_info
571                    .get("mutable_borrows")
572                    .and_then(|v| v.as_u64())
573                    .unwrap_or(0);
574                immutable > 0 && mutable > 0
575            } else {
576                false
577            }
578        })
579        .count();
580
581    // Count clones
582    let total_clones = allocations
583        .iter()
584        .map(|item| {
585            item.get("clone_info")
586                .and_then(|c| c.get("clone_count"))
587                .and_then(|cc| cc.as_u64())
588                .unwrap_or(0)
589        })
590        .sum::<u64>();
591
592    let total_memory = allocations
593        .iter()
594        .map(|item| item.get("size").and_then(|s| s.as_u64()).unwrap_or(0))
595        .sum::<u64>();
596
597    serde_json::json!({
598        "total_allocations": allocations.len(),
599        "ffi_tracked_allocations": ffi_tracked_allocations,
600        "non_ffi_allocations": non_ffi_allocations,
601        "boundary_crossings": boundary_crossings,
602        "safety_violations": safety_violations,
603        "borrow_conflicts": borrow_conflicts,
604        "total_clones": total_clones,
605        "total_memory": total_memory
606    })
607}
608
609/// Analyze language interactions from boundary events
610fn analyze_language_interactions(boundary_events: &[Value]) -> Value {
611    let mut interactions = std::collections::HashMap::new();
612
613    for event in boundary_events {
614        if let (Some(from), Some(to)) = (
615            event.get("from_context").and_then(|f| f.as_str()),
616            event.get("to_context").and_then(|t| t.as_str()),
617        ) {
618            let key = format!("{from} → {to}");
619            *interactions.entry(key).or_insert(0) += 1;
620        }
621    }
622
623    let interactions_vec: Vec<_> = interactions
624        .into_iter()
625        .map(|(interaction, count)| {
626            serde_json::json!({
627                "interaction": interaction,
628                "count": count
629            })
630        })
631        .collect();
632
633    serde_json::json!(interactions_vec)
634}
635
636/// Analyze safety metrics from allocations
637fn analyze_safety_metrics_from_allocations(allocations: &[Value]) -> Value {
638    let safe_operations = allocations
639        .iter()
640        .filter(|item| {
641            // Check if safety_violations array is empty
642            item.get("safety_violations")
643                .and_then(|s| s.as_array())
644                .map(|arr| arr.is_empty())
645                .unwrap_or(true)
646        })
647        .count();
648
649    let unsafe_operations = allocations.len() - safe_operations;
650    let total_operations = allocations.len();
651
652    let safety_percentage = if total_operations > 0 {
653        (safe_operations as f64 / total_operations as f64 * 100.0) as u32
654    } else {
655        100
656    };
657
658    // Count allocations with ownership history
659    let with_ownership_history = allocations
660        .iter()
661        .filter(|item| {
662            item.get("ownership_history_available")
663                .and_then(|o| o.as_bool())
664                .unwrap_or(false)
665        })
666        .count();
667
668    // Count leaked allocations
669    let leaked_allocations = allocations
670        .iter()
671        .filter(|item| {
672            item.get("is_leaked")
673                .and_then(|l| l.as_bool())
674                .unwrap_or(false)
675        })
676        .count();
677
678    serde_json::json!({
679        "safe_operations": safe_operations,
680        "unsafe_operations": unsafe_operations,
681        "total_operations": total_operations,
682        "safety_percentage": safety_percentage,
683        "with_ownership_history": with_ownership_history,
684        "leaked_allocations": leaked_allocations
685    })
686}
687
688/// Analyze safety metrics (legacy function for backward compatibility)
689fn _analyze_safety_metrics(enhanced_data: &[Value]) -> Value {
690    analyze_safety_metrics_from_allocations(enhanced_data)
691}
692
693/// Get progress bar color by index
694fn get_progress_color(index: usize) -> &'static str {
695    const COLORS: &[&str] = &[
696        "#ff6b6b", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff", "#5f27cd",
697        "#00d2d3", "#ff9f43",
698    ];
699    COLORS[index % COLORS.len()]
700}
701
702/// Get fragmentation analysis text
703fn get_fragmentation_analysis(score: u32) -> &'static str {
704    match score {
705        0..=9 => "Excellent memory layout with minimal fragmentation.",
706        10..=24 => "Good memory layout with low fragmentation.",
707        25..=49 => "Moderate fragmentation detected. Consider memory pool allocation.",
708        _ => "High fragmentation detected. Memory layout optimization recommended.",
709    }
710}
711
712/// Get trend analysis text
713fn get_trend_analysis(growth_rate: i32) -> &'static str {
714    match growth_rate {
715        i32::MIN..=-1 => "Memory usage is decreasing - good memory management.",
716        0..=9 => "Stable memory usage with minimal growth.",
717        10..=49 => "Moderate memory growth - monitor for potential leaks.",
718        _ => "High memory growth detected - investigate for memory leaks.",
719    }
720}
721
722/// Format memory size for display
723fn format_memory_size(bytes: u64) -> String {
724    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
725    let mut size = bytes as f64;
726    let mut unit_index = 0;
727
728    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
729        size /= 1024.0;
730        unit_index += 1;
731    }
732
733    if unit_index == 0 {
734        format!("{bytes} {unit}", unit = UNITS[unit_index])
735    } else {
736        format!("{:.1} {unit}", size, unit = UNITS[unit_index])
737    }
738}
739
740/// Calculate risk level for memory allocation
741fn calculate_risk_level(size: u64, is_unsafe: bool, is_ffi: bool) -> String {
742    if is_unsafe {
743        "HIGH".to_string()
744    } else if is_ffi && size > 1024 * 1024 {
745        "MEDIUM".to_string()
746    } else if is_ffi {
747        "LOW".to_string()
748    } else {
749        "SAFE".to_string()
750    }
751}
752
753/// Create FFI dashboard metrics inspired by SVG design
754fn create_ffi_dashboard_metrics(allocations: &[Value], boundary_events: &[Value]) -> Value {
755    let total_allocations = allocations.len();
756
757    // Count unsafe allocations (those with safety violations)
758    let unsafe_allocations = allocations
759        .iter()
760        .filter(|item| {
761            item.get("safety_violations")
762                .and_then(|s| s.as_array())
763                .map(|arr| !arr.is_empty())
764                .unwrap_or(false)
765        })
766        .count();
767
768    // Count FFI-tracked allocations
769    let ffi_allocations = allocations
770        .iter()
771        .filter(|item| {
772            item.get("ffi_tracked")
773                .and_then(|f| f.as_bool())
774                .unwrap_or(false)
775        })
776        .count();
777
778    // Count boundary crossings
779    let boundary_crossings = boundary_events.len();
780
781    // Count safety violations
782    let safety_violations = allocations
783        .iter()
784        .map(|item| {
785            item.get("safety_violations")
786                .and_then(|s| s.as_array())
787                .map(|arr| arr.len())
788                .unwrap_or(0)
789        })
790        .sum::<usize>();
791
792    // Calculate total unsafe memory
793    let unsafe_memory: u64 = allocations
794        .iter()
795        .filter(|item| {
796            item.get("safety_violations")
797                .and_then(|s| s.as_array())
798                .map(|arr| !arr.is_empty())
799                .unwrap_or(false)
800        })
801        .map(|item| item.get("size").and_then(|s| s.as_u64()).unwrap_or(0))
802        .sum();
803
804    // Calculate safety score
805    let safety_score = if total_allocations > 0 {
806        ((total_allocations - unsafe_allocations) as f64 / total_allocations as f64 * 100.0) as u32
807    } else {
808        100
809    };
810
811    // Analyze smart pointer types
812    let smart_pointer_types = analyze_smart_pointer_types(allocations);
813
814    // Analyze borrow checker metrics
815    let borrow_metrics = analyze_borrow_checker_metrics(allocations);
816
817    serde_json::json!({
818        "unsafe_allocations": unsafe_allocations,
819        "ffi_allocations": ffi_allocations,
820        "boundary_crossings": boundary_crossings,
821        "safety_violations": safety_violations,
822        "unsafe_memory": unsafe_memory,
823        "total_allocations": total_allocations,
824        "safety_score": safety_score,
825        "unsafe_memory_formatted": format_memory_size(unsafe_memory),
826        "smart_pointer_types": smart_pointer_types,
827        "borrow_metrics": borrow_metrics
828    })
829}
830
831/// Analyze smart pointer types distribution
832fn analyze_smart_pointer_types(allocations: &[Value]) -> Value {
833    let mut type_counts = std::collections::HashMap::new();
834
835    for allocation in allocations {
836        if let Some(type_name) = allocation.get("type_name").and_then(|t| t.as_str()) {
837            if type_name.contains("Arc")
838                || type_name.contains("Rc")
839                || type_name.contains("Box")
840                || type_name.contains("RefCell")
841            {
842                // Extract the main type name
843                let short_type = if type_name.contains("Arc") {
844                    "Arc"
845                } else if type_name.contains("Rc") {
846                    "Rc"
847                } else if type_name.contains("Box") {
848                    "Box"
849                } else if type_name.contains("RefCell") {
850                    "RefCell"
851                } else {
852                    "Other"
853                };
854
855                *type_counts.entry(short_type.to_string()).or_insert(0) += 1;
856            }
857        }
858    }
859
860    serde_json::json!(type_counts)
861}
862
863/// Analyze borrow checker metrics
864fn analyze_borrow_checker_metrics(allocations: &[Value]) -> Value {
865    let mut max_concurrent = 0;
866    let mut total_borrows = 0;
867    let mut conflicts = 0;
868
869    for allocation in allocations {
870        if let Some(borrow_info) = allocation.get("borrow_info") {
871            if let Some(max_concurrent_borrows) = borrow_info
872                .get("max_concurrent_borrows")
873                .and_then(|m| m.as_u64())
874            {
875                max_concurrent = max_concurrent.max(max_concurrent_borrows);
876            }
877
878            let immutable = borrow_info
879                .get("immutable_borrows")
880                .and_then(|i| i.as_u64())
881                .unwrap_or(0);
882            let mutable = borrow_info
883                .get("mutable_borrows")
884                .and_then(|m| m.as_u64())
885                .unwrap_or(0);
886
887            total_borrows += immutable + mutable;
888
889            // Check for conflicts (both immutable and mutable borrows)
890            if immutable > 0 && mutable > 0 {
891                conflicts += 1;
892            }
893        }
894    }
895
896    serde_json::json!({
897        "max_concurrent_borrows": max_concurrent,
898        "total_borrow_operations": total_borrows,
899        "borrow_conflicts": conflicts
900    })
901}
902
903/// Analyze memory hotspots for visualization
904fn analyze_memory_hotspots(allocations: &[Value]) -> Value {
905    let mut hotspots = Vec::new();
906
907    for allocation in allocations {
908        if let (Some(size), Some(ptr), Some(type_name)) = (
909            allocation.get("size").and_then(|s| s.as_u64()),
910            allocation.get("ptr").and_then(|p| p.as_str()),
911            allocation.get("type_name").and_then(|t| t.as_str()),
912        ) {
913            let is_unsafe = allocation
914                .get("safety_violations")
915                .and_then(|s| s.as_array())
916                .map(|arr| !arr.is_empty())
917                .unwrap_or(false);
918
919            let is_ffi = allocation
920                .get("ffi_tracked")
921                .and_then(|f| f.as_bool())
922                .unwrap_or(false);
923
924            hotspots.push(serde_json::json!({
925                "ptr": ptr,
926                "size": size,
927                "type_name": type_name,
928                "is_unsafe": is_unsafe,
929                "is_ffi": is_ffi,
930                "category": if is_unsafe { "UNSAFE" } else { "FFI" },
931                "size_formatted": format_memory_size(size),
932                "risk_level": calculate_risk_level(size, is_unsafe, is_ffi)
933            }));
934        }
935    }
936
937    // Sort by size descending
938    hotspots.sort_by(|a, b| {
939        let size_a = a.get("size").and_then(|s| s.as_u64()).unwrap_or(0);
940        let size_b = b.get("size").and_then(|s| s.as_u64()).unwrap_or(0);
941        size_b.cmp(&size_a)
942    });
943
944    serde_json::json!(hotspots)
945}
946
947/// Analyze cross-language memory flow
948fn analyze_cross_language_memory_flow(allocations: &[Value], boundary_events: &[Value]) -> Value {
949    let rust_allocations = allocations
950        .iter()
951        .filter(|item| {
952            !item
953                .get("ffi_tracked")
954                .and_then(|f| f.as_bool())
955                .unwrap_or(false)
956        })
957        .count();
958
959    let ffi_allocations = allocations.len() - rust_allocations;
960
961    // Analyze flow directions from boundary events
962    let mut rust_to_ffi = 0;
963    let mut ffi_to_rust = 0;
964
965    for event in boundary_events {
966        if let (Some(from), Some(to)) = (
967            event.get("from_context").and_then(|f| f.as_str()),
968            event.get("to_context").and_then(|t| t.as_str()),
969        ) {
970            match (from, to) {
971                ("rust", "ffi") | ("rust", "c") => rust_to_ffi += 1,
972                ("ffi", "rust") | ("c", "rust") => ffi_to_rust += 1,
973                _ => {}
974            }
975        }
976    }
977
978    serde_json::json!({
979        "rust_allocations": rust_allocations,
980        "ffi_allocations": ffi_allocations,
981        "rust_to_ffi_flow": rust_to_ffi,
982        "ffi_to_rust_flow": ffi_to_rust,
983        "total_boundary_crossings": boundary_events.len()
984    })
985}
986
987/// Create FFI risk assessment
988fn create_ffi_risk_assessment(allocations: &[Value]) -> Value {
989    let mut risk_items = Vec::new();
990
991    for allocation in allocations {
992        let empty_vec = vec![];
993        let safety_violations = allocation
994            .get("safety_violations")
995            .and_then(|s| s.as_array())
996            .unwrap_or(&empty_vec);
997
998        if !safety_violations.is_empty() {
999            for violation in safety_violations {
1000                if let Some(violation_str) = violation.as_str() {
1001                    risk_items.push(serde_json::json!({
1002                        "type": "safety_violation",
1003                        "description": violation_str,
1004                        "severity": get_violation_severity(violation_str),
1005                        "ptr": allocation.get("ptr"),
1006                        "size": allocation.get("size")
1007                    }));
1008                }
1009            }
1010        }
1011
1012        // Check for potential risks based on borrow patterns
1013        if let Some(borrow_info) = allocation.get("borrow_info") {
1014            let immutable = borrow_info
1015                .get("immutable_borrows")
1016                .and_then(|v| v.as_u64())
1017                .unwrap_or(0);
1018            let mutable = borrow_info
1019                .get("mutable_borrows")
1020                .and_then(|v| v.as_u64())
1021                .unwrap_or(0);
1022
1023            if immutable > 0 && mutable > 0 {
1024                risk_items.push(serde_json::json!({
1025                    "type": "borrow_conflict",
1026                    "description": "Concurrent immutable and mutable borrows detected",
1027                    "severity": "medium",
1028                    "ptr": allocation.get("ptr"),
1029                    "immutable_borrows": immutable,
1030                    "mutable_borrows": mutable
1031                }));
1032            }
1033        }
1034    }
1035
1036    // Calculate risk summary
1037    let critical_risks = risk_items
1038        .iter()
1039        .filter(|r| r.get("severity").and_then(|s| s.as_str()) == Some("critical"))
1040        .count();
1041    let high_risks = risk_items
1042        .iter()
1043        .filter(|r| r.get("severity").and_then(|s| s.as_str()) == Some("high"))
1044        .count();
1045    let medium_risks = risk_items
1046        .iter()
1047        .filter(|r| r.get("severity").and_then(|s| s.as_str()) == Some("medium"))
1048        .count();
1049    let low_risks = risk_items
1050        .iter()
1051        .filter(|r| r.get("severity").and_then(|s| s.as_str()) == Some("low"))
1052        .count();
1053
1054    serde_json::json!({
1055        "risk_items": risk_items,
1056        "summary": {
1057            "total_risks": risk_items.len(),
1058            "critical": critical_risks,
1059            "high": high_risks,
1060            "medium": medium_risks,
1061            "low": low_risks
1062        }
1063    })
1064}
1065
1066/// Get violation severity
1067fn get_violation_severity(violation: &str) -> &'static str {
1068    match violation.to_lowercase().as_str() {
1069        v if v.contains("double free") || v.contains("use after free") => "critical",
1070        v if v.contains("invalid free") || v.contains("buffer overflow") => "high",
1071        v if v.contains("memory leak") || v.contains("uninitialized") => "medium",
1072        _ => "low",
1073    }
1074}
1075
1076/// Generate safety risk data from JSON data structure
1077fn generate_safety_risk_data_from_json(
1078    transformed_data: &serde_json::Map<String, Value>,
1079) -> Result<String, Box<dyn Error>> {
1080    let mut safety_risks = Vec::new();
1081
1082    // Extract allocations from memory_analysis
1083    if let Some(memory_analysis) = transformed_data.get("memory_analysis") {
1084        if let Some(allocations) = memory_analysis
1085            .get("allocations")
1086            .and_then(|a| a.as_array())
1087        {
1088            for allocation in allocations {
1089                // Check for potential unsafe operations based on allocation patterns
1090
1091                // 1. Large allocations that might indicate unsafe buffer operations
1092                if let Some(size) = allocation.get("size").and_then(|s| s.as_u64()) {
1093                    if size > 1024 * 1024 {
1094                        // > 1MB
1095                        safety_risks.push(serde_json::json!({
1096                            "location": format!("{}::{}",
1097                                allocation.get("scope_name").and_then(|s| s.as_str()).unwrap_or("unknown"),
1098                                allocation.get("var_name").and_then(|s| s.as_str()).unwrap_or("unnamed")),
1099                            "operation": "Large Memory Allocation",
1100                            "risk_level": "Medium",
1101                            "description": format!("Large allocation of {} bytes may indicate unsafe buffer operations", size)
1102                        }));
1103                    }
1104                }
1105
1106                // 2. Leaked memory indicates potential unsafe operations
1107                if let Some(is_leaked) = allocation.get("is_leaked").and_then(|l| l.as_bool()) {
1108                    if is_leaked {
1109                        safety_risks.push(serde_json::json!({
1110                            "location": format!("{}::{}",
1111                                allocation.get("scope_name").and_then(|s| s.as_str()).unwrap_or("unknown"),
1112                                allocation.get("var_name").and_then(|s| s.as_str()).unwrap_or("unnamed")),
1113                            "operation": "Memory Leak",
1114                            "risk_level": "High",
1115                            "description": "Memory leak detected - potential unsafe memory management"
1116                        }));
1117                    }
1118                }
1119
1120                // 3. High borrow count might indicate unsafe sharing
1121                if let Some(borrow_count) = allocation.get("borrow_count").and_then(|b| b.as_u64())
1122                {
1123                    if borrow_count > 10 {
1124                        safety_risks.push(serde_json::json!({
1125                            "location": format!("{}::{}",
1126                                allocation.get("scope_name").and_then(|s| s.as_str()).unwrap_or("unknown"),
1127                                allocation.get("var_name").and_then(|s| s.as_str()).unwrap_or("unnamed")),
1128                            "operation": "High Borrow Count",
1129                            "risk_level": "Medium",
1130                            "description": format!("High borrow count ({}) may indicate unsafe sharing patterns", borrow_count)
1131                        }));
1132                    }
1133                }
1134
1135                // 4. Raw pointer types indicate direct unsafe operations
1136                if let Some(type_name) = allocation.get("type_name").and_then(|t| t.as_str()) {
1137                    if type_name.contains("*mut") || type_name.contains("*const") {
1138                        safety_risks.push(serde_json::json!({
1139                            "location": format!("{}::{}",
1140                                allocation.get("scope_name").and_then(|s| s.as_str()).unwrap_or("unknown"),
1141                                allocation.get("var_name").and_then(|s| s.as_str()).unwrap_or("unnamed")),
1142                            "operation": "Raw Pointer Usage",
1143                            "risk_level": "High",
1144                            "description": format!("Raw pointer type '{}' requires unsafe operations", type_name)
1145                        }));
1146                    }
1147
1148                    // 5. FFI-related types
1149                    if type_name.contains("CString")
1150                        || type_name.contains("CStr")
1151                        || type_name.contains("c_void")
1152                        || type_name.contains("extern")
1153                    {
1154                        safety_risks.push(serde_json::json!({
1155                            "location": format!("{}::{}",
1156                                allocation.get("scope_name").and_then(|s| s.as_str()).unwrap_or("unknown"),
1157                                allocation.get("var_name").and_then(|s| s.as_str()).unwrap_or("unnamed")),
1158                            "operation": "FFI Boundary Crossing",
1159                            "risk_level": "Medium",
1160                            "description": format!("FFI type '{}' crosses safety boundaries", type_name)
1161                        }));
1162                    }
1163                }
1164
1165                // 6. Very short-lived allocations might indicate unsafe temporary operations
1166                if let Some(lifetime_ms) = allocation.get("lifetime_ms").and_then(|l| l.as_u64()) {
1167                    if lifetime_ms < 1 {
1168                        // Less than 1ms
1169                        safety_risks.push(serde_json::json!({
1170                            "location": format!("{}::{}",
1171                                allocation.get("scope_name").and_then(|s| s.as_str()).unwrap_or("unknown"),
1172                                allocation.get("var_name").and_then(|s| s.as_str()).unwrap_or("unnamed")),
1173                            "operation": "Short-lived Allocation",
1174                            "risk_level": "Low",
1175                            "description": format!("Very short lifetime ({}ms) may indicate unsafe temporary operations", lifetime_ms)
1176                        }));
1177                    }
1178                }
1179            }
1180        }
1181    }
1182
1183    // Check unsafe_ffi data for additional risks
1184    if let Some(unsafe_ffi) = transformed_data.get("unsafe_ffi") {
1185        if let Some(safety_violations) = unsafe_ffi
1186            .get("safety_violations")
1187            .and_then(|sv| sv.as_array())
1188        {
1189            for violation in safety_violations {
1190                if let Some(violation_type) =
1191                    violation.get("violation_type").and_then(|vt| vt.as_str())
1192                {
1193                    let severity = get_violation_severity(violation_type);
1194                    let risk_level = match severity {
1195                        "critical" => "High",
1196                        "high" => "High",
1197                        "medium" => "Medium",
1198                        _ => "Low",
1199                    };
1200
1201                    safety_risks.push(serde_json::json!({
1202                        "location": violation.get("location").and_then(|l| l.as_str()).unwrap_or("Unknown"),
1203                        "operation": format!("Safety Violation: {violation_type}"),
1204                        "risk_level": risk_level,
1205                        "description": violation.get("description").and_then(|d| d.as_str()).unwrap_or("Safety violation detected")
1206                    }));
1207                }
1208            }
1209        }
1210    }
1211
1212    // If no risks found, add a placeholder to show the system is working
1213    if safety_risks.is_empty() {
1214        safety_risks.push(serde_json::json!({
1215            "location": "Global Analysis",
1216            "operation": "Safety Scan Complete",
1217            "risk_level": "Low",
1218            "description": "No significant safety risks detected in current allocations"
1219        }));
1220    }
1221
1222    serde_json::to_string(&safety_risks)
1223        .map_err(|e| format!("Failed to serialize safety risk data: {e}").into())
1224}
1225
1226/// Inject safety risk data into HTML template
1227fn inject_safety_risk_data_into_html(
1228    mut html: String,
1229    safety_risk_data: &str,
1230) -> Result<String, Box<dyn Error>> {
1231    // Replace the safety risk data in the existing template
1232    html = html.replace(
1233        "window.safetyRisks = [];",
1234        &format!("window.safetyRisks = {safety_risk_data};"),
1235    );
1236
1237    // Always ensure loadSafetyRisks function is available
1238    if !html.contains("function loadSafetyRisks") {
1239        // Find a good injection point - before the closing </script> tag
1240        if let Some(script_end) = html.rfind("</script>") {
1241            let before = &html[..script_end];
1242            let after = &html[script_end..];
1243
1244            let safety_function_injection = r#"
1245    // Safety Risk Data Management Function
1246    function loadSafetyRisks() {
1247        console.log("🛡️ Loading safety risk data...");
1248        const unsafeTable = document.getElementById('unsafeTable');
1249        if (!unsafeTable) {
1250            console.warn('⚠️ unsafeTable not found');
1251            return;
1252        }
1253        
1254        const risks = window.safetyRisks || [];
1255        if (risks.length === 0) {
1256            unsafeTable.innerHTML = '<tr><td colspan="3" class="text-center text-gray-500">No safety risks detected</td></tr>';
1257            return;
1258        }
1259        
1260        unsafeTable.innerHTML = '';
1261        risks.forEach((risk, index) => {
1262            const row = document.createElement('tr');
1263            row.className = "hover:bg-gray-50 dark:hover:bg-gray-700";
1264            
1265            const riskLevelClass = risk.risk_level === 'High' ? 'text-red-600 font-bold' : 
1266                                 risk.risk_level === 'Medium' ? 'text-yellow-600 font-semibold' : 
1267                                 'text-green-600';
1268            
1269            row.innerHTML = `
1270                <td class="px-3 py-2 text-sm">${risk.location || 'Unknown'}</td>
1271                <td class="px-3 py-2 text-sm">${risk.operation || 'Unknown'}</td>
1272                <td class="px-3 py-2 text-sm"><span class="${riskLevelClass}">${risk.risk_level || 'Low'}</span></td>
1273            `;
1274            unsafeTable.appendChild(row);
1275        });
1276        
1277        console.log("✅ Safety risks loaded:", risks.length, 'items');
1278    }
1279    
1280    "#;
1281
1282            html = format!("{before}{safety_function_injection}{after}");
1283        }
1284    }
1285
1286    // Ensure safety risks are loaded after initialization - but only call if function exists
1287    html = html.replace("console.log('✅ Enhanced dashboard initialized');", 
1288                       "console.log('✅ Enhanced dashboard initialized'); setTimeout(() => { if (typeof loadSafetyRisks === 'function') { loadSafetyRisks(); } }, 100);");
1289
1290    // Also add to manual initialization if it exists - with safer replacement
1291    if html.contains("manualBtn.addEventListener('click', manualInitialize);") {
1292        html = html.replace("manualBtn.addEventListener('click', manualInitialize);", 
1293                           "manualBtn.addEventListener('click', function() { manualInitialize(); setTimeout(() => { if (typeof loadSafetyRisks === 'function') { loadSafetyRisks(); } }, 100); });");
1294    }
1295
1296    // Remove any standalone loadSafetyRisks calls that might cause errors
1297    html = html.replace(
1298        "loadSafetyRisks();",
1299        "if (typeof loadSafetyRisks === 'function') { loadSafetyRisks(); }",
1300    );
1301
1302    tracing::info!("📊 Safety risk data and function injected into HTML template");
1303
1304    Ok(html)
1305}
1306
1307#[cfg(test)]
1308mod tests {
1309    use super::*;
1310    use std::collections::HashMap;
1311
1312    #[test]
1313    fn test_generate_direct_html_with_empty_data() {
1314        let json_data = HashMap::new();
1315        let result = generate_direct_html(&json_data);
1316        assert!(result.is_err());
1317        assert_eq!(
1318            result.unwrap_err().to_string(),
1319            "No JSON data provided for HTML generation"
1320        );
1321    }
1322
1323    #[test]
1324    fn test_transform_json_data_structure_with_empty_input() {
1325        let json_data = HashMap::new();
1326        let result = transform_json_data_structure(&json_data);
1327        assert!(result.is_ok());
1328
1329        let transformed = result.unwrap();
1330        assert!(transformed.contains_key("memory_analysis"));
1331        assert!(transformed.contains_key("lifetime"));
1332        assert!(transformed.contains_key("complex_types"));
1333        assert!(transformed.contains_key("performance"));
1334        assert!(transformed.contains_key("unsafe_ffi"));
1335        assert!(transformed.contains_key("security_violations"));
1336    }
1337
1338    #[test]
1339    fn test_transform_json_data_structure_with_memory_analysis() {
1340        let mut json_data = HashMap::new();
1341        json_data.insert(
1342            "test_memory_analysis".to_string(),
1343            serde_json::json!({
1344                "allocations": [],
1345                "stats": {
1346                    "total_allocations": 0,
1347                    "active_allocations": 0,
1348                    "total_memory": 0,
1349                    "active_memory": 0
1350                }
1351            }),
1352        );
1353
1354        let result = transform_json_data_structure(&json_data);
1355        assert!(result.is_ok());
1356
1357        let transformed = result.unwrap();
1358        assert!(transformed.contains_key("memory_analysis"));
1359    }
1360
1361    #[test]
1362    fn test_transform_json_data_structure_with_lifetime_data() {
1363        let mut json_data = HashMap::new();
1364        json_data.insert(
1365            "test_lifetime".to_string(),
1366            serde_json::json!({
1367                "lifecycle_events": []
1368            }),
1369        );
1370
1371        let result = transform_json_data_structure(&json_data);
1372        assert!(result.is_ok());
1373
1374        let transformed = result.unwrap();
1375        assert!(transformed.contains_key("lifetime"));
1376    }
1377
1378    #[test]
1379    fn test_transform_json_data_structure_with_complex_types() {
1380        let mut json_data = HashMap::new();
1381        json_data.insert(
1382            "test_complex_types".to_string(),
1383            serde_json::json!({
1384                "categorized_types": {
1385                    "generic_types": [],
1386                    "collections": [],
1387                    "smart_pointers": [],
1388                    "trait_objects": []
1389                },
1390                "summary": {
1391                    "total_complex_types": 0,
1392                    "generic_type_count": 0
1393                }
1394            }),
1395        );
1396
1397        let result = transform_json_data_structure(&json_data);
1398        assert!(result.is_ok());
1399
1400        let transformed = result.unwrap();
1401        assert!(transformed.contains_key("complex_types"));
1402    }
1403
1404    #[test]
1405    fn test_transform_json_data_structure_with_performance_data() {
1406        let mut json_data = HashMap::new();
1407        json_data.insert(
1408            "test_performance".to_string(),
1409            serde_json::json!({
1410                "memory_performance": {
1411                    "active_memory": 0,
1412                    "peak_memory": 0,
1413                    "total_allocated": 0
1414                },
1415                "allocation_distribution": {
1416                    "tiny": 0,
1417                    "small": 0,
1418                    "medium": 0,
1419                    "large": 0,
1420                    "massive": 0
1421                }
1422            }),
1423        );
1424
1425        let result = transform_json_data_structure(&json_data);
1426        assert!(result.is_ok());
1427
1428        let transformed = result.unwrap();
1429        assert!(transformed.contains_key("performance"));
1430    }
1431
1432    #[test]
1433    fn test_transform_json_data_structure_with_ffi_data() {
1434        let mut json_data = HashMap::new();
1435        json_data.insert(
1436            "test_unsafe_ffi".to_string(),
1437            serde_json::json!({
1438                "summary": {
1439                    "total_risk_items": 0,
1440                    "unsafe_count": 0,
1441                    "ffi_count": 0,
1442                    "safety_violations": 0
1443                },
1444                "enhanced_ffi_data": [],
1445                "safety_violations": []
1446            }),
1447        );
1448
1449        let result = transform_json_data_structure(&json_data);
1450        assert!(result.is_ok());
1451
1452        let transformed = result.unwrap();
1453        assert!(transformed.contains_key("unsafe_ffi"));
1454    }
1455
1456    #[test]
1457    fn test_transform_json_data_structure_with_security_violations() {
1458        let mut json_data = HashMap::new();
1459        json_data.insert(
1460            "test_security_violations".to_string(),
1461            serde_json::json!({
1462                "metadata": {
1463                    "total_violations": 0
1464                },
1465                "violation_reports": [],
1466                "security_summary": {
1467                    "security_analysis_summary": {
1468                        "total_violations": 0,
1469                        "severity_breakdown": {
1470                            "critical": 0,
1471                            "high": 0,
1472                            "medium": 0,
1473                            "low": 0,
1474                            "info": 0
1475                        }
1476                    }
1477                }
1478            }),
1479        );
1480
1481        let result = transform_json_data_structure(&json_data);
1482        assert!(result.is_ok());
1483
1484        let transformed = result.unwrap();
1485        assert!(transformed.contains_key("security_violations"));
1486    }
1487
1488    #[test]
1489    fn test_enhance_memory_analysis_data() {
1490        let data = serde_json::json!({
1491            "allocations": []
1492        });
1493
1494        let result = enhance_memory_analysis_data(&data);
1495        assert!(result.is_ok());
1496    }
1497
1498    #[test]
1499    fn test_enhance_lifetime_data() {
1500        let data = serde_json::json!({
1501            "lifecycle_events": []
1502        });
1503
1504        let result = enhance_lifetime_data(&data);
1505        assert!(result.is_ok());
1506    }
1507
1508    #[test]
1509    fn test_enhance_ffi_data() {
1510        let data = serde_json::json!({
1511            "allocations": [],
1512            "boundary_events": []
1513        });
1514
1515        let result = enhance_ffi_data(&data);
1516        assert!(result.is_ok());
1517    }
1518
1519    #[test]
1520    fn test_analyze_memory_fragmentation() {
1521        let allocations = vec![];
1522        let result = analyze_memory_fragmentation(&allocations);
1523        assert_eq!(result["total_blocks"], serde_json::json!(0));
1524    }
1525
1526    #[test]
1527    fn test_analyze_memory_growth_trends() {
1528        let allocations = vec![];
1529        let result = analyze_memory_growth_trends(&allocations);
1530        assert_eq!(result["peak_memory"], serde_json::json!(0));
1531    }
1532
1533    #[test]
1534    fn test_calculate_ffi_statistics_from_allocations() {
1535        let allocations = vec![];
1536        let boundary_events = vec![];
1537        let result = calculate_ffi_statistics_from_allocations(&allocations, &boundary_events);
1538        assert_eq!(result["total_allocations"], serde_json::json!(0));
1539    }
1540
1541    #[test]
1542    fn test_analyze_language_interactions() {
1543        let boundary_events = vec![];
1544        let result = analyze_language_interactions(&boundary_events);
1545        assert_eq!(result, serde_json::json!([]));
1546    }
1547
1548    #[test]
1549    fn test_analyze_safety_metrics_from_allocations() {
1550        let allocations = vec![];
1551        let result = analyze_safety_metrics_from_allocations(&allocations);
1552        assert_eq!(result["total_operations"], serde_json::json!(0));
1553    }
1554
1555    #[test]
1556    fn test_get_progress_color() {
1557        let color = get_progress_color(0);
1558        assert_eq!(color, "#ff6b6b");
1559
1560        let color = get_progress_color(10);
1561        assert_eq!(color, "#ff6b6b"); // Should wrap around
1562    }
1563
1564    #[test]
1565    fn test_get_fragmentation_analysis() {
1566        let analysis = get_fragmentation_analysis(5);
1567        assert_eq!(
1568            analysis,
1569            "Excellent memory layout with minimal fragmentation."
1570        );
1571
1572        let analysis = get_fragmentation_analysis(15);
1573        assert_eq!(analysis, "Good memory layout with low fragmentation.");
1574
1575        let analysis = get_fragmentation_analysis(35);
1576        assert_eq!(
1577            analysis,
1578            "Moderate fragmentation detected. Consider memory pool allocation."
1579        );
1580
1581        let analysis = get_fragmentation_analysis(60);
1582        assert_eq!(
1583            analysis,
1584            "High fragmentation detected. Memory layout optimization recommended."
1585        );
1586    }
1587
1588    #[test]
1589    fn test_get_trend_analysis() {
1590        let analysis = get_trend_analysis(-5);
1591        assert_eq!(
1592            analysis,
1593            "Memory usage is decreasing - good memory management."
1594        );
1595
1596        let analysis = get_trend_analysis(5);
1597        assert_eq!(analysis, "Stable memory usage with minimal growth.");
1598
1599        let analysis = get_trend_analysis(25);
1600        assert_eq!(
1601            analysis,
1602            "Moderate memory growth - monitor for potential leaks."
1603        );
1604
1605        let analysis = get_trend_analysis(75);
1606        assert_eq!(
1607            analysis,
1608            "High memory growth detected - investigate for memory leaks."
1609        );
1610    }
1611
1612    #[test]
1613    fn test_format_memory_size() {
1614        let formatted = format_memory_size(1023);
1615        assert_eq!(formatted, "1023 B");
1616
1617        let formatted = format_memory_size(1024);
1618        assert_eq!(formatted, "1.0 KB");
1619
1620        let formatted = format_memory_size(1024 * 1024);
1621        assert_eq!(formatted, "1.0 MB");
1622
1623        let formatted = format_memory_size(1024 * 1024 * 1024);
1624        assert_eq!(formatted, "1.0 GB");
1625    }
1626
1627    #[test]
1628    fn test_calculate_risk_level() {
1629        let risk = calculate_risk_level(100, true, false);
1630        assert_eq!(risk, "HIGH");
1631
1632        let risk = calculate_risk_level(1024 * 1024 + 1, false, true);
1633        assert_eq!(risk, "MEDIUM");
1634
1635        let risk = calculate_risk_level(100, false, true);
1636        assert_eq!(risk, "LOW");
1637
1638        let risk = calculate_risk_level(100, false, false);
1639        assert_eq!(risk, "SAFE");
1640    }
1641
1642    #[test]
1643    fn test_create_ffi_dashboard_metrics() {
1644        let allocations = vec![];
1645        let boundary_events = vec![];
1646        let result = create_ffi_dashboard_metrics(&allocations, &boundary_events);
1647        assert_eq!(result["total_allocations"], serde_json::json!(0));
1648    }
1649
1650    #[test]
1651    fn test_analyze_smart_pointer_types() {
1652        let allocations = vec![];
1653        let result = analyze_smart_pointer_types(&allocations);
1654        assert_eq!(result, serde_json::json!({}));
1655    }
1656
1657    #[test]
1658    fn test_analyze_borrow_checker_metrics() {
1659        let allocations = vec![];
1660        let result = analyze_borrow_checker_metrics(&allocations);
1661        assert_eq!(result["max_concurrent_borrows"], serde_json::json!(0));
1662    }
1663
1664    #[test]
1665    fn test_analyze_memory_hotspots() {
1666        let allocations = vec![];
1667        let result = analyze_memory_hotspots(&allocations);
1668        assert_eq!(result, serde_json::json!([]));
1669    }
1670
1671    #[test]
1672    fn test_analyze_cross_language_memory_flow() {
1673        let allocations = vec![];
1674        let boundary_events = vec![];
1675        let result = analyze_cross_language_memory_flow(&allocations, &boundary_events);
1676        assert_eq!(result["rust_allocations"], serde_json::json!(0));
1677    }
1678
1679    #[test]
1680    fn test_create_ffi_risk_assessment() {
1681        let allocations = vec![];
1682        let result = create_ffi_risk_assessment(&allocations);
1683        assert_eq!(result["summary"]["total_risks"], serde_json::json!(0));
1684    }
1685
1686    #[test]
1687    fn test_get_violation_severity() {
1688        let severity = get_violation_severity("double free detected");
1689        assert_eq!(severity, "critical");
1690
1691        let severity = get_violation_severity("invalid free operation");
1692        assert_eq!(severity, "high");
1693
1694        let severity = get_violation_severity("memory leak detected");
1695        assert_eq!(severity, "medium");
1696
1697        let severity = get_violation_severity("unknown issue");
1698        assert_eq!(severity, "low");
1699    }
1700
1701    #[test]
1702    fn test_generate_safety_risk_data_from_json() {
1703        let transformed_data = serde_json::Map::new();
1704        let result = generate_safety_risk_data_from_json(&transformed_data);
1705        assert!(result.is_ok());
1706    }
1707
1708    #[test]
1709    fn test_inject_safety_risk_data_into_html() {
1710        let html = "<script>window.safetyRisks = [];</script>".to_string();
1711        let safety_risk_data = "[]";
1712        let result = inject_safety_risk_data_into_html(html, safety_risk_data);
1713        assert!(result.is_ok());
1714    }
1715}