# frozen_string_literal: true require 'gir_ffi_test_helper' describe GirFFI::InfoExt::ITypeInfo do let(:info_class) do Class.new do include GirFFI::InfoExt::ITypeInfo end end let(:type_info) { info_class.new } let(:elmtype_info) { info_class.new } let(:keytype_info) { info_class.new } let(:valtype_info) { info_class.new } let(:iface_info) { Object.new } let(:callback_type_info) do get_introspection_data('Regress', 'test_callback').args[0].argument_type end let(:ghash_type_info) do get_introspection_data('Regress', 'test_ghash_nested_everything_return').return_type end describe '#to_ffi_type' do it 'returns an array with elements subtype and size for type :array' do expect(type_info).to receive(:pointer?).and_return false allow(type_info).to receive(:tag).and_return :array expect(type_info).to receive(:array_fixed_size).and_return 2 expect(elmtype_info).to receive(:to_ffi_type).and_return :foo expect(type_info).to receive(:param_type).with(0).and_return elmtype_info result = type_info.to_ffi_type assert_equal [:foo, 2], result end describe 'for an :interface type' do before do allow(type_info).to receive(:interface).and_return iface_info allow(type_info).to receive(:tag).and_return :interface allow(type_info).to receive(:pointer?).and_return false end it "maps a the interface's ffi_type" do allow(iface_info).to receive(:to_ffi_type).and_return :foo type_info.to_ffi_type.must_equal :foo end end end describe '#element_type' do it 'returns the element type for lists' do allow(elmtype_info).to receive(:tag).and_return :foo expect(elmtype_info).to receive(:pointer?).and_return false expect(type_info).to receive(:tag).and_return :glist expect(type_info).to receive(:param_type).with(0).and_return elmtype_info result = type_info.element_type result.must_equal :foo end it 'returns the key and value types for ghashes' do allow(keytype_info).to receive(:tag).and_return :foo expect(keytype_info).to receive(:pointer?).and_return false allow(valtype_info).to receive(:tag).and_return :bar expect(valtype_info).to receive(:pointer?).and_return false expect(type_info).to receive(:tag).and_return :ghash expect(type_info).to receive(:param_type).with(0).and_return keytype_info expect(type_info).to receive(:param_type).with(1).and_return valtype_info result = type_info.element_type result.must_equal [:foo, :bar] end it 'returns nil for other types' do expect(type_info).to receive(:tag).and_return :foo result = type_info.element_type result.must_be_nil end it 'returns [:pointer, :void] if the element type is a pointer with tag :void' do allow(elmtype_info).to receive(:tag_or_class).and_return [:pointer, :void] expect(type_info).to receive(:tag).and_return :glist expect(type_info).to receive(:param_type).with(0).and_return elmtype_info assert_equal [:pointer, :void], type_info.element_type end end describe '#flattened_tag' do describe 'for a simple type' do it 'returns the type tag' do allow(type_info).to receive(:tag).and_return :uint32 type_info.flattened_tag.must_equal :uint32 end end describe 'for a zero-terminated array' do before do allow(type_info).to receive(:tag).and_return :array allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(type_info).to receive(:zero_terminated?).and_return true end describe 'of utf8' do it 'returns :strv' do allow(elmtype_info).to receive(:tag).and_return :utf8 allow(elmtype_info).to receive(:pointer?).and_return true type_info.flattened_tag.must_equal :strv end end describe 'of filename' do it 'returns :strv' do allow(elmtype_info).to receive(:tag).and_return :filename allow(elmtype_info).to receive(:pointer?).and_return true type_info.flattened_tag.must_equal :strv end end describe 'of another type' do it 'returns :zero_terminated' do allow(elmtype_info).to receive(:tag).and_return :foo allow(elmtype_info).to receive(:pointer?).and_return false type_info.flattened_tag.must_equal :zero_terminated end end end describe 'for a fixed length c-like array' do it 'returns :c' do expect(type_info).to receive(:tag).and_return :array expect(type_info).to receive(:zero_terminated?).and_return false expect(type_info).to receive(:array_type).and_return :c type_info.flattened_tag.must_equal :c end end describe 'for a GLib array' do it 'returns :c' do expect(type_info).to receive(:tag).and_return :array expect(type_info).to receive(:zero_terminated?).and_return false expect(type_info).to receive(:array_type).and_return :array type_info.flattened_tag.must_equal :array end end end describe '#tag_or_class' do describe 'for a simple type' do it "returns the type's tag" do allow(type_info).to receive(:tag).and_return :foo expect(type_info).to receive(:pointer?).and_return false type_info.tag_or_class.must_equal :foo end end describe 'for utf8 strings' do it 'returns the tag :utf8' do allow(type_info).to receive(:tag).and_return :utf8 expect(type_info).to receive(:pointer?).and_return true type_info.tag_or_class.must_equal :utf8 end end describe 'for filename strings' do it 'returns the tag :filename' do allow(type_info).to receive(:tag).and_return :filename expect(type_info).to receive(:pointer?).and_return true type_info.tag_or_class.must_equal :filename end end describe 'for an interface class' do let(:interface) { Object.new } before do allow(type_info).to receive(:tag).and_return :interface allow(type_info).to receive(:interface).and_return iface_info expect(type_info).to receive(:pointer?).and_return false expect(GirFFI::Builder).to receive(:build_class).with(iface_info).and_return interface end describe 'when the interface type is :enum' do it 'returns the built interface module' do allow(iface_info).to receive(:info_type).and_return :enum type_info.tag_or_class.must_equal interface end end describe 'when the interface type is :object' do it 'returns the built interface class' do allow(iface_info).to receive(:info_type).and_return :object type_info.tag_or_class.must_equal interface end end describe 'when the interface type is :struct' do it 'returns the built interface class' do allow(iface_info).to receive(:info_type).and_return :struct type_info.tag_or_class.must_equal interface end end end describe 'for a callback' do it "returns the callback's wrapper class" do callback_type_info.tag_or_class.must_equal Regress::TestCallback end end describe 'for a pointer to simple type :foo' do it 'returns [:pointer, :foo]' do allow(type_info).to receive(:tag).and_return :foo expect(type_info).to receive(:pointer?).and_return true type_info.tag_or_class.must_equal [:pointer, :foo] end end describe 'for a pointer to :void' do it 'returns [:pointer, :void]' do allow(type_info).to receive(:tag).and_return :void allow(type_info).to receive(:pointer?).and_return true type_info.tag_or_class.must_equal [:pointer, :void] end end describe 'for a complex nested hash type' do it 'returns a representeation of the nested structure' do ghash_type_info.tag_or_class.must_equal( [:pointer, [:ghash, :utf8, [:pointer, [:ghash, :utf8, :utf8]]]]) end end end describe '#to_callback_ffi_type' do describe 'for an :interface argument' do before do allow(type_info).to receive(:interface).and_return iface_info allow(type_info).to receive(:tag).and_return :interface allow(type_info).to receive(:pointer?).and_return false end it 'correctly maps a :union argument to :pointer' do allow(iface_info).to receive(:info_type).and_return :union type_info.to_callback_ffi_type.must_equal :pointer end it 'correctly maps a :flags argument to :int32' do allow(iface_info).to receive(:info_type).and_return :flags type_info.to_callback_ffi_type.must_equal :int32 end end end describe '#extra_conversion_arguments' do describe 'for normal types' do before do allow(type_info).to receive(:tag).and_return :foo end it 'returns an empty array' do type_info.extra_conversion_arguments.must_equal [] end end describe 'for a fixed-size array' do before do allow(type_info).to receive(:tag).and_return :array allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :c allow(type_info).to receive(:array_fixed_size).and_return 3 allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end it 'returns an array containing the element type' do type_info.extra_conversion_arguments.must_equal [:foo, 3] end end describe 'for a zero-terminated array' do before do allow(type_info).to receive(:tag).and_return :array allow(type_info).to receive(:zero_terminated?).and_return true allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end it 'returns an array containing the element type' do type_info.extra_conversion_arguments.must_equal [:foo] end end describe 'for a GArray' do before do allow(type_info).to receive(:tag).and_return :array allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :array allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end it 'returns an array containing the element type' do type_info.extra_conversion_arguments.must_equal [:foo] end end describe 'for a GHashTable' do before do allow(type_info).to receive(:tag).and_return :ghash allow(type_info).to receive(:param_type).with(0).and_return keytype_info allow(type_info).to receive(:param_type).with(1).and_return valtype_info allow(keytype_info).to receive(:tag_or_class).and_return :foo allow(valtype_info).to receive(:tag_or_class).and_return :bar end it 'returns an array containing the element type pair' do type_info.extra_conversion_arguments.must_equal [[:foo, :bar]] end end describe 'for a GList' do before do allow(type_info).to receive(:tag).and_return :glist allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end it 'returns an array containing the element type' do type_info.extra_conversion_arguments.must_equal [:foo] end end describe 'for a GSList' do before do allow(type_info).to receive(:tag).and_return :gslist allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end it 'returns an array containing the element type' do type_info.extra_conversion_arguments.must_equal [:foo] end end describe 'for a GPtrArray' do before do allow(type_info).to receive(:tag).and_return :array allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :ptr_array allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end it 'returns an array containing the element type' do type_info.extra_conversion_arguments.must_equal [:foo] end end describe 'for a :callback' do before do allow(interface_type_info = Object.new).to receive(:namespace).and_return 'Bar' allow(interface_type_info).to receive(:name).and_return 'Foo' allow(type_info).to receive(:tag).and_return :callback allow(type_info).to receive(:interface).and_return interface_type_info end it 'returns an empty array' do type_info.extra_conversion_arguments.must_equal [] end end end describe '#argument_class_name' do before do allow(type_info).to receive(:tag).and_return tag end describe 'for :gint32' do let(:tag) { :gint32 } it 'is nil' do type_info.argument_class_name.must_be_nil end end describe 'for interfaces' do let(:tag) { :interface } before do allow(type_info).to receive(:interface).and_return iface_info allow(iface_info).to receive(:info_type).and_return interface_type allow(iface_info).to receive(:full_type_name).and_return 'Bar::Foo' end describe 'for :struct' do let(:interface_type) { :struct } it 'equals the struct class name' do type_info.argument_class_name.must_equal 'Bar::Foo' end end describe 'for :union' do let(:interface_type) { :union } it 'equals the union class name' do type_info.argument_class_name.must_equal 'Bar::Foo' end end describe 'for :interface' do let(:interface_type) { :interface } it 'equals the interface module name' do type_info.argument_class_name.must_equal 'Bar::Foo' end end describe 'for :object' do let(:interface_type) { :object } it 'equals the object class name' do type_info.argument_class_name.must_equal 'Bar::Foo' end end describe 'for :callback' do let(:interface_type) { :callback } it 'equals the callback type name' do type_info.argument_class_name.must_equal 'Bar::Foo' end end end describe 'for :strv' do let(:tag) { :strv } it 'equals GLib::Strv' do type_info.argument_class_name.must_equal 'GLib::Strv' end end describe 'for arrays' do let(:tag) { :array } before do allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(elmtype_info).to receive(:tag_or_class).and_return :foo end describe 'for :zero_terminated' do before do allow(type_info).to receive(:zero_terminated?).and_return true end it 'equals GirFFI::ZeroTerminated' do type_info.argument_class_name.must_equal 'GirFFI::ZeroTerminated' end end describe 'for :byte_array' do before do allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :byte_array end it 'equals GLib::ByteArray' do type_info.argument_class_name.must_equal 'GLib::ByteArray' end end describe 'for :ptr_array' do before do allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :ptr_array end it 'equals GLib::PtrArray' do type_info.argument_class_name.must_equal 'GLib::PtrArray' end end describe 'for :array' do before do allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :array end it 'equals GLib::Array' do type_info.argument_class_name.must_equal 'GLib::Array' end end end describe 'for :glist' do let(:tag) { :glist } it 'equals GLib::List' do type_info.argument_class_name.must_equal 'GLib::List' end end describe 'for :gslist' do let(:tag) { :gslist } it 'equals GLib::SList' do type_info.argument_class_name.must_equal 'GLib::SList' end end describe 'for :ghash' do let(:tag) { :ghash } it 'equals GLib::HashTable' do type_info.argument_class_name.must_equal 'GLib::HashTable' end end describe 'for :error' do let(:tag) { :error } it 'equals GLib::Error' do type_info.argument_class_name.must_equal 'GLib::Error' end end end describe '#gtype' do before do allow(type_info).to receive(:tag).and_return tag allow(type_info).to receive(:pointer?).and_return pointer? end describe 'for :void' do let(:tag) { :void } let(:pointer?) { false } it 'equals the none type' do GObject.type_name(type_info.gtype).must_equal 'void' end end describe 'for :void pointer' do let(:tag) { :void } let(:pointer?) { true } it 'equals the none type' do GObject.type_name(type_info.gtype).must_equal 'gpointer' end end describe 'for :gboolean' do let(:tag) { :gboolean } let(:pointer?) { false } it 'equals the gboolean type' do GObject.type_name(type_info.gtype).must_equal 'gboolean' end end describe 'for :gint32' do let(:tag) { :gint32 } let(:pointer?) { false } it 'equals the gint type' do GObject.type_name(type_info.gtype).must_equal 'gint' end end describe 'for :gint64' do let(:tag) { :gint64 } let(:pointer?) { false } it 'equals the gint64 type' do GObject.type_name(type_info.gtype).must_equal 'gint64' end end describe 'for :guint64' do let(:tag) { :guint64 } let(:pointer?) { false } it 'equals the guint64 type' do GObject.type_name(type_info.gtype).must_equal 'guint64' end end describe 'for pointer to :utf8' do let(:tag) { :utf8 } let(:pointer?) { true } it 'equals the gchararray type' do GObject.type_name(type_info.gtype).must_equal 'gchararray' end end describe 'for pointer to :ghash' do let(:tag) { :ghash } let(:pointer?) { true } it 'equals the GHashTable type' do GObject.type_name(type_info.gtype).must_equal 'GHashTable' end end describe 'for pointer to :glist' do let(:tag) { :glist } let(:pointer?) { true } it 'equals the pointer type' do GObject.type_name(type_info.gtype).must_equal 'gpointer' end end describe 'for arrays' do let(:tag) { :array } let(:pointer?) { true } describe 'for pointer to GArray' do before do allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :array end it 'equals the GArray type' do GObject.type_name(type_info.gtype).must_equal 'GArray' end end describe 'for a C array' do before do allow(type_info).to receive(:zero_terminated?).and_return false allow(type_info).to receive(:array_type).and_return :c end it 'equals the gpointer type' do GObject.type_name(type_info.gtype).must_equal 'gpointer' end end describe 'for a zero-terminated array' do before do allow(type_info).to receive(:param_type).with(0).and_return elmtype_info allow(type_info).to receive(:zero_terminated?).and_return true end describe 'of utf8' do it 'equals the GStrv type' do allow(elmtype_info).to receive(:tag).and_return :utf8 allow(elmtype_info).to receive(:pointer?).and_return true GObject.type_name(type_info.gtype).must_equal 'GStrv' end end describe 'of filename' do it 'equals the GStrv type' do allow(elmtype_info).to receive(:tag).and_return :filename allow(elmtype_info).to receive(:pointer?).and_return true GObject.type_name(type_info.gtype).must_equal 'GStrv' end end end end end end