ffi 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (59) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +34 -26
  3. data/ext/ffi_c/AbstractMemory.c +73 -70
  4. data/ext/ffi_c/AbstractMemory.h +8 -4
  5. data/ext/ffi_c/AutoPointer.c +8 -9
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +19 -20
  8. data/ext/ffi_c/Callback.c +85 -33
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +148 -192
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +26 -19
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +49 -47
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +52 -21
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +70 -61
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +47 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +20 -43
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/lib/ffi.rb +10 -1
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +78 -17
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/spec/ffi/bool_spec.rb +24 -0
  47. data/spec/ffi/callback_spec.rb +217 -17
  48. data/spec/ffi/enum_spec.rb +164 -0
  49. data/spec/ffi/managed_struct_spec.rb +6 -1
  50. data/spec/ffi/number_spec.rb +30 -0
  51. data/spec/ffi/pointer_spec.rb +33 -8
  52. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  53. data/spec/ffi/spec_helper.rb +5 -1
  54. data/spec/ffi/string_spec.rb +65 -4
  55. data/spec/ffi/struct_callback_spec.rb +41 -0
  56. data/spec/ffi/struct_initialize_spec.rb +30 -0
  57. data/spec/ffi/struct_spec.rb +19 -20
  58. metadata +29 -52
  59. data/ext/ffi_c/ffi.mk +0 -23
@@ -1,7 +1,7 @@
1
1
  module FFI
2
2
  # TypeDefs = Hash.new
3
3
  def self.add_typedef(current, add)
4
- if current.kind_of? Integer
4
+ if current.kind_of?(FFI::Type)
5
5
  code = current
6
6
  else
7
7
  code = TypeDefs[current]
@@ -13,8 +13,7 @@ module FFI
13
13
  def self.find_type(name, type_map = nil)
14
14
  type_map = TypeDefs if type_map.nil?
15
15
  code = type_map[name]
16
- code = name if !code && name.kind_of?(Integer)
17
- code = name if !code && name.kind_of?(FFI::CallbackInfo)
16
+ code = name if !code && name.kind_of?(FFI::Type)
18
17
  raise TypeError, "Unable to resolve type '#{name}'" unless code
19
18
  return code
20
19
  end
@@ -92,7 +91,11 @@ module FFI
92
91
  add_typedef(NativeType::BUFFER_IN, :buffer_in)
93
92
  add_typedef(NativeType::BUFFER_OUT, :buffer_out)
94
93
  add_typedef(NativeType::BUFFER_INOUT, :buffer_inout)
94
+
95
95
  add_typedef(NativeType::VARARGS, :varargs)
96
+
97
+ add_typedef(NativeType::ENUM, :enum)
98
+ add_typedef(NativeType::BOOL, :bool)
96
99
 
97
100
  # Use for a C struct with a char [] embedded inside.
98
101
  add_typedef(NativeType::CHAR_ARRAY, :char_array)
@@ -1,7 +1,7 @@
1
1
  module FFI
2
2
  class VariadicInvoker
3
- def VariadicInvoker.new(library, function, arg_types, ret_type, options)
4
- invoker = self.__new(library, function, ret_type, options[:convention].to_s)
3
+ def VariadicInvoker.new(function, arg_types, rb_ret_type, ret_type, options)
4
+ invoker = self.__new(function, rb_ret_type, ret_type, options[:convention].to_s, options[:enums])
5
5
  invoker.init(arg_types, options[:type_map])
6
6
  invoker
7
7
  end
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+ describe "Function with primitive boolean arguments and return values" do
3
+ module LibTest
4
+ extend FFI::Library
5
+ ffi_lib TestLibrary::PATH
6
+ attach_function :bool_return_true, [ ], :bool
7
+ attach_function :bool_return_false, [ ], :bool
8
+ attach_function :bool_return_val, [ :bool ], :bool
9
+ attach_function :bool_reverse_val, [ :bool ], :bool
10
+ end
11
+ it "bools" do
12
+ LibTest.bool_return_true.should == true
13
+ LibTest.bool_return_false.should == false
14
+
15
+ LibTest.bool_return_val(true).should == true
16
+ LibTest.bool_return_val(false).should == false
17
+
18
+ LibTest.bool_reverse_val(true).should == false
19
+ LibTest.bool_reverse_val(false).should == true
20
+ end
21
+ it "raise error on invalid types" do
22
+ lambda { LibTest.bool_return_val(nil) }.should raise_error(::TypeError)
23
+ end
24
+ end
@@ -37,21 +37,30 @@ describe "Callback" do
37
37
  callback :cbVrU16, [ ], :ushort
38
38
  callback :cbVrS32, [ ], :int
39
39
  callback :cbVrU32, [ ], :uint
40
+ callback :cbVrL, [ ], :long
41
+ callback :cbVrUL, [ ], :ulong
40
42
  callback :cbVrS64, [ ], :long_long
41
43
  callback :cbVrU64, [ ], :ulong_long
42
44
  callback :cbVrP, [], :pointer
45
+ callback :cbVrZ, [], :bool
43
46
  callback :cbCrV, [ :char ], :void
44
47
  callback :cbSrV, [ :short ], :void
45
48
  callback :cbIrV, [ :int ], :void
49
+ callback :cbLrV, [ :long ], :void
50
+ callback :cbULrV, [ :ulong ], :void
46
51
  callback :cbLrV, [ :long_long ], :void
52
+
47
53
  attach_function :testCallbackVrS8, :testClosureVrB, [ :cbVrS8 ], :char
48
54
  attach_function :testCallbackVrU8, :testClosureVrB, [ :cbVrU8 ], :uchar
49
55
  attach_function :testCallbackVrS16, :testClosureVrS, [ :cbVrS16 ], :short
50
56
  attach_function :testCallbackVrU16, :testClosureVrS, [ :cbVrU16 ], :ushort
51
57
  attach_function :testCallbackVrS32, :testClosureVrI, [ :cbVrS32 ], :int
52
58
  attach_function :testCallbackVrU32, :testClosureVrI, [ :cbVrU32 ], :uint
53
- attach_function :testCallbackVrS64, :testClosureVrL, [ :cbVrS64 ], :long_long
54
- attach_function :testCallbackVrU64, :testClosureVrL, [ :cbVrU64 ], :ulong_long
59
+ attach_function :testCallbackVrL, :testClosureVrL, [ :cbVrL ], :long
60
+ attach_function :testCallbackVrZ, :testClosureVrZ, [ :cbVrZ ], :bool
61
+ attach_function :testCallbackVrUL, :testClosureVrL, [ :cbVrUL ], :ulong
62
+ attach_function :testCallbackVrS64, :testClosureVrLL, [ :cbVrS64 ], :long_long
63
+ attach_function :testCallbackVrU64, :testClosureVrLL, [ :cbVrU64 ], :ulong_long
55
64
  attach_function :testCallbackVrP, :testClosureVrP, [ :cbVrP ], :pointer
56
65
  attach_function :testCallbackCrV, :testClosureBrV, [ :cbCrV, :char ], :void
57
66
  attach_variable :cbVrS8, :gvar_pointer, :cbVrS8
@@ -122,7 +131,6 @@ describe "Callback" do
122
131
  it "returning :ushort (-1)" do
123
132
  LibTest.testCallbackVrU16 { -1 }.should == 0xffff
124
133
  end
125
-
126
134
  it "returning :int (0)" do
127
135
  LibTest.testCallbackVrS32 { 0 }.should == 0
128
136
  end
@@ -136,7 +144,6 @@ describe "Callback" do
136
144
  it "returning :int (-1)" do
137
145
  LibTest.testCallbackVrS32 { -1 }.should == -1
138
146
  end
139
-
140
147
  it "returning :uint (0)" do
141
148
  LibTest.testCallbackVrU32 { 0 }.should == 0
142
149
  end
@@ -153,7 +160,39 @@ describe "Callback" do
153
160
  it "Callback returning :uint (-1)" do
154
161
  LibTest.testCallbackVrU32 { -1 }.should == 0xffffffff
155
162
  end
156
-
163
+ it "returning :long (0)" do
164
+ LibTest.testCallbackVrL { 0 }.should == 0
165
+ end
166
+ it "returning :long (0x7fffffff)" do
167
+ LibTest.testCallbackVrL { 0x7fffffff }.should == 0x7fffffff
168
+ end
169
+ # test wrap around
170
+ it "returning :long (-0x80000000)" do
171
+ LibTest.testCallbackVrL { -0x80000000 }.should == -0x80000000
172
+ end
173
+ it "returning :long (-1)" do
174
+ LibTest.testCallbackVrL { -1 }.should == -1
175
+ end
176
+ it "returning :ulong (0)" do
177
+ LibTest.testCallbackVrUL { 0 }.should == 0
178
+ end
179
+ it "returning :ulong (0x7fffffff)" do
180
+ LibTest.testCallbackVrUL { 0x7fffffff }.should == 0x7fffffff
181
+ end
182
+ # test wrap around
183
+ it "returning :ulong (0x80000000)" do
184
+ LibTest.testCallbackVrUL { 0x80000000 }.should == 0x80000000
185
+ end
186
+ it "returning :ulong (0xffffffff)" do
187
+ LibTest.testCallbackVrUL { 0xffffffff }.should == 0xffffffff
188
+ end
189
+ it "Callback returning :ulong (-1)" do
190
+ if FFI::Platform::LONG_SIZE == 32
191
+ LibTest.testCallbackVrUL { -1 }.should == 0xffffffff
192
+ else
193
+ LibTest.testCallbackVrUL { -1 }.should == 0xffffffffffffffff
194
+ end
195
+ end
157
196
  it "returning :long_long (0)" do
158
197
  LibTest.testCallbackVrS64 { 0 }.should == 0
159
198
  end
@@ -167,11 +206,14 @@ describe "Callback" do
167
206
  it "returning :long_long (-1)" do
168
207
  LibTest.testCallbackVrS64 { -1 }.should == -1
169
208
  end
209
+ it "returning bool" do
210
+ LibTest.testCallbackVrZ { true }.should be_true
211
+ end
170
212
  it "returning :pointer (nil)" do
171
213
  LibTest.testCallbackVrP { nil }.null?.should be_true
172
214
  end
173
215
  it "returning :pointer (MemoryPointer)" do
174
- p = MemoryPointer.new :long
216
+ p = FFI::MemoryPointer.new :long
175
217
  LibTest.testCallbackVrP { p }.should == p
176
218
  end
177
219
 
@@ -187,6 +229,113 @@ describe "Callback" do
187
229
  end
188
230
  end
189
231
 
232
+ describe 'when inlined' do
233
+ it 'could be anonymous' do
234
+ module LibTest
235
+ extend FFI::Library
236
+ attach_function :testCallbackVrS8, :testClosureVrB, [ callback([ ], :char) ], :char
237
+ end
238
+ LibTest.testCallbackVrS8 { 0 }.should == 0
239
+ end
240
+ end
241
+
242
+ describe "as return value" do
243
+
244
+ it "should not blow up when a callback is defined that returns a callback" do
245
+ module LibTest
246
+ extend FFI::Library
247
+ callback :cb_return_type_1, [ :short ], :short
248
+ callback :cb_lookup_1, [ :short ], :cb_return_type_1
249
+ attach_function :testReturnsCallback_1, :testReturnsClosure, [ :cb_lookup_1, :short ], :cb_return_type_1
250
+ end
251
+ end
252
+
253
+ it "should return a callback" do
254
+ module LibTest
255
+ extend FFI::Library
256
+ callback :cb_return_type, [ :int ], :int
257
+ callback :cb_lookup, [ ], :cb_return_type
258
+ attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
259
+ end
260
+
261
+ lookup_proc_called = false
262
+ return_proc_called = false
263
+
264
+ return_proc = Proc.new do |a|
265
+ return_proc_called = true
266
+ a * 2
267
+ end
268
+ lookup_proc = Proc.new do
269
+ lookup_proc_called = true
270
+ return_proc
271
+ end
272
+
273
+ val = LibTest.testReturnsCallback(lookup_proc, 0x1234)
274
+ val.should == 0x1234 * 2
275
+ lookup_proc_called.should be_true
276
+ return_proc_called.should be_true
277
+ end
278
+
279
+ it "should return a method callback" do
280
+ module LibTest
281
+ extend FFI::Library
282
+ callback :cb_return_type, [ :int ], :int
283
+ callback :cb_lookup, [ ], :cb_return_type
284
+ attach_function :testReturnsCallback, :testReturnsClosure, [ :cb_lookup, :int ], :int
285
+ end
286
+ module MethodCallback
287
+ def self.lookup
288
+ method(:perform)
289
+ end
290
+ def self.perform num
291
+ num * 2
292
+ end
293
+ end
294
+
295
+ LibTest.testReturnsCallback(MethodCallback.method(:lookup), 0x1234).should == 0x2468
296
+ end
297
+
298
+ it 'should not blow up when a callback takes a callback as argument' do
299
+ module LibTest
300
+ extend FFI::Library
301
+ callback :cb_argument, [ :int ], :int
302
+ callback :cb_with_cb_argument, [ :cb_argument, :int ], :int
303
+ attach_function :testCallbackAsArgument, :testArgumentClosure, [ :cb_with_cb_argument, :int ], :int
304
+ end
305
+ end
306
+ it 'should be able to use the callback argument' do
307
+ module LibTest
308
+ extend FFI::Library
309
+ callback :cb_argument, [ :int ], :int
310
+ callback :cb_with_cb_argument, [ :cb_argument, :int ], :int
311
+ attach_function :testCallbackAsArgument, :testArgumentClosure, [ :cb_with_cb_argument, :cb_argument, :int ], :int
312
+ end
313
+ callback_arg_called = false
314
+ callback_with_callback_arg_called = false
315
+ callback_arg = Proc.new do |val|
316
+ callback_arg_called = true
317
+ val * 2
318
+ end
319
+ callback_with_callback_arg = Proc.new do |cb, val|
320
+ callback_with_callback_arg_called = true
321
+ cb.call(val)
322
+ end
323
+ val = LibTest.testCallbackAsArgument(callback_with_callback_arg, callback_arg, 0xff1)
324
+ val.should == 0xff1 * 2
325
+ callback_arg_called.should be_true
326
+ callback_with_callback_arg_called.should be_true
327
+ end
328
+ it 'function returns callable object' do
329
+ module LibTest
330
+ extend FFI::Library
331
+ callback :funcptr, [ :int ], :int
332
+ attach_function :testReturnsFunctionPointer, [ ], :funcptr
333
+ end
334
+ f = LibTest.testReturnsFunctionPointer
335
+ f.call(3).should == 6
336
+ end
337
+ end
338
+
190
339
  end
191
340
  describe "primitive argument" do
192
341
  #
@@ -199,16 +348,27 @@ describe "primitive argument" do
199
348
  callback :cbU8rV, [ :uchar ], :void
200
349
  callback :cbS16rV, [ :short ], :void
201
350
  callback :cbU16rV, [ :ushort ], :void
351
+
352
+ callback :cbZrV, [ :bool ], :void
202
353
  callback :cbS32rV, [ :int ], :void
203
354
  callback :cbU32rV, [ :uint ], :void
355
+
356
+ callback :cbLrV, [ :long ], :void
357
+ callback :cbULrV, [ :ulong ], :void
358
+
204
359
  callback :cbS64rV, [ :long_long ], :void
205
360
  attach_function :testCallbackCrV, :testClosureBrV, [ :cbS8rV, :char ], :void
206
361
  attach_function :testCallbackU8rV, :testClosureBrV, [ :cbU8rV, :uchar ], :void
207
362
  attach_function :testCallbackSrV, :testClosureSrV, [ :cbS16rV, :short ], :void
208
363
  attach_function :testCallbackU16rV, :testClosureSrV, [ :cbU16rV, :ushort ], :void
364
+ attach_function :testCallbackZrV, :testClosureZrV, [ :cbZrV, :bool ], :void
209
365
  attach_function :testCallbackIrV, :testClosureIrV, [ :cbS32rV, :int ], :void
210
366
  attach_function :testCallbackU32rV, :testClosureIrV, [ :cbU32rV, :uint ], :void
211
- attach_function :testCallbackLrV, :testClosureLrV, [ :cbS64rV, :long_long ], :void
367
+
368
+ attach_function :testCallbackLrV, :testClosureLrV, [ :cbLrV, :long ], :void
369
+ attach_function :testCallbackULrV, :testClosureULrV, [ :cbULrV, :ulong ], :void
370
+
371
+ attach_function :testCallbackLLrV, :testClosureLLrV, [ :cbS64rV, :long_long ], :void
212
372
  end
213
373
  it ":char (0) argument" do
214
374
  v = 0xdeadbeef
@@ -230,7 +390,6 @@ describe "primitive argument" do
230
390
  LibTest.testCallbackCrV(-1) { |i| v = i }
231
391
  v.should == -1
232
392
  end
233
-
234
393
  it ":uchar (0) argument" do
235
394
  v = 0xdeadbeef
236
395
  LibTest.testCallbackU8rV(0) { |i| v = i }
@@ -272,7 +431,6 @@ describe "primitive argument" do
272
431
  LibTest.testCallbackSrV(-1) { |i| v = i }
273
432
  v.should == -1
274
433
  end
275
-
276
434
  it ":ushort (0) argument" do
277
435
  v = 0xdeadbeef
278
436
  LibTest.testCallbackU16rV(0) { |i| v = i }
@@ -293,7 +451,11 @@ describe "primitive argument" do
293
451
  LibTest.testCallbackU16rV(0xffff) { |i| v = i }
294
452
  v.should == 0xffff
295
453
  end
296
-
454
+ it ":bool (true) argument" do
455
+ v = false
456
+ LibTest.testCallbackZrV(true) { |i| v = i }
457
+ v.should be_true
458
+ end
297
459
  it ":int (0) argument" do
298
460
  v = 0xdeadbeef
299
461
  LibTest.testCallbackIrV(0) { |i| v = i }
@@ -314,7 +476,6 @@ describe "primitive argument" do
314
476
  LibTest.testCallbackIrV(-1) { |i| v = i }
315
477
  v.should == -1
316
478
  end
317
-
318
479
  it ":uint (0) argument" do
319
480
  v = 0xdeadbeef
320
481
  LibTest.testCallbackU32rV(0) { |i| v = i }
@@ -335,26 +496,65 @@ describe "primitive argument" do
335
496
  LibTest.testCallbackU32rV(0xffffffff) { |i| v = i }
336
497
  v.should == 0xffffffff
337
498
  end
338
-
339
- it ":long_long (0) argument" do
499
+ it ":long (0) argument" do
340
500
  v = 0xdeadbeef
341
501
  LibTest.testCallbackLrV(0) { |i| v = i }
342
502
  v.should == 0
343
503
  end
504
+ it ":long (0x7fffffff) argument" do
505
+ v = 0xdeadbeef
506
+ LibTest.testCallbackLrV(0x7fffffff) { |i| v = i }
507
+ v.should == 0x7fffffff
508
+ end
509
+ it ":long (-0x80000000) argument" do
510
+ v = 0xdeadbeef
511
+ LibTest.testCallbackLrV(-0x80000000) { |i| v = i }
512
+ v.should == -0x80000000
513
+ end
514
+ it ":long (-1) argument" do
515
+ v = 0xdeadbeef
516
+ LibTest.testCallbackLrV(-1) { |i| v = i }
517
+ v.should == -1
518
+ end
519
+ it ":ulong (0) argument" do
520
+ v = 0xdeadbeef
521
+ LibTest.testCallbackULrV(0) { |i| v = i }
522
+ v.should == 0
523
+ end
524
+ it ":ulong (0x7fffffff) argument" do
525
+ v = 0xdeadbeef
526
+ LibTest.testCallbackULrV(0x7fffffff) { |i| v = i }
527
+ v.should == 0x7fffffff
528
+ end
529
+ it ":ulong (0x80000000) argument" do
530
+ v = 0xdeadbeef
531
+ LibTest.testCallbackULrV(0x80000000) { |i| v = i }
532
+ v.should == 0x80000000
533
+ end
534
+ it ":ulong (0xffffffff) argument" do
535
+ v = 0xdeadbeef
536
+ LibTest.testCallbackULrV(0xffffffff) { |i| v = i }
537
+ v.should == 0xffffffff
538
+ end
539
+ it ":long_long (0) argument" do
540
+ v = 0xdeadbeef
541
+ LibTest.testCallbackLLrV(0) { |i| v = i }
542
+ v.should == 0
543
+ end
344
544
  it ":long_long (0x7fffffffffffffff) argument" do
345
545
  v = 0xdeadbeef
346
- LibTest.testCallbackLrV(0x7fffffffffffffff) { |i| v = i }
546
+ LibTest.testCallbackLLrV(0x7fffffffffffffff) { |i| v = i }
347
547
  v.should == 0x7fffffffffffffff
348
548
  end
349
549
  it ":long_long (-0x8000000000000000) argument" do
350
550
  v = 0xdeadbeef
351
- LibTest.testCallbackLrV(-0x8000000000000000) { |i| v = i }
551
+ LibTest.testCallbackLLrV(-0x8000000000000000) { |i| v = i }
352
552
  v.should == -0x8000000000000000
353
553
  end
354
554
  it ":long_long (-1) argument" do
355
555
  v = 0xdeadbeef
356
- LibTest.testCallbackLrV(-1) { |i| v = i }
556
+ LibTest.testCallbackLLrV(-1) { |i| v = i }
357
557
  v.should == -1
358
558
  end
359
559
 
360
- end unless true
560
+ end # unless true
@@ -0,0 +1,164 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ module TestEnum0
4
+ extend FFI::Library
5
+ end
6
+
7
+ module TestEnum1
8
+ extend FFI::Library
9
+ ffi_lib TestLibrary::PATH
10
+
11
+ enum [:c1, :c2, :c3, :c4]
12
+ enum [:c5, 42, :c6, :c7, :c8]
13
+ enum [:c9, 42, :c10, :c11, 4242, :c12]
14
+ enum [:c13, 42, :c14, 4242, :c15, 424242, :c16, 42424242]
15
+
16
+ attach_function :test_untagged_enum, [:int], :int
17
+ end
18
+
19
+ module TestEnum3
20
+ extend FFI::Library
21
+ ffi_lib TestLibrary::PATH
22
+
23
+ enum :enum_type1, [:c1, :c2, :c3, :c4]
24
+ enum :enum_type2, [:c5, 42, :c6, :c7, :c8]
25
+ enum :enum_type3, [:c9, 42, :c10, :c11, 4242, :c12]
26
+ enum :enum_type4, [:c13, 42, :c14, 4242, :c15, 424242, :c16, 42424242]
27
+
28
+ attach_function :test_tagged_typedef_enum1, [:enum_type1], :enum_type1
29
+ attach_function :test_tagged_typedef_enum2, [:enum_type2], :enum_type2
30
+ attach_function :test_tagged_typedef_enum3, [:enum_type3], :enum_type3
31
+ attach_function :test_tagged_typedef_enum4, [:enum_type4], :enum_type4
32
+ end
33
+
34
+ describe "A library with no enum defined" do
35
+ it "returns nil when asked for an enum" do
36
+ TestEnum0.enum_type(:foo).should == nil
37
+ end
38
+ end
39
+
40
+ describe "An untagged enum" do
41
+ it "constants can be used as function parameters and return value" do
42
+ TestEnum1.test_untagged_enum(:c1).should == 0
43
+ TestEnum1.test_untagged_enum(:c2).should == 1
44
+ TestEnum1.test_untagged_enum(:c3).should == 2
45
+ TestEnum1.test_untagged_enum(:c4).should == 3
46
+ TestEnum1.test_untagged_enum(:c5).should == 42
47
+ TestEnum1.test_untagged_enum(:c6).should == 43
48
+ TestEnum1.test_untagged_enum(:c7).should == 44
49
+ TestEnum1.test_untagged_enum(:c8).should == 45
50
+ TestEnum1.test_untagged_enum(:c9).should == 42
51
+ TestEnum1.test_untagged_enum(:c10).should == 43
52
+ TestEnum1.test_untagged_enum(:c11).should == 4242
53
+ TestEnum1.test_untagged_enum(:c12).should == 4243
54
+ TestEnum1.test_untagged_enum(:c13).should == 42
55
+ TestEnum1.test_untagged_enum(:c14).should == 4242
56
+ TestEnum1.test_untagged_enum(:c15).should == 424242
57
+ TestEnum1.test_untagged_enum(:c16).should == 42424242
58
+ end
59
+ end
60
+
61
+ describe "A tagged typedef enum" do
62
+ it "is accessible through its tag" do
63
+ TestEnum3.enum_type(:enum_type1).should_not == nil
64
+ TestEnum3.enum_type(:enum_type2).should_not == nil
65
+ TestEnum3.enum_type(:enum_type3).should_not == nil
66
+ TestEnum3.enum_type(:enum_type4).should_not == nil
67
+ end
68
+ it "contains enum constants" do
69
+ TestEnum3.enum_type(:enum_type1).symbols.length.should == 4
70
+ TestEnum3.enum_type(:enum_type2).symbols.length.should == 4
71
+ TestEnum3.enum_type(:enum_type3).symbols.length.should == 4
72
+ TestEnum3.enum_type(:enum_type4).symbols.length.should == 4
73
+ end
74
+ it "constants can be used as function parameters and return value" do
75
+ TestEnum3.test_tagged_typedef_enum1(:c1).should == :c1
76
+ TestEnum3.test_tagged_typedef_enum1(:c2).should == :c2
77
+ TestEnum3.test_tagged_typedef_enum1(:c3).should == :c3
78
+ TestEnum3.test_tagged_typedef_enum1(:c4).should == :c4
79
+ TestEnum3.test_tagged_typedef_enum2(:c5).should == :c5
80
+ TestEnum3.test_tagged_typedef_enum2(:c6).should == :c6
81
+ TestEnum3.test_tagged_typedef_enum2(:c7).should == :c7
82
+ TestEnum3.test_tagged_typedef_enum2(:c8).should == :c8
83
+ TestEnum3.test_tagged_typedef_enum3(:c9).should == :c9
84
+ TestEnum3.test_tagged_typedef_enum3(:c10).should == :c10
85
+ TestEnum3.test_tagged_typedef_enum3(:c11).should == :c11
86
+ TestEnum3.test_tagged_typedef_enum3(:c12).should == :c12
87
+ TestEnum3.test_tagged_typedef_enum4(:c13).should == :c13
88
+ TestEnum3.test_tagged_typedef_enum4(:c14).should == :c14
89
+ TestEnum3.test_tagged_typedef_enum4(:c15).should == :c15
90
+ TestEnum3.test_tagged_typedef_enum4(:c16).should == :c16
91
+ end
92
+ end
93
+
94
+ describe "All enums" do
95
+ it "have autonumbered constants when defined with names only" do
96
+ TestEnum1.enum_value(:c1).should == 0
97
+ TestEnum1.enum_value(:c2).should == 1
98
+ TestEnum1.enum_value(:c3).should == 2
99
+ TestEnum1.enum_value(:c4).should == 3
100
+
101
+ TestEnum3.enum_value(:c1).should == 0
102
+ TestEnum3.enum_value(:c2).should == 1
103
+ TestEnum3.enum_value(:c3).should == 2
104
+ TestEnum3.enum_value(:c4).should == 3
105
+ end
106
+ it "can have an explicit first constant and autonumbered subsequent constants" do
107
+ TestEnum1.enum_value(:c5).should == 42
108
+ TestEnum1.enum_value(:c6).should == 43
109
+ TestEnum1.enum_value(:c7).should == 44
110
+ TestEnum1.enum_value(:c8).should == 45
111
+
112
+ TestEnum3.enum_value(:c5).should == 42
113
+ TestEnum3.enum_value(:c6).should == 43
114
+ TestEnum3.enum_value(:c7).should == 44
115
+ TestEnum3.enum_value(:c8).should == 45
116
+ end
117
+ it "can have a mix of explicit and autonumbered constants" do
118
+ TestEnum1.enum_value(:c9).should == 42
119
+ TestEnum1.enum_value(:c10).should == 43
120
+ TestEnum1.enum_value(:c11).should == 4242
121
+ TestEnum1.enum_value(:c12).should == 4243
122
+
123
+ TestEnum3.enum_value(:c9).should == 42
124
+ TestEnum3.enum_value(:c10).should == 43
125
+ TestEnum3.enum_value(:c11).should == 4242
126
+ TestEnum3.enum_value(:c12).should == 4243
127
+ end
128
+ it "can have all its constants explicitely valued" do
129
+ TestEnum1.enum_value(:c13).should == 42
130
+ TestEnum1.enum_value(:c14).should == 4242
131
+ TestEnum1.enum_value(:c15).should == 424242
132
+ TestEnum1.enum_value(:c16).should == 42424242
133
+
134
+ TestEnum3.enum_value(:c13).should == 42
135
+ TestEnum3.enum_value(:c14).should == 4242
136
+ TestEnum3.enum_value(:c15).should == 424242
137
+ TestEnum3.enum_value(:c16).should == 42424242
138
+ end
139
+ it "return the constant corresponding to a specific value" do
140
+ enum = TestEnum3.enum_type(:enum_type1)
141
+ enum[0].should == :c1
142
+ enum[1].should == :c2
143
+ enum[2].should == :c3
144
+ enum[3].should == :c4
145
+
146
+ enum = TestEnum3.enum_type(:enum_type2)
147
+ enum[42].should == :c5
148
+ enum[43].should == :c6
149
+ enum[44].should == :c7
150
+ enum[45].should == :c8
151
+
152
+ enum = TestEnum3.enum_type(:enum_type3)
153
+ enum[42].should == :c9
154
+ enum[43].should == :c10
155
+ enum[4242].should == :c11
156
+ enum[4243].should == :c12
157
+
158
+ enum = TestEnum3.enum_type(:enum_type4)
159
+ enum[42].should == :c13
160
+ enum[4242].should == :c14
161
+ enum[424242].should == :c15
162
+ enum[42424242].should == :c16
163
+ end
164
+ end