mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-07 12:05:46 +00:00
commit
3a5f43a76e
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,3 +6,6 @@ makeshift_testing.py
|
|||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# crash logs generated by proptest
|
||||||
|
*.proptest-regressions
|
||||||
|
@ -6,6 +6,11 @@ Feel free to open an issue anytime you wish to ask a question, suggest a feature
|
|||||||
|
|
||||||
1. Be nice to other people.
|
1. Be nice to other people.
|
||||||
2. If editing the Rust source code, remember to run `rustfmt` (otherwise, CI will warn you the code was not properly formatted).
|
2. If editing the Rust source code, remember to run `rustfmt` (otherwise, CI will warn you the code was not properly formatted).
|
||||||
|
3. If new formats are added, please add the format to `tests/integration.rs`.
|
||||||
|
If it is an archive format that handles directories, it should be added to `DirectoryExtension`, otherwise it should be added to `FileExtension`.
|
||||||
|
It should be added to `mime.rs` as well if the [`infer`](https://docs.rs/infer) crate supports it.
|
||||||
|
Most tests are written with `proptest` ([book](https://altsysrq.github.io/proptest-book/), [docs](https://docs.rs/proptest)).
|
||||||
|
If you wish to improve these tests, the proptest book might help you.
|
||||||
|
|
||||||
Note: we are using `unstable` features of `rustfmt`! Nightly toolchain is required (will likely be installed automatically, cause the toolchain was specified in the project root).
|
Note: we are using `unstable` features of `rustfmt`! Nightly toolchain is required (will likely be installed automatically, cause the toolchain was specified in the project root).
|
||||||
|
|
||||||
|
274
Cargo.lock
generated
274
Cargo.lock
generated
@ -8,6 +8,29 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
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]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -25,12 +48,38 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
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]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.4.3"
|
version = "1.4.3"
|
||||||
@ -132,6 +181,24 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "difflib"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "filetime"
|
name = "filetime"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@ -157,6 +224,12 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs-err"
|
name = "fs-err"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@ -217,6 +290,15 @@ dependencies = [
|
|||||||
"cfb",
|
"cfb",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.24"
|
version = "0.1.24"
|
||||||
@ -291,6 +373,15 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@ -310,6 +401,7 @@ dependencies = [
|
|||||||
name = "ouch"
|
name = "ouch"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"assert_cmd",
|
||||||
"atty",
|
"atty",
|
||||||
"bzip2",
|
"bzip2",
|
||||||
"clap",
|
"clap",
|
||||||
@ -321,15 +413,44 @@ dependencies = [
|
|||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
"lz4_flex",
|
"lz4_flex",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"parse-display",
|
||||||
|
"proptest",
|
||||||
"rand",
|
"rand",
|
||||||
"tar",
|
"tar",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"test-strategy",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"xz2",
|
"xz2",
|
||||||
"zip",
|
"zip",
|
||||||
"zstd",
|
"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]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.22"
|
version = "0.3.22"
|
||||||
@ -342,6 +463,33 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
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]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -375,6 +523,38 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"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]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
@ -424,6 +604,15 @@ dependencies = [
|
|||||||
"rand_core",
|
"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]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
@ -433,6 +622,29 @@ dependencies = [
|
|||||||
"bitflags",
|
"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]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -442,6 +654,18 @@ dependencies = [
|
|||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
@ -463,6 +687,29 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.81"
|
version = "1.0.81"
|
||||||
@ -508,6 +755,24 @@ dependencies = [
|
|||||||
"winapi-util",
|
"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]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.14.2"
|
version = "0.14.2"
|
||||||
@ -592,6 +857,15 @@ version = "0.9.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
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]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
|
@ -33,9 +33,13 @@ clap = "=3.0.0-beta.5"
|
|||||||
clap_generate = "=3.0.0-beta.5"
|
clap_generate = "=3.0.0-beta.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.2.0"
|
assert_cmd = "2.0.2"
|
||||||
infer = "0.5.0"
|
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"] }
|
rand = { version = "0.8.3", default-features = false, features = ["small_rng", "std"] }
|
||||||
|
tempfile = "3.2.0"
|
||||||
|
test-strategy = "0.1.2"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
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);
|
|
||||||
}
|
|
123
tests/integration.rs
Normal file
123
tests/integration.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#[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::{assert_same_directory, write_random_content};
|
||||||
|
|
||||||
|
// tar and zip extensions
|
||||||
|
#[derive(Arbitrary, Debug, Display)]
|
||||||
|
#[display(style = "lowercase")]
|
||||||
|
enum DirectoryExtension {
|
||||||
|
Tar,
|
||||||
|
Tbz,
|
||||||
|
Tgz,
|
||||||
|
Tlz4,
|
||||||
|
Tlz,
|
||||||
|
Tlzma,
|
||||||
|
Txz,
|
||||||
|
Zip,
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensions of single file compression formats
|
||||||
|
#[derive(Arbitrary, Debug, Display)]
|
||||||
|
#[display(style = "lowercase")]
|
||||||
|
enum FileExtension {
|
||||||
|
Bz,
|
||||||
|
Bz2,
|
||||||
|
Gz,
|
||||||
|
// Lz4, // broken
|
||||||
|
Lz,
|
||||||
|
Lzma,
|
||||||
|
Xz,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Arbitrary, Debug, Display)]
|
||||||
|
#[display("{0}")]
|
||||||
|
enum Extension {
|
||||||
|
Directory(DirectoryExtension),
|
||||||
|
File(FileExtension),
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts a list of extension structs to string
|
||||||
|
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(".")
|
||||||
|
}
|
||||||
|
|
||||||
|
// create random nested directories and files under the specified directory
|
||||||
|
fn create_random_files(dir: impl Into<PathBuf>, depth: u8, rng: &mut SmallRng) {
|
||||||
|
if depth == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dir = &dir.into();
|
||||||
|
|
||||||
|
// create 0 to 7 random files
|
||||||
|
for _ in 0..rng.next_u32() % 8 {
|
||||||
|
write_random_content(&mut tempfile::Builder::new().tempfile_in(dir).unwrap().keep().unwrap().0, rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create more random files in 0 to 3 new directories
|
||||||
|
for _ in 0..rng.next_u32() % 4 {
|
||||||
|
create_random_files(&tempfile::tempdir_in(dir).unwrap().into_path(), depth - 1, rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compress and decompress a single empty file
|
||||||
|
#[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");
|
||||||
|
write_random_content(&mut fs::File::create(before_file).unwrap(), &mut SmallRng::from_entropy());
|
||||||
|
ouch!("c", before_file, archive);
|
||||||
|
ouch!("d", archive, "-d", after);
|
||||||
|
assert_same_directory(before, after, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compress and decompress a single file
|
||||||
|
#[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_same_directory(before, after, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compress and decompress a directory with random content generated with create_random_files
|
||||||
|
#[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_same_directory(before, after, !matches!(ext, DirectoryExtension::Zip));
|
||||||
|
}
|
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::write_random_content;
|
||||||
|
|
||||||
|
#[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");
|
||||||
|
write_random_content(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);
|
||||||
|
}
|
||||||
|
}
|
144
tests/utils.rs
144
tests/utils.rs
@ -1,68 +1,86 @@
|
|||||||
//! Files in common between one or more integration tests
|
use std::{io::Write, path::PathBuf};
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use ouch::{commands::run, Opts, QuestionPolicy, Subcommand};
|
use rand::RngCore;
|
||||||
|
|
||||||
pub fn create_empty_dir(at: &Path, filename: &str) -> PathBuf {
|
#[macro_export]
|
||||||
let dirname = Path::new(filename);
|
macro_rules! ouch {
|
||||||
let full_path = at.join(dirname);
|
($($e:expr),*) => {
|
||||||
|
::assert_cmd::Command::cargo_bin("ouch")
|
||||||
fs::create_dir(&full_path).expect("Failed to create an empty directory");
|
.expect("Failed to find ouch executable")
|
||||||
|
$(.arg($e))*
|
||||||
full_path
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write random content to a file
|
||||||
|
pub fn write_random_content(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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that two directories have the exact same content recursively
|
||||||
|
// checks equility of file types if preserve_permissions is true, ignored on non-unix
|
||||||
|
pub fn assert_same_directory(x: impl Into<PathBuf>, y: impl Into<PathBuf>, preserve_permissions: bool) {
|
||||||
|
fn read_dir(dir: impl Into<PathBuf>) -> impl Iterator<Item = fs::DirEntry> {
|
||||||
|
let mut dir: Vec<_> = fs::read_dir(dir).unwrap().map(|entry| entry.unwrap()).collect();
|
||||||
|
dir.sort_by_key(|x| x.file_name());
|
||||||
|
dir.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut x = read_dir(x);
|
||||||
|
let mut y = read_dir(y);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match (x.next(), y.next()) {
|
||||||
|
(Some(x), Some(y)) => {
|
||||||
|
assert_eq!(x.file_name(), y.file_name());
|
||||||
|
|
||||||
|
let meta_x = x.metadata().unwrap();
|
||||||
|
let meta_y = y.metadata().unwrap();
|
||||||
|
let ft_x = meta_x.file_type();
|
||||||
|
let ft_y = meta_y.file_type();
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
if preserve_permissions {
|
||||||
|
assert_eq!(ft_x, ft_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ft_x.is_dir() && ft_y.is_dir() {
|
||||||
|
assert_same_directory(x.path(), y.path(), preserve_permissions);
|
||||||
|
} else if ft_x.is_file() && ft_y.is_file() {
|
||||||
|
assert_eq!(meta_x.len(), meta_y.len());
|
||||||
|
assert_eq!(fs::read(x.path()).unwrap(), fs::read(y.path()).unwrap());
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"entries should be both directories or both files\n left: `{:?}`,\n right: `{:?}`",
|
||||||
|
x.path(),
|
||||||
|
y.path()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, None) => break,
|
||||||
|
|
||||||
|
(x, y) => {
|
||||||
|
panic!(
|
||||||
|
"directories don't have the same number of entires\n left: `{:?}`,\n right: `{:?}`",
|
||||||
|
x.map(|x| x.path()),
|
||||||
|
y.map(|y| y.path()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn src_is_src() {
|
||||||
|
assert_same_directory("src", "src", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn src_is_not_tests() {
|
||||||
|
assert_same_directory("src", "tests", false);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user