summaryrefslogtreecommitdiff
path: root/bindgen-tests/tests/quickchecking/src/bin.rs
blob: 7c189ee886ff23a66a26bcae85f32fafd6d4ecde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! An application to run property tests for `bindgen` with _fuzzed_ C headers
//! using `quickcheck`
//!
//! ## Usage
//!
//! Print help
//! ```bash
//! $ cargo run --bin=quickchecking -- -h
//! ```
//!
//! Run with default values
//! ```bash
//! $ cargo run --bin=quickchecking
//! ```
//!
#![deny(missing_docs)]
extern crate clap;
extern crate quickchecking;

use clap::{App, Arg};
use std::path::Path;

// Validate CLI argument input for generation range.
fn validate_generate_range(v: String) -> Result<(), String> {
    match v.parse::<usize>() {
        Ok(_) => Ok(()),
        Err(_) => Err(String::from(
            "Generate range could not be converted to a usize.",
        )),
    }
}

// Validate CLI argument input for tests count.
fn validate_tests_count(v: String) -> Result<(), String> {
    match v.parse::<usize>() {
        Ok(_) => Ok(()),
        Err(_) => Err(String::from(
            "Tests count could not be converted to a usize.",
        )),
    }
}

// Validate CLI argument input for fuzzed headers output path.
fn validate_path(v: String) -> Result<(), String> {
    match Path::new(&v).is_dir() {
        true => Ok(()),
        false => Err(String::from("Provided directory path does not exist.")),
    }
}

fn main() {
    let matches = App::new("quickchecking")
        .version("0.2.0")
        .about(
            "Bindgen property tests with quickcheck. \
             Generate random valid C code and pass it to the \
             csmith/predicate.py script",
        )
        .arg(
            Arg::with_name("path")
                .short("p")
                .long("path")
                .value_name("PATH")
                .help(
                    "Optional. Preserve generated headers for inspection, \
                     provide directory path for header output. [default: None] ",
                )
                .takes_value(true)
                .validator(validate_path),
        )
        .arg(
            Arg::with_name("range")
                .short("r")
                .long("range")
                .value_name("RANGE")
                .help(
                    "Sets the range quickcheck uses during generation. \
                     Corresponds to things like arbitrary usize and \
                     arbitrary vector length. This number doesn't have \
                     to grow much for execution time to increase \
                     significantly.",
                )
                .takes_value(true)
                .default_value("32")
                .validator(validate_generate_range),
        )
        .arg(
            Arg::with_name("count")
                .short("c")
                .long("count")
                .value_name("COUNT")
                .help(
                    "Count / number of tests to run. Running a fuzzed \
                     header through the predicate.py script can take a \
                     long time, especially if the generation range is \
                     large. Increase this number if you're willing to \
                     wait a while.",
                )
                .takes_value(true)
                .default_value("2")
                .validator(validate_tests_count),
        )
        .get_matches();

    let output_path: Option<&str> = matches.value_of("path");
    let generate_range: usize =
        matches.value_of("range").unwrap().parse::<usize>().unwrap();
    let tests: u64 = matches.value_of("count").unwrap().parse::<u64>().unwrap();

    quickchecking::test_bindgen(generate_range, tests, output_path)
}