trimdown 0.1.6

Fast file compression tool for Office documents (PPTX, DOCX, XLSX), PDFs, videos, images, OpenDocument formats, and archives with streaming support
Documentation
use std::path::PathBuf;
use std::process::Command;
use serde_json::Value;

/// Test video output quality using ffprobe
#[test]
fn test_video_quality_validation() {
    let test_cases = vec![
        ("examples/output/video_high_quality.mp4", 400_000, 500_000), // Higher bitrate
        ("examples/output/video_balanced.mp4", 300_000, 400_000),     // Medium bitrate
        ("examples/output/video_720p.mp4", 200_000, 350_000),         // Lower bitrate
    ];

    for (path, min_bitrate, max_bitrate) in test_cases {
        if !PathBuf::from(path).exists() {
            eprintln!("Skipping {}: file not found (run examples first)", path);
            continue;
        }

        let output = Command::new("ffprobe")
            .args(&[
                "-v", "error",
                "-select_streams", "v:0",
                "-show_entries", "stream=codec_name,width,height,bit_rate",
                "-of", "json",
                path
            ])
            .output()
            .expect("Failed to run ffprobe");

        assert!(output.status.success(), "ffprobe failed for {}", path);

        let json: Value = serde_json::from_slice(&output.stdout)
            .expect("Failed to parse ffprobe output");

        let stream = &json["streams"][0];
        
        // Validate codec
        assert_eq!(stream["codec_name"].as_str().unwrap(), "h264", 
            "{} should use H.264 codec", path);

        // Validate resolution
        let width = stream["width"].as_u64().unwrap();
        let height = stream["height"].as_u64().unwrap();
        assert!(width > 0 && height > 0, 
            "{} should have valid resolution", path);

        // Validate bitrate
        if let Some(bitrate_str) = stream["bit_rate"].as_str() {
            let bitrate: u64 = bitrate_str.parse().unwrap();
            assert!(bitrate >= min_bitrate && bitrate <= max_bitrate,
                "{} bitrate {} should be between {} and {}", 
                path, bitrate, min_bitrate, max_bitrate);
        }

        println!("{} validated: {}x{}, codec: {}", 
            path, width, height, stream["codec_name"].as_str().unwrap());
    }
}

/// Test concatenated video quality
#[test]
fn test_concat_video_quality() {
    let test_cases = vec![
        ("examples/output/concat_fast.mp4", "Fast concat"),
        ("examples/output/concat_reencode.mp4", "Re-encode concat"),
        ("examples/output/concat_720p.mp4", "720p concat"),
    ];

    for (path, description) in test_cases {
        if !PathBuf::from(path).exists() {
            eprintln!("Skipping {}: file not found", path);
            continue;
        }

        let output = Command::new("ffprobe")
            .args(&[
                "-v", "error",
                "-select_streams", "v:0",
                "-show_entries", "stream=codec_name,duration,nb_frames",
                "-of", "json",
                path
            ])
            .output()
            .expect("Failed to run ffprobe");

        assert!(output.status.success(), "ffprobe failed for {}", path);

        let json: Value = serde_json::from_slice(&output.stdout)
            .expect("Failed to parse ffprobe output");

        let stream = &json["streams"][0];
        
        // Validate codec
        assert_eq!(stream["codec_name"].as_str().unwrap(), "h264");

        // Validate duration (concatenated videos should be longer)
        if let Some(duration_str) = stream["duration"].as_str() {
            let duration: f64 = duration_str.parse().unwrap();
            assert!(duration > 1.0, 
                "{} should have duration > 1s (concatenated)", path);
        }

        println!("{} validated: {}", path, description);
    }
}

/// Test PDF output integrity
#[test]
fn test_pdf_quality_validation() {
    let test_cases = vec![
        "examples/output/pdf_screen.pdf",
        "examples/output/pdf_ebook.pdf",
        "examples/output/pdf_printer.pdf",
    ];

    for path in test_cases {
        if !PathBuf::from(path).exists() {
            eprintln!("Skipping {}: file not found", path);
            continue;
        }

        // Check PDF header
        let content = std::fs::read(path).expect("Failed to read PDF");
        assert!(content.starts_with(b"%PDF-"), 
            "{} should have valid PDF header", path);

        // Check file size
        let metadata = std::fs::metadata(path).unwrap();
        assert!(metadata.len() > 500, 
            "{} should be larger than 500 bytes", path);

        // Validate with pdfinfo if available
        let output = Command::new("pdfinfo")
            .arg(path)
            .output();

        if let Ok(output) = output {
            if output.status.success() {
                let info = String::from_utf8_lossy(&output.stdout);
                assert!(info.contains("Pages:"), 
                    "{} should have page information", path);
                assert!(info.contains("PDF version:"), 
                    "{} should have PDF version", path);
                
                println!("{} validated: PDF version found, valid structure", path);
            }
        } else {
            println!("{} validated (basic check only, pdfinfo not available)", path);
        }
    }
}

/// Test Office file output integrity
#[test]
fn test_office_quality_validation() {
    let test_cases = vec![
        ("examples/output/presentation_compressed.pptx", "PPTX"),
        ("examples/output/document_compressed.docx", "DOCX"),
    ];

    for (path, file_type) in test_cases {
        if !PathBuf::from(path).exists() {
            eprintln!("Skipping {}: file not found", path);
            continue;
        }

        // Office files are ZIP archives
        let content = std::fs::read(path).expect("Failed to read file");
        assert!(content.starts_with(b"PK"), 
            "{} should have valid ZIP header", path);

        // Validate with unzip
        let output = Command::new("unzip")
            .args(&["-l", path])
            .output()
            .expect("Failed to run unzip");

        assert!(output.status.success(), 
            "{} should be a valid ZIP archive", path);

        let listing = String::from_utf8_lossy(&output.stdout);
        
        // Check for required Office XML files
        if file_type == "PPTX" {
            assert!(listing.contains("[Content_Types].xml"), 
                "{} should contain [Content_Types].xml", path);
            assert!(listing.contains("ppt/presentation.xml"), 
                "{} should contain presentation.xml", path);
        } else if file_type == "DOCX" {
            assert!(listing.contains("[Content_Types].xml"), 
                "{} should contain [Content_Types].xml", path);
            assert!(listing.contains("word/document.xml"), 
                "{} should contain document.xml", path);
        }

        println!("{} validated: Valid {} structure", path, file_type);
    }
}

/// Test compression ratios are reasonable
#[test]
fn test_compression_ratios() {
    let input_output_pairs = vec![
        ("tests/fixtures/videos/sample.mp4", "examples/output/video_balanced.mp4"),
        ("tests/fixtures/pdfs/sample.pdf", "examples/output/pdf_ebook.pdf"),
    ];

    for (input, output) in input_output_pairs {
        if !PathBuf::from(output).exists() {
            eprintln!("Skipping {}: file not found", output);
            continue;
        }

        let input_size = std::fs::metadata(input).unwrap().len();
        let output_size = std::fs::metadata(output).unwrap().len();

        // Output should exist and have content
        assert!(output_size > 0, "{} should not be empty", output);

        // Calculate ratio
        let ratio = (output_size as f64 / input_size as f64) * 100.0;
        
        println!("{}: {:.1}% of original size ({}B -> {}B)", 
            output, ratio, input_size, output_size);
    }
}

/// Test all output files have valid formats
#[test]
fn test_output_file_formats() {
    let files: Vec<(&str, &[u8], &str)> = vec![
        ("examples/output/video_high_quality.mp4", &[0x00, 0x00, 0x00], "MP4"),
        ("examples/output/concat_fast.mp4", &[0x00, 0x00, 0x00], "MP4"),
        ("examples/output/pdf_screen.pdf", &[0x25, 0x50, 0x44, 0x46, 0x2D], "PDF"), // %PDF-
        ("examples/output/presentation_compressed.pptx", &[0x50, 0x4B], "ZIP/PPTX"), // PK
        ("examples/output/document_compressed.docx", &[0x50, 0x4B], "ZIP/DOCX"), // PK
    ];

    for (path, magic_bytes, format) in files {
        if !PathBuf::from(path).exists() {
            eprintln!("Skipping {}: file not found", path);
            continue;
        }

        let mut file = std::fs::File::open(path).unwrap();
        let mut buffer = vec![0u8; magic_bytes.len()];
        use std::io::Read;
        
        if file.read_exact(&mut buffer).is_ok() {
            if magic_bytes == b"\x00\x00\x00" {
                // MP4 files start with ftyp box
                assert!(buffer.starts_with(b"\x00\x00\x00") || buffer.len() >= 3,
                    "{} should have valid {} format", path, format);
            } else {
                assert_eq!(&buffer[..], magic_bytes,
                    "{} should have valid {} magic bytes", path, format);
            }
            println!("{} validated: {} format", path, format);
        }
    }
}