Skip to content

Commit dc09012

Browse files
committed
Allow asserting expectations across different libclang versions
Rather than having a tests that we only run if libclang >= 3.9, this makes the test suite dynamically detect when we have different expectations for different libclang versions. It does this by adding `tests/expectations/tests/libclang-$VERSION` directories, and `testing_only_libclang_$VERSION` features that are consulted when the usual expectation file does not exist. Fixes #697
1 parent f63eb00 commit dc09012

28 files changed

+537
-15
lines changed

.travis.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ env:
1717
global:
1818
- CARGO_TARGET_DIR=/tmp/bindgen
1919
matrix:
20-
- LLVM_VERSION=3.7.1 BINDGEN_FEATURES=testing_only_llvm_stable
21-
- LLVM_VERSION=3.8.1 BINDGEN_FEATURES=testing_only_llvm_stable
22-
- LLVM_VERSION=3.9.0 BINDGEN_FEATURES=
23-
- LLVM_VERSION=4.0.0 BINDGEN_FEATURES=
20+
- LLVM_VERSION=3.7.1 BINDGEN_FEATURES=testing_only_libclang_3_8
21+
- LLVM_VERSION=3.8.1 BINDGEN_FEATURES=testing_only_libclang_3_8
22+
- LLVM_VERSION=3.9.0 BINDGEN_FEATURES=testing_only_libclang_3_9
23+
- LLVM_VERSION=4.0.0 BINDGEN_FEATURES=testing_only_libclang_4
2424

2525
matrix:
2626
fast_finish: true
2727
allow_failures:
28-
- env: LLVM_VERSION=4.0.0 BINDGEN_FEATURES=
29-
- env: LLVM_VERSION=3.7.1 BINDGEN_FEATURES=testing_only_llvm_stable
28+
- env: LLVM_VERSION=3.7.1 BINDGEN_FEATURES=testing_only_libclang_3_8
3029

3130
cache:
3231
directories:

CONTRIBUTING.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ out to us in a GitHub issue, or stop by
1414
- [Testing](#testing)
1515
- [Overview](#overview)
1616
- [Running All Tests](#running-all-tests)
17+
- [Running a Single Test](#running-a-single-test)
1718
- [Authoring New Tests](#authoring-new-tests)
19+
- [Test Expectations and `libclang` Versions](#test-expectations-and-libclang-versions)
1820
- [Automatic code formatting](#automatic-code-formatting)
1921
- [Generating Graphviz Dot Files](#generating-graphviz-dot-files)
2022
- [Debug Logging](#debug-logging)
@@ -91,9 +93,17 @@ Run `cargo test` to compare generated Rust bindings to the expectations.
9193
### Running All Tests
9294

9395
```
94-
$ cargo test [--all-features]
96+
$ cargo test --features testing_only_libclang_$VERSION
9597
```
9698

99+
Where `$VERSION` is one of:
100+
101+
* `4`
102+
* `3_9`
103+
* `3_8`
104+
105+
depending on which version of `libclang` you have installed.
106+
97107
### Running a Single Test
98108

99109
To generate bindings for a single test header, compile the bindings, and run the
@@ -124,6 +134,25 @@ Then verify the new Rust bindings compile and pass some basic tests:
124134
$ cargo test -p tests_expectations
125135
```
126136

137+
### Test Expectations and `libclang` Versions
138+
139+
If a test generates different bindings across different `libclang` versions (for
140+
example, because we take advantage of better/newer APIs when possible), then you
141+
can add multiple test expectations, one for each supported `libclang`
142+
version. Instead of having a single `tests/expectations/tests/my_test.rs` file,
143+
add each of:
144+
145+
* `tests/expectations/tests/libclang-4/my_test.rs`
146+
* `tests/expectations/tests/libclang-3.9/my_test.rs`
147+
* `tests/expectations/tests/libclang-3.8/my_test.rs`
148+
149+
If you need to update the test expectations for a test file that generates
150+
different bindings for different `libclang` versions, you *don't* need to have
151+
many version of `libclang` installed locally. Just make a work-in-progress pull
152+
request, and then when Travis CI fails, it will log a diff of the
153+
expectations. Use the diff to patch the appropriate expectation file locally and
154+
then update your pull request.
155+
127156
## Automatic code formatting
128157

129158
We use [`rustfmt`](https://github.com/rust-lang-nursery/rustfmt) to enforce a

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,6 @@ static = []
7777
# on bindgen!
7878
testing_only_docs = []
7979
testing_only_extra_assertions = []
80-
testing_only_llvm_stable = []
80+
testing_only_libclang_4 = []
81+
testing_only_libclang_3_9 = []
82+
testing_only_libclang_3_8 = []

bindgen-integration/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ bindgen = { path = ".." }
1111
gcc = "0.3"
1212

1313
[features]
14-
testing_only_llvm_stable = ["bindgen/testing_only_llvm_stable"]
14+
testing_only_libclang_4 = ["bindgen/testing_only_libclang_4"]
15+
testing_only_libclang_3_9 = ["bindgen/testing_only_libclang_3_9"]
16+
testing_only_libclang_3_8 = ["bindgen/testing_only_libclang_3_8"]

src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ pub fn main() {
3131
let bind_args: Vec<_> = env::args().collect();
3232

3333
let version = clang_version();
34-
let expected_version = if cfg!(feature = "testing_only_llvm_stable") {
34+
let expected_version = if cfg!(feature = "testing_only_libclang_4") {
35+
(4, 0)
36+
} else if cfg!(feature = "testing_only_libclang_3_8") {
3537
(3, 8)
3638
} else {
39+
// Default to 3.9.
3740
(3, 9)
3841
};
3942

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy)]
9+
pub struct Foo {
10+
pub _address: u8,
11+
}
12+
extern "C" {
13+
#[link_name = "_ZN3Foo4kFooE"]
14+
pub static Foo_kFoo: bool;
15+
}
16+
#[test]
17+
fn bindgen_test_layout_Foo() {
18+
assert_eq!(::std::mem::size_of::<Foo>() , 1usize , concat ! (
19+
"Size of: " , stringify ! ( Foo ) ));
20+
assert_eq! (::std::mem::align_of::<Foo>() , 1usize , concat ! (
21+
"Alignment of " , stringify ! ( Foo ) ));
22+
}
23+
impl Clone for Foo {
24+
fn clone(&self) -> Self { *self }
25+
}
26+
#[repr(C)]
27+
#[derive(Debug, Default, Copy, Clone)]
28+
pub struct Bar {
29+
pub _address: u8,
30+
}
31+
extern "C" {
32+
#[link_name = "_Z5Test2v"]
33+
pub fn Test2() -> ::std::os::raw::c_uint;
34+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Copy)]
9+
pub struct JNINativeInterface_ {
10+
pub GetVersion: ::std::option::Option<unsafe extern "stdcall" fn(env:
11+
*mut ::std::os::raw::c_void)
12+
-> ::std::os::raw::c_int>,
13+
pub __hack: ::std::os::raw::c_ulonglong,
14+
}
15+
#[test]
16+
fn bindgen_test_layout_JNINativeInterface_() {
17+
assert_eq!(::std::mem::size_of::<JNINativeInterface_>() , 16usize , concat
18+
! ( "Size of: " , stringify ! ( JNINativeInterface_ ) ));
19+
assert_eq! (::std::mem::align_of::<JNINativeInterface_>() , 8usize ,
20+
concat ! (
21+
"Alignment of " , stringify ! ( JNINativeInterface_ ) ));
22+
assert_eq! (unsafe {
23+
& ( * ( 0 as * const JNINativeInterface_ ) ) . GetVersion as *
24+
const _ as usize } , 0usize , concat ! (
25+
"Alignment of field: " , stringify ! ( JNINativeInterface_ ) ,
26+
"::" , stringify ! ( GetVersion ) ));
27+
assert_eq! (unsafe {
28+
& ( * ( 0 as * const JNINativeInterface_ ) ) . __hack as *
29+
const _ as usize } , 8usize , concat ! (
30+
"Alignment of field: " , stringify ! ( JNINativeInterface_ ) ,
31+
"::" , stringify ! ( __hack ) ));
32+
}
33+
impl Clone for JNINativeInterface_ {
34+
fn clone(&self) -> Self { *self }
35+
}
36+
impl Default for JNINativeInterface_ {
37+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
38+
}
39+
extern "C" {
40+
#[link_name = "_bar@0"]
41+
pub fn bar();
42+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
extern "C" {
8+
#[link_name = "_ZL1k"]
9+
pub static k: bool;
10+
}
11+
#[repr(C)]
12+
#[derive(Debug, Default, Copy)]
13+
pub struct A {
14+
pub _address: u8,
15+
}
16+
extern "C" {
17+
#[link_name = "_ZN1A1kE"]
18+
pub static A_k: bool;
19+
}
20+
#[test]
21+
fn bindgen_test_layout_A() {
22+
assert_eq!(::std::mem::size_of::<A>() , 1usize , concat ! (
23+
"Size of: " , stringify ! ( A ) ));
24+
assert_eq! (::std::mem::align_of::<A>() , 1usize , concat ! (
25+
"Alignment of " , stringify ! ( A ) ));
26+
}
27+
impl Clone for A {
28+
fn clone(&self) -> Self { *self }
29+
}
30+
pub type foo = bool;
31+
extern "C" {
32+
#[link_name = "_ZL2k2"]
33+
pub static k2: foo;
34+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
pub const foo: _bindgen_ty_1 = _bindgen_ty_1::foo;
8+
pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
9+
#[repr(u32)]
10+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11+
pub enum _bindgen_ty_1 { foo = 4, bar = 8, }
12+
pub type EasyToOverflow = ::std::os::raw::c_ulonglong;
13+
pub const k: EasyToOverflow = 2147483648;
14+
extern "C" {
15+
#[link_name = "k_expr"]
16+
pub static k_expr: EasyToOverflow;
17+
}
18+
extern "C" {
19+
#[link_name = "BAZ"]
20+
pub static BAZ: ::std::os::raw::c_longlong;
21+
}
22+
extern "C" {
23+
#[link_name = "fuzz"]
24+
pub static fuzz: f64;
25+
}
26+
extern "C" {
27+
#[link_name = "BAZZ"]
28+
pub static BAZZ: ::std::os::raw::c_char;
29+
}
30+
extern "C" {
31+
#[link_name = "WAT"]
32+
pub static WAT: ::std::os::raw::c_char;
33+
}
34+
extern "C" {
35+
#[link_name = "bytestring"]
36+
pub static mut bytestring: *const ::std::os::raw::c_char;
37+
}
38+
extern "C" {
39+
#[link_name = "NOT_UTF8"]
40+
pub static mut NOT_UTF8: *const ::std::os::raw::c_char;
41+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy, Clone)]
9+
pub struct Base {
10+
pub _address: u8,
11+
}
12+
#[repr(C)]
13+
#[derive(Debug, Default, Copy, Clone)]
14+
pub struct Derived {
15+
pub b: bool,
16+
}
17+
#[test]
18+
fn __bindgen_test_layout__bindgen_ty_id_21_instantiation_1() {
19+
assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat ! (
20+
"Size of template specialization: " , stringify ! (
21+
[u32; 2usize] ) ));
22+
assert_eq!(::std::mem::align_of::<[u32; 2usize]>() , 4usize , concat ! (
23+
"Alignment of template specialization: " , stringify ! (
24+
[u32; 2usize] ) ));
25+
}
26+
#[repr(C)]
27+
#[derive(Debug, Default, Copy)]
28+
pub struct Usage {
29+
pub _address: u8,
30+
}
31+
extern "C" {
32+
#[link_name = "_ZN5Usage13static_memberE"]
33+
pub static mut Usage_static_member: [u32; 2usize];
34+
}
35+
#[test]
36+
fn bindgen_test_layout_Usage() {
37+
assert_eq!(::std::mem::size_of::<Usage>() , 1usize , concat ! (
38+
"Size of: " , stringify ! ( Usage ) ));
39+
assert_eq! (::std::mem::align_of::<Usage>() , 1usize , concat ! (
40+
"Alignment of " , stringify ! ( Usage ) ));
41+
}
42+
extern "C" {
43+
#[link_name = "_ZN5UsageC1Ev"]
44+
pub fn Usage_Usage(this: *mut Usage);
45+
}
46+
impl Clone for Usage {
47+
fn clone(&self) -> Self { *self }
48+
}
49+
impl Usage {
50+
#[inline]
51+
pub unsafe fn new() -> Self {
52+
let mut __bindgen_tmp = ::std::mem::uninitialized();
53+
Usage_Usage(&mut __bindgen_tmp);
54+
__bindgen_tmp
55+
}
56+
}

tests/expectations/tests/call-conv-field.rs renamed to tests/expectations/tests/libclang-3.9/call-conv-field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* automatically generated by rust-bindgen */
22

33

4-
#![allow(non_snake_case)]
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
55

66

77
#[repr(C)]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
#![cfg(target_os="macos")]
7+
8+
#[macro_use]
9+
extern crate objc;
10+
#[allow(non_camel_case_types)]
11+
pub type id = *mut objc::runtime::Object;
12+
pub trait Foo {
13+
unsafe fn get(self)
14+
-> id;
15+
}
16+
impl Foo for id {
17+
unsafe fn get(self) -> id { msg_send!(self , get) }
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Default, Copy)]
9+
pub struct Rooted {
10+
pub ptr: ::std::os::raw::c_int,
11+
}
12+
#[test]
13+
fn bindgen_test_layout_Rooted() {
14+
assert_eq!(::std::mem::size_of::<Rooted>() , 4usize , concat ! (
15+
"Size of: " , stringify ! ( Rooted ) ));
16+
assert_eq! (::std::mem::align_of::<Rooted>() , 4usize , concat ! (
17+
"Alignment of " , stringify ! ( Rooted ) ));
18+
assert_eq! (unsafe {
19+
& ( * ( 0 as * const Rooted ) ) . ptr as * const _ as usize }
20+
, 0usize , concat ! (
21+
"Alignment of field: " , stringify ! ( Rooted ) , "::" ,
22+
stringify ! ( ptr ) ));
23+
}
24+
impl Clone for Rooted {
25+
fn clone(&self) -> Self { *self }
26+
}
27+
/// <div rustbindgen replaces="MaybeWrapped"></div>
28+
pub type MaybeWrapped<a> = a;

0 commit comments

Comments
 (0)