#![allow(clippy::expect_used, clippy::unwrap_used)]
use jugar_probar::pixel_coverage::{
ColorPalette, CombinedCoverageReport, ConfidenceInterval, CoverageCell, FalsifiabilityGate,
FalsifiableHypothesis, LineCoverageReport, OutputMode, PixelCoverageTracker, PixelRegion,
PngHeatmap, ScoreBar,
};
fn main() {
println!("Pixel Coverage Heatmap Example (PIXEL-001 v2.1)");
println!("=================================================\n");
println!("Step 1: Creating coverage tracker (10x8 grid on 800x600 screen)...");
let mut tracker = PixelCoverageTracker::new(800, 600, 10, 8);
println!("\nStep 2: Simulating coverage with gaps...");
tracker.record_region(PixelRegion::new(0, 0, 800, 150));
println!(" ✓ Header area covered (rows 0-1)");
tracker.record_region(PixelRegion::new(0, 150, 320, 300));
println!(" ✓ Left sidebar covered");
tracker.record_region(PixelRegion::new(480, 150, 320, 300));
println!(" ✓ Right content covered");
println!(" ⚠ Middle content area is a GAP (uncovered)");
tracker.record_region(PixelRegion::new(0, 525, 800, 75));
println!(" ✓ Footer area covered");
let report = tracker.generate_report();
println!("\nStep 3: Coverage Report");
println!(
" Overall Coverage: {:.1}%",
report.overall_coverage * 100.0
);
println!(
" Covered Cells: {}/{}",
report.covered_cells, report.total_cells
);
println!(" Uncovered Regions: {}", report.uncovered_regions.len());
println!(
" Meets Threshold: {}",
if report.meets_threshold { "✓" } else { "✗" }
);
println!("\nStep 3b: PIXEL-001 v2.1 Verification...");
let gate = FalsifiabilityGate::new(15.0);
let h1 = FalsifiableHypothesis::coverage_threshold("H0-HEATMAP-COV", 0.75)
.evaluate(report.overall_coverage);
let h2 = FalsifiableHypothesis::max_gap_size("H0-HEATMAP-GAP", 8.0)
.evaluate(report.uncovered_regions.len() as f32);
println!(
" H0-HEATMAP-COV (≥75%): {}",
if h1.falsified {
"FALSIFIED"
} else {
"NOT FALSIFIED"
}
);
println!(
" H0-HEATMAP-GAP (≤8 gaps): {}",
if h2.falsified {
"FALSIFIED"
} else {
"NOT FALSIFIED"
}
);
let gate_result = gate.evaluate(&h1);
println!(
" FalsifiabilityGate: {}",
if gate_result.is_passed() {
"PASSED"
} else {
"FAILED"
}
);
println!("\n Wilson Score CI (95%):");
let ci = ConfidenceInterval::wilson_score(report.covered_cells, report.total_cells, 0.95);
println!(
" Coverage: [{:.1}%, {:.1}%]",
ci.lower * 100.0,
ci.upper * 100.0
);
println!("\n Score Bars:");
let mode = OutputMode::from_env();
let coverage_bar = ScoreBar::new("Pixel", report.overall_coverage, 0.80);
println!(" {}", coverage_bar.render(mode));
println!("\nStep 4: Generating PNG heatmaps...");
let output_path = std::env::temp_dir().join("coverage_viridis.png");
PngHeatmap::new(800, 600)
.with_palette(ColorPalette::viridis())
.with_title("Pixel Coverage Heatmap")
.with_subtitle("Viridis Palette - Colorblind Safe")
.with_legend()
.with_gap_highlighting()
.with_margin(40)
.export_to_file(tracker.cells(), &output_path)
.expect("Failed to export PNG");
println!(" ✓ Viridis heatmap: {}", output_path.display());
let output_path = std::env::temp_dir().join("coverage_magma.png");
PngHeatmap::new(800, 600)
.with_palette(ColorPalette::magma())
.with_title("Coverage Analysis")
.with_subtitle("Magma Palette - Dark to Bright")
.with_legend()
.with_gap_highlighting()
.with_margin(40)
.export_to_file(tracker.cells(), &output_path)
.expect("Failed to export PNG");
println!(" ✓ Magma heatmap: {}", output_path.display());
let output_path = std::env::temp_dir().join("coverage_heat.png");
PngHeatmap::new(800, 600)
.with_palette(ColorPalette::heat())
.with_title("Heat Map View")
.with_subtitle("Classic Heat Palette")
.with_legend()
.with_gap_highlighting()
.with_margin(40)
.export_to_file(tracker.cells(), &output_path)
.expect("Failed to export PNG");
println!(" ✓ Heat heatmap: {}", output_path.display());
println!("\nStep 5: Terminal Heatmap (STDOUT)");
println!("{}", "─".repeat(50));
let terminal = tracker.terminal_heatmap();
println!("{}", terminal.render_with_border());
println!("{}", terminal.legend());
println!("\nStep 6: Combined Coverage Report (STDOUT)");
println!("{}", "─".repeat(50));
let line_report = LineCoverageReport::new(
0.90, 1.0, 0.85, 22, 20, );
let combined = CombinedCoverageReport::from_parts(line_report, report);
println!("{}", combined.summary());
println!("\nStep 6b: Generating Combined PNG with Stats Panel...");
let output_path = std::env::temp_dir().join("coverage_combined.png");
PngHeatmap::new(800, 700)
.with_palette(ColorPalette::viridis())
.with_title("Combined Coverage Report")
.with_subtitle("Line + Pixel Coverage")
.with_legend()
.with_gap_highlighting()
.with_margin(40)
.with_combined_stats(&combined)
.export_to_file(tracker.cells(), &output_path)
.expect("Failed to export PNG");
println!(" ✓ Combined stats heatmap: {}", output_path.display());
println!("\nStep 7: Generating pattern heatmap...");
let cells = create_pattern_cells();
println!("\n Pattern Preview (ASCII):");
print_ascii_heatmap(&cells);
let output_path = std::env::temp_dir().join("coverage_pattern.png");
PngHeatmap::new(800, 600)
.with_palette(ColorPalette::viridis())
.with_legend()
.with_gap_highlighting()
.with_margin(40)
.export_to_file(&cells, &output_path)
.expect("Failed to export PNG");
println!("\n ✓ Pattern heatmap: {}", output_path.display());
println!("\nStep 8: Gap Analysis (STDOUT)");
println!("{}", "─".repeat(50));
print_gap_analysis(&cells);
println!("\n✅ Pixel coverage heatmap example completed (PIXEL-001 v2.1)!");
println!("\nGenerated PNG files:");
for name in ["viridis", "magma", "heat", "combined", "pattern"] {
println!(
" • {}/coverage_{}.png",
std::env::temp_dir().display(),
name
);
}
println!("\n--- PIXEL-001 v2.1 Features Demonstrated ---");
println!(" • FalsifiabilityGate: Popperian methodology with 15/25 threshold");
println!(" • FalsifiableHypothesis: coverage_threshold, max_gap_size");
println!(" • ConfidenceInterval: Wilson score for statistical rigor");
println!(" • ScoreBar: Visual progress indicators");
println!(" • CombinedCoverageReport: Line + Pixel coverage");
println!("\n--- CLI Usage ---");
println!("Generate heatmaps via CLI:");
println!(" probar coverage --png output.png --palette viridis --legend --gaps");
println!(" probar coverage --png output.png --title \"My Coverage\" --palette magma");
println!(" probar coverage --json report.json");
}
fn print_ascii_heatmap(cells: &[Vec<CoverageCell>]) {
println!(" ┌{}┐", "─".repeat(cells[0].len()));
for row in cells {
print!(" │");
for cell in row {
let ch = match cell.coverage {
c if c <= 0.0 => '·', c if c <= 0.25 => '░',
c if c <= 0.50 => '▒',
c if c <= 0.75 => '▓',
_ => '█',
};
print!("{}", ch);
}
println!("│");
}
println!(" └{}┘", "─".repeat(cells[0].len()));
println!(" Legend: · = Gap (0%) ░ = 1-25% ▒ = 26-50% ▓ = 51-75% █ = 76-100%");
}
fn print_gap_analysis(cells: &[Vec<CoverageCell>]) {
let mut gaps = Vec::new();
for (row_idx, row) in cells.iter().enumerate() {
for (col_idx, cell) in row.iter().enumerate() {
if cell.coverage <= 0.0 {
gaps.push((row_idx, col_idx));
}
}
}
let total_cells = cells.len() * cells[0].len();
let covered = total_cells - gaps.len();
let coverage_pct = (covered as f32 / total_cells as f32) * 100.0;
println!(" Total Cells: {}", total_cells);
println!(" Covered Cells: {}", covered);
println!(
" Gap Cells: {} (highlighted in red on PNG)",
gaps.len()
);
println!(" Coverage: {:.1}%", coverage_pct);
if !gaps.is_empty() {
println!("\n Gap Locations:");
for (row, col) in &gaps {
println!(" ⚠ Cell ({}, {}) - UNTESTED", row, col);
}
} else {
println!("\n ✓ No gaps detected - 100% coverage!");
}
}
fn is_gap_position(row: usize, col: usize) -> bool {
let middle_gap = row == 5 && (5..=7).contains(&col);
let end_gap = row == 2 && col > 10;
middle_gap || end_gap
}
fn gradient_coverage(row: usize, col: usize, rows: usize, cols: usize) -> f32 {
if is_gap_position(row, col) {
return 0.0;
}
let x_factor = col as f32 / (cols - 1) as f32;
let y_factor = row as f32 / (rows - 1) as f32;
(x_factor + y_factor) / 2.0
}
fn create_pattern_cells() -> Vec<Vec<CoverageCell>> {
const ROWS: usize = 10;
const COLS: usize = 15;
(0..ROWS)
.map(|row| {
(0..COLS)
.map(|col| {
let coverage = gradient_coverage(row, col, ROWS, COLS);
CoverageCell {
coverage,
hit_count: (coverage * 10.0) as u64,
}
})
.collect()
})
.collect()
}