s7cmd 1.2.2

Reliable, flexible, and fast command-line tool for Amazon S3
//! Process-level CLI tests for the `put-bucket-request-payment` subcommand.
//! These run without AWS credentials or network access.

use std::process::{Command, Stdio};

fn s7cmd() -> Command {
    Command::new(env!("CARGO_BIN_EXE_s7cmd"))
}

fn run(cmd: &mut Command) -> (bool, String, String, Option<i32>) {
    let output = cmd
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .expect("failed to spawn s7cmd binary");
    let stdout = String::from_utf8_lossy(&output.stdout).to_string();
    let stderr = String::from_utf8_lossy(&output.stderr).to_string();
    (
        output.status.success(),
        stdout,
        stderr,
        output.status.code(),
    )
}

#[test]
fn help_succeeds_and_lists_option_groups() {
    let (ok, stdout, _stderr, _code) = run(s7cmd().args(["put-bucket-request-payment", "--help"]));
    assert!(ok, "put-bucket-request-payment --help must succeed");
    assert!(stdout.contains("AWS Configuration"));
    assert!(stdout.contains("Retry Options"));
    assert!(stdout.contains("Timeout Options"));
}

#[test]
fn missing_both_payer_flags_exits_2() {
    let (ok, _stdout, stderr, code) =
        run(s7cmd().args(["put-bucket-request-payment", "s3://example"]));
    assert!(!ok);
    assert_eq!(
        code,
        Some(2),
        "missing payer flags should exit 2; got {code:?}; stderr: {stderr}"
    );
    assert!(
        stderr.to_lowercase().contains("required") || stderr.to_lowercase().contains("usage"),
        "expected 'required' or 'usage' in stderr; got: {stderr}"
    );
}

#[test]
fn both_requester_and_bucket_owner_exits_2() {
    let (ok, _stdout, stderr, code) = run(s7cmd().args([
        "put-bucket-request-payment",
        "s3://example",
        "--requester",
        "--bucket-owner",
    ]));
    assert!(!ok);
    assert_eq!(
        code,
        Some(2),
        "conflicting flags should exit 2; got {code:?}; stderr: {stderr}"
    );
    assert!(
        stderr.to_lowercase().contains("cannot be used")
            || stderr.to_lowercase().contains("conflict")
            || stderr.to_lowercase().contains("error"),
        "expected conflict message in stderr; got: {stderr}"
    );
}

#[test]
fn requester_alone_with_valid_bucket_parses_ok() {
    let (ok, _stdout, stderr, code) =
        run(s7cmd().args(["put-bucket-request-payment", "s3://example", "--requester"]));
    assert!(
        code != Some(2),
        "--requester alone must parse without clap error; code={code:?}; stderr={stderr}"
    );
    let _ = ok;
}

#[test]
fn bucket_owner_alone_with_valid_bucket_parses_ok() {
    let (ok, _stdout, stderr, code) = run(s7cmd().args([
        "put-bucket-request-payment",
        "s3://example",
        "--bucket-owner",
    ]));
    assert!(
        code != Some(2),
        "--bucket-owner alone must parse without clap error; code={code:?}; stderr={stderr}"
    );
    let _ = ok;
}

#[test]
fn missing_target_exits_non_zero() {
    let (ok, _stdout, stderr, code) =
        run(s7cmd().args(["put-bucket-request-payment", "--requester"]));
    assert!(!ok);
    assert_eq!(
        code,
        Some(2),
        "missing target should exit 2; stderr: {stderr}"
    );
}

#[test]
fn bucket_with_key_exits_1() {
    let (ok, _stdout, stderr, code) = run(s7cmd().args([
        "put-bucket-request-payment",
        "s3://example/key",
        "--requester",
    ]));
    assert!(!ok);
    assert_eq!(
        code,
        Some(1),
        "bucket path with key should exit 1 (validation)"
    );
    assert!(
        !stderr.is_empty(),
        "should have an error message on stderr; got empty"
    );
}