<commit_before>require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))

describe "Callback" do
#  module LibC
#    extend FFI::Library
#    callback :qsort_cmp, [ :pointer, :pointer ], :int
#    attach_function :qsort, [ :pointer, :int, :int, :qsort_cmp ], :int
#  end
#  it "arguments get passed correctly" do
#    p = MemoryPointer.new(:int, 2)
#    p.put_array_of_int32(0, [ 1 , 2 ])
#    args = []
#    cmp = proc do |p1, p2| args.push(p1.get_int(0)); args.push(p2.get_int(0)); 0; end
#    # this is a bit dodgey, as it relies on qsort passing the args in order
#    LibC.qsort(p, 2, 4, cmp)
#    args.should == [ 1, 2 ]
#  end
#
#  it "Block can be substituted for Callback as last argument" do
#    p = MemoryPointer.new(:int, 2)
#    p.put_array_of_int32(0, [ 1 , 2 ])
#    args = []
#    # this is a bit dodgey, as it relies on qsort passing the args in order
#    LibC.qsort(p, 2, 4) do |p1, p2|
#      args.push(p1.get_int(0))
#      args.push(p2.get_int(0))
#      0
#    end
#    args.should == [ 1, 2 ]
#  end
  module LibTest
    extend FFI::Library
    ffi_lib TestLibrary::PATH
    callback :cbVrS8, [ ], :char
    callback :cbVrU8, [ ], :uchar
    callback :cbVrS16, [ ], :short
    callback :cbVrU16, [ ], :ushort
    callback :cbVrS32, [ ], :int
    callback :cbVrU32, [ ], :uint
    callback :cbVrS64, [ ], :long_long
    callback :cbVrU64, [ ], :ulong_long
    callback :cbVrP, [], :pointer
    callback :cbCrV, [ :char ], :void
    callback :cbSrV, [ :short ], :void
    callback :cbIrV, [ :int ], :void
    callback :cbLrV, [ :long_long ], :void
    attach_function :testCallbackVrS8, :testClosureVrB, [ :cbVrS8 ], :char
    attach_function :testCallbackVrU8, :testClosureVrB, [ :cbVrU8 ], :uchar
    attach_function :testCallbackVrS16, :testClosureVrS, [ :cbVrS16 ], :short
    attach_function :testCallbackVrU16, :testClosureVrS, [ :cbVrU16 ], :ushort
    attach_function :testCallbackVrS32, :testClosureVrI, [ :cbVrS32 ], :int
    attach_function :testCallbackVrU32, :testClosureVrI, [ :cbVrU32 ], :uint
    attach_function :testCallbackVrS64, :testClosureVrL, [ :cbVrS64 ], :long_long
    attach_function :testCallbackVrU64, :testClosureVrL, [ :cbVrU64 ], :ulong_long
    attach_function :testCallbackVrP, :testClosureVrP, [ :cbVrP ], :pointer
    attach_function :testCallbackCrV, :testClosureBrV, [ :cbCrV, :char ], :void
    attach_variable :cbVrS8, :gvar_pointer, :cbVrS8
    attach_variable :pVrS8, :gvar_pointer, :pointer
    attach_function :testGVarCallbackVrS8, :testClosureVrB, [ :pointer ], :char
    attach_function :testOptionalCallbackCrV, :testOptionalClosureBrV, [ :cbCrV, :char ], :void

  end
  it "function with Callback plus another arg should raise error if no arg given" do
    lambda { LibTest.testCallbackCrV { |*a| }}.should raise_error
  end
  it "returning :char (0)" do
    LibTest.testCallbackVrS8 { 0 }.should == 0
  end
  it "returning :char (127)" do
    LibTest.testCallbackVrS8 { 127 }.should == 127
  end
  it "returning :char (-128)" do
    LibTest.testCallbackVrS8 { -128 }.should == -128
  end
  # test wrap around
  it "returning :char (128)" do
    LibTest.testCallbackVrS8 { 128 }.should == -128
  end
  it "returning :char (255)" do
    LibTest.testCallbackVrS8 { 0xff }.should == -1
  end
  it "returning :uchar (0)" do
    LibTest.testCallbackVrU8 { 0 }.should == 0
  end
  it "returning :uchar (0xff)" do
    LibTest.testCallbackVrU8 { 0xff }.should == 0xff
  end
  it "returning :uchar (-1)" do
    LibTest.testCallbackVrU8 { -1 }.should == 0xff
  end
  it "returning :uchar (128)" do
    LibTest.testCallbackVrU8 { 128 }.should == 128
  end
  it "returning :uchar (-128)" do
    LibTest.testCallbackVrU8 { -128 }.should == 128
  end
  it "returning :short (0)" do
    LibTest.testCallbackVrS16 { 0 }.should == 0
  end
  it "returning :short (0x7fff)" do
    LibTest.testCallbackVrS16 { 0x7fff }.should == 0x7fff
  end
  # test wrap around
  it "returning :short (0x8000)" do
    LibTest.testCallbackVrS16 { 0x8000 }.should == -0x8000
  end
  it "returning :short (0xffff)" do
    LibTest.testCallbackVrS16 { 0xffff }.should == -1
  end
  it "returning :ushort (0)" do
    LibTest.testCallbackVrU16 { 0 }.should == 0
  end
  it "returning :ushort (0x7fff)" do
    LibTest.testCallbackVrU16 { 0x7fff }.should == 0x7fff
  end
  it "returning :ushort (0x8000)" do
    LibTest.testCallbackVrU16 { 0x8000 }.should == 0x8000
  end
  it "returning :ushort (0xffff)" do
    LibTest.testCallbackVrU16 { 0xffff }.should == 0xffff
  end
  it "returning :ushort (-1)" do
    LibTest.testCallbackVrU16 { -1 }.should == 0xffff
  end

  it "returning :int (0)" do
    LibTest.testCallbackVrS32 { 0 }.should == 0
  end
  it "returning :int (0x7fffffff)" do
    LibTest.testCallbackVrS32 { 0x7fffffff }.should == 0x7fffffff
  end
  # test wrap around
  it "returning :int (-0x80000000)" do
    LibTest.testCallbackVrS32 { -0x80000000 }.should == -0x80000000
  end
  it "returning :int (-1)" do
    LibTest.testCallbackVrS32 { -1 }.should == -1
  end

  it "returning :uint (0)" do
    LibTest.testCallbackVrU32 { 0 }.should == 0
  end
  it "returning :uint (0x7fffffff)" do
    LibTest.testCallbackVrU32 { 0x7fffffff }.should == 0x7fffffff
  end
  # test wrap around
  it "returning :uint (0x80000000)" do
    LibTest.testCallbackVrU32 { 0x80000000 }.should == 0x80000000
  end
  it "returning :uint (0xffffffff)" do
    LibTest.testCallbackVrU32 { 0xffffffff }.should == 0xffffffff
  end
  it "Callback returning :uint (-1)" do
    LibTest.testCallbackVrU32 { -1 }.should == 0xffffffff
  end

  it "returning :long_long (0)" do
    LibTest.testCallbackVrS64 { 0 }.should == 0
  end
  it "returning :long_long (0x7fffffffffffffff)" do
    LibTest.testCallbackVrS64 { 0x7fffffffffffffff }.should == 0x7fffffffffffffff
  end
  # test wrap around
  it "returning :long_long (-0x8000000000000000)" do
    LibTest.testCallbackVrS64 { -0x8000000000000000 }.should == -0x8000000000000000
  end
  it "returning :long_long (-1)" do
    LibTest.testCallbackVrS64 { -1 }.should == -1
  end
  it "returning :pointer (nil)" do
    LibTest.testCallbackVrP { nil }.null?.should be_true
  end
  it "returning :pointer (MemoryPointer)" do
    p = FFI::MemoryPointer.new :long
    LibTest.testCallbackVrP { p }.should == p
  end

  it "global variable" do
    proc = Proc.new { 0x1e }
    LibTest.cbVrS8 = proc
    LibTest.testGVarCallbackVrS8(LibTest.pVrS8).should == 0x1e
  end

  describe "When the callback is considered optional by the underlying library" do
    it "should handle receiving 'nil' in place of the closure" do
      LibTest.testOptionalCallbackCrV(nil, 13)
    end
  end

  describe "as return value" do

    it "should not blow up when a callback is defined that returns a callback" do
      module LibTest
        extend FFI::Library
        callback :cb_return_type_1, [ :short ], :short
        callback :cb_lookup_1, [ :short ], :cb_return_type_1
        attach_function :testReturnsCallback_1, :testReturnsClosure, [ :cb_lookup_1, :short ], :cb_return_type_1
      end      
    end

    it "should return a callback" do
      module LibTest
        extend FFI::Library
        callback :cb_return_type, [ :int ], :int
        callback :cb_lookup, [ ], :cb_return_type
        attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
      end      <commit_msg>Add spec for anonymous callback inside function definition<commit_after>require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))

describe "Callback" do
#  module LibC
#    extend FFI::Library
#    callback :qsort_cmp, [ :pointer, :pointer ], :int
#    attach_function :qsort, [ :pointer, :int, :int, :qsort_cmp ], :int
#  end
#  it "arguments get passed correctly" do
#    p = MemoryPointer.new(:int, 2)
#    p.put_array_of_int32(0, [ 1 , 2 ])
#    args = []
#    cmp = proc do |p1, p2| args.push(p1.get_int(0)); args.push(p2.get_int(0)); 0; end
#    # this is a bit dodgey, as it relies on qsort passing the args in order
#    LibC.qsort(p, 2, 4, cmp)
#    args.should == [ 1, 2 ]
#  end
#
#  it "Block can be substituted for Callback as last argument" do
#    p = MemoryPointer.new(:int, 2)
#    p.put_array_of_int32(0, [ 1 , 2 ])
#    args = []
#    # this is a bit dodgey, as it relies on qsort passing the args in order
#    LibC.qsort(p, 2, 4) do |p1, p2|
#      args.push(p1.get_int(0))
#      args.push(p2.get_int(0))
#      0
#    end
#    args.should == [ 1, 2 ]
#  end
  module LibTest
    extend FFI::Library
    ffi_lib TestLibrary::PATH
    callback :cbVrS8, [ ], :char
    callback :cbVrU8, [ ], :uchar
    callback :cbVrS16, [ ], :short
    callback :cbVrU16, [ ], :ushort
    callback :cbVrS32, [ ], :int
    callback :cbVrU32, [ ], :uint
    callback :cbVrS64, [ ], :long_long
    callback :cbVrU64, [ ], :ulong_long
    callback :cbVrP, [], :pointer
    callback :cbCrV, [ :char ], :void
    callback :cbSrV, [ :short ], :void
    callback :cbIrV, [ :int ], :void
    callback :cbLrV, [ :long_long ], :void
    attach_function :testCallbackVrS8, :testClosureVrB, [ :cbVrS8 ], :char
    attach_function :testCallbackVrU8, :testClosureVrB, [ :cbVrU8 ], :uchar
    attach_function :testCallbackVrS16, :testClosureVrS, [ :cbVrS16 ], :short
    attach_function :testCallbackVrU16, :testClosureVrS, [ :cbVrU16 ], :ushort
    attach_function :testCallbackVrS32, :testClosureVrI, [ :cbVrS32 ], :int
    attach_function :testCallbackVrU32, :testClosureVrI, [ :cbVrU32 ], :uint
    attach_function :testCallbackVrS64, :testClosureVrL, [ :cbVrS64 ], :long_long
    attach_function :testCallbackVrU64, :testClosureVrL, [ :cbVrU64 ], :ulong_long
    attach_function :testCallbackVrP, :testClosureVrP, [ :cbVrP ], :pointer
    attach_function :testCallbackCrV, :testClosureBrV, [ :cbCrV, :char ], :void
    attach_variable :cbVrS8, :gvar_pointer, :cbVrS8
    attach_variable :pVrS8, :gvar_pointer, :pointer
    attach_function :testGVarCallbackVrS8, :testClosureVrB, [ :pointer ], :char
    attach_function :testOptionalCallbackCrV, :testOptionalClosureBrV, [ :cbCrV, :char ], :void

  end
  it "function with Callback plus another arg should raise error if no arg given" do
    lambda { LibTest.testCallbackCrV { |*a| }}.should raise_error
  end
  it "returning :char (0)" do
    LibTest.testCallbackVrS8 { 0 }.should == 0
  end
  it "returning :char (127)" do
    LibTest.testCallbackVrS8 { 127 }.should == 127
  end
  it "returning :char (-128)" do
    LibTest.testCallbackVrS8 { -128 }.should == -128
  end
  # test wrap around
  it "returning :char (128)" do
    LibTest.testCallbackVrS8 { 128 }.should == -128
  end
  it "returning :char (255)" do
    LibTest.testCallbackVrS8 { 0xff }.should == -1
  end
  it "returning :uchar (0)" do
    LibTest.testCallbackVrU8 { 0 }.should == 0
  end
  it "returning :uchar (0xff)" do
    LibTest.testCallbackVrU8 { 0xff }.should == 0xff
  end
  it "returning :uchar (-1)" do
    LibTest.testCallbackVrU8 { -1 }.should == 0xff
  end
  it "returning :uchar (128)" do
    LibTest.testCallbackVrU8 { 128 }.should == 128
  end
  it "returning :uchar (-128)" do
    LibTest.testCallbackVrU8 { -128 }.should == 128
  end
  it "returning :short (0)" do
    LibTest.testCallbackVrS16 { 0 }.should == 0
  end
  it "returning :short (0x7fff)" do
    LibTest.testCallbackVrS16 { 0x7fff }.should == 0x7fff
  end
  # test wrap around
  it "returning :short (0x8000)" do
    LibTest.testCallbackVrS16 { 0x8000 }.should == -0x8000
  end
  it "returning :short (0xffff)" do
    LibTest.testCallbackVrS16 { 0xffff }.should == -1
  end
  it "returning :ushort (0)" do
    LibTest.testCallbackVrU16 { 0 }.should == 0
  end
  it "returning :ushort (0x7fff)" do
    LibTest.testCallbackVrU16 { 0x7fff }.should == 0x7fff
  end
  it "returning :ushort (0x8000)" do
    LibTest.testCallbackVrU16 { 0x8000 }.should == 0x8000
  end
  it "returning :ushort (0xffff)" do
    LibTest.testCallbackVrU16 { 0xffff }.should == 0xffff
  end
  it "returning :ushort (-1)" do
    LibTest.testCallbackVrU16 { -1 }.should == 0xffff
  end

  it "returning :int (0)" do
    LibTest.testCallbackVrS32 { 0 }.should == 0
  end
  it "returning :int (0x7fffffff)" do
    LibTest.testCallbackVrS32 { 0x7fffffff }.should == 0x7fffffff
  end
  # test wrap around
  it "returning :int (-0x80000000)" do
    LibTest.testCallbackVrS32 { -0x80000000 }.should == -0x80000000
  end
  it "returning :int (-1)" do
    LibTest.testCallbackVrS32 { -1 }.should == -1
  end

  it "returning :uint (0)" do
    LibTest.testCallbackVrU32 { 0 }.should == 0
  end
  it "returning :uint (0x7fffffff)" do
    LibTest.testCallbackVrU32 { 0x7fffffff }.should == 0x7fffffff
  end
  # test wrap around
  it "returning :uint (0x80000000)" do
    LibTest.testCallbackVrU32 { 0x80000000 }.should == 0x80000000
  end
  it "returning :uint (0xffffffff)" do
    LibTest.testCallbackVrU32 { 0xffffffff }.should == 0xffffffff
  end
  it "Callback returning :uint (-1)" do
    LibTest.testCallbackVrU32 { -1 }.should == 0xffffffff
  end

  it "returning :long_long (0)" do
    LibTest.testCallbackVrS64 { 0 }.should == 0
  end
  it "returning :long_long (0x7fffffffffffffff)" do
    LibTest.testCallbackVrS64 { 0x7fffffffffffffff }.should == 0x7fffffffffffffff
  end
  # test wrap around
  it "returning :long_long (-0x8000000000000000)" do
    LibTest.testCallbackVrS64 { -0x8000000000000000 }.should == -0x8000000000000000
  end
  it "returning :long_long (-1)" do
    LibTest.testCallbackVrS64 { -1 }.should == -1
  end
  it "returning :pointer (nil)" do
    LibTest.testCallbackVrP { nil }.null?.should be_true
  end
  it "returning :pointer (MemoryPointer)" do
    p = FFI::MemoryPointer.new :long
    LibTest.testCallbackVrP { p }.should == p
  end

  it "global variable" do
    proc = Proc.new { 0x1e }
    LibTest.cbVrS8 = proc
    LibTest.testGVarCallbackVrS8(LibTest.pVrS8).should == 0x1e
  end

  describe "When the callback is considered optional by the underlying library" do
    it "should handle receiving 'nil' in place of the closure" do
      LibTest.testOptionalCallbackCrV(nil, 13)
    end
  end

  describe 'when inlined' do
    it 'could be anonymous' do
      pending do
        module LibTest
          extend FFI::Library
          attach_function :testCallbackVrS8, :testClosureVrB, [ callback([ ], :char) ], :char
        end       
      end  
    end
  end

  describe "as return value" do

    it "should not blow up when a callback is defined that returns a callback" do
      module LibTest
        extend FFI::Library
        callback :cb_return_type_1, [ :short ], :short
        callback :cb_lookup_1, [ :short ], :cb_return_type_1
        attach_function :testReturnsCallback_1, :testReturnsClosure, [ :cb_lookup_1, :short ], :cb_return_type_1
      end      
    end

    it "should return a callback" do
      module LibTest
        extend FFI::Library
        callback :cb_return_type, [ :int ], :int
        callback :cb_lookup, [ ], :cb_return_type
        attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
      end      
{'fraction_non_alphanumeric': 0.11805325011619415, 'fraction_numerical': 0.05477723922714295, 'mean_word_length': 3.3506643558636626, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 44, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7216724', 'n_tokens_mistral': 6103, 'n_tokens_neox': 5554, 'n_words': 1468}