From b067513aa48fa8f1d40d7d626c4471ad93763026 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Thu, 6 Oct 2022 19:47:06 -0400 Subject: [PATCH] Add cli tests --- Cargo.lock | 107 +++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/bin/cargo-afl.rs | 138 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 245 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 101fe58f4..02ff5a5af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ name = "afl" version = "0.12.8" dependencies = [ "arbitrary", + "assert_cmd", "clap", "fs_extra", "lazy_static", @@ -25,6 +26,20 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "assert_cmd" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e" +dependencies = [ + "bstr", + "doc-comment", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + [[package]] name = "atty" version = "0.2.14" @@ -42,6 +57,17 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -82,6 +108,12 @@ dependencies = [ "syn", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "dirs" version = "4.0.0" @@ -102,6 +134,18 @@ dependencies = [ "winapi", ] +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + [[package]] name = "fastrand" version = "1.8.0" @@ -146,6 +190,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -158,6 +211,12 @@ version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "once_cell" version = "1.13.1" @@ -170,6 +229,33 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "predicates" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c" +dependencies = [ + "difflib", + "itertools", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb" + +[[package]] +name = "predicates-tree" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "proc-macro2" version = "1.0.43" @@ -208,6 +294,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -272,6 +364,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" + [[package]] name = "thiserror" version = "1.0.33" @@ -298,6 +396,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index d9dc5168c..87832386e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ xdg = "2.4" [dev-dependencies] arbitrary = { version = "1", features = ["derive"] } +assert_cmd = "2.0" tempfile = "3.3" [features] diff --git a/src/bin/cargo-afl.rs b/src/bin/cargo-afl.rs index d1c7e9110..f3e63fe0f 100644 --- a/src/bin/cargo-afl.rs +++ b/src/bin/cargo-afl.rs @@ -430,12 +430,148 @@ fn is_nightly() -> bool { .success() } -#[cfg(test)] +#[cfg(all(test, unix))] mod tests { use super::*; + use assert_cmd::Command; + use std::os::unix::ffi::OsStringExt; #[test] fn test_app() { clap_app().debug_assert(); } + + #[test] + fn display_name() { + assert!( + String::from_utf8(cargo_afl(&["-V"]).output().unwrap().stdout) + .unwrap() + .starts_with("cargo-afl") + ); + } + + #[test] + fn afl_required_else_help() { + assert_eq!( + String::from_utf8(command().arg("--help").output().unwrap().stdout).unwrap(), + String::from_utf8(command().output().unwrap().stderr).unwrap() + ); + } + + #[test] + fn subcommand_required_else_help() { + assert_eq!( + String::from_utf8(cargo_afl(&["--help"]).output().unwrap().stdout).unwrap(), + String::from_utf8(cargo_afl::<&OsStr>(&[]).output().unwrap().stderr).unwrap() + ); + } + + #[test] + fn external_subcommands_allow_invalid_utf8() { + let _arg_matches = clap_app() + .try_get_matches_from(&[ + OsStr::new("cargo"), + OsStr::new("afl"), + OsStr::new("test"), + &invalid_utf8(), + ]) + .unwrap(); + } + + const SUBCOMMANDS: &[&str] = &[ + "analyze", "cmin", "fuzz", "gotcpu", "plot", "showmap", "tmin", "whatsup", + ]; + + #[test] + fn subcommands_allow_invalid_utf8() { + for &subcommand in SUBCOMMANDS.iter() { + let _arg_matches = clap_app() + .try_get_matches_from(&[ + OsStr::new("cargo"), + OsStr::new("afl"), + OsStr::new(subcommand), + &invalid_utf8(), + ]) + .unwrap(); + } + } + + #[test] + fn subcommands_allow_hyphen_values() { + for &subcommand in SUBCOMMANDS.iter() { + let _arg_matches = clap_app() + .try_get_matches_from(&["cargo", "afl", subcommand, "-i", "--input"]) + .unwrap(); + } + } + + #[test] + fn subcommands_help_subcommand_disabled() { + assert!( + String::from_utf8(cargo_afl(&["help"]).output().unwrap().stdout) + .unwrap() + .starts_with("Usage:") + ); + + for &subcommand in SUBCOMMANDS.iter() { + assert!( + !String::from_utf8(cargo_afl(&[subcommand, "help"]).output().unwrap().stdout) + .unwrap() + .starts_with("Usage:") + ); + } + } + + #[test] + fn subcommands_help_flag_disabled() { + assert!( + String::from_utf8(cargo_afl(&["--help"]).output().unwrap().stdout) + .unwrap() + .starts_with("Usage:") + ); + + for &subcommand in SUBCOMMANDS.iter() { + assert!(!String::from_utf8( + cargo_afl(&[subcommand, "--help"]).output().unwrap().stdout + ) + .unwrap() + .starts_with("Usage:")); + } + } + + #[test] + fn subcommands_version_flag_disabled() { + assert!( + String::from_utf8(cargo_afl(&["-V"]).output().unwrap().stdout) + .unwrap() + .starts_with("cargo-afl") + ); + + for &subcommand in SUBCOMMANDS.iter() { + assert!( + !String::from_utf8(cargo_afl(&[subcommand, "-V"]).output().unwrap().stdout) + .unwrap() + .starts_with("cargo-afl") + ); + } + } + + fn cargo_afl>(args: &[T]) -> Command { + let mut command = command(); + command.arg("afl").args(args); + command + } + + fn command() -> Command { + Command::cargo_bin("cargo-afl").unwrap() + } + + fn invalid_utf8() -> OsString { + OsString::from_vec(vec![0xfe]) + } + + #[test] + fn invalid_utf8_is_invalid() { + assert!(String::from_utf8(invalid_utf8().into_vec()).is_err()); + } }