RubyInlineWithoutZenTest 3.12.2

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