opsb-RubyInline 3.8.6

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.
@@ -0,0 +1,1051 @@
1
+ $TESTING = true
2
+
3
+ $0 = __FILE__ if $0 =~ /-e|\(eval\)/
4
+
5
+ require 'inline'
6
+ require 'tempfile'
7
+ require 'tmpdir'
8
+ require 'fileutils' unless defined?(::FileUtils)
9
+
10
+ require 'minitest/autorun'
11
+
12
+ File.umask(0)
13
+
14
+ require 'pathname'
15
+
16
+ $expand_paths = Pathname.new(__FILE__).absolute?
17
+ $inline_path = './lib/inline.rb'
18
+ $test_inline_path = './test/test_inline.rb'
19
+
20
+ if $expand_paths then
21
+ $inline_path = File.expand_path $inline_path
22
+ $test_inline_path = File.expand_path $test_inline_path
23
+ end
24
+
25
+ class InlineTestCase < MiniTest::Unit::TestCase
26
+ def setup
27
+ super
28
+ @rootdir = File.join(Dir.tmpdir, "test_inline.#{$$}")
29
+ Dir.mkdir @rootdir, 0700 unless test ?d, @rootdir
30
+ ENV['INLINEDIR'] = @rootdir
31
+ end
32
+
33
+ def teardown
34
+ unless $DEBUG then
35
+ FileUtils.rm_rf @rootdir
36
+ ENV.delete 'INLINEDIR'
37
+ end
38
+ end
39
+
40
+ def test_stupid
41
+ #shuts test unit up
42
+ end
43
+ end
44
+
45
+ class TestDir < InlineTestCase
46
+ def setup
47
+ super
48
+ @count = 1
49
+ end
50
+
51
+ def util_assert_secure(perms, should_pass)
52
+ path = File.join(@rootdir, @count.to_s)
53
+ @count += 1
54
+ Dir.mkdir path, perms unless perms.nil?
55
+ if should_pass then
56
+ Dir.assert_secure path
57
+ else
58
+ assert_raises(SecurityError) do
59
+ Dir.assert_secure path
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_assert_secure
65
+ # existing/good
66
+ util_assert_secure 0700, true
67
+ # existing/bad
68
+ util_assert_secure 0707, false
69
+ util_assert_secure 0770, false
70
+ util_assert_secure 0777, false
71
+ # missing
72
+ util_assert_secure nil, true
73
+ end
74
+ end unless Inline::WINDOZE
75
+
76
+ class TestInline < InlineTestCase
77
+
78
+ def test_rootdir
79
+ assert_equal(@rootdir, Inline.rootdir)
80
+ end
81
+
82
+ def test_directory
83
+ inlinedir = File.join(@rootdir, ".ruby_inline")
84
+ assert_equal(inlinedir, Inline.directory)
85
+ end
86
+
87
+ end
88
+
89
+ class TestInline
90
+ class TestC < InlineTestCase
91
+
92
+ def setup
93
+ super
94
+ @builder = Inline::C.new(self.class)
95
+ end
96
+
97
+
98
+ # quick hack to make tests more readable,
99
+ # does nothing I wouldn't otherwise do...
100
+ def inline(lang=:C)
101
+ self.class.inline(lang, true) do |builder|
102
+ yield(builder)
103
+ end
104
+ end
105
+
106
+ def test_initialize
107
+ x = Inline::C.new(self.class)
108
+ assert_equal TestInline::TestC, x.mod
109
+ assert_equal [], x.src
110
+ assert_equal({}, x.sig)
111
+ assert_equal [], x.flags
112
+ assert_equal [], x.libs
113
+ end
114
+
115
+ def test_accessor
116
+ builder = Inline::C.new self.class
117
+
118
+ builder.struct_name = 'MyStruct'
119
+ builder.accessor 'method_name', 'int'
120
+
121
+ source = util_strip_lines builder.src
122
+
123
+ expected = []
124
+ expected << <<-READER
125
+ # line N "#{$inline_path}"
126
+ static VALUE method_name(VALUE self) {
127
+
128
+ MyStruct *pointer;
129
+
130
+ Data_Get_Struct(self, MyStruct, pointer);
131
+
132
+ return (INT2FIX(pointer->method_name));
133
+ }
134
+ READER
135
+
136
+ expected << <<-WRITER
137
+ # line N "#{$inline_path}"
138
+ static VALUE method_name_equals(VALUE self, VALUE _value) {
139
+ VALUE value = (_value);
140
+
141
+ MyStruct *pointer;
142
+
143
+ Data_Get_Struct(self, MyStruct, pointer);
144
+
145
+ pointer->method_name = FIX2INT(value);
146
+
147
+ return (value);
148
+ }
149
+ WRITER
150
+
151
+ assert_equal expected, source
152
+ end
153
+
154
+ def test_accessor_member_name
155
+ builder = Inline::C.new self.class
156
+
157
+ builder.struct_name = 'MyStruct'
158
+ builder.accessor 'method_name', 'int', 'member_name'
159
+
160
+ source = util_strip_lines builder.src
161
+
162
+ expected = []
163
+ expected << <<-READER
164
+ # line N "#{$inline_path}"
165
+ static VALUE method_name(VALUE self) {
166
+
167
+ MyStruct *pointer;
168
+
169
+ Data_Get_Struct(self, MyStruct, pointer);
170
+
171
+ return (INT2FIX(pointer->member_name));
172
+ }
173
+ READER
174
+
175
+ expected << <<-WRITER
176
+ # line N "#{$inline_path}"
177
+ static VALUE method_name_equals(VALUE self, VALUE _value) {
178
+ VALUE value = (_value);
179
+
180
+ MyStruct *pointer;
181
+
182
+ Data_Get_Struct(self, MyStruct, pointer);
183
+
184
+ pointer->member_name = FIX2INT(value);
185
+
186
+ return (value);
187
+ }
188
+ WRITER
189
+
190
+ assert_equal expected, source
191
+ end
192
+
193
+ def test_accessor_no_struct_name
194
+ builder = Inline::C.new self.class
195
+
196
+ e = assert_raises RuntimeError do
197
+ builder.accessor 'method_name', 'int'
198
+ end
199
+
200
+ assert_equal "struct name not set for reader method_name int", e.message
201
+ end
202
+
203
+ def test_add_type_converter
204
+ builder = Inline::C.new self.class
205
+
206
+ builder.add_type_converter 'my_type', 'ruby_type2my_type',
207
+ 'my_type2ruby_type'
208
+
209
+ assert_equal 'my_type2ruby_type', builder.c2ruby('my_type')
210
+ assert_equal 'ruby_type2my_type', builder.ruby2c('my_type')
211
+ end
212
+
213
+ def test_alias_type_converter
214
+ builder = Inline::C.new self.class
215
+
216
+ builder.alias_type_converter 'long long', 'int64_t'
217
+
218
+ assert_equal 'LL2NUM', builder.c2ruby('int64_t')
219
+ assert_equal 'NUM2LL', builder.ruby2c('int64_t')
220
+ end
221
+
222
+ def test_reader
223
+ builder = Inline::C.new self.class
224
+
225
+ builder.struct_name = 'MyStruct'
226
+ builder.reader 'method_name', 'int'
227
+
228
+ source = util_strip_lines builder.src
229
+
230
+ expected = []
231
+ expected << <<-READER
232
+ # line N "#{$inline_path}"
233
+ static VALUE method_name(VALUE self) {
234
+
235
+ MyStruct *pointer;
236
+
237
+ Data_Get_Struct(self, MyStruct, pointer);
238
+
239
+ return (INT2FIX(pointer->method_name));
240
+ }
241
+ READER
242
+
243
+ assert_equal expected, source
244
+ end
245
+
246
+ def test_reader_member_name
247
+ builder = Inline::C.new self.class
248
+
249
+ builder.struct_name = 'MyStruct'
250
+ builder.reader 'method_name', 'int', 'member_name'
251
+
252
+ source = util_strip_lines builder.src
253
+
254
+ expected = []
255
+ expected << <<-READER
256
+ # line N "#{$inline_path}"
257
+ static VALUE method_name(VALUE self) {
258
+
259
+ MyStruct *pointer;
260
+
261
+ Data_Get_Struct(self, MyStruct, pointer);
262
+
263
+ return (INT2FIX(pointer->member_name));
264
+ }
265
+ READER
266
+
267
+ assert_equal expected, source
268
+ end
269
+
270
+ def test_reader_no_struct_name
271
+ builder = Inline::C.new self.class
272
+
273
+ e = assert_raises RuntimeError do
274
+ builder.reader 'method_name', 'int'
275
+ end
276
+
277
+ assert_equal "struct name not set for reader method_name int", e.message
278
+ end
279
+
280
+ def test_remove_type_converter
281
+ builder = Inline::C.new self.class
282
+
283
+ builder.remove_type_converter 'long'
284
+
285
+ assert_raises ArgumentError do
286
+ builder.c2ruby 'long'
287
+ end
288
+ end
289
+
290
+ def test_writer
291
+ builder = Inline::C.new self.class
292
+
293
+ builder.struct_name = 'MyStruct'
294
+ builder.writer 'method_name', 'int'
295
+
296
+ source = util_strip_lines builder.src
297
+
298
+ expected = []
299
+ expected << <<-WRITER
300
+ # line N "#{$inline_path}"
301
+ static VALUE method_name_equals(VALUE self, VALUE _value) {
302
+ VALUE value = (_value);
303
+
304
+ MyStruct *pointer;
305
+
306
+ Data_Get_Struct(self, MyStruct, pointer);
307
+
308
+ pointer->method_name = FIX2INT(value);
309
+
310
+ return (value);
311
+ }
312
+ WRITER
313
+
314
+ assert_equal expected, source
315
+ end
316
+
317
+ def test_writer_member_name
318
+ builder = Inline::C.new self.class
319
+
320
+ builder.struct_name = 'MyStruct'
321
+ builder.writer 'method_name', 'int', 'member_name'
322
+
323
+ source = util_strip_lines builder.src
324
+
325
+ expected = []
326
+ expected << <<-WRITER
327
+ # line N "#{$inline_path}"
328
+ static VALUE method_name_equals(VALUE self, VALUE _value) {
329
+ VALUE value = (_value);
330
+
331
+ MyStruct *pointer;
332
+
333
+ Data_Get_Struct(self, MyStruct, pointer);
334
+
335
+ pointer->member_name = FIX2INT(value);
336
+
337
+ return (value);
338
+ }
339
+ WRITER
340
+
341
+ assert_equal expected, source
342
+ end
343
+
344
+ def test_writer_no_struct_name
345
+ builder = Inline::C.new self.class
346
+
347
+ e = assert_raises RuntimeError do
348
+ builder.writer 'method_name', 'int'
349
+ end
350
+
351
+ assert_equal "struct name not set for writer method_name int", e.message
352
+ end
353
+
354
+ def test_ruby2c
355
+ x = Inline::C.new(self.class)
356
+ assert_equal 'NUM2CHR', x.ruby2c("char")
357
+ assert_equal 'StringValuePtr', x.ruby2c("char *")
358
+
359
+ assert_equal "FI\X2INT", x.ruby2c("int")
360
+ assert_equal 'NUM2UINT', x.ruby2c("unsigned")
361
+ assert_equal 'NUM2UINT', x.ruby2c("unsigned int")
362
+
363
+ assert_equal 'NUM2LONG', x.ruby2c("long")
364
+ assert_equal 'NUM2ULONG', x.ruby2c("unsigned long")
365
+
366
+ assert_equal 'NUM2LL', x.ruby2c("long long")
367
+ assert_equal 'NUM2ULL', x.ruby2c("unsigned long long")
368
+
369
+ assert_equal 'NUM2DBL', x.ruby2c("double")
370
+
371
+ assert_equal 'NUM2OFFT', x.ruby2c("off_t")
372
+
373
+ assert_equal '', x.ruby2c("VALUE")
374
+
375
+ assert_raises ArgumentError do
376
+ x.ruby2c('blah')
377
+ end
378
+ end
379
+
380
+ def test_c2ruby
381
+ x = Inline::C.new(self.class)
382
+ assert_equal 'CHR2FIX', x.c2ruby("char")
383
+
384
+ assert_equal 'rb_str_new2', x.c2ruby("char *")
385
+
386
+ assert_equal 'INT2FIX', x.c2ruby("int")
387
+ assert_equal 'UINT2NUM', x.c2ruby("unsigned int")
388
+ assert_equal 'UINT2NUM', x.c2ruby("unsigned")
389
+
390
+ assert_equal 'LONG2NUM', x.c2ruby("long")
391
+ assert_equal 'ULONG2NUM', x.c2ruby("unsigned long")
392
+
393
+ assert_equal 'LL2NUM', x.c2ruby("long long")
394
+ assert_equal 'ULL2NUM', x.c2ruby("unsigned long long")
395
+
396
+ assert_equal 'rb_float_new', x.c2ruby("double")
397
+
398
+ assert_equal 'OFFT2NUM', x.c2ruby("off_t")
399
+
400
+ assert_equal '', x.c2ruby("VALUE")
401
+
402
+ assert_raises ArgumentError do
403
+ x.c2ruby('blah')
404
+ end
405
+ end
406
+
407
+ def util_module_name(*signatures)
408
+ md5 = Digest::MD5.new
409
+
410
+ signatures.each do |signature|
411
+ @builder.sig[signature] = [nil, 0]
412
+ md5 << signature.to_s
413
+ end
414
+
415
+ assert_equal("Inline_TestInline__TestC_#{md5.to_s[0,4]}",
416
+ @builder.module_name)
417
+ end
418
+
419
+ def test_module_name_0_methods
420
+ util_module_name
421
+ end
422
+
423
+ def test_module_name_1_method
424
+ util_module_name :something1
425
+ end
426
+
427
+ def test_module_name_2_methods
428
+ util_module_name :something2, :something3
429
+ end
430
+
431
+ def test_module_name_2_other_methods
432
+ util_module_name :something4, :something5
433
+ end
434
+
435
+ def util_parse_signature(src, expected, t=nil, a=nil, b=nil)
436
+ result = nil
437
+
438
+ @builder.add_type_converter t, a, b unless t.nil?
439
+ result = @builder.parse_signature(src)
440
+
441
+ assert_equal(expected, result)
442
+ end
443
+
444
+ def test_parse_signature
445
+ src = "// stupid cpp comment
446
+ #include \"header.h\"
447
+ /* stupid c comment */
448
+ int
449
+ add(int x, int y) {
450
+ int result = x+y;
451
+ return result;
452
+ }
453
+ "
454
+
455
+ expected = {
456
+ 'name' => 'add',
457
+ 'return' => 'int',
458
+ 'arity' => 2,
459
+ 'args' => [
460
+ ['x', 'int'],
461
+ ['y', 'int']
462
+ ]
463
+ }
464
+
465
+ util_parse_signature(src, expected)
466
+ end
467
+
468
+ def test_parse_signature_custom
469
+
470
+ src = "// stupid cpp comment
471
+ #include \"header.h\"
472
+ /* stupid c comment */
473
+ int
474
+ add(fooby x, int y) {
475
+ int result = x+y;
476
+ return result;
477
+ }
478
+ "
479
+
480
+ expected = {
481
+ 'name' => 'add',
482
+ 'return' => 'int',
483
+ 'arity' => 2,
484
+ 'args' => [
485
+ [ 'x', 'fooby' ],
486
+ ['y', 'int']
487
+ ]
488
+ }
489
+
490
+ util_parse_signature(src, expected,
491
+ "fooby", "r2c_fooby", "c2r_fooby")
492
+ end
493
+
494
+ def test_parse_signature_register
495
+
496
+ src = "// stupid cpp comment
497
+ #include \"header.h\"
498
+ /* stupid c comment */
499
+ int
500
+ add(register int x, int y) {
501
+ int result = x+y;
502
+ return result;
503
+ }
504
+ "
505
+
506
+ expected = {
507
+ 'name' => 'add',
508
+ 'return' => 'int',
509
+ 'arity' => 2,
510
+ 'args' => [
511
+ [ 'x', 'register int' ],
512
+ ['y', 'int']
513
+ ]
514
+ }
515
+
516
+
517
+ util_parse_signature(src, expected,
518
+ "register int", "FI\X2INT", "INT2FI\X")
519
+ end
520
+
521
+ def util_generate(src, expected, expand_types=true)
522
+ result = @builder.generate src, expand_types
523
+ result = util_strip_lines result
524
+ result.gsub!(/\# line \d+/, '# line N')
525
+ expected = "# line N \"#{$0}\"\n" + expected
526
+ assert_equal(expected, result)
527
+ end
528
+
529
+ def util_generate_raw(src, expected)
530
+ util_generate(src, expected, false)
531
+ end
532
+
533
+ def util_strip_lines(src)
534
+ case src
535
+ when String then
536
+ src.gsub(/\# line \d+/, '# line N')
537
+ when Array then
538
+ src.map do |chunk|
539
+ util_strip_lines chunk
540
+ end
541
+ end
542
+ end
543
+
544
+ # Ruby Arity Rules, from the mouth of Matz:
545
+ # -2 = ruby array argv
546
+ # -1 = c array argv
547
+ # 0 = self
548
+ # 1 = self, value
549
+ # 2 = self, value, value
550
+ # ...
551
+ # 16 = self, value * 15
552
+
553
+ def test_generate_raw_arity_0
554
+ src = "VALUE y(VALUE self) {blah;}"
555
+
556
+ expected = "static VALUE y(VALUE self) {blah;}"
557
+
558
+ util_generate_raw(src, expected)
559
+ end
560
+
561
+ def test_generate_arity_0
562
+ src = "int y() { do_something; return 42; }"
563
+
564
+ expected = "static VALUE y(VALUE self) {\n do_something; return INT2FIX(42); }"
565
+
566
+ util_generate(src, expected)
567
+ end
568
+
569
+ def test_generate_arity_0_no_return
570
+ src = "void y() { do_something; }"
571
+
572
+ expected = "static VALUE y(VALUE self) {\n do_something;\nreturn Qnil;\n}"
573
+
574
+ util_generate(src, expected)
575
+ end
576
+
577
+ def test_generate_arity_0_void_return
578
+ src = "void y(void) {go_do_something_external;}"
579
+
580
+ expected = "static VALUE y(VALUE self) {
581
+ go_do_something_external;\nreturn Qnil;\n}"
582
+
583
+ util_generate(src, expected)
584
+ end
585
+
586
+ def test_generate_arity_0_int_return
587
+ src = "int x() {return 42}"
588
+
589
+ expected = "static VALUE x(VALUE self) {
590
+ return INT2FIX(42)}"
591
+
592
+ util_generate(src, expected)
593
+ end
594
+
595
+ def test_generate_raw_arity_1
596
+ src = "VALUE y(VALUE self, VALUE obj) {blah;}"
597
+
598
+ expected = "static VALUE y(VALUE self, VALUE obj) {blah;}"
599
+
600
+ util_generate_raw(src, expected)
601
+ end
602
+
603
+ def test_generate_arity_1
604
+ src = "int y(int x) {blah; return x+1;}"
605
+
606
+ expected = "static VALUE y(VALUE self, VALUE _x) {\n int x = FIX2INT(_x);\nblah; return INT2FIX(x+1);}"
607
+
608
+ util_generate(src, expected)
609
+ end
610
+
611
+ def test_generate_arity_1_no_return
612
+ src = "void y(int x) {blah;}"
613
+
614
+ expected = "static VALUE y(VALUE self, VALUE _x) {\n int x = FIX2INT(_x);\nblah;\nreturn Qnil;\n}"
615
+
616
+ util_generate(src, expected)
617
+ end
618
+
619
+ def test_generate_raw_arity_2
620
+ src = "VALUE func(VALUE self, VALUE obj1, VALUE obj2) {blah;}"
621
+
622
+ expected = "static VALUE func(VALUE self, VALUE obj1, VALUE obj2) {blah;}"
623
+
624
+ util_generate_raw(src, expected)
625
+ end
626
+
627
+ def test_generate_arity_2
628
+ src = "int func(int x, int y) {blah; return x+y;}"
629
+
630
+ expected = "static VALUE func(VALUE self, VALUE _x, VALUE _y) {\n int x = FIX2INT(_x);\n int y = FIX2INT(_y);\nblah; return INT2FIX(x+y);}"
631
+
632
+ util_generate(src, expected)
633
+ end
634
+
635
+ def test_generate_raw_arity_3
636
+ src = "VALUE func(VALUE self, VALUE obj1, VALUE obj2, VALUE obj3) {blah;}"
637
+
638
+ expected = "static VALUE func(VALUE self, VALUE obj1, VALUE obj2, VALUE obj3) {blah;}"
639
+
640
+ util_generate_raw(src, expected)
641
+ end
642
+
643
+ def test_generate_arity_too_many
644
+ src = "int too_many(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int aA, int aB, int aC, int aD, int aE, int aF, int ugh) {
645
+ int q = v + w;
646
+ return q+x+y+z;
647
+ }"
648
+
649
+ assert_raises ArgumentError do
650
+ @builder.generate src, true
651
+ end
652
+ end
653
+
654
+ def test_generate_comments
655
+ src = "// stupid cpp comment
656
+ /* stupid c comment */
657
+ int
658
+ add(int x, int y) { // add two numbers
659
+ return x+y;
660
+ }
661
+ "
662
+
663
+ expected = "static VALUE add(VALUE self, VALUE _x, VALUE _y) {
664
+ int x = FIX2INT(_x);
665
+ int y = FIX2INT(_y);
666
+
667
+ return INT2FIX(x+y);
668
+ }
669
+ "
670
+
671
+ util_generate(src, expected)
672
+ end
673
+
674
+ def test_generate_local_header
675
+ src = "// stupid cpp comment
676
+ #include \"header\"
677
+ /* stupid c comment */
678
+ int
679
+ add(int x, int y) { // add two numbers
680
+ return x+y;
681
+ }
682
+ "
683
+ # FIX: should be 2 spaces before the return. Can't find problem.
684
+ expected = "#include \"header\"
685
+ static VALUE add(VALUE self, VALUE _x, VALUE _y) {
686
+ int x = FIX2INT(_x);
687
+ int y = FIX2INT(_y);
688
+
689
+ return INT2FIX(x+y);
690
+ }
691
+ "
692
+ util_generate(src, expected)
693
+ end
694
+
695
+ def test_generate_map_name
696
+ src = "VALUE y_equals(VALUE self) {blah;}"
697
+
698
+ expected = "static VALUE y_equals(VALUE self) {blah;}"
699
+
700
+ util_generate_raw(src, expected)
701
+
702
+ assert_equal [-1, nil, 'y='], @builder.sig['y_equals']
703
+ end
704
+
705
+ def test_generate_system_header
706
+ src = "// stupid cpp comment
707
+ #include <header>
708
+ /* stupid c comment */
709
+ int
710
+ add(int x, int y) { // add two numbers
711
+ return x+y;
712
+ }
713
+ "
714
+ expected = "#include <header>
715
+ static VALUE add(VALUE self, VALUE _x, VALUE _y) {
716
+ int x = FIX2INT(_x);
717
+ int y = FIX2INT(_y);
718
+
719
+ return INT2FIX(x+y);
720
+ }
721
+ "
722
+ util_generate(src, expected)
723
+ end
724
+
725
+ def test_generate_wonky_return
726
+ src = "unsigned\nlong z(void) {return 42}"
727
+
728
+ expected = "static VALUE z(VALUE self) {
729
+ return ULONG2NUM(42)}"
730
+
731
+ util_generate(src, expected)
732
+ end
733
+
734
+ def test_generate_compact
735
+ src = "int add(int x, int y) {return x+y}"
736
+
737
+ expected = "static VALUE add(VALUE self, VALUE _x, VALUE _y) {
738
+ int x = FIX2INT(_x);
739
+ int y = FIX2INT(_y);
740
+ return INT2FIX(x+y)}"
741
+
742
+ util_generate(src, expected)
743
+ end
744
+
745
+ def test_generate_char_star_normalize
746
+ src = "char\n\*\n blah( char*s) {puts(s); return s}"
747
+
748
+ expected = "static VALUE blah(VALUE self, VALUE _s) {
749
+ char * s = StringValuePtr(_s);
750
+ puts(s); return rb_str_new2(s)}"
751
+
752
+ util_generate(src, expected)
753
+ end
754
+
755
+ def test_generate_ext
756
+ @builder.c_singleton "VALUE allocate() { return Qnil; }"
757
+
758
+ @builder.c "VALUE my_method() { return Qnil; }"
759
+
760
+ windoze = "\n __declspec(dllexport)" if Inline::WINDOZE
761
+
762
+ expected = <<-EXT
763
+ #include "ruby.h"
764
+
765
+ # line N "#{$test_inline_path}"
766
+ static VALUE allocate(VALUE self) {
767
+ return (Qnil); }
768
+
769
+ # line N "#{$test_inline_path}"
770
+ static VALUE my_method(VALUE self) {
771
+ return (Qnil); }
772
+
773
+
774
+ #ifdef __cplusplus
775
+ extern \"C\" {
776
+ #endif#{windoze}
777
+ void Init_Inline_TestInline__TestC_eba5() {
778
+ VALUE c = rb_cObject;
779
+ c = rb_const_get(c, rb_intern("TestInline"));
780
+ c = rb_const_get(c, rb_intern("TestC"));
781
+
782
+ rb_define_alloc_func(c, (VALUE(*)(VALUE))allocate);
783
+ rb_define_method(c, "my_method", (VALUE(*)(ANYARGS))my_method, 0);
784
+
785
+ }
786
+ #ifdef __cplusplus
787
+ }
788
+ #endif
789
+ EXT
790
+
791
+ assert_equal expected, util_strip_lines(@builder.generate_ext)
792
+ end
793
+
794
+ def test_generate_ext_bad_allocate
795
+ @builder.c_singleton "VALUE allocate(VALUE bad) { return Qnil; }"
796
+
797
+ e = assert_raises RuntimeError do
798
+ @builder.generate_ext
799
+ end
800
+
801
+ assert_equal 'TestInline::TestC::allocate must have an arity of zero',
802
+ e.message
803
+ end
804
+
805
+ def test_c
806
+ result = @builder.c "int add(int a, int b) { return a + b; }"
807
+
808
+ expected = "# line N \"#{$0}\"\nstatic VALUE add(VALUE self, VALUE _a, VALUE _b) {\n int a = FIX2INT(_a);\n int b = FIX2INT(_b);\n return INT2FIX(a + b); }"
809
+
810
+ result.gsub!(/\# line \d+/, '# line N')
811
+
812
+ assert_equal expected, result
813
+ assert_equal [expected], @builder.src
814
+ end
815
+
816
+ def test_c_raw
817
+ src = "static VALUE answer_raw(int argc, VALUE *argv, VALUE self) { return INT2NUM(42); }"
818
+ result = @builder.c_raw src.dup
819
+
820
+ result.gsub!(/\# line \d+/, '# line N')
821
+ expected = "# line N \"#{$0}\"\n" + src
822
+
823
+ assert_equal expected, result
824
+ assert_equal [expected], @builder.src
825
+ end
826
+
827
+ def test_map_c_const
828
+ @builder.map_c_const :C_NAME => :int
829
+
830
+ expected = [
831
+ " rb_define_const(c, \"C_NAME\", INT2FIX(C_NAME));"
832
+ ]
833
+
834
+ assert_equal expected, @builder.init_extra
835
+ end
836
+
837
+ def test_map_c_const_named
838
+ @builder.map_c_const :C_NAME => [:int, :RUBY_NAME]
839
+
840
+ expected = [
841
+ " rb_define_const(c, \"RUBY_NAME\", INT2FIX(C_NAME));"
842
+ ]
843
+
844
+ assert_equal expected, @builder.init_extra
845
+ end
846
+
847
+ # TODO: fix ?
848
+ def util_simple_code(klassname, c_src)
849
+ result = "
850
+ require 'inline'
851
+
852
+ class #{klassname}
853
+ inline do |builder|
854
+ builder.c <<-EOC
855
+ #{c_src}
856
+ EOC
857
+ end
858
+ end"
859
+ result
860
+ end
861
+
862
+ def util_test_build(src)
863
+ tempfile = Tempfile.new("util_test_build")
864
+ tempfile.write src
865
+ tempfile.close
866
+ rb_file = tempfile.path + ".rb"
867
+ File.rename tempfile.path, rb_file
868
+ begin
869
+ Kernel.module_eval { require rb_file }
870
+ yield if block_given?
871
+ ensure
872
+ File.unlink rb_file
873
+ end
874
+ end
875
+
876
+ def test_build_good
877
+ code = util_simple_code(:DumbTest1, "long dumbpi() { return 314; }")
878
+ util_test_build(code) do
879
+ result = DumbTest1.new.dumbpi
880
+ assert_equal(314, result)
881
+ end
882
+ end
883
+
884
+ def test_build_bad
885
+ code = util_simple_code(:DumbTest2, "void should_puke() { 1+1 2+2 }")
886
+ assert_raises(CompilationError) do
887
+ util_test_build(code) do
888
+ flunk
889
+ end
890
+ end
891
+ end
892
+
893
+ def util_strip_comments(input)
894
+ expect = 'line 1
895
+
896
+ #if 0
897
+ line 2
898
+ #endif
899
+ line 3
900
+
901
+ '
902
+
903
+ assert_equal expect, @builder.strip_comments(input)
904
+ end
905
+
906
+ def test_strip_comments_cpp
907
+ input = 'line 1
908
+
909
+ #if 0
910
+ line 2
911
+ #endif
912
+ // 1 comment
913
+ // 2 comment
914
+ line 3 // trailing comment
915
+
916
+ '
917
+ util_strip_comments(input)
918
+ end
919
+
920
+ def test_strip_comments_c
921
+ input = 'line 1
922
+
923
+ #if 0
924
+ line 2
925
+ #endif
926
+ /*
927
+ * 1 comment
928
+ * 2 comment
929
+ */
930
+ line 3 /* trailing comment */
931
+
932
+ '
933
+ util_strip_comments(input)
934
+ end
935
+
936
+ def test_load
937
+ # totally tested by test_build
938
+ end
939
+
940
+ end # class TestC
941
+ end # class TestInline
942
+
943
+ module Foo
944
+ class Bar
945
+ # inline stuff will go here...
946
+ end
947
+ end
948
+
949
+ $test_module_code = <<-EOR
950
+ module Foo
951
+ class Bar
952
+ inline do |builder|
953
+ builder.c <<-EOC
954
+ static int forty_two_instance() { return 42; }
955
+ EOC
956
+ builder.c_singleton <<-EOC
957
+ static int twenty_four_class() { return 24; }
958
+ EOC
959
+ end
960
+ end
961
+ end
962
+ EOR
963
+
964
+ $test_module_code2 = <<-EOR
965
+ require 'inline'
966
+
967
+ # Demonstrates native functions in nested classes and
968
+ # extending a class more than once from different ruby
969
+ # source files
970
+ module Foo
971
+ class Bar
972
+ inline do |builder|
973
+ builder.c <<-EOC
974
+ int twelve_instance() { return 12; }
975
+ EOC
976
+ builder.c_singleton <<-EOC
977
+ int twelve_class() { return 12; }
978
+ EOC
979
+ end
980
+ end
981
+ end
982
+ EOR
983
+
984
+ class TestModule < InlineTestCase
985
+ def test_nested
986
+ Object.class_eval $test_module_code
987
+ fb = Foo::Bar.new
988
+ assert_equal(42, fb.forty_two_instance)
989
+ assert_equal(24, Foo::Bar.twenty_four_class)
990
+
991
+ tempfile = Tempfile.new("test_inline_nested")
992
+ tempfile.write($test_module_code2)
993
+ tempfile.flush
994
+ tempfile.rewind
995
+
996
+ FileUtils.cp tempfile.path, "#{tempfile.path}.rb"
997
+
998
+ require "#{tempfile.path}.rb"
999
+ assert_equal(12, fb.twelve_instance)
1000
+ assert_equal(12, Foo::Bar.twelve_class)
1001
+
1002
+ FileUtils.rm "#{tempfile.path}.rb"
1003
+ end
1004
+
1005
+ def test_argument_check_good
1006
+ util_arity_check
1007
+ fb = Foo::Bar.new
1008
+ assert_equal 13, fb.arity6(1, 2, 3, 4, 5, "blah")
1009
+ end
1010
+
1011
+ def test_argument_check_fewer
1012
+ util_arity_check
1013
+ fb = Foo::Bar.new
1014
+
1015
+ assert_raises ArgumentError do
1016
+ fb.arity6(1, 2, 3)
1017
+ end
1018
+ end
1019
+
1020
+ def test_argument_check_more
1021
+ util_arity_check
1022
+ fb = Foo::Bar.new
1023
+ assert_raises ArgumentError do
1024
+ fb.arity6(1, 2, 3, 4, 5, "blah", :extra)
1025
+ end
1026
+ end
1027
+
1028
+ def test_inline
1029
+ self.class.inline(:C) do |builder|
1030
+ builder.c "int add(int a, int b) { return a + b; }"
1031
+ end
1032
+ assert(test(?d, Inline.directory),
1033
+ "inline dir should have been created")
1034
+ matches = Dir[File.join(Inline.directory, "Inline_TestModule_*.c")]
1035
+ assert_equal(1, matches.length, "Source should have been created")
1036
+ library_file = matches.first.gsub(/\.c$/) { "." + Config::CONFIG["DLEXT"] }
1037
+ assert(test(?f, library_file),
1038
+ "Library file should have been created")
1039
+ end
1040
+
1041
+ def util_arity_check
1042
+ methods = Foo::Bar.public_instance_methods.map { |s| s.to_s }
1043
+
1044
+ unless methods.include? "arity6" then
1045
+ Foo::Bar.inline do |builder|
1046
+ builder.include "<string.h>"
1047
+ builder.c "int arity6(int u, int v, int w, int x, int y, char * z) { return x + y + strlen(z); }"
1048
+ end
1049
+ end
1050
+ end
1051
+ end