summaryrefslogtreecommitdiff
path: root/test/fiddle/test_c_struct_entry.rb
blob: 9fd16d71014c9daa640bdad6c1c701a24c9726f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# frozen_string_literal: true
begin
  require_relative 'helper'
  require 'fiddle/struct'
rescue LoadError
end

module Fiddle
  class TestCStructEntity < TestCase
    def test_class_size
      types = [TYPE_DOUBLE, TYPE_CHAR]

      size = CStructEntity.size types

      alignments = types.map { |type| PackInfo::ALIGN_MAP[type] }

      expected = PackInfo.align 0, alignments[0]
      expected += PackInfo::SIZE_MAP[TYPE_DOUBLE]

      expected = PackInfo.align expected, alignments[1]
      expected += PackInfo::SIZE_MAP[TYPE_CHAR]

      expected = PackInfo.align expected, alignments.max

      assert_equal expected, size
    end

    def test_class_size_with_count
      size = CStructEntity.size([[TYPE_DOUBLE, 2], [TYPE_CHAR, 20]])

      types = [TYPE_DOUBLE, TYPE_CHAR]
      alignments = types.map { |type| PackInfo::ALIGN_MAP[type] }

      expected = PackInfo.align 0, alignments[0]
      expected += PackInfo::SIZE_MAP[TYPE_DOUBLE] * 2

      expected = PackInfo.align expected, alignments[1]
      expected += PackInfo::SIZE_MAP[TYPE_CHAR] * 20

      expected = PackInfo.align expected, alignments.max

      assert_equal expected, size
    end

    def test_set_ctypes
      CStructEntity.malloc([TYPE_INT, TYPE_LONG], Fiddle::RUBY_FREE) do |struct|
        struct.assign_names %w[int long]

        # this test is roundabout because the stored ctypes are not accessible
        struct['long'] = 1
        struct['int'] = 2

        assert_equal 1, struct['long']
        assert_equal 2, struct['int']
      end
    end

    def test_aref_pointer_array
      CStructEntity.malloc([[TYPE_VOIDP, 2]], Fiddle::RUBY_FREE) do |team|
        team.assign_names(["names"])
        Fiddle::Pointer.malloc(6, Fiddle::RUBY_FREE) do |alice|
          alice[0, 6] = "Alice\0"
          Fiddle::Pointer.malloc(4, Fiddle::RUBY_FREE) do |bob|
            bob[0, 4] = "Bob\0"
            team["names"] = [alice, bob]
            assert_equal(["Alice", "Bob"], team["names"].map(&:to_s))
          end
        end
      end
    end

    def test_aref_pointer
      CStructEntity.malloc([TYPE_VOIDP], Fiddle::RUBY_FREE) do |user|
        user.assign_names(["name"])
        Fiddle::Pointer.malloc(6, Fiddle::RUBY_FREE) do |alice|
          alice[0, 6] = "Alice\0"
          user["name"] = alice
          assert_equal("Alice", user["name"].to_s)
        end
      end
    end

    def test_new_double_free
      types = [TYPE_INT]
      Pointer.malloc(CStructEntity.size(types), Fiddle::RUBY_FREE) do |pointer|
        assert_raise ArgumentError do
          CStructEntity.new(pointer, types, Fiddle::RUBY_FREE)
        end
      end
    end

    def test_malloc_block
      escaped_struct = nil
      returned = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE) do |struct|
        assert_equal Fiddle::SIZEOF_INT, struct.size
        assert_equal Fiddle::RUBY_FREE, struct.free.to_i
        escaped_struct = struct
        :returned
      end
      assert_equal :returned, returned
      assert escaped_struct.freed?
    end

    def test_malloc_block_no_free
      assert_raise ArgumentError do
        CStructEntity.malloc([TYPE_INT]) { |struct| }
      end
    end

    def test_free
      struct = CStructEntity.malloc([TYPE_INT])
      begin
        assert_nil struct.free
      ensure
        Fiddle.free struct
      end
    end

    def test_free_with_func
      struct = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE)
      refute struct.freed?
      struct.call_free
      assert struct.freed?
      struct.call_free                 # you can safely run it again
      assert struct.freed?
      GC.start                         # you can safely run the GC routine
      assert struct.freed?
    end

    def test_free_with_no_func
      struct = CStructEntity.malloc([TYPE_INT])
      refute struct.freed?
      struct.call_free
      refute struct.freed?
      struct.call_free                 # you can safely run it again
      refute struct.freed?
    end

    def test_freed?
      struct = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE)
      refute struct.freed?
      struct.call_free
      assert struct.freed?
    end

    def test_null?
      struct = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE)
      refute struct.null?
    end

    def test_size
      CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE) do |struct|
        assert_equal Fiddle::SIZEOF_INT, struct.size
      end
    end

    def test_size=
      CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE) do |struct|
        assert_raise NoMethodError do
          struct.size = 1
        end
      end
    end
  end
end if defined?(Fiddle)