diff options
Diffstat (limited to 'tests/quickchecking/src/fuzzers.rs')
-rw-r--r-- | tests/quickchecking/src/fuzzers.rs | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/tests/quickchecking/src/fuzzers.rs b/tests/quickchecking/src/fuzzers.rs new file mode 100644 index 00000000..7549149f --- /dev/null +++ b/tests/quickchecking/src/fuzzers.rs @@ -0,0 +1,599 @@ +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 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 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 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(Debug, 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", + // "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(); + // Don't allow size 0 dimension until #684 and #1153 are closed. + // 16 is an arbitrary "not too big" number for capping array size. + for _ in 1..dimensions { + def += &format!("[{}]", g.gen_range(1, 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), + 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 + ) + } +} + +/// 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)), + } + } +} + +/// 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) + } +} + +/// 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)), + } + } +} + +/// 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) + } +} + +/// 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) + } +} |