mod common;
use common::fixtures::*;
use common::*;
use log::debug;
use predicates::prelude::*;
use predicates::str::contains;
use rstest::*;
#[rstest]
fn test_output_default(stdout_test_env: StdoutTestEnv) {
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.assert()
.success()
.stdout(contains("test.py"))
.stdout(contains("print('Hello, World!')"))
.stderr(contains("Token count:"))
.stdout(contains("Token count:").not());
debug!("✓ Default stdout output test passed");
}
#[rstest]
#[case("explicit_dash", vec!["-O", "-", "--no-clipboard"], vec!["test.py", "print('Hello, World!')", "README.md", "# Test Project"], vec!["✓","▹▹▹▹▸ Done!","Token count:","Copied to clipboard successfully"], true)]
#[case("long_form", vec!["--output-file", "-", "--no-clipboard"], vec!["test.py", "print('Hello, World!')", "README.md", "# Test Project"], vec!["✓","▹▹▹▹▸ Done!","Token count:","Copied to clipboard successfully"], true)]
#[case("quiet_mode", vec!["--quiet", "-O", "-", "--no-clipboard"], vec!["test.py", "print('Hello, World!')"], vec!["✓","▹▹▹▹▸ Done!","Token count:","Copied to clipboard successfully"], true)]
fn test_stdout_configurations(
stdout_test_env: StdoutTestEnv,
#[case] test_name: &str,
#[case] args: Vec<&str>,
#[case] should_contain: Vec<&str>,
#[case] should_not_contain: Vec<&str>,
#[case] should_succeed: bool,
) {
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path());
for arg in args {
cmd.arg(arg);
}
let assertion = cmd.assert();
if should_succeed {
let assertion = assertion.success();
let mut assertion = assertion;
for content in should_contain {
assertion = assertion.stdout(contains(content));
}
for content in should_not_contain {
assertion = assertion.stdout(contains(content).not());
}
debug!("✓ {} test passed", test_name);
} else {
assertion.failure();
debug!("✓ {} test passed (correctly failed)", test_name);
}
}
#[rstest]
#[case("file_output", vec!["--output-file", "output.txt", "--no-clipboard"], vec!["test.py", "print('Hello, World!')", "README.md"], vec![], true)]
#[case("file_output_quiet", vec!["--output-file", "output.txt", "--quiet", "--no-clipboard"], vec!["test.py", "print('Hello, World!')"], vec!["✓"], true)]
#[case("file_output_json", vec!["--output-file", "output.txt", "--output-format", "json", "--no-clipboard"], vec!["{", "\"files\"", "test.py"], vec![], true)]
#[case("file_output_xml", vec!["--output-file", "output.txt", "--output-format", "xml", "--no-clipboard"], vec!["<directory>", "</file>", "test.py"], vec![], true)]
#[case("file_output_markdown", vec!["--output-file", "output.txt", "--output-format", "markdown", "--no-clipboard"], vec!["Source Tree:", "```", "test.py"], vec![], true)]
fn test_file_output_configurations(
stdout_test_env: StdoutTestEnv,
#[case] test_name: &str,
#[case] args: Vec<&str>,
#[case] should_contain: Vec<&str>,
#[case] should_not_contain: Vec<&str>,
#[case] should_succeed: bool,
) {
let output_file = stdout_test_env.dir.path().join("output.txt");
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path());
for arg in args {
if arg == "output.txt" {
cmd.arg(output_file.to_str().unwrap());
} else {
cmd.arg(arg);
}
}
let assertion = cmd.assert();
if should_succeed {
assertion.success();
let file_content =
std::fs::read_to_string(&output_file).expect("Should be able to read output file");
for content in should_contain {
assert!(
file_content.contains(content),
"Test {}: Expected '{}' in file output",
test_name,
content
);
}
for content in should_not_contain {
assert!(
!file_content.contains(content),
"Test {}: Expected '{}' NOT to be in file output",
test_name,
content
);
}
debug!("✓ {} test passed", test_name);
} else {
assertion.failure();
debug!("✓ {} test passed (correctly failed)", test_name);
}
}
#[rstest]
fn test_conflicting_output_options_should_fail(stdout_test_env: StdoutTestEnv) {
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("-")
.arg("-O")
.arg("-")
.arg("--no-clipboard")
.assert()
.failure();
debug!("✓ Conflicting output options test passed (correctly failed)");
}
#[rstest]
fn test_output_file_vs_stdout_conflict(stdout_test_env: StdoutTestEnv) {
let output_file = stdout_test_env.dir.path().join("output.txt");
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("--output-file")
.arg(output_file.to_str().unwrap())
.arg("-O")
.arg("-")
.arg("--no-clipboard")
.assert()
.failure()
.stderr(
contains("cannot be used multiple times")
.or(contains("conflict"))
.or(contains("mutually exclusive")),
);
debug!("✓ Output file vs stdout conflict test passed (correctly failed)");
}
#[rstest]
#[case("json", "{", "\"files\"")]
#[case("xml", "<", ">")]
#[case("markdown", "Source Tree:", "```")]
fn test_stdout_with_different_formats(
stdout_test_env: StdoutTestEnv,
#[case] format: &str,
#[case] expected_start: &str,
#[case] expected_content: &str,
) {
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("--output-format")
.arg(format)
.arg("-O")
.arg("-")
.arg("--no-clipboard")
.assert()
.success()
.stdout(contains(expected_start))
.stdout(contains(expected_content))
.stdout(contains("test.py"));
debug!("✓ Stdout with {} format test passed", format);
}
#[rstest]
fn test_stderr_messages_normal_mode(stdout_test_env: StdoutTestEnv) {
let output_file = stdout_test_env.dir.path().join("output.txt");
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("--output-file")
.arg(output_file.to_str().unwrap())
.arg("--no-clipboard")
.assert()
.success()
.stderr(contains("Prompt written to file:"));
debug!("✓ Normal mode stderr messages test passed");
}
#[rstest]
fn test_stderr_messages_quiet_mode(stdout_test_env: StdoutTestEnv) {
let output_file = stdout_test_env.dir.path().join("output.txt");
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("--output-file")
.arg(output_file.to_str().unwrap())
.arg("--quiet")
.arg("--no-clipboard")
.assert()
.success()
.stderr(contains("Done!").not());
debug!("✓ Quiet mode stderr messages test passed");
}
#[rstest]
fn test_stderr_messages_with_clipboard(stdout_test_env: StdoutTestEnv) {
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path()).assert().success();
debug!("✓ Clipboard stderr messages test passed");
}
#[rstest]
#[case("json")]
#[case("xml")]
#[case("markdown")]
fn test_stderr_with_output_formats(stdout_test_env: StdoutTestEnv, #[case] format: &str) {
let output_file = stdout_test_env.dir.path().join("output.txt");
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("--output-file")
.arg(output_file.to_str().unwrap())
.arg("--output-format")
.arg(format)
.arg("--no-clipboard")
.assert()
.success()
.stderr(contains("Prompt written to file:"));
debug!("✓ Stderr with {} format test passed", format);
}
#[rstest]
fn test_stdout_stderr_separation(stdout_test_env: StdoutTestEnv) {
let mut cmd = assert_cmd::cargo::cargo_bin_cmd!("code2prompt");
cmd.arg(stdout_test_env.path())
.arg("-O")
.arg("-")
.arg("--no-clipboard")
.assert()
.success()
.stdout(contains("test.py"))
.stdout(contains("print('Hello, World!')"))
.stdout(contains("Token count:").not())
.stdout(contains("✓").not());
debug!("✓ Stdout/stderr separation test passed");
}
#[rstest]
fn test_stdout_fixture_setup(stdout_test_env: StdoutTestEnv) {
let test_files = vec!["test.py", "README.md", "config.json"];
for file in test_files {
let file_path = stdout_test_env.dir.path().join(file);
assert!(file_path.exists(), "Test file {} should exist", file);
}
debug!("✓ Stdout fixture setup test passed");
}