tests/cli_tail.rs

//! End-to-end tests for `ripgrab tail`.

use std::io::Write;
use std::thread;
use std::time::Duration;

use assert_cmd::Command;
use predicates::str::contains;
use tempfile::NamedTempFile;

fn bin() -> Command {
    Command::cargo_bin("ripgrab").unwrap()
}

#[test]
fn tail_with_include_filter_reads_matching_lines() {
    let mut tmp = NamedTempFile::new().unwrap();
    writeln!(tmp, "request ok status=200").unwrap();
    writeln!(tmp, "request failed status=503").unwrap();
    writeln!(tmp, "request ok status=200").unwrap();
    tmp.flush().unwrap();

    bin()
        .args(["tail", tmp.path().to_str().unwrap(), "-i", "status=5\\d\\d"])
        .env("NO_COLOR", "1")
        .assert()
        .success()
        .stdout(contains("status=503"))
        .stdout(contains("status=200").not());
}

#[test]
fn tail_with_exclude_filter_drops_matching_lines() {
    let mut tmp = NamedTempFile::new().unwrap();
    writeln!(tmp, "heartbeat ok").unwrap();
    writeln!(tmp, "request ok").unwrap();
    tmp.flush().unwrap();

    bin()
        .args(["tail", tmp.path().to_str().unwrap(), "-e", "heartbeat"])
        .env("NO_COLOR", "1")
        .assert()
        .success()
        .stdout(contains("request ok"))
        .stdout(contains("heartbeat").not());
}

#[test]
fn tail_no_origin_hides_filename_column() {
    let mut tmp = NamedTempFile::new().unwrap();
    writeln!(tmp, "hello").unwrap();
    tmp.flush().unwrap();

    let out = bin()
        .args(["tail", tmp.path().to_str().unwrap(), "--no-origin"])
        .env("NO_COLOR", "1")
        .output()
        .unwrap();
    let stdout = String::from_utf8(out.stdout).unwrap();
    assert_eq!(stdout.trim_end(), "hello");
}

#[test]
fn tail_from_end_skips_existing_lines() {
    let mut tmp = NamedTempFile::new().unwrap();
    for i in 0..5 {
        writeln!(tmp, "old-{}", i).unwrap();
    }
    tmp.flush().unwrap();

    let cmd = bin()
        .args([
            "tail",
            tmp.path().to_str().unwrap(),
            "--from-end", "2",
        ])
        .env("NO_COLOR", "1")
        .output()
        .unwrap();
    let stdout = String::from_utf8(cmd.stdout).unwrap();
    assert!(!stdout.contains("old-0"));
    assert!(stdout.contains("old-3") || stdout.contains("old-4"));
}

#[test]
fn tail_stdin_input() {
    bin()
        .args(["tail", "-"])
        .env("NO_COLOR", "1")
        .write_stdin("from stdin\n")
        .assert()
        .success()
        .stdout(contains("from stdin"));
}

#[test]
fn tail_rejects_missing_path() {
    bin()
        .args(["tail", "/does/not/exist"])
        .assert()
        .failure();
    thread::sleep(Duration::from_millis(10));
}