mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
rewrite tests
This commit is contained in:
parent
739a52f00e
commit
35df50857d
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,3 +6,6 @@ makeshift_testing.py
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# crash logs generated by proptest
|
||||
*.proptest-regressions
|
||||
|
284
Cargo.lock
generated
284
Cargo.lock
generated
@ -8,6 +8,29 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e996dc7940838b7ef1096b882e29ec30a3149a3a443cdc8dba19ed382eca1fe2"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"doc-comment",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
@ -25,12 +48,38 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
@ -132,6 +181,33 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difflib"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||
|
||||
[[package]]
|
||||
name = "dir-diff"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b"
|
||||
dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.15"
|
||||
@ -157,6 +233,12 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "2.6.0"
|
||||
@ -217,6 +299,15 @@ dependencies = [
|
||||
"cfb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.24"
|
||||
@ -291,6 +382,15 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
@ -310,10 +410,12 @@ dependencies = [
|
||||
name = "ouch"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"atty",
|
||||
"bzip2",
|
||||
"clap",
|
||||
"clap_generate",
|
||||
"dir-diff",
|
||||
"flate2",
|
||||
"fs-err",
|
||||
"infer",
|
||||
@ -321,15 +423,44 @@ dependencies = [
|
||||
"linked-hash-map",
|
||||
"lz4_flex",
|
||||
"once_cell",
|
||||
"parse-display",
|
||||
"proptest",
|
||||
"rand",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"test-strategy",
|
||||
"walkdir",
|
||||
"xz2",
|
||||
"zip",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "898bf4c2a569dedbfd4e6c3f0bbd0ae825e5b6b0b69bae3e3c1000158689334a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"parse-display-derive",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display-derive"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1779d1e28ab04568223744c2af4aa4e642e67b92c76bdce0929a6d2c36267199"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"structmeta",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
@ -342,6 +473,33 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6ce811d0b2e103743eec01db1c50612221f173084ce2f7941053e94b6bb474"
|
||||
dependencies = [
|
||||
"difflib",
|
||||
"itertools",
|
||||
"predicates-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
@ -375,6 +533,38 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proptest"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"quick-error 2.0.1",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"rand_xorshift",
|
||||
"regex-syntax",
|
||||
"rusty-fork",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.10"
|
||||
@ -424,6 +614,15 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
@ -433,6 +632,29 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
@ -442,6 +664,18 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusty-fork"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"quick-error 1.2.3",
|
||||
"tempfile",
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -463,6 +697,29 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "structmeta"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59915b528a896f2e3bfa1a6ace65f7bb0ff9f9863de6213b0c01cb6fd3c3ac71"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structmeta-derive"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b73800bcca56045d5ab138a48cd28a96093335335deaa916f22b5749c4150c79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
@ -508,6 +765,24 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16"
|
||||
|
||||
[[package]]
|
||||
name = "test-strategy"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22c726321a7c108ca1de4ed2e6a362ead7193ecfbe0b326c5dff602b65a09e6a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.14.2"
|
||||
@ -592,6 +867,15 @@ version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
|
@ -33,9 +33,14 @@ clap = "=3.0.0-beta.5"
|
||||
clap_generate = "=3.0.0-beta.5"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.2.0"
|
||||
assert_cmd = "2.0.2"
|
||||
dir-diff = "0.3.2"
|
||||
infer = "0.5.0"
|
||||
parse-display = "0.5.3"
|
||||
proptest = "1.0.0"
|
||||
rand = { version = "0.8.3", default-features = false, features = ["small_rng", "std"] }
|
||||
tempfile = "3.2.0"
|
||||
test-strategy = "0.1.2"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
@ -1,215 +0,0 @@
|
||||
mod utils;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
io::prelude::*,
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use fs_err as fs;
|
||||
use ouch::{commands::run, Opts, QuestionPolicy, Subcommand};
|
||||
use rand::{rngs::SmallRng, RngCore, SeedableRng};
|
||||
use tempfile::NamedTempFile;
|
||||
use utils::*;
|
||||
|
||||
#[test]
|
||||
/// Makes sure that the files ouch produces are what they claim to be, checking their
|
||||
/// types through MIME sniffing.
|
||||
fn sanity_check_through_mime() {
|
||||
// Somehow this test causes test failures when run in parallel with test_each_format
|
||||
// This is a temporary hack that should allow the tests to pass while this bug isn't solved.
|
||||
std::thread::sleep(Duration::from_secs(2));
|
||||
|
||||
let temp_dir = tempfile::tempdir().expect("to build a temporary directory");
|
||||
|
||||
let mut test_file = NamedTempFile::new_in(temp_dir.path()).expect("to be able to build a temporary file");
|
||||
|
||||
let bytes = generate_random_file_content(&mut SmallRng::from_entropy());
|
||||
test_file.write_all(&bytes).expect("to successfully write bytes to the file");
|
||||
|
||||
let formats = [
|
||||
"tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma",
|
||||
"tar.xz", "tar.zst",
|
||||
];
|
||||
|
||||
let expected_mimes = [
|
||||
"application/x-tar",
|
||||
"application/zip",
|
||||
"application/gzip",
|
||||
"application/gzip",
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/zstd",
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/zstd",
|
||||
];
|
||||
|
||||
assert_eq!(formats.len(), expected_mimes.len());
|
||||
|
||||
for (format, expected_mime) in formats.iter().zip(expected_mimes.iter()) {
|
||||
let temp_dir_path = temp_dir.path();
|
||||
let paths_to_compress = &[test_file.path().into()];
|
||||
|
||||
let compressed_file_path = compress_files(temp_dir_path, paths_to_compress, format);
|
||||
|
||||
let sniffed =
|
||||
infer::get_from_path(compressed_file_path).expect("the file to be read").expect("the MIME to be found");
|
||||
|
||||
assert_eq!(&sniffed.mime_type(), expected_mime);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests each format that supports multiple files with random input.
|
||||
/// TODO: test the remaining formats.
|
||||
fn test_each_format() {
|
||||
test_compressing_and_decompressing_archive("tar");
|
||||
test_compressing_and_decompressing_archive("tar.gz");
|
||||
test_compressing_and_decompressing_archive("tar.bz");
|
||||
test_compressing_and_decompressing_archive("tar.bz2");
|
||||
test_compressing_and_decompressing_archive("tar.xz");
|
||||
test_compressing_and_decompressing_archive("tar.lz");
|
||||
test_compressing_and_decompressing_archive("tar.lz4");
|
||||
test_compressing_and_decompressing_archive("tar.lzma");
|
||||
test_compressing_and_decompressing_archive("tar.zst");
|
||||
test_compressing_and_decompressing_archive("tgz");
|
||||
test_compressing_and_decompressing_archive("tbz");
|
||||
test_compressing_and_decompressing_archive("tbz2");
|
||||
test_compressing_and_decompressing_archive("txz");
|
||||
test_compressing_and_decompressing_archive("tlz4");
|
||||
test_compressing_and_decompressing_archive("tlz");
|
||||
test_compressing_and_decompressing_archive("tlzma");
|
||||
test_compressing_and_decompressing_archive("tzst");
|
||||
test_compressing_and_decompressing_archive("zip");
|
||||
test_compressing_and_decompressing_archive("zip.gz");
|
||||
test_compressing_and_decompressing_archive("zip.bz");
|
||||
test_compressing_and_decompressing_archive("zip.bz2");
|
||||
test_compressing_and_decompressing_archive("zip.xz");
|
||||
test_compressing_and_decompressing_archive("zip.lz");
|
||||
test_compressing_and_decompressing_archive("zip.lzma");
|
||||
|
||||
// Why not
|
||||
test_compressing_and_decompressing_archive(
|
||||
"tar.gz.gz.gz.gz.gz.gz.gz.gz.zst.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz",
|
||||
);
|
||||
}
|
||||
|
||||
type FileContent = Vec<u8>;
|
||||
|
||||
/// Compress and decompresses random files to archive formats, checks if contents match
|
||||
fn test_compressing_and_decompressing_archive(format: &str) {
|
||||
// System temporary directory depends on the platform, for linux it's /tmp
|
||||
let system_tmp = env::temp_dir();
|
||||
|
||||
// Create a temporary testing folder that will be deleted on scope drop
|
||||
let testing_dir =
|
||||
tempfile::Builder::new().prefix("ouch-testing").tempdir_in(system_tmp).expect("Could not create testing_dir");
|
||||
let testing_dir_path = testing_dir.path();
|
||||
|
||||
// Quantity of compressed files vary from 1 to 10
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
let quantity_of_files = rng.next_u32() % 10 + 1;
|
||||
|
||||
let contents_of_files: Vec<FileContent> =
|
||||
(0..quantity_of_files).map(|_| generate_random_file_content(&mut rng)).collect();
|
||||
|
||||
// Create them
|
||||
let mut file_paths = create_files(testing_dir_path, &contents_of_files);
|
||||
// Compress them
|
||||
let compressed_archive_path = compress_files(testing_dir_path, &file_paths, format);
|
||||
// Decompress them
|
||||
let mut extracted_paths = extract_files(&compressed_archive_path);
|
||||
|
||||
// // DEBUG UTIL:
|
||||
// // Uncomment line below to freeze the code and see compressed and extracted files in
|
||||
// // the temporary directory before their auto-destruction.
|
||||
// std::thread::sleep(std::time::Duration::from_secs(1_000_000));
|
||||
|
||||
file_paths.sort();
|
||||
extracted_paths.sort();
|
||||
|
||||
assert_correct_paths(&file_paths, &extracted_paths, format);
|
||||
compare_file_contents(&extracted_paths, &contents_of_files, format);
|
||||
}
|
||||
|
||||
/// Crate file contents from 1024 up to 8192 random bytes
|
||||
fn generate_random_file_content(rng: &mut impl RngCore) -> FileContent {
|
||||
let quantity = 1024 + rng.next_u32() % (8192 - 1024);
|
||||
let mut vec = vec![0; quantity as usize];
|
||||
rng.fill_bytes(&mut vec);
|
||||
vec
|
||||
}
|
||||
|
||||
/// Create files using the indexes as file names (eg. 0, 1, 2 and 3)
|
||||
///
|
||||
/// Return the path to each one.
|
||||
fn create_files(at: &Path, contents: &[FileContent]) -> Vec<PathBuf> {
|
||||
contents
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, content)| {
|
||||
let path = at.join(i.to_string());
|
||||
let mut file = fs::File::create(&path).expect("Could not create dummy test file");
|
||||
file.write_all(content).expect("Could not write to dummy test file");
|
||||
path
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn extract_files(archive_path: &Path) -> Vec<PathBuf> {
|
||||
// We will extract in the same folder as the archive
|
||||
// If the archive is at:
|
||||
// /tmp/ouch-testing-tar.Rbq4DusBrtF8/archive.tar
|
||||
// Then the extraction_output_folder will be:
|
||||
// /tmp/ouch-testing-tar.Rbq4DusBrtF8/extraction_results/
|
||||
let mut extraction_output_folder = archive_path.to_path_buf();
|
||||
// Remove the name of the extracted archive
|
||||
assert!(extraction_output_folder.pop());
|
||||
// Add the suffix "results"
|
||||
extraction_output_folder.push("extraction_results");
|
||||
|
||||
let command = Opts {
|
||||
yes: false,
|
||||
no: false,
|
||||
cmd: Subcommand::Decompress {
|
||||
files: vec![archive_path.to_owned()],
|
||||
output_dir: Some(extraction_output_folder.clone()),
|
||||
},
|
||||
};
|
||||
run(command, QuestionPolicy::Ask).expect("Failed to extract");
|
||||
|
||||
fs::read_dir(extraction_output_folder).unwrap().map(Result::unwrap).map(|entry| entry.path()).collect()
|
||||
}
|
||||
|
||||
fn assert_correct_paths(original: &[PathBuf], extracted: &[PathBuf], format: &str) {
|
||||
assert_eq!(
|
||||
original.len(),
|
||||
extracted.len(),
|
||||
"Number of compressed files does not match number of decompressed when testing archive format '{:?}'.",
|
||||
format
|
||||
);
|
||||
for (original, extracted) in original.iter().zip(extracted) {
|
||||
assert_eq!(original.file_name(), extracted.file_name(), "");
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_file_contents(extracted: &[PathBuf], contents: &[FileContent], format: &str) {
|
||||
extracted.iter().zip(contents).for_each(|(extracted_path, expected_content)| {
|
||||
let actual_content = fs::read(extracted_path).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
expected_content,
|
||||
actual_content.as_slice(),
|
||||
"Contents of file with path '{:?}' does not match after compression and decompression while testing archive format '{:?}.'",
|
||||
extracted_path.canonicalize().unwrap(),
|
||||
format
|
||||
);
|
||||
});
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
mod utils;
|
||||
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
use utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_each_format() {
|
||||
test_compress_decompress_with_empty_dir("tar");
|
||||
test_compress_decompress_with_empty_dir("zip");
|
||||
}
|
||||
|
||||
fn test_compress_decompress_with_empty_dir(format: &str) {
|
||||
// System temporary directory depends on the platform, for linux it's /tmp
|
||||
let system_tmp = env::temp_dir();
|
||||
|
||||
// Create a temporary testing folder that will be deleted on scope drop
|
||||
let testing_dir =
|
||||
tempfile::Builder::new().prefix("ouch-testing").tempdir_in(system_tmp).expect("Could not create testing_dir");
|
||||
|
||||
let testing_dir_path = testing_dir.path();
|
||||
|
||||
let empty_dir_path: PathBuf = create_empty_dir(testing_dir_path, "dummy_empty_dir_name");
|
||||
|
||||
let mut file_paths: Vec<PathBuf> = vec![empty_dir_path];
|
||||
|
||||
let compressed_archive_path: PathBuf = compress_files(testing_dir_path, &file_paths, format);
|
||||
|
||||
let mut extracted_paths = extract_files(&compressed_archive_path);
|
||||
|
||||
// // DEBUG UTIL:
|
||||
// // Uncomment line below to freeze the code and see compressed and extracted files in
|
||||
// // the temporary directory before their auto-destruction.
|
||||
// std::thread::sleep(std::time::Duration::from_secs(10));
|
||||
|
||||
// no need to sort a unitary value vector but i will keep this
|
||||
// for retrocompatibility, for now.
|
||||
file_paths.sort();
|
||||
extracted_paths.sort();
|
||||
|
||||
assert_correct_paths(&file_paths, &extracted_paths, format);
|
||||
}
|
114
tests/integration.rs
Normal file
114
tests/integration.rs
Normal file
@ -0,0 +1,114 @@
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
|
||||
use std::{iter::once, path::PathBuf};
|
||||
|
||||
use fs_err as fs;
|
||||
use parse_display::Display;
|
||||
use proptest::sample::size_range;
|
||||
use rand::{rngs::SmallRng, RngCore, SeedableRng};
|
||||
use tempfile::tempdir;
|
||||
use test_strategy::{proptest, Arbitrary};
|
||||
|
||||
use crate::utils::create_file_random;
|
||||
|
||||
#[derive(Arbitrary, Debug, Display)]
|
||||
#[display(style = "snake_case")]
|
||||
enum DirectoryExtension {
|
||||
Tar,
|
||||
Tbz,
|
||||
Tgz,
|
||||
Tlz4,
|
||||
Tlz,
|
||||
Tlzma,
|
||||
Txz,
|
||||
Zip,
|
||||
}
|
||||
|
||||
#[derive(Arbitrary, Debug, Display)]
|
||||
#[display(style = "snake_case")]
|
||||
enum FileExtension {
|
||||
Bz,
|
||||
Bz2,
|
||||
Gz,
|
||||
// Lz4, // broken
|
||||
Lz,
|
||||
Lzma,
|
||||
Xz,
|
||||
}
|
||||
|
||||
#[derive(Arbitrary, Debug, Display)]
|
||||
#[display("{0}")]
|
||||
enum Extension {
|
||||
Directory(DirectoryExtension),
|
||||
File(FileExtension),
|
||||
}
|
||||
|
||||
fn merge_extensions(ext: impl ToString, exts: Vec<FileExtension>) -> String {
|
||||
once(ext.to_string()).chain(exts.into_iter().map(|x| x.to_string())).collect::<Vec<_>>().join(".")
|
||||
}
|
||||
|
||||
fn create_random_files(dir: impl Into<PathBuf>, depth: u8, rng: &mut SmallRng) {
|
||||
if depth == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let dir = &dir.into();
|
||||
|
||||
for _ in 0..rng.next_u32() % 8 {
|
||||
create_file_random(&mut tempfile::Builder::new().tempfile_in(dir).unwrap().keep().unwrap().0, rng);
|
||||
}
|
||||
|
||||
for _ in 0..rng.next_u32() % 4 {
|
||||
create_random_files(&tempfile::tempdir_in(dir).unwrap().into_path(), depth - 1, rng);
|
||||
}
|
||||
}
|
||||
|
||||
#[proptest(cases = 512)]
|
||||
fn single_empty_file(ext: Extension, #[any(size_range(0..8).lift())] exts: Vec<FileExtension>) {
|
||||
let dir = tempdir().unwrap();
|
||||
let dir = dir.path();
|
||||
let before = &dir.join("before");
|
||||
fs::create_dir(before).unwrap();
|
||||
let before_file = &before.join("file");
|
||||
let archive = &dir.join(format!("file.{}", merge_extensions(ext, exts)));
|
||||
let after = &dir.join("after");
|
||||
create_file_random(&mut fs::File::create(before_file).unwrap(), &mut SmallRng::from_entropy());
|
||||
ouch!("c", before_file, archive);
|
||||
ouch!("d", archive, "-d", after);
|
||||
assert!(!dir_diff::is_different(before, after).unwrap());
|
||||
}
|
||||
|
||||
#[proptest(cases = 512)]
|
||||
fn single_file(ext: Extension, #[any(size_range(0..8).lift())] exts: Vec<FileExtension>) {
|
||||
let dir = tempdir().unwrap();
|
||||
let dir = dir.path();
|
||||
let before = &dir.join("before");
|
||||
fs::create_dir(before).unwrap();
|
||||
let before_file = &before.join("file");
|
||||
let archive = &dir.join(format!("file.{}", merge_extensions(ext, exts)));
|
||||
let after = &dir.join("after");
|
||||
fs::write(before_file, []).unwrap();
|
||||
ouch!("c", before_file, archive);
|
||||
ouch!("d", archive, "-d", after);
|
||||
assert!(!dir_diff::is_different(before, after).unwrap());
|
||||
}
|
||||
|
||||
#[proptest(cases = 512)]
|
||||
fn multiple_files(
|
||||
ext: DirectoryExtension,
|
||||
#[any(size_range(0..8).lift())] exts: Vec<FileExtension>,
|
||||
#[strategy(0u8..4)] depth: u8,
|
||||
) {
|
||||
let dir = tempdir().unwrap();
|
||||
let dir = dir.path();
|
||||
let before = &dir.join("before");
|
||||
let before_dir = &before.join("dir");
|
||||
fs::create_dir_all(before_dir).unwrap();
|
||||
let archive = &dir.join(format!("archive.{}", merge_extensions(ext, exts)));
|
||||
let after = &dir.join("after");
|
||||
create_random_files(before_dir, depth, &mut SmallRng::from_entropy());
|
||||
ouch!("c", before_dir, archive);
|
||||
ouch!("d", archive, "-d", after);
|
||||
assert!(!dir_diff::is_different(before, after).unwrap());
|
||||
}
|
55
tests/mime.rs
Normal file
55
tests/mime.rs
Normal file
@ -0,0 +1,55 @@
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
|
||||
use rand::{rngs::SmallRng, SeedableRng};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::utils::create_file_random;
|
||||
|
||||
#[test]
|
||||
/// Makes sure that the files ouch produces are what they claim to be, checking their
|
||||
/// types through MIME sniffing.
|
||||
fn sanity_check_through_mime() {
|
||||
let temp_dir = tempfile::tempdir().expect("to build a temporary directory");
|
||||
let temp_dir_path = temp_dir.path();
|
||||
|
||||
let test_file = &mut NamedTempFile::new_in(temp_dir_path).expect("to be able to build a temporary file");
|
||||
create_file_random(test_file, &mut SmallRng::from_entropy());
|
||||
|
||||
let formats = [
|
||||
"tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma",
|
||||
"tar.xz", "tar.zst",
|
||||
];
|
||||
|
||||
let expected_mimes = [
|
||||
"application/x-tar",
|
||||
"application/zip",
|
||||
"application/gzip",
|
||||
"application/gzip",
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/zstd",
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/zstd",
|
||||
];
|
||||
|
||||
assert_eq!(formats.len(), expected_mimes.len());
|
||||
|
||||
for (format, expected_mime) in formats.iter().zip(expected_mimes.iter()) {
|
||||
let path_to_compress = test_file.path();
|
||||
|
||||
let compressed_file_path = &format!("{}.{}", path_to_compress.display(), format);
|
||||
ouch!("c", path_to_compress, compressed_file_path);
|
||||
|
||||
let sniffed =
|
||||
infer::get_from_path(compressed_file_path).expect("the file to be read").expect("the MIME to be found");
|
||||
|
||||
assert_eq!(&sniffed.mime_type(), expected_mime);
|
||||
}
|
||||
}
|
@ -1,68 +1,19 @@
|
||||
//! Files in common between one or more integration tests
|
||||
use std::io::Write;
|
||||
|
||||
#![allow(dead_code)]
|
||||
use rand::RngCore;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use fs_err as fs;
|
||||
use ouch::{commands::run, Opts, QuestionPolicy, Subcommand};
|
||||
|
||||
pub fn create_empty_dir(at: &Path, filename: &str) -> PathBuf {
|
||||
let dirname = Path::new(filename);
|
||||
let full_path = at.join(dirname);
|
||||
|
||||
fs::create_dir(&full_path).expect("Failed to create an empty directory");
|
||||
|
||||
full_path
|
||||
}
|
||||
|
||||
pub fn compress_files(at: &Path, paths_to_compress: &[PathBuf], format: &str) -> PathBuf {
|
||||
let archive_path = String::from("archive.") + format;
|
||||
let archive_path = at.join(archive_path);
|
||||
|
||||
let command = Opts {
|
||||
yes: false,
|
||||
no: false,
|
||||
cmd: Subcommand::Compress { files: paths_to_compress.to_vec(), output: archive_path.clone() },
|
||||
};
|
||||
run(command, QuestionPolicy::Ask).expect("Failed to compress test dummy files");
|
||||
|
||||
archive_path
|
||||
}
|
||||
|
||||
pub fn extract_files(archive_path: &Path) -> Vec<PathBuf> {
|
||||
// We will extract in the same folder as the archive
|
||||
// If the archive is at:
|
||||
// /tmp/ouch-testing-tar.Rbq4DusBrtF8/archive.tar
|
||||
// Then the extraction_output_folder will be:
|
||||
// /tmp/ouch-testing-tar.Rbq4DusBrtF8/extraction_results/
|
||||
let mut extraction_output_folder = archive_path.to_path_buf();
|
||||
// Remove the name of the extracted archive
|
||||
assert!(extraction_output_folder.pop());
|
||||
// Add the suffix "results"
|
||||
extraction_output_folder.push("extraction_results");
|
||||
|
||||
let command = Opts {
|
||||
yes: false,
|
||||
no: false,
|
||||
cmd: Subcommand::Decompress {
|
||||
files: vec![archive_path.to_owned()],
|
||||
output_dir: Some(extraction_output_folder.clone()),
|
||||
},
|
||||
};
|
||||
run(command, QuestionPolicy::Ask).expect("Failed to extract");
|
||||
|
||||
fs::read_dir(extraction_output_folder).unwrap().map(Result::unwrap).map(|entry| entry.path()).collect()
|
||||
}
|
||||
|
||||
pub fn assert_correct_paths(original: &[PathBuf], extracted: &[PathBuf], format: &str) {
|
||||
assert_eq!(
|
||||
original.len(),
|
||||
extracted.len(),
|
||||
"Number of compressed files does not match number of decompressed when testing archive format '{:?}'.",
|
||||
format
|
||||
);
|
||||
for (original, extracted) in original.iter().zip(extracted) {
|
||||
assert_eq!(original.file_name(), extracted.file_name());
|
||||
#[macro_export]
|
||||
macro_rules! ouch {
|
||||
($($e:expr),*) => {
|
||||
::assert_cmd::Command::cargo_bin("ouch")
|
||||
.expect("Failed to find ouch executable")
|
||||
$(.arg($e))*
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_file_random(file: &mut impl Write, rng: &mut impl RngCore) {
|
||||
let data = &mut Vec::with_capacity((rng.next_u32() % 8192) as usize);
|
||||
rng.fill_bytes(data);
|
||||
file.write_all(data).unwrap();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user