//! Integration tests for the `chunkcat` command. use std::fs; use std::path::{Path, PathBuf}; use assert_cmd::Command; use predicates::prelude::*; use serde_json::Value; use tempfile::{TempDir, tempdir}; const SAMPLE_RS: &str = "reading/sample.rs"; fn cargo_command() -> Command { Command::cargo_bin("chunkcat").expect("binary") } fn fixture(path: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("..") .join("..") .join("fixtures") .join(path) } fn temp_file(name: &str, contents: impl AsRef<[u8]>) -> (TempDir, PathBuf) { let dir = tempdir().expect("tempdir"); let path = dir.path().join(name); fs::write(&path, contents).expect("fixture"); (dir, path) } fn pwsh_command(script: impl AsRef) -> Command { let mut command = Command::new("pwsh"); command .arg("-NoProfile") .arg("-Command") .arg(script.as_ref()); command } fn ps_quote(value: impl std::fmt::Display) -> String { format!("'{}'", value.to_string().replace('\'', "''")) } fn display_path(path: &Path) -> String { path.display().to_string() } #[test] fn lists_chunk_inventory_in_text_mode() { let mut command = cargo_command(); command .arg(fixture(SAMPLE_RS)) .arg("--max-lines") .arg("8") .arg("--overlap") .arg("2") .arg("--inventory") .assert() .success() .stdout(predicate::str::contains("chunks=6")) .stdout(predicate::str::contains("0 lines=1:8")) .stdout(predicate::str::contains("5 lines=31:35")); } #[test] fn renders_selected_chunk_with_line_numbers() { let mut command = cargo_command(); command .arg(fixture(SAMPLE_RS)) .arg("--max-lines") .arg("8") .arg("--overlap") .arg("2") .arg("--chunk") .arg("2") .assert() .success() .stdout(predicate::str::contains("chunk=2 lines=13:20")) .stdout(predicate::str::contains("13: pub enum Mode {")) .stdout(predicate::str::contains("20: Mode::Safe")); } #[test] fn emits_json_inventory_and_selected_chunk_payloads() { let mut inventory = cargo_command(); let inventory_output = inventory .arg("--json") .arg(fixture(SAMPLE_RS)) .arg("--max-lines") .arg("8") .arg("--overlap") .arg("2") .assert() .success() .get_output() .stdout .clone(); let inventory_json = serde_json::from_slice::(&inventory_output).expect("inventory"); assert_eq!(inventory_json["path"], display_path(&fixture(SAMPLE_RS))); assert_eq!(inventory_json["total_lines"], 35); assert_eq!(inventory_json["chunks"][0]["start_line"], 1); assert_eq!(inventory_json["chunks"][5]["end_line"], 35); assert!(inventory_json["selected_chunk"].is_null()); let mut selected = cargo_command(); let selected_output = selected .arg("--json") .arg(fixture(SAMPLE_RS)) .arg("--max-lines") .arg("8") .arg("--overlap") .arg("2") .arg("--chunk") .arg("4") .assert() .success() .get_output() .stdout .clone(); let selected_json = serde_json::from_slice::(&selected_output).expect("selected"); assert_eq!(selected_json["selected_chunk"]["index"], 4); assert_eq!(selected_json["selected_chunk"]["start_line"], 25); assert_eq!(selected_json["selected_chunk"]["lines"][0]["number"], 25); assert_eq!( selected_json["selected_chunk"]["lines"][0]["text"], " match mode {" ); } #[test] fn supports_powershell_pipeline_for_path_input() { let binary = assert_cmd::cargo::cargo_bin("chunkcat"); let input = fixture(SAMPLE_RS); let script = format!( "{} | & {} --json --max-lines 10 --chunk 1", ps_quote(input.display()), ps_quote(binary.display()) ); let mut command = pwsh_command(script); command .assert() .success() .stdout(predicate::str::contains("\"selected_chunk\"")) .stdout(predicate::str::contains("\"index\":1")); } #[test] fn utf8_bom_file_does_not_pollute_first_chunk_line() { let (_dir, path) = temp_file("bom.txt", "\u{feff}alpha\nbeta\n"); let mut command = cargo_command(); command .arg(&path) .arg("--max-lines") .arg("2") .arg("--chunk") .arg("0") .assert() .success() .stdout(predicate::str::contains("1: alpha")) .stdout(predicate::str::contains("\u{feff}alpha").not()); } #[test] fn invalid_utf8_file_reports_text_read_error() { let (_dir, path) = temp_file("invalid-utf8.txt", [0x61, 0x80, 0x0A]); let mut command = cargo_command(); command .arg(&path) .arg("--max-lines") .arg("2") .arg("--chunk") .arg("0") .assert() .failure() .stderr(predicate::str::contains("looks like a binary file")) .stderr(predicate::str::contains("invalid-utf8.txt")); } #[test] fn help_includes_examples_and_pipeline_usage() { let mut command = cargo_command(); command .arg("--help") .assert() .success() .stdout(predicate::str::contains( "chunkcat .\\fixtures\\reading\\sample.rs --max-lines 8", )) .stdout(predicate::str::contains("--inventory")) .stdout(predicate::str::contains("ConvertFrom-Json")) .stdout(predicate::str::contains("--chunk")); }