diff options
Diffstat (limited to 'tests/quickchecking/src')
-rw-r--r-- | tests/quickchecking/src/bin.rs | 110 | ||||
-rw-r--r-- | tests/quickchecking/src/fuzzers.rs | 637 | ||||
-rw-r--r-- | tests/quickchecking/src/lib.rs | 126 |
3 files changed, 0 insertions, 873 deletions
diff --git a/tests/quickchecking/src/bin.rs b/tests/quickchecking/src/bin.rs deleted file mode 100644 index d2774eb0..00000000 --- a/tests/quickchecking/src/bin.rs +++ /dev/null @@ -1,110 +0,0 @@ -//! 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: usize = matches.value_of("count").unwrap().parse::<usize>().unwrap(); - - quickchecking::test_bindgen(generate_range, tests, output_path) -} diff --git a/tests/quickchecking/src/fuzzers.rs b/tests/quickchecking/src/fuzzers.rs deleted file mode 100644 index 7c764425..00000000 --- a/tests/quickchecking/src/fuzzers.rs +++ /dev/null @@ -1,637 +0,0 @@ -use quickcheck::{Arbitrary, Gen, StdGen}; -use std::fmt; -use rand::thread_rng; - -/// BaseTypeC is used in generation of C headers to represent the C language's -/// primitive types as well as `void*`. -#[derive(Debug, Clone)] -pub struct BaseTypeC { - /// String representation of C type. - pub def: String, -} - -/// TypeQualifierC is used in generation of C headers to represent qualifiers -/// such as `const`. -#[derive(Debug, Clone)] -pub struct TypeQualifierC { - /// String representation of C type qualifier. - pub def: String, -} - -/// PointerLevelC is used in generation of C headers to represent number of -/// `*` for pointer types. -#[derive(Debug, Clone)] -pub struct PointerLevelC { - /// String representation of C declaration's pointer level. - pub def: String, -} - -/// ArrayDimensionC is used in generation of C headers to represent number of -/// `[]` used to define array types. -#[derive(Debug, Clone)] -pub struct ArrayDimensionC { - /// String representation of C declaration's array dimension. - pub def: String, -} - -/// BasicTypeDeclarationC is used in generation of C headers to represent -/// declarations outside of function pointers that take the form -/// `BaseTypeC` + `TypeQualifierC` + `PointerLevelC` + `ident_id`. -#[derive(Debug, Clone)] -pub struct BasicTypeDeclarationC { - /// The declaration's base type, i.e. `int`. - pub type_name: BaseTypeC, - /// The declaration's type qualifier, i.e. `const`. - pub type_qualifier: TypeQualifierC, - /// The declaration's pointer level, i.e. `***`. - pub pointer_level: PointerLevelC, - /// The declaration's array dimension, i.e. [][][]. - pub array_dimension: ArrayDimensionC, - /// The declaration's identifier, i.e. ident_N. - pub ident_id: String, -} - -/// StructDeclarationC is used in generation of C headers to represent the -/// definition of a struct type. -#[derive(Debug, Clone)] -pub struct StructDeclarationC { - /// The declaration's fields. - pub fields: DeclarationListC, - /// The declaration's array dimension, i.e. [][][]. - pub array_dimension: ArrayDimensionC, - /// The declaration's identifier, i.e. struct_N. - pub ident_id: String, -} - -/// UnionDeclarationC is used in generation of C headers to represent the -/// definition of a union type. -#[derive(Debug, Clone)] -pub struct UnionDeclarationC { - /// The declaration's fields. - pub fields: DeclarationListC, - /// The declaration's array dimension, i.e. [][][]. - pub array_dimension: ArrayDimensionC, - /// The declaration's identifier, i.e. union_N. - pub ident_id: String, -} - -/// FunctionPointerDeclarationC is used in generation of C headers to represent -/// the definition of a function pointer type. -#[derive(Debug, Clone)] -pub struct FunctionPointerDeclarationC { - /// The function's type qualifier, i.e. `const`. - pub type_qualifier: TypeQualifierC, - /// The function's return type, i.e. `int`. - pub type_name: BaseTypeC, - /// The function's pointer level, i.e. `***`. - pub pointer_level: PointerLevelC, - /// The function's parameters. - pub params: ParameterListC, - /// The declaration's identifier, i.e. func_ptr_N. - pub ident_id: String, -} - -/// FunctionPrototypeC is used in generation of C headers to represent the -/// definition of a function prototype. -#[derive(Debug, Clone)] -pub struct FunctionPrototypeC { - /// The function's type qualifier, i.e. `const`. - pub type_qualifier: TypeQualifierC, - /// The function's return type, i.e. `int`. - pub type_name: BaseTypeC, - /// The function's pointer level, i.e. `***`. - pub pointer_level: PointerLevelC, - /// The function's parameters. - pub params: ParameterListC, - /// The prototype's identifier, i.e. `func_N`. - pub ident_id: String, -} - -/// ParameterC is used in generation of C headers to represent the -/// definition function parameters. -#[derive(Debug, Clone)] -pub struct ParameterC { - /// The parameter's type qualifier, i.e. `const`. - pub type_qualifier: TypeQualifierC, - /// The parameter's base type, i.e. `int`. - pub type_name: BaseTypeC, - /// The parameter's pointer level, i.e. `***`. - pub pointer_level: PointerLevelC, -} - -/// ParameterListC is used in generation of C headers to represent a list of -/// definitions of function parameters. -#[derive(Debug, Clone)] -pub struct ParameterListC { - /// Parameters that define a C function signature. - pub params: Vec<ParameterC>, -} - -/// DeclarationC is used in generation of C headers to represent all supported -/// C type declarations allowed in the generated header. -#[derive(Debug, Clone)] -pub enum DeclarationC { - /// Function prototype declaration kind. - FunctionDecl(FunctionPrototypeC), - /// Function pointer declaration kind. - FunctionPtrDecl(FunctionPointerDeclarationC), - /// Struct declaration kind. - StructDecl(StructDeclarationC), - /// Union declaration kind. - UnionDecl(UnionDeclarationC), - /// Basic type declaration kind. - VariableDecl(BasicTypeDeclarationC), -} - -/// DeclarationListC is used in generation of C headers to represent a list of -/// declarations. -#[derive(Debug, Clone)] -pub struct DeclarationListC { - /// Grouping of C declarations. - pub decls: Vec<DeclarationC>, -} - -/// HeaderC is used in generation of C headers to represent a collection of -/// declarations. -#[derive(Clone)] -pub struct HeaderC { - /// The header's declarations. - pub def: DeclarationListC, -} - -/// MakeUnique is used in generation of C headers to make declaration -/// identifiers unique by incorporating the `stamp` parameter into it's name. -trait MakeUnique { - fn make_unique(&mut self, stamp: usize); -} - -/// MakeUnique is used in generation of C headers to make DeclarationC -/// identifiers unique. -impl MakeUnique for DeclarationC { - fn make_unique(&mut self, stamp: usize) { - match *self { - DeclarationC::FunctionDecl(ref mut d) => d.make_unique(stamp), - DeclarationC::FunctionPtrDecl(ref mut d) => d.make_unique(stamp), - DeclarationC::StructDecl(ref mut d) => d.make_unique(stamp), - DeclarationC::UnionDecl(ref mut d) => d.make_unique(stamp), - DeclarationC::VariableDecl(ref mut d) => d.make_unique(stamp), - } - } -} - -/// A qucickcheck trait for describing how DeclarationC types can be -/// randomly generated and shrunk. -impl Arbitrary for DeclarationC { - fn arbitrary<G: Gen>(g: &mut G) -> DeclarationC { - match g.gen_range(0, 5) { - 0 => DeclarationC::FunctionDecl(FunctionPrototypeC::arbitrary(g)), - 1 => DeclarationC::FunctionPtrDecl(FunctionPointerDeclarationC::arbitrary(g)), - 2 => DeclarationC::StructDecl(StructDeclarationC::arbitrary(g)), - 3 => DeclarationC::UnionDecl(UnionDeclarationC::arbitrary(g)), - 4 => DeclarationC::VariableDecl(BasicTypeDeclarationC::arbitrary(g)), - _ => unreachable!(), - } - } -} - -/// Enables to string and format for DeclarationC types. -impl fmt::Display for DeclarationC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - DeclarationC::FunctionPtrDecl(ref d) => write!(f, "{}", d), - DeclarationC::StructDecl(ref d) => write!(f, "{}", d), - DeclarationC::UnionDecl(ref d) => write!(f, "{}", d), - DeclarationC::VariableDecl(ref d) => write!(f, "{}", d), - DeclarationC::FunctionDecl(ref d) => write!(f, "{}", d), - } - } -} - -/// A qucickcheck trait for describing how DeclarationListC types can be -/// randomly generated and shrunk. -impl Arbitrary for DeclarationListC { - fn arbitrary<G: Gen>(g: &mut G) -> DeclarationListC { - DeclarationListC { - decls: Arbitrary::arbitrary(g), - } - } -} - -/// Enables to string and format for DeclarationListC types. -impl fmt::Display for DeclarationListC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut display = String::new(); - for decl in &self.decls { - display += &format!("{}", decl); - } - write!(f, "{}", display) - } -} - -/// A qucickcheck trait for describing how BaseTypeC types can be -/// randomly generated and shrunk. -impl Arbitrary for BaseTypeC { - fn arbitrary<G: Gen>(g: &mut G) -> BaseTypeC { - // Special case `long double` until issue #550 is resolved. - let base_type = vec![ - "char", - "signed char", - "unsigned char", - "short", - "short int", - "signed short", - "signed short int", - "unsigned short", - "unsigned short int", - "int", - "signed", - "signed int", - "unsigned", - "unsigned int", - "long", - "long int", - "signed long", - "signed long int", - "unsigned long", - "unsigned long int", - "long long", - "long long int", - "signed long long", - "signed long long int", - "unsigned long long", - "unsigned long long int", - "float", - "double", - #[cfg(feature = "long-doubles")] - "long double", - "void*", - ]; - BaseTypeC { - def: String::from(*g.choose(&base_type).unwrap()), - } - } -} - -/// Enables to string and format for BaseTypeC types, -impl fmt::Display for BaseTypeC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.def) - } -} - -/// A qucickcheck trait for describing how TypeQualifierC types can be -/// randomly generated and shrunk. -impl Arbitrary for TypeQualifierC { - fn arbitrary<G: Gen>(g: &mut G) -> TypeQualifierC { - let qualifier = vec!["const", ""]; - TypeQualifierC { - def: String::from(*g.choose(&qualifier).unwrap()), - } - } -} - -/// Enables to string and format for TypeQualifierC types. -impl fmt::Display for TypeQualifierC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.def) - } -} - -/// A qucickcheck trait for describing how PointerLevelC types can be -/// randomly generated and shrunk. -impl Arbitrary for PointerLevelC { - fn arbitrary<G: Gen>(g: &mut G) -> PointerLevelC { - PointerLevelC { - // 16 is an arbitrary "not too big" number for capping pointer level. - def: (0..g.gen_range(0, 16)).map(|_| "*").collect::<String>(), - } - } -} - -/// Enables to string and format for PointerLevelC types. -impl fmt::Display for PointerLevelC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.def) - } -} - -/// A qucickcheck trait for describing how ArrayDimensionC types can be -/// randomly generated and shrunk. -impl Arbitrary for ArrayDimensionC { - fn arbitrary<G: Gen>(g: &mut G) -> ArrayDimensionC { - // Keep these small, clang complains when they get too big. - let dimensions = g.gen_range(0, 5); - let mut def = String::new(); - - let lower_bound; - if cfg!(feature = "zero-sized-arrays") { - lower_bound = 0; - } else { - lower_bound = 1; - } - - for _ in 1..dimensions { - // 16 is an arbitrary "not too big" number for capping array size. - def += &format!("[{}]", g.gen_range(lower_bound, 16)); - } - ArrayDimensionC { def } - } -} - -/// Enables to string and format for ArrayDimensionC types. -impl fmt::Display for ArrayDimensionC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.def) - } -} - -/// MakeUnique is used in generation of C headers to make BasicTypeDeclarationC -/// identifiers unique. -impl MakeUnique for BasicTypeDeclarationC { - fn make_unique(&mut self, stamp: usize) { - self.ident_id += &format!("_{}", stamp); - } -} - -/// A qucickcheck trait for describing how BasicTypeDeclarationC types can be -/// randomly generated and shrunk. -impl Arbitrary for BasicTypeDeclarationC { - fn arbitrary<G: Gen>(g: &mut G) -> BasicTypeDeclarationC { - BasicTypeDeclarationC { - type_qualifier: Arbitrary::arbitrary(g), - type_name: Arbitrary::arbitrary(g), - pointer_level: Arbitrary::arbitrary(g), - array_dimension: Arbitrary::arbitrary(g), - ident_id: format!("{}", usize::arbitrary(g)), - } - } -} - -/// Enables to string and format for BasicTypeDeclarationC types. -impl fmt::Display for BasicTypeDeclarationC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {} ident_{}{};", - self.type_qualifier, - self.type_name, - self.pointer_level, - self.ident_id, - self.array_dimension - ) - } -} - -/// MakeUnique is used in generation of C headers to make StructDeclarationC -/// identifiers unique. -impl MakeUnique for StructDeclarationC { - fn make_unique(&mut self, stamp: usize) { - self.ident_id += &format!("_{}", stamp); - } -} - -/// A qucickcheck trait for describing how StructDeclarationC types can be -/// randomly generated and shrunk. -impl Arbitrary for StructDeclarationC { - fn arbitrary<G: Gen>(g: &mut G) -> StructDeclarationC { - // Reduce generator size as a method of putting a bound on recursion. - // When size < 1 the empty list is generated. - let reduced_size: usize = (g.size() / 2) as usize + 1; - let mut decl_list: DeclarationListC = - Arbitrary::arbitrary(&mut StdGen::new(thread_rng(), reduced_size)); - let mut fields: DeclarationListC = DeclarationListC { decls: vec![] }; - - for (i, decl) in decl_list.decls.iter_mut().enumerate() { - match *decl { - DeclarationC::FunctionDecl(_) => {} - ref mut decl => { - decl.make_unique(i); - fields.decls.push(decl.clone()); - } - } - } - - StructDeclarationC { - fields, - ident_id: format!("{}", usize::arbitrary(g)), - array_dimension: Arbitrary::arbitrary(g), - } - } -} - -/// Enables to string and format for StructDeclarationC types. -impl fmt::Display for StructDeclarationC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "struct {{ {} }} struct_{}{};", - self.fields, - self.ident_id, - self.array_dimension - ) - } -} - -/// MakeUnique is used in generation of C headers to make UnionDeclarationC -/// identifiers unique. -impl MakeUnique for UnionDeclarationC { - fn make_unique(&mut self, stamp: usize) { - self.ident_id += &format!("_{}", stamp); - } -} - -/// A qucickcheck trait for describing how UnionDeclarationC types can be -/// randomly generated and shrunk. -impl Arbitrary for UnionDeclarationC { - fn arbitrary<G: Gen>(g: &mut G) -> UnionDeclarationC { - // Reduce generator size as a method of putting a bound on recursion. - // When size < 1 the empty list is generated. - let reduced_size: usize = (g.size() / 2) as usize + 1; - let mut decl_list: DeclarationListC = - Arbitrary::arbitrary(&mut StdGen::new(thread_rng(), reduced_size)); - let mut fields: DeclarationListC = DeclarationListC { decls: vec![] }; - - for (i, decl) in decl_list.decls.iter_mut().enumerate() { - match *decl { - DeclarationC::FunctionDecl(_) => {} - ref mut decl => { - decl.make_unique(i); - fields.decls.push(decl.clone()); - } - } - } - - UnionDeclarationC { - fields, - ident_id: format!("{}", usize::arbitrary(g)), - array_dimension: Arbitrary::arbitrary(g), - } - } -} - -/// Enables to string and format for UnionDeclarationC types. -impl fmt::Display for UnionDeclarationC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "union {{ {} }} union_{}{};", - self.fields, - self.ident_id, - self.array_dimension - ) - } -} - -/// MakeUnique is used in generation of C headers to make -/// FunctionPointerDeclarationC identifiers unique. -impl MakeUnique for FunctionPointerDeclarationC { - fn make_unique(&mut self, stamp: usize) { - self.ident_id += &format!("_{}", stamp); - } -} - -/// A qucickcheck trait for describing how FunctionPointerDeclarationC types can -/// be randomly generated and shrunk. -impl Arbitrary for FunctionPointerDeclarationC { - fn arbitrary<G: Gen>(g: &mut G) -> FunctionPointerDeclarationC { - FunctionPointerDeclarationC { - type_qualifier: Arbitrary::arbitrary(g), - type_name: Arbitrary::arbitrary(g), - pointer_level: Arbitrary::arbitrary(g), - params: Arbitrary::arbitrary(g), - ident_id: format!("{}", usize::arbitrary(g)), - } - } -} - -/// Enables to string and format for FunctionPointerDeclarationC types. -impl fmt::Display for FunctionPointerDeclarationC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {} (*func_ptr_{})({});", - self.type_qualifier, - self.type_name, - self.pointer_level, - self.ident_id, - self.params - ) - } -} - -/// MakeUnique is used in generation of C headers to make FunctionPrototypeC -/// identifiers unique. -impl MakeUnique for FunctionPrototypeC { - fn make_unique(&mut self, stamp: usize) { - self.ident_id += &format!("_{}", stamp); - } -} - -/// A qucickcheck trait for describing how FunctionPrototypeC types can be -/// randomly generated and shrunk. -impl Arbitrary for FunctionPrototypeC { - fn arbitrary<G: Gen>(g: &mut G) -> FunctionPrototypeC { - FunctionPrototypeC { - type_qualifier: Arbitrary::arbitrary(g), - type_name: Arbitrary::arbitrary(g), - pointer_level: Arbitrary::arbitrary(g), - params: Arbitrary::arbitrary(g), - ident_id: format!("{}", usize::arbitrary(g)), - } - } -} - -/// Enables to string and format for FunctionPrototypeC types. -impl fmt::Display for FunctionPrototypeC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {} func_{}({});", - self.type_qualifier, - self.type_name, - self.pointer_level, - self.ident_id, - self.params - ) - } -} - -/// A qucickcheck trait for describing how ParameterC types can be -/// randomly generated and shrunk. -impl Arbitrary for ParameterC { - fn arbitrary<G: Gen>(g: &mut G) -> ParameterC { - ParameterC { - type_qualifier: Arbitrary::arbitrary(g), - type_name: Arbitrary::arbitrary(g), - pointer_level: Arbitrary::arbitrary(g), - } - } -} - -/// Enables to string and format for ParameterC types. -impl fmt::Display for ParameterC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {}", - self.type_qualifier, - self.type_name, - self.pointer_level - ) - } -} - -/// A qucickcheck trait for describing how ParameterListC types can be -/// randomly generated and shrunk. -impl Arbitrary for ParameterListC { - fn arbitrary<G: Gen>(g: &mut G) -> ParameterListC { - ParameterListC { - params: Arbitrary::arbitrary(g), - } - } -} - -/// Enables to string and format for ParameterListC types. -impl fmt::Display for ParameterListC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut display = String::new(); - for (i, p) in self.params.iter().enumerate() { - match i { - 0 => display += &format!("{}", p), - _ => display += &format!(",{}", p), - } - } - write!(f, "{}", display) - } -} - -/// A qucickcheck trait for describing how HeaderC types can be -/// randomly generated and shrunk. -impl Arbitrary for HeaderC { - fn arbitrary<G: Gen>(g: &mut G) -> HeaderC { - let mut decl_list: DeclarationListC = Arbitrary::arbitrary(g); - for (i, decl) in decl_list.decls.iter_mut().enumerate() { - decl.make_unique(i); - } - HeaderC { def: decl_list } - } -} - -/// Enables to string and format for HeaderC types. -impl fmt::Display for HeaderC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut display = String::new(); - for decl in &self.def.decls { - display += &format!("{}", decl); - } - write!(f, "{}", display) - } -} - -/// Use Display trait for Debug so that any failing property tests report -/// generated C code rather than the data structures that contain it. -impl fmt::Debug for HeaderC { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self) - } -} diff --git a/tests/quickchecking/src/lib.rs b/tests/quickchecking/src/lib.rs deleted file mode 100644 index d8633dfb..00000000 --- a/tests/quickchecking/src/lib.rs +++ /dev/null @@ -1,126 +0,0 @@ -//! A library to generate __fuzzed__ C headers for use with `quickcheck` -//! -//! ## Example -//! -//! ```rust -//! extern crate quickcheck; -//! extern crate quickchecking; -//! extern crate rand; -//! use quickcheck::{Arbitrary, Gen, StdGen}; -//! use quickchecking::fuzzers; -//! use rand::thread_rng; -//! -//! fn main() { -//! let generate_range: usize = 10; // Determines things like the length of -//! // arbitrary vectors generated. -//! let header = fuzzers::HeaderC::arbitrary( -//! &mut StdGen::new(thread_rng(), generate_range)); -//! println!("{}", header); -//! } -//! ``` -//! -#![deny(missing_docs)] -#[macro_use] -extern crate lazy_static; -extern crate quickcheck; -extern crate rand; -extern crate tempdir; - -use std::sync::Mutex; -use quickcheck::{QuickCheck, StdGen, TestResult}; -use std::fs::File; -use std::io::Write; -use tempdir::TempDir; -use std::process::{Command, Output}; -use std::path::PathBuf; -use std::error::Error; -use rand::thread_rng; - -/// Contains definitions of and impls for types used to fuzz C declarations. -pub mod fuzzers; - -// Global singleton, manages context across tests. For now that context is -// only the output_path for inspecting fuzzed headers (if specified). -struct Context { - output_path: Option<String>, -} - -// Initialize global context. -lazy_static! { - static ref CONTEXT: Mutex<Context> = Mutex::new(Context { output_path: None }); -} - -// Passes fuzzed header to the `csmith-fuzzing/predicate.py` script, returns -// output of the associated command. -fn run_predicate_script(header: fuzzers::HeaderC) -> Result<Output, Box<Error>> { - let dir = TempDir::new("bindgen_prop")?; - let header_path = dir.path().join("prop_test.h"); - - let mut header_file = File::create(&header_path)?; - header_file.write_all(header.to_string().as_bytes())?; - header_file.sync_all()?; - - let header_path_string; - match header_path.into_os_string().into_string() { - Ok(s) => header_path_string = s, - Err(_) => return Err(From::from("error converting path into String")), - } - - let mut predicate_script_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - predicate_script_path.push("../../csmith-fuzzing/predicate.py"); - - let predicate_script_path_string; - match predicate_script_path.into_os_string().into_string() { - Ok(s) => predicate_script_path_string = s, - Err(_) => return Err(From::from("error converting path into String")), - } - - // Copy generated temp files to output_path directory for inspection. - // If `None`, output path not specified, don't copy. - match CONTEXT.lock().unwrap().output_path { - Some(ref path) => { - Command::new("cp") - .arg("-a") - .arg(&dir.path().to_str().unwrap()) - .arg(&path) - .output()?; - } - None => {} - } - - Ok(Command::new(&predicate_script_path_string) - .arg(&header_path_string) - .output()?) -} - -// Generatable property. Pass generated headers off to run through the -// `csmith-fuzzing/predicate.py` script. Success is measured by the success -// status of that command. -fn bindgen_prop(header: fuzzers::HeaderC) -> TestResult { - match run_predicate_script(header) { - Ok(o) => return TestResult::from_bool(o.status.success()), - Err(e) => { - println!("{:?}", e); - return TestResult::from_bool(false); - } - } -} - -/// Instantiate a Quickcheck object and use it to run property tests using -/// fuzzed C headers generated with types defined in the `fuzzers` module. -/// Success/Failure is dictated by the result of passing the fuzzed headers -/// to the `csmith-fuzzing/predicate.py` script. -pub fn test_bindgen(generate_range: usize, tests: usize, output_path: Option<&str>) { - match output_path { - Some(path) => { - CONTEXT.lock().unwrap().output_path = - Some(String::from(PathBuf::from(path).to_str().unwrap())); - } - None => {} // Path not specified, don't provide output. - } - - QuickCheck::new() - .tests(tests) - .gen(StdGen::new(thread_rng(), generate_range)) - .quickcheck(bindgen_prop as fn(fuzzers::HeaderC) -> TestResult) -} |