# 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 :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 = GirFFI::InPointer.from(:void, 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::InPointer.from_closure_data(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 = GirFFI::InOutPointer.for GIMarshallingTests::GEnum'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value'] 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 = GirFFI::InOutPointer.for GIMarshallingTests::Flags'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value'] end end describe 'for :object' 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 = GirFFI::InOutPointer.for [:pointer, Regress::TestObj]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = Regress::TestObj.wrap(_v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, GIMarshallingTests::BoxedStruct]' ] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GIMarshallingTests::BoxedStruct.wrap(_v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :strv]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Strv.wrap(_v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :array]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Array.wrap(:utf8, _v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :ptr_array]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::PtrArray.wrap(:utf8, _v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :error]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::Error.wrap(_v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :c]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GirFFI::SizedArray.wrap(:gint32, 4, _v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :c]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GirFFI::SizedArray.wrap(:gint32, bar, _v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :glist]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::List.wrap(:utf8, _v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :gslist]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::SList.wrap(:utf8, _v1.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, [:ghash, :utf8, :utf8]]'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = GLib::HashTable.wrap([:utf8, :utf8], _v1.to_value)'] 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 = GirFFI::InOutPointer.for GIMarshallingTests::Enum', "_v1.set_value #{arg_info.name}"] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value'] 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 = GirFFI::InOutPointer.for GIMarshallingTests::NoTypeFlags', "_v1.set_value #{arg_info.name}"] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value'] 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 = GirFFI::InOutPointer.for :gint32', "_v1.set_value #{arg_info.name}"] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value'] 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 = GirFFI::InOutPointer.for :gint32', '_v1.set_value n_ints'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value'] 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 = GirFFI::InOutPointer.for [:pointer, :strv]', '_v1.set_value 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.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :ptr_array]', '_v1.set_value 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.to_value)'] 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 = GirFFI::InOutPointer.for :utf8', '_v1.set_value GirFFI::InPointer.from(:utf8, utf8)'] end it 'has the correct value for #post_conversion' do builder.post_conversion.must_equal ['_v2 = _v1.to_value.to_utf8'] 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 = GirFFI::InOutPointer.for [:pointer, :c]', '_v1.set_value 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.to_value)'] 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 = GirFFI::InOutPointer.for [:pointer, :c]', '_v1.set_value GirFFI::SizedArray.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.to_value)'] 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 = GirFFI::InOutPointer.for :gint32', '_v1.set_value 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 = GirFFI::InOutPointer.for :gint32'] 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