mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
* cksum: fix parsing error with tagged cheksum files When passed the '-c'/'--check' flag, and parsing a checksum file in the "tagged" format, cksum (symlinked to sha256sum, etc...) expects a line that looks like this: ShA256 (file.bin) = da39a3ee5e6b4b0d3255bfef95601890afd80709 If the hash algorithm at the beginning of the line (in the above case SHA256) is missing, then cksum panics because it is attempts to use the value of an array at index -1. This fix causes cksum to instead consider the line a syntax error and ignore it, just as GNU cksum does. I also added unit and integration tests to check for the above behaviour. --------- Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
3426 lines
95 KiB
Rust
3426 lines
95 KiB
Rust
// This file is part of the uutils coreutils package.
|
|
//
|
|
// For the full copyright and license information, please view the LICENSE
|
|
// file that was distributed with this source code.
|
|
// spell-checker:ignore (words) asdf algo algos asha mgmt xffname hexa GFYEQ HYQK Yqxb dont checkfile
|
|
|
|
use rstest::rstest;
|
|
use rstest_reuse::{apply, template};
|
|
|
|
use uutests::at_and_ucmd;
|
|
use uutests::new_ucmd;
|
|
use uutests::util::TestScenario;
|
|
use uutests::util::UCommand;
|
|
use uutests::util::log_info;
|
|
use uutests::util_name;
|
|
|
|
#[template]
|
|
#[rstest]
|
|
#[case::sysv("sysv")]
|
|
#[case::bsd("bsd")]
|
|
#[case::crc("crc")]
|
|
#[case::md5("md5")]
|
|
#[case::sha1("sha1")]
|
|
#[case::sha224("sha224")]
|
|
#[case::sha256("sha256")]
|
|
#[case::sha384("sha384")]
|
|
#[case::sha512("sha512")]
|
|
#[case::blake2b("blake2b")]
|
|
#[case::blake3("blake3")]
|
|
#[case::sm3("sm3")]
|
|
fn test_all_algos(#[case] algo: &str) {}
|
|
|
|
#[template]
|
|
#[rstest]
|
|
fn test_sha(#[values("sha2", "sha3")] algo: &str, #[values(224, 256, 384, 512)] len: u32) {}
|
|
|
|
fn sha_fixture_name(algo: &str, len: u32, prefix: &str, suffix: &str) -> String {
|
|
// assume algo is always "sha2" or "sha3"
|
|
match algo {
|
|
"sha2" => format!("{prefix}sha{len}{suffix}"),
|
|
_ => format!("{prefix}sha3_{len}{suffix}"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_invalid_arg() {
|
|
new_ucmd!().arg("--definitely-invalid").fails_with_code(1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_single_file() {
|
|
new_ucmd!()
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("crc_single_file.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_files() {
|
|
new_ucmd!()
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("crc_multiple_files.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_stdin() {
|
|
new_ucmd!()
|
|
.pipe_in_fixture("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("crc_stdin.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_empty_file() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
at.touch("a");
|
|
|
|
ucmd.arg("a")
|
|
.succeeds()
|
|
.no_stderr()
|
|
.normalized_newlines_stdout_is("4294967295 0 a\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_arg_overrides_stdin() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let input = "foobarfoobar"; // spell-checker:disable-line
|
|
|
|
at.touch("a");
|
|
|
|
ucmd.arg("a")
|
|
.pipe_in(input.as_bytes())
|
|
// the command might have exited before all bytes have been pipe in.
|
|
// in that case, we don't care about the error (broken pipe)
|
|
.ignore_stdin_write_error()
|
|
.succeeds()
|
|
.no_stderr()
|
|
.normalized_newlines_stdout_is("4294967295 0 a\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_nonexisting_file() {
|
|
let file_name = "asdf";
|
|
|
|
new_ucmd!()
|
|
.arg(file_name)
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("cksum: {file_name}: No such file or directory"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_nonexisting_file_out() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write(
|
|
"f",
|
|
"MD5 (nonexistent) = e5773576fc75ff0f8eba14f61587ae28\n",
|
|
);
|
|
|
|
ucmd.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stdout_contains("nonexistent: FAILED open or read")
|
|
.stderr_contains("cksum: nonexistent: No such file or directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_one_nonexisting_file() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
at.touch("abc.txt");
|
|
at.touch("xyz.txt");
|
|
|
|
ucmd.arg("abc.txt")
|
|
.arg("asdf.txt")
|
|
.arg("xyz.txt")
|
|
.fails()
|
|
.stdout_contains_line("4294967295 0 xyz.txt")
|
|
.stderr_contains("asdf.txt: No such file or directory")
|
|
.stdout_contains_line("4294967295 0 abc.txt");
|
|
}
|
|
|
|
// Make sure crc is correct for files larger than 32 bytes
|
|
// but <128 bytes (1 fold pclmul) // spell-checker:disable-line
|
|
#[test]
|
|
fn test_crc_for_bigger_than_32_bytes() {
|
|
let result = new_ucmd!().arg("chars.txt").succeeds();
|
|
|
|
let mut stdout_split = result.stdout_str().split(' ');
|
|
|
|
let cksum: i64 = stdout_split.next().unwrap().parse().unwrap();
|
|
let bytes_cnt: i64 = stdout_split.next().unwrap().parse().unwrap();
|
|
|
|
assert_eq!(cksum, 586_047_089);
|
|
assert_eq!(bytes_cnt, 16);
|
|
}
|
|
|
|
#[test]
|
|
fn test_stdin_larger_than_128_bytes() {
|
|
let result = new_ucmd!().arg("larger_than_2056_bytes.txt").succeeds();
|
|
|
|
let mut stdout_split = result.stdout_str().split(' ');
|
|
|
|
let cksum: i64 = stdout_split.next().unwrap().parse().unwrap();
|
|
let bytes_cnt: i64 = stdout_split.next().unwrap().parse().unwrap();
|
|
|
|
assert_eq!(cksum, 945_881_979);
|
|
assert_eq!(bytes_cnt, 2058);
|
|
}
|
|
|
|
#[test]
|
|
fn test_repeated_flags() {
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("sha1")
|
|
.arg("--algo=sha256")
|
|
.arg("-a=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("md5_single_file.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_tag_after_untagged() {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg("--tag")
|
|
.arg("-a=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("md5_single_file.expected");
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_algorithm_single_file(#[case] algo: &str) {
|
|
for option in ["-a", "--algorithm"] {
|
|
new_ucmd!()
|
|
.arg(format!("{option}={algo}"))
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(format!("{algo}_single_file.expected"));
|
|
}
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_algorithm_multiple_files(#[case] algo: &str) {
|
|
for option in ["-a", "--algorithm"] {
|
|
new_ucmd!()
|
|
.arg(format!("{option}={algo}"))
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(format!("{algo}_multiple_files.expected"));
|
|
}
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_algorithm_stdin(#[case] algo: &str) {
|
|
for option in ["-a", "--algorithm"] {
|
|
new_ucmd!()
|
|
.arg(format!("{option}={algo}"))
|
|
.pipe_in_fixture("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(format!("{algo}_stdin.expected"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_untagged_single_file() {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("untagged/crc_single_file.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_untagged_multiple_files() {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("untagged/crc_multiple_files.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_untagged_stdin() {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.pipe_in_fixture("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("untagged/crc_stdin.expected");
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_untagged_algorithm_single_file(#[case] algo: &str) {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(format!("untagged/{algo}_single_file.expected"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_tag_short() {
|
|
new_ucmd!()
|
|
.arg("-t")
|
|
.arg("--untagged")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is("cd724690f7dc61775dfac400a71f2caa lorem_ipsum.txt\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_untagged_algorithm_after_tag() {
|
|
new_ucmd!()
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("untagged/md5_single_file.expected");
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_untagged_algorithm_multiple_files(#[case] algo: &str) {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(format!("untagged/{algo}_multiple_files.expected"));
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_untagged_algorithm_stdin(#[case] algo: &str) {
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.pipe_in_fixture("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(format!("untagged/{algo}_stdin.expected"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_sha_length_invalid() {
|
|
for algo in ["sha2", "sha3"] {
|
|
for l in ["0", "00", "13", "56", "99999999999999999999999999"] {
|
|
new_ucmd!()
|
|
.arg("--algorithm")
|
|
.arg(algo)
|
|
.arg("--length")
|
|
.arg(l)
|
|
.arg("/dev/null")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("invalid length: '{l}'"))
|
|
.stderr_contains(format!(
|
|
"digest length for '{}' must be 224, 256, 384, or 512",
|
|
algo.to_ascii_uppercase()
|
|
));
|
|
|
|
// Also fails with --check
|
|
new_ucmd!()
|
|
.arg("--algorithm")
|
|
.arg(algo)
|
|
.arg("--length")
|
|
.arg(l)
|
|
.arg("/dev/null")
|
|
.arg("--check")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("invalid length: '{l}'"))
|
|
.stderr_contains(format!(
|
|
"digest length for '{}' must be 224, 256, 384, or 512",
|
|
algo.to_ascii_uppercase()
|
|
));
|
|
}
|
|
|
|
// Different error for NaNs
|
|
for l in ["512x", "x512", "512x512"] {
|
|
new_ucmd!()
|
|
.arg("--algorithm")
|
|
.arg(algo)
|
|
.arg("--length")
|
|
.arg(l)
|
|
.arg("/dev/null")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("invalid length: '{l}'"));
|
|
|
|
// Also fails with --check
|
|
new_ucmd!()
|
|
.arg("--algorithm")
|
|
.arg(algo)
|
|
.arg("--length")
|
|
.arg(l)
|
|
.arg("/dev/null")
|
|
.arg("--check")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("invalid length: '{l}'"));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_sha_missing_length() {
|
|
for algo in ["sha2", "sha3"] {
|
|
new_ucmd!()
|
|
.arg("--algorithm")
|
|
.arg(algo)
|
|
.arg("lorem_ipsum.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!(
|
|
"--algorithm={algo} requires specifying --length 224, 256, 384, or 512"
|
|
));
|
|
}
|
|
}
|
|
|
|
fn sha_cmd(algo: &str, len: u32) -> UCommand {
|
|
let mut ucmd = new_ucmd!();
|
|
ucmd.arg(format!("--algorithm={algo}"))
|
|
.arg(format!("--length={len}"));
|
|
ucmd
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_sha_single_file(algo: &str, len: u32) {
|
|
sha_cmd(algo, len)
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(sha_fixture_name(algo, len, "", "_single_file.expected"));
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_sha_multiple_files(algo: &str, len: u32) {
|
|
sha_cmd(algo, len)
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(sha_fixture_name(algo, len, "", "_multiple_files.expected"));
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_sha_stdin(algo: &str, len: u32) {
|
|
sha_cmd(algo, len)
|
|
.pipe_in_fixture("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(sha_fixture_name(algo, len, "", "_stdin.expected"));
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_untagged_sha_single_file(algo: &str, len: u32) {
|
|
sha_cmd(algo, len)
|
|
.arg("--untagged")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(sha_fixture_name(
|
|
algo,
|
|
len,
|
|
"untagged/",
|
|
"_single_file.expected",
|
|
));
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_untagged_sha_multiple_files(algo: &str, len: u32) {
|
|
sha_cmd(algo, len)
|
|
.arg("--untagged")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(sha_fixture_name(
|
|
algo,
|
|
len,
|
|
"untagged/",
|
|
"_multiple_files.expected",
|
|
));
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_untagged_sha_stdin(algo: &str, len: u32) {
|
|
sha_cmd(algo, len)
|
|
.arg("--untagged")
|
|
.pipe_in_fixture("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture(sha_fixture_name(algo, len, "untagged/", "_stdin.expected"));
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_check_tagged_sha_single_file(algo: &str, len: u32) {
|
|
new_ucmd!()
|
|
.arg("--check")
|
|
.arg(sha_fixture_name(algo, len, "", "_single_file.expected"))
|
|
.succeeds()
|
|
.stdout_is("lorem_ipsum.txt: OK\n");
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_check_tagged_sha_multiple_files(algo: &str, len: u32) {
|
|
new_ucmd!()
|
|
.arg("--check")
|
|
.arg(sha_fixture_name(algo, len, "", "_multiple_files.expected"))
|
|
.succeeds()
|
|
.stdout_contains("lorem_ipsum.txt: OK\n")
|
|
.stdout_contains("alice_in_wonderland.txt: OK\n");
|
|
}
|
|
|
|
// When checking sha2/sha3 in untagged mode, the length is automatically
|
|
// deduced from the length of the digest.
|
|
#[apply(test_sha)]
|
|
fn test_check_untagged_sha_single_file(algo: &str, len: u32) {
|
|
new_ucmd!()
|
|
.arg("--check")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.arg(sha_fixture_name(
|
|
algo,
|
|
len,
|
|
"untagged/",
|
|
"_single_file.expected",
|
|
))
|
|
.succeeds()
|
|
.stdout_is("lorem_ipsum.txt: OK\n");
|
|
}
|
|
|
|
#[apply(test_sha)]
|
|
fn test_check_untagged_sha_multiple_files(algo: &str, len: u32) {
|
|
new_ucmd!()
|
|
.arg("--check")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.arg(sha_fixture_name(
|
|
algo,
|
|
len,
|
|
"untagged/",
|
|
"_multiple_files.expected",
|
|
))
|
|
.succeeds()
|
|
.stdout_contains("lorem_ipsum.txt: OK\n")
|
|
.stdout_contains("alice_in_wonderland.txt: OK\n");
|
|
}
|
|
|
|
#[rstest]
|
|
#[case::sha2("sha2", &[
|
|
"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
|
|
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
|
|
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
|
|
])]
|
|
#[case::sha3("sha3", &[
|
|
"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7",
|
|
"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a",
|
|
"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004",
|
|
"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
|
|
])]
|
|
fn test_check_untagged_sha_invalid_length(#[case] algo: &str, #[case] digests: &[&str; 4]) {
|
|
// When checking with --algorithm sha2/sha3, Guess the length from the provided
|
|
// digest. Raise "improperly formatted" if the digest is not af adequate
|
|
// size (224, 256, 384 or 512 bits).
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("a");
|
|
at.touch("b");
|
|
at.touch("c");
|
|
at.touch("d");
|
|
at.touch("e");
|
|
|
|
let invalid = "xxxx e";
|
|
|
|
ucmd.arg("-a")
|
|
.arg(algo)
|
|
.arg("-c")
|
|
.pipe_in(format!(
|
|
"{} a\n{} b\n{} c\n{} d\n{invalid}",
|
|
digests[0], digests[1], digests[2], digests[3]
|
|
))
|
|
.succeeds()
|
|
.stdout_contains("a: OK")
|
|
.stdout_contains("b: OK")
|
|
.stdout_contains("c: OK")
|
|
.stdout_contains("d: OK")
|
|
.stdout_does_not_contain("e: FAILED")
|
|
.stderr_contains("improperly formatted");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_sha2_tagged_variant() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.touch("f");
|
|
|
|
// SHA2-xxx is an alias to SHAxxx we don't output but we still recognize.
|
|
let checksum_lines = [
|
|
(
|
|
"SHA224",
|
|
"SHA2-224",
|
|
"(f) = d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
|
|
),
|
|
(
|
|
"SHA256",
|
|
"SHA2-256",
|
|
"(f) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
|
),
|
|
(
|
|
"SHA384",
|
|
"SHA2-384",
|
|
"(f) = 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
|
|
),
|
|
(
|
|
"SHA512",
|
|
"SHA2-512",
|
|
"(f) = cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
|
|
),
|
|
];
|
|
|
|
for (basic, variant, digest) in checksum_lines {
|
|
let stdin = format!("{basic} {digest}");
|
|
log_info("stdin is: ", &stdin);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--algorithm=sha2")
|
|
.pipe_in(stdin)
|
|
.succeeds()
|
|
.stdout_is("f: OK\n");
|
|
|
|
// Check that the variant works the same
|
|
let stdin = format!("{variant} {digest}");
|
|
log_info("stdin is: ", &stdin);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--algorithm=sha2")
|
|
.pipe_in(stdin)
|
|
.succeeds()
|
|
.stdout_is("f: OK\n");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_sha2_tagged_missing_hint() {
|
|
// SHA2 (<file>) = <digest>
|
|
//
|
|
// should fail and raise "improperly formatted" because SHA2 expects a
|
|
// mandatory length hint.
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("a");
|
|
at.touch("b");
|
|
|
|
// valid digest but missing hint
|
|
let invalid_sha224 = "SHA2 (a) = d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f";
|
|
// invalid digest
|
|
let invalid = "SHA2 (b) = xxxx";
|
|
|
|
ucmd.arg("-c")
|
|
.pipe_in(format!("{invalid_sha224}\n{invalid}"))
|
|
.fails()
|
|
.stderr_contains("no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_tagged_missing_algo() {
|
|
// When checking tagged lines, if the algorithm is missing, print an "improperly
|
|
// formatted" message rather than panic.
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("a");
|
|
|
|
let invalid1 = "(a) = d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f";
|
|
let invalid2 = "a) = d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f";
|
|
let invalid3 = "(a = d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f";
|
|
|
|
ucmd.arg("-c")
|
|
.pipe_in(format!("{invalid1}\n{invalid2}\n{invalid3}"))
|
|
.fails()
|
|
.stderr_contains("no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[rstest]
|
|
#[case::md5("md5", "d41d8cd98f00b204e9800998ecf8427e")]
|
|
#[case::sha1("sha1", "da39a3ee5e6b4b0d3255bfef95601890afd80709")]
|
|
#[case::sha224("sha224", "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f")]
|
|
#[case::sha256(
|
|
"sha256",
|
|
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
)]
|
|
#[case::sha384(
|
|
"sha384",
|
|
"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
|
|
)]
|
|
#[case::sha512(
|
|
"sha512",
|
|
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
|
|
)]
|
|
#[case::sm3(
|
|
"sm3",
|
|
"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b"
|
|
)]
|
|
fn test_check_untagged_with_invalid_length(#[case] algo: &str, #[case] digest: &str) {
|
|
// issue #11202
|
|
|
|
// Ensures that when checking untagged lines, if the provided algorithm is
|
|
// one of `sha(224|256|384|512)`, digests whose length mismatches the
|
|
// length of the given algorithm will report as "improperly formatted"
|
|
// rather than a FAILED check.
|
|
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("a");
|
|
at.touch("b");
|
|
|
|
let good_checksum = format!("{digest} a");
|
|
let invalid_checksum = "e3b0 b";
|
|
|
|
ucmd.arg("-a")
|
|
.arg(algo)
|
|
.arg("-c")
|
|
.pipe_in(format!("{invalid_checksum}\n{good_checksum}"))
|
|
.succeeds()
|
|
.stdout_contains("a: OK")
|
|
.stdout_does_not_contain("b: FAILED")
|
|
.stderr_contains("WARNING: 1 line is improperly formatted");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_algo() {
|
|
for algo in ["bsd", "sysv", "crc", "crc32b"] {
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg(algo)
|
|
.arg("--check")
|
|
.arg("lorem_ipsum.txt")
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains(
|
|
"cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}",
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_length_with_wrong_algorithm() {
|
|
new_ucmd!()
|
|
.arg("--length=16")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(
|
|
"cksum: --length is only supported with --algorithm blake2b, sha2, or sha3",
|
|
);
|
|
|
|
new_ucmd!()
|
|
.arg("--length=16")
|
|
.arg("--algorithm=md5")
|
|
.arg("-c")
|
|
.arg("foo.sums")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(
|
|
"cksum: --length is only supported with --algorithm blake2b, sha2, or sha3",
|
|
);
|
|
}
|
|
|
|
/// Giving --length to a wrong algorithm doesn't fail if the length is zero
|
|
#[test]
|
|
fn test_length_is_zero_with_wrong_algorithm() {
|
|
for algo in ["md5", "crc", "sha1", "sha224", "sha256", "sha384", "sha512"] {
|
|
new_ucmd!()
|
|
.arg("--length=0")
|
|
.args(&["-a", algo])
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.no_stderr()
|
|
.stdout_is_fixture(format!("{algo}_single_file.expected"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_length_not_supported() {
|
|
new_ucmd!()
|
|
.arg("--length=15")
|
|
.arg("lorem_ipsum.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(
|
|
"cksum: --length is only supported with --algorithm blake2b, sha2, or sha3",
|
|
);
|
|
|
|
new_ucmd!()
|
|
.arg("-l")
|
|
.arg("158")
|
|
.arg("-c")
|
|
.arg("-a")
|
|
.arg("crc")
|
|
.arg("/tmp/xxx")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(
|
|
"cksum: --length is only supported with --algorithm blake2b, sha2, or sha3",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_length() {
|
|
new_ucmd!()
|
|
.arg("--length=16")
|
|
.arg("--algorithm=blake2b")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_contains(
|
|
"BLAKE2b-16 (lorem_ipsum.txt) = 7e2f\nBLAKE2b-16 (alice_in_wonderland.txt) = a546",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_length_greater_than_512() {
|
|
for l in ["513", "1024", "73786976294838206464"] {
|
|
new_ucmd!()
|
|
.arg("--algorithm=blake2b")
|
|
.arg("--length")
|
|
.arg(l)
|
|
.arg("lorem_ipsum.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("invalid length: '{l}'"))
|
|
.stderr_contains("maximum digest length for 'BLAKE2b' is 512 bits");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_length_nan() {
|
|
for l in ["foo", "512x", "x512", "0xff"] {
|
|
new_ucmd!()
|
|
.arg("--algorithm=blake2b")
|
|
.arg("--length")
|
|
.arg(l)
|
|
.arg("lorem_ipsum.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(format!("invalid length: '{l}'"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_length_is_zero() {
|
|
new_ucmd!()
|
|
.arg("--length=0")
|
|
.arg("--algorithm=blake2b")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.no_stderr()
|
|
.stdout_is_fixture("length_is_zero.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_length_repeated() {
|
|
new_ucmd!()
|
|
.arg("--length=10")
|
|
.arg("--length=123456")
|
|
.arg("--length=0")
|
|
.arg("--algorithm=blake2b")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.no_stderr()
|
|
.stdout_is_fixture("length_is_zero.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_length_invalid() {
|
|
for len in [
|
|
"1", "01", // Odd
|
|
"",
|
|
] {
|
|
new_ucmd!()
|
|
.arg("--length")
|
|
.arg(len)
|
|
.arg("--algorithm=blake2b")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.fails_with_code(1)
|
|
.stderr_contains(format!("invalid length: '{len}'"));
|
|
}
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_raw_single_file(#[case] algo: &str) {
|
|
new_ucmd!()
|
|
.arg("--raw")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.succeeds()
|
|
.no_stderr()
|
|
.stdout_is_fixture_bytes(format!("raw/{algo}_single_file.expected"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_multiple_files() {
|
|
new_ucmd!()
|
|
.arg("--raw")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains("cksum: the --raw option is not supported with multiple files");
|
|
}
|
|
|
|
#[test]
|
|
fn test_base64_raw_conflicts() {
|
|
new_ucmd!()
|
|
.arg("--base64")
|
|
.arg("--raw")
|
|
.arg("lorem_ipsum.txt")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains("--base64")
|
|
.stderr_contains("cannot be used with")
|
|
.stderr_contains("--raw");
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_base64_single_file(#[case] algo: &str) {
|
|
new_ucmd!()
|
|
.arg("--base64")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg(format!("--algorithm={algo}"))
|
|
.succeeds()
|
|
.no_stderr()
|
|
.stdout_is_fixture_bytes(format!("base64/{algo}_single_file.expected"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_base64_multiple_files() {
|
|
new_ucmd!()
|
|
.arg("--base64")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.no_stderr()
|
|
.stdout_is_fixture_bytes("base64/md5_multiple_files.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_fail_on_folder() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
let folder_name = "a_folder";
|
|
at.mkdir(folder_name);
|
|
|
|
ucmd.arg(folder_name)
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains(format!("cksum: {folder_name}: Is a directory"));
|
|
}
|
|
|
|
#[apply(test_all_algos)]
|
|
fn test_all_algorithms_fail_on_folder(#[case] algo: &str) {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
let folder_name = "a_folder";
|
|
at.mkdir(folder_name);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg(format!("--algorithm={algo}"))
|
|
.arg(folder_name)
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains(format!("cksum: {folder_name}: Is a directory"));
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn test_check_error_incorrect_format() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.write("checksum", "e5773576fc75ff0f8eba14f61587ae28 README.md");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-c")
|
|
.arg("checksum")
|
|
.fails()
|
|
.stderr_contains("no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn test_dev_null() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--algorithm=md5")
|
|
.arg("/dev/null")
|
|
.succeeds()
|
|
.stdout_contains("d41d8cd98f00b204e9800998ecf8427e ");
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn test_blake2b_default_length() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("blake2b")
|
|
.arg("-l512")
|
|
.arg("f")
|
|
.succeeds()
|
|
.stdout_contains("BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce");
|
|
|
|
// test also the read
|
|
at.write("checksum", "BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("checksum")
|
|
.succeeds()
|
|
.stdout_contains("f: OK");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--check")
|
|
.arg("checksum")
|
|
.succeeds()
|
|
.no_output();
|
|
}
|
|
|
|
#[test]
|
|
fn test_reset_binary() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--binary")
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--algorithm=md5")
|
|
.arg(at.subdir.join("f"))
|
|
.succeeds()
|
|
.stdout_contains("d41d8cd98f00b204e9800998ecf8427e *");
|
|
}
|
|
|
|
#[test]
|
|
fn test_reset_binary_but_set() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--binary")
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--binary")
|
|
.arg("--algorithm=md5")
|
|
.arg(at.subdir.join("f"))
|
|
.succeeds()
|
|
.stdout_contains("d41d8cd98f00b204e9800998ecf8427e *");
|
|
}
|
|
|
|
mod output_format {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_text_tag() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("f");
|
|
|
|
ucmd.arg("--text")
|
|
.arg("--tag")
|
|
.args(&["-a", "md5"])
|
|
.arg(at.subdir.join("f"))
|
|
.fails();
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_no_untagged() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("f");
|
|
|
|
// --text without --untagged fails
|
|
ucmd.arg("--text")
|
|
.args(&["-a", "md5"])
|
|
.arg(at.subdir.join("f"))
|
|
.fails_with_code(1)
|
|
.stderr_contains("--text mode is only supported with --untagged");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_binary() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("f");
|
|
|
|
// --binary overwrites --text, thus no error is raised
|
|
ucmd.arg("--text")
|
|
.arg("--binary")
|
|
.args(&["-a", "md5"])
|
|
.arg(at.subdir.join("f"))
|
|
.succeeds()
|
|
// No --untagged, tagged output is used
|
|
.stdout_contains("f) = d41d8cd98f00b204e9800998ecf8427e");
|
|
}
|
|
|
|
#[test]
|
|
fn test_text_binary_untagged() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.touch("f");
|
|
|
|
// --binary overwrites --text
|
|
ucmd.arg("--text")
|
|
.arg("--binary")
|
|
.arg("--untagged")
|
|
.args(&["-a", "md5"])
|
|
.arg(at.subdir.join("f"))
|
|
.succeeds()
|
|
// Untagged output is used
|
|
.stdout_contains("d41d8cd98f00b204e9800998ecf8427e *");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_binary_file() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--untagged")
|
|
.arg("-b")
|
|
.arg("--algorithm=md5")
|
|
.arg(at.subdir.join("f"))
|
|
.succeeds()
|
|
.stdout_contains("d41d8cd98f00b204e9800998ecf8427e *");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--binary")
|
|
.arg("--algorithm=md5")
|
|
.arg(at.subdir.join("f"))
|
|
.succeeds()
|
|
.stdout_contains("d41d8cd98f00b204e9800998ecf8427e *");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--binary")
|
|
.arg("--algorithm=md5")
|
|
.arg("raw/blake2b_single_file.expected")
|
|
.succeeds()
|
|
.stdout_contains("7e297c07ed8e053600092f91bdd1dad7 *");
|
|
|
|
new_ucmd!()
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("--binary")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is("cd724690f7dc61775dfac400a71f2caa *lorem_ipsum.txt\n");
|
|
|
|
new_ucmd!()
|
|
.arg("--untagged")
|
|
.arg("--binary")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is("cd724690f7dc61775dfac400a71f2caa *lorem_ipsum.txt\n");
|
|
|
|
new_ucmd!()
|
|
.arg("--binary")
|
|
.arg("--untagged")
|
|
.arg("--algorithm=md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is("cd724690f7dc61775dfac400a71f2caa *lorem_ipsum.txt\n");
|
|
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("--binary")
|
|
.arg("--untagged")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is("cd724690f7dc61775dfac400a71f2caa *lorem_ipsum.txt\n");
|
|
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("--binary")
|
|
.arg("--tag")
|
|
.arg("--untagged")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is("cd724690f7dc61775dfac400a71f2caa *lorem_ipsum.txt\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_folder_and_file() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
let folder_name = "a_folder";
|
|
at.mkdir(folder_name);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg(folder_name)
|
|
.arg("lorem_ipsum.txt")
|
|
.fails()
|
|
.stderr_contains(format!("cksum: {folder_name}: Is a directory"))
|
|
.stdout_is_fixture("crc_single_file.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_conflicting_options() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--binary")
|
|
.arg("--check")
|
|
.arg("f")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains(
|
|
"cksum: the --binary and --text options are meaningless when verifying checksums",
|
|
);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--tag")
|
|
.arg("-c")
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains("cksum: the --tag option is meaningless when verifying checksums");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_algo_err() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("sm3")
|
|
.arg("--check")
|
|
.arg("f")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains("cksum: f: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_pipe() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("-")
|
|
.pipe_in("f")
|
|
.fails_with_code(1)
|
|
.no_stdout()
|
|
.stderr_contains("cksum: 'standard input': no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check_empty_line() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
at.write("CHECKSUM", "\
|
|
SHA384 (f) = 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b\n\
|
|
BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n\
|
|
BLAKE2b-384 (f) = b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100\n\
|
|
SM3 (f) = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b\n\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n")
|
|
.stderr_does_not_contain("line is improperly formatted");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check_space() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
at.write("CHECKSUM", "\
|
|
SHA384 (f) = 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b\n\
|
|
BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n\
|
|
BLAKE2b-384 (f) = b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100\n\
|
|
SM3 (f) = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b\n \n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n")
|
|
.stderr_contains("line is improperly formatted");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check_leading_info() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
at.write("CHECKSUM", "\
|
|
\\SHA384 (f) = 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b\n\
|
|
\\BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n\
|
|
\\BLAKE2b-384 (f) = b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100\n\
|
|
\\SM3 (f) = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
at.write("CHECKSUM", "\
|
|
SHA384 (f) = 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b\n\
|
|
BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n\
|
|
BLAKE2b-384 (f) = b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100\n\
|
|
SM3 (f) = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n")
|
|
.stderr_does_not_contain("line is improperly formatted");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--strict")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n")
|
|
.stderr_does_not_contain("line is improperly formatted");
|
|
// inject invalid content
|
|
at.append("CHECKSUM", "incorrect data");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n")
|
|
.stderr_contains("line is improperly formatted");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--strict")
|
|
.arg("CHECKSUM")
|
|
.fails()
|
|
.stdout_contains("f: OK\nf: OK\nf: OK\nf: OK\n")
|
|
.stderr_contains("line is improperly formatted");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check_case() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("f");
|
|
at.write(
|
|
"CHECKSUM",
|
|
"Sha1 (f) = da39a3ee5e6b4b0d3255bfef95601890afd80709\n",
|
|
);
|
|
scene.ucmd().arg("--check").arg("CHECKSUM").fails();
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check_invalid() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
let commands = [vec!["-a", "sha384"]];
|
|
at.touch("f");
|
|
at.touch("CHECKSUM");
|
|
for command in &commands {
|
|
let result = scene.ucmd().args(command).arg("f").succeeds();
|
|
at.append("CHECKSUM", result.stdout_str());
|
|
}
|
|
// inject invalid content
|
|
at.append("CHECKSUM", "again incorrect data\naze\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--strict")
|
|
.arg("CHECKSUM")
|
|
.fails()
|
|
.stdout_contains("f: OK\n")
|
|
.stderr_contains("2 lines");
|
|
|
|
// without strict, it passes
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.succeeds()
|
|
.stdout_contains("f: OK\n")
|
|
.stderr_contains("2 lines");
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_check_failed() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
let commands = [vec!["-a", "sha384"]];
|
|
at.touch("f");
|
|
at.touch("CHECKSUM");
|
|
for command in &commands {
|
|
let result = scene.ucmd().args(command).arg("f").succeeds();
|
|
at.append("CHECKSUM", result.stdout_str());
|
|
}
|
|
// inject invalid content
|
|
at.append("CHECKSUM", "again incorrect data\naze\nSM3 (input) = 7cfb120d4fabea2a904948538a438fdb57c725157cb40b5aee8d937b8351477e\n");
|
|
|
|
let result = scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--strict")
|
|
.arg("CHECKSUM")
|
|
.fails();
|
|
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("input: No such file or directory")
|
|
);
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("2 lines are improperly formatted\n")
|
|
);
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("1 listed file could not be read\n")
|
|
);
|
|
assert!(result.stdout_str().contains("f: OK\n"));
|
|
|
|
// without strict
|
|
let result = scene.ucmd().arg("--check").arg("CHECKSUM").fails();
|
|
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("input: No such file or directory")
|
|
);
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("2 lines are improperly formatted\n")
|
|
);
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("1 listed file could not be read\n")
|
|
);
|
|
assert!(result.stdout_str().contains("f: OK\n"));
|
|
|
|
// tests with two files
|
|
at.touch("CHECKSUM2");
|
|
at.write("f2", "42");
|
|
for command in &commands {
|
|
let result = scene.ucmd().args(command).arg("f2").succeeds();
|
|
at.append("CHECKSUM2", result.stdout_str());
|
|
}
|
|
// inject invalid content
|
|
at.append("CHECKSUM2", "again incorrect data\naze\nSM3 (input2) = 7cfb120d4fabea2a904948538a438fdb57c725157cb40b5aee8d937b8351477e\n");
|
|
at.append("CHECKSUM2", "again incorrect data\naze\nSM3 (input2) = 7cfb120d4fabea2a904948538a438fdb57c725157cb40b5aee8d937b8351477e\n");
|
|
|
|
let result = scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.arg("CHECKSUM2")
|
|
.fails();
|
|
println!("result.stderr_str() {}", result.stderr_str());
|
|
println!("result.stdout_str() {}", result.stdout_str());
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("input2: No such file or directory")
|
|
);
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("4 lines are improperly formatted\n")
|
|
);
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("2 listed files could not be read\n")
|
|
);
|
|
assert!(result.stdout_str().contains("f: OK\n"));
|
|
assert!(result.stdout_str().contains("2: OK\n"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_md5_format() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
at.touch("empty");
|
|
at.write("f", "d41d8cd98f00b204e9800998ecf8427e *empty\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("--check")
|
|
.arg("f")
|
|
.succeeds()
|
|
.stdout_contains("empty: OK");
|
|
|
|
// with a second file
|
|
at.write("not-empty", "42");
|
|
at.write("f2", "a1d0c6e83f027327d8461063f4ac58a6 *not-empty\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("--check")
|
|
.arg("f")
|
|
.arg("f2")
|
|
.succeeds()
|
|
.stdout_contains("empty: OK")
|
|
.stdout_contains("not-empty: OK");
|
|
}
|
|
|
|
// Manage the mixed behavior
|
|
// cksum --check -a sm3 CHECKSUMS
|
|
// when CHECKSUM contains among other lines:
|
|
// SHA384 (input) = f392fd0ae43879ced890c665a1d47179116b5eddf6fb5b49f4982746418afdcbd54ba5eedcd422af3592f57f666da285
|
|
#[test]
|
|
fn test_cksum_mixed() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
let commands = [
|
|
vec!["-a", "sha384"],
|
|
vec!["-a", "blake2b"],
|
|
vec!["-a", "blake2b", "-l", "384"],
|
|
vec!["-a", "sm3"],
|
|
];
|
|
at.touch("f");
|
|
at.touch("CHECKSUM");
|
|
for command in &commands {
|
|
let result = scene.ucmd().args(command).arg("f").succeeds();
|
|
at.append("CHECKSUM", result.stdout_str());
|
|
}
|
|
println!("Content of CHECKSUM:\n{}", at.read("CHECKSUM"));
|
|
let result = scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("-a")
|
|
.arg("sm3")
|
|
.arg("CHECKSUM")
|
|
.succeeds();
|
|
|
|
println!("result.stderr_str() {}", result.stderr_str());
|
|
println!("result.stdout_str() {}", result.stdout_str());
|
|
assert!(result.stdout_str().contains("f: OK"));
|
|
assert!(
|
|
result
|
|
.stderr_str()
|
|
.contains("3 lines are improperly formatted")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cksum_garbage() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
// Incorrect data at the start
|
|
at.write(
|
|
"check-file",
|
|
"garbage MD5 (README.md) = e5773576fc75ff0f8eba14f61587ae28",
|
|
);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("check-file")
|
|
.fails()
|
|
.stderr_contains("check-file: no properly formatted checksum lines found");
|
|
|
|
// Incorrect data at the end
|
|
at.write(
|
|
"check-file",
|
|
"MD5 (README.md) = e5773576fc75ff0f8eba14f61587ae28 garbage",
|
|
);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("check-file")
|
|
.fails()
|
|
.stderr_contains("check-file: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_md5_bits() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write(
|
|
"f",
|
|
"MD5-65536 (README.md) = e5773576fc75ff0f8eba14f61587ae28\n",
|
|
);
|
|
|
|
ucmd.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stderr_contains("f: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2b_bits() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write(
|
|
"f",
|
|
"BLAKE2b-257 (README.md) = f9a984b70cf9a7549920864860fd1131c9fb6c0552def0b6dcce1d87b4ec4c5d\n"
|
|
);
|
|
|
|
ucmd.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stderr_contains("f: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_bsd_case() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.write("f", "bSD (README.md) = 0000\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stderr_contains("f: no properly formatted checksum lines found");
|
|
at.write("f", "BsD (README.md) = 0000\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stderr_contains("f: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_blake2d_tested_with_sha1() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write(
|
|
"f",
|
|
"BLAKE2b (f) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n"
|
|
);
|
|
|
|
ucmd.arg("-a")
|
|
.arg("sha1")
|
|
.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stderr_contains("f: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_unknown_sha() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write("f", "SHA4 (README.md) = 00000000\n");
|
|
|
|
ucmd.arg("-c")
|
|
.arg("f")
|
|
.fails()
|
|
.stderr_contains("f: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_directory_error() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
at.mkdir("d");
|
|
at.write(
|
|
"f",
|
|
"BLAKE2b (d) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n"
|
|
);
|
|
#[cfg(not(windows))]
|
|
let err_msg = "cksum: d: Is a directory\n";
|
|
#[cfg(windows)]
|
|
let err_msg = "cksum: d: Permission denied\n";
|
|
ucmd.arg("--check")
|
|
.arg(at.subdir.join("f"))
|
|
.fails()
|
|
.stderr_contains(err_msg);
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_base64_hashes() {
|
|
let hashes = "MD5 (empty) = 1B2M2Y8AsgTpgAmY7PhCfg==\nSHA256 (empty) = 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\nBLAKE2b (empty) = eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg==\n";
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("empty");
|
|
at.write("check", hashes);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("check"))
|
|
.succeeds()
|
|
.stdout_is("empty: OK\nempty: OK\nempty: OK\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_several_files_error_mgmt() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
// don't exist
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("empty")
|
|
.arg("incorrect")
|
|
.fails()
|
|
.stderr_contains("empty: No such file ")
|
|
.stderr_contains("incorrect: No such file ");
|
|
|
|
at.touch("empty");
|
|
at.touch("incorrect");
|
|
|
|
// exists but incorrect
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("empty")
|
|
.arg("incorrect")
|
|
.fails()
|
|
.stderr_contains("empty: no properly ")
|
|
.stderr_contains("incorrect: no properly ");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_unknown_checksum_file() {
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("missing")
|
|
.fails()
|
|
.stderr_only("cksum: missing: No such file or directory\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_comment_line() {
|
|
// A comment in a checksum file shall be discarded unnoticed.
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("foo", "foo-content\n");
|
|
at.write(
|
|
"CHECKSUM-sha1",
|
|
"\
|
|
# This is a comment\n\
|
|
SHA1 (foo) = 058ab38dd3603703b3a7063cf95dc51a4286b6fe\n\
|
|
# next comment is empty\n#",
|
|
);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM-sha1")
|
|
.succeeds()
|
|
.stdout_contains("foo: OK")
|
|
.no_stderr();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_comment_only() {
|
|
// A file only filled with comments is equivalent to an empty file,
|
|
// and therefore produces an error.
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("CHECKSUM", "# This is a comment\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.fails()
|
|
.stderr_contains("no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_comment_leading_space() {
|
|
// A comment must have its '#' in first position on the line.
|
|
// A space before it will raise a warning for improperly formatted line.
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("foo", "foo-content\n");
|
|
at.write(
|
|
"CHECKSUM-sha1",
|
|
" # This is a comment\n\
|
|
SHA1 (foo) = 058ab38dd3603703b3a7063cf95dc51a4286b6fe\n",
|
|
);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM-sha1")
|
|
.succeeds()
|
|
.stdout_contains("foo: OK")
|
|
.stderr_contains("WARNING: 1 line is improperly formatted");
|
|
}
|
|
|
|
/// This test checks alignment with GNU's error handling.
|
|
/// Windows has a different logic and is guarded by [`test_check_directory_error`].
|
|
#[cfg(not(windows))]
|
|
#[test]
|
|
fn test_check_failed_to_read() {
|
|
// check `cksum`'s behavior when encountering directories or non existing files
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write(
|
|
"CHECKSUM",
|
|
"SHA1 (dir) = ffffffffffffffffffffffffffffffffffffffff\n\
|
|
SHA1 (not-file) = ffffffffffffffffffffffffffffffffffffffff\n",
|
|
);
|
|
at.mkdir("dir");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.fails()
|
|
.stdout_is(
|
|
"dir: FAILED open or read\n\
|
|
not-file: FAILED open or read\n",
|
|
)
|
|
.stderr_contains("cksum: WARNING: 2 listed files could not be read");
|
|
|
|
// check with `--ignore-missing`
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.arg("--ignore-missing")
|
|
.fails()
|
|
.stdout_is("dir: FAILED open or read\n")
|
|
.stderr_contains("cksum: WARNING: 1 listed file could not be read");
|
|
}
|
|
|
|
#[test]
|
|
fn test_zero_multiple_file() {
|
|
new_ucmd!()
|
|
.arg("-z")
|
|
.arg("alice_in_wonderland.txt")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("zero_multiple_file.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_zero_single_file() {
|
|
new_ucmd!()
|
|
.arg("--zero")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("zero_single_file.expected");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_trailing_space_fails() {
|
|
// If a checksum line has trailing spaces after the digest,
|
|
// it shall be considered improperly formatted.
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("foo", "foo-content\n");
|
|
at.write(
|
|
"CHECKSUM",
|
|
"SHA1 (foo) = 058ab38dd3603703b3a7063cf95dc51a4286b6fe \n",
|
|
);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUM")
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains("CHECKSUM: no properly formatted checksum lines found");
|
|
}
|
|
|
|
/// Regroup tests related to the handling of non-utf-8 content
|
|
/// in checksum files.
|
|
/// These tests are excluded from Windows because it does not provide any safe
|
|
/// conversion between `OsString` and byte sequences for non-utf-8 strings.
|
|
mod check_encoding {
|
|
|
|
// This test should pass on linux and macos.
|
|
#[cfg(not(windows))]
|
|
#[test]
|
|
fn test_check_non_utf8_comment() {
|
|
use super::*;
|
|
let hashes =
|
|
b"MD5 (empty) = 1B2M2Y8AsgTpgAmY7PhCfg==\n\
|
|
# Comment with a non utf8 char: >>\xff<<\n\
|
|
SHA256 (empty) = 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\n\
|
|
BLAKE2b (empty) = eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg==\n"
|
|
;
|
|
|
|
let (at, mut cmd) = at_and_ucmd!();
|
|
|
|
at.touch("empty");
|
|
at.write_bytes("check", hashes);
|
|
|
|
cmd.arg("--check")
|
|
.arg(at.subdir.join("check"))
|
|
.succeeds()
|
|
.stdout_is("empty: OK\nempty: OK\nempty: OK\n")
|
|
.no_stderr();
|
|
}
|
|
|
|
// This test should pass on linux. Windows and macos will fail to
|
|
// create a file which name contains '\xff'.
|
|
#[cfg(target_os = "linux")]
|
|
#[test]
|
|
fn test_check_non_utf8_filename() {
|
|
use super::*;
|
|
use std::{ffi::OsString, os::unix::ffi::OsStringExt};
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
let filename: OsString = OsStringExt::from_vec(b"funky\xffname".to_vec());
|
|
at.touch(filename);
|
|
|
|
// Checksum match
|
|
at.write_bytes("check",
|
|
b"SHA256 (funky\xffname) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("check"))
|
|
.succeeds()
|
|
.stdout_is_bytes(b"funky\xffname: OK\n")
|
|
.no_stderr();
|
|
|
|
// Checksum mismatch
|
|
at.write_bytes("check",
|
|
b"SHA256 (funky\xffname) = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("check"))
|
|
.fails()
|
|
.stdout_is_bytes(b"funky\xffname: FAILED\n")
|
|
.stderr_contains("1 computed checksum did NOT match");
|
|
|
|
// file not found
|
|
at.write_bytes("check",
|
|
b"SHA256 (flakey\xffname) = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("check"))
|
|
.fails()
|
|
.stdout_is_bytes(b"flakey\xffname: FAILED open or read\n")
|
|
.stderr_contains("1 listed file could not be read");
|
|
}
|
|
|
|
#[cfg(target_os = "linux")]
|
|
#[test]
|
|
fn test_quoting_in_stderr() {
|
|
use super::*;
|
|
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
|
|
|
|
let (at, mut cmd) = at_and_ucmd!();
|
|
|
|
at.mkdir(<OsStr as OsStrExt>::from_bytes(b"FFF\xffDIR"));
|
|
at.write_bytes(
|
|
"check",
|
|
b"SHA256 (FFF\xffFFF) = 29953405eaa3dcc41c37d1621d55b6a47eee93e05613e439e73295029740b10c\nSHA256 (FFF\xffDIR) = 29953405eaa3dcc41c37d1621d55b6a47eee93e05613e439e73295029740b10c\n",
|
|
);
|
|
|
|
cmd.arg("-c")
|
|
.arg("check")
|
|
.fails_with_code(1)
|
|
.stdout_contains_bytes(b"FFF\xffFFF: FAILED open or read")
|
|
.stdout_contains_bytes(b"FFF\xffDIR: FAILED open or read")
|
|
.stderr_contains("'FFF'$'\\377''FFF': No such file or directory")
|
|
.stderr_contains("'FFF'$'\\377''DIR': Is a directory");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_blake_length_guess() {
|
|
let correct_lines = [
|
|
// Correct: The length is not explicit, but the checksum's size
|
|
// matches the default parameter.
|
|
"BLAKE2b (foo.dat) = ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6dc1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d",
|
|
// Correct: The length is explicitly given, and the checksum's size
|
|
// matches the length.
|
|
"BLAKE2b-512 (foo.dat) = ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6dc1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d",
|
|
// Correct: the checksum size is not default but
|
|
// the length is explicitly given.
|
|
"BLAKE2b-48 (foo.dat) = 171cdfdf84ed",
|
|
];
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("foo.dat", "foo");
|
|
|
|
for line in correct_lines {
|
|
at.write("foo.sums", line);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("foo.sums"))
|
|
.succeeds()
|
|
.stdout_is("foo.dat: OK\n");
|
|
}
|
|
|
|
// Incorrect lines
|
|
|
|
// This is incorrect because the algorithm provides no length,
|
|
// and the checksum length is not default.
|
|
let incorrect = "BLAKE2b (foo.dat) = 171cdfdf84ed";
|
|
at.write("foo.sums", incorrect);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("foo.sums"))
|
|
.fails()
|
|
.stderr_contains("foo.sums: no properly formatted checksum lines found");
|
|
|
|
// This is incorrect because the length hint provided doesn't match the
|
|
// checksum length.
|
|
let length_mismatch = "BLAKE2b-8 (foo.dat) = 171cdfdf84ed";
|
|
at.write("foo.sums", length_mismatch);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("foo.sums"))
|
|
.fails()
|
|
.stderr_contains("foo.sums: no properly formatted checksum lines found");
|
|
|
|
// In this case, validation should fail because even though the checksum
|
|
// length matches the hint, it is above BLAKE2b's max (512).
|
|
let too_long = "BLAKE2b-520 (/dev/null) = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
|
at.write("foo.sums", too_long);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("foo.sums"))
|
|
.fails()
|
|
.stderr_contains("foo.sums: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_confusing_base64() {
|
|
let cksum = "BLAKE2b-48 (foo.dat) = fc1f97C4";
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("foo.dat", "esq");
|
|
at.write("foo.sums", cksum);
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("foo.sums"))
|
|
.succeeds()
|
|
.stdout_is("foo.dat: OK\n");
|
|
}
|
|
|
|
/// This test checks that when a file contains several checksum lines
|
|
/// with different encoding, the decoding still works.
|
|
#[test]
|
|
fn test_check_mix_hex_base64() {
|
|
let b64 = "BLAKE2b-128 (foo1.dat) = BBNuJPhdRwRlw9tm5Y7VbA==";
|
|
let hex = "BLAKE2b-128 (foo2.dat) = 04136e24f85d470465c3db66e58ed56c";
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("foo1.dat", "foo");
|
|
at.write("foo2.dat", "foo");
|
|
|
|
at.write("hex_b64", &format!("{hex}\n{b64}"));
|
|
at.write("b64_hex", &format!("{b64}\n{hex}"));
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("hex_b64"))
|
|
.succeeds()
|
|
.stdout_only("foo2.dat: OK\nfoo1.dat: OK\n");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg(at.subdir.join("b64_hex"))
|
|
.succeeds()
|
|
.stdout_only("foo1.dat: OK\nfoo2.dat: OK\n");
|
|
}
|
|
|
|
/// This test ensures that an improperly formatted base64 checksum in a file
|
|
/// does not interrupt the processing of next lines.
|
|
#[test]
|
|
fn test_check_incorrectly_formatted_checksum_keeps_processing_b64() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.touch("f");
|
|
|
|
let good_ck = "MD5 (f) = 1B2M2Y8AsgTpgAmY7PhCfg=="; // OK
|
|
let bad_ck = "MD5 (f) = 1B2M2Y8AsgTpgAmY7PhCfg="; // Missing last '='
|
|
|
|
// Good then Bad
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in([good_ck, bad_ck].join("\n").as_bytes().to_vec())
|
|
.succeeds()
|
|
.stdout_contains("f: OK")
|
|
.stderr_contains("cksum: WARNING: 1 line is improperly formatted");
|
|
|
|
// Bad then Good
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in([bad_ck, good_ck].join("\n").as_bytes().to_vec())
|
|
.succeeds()
|
|
.stdout_contains("f: OK")
|
|
.stderr_contains("cksum: WARNING: 1 line is improperly formatted");
|
|
}
|
|
|
|
/// This test ensures that an improperly formatted hexadecimal checksum in a
|
|
/// file does not interrupt the processing of next lines.
|
|
#[test]
|
|
fn test_check_incorrectly_formatted_checksum_keeps_processing_hex() {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.touch("f");
|
|
|
|
let good_ck = "MD5 (f) = d41d8cd98f00b204e9800998ecf8427e"; // OK
|
|
let bad_ck = "MD5 (f) = d41d8cd98f00b204e9800998ecf8427"; // Missing last
|
|
|
|
// Good then Bad
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in([good_ck, bad_ck].join("\n").as_bytes().to_vec())
|
|
.succeeds()
|
|
.stdout_contains("f: OK")
|
|
.stderr_contains("cksum: WARNING: 1 line is improperly formatted");
|
|
|
|
// Bad then Good
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in([bad_ck, good_ck].join("\n").as_bytes().to_vec())
|
|
.succeeds()
|
|
.stdout_contains("f: OK")
|
|
.stderr_contains("cksum: WARNING: 1 line is improperly formatted");
|
|
}
|
|
|
|
/// This module reimplements the cksum-base64.pl GNU test.
|
|
mod gnu_cksum_base64 {
|
|
use super::*;
|
|
use uutests::util::log_info;
|
|
|
|
const PAIRS: [(&str, &str); 12] = [
|
|
("sysv", "0 0 f"),
|
|
("bsd", "00000 0 f"),
|
|
("crc", "4294967295 0 f"),
|
|
("crc32b", "0 0 f"),
|
|
("md5", "1B2M2Y8AsgTpgAmY7PhCfg=="),
|
|
("sha1", "2jmj7l5rSw0yVb/vlWAYkK/YBwk="),
|
|
("sha224", "0UoCjCo6K8lHYQK7KII0xBWisB+CjqYqxbPkLw=="),
|
|
("sha256", "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="),
|
|
(
|
|
"sha384",
|
|
"OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb",
|
|
),
|
|
(
|
|
"sha512",
|
|
"z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==",
|
|
),
|
|
(
|
|
"blake2b",
|
|
"eGoC90IBWQPGxv2FJVLScpEvR0DhWEdhiobiF/cfVBnSXhAxr+5YUxOJZESTTrBLkDpoWxRIt1XVb3Aa/pvizg==",
|
|
),
|
|
("sm3", "GrIdg1XPoX+OYRlIMegajyK+yMco/vt0ftA161CCqis="),
|
|
];
|
|
|
|
fn make_scene() -> TestScenario {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.touch("f");
|
|
|
|
scene
|
|
}
|
|
|
|
fn output_format(algo: &str, digest: &str) -> String {
|
|
if ["sysv", "bsd", "crc", "crc32b"].contains(&algo) {
|
|
digest.to_string()
|
|
} else {
|
|
format!("{} (f) = {digest}", algo.to_uppercase()).replace("BLAKE2B", "BLAKE2b")
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_generating() {
|
|
// Ensure that each algorithm works with `--base64`.
|
|
let scene = make_scene();
|
|
|
|
for (algo, digest) in PAIRS {
|
|
log_info("ALGORITHM", algo);
|
|
scene
|
|
.ucmd()
|
|
.arg("--base64")
|
|
.arg("-a")
|
|
.arg(algo)
|
|
.arg("f")
|
|
.succeeds()
|
|
.stdout_only(format!("{}\n", output_format(algo, digest)));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_chk() {
|
|
// For each algorithm that accepts `--check`,
|
|
// ensure that it works with base64 digests.
|
|
let scene = make_scene();
|
|
|
|
for (algo, digest) in PAIRS {
|
|
if ["sysv", "bsd", "crc", "crc32b"].contains(&algo) {
|
|
// These algorithms do not accept `--check`
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("-a")
|
|
.arg(algo)
|
|
.fails()
|
|
.stderr_only(
|
|
"cksum: --check is not supported with --algorithm={bsd,sysv,crc,crc32b}\n",
|
|
);
|
|
continue;
|
|
}
|
|
|
|
let line = output_format(algo, digest);
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--strict")
|
|
.pipe_in(line)
|
|
.succeeds()
|
|
.stdout_only("f: OK\n");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_chk_eq1() {
|
|
// For digests ending with '=', ensure `--check` fails if '=' is removed.
|
|
let scene = make_scene();
|
|
|
|
for (algo, digest) in PAIRS {
|
|
if !digest.ends_with('=') {
|
|
continue;
|
|
}
|
|
|
|
let mut line = output_format(algo, digest);
|
|
if line.ends_with('=') {
|
|
line.pop();
|
|
}
|
|
|
|
log_info(format!("ALGORITHM: {algo}, STDIN: '{line}'"), "");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in(line)
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains("no properly formatted checksum lines found");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_chk_eq2() {
|
|
// For digests ending with '==',
|
|
// ensure `--check` fails if '==' is removed.
|
|
let scene = make_scene();
|
|
|
|
for (algo, digest) in PAIRS {
|
|
if !digest.ends_with("==") {
|
|
continue;
|
|
}
|
|
|
|
let line = output_format(algo, digest);
|
|
let line = line.trim_end_matches("==");
|
|
|
|
log_info(format!("ALGORITHM: {algo}, STDIN: '{line}'"), "");
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in(line)
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains("no properly formatted checksum lines found");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This module reimplements the cksum-base64-untagged.sh GNU test.
|
|
mod gnu_cksum_base64_untagged {
|
|
use super::*;
|
|
|
|
macro_rules! decl_sha_test {
|
|
($id:ident, $algo:literal, $len:expr) => {
|
|
mod $id {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn check_length_guess() {
|
|
let ts = TestScenario::new(util_name!());
|
|
let at = &ts.fixtures;
|
|
|
|
at.write("inp", "test input\n");
|
|
|
|
let compute = ts
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg($algo)
|
|
.arg("-l")
|
|
.arg(stringify!($len))
|
|
.arg("--base64")
|
|
.arg("--untagged")
|
|
.arg("inp")
|
|
.succeeds();
|
|
|
|
at.write_bytes("check", compute.stdout());
|
|
|
|
ts.ucmd()
|
|
.arg("-a")
|
|
.arg($algo)
|
|
.arg("--check")
|
|
.arg("check")
|
|
.succeeds()
|
|
.stdout_only("inp: OK\n");
|
|
|
|
at.write("check", " inp");
|
|
|
|
ts.ucmd()
|
|
.arg("-a")
|
|
.arg($algo)
|
|
.arg("check")
|
|
.fails()
|
|
.stderr_contains(concat!(
|
|
"--algorithm=",
|
|
$algo,
|
|
" requires specifying --length"
|
|
));
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
decl_sha_test!(sha2_224, "sha2", 224);
|
|
decl_sha_test!(sha2_256, "sha2", 256);
|
|
decl_sha_test!(sha2_384, "sha2", 384);
|
|
decl_sha_test!(sha2_512, "sha2", 512);
|
|
decl_sha_test!(sha3_224, "sha3", 224);
|
|
decl_sha_test!(sha3_256, "sha3", 256);
|
|
decl_sha_test!(sha3_384, "sha3", 384);
|
|
decl_sha_test!(sha3_512, "sha3", 512);
|
|
|
|
macro_rules! decl_blake_test {
|
|
($id:ident, $len:expr) => {
|
|
mod $id {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn check_length_guess() {
|
|
let ts = TestScenario::new(util_name!());
|
|
let at = &ts.fixtures;
|
|
|
|
at.write("inp", "test input\n");
|
|
|
|
let compute = ts
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("blake2b")
|
|
.arg("-l")
|
|
.arg(stringify!($len))
|
|
.arg("--base64")
|
|
.arg("--untagged")
|
|
.arg("inp")
|
|
.succeeds();
|
|
|
|
at.write_bytes("check", compute.stdout());
|
|
|
|
ts.ucmd()
|
|
.arg("-a")
|
|
.arg("blake2b")
|
|
.arg("--check")
|
|
.arg("check")
|
|
.succeeds()
|
|
.stdout_only("inp: OK\n");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
decl_blake_test!(blake2b_8, 8);
|
|
decl_blake_test!(blake2b_216, 216);
|
|
decl_blake_test!(blake2b_224, 224);
|
|
decl_blake_test!(blake2b_232, 232);
|
|
decl_blake_test!(blake2b_248, 248);
|
|
decl_blake_test!(blake2b_256, 256);
|
|
decl_blake_test!(blake2b_264, 264);
|
|
decl_blake_test!(blake2b_376, 376);
|
|
decl_blake_test!(blake2b_384, 384);
|
|
decl_blake_test!(blake2b_392, 392);
|
|
decl_blake_test!(blake2b_504, 504);
|
|
decl_blake_test!(blake2b_512, 512);
|
|
}
|
|
/// This module reimplements the cksum-c.sh GNU test.
|
|
mod gnu_cksum_c {
|
|
use super::*;
|
|
|
|
const INVALID_SUM: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaafdb57c725157cb40b5aee8d937b8351477e";
|
|
|
|
fn make_scene() -> TestScenario {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
at.write("input", "9\n7\n1\n4\n2\n6\n3\n5\n8\n10\n");
|
|
|
|
let algos: &[&[&str]] = &[
|
|
&["-a", "sha384"],
|
|
&["-a", "blake2b"],
|
|
&["-a", "blake2b", "-l", "384"],
|
|
&["-a", "sm3"],
|
|
];
|
|
|
|
for args in algos {
|
|
let result = scene.ucmd().args(args).succeeds();
|
|
let stdout = result.stdout();
|
|
at.append_bytes("CHECKSUMS", stdout);
|
|
}
|
|
|
|
scene
|
|
}
|
|
|
|
fn make_scene_with_comment() -> TestScenario {
|
|
let scene = make_scene();
|
|
|
|
scene
|
|
.fixtures
|
|
.append("CHECKSUMS", "# Very important comment\n");
|
|
|
|
scene
|
|
}
|
|
|
|
fn make_scene_with_invalid_line() -> TestScenario {
|
|
let scene = make_scene_with_comment();
|
|
|
|
scene.fixtures.append("CHECKSUMS", "invalid_line\n");
|
|
|
|
scene
|
|
}
|
|
|
|
#[test]
|
|
fn test_tagged_invalid_length() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
at.write(
|
|
"sha2-bad-length.sum",
|
|
"SHA2-128 (/dev/null) = 38b060a751ac96384cd9327eb1b1e36a",
|
|
);
|
|
|
|
ucmd.arg("--check")
|
|
.arg("sha2-bad-length.sum")
|
|
.fails()
|
|
.stderr_contains("sha2-bad-length.sum: no properly formatted checksum lines found");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(not(unix), ignore = "/dev/null is only available on UNIX")]
|
|
fn test_untagged_base64_matching_tag() {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
|
|
at.write("tag-prefix.sum", "SHA1+++++++++++++++++++++++= /dev/null");
|
|
|
|
ucmd.arg("--check")
|
|
.arg("-a")
|
|
.arg("sha1")
|
|
.arg("tag-prefix.sum")
|
|
.fails()
|
|
.stderr_contains("WARNING: 1 computed checksum did NOT match");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg_attr(windows, ignore = "Awkward filename is not supported on windows")]
|
|
fn test_awkward_filename() {
|
|
let ts = TestScenario::new(util_name!());
|
|
let at = &ts.fixtures;
|
|
|
|
let awkward_file = "abc (f) = abc";
|
|
|
|
at.touch(awkward_file);
|
|
|
|
let result = ts.ucmd().arg("-a").arg("sha1").arg(awkward_file).succeeds();
|
|
|
|
at.write_bytes("tag-awkward.sum", result.stdout());
|
|
|
|
ts.ucmd().arg("-c").arg("tag-awkward.sum").succeeds();
|
|
}
|
|
|
|
#[test]
|
|
fn test_signed_checksums() {
|
|
let ts = TestScenario::new(util_name!());
|
|
let at = &ts.fixtures;
|
|
|
|
let filename = "test_file";
|
|
at.touch(filename);
|
|
|
|
let checksum_result = ts.ucmd().arg("-a").arg("sha256").arg(filename).succeeds();
|
|
let valid_checksum_line = checksum_result.stdout_str().trim();
|
|
|
|
let signed_content = format!(
|
|
"-----BEGIN PGP SIGNED MESSAGE-----\n\
|
|
Hash: SHA256\n\
|
|
\n\
|
|
# This is a comment that should be ignored\n\
|
|
{valid_checksum_line}\n\
|
|
-----BEGIN PGP SIGNATURE-----\n\
|
|
\n\
|
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\
|
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n\
|
|
=PlaceHolder\n\
|
|
-----END PGP SIGNATURE-----"
|
|
);
|
|
|
|
at.write("signed_CHECKSUMS", &signed_content);
|
|
|
|
ts.ucmd().arg("--check").arg("signed_CHECKSUMS").succeeds();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_individual_digests_in_mixed_file() {
|
|
let scene = make_scene();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("-a")
|
|
.arg("sm3")
|
|
.arg("CHECKSUMS")
|
|
.succeeds();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_against_older_non_hex_formats() {
|
|
let scene = make_scene();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-c")
|
|
.arg("-a")
|
|
.arg("crc")
|
|
.arg("CHECKSUMS")
|
|
.fails();
|
|
|
|
let crc_cmd = scene.ucmd().arg("-a").arg("crc").arg("input").succeeds();
|
|
let crc_cmd_out = crc_cmd.stdout();
|
|
scene.fixtures.write_bytes("CHECKSUMS.crc", crc_cmd_out);
|
|
|
|
scene.ucmd().arg("-c").arg("CHECKSUMS.crc").fails();
|
|
}
|
|
|
|
#[test]
|
|
fn test_status() {
|
|
let scene = make_scene();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.succeeds()
|
|
.no_output();
|
|
}
|
|
|
|
#[test]
|
|
fn test_status_with_comment() {
|
|
let scene = make_scene_with_comment();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.succeeds()
|
|
.no_output();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_strict() {
|
|
let scene = make_scene_with_invalid_line();
|
|
|
|
// without strict, succeeds
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.succeeds()
|
|
.stderr_contains("1 line is improperly formatted");
|
|
|
|
// with strict, fails
|
|
scene
|
|
.ucmd()
|
|
.arg("--strict")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stderr_contains("1 line is improperly formatted");
|
|
}
|
|
|
|
fn make_scene_with_two_invalid_lines() -> TestScenario {
|
|
let scene = make_scene_with_comment();
|
|
|
|
scene
|
|
.fixtures
|
|
.append("CHECKSUMS", "invalid_line\ninvalid_line\n");
|
|
|
|
scene
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_strict_plural_checks() {
|
|
let scene = make_scene_with_two_invalid_lines();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--strict")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stderr_contains("2 lines are improperly formatted");
|
|
}
|
|
|
|
fn make_scene_with_incorrect_checksum() -> TestScenario {
|
|
let scene = make_scene_with_two_invalid_lines();
|
|
|
|
scene
|
|
.fixtures
|
|
.append("CHECKSUMS", &format!("SM3 (input) = {INVALID_SUM}\n"));
|
|
|
|
scene
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_with_incorrect_checksum() {
|
|
let scene = make_scene_with_incorrect_checksum();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stdout_contains("input: FAILED")
|
|
.stderr_contains("1 computed checksum did NOT match");
|
|
|
|
// also fails with strict
|
|
scene
|
|
.ucmd()
|
|
.arg("--strict")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stdout_contains("input: FAILED")
|
|
.stderr_contains("1 computed checksum did NOT match");
|
|
}
|
|
|
|
#[test]
|
|
fn test_status_with_errors() {
|
|
let scene = make_scene_with_incorrect_checksum();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.no_output();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_with_non_existing_file() {
|
|
let scene = make_scene();
|
|
scene
|
|
.fixtures
|
|
.write("CHECKSUMS2", &format!("SM3 (input2) = {INVALID_SUM}\n"));
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("CHECKSUMS2")
|
|
.fails()
|
|
.stdout_contains("input2: FAILED open or read")
|
|
.stderr_contains("1 listed file could not be read");
|
|
|
|
// also fails with strict
|
|
scene
|
|
.ucmd()
|
|
.arg("--strict")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS2")
|
|
.fails()
|
|
.stdout_contains("input2: FAILED open or read")
|
|
.stderr_contains("1 listed file could not be read");
|
|
}
|
|
|
|
fn make_scene_with_another_improperly_formatted() -> TestScenario {
|
|
let scene = make_scene_with_incorrect_checksum();
|
|
|
|
scene.fixtures.append(
|
|
"CHECKSUMS",
|
|
&format!("BLAKE2b (missing-file) = {INVALID_SUM}\n"),
|
|
);
|
|
|
|
scene
|
|
}
|
|
|
|
#[test]
|
|
fn test_warn() {
|
|
let scene = make_scene_with_another_improperly_formatted();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--warn")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stderr_contains("CHECKSUMS: 6: improperly formatted SM3 checksum line")
|
|
.stderr_contains("CHECKSUMS: 9: improperly formatted BLAKE2b checksum line");
|
|
}
|
|
|
|
fn make_scene_with_checksum_missing() -> TestScenario {
|
|
let scene = make_scene_with_another_improperly_formatted();
|
|
|
|
scene.fixtures.write(
|
|
"CHECKSUMS-missing",
|
|
&format!("SM3 (nonexistent) = {INVALID_SUM}\n"),
|
|
);
|
|
|
|
scene
|
|
}
|
|
|
|
#[test]
|
|
fn test_ignore_missing() {
|
|
let scene = make_scene_with_checksum_missing();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--ignore-missing")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS-missing")
|
|
.fails()
|
|
.stdout_does_not_contain("nonexistent: No such file or directory")
|
|
.stdout_does_not_contain("nonexistent: FAILED open or read")
|
|
.stderr_contains("CHECKSUMS-missing: no file was verified");
|
|
}
|
|
|
|
#[test]
|
|
fn test_ignore_missing_stdin() {
|
|
let scene = make_scene_with_checksum_missing();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--ignore-missing")
|
|
.arg("--check")
|
|
.pipe_in_fixture("CHECKSUMS-missing")
|
|
.fails()
|
|
.no_stdout()
|
|
.stderr_contains("'standard input': no file was verified");
|
|
}
|
|
|
|
#[test]
|
|
fn test_status_and_warn() {
|
|
let scene = make_scene_with_checksum_missing();
|
|
|
|
// --status before --warn
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--warn")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stderr_contains("CHECKSUMS: 9: improperly formatted BLAKE2b checksum line")
|
|
.stderr_contains("WARNING: 3 lines are improperly formatted")
|
|
.stderr_contains("WARNING: 1 computed checksum did NOT match");
|
|
|
|
// --warn before --status (status hides the results)
|
|
scene
|
|
.ucmd()
|
|
.arg("--warn")
|
|
.arg("--status")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.stderr_does_not_contain("CHECKSUMS: 9: improperly formatted BLAKE2b checksum line")
|
|
.stderr_does_not_contain("WARNING: 3 lines are improperly formatted")
|
|
.stderr_does_not_contain("WARNING: 1 computed checksum did NOT match");
|
|
}
|
|
|
|
#[test]
|
|
fn test_status_and_ignore_missing() {
|
|
let scene = make_scene_with_checksum_missing();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--ignore-missing")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS")
|
|
.fails()
|
|
.no_output();
|
|
}
|
|
|
|
#[test]
|
|
fn test_status_warn_and_ignore_missing() {
|
|
let scene = make_scene_with_checksum_missing();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--status")
|
|
.arg("--warn")
|
|
.arg("--ignore-missing")
|
|
.arg("--check")
|
|
.arg("CHECKSUMS-missing")
|
|
.fails()
|
|
.stderr_contains("CHECKSUMS-missing: no file was verified")
|
|
.stdout_does_not_contain("nonexistent: No such file or directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_several_files_dont_exist() {
|
|
let scene = make_scene();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("non-existing-1")
|
|
.arg("non-existing-2")
|
|
.fails()
|
|
.stderr_contains("non-existing-1: No such file or directory")
|
|
.stderr_contains("non-existing-2: No such file or directory");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_several_files_empty() {
|
|
let scene = make_scene();
|
|
scene.fixtures.touch("empty-1");
|
|
scene.fixtures.touch("empty-2");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("empty-1")
|
|
.arg("empty-2")
|
|
.fails()
|
|
.stderr_contains("empty-1: no properly formatted checksum lines found")
|
|
.stderr_contains("empty-2: no properly formatted checksum lines found");
|
|
}
|
|
}
|
|
|
|
/// The tests in this module check the behavior of cksum when given different
|
|
/// checksum formats and algorithms in the same file, while specifying an
|
|
/// algorithm on CLI or not.
|
|
mod format_mix {
|
|
use super::*;
|
|
|
|
// First line is algo-based, second one is not
|
|
const INPUT_ALGO_NON_ALGO: &str = "\
|
|
BLAKE2b (bar) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce\n\
|
|
786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce foo";
|
|
|
|
// First line is non algo-based, second one is
|
|
const INPUT_NON_ALGO_ALGO: &str = "\
|
|
786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce foo\n\
|
|
BLAKE2b (bar) = 786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
|
|
|
|
/// Make a simple scene with foo and bar empty files
|
|
fn make_scene() -> TestScenario {
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("foo");
|
|
at.touch("bar");
|
|
|
|
scene
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_cli_algo_non_algo() {
|
|
let scene = make_scene();
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--algo=blake2b")
|
|
.pipe_in(INPUT_ALGO_NON_ALGO)
|
|
.succeeds()
|
|
.stdout_contains("bar: OK\nfoo: OK")
|
|
.no_stderr();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_cli_non_algo_algo() {
|
|
let scene = make_scene();
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.arg("--algo=blake2b")
|
|
.pipe_in(INPUT_NON_ALGO_ALGO)
|
|
.succeeds()
|
|
.stdout_contains("foo: OK\nbar: OK")
|
|
.no_stderr();
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_algo_non_algo() {
|
|
let scene = make_scene();
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in(INPUT_ALGO_NON_ALGO)
|
|
.succeeds()
|
|
.stdout_contains("bar: OK")
|
|
.stderr_contains("cksum: WARNING: 1 line is improperly formatted");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_non_algo_algo() {
|
|
let scene = make_scene();
|
|
scene
|
|
.ucmd()
|
|
.arg("--check")
|
|
.pipe_in(INPUT_NON_ALGO_ALGO)
|
|
.succeeds()
|
|
.stdout_contains("bar: OK")
|
|
.stderr_contains("cksum: WARNING: 1 line is improperly formatted");
|
|
}
|
|
}
|
|
|
|
#[cfg(not(target_os = "android"))]
|
|
mod debug_flag {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_debug_flag() {
|
|
// Test with default CRC algorithm - should output CPU feature detection
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("crc_single_file.expected")
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
|
|
// Test with MD5 algorithm - CPU detection should be same regardless of algorithm
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("md5_single_file.expected")
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
|
|
// Test with stdin - CPU detection should appear once
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.pipe_in("test")
|
|
.succeeds()
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
|
|
// Test with multiple files - CPU detection should appear once, not per file
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("lorem_ipsum.txt")
|
|
.arg("alice_in_wonderland.txt")
|
|
.succeeds()
|
|
.stdout_is_fixture("crc_multiple_files.expected")
|
|
.stderr_str_check(|stderr| {
|
|
// Verify CPU detection happens only once by checking the count of each feature line
|
|
let avx512_count = stderr
|
|
.lines()
|
|
.filter(|line| line.contains("avx512"))
|
|
.count();
|
|
let avx2_count = stderr.lines().filter(|line| line.contains("avx2")).count();
|
|
let pclmul_count = stderr
|
|
.lines()
|
|
.filter(|line| line.contains("pclmul"))
|
|
.count();
|
|
|
|
avx512_count == 1 && avx2_count == 1 && pclmul_count == 1
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn test_debug_with_algorithms() {
|
|
// Test with SHA256 - CPU detection should be same regardless of algorithm
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("-a")
|
|
.arg("sha256")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
|
|
// Test with BLAKE2b default length
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("-a")
|
|
.arg("blake2b")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
|
|
// Test with BLAKE2b custom length
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("-a")
|
|
.arg("blake2b")
|
|
.arg("--length")
|
|
.arg("256")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
|
|
// Test with SHA1
|
|
new_ucmd!()
|
|
.arg("--debug")
|
|
.arg("-a")
|
|
.arg("sha1")
|
|
.arg("lorem_ipsum.txt")
|
|
.succeeds()
|
|
.stderr_contains("avx512")
|
|
.stderr_contains("avx2")
|
|
.stderr_contains("pclmul");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
|
fn test_check_file_with_io_error() {
|
|
// /proc/self/mem causes EIO when read without proper seeking
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("--check")
|
|
.pipe_in("d8e8fca2dc0f896fd7cb4cb0031ba249 /proc/self/mem\n")
|
|
.fails()
|
|
.stderr_contains("Input/output error")
|
|
.stdout_contains("FAILED open or read");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
|
|
fn test_check_checkfile_with_io_error() {
|
|
// /proc/self/mem causes EIO when read without proper seeking
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("md5")
|
|
.arg("--check")
|
|
.arg("/proc/self/mem")
|
|
.fails()
|
|
.stderr_contains("/proc/self/mem: read error")
|
|
.no_stdout();
|
|
}
|
|
|
|
#[rstest]
|
|
#[case::default_length(
|
|
&[],
|
|
"ac8549b2861a151896ab721bd29d7a20c1a3d1f75b31266f786f20d963fb0fdf"
|
|
)]
|
|
#[case::pass_default_length(
|
|
&["-l", "256"],
|
|
"ac8549b2861a151896ab721bd29d7a20c1a3d1f75b31266f786f20d963fb0fdf"
|
|
)]
|
|
#[case::smaller_length(
|
|
&["-l", "128"],
|
|
"ac8549b2861a151896ab721bd29d7a20"
|
|
)]
|
|
#[case::bigger_length(
|
|
&["-l", "264"],
|
|
"ac8549b2861a151896ab721bd29d7a20c1a3d1f75b31266f786f20d963fb0fdfc2"
|
|
)]
|
|
#[case::length_0(
|
|
&["-l", "0"],
|
|
"ac8549b2861a151896ab721bd29d7a20c1a3d1f75b31266f786f20d963fb0fdf"
|
|
)]
|
|
#[case::length_1(
|
|
&["-l", "1"],
|
|
"00"
|
|
)]
|
|
#[case::length_2(
|
|
&["-l", "2"],
|
|
"00"
|
|
)]
|
|
#[case::length_3(
|
|
&["-l", "3"],
|
|
"04"
|
|
)]
|
|
#[case::length_4(
|
|
&["-l", "4"],
|
|
"0c"
|
|
)]
|
|
#[case::length_5(
|
|
&["-l", "5"],
|
|
"0c"
|
|
)]
|
|
#[case::length_6(
|
|
&["-l", "6"],
|
|
"2c"
|
|
)]
|
|
#[case::length_7(
|
|
&["-l", "7"],
|
|
"2c"
|
|
)]
|
|
#[case::length_8(
|
|
&["-l", "8"],
|
|
"ac"
|
|
)]
|
|
fn test_shake128(#[case] args: &[&str], #[case] expected: &str) {
|
|
let bit_len = if args.is_empty() || args[1] == "0" {
|
|
"256"
|
|
} else {
|
|
args[1]
|
|
};
|
|
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("shake128")
|
|
.args(args)
|
|
.pipe_in("xxx")
|
|
.succeeds()
|
|
.stdout_only(format!("SHAKE128-{bit_len} (-) = {expected}\n"));
|
|
}
|
|
|
|
#[rstest]
|
|
#[case::default_length(
|
|
&[],
|
|
"2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7b24958f3e3c4cc0e71f1fe6f054cd3fb28b9efb62b4f8f3fbe6d50d90f5c6eba"
|
|
)]
|
|
#[case::pass_default_length(
|
|
&["-l", "512"],
|
|
"2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7b24958f3e3c4cc0e71f1fe6f054cd3fb28b9efb62b4f8f3fbe6d50d90f5c6eba"
|
|
)]
|
|
#[case::smaller_length(
|
|
&["-l", "128"],
|
|
"2fa631503c3ea5fe85131dbfa2480518"
|
|
)]
|
|
#[case::bigger_length(
|
|
&["-l", "1024"],
|
|
"2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7b24958f3e3c4cc0e71f1fe6f054cd3fb28b9efb62b4f8f3fbe6d50d90f5c6eba18783d25f8b36d92b8607f016352b5c405945a7859a8339201728f680647324d1b8ea93a01d2ef965dadf4a1bee3ff044ed2b4bd95e4311f5e3f2cd5bae0b7c6"
|
|
)]
|
|
#[case::length_0(
|
|
&["-l", "0"],
|
|
"2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7b24958f3e3c4cc0e71f1fe6f054cd3fb28b9efb62b4f8f3fbe6d50d90f5c6eba"
|
|
)]
|
|
#[case::length_1(
|
|
&["-l", "1"],
|
|
"01"
|
|
)]
|
|
#[case::length_2(
|
|
&["-l", "2"],
|
|
"03"
|
|
)]
|
|
#[case::length_3(
|
|
&["-l", "3"],
|
|
"07"
|
|
)]
|
|
#[case::length_4(
|
|
&["-l", "4"],
|
|
"0f"
|
|
)]
|
|
#[case::length_5(
|
|
&["-l", "5"],
|
|
"0f"
|
|
)]
|
|
#[case::length_6(
|
|
&["-l", "6"],
|
|
"2f"
|
|
)]
|
|
#[case::length_7(
|
|
&["-l", "7"],
|
|
"2f"
|
|
)]
|
|
#[case::length_8(
|
|
&["-l", "8"],
|
|
"2f"
|
|
)]
|
|
fn test_shake256(#[case] args: &[&str], #[case] expected: &str) {
|
|
let bit_len = if args.is_empty() || args[1] == "0" {
|
|
"512"
|
|
} else {
|
|
args[1]
|
|
};
|
|
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("shake256")
|
|
.args(args)
|
|
.pipe_in("xxx")
|
|
.succeeds()
|
|
.stdout_only(format!("SHAKE256-{bit_len} (-) = {expected}\n"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_shake128_no_length() {
|
|
const INPUT_SHAKE128_CORRECT_LEN: &str =
|
|
"SHAKE128 (bar) = ac8549b2861a151896ab721bd29d7a20c1a3d1f75b31266f786f20d963fb0fdf";
|
|
const INPUT_SHAKE128_WRONG_LEN: &str = "SHAKE128 (bar) = ac8549b2861a151896ab721bd29d7a20";
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("bar", "xxx");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("shake128")
|
|
.arg("-c")
|
|
.pipe_in(INPUT_SHAKE128_CORRECT_LEN)
|
|
.succeeds();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-a")
|
|
.arg("shake128")
|
|
.arg("-c")
|
|
.pipe_in(INPUT_SHAKE128_WRONG_LEN)
|
|
.fails()
|
|
.stderr_only("cksum: 'standard input': no properly formatted checksum lines found\n");
|
|
}
|
|
|
|
#[test]
|
|
fn test_check_shake256_no_length() {
|
|
const INPUT_SHAKE256_CORRECT_LEN: &str = "SHAKE256 (bar) = 2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7b24958f3e3c4cc0e71f1fe6f054cd3fb28b9efb62b4f8f3fbe6d50d90f5c6eba";
|
|
const INPUT_SHAKE256_WRONG_LEN: &str =
|
|
"SHAKE256 (bar) = 2fa631503c3ea5fe85131dbfa24805185474740e6dcb5f2a64f69d932bcb55f7";
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
let at = &scene.fixtures;
|
|
|
|
at.write("bar", "xxx");
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-c")
|
|
.pipe_in(INPUT_SHAKE256_CORRECT_LEN)
|
|
.succeeds();
|
|
|
|
scene
|
|
.ucmd()
|
|
.arg("-c")
|
|
.pipe_in(INPUT_SHAKE256_WRONG_LEN)
|
|
.fails()
|
|
.stderr_only("cksum: 'standard input': no properly formatted checksum lines found\n");
|
|
}
|
|
|
|
#[template]
|
|
#[rstest]
|
|
#[case::no_length(
|
|
b"foo",
|
|
"04e0bb39f30b1a3feb89f536c93be15055482df748674b00d26e5a75777702e9",
|
|
None
|
|
)]
|
|
#[case(
|
|
b"foo",
|
|
"04e0bb39f30b1a3feb89f536c93be15055482df748674b00d26e5a75777702e9",
|
|
Some(0)
|
|
)]
|
|
#[case(
|
|
b"foo",
|
|
"04e0bb39f30b1a3feb89f536c93be15055482df748674b00d26e5a75777702e9",
|
|
Some(256)
|
|
)]
|
|
#[case(
|
|
b"foo",
|
|
"04e0bb39f30b1a3feb89f536c93be15055482df748674b00d26e5a75777702e9791074b7511b59d31c71c62f5a745689fa6c",
|
|
Some(400)
|
|
)]
|
|
#[case(b"foo", "04e0bb39f3", Some(40))]
|
|
#[case(b"foo", "04e0", Some(16))]
|
|
#[case(b"foo", "04", Some(8))]
|
|
fn test_blake3(#[case] input: &[u8], #[case] expected: &str, #[case] length: Option<usize>) {}
|
|
|
|
#[apply(test_blake3)]
|
|
fn test_compute_blake3(
|
|
#[case] input: &[u8],
|
|
#[case] expected: &str,
|
|
#[case] length: Option<usize>,
|
|
) {
|
|
let length_args: &[String] = if let Some(len) = length {
|
|
&["-l".into(), len.to_string()]
|
|
} else {
|
|
&[]
|
|
};
|
|
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("blake3")
|
|
.args(length_args)
|
|
.pipe_in(input)
|
|
.succeeds()
|
|
.stdout_only(format!(
|
|
"BLAKE3{} (-) = {expected}\n",
|
|
match length {
|
|
Some(0) | None => "-256".into(),
|
|
Some(i) => format!("-{i}"),
|
|
}
|
|
));
|
|
|
|
// with --untagged
|
|
new_ucmd!()
|
|
.arg("-a")
|
|
.arg("blake3")
|
|
.arg("--untagged")
|
|
.args(length_args)
|
|
.pipe_in(input)
|
|
.succeeds()
|
|
.stdout_only(format!("{expected} -\n"));
|
|
}
|
|
|
|
#[apply(test_blake3)]
|
|
fn test_check_blake3_tagged(
|
|
#[case] input: &[u8],
|
|
#[case] digest: &str,
|
|
#[case] opt_len: Option<usize>,
|
|
) {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write_bytes("FILE", input);
|
|
|
|
let len = match opt_len {
|
|
Some(0) => "-256".into(),
|
|
Some(i) => format!("-{i}"),
|
|
None => String::new(),
|
|
};
|
|
|
|
let tagged = format!("BLAKE3{len} (FILE) = {digest}");
|
|
|
|
ucmd.arg("-c")
|
|
.arg("-a")
|
|
.arg("blake3")
|
|
.pipe_in(tagged)
|
|
.succeeds()
|
|
.stdout_only("FILE: OK\n");
|
|
}
|
|
|
|
#[apply(test_blake3)]
|
|
#[allow(clippy::used_underscore_binding)]
|
|
fn test_check_blake3_untagged(
|
|
#[case] input: &[u8],
|
|
#[case] digest: &str,
|
|
#[case] _opt_len: Option<usize>,
|
|
) {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write_bytes("FILE", input);
|
|
|
|
let untagged = format!("{digest} FILE");
|
|
|
|
ucmd.arg("-c")
|
|
.arg("-a")
|
|
.arg("blake3")
|
|
.pipe_in(untagged)
|
|
.succeeds()
|
|
.stdout_only("FILE: OK\n");
|
|
}
|