2019-12-12 08:13:16 +01:00
|
|
|
|
use duct::cmd;
|
2020-05-04 03:13:58 +02:00
|
|
|
|
use std::ffi::OsString;
|
2019-12-12 08:13:16 +01:00
|
|
|
|
use std::fs;
|
2019-12-13 21:56:21 +01:00
|
|
|
|
use std::io::prelude::*;
|
2019-12-12 08:13:16 +01:00
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
|
|
pub fn b3sum_exe() -> PathBuf {
|
2020-05-13 23:47:29 +02:00
|
|
|
|
env!("CARGO_BIN_EXE_b3sum").into()
|
2019-12-12 08:13:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_hash_one() {
|
2020-05-13 21:33:17 +02:00
|
|
|
|
let expected = format!("{} -", blake3::hash(b"foo").to_hex());
|
2019-12-12 08:13:16 +01:00
|
|
|
|
let output = cmd!(b3sum_exe()).stdin_bytes("foo").read().unwrap();
|
2020-01-13 22:12:47 +01:00
|
|
|
|
assert_eq!(&*expected, output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_hash_one_raw() {
|
|
|
|
|
let expected = blake3::hash(b"foo").as_bytes().to_owned();
|
2020-01-13 23:43:09 +01:00
|
|
|
|
let output = cmd!(b3sum_exe(), "--raw")
|
2020-01-13 22:12:47 +01:00
|
|
|
|
.stdin_bytes("foo")
|
2020-01-13 23:43:09 +01:00
|
|
|
|
.stdout_capture()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.stdout;
|
|
|
|
|
assert_eq!(expected, output.as_slice());
|
2019-12-12 08:13:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_hash_many() {
|
2019-12-13 21:56:21 +01:00
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
2019-12-12 08:13:16 +01:00
|
|
|
|
let file1 = dir.path().join("file1");
|
|
|
|
|
fs::write(&file1, b"foo").unwrap();
|
|
|
|
|
let file2 = dir.path().join("file2");
|
|
|
|
|
fs::write(&file2, b"bar").unwrap();
|
2019-12-13 21:56:21 +01:00
|
|
|
|
|
2019-12-12 08:13:16 +01:00
|
|
|
|
let output = cmd!(b3sum_exe(), &file1, &file2).read().unwrap();
|
|
|
|
|
let foo_hash = blake3::hash(b"foo");
|
|
|
|
|
let bar_hash = blake3::hash(b"bar");
|
|
|
|
|
let expected = format!(
|
|
|
|
|
"{} {}\n{} {}",
|
|
|
|
|
foo_hash.to_hex(),
|
2020-05-04 03:13:58 +02:00
|
|
|
|
// account for slash normalization on Windows
|
|
|
|
|
file1.to_string_lossy().replace("\\", "/"),
|
2019-12-12 08:13:16 +01:00
|
|
|
|
bar_hash.to_hex(),
|
2020-05-04 03:13:58 +02:00
|
|
|
|
file2.to_string_lossy().replace("\\", "/"),
|
2019-12-12 08:13:16 +01:00
|
|
|
|
);
|
|
|
|
|
assert_eq!(expected, output);
|
2019-12-13 21:56:21 +01:00
|
|
|
|
|
|
|
|
|
let output_no_names = cmd!(b3sum_exe(), "--no-names", &file1, &file2)
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let expected_no_names = format!("{}\n{}", foo_hash.to_hex(), bar_hash.to_hex(),);
|
|
|
|
|
assert_eq!(expected_no_names, output_no_names);
|
2019-12-12 08:13:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 23:51:41 +02:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_missing_files() {
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
let file1 = dir.path().join("file1");
|
|
|
|
|
fs::write(&file1, b"foo").unwrap();
|
|
|
|
|
let file2 = dir.path().join("file2");
|
|
|
|
|
fs::write(&file2, b"bar").unwrap();
|
|
|
|
|
|
|
|
|
|
let output = cmd!(b3sum_exe(), "file1", "missing_file", "file2")
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
|
|
|
|
|
let foo_hash = blake3::hash(b"foo");
|
|
|
|
|
let bar_hash = blake3::hash(b"bar");
|
|
|
|
|
let expected_stdout = format!(
|
|
|
|
|
"{} file1\n{} file2\n",
|
|
|
|
|
foo_hash.to_hex(),
|
|
|
|
|
bar_hash.to_hex(),
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(expected_stdout.as_bytes(), &output.stdout[..]);
|
|
|
|
|
|
|
|
|
|
let bing_error = fs::File::open(dir.path().join("missing_file")).unwrap_err();
|
|
|
|
|
let expected_stderr = format!("b3sum: missing_file: {}\n", bing_error.to_string());
|
|
|
|
|
assert_eq!(expected_stderr.as_bytes(), &output.stderr[..]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-12 08:13:16 +01:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_hash_length() {
|
|
|
|
|
let mut buf = [0; 100];
|
|
|
|
|
blake3::Hasher::new()
|
|
|
|
|
.update(b"foo")
|
|
|
|
|
.finalize_xof()
|
|
|
|
|
.fill(&mut buf);
|
2020-05-13 21:33:17 +02:00
|
|
|
|
let expected = format!("{} -", hex::encode(&buf[..]));
|
2019-12-12 08:13:16 +01:00
|
|
|
|
let output = cmd!(b3sum_exe(), "--length=100")
|
|
|
|
|
.stdin_bytes("foo")
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(&*expected, &*output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2019-12-13 21:56:21 +01:00
|
|
|
|
fn test_keyed() {
|
2019-12-12 08:13:16 +01:00
|
|
|
|
let key = [42; blake3::KEY_LEN];
|
2019-12-13 21:56:21 +01:00
|
|
|
|
let f = tempfile::NamedTempFile::new().unwrap();
|
|
|
|
|
f.as_file().write_all(b"foo").unwrap();
|
|
|
|
|
f.as_file().flush().unwrap();
|
2019-12-12 08:13:16 +01:00
|
|
|
|
let expected = blake3::keyed_hash(&key, b"foo").to_hex();
|
2019-12-13 21:56:21 +01:00
|
|
|
|
let output = cmd!(b3sum_exe(), "--keyed", "--no-names", f.path())
|
|
|
|
|
.stdin_bytes(&key[..])
|
2019-12-12 08:13:16 +01:00
|
|
|
|
.read()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(&*expected, &*output);
|
2022-12-14 00:56:08 +01:00
|
|
|
|
|
|
|
|
|
// Make sure that keys of the wrong length lead to errors.
|
|
|
|
|
for bad_length in [0, 1, blake3::KEY_LEN - 1, blake3::KEY_LEN + 1] {
|
|
|
|
|
dbg!(bad_length);
|
2023-02-04 19:00:23 +01:00
|
|
|
|
let output = cmd!(b3sum_exe(), "--keyed", f.path())
|
2022-12-14 00:56:08 +01:00
|
|
|
|
.stdin_bytes(vec![0; bad_length])
|
2023-02-04 19:00:23 +01:00
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert!(output.stdout.is_empty());
|
|
|
|
|
// Make sure the error message is relevant.
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
assert!(stderr.contains("key bytes"));
|
2022-12-14 00:56:08 +01:00
|
|
|
|
}
|
2019-12-12 08:13:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_derive_key() {
|
2019-12-27 23:20:38 +01:00
|
|
|
|
let context = "BLAKE3 2019-12-28 10:28:41 example context";
|
2019-12-13 21:56:21 +01:00
|
|
|
|
let f = tempfile::NamedTempFile::new().unwrap();
|
2019-12-27 23:20:38 +01:00
|
|
|
|
f.as_file().write_all(b"key material").unwrap();
|
2019-12-13 21:56:21 +01:00
|
|
|
|
f.as_file().flush().unwrap();
|
2021-03-01 00:05:20 +01:00
|
|
|
|
let expected = hex::encode(blake3::derive_key(context, b"key material"));
|
2019-12-27 23:20:38 +01:00
|
|
|
|
let output = cmd!(b3sum_exe(), "--derive-key", context, "--no-names", f.path())
|
2019-12-12 08:13:16 +01:00
|
|
|
|
.read()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(&*expected, &*output);
|
|
|
|
|
}
|
2020-01-05 21:33:12 +01:00
|
|
|
|
|
2020-01-20 15:09:37 +01:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_no_mmap() {
|
|
|
|
|
let f = tempfile::NamedTempFile::new().unwrap();
|
|
|
|
|
f.as_file().write_all(b"foo").unwrap();
|
|
|
|
|
f.as_file().flush().unwrap();
|
|
|
|
|
|
|
|
|
|
let expected = blake3::hash(b"foo").to_hex();
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--no-mmap", "--no-names", f.path())
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(&*expected, &*output);
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-05 21:33:12 +01:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_length_without_value_is_an_error() {
|
|
|
|
|
let result = cmd!(b3sum_exe(), "--length")
|
|
|
|
|
.stdin_bytes("foo")
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.run();
|
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
}
|
2020-01-13 22:12:47 +01:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_raw_with_multi_files_is_an_error() {
|
2020-01-13 23:48:24 +01:00
|
|
|
|
let f1 = tempfile::NamedTempFile::new().unwrap();
|
|
|
|
|
let f2 = tempfile::NamedTempFile::new().unwrap();
|
|
|
|
|
|
|
|
|
|
// Make sure it doesn't error with just one file
|
|
|
|
|
let result = cmd!(b3sum_exe(), "--raw", f1.path()).stdout_capture().run();
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
|
|
|
|
|
// Make sure it errors when both file are passed
|
|
|
|
|
let result = cmd!(b3sum_exe(), "--raw", f1.path(), f2.path())
|
2020-01-13 22:12:47 +01:00
|
|
|
|
.stderr_capture()
|
|
|
|
|
.run();
|
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
}
|
2020-05-04 03:13:58 +02:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
fn test_newline_and_backslash_escaping_on_unix() {
|
|
|
|
|
let empty_hash = blake3::hash(b"").to_hex();
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
fs::create_dir(dir.path().join("subdir")).unwrap();
|
|
|
|
|
let names = [
|
|
|
|
|
"abcdef",
|
|
|
|
|
"abc\ndef",
|
|
|
|
|
"abc\\def",
|
|
|
|
|
"abc\rdef",
|
|
|
|
|
"abc\r\ndef",
|
|
|
|
|
"subdir/foo",
|
|
|
|
|
];
|
|
|
|
|
let mut paths = Vec::new();
|
|
|
|
|
for name in &names {
|
|
|
|
|
let path = dir.path().join(name);
|
|
|
|
|
println!("creating file at {:?}", path);
|
|
|
|
|
fs::write(&path, b"").unwrap();
|
|
|
|
|
paths.push(path);
|
|
|
|
|
}
|
|
|
|
|
let output = cmd(b3sum_exe(), &names).dir(dir.path()).read().unwrap();
|
|
|
|
|
let expected = format!(
|
|
|
|
|
"\
|
2020-05-12 15:55:09 +02:00
|
|
|
|
{0} abcdef
|
|
|
|
|
\\{0} abc\\ndef
|
|
|
|
|
\\{0} abc\\\\def
|
|
|
|
|
{0} abc\rdef
|
|
|
|
|
\\{0} abc\r\\ndef
|
2020-05-04 03:13:58 +02:00
|
|
|
|
{0} subdir/foo",
|
|
|
|
|
empty_hash,
|
|
|
|
|
);
|
|
|
|
|
println!("output");
|
|
|
|
|
println!("======");
|
|
|
|
|
println!("{}", output);
|
|
|
|
|
println!();
|
|
|
|
|
println!("expected");
|
|
|
|
|
println!("========");
|
|
|
|
|
println!("{}", expected);
|
|
|
|
|
println!();
|
|
|
|
|
assert_eq!(expected, output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
fn test_slash_normalization_on_windows() {
|
|
|
|
|
let empty_hash = blake3::hash(b"").to_hex();
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
fs::create_dir(dir.path().join("subdir")).unwrap();
|
|
|
|
|
// Note that filenames can't contain newlines or backslashes on Windows, so
|
|
|
|
|
// we don't test escaping here. We only test forward slash and backslash as
|
|
|
|
|
// directory separators.
|
|
|
|
|
let names = ["abcdef", "subdir/foo", "subdir\\bar"];
|
|
|
|
|
let mut paths = Vec::new();
|
|
|
|
|
for name in &names {
|
|
|
|
|
let path = dir.path().join(name);
|
|
|
|
|
println!("creating file at {:?}", path);
|
|
|
|
|
fs::write(&path, b"").unwrap();
|
|
|
|
|
paths.push(path);
|
|
|
|
|
}
|
|
|
|
|
let output = cmd(b3sum_exe(), &names).dir(dir.path()).read().unwrap();
|
|
|
|
|
let expected = format!(
|
|
|
|
|
"\
|
2020-05-12 15:55:09 +02:00
|
|
|
|
{0} abcdef
|
|
|
|
|
{0} subdir/foo
|
2020-05-04 03:13:58 +02:00
|
|
|
|
{0} subdir/bar",
|
|
|
|
|
empty_hash,
|
|
|
|
|
);
|
|
|
|
|
println!("output");
|
|
|
|
|
println!("======");
|
|
|
|
|
println!("{}", output);
|
|
|
|
|
println!();
|
|
|
|
|
println!("expected");
|
|
|
|
|
println!("========");
|
|
|
|
|
println!("{}", expected);
|
|
|
|
|
println!();
|
|
|
|
|
assert_eq!(expected, output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
fn test_invalid_unicode_on_unix() {
|
|
|
|
|
use std::os::unix::ffi::OsStringExt;
|
|
|
|
|
|
|
|
|
|
let empty_hash = blake3::hash(b"").to_hex();
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
let names = ["abcdef".into(), OsString::from_vec(b"abc\xffdef".to_vec())];
|
|
|
|
|
let mut paths = Vec::new();
|
|
|
|
|
for name in &names {
|
|
|
|
|
let path = dir.path().join(name);
|
|
|
|
|
println!("creating file at {:?}", path);
|
|
|
|
|
// Note: Some operating systems, macOS in particular, simply don't
|
|
|
|
|
// allow invalid Unicode in filenames. On those systems, this write
|
|
|
|
|
// will fail. That's fine, we'll just short-circuit this test in that
|
|
|
|
|
// case. But assert that at least Linux allows this.
|
|
|
|
|
let write_result = fs::write(&path, b"");
|
|
|
|
|
if cfg!(target_os = "linux") {
|
|
|
|
|
write_result.expect("Linux should allow invalid Unicode");
|
|
|
|
|
} else if write_result.is_err() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
paths.push(path);
|
|
|
|
|
}
|
|
|
|
|
let output = cmd(b3sum_exe(), &names).dir(dir.path()).read().unwrap();
|
|
|
|
|
let expected = format!(
|
|
|
|
|
"\
|
2020-05-12 15:55:09 +02:00
|
|
|
|
{0} abcdef
|
2020-05-04 03:13:58 +02:00
|
|
|
|
{0} abc<EFBFBD>def",
|
|
|
|
|
empty_hash,
|
|
|
|
|
);
|
|
|
|
|
println!("output");
|
|
|
|
|
println!("======");
|
|
|
|
|
println!("{}", output);
|
|
|
|
|
println!();
|
|
|
|
|
println!("expected");
|
|
|
|
|
println!("========");
|
|
|
|
|
println!("{}", expected);
|
|
|
|
|
println!();
|
|
|
|
|
assert_eq!(expected, output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
fn test_invalid_unicode_on_windows() {
|
|
|
|
|
use std::os::windows::ffi::OsStringExt;
|
|
|
|
|
|
|
|
|
|
let empty_hash = blake3::hash(b"").to_hex();
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
let surrogate_char = 0xDC00;
|
|
|
|
|
let bad_unicode_wchars = [
|
|
|
|
|
'a' as u16,
|
|
|
|
|
'b' as u16,
|
|
|
|
|
'c' as u16,
|
|
|
|
|
surrogate_char,
|
|
|
|
|
'd' as u16,
|
|
|
|
|
'e' as u16,
|
|
|
|
|
'f' as u16,
|
|
|
|
|
];
|
|
|
|
|
let bad_osstring = OsString::from_wide(&bad_unicode_wchars);
|
|
|
|
|
let names = ["abcdef".into(), bad_osstring];
|
|
|
|
|
let mut paths = Vec::new();
|
|
|
|
|
for name in &names {
|
|
|
|
|
let path = dir.path().join(name);
|
|
|
|
|
println!("creating file at {:?}", path);
|
|
|
|
|
fs::write(&path, b"").unwrap();
|
|
|
|
|
paths.push(path);
|
|
|
|
|
}
|
|
|
|
|
let output = cmd(b3sum_exe(), &names).dir(dir.path()).read().unwrap();
|
|
|
|
|
let expected = format!(
|
|
|
|
|
"\
|
2020-05-12 15:55:09 +02:00
|
|
|
|
{0} abcdef
|
2020-05-04 03:13:58 +02:00
|
|
|
|
{0} abc<EFBFBD>def",
|
|
|
|
|
empty_hash,
|
|
|
|
|
);
|
|
|
|
|
println!("output");
|
|
|
|
|
println!("======");
|
|
|
|
|
println!("{}", output);
|
|
|
|
|
println!();
|
|
|
|
|
println!("expected");
|
|
|
|
|
println!("========");
|
|
|
|
|
println!("{}", expected);
|
|
|
|
|
println!();
|
|
|
|
|
assert_eq!(expected, output);
|
|
|
|
|
}
|
2020-05-13 21:33:17 +02:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_check() {
|
|
|
|
|
// Make a directory full of files, and make sure the b3sum output in that
|
|
|
|
|
// directory is what we expect.
|
|
|
|
|
let a_hash = blake3::hash(b"a").to_hex();
|
|
|
|
|
let b_hash = blake3::hash(b"b").to_hex();
|
|
|
|
|
let cd_hash = blake3::hash(b"cd").to_hex();
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
fs::write(dir.path().join("a"), b"a").unwrap();
|
|
|
|
|
fs::write(dir.path().join("b"), b"b").unwrap();
|
|
|
|
|
fs::create_dir(dir.path().join("c")).unwrap();
|
|
|
|
|
fs::write(dir.path().join("c/d"), b"cd").unwrap();
|
|
|
|
|
let output = cmd!(b3sum_exe(), "a", "b", "c/d")
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
let expected_checkfile = format!(
|
|
|
|
|
"{} a\n\
|
|
|
|
|
{} b\n\
|
|
|
|
|
{} c/d\n",
|
|
|
|
|
a_hash, b_hash, cd_hash,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(expected_checkfile, stdout);
|
|
|
|
|
assert_eq!("", stderr);
|
|
|
|
|
|
|
|
|
|
// Now use the output we just validated as a checkfile, passed to stdin.
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check")
|
|
|
|
|
.stdin_bytes(expected_checkfile.as_bytes())
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
let expected_check_output = "\
|
|
|
|
|
a: OK\n\
|
|
|
|
|
b: OK\n\
|
|
|
|
|
c/d: OK\n";
|
|
|
|
|
assert_eq!(expected_check_output, stdout);
|
|
|
|
|
assert_eq!("", stderr);
|
|
|
|
|
|
|
|
|
|
// Now pass the same checkfile twice on the command line just for fun.
|
|
|
|
|
let checkfile_path = dir.path().join("checkfile");
|
|
|
|
|
fs::write(&checkfile_path, &expected_checkfile).unwrap();
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check", &checkfile_path, &checkfile_path)
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
let mut double_check_output = String::new();
|
|
|
|
|
double_check_output.push_str(&expected_check_output);
|
|
|
|
|
double_check_output.push_str(&expected_check_output);
|
|
|
|
|
assert_eq!(double_check_output, stdout);
|
|
|
|
|
assert_eq!("", stderr);
|
|
|
|
|
|
2020-05-14 17:13:25 +02:00
|
|
|
|
// Corrupt one of the files and check again.
|
2020-05-13 21:33:17 +02:00
|
|
|
|
fs::write(dir.path().join("b"), b"CORRUPTION").unwrap();
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check", &checkfile_path)
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
let expected_check_failure = "\
|
|
|
|
|
a: OK\n\
|
|
|
|
|
b: FAILED\n\
|
|
|
|
|
c/d: OK\n";
|
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!(expected_check_failure, stdout);
|
2023-02-04 19:13:34 +01:00
|
|
|
|
assert_eq!(
|
|
|
|
|
"b3sum: WARNING: 1 computed checksum did NOT match\n",
|
|
|
|
|
stderr,
|
|
|
|
|
);
|
2020-05-14 17:13:25 +02:00
|
|
|
|
|
|
|
|
|
// Delete one of the files and check again.
|
|
|
|
|
fs::remove_file(dir.path().join("b")).unwrap();
|
|
|
|
|
let open_file_error = fs::File::open(dir.path().join("b")).unwrap_err();
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check", &checkfile_path)
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
let expected_check_failure = format!(
|
|
|
|
|
"a: OK\n\
|
|
|
|
|
b: FAILED ({})\n\
|
|
|
|
|
c/d: OK\n",
|
|
|
|
|
open_file_error,
|
|
|
|
|
);
|
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!(expected_check_failure, stdout);
|
2023-02-04 19:13:34 +01:00
|
|
|
|
assert_eq!(
|
|
|
|
|
"b3sum: WARNING: 1 computed checksum did NOT match\n",
|
|
|
|
|
stderr,
|
|
|
|
|
);
|
2020-05-23 18:18:54 +02:00
|
|
|
|
|
|
|
|
|
// Confirm that --quiet suppresses the OKs but not the FAILEDs.
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check", "--quiet", &checkfile_path)
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
|
|
|
|
let expected_check_failure = format!("b: FAILED ({})\n", open_file_error);
|
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!(expected_check_failure, stdout);
|
2023-02-04 19:13:34 +01:00
|
|
|
|
assert_eq!(
|
|
|
|
|
"b3sum: WARNING: 1 computed checksum did NOT match\n",
|
|
|
|
|
stderr,
|
|
|
|
|
);
|
2020-05-13 21:33:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_check_invalid_characters() {
|
|
|
|
|
// Check that a null character in the path fails.
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check")
|
|
|
|
|
.stdin_bytes("0000000000000000000000000000000000000000000000000000000000000000 \0")
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
2023-01-13 02:33:06 +01:00
|
|
|
|
let expected_stderr = "\
|
|
|
|
|
b3sum: Null character in path\n\
|
2023-02-04 19:13:34 +01:00
|
|
|
|
b3sum: WARNING: 1 computed checksum did NOT match\n";
|
2020-05-13 21:33:17 +02:00
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!("", stdout);
|
2023-01-13 02:33:06 +01:00
|
|
|
|
assert_eq!(expected_stderr, stderr);
|
2020-05-13 21:33:17 +02:00
|
|
|
|
|
|
|
|
|
// Check that a Unicode replacement character in the path fails.
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check")
|
|
|
|
|
.stdin_bytes("0000000000000000000000000000000000000000000000000000000000000000 <20>")
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
2023-01-13 02:33:06 +01:00
|
|
|
|
let expected_stderr = "\
|
|
|
|
|
b3sum: Unicode replacement character in path\n\
|
2023-02-04 19:13:34 +01:00
|
|
|
|
b3sum: WARNING: 1 computed checksum did NOT match\n";
|
2020-05-13 21:33:17 +02:00
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!("", stdout);
|
2023-01-13 02:33:06 +01:00
|
|
|
|
assert_eq!(expected_stderr, stderr);
|
2020-05-13 21:33:17 +02:00
|
|
|
|
|
|
|
|
|
// Check that an invalid escape sequence in the path fails.
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check")
|
|
|
|
|
.stdin_bytes("\\0000000000000000000000000000000000000000000000000000000000000000 \\a")
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
2023-01-13 02:33:06 +01:00
|
|
|
|
let expected_stderr = "\
|
|
|
|
|
b3sum: Invalid backslash escape\n\
|
2023-02-04 19:13:34 +01:00
|
|
|
|
b3sum: WARNING: 1 computed checksum did NOT match\n";
|
2020-05-13 21:33:17 +02:00
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!("", stdout);
|
2023-01-13 02:33:06 +01:00
|
|
|
|
assert_eq!(expected_stderr, stderr);
|
2020-05-13 21:33:17 +02:00
|
|
|
|
|
|
|
|
|
// Windows also forbids literal backslashes. Check for that if and only if
|
|
|
|
|
// we're on Windows.
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
let output = cmd!(b3sum_exe(), "--check")
|
|
|
|
|
.stdin_bytes("0000000000000000000000000000000000000000000000000000000000000000 \\")
|
|
|
|
|
.stdout_capture()
|
|
|
|
|
.stderr_capture()
|
|
|
|
|
.unchecked()
|
|
|
|
|
.run()
|
|
|
|
|
.unwrap();
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
2023-01-13 02:33:06 +01:00
|
|
|
|
let expected_stderr = "\
|
|
|
|
|
b3sum: Backslash in path\n\
|
2023-02-04 19:13:34 +01:00
|
|
|
|
b3sum: WARNING: 1 computed checksum did NOT match\n";
|
2020-05-13 21:33:17 +02:00
|
|
|
|
assert!(!output.status.success());
|
|
|
|
|
assert_eq!("", stdout);
|
2023-01-13 02:33:06 +01:00
|
|
|
|
assert_eq!(expected_stderr, stderr);
|
2020-05-13 21:33:17 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 18:34:02 +02:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_globbing() {
|
|
|
|
|
// On Unix, globbing is provided by the shell. On Windows, globbing is
|
|
|
|
|
// provided by us, using the `wild` crate.
|
|
|
|
|
let dir = tempfile::tempdir().unwrap();
|
|
|
|
|
let file1 = dir.path().join("file1");
|
|
|
|
|
fs::write(&file1, b"foo").unwrap();
|
|
|
|
|
let file2 = dir.path().join("file2");
|
|
|
|
|
fs::write(&file2, b"bar").unwrap();
|
|
|
|
|
|
|
|
|
|
let foo_hash = blake3::hash(b"foo");
|
|
|
|
|
let bar_hash = blake3::hash(b"bar");
|
2020-05-23 20:56:43 +02:00
|
|
|
|
// NOTE: This assumes that the glob will be expanded in alphabetical order,
|
|
|
|
|
// to "file1 file2" rather than "file2 file1". So far, this seems to
|
|
|
|
|
// be true (guaranteed?) of Unix shell behavior, and true in practice
|
|
|
|
|
// with the `wild` crate on Windows. It's possible that this could
|
|
|
|
|
// start failing in the future, though, or on some unknown platform.
|
|
|
|
|
// If that ever happens, we'll need to relax this test somehow,
|
|
|
|
|
// probably by just testing for both possible outputs. I'm not
|
|
|
|
|
// handling that case in advance, though, because I'd prefer to hear
|
|
|
|
|
// about it if it comes up.
|
2020-05-23 18:34:02 +02:00
|
|
|
|
let expected = format!("{} file1\n{} file2", foo_hash.to_hex(), bar_hash.to_hex());
|
|
|
|
|
|
|
|
|
|
let star_command = format!("{} *", b3sum_exe().to_str().unwrap());
|
|
|
|
|
let (exe, c_flag) = if cfg!(windows) {
|
|
|
|
|
("cmd.exe", "/C")
|
|
|
|
|
} else {
|
|
|
|
|
("/bin/sh", "-c")
|
|
|
|
|
};
|
|
|
|
|
let output = cmd!(exe, c_flag, star_command)
|
|
|
|
|
.dir(dir.path())
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap();
|
|
|
|
|
assert_eq!(expected, output);
|
|
|
|
|
}
|