1use crate::export::binary::binary_html_writer::{BinaryHtmlStats, BinaryHtmlWriter};
9use crate::export::binary::error::BinaryExportError;
10use crate::export::binary::reader::BinaryReader;
11use crate::export::binary::selective_reader::AllocationField;
12
13use std::fs::File;
14use std::path::Path;
15use std::time::Instant;
16
17#[derive(Debug, Clone)]
19pub struct BinaryHtmlExportConfig {
20 pub enable_auto_strategy: bool,
22
23 pub parallel_threshold: usize,
25
26 pub large_file_threshold: u64,
28
29 pub batch_size: usize,
31
32 pub enable_progress_reporting: bool,
34
35 pub max_memory_usage: usize,
37
38 pub enable_optimizations: bool,
40}
41
42impl Default for BinaryHtmlExportConfig {
43 fn default() -> Self {
44 Self {
45 enable_auto_strategy: true,
46 parallel_threshold: 5000,
47 large_file_threshold: 100 * 1024 * 1024, batch_size: 1000,
49 enable_progress_reporting: false,
50 max_memory_usage: 64 * 1024 * 1024, enable_optimizations: true,
52 }
53 }
54}
55
56#[derive(Debug, Clone)]
58pub struct BinaryHtmlExportStats {
59 pub writer_stats: BinaryHtmlStats,
61
62 pub total_export_time_ms: u64,
64
65 pub binary_read_time_ms: u64,
67
68 pub html_generation_time_ms: u64,
70
71 pub file_size_bytes: u64,
73
74 pub strategy_used: ProcessingStrategy,
76
77 pub throughput_allocations_per_sec: f64,
79
80 pub memory_efficiency: f64,
82}
83
84#[derive(Debug, Clone, PartialEq)]
86pub enum ProcessingStrategy {
87 Standard,
89 Optimized,
91 Parallel,
93}
94
95impl BinaryHtmlExportStats {
96 pub fn processing_efficiency(&self) -> f64 {
98 if self.total_export_time_ms == 0 {
99 0.0
100 } else {
101 (self.writer_stats.allocations_processed as f64 * 1000.0)
102 / self.total_export_time_ms as f64
103 }
104 }
105
106 pub fn performance_improvement(&self) -> f64 {
108 let baseline_time_ms = 800.0;
110 if self.total_export_time_ms == 0 {
111 0.0
112 } else {
113 (baseline_time_ms - self.total_export_time_ms as f64) / baseline_time_ms * 100.0
114 }
115 }
116}
117
118pub fn parse_binary_to_html_direct<P: AsRef<Path>>(
146 binary_path: P,
147 html_path: P,
148 project_name: &str,
149) -> Result<BinaryHtmlExportStats, BinaryExportError> {
150 tracing::debug!("parse_binary_to_html_direct called - using binary_dashboard.html template");
151
152 crate::export::binary::html_converter::convert_binary_to_html(
154 binary_path.as_ref(),
155 html_path.as_ref(),
156 project_name,
157 )?;
158
159 Ok(BinaryHtmlExportStats {
161 throughput_allocations_per_sec: 0.0,
162 memory_efficiency: 0.0,
163 writer_stats: BinaryHtmlStats::default(),
164 total_export_time_ms: 0,
165 binary_read_time_ms: 0,
166 html_generation_time_ms: 0,
167 file_size_bytes: 0,
168 strategy_used: ProcessingStrategy::Standard,
169 })
170}
171
172pub fn parse_binary_to_html_with_config<P: AsRef<Path>>(
177 binary_path: P,
178 html_path: P,
179 project_name: &str,
180 config: &BinaryHtmlExportConfig,
181) -> Result<BinaryHtmlExportStats, BinaryExportError> {
182 let export_start = Instant::now();
183 let binary_path = binary_path.as_ref();
184 let html_path = html_path.as_ref();
185
186 tracing::info!("🚀 Starting high-performance binary → HTML conversion");
187 tracing::info!(" Binary file: {:?}", binary_path);
188 tracing::info!(" Output file: {:?}", html_path);
189 tracing::info!(" Project: {}", project_name);
190
191 let file_size = std::fs::metadata(binary_path)
193 .map_err(BinaryExportError::Io)?
194 .len();
195
196 let strategy = if config.enable_auto_strategy {
198 select_optimal_strategy(file_size, config)
199 } else {
200 ProcessingStrategy::Standard
201 };
202
203 tracing::info!(" Strategy: {:?}", strategy);
204 tracing::info!(" File size: {:.1} MB", file_size as f64 / 1024.0 / 1024.0);
205
206 let stats = match strategy {
208 ProcessingStrategy::Standard => {
209 execute_standard_conversion(binary_path, html_path, project_name, config)?
210 }
211 ProcessingStrategy::Optimized => {
212 execute_optimized_conversion(binary_path, html_path, project_name, config)?
213 }
214 ProcessingStrategy::Parallel => {
215 execute_parallel_conversion(binary_path, html_path, project_name, config)?
216 }
217 };
218
219 let total_time = export_start.elapsed().as_millis() as u64;
220
221 let export_stats = BinaryHtmlExportStats {
222 throughput_allocations_per_sec: if total_time > 0 {
223 (stats.allocations_processed as f64 * 1000.0) / total_time as f64
224 } else {
225 0.0
226 },
227 memory_efficiency: if stats.peak_memory_usage > 0 {
228 stats.allocations_processed as f64 / (stats.peak_memory_usage as f64 / 1024.0 / 1024.0)
229 } else {
230 0.0
231 },
232 writer_stats: stats,
233 total_export_time_ms: total_time,
234 binary_read_time_ms: 0, html_generation_time_ms: 0, file_size_bytes: file_size,
237 strategy_used: strategy,
238 };
239
240 tracing::info!("✅ Binary → HTML conversion completed!");
241 tracing::info!(
242 " Processing time: {}ms",
243 export_stats.total_export_time_ms
244 );
245 tracing::info!(
246 " Allocations processed: {}",
247 export_stats.writer_stats.allocations_processed
248 );
249 tracing::info!(
250 " Throughput: {:.1} allocs/sec",
251 export_stats.throughput_allocations_per_sec
252 );
253 tracing::info!(
254 " Performance improvement: {:.1}%",
255 export_stats.performance_improvement()
256 );
257
258 Ok(export_stats)
259}
260
261fn select_optimal_strategy(file_size: u64, config: &BinaryHtmlExportConfig) -> ProcessingStrategy {
263 if file_size > config.large_file_threshold {
264 ProcessingStrategy::Parallel
265 } else if file_size > config.large_file_threshold / 2 {
266 ProcessingStrategy::Optimized
267 } else {
268 ProcessingStrategy::Standard
269 }
270}
271
272fn execute_standard_conversion<P: AsRef<Path>>(
274 binary_path: P,
275 html_path: P,
276 project_name: &str,
277 config: &BinaryHtmlExportConfig,
278) -> Result<BinaryHtmlStats, BinaryExportError> {
279 let read_start = Instant::now();
280
281 let mut reader = BinaryReader::new(&binary_path)?;
283 let header = reader.read_header()?;
284
285 tracing::debug!(
286 "📖 Reading {} allocations using standard strategy",
287 header.total_count
288 );
289
290 let html_file = File::create(&html_path)?;
292 let mut html_writer = BinaryHtmlWriter::new(html_file)?;
293
294 let requested_fields = AllocationField::all_basic_fields();
296 let mut allocations_buffer = Vec::with_capacity(config.batch_size);
297
298 for i in 0..header.total_count {
299 let allocation = reader.read_allocation()?;
300 allocations_buffer.push(allocation);
301
302 if allocations_buffer.len() >= config.batch_size || i == header.total_count - 1 {
304 html_writer.write_binary_allocation_batch(&allocations_buffer, &requested_fields)?;
305 allocations_buffer.clear();
306
307 if config.enable_progress_reporting && i % (config.batch_size * 10) as u32 == 0 {
308 tracing::debug!(" Progress: {}/{} allocations", i + 1, header.total_count);
309 }
310 }
311 }
312
313 let stats = html_writer.finalize_with_binary_template(project_name)?;
315
316 tracing::debug!(
317 "📊 Standard conversion completed in {}ms",
318 read_start.elapsed().as_millis()
319 );
320
321 Ok(stats)
322}
323
324fn execute_optimized_conversion<P: AsRef<Path>>(
326 binary_path: P,
327 html_path: P,
328 project_name: &str,
329 config: &BinaryHtmlExportConfig,
330) -> Result<BinaryHtmlStats, BinaryExportError> {
331 let read_start = Instant::now();
332
333 tracing::debug!("⚡ Using optimized conversion strategy");
334
335 let mut reader = BinaryReader::new(&binary_path)?;
337 let header = reader.read_header()?;
338
339 let html_file = File::create(&html_path)?;
340 let mut html_writer = BinaryHtmlWriter::new(html_file)?;
341
342 let requested_fields = AllocationField::memory_analysis_fields();
344 let optimized_batch_size = config.batch_size * 2; let mut allocations_buffer = Vec::with_capacity(optimized_batch_size);
347
348 for i in 0..header.total_count {
349 let allocation = reader.read_allocation()?;
350 allocations_buffer.push(allocation);
351
352 if allocations_buffer.len() >= optimized_batch_size || i == header.total_count - 1 {
353 html_writer.write_binary_allocation_batch(&allocations_buffer, &requested_fields)?;
354 allocations_buffer.clear();
355
356 if config.enable_progress_reporting && i % (optimized_batch_size * 5) as u32 == 0 {
357 tracing::debug!(" Progress: {}/{} allocations", i + 1, header.total_count);
358 }
359 }
360 }
361
362 let stats = html_writer.finalize_with_binary_template(project_name)?;
363
364 tracing::debug!(
365 "📊 Optimized conversion completed in {}ms",
366 read_start.elapsed().as_millis()
367 );
368
369 Ok(stats)
370}
371
372fn execute_parallel_conversion<P: AsRef<Path>>(
374 binary_path: P,
375 html_path: P,
376 project_name: &str,
377 config: &BinaryHtmlExportConfig,
378) -> Result<BinaryHtmlStats, BinaryExportError> {
379 let read_start = Instant::now();
380
381 tracing::debug!("🚀 Using parallel conversion strategy for large file");
382
383 let mut reader = BinaryReader::new(&binary_path)?;
386 let header = reader.read_header()?;
387
388 let html_file = File::create(&html_path)?;
389 let mut html_writer = BinaryHtmlWriter::new(html_file)?;
390
391 let requested_fields = [
393 AllocationField::Ptr,
394 AllocationField::Size,
395 AllocationField::TypeName,
396 AllocationField::IsLeaked,
397 ]
398 .into_iter()
399 .collect();
400
401 let parallel_batch_size = config.batch_size * 4; let mut allocations_buffer = Vec::with_capacity(parallel_batch_size);
403
404 for i in 0..header.total_count {
405 let allocation = reader.read_allocation()?;
406 allocations_buffer.push(allocation);
407
408 if allocations_buffer.len() >= parallel_batch_size || i == header.total_count - 1 {
409 html_writer.write_binary_allocation_batch(&allocations_buffer, &requested_fields)?;
410 allocations_buffer.clear();
411
412 if config.enable_progress_reporting && i % (parallel_batch_size * 2) as u32 == 0 {
413 tracing::debug!(" Progress: {}/{} allocations", i + 1, header.total_count);
414 }
415 }
416 }
417
418 let stats = html_writer.finalize_with_binary_template(project_name)?;
419
420 tracing::debug!(
421 "📊 Parallel conversion completed in {}ms",
422 read_start.elapsed().as_millis()
423 );
424
425 Ok(stats)
426}
427
428pub fn parse_binary_to_html_auto<P: AsRef<Path>>(
433 binary_path: P,
434 html_path: P,
435 project_name: &str,
436) -> Result<BinaryHtmlExportStats, BinaryExportError> {
437 let config = BinaryHtmlExportConfig {
438 enable_auto_strategy: true,
439 enable_progress_reporting: true,
440 enable_optimizations: true,
441 ..Default::default()
442 };
443
444 parse_binary_to_html_with_config(binary_path, html_path, project_name, &config)
445}
446
447pub fn get_recommended_config<P: AsRef<Path>>(
449 binary_path: P,
450) -> Result<BinaryHtmlExportConfig, BinaryExportError> {
451 let file_size = std::fs::metadata(binary_path)
452 .map_err(BinaryExportError::Io)?
453 .len();
454
455 let config = if file_size > 100 * 1024 * 1024 {
456 BinaryHtmlExportConfig {
458 enable_auto_strategy: true,
459 parallel_threshold: 3000,
460 batch_size: 2000,
461 enable_progress_reporting: true,
462 max_memory_usage: 128 * 1024 * 1024, enable_optimizations: true,
464 ..Default::default()
465 }
466 } else if file_size > 10 * 1024 * 1024 {
467 BinaryHtmlExportConfig {
469 enable_auto_strategy: true,
470 batch_size: 1500,
471 enable_progress_reporting: true,
472 enable_optimizations: true,
473 ..Default::default()
474 }
475 } else {
476 BinaryHtmlExportConfig {
478 enable_auto_strategy: false,
479 batch_size: 500,
480 enable_progress_reporting: false,
481 enable_optimizations: false,
482 ..Default::default()
483 }
484 };
485
486 Ok(config)
487}
488
489#[cfg(test)]
490mod tests {
491 use super::*;
492
493 #[test]
494 fn test_strategy_selection() {
495 let config = BinaryHtmlExportConfig::default();
496
497 let strategy = select_optimal_strategy(1024 * 1024, &config); assert_eq!(strategy, ProcessingStrategy::Standard);
500
501 let strategy = select_optimal_strategy(60 * 1024 * 1024, &config); assert_eq!(strategy, ProcessingStrategy::Optimized);
504
505 let strategy = select_optimal_strategy(150 * 1024 * 1024, &config); assert_eq!(strategy, ProcessingStrategy::Parallel);
508 }
509
510 #[test]
511 fn test_config_recommendations() {
512 let small_config = BinaryHtmlExportConfig {
515 enable_auto_strategy: false,
516 batch_size: 500,
517 ..Default::default()
518 };
519
520 let medium_config = BinaryHtmlExportConfig {
521 enable_auto_strategy: true,
522 batch_size: 1500,
523 ..Default::default()
524 };
525
526 let large_config = BinaryHtmlExportConfig {
527 enable_auto_strategy: true,
528 batch_size: 2000,
529 max_memory_usage: 128 * 1024 * 1024,
530 ..Default::default()
531 };
532
533 assert!(small_config.batch_size < medium_config.batch_size);
535 assert!(medium_config.batch_size < large_config.batch_size);
536 assert!(large_config.max_memory_usage > small_config.max_memory_usage);
537 }
538
539 #[test]
540 fn test_export_stats_calculations() {
541 let writer_stats = BinaryHtmlStats {
542 allocations_processed: 1000,
543 total_html_size: 50000,
544 peak_memory_usage: 10 * 1024 * 1024, ..Default::default()
546 };
547
548 let export_stats = BinaryHtmlExportStats {
549 writer_stats,
550 total_export_time_ms: 500,
551 file_size_bytes: 5 * 1024 * 1024, strategy_used: ProcessingStrategy::Standard,
553 throughput_allocations_per_sec: 2000.0,
554 memory_efficiency: 100.0,
555 binary_read_time_ms: 100,
556 html_generation_time_ms: 400,
557 };
558
559 assert_eq!(export_stats.processing_efficiency(), 2000.0);
560 assert!(export_stats.performance_improvement() > 0.0); }
562
563 #[test]
564 fn test_processing_strategy_enum() {
565 assert_eq!(ProcessingStrategy::Standard, ProcessingStrategy::Standard);
566 assert_ne!(ProcessingStrategy::Standard, ProcessingStrategy::Parallel);
567
568 let strategy = ProcessingStrategy::Optimized;
570 assert_eq!(format!("{strategy:?}"), "Optimized");
571 }
572
573 #[test]
574 fn test_binary_html_export_config_default() {
575 let config = BinaryHtmlExportConfig::default();
576
577 assert!(config.enable_auto_strategy);
578 assert_eq!(config.parallel_threshold, 5000);
579 assert_eq!(config.large_file_threshold, 100 * 1024 * 1024);
580 assert_eq!(config.batch_size, 1000);
581 assert!(!config.enable_progress_reporting);
582 assert_eq!(config.max_memory_usage, 64 * 1024 * 1024);
583 assert!(config.enable_optimizations);
584 }
585
586 #[test]
587 fn test_binary_html_export_config_debug_clone() {
588 let config = BinaryHtmlExportConfig::default();
589
590 let debug_str = format!("{:?}", config);
592 assert!(debug_str.contains("BinaryHtmlExportConfig"));
593 assert!(debug_str.contains("enable_auto_strategy"));
594 assert!(debug_str.contains("parallel_threshold"));
595
596 let cloned_config = config.clone();
598 assert_eq!(
599 cloned_config.enable_auto_strategy,
600 config.enable_auto_strategy
601 );
602 assert_eq!(cloned_config.parallel_threshold, config.parallel_threshold);
603 assert_eq!(
604 cloned_config.large_file_threshold,
605 config.large_file_threshold
606 );
607 assert_eq!(cloned_config.batch_size, config.batch_size);
608 assert_eq!(
609 cloned_config.enable_progress_reporting,
610 config.enable_progress_reporting
611 );
612 assert_eq!(cloned_config.max_memory_usage, config.max_memory_usage);
613 assert_eq!(
614 cloned_config.enable_optimizations,
615 config.enable_optimizations
616 );
617 }
618
619 #[test]
620 fn test_binary_html_export_stats_debug_clone() {
621 let writer_stats = BinaryHtmlStats::default();
622 let stats = BinaryHtmlExportStats {
623 writer_stats,
624 total_export_time_ms: 1000,
625 binary_read_time_ms: 200,
626 html_generation_time_ms: 800,
627 file_size_bytes: 5 * 1024 * 1024,
628 strategy_used: ProcessingStrategy::Standard,
629 throughput_allocations_per_sec: 1000.0,
630 memory_efficiency: 50.0,
631 };
632
633 let debug_str = format!("{:?}", stats);
635 assert!(debug_str.contains("BinaryHtmlExportStats"));
636 assert!(debug_str.contains("total_export_time_ms"));
637 assert!(debug_str.contains("strategy_used"));
638
639 let cloned_stats = stats.clone();
641 assert_eq!(
642 cloned_stats.total_export_time_ms,
643 stats.total_export_time_ms
644 );
645 assert_eq!(cloned_stats.binary_read_time_ms, stats.binary_read_time_ms);
646 assert_eq!(
647 cloned_stats.html_generation_time_ms,
648 stats.html_generation_time_ms
649 );
650 assert_eq!(cloned_stats.file_size_bytes, stats.file_size_bytes);
651 assert_eq!(cloned_stats.strategy_used, stats.strategy_used);
652 assert_eq!(
653 cloned_stats.throughput_allocations_per_sec,
654 stats.throughput_allocations_per_sec
655 );
656 assert_eq!(cloned_stats.memory_efficiency, stats.memory_efficiency);
657 }
658
659 #[test]
660 fn test_processing_strategy_debug_clone_partialeq() {
661 let strategy = ProcessingStrategy::Parallel;
663 let debug_str = format!("{:?}", strategy);
664 assert_eq!(debug_str, "Parallel");
665
666 let strategy1 = ProcessingStrategy::Optimized;
668 let strategy2 = strategy1.clone();
669 assert_eq!(strategy1, strategy2);
670
671 assert_eq!(ProcessingStrategy::Standard, ProcessingStrategy::Standard);
673 assert_eq!(ProcessingStrategy::Optimized, ProcessingStrategy::Optimized);
674 assert_eq!(ProcessingStrategy::Parallel, ProcessingStrategy::Parallel);
675
676 assert_ne!(ProcessingStrategy::Standard, ProcessingStrategy::Optimized);
677 assert_ne!(ProcessingStrategy::Optimized, ProcessingStrategy::Parallel);
678 assert_ne!(ProcessingStrategy::Standard, ProcessingStrategy::Parallel);
679 }
680
681 #[test]
682 fn test_binary_html_export_stats_processing_efficiency() {
683 let writer_stats = BinaryHtmlStats {
685 allocations_processed: 2000,
686 ..Default::default()
687 };
688 let stats = BinaryHtmlExportStats {
689 writer_stats,
690 total_export_time_ms: 1000, throughput_allocations_per_sec: 0.0,
692 memory_efficiency: 0.0,
693 binary_read_time_ms: 0,
694 html_generation_time_ms: 0,
695 file_size_bytes: 0,
696 strategy_used: ProcessingStrategy::Standard,
697 };
698
699 assert_eq!(stats.processing_efficiency(), 2000.0); let stats_zero_time = BinaryHtmlExportStats {
703 writer_stats: BinaryHtmlStats {
704 allocations_processed: 1000,
705 ..Default::default()
706 },
707 total_export_time_ms: 0,
708 throughput_allocations_per_sec: 0.0,
709 memory_efficiency: 0.0,
710 binary_read_time_ms: 0,
711 html_generation_time_ms: 0,
712 file_size_bytes: 0,
713 strategy_used: ProcessingStrategy::Standard,
714 };
715
716 assert_eq!(stats_zero_time.processing_efficiency(), 0.0);
717 }
718
719 #[test]
720 fn test_binary_html_export_stats_performance_improvement() {
721 let stats_fast = BinaryHtmlExportStats {
723 writer_stats: BinaryHtmlStats::default(),
724 total_export_time_ms: 400, throughput_allocations_per_sec: 0.0,
726 memory_efficiency: 0.0,
727 binary_read_time_ms: 0,
728 html_generation_time_ms: 0,
729 file_size_bytes: 0,
730 strategy_used: ProcessingStrategy::Parallel,
731 };
732
733 assert_eq!(stats_fast.performance_improvement(), 50.0); let stats_slow = BinaryHtmlExportStats {
737 writer_stats: BinaryHtmlStats::default(),
738 total_export_time_ms: 1200, throughput_allocations_per_sec: 0.0,
740 memory_efficiency: 0.0,
741 binary_read_time_ms: 0,
742 html_generation_time_ms: 0,
743 file_size_bytes: 0,
744 strategy_used: ProcessingStrategy::Standard,
745 };
746
747 assert_eq!(stats_slow.performance_improvement(), -50.0); let stats_zero = BinaryHtmlExportStats {
751 writer_stats: BinaryHtmlStats::default(),
752 total_export_time_ms: 0,
753 throughput_allocations_per_sec: 0.0,
754 memory_efficiency: 0.0,
755 binary_read_time_ms: 0,
756 html_generation_time_ms: 0,
757 file_size_bytes: 0,
758 strategy_used: ProcessingStrategy::Standard,
759 };
760
761 assert_eq!(stats_zero.performance_improvement(), 0.0);
762 }
763
764 #[test]
765 fn test_select_optimal_strategy_edge_cases() {
766 let config = BinaryHtmlExportConfig::default();
767
768 let strategy = select_optimal_strategy(config.large_file_threshold, &config);
770 assert_eq!(strategy, ProcessingStrategy::Optimized);
771
772 let strategy = select_optimal_strategy(config.large_file_threshold + 1, &config);
774 assert_eq!(strategy, ProcessingStrategy::Parallel);
775
776 let half_threshold = config.large_file_threshold / 2;
778 let strategy = select_optimal_strategy(half_threshold, &config);
779 assert_eq!(strategy, ProcessingStrategy::Standard);
781
782 let strategy = select_optimal_strategy(config.large_file_threshold / 2 + 1, &config);
784 assert_eq!(strategy, ProcessingStrategy::Optimized);
786
787 let strategy = select_optimal_strategy(config.large_file_threshold / 2 - 1, &config);
789 assert_eq!(strategy, ProcessingStrategy::Standard);
790
791 let strategy = select_optimal_strategy(0, &config);
793 assert_eq!(strategy, ProcessingStrategy::Standard);
794
795 let strategy = select_optimal_strategy(u64::MAX, &config);
797 assert_eq!(strategy, ProcessingStrategy::Parallel);
798 }
799
800 #[test]
801 fn test_select_optimal_strategy_custom_config() {
802 let custom_config = BinaryHtmlExportConfig {
803 large_file_threshold: 50 * 1024 * 1024, ..Default::default()
805 };
806
807 let strategy = select_optimal_strategy(30 * 1024 * 1024, &custom_config); assert_eq!(strategy, ProcessingStrategy::Optimized);
810
811 let strategy = select_optimal_strategy(60 * 1024 * 1024, &custom_config); assert_eq!(strategy, ProcessingStrategy::Parallel);
813
814 let strategy = select_optimal_strategy(10 * 1024 * 1024, &custom_config); assert_eq!(strategy, ProcessingStrategy::Standard);
816 }
817
818 #[test]
819 fn test_parse_binary_to_html_direct_dummy_stats() {
820 use tempfile::TempDir;
821
822 let temp_dir = TempDir::new().unwrap();
823 let binary_path = temp_dir.path().join("test.memscope");
824 let html_path = temp_dir.path().join("test.html");
825
826 std::fs::write(&binary_path, b"dummy binary data").unwrap();
828
829 let result = parse_binary_to_html_direct(&binary_path, &html_path, "test_project");
831
832 assert!(result.is_err());
835 }
836
837 #[test]
838 fn test_parse_binary_to_html_auto_config() {
839 use tempfile::TempDir;
840
841 let temp_dir = TempDir::new().unwrap();
842 let binary_path = temp_dir.path().join("test.memscope");
843 let html_path = temp_dir.path().join("test.html");
844
845 std::fs::write(&binary_path, b"dummy binary data").unwrap();
847
848 let result = parse_binary_to_html_auto(&binary_path, &html_path, "test_project");
850
851 assert!(result.is_err());
853 }
854
855 #[test]
856 fn test_get_recommended_config_file_sizes() {
857 use tempfile::TempDir;
858
859 let temp_dir = TempDir::new().unwrap();
860
861 let small_file = temp_dir.path().join("small.memscope");
863 let small_data = vec![0u8; 5 * 1024 * 1024]; std::fs::write(&small_file, small_data).unwrap();
865
866 let config = get_recommended_config(&small_file).unwrap();
867 assert!(!config.enable_auto_strategy);
868 assert_eq!(config.batch_size, 500);
869 assert!(!config.enable_progress_reporting);
870 assert!(!config.enable_optimizations);
871
872 let medium_file = temp_dir.path().join("medium.memscope");
874 let medium_data = vec![0u8; 50 * 1024 * 1024]; std::fs::write(&medium_file, medium_data).unwrap();
876
877 let config = get_recommended_config(&medium_file).unwrap();
878 assert!(config.enable_auto_strategy);
879 assert_eq!(config.batch_size, 1500);
880 assert!(config.enable_progress_reporting);
881 assert!(config.enable_optimizations);
882
883 let large_file = temp_dir.path().join("large.memscope");
885 let large_data = vec![0u8; 150 * 1024 * 1024]; std::fs::write(&large_file, large_data).unwrap();
887
888 let config = get_recommended_config(&large_file).unwrap();
889 assert!(config.enable_auto_strategy);
890 assert_eq!(config.batch_size, 2000);
891 assert_eq!(config.parallel_threshold, 3000);
892 assert!(config.enable_progress_reporting);
893 assert_eq!(config.max_memory_usage, 128 * 1024 * 1024);
894 assert!(config.enable_optimizations);
895 }
896
897 #[test]
898 fn test_get_recommended_config_nonexistent_file() {
899 let result = get_recommended_config("nonexistent_file.memscope");
900 assert!(result.is_err());
901
902 match result {
904 Err(BinaryExportError::Io(_)) => {
905 }
907 _ => panic!("Expected BinaryExportError::Io"),
908 }
909 }
910
911 #[test]
912 fn test_parse_binary_to_html_with_config_file_not_found() {
913 use tempfile::TempDir;
914
915 let temp_dir = TempDir::new().unwrap();
916 let nonexistent_binary = temp_dir.path().join("nonexistent.memscope");
917 let html_path = temp_dir.path().join("output.html");
918 let config = BinaryHtmlExportConfig::default();
919
920 let result = parse_binary_to_html_with_config(
921 &nonexistent_binary,
922 &html_path,
923 "test_project",
924 &config,
925 );
926
927 assert!(result.is_err());
928 match result {
929 Err(BinaryExportError::Io(_)) => {
930 }
932 _ => panic!("Expected BinaryExportError::Io for file not found"),
933 }
934 }
935
936 #[test]
937 fn test_binary_html_export_stats_with_real_values() {
938 let writer_stats = BinaryHtmlStats {
939 allocations_processed: 5000,
940 total_html_size: 250000,
941 peak_memory_usage: 20 * 1024 * 1024, ..Default::default()
943 };
944
945 let export_stats = BinaryHtmlExportStats {
946 writer_stats,
947 total_export_time_ms: 2000, binary_read_time_ms: 500,
949 html_generation_time_ms: 1500,
950 file_size_bytes: 10 * 1024 * 1024, strategy_used: ProcessingStrategy::Optimized,
952 throughput_allocations_per_sec: 2500.0, memory_efficiency: 250.0, };
955
956 assert_eq!(export_stats.processing_efficiency(), 2500.0);
958
959 assert_eq!(export_stats.performance_improvement(), -150.0); assert_eq!(export_stats.writer_stats.allocations_processed, 5000);
965 assert_eq!(export_stats.total_export_time_ms, 2000);
966 assert_eq!(export_stats.binary_read_time_ms, 500);
967 assert_eq!(export_stats.html_generation_time_ms, 1500);
968 assert_eq!(export_stats.file_size_bytes, 10 * 1024 * 1024);
969 assert_eq!(export_stats.strategy_used, ProcessingStrategy::Optimized);
970 assert_eq!(export_stats.throughput_allocations_per_sec, 2500.0);
971 assert_eq!(export_stats.memory_efficiency, 250.0);
972 }
973
974 #[test]
975 fn test_config_builder_pattern_simulation() {
976 let base_config = BinaryHtmlExportConfig::default();
978
979 let custom_config = BinaryHtmlExportConfig {
980 enable_auto_strategy: false,
981 parallel_threshold: 10000,
982 large_file_threshold: 200 * 1024 * 1024,
983 batch_size: 2000,
984 enable_progress_reporting: true,
985 max_memory_usage: 128 * 1024 * 1024,
986 enable_optimizations: false,
987 };
988
989 assert_ne!(
991 custom_config.enable_auto_strategy,
992 base_config.enable_auto_strategy
993 );
994 assert_ne!(
995 custom_config.parallel_threshold,
996 base_config.parallel_threshold
997 );
998 assert_ne!(
999 custom_config.large_file_threshold,
1000 base_config.large_file_threshold
1001 );
1002 assert_ne!(custom_config.batch_size, base_config.batch_size);
1003 assert_ne!(
1004 custom_config.enable_progress_reporting,
1005 base_config.enable_progress_reporting
1006 );
1007 assert_ne!(custom_config.max_memory_usage, base_config.max_memory_usage);
1008 assert_ne!(
1009 custom_config.enable_optimizations,
1010 base_config.enable_optimizations
1011 );
1012
1013 assert!(!custom_config.enable_auto_strategy);
1015 assert_eq!(custom_config.parallel_threshold, 10000);
1016 assert_eq!(custom_config.large_file_threshold, 200 * 1024 * 1024);
1017 assert_eq!(custom_config.batch_size, 2000);
1018 assert!(custom_config.enable_progress_reporting);
1019 assert_eq!(custom_config.max_memory_usage, 128 * 1024 * 1024);
1020 assert!(!custom_config.enable_optimizations);
1021 }
1022
1023 #[test]
1024 fn test_strategy_selection_comprehensive() {
1025 let configs = [
1026 BinaryHtmlExportConfig::default(),
1028 BinaryHtmlExportConfig {
1030 large_file_threshold: 10 * 1024 * 1024, ..Default::default()
1032 },
1033 BinaryHtmlExportConfig {
1035 large_file_threshold: 500 * 1024 * 1024, ..Default::default()
1037 },
1038 ];
1039
1040 let file_sizes = [
1041 1024, 1024 * 1024, 10 * 1024 * 1024, 50 * 1024 * 1024, 100 * 1024 * 1024, 200 * 1024 * 1024, 1024 * 1024 * 1024, ];
1049
1050 for config in &configs {
1051 for &file_size in &file_sizes {
1052 let strategy = select_optimal_strategy(file_size, config);
1053
1054 match strategy {
1056 ProcessingStrategy::Standard
1057 | ProcessingStrategy::Optimized
1058 | ProcessingStrategy::Parallel => {
1059 }
1061 }
1062
1063 if file_size > config.large_file_threshold {
1065 assert_eq!(strategy, ProcessingStrategy::Parallel);
1066 } else if file_size > config.large_file_threshold / 2 {
1067 assert_eq!(strategy, ProcessingStrategy::Optimized);
1068 } else {
1069 assert_eq!(strategy, ProcessingStrategy::Standard);
1070 }
1071 }
1072 }
1073 }
1074}