diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | src/codegen/mod.rs | 2 | ||||
-rw-r--r-- | src/ir/annotations.rs | 2 | ||||
-rw-r--r-- | src/ir/context.rs | 2 | ||||
-rw-r--r-- | src/ir/item.rs | 2 | ||||
-rwxr-xr-x | src/lib.rs | 14 | ||||
-rw-r--r-- | tests/support.rs | 108 | ||||
-rw-r--r-- | tests/test_builtins.rs | 10 | ||||
-rw-r--r-- | tests/test_cmath.rs | 13 | ||||
-rw-r--r-- | tests/test_cxx.rs | 34 | ||||
-rw-r--r-- | tests/test_decl.rs | 10 | ||||
-rw-r--r-- | tests/test_enum.rs | 132 | ||||
-rw-r--r-- | tests/test_extern.rs | 8 | ||||
-rw-r--r-- | tests/test_func.rs | 50 | ||||
-rw-r--r-- | tests/test_struct.rs | 264 | ||||
-rw-r--r-- | tests/test_union.rs | 271 | ||||
-rw-r--r-- | tests/tests.rs | 139 | ||||
-rwxr-xr-x | tests/tools/run-bindgen.py | 23 |
19 files changed, 150 insertions, 940 deletions
diff --git a/.travis.yml b/.travis.yml index 274aefc1..70db4df3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ before_script: script: - cargo build --verbose --features llvm_stable - - make test + - cargo test --features llvm_stable - git add -A - git diff @ - git diff-index --quiet HEAD @@ -12,8 +12,8 @@ $(BINDGEN): [ -f $@ ] || cargo build --features llvm_stable .PHONY: test -test: regen-tests - @echo > /dev/null +test: + cargo test --features llvm_stable .PHONY: regen-tests diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index a5159c98..5688065f 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -41,7 +41,7 @@ struct CodegenResult { /// The set of generated function/var names, needed because in C/C++ is legal to /// do something like: /// - /// ``` + /// ```c++ /// extern "C" { /// void foo(); /// extern int bar; diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs index cc61dbfd..64ab255d 100644 --- a/src/ir/annotations.rs +++ b/src/ir/annotations.rs @@ -87,7 +87,7 @@ impl Annotations { /// /// the generated code would look something like: /// - /// ```rust + /// ```c++ /// /** <div rustbindgen replaces="Bar"></div> */ /// struct Bar { /// int x; diff --git a/src/ir/context.rs b/src/ir/context.rs index e6659697..da5f334f 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -421,7 +421,7 @@ impl<'ctx> BindgenContext<'ctx> { /// /// To see an example of what this handles: /// - /// ``` + /// ```c++ /// template<typename T> /// class Incomplete { /// T p; diff --git a/src/ir/item.rs b/src/ir/item.rs index 5b6297bd..4808806b 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -28,7 +28,7 @@ pub trait ItemCanonicalName { /// /// To contrast with canonical_name, here's an example: /// -/// ``` +/// ```c++ /// namespace foo { /// const BAR = 3; /// } @@ -294,20 +294,6 @@ impl Bindings { } } -#[test] -fn builder_state() { - let logger = DummyLogger; - let mut build = builder(); - { - build.header("example.h"); - build.link_static("m"); - build.log(&logger); - } - assert!(build.logger.is_some()); - assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok()); - assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok()); -} - /// Determines whether the given cursor is in any of the files matched by the /// options. fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool { diff --git a/tests/support.rs b/tests/support.rs deleted file mode 100644 index 0ac92f5f..00000000 --- a/tests/support.rs +++ /dev/null @@ -1,108 +0,0 @@ -use bindgen; -use bindgen::{Logger, BindgenOptions}; - -use syntax::ast; -use syntax::codemap; -use syntax::codemap::DUMMY_SP; -use syntax::parse; -use syntax::parse::token; -use syntax::print::pprust; -use syntax::ptr::P; - -struct TestLogger; - -impl Logger for TestLogger { - fn error(&self, msg: &str) { - println!("err: {}", msg); - } - - fn warn(&self, msg: &str) { - println!("warn: {}", msg); - } -} - -pub fn generate_bindings(mut options: BindgenOptions, - filename: &str) - -> Result<Vec<P<ast::Item>>, ()> { - if filename.ends_with("hpp") { - options.clang_args.push("-std=c++11".to_string()); - options.clang_args.push("-Wno-narrowing".to_string()); - } - options.clang_args.push(filename.to_string()); - - let logger = TestLogger; - Ok(try!(bindgen::Bindings::generate(&options, Some(&logger as &Logger), None)).into_ast()) -} - -pub fn assert_bind_eq(options: BindgenOptions, - filename: &str, - reference_items_str: &str) { - let ext_cx = mk_dummy_ext_ctxt(); - let generated_items = - generate_bindings(options, &format!("tests/{}", filename)[..]).unwrap(); - - let mut parser = parse::new_parser_from_source_str(ext_cx.parse_sess(), ext_cx.cfg(), "".to_string(), reference_items_str.to_string()); - let mut reference_items = Vec::new(); - while let Ok(Some(item)) = parser.parse_item() { - reference_items.push(item); - } - - // The ast::Items themselves have insignificant (for our purposes) - // differences that make them difficult to compare directly. So, compare - // rendered versions, which is not beautiful, but should work. - let reference_rendered = render_items(&reference_items); - let generated_rendered = render_items(&generated_items); - - if reference_rendered != generated_rendered { - println!("Generated bindings for {} do not match the reference bindings.", filename); - println!(""); - println!("Generated:"); - println!(""); - println!("{}", generated_rendered); - println!(""); - println!("Reference:"); - println!(""); - println!("{}", reference_rendered); - panic!(); - } -} - -fn render_items(items: &Vec<P<ast::Item>>) -> String { - pprust::to_string(|s| { - let module = ast::Mod { - inner: DUMMY_SP, - items: items.clone(), - }; - s.print_mod(&module, &[]) - }) -} - -pub struct DummyExtCtxt { - sess: parse::ParseSess, -} - -impl DummyExtCtxt { - pub fn cfg(&self) -> ast::CrateConfig { - vec!() - } - pub fn parse_sess(&self) -> &parse::ParseSess { - &self.sess - } - pub fn call_site(&self) -> codemap::Span { - codemap::Span { - lo: codemap::BytePos(0), - hi: codemap::BytePos(0), - expn_id: codemap::NO_EXPANSION - } - } - pub fn ident_of(&self, s: &str) -> ast::Ident { - token::str_to_ident(s) - } - pub fn name_of(&self, s: &str) -> ast::Name { - token::intern(s) - } -} - -fn mk_dummy_ext_ctxt<'a>() -> DummyExtCtxt { - DummyExtCtxt { sess: parse::ParseSess::new() } -} diff --git a/tests/test_builtins.rs b/tests/test_builtins.rs deleted file mode 100644 index c1ddce72..00000000 --- a/tests/test_builtins.rs +++ /dev/null @@ -1,10 +0,0 @@ -use bindgen; - -#[test] -fn test_builtin_va_list() { - let bindings = bindgen::builder().header("tests/headers/builtin_va_list.h") - .emit_builtins().generate().unwrap().to_string(); - println!("{}", bindings); - assert!(bindings.contains("__builtin_va_list")); -} - diff --git a/tests/test_cmath.rs b/tests/test_cmath.rs deleted file mode 100644 index 564e40e3..00000000 --- a/tests/test_cmath.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Unused until we can generate code for tests - -#[allow(dead_code, non_camel_case_types)] -pub mod ffi { bindgen!("/usr/include/math.h", link = "m"); } - -#[test] -fn floor_is_bound_and_callable() { - unsafe { - assert_eq!(ffi::floor( 2.7), 2.0); - assert_eq!(ffi::floor(-2.7), -3.0); - assert_eq!(ffi::floor(-0.0), 0.0); - } -} diff --git a/tests/test_cxx.rs b/tests/test_cxx.rs deleted file mode 100644 index ea4e516f..00000000 --- a/tests/test_cxx.rs +++ /dev/null @@ -1,34 +0,0 @@ -use bindgen; -use bindgen::BindgenOptions; -use support::assert_bind_eq; - -fn cxx_options() -> BindgenOptions { - let mut options = BindgenOptions::default(); - options.rename_types = false; - - options -} - -#[test] -fn test_cxx_class() { - assert_bind_eq(cxx_options(), "headers/class.hpp", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct C { - pub a: ::std::os::raw::c_int, - }"); -} - -#[test] -fn test_cxx_template() { - assert_bind_eq(cxx_options(), "headers/template.hpp", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Foo<T> { - pub m_member: T, - } - extern \"C\" { - #[link_name = \"_Z3bar3FooIiE\"] - pub fn bar(foo: Foo<::std::os::raw::c_int>); - }"); -} diff --git a/tests/test_decl.rs b/tests/test_decl.rs deleted file mode 100644 index 6858d416..00000000 --- a/tests/test_decl.rs +++ /dev/null @@ -1,10 +0,0 @@ -use support::assert_bind_eq; - -#[test] -fn ptr_to_array() { - assert_bind_eq(Default::default(), "headers/decl_ptr_to_array.h", " - extern \"C\" { - pub static mut foo: [::std::os::raw::c_int; 1usize]; - } - "); -} diff --git a/tests/test_enum.rs b/tests/test_enum.rs deleted file mode 100644 index 0a8a2bb8..00000000 --- a/tests/test_enum.rs +++ /dev/null @@ -1,132 +0,0 @@ -use bindgen::BindgenOptions; -use support::assert_bind_eq; - -fn default_without_rust_enums() -> BindgenOptions { - BindgenOptions { rust_enums: false, .. Default::default() } -} - -#[test] -fn with_simple_enum() { - assert_bind_eq(Default::default(), "headers/enum.h", " - #[repr(u32)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Foo { Bar = 0, Qux = 1, } - #[repr(i32)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Neg { MinusOne = -1, One = 1, } - "); - assert_bind_eq(default_without_rust_enums(), "headers/enum.h", " - type Enum_Foo = u32; - const Bar: Enum_Foo = 0; - const Qux: Enum_Foo = 1; - type Enum_Neg = i32; - const MinusOne: Enum_Neg = -1; - const One: Enum_Neg = 1; - "); -} - -#[test] -fn with_packed_enums() { - assert_bind_eq(Default::default(), "headers/enum_packed.h", " - #[repr(u8)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Foo { Bar = 0, Qux = 1, } - #[repr(i8)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Neg { MinusOne = -1, One = 1, } - #[repr(u16)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Bigger { Much = 255, Larger = 256, } - "); - assert_bind_eq(default_without_rust_enums(), "headers/enum_packed.h", " - type Enum_Foo = u8; - const Bar: Enum_Foo = 0; - const Qux: Enum_Foo = 1; - type Enum_Neg = i8; - const MinusOne: Enum_Neg = -1; - const One: Enum_Neg = 1; - type Enum_Bigger = u16; - const Much: Enum_Bigger = 255; - const Larger: Enum_Bigger = 256; - "); -} - -#[test] -fn with_duplicate_enum_value() { - assert_bind_eq(Default::default(), "headers/enum_dupe.h", " - pub const Dupe: Enum_Foo = Enum_Foo::Bar; - #[repr(u32)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Foo { Bar = 1, } - "); - assert_bind_eq(default_without_rust_enums(), "headers/enum_dupe.h", " - type Enum_Foo = u32; - const Bar: Enum_Foo = 1; - const Dupe: Enum_Foo = 1; - "); -} - -#[test] -fn with_explicitly_typed_cxx_enum() { - assert_bind_eq(Default::default(), "headers/enum_explicit_type.hpp", " - #[repr(u8)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Foo { Bar = 0, Qux = 1, } - - #[repr(i8)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Neg { MinusOne = -1, One = 1, } - - #[repr(u16)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Bigger { Much = 255, Larger = 256, } - - #[repr(i64)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_MuchLong { MuchLow = -4294967296, } - - #[repr(u64)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_MuchLongLong { MuchHigh = 4294967296, } - "); - assert_bind_eq(default_without_rust_enums(), "headers/enum_explicit_type.hpp", " - type Enum_Foo = u8; - const Bar: Enum_Foo = 0; - const Qux: Enum_Foo = 1; - type Enum_Neg = i8; - const MinusOne: Enum_Neg = -1; - const One: Enum_Neg = 1; - type Enum_Bigger = u16; - const Much: Enum_Bigger = 255; - const Larger: Enum_Bigger = 256; - type Enum_MuchLong = i64; - const MuchLow: Enum_MuchLong = -4294967296; - type Enum_MuchLongLong = u64; - const MuchHigh: Enum_MuchLongLong = 4294967296; - "); -} - -#[test] -fn with_overflowed_enum_value() { - assert_bind_eq(Default::default(), "headers/overflowed_enum.hpp", " - #[repr(u32)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Foo { - BAP_ARM = 9698489, - BAP_X86 = 11960045, - BAP_X86_64 = 3128633167, - } - #[repr(u16)] - #[derive(Copy, Clone, Debug)] - pub enum Enum_Bar { One = 1, Big = 2, } - "); - assert_bind_eq(default_without_rust_enums(), "headers/overflowed_enum.hpp", " - type Enum_Foo = u32; - const BAP_ARM: Enum_Foo = 9698489; - const BAP_X86: Enum_Foo = 11960045; - const BAP_X86_64: Enum_Foo = 3128633167; - type Enum_Bar = u16; - const One: Enum_Bar = 1; - const Big: Enum_Bar = 2; - "); -} diff --git a/tests/test_extern.rs b/tests/test_extern.rs deleted file mode 100644 index bbe823ff..00000000 --- a/tests/test_extern.rs +++ /dev/null @@ -1,8 +0,0 @@ -use support::assert_bind_eq; - -#[test] -fn extern_c_in_hpp() { - assert_bind_eq(Default::default(), "headers/extern.hpp", " - pub type foo = unsafe extern \"C\" fn(bar: ::std::os::raw::c_int) -> ::std::os::raw::c_int; - "); -} diff --git a/tests/test_func.rs b/tests/test_func.rs deleted file mode 100644 index b210186f..00000000 --- a/tests/test_func.rs +++ /dev/null @@ -1,50 +0,0 @@ -use support::assert_bind_eq; - -#[test] -fn func_ptr() { - assert_bind_eq(Default::default(), "headers/func_ptr.h", " - extern \"C\" { - pub static mut foo: ::std::option::Option< - unsafe extern \"C\" fn(x: ::std::os::raw::c_int, - y: ::std::os::raw::c_int) -> ::std::os::raw::c_int>; - } - "); -} - -#[test] -fn func_ptr_in_struct() { - assert_bind_eq(Default::default(), "headers/func_ptr_in_struct.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_Foo { - pub bar: ::std::option::Option< - unsafe extern \"C\" fn(x: ::std::os::raw::c_int, - y: ::std::os::raw::c_int) -> Enum_baz>, - } - "); -} - -#[test] -fn func_proto() { - assert_bind_eq(Default::default(), "headers/func_proto.h", " - pub type foo = unsafe extern \"C\" fn(bar: ::std::os::raw::c_int) -> ::std::os::raw::c_int; - "); -} - -#[test] -fn with_func_ptr_arg() { - assert_bind_eq(Default::default(), "headers/func_with_func_ptr_arg.h", " - extern \"C\" { - pub fn foo(bar: ::std::option::Option<unsafe extern \"C\" fn()>); - } - "); -} - -#[test] -fn with_array_arg() { - assert_bind_eq(Default::default(), "headers/func_with_array_arg.h", " - extern \"C\" { - pub fn f(x: *mut ::std::os::raw::c_int); - } - "); -} diff --git a/tests/test_struct.rs b/tests/test_struct.rs deleted file mode 100644 index 47e165f1..00000000 --- a/tests/test_struct.rs +++ /dev/null @@ -1,264 +0,0 @@ -use support::assert_bind_eq; - -#[test] -fn with_anon_struct() { - assert_bind_eq(Default::default(), "headers/struct_with_anon_struct.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_foo { - pub bar: Struct_struct_with_anon_struct_h_unnamed_1, - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_struct_with_anon_struct_h_unnamed_1 { - pub a: ::std::os::raw::c_int, - pub b: ::std::os::raw::c_int, - }"); -} - -#[test] -fn with_anon_struct_array() { - assert_bind_eq(Default::default(), "headers/struct_with_anon_struct_array.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_foo { - pub bar: [Struct_struct_with_anon_struct_array_h_unnamed_1; 2usize], - pub baz: [[[Struct_struct_with_anon_struct_array_h_unnamed_2; 4usize]; 3usize]; 2usize], - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_struct_with_anon_struct_array_h_unnamed_1 { - pub a: ::std::os::raw::c_int, - pub b: ::std::os::raw::c_int, - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_struct_with_anon_struct_array_h_unnamed_2 { - pub a: ::std::os::raw::c_int, - pub b: ::std::os::raw::c_int, - }"); -} - -#[test] -fn with_anon_struct_pointer() { - assert_bind_eq(Default::default(), "headers/struct_with_anon_struct_pointer.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_foo { - pub bar: *mut Struct_struct_with_anon_struct_pointer_h_unnamed_1, - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_struct_with_anon_struct_pointer_h_unnamed_1 { - pub a: ::std::os::raw::c_int, - pub b: ::std::os::raw::c_int, - }"); -} - -#[test] -fn with_anon_union() { - assert_bind_eq(Default::default(), "headers/struct_with_anon_union.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_foo { - pub bar: Union_unnamed1, - } - impl ::std::clone::Clone for Struct_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Struct_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - #[repr(C)] - #[derive(Copy, Clone, Debug)] - pub struct Union_unnamed1 { - pub _bindgen_data_: [u32; 1usize], - } - impl Union_unnamed1 { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - "); -} - -#[test] -fn with_anon_unnamed_struct() { - assert_bind_eq(Default::default(), "headers/struct_with_anon_unnamed_struct.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Struct_foo { - pub _bindgen_data_1_: [u32; 2usize], - } - impl Struct_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(4)) - } - } - impl ::std::clone::Clone for Struct_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Struct_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_anon_unnamed_union() { - assert_bind_eq(Default::default(), "headers/struct_with_anon_unnamed_union.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_foo { - pub _bindgen_data_1_: [u32; 1usize], - } - impl Struct_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Struct_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Struct_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_nesting() { - assert_bind_eq(Default::default(), "headers/struct_with_nesting.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Struct_foo { - pub a: ::std::os::raw::c_uint, - pub _bindgen_data_1_: [u32; 1usize], - } - impl Struct_foo { - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn c1(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn c2(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(2)) - } - pub unsafe fn d1(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn d2(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(1)) - } - pub unsafe fn d3(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(2)) - } - pub unsafe fn d4(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_1_); - ::std::mem::transmute(raw.offset(3)) - } - } - impl ::std::clone::Clone for Struct_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Struct_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn containing_fwd_decl_struct() { - assert_bind_eq(Default::default(), "headers/struct_containing_forward_declared_struct.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_a { - pub val_a: *mut Struct_b, - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_b { - pub val_b: ::std::os::raw::c_int, - } - "); -} - -#[test] -fn with_bitfields() { - assert_bind_eq(Default::default(), "headers/struct_with_bitfields.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Struct_bitfield { - pub _bindgen_bitfield_1_: ::std::os::raw::c_ushort, - pub e: ::std::os::raw::c_int, - pub _bindgen_bitfield_2_: ::std::os::raw::c_uint, - pub _bindgen_bitfield_3_: ::std::os::raw::c_uint, - } - - impl ::std::clone::Clone for Struct_bitfield { - fn clone(&self) -> Self { *self } - } - - impl ::std::default::Default for Struct_bitfield { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_fwd_decl_struct() { - assert_bind_eq(Default::default(), "headers/forward_declared_struct.h", " - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_a { - pub b: ::std::os::raw::c_int, - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct Struct_c { - pub d: ::std::os::raw::c_int, - }"); -} - - -#[test] -fn packed_struct() { - assert_bind_eq(Default::default(), "headers/struct_with_packing.h", " - #[repr(C, packed)] - #[derive(Copy, Clone)] - pub struct Struct_a { - pub b: ::std::os::raw::c_char, - pub c: ::std::os::raw::c_short, - }"); -} diff --git a/tests/test_union.rs b/tests/test_union.rs deleted file mode 100644 index f35e325a..00000000 --- a/tests/test_union.rs +++ /dev/null @@ -1,271 +0,0 @@ -use support::assert_bind_eq; - -#[test] -fn with_anon_struct() { - assert_bind_eq(Default::default(), "headers/union_with_anon_struct.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_foo { - pub _bindgen_data_: [u32; 2usize], - } - impl Union_foo { - pub unsafe fn bar(&mut self) -> *mut Struct_Unnamed1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Struct_Unnamed1 { - pub a: ::std::os::raw::c_uint, - pub b: ::std::os::raw::c_uint, - } - impl ::std::clone::Clone for Struct_Unnamed1 { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Struct_Unnamed1 { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_anon_struct_bitfield() { - assert_bind_eq(Default::default(), "headers/union_with_anon_struct_bitfield.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_foo { - pub _bindgen_data_: [u32; 1usize], - } - - impl Union_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - - impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } - } - - impl ::std::default::Default for Union_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_anon_union() { - assert_bind_eq(Default::default(), "headers/union_with_anon_union.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_foo { - pub _bindgen_data_: [u32; 1usize], - } - impl Union_foo { - pub unsafe fn bar(&mut self) -> *mut Union_Unnamed1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_Unnamed1 { - pub _bindgen_data_: [u32; 1usize], - } - impl Union_Unnamed1 { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Union_Unnamed1 { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_Unnamed1 { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_anon_unnamed_struct() { - assert_bind_eq(Default::default(), "headers/union_with_anon_unnamed_struct.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_pixel { - pub _bindgen_data_: [u32; 1usize], - } - impl Union_pixel { - pub unsafe fn rgba(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn r(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn g(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(1)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(2)) - } - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(3)) - } - } - impl ::std::clone::Clone for Union_pixel { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_pixel { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_anon_unnamed_union() { - assert_bind_eq(Default::default(), "headers/union_with_anon_unnamed_union.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_foo { - pub _bindgen_data_: [u32; 1usize], - } - impl Union_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn c(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_nesting() { - assert_bind_eq(Default::default(), "headers/union_with_nesting.h", " - #[repr(C)] - #[derive(Copy)] - #[derive(Debug)] - pub struct Union_foo { - pub _bindgen_data_: [u32; 1usize], - } - impl Union_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b1(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b2(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn c1(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(2)) - } - pub unsafe fn c2(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(2)) - } - } - impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} - -#[test] -fn with_derive_debug() { - assert_bind_eq(Default::default(), "headers/union_with_big_member.h", " - #[repr(C)] - #[derive(Copy)] - pub struct Union_WithBigArray { - pub _bindgen_data_: [u32; 33usize], - } - impl Union_WithBigArray { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut [::std::os::raw::c_int; 33usize] { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Union_WithBigArray { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_WithBigArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - #[repr(C)] - #[derive(Copy)] - pub struct Union_WithBigMember { - pub _bindgen_data_: [u32; 33usize], - } - impl Union_WithBigMember { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut Union_WithBigArray { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - } - impl ::std::clone::Clone for Union_WithBigMember { - fn clone(&self) -> Self { *self } - } - impl ::std::default::Default for Union_WithBigMember { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } - } - "); -} diff --git a/tests/tests.rs b/tests/tests.rs index 2e7072fe..aaa7628e 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,17 +1,122 @@ -#![allow(dead_code)] - -extern crate bindgen; -extern crate syntex_syntax as syntax; - -mod support; - -// Unused until we can generate code for tests -//mod test_cmath; -mod test_cxx; -mod test_enum; -mod test_decl; -mod test_extern; -mod test_func; -mod test_struct; -mod test_union; -mod test_builtins; +use std::env; +use std::fs; +use std::io::Read; +use std::path::{Path, PathBuf}; +use std::process; + +fn spawn_run_bindgen<P, Q, R>(run_bindgen: P, bindgen: Q, header: R) -> process::Child + where P: AsRef<Path>, + Q: AsRef<Path>, + R: AsRef<Path> +{ + let run_bindgen = run_bindgen.as_ref(); + let bindgen = bindgen.as_ref(); + let header = header.as_ref(); + + // Convert from "tests/headers/foo.hpp" to "tests/expectations/foo.rs" by + // saving the filename, popping off "headers/foo.hpp", pushing + // "expectations", pushing the saved filename, and finally modifying the + // extension. + + let mut expected = PathBuf::from(header); + let file_name = expected.file_name() + .expect("Should have filename") + .to_os_string(); + expected.pop(); + expected.pop(); + expected.push("expectations"); + expected.push(file_name); + expected.set_extension("rs"); + + process::Command::new(run_bindgen) + .arg(bindgen) + .arg(header) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .arg(expected) + .spawn() + .expect("Should be able to spawn run-bindgen.py child process") +} + +#[test] +fn run_bindgen_tests() { + let crate_root = env::var("CARGO_MANIFEST_DIR") + .expect("should have CARGO_MANIFEST_DIR environment variable"); + + let mut run_bindgen = PathBuf::from(&crate_root); + run_bindgen.push("tests"); + run_bindgen.push("tools"); + run_bindgen.push("run-bindgen.py"); + + let mut bindgen = PathBuf::from(&crate_root); + bindgen.push("target"); + bindgen.push("debug"); + bindgen.push("bindgen"); + if !bindgen.is_file() { + panic!("{} is not a file! Build bindgen before running tests.", + bindgen.display()); + } + + let mut headers_dir = PathBuf::from(&crate_root); + headers_dir.push("tests"); + headers_dir.push("headers"); + + let entries = fs::read_dir(&headers_dir) + .expect("Should read directory") + .map(|result| result.expect("Should read directory entry")); + + let tests = entries.filter(|entry| { + match entry.path().extension().map(|s| s.to_str()) { + Some(Some("h")) | + Some(Some("hpp")) => true, + _ => false, + } + }); + + // First spawn all child processes and collect them, then wait on each + // one. This runs the tests in parallel rather than serially. + + let children: Vec<_> = tests.map(|entry| { + let child = spawn_run_bindgen(run_bindgen.clone(), bindgen.clone(), entry.path()); + (entry.path(), child) + }) + .collect(); + + let failures: Vec<_> = children.into_iter() + .filter_map(|(path, mut child)| { + let passed = child.wait() + .expect("Should wait on child process") + .success(); + + if passed { None } else { Some((path, child)) } + }) + .collect(); + + let num_failures = failures.len(); + + for (path, child) in failures { + println!("FAIL: {}", path.display()); + + let mut buf = String::new(); + + child.stdout + .expect("should have stdout piped") + .read_to_string(&mut buf) + .expect("should read child's stdout"); + for line in buf.lines() { + println!("child stdout> {}", line); + } + + child.stderr + .expect("should have stderr piped") + .read_to_string(&mut buf) + .expect("should read child's stderr"); + for line in buf.lines() { + println!("child stderr> {}", line); + } + } + + if num_failures > 0 { + panic!("{} test failures!", num_failures); + } +} diff --git a/tests/tools/run-bindgen.py b/tests/tools/run-bindgen.py index 0d8ed580..656c6ae5 100755 --- a/tests/tools/run-bindgen.py +++ b/tests/tools/run-bindgen.py @@ -19,7 +19,7 @@ if len(sys.argv) != 4: flags = ["--no-unstable-rust"] -with open(sys.argv[2]) as f: +with open(c_path) as f: for line in f: if line.startswith(BINDGEN_FLAGS_PREFIX): flags.extend(line.strip().split(BINDGEN_FLAGS_PREFIX)[1].split(" ")) @@ -40,11 +40,30 @@ env = os.environ.copy() # https://forums.developer.apple.com/thread/9233 if "DYLD_LIBRARY_PATH" not in env and "LIBCLANG_PATH" in env: env["DYLD_LIBRARY_PATH"] = env["LIBCLANG_PATH"] -subprocess.check_call(base_command, cwd=os.getcwd(), env=env) +# If the rust file already exists, read it now so we can compare its contents +# before and after. +original_rust_contents = None +if os.path.isfile(rust_path): + with open(rust_path) as f: + original_rust_contents = f.read() + +subprocess.check_call(base_command, cwd=os.getcwd(), env=env) name = None with tempfile.NamedTemporaryFile(delete=False) as tests: name = tests.name subprocess.check_call(["rustc", "--test", sys.argv[3], "-o", tests.name]) subprocess.check_call([tests.name]) + +if original_rust_contents is not None: + new_rust_contents = None + with open(rust_path) as f: + new_rust_contents = f.read() + if new_rust_contents != original_rust_contents: + print("Generated rust bindings do not match expectation!") + print("Expected rust bindings:") + print(original_rust_contents) + print("Actual rust bindings:") + print(new_rust_contents) + sys.exit(1) |