require 'gir_ffi_test_helper' describe GirFFI::Builder do setup do @gir = GObjectIntrospection::IRepository.default end describe "::itypeinfo_to_callback_ffitype" do describe "for an :interface argument" do before do @iface = Object.new stub(@info = Object.new).interface { @iface } stub(@info).tag { :interface } stub(@info).pointer? { false } end it "correctly maps a :union argument to :pointer" do stub(@iface).info_type { :union } result = GirFFI::Builder.itypeinfo_to_callback_ffitype @info assert_equal :pointer, result end it "correctly maps a :flags argument to :int32" do stub(@iface).info_type { :flags } result = GirFFI::Builder.itypeinfo_to_callback_ffitype @info assert_equal :int32, result end end end describe "building GObject::Object" do before do save_module :GObject GirFFI::Builder.build_class get_introspection_data('GObject', 'Object') end should "create a Lib module in the parent namespace ready to attach functions from gobject-2.0" do expected = @gir.shared_library('GObject') assert_equal [expected], GObject::Lib.ffi_libraries.map(&:name) end should "not replace existing classes" do oldclass = GObject::Object GirFFI::Builder.build_class get_introspection_data('GObject', 'Object') assert_equal oldclass, GObject::Object end after do restore_module :GObject end end describe "looking at Regress.test_callback_destroy_notify" do before do save_module :GObject save_module :Regress GirFFI::Builder.build_module 'GObject' GirFFI::Builder.build_module 'Regress' @go = get_introspection_data 'Regress', 'test_callback_destroy_notify' end should "have the correct types of the arguments for the attached function" do argtypes = GirFFI::Builder.send(:ffi_function_argument_types, @go) assert_equal [Regress::TestCallbackUserData, :pointer, GLib::DestroyNotify], argtypes end should "define ffi callback types :Callback and :ClosureNotify" do Regress.setup_method 'test_callback_destroy_notify' tcud = Regress::Lib.find_type :TestCallbackUserData dn = GLib::Lib.find_type :DestroyNotify assert_equal FFI.find_type(:int32), tcud.result_type assert_equal FFI.find_type(:void), dn.result_type assert_equal [FFI.find_type(:pointer)], tcud.param_types assert_equal [FFI.find_type(:pointer)], dn.param_types end after do restore_module :Regress restore_module :GObject end end describe "building Regress::TestStructA" do setup do GirFFI::Builder.build_class get_introspection_data('Regress', 'TestStructA') end should "set up the correct struct members" do assert_equal [:some_int, :some_int8, :some_double, :some_enum], Regress::TestStructA::Struct.members end should "set up struct members with the correct offset" do info = @gir.find_by_name 'Regress', 'TestStructA' assert_equal info.fields.map{|f| [f.name.to_sym, f.offset]}, Regress::TestStructA::Struct.offsets end should "set up struct members with the correct types" do tags = [:int, :int8, :double, Regress::TestEnum] assert_equal tags.map {|t| FFI.find_type t}, Regress::TestStructA::Struct.layout.fields.map {|f| f.type} end end describe "building GObject::TypeCValue" do setup do GirFFI::Builder.build_class get_introspection_data('GObject', 'TypeCValue') end should "set up the correct union members" do assert_equal [:v_int, :v_long, :v_int64, :v_double, :v_pointer], GObject::TypeCValue::Struct.members end should "set up union members with the correct offset" do assert_equal [0, 0, 0, 0, 0], GObject::TypeCValue::Struct.offsets.map {|o| o[1]} end should "set up the inner class as derived from FFI::Union" do assert_equal FFI::Union, GObject::TypeCValue::Struct.superclass end end describe "building GObject::ValueArray" do should "use provided constructor if present" do GirFFI::Builder.build_class get_introspection_data('GObject', 'ValueArray') assert_nothing_raised { GObject::ValueArray.new 2 } end end describe "building Regress::TestBoxed" do setup do GirFFI::Builder.build_class get_introspection_data('Regress', 'TestBoxed') end should "set up #wrap" do assert Regress::TestBoxed.respond_to? "wrap" end should "set up #allocate" do assert Regress::TestBoxed.respond_to? "allocate" end end describe "built Regress module" do before do save_module :Regress GirFFI::Builder.build_module 'Regress' end should "autocreate singleton methods" do refute_defines_singleton_method Regress, :test_uint Regress.test_uint 31 assert_defines_singleton_method Regress, :test_uint end should "autocreate the TestObj class" do assert !Regress.const_defined?(:TestObj) assert_nothing_raised {Regress::TestObj} assert Regress.const_defined? :TestObj end should "know its own module builder" do assert GirFFI::Builder::Module === Regress.gir_ffi_builder end after do restore_module :Regress end end describe "built Regress::TestObj" do before do save_module :Regress GirFFI::Builder.build_class get_introspection_data('Regress', 'TestObj') end should "make autocreated instance method available to all instances" do o1 = Regress::TestObj.new_from_file("foo") o2 = Regress::TestObj.new_from_file("foo") o1.instance_method Regress::TestObj.class_eval do undef method_missing end assert_nothing_raised { o2.instance_method } end should "attach C functions to Regress::Lib" do o = Regress::TestObj.new_from_file("foo") o.instance_method assert Regress::Lib.respond_to? :regress_test_obj_instance_method end should "know its own GIR info" do assert_equal 'TestObj', Regress::TestObj.gir_info.name end should "know its own class builder" do assert GirFFI::Builder::Type::Base === Regress::TestObj.gir_ffi_builder end describe "its #torture_signature_0 method" do should "have the correct types of the arguments for the attached function" do info = get_method_introspection_data 'Regress', 'TestObj', 'torture_signature_0' assert_equal [:pointer, :int32, :pointer, :pointer, :pointer, :pointer, :uint32], GirFFI::Builder.send(:ffi_function_argument_types, info) end end after do restore_module :Regress end end describe "built Regress::TestSubObj" do before do save_module :Regress GirFFI::Builder.build_class get_introspection_data('Regress', 'TestSubObj') end should "autocreate parent class' set_bare inside the parent class" do o1 = Regress::TestSubObj.new o2 = Regress::TestObj.new_from_file("foo") assert_nothing_raised {o1.set_bare(nil)} Regress::TestObj.class_eval do undef method_missing end assert_nothing_raised {o2.set_bare(nil)} end should "use its own version of instance_method when parent's version has been created" do obj = Regress::TestObj.new_from_file("foo") assert_equal(-1, obj.instance_method) subobj = Regress::TestSubObj.new assert_equal 0, subobj.instance_method end after do restore_module :Regress end end describe "built Gio::ThreadedSocketService" do before do save_module :Gio GirFFI::Builder.build_module 'Gio' end describe "when parent constructor has been called" do setup do Gio::SocketService.new end should "still use its own constructor" do assert_nothing_raised { Gio::ThreadedSocketService.new 2 } end end after do restore_module :Gio end end describe "building Regress::TestSubObj" do before do save_module :Regress save_module :GObject GirFFI::Builder.build_class get_introspection_data('Regress', 'TestSubObj') end it "builds Regress namespace" do assert Regress.const_defined? :Lib assert Regress.respond_to? :method_missing end it "builds parent classes also" do assert Regress.const_defined? :TestObj assert Object.const_defined? :GObject assert GObject.const_defined? :Object end it "sets up the inheritance chain" do ancestors = Regress::TestSubObj.ancestors assert_equal [ Regress::TestSubObj, Regress::TestObj, GObject::Object ], ancestors[0..2] end it "creates a Regress::TestSubObj#to_ptr method" do assert Regress::TestSubObj.public_method_defined? :to_ptr end after do restore_module :Regress restore_module :GObject end end describe "building Regress" do before do save_module :Regress GirFFI::Builder.build_module 'Regress' end it "creates a Lib module ready to attach functions from the shared library" do gir = GObjectIntrospection::IRepository.default expected = [gir.shared_library('Regress')] assert_equal expected, Regress::Lib.ffi_libraries.map(&:name) end it "does not replace existing module" do oldmodule = Regress GirFFI::Builder.build_module 'Regress' assert_equal oldmodule, Regress end it "does not replace existing Lib module" do oldmodule = Regress::Lib GirFFI::Builder.build_module 'Regress' assert_equal oldmodule, Regress::Lib end after do restore_module :Regress end end describe "looking at Regress.test_array_gint32_in" do setup do save_module :Regress GirFFI::Builder.build_module 'Regress' @go = get_introspection_data 'Regress', 'test_array_gint32_in' end it "has correct introspection data" do gir = GObjectIntrospection::IRepository.default gir.require "Regress", nil go2 = gir.find_by_name "Regress", "test_array_gint32_in" assert_equal go2, @go end it "attaches function to Regress::Lib" do GirFFI::Builder.send :attach_ffi_function, Regress::Lib, @go assert_defines_singleton_method Regress::Lib, :regress_test_array_gint32_in end it "has :pointer, :pointer as types of the arguments for the attached function" do assert_equal [:int32, :pointer], GirFFI::Builder.send(:ffi_function_argument_types, @go) end it "has :void as return type for the attached function" do assert_equal :int32, GirFFI::Builder.send(:ffi_function_return_type, @go) end after do restore_module :Regress end end describe "looking at Regress::TestObj#instance_method" do setup do @go = get_method_introspection_data 'Regress', 'TestObj', 'instance_method' end it "has :pointer as types of the arguments for the attached function" do assert_equal [:pointer], GirFFI::Builder.send(:ffi_function_argument_types, @go) end end end