1require 'rdoc/test_case' 2 3=begin 4 TODO: test call-seq parsing 5 6/* 7 * call-seq: 8 * ARGF.readlines(sep=$/) -> array 9 * ARGF.readlines(limit) -> array 10 * ARGF.readlines(sep, limit) -> array 11 * 12 * ARGF.to_a(sep=$/) -> array 13 * ARGF.to_a(limit) -> array 14 * ARGF.to_a(sep, limit) -> array 15 * 16 * Reads +ARGF+'s current file in its entirety, returning an +Array+ of its 17 * lines, one line per element. Lines are assumed to be separated by _sep_. 18 * 19 * lines = ARGF.readlines 20 * lines[0] #=> "This is line one\n" 21 */ 22 23assert call-seq did not stop at first empty line 24 25/* 26 * call-seq: 27 * 28 * flt ** other -> float 29 * 30 * Raises <code>float</code> the <code>other</code> power. 31 * 32 * 2.0**3 #=> 8.0 33 */ 34 35assert call-seq correct (bug: was empty) 36 37/* call-seq: flt ** other -> float */ 38 39assert call-seq correct 40 41=end 42 43class TestRDocParserC < RDoc::TestCase 44 45 def setup 46 super 47 48 @tempfile = Tempfile.new self.class.name 49 filename = @tempfile.path 50 51 @top_level = @store.add_file filename 52 @fn = filename 53 @options = RDoc::Options.new 54 @options.verbosity = 2 55 @stats = RDoc::Stats.new @store, 0 56 end 57 58 def teardown 59 super 60 61 @tempfile.close 62 end 63 64 def test_class_can_parse 65 c_parser = RDoc::Parser::C 66 67 temp_dir do 68 FileUtils.touch 'file.C' 69 assert_equal c_parser, c_parser.can_parse('file.C') 70 71 FileUtils.touch 'file.CC' 72 assert_equal c_parser, c_parser.can_parse('file.CC') 73 74 FileUtils.touch 'file.H' 75 assert_equal c_parser, c_parser.can_parse('file.H') 76 77 FileUtils.touch 'file.HH' 78 assert_equal c_parser, c_parser.can_parse('file.HH') 79 80 FileUtils.touch 'file.c' 81 assert_equal c_parser, c_parser.can_parse('file.c') 82 83 FileUtils.touch 'file.cc' 84 assert_equal c_parser, c_parser.can_parse('file.cc') 85 86 FileUtils.touch 'file.cpp' 87 assert_equal c_parser, c_parser.can_parse('file.cpp') 88 89 FileUtils.touch 'file.cxx' 90 assert_equal c_parser, c_parser.can_parse('file.cxx') 91 92 FileUtils.touch 'file.h' 93 assert_equal c_parser, c_parser.can_parse('file.h') 94 95 FileUtils.touch 'file.hh' 96 assert_equal c_parser, c_parser.can_parse('file.hh') 97 98 FileUtils.touch 'file.y' 99 assert_equal c_parser, c_parser.can_parse('file.y') 100 end 101 end 102 103 def test_initialize 104 some_ext = @top_level.add_class RDoc::NormalClass, 'SomeExt' 105 @top_level.add_class RDoc::SingleClass, 'SomeExtSingle' 106 107 @store.cache[:c_class_variables] = { 108 @fn => { 'cSomeExt' => 'SomeExt' } 109 } 110 111 @store.cache[:c_singleton_class_variables] = { 112 @fn => { 'cSomeExtSingle' => 'SomeExtSingle' } 113 } 114 115 parser = RDoc::Parser::C.new @top_level, @fn, '', @options, @stats 116 117 expected = { 'cSomeExt' => some_ext } 118 assert_equal expected, parser.classes 119 120 expected = { 'cSomeExtSingle' => 'SomeExtSingle' } 121 assert_equal expected, parser.singleton_classes 122 123 expected = { 124 'cSomeExt' => 'SomeExt', 125 'cSomeExtSingle' => 'SomeExtSingle', 126 } 127 known_classes = parser.known_classes.delete_if do |key, _| 128 RDoc::KNOWN_CLASSES.keys.include? key 129 end 130 131 assert_equal expected, known_classes 132 end 133 134 def test_do_attr_rb_attr 135 content = <<-EOF 136void Init_Blah(void) { 137 cBlah = rb_define_class("Blah", rb_cObject); 138 139 /* 140 * This is an accessor 141 */ 142 rb_attr(cBlah, rb_intern("accessor"), 1, 1, Qfalse); 143 144 /* 145 * This is a reader 146 */ 147 rb_attr(cBlah, rb_intern("reader"), 1, 0, Qfalse); 148 149 /* 150 * This is a writer 151 */ 152 rb_attr(cBlah, rb_intern("writer"), 0, 1, Qfalse); 153} 154 EOF 155 156 klass = util_get_class content, 'cBlah' 157 158 attrs = klass.attributes 159 assert_equal 3, attrs.length, attrs.inspect 160 161 accessor = attrs.shift 162 assert_equal 'accessor', accessor.name 163 assert_equal 'RW', accessor.rw 164 assert_equal 'This is an accessor', accessor.comment.text 165 assert_equal @top_level, accessor.file 166 167 reader = attrs.shift 168 assert_equal 'reader', reader.name 169 assert_equal 'R', reader.rw 170 assert_equal 'This is a reader', reader.comment.text 171 172 writer = attrs.shift 173 assert_equal 'writer', writer.name 174 assert_equal 'W', writer.rw 175 assert_equal 'This is a writer', writer.comment.text 176 end 177 178 def test_do_attr_rb_define_attr 179 content = <<-EOF 180void Init_Blah(void) { 181 cBlah = rb_define_class("Blah", rb_cObject); 182 183 /* 184 * This is an accessor 185 */ 186 rb_define_attr(cBlah, "accessor", 1, 1); 187} 188 EOF 189 190 klass = util_get_class content, 'cBlah' 191 192 attrs = klass.attributes 193 assert_equal 1, attrs.length, attrs.inspect 194 195 accessor = attrs.shift 196 assert_equal 'accessor', accessor.name 197 assert_equal 'RW', accessor.rw 198 assert_equal 'This is an accessor', accessor.comment.text 199 assert_equal @top_level, accessor.file 200 end 201 202 def test_do_aliases 203 content = <<-EOF 204/* 205 * This should show up as an alias with documentation 206 */ 207VALUE blah(VALUE klass, VALUE year) { 208} 209 210void Init_Blah(void) { 211 cDate = rb_define_class("Date", rb_cObject); 212 213 rb_define_method(cDate, "blah", blah, 1); 214 215 rb_define_alias(cDate, "bleh", "blah"); 216} 217 EOF 218 219 klass = util_get_class content, 'cDate' 220 221 methods = klass.method_list 222 assert_equal 2, methods.length 223 assert_equal 'bleh', methods.last.name 224 assert_equal 'blah', methods.last.is_alias_for.name 225 226 assert_equal @top_level, methods.last.is_alias_for.file 227 assert_equal @top_level, methods.last.file 228 end 229 230 def test_do_aliases_singleton 231 content = <<-EOF 232/* 233 * This should show up as a method with documentation 234 */ 235VALUE blah(VALUE klass, VALUE year) { 236} 237 238void Init_Blah(void) { 239 cDate = rb_define_class("Date", rb_cObject); 240 sDate = rb_singleton_class(cDate); 241 242 rb_define_method(sDate, "blah", blah, 1); 243 244 /* 245 * This should show up as an alias 246 */ 247 rb_define_alias(sDate, "bleh", "blah"); 248} 249 EOF 250 251 klass = util_get_class content, 'cDate' 252 253 methods = klass.method_list 254 255 assert_equal 2, methods.length 256 assert_equal 'bleh', methods.last.name 257 assert methods.last.singleton 258 assert_equal 'blah', methods.last.is_alias_for.name 259 assert_equal 'This should show up as an alias', methods.last.comment.text 260 end 261 262 def test_do_classes_boot_class 263 content = <<-EOF 264/* Document-class: Foo 265 * this is the Foo boot class 266 */ 267VALUE cFoo = boot_defclass("Foo", rb_cObject); 268 EOF 269 270 klass = util_get_class content, 'cFoo' 271 assert_equal "this is the Foo boot class", klass.comment.text 272 assert_equal 'Object', klass.superclass 273 end 274 275 def test_do_classes_boot_class_nil 276 content = <<-EOF 277/* Document-class: Foo 278 * this is the Foo boot class 279 */ 280VALUE cFoo = boot_defclass("Foo", 0); 281 EOF 282 283 klass = util_get_class content, 'cFoo' 284 assert_equal "this is the Foo boot class", klass.comment.text 285 assert_equal nil, klass.superclass 286 end 287 288 def test_do_aliases_missing_class 289 content = <<-EOF 290void Init_Blah(void) { 291 rb_define_alias(cDate, "b", "a"); 292} 293 EOF 294 295 _, err = verbose_capture_io do 296 refute util_get_class(content, 'cDate') 297 end 298 299 assert_equal "Enclosing class or module \"cDate\" for alias b a is not known\n", 300 err 301 end 302 303 def test_do_classes_class 304 content = <<-EOF 305/* Document-class: Foo 306 * this is the Foo class 307 */ 308VALUE cFoo = rb_define_class("Foo", rb_cObject); 309 EOF 310 311 klass = util_get_class content, 'cFoo' 312 assert_equal "this is the Foo class", klass.comment.text 313 end 314 315 def test_do_classes_struct 316 content = <<-EOF 317/* Document-class: Foo 318 * this is the Foo class 319 */ 320VALUE cFoo = rb_struct_define_without_accessor( 321 "Foo", rb_cObject, foo_alloc, 322 "some", "various", "fields", NULL); 323 EOF 324 325 klass = util_get_class content, 'cFoo' 326 assert_equal "this is the Foo class", klass.comment.text 327 end 328 329 def test_do_classes_class_under 330 content = <<-EOF 331/* Document-class: Kernel::Foo 332 * this is the Foo class under Kernel 333 */ 334VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_cObject); 335 EOF 336 337 klass = util_get_class content, 'cFoo' 338 assert_equal 'Kernel::Foo', klass.full_name 339 assert_equal "this is the Foo class under Kernel", klass.comment.text 340 end 341 342 def test_do_classes_class_under_rb_path2class 343 content = <<-EOF 344/* Document-class: Kernel::Foo 345 * this is Kernel::Foo < A::B 346 */ 347VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_path2class("A::B")); 348 EOF 349 350 klass = util_get_class content, 'cFoo' 351 352 assert_equal 'Kernel::Foo', klass.full_name 353 assert_equal 'A::B', klass.superclass 354 assert_equal 'this is Kernel::Foo < A::B', klass.comment.text 355 end 356 357 def test_do_classes_singleton 358 content = <<-EOF 359VALUE cFoo = rb_define_class("Foo", rb_cObject); 360VALUE cFooS = rb_singleton_class(cFoo); 361 EOF 362 363 util_get_class content, 'cFooS' 364 365 assert_equal 'Foo', @parser.singleton_classes['cFooS'] 366 end 367 368 def test_do_classes_module 369 content = <<-EOF 370/* Document-module: Foo 371 * this is the Foo module 372 */ 373VALUE mFoo = rb_define_module("Foo"); 374 EOF 375 376 klass = util_get_class content, 'mFoo' 377 assert_equal "this is the Foo module", klass.comment.text 378 end 379 380 def test_do_classes_module_under 381 content = <<-EOF 382/* Document-module: Kernel::Foo 383 * this is the Foo module under Kernel 384 */ 385VALUE mFoo = rb_define_module_under(rb_mKernel, "Foo"); 386 EOF 387 388 klass = util_get_class content, 'mFoo' 389 assert_equal "this is the Foo module under Kernel", klass.comment.text 390 end 391 392 def test_do_constants 393 content = <<-EOF 394#include <ruby.h> 395 396void Init_foo(){ 397 VALUE cFoo = rb_define_class("Foo", rb_cObject); 398 399 /* 300: The highest possible score in bowling */ 400 rb_define_const(cFoo, "PERFECT", INT2FIX(300)); 401 402 /* Huzzah!: What you cheer when you roll a perfect game */ 403 rb_define_const(cFoo, "CHEER", rb_str_new2("Huzzah!")); 404 405 /* TEST\:TEST: Checking to see if escaped colon works */ 406 rb_define_const(cFoo, "TEST", rb_str_new2("TEST:TEST")); 407 408 /* \\: The file separator on MS Windows */ 409 rb_define_const(cFoo, "MSEPARATOR", rb_str_new2("\\")); 410 411 /* /: The file separator on Unix */ 412 rb_define_const(cFoo, "SEPARATOR", rb_str_new2("/")); 413 414 /* C:\\Program Files\\Stuff: A directory on MS Windows */ 415 rb_define_const(cFoo, "STUFF", rb_str_new2("C:\\Program Files\\Stuff")); 416 417 /* Default definition */ 418 rb_define_const(cFoo, "NOSEMI", INT2FIX(99)); 419 420 rb_define_const(cFoo, "NOCOMMENT", rb_str_new2("No comment")); 421 422 /* 423 * Multiline comment goes here because this comment spans multiple lines. 424 * Multiline comment goes here because this comment spans multiple lines. 425 */ 426 rb_define_const(cFoo, "MULTILINE", INT2FIX(1)); 427 428 /* 429 * 1: Multiline comment goes here because this comment spans multiple lines. 430 * Multiline comment goes here because this comment spans multiple lines. 431 */ 432 rb_define_const(cFoo, "MULTILINE_VALUE", INT2FIX(1)); 433 434 /* Multiline comment goes here because this comment spans multiple lines. 435 * Multiline comment goes here because this comment spans multiple lines. 436 */ 437 rb_define_const(cFoo, "MULTILINE_NOT_EMPTY", INT2FIX(1)); 438 439 /* 440 * Multiline comment goes here because this comment spans multiple lines. 441 * 1: However, the value extraction should only happen for the first line 442 */ 443 rb_define_const(cFoo, "MULTILINE_COLON_ON_SECOND_LINE", INT2FIX(1)); 444 445} 446 EOF 447 448 @parser = util_parser content 449 450 @parser.do_classes 451 @parser.do_constants 452 453 klass = @parser.classes['cFoo'] 454 assert klass 455 456 constants = klass.constants 457 assert !klass.constants.empty? 458 459 assert_equal @top_level, constants.first.file 460 461 constants = constants.map { |c| [c.name, c.value, c.comment.text] } 462 463 assert_equal ['PERFECT', '300', 'The highest possible score in bowling '], 464 constants.shift 465 assert_equal ['CHEER', 'Huzzah!', 466 'What you cheer when you roll a perfect game '], 467 constants.shift 468 assert_equal ['TEST', 'TEST:TEST', 469 'Checking to see if escaped colon works '], 470 constants.shift 471 assert_equal ['MSEPARATOR', '\\', 472 'The file separator on MS Windows '], 473 constants.shift 474 assert_equal ['SEPARATOR', '/', 475 'The file separator on Unix '], 476 constants.shift 477 assert_equal ['STUFF', 'C:\\Program Files\\Stuff', 478 'A directory on MS Windows '], 479 constants.shift 480 assert_equal ['NOSEMI', 'INT2FIX(99)', 481 'Default definition '], 482 constants.shift 483 assert_equal ['NOCOMMENT', 'rb_str_new2("No comment")', ''], 484 constants.shift 485 486 comment = <<-EOF.chomp 487Multiline comment goes here because this comment spans multiple lines. 488Multiline comment goes here because this comment spans multiple lines. 489 EOF 490 assert_equal ['MULTILINE', 'INT2FIX(1)', comment], constants.shift 491 assert_equal ['MULTILINE_VALUE', '1', comment], constants.shift 492 assert_equal ['MULTILINE_NOT_EMPTY', 'INT2FIX(1)', comment], constants.shift 493 494 comment = <<-EOF.chomp 495Multiline comment goes here because this comment spans multiple lines. 4961: However, the value extraction should only happen for the first line 497 EOF 498 assert_equal ['MULTILINE_COLON_ON_SECOND_LINE', 'INT2FIX(1)', comment], 499 constants.shift 500 501 assert constants.empty?, constants.inspect 502 end 503 504 def test_do_constants_curses 505 content = <<-EOF 506void Init_curses(){ 507 mCurses = rb_define_module("Curses"); 508 509 /* 510 * Document-const: Curses::COLOR_BLACK 511 * 512 * Value of the color black 513 */ 514 rb_curses_define_const(COLOR_BLACK); 515} 516 EOF 517 518 @parser = util_parser content 519 520 @parser.do_modules 521 @parser.do_classes 522 @parser.do_constants 523 524 klass = @parser.classes['mCurses'] 525 526 constants = klass.constants 527 refute_empty klass.constants 528 529 assert_equal 'COLOR_BLACK', constants.first.name 530 assert_equal 'UINT2NUM(COLOR_BLACK)', constants.first.value 531 assert_equal 'Value of the color black', constants.first.comment.text 532 end 533 534 def test_do_constants_file 535 content = <<-EOF 536void Init_File(void) { 537 rb_cFile = rb_define_class("File", rb_cIO); 538 rb_mFConst = rb_define_module_under(rb_cFile, "Constants"); 539 rb_include_module(rb_cIO, rb_mFConst); 540 541 /* Document-const: LOCK_SH 542 * 543 * Shared lock 544 */ 545 rb_file_const("LOCK_SH", INT2FIX(LOCK_SH)); 546} 547 EOF 548 549 @parser = util_parser content 550 551 @parser.do_modules 552 @parser.do_classes 553 @parser.do_constants 554 555 klass = @parser.classes['rb_mFConst'] 556 557 constants = klass.constants 558 refute_empty klass.constants 559 560 constant = constants.first 561 562 assert_equal 'LOCK_SH', constant.name 563 assert_equal 'INT2FIX(LOCK_SH)', constant.value 564 assert_equal 'Shared lock', constant.comment.text 565 end 566 567 def test_do_includes 568 content = <<-EOF 569Init_foo() { 570 VALUE cFoo = rb_define_class("Foo", rb_cObject); 571 VALUE mInc = rb_define_module("Inc"); 572 573 rb_include_module(cFoo, mInc); 574} 575 EOF 576 577 klass = util_get_class content, 'cFoo' 578 579 incl = klass.includes.first 580 assert_equal 'Inc', incl.name 581 assert_equal '', incl.comment.text 582 assert_equal @top_level, incl.file 583 end 584 585 # HACK parsing warning instead of setting up in file 586 def test_do_methods_in_c 587 content = <<-EOF 588VALUE blah(VALUE klass, VALUE year) { 589} 590 591void Init_Blah(void) { 592 cDate = rb_define_class("Date", rb_cObject); 593 594 rb_define_method(cDate, "blah", blah, 1); /* in blah.c */ 595} 596 EOF 597 598 klass = nil 599 600 _, err = verbose_capture_io do 601 klass = util_get_class content, 'cDate' 602 end 603 604 assert_match ' blah.c ', err 605 end 606 607 # HACK parsing warning instead of setting up in file 608 def test_do_methods_in_cpp 609 content = <<-EOF 610VALUE blah(VALUE klass, VALUE year) { 611} 612 613void Init_Blah(void) { 614 cDate = rb_define_class("Date", rb_cObject); 615 616 rb_define_method(cDate, "blah", blah, 1); /* in blah.cpp */ 617} 618 EOF 619 620 klass = nil 621 622 _, err = verbose_capture_io do 623 klass = util_get_class content, 'cDate' 624 end 625 626 assert_match ' blah.cpp ', err 627 end 628 629 # HACK parsing warning instead of setting up in file 630 def test_do_methods_in_y 631 content = <<-EOF 632VALUE blah(VALUE klass, VALUE year) { 633} 634 635void Init_Blah(void) { 636 cDate = rb_define_class("Date", rb_cObject); 637 638 rb_define_method(cDate, "blah", blah, 1); /* in blah.y */ 639} 640 EOF 641 642 klass = nil 643 644 _, err = verbose_capture_io do 645 klass = util_get_class content, 'cDate' 646 end 647 648 assert_match ' blah.y ', err 649 end 650 651 def test_do_methods_singleton_class 652 content = <<-EOF 653VALUE blah(VALUE klass, VALUE year) { 654} 655 656void Init_Blah(void) { 657 cDate = rb_define_class("Date", rb_cObject); 658 sDate = rb_singleton_class(cDate); 659 660 rb_define_method(sDate, "blah", blah, 1); 661} 662 EOF 663 664 klass = util_get_class content, 'cDate' 665 666 methods = klass.method_list 667 assert_equal 1, methods.length 668 assert_equal 'blah', methods.first.name 669 assert methods.first.singleton 670 end 671 672 def test_do_missing 673 parser = util_parser 674 675 klass_a = @top_level.add_class RDoc::ClassModule, 'A' 676 parser.classes['a'] = klass_a 677 678 parser.enclosure_dependencies['c'] << 'b' 679 parser.enclosure_dependencies['b'] << 'a' 680 parser.enclosure_dependencies['d'] << 'a' 681 682 parser.missing_dependencies['d'] = ['d', :class, 'D', 'Object', 'a'] 683 parser.missing_dependencies['c'] = ['c', :class, 'C', 'Object', 'b'] 684 parser.missing_dependencies['b'] = ['b', :class, 'B', 'Object', 'a'] 685 686 parser.do_missing 687 688 assert_equal %w[A A::B A::B::C A::D], 689 @store.all_classes_and_modules.map { |m| m.full_name }.sort 690 end 691 692 def test_do_missing_cycle 693 parser = util_parser 694 695 klass_a = @top_level.add_class RDoc::ClassModule, 'A' 696 parser.classes['a'] = klass_a 697 698 parser.enclosure_dependencies['c'] << 'b' 699 parser.enclosure_dependencies['b'] << 'a' 700 701 parser.missing_dependencies['c'] = ['c', :class, 'C', 'Object', 'b'] 702 parser.missing_dependencies['b'] = ['b', :class, 'B', 'Object', 'a'] 703 704 parser.enclosure_dependencies['y'] << 'z' 705 parser.enclosure_dependencies['z'] << 'y' 706 707 parser.missing_dependencies['y'] = ['y', :class, 'Y', 'Object', 'z'] 708 parser.missing_dependencies['z'] = ['z', :class, 'Z', 'Object', 'y'] 709 710 _, err = verbose_capture_io do 711 parser.do_missing 712 end 713 714 expected = 'Unable to create class Y (y), class Z (z) ' + 715 'due to a cyclic class or module creation' 716 717 assert_equal expected, err.chomp 718 719 assert_equal %w[A A::B A::B::C], 720 @store.all_classes_and_modules.map { |m| m.full_name }.sort 721 end 722 723 def test_find_alias_comment 724 parser = util_parser 725 726 comment = parser.find_alias_comment 'C', '[]', 'index' 727 728 assert_equal '', comment.text 729 730 parser = util_parser <<-C 731/* 732 * comment 733 */ 734 735rb_define_alias(C, "[]", "index"); 736 C 737 738 comment = parser.find_alias_comment 'C', '[]', 'index' 739 740 assert_equal "/*\n * comment\n */\n\n", comment.text 741 end 742 743 def test_find_class_comment 744 @options.rdoc_include << File.dirname(__FILE__) 745 746 content = <<-EOF 747/* 748 * Comment 1 749 */ 750foo = rb_define_class("MyClassName1", rb_cObject); 751 752/* 753 * Comment 2 754 */ 755bar = rb_define_class("MyClassName2", rb_cObject); 756 EOF 757 758 util_get_class content 759 760 assert_equal "Comment 1", @parser.classes['foo'].comment.text 761 assert_equal "Comment 2", @parser.classes['bar'].comment.text 762 end 763 764 def test_find_class_comment_init 765 content = <<-EOF 766/* 767 * a comment for class Foo 768 */ 769void 770Init_Foo(void) { 771 VALUE foo = rb_define_class("Foo", rb_cObject); 772} 773 EOF 774 775 klass = util_get_class content, 'foo' 776 777 assert_equal "a comment for class Foo", klass.comment.text 778 end 779 780 def test_find_class_comment_define_class 781 content = <<-EOF 782/* 783 * a comment for class Foo 784 */ 785VALUE foo = rb_define_class("Foo", rb_cObject); 786 EOF 787 788 klass = util_get_class content, 'foo' 789 790 assert_equal "a comment for class Foo", klass.comment.text 791 end 792 793 def test_find_class_comment_define_class_Init_Foo 794 content = <<-EOF 795/* 796 * a comment for class Foo on Init 797 */ 798void 799Init_Foo(void) { 800 /* 801 * a comment for class Foo on rb_define_class 802 */ 803 VALUE foo = rb_define_class("Foo", rb_cObject); 804} 805 EOF 806 807 klass = util_get_class content, 'foo' 808 809 assert_equal "a comment for class Foo on Init", klass.comment.text 810 end 811 812 def test_find_class_comment_define_class_Init_Foo_no_void 813 content = <<-EOF 814/* 815 * a comment for class Foo on Init 816 */ 817void 818Init_Foo() { 819 /* 820 * a comment for class Foo on rb_define_class 821 */ 822 VALUE foo = rb_define_class("Foo", rb_cObject); 823} 824 EOF 825 826 klass = util_get_class content, 'foo' 827 828 assert_equal "a comment for class Foo on Init", klass.comment.text 829 end 830 831 def test_find_class_comment_define_class_bogus_comment 832 content = <<-EOF 833/* 834 * a comment for other_function 835 */ 836void 837other_function() { 838} 839 840void 841Init_Foo(void) { 842 VALUE foo = rb_define_class("Foo", rb_cObject); 843} 844 EOF 845 846 klass = util_get_class content, 'foo' 847 848 assert_equal '', klass.comment.text 849 end 850 851 def test_find_class_comment_define_class_under 852 content = <<-EOF 853/* 854 * a comment for class Foo 855 */ 856VALUE foo = rb_define_class_under(rb_cObject, "Foo", rb_cObject); 857 EOF 858 859 klass = util_get_class content, 'foo' 860 861 assert_equal "a comment for class Foo", klass.comment.text 862 end 863 864 def test_find_class_comment_define_class_under_Init 865 content = <<-EOF 866/* 867 * a comment for class Foo on Init 868 */ 869void 870Init_Foo(void) { 871 /* 872 * a comment for class Foo on rb_define_class 873 */ 874 VALUE foo = rb_define_class_under(rb_cObject, "Foo", rb_cObject); 875} 876 EOF 877 878 klass = util_get_class content, 'foo' 879 880 # the inner comment is used since Object::Foo is not necessarily the same 881 # thing as "Foo" for Init_ 882 assert_equal "a comment for class Foo on rb_define_class", 883 klass.comment.text 884 end 885 886 def test_find_const_comment_rb_define 887 content = <<-EOF 888/* 889 * A comment 890 */ 891rb_define_const(cFoo, "CONST", value); 892 EOF 893 894 parser = util_parser content 895 896 comment = parser.find_const_comment 'const', 'CONST' 897 898 assert_equal "/*\n * A comment\n */\n", comment.text 899 end 900 901 def test_find_const_comment_document_const 902 content = <<-EOF 903/* 904 * Document-const: CONST 905 * 906 * A comment 907 */ 908 EOF 909 910 parser = util_parser content 911 912 comment = parser.find_const_comment nil, 'CONST' 913 914 assert_equal "/*\n *\n * A comment\n */", comment.text 915 end 916 917 def test_find_const_comment_document_const_full_name 918 content = <<-EOF 919/* 920 * Document-const: Foo::CONST 921 * 922 * A comment 923 */ 924 EOF 925 926 parser = util_parser content 927 928 comment = parser.find_const_comment nil, 'CONST', 'Foo' 929 930 assert_equal "/*\n *\n * A comment\n */", comment.text 931 end 932 933 def test_find_body 934 content = <<-EOF 935/* 936 * a comment for other_function 937 */ 938VALUE 939other_function() { 940} 941 942void 943Init_Foo(void) { 944 VALUE foo = rb_define_class("Foo", rb_cObject); 945 946 rb_define_method(foo, "my_method", other_function, 0); 947} 948 EOF 949 950 klass = util_get_class content, 'foo' 951 other_function = klass.method_list.first 952 953 assert_equal 'my_method', other_function.name 954 assert_equal "a comment for other_function", 955 other_function.comment.text 956 assert_equal '()', other_function.params 957 958 code = other_function.token_stream.first.text 959 960 assert_equal "VALUE\nother_function() {\n}", code 961 end 962 963 def test_find_body_2 964 content = <<-CONTENT 965/* Copyright (C) 2010 Sven Herzberg 966 * 967 * This file is free software; the author(s) gives unlimited 968 * permission to copy and/or distribute it, with or without 969 * modifications, as long as this notice is preserved. 970 */ 971 972#include <ruby.h> 973 974static VALUE 975wrap_initialize (VALUE self) 976{ 977 return self; 978} 979 980/* */ 981static VALUE 982wrap_shift (VALUE self, 983 VALUE arg) 984{ 985 return self; 986} 987 988void 989init_gi_repository (void) 990{ 991 VALUE mTest = rb_define_module ("Test"); 992 VALUE cTest = rb_define_class_under (mTest, "Test", rb_cObject); 993 994 rb_define_method (cTest, "initialize", wrap_initialize, 0); 995 rb_define_method (cTest, "shift", wrap_shift, 0); 996} 997 CONTENT 998 999 klass = util_get_class content, 'cTest' 1000 assert_equal 2, klass.method_list.length 1001 end 1002 1003 def test_find_body_define 1004 content = <<-EOF 1005#define something something_else 1006 1007#define other_function rb_other_function 1008 1009/* 1010 * a comment for rb_other_function 1011 */ 1012VALUE 1013rb_other_function() { 1014} 1015 1016void 1017Init_Foo(void) { 1018 VALUE foo = rb_define_class("Foo", rb_cObject); 1019 1020 rb_define_method(foo, "my_method", other_function, 0); 1021} 1022 EOF 1023 1024 klass = util_get_class content, 'foo' 1025 other_function = klass.method_list.first 1026 1027 assert_equal 'my_method', other_function.name 1028 assert_equal 'a comment for rb_other_function', other_function.comment.text 1029 assert_equal '()', other_function.params 1030 assert_equal 118, other_function.offset 1031 assert_equal 8, other_function.line 1032 1033 code = other_function.token_stream.first.text 1034 1035 assert_equal "VALUE\nrb_other_function() {\n}", code 1036 end 1037 1038 def test_find_body_define_comment 1039 content = <<-EOF 1040/* 1041 * a comment for other_function 1042 */ 1043#define other_function rb_other_function 1044 1045/* */ 1046VALUE 1047rb_other_function() { 1048} 1049 1050void 1051Init_Foo(void) { 1052 VALUE foo = rb_define_class("Foo", rb_cObject); 1053 1054 rb_define_method(foo, "my_method", other_function, 0); 1055} 1056 EOF 1057 1058 klass = util_get_class content, 'foo' 1059 other_function = klass.method_list.first 1060 1061 assert_equal 'my_method', other_function.name 1062 assert_equal 'a comment for other_function', other_function.comment.text 1063 assert_equal '()', other_function.params 1064 assert_equal 39, other_function.offset 1065 assert_equal 4, other_function.line 1066 1067 code = other_function.token_stream.first.text 1068 1069 assert_equal "#define other_function rb_other_function", code 1070 end 1071 1072 def test_find_body_document_method 1073 content = <<-EOF 1074/* 1075 * Document-method: bar 1076 * Document-method: baz 1077 * 1078 * a comment for bar 1079 */ 1080VALUE 1081bar() { 1082} 1083 1084void 1085Init_Foo(void) { 1086 VALUE foo = rb_define_class("Foo", rb_cObject); 1087 1088 rb_define_method(foo, "bar", bar, 0); 1089 rb_define_method(foo, "baz", bar, 0); 1090} 1091 EOF 1092 1093 klass = util_get_class content, 'foo' 1094 assert_equal 2, klass.method_list.length 1095 1096 methods = klass.method_list.sort 1097 1098 bar = methods.first 1099 assert_equal 'Foo#bar', bar.full_name 1100 assert_equal "a comment for bar", bar.comment.text 1101 1102 baz = methods.last 1103 assert_equal 'Foo#baz', baz.full_name 1104 assert_equal "a comment for bar", baz.comment.text 1105 end 1106 1107 def test_find_body_document_method_equals 1108 content = <<-EOF 1109/* 1110 * Document-method: Zlib::GzipFile#mtime= 1111 * 1112 * A comment 1113 */ 1114static VALUE 1115rb_gzfile_set_mtime(VALUE obj, VALUE mtime) 1116{ 1117 1118void 1119Init_zlib() { 1120 mZlib = rb_define_module("Zlib"); 1121 cGzipFile = rb_define_class_under(mZlib, "GzipFile", rb_cObject); 1122 cGzipWriter = rb_define_class_under(mZlib, "GzipWriter", cGzipFile); 1123 rb_define_method(cGzipWriter, "mtime=", rb_gzfile_set_mtime, 1); 1124} 1125 EOF 1126 1127 klass = util_get_class content, 'cGzipWriter' 1128 assert_equal 1, klass.method_list.length 1129 1130 methods = klass.method_list.sort 1131 1132 bar = methods.first 1133 assert_equal 'Zlib::GzipWriter#mtime=', bar.full_name 1134 assert_equal 'A comment', bar.comment.text 1135 end 1136 1137 def test_find_body_document_method_same 1138 content = <<-EOF 1139VALUE 1140s_bar() { 1141} 1142 1143VALUE 1144bar() { 1145} 1146 1147/* 1148 * Document-method: Foo::bar 1149 * 1150 * a comment for Foo::bar 1151 */ 1152 1153/* 1154 * Document-method: Foo#bar 1155 * 1156 * a comment for Foo#bar 1157 */ 1158 1159void 1160Init_Foo(void) { 1161 VALUE foo = rb_define_class("Foo", rb_cObject); 1162 1163 rb_define_singleton_method(foo, "bar", s_bar, 0); 1164 rb_define_method(foo, "bar", bar, 0); 1165} 1166 EOF 1167 1168 klass = util_get_class content, 'foo' 1169 assert_equal 2, klass.method_list.length 1170 1171 methods = klass.method_list.sort 1172 1173 s_bar = methods.first 1174 assert_equal 'Foo::bar', s_bar.full_name 1175 assert_equal "a comment for Foo::bar", s_bar.comment.text 1176 1177 bar = methods.last 1178 assert_equal 'Foo#bar', bar.full_name 1179 assert_equal "a comment for Foo#bar", bar.comment.text 1180 end 1181 1182 def test_find_modifiers_call_seq 1183 comment = RDoc::Comment.new <<-COMMENT 1184call-seq: 1185 commercial() -> Date <br /> 1186 1187If no arguments are given: 1188 1189 COMMENT 1190 1191 parser = util_parser 1192 method_obj = RDoc::AnyMethod.new nil, 'blah' 1193 1194 parser.find_modifiers comment, method_obj 1195 1196 expected = <<-CALL_SEQ.chomp 1197commercial() -> Date <br /> 1198 1199 CALL_SEQ 1200 1201 assert_equal expected, method_obj.call_seq 1202 end 1203 1204 def test_find_modifiers_nodoc 1205 comment = RDoc::Comment.new <<-COMMENT 1206/* :nodoc: 1207 * 1208 * Blah 1209 */ 1210 1211 COMMENT 1212 1213 parser = util_parser 1214 method_obj = RDoc::AnyMethod.new nil, 'blah' 1215 1216 parser.find_modifiers comment, method_obj 1217 1218 assert_equal nil, method_obj.document_self 1219 end 1220 1221 def test_find_modifiers_yields 1222 comment = RDoc::Comment.new <<-COMMENT 1223/* :yields: a, b 1224 * 1225 * Blah 1226 */ 1227 1228 COMMENT 1229 1230 parser = util_parser 1231 method_obj = RDoc::AnyMethod.new nil, 'blah' 1232 1233 parser.find_modifiers comment, method_obj 1234 1235 assert_equal 'a, b', method_obj.block_params 1236 1237 assert_equal "\n\nBlah", comment.text 1238 end 1239 1240 def test_handle_method_args_minus_1 1241 parser = util_parser "Document-method: Object#m\n blah */" 1242 1243 parser.content = <<-BODY 1244VALUE 1245rb_other(VALUE obj) { 1246 rb_funcall(obj, rb_intern("other"), 0); 1247 return rb_str_new2("blah, blah, blah"); 1248} 1249 1250VALUE 1251rb_m(int argc, VALUE *argv, VALUE obj) { 1252 VALUE o1, o2; 1253 rb_scan_args(argc, argv, "1", &o1, &o2); 1254} 1255 BODY 1256 1257 parser.handle_method 'method', 'rb_cObject', 'm', 'rb_m', -1 1258 1259 m = @top_level.find_module_named('Object').method_list.first 1260 1261 assert_equal 'm', m.name 1262 assert_equal @top_level, m.file 1263 assert_equal 115, m.offset 1264 assert_equal 7, m.line 1265 1266 assert_equal '(p1)', m.params 1267 end 1268 1269 def test_handle_method_args_0 1270 parser = util_parser "Document-method: BasicObject#==\n blah */" 1271 1272 parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 0 1273 1274 bo = @top_level.find_module_named 'BasicObject' 1275 1276 assert_equal 1, bo.method_list.length 1277 1278 equals2 = bo.method_list.first 1279 1280 assert_equal '()', equals2.params 1281 end 1282 1283 def test_handle_method_args_1 1284 parser = util_parser "Document-method: BasicObject#==\n blah */" 1285 1286 parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 1 1287 1288 bo = @top_level.find_module_named 'BasicObject' 1289 1290 assert_equal 1, bo.method_list.length 1291 1292 equals2 = bo.method_list.first 1293 1294 assert_equal '(p1)', equals2.params 1295 end 1296 1297 def test_handle_method_args_2 1298 parser = util_parser "Document-method: BasicObject#==\n blah */" 1299 1300 parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', 2 1301 1302 bo = @top_level.find_module_named 'BasicObject' 1303 1304 assert_equal 1, bo.method_list.length 1305 1306 equals2 = bo.method_list.first 1307 1308 assert_equal '(p1, p2)', equals2.params 1309 end 1310 1311 # test_handle_args_minus_1 handled by test_handle_method 1312 1313 def test_handle_method_args_minus_2 1314 parser = util_parser "Document-method: BasicObject#==\n blah */" 1315 1316 parser.handle_method 'method', 'rb_cBasicObject', '==', 'rb_obj_equal', -2 1317 1318 bo = @top_level.find_module_named 'BasicObject' 1319 1320 assert_equal 1, bo.method_list.length 1321 1322 equals2 = bo.method_list.first 1323 1324 assert_equal '(*args)', equals2.params 1325 end 1326 1327 def test_handle_method_initialize 1328 parser = util_parser "Document-method: BasicObject::new\n blah */" 1329 1330 parser.handle_method('private_method', 'rb_cBasicObject', 1331 'initialize', 'rb_obj_dummy', -1) 1332 1333 bo = @top_level.find_module_named 'BasicObject' 1334 1335 assert_equal 1, bo.method_list.length 1336 1337 new = bo.method_list.first 1338 1339 assert_equal 'new', new.name 1340 assert_equal :public, new.visibility 1341 end 1342 1343 def test_handle_singleton 1344 parser = util_parser <<-SINGLE 1345void Init_Blah(void) { 1346 cDate = rb_define_class("Date", rb_cObject); 1347 sDate = rb_singleton_class(cDate); 1348} 1349 SINGLE 1350 1351 parser.scan 1352 1353 assert_equal 'Date', parser.known_classes['sDate'] 1354 assert_equal 'Date', parser.singleton_classes['sDate'] 1355 end 1356 1357 def test_look_for_directives_in 1358 parser = util_parser 1359 1360 comment = RDoc::Comment.new "# :other: not_handled\n" 1361 1362 parser.look_for_directives_in @top_level, comment 1363 1364 assert_equal "# :other: not_handled\n", comment.text 1365 assert_equal 'not_handled', @top_level.metadata['other'] 1366 end 1367 1368 def test_load_variable_map 1369 some_ext = @top_level.add_class RDoc::NormalClass, 'SomeExt' 1370 @top_level.add_class RDoc::NormalClass, 'OtherExt' 1371 1372 @store.cache[:c_class_variables][@fn] = { 'cSomeExt' => 'SomeExt' } 1373 @store.cache[:c_class_variables]['other.c'] = { 'cOtherExt' => 'OtherExt' } 1374 1375 parser = util_parser 1376 1377 map = parser.load_variable_map :c_class_variables 1378 1379 expected = { 'cSomeExt' => some_ext } 1380 1381 assert_equal expected, map 1382 1383 assert_equal 'SomeExt', parser.known_classes['cSomeExt'] 1384 assert_nil parser.known_classes['cOtherExt'] 1385 end 1386 1387 def test_load_variable_map_empty 1388 parser = util_parser 1389 1390 map = parser.load_variable_map :c_class_variables 1391 1392 assert_empty map 1393 end 1394 1395 def test_load_variable_map_legacy 1396 @store.cache[:c_class_variables] = nil 1397 1398 parser = util_parser 1399 1400 map = parser.load_variable_map :c_class_variables 1401 1402 assert_empty map 1403 end 1404 1405 def test_load_variable_map_singleton 1406 @top_level.add_class RDoc::NormalClass, 'SomeExt' 1407 @top_level.add_class RDoc::NormalClass, 'OtherExt' 1408 1409 @store.cache[:c_singleton_class_variables][@fn] = 1410 { 'cSomeExt' => 'SomeExt' } 1411 @store.cache[:c_singleton_class_variables]['other.c'] = 1412 { 'cOtherExt' => 'OtherExt' } 1413 1414 parser = util_parser 1415 1416 map = parser.load_variable_map :c_singleton_class_variables 1417 1418 expected = { 'cSomeExt' => 'SomeExt' } 1419 1420 assert_equal expected, map 1421 1422 assert_equal 'SomeExt', parser.known_classes['cSomeExt'] 1423 assert_nil parser.known_classes['cOtherExt'] 1424 end 1425 1426 def test_load_variable_map_trim 1427 a = @top_level.add_class RDoc::NormalClass, 'A' 1428 1429 @store.cache[:c_class_variables][@fn] = { 1430 'cA' => 'A', 1431 'cB' => 'B', 1432 } 1433 1434 parser = util_parser 1435 1436 map = parser.load_variable_map :c_class_variables 1437 1438 expected = { 'cA' => a } 1439 1440 assert_equal expected, map 1441 end 1442 1443 def test_define_method 1444 content = <<-EOF 1445/*Method Comment! */ 1446static VALUE 1447rb_io_s_read(argc, argv, io) 1448 int argc; 1449 VALUE *argv; 1450 VALUE io; 1451{ 1452} 1453 1454void 1455Init_IO(void) { 1456 /* 1457 * a comment for class Foo on rb_define_class 1458 */ 1459 VALUE rb_cIO = rb_define_class("IO", rb_cObject); 1460 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1); 1461} 1462 EOF 1463 1464 klass = util_get_class content, 'rb_cIO' 1465 read_method = klass.method_list.first 1466 assert_equal "read", read_method.name 1467 assert_equal "Method Comment! ", read_method.comment.text 1468 assert_equal "rb_io_s_read", read_method.c_function 1469 assert read_method.singleton 1470 end 1471 1472 def test_define_method_with_prototype 1473 content = <<-EOF 1474static VALUE rb_io_s_read(int, VALUE*, VALUE); 1475 1476/* Method Comment! */ 1477static VALUE 1478rb_io_s_read(argc, argv, io) 1479 int argc; 1480 VALUE *argv; 1481 VALUE io; 1482{ 1483} 1484 1485void 1486Init_IO(void) { 1487 /* 1488 * a comment for class Foo on rb_define_class 1489 */ 1490 VALUE rb_cIO = rb_define_class("IO", rb_cObject); 1491 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1); 1492} 1493 EOF 1494 1495 klass = util_get_class content, 'rb_cIO' 1496 read_method = klass.method_list.first 1497 assert_equal "read", read_method.name 1498 assert_equal "Method Comment! ", read_method.comment.text 1499 assert_equal "rb_io_s_read", read_method.c_function 1500 assert read_method.singleton 1501 end 1502 1503 def test_define_method_private 1504 content = <<-EOF 1505/*Method Comment! */ 1506static VALUE 1507rb_io_s_read(argc, argv, io) 1508 int argc; 1509 VALUE *argv; 1510 VALUE io; 1511{ 1512} 1513 1514void 1515Init_IO(void) { 1516 /* 1517 * a comment for class Foo on rb_define_class 1518 */ 1519 VALUE rb_cIO = rb_define_class("IO", rb_cObject); 1520 rb_define_private_method(rb_cIO, "read", rb_io_s_read, -1); 1521} 1522 EOF 1523 1524 klass = util_get_class content, 'rb_cIO' 1525 read_method = klass.method_list.first 1526 assert_equal 'IO#read', read_method.full_name 1527 assert_equal :private, read_method.visibility 1528 assert_equal "Method Comment! ", read_method.comment.text 1529 end 1530 1531 def test_define_method_private_singleton 1532 content = <<-EOF 1533/*Method Comment! */ 1534static VALUE 1535rb_io_s_read(argc, argv, io) 1536 int argc; 1537 VALUE *argv; 1538 VALUE io; 1539{ 1540} 1541 1542void 1543Init_IO(void) { 1544 /* 1545 * a comment for class Foo on rb_define_class 1546 */ 1547 VALUE rb_cIO = rb_define_class("IO", rb_cObject); 1548 VALUE rb_cIO_s = rb_singleton_class(rb_cIO); 1549 rb_define_private_method(rb_cIO_s, "read", rb_io_s_read, -1); 1550} 1551 EOF 1552 1553 klass = util_get_class content, 'rb_cIO' 1554 read_method = klass.method_list.first 1555 assert_equal "read", read_method.name 1556 assert_equal "Method Comment! ", read_method.comment.text 1557 assert_equal :private, read_method.visibility 1558 assert read_method.singleton 1559 end 1560 1561 def test_define_method_singleton 1562 content = <<-EOF 1563/*Method Comment! */ 1564static VALUE 1565rb_io_s_read(argc, argv, io) 1566 int argc; 1567 VALUE *argv; 1568 VALUE io; 1569{ 1570} 1571 1572void 1573Init_IO(void) { 1574 /* 1575 * a comment for class Foo on rb_define_class 1576 */ 1577 VALUE rb_cIO = rb_define_class("IO", rb_cObject); 1578 VALUE rb_cIO_s = rb_singleton_class(rb_cIO); 1579 rb_define_method(rb_cIO_s, "read", rb_io_s_read, -1); 1580} 1581 EOF 1582 1583 klass = util_get_class content, 'rb_cIO' 1584 read_method = klass.method_list.first 1585 assert_equal "read", read_method.name 1586 assert_equal "Method Comment! ", read_method.comment.text 1587 assert read_method.singleton 1588 end 1589 1590 def test_rb_scan_args 1591 parser = util_parser 1592 1593 assert_equal '(p1)', 1594 parser.rb_scan_args('rb_scan_args(a, b, "1",)') 1595 assert_equal '(p1, p2)', 1596 parser.rb_scan_args('rb_scan_args(a, b, "2",)') 1597 1598 assert_equal '(p1 = v1)', 1599 parser.rb_scan_args('rb_scan_args(a, b, "01",)') 1600 assert_equal '(p1 = v1, p2 = v2)', 1601 parser.rb_scan_args('rb_scan_args(a, b, "02",)') 1602 1603 assert_equal '(p1, p2 = v2)', 1604 parser.rb_scan_args('rb_scan_args(a, b, "11",)') 1605 1606 assert_equal '(p1, *args)', 1607 parser.rb_scan_args('rb_scan_args(a, b, "1*",)') 1608 assert_equal '(p1, p2 = {})', 1609 parser.rb_scan_args('rb_scan_args(a, b, "1:",)') 1610 assert_equal '(p1, &block)', 1611 parser.rb_scan_args('rb_scan_args(a, b, "1&",)') 1612 1613 assert_equal '(p1, p2)', 1614 parser.rb_scan_args('rb_scan_args(a, b, "101",)') 1615 1616 assert_equal '(p1, p2 = v2, p3)', 1617 parser.rb_scan_args('rb_scan_args(a, b, "111",)') 1618 1619 assert_equal '(p1, *args, p3)', 1620 parser.rb_scan_args('rb_scan_args(a, b, "1*1",)') 1621 1622 assert_equal '(p1, p2 = v2, *args)', 1623 parser.rb_scan_args('rb_scan_args(a, b, "11*",)') 1624 assert_equal '(p1, p2 = v2, p3 = {})', 1625 parser.rb_scan_args('rb_scan_args(a, b, "11:",)') 1626 assert_equal '(p1, p2 = v2, &block)', 1627 parser.rb_scan_args('rb_scan_args(a, b, "11&",)') 1628 1629 assert_equal '(p1, p2 = v2, *args, p4, p5 = {}, &block)', 1630 parser.rb_scan_args('rb_scan_args(a, b, "11*1:&",)') 1631 1632 # The following aren't valid according to spec but are according to the 1633 # implementation. 1634 assert_equal '(*args)', 1635 parser.rb_scan_args('rb_scan_args(a, b, "*",)') 1636 assert_equal '(p1 = {})', 1637 parser.rb_scan_args('rb_scan_args(a, b, ":",)') 1638 assert_equal '(&block)', 1639 parser.rb_scan_args('rb_scan_args(a, b, "&",)') 1640 1641 assert_equal '(*args, p2 = {})', 1642 parser.rb_scan_args('rb_scan_args(a, b, "*:",)') 1643 assert_equal '(p1 = {}, &block)', 1644 parser.rb_scan_args('rb_scan_args(a, b, ":&",)') 1645 assert_equal '(*args, p2 = {}, &block)', 1646 parser.rb_scan_args('rb_scan_args(a, b, "*:&",)') 1647 end 1648 1649 def test_scan 1650 parser = util_parser <<-C 1651void Init(void) { 1652 mM = rb_define_module("M"); 1653 cC = rb_define_class("C", rb_cObject); 1654 sC = rb_singleton_class(cC); 1655} 1656 C 1657 1658 parser.scan 1659 1660 expected = { 1661 @fn => { 1662 'mM' => 'M', 1663 'cC' => 'C', }} 1664 assert_equal expected, @store.c_class_variables 1665 1666 expected = { 1667 @fn => { 1668 'sC' => 'C' } } 1669 assert_equal expected, @store.c_singleton_class_variables 1670 end 1671 1672 def test_scan_order_dependent 1673 parser = util_parser <<-C 1674void a(void) { 1675 mA = rb_define_module("A"); 1676} 1677 1678void b(void) { 1679 cB = rb_define_class_under(mA, "B", rb_cObject); 1680} 1681 1682void c(void) { 1683 mC = rb_define_module_under(cB, "C"); 1684} 1685 1686void d(void) { 1687 mD = rb_define_class_under(mC, "D"); 1688} 1689 C 1690 1691 parser.scan 1692 1693 assert_equal %w[A A::B A::B::C], 1694 @store.all_classes_and_modules.map { |m| m.full_name }.sort 1695 end 1696 1697 def util_get_class content, name = nil 1698 @parser = util_parser content 1699 @parser.scan 1700 1701 @parser.classes[name] if name 1702 end 1703 1704 def util_parser content = '' 1705 RDoc::Parser::C.new @top_level, @fn, content, @options, @stats 1706 end 1707 1708end 1709 1710