diff --git a/Cargo.lock b/Cargo.lock index 888718f..fdc2d2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,6 +22,27 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "assert_cmd" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "escargot 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "assert_fs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "globwalk 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.11" @@ -79,7 +100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -87,7 +108,7 @@ name = "bytes" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -103,7 +124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chrono" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -182,6 +203,16 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "dtoa" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "env_logger" version = "0.5.11" @@ -210,6 +241,15 @@ dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "escargot" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.1" @@ -239,6 +279,14 @@ dependencies = [ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "float-cmp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fnv" version = "1.0.6" @@ -288,14 +336,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "globwalk" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ignore 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -325,6 +382,23 @@ dependencies = [ "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ignore" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.2" @@ -351,6 +425,11 @@ name = "ipnetwork" version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "itoa" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -379,15 +458,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "libmesabox" version = "0.1.0" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (git+https://github.com/mesalock-linux/glob)", - "globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -456,10 +535,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "mesabox" version = "0.1.0" dependencies = [ + "assert_cmd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_fs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "libmesabox 0.1.0", + "predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -656,6 +738,24 @@ dependencies = [ "pnet_sys 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "predicates" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quick-error" version = "1.2.2" @@ -666,6 +766,14 @@ name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "quote" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.4.2" @@ -799,6 +907,34 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "serde" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.0" @@ -838,6 +974,16 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "synom" version = "0.11.3" @@ -1099,7 +1245,7 @@ name = "trust-dns-proto" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1173,6 +1319,11 @@ name = "unicode-xid" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -1307,17 +1458,19 @@ dependencies = [ "checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum assert_cmd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11d61ba2f519654febb9a504d172cfc21c667c9889e707b9860d78dd5e2b69b3" +"checksum assert_fs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43012797d17b83c33793dba19f3c4154011bb5eeaac11763d6ea538c87380917" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" -"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" +"checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" "checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" "checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" -"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37" +"checksum chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e48d85528df61dc964aa43c5f6ca681a19cfa74939b2348d204bd08a981f2fb0" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" @@ -1326,12 +1479,16 @@ dependencies = [ "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67df0571a74bf0d97fb8b2ed22abdd9a48475c96bd327db968b7d9cace99655e" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" +"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum env_logger 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "7873e292d20e8778f951278972596b3df36ac72a65c5b406f6d4961070a870c1" "checksum error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faa976b4fd2e4c2b2f3f486874b19e61944d3de3de8b61c9fcf835d583871bcc" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" +"checksum escargot 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddeb6acd0f12aeba309aa295bcad6d4d88603406640bf2595c887a7a9684a4bd" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f" +"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" @@ -1340,13 +1497,16 @@ dependencies = [ "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" "checksum glob 0.2.11 (git+https://github.com/mesalock-linux/glob)" = "" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d" +"checksum globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e49edbcc9c7fc5beb8c0a54e7319ff8bed353a2b55e85811c6281188c2a6c84" +"checksum globwalk 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce5d04da8cf35b507b2cbec92bbf2d5085292d07cd87637994fd437fe1617bbb" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum ignore 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e9faa7c84064f07b40da27044af629f578bc7994b650d3e458d0c29183c1d91" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec4e18c0a0d4340870c14284293632d8421f419008371422dd327892b88877c" "checksum ipnetwork 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)" = "70783119ac90828aaba91eae39db32c6c1b8838deea3637e5238efa0130801ab" +"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" @@ -1378,8 +1538,11 @@ dependencies = [ "checksum pnet_packet 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef99f3cfa2c0ed07e9ad6d9f788592d863361a8dd3102989d79b0f6a787ba434" "checksum pnet_sys 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "963b9109a05c3ac370abc3fda61bff20d03743c2947942173871b9cac2b9acb0" "checksum pnet_transport 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "568a118fe2f74ebb08e9b9b6ac812b9730a7b043c5ca4d97325f4edeb018cae0" +"checksum predicates 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3dc50ff273939a7688f8bccd748add1a0822dd6a9aa132b52600c7c45cc6409" +"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b71f9f575d55555aa9c06188be9d4e2bfc83ed02537948ac0d520c24d0419f1a" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" @@ -1396,11 +1559,15 @@ dependencies = [ "checksum rustyline 2.0.0-alpha (git+https://github.com/kkawakam/rustyline)" = "" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" +"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" +"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" "checksum socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "962a516af4d3a7c272cb3a1d50a8cc4e5b41802e4ad54cfb7bee8ba61d37d703" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4bad7abdf6633f07c7046b90484f1d9dc055eca39f8c991177b1046ce61dba9a" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum syntex 0.42.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0a30b08a6b383a22e5f6edc127d169670d48f905bb00ca79a00ea3e442ebe317" @@ -1434,6 +1601,7 @@ dependencies = [ "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" diff --git a/Cargo.toml b/Cargo.toml index fd0a734..9b81ff6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,9 @@ env_logger = { version = "0.5.11", optional = true } tempfile = "3.0.2" libc = "0.2.40" lazy_static = "1.0.1" +assert_cmd = "0.6.0" +assert_fs = "0.3.0" +predicates = "0.5.2" [profile.release] lto = true diff --git a/ci/libmesabox-cov-rustc b/ci/libmesabox-cov-rustc new file mode 100755 index 0000000..31eeb52 --- /dev/null +++ b/ci/libmesabox-cov-rustc @@ -0,0 +1,25 @@ +#!/bin/bash -e + +get_crate_name() +{ + while [[ $# -gt 1 ]] ; do + v=$1 + case $v in + --crate-name) + echo $2 + return + ;; + esac + shift + done +} + +case $(get_crate_name "$@") in + libmesabox) + EXTRA=$COVERAGE_OPTIONS + ;; + *) + ;; +esac + +exec "$@" $EXTRA diff --git a/ci/cov-rustc b/ci/mesabox-cov-rustc similarity index 100% rename from ci/cov-rustc rename to ci/mesabox-cov-rustc diff --git a/ci/run-cov b/ci/run-cov index 8b146f9..5d4f294 100755 --- a/ci/run-cov +++ b/ci/run-cov @@ -2,7 +2,6 @@ for path in /usr/lib/llvm-3.8/lib/clang/3.8.[0-9]/lib/linux/; do LLVM_PATH=$path; done export COVERAGE_OPTIONS="-Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Cpasses=insert-gcov-profiling -Zno-landing-pads -L$LLVM_PATH -lclang_rt.profile-x86_64" -export RUSTC_WRAPPER="./ci/cov-rustc" export CARGO_INCREMENTAL=0 LCOVOPT="--gcov-tool ./ci/llvm-gcov --rc lcov_branch_coverage=1 --rc lcov_excl_line=assert" @@ -12,25 +11,27 @@ LCOV="/usr/local/bin/lcov" rm -rf *.info *.gcda *.gcno cargo clean -# unit tests -cargo rustc --all-features --profile test --lib -rm ./target/debug/mesabox-*.d -./target/debug/mesabox-* -${LCOV} ${LCOVOPT} --capture --directory . --base-directory . -o mesabox.info +# unit tests of libmesabox +export RUSTC_WRAPPER="./ci/libmesabox-cov-rustc" +cargo rustc --package libmesabox --all-features --profile test --lib +rm ./target/debug/libmesabox-*.d +./target/debug/libmesabox-* +${LCOV} ${LCOVOPT} --capture --directory . --base-directory . -o libmesabox.info # cleanup target rm -rf *.gcda *.gcno cargo clean # integration tests +export RUSTC_WRAPPER="./ci/mesabox-cov-rustc" cargo rustc --all-features --test tests rm ./target/debug/tests-*.d ./target/debug/tests-* ${LCOV} ${LCOVOPT} --capture --directory . --base-directory . -o tests.info # combining and filtering -${LCOV} ${LCOVOPT} --add mesabox.info --add tests.info -o coverage.info -${LCOV} ${LCOVOPT} --extract coverage.info `find "$(cd src; pwd)" -name "*.rs"` -o final.info +${LCOV} ${LCOVOPT} --add libmesabox.info --add tests.info -o coverage.info +${LCOV} ${LCOVOPT} --extract coverage.info `find "$(cd src; pwd)" "$(cd libmesabox; pwd)" -name "*.rs"` -o final.info # generate report if not in CI if [[ "$CI" != true ]]; then diff --git a/tests/gnu/arch.rs b/tests/gnu/arch.rs index 3b606dd..fd24517 100644 --- a/tests/gnu/arch.rs +++ b/tests/gnu/arch.rs @@ -6,30 +6,37 @@ // For a copy, see the LICENSE file. // -use util::*; +use std::process::Command; +use assert_cmd::prelude::*; const NAME: &str = "arch"; #[test] #[cfg(target_arch = "x86_64")] fn test_x86_64() { - new_ucmd!() - .succeeds() - .stdout_only("x86_64\n"); + new_cmd!() + .assert() + .success() + .stdout("x86_64\n") + .stderr(""); } #[test] #[cfg(target_arch = "arm")] fn test_arm() { - new_ucmd!() - .succeeds() - .stdout_only("arm\n"); + new_cmd!() + .assert() + .success() + .stdout("arm\n") + .stderr(""); } #[test] #[cfg(target_arch = "aarch64")] fn test_aarch64() { - new_ucmd!() - .succeeds() - .stdout_only("aarch64\n"); + new_cmd!() + .assert() + .success() + .stdout("aarch64\n") + .stderr(""); } diff --git a/tests/gnu/base32.rs b/tests/gnu/base32.rs index 6e071a4..7fd6cd3 100644 --- a/tests/gnu/base32.rs +++ b/tests/gnu/base32.rs @@ -1,7 +1,7 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // @@ -32,52 +32,60 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -use util::*; +use assert_cmd::prelude::*; +use predicates::prelude::*; +use std::process::Command; const NAME: &str = "base32"; #[test] fn test_encode() { let input = "Hello, World!"; - new_ucmd!() - .pipe_in(input) - .succeeds() - .stdout_only("JBSWY3DPFQQFO33SNRSCC===\n"); + new_cmd!() + .with_stdin().buffer(input) + .assert() + .success() + .stdout("JBSWY3DPFQQFO33SNRSCC===\n") + .stderr(""); } #[test] fn test_decode() { for decode_param in vec!["-d", "--decode"] { let input = "JBSWY3DPFQQFO33SNRSCC===\n"; - new_ucmd!() + new_cmd!() .arg(decode_param) - .pipe_in(input) - .succeeds() - .stdout_only("Hello, World!"); + .with_stdin().buffer(input) + .assert() + .success() + .stdout("Hello, World!") + .stderr(""); } } #[test] fn test_garbage() { let input = "aGVsbG8sIHdvcmxkIQ==\0"; - new_ucmd!() + new_cmd!() .arg("-d") - .pipe_in(input) - .fails() - .no_stdout() - .stderr_contains("invalid length at 16"); + .with_stdin().buffer(input) + .assert() + .failure() + .stdout("") + .stderr(predicate::str::contains("invalid length at 16").from_utf8()); } #[test] fn test_ignore_garbage() { for ignore_garbage_param in vec!["-i", "--ignore-garbage"] { let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n"; - new_ucmd!() - .arg("-d") - .arg(ignore_garbage_param) - .pipe_in(input) - .succeeds() - .stdout_only("Hello, World!"); + new_cmd!() + .args(&["-d", ignore_garbage_param]) + .with_stdin().buffer(input) + .assert() + .success() + .stdout("Hello, World!") + .stderr(""); } } @@ -85,33 +93,36 @@ fn test_ignore_garbage() { fn test_wrap() { for wrap_param in vec!["-w", "--wrap"] { let input = "The quick brown fox jumps over the lazy dog."; - new_ucmd!() - .arg(wrap_param) - .arg("20") - .pipe_in(input) - .succeeds() - .stdout_only("KRUGKIDROVUWG2ZAMJZG\n653OEBTG66BANJ2W24DT\nEBXXMZLSEB2GQZJANRQX\nU6JAMRXWOLQ=\n"); + new_cmd!() + .args(&[wrap_param, "20"]) + .with_stdin().buffer(input) + .assert() + .success() + .stdout("KRUGKIDROVUWG2ZAMJZG\n653OEBTG66BANJ2W24DT\nEBXXMZLSEB2GQZJANRQX\nU6JAMRXWOLQ=\n") + .stderr(""); } } #[test] fn test_wrap_no_arg() { for wrap_param in vec!["-w", "--wrap"] { - new_ucmd!() + new_cmd!() .arg(wrap_param) - .fails() - .no_stdout() - .stderr_contains("requires a value but none was supplied\n"); + .assert() + .failure() + .stdout("") + .stderr(predicate::str::contains("requires a value but none was supplied\n").from_utf8()); } } #[test] fn test_wrap_bad_arg() { for wrap_param in vec!["-w", "--wrap"] { - new_ucmd!() - .arg(wrap_param).arg("b") - .fails() - .no_stdout() - .stderr_contains("'b' is not a number\n"); + new_cmd!() + .args(&[wrap_param, "b"]) + .assert() + .failure() + .stdout("") + .stderr(predicate::str::contains("'b' is not a number\n").from_utf8()); } } diff --git a/tests/gnu/base64.rs b/tests/gnu/base64.rs index 0ac0c01..e6f1150 100644 --- a/tests/gnu/base64.rs +++ b/tests/gnu/base64.rs @@ -1,7 +1,7 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // @@ -32,52 +32,60 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -use util::*; +use assert_cmd::prelude::*; +use predicates::prelude::*; +use std::process::Command; const NAME: &str = "base64"; #[test] fn test_encode() { let input = "hello, world!"; - new_ucmd!() - .pipe_in(input) - .succeeds() - .stdout_only("aGVsbG8sIHdvcmxkIQ==\n"); + new_cmd!() + .with_stdin().buffer(input) + .assert() + .success() + .stdout("aGVsbG8sIHdvcmxkIQ==\n") + .stderr(""); } #[test] fn test_decode() { for decode_param in vec!["-d", "--decode"] { let input = "aGVsbG8sIHdvcmxkIQ=="; - new_ucmd!() + new_cmd!() .arg(decode_param) - .pipe_in(input) - .succeeds() - .stdout_only("hello, world!"); + .with_stdin().buffer(input) + .assert() + .success() + .stdout("hello, world!") + .stderr(""); } } #[test] fn test_garbage() { let input = "aGVsbG8sIHdvcmxkIQ==\0"; - new_ucmd!() + new_cmd!() .arg("-d") - .pipe_in(input) - .fails() - .no_stdout() - .stderr_contains("invalid length at 20"); + .with_stdin().buffer(input) + .assert() + .failure() + .stderr(predicate::str::contains("invalid length at 20").from_utf8()) + .stdout(""); } #[test] fn test_ignore_garbage() { for ignore_garbage_param in vec!["-i", "--ignore-garbage"] { let input = "aGVsbG8sIHdvcmxkIQ==\0"; - new_ucmd!() - .arg("-d") - .arg(ignore_garbage_param) - .pipe_in(input) - .succeeds() - .stdout_only("hello, world!"); + new_cmd!() + .args(&["-d", ignore_garbage_param]) + .with_stdin().buffer(input) + .assert() + .success() + .stdout("hello, world!") + .stderr(""); } } @@ -85,33 +93,36 @@ fn test_ignore_garbage() { fn test_wrap() { for wrap_param in vec!["-w", "--wrap"] { let input = "The quick brown fox jumps over the lazy dog."; - new_ucmd!() - .arg(wrap_param) - .arg("20") - .pipe_in(input) - .succeeds() - .stdout_only("VGhlIHF1aWNrIGJyb3du\nIGZveCBqdW1wcyBvdmVy\nIHRoZSBsYXp5IGRvZy4=\n"); + new_cmd!() + .args(&[wrap_param, "20"]) + .with_stdin().buffer(input) + .assert() + .success() + .stdout("VGhlIHF1aWNrIGJyb3du\nIGZveCBqdW1wcyBvdmVy\nIHRoZSBsYXp5IGRvZy4=\n") + .stderr(""); } } #[test] fn test_wrap_no_arg() { for wrap_param in vec!["-w", "--wrap"] { - new_ucmd!() + new_cmd!() .arg(wrap_param) - .fails() - .no_stdout() - .stderr_contains("requires a value but none was supplied\n"); + .assert() + .failure() + .stdout("") + .stderr(pred_str_contains!("requires a value but none was supplied")); } } #[test] fn test_wrap_bad_arg() { for wrap_param in vec!["-w", "--wrap"] { - new_ucmd!() - .arg(wrap_param).arg("b") - .fails() - .no_stdout() - .stderr_contains("'b' is not a number\n"); + new_cmd!() + .args(&[wrap_param, "b"]) + .assert() + .failure() + .stdout("") + .stderr(pred_str_contains!("'b' is not a number\n")); } } diff --git a/tests/macros.rs b/tests/macros.rs index de885c2..44b1227 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -5,82 +5,6 @@ // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // -// This file incorporates work covered by the following copyright and -// permission notice: -// -// Copyright (c) 2013-2018, Jordi Boggiano -// Copyright (c) 2013-2018, Alex Lyon -// Copyright (c) 2015, Joseph Crail -// Copyright (c) 2015-2016, Nathan Ross -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -#[macro_export] -macro_rules! assert_empty_stderr( - ($cond:expr) => ( - if $cond.stderr.len() > 0 { - panic!(format!("stderr: {}", $cond.stderr)) - } - ); -); - -#[macro_export] -macro_rules! assert_empty_stdout( - ($cond:expr) => ( - if $cond.stdout.len() > 0 { - panic!(format!("stdout: {}", $cond.stdout)) - } - ); -); - -#[macro_export] -macro_rules! assert_no_error( - ($cond:expr) => ( - assert!($cond.success); - if $cond.stderr.len() > 0 { - panic!(format!("stderr: {}", $cond.stderr)) - } - ); -); - -#[macro_export] -macro_rules! path_concat { - ($e:expr, ..$n:expr) => {{ - use std::path::PathBuf; - let n = $n; - let mut pb = PathBuf::new(); - for _ in 0..n { - pb.push($e); - } - pb.to_str().unwrap().to_owned() - }}; - ($($e:expr),*) => {{ - use std::path::PathBuf; - let mut pb = PathBuf::new(); - $( - pb.push($e); - )* - pb.to_str().unwrap().to_owned() - }}; -} #[macro_export] macro_rules! util_name { @@ -90,16 +14,42 @@ macro_rules! util_name { } #[macro_export] -macro_rules! new_ucmd { +macro_rules! new_cmd { () => { - TestScenario::new(util_name!()).ucmd() + Command::main_binary().unwrap().arg(util_name!()) }; } #[macro_export] -macro_rules! at_and_ucmd { +macro_rules! fixtures_dir { () => {{ - let ts = TestScenario::new(util_name!()); - (ts.fixtures.clone(), ts.ucmd()) + use std::env; + let mut path = env::current_dir().unwrap(); + path.push("tests/fixtures"); + path.push(util_name!()); + path + }}; +} + +#[macro_export] +macro_rules! fixtures_path { + ($filename:expr) => {{ + let mut fixtures_path = fixtures_dir!(); + fixtures_path.push($filename); + fixtures_path }}; } + +#[macro_export] +macro_rules! pred_eq_file { + ($filename:expr) => { + predicate::path::eq_file(fixtures_path!($filename).as_path()) + } +} + +#[macro_export] +macro_rules! pred_str_contains { + ($str:expr) => { + predicate::str::contains($str).from_utf8() + } +} diff --git a/tests/posix/cat.rs b/tests/posix/cat.rs index e46f385..9f0017c 100644 --- a/tests/posix/cat.rs +++ b/tests/posix/cat.rs @@ -31,16 +31,19 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -use util::*; +use assert_cmd::prelude::*; +use std::process::Command; const NAME: &str = "cat"; #[test] fn test_output_multi_files_print_all_chars() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["alpha.txt", "256.txt", "-A", "-n"]) - .succeeds() - .stdout_only(" 1\tabcde$\n 2\tfghij$\n 3\tklmno$\n 4\tpqrst$\n \ + .assert() + .success() + .stdout(" 1\tabcde$\n 2\tfghij$\n 3\tklmno$\n 4\tpqrst$\n \ 5\tuvwxyz$\n 6\t^@^A^B^C^D^E^F^G^H^I$\n \ 7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ \ !\"#$%&\'()*+,-./0123456789:;\ @@ -50,123 +53,146 @@ fn test_output_multi_files_print_all_chars() { M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:\ M-;M-M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-U\ M-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-\ - pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?"); + pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?") + .stderr(""); } #[test] fn test_numbered_lines_no_trailing_newline() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["nonewline.txt", "alpha.txt", "-n"]) - .succeeds() - .stdout_only(" 1\ttext without a trailing newlineabcde\n 2\tfghij\n \ - 3\tklmno\n 4\tpqrst\n 5\tuvwxyz\n"); + .assert() + .success() + .stdout(" 1\ttext without a trailing newlineabcde\n 2\tfghij\n \ + 3\tklmno\n 4\tpqrst\n 5\tuvwxyz\n") + .stderr(""); } #[test] -fn test_stdin_show_nonprinting() { +fn test_with_stdin_show_nonprinting() { for same_param in vec!["-v", "--show-nonprinting"] { - new_ucmd!() + new_cmd!() .args(&[same_param]) - .pipe_in("\t\0\n") - .succeeds() - .stdout_only("\t^@\n"); + .with_stdin().buffer("\t\0\n") + .assert() + .success() + .stdout("\t^@\n") + .stderr(""); } } #[test] -fn test_stdin_show_tabs() { +fn test_with_stdin_show_tabs() { for same_param in vec!["-T", "--show-tabs"] { - new_ucmd!() + new_cmd!() .args(&[same_param]) - .pipe_in("\t\0\n") - .succeeds() - .stdout_only("^I\0\n"); + .with_stdin().buffer("\t\0\n") + .assert() + .success() + .stdout("^I\0\n") + .stderr(""); } } #[test] -fn test_stdin_show_ends() { +fn test_with_stdin_show_ends() { for same_param in vec!["-E", "--show-ends"] { - new_ucmd!() + new_cmd!() .args(&[same_param,"-"]) - .pipe_in("\t\0\n") - .succeeds() - .stdout_only("\t\0$\n"); + .with_stdin().buffer("\t\0\n") + .assert() + .success() + .stdout("\t\0$\n") + .stderr(""); } } #[test] -fn test_stdin_show_all() { +fn test_with_stdin_show_all() { for same_param in vec!["-A", "--show-all"] { - new_ucmd!() + new_cmd!() .args(&[same_param]) - .pipe_in("\t\0\n") - .succeeds() - .stdout_only("^I^@$\n"); + .with_stdin().buffer("\t\0\n") + .assert() + .success() + .stdout("^I^@$\n") + .stderr(""); } } #[test] -fn test_stdin_nonprinting_and_endofline() { - new_ucmd!() +fn test_with_stdin_nonprinting_and_endofline() { + new_cmd!() .args(&["-e"]) - .pipe_in("\t\0\n") - .succeeds() - .stdout_only("\t^@$\n"); + .with_stdin().buffer("\t\0\n") + .assert() + .success() + .stdout("\t^@$\n") + .stderr(""); } #[test] -fn test_stdin_nonprinting_and_tabs() { - new_ucmd!() +fn test_with_stdin_nonprinting_and_tabs() { + new_cmd!() .args(&["-t"]) - .pipe_in("\t\0\n") - .succeeds() - .stdout_only("^I^@\n"); + .with_stdin().buffer("\t\0\n") + .assert() + .success() + .stdout("^I^@\n") + .stderr(""); } #[test] -fn test_stdin_squeeze_blank() { +fn test_with_stdin_squeeze_blank() { for same_param in vec!["-s", "--squeeze-blank"] { - new_ucmd!() - .arg(same_param) - .pipe_in("\n\na\n\n\n\n\nb\n\n\n") - .succeeds() - .stdout_only("\na\n\nb\n\n"); + new_cmd!() + .args(&[same_param]) + .with_stdin().buffer("\n\na\n\n\n\n\nb\n\n\n") + .assert() + .success() + .stdout("\na\n\nb\n\n") + .stderr(""); } } #[test] -fn test_stdin_number_non_blank() { +fn test_with_stdin_number_non_blank() { for same_param in vec!["-b", "--number-nonblank"] { - new_ucmd!() - .arg(same_param) - .arg("-") - .pipe_in("\na\nb\n\n\nc") - .succeeds() - .stdout_only("\n 1\ta\n 2\tb\n\n\n 3\tc"); + new_cmd!() + .args(&[same_param, "-"]) + .with_stdin().buffer("\na\nb\n\n\nc") + .assert() + .success() + .stdout("\n 1\ta\n 2\tb\n\n\n 3\tc") + .stderr(""); } } #[test] fn test_non_blank_overrides_number() { for same_param in vec!["-b", "--number-nonblank"] { - new_ucmd!() + new_cmd!() .args(&[same_param, "-"]) - .pipe_in("\na\nb\n\n\nc") - .succeeds() - .stdout_only("\n 1\ta\n 2\tb\n\n\n 3\tc"); + .with_stdin().buffer("\na\nb\n\n\nc") + .assert() + .success() + .stdout("\n 1\ta\n 2\tb\n\n\n 3\tc") + .stderr(""); } } #[test] fn test_squeeze_blank_before_numbering() { for same_param in vec!["-s", "--squeeze-blank"] { - new_ucmd!() + new_cmd!() .args(&[same_param, "-n", "-"]) - .pipe_in("a\n\n\nb") - .succeeds() - .stdout_only(" 1\ta\n 2\t\n 3\tb"); + .with_stdin().buffer("a\n\n\nb") + .assert() + .success() + .stdout(" 1\ta\n 2\t\n 3\tb") + .stderr(""); } } @@ -187,10 +213,12 @@ fn test_domain_socket() { stream.write_all(b"a\tb").expect("failed to write test data"); }); - new_ucmd!() + new_cmd!() .args(&[socket_path]) - .succeeds() - .stdout_only("a\tb"); + .assert() + .success() + .stdout("a\tb") + .stderr(""); thread.join().unwrap(); } diff --git a/tests/posix/chmod.rs b/tests/posix/chmod.rs index b5c5b77..3997f17 100644 --- a/tests/posix/chmod.rs +++ b/tests/posix/chmod.rs @@ -1,7 +1,7 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // @@ -31,78 +31,58 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -use util::*; -use std::fs::{metadata, OpenOptions, set_permissions}; -use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; +use assert_cmd::prelude::*; +use assert_fs; +use assert_fs::prelude::*; +use std::fs::{metadata, set_permissions}; +use std::os::unix::fs::PermissionsExt; +use std::process::Command; use std::sync::Mutex; use libc::umask; const NAME: &str = "chmod"; -const TEST_FILE: &str = "file"; -const REFERENCE_FILE: &str = "reference"; -const REFERENCE_PERMS: u32 = 0o247; - lazy_static! { static ref UMASK_MUTEX: Mutex<()> = Mutex::new(()); } -struct TestCase { - args: Vec<&'static str>, - before: u32, - after: u32 -} - -fn mkfile(file: &str, mode: u32) { - OpenOptions::new().mode(mode).create(true).write(true).open(file).unwrap(); - let mut perms = metadata(file).unwrap().permissions(); - perms.set_mode(mode); - set_permissions(file, perms).unwrap(); -} - -fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) { - mkfile(&at.plus_as_string(TEST_FILE), test.before); - let perms = at.metadata(TEST_FILE).permissions().mode(); - if perms != test.before { - panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions on test files before actual test run failed", test.after, perms)); - } - - for arg in &test.args { - ucmd.arg(arg); - } - let r = ucmd.run(); - if !r.success { - println!("{}", r.stderr_str()); - panic!(format!("{:?}: failed", ucmd.command_str())); - } - - let perms = at.metadata(TEST_FILE).permissions().mode(); - if perms != test.after { - panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.command_str(), test.after, perms)); - } -} - -fn run_tests(tests: Vec) { - for test in tests { - let (at, ucmd) = at_and_ucmd!(); - run_single_test(&test, at, ucmd); +fn run_test(before: u32, mode: &str, expected: u32) { + let temp_dir = assert_fs::TempDir::new().unwrap(); + let temp_file = temp_dir.child("TEST_FILE"); + temp_file.touch().unwrap(); + let temp_filepath = temp_file.path(); + let mut perms = metadata(temp_filepath).unwrap().permissions(); + perms.set_mode(before); + set_permissions(temp_filepath, perms).unwrap(); + + new_cmd!() + .args(&[mode, temp_filepath.to_str().unwrap()]) + .assert() + .success(); + + let perms_after = metadata(temp_filepath).unwrap().permissions().mode(); + if perms_after != expected { + panic!(format!("expected: {:o} got: {:o}", expected, perms_after)); } } #[test] fn test_chmod_octal() { - let tests = vec!{ - TestCase{args: vec!{"0700", TEST_FILE}, before: 0o100000, after: 0o100700}, - TestCase{args: vec!{"0070", TEST_FILE}, before: 0o100000, after: 0o100070}, - TestCase{args: vec!{"0007", TEST_FILE}, before: 0o100000, after: 0o100007}, - TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o100700, after: 0o100000}, - TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o100060, after: 0o100000}, - TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o100001, after: 0o100000}, - TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o100600, after: 0o100700}, - TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o100050, after: 0o100070}, - TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o100003, after: 0o100007}, - }; - run_tests(tests); + let tests = vec![ + (0o100000, "0700", 0o100700), + (0o100000, "0070", 0o100070), + (0o100000, "0007", 0o100007), + (0o100700, "-0700", 0o100000), + (0o100060, "-0070", 0o100000), + (0o100001, "-0007", 0o100000), + (0o100600, "+0100", 0o100700), + (0o100050, "+0020", 0o100070), + (0o100003, "+0004", 0o100007), + ]; + for t in tests { + let (before, mode, expected) = t; + run_test(before, mode, expected); + } } #[test] @@ -112,31 +92,39 @@ fn test_chmod_ugoa() { let last = unsafe { umask(0) }; - let tests = vec!{ - TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o100000, after: 0o100700}, - TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o100000, after: 0o100070}, - TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o100000, after: 0o100007}, - TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o100000, after: 0o100777}, - TestCase{args: vec!{"-r", TEST_FILE}, before: 0o100777, after: 0o100333}, - TestCase{args: vec!{"-w", TEST_FILE}, before: 0o100777, after: 0o100555}, - TestCase{args: vec!{"-x", TEST_FILE}, before: 0o100777, after: 0o100666}, - }; - run_tests(tests); + let tests = vec![ + (0o100000, "u=rwx", 0o100700), + (0o100000, "g=rwx", 0o100070), + (0o100000, "o=rwx", 0o100007), + (0o100000, "a=rwx", 0o100777), + (0o100777, "-r" , 0o100333), + (0o100777, "-w" , 0o100555), + (0o100777, "-x" , 0o100666), + ]; + for t in tests { + let (before, mode, expected) = t; + run_test(before, mode, expected); + } unsafe { umask(0o022); } - let tests = vec!{ - TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o100000, after: 0o100700}, - TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o100000, after: 0o100070}, - TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o100000, after: 0o100007}, - TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o100000, after: 0o100777}, - TestCase{args: vec!{"+rw", TEST_FILE}, before: 0o100000, after: 0o100644}, - TestCase{args: vec!{"=rwx", TEST_FILE}, before: 0o100000, after: 0o100755}, - TestCase{args: vec!{"-w", TEST_FILE}, before: 0o100777, after: 0o100577}, - TestCase{args: vec!{"-x", TEST_FILE}, before: 0o100777, after: 0o100666}, - }; - run_tests(tests); + + let tests = vec![ + (0o100000, "u=rwx", 0o100700), + (0o100000, "g=rwx", 0o100070), + (0o100000, "o=rwx", 0o100007), + (0o100000, "a=rwx", 0o100777), + (0o100000, "+rw" , 0o100644), + (0o100000, "=rwx" , 0o100755), + (0o100777, "-w" , 0o100577), + (0o100777, "-x" , 0o100666), + ]; + for t in tests { + let (before, mode, expected) = t; + run_test(before, mode, expected); + } + unsafe { umask(last); } @@ -144,14 +132,18 @@ fn test_chmod_ugoa() { #[test] fn test_chmod_ugo_copy() { - let tests = vec!{ - TestCase{args: vec!{"u=g", TEST_FILE}, before: 0o100070, after: 0o100770}, - TestCase{args: vec!{"g=o", TEST_FILE}, before: 0o100005, after: 0o100055}, - TestCase{args: vec!{"o=u", TEST_FILE}, before: 0o100200, after: 0o100202}, - TestCase{args: vec!{"u-g", TEST_FILE}, before: 0o100710, after: 0o100610}, - TestCase{args: vec!{"u+g", TEST_FILE}, before: 0o100250, after: 0o100750}, - }; - run_tests(tests); + let tests = vec![ + (0o100070, "u=g", 0o100770), + (0o100005, "g=o", 0o100055), + (0o100200, "o=u", 0o100202), + (0o100710, "u-g", 0o100610), + (0o100250, "u+g", 0o100750), + ]; + + for t in tests { + let (before, mode, expected) = t; + run_test(before, mode, expected); + } } #[test] @@ -161,23 +153,17 @@ fn test_chmod_many_options() { let original_umask = unsafe { umask(0) }; - let tests = vec!{ - TestCase{args: vec!{"-r,a+w", TEST_FILE}, before: 0o100444, after: 0o100222}, - }; - run_tests(tests); + + let tests = vec![ + (0o100444, "-r,a+w", 0o100222), + ]; + + for t in tests { + let (before, mode, expected) = t; + run_test(before, mode, expected); + } + unsafe { umask(original_umask); } } - -#[test] -#[ignore] -fn test_chmod_reference_file() { - let tests = vec!{ - TestCase{args: vec!{"--reference", REFERENCE_FILE, TEST_FILE}, before: 0o100070, after: 0o100247}, - TestCase{args: vec!{"a-w", "--reference", REFERENCE_FILE, TEST_FILE}, before: 0o100070, after: 0o100247}, - }; - let (at, ucmd) = at_and_ucmd!(); - mkfile(&at.plus_as_string(REFERENCE_FILE), REFERENCE_PERMS); - run_single_test(&tests[0], at, ucmd); -} diff --git a/tests/posix/echo.rs b/tests/posix/echo.rs index 419f66f..ee7b8d8 100644 --- a/tests/posix/echo.rs +++ b/tests/posix/echo.rs @@ -1,7 +1,7 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // @@ -31,104 +31,113 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -use util::*; +use assert_cmd::prelude::*; +use std::process::Command; const NAME: &str = "echo"; #[test] fn test_default() { - //CmdResult.stdout_only(...) trims trailing newlines - assert_eq!("hi\n".as_bytes(), &new_ucmd!().arg("hi").succeeds().no_stderr().stdout[..]); + new_cmd!() + .arg("hi") + .assert() + .success() + .stdout("hi\n") + .stderr(""); } #[test] fn test_no_trailing_newline() { - //CmdResult.stdout_only(...) trims trailing newlines - assert_eq!("hi".as_bytes(), &new_ucmd!().arg(r"hi\c").succeeds().no_stderr().stdout[..]); + new_cmd!() + .arg(r"hi\c") + .assert() + .success() + .stdout("hi") + .stderr(""); } #[test] fn test_escape_alert() { - new_ucmd!().arg(r"\a").succeeds().stdout_only("\x07\n"); + new_cmd!().arg(r"\a").assert().success().stdout("\x07\n").stderr(""); } #[test] fn test_escape_backslash() { - new_ucmd!().arg(r"\\").succeeds().stdout_only("\\\n"); + new_cmd!().arg(r"\\").assert().success().stdout("\\\n").stderr(""); } #[test] fn test_escape_backspace() { - new_ucmd!().arg(r"\b").succeeds().stdout_only("\x08\n"); + new_cmd!().arg(r"\b").assert().success().stdout("\x08\n").stderr(""); } #[test] fn test_escape_carriage_return() { - new_ucmd!().arg(r"\r").succeeds().stdout_only("\r\n"); + new_cmd!().arg(r"\r").assert().success().stdout("\r\n").stderr(""); } #[test] fn test_escape_form_feed() { - new_ucmd!().arg(r"\f").succeeds().stdout_only("\x0C\n"); + new_cmd!().arg(r"\f").assert().success().stdout("\x0C\n").stderr(""); } #[test] fn test_escape_newline() { - new_ucmd!().arg(r"\na").succeeds().stdout_only("\na\n"); + new_cmd!().arg(r"\na").assert().success().stdout("\na\n").stderr(""); } #[test] fn test_escape_no_further_output() { - new_ucmd!().arg(r"a\cb").succeeds().stdout_only("a"); + new_cmd!().arg(r"a\cb").assert().success().stdout("a").stderr(""); } #[test] fn test_escape_octal() { - new_ucmd!().arg(r"\0100").succeeds().stdout_only("@\n"); + new_cmd!().arg(r"\0100").assert().success().stdout("@\n").stderr(""); } #[test] fn test_escape_tab() { - new_ucmd!().arg(r"\t").succeeds().stdout_only("\t\n"); + new_cmd!().arg(r"\t").assert().success().stdout("\t\n").stderr(""); } #[test] fn test_escape_vertical_tab() { - new_ucmd!().arg(r"\v").succeeds().stdout_only("\x0B\n"); + new_cmd!().arg(r"\v").assert().success().stdout("\x0B\n").stderr(""); } #[test] fn test_escape_others() { - new_ucmd!().arg(r"\o").succeeds().stdout_only("\\o\n"); + new_cmd!().arg(r"\o").assert().success().stdout("\\o\n").stderr(""); } #[test] fn test_escape_octal_break() { - new_ucmd!().arg(r"\0178").succeeds().stdout_only("\x0f\x38\n"); + new_cmd!().arg(r"\0178").assert().success().stdout("\x0f\x38\n").stderr(""); } #[test] fn test_escape_octal_nothing() { - new_ucmd!().arg(r"\0").succeeds().stdout_only("\x00\n"); + new_cmd!().arg(r"\0").assert().success().stdout("\x00\n").stderr(""); } #[test] fn test_multiple_args() { - new_ucmd!().args(&[r"a", r"b", r"c"]).succeeds().stdout_only("a b c\n"); + new_cmd!().args(&[r"a", r"b", r"c"]).assert().success().stdout("a b c\n").stderr(""); } #[test] fn test_no_arg() { - new_ucmd!().succeeds().stdout_only("\n"); + new_cmd!().assert().success().stdout("\n").stderr(""); } #[test] fn test_escape_none() { - new_ucmd!().arg(r"\").succeeds().stdout_only("\\\n"); + new_cmd!().arg(r"\").assert().success().stdout("\\\n").stderr(""); } #[test] fn test_many_backslash() { // should output 4 backslashes + newline - new_ucmd!().arg(r"\\\\\\\").succeeds().stdout_only("\\\\\\\\\n"); + new_cmd!().arg(r"\\\\\\\").assert().success().stdout("\\\\\\\\\n").stderr(""); } diff --git a/tests/posix/false.rs b/tests/posix/false.rs index 83f1bfe..ca4cb67 100644 --- a/tests/posix/false.rs +++ b/tests/posix/false.rs @@ -1,16 +1,17 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // -use util::*; +use assert_cmd::prelude::*; +use std::process::Command; const NAME: &str = "false"; #[test] fn test_false() { - new_ucmd!().fails(); + new_cmd!().assert().failure(); } diff --git a/tests/posix/head.rs b/tests/posix/head.rs index 8a9d3f0..bd0fea7 100644 --- a/tests/posix/head.rs +++ b/tests/posix/head.rs @@ -31,7 +31,9 @@ // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -use util::*; +use assert_cmd::prelude::*; +use predicates::prelude::*; +use std::process::Command; const NAME: &str = "head"; @@ -40,87 +42,131 @@ const INPUT2: &str = "lorem_ipsum_reverse.txt"; #[test] fn test_stdin_default() { - new_ucmd!() - .pipe_in_fixture(INPUT) - .run().stdout_is_fixture("lorem_ipsum_default.expected"); + new_cmd!() + .with_stdin().path(fixtures_path!(INPUT)).unwrap() + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_default.expected")) + .stderr(""); } #[test] fn test_stdin_1_line_obsolete() { - new_ucmd!() + new_cmd!() .args(&["-1"]) - .pipe_in_fixture(INPUT) - .run().stdout_is_fixture("lorem_ipsum_1_line.expected"); + .with_stdin().path(fixtures_path!(INPUT)).unwrap() + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_1_line.expected")) + .stderr(""); } #[test] fn test_stdin_1_line() { - new_ucmd!() + new_cmd!() .args(&["-n", "1"]) - .pipe_in_fixture(INPUT) - .run().stdout_is_fixture("lorem_ipsum_1_line.expected"); + .with_stdin().path(fixtures_path!(INPUT)).unwrap() + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_1_line.expected")) + .stderr(""); } #[test] fn test_stdin_5_chars() { - new_ucmd!() + new_cmd!() .args(&["-c", "5"]) - .pipe_in_fixture(INPUT) - .run().stdout_is_fixture("lorem_ipsum_5_chars.expected"); + .with_stdin().path(fixtures_path!(INPUT)).unwrap() + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_5_chars.expected")) + .stderr(""); } #[test] fn test_single_default() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .arg(INPUT) - .run().stdout_is_fixture("lorem_ipsum_default.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_default.expected")) + .stderr(""); } #[test] fn test_single_1_line_obsolete() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["-1", INPUT]) - .run().stdout_is_fixture("lorem_ipsum_1_line.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_1_line.expected")) + .stderr(""); } #[test] fn test_single_1_line() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["-n", "1", INPUT]) - .run().stdout_is_fixture("lorem_ipsum_1_line.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_1_line.expected")) + .stderr(""); } #[test] fn test_single_5_chars() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["-c", "5", INPUT]) - .run().stdout_is_fixture("lorem_ipsum_5_chars.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_5_chars.expected")) + .stderr(""); } #[test] fn test_minus_1_line() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["-n", "-1", INPUT]) - .run().stdout_is_fixture("lorem_ipsum_minus_1_line.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_minus_1_line.expected")) + .stderr(""); } #[test] fn test_minus_5_chars() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["-c", "-5", INPUT]) - .run().stdout_is_fixture("lorem_ipsum_minus_5_chars.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_minus_5_chars.expected")) + .stderr(""); } #[test] fn test_multiple_input_files() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&[INPUT, INPUT2]) - .run().stdout_is_fixture("lorem_ipsum_multiple_input_files.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_multiple_input_files.expected")) + .stderr(""); } #[test] fn test_verbose() { - new_ucmd!() + new_cmd!() + .current_dir(fixtures_dir!()) .args(&["-v", INPUT]) - .run().stdout_is_fixture("lorem_ipsum_verbose.expected"); + .assert() + .success() + .stdout(pred_eq_file!("lorem_ipsum_verbose.expected")) + .stderr(""); } diff --git a/tests/posix/sh.rs b/tests/posix/sh.rs index 4b433d2..8b47637 100644 --- a/tests/posix/sh.rs +++ b/tests/posix/sh.rs @@ -1,12 +1,14 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // -use util::*; +use assert_cmd::prelude::*; +use predicates::prelude::*; +use std::process::Command; const NAME: &str = "sh"; @@ -18,27 +20,32 @@ mod stdin { #[test] fn test_pipeline() { - new_ucmd!() - .pipe_in_fixture(input_fixture(PIPELINE)) - .run() - .stdout_is_fixture(expected_fixture(PIPELINE)); + new_cmd!() + .with_stdin().path(fixtures_path!(input_fixture(PIPELINE))).unwrap() + .assert() + .success() + .stdout(pred_eq_file!(expected_fixture(PIPELINE))) + .stderr(""); } #[test] fn test_pipeline_subshell() { - new_ucmd!() - .pipe_in_fixture(input_fixture(PIPELINE_SUBSHELL)) - .run() - .stdout_is_fixture(expected_fixture(PIPELINE_SUBSHELL)); + new_cmd!() + .with_stdin().path(fixtures_path!(input_fixture(PIPELINE_SUBSHELL))).unwrap() + .assert() + .success() + .stdout(pred_eq_file!(expected_fixture(PIPELINE_SUBSHELL))) + .stderr(""); } // XXX: this is likely a parser issue (again) #[test] #[ignore] fn test_invalid_subshell_loc() { - new_ucmd!() - .pipe_in("echo hi | echo hello (echo hi; cat) | cat") - .fails(); + new_cmd!() + .with_stdin().buffer("echo hi | echo hello (echo hi; cat) | cat") + .assert() + .failure(); } } @@ -47,18 +54,22 @@ mod script { #[test] fn test_pipeline() { - new_ucmd!() - .arg(input_fixture(PIPELINE)) - .run() - .stdout_is_fixture(expected_fixture(PIPELINE)); + new_cmd!() + .arg(fixtures_path!(input_fixture(PIPELINE))) + .assert() + .success() + .stdout(pred_eq_file!(expected_fixture(PIPELINE))) + .stderr(""); } #[test] fn test_pipeline_subshell() { - new_ucmd!() - .arg(input_fixture(PIPELINE_SUBSHELL)) - .run() - .stdout_is_fixture(expected_fixture(PIPELINE_SUBSHELL)); + new_cmd!() + .arg(fixtures_path!(input_fixture(PIPELINE_SUBSHELL))) + .assert() + .success() + .stdout(pred_eq_file!(expected_fixture(PIPELINE_SUBSHELL))) + .stderr(""); } } diff --git a/tests/posix/sleep.rs b/tests/posix/sleep.rs index d2b4eac..f7af2aa 100644 --- a/tests/posix/sleep.rs +++ b/tests/posix/sleep.rs @@ -1,40 +1,42 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // -use util::*; - +use assert_cmd::prelude::*; +use std::process::Command; use std::time::{Duration, Instant}; const NAME: &str = "sleep"; -const SLEEP_TIME: f32 = 1.75; -const DIFF: f32 = 0.5; +const SLEEP_TIME: f32 = 5.75; +const DIFF: f32 = 1.5; #[test] fn test_one_param() { let now = Instant::now(); - new_ucmd!() + new_cmd!() .args(&[SLEEP_TIME.to_string()]) - .succeeds(); + .assert() + .success(); - validate_duration(now.elapsed(), SLEEP_TIME); + validate_duration(now.elapsed(), SLEEP_TIME); } #[test] fn test_many_params() { let now = Instant::now(); - new_ucmd!() + new_cmd!() .args(&[(SLEEP_TIME / 4.0).to_string(), (SLEEP_TIME / 2.0).to_string(), (SLEEP_TIME / 8.0).to_string(), (SLEEP_TIME / 8.0).to_string()]) - .succeeds(); + .assert() + .success(); - validate_duration(now.elapsed(), SLEEP_TIME); + validate_duration(now.elapsed(), SLEEP_TIME); } fn validate_duration(duration: Duration, sleep_time: f32) { diff --git a/tests/posix/true.rs b/tests/posix/true.rs index 86c8d32..101959c 100644 --- a/tests/posix/true.rs +++ b/tests/posix/true.rs @@ -1,16 +1,17 @@ // // Copyright (c) 2018, The MesaLock Linux Project Contributors // All rights reserved. -// +// // This work is licensed under the terms of the BSD 3-Clause License. // For a copy, see the LICENSE file. // -use util::*; +use assert_cmd::prelude::*; +use std::process::Command; const NAME: &str = "true"; #[test] fn test_true() { - new_ucmd!().succeeds(); + new_cmd!().assert().success(); } diff --git a/tests/tests.rs b/tests/tests.rs index 0426e93..8bb12a7 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -11,8 +11,10 @@ extern crate libmesabox as mesabox; extern crate lazy_static; extern crate libc; extern crate tempfile; +extern crate assert_cmd; +extern crate assert_fs; +extern crate predicates; -mod util; #[macro_use] mod macros; diff --git a/tests/util.rs b/tests/util.rs deleted file mode 100644 index c1277a7..0000000 --- a/tests/util.rs +++ /dev/null @@ -1,765 +0,0 @@ -// -// Copyright (c) 2018, The MesaLock Linux Project Contributors -// All rights reserved. -// -// This work is licensed under the terms of the BSD 3-Clause License. -// For a copy, see the LICENSE file. -// -// This file incorporates work covered by the following copyright and -// permission notice: -// -// Copyright (c) 2013-2018, Jordi Boggiano -// Copyright (c) 2013-2018, Alex Lyon -// Copyright (c) 2015, Joseph Crail -// Copyright (c) 2015-2016, Nathan Ross -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -#![allow(unused)] - -use std::borrow::Cow; -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fs::{self, File, OpenOptions}; -use std::io::{Read, Result, Seek, SeekFrom, Write}; -#[cfg(unix)] -use std::os::unix::ffi::OsStringExt; -#[cfg(unix)] -use std::os::unix::fs::symlink as symlink_file; -#[cfg(windows)] -use std::os::windows::fs::symlink_file; -use std::path::{Path, PathBuf}; -use std::rc::Rc; -use std::sync::{Arc, Mutex}; -use std::thread::{self, sleep, JoinHandle}; -use std::time::Duration; - -use mesabox::{self, UtilData}; -use tempfile::{self, TempDir}; - -const TESTS_DIR: &str = "tests"; -const FIXTURES_DIR: &str = "fixtures"; - -const ALREADY_RUN: &str = " you have already run this UCommand, if you want to run \ - another command in the same test, use TestScenario::new instead of \ - testing();"; -const MULTIPLE_STDIN_MEANINGLESS: &str = "Ucommand is designed around a typical use case of: provide args and input stream -> spawn process -> block until completion -> return output streams. For verifying that a particular section of the input stream is what causes a particular behavior, use the Command type directly."; - -fn read_scenario_fixture>(tmpd: &Option>, file_rel_path: S) -> Vec { - let tmpdir_path = tmpd.as_ref().unwrap().as_ref().path(); - AtPath::new(tmpdir_path).read(file_rel_path) -} - -pub fn repeat_str(s: &str, n: u32) -> String { - let mut repeated = String::new(); - for _ in 0..n { - repeated.push_str(s); - } - repeated -} - -/// A command result is the outputs of a command (streams and status code) -/// within a struct which has convenience assertion functions about those outputs -pub struct CmdResult { - //tmpd is used for convenience functions for asserts against fixtures - tmpd: Option>, - pub success: bool, - pub stdout: Vec, - pub stderr: Vec, -} - -impl CmdResult { - /// asserts that the command resulted in a success (zero) status code - pub fn success(&self) -> &CmdResult { - assert!(self.success); - self - } - - /// asserts that the command resulted in a failure (non-zero) status code - pub fn failure(&self) -> &CmdResult { - assert!(!self.success); - self - } - - /// asserts that the command resulted in empty (zero-length) stderr stream output - /// generally, it's better to use stdout_only() instead, - /// but you might find yourself using this function if - /// 1. you can not know exactly what stdout will be - /// or 2. you know that stdout will also be empty - pub fn no_stderr(&self) -> &CmdResult { - assert!(self.stderr.is_empty()); - self - } - - /// asserts that the command resulted in empty (zero-length) stderr stream output - /// unless asserting there was neither stdout or stderr, stderr_only is usually a better choice - /// generally, it's better to use stderr_only() instead, - /// but you might find yourself using this function if - /// 1. you can not know exactly what stderr will be - /// or 2. you know that stderr will also be empty - pub fn no_stdout(&self) -> &CmdResult { - assert!(self.stdout.is_empty()); - self - } - - /// asserts that the command resulted in stdout stream output that equals the - /// passed in value - /// stdout_only is a better choice unless stderr may or will be non-empty - pub fn stdout_is>(&self, msg: T) -> &CmdResult { - assert_eq!(msg.as_ref(), &self.stdout[..]); - self - } - - /// like stdout_is(...), but expects the contents of the file at the provided relative path - pub fn stdout_is_fixture>(&self, file_rel_path: T) -> &CmdResult { - let contents = read_scenario_fixture(&self.tmpd, file_rel_path); - self.stdout_is(contents) - } - - /// like stdout_is(...), but only checks if the stdout stream contains the given value - pub fn stdout_contains>(&self, msg: T) -> &CmdResult { - assert!(self.stdout_str().contains(msg.as_ref())); - self - } - - /// asserts that the command resulted in stderr stream output that equals the - /// passed in value - /// stderr_only is a better choice unless stdout may or will be non-empty - pub fn stderr_is>(&self, msg: T) -> &CmdResult { - assert_eq!(msg.as_ref(), &self.stderr[..]); - self - } - - /// like stderr_is(...), but expects the contents of the file at the provided relative path - pub fn stderr_is_fixture>(&self, file_rel_path: T) -> &CmdResult { - let contents = read_scenario_fixture(&self.tmpd, file_rel_path); - self.stderr_is(contents) - } - - /// like stderr_is(...), but only checks if the stderr stream contains the given value - pub fn stderr_contains>(&self, msg: T) -> &CmdResult { - assert!(self.stderr_str().contains(&msg.as_ref())); - self - } - - /// asserts that - /// 1. the command resulted in stdout stream output that equals the - /// passed in value - /// and 2. the command resulted in empty (zero-length) stderr stream output - pub fn stdout_only>(&self, msg: T) -> &CmdResult { - self.no_stderr().stdout_is(msg) - } - - /// like stdout_only(...), but expects the contents of the file at the provided relative path - pub fn stdout_only_fixture>(&self, file_rel_path: T) -> &CmdResult { - let contents = read_scenario_fixture(&self.tmpd, file_rel_path); - self.stdout_only(contents) - } - - /// asserts that - /// 1. the command resulted in stderr stream output that equals the - /// passed in value - /// and 2. the command resulted in empty (zero-length) stdout stream output - pub fn stderr_only>(&self, msg: T) -> &CmdResult { - self.no_stdout().stderr_is(msg) - } - - /// like stderr_only(...), but expects the contents of the file at the provided relative path - pub fn stderr_only_fixture>(&self, file_rel_path: T) -> &CmdResult { - let contents = read_scenario_fixture(&self.tmpd, file_rel_path); - self.stderr_only(contents) - } - - pub fn fails_silently(&self) -> &CmdResult { - assert!(!self.success); - assert!(self.stderr.is_empty()); - self - } - - pub fn stdout_str(&self) -> Cow { - String::from_utf8_lossy(&self.stdout) - } - - pub fn stderr_str(&self) -> Cow { - String::from_utf8_lossy(&self.stderr) - } -} - -pub fn log_info, U: AsRef>(msg: T, par: U) { - println!("{}: {}", msg.as_ref(), par.as_ref()); -} - -// XXX: there is a similar function in src/util.rs, maybe share common code? -pub fn recursive_copy(src: &Path, dest: &Path) -> Result<()> { - if fs::metadata(src)?.is_dir() { - for entry in fs::read_dir(src)? { - let entry = entry?; - let mut new_dest = PathBuf::from(dest); - new_dest.push(entry.file_name()); - if fs::metadata(entry.path())?.is_dir() { - fs::create_dir(&new_dest)?; - recursive_copy(&entry.path(), &new_dest)?; - } else { - fs::copy(&entry.path(), new_dest)?; - } - } - } - Ok(()) -} - -pub fn get_root_path() -> &'static str { - if cfg!(windows) { - "C:\\" - } else { - "/" - } -} - -/// Object-oriented path struct that represents and operates on -/// paths relative to the directory it was constructed for. -#[derive(Clone)] -pub struct AtPath { - pub subdir: PathBuf, -} - -impl AtPath { - pub fn new(subdir: &Path) -> AtPath { - AtPath { - subdir: PathBuf::from(subdir), - } - } - - pub fn to_string_lossy(&self) -> Cow { - self.subdir.to_string_lossy() - } - - pub fn plus>(&self, name: S) -> PathBuf { - let mut pathbuf = self.subdir.clone(); - pathbuf.push(name.as_ref()); - pathbuf - } - - pub fn plus_as_string>(&self, name: S) -> String { - self.plus(name).to_string_lossy().into_owned() - } - - fn minus>(&self, name: S) -> PathBuf { - let prefixed = PathBuf::from(name.as_ref()); - if prefixed.starts_with(&self.subdir) { - let mut unprefixed = PathBuf::new(); - for component in prefixed.components().skip(self.subdir.components().count()) { - unprefixed.push(component.as_os_str().to_str().unwrap()); - } - unprefixed - } else { - prefixed - } - } - - pub fn minus_as_string>(&self, name: S) -> String { - self.minus(name).to_string_lossy().into_owned() - } - - pub fn open>(&self, name: S) -> File { - log_info("open", self.plus_as_string(&name)); - File::open(self.plus(name)).unwrap() - } - - pub fn read_to_string>(&self, name: S) -> String { - let mut f = self.open(name); - let mut contents = String::new(); - let _ = f.read_to_string(&mut contents); - contents - } - - pub fn read>(&self, name: S) -> Vec { - let mut f = self.open(name); - let mut contents = vec![]; - let _ = f.read_to_end(&mut contents); - contents - } - - pub fn write>(&self, name: S, contents: &[u8]) { - let mut f = self.open(name); - let _ = f.write_all(contents); - } - - pub fn append>(&self, name: S, contents: &[u8]) { - log_info("open(append)", self.plus_as_string(&name)); - let mut f = OpenOptions::new() - .write(true) - .append(true) - .open(self.plus(name)) - .unwrap(); - let _ = f.write_all(contents); - } - - pub fn mkdir>(&self, dir: S) { - log_info("mkdir", self.plus_as_string(&dir)); - fs::create_dir(&self.plus(dir)).unwrap(); - } - pub fn mkdir_all>(&self, dir: S) { - log_info("mkdir_all", self.plus_as_string(&dir)); - fs::create_dir_all(self.plus(dir)).unwrap(); - } - - pub fn make_file>(&self, name: S) -> File { - File::create(&self.plus(name)).unwrap() - } - - pub fn touch>(&self, file: S) { - log_info("touch", self.plus_as_string(&file)); - File::create(&self.plus(file)).unwrap(); - } - - pub fn symlink(&self, src: S, dst: D) - where - S: AsRef, - D: AsRef, - { - log_info( - "symlink", - &format!( - "{},{}", - self.plus_as_string(&src), - self.plus_as_string(&dst) - ), - ); - symlink_file(&self.plus(src), &self.plus(dst)).unwrap(); - } - - pub fn is_symlink>(&self, path: S) -> bool { - log_info("is_symlink", self.plus_as_string(&path)); - fs::symlink_metadata(&self.plus(path)) - .map(|m| m.file_type().is_symlink()) - .unwrap_or(false) - } - - pub fn resolve_link>(&self, path: S) -> PathBuf { - log_info("resolve_link", self.plus_as_string(&path)); - fs::read_link(&self.plus(path)) - .map(|p| self.minus(p)) - .unwrap_or_default() - } - - pub fn symlink_metadata>(&self, path: S) -> fs::Metadata { - fs::symlink_metadata(&self.plus(path)).unwrap() - } - - pub fn metadata>(&self, path: S) -> fs::Metadata { - fs::metadata(&self.plus(path)).unwrap() - } - - pub fn file_exists>(&self, path: S) -> bool { - fs::metadata(&self.plus(path)) - .map(|m| m.is_file()) - .unwrap_or(false) - } - - pub fn dir_exists>(&self, path: S) -> bool { - fs::metadata(&self.plus(path)) - .map(|m| m.is_dir()) - .unwrap_or(false) - } - - pub fn cleanup>(&self, path: S) { - let p = &self.plus(path); - if let Ok(m) = fs::metadata(p) { - if m.is_file() { - fs::remove_file(&p).unwrap(); - } else { - fs::remove_dir(&p).unwrap(); - } - } - } - - pub fn root_dir(&self) -> &Path { - log_info("current_directory", ""); - &self.subdir - } - - pub fn root_dir_resolved(&self) -> PathBuf { - log_info("current_directory_resolved", ""); - let s = self.subdir.canonicalize().unwrap(); - - // Due to canonicalize()'s use of GetFinalPathNameByHandleW() on Windows, the resolved path - // starts with '\\?\' to extend the limit of a given path to 32,767 wide characters. - // - // To address this issue, we remove this prepended string if available. - // - // Source: - // http://stackoverflow.com/questions/31439011/getfinalpathnamebyhandle-without-prepended - let prefix = "\\\\?\\"; - if s.starts_with(prefix) { - s.strip_prefix(prefix).unwrap().to_path_buf() - } else { - s - } - } -} - -/// An environment for running a single uutils test case, serves three functions: -/// 1. centralizes logic for locating the uutils binary and calling the utility -/// 2. provides a temporary directory for the test case -/// 3. copies over fixtures for the utility to the temporary directory -pub struct TestScenario { - util_name: String, - pub fixtures: AtPath, - tmpd: Rc, -} - -impl TestScenario { - pub fn new(util_name: &str) -> TestScenario { - let tmpd = Rc::new(TempDir::new().unwrap()); - let ts = TestScenario { - util_name: String::from(util_name), - fixtures: AtPath::new(tmpd.as_ref().path()), - tmpd: tmpd, - }; - let mut fixture_path_builder = env::current_dir().unwrap(); - fixture_path_builder.push(TESTS_DIR); - fixture_path_builder.push(FIXTURES_DIR); - fixture_path_builder.push(util_name); - if let Ok(m) = fs::metadata(&fixture_path_builder) { - if m.is_dir() { - recursive_copy(&fixture_path_builder, &ts.fixtures.subdir).unwrap(); - } - } - ts - } - - pub fn ucmd(&self) -> UCommand { - let mut cmd = self.cmd(Some("mesabox")); - cmd.arg(&self.util_name); - cmd - } - - pub fn cmd>(&self, bin: Option) -> UCommand { - UCommand::new_from_tmp( - bin.as_ref() - .map(|s| s.as_ref()) - .unwrap_or(self.util_name.as_ref()), - self.tmpd.clone(), - true, - ) - } - - // different names are used rather than an argument - // because the need to keep the environment is exceedingly rare. - pub fn ucmd_keepenv(&self) -> UCommand { - let mut cmd = self.cmd_keepenv(Some("mesabox")); - cmd.arg(&self.util_name); - cmd - } - - pub fn cmd_keepenv>(&self, bin: Option) -> UCommand { - UCommand::new_from_tmp( - bin.as_ref() - .map(|s| s.as_ref()) - .unwrap_or(self.util_name.as_ref()), - self.tmpd.clone(), - false, - ) - } -} - -/// A `UCommand` is a wrapper around an individual Command that provides several additional features -/// 1. it has convenience functions that are more ergonomic to use for piping in stdin, spawning the command -/// and asserting on the results. -/// 2. it tracks arguments provided so that in test cases which may provide variations of an arg in loops -/// the test failure can display the exact call which preceded an assertion failure. -/// 3. it provides convenience construction arguments to set the Command working directory and/or clear its environment. -pub struct UCommand { - args: Vec, - env: Vec<(OsString, OsString)>, - current_dir: PathBuf, - comm_string: String, - tmpd: Option>, - has_run: bool, - stdin: Option>, -} - -impl UCommand { - pub fn new, U: AsRef>(arg: T, curdir: U, env_clear: bool) -> UCommand { - let mut env = vec![]; - - if !env_clear { - env.extend(env::vars_os()); - } - if cfg!(windows) { - // %SYSTEMROOT% is required on Windows to initialize crypto provider - // ... and crypto provider is required for std::rand - // From procmon: RegQueryValue HKLM\SOFTWARE\Microsoft\Cryptography\Defaults\Provider\Microsoft Strong Cryptographic Provider\Image Path - // SUCCESS Type: REG_SZ, Length: 66, Data: %SystemRoot%\system32\rsaenh.dll" - env.push(("SYSTEMROOT".into(), env::var_os("SYSTEMROOT").unwrap())); - } - - let current_dir = PathBuf::from(curdir.as_ref()); - - UCommand { - tmpd: None, - has_run: false, - args: vec![arg.as_ref().to_owned()], - env: env, - current_dir: current_dir, - - comm_string: String::from(arg.as_ref().to_str().unwrap()), - stdin: None, - } - } - - pub fn new_from_tmp>(arg: T, tmpd: Rc, env_clear: bool) -> UCommand { - let tmpd_path_buf = tmpd.as_ref().path().to_path_buf(); - let mut ucmd: UCommand = UCommand::new(arg.as_ref(), tmpd_path_buf, env_clear); - ucmd.tmpd = Some(tmpd); - ucmd - } - - pub fn arg>(&mut self, arg: S) -> &mut UCommand { - if self.has_run { - panic!(ALREADY_RUN); - } - let arg = arg.into(); - - self.comm_string.push_str(" "); - // FIXME: should never use to_str().unwrap() for args - self.comm_string.push_str(arg.to_str().unwrap()); - self.args.push(arg); - self - } - - /// like arg(...), but uses the contents of the file at the provided relative path as the argument - #[cfg(unix)] - pub fn arg_fixture>(&mut self, file_rel_path: S) -> &mut UCommand { - let contents = read_scenario_fixture(&self.tmpd, file_rel_path); - self.arg(OsString::from_vec(contents)) - } - - pub fn args>(&mut self, args: &[S]) -> &mut UCommand { - if self.has_run { - panic!(MULTIPLE_STDIN_MEANINGLESS); - } - for s in args { - let s = s.as_ref(); - - self.comm_string.push_str(" "); - // FIXME: don't use to_str() - self.comm_string.push_str(s.to_str().unwrap()); - self.args.push(s.to_owned()); - } - - self - } - - /// provides stdinput to feed in to the command when spawned - pub fn pipe_in>>(&mut self, input: T) -> &mut UCommand { - if self.stdin.is_some() { - panic!(MULTIPLE_STDIN_MEANINGLESS); - } - self.stdin = Some(input.into()); - self - } - - /// like pipe_in(...), but uses the contents of the file at the provided relative path as the piped in data - pub fn pipe_in_fixture>(&mut self, file_rel_path: S) -> &mut UCommand { - let contents = read_scenario_fixture(&self.tmpd, file_rel_path); - self.pipe_in(contents) - } - - pub fn env(&mut self, key: K, val: V) -> &mut UCommand - where - K: Into, - V: Into, - { - if self.has_run { - panic!(ALREADY_RUN); - } - self.env.push((key.into(), val.into())); - self - } - - /// Spawns the command, feeds the stdin if any, and returns the - /// child process immediately. - pub fn run_no_wait(&mut self) -> UChild { - if self.has_run { - panic!(ALREADY_RUN); - } - self.has_run = true; - log_info("run", &self.comm_string); - - let mut stdin = self.stdin.clone().unwrap_or_default(); - let current_dir = Some(self.current_dir.clone()); - let env = self.env.clone().into_iter(); - let args = self.args.clone().into_iter(); - - // FIXME: would be easier to use Vec, but not sure how to get this to work with sh at - // the moment - let mut stdin = tempfile::tempfile().unwrap(); - if let Some(input) = self.stdin.as_ref() { - stdin.write_all(input).unwrap(); - stdin.seek(SeekFrom::Start(0)); - } - - // FIXME: same issue - let stdout = tempfile::tempfile().unwrap(); - let stderr = tempfile::tempfile().unwrap(); - - let mut stdout_clone = stdout.try_clone().unwrap(); - let mut stderr_clone = stderr.try_clone().unwrap(); - UChild::new( - thread::spawn(move || { - let mut args = args; - let mut setup = UtilData::new( - &mut stdin, - &mut stdout_clone, - &mut stderr_clone, - env, - current_dir, - ); - mesabox::execute(&mut setup, &mut args) - }), - stdout, - stderr, - ) - } - - /// Spawns the command, feeds the stdin if any, waits for the result - /// and returns a command result. - /// It is recommended that you instead use succeeds() or fails() - pub fn run(&mut self) -> CmdResult { - let prog = self.run_no_wait().wait_with_output(); - - CmdResult { - tmpd: self.tmpd.clone(), - success: prog.success, - stdout: prog.stdout, - stderr: prog.stderr, - } - } - - /// Spawns the command, feeding the passed in stdin, waits for the result - /// and returns a command result. - /// It is recommended that, instead of this, you use a combination of pipe_in() - /// with succeeds() or fails() - pub fn run_piped_stdin>>(&mut self, input: T) -> CmdResult { - self.pipe_in(input).run() - } - - /// Spawns the command, feeds the stdin if any, waits for the result, - /// asserts success, and returns a command result. - pub fn succeeds(&mut self) -> CmdResult { - let cmd_result = self.run(); - cmd_result.success(); - cmd_result - } - - /// Spawns the command, feeds the stdin if any, waits for the result, - /// asserts success, and returns a command result. - pub fn fails(&mut self) -> CmdResult { - let cmd_result = self.run(); - cmd_result.failure(); - cmd_result - } - - pub fn command_str(&self) -> String { - let mut res = self.args.iter().fold(String::new(), |mut acc, s| { - acc.push_str(&s.to_string_lossy()); - acc.push(' '); - acc - }); - res.pop(); - res - } -} - -pub struct UChild { - handle: JoinHandle>, - stdout: File, - stderr: File, -} - -impl UChild { - pub fn new( - handle: JoinHandle>, - stdout: File, - stderr: File, - ) -> Self { - Self { - handle: handle, - stdout: stdout, - stderr: stderr, - } - } - - pub fn wait_with_output(mut self) -> UOutput { - let res = self.handle.join().unwrap(); - - let mut output = vec![]; - let mut error = vec![]; - - self.stdout.seek(SeekFrom::Start(0)).unwrap(); - self.stderr.seek(SeekFrom::Start(0)).unwrap(); - - self.stdout.read_to_end(&mut output).unwrap(); - self.stderr.read_to_end(&mut error).unwrap(); - - // FIXME: what to do with res? print error to stderr first? should this just be done in library? - if let Err(ref f) = res { - write!(error, "{}", f).unwrap(); - } - - UOutput { - success: res.map(|code| code == 0).unwrap_or(false), - stdout: output, - stderr: error, - } - } -} - -pub struct UOutput { - success: bool, - stdout: Vec, - stderr: Vec, -} - -// TODO: figure out a good way to do this -/* -pub fn read_size_string(child: &mut UChild, size: usize) -> String { - let output = read_size(child, size); - String::from_utf8(output).unwrap() -} - -pub fn read_size(child: &mut UChild, size: usize) -> Vec { - let mut output = vec![0; size]; - - // FIXME: if output is too slow this will cause issues - sleep(Duration::from_secs(1)); - - child - .stdout - .as_mut() - .unwrap() - .read_to_end(&mut output) - .unwrap(); - - output -} -*/