112a9d9c8Sopenharmony_ci//! An application to run property tests for `bindgen` with _fuzzed_ C headers
212a9d9c8Sopenharmony_ci//! using `quickcheck`
312a9d9c8Sopenharmony_ci//!
412a9d9c8Sopenharmony_ci//! ## Usage
512a9d9c8Sopenharmony_ci//!
612a9d9c8Sopenharmony_ci//! Print help
712a9d9c8Sopenharmony_ci//! ```bash
812a9d9c8Sopenharmony_ci//! $ cargo run --bin=quickchecking -- -h
912a9d9c8Sopenharmony_ci//! ```
1012a9d9c8Sopenharmony_ci//!
1112a9d9c8Sopenharmony_ci//! Run with default values
1212a9d9c8Sopenharmony_ci//! ```bash
1312a9d9c8Sopenharmony_ci//! $ cargo run --bin=quickchecking
1412a9d9c8Sopenharmony_ci//! ```
1512a9d9c8Sopenharmony_ci//!
1612a9d9c8Sopenharmony_ci#![deny(missing_docs)]
1712a9d9c8Sopenharmony_ciextern crate clap;
1812a9d9c8Sopenharmony_ciextern crate quickchecking;
1912a9d9c8Sopenharmony_ci
2012a9d9c8Sopenharmony_ciuse clap::{App, Arg};
2112a9d9c8Sopenharmony_ciuse std::path::Path;
2212a9d9c8Sopenharmony_ci
2312a9d9c8Sopenharmony_ci// Validate CLI argument input for generation range.
2412a9d9c8Sopenharmony_cifn validate_generate_range(v: String) -> Result<(), String> {
2512a9d9c8Sopenharmony_ci    match v.parse::<usize>() {
2612a9d9c8Sopenharmony_ci        Ok(_) => Ok(()),
2712a9d9c8Sopenharmony_ci        Err(_) => Err(String::from(
2812a9d9c8Sopenharmony_ci            "Generate range could not be converted to a usize.",
2912a9d9c8Sopenharmony_ci        )),
3012a9d9c8Sopenharmony_ci    }
3112a9d9c8Sopenharmony_ci}
3212a9d9c8Sopenharmony_ci
3312a9d9c8Sopenharmony_ci// Validate CLI argument input for tests count.
3412a9d9c8Sopenharmony_cifn validate_tests_count(v: String) -> Result<(), String> {
3512a9d9c8Sopenharmony_ci    match v.parse::<usize>() {
3612a9d9c8Sopenharmony_ci        Ok(_) => Ok(()),
3712a9d9c8Sopenharmony_ci        Err(_) => Err(String::from(
3812a9d9c8Sopenharmony_ci            "Tests count could not be converted to a usize.",
3912a9d9c8Sopenharmony_ci        )),
4012a9d9c8Sopenharmony_ci    }
4112a9d9c8Sopenharmony_ci}
4212a9d9c8Sopenharmony_ci
4312a9d9c8Sopenharmony_ci// Validate CLI argument input for fuzzed headers output path.
4412a9d9c8Sopenharmony_cifn validate_path(v: String) -> Result<(), String> {
4512a9d9c8Sopenharmony_ci    match Path::new(&v).is_dir() {
4612a9d9c8Sopenharmony_ci        true => Ok(()),
4712a9d9c8Sopenharmony_ci        false => Err(String::from("Provided directory path does not exist.")),
4812a9d9c8Sopenharmony_ci    }
4912a9d9c8Sopenharmony_ci}
5012a9d9c8Sopenharmony_ci
5112a9d9c8Sopenharmony_cifn main() {
5212a9d9c8Sopenharmony_ci    let matches = App::new("quickchecking")
5312a9d9c8Sopenharmony_ci        .version("0.2.0")
5412a9d9c8Sopenharmony_ci        .about(
5512a9d9c8Sopenharmony_ci            "Bindgen property tests with quickcheck. \
5612a9d9c8Sopenharmony_ci             Generate random valid C code and pass it to the \
5712a9d9c8Sopenharmony_ci             csmith/predicate.py script",
5812a9d9c8Sopenharmony_ci        )
5912a9d9c8Sopenharmony_ci        .arg(
6012a9d9c8Sopenharmony_ci            Arg::with_name("path")
6112a9d9c8Sopenharmony_ci                .short("p")
6212a9d9c8Sopenharmony_ci                .long("path")
6312a9d9c8Sopenharmony_ci                .value_name("PATH")
6412a9d9c8Sopenharmony_ci                .help(
6512a9d9c8Sopenharmony_ci                    "Optional. Preserve generated headers for inspection, \
6612a9d9c8Sopenharmony_ci                     provide directory path for header output. [default: None] ",
6712a9d9c8Sopenharmony_ci                )
6812a9d9c8Sopenharmony_ci                .takes_value(true)
6912a9d9c8Sopenharmony_ci                .validator(validate_path),
7012a9d9c8Sopenharmony_ci        )
7112a9d9c8Sopenharmony_ci        .arg(
7212a9d9c8Sopenharmony_ci            Arg::with_name("range")
7312a9d9c8Sopenharmony_ci                .short("r")
7412a9d9c8Sopenharmony_ci                .long("range")
7512a9d9c8Sopenharmony_ci                .value_name("RANGE")
7612a9d9c8Sopenharmony_ci                .help(
7712a9d9c8Sopenharmony_ci                    "Sets the range quickcheck uses during generation. \
7812a9d9c8Sopenharmony_ci                     Corresponds to things like arbitrary usize and \
7912a9d9c8Sopenharmony_ci                     arbitrary vector length. This number doesn't have \
8012a9d9c8Sopenharmony_ci                     to grow much for execution time to increase \
8112a9d9c8Sopenharmony_ci                     significantly.",
8212a9d9c8Sopenharmony_ci                )
8312a9d9c8Sopenharmony_ci                .takes_value(true)
8412a9d9c8Sopenharmony_ci                .default_value("32")
8512a9d9c8Sopenharmony_ci                .validator(validate_generate_range),
8612a9d9c8Sopenharmony_ci        )
8712a9d9c8Sopenharmony_ci        .arg(
8812a9d9c8Sopenharmony_ci            Arg::with_name("count")
8912a9d9c8Sopenharmony_ci                .short("c")
9012a9d9c8Sopenharmony_ci                .long("count")
9112a9d9c8Sopenharmony_ci                .value_name("COUNT")
9212a9d9c8Sopenharmony_ci                .help(
9312a9d9c8Sopenharmony_ci                    "Count / number of tests to run. Running a fuzzed \
9412a9d9c8Sopenharmony_ci                     header through the predicate.py script can take a \
9512a9d9c8Sopenharmony_ci                     long time, especially if the generation range is \
9612a9d9c8Sopenharmony_ci                     large. Increase this number if you're willing to \
9712a9d9c8Sopenharmony_ci                     wait a while.",
9812a9d9c8Sopenharmony_ci                )
9912a9d9c8Sopenharmony_ci                .takes_value(true)
10012a9d9c8Sopenharmony_ci                .default_value("2")
10112a9d9c8Sopenharmony_ci                .validator(validate_tests_count),
10212a9d9c8Sopenharmony_ci        )
10312a9d9c8Sopenharmony_ci        .get_matches();
10412a9d9c8Sopenharmony_ci
10512a9d9c8Sopenharmony_ci    let output_path: Option<&str> = matches.value_of("path");
10612a9d9c8Sopenharmony_ci    let generate_range: usize =
10712a9d9c8Sopenharmony_ci        matches.value_of("range").unwrap().parse::<usize>().unwrap();
10812a9d9c8Sopenharmony_ci    let tests: usize =
10912a9d9c8Sopenharmony_ci        matches.value_of("count").unwrap().parse::<usize>().unwrap();
11012a9d9c8Sopenharmony_ci
11112a9d9c8Sopenharmony_ci    quickchecking::test_bindgen(generate_range, tests, output_path)
11212a9d9c8Sopenharmony_ci}
113