face 0.1.0

Fold And Cluster Entries — a Unix-style CLI for grouping, paging, and summarizing structured command output.
Documentation
//! Shared test driver for the end-to-end pipeline tests.
//!
//! Each `tests/*.rs` file is its own crate, so this module is included
//! via `mod common;` from each test file rather than imported. The
//! single `drive(args, stdin)` helper drives the lib through the
//! `Io<R, W, E>` entry point and returns `(exit_code, stdout, stderr)`.

use clap::Parser;
use face_cli::{Io, cli::Cli, run};
use std::io::Cursor;

/// Drive `face` end-to-end with `args` and `stdin`, returning
/// `(exit_code, stdout, stderr)`.
///
/// `args` is the full argv slice, starting with the program name
/// (`["face", "--flag", "value"]`) so it matches what `Cli::try_parse_from`
/// expects. Parse errors panic — they're test bugs in the argv shape,
/// not behaviors under test. Runtime errors map to a non-zero exit code,
/// matching the binary's `main()` mapping.
#[allow(dead_code)] // Each test file is a separate crate; not all use every helper.
pub fn drive(args: &[&str], stdin: &str) -> (i32, String, String) {
    let cli = Cli::try_parse_from(args).expect("argv parse");
    let mut io = Io::new(
        Cursor::new(stdin.as_bytes().to_vec()),
        Vec::<u8>::new(),
        Vec::<u8>::new(),
    );
    let exit_code = match run(cli, &mut io) {
        Ok(()) => 0,
        Err(_) => 1,
    };
    (
        exit_code,
        String::from_utf8(io.stdout).expect("stdout utf-8"),
        String::from_utf8(io.stderr).expect("stderr utf-8"),
    )
}

/// Drive `face` and return whether the run produced an error, plus
/// stdout/stderr for diagnostics in test failure messages.
#[allow(dead_code)]
pub fn drive_result(args: &[&str], stdin: &str) -> Result<(String, String), (String, String)> {
    let cli = Cli::try_parse_from(args).expect("argv parse");
    let mut io = Io::new(
        Cursor::new(stdin.as_bytes().to_vec()),
        Vec::<u8>::new(),
        Vec::<u8>::new(),
    );
    let outcome = run(cli, &mut io);
    let stdout = String::from_utf8(io.stdout).expect("stdout utf-8");
    let stderr = String::from_utf8(io.stderr).expect("stderr utf-8");
    match outcome {
        Ok(()) => Ok((stdout, stderr)),
        Err(_) => Err((stdout, stderr)),
    }
}

/// Try to parse argv only; return `true` on success, `false` on a clap
/// parse error.
#[allow(dead_code)]
pub fn parses(args: &[&str]) -> bool {
    Cli::try_parse_from(args).is_ok()
}