# frozen_string_literal: true require 'gir_ffi_test_helper' describe GirFFI::Builders::ArgumentBuilder do let(:var_gen) { GirFFI::VariableNameGenerator.new } let(:builder) { GirFFI::Builders::ArgumentBuilder.new(var_gen, arg_info) } describe 'for an argument with direction :in' do describe 'for :c' do describe 'with full ownership transfer' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'array_struct_take_in').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion. must_equal ['_v1 = GirFFI::SizedArray.copy_from([:pointer, GIMarshallingTests::BoxedStruct], -1, structs)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end end describe 'for :callback' do let(:arg_info) do get_introspection_data('Regress', 'test_callback_destroy_notify').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = Regress::TestCallbackUserData.from(callback)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end describe 'for :zero_terminated' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'array_in_len_zero_terminated').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = GirFFI::ZeroTerminated.from(:gint32, ints)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end describe 'for :void' do let(:arg_info) { get_introspection_data('Regress', 'test_callback_user_data').args[1] } describe 'when it is a regular argument' do before do builder.closure = false end it 'has the correct value for method_argument_name' do builder.method_argument_name.must_equal arg_info.name end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = user_data'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end describe 'when it is a closure' do before do callback = Object.new allow(callback).to receive(:call_argument_name).and_return 'foo' builder.closure = callback end it 'has the correct value for method_argument_name' do builder.method_argument_name.must_be_nil end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = GirFFI::ArgHelper.store(foo)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end end end describe 'for an argument with direction :out' do describe 'for :enum' do let(:arg_info) { get_introspection_data('GIMarshallingTests', 'genum_out').args[0] } it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new GIMarshallingTests::GEnum'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GIMarshallingTests::GEnum.get_value_from_pointer(_v1, 0)'] end end describe 'for :flags' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'flags_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new GIMarshallingTests::Flags'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GIMarshallingTests::Flags.get_value_from_pointer(_v1, 0)'] end end describe 'for :object' do describe 'with full ownership transfer' do let(:arg_info) do get_method_introspection_data('Regress', 'TestObj', 'null_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = Regress::TestObj.wrap(_v1.get_pointer(0))'] end end describe 'with no ownership transfer' do let(:arg_info) do get_method_introspection_data('GIMarshallingTests', 'Object', 'none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion. must_equal ['_v2 = GIMarshallingTests::Object.wrap(_v1.get_pointer(0)).tap { |it| it && it.ref }'] end end end describe 'for :struct' do describe 'when not allocated by the caller' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'boxed_struct_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal [ '_v1 = FFI::MemoryPointer.new :pointer' ] end it 'has the correct value for #post_conversion' do builder.post_conversion. must_equal ['_v2 = GIMarshallingTests::BoxedStruct.wrap_copy(_v1.get_pointer(0))'] end end describe 'when allocated by the caller' do let(:arg_info) do get_method_introspection_data('Regress', 'TestStructA', 'clone').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = Regress::TestStructA.new'] end it 'has empty #post_conversion' do builder.post_conversion.must_equal [] end end end describe 'for :strv' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'gstrv_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Strv.wrap(_v1.get_pointer(0))'] end end describe 'for :array' do describe 'when allocated by the callee' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'garray_utf8_none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Array.wrap(:utf8, _v1.get_pointer(0))'] end end describe 'when allocated by the caller' do let(:function_info) do get_introspection_data('GIMarshallingTests', 'garray_utf8_full_out_caller_allocated') end let(:arg_info) { function_info.args[0] } before do skip unless function_info end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = GLib::Array.new :utf8'] end it 'has empty #post_conversion' do builder.post_conversion.must_equal [] end end end describe 'for :ptr_array' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'gptrarray_utf8_none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::PtrArray.wrap(:utf8, _v1.get_pointer(0))'] end end describe 'for :error' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'gerror_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Error.wrap(_v1.get_pointer(0))'] end end describe 'for :c' do describe 'with fixed size' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'array_fixed_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GirFFI::SizedArray.wrap(:gint32, 4, _v1.get_pointer(0))'] end end describe 'with separate size parameter' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'array_out').args[0] end let(:length_argument) { Object.new } before do allow(length_argument).to receive(:post_converted_name).and_return 'bar' builder.length_arg = length_argument end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GirFFI::SizedArray.wrap(:gint32, bar, _v1.get_pointer(0))'] end end end describe 'for :glist' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'glist_utf8_none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::List.wrap(:utf8, _v1.get_pointer(0))'] end end describe 'for :gslist' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'gslist_utf8_none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::SList.wrap(:utf8, _v1.get_pointer(0))'] end end describe 'for :ghash' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'ghashtable_utf8_none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::HashTable.wrap([:utf8, :utf8], _v1.get_pointer(0))'] end end describe 'for :utf8' do describe 'with full ownership transfer' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'utf8_full_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [ '_v2 = GirFFI::AllocationHelper.free_after _v1.get_pointer(0), &:to_utf8' ] end it 'has the correct value for #return_value_name' do builder.post_conversion builder.return_value_name.must_equal '_v2' end end describe 'with no ownership transfer' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'utf8_none_out').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.get_pointer(0).to_utf8'] end end end end describe 'for an argument with direction :inout' do describe 'for :enum' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'enum_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new GIMarshallingTests::Enum', "GIMarshallingTests::Enum.copy_value_to_pointer(#{arg_info.name}, _v1)"] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GIMarshallingTests::Enum.get_value_from_pointer(_v1, 0)'] end end describe 'for :flags' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'no_type_flags_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion. must_equal ['_v1 = FFI::MemoryPointer.new GIMarshallingTests::NoTypeFlags', "GIMarshallingTests::NoTypeFlags.copy_value_to_pointer(#{arg_info.name}, _v1)"] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GIMarshallingTests::NoTypeFlags.get_value_from_pointer(_v1, 0)'] end end describe 'for :gint32' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'int32_inout_min_max').args[0] end it 'has the correct value for method_argument_name' do builder.method_argument_name.must_equal arg_info.name end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :int32', "_v1.put_int32 0, #{arg_info.name}"] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.get_int32(0)'] end end describe 'for an array length' do let(:function_info) do get_introspection_data('Regress', 'test_array_int_inout') end let(:arg_info) { function_info.args[0] } let(:array_arg_info) { function_info.args[1] } let(:array_arg_builder) do GirFFI::Builders::ArgumentBuilder.new(var_gen, array_arg_info) end before do builder.array_arg = array_arg_builder end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['n_ints = ints.nil? ? 0 : ints.length', '_v1 = FFI::MemoryPointer.new :int32', '_v1.put_int32 0, n_ints'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.get_int32(0)'] end end describe 'for :strv' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'gstrv_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer', '_v1.put_pointer 0, GLib::Strv.from(g_strv)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Strv.wrap(_v1.get_pointer(0))'] end end describe 'for :ptr_array' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'gptrarray_utf8_none_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer', '_v1.put_pointer 0, GLib::PtrArray.from(:utf8, parray_)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::PtrArray.wrap(:utf8, _v1.get_pointer(0))'] end end describe 'for :utf8' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'utf8_none_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :pointer', '_v1.put_pointer 0, GirFFI::InPointer.from_utf8(utf8)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.get_pointer(0).to_utf8'] end end describe 'for :struct' do describe 'with full ownership transfer' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'boxed_struct_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal [ '_v1 = FFI::MemoryPointer.new :pointer', '_v1.put_pointer 0, GIMarshallingTests::BoxedStruct.copy_from(struct_)' ] end it 'has the correct value for #post_conversion' do builder.post_conversion. must_equal ['_v2 = GIMarshallingTests::BoxedStruct.wrap_own(_v1.get_pointer(0))'] end end end describe 'for :c' do describe 'with fixed size' do let(:arg_info) do get_introspection_data('GIMarshallingTests', 'array_fixed_inout').args[0] end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal [ 'GirFFI::ArgHelper.check_fixed_array_size 4, ints, "ints"', '_v1 = FFI::MemoryPointer.new :pointer', '_v1.put_pointer 0, GirFFI::SizedArray.from(:gint32, 4, ints)' ] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GirFFI::SizedArray.wrap(:gint32, 4, _v1.get_pointer(0))'] end end describe 'with separate size parameter' do let(:function_info) do get_introspection_data('Regress', 'test_array_int_inout') end let(:length_arg_info) { function_info.args[0] } let(:arg_info) { function_info.args[1] } let(:length_arg_builder) do GirFFI::Builders::ArgumentBuilder.new(var_gen, length_arg_info) end before do builder.length_arg = length_arg_builder end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal [ '_v1 = FFI::MemoryPointer.new :pointer', '_v1.put_pointer 0, GirFFI::SizedArray.copy_from(:gint32, -1, ints)' ] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v3 = GirFFI::SizedArray.wrap(:gint32, _v2, _v1.get_pointer(0))'] end end end end describe 'for a skipped argument with direction :in' do let(:arg_info) do get_method_introspection_data('Regress', 'TestObj', 'skip_param').args[2] end it 'has the correct value for method_argument_name' do builder.method_argument_name.must_be_nil end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = 0'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end describe 'for a skipped argument with direction :inout' do let(:arg_info) do get_method_introspection_data('Regress', 'TestObj', 'skip_inout_param').args[3] end it 'has the correct value for method_argument_name' do builder.method_argument_name.must_be_nil end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :int32', '_v1.put_int32 0, 0'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end describe 'for a skipped argument with direction :out' do let(:arg_info) do get_method_introspection_data('Regress', 'TestObj', 'skip_out_param').args[1] end it 'has the correct value for method_argument_name' do builder.method_argument_name.must_be_nil end it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal ['_v1 = FFI::MemoryPointer.new :int32'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [] end end describe 'for an argument with direction :error' do let(:arg_info) { GirFFI::ErrorArgumentInfo.new } it 'has the correct value for #pre_conversion' do builder.pre_conversion.must_equal [ '_v1 = FFI::MemoryPointer.new(:pointer).write_pointer nil' ] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal [ 'GirFFI::ArgHelper.check_error(_v1)' ] end end end