summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorShea Newton <sheanewt@gmail.com>2017-12-05 21:18:59 -0800
committerShea Newton <sheanewt@gmail.com>2017-12-07 18:38:42 -0800
commit299ff28d4a713ad0aa8f7de700e67b55f9a60cb4 (patch)
treee824445f56938f59f332f9837559038625fd44c2 /tests
parenta59205e8cf9aa1acfaceafa5c37ba297341e178b (diff)
Enable Cargo features for quickchecking crate
Logic to enable/disable special casing (due to known issues #550, #684, and #1153) has been exposed as features in the `quickchecking` crate's Cargo.toml file and corresponding `cfg` attributes in the source. In addition to adding Cargo features, this PR represents the following: - Documentation in `bindgen`'s CONTRIBUTING.md that points to a new README.md located in the `quickchecking` crate's directory. - The Debug trait was implemented for the `HeaderC` type. This enables failing property tests to be reported as C source code rather than a Rust data structure. - The ArrayDimensionC type is now used in header generation for union, struct, and basic declarations. Thanks for taking a look and for any feedback! Closes #1169 r? @fitzgen
Diffstat (limited to 'tests')
-rw-r--r--tests/quickchecking/Cargo.toml12
-rw-r--r--tests/quickchecking/README.md59
-rw-r--r--tests/quickchecking/src/bin.rs6
-rw-r--r--tests/quickchecking/src/fuzzers.rs56
4 files changed, 121 insertions, 12 deletions
diff --git a/tests/quickchecking/Cargo.toml b/tests/quickchecking/Cargo.toml
index eb5cdfcf..ddefb33d 100644
--- a/tests/quickchecking/Cargo.toml
+++ b/tests/quickchecking/Cargo.toml
@@ -18,3 +18,15 @@ lazy_static = "1.0"
quickcheck = "0.4"
rand = "0.3"
tempdir = "0.3"
+
+[features]
+# No features by default.
+default = []
+
+# Enable the generation of code that allows for zero sized arrays as struct
+# fields. Until issues #684 and #1153 are resolved this can result in failing tests.
+zero-sized-arrays = []
+
+# Enable the generation of code that allows for long double types as struct
+# fields. Until issue #550 is resolved this can result in failing tests.
+long-doubles = []
diff --git a/tests/quickchecking/README.md b/tests/quickchecking/README.md
new file mode 100644
index 00000000..8a962163
--- /dev/null
+++ b/tests/quickchecking/README.md
@@ -0,0 +1,59 @@
+# Property tests for `bindgen` with `quickchecking`
+
+`quickchecking` generates random C headers to test `bindgen`
+using the [`quickcheck`][quickcheck] property testing crate. When testing
+`bindgen` with `quickchecking`, the generated header files are passed to
+`bindgen`'s `csmith-fuzzing/predicate.py` script. If that script fails,
+`quickchecking` panics, and you can report an issue containing the test case!
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+
+- [Prerequisites](#prerequisites)
+- [Running](#running)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+## Prerequisites
+
+Requires `python3` to be in `$PATH`.
+
+Many systems have `python3` by default but if your OS doesn't, its package
+manager may make it available:
+
+```
+$ sudo apt install python3
+$ brew install python3
+$ # Etc...
+```
+
+## Running
+
+Run `quickchecking` binary to generate and test fuzzed C headers with
+`cargo run`. Additional configuration is exposed through the binary's CLI.
+
+```
+$ cargo run --bin=quickchecking -- -h
+quickchecking 0.2.0
+Bindgen property tests with quickcheck. Generate random valid C code and pass it to the csmith/predicate.py script
+
+USAGE:
+ quickchecking [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --count <COUNT> 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. [default: 2]
+ -p, --path <PATH> Optional. Preserve generated headers for inspection, provide directory path for header
+ output. [default: None]
+ -r, --range <RANGE> 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. [default: 32]
+
+```
+[quickcheck]: https://github.com/BurntSushi/quickcheck
diff --git a/tests/quickchecking/src/bin.rs b/tests/quickchecking/src/bin.rs
index 9cf313cd..d2774eb0 100644
--- a/tests/quickchecking/src/bin.rs
+++ b/tests/quickchecking/src/bin.rs
@@ -1,5 +1,5 @@
-//! An application to run property tests for `bindgen` with _fuzzed_ C headers
-//! using `quickcheck`
+//! An application to run property tests for `bindgen` with _fuzzed_ C headers
+//! using `quickcheck`
//!
//! ## Usage
//!
@@ -77,7 +77,7 @@ fn main() {
"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 that execution time to increase \
+ to grow much for execution time to increase \
significantly.",
)
.takes_value(true)
diff --git a/tests/quickchecking/src/fuzzers.rs b/tests/quickchecking/src/fuzzers.rs
index 7549149f..2876da86 100644
--- a/tests/quickchecking/src/fuzzers.rs
+++ b/tests/quickchecking/src/fuzzers.rs
@@ -45,6 +45,8 @@ pub struct BasicTypeDeclarationC {
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,
}
@@ -55,6 +57,8 @@ pub struct BasicTypeDeclarationC {
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,
}
@@ -65,6 +69,8 @@ pub struct StructDeclarationC {
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,
}
@@ -147,7 +153,7 @@ pub struct DeclarationListC {
/// HeaderC is used in generation of C headers to represent a collection of
/// declarations.
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct HeaderC {
/// The header's declarations.
pub def: DeclarationListC,
@@ -256,7 +262,8 @@ impl Arbitrary for BaseTypeC {
"unsigned long long int",
"float",
"double",
- // "long double",
+ #[cfg(feature = "long-doubles")]
+ "long double",
"void*",
];
BaseTypeC {
@@ -315,10 +322,17 @@ impl Arbitrary for 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.
+
+ let lower_bound;
+ if cfg!(feature = "zero-sized-arrays") {
+ lower_bound = 0;
+ } else {
+ lower_bound = 1;
+ }
+
for _ in 1..dimensions {
- def += &format!("[{}]", g.gen_range(1, 16));
+ // 16 is an arbitrary "not too big" number for capping array size.
+ def += &format!("[{}]", g.gen_range(lower_bound, 16));
}
ArrayDimensionC { def }
}
@@ -347,6 +361,7 @@ impl Arbitrary for 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)),
}
}
@@ -357,11 +372,12 @@ impl fmt::Display for BasicTypeDeclarationC {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
- "{} {} {} ident_{};",
+ "{} {} {} ident_{}{};",
self.type_qualifier,
self.type_name,
self.pointer_level,
- self.ident_id
+ self.ident_id,
+ self.array_dimension
)
}
}
@@ -398,6 +414,7 @@ impl Arbitrary for StructDeclarationC {
StructDeclarationC {
fields,
ident_id: format!("{}", usize::arbitrary(g)),
+ array_dimension: Arbitrary::arbitrary(g),
}
}
}
@@ -405,7 +422,13 @@ impl Arbitrary for StructDeclarationC {
/// 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)
+ write!(
+ f,
+ "struct {{ {} }} struct_{}{};",
+ self.fields,
+ self.ident_id,
+ self.array_dimension
+ )
}
}
@@ -441,6 +464,7 @@ impl Arbitrary for UnionDeclarationC {
UnionDeclarationC {
fields,
ident_id: format!("{}", usize::arbitrary(g)),
+ array_dimension: Arbitrary::arbitrary(g),
}
}
}
@@ -448,7 +472,13 @@ impl Arbitrary for UnionDeclarationC {
/// 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)
+ write!(
+ f,
+ "union {{ {} }} union_{}{};",
+ self.fields,
+ self.ident_id,
+ self.array_dimension
+ )
}
}
@@ -597,3 +627,11 @@ impl fmt::Display for HeaderC {
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)
+ }
+}