1 //! An application to run property tests for `bindgen` with _fuzzed_ C headers
2 //! using `quickcheck`
3 //!
4 //! ## Usage
5 //!
6 //! Print help
7 //! ```bash
8 //! $ cargo run --bin=quickchecking -- -h
9 //! ```
10 //!
11 //! Run with default values
12 //! ```bash
13 //! $ cargo run --bin=quickchecking
14 //! ```
15 //!
16 #![deny(missing_docs)]
17 extern crate clap;
18 extern crate quickchecking;
19
20 use clap::{App, Arg};
21 use std::path::Path;
22
23 // Validate CLI argument input for generation range.
validate_generate_range(v: String) -> Result<(), String>24 fn validate_generate_range(v: String) -> Result<(), String> {
25 match v.parse::<usize>() {
26 Ok(_) => Ok(()),
27 Err(_) => Err(String::from(
28 "Generate range could not be converted to a usize.",
29 )),
30 }
31 }
32
33 // Validate CLI argument input for tests count.
validate_tests_count(v: String) -> Result<(), String>34 fn validate_tests_count(v: String) -> Result<(), String> {
35 match v.parse::<usize>() {
36 Ok(_) => Ok(()),
37 Err(_) => Err(String::from(
38 "Tests count could not be converted to a usize.",
39 )),
40 }
41 }
42
43 // Validate CLI argument input for fuzzed headers output path.
validate_path(v: String) -> Result<(), String>44 fn validate_path(v: String) -> Result<(), String> {
45 match Path::new(&v).is_dir() {
46 true => Ok(()),
47 false => Err(String::from("Provided directory path does not exist.")),
48 }
49 }
50
main()51 fn main() {
52 let matches = App::new("quickchecking")
53 .version("0.2.0")
54 .about(
55 "Bindgen property tests with quickcheck. \
56 Generate random valid C code and pass it to the \
57 csmith/predicate.py script",
58 )
59 .arg(
60 Arg::with_name("path")
61 .short("p")
62 .long("path")
63 .value_name("PATH")
64 .help(
65 "Optional. Preserve generated headers for inspection, \
66 provide directory path for header output. [default: None] ",
67 )
68 .takes_value(true)
69 .validator(validate_path),
70 )
71 .arg(
72 Arg::with_name("range")
73 .short("r")
74 .long("range")
75 .value_name("RANGE")
76 .help(
77 "Sets the range quickcheck uses during generation. \
78 Corresponds to things like arbitrary usize and \
79 arbitrary vector length. This number doesn't have \
80 to grow much for execution time to increase \
81 significantly.",
82 )
83 .takes_value(true)
84 .default_value("32")
85 .validator(validate_generate_range),
86 )
87 .arg(
88 Arg::with_name("count")
89 .short("c")
90 .long("count")
91 .value_name("COUNT")
92 .help(
93 "Count / number of tests to run. Running a fuzzed \
94 header through the predicate.py script can take a \
95 long time, especially if the generation range is \
96 large. Increase this number if you're willing to \
97 wait a while.",
98 )
99 .takes_value(true)
100 .default_value("2")
101 .validator(validate_tests_count),
102 )
103 .get_matches();
104
105 let output_path: Option<&str> = matches.value_of("path");
106 let generate_range: usize =
107 matches.value_of("range").unwrap().parse::<usize>().unwrap();
108 let tests: usize =
109 matches.value_of("count").unwrap().parse::<usize>().unwrap();
110
111 quickchecking::test_bindgen(generate_range, tests, output_path)
112 }
113