unbundle 5.2.0

Unbundle media files - extract still frames, audio tracks, and subtitles from video files
Documentation
//! Subtitle search and time-range filtering integration tests.
//!
//! These tests require the fixture files generated by
//! `tests/fixtures/generate_fixtures.sh` (or `.bat` on Windows).

use std::path::Path;
use std::time::Duration;

use unbundle::MediaFile;

fn subtitled_path() -> &'static str {
    "tests/fixtures/sample_with_subtitles.mkv"
}

#[test]
fn extract_subtitle_range() {
    let path = subtitled_path();
    if !Path::new(path).exists() {
        return;
    }

    let mut unbundler = MediaFile::open(path).expect("open");
    let events = unbundler
        .subtitle()
        .extract_range(Duration::from_millis(0), Duration::from_millis(2500))
        .expect("subtitle range");

    // The fixture has subtitle #1 at 0.5–2.0s and #2 at 2.5–4.0s.
    // Only subs overlapping [0, 2.5s) should appear.
    assert!(
        !events.is_empty(),
        "expected at least one subtitle in range"
    );

    for event in &events {
        // Start should be before the end of our range window.
        assert!(
            event.start_time < Duration::from_millis(2500),
            "subtitle start {:?} should be < 2.5s",
            event.start_time
        );
    }
}

#[test]
fn search_subtitles_case_insensitive() {
    let path = subtitled_path();
    if !Path::new(path).exists() {
        return;
    }

    let mut unbundler = MediaFile::open(path).expect("open");
    let results = unbundler.subtitle().search("hello").expect("search");

    assert!(!results.is_empty(), "expected to find 'hello' in subtitles");
    // "Hello, world!" should match.
    assert!(
        results[0].text.to_lowercase().contains("hello"),
        "expected match to contain 'hello'"
    );
}

#[test]
fn search_subtitles_no_match() {
    let path = subtitled_path();
    if !Path::new(path).exists() {
        return;
    }

    let mut unbundler = MediaFile::open(path).expect("open");
    let results = unbundler
        .subtitle()
        .search("nonexistent_xyzzy")
        .expect("search");

    assert!(results.is_empty(), "expected no matches");
}

#[test]
fn search_exact_case_sensitive() {
    let path = subtitled_path();
    if !Path::new(path).exists() {
        return;
    }

    let mut unbundler = MediaFile::open(path).expect("open");

    // Exact casing: "Hello" (capital H) should match.
    let results = unbundler
        .subtitle()
        .search_exact("Hello")
        .expect("search_exact");
    assert!(
        !results.is_empty(),
        "expected 'Hello' to match (exact case)"
    );

    // Lower case "hello" should NOT match search_exact.
    let results_lower = unbundler
        .subtitle()
        .search_exact("hello")
        .expect("search_exact lower");
    assert!(
        results_lower.is_empty(),
        "expected 'hello' (lowercase) to NOT match search_exact"
    );
}