mod common;
use common::{run, s7cmd_cmd};
#[test]
fn no_subcommand_exits_2_with_usage() {
let (code, _stdout, stderr) = run(&mut s7cmd_cmd());
assert_eq!(code, Some(2), "no subcommand must exit 2; stderr={stderr}");
assert!(
stderr.to_lowercase().contains("usage"),
"expected usage on stderr; got: {stderr}"
);
}
#[test]
fn unrecognized_subcommand_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("not-a-real-cmd"));
assert_eq!(code, Some(2), "unrecognized subcommand must exit 2");
assert!(
stderr.contains("unrecognized subcommand"),
"expected 'unrecognized subcommand' on stderr; got: {stderr}"
);
}
#[test]
fn sync_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("sync"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty(), "sync with no args must produce stderr");
}
#[test]
fn ls_invalid_target_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["ls", "notavalidpath"]));
assert_eq!(code, Some(2));
assert!(
stderr.contains("must be an S3 path"),
"expected S3 path error; got: {stderr}"
);
}
#[test]
fn clean_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("clean"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn cp_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("cp"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn cp_missing_target_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["cp", "s3://b/k"]));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn mv_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("mv"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn mv_missing_target_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["mv", "s3://b/k"]));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn mv_self_move_identical_keys_exits_1() {
let (code, _stdout, stderr) =
run(s7cmd_cmd().args(["mv", "s3://b/dir/k.txt", "s3://b/dir/k.txt"]));
assert_eq!(code, Some(1), "mv onto itself must exit 1; stderr={stderr}");
assert!(
stderr.contains("onto itself"),
"expected the self-move rejection on stderr; got: {stderr}"
);
}
#[test]
fn mv_self_move_directory_style_target_exits_1() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["mv", "s3://b/dir/k.txt", "s3://b/dir/"]));
assert_eq!(
code,
Some(1),
"directory-style self-move must exit 1; stderr={stderr}"
);
assert!(
stderr.contains("onto itself"),
"expected the self-move rejection on stderr; got: {stderr}"
);
}
#[test]
fn cp_skip_existing_with_stdio_target_rejected() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["cp", "--skip-existing", "s3://b/k", "-"]));
assert_eq!(
code,
Some(2),
"cp --skip-existing with stdout target must exit 2; stderr={stderr}"
);
assert!(
stderr.contains("stdout target"),
"expected stdout target error.\n--- stderr ---\n{stderr}"
);
}
#[test]
fn cp_skip_existing_with_if_none_match_rejected() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args([
"cp",
"--skip-existing",
"--if-none-match",
"/tmp/a",
"s3://b/k",
]));
assert_eq!(
code,
Some(2),
"cp --skip-existing --if-none-match must exit 2; stderr={stderr}"
);
assert!(
stderr.contains("--if-none-match"),
"expected --if-none-match error.\n--- stderr ---\n{stderr}"
);
}
#[test]
fn rm_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("rm"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn head_object_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("head-object"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_object_tagging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-object-tagging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_object_tagging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-object-tagging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_object_tagging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-object-tagging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_object_annotation_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-object-annotation"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_object_annotation_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-object-annotation"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_object_annotation_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-object-annotation"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn list_object_annotations_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("list-object-annotations"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn create_bucket_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("create-bucket"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn head_bucket_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("head-bucket"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_tagging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-tagging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_tagging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-tagging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_tagging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-tagging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_policy_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-policy"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_policy_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-policy"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_policy_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-policy"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_versioning_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-versioning"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_versioning_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-versioning"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_lifecycle_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-lifecycle-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_lifecycle_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-lifecycle-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_lifecycle_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-lifecycle-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_encryption_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-encryption"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_encryption_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-encryption"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_encryption_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-encryption"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_cors_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-cors"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_cors_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-cors"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_cors_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-cors"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_public_access_block_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-public-access-block"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_public_access_block_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-public-access-block"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_public_access_block_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-public-access-block"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_website_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-website"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_website_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-website"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_website_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-website"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_logging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-logging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_logging_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-logging"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_notification_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-notification-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_notification_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-notification-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_replication_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-replication"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_replication_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-replication"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn delete_bucket_replication_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("delete-bucket-replication"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_accelerate_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-accelerate-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_accelerate_configuration_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-accelerate-configuration"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_request_payment_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-request-payment"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn put_bucket_request_payment_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("put-bucket-request-payment"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn get_bucket_policy_status_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("get-bucket-policy-status"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn restore_object_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("restore-object"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn presign_no_args_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("presign"));
assert_eq!(code, Some(2));
assert!(!stderr.is_empty());
}
#[test]
fn auto_complete_shell_env_does_not_lift_required_target() {
let (code, _stdout, stderr) = run(s7cmd_cmd()
.arg("get-bucket-versioning")
.env("AUTO_COMPLETE_SHELL", "bash"));
assert_eq!(
code,
Some(2),
"env var must not satisfy the required target; stderr={stderr}"
);
assert!(
stderr.to_lowercase().contains("required"),
"expected missing-required parse error; got: {stderr}"
);
}
#[test]
fn auto_complete_shell_env_does_not_default_sync_paths() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("sync").env("AUTO_COMPLETE_SHELL", "bash"));
assert_eq!(
code,
Some(2),
"sync must still require source/target with the env var set; stderr={stderr}"
);
assert!(
stderr.to_lowercase().contains("source"),
"expected missing source error; got: {stderr}"
);
}
#[test]
fn auto_complete_shell_env_invalid_value_is_ignored() {
let (code, _stdout, stderr) = run(s7cmd_cmd()
.arg("get-bucket-versioning")
.env("AUTO_COMPLETE_SHELL", "not-a-shell"));
assert_eq!(code, Some(2));
assert!(
stderr.to_lowercase().contains("required") && !stderr.contains("invalid value"),
"env value must be ignored entirely, not parsed; got: {stderr}"
);
}
#[test]
fn auto_complete_shell_env_does_not_default_clean_target() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("clean").env("AUTO_COMPLETE_SHELL", "bash"));
assert_eq!(
code,
Some(2),
"clean must still require a target with the env var set; stderr={stderr}"
);
assert!(
stderr.to_lowercase().contains("required"),
"expected missing target error; got: {stderr}"
);
}
#[test]
fn auto_complete_shell_env_does_not_lift_cp_paths() {
let (code, _stdout, stderr) = run(s7cmd_cmd().arg("cp").env("AUTO_COMPLETE_SHELL", "bash"));
assert_eq!(
code,
Some(2),
"cp must still require source/target with the env var set; stderr={stderr}"
);
assert!(
stderr.to_lowercase().contains("required"),
"expected missing source/target error; got: {stderr}"
);
}
#[test]
fn batch_run_parallel_over_cap_exits_2() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["batch-run", "--parallel", "100000", "-"]));
assert_eq!(
code,
Some(2),
"oversized --parallel must be a clean parse error; stderr={stderr}"
);
assert!(
stderr.to_lowercase().contains("no more than")
|| stderr.to_lowercase().contains("parallel"),
"expected a --parallel range error; got: {stderr}"
);
}
#[test]
fn batch_run_parallel_semaphore_panic_value_exits_2_not_101() {
let huge = (usize::MAX >> 3).wrapping_add(1).to_string();
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["batch-run", "--parallel", &huge, "-"]));
assert_eq!(
code,
Some(2),
"must be a clean exit 2, not a panic; stderr={stderr}"
);
}
#[test]
fn batch_run_parallel_overflow_value_exits_2() {
let (code, _stdout, _stderr) =
run(s7cmd_cmd().args(["batch-run", "--parallel", "99999999999999999999999999", "-"]));
assert_eq!(code, Some(2));
}
#[test]
fn batch_run_parallel_at_cap_is_accepted() {
let (code, _stdout, stderr) = run(s7cmd_cmd().args(["batch-run", "--parallel", "1024", "-"]));
assert_eq!(
code,
Some(0),
"MAX_PARALLEL must be accepted and run; stderr={stderr}"
);
}