1# coding: utf-8
2
3require 'rdoc/test_case'
4
5class TestRDocParserRuby < RDoc::TestCase
6
7  def setup
8    super
9
10    @tempfile = Tempfile.new self.class.name
11    @filename = @tempfile.path
12
13    # Some tests need two paths.
14    @tempfile2 = Tempfile.new self.class.name
15    @filename2 = @tempfile2.path
16
17    @top_level = @store.add_file @filename
18    @top_level2 = @store.add_file @filename2
19
20    @options = RDoc::Options.new
21    @options.quiet = true
22    @options.option_parser = OptionParser.new
23
24    @comment = RDoc::Comment.new '', @top_level
25
26    @stats = RDoc::Stats.new @store, 0
27  end
28
29  def teardown
30    super
31
32    @tempfile.close
33    @tempfile2.close
34  end
35
36  def mu_pp obj
37    s = ''
38    s = PP.pp obj, s
39    s = s.force_encoding(Encoding.default_external) if defined? Encoding
40    s.chomp
41  end
42
43  def test_collect_first_comment
44    p = util_parser <<-CONTENT
45# first
46
47# second
48class C; end
49    CONTENT
50
51    comment = p.collect_first_comment
52
53    assert_equal RDoc::Comment.new("# first\n", @top_level), comment
54  end
55
56  def test_collect_first_comment_encoding
57    skip "Encoding not implemented" unless Object.const_defined? :Encoding
58
59    @options.encoding = Encoding::CP852
60
61    p = util_parser <<-CONTENT
62# first
63
64# second
65class C; end
66    CONTENT
67
68    comment = p.collect_first_comment
69
70    assert_equal Encoding::CP852, comment.text.encoding
71  end
72
73  def test_get_class_or_module
74    ctxt = RDoc::Context.new
75    ctxt.store = @store
76
77    cont, name_t, given_name = util_parser('A')    .get_class_or_module ctxt
78
79    assert_equal ctxt, cont
80    assert_equal 'A', name_t.text
81    assert_equal 'A', given_name
82
83    cont, name_t, given_name = util_parser('B::C') .get_class_or_module ctxt
84
85    b = @store.find_module_named('B')
86    assert_equal b, cont
87    assert_equal [@top_level], b.in_files
88    assert_equal 'C', name_t.text
89    assert_equal 'B::C', given_name
90
91    cont, name_t, given_name = util_parser('D:: E').get_class_or_module ctxt
92
93    assert_equal @store.find_module_named('D'), cont
94    assert_equal 'E', name_t.text
95    assert_equal 'D::E', given_name
96
97    assert_raises NoMethodError do
98      util_parser("A::\nB").get_class_or_module ctxt
99    end
100  end
101
102  def test_get_class_or_module_document_children
103    ctxt = @top_level.add_class RDoc::NormalClass, 'A'
104    ctxt.stop_doc
105
106    util_parser('B::C').get_class_or_module ctxt
107
108    b = @store.find_module_named('A::B')
109    assert b.ignored?
110
111    d = @top_level.add_class RDoc::NormalClass, 'A::D'
112
113    util_parser('D::E').get_class_or_module ctxt
114
115    refute d.ignored?
116  end
117
118  def test_get_class_or_module_ignore_constants
119    ctxt = RDoc::Context.new
120    ctxt.store = @store
121
122    util_parser('A')   .get_class_or_module ctxt, true
123    util_parser('A::B').get_class_or_module ctxt, true
124
125    assert_empty ctxt.constants
126    assert_empty @store.modules_hash.keys
127    assert_empty @store.classes_hash.keys
128  end
129
130  def test_get_class_specification
131    assert_equal 'A',    util_parser('A')   .get_class_specification
132    assert_equal 'A::B', util_parser('A::B').get_class_specification
133    assert_equal '::A',  util_parser('::A').get_class_specification
134
135    assert_equal 'self', util_parser('self').get_class_specification
136
137    assert_equal '',     util_parser('').get_class_specification
138
139    assert_equal '',     util_parser('$g').get_class_specification
140  end
141
142  def test_get_symbol_or_name
143    util_parser "* & | + 5 / 4"
144
145    assert_equal '*', @parser.get_symbol_or_name
146
147    @parser.skip_tkspace
148
149    assert_equal '&', @parser.get_symbol_or_name
150
151    @parser.skip_tkspace
152
153    assert_equal '|', @parser.get_symbol_or_name
154
155    @parser.skip_tkspace
156
157    assert_equal '+', @parser.get_symbol_or_name
158
159    @parser.skip_tkspace
160    @parser.get_tk
161    @parser.skip_tkspace
162
163    assert_equal '/', @parser.get_symbol_or_name
164  end
165
166  def test_look_for_directives_in_attr
167    util_parser ""
168
169    comment = RDoc::Comment.new "# :attr: my_attr\n", @top_level
170
171    @parser.look_for_directives_in @top_level, comment
172
173    assert_equal "# :attr: my_attr\n", comment.text
174
175    comment = RDoc::Comment.new "# :attr_reader: my_method\n", @top_level
176
177    @parser.look_for_directives_in @top_level, comment
178
179    assert_equal "# :attr_reader: my_method\n", comment.text
180
181    comment = RDoc::Comment.new "# :attr_writer: my_method\n", @top_level
182
183    @parser.look_for_directives_in @top_level, comment
184
185    assert_equal "# :attr_writer: my_method\n", comment.text
186  end
187
188  def test_look_for_directives_in_commented
189    util_parser ""
190
191    comment = RDoc::Comment.new <<-COMMENT, @top_level
192# how to make a section:
193# # :section: new section
194    COMMENT
195
196    @parser.look_for_directives_in @top_level, comment
197
198    section = @top_level.current_section
199    assert_equal nil, section.title
200    assert_equal nil, section.comment
201
202    assert_equal "# how to make a section:\n# # :section: new section\n",
203                 comment.text
204  end
205
206  def test_look_for_directives_in_method
207    util_parser ""
208
209    comment = RDoc::Comment.new "# :method: my_method\n", @top_level
210
211    @parser.look_for_directives_in @top_level, comment
212
213    assert_equal "# :method: my_method\n", comment.text
214
215    comment = RDoc::Comment.new "# :singleton-method: my_method\n", @top_level
216
217    @parser.look_for_directives_in @top_level, comment
218
219    assert_equal "# :singleton-method: my_method\n", comment.text
220  end
221
222  def test_look_for_directives_in_section
223    util_parser ""
224
225    comment = RDoc::Comment.new <<-COMMENT, @top_level
226# :section: new section
227# woo stuff
228    COMMENT
229
230    @parser.look_for_directives_in @top_level, comment
231
232    section = @top_level.current_section
233    assert_equal 'new section', section.title
234    assert_equal [comment("# woo stuff\n", @top_level)], section.comments
235
236    assert_empty comment
237  end
238
239  def test_look_for_directives_in_unhandled
240    util_parser ""
241
242    comment = RDoc::Comment.new "# :unhandled: blah\n", @top_level
243
244    @parser.look_for_directives_in @top_level, comment
245
246    assert_equal 'blah', @top_level.metadata['unhandled']
247  end
248
249  def test_parse_alias
250    klass = RDoc::NormalClass.new 'Foo'
251    klass.parent = @top_level
252
253    util_parser "alias :next= :bar"
254
255    tk = @parser.get_tk
256
257    alas = @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment'
258
259    assert_equal 'bar',      alas.old_name
260    assert_equal 'next=',    alas.new_name
261    assert_equal klass,      alas.parent
262    assert_equal 'comment',  alas.comment
263    assert_equal @top_level, alas.file
264    assert_equal 0,          alas.offset
265    assert_equal 1,          alas.line
266  end
267
268  def test_parse_alias_singleton
269    klass = RDoc::NormalClass.new 'Foo'
270    klass.parent = @top_level
271
272    util_parser "alias :next= :bar"
273
274    tk = @parser.get_tk
275
276    alas = @parser.parse_alias klass, RDoc::Parser::Ruby::SINGLE, tk, 'comment'
277
278    assert_equal 'bar',      alas.old_name
279    assert_equal 'next=',    alas.new_name
280    assert_equal klass,      alas.parent
281    assert_equal 'comment',  alas.comment
282    assert_equal @top_level, alas.file
283    assert                   alas.singleton
284  end
285
286  def test_parse_alias_stopdoc
287    klass = RDoc::NormalClass.new 'Foo'
288    klass.parent = @top_level
289    klass.stop_doc
290
291    util_parser "alias :next= :bar"
292
293    tk = @parser.get_tk
294
295    @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment'
296
297    assert_empty klass.aliases
298    assert_empty klass.unmatched_alias_lists
299  end
300
301  def test_parse_alias_meta
302    klass = RDoc::NormalClass.new 'Foo'
303    klass.parent = @top_level
304
305    util_parser "alias m.chop m"
306
307    tk = @parser.get_tk
308
309    alas = @parser.parse_alias klass, RDoc::Parser::Ruby::NORMAL, tk, 'comment'
310
311    assert_nil alas
312  end
313
314  def test_parse_attr
315    klass = RDoc::NormalClass.new 'Foo'
316    klass.parent = @top_level
317
318    comment = RDoc::Comment.new "##\n# my attr\n", @top_level
319
320    util_parser "attr :foo, :bar"
321
322    tk = @parser.get_tk
323
324    @parser.parse_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
325
326    assert_equal 1, klass.attributes.length
327
328    foo = klass.attributes.first
329    assert_equal 'foo', foo.name
330    assert_equal 'my attr', foo.comment.text
331    assert_equal @top_level, foo.file
332    assert_equal 0, foo.offset
333    assert_equal 1, foo.line
334  end
335
336  def test_parse_attr_stopdoc
337    klass = RDoc::NormalClass.new 'Foo'
338    klass.parent = @top_level
339    klass.stop_doc
340
341    comment = RDoc::Comment.new "##\n# my attr\n", @top_level
342
343    util_parser "attr :foo, :bar"
344
345    tk = @parser.get_tk
346
347    @parser.parse_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
348
349    assert_empty klass.attributes
350  end
351
352  def test_parse_attr_accessor
353    klass = RDoc::NormalClass.new 'Foo'
354    klass.parent = @top_level
355
356    comment = RDoc::Comment.new "##\n# my attr\n", @top_level
357
358    util_parser "attr_accessor :foo, :bar"
359
360    tk = @parser.get_tk
361
362    @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment
363
364    assert_equal 2, klass.attributes.length
365
366    foo = klass.attributes.first
367    assert_equal 'foo', foo.name
368    assert_equal 'RW', foo.rw
369    assert_equal 'my attr', foo.comment.text
370    assert_equal @top_level, foo.file
371    assert_equal 0, foo.offset
372    assert_equal 1, foo.line
373
374    bar = klass.attributes.last
375    assert_equal 'bar', bar.name
376    assert_equal 'RW', bar.rw
377    assert_equal 'my attr', bar.comment.text
378  end
379
380  def test_parse_attr_accessor_nodoc
381    klass = RDoc::NormalClass.new 'Foo'
382    klass.parent = @top_level
383
384    comment = RDoc::Comment.new "##\n# my attr\n", @top_level
385
386    util_parser "attr_accessor :foo, :bar # :nodoc:"
387
388    tk = @parser.get_tk
389
390    @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment
391
392    assert_equal 0, klass.attributes.length
393  end
394
395  def test_parse_attr_accessor_stopdoc
396    klass = RDoc::NormalClass.new 'Foo'
397    klass.parent = @top_level
398    klass.stop_doc
399
400    comment = RDoc::Comment.new "##\n# my attr\n", @top_level
401
402    util_parser "attr_accessor :foo, :bar"
403
404    tk = @parser.get_tk
405
406    @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment
407
408    assert_empty klass.attributes
409  end
410
411  def test_parse_attr_accessor_writer
412    klass = RDoc::NormalClass.new 'Foo'
413    klass.parent = @top_level
414
415    comment = RDoc::Comment.new "##\n# my attr\n", @top_level
416
417    util_parser "attr_writer :foo, :bar"
418
419    tk = @parser.get_tk
420
421    @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment
422
423    assert_equal 2, klass.attributes.length
424
425    foo = klass.attributes.first
426    assert_equal 'foo', foo.name
427    assert_equal 'W', foo.rw
428    assert_equal "my attr", foo.comment.text
429    assert_equal @top_level, foo.file
430
431    bar = klass.attributes.last
432    assert_equal 'bar', bar.name
433    assert_equal 'W', bar.rw
434    assert_equal "my attr", bar.comment.text
435  end
436
437  def test_parse_meta_attr
438    klass = RDoc::NormalClass.new 'Foo'
439    klass.parent = @top_level
440
441    comment = RDoc::Comment.new "##\n# :attr: \n# my method\n", @top_level
442
443    util_parser "add_my_method :foo, :bar"
444
445    tk = @parser.get_tk
446
447    @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
448
449    assert_equal 2, klass.attributes.length
450    foo = klass.attributes.first
451    assert_equal 'foo', foo.name
452    assert_equal 'RW', foo.rw
453    assert_equal "my method", foo.comment.text
454    assert_equal @top_level, foo.file
455  end
456
457  def test_parse_meta_attr_accessor
458    klass = RDoc::NormalClass.new 'Foo'
459    klass.parent = @top_level
460
461    comment =
462      RDoc::Comment.new "##\n# :attr_accessor: \n# my method\n", @top_level
463
464    util_parser "add_my_method :foo, :bar"
465
466    tk = @parser.get_tk
467
468    @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
469
470    assert_equal 2, klass.attributes.length
471    foo = klass.attributes.first
472    assert_equal 'foo', foo.name
473    assert_equal 'RW', foo.rw
474    assert_equal 'my method', foo.comment.text
475    assert_equal @top_level, foo.file
476  end
477
478  def test_parse_meta_attr_named
479    klass = RDoc::NormalClass.new 'Foo'
480    klass.parent = @top_level
481
482    comment = RDoc::Comment.new "##\n# :attr: foo\n# my method\n", @top_level
483
484    util_parser "add_my_method :foo, :bar"
485
486    tk = @parser.get_tk
487
488    @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
489
490    assert_equal 1, klass.attributes.length
491    foo = klass.attributes.first
492    assert_equal 'foo', foo.name
493    assert_equal 'RW', foo.rw
494    assert_equal 'my method', foo.comment.text
495    assert_equal @top_level, foo.file
496  end
497
498  def test_parse_meta_attr_reader
499    klass = RDoc::NormalClass.new 'Foo'
500    klass.parent = @top_level
501
502    comment =
503      RDoc::Comment.new "##\n# :attr_reader: \n# my method\n", @top_level
504
505    util_parser "add_my_method :foo, :bar"
506
507    tk = @parser.get_tk
508
509    @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
510
511    foo = klass.attributes.first
512    assert_equal 'foo', foo.name
513    assert_equal 'R', foo.rw
514    assert_equal 'my method', foo.comment.text
515    assert_equal @top_level, foo.file
516  end
517
518  def test_parse_meta_attr_stopdoc
519    klass = RDoc::NormalClass.new 'Foo'
520    klass.parent = @top_level
521    klass.stop_doc
522
523    comment = RDoc::Comment.new "##\n# :attr: \n# my method\n", @top_level
524
525    util_parser "add_my_method :foo, :bar"
526
527    tk = @parser.get_tk
528
529    @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
530
531    assert_empty klass.attributes
532  end
533
534  def test_parse_meta_attr_writer
535    klass = RDoc::NormalClass.new 'Foo'
536    klass.parent = @top_level
537
538    comment =
539      RDoc::Comment.new "##\n# :attr_writer: \n# my method\n", @top_level
540
541    util_parser "add_my_method :foo, :bar"
542
543    tk = @parser.get_tk
544
545    @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment
546
547    foo = klass.attributes.first
548    assert_equal 'foo', foo.name
549    assert_equal 'W', foo.rw
550    assert_equal "my method", foo.comment.text
551    assert_equal @top_level, foo.file
552  end
553
554  def test_parse_class
555    comment = RDoc::Comment.new "##\n# my class\n", @top_level
556
557    util_parser "class Foo\nend"
558
559    tk = @parser.get_tk
560
561    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
562
563    foo = @top_level.classes.first
564    assert_equal 'Foo', foo.full_name
565    assert_equal 'my class', foo.comment.text
566    assert_equal [@top_level], foo.in_files
567    assert_equal 0, foo.offset
568    assert_equal 1, foo.line
569  end
570
571  def test_parse_class_ghost_method
572    util_parser <<-CLASS
573class Foo
574  ##
575  # :method: blah
576  # my method
577end
578    CLASS
579
580    tk = @parser.get_tk
581
582    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
583
584    foo = @top_level.classes.first
585    assert_equal 'Foo', foo.full_name
586
587    blah = foo.method_list.first
588    assert_equal 'Foo#blah', blah.full_name
589    assert_equal @top_level, blah.file
590  end
591
592  def test_parse_class_multi_ghost_methods
593    util_parser <<-'CLASS'
594class Foo
595  ##
596  # :method: one
597  #
598  # my method
599
600  ##
601  # :method: two
602  #
603  # my method
604
605  [:one, :two].each do |t|
606    eval("def #{t}; \"#{t}\"; end")
607  end
608end
609    CLASS
610
611    tk = @parser.get_tk
612
613    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
614
615    foo = @top_level.classes.first
616    assert_equal 'Foo', foo.full_name
617
618    assert_equal 2, foo.method_list.length
619  end
620
621  def test_parse_class_nodoc
622    comment = RDoc::Comment.new "##\n# my class\n", @top_level
623
624    util_parser "class Foo # :nodoc:\nend"
625
626    tk = @parser.get_tk
627
628    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
629
630    foo = @top_level.classes.first
631    assert_equal 'Foo', foo.full_name
632    assert_empty foo.comment
633    assert_equal [@top_level], foo.in_files
634    assert_equal 0, foo.offset
635    assert_equal 1, foo.line
636  end
637
638  def test_parse_class_single_root
639    comment = RDoc::Comment.new "##\n# my class\n", @top_level
640
641    util_parser "class << ::Foo\nend"
642
643    tk = @parser.get_tk
644
645    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
646
647    foo = @store.all_modules.first
648    assert_equal 'Foo', foo.full_name
649  end
650
651  def test_parse_class_stopdoc
652    @top_level.stop_doc
653
654    comment = RDoc::Comment.new "##\n# my class\n", @top_level
655
656    util_parser "class Foo\nend"
657
658    tk = @parser.get_tk
659
660    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
661
662    assert_empty @top_level.classes.first.comment
663  end
664
665  def test_parse_multi_ghost_methods
666    util_parser <<-'CLASS'
667class Foo
668  ##
669  # :method: one
670  #
671  # my method
672
673  ##
674  # :method: two
675  #
676  # my method
677
678  [:one, :two].each do |t|
679    eval("def #{t}; \"#{t}\"; end")
680  end
681end
682    CLASS
683
684    tk = @parser.get_tk
685
686    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
687
688    foo = @top_level.classes.first
689    assert_equal 'Foo', foo.full_name
690
691    assert_equal 2, foo.method_list.length
692  end
693
694  def test_parse_const_fail_w_meta
695    util_parser <<-CLASS
696class ConstFailMeta
697  ##
698  # :attr: one
699  #
700  # an attribute
701
702  OtherModule.define_attr(self, :one)
703end
704    CLASS
705
706    tk = @parser.get_tk
707
708    @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
709
710    const_fail_meta = @top_level.classes.first
711    assert_equal 'ConstFailMeta', const_fail_meta.full_name
712
713    assert_equal 1, const_fail_meta.attributes.length
714  end
715
716  def test_parse_class_nested_superclass
717    foo = @top_level.add_module RDoc::NormalModule, 'Foo'
718
719    util_parser "class Bar < Super\nend"
720
721    tk = @parser.get_tk
722
723    @parser.parse_class foo, RDoc::Parser::Ruby::NORMAL, tk, @comment
724
725    bar = foo.classes.first
726    assert_equal 'Super', bar.superclass
727  end
728
729  def test_parse_module
730    comment = RDoc::Comment.new "##\n# my module\n", @top_level
731
732    util_parser "module Foo\nend"
733
734    tk = @parser.get_tk
735
736    @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
737
738    foo = @top_level.modules.first
739    assert_equal 'Foo', foo.full_name
740    assert_equal 'my module', foo.comment.text
741  end
742
743  def test_parse_module_nodoc
744    @top_level.stop_doc
745
746    comment = RDoc::Comment.new "##\n# my module\n", @top_level
747
748    util_parser "module Foo # :nodoc:\nend"
749
750    tk = @parser.get_tk
751
752    @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
753
754    foo = @top_level.modules.first
755    assert_equal 'Foo', foo.full_name
756    assert_empty foo.comment
757  end
758
759  def test_parse_module_stopdoc
760    @top_level.stop_doc
761
762    comment = RDoc::Comment.new "##\n# my module\n", @top_level
763
764    util_parser "module Foo\nend"
765
766    tk = @parser.get_tk
767
768    @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment
769
770    foo = @top_level.modules.first
771    assert_equal 'Foo', foo.full_name
772    assert_empty foo.comment
773  end
774
775  def test_parse_class_colon3
776    code = <<-CODE
777class A
778  class ::B
779  end
780end
781    CODE
782
783    util_parser code
784
785    @parser.parse_class @top_level, false, @parser.get_tk, @comment
786
787    assert_equal %w[A B], @store.all_classes.map { |c| c.full_name }.sort
788  end
789
790  def test_parse_class_colon3_self_reference
791    code = <<-CODE
792class A::B
793  class ::A
794  end
795end
796    CODE
797
798    util_parser code
799
800    @parser.parse_class @top_level, false, @parser.get_tk, @comment
801
802    assert_equal %w[A A::B], @store.all_classes.map { |c| c.full_name }.sort
803  end
804
805  def test_parse_class_single
806    code = <<-CODE
807class A
808  class << B
809  end
810  class << d = Object.new
811    def foo; end
812    alias bar foo
813  end
814end
815    CODE
816
817    util_parser code
818
819    @parser.parse_class @top_level, false, @parser.get_tk, @comment
820
821    assert_equal %w[A], @store.all_classes.map { |c| c.full_name }
822
823    modules = @store.all_modules.sort_by { |c| c.full_name }
824    assert_equal %w[A::B A::d], modules.map { |c| c.full_name }
825
826    b = modules.first
827    assert_equal 10, b.offset
828    assert_equal 2,  b.line
829
830    # make sure method/alias was not added to enclosing class/module
831    a = @store.classes_hash['A']
832    assert_empty a.method_list
833
834    # make sure non-constant-named module will be removed from documentation
835    d = @store.modules_hash['A::d']
836    assert d.remove_from_documentation?
837  end
838
839  def test_parse_class_single_gvar
840    code = <<-CODE
841class << $g
842  def m
843  end
844end
845    CODE
846
847    util_parser code
848
849    @parser.parse_class @top_level, false, @parser.get_tk, ''
850
851    assert_empty @store.all_classes
852    mod = @store.all_modules.first
853
854    refute mod.document_self
855
856    assert_empty mod.method_list
857  end
858
859  # TODO this is really a Context#add_class test
860  def test_parse_class_object
861    code = <<-CODE
862module A
863  class B
864  end
865  class Object
866  end
867  class C < Object
868  end
869end
870    CODE
871
872    util_parser code
873
874    @parser.parse_module @top_level, false, @parser.get_tk, @comment
875
876    assert_equal %w[A],
877      @store.all_modules.map { |c| c.full_name }
878    assert_equal %w[A::B A::C A::Object],
879      @store.all_classes.map { |c| c.full_name }.sort
880
881    assert_equal 'Object',    @store.classes_hash['A::B'].superclass
882    assert_equal 'Object',    @store.classes_hash['A::Object'].superclass
883    assert_equal 'A::Object', @store.classes_hash['A::C'].superclass.full_name
884  end
885
886  def test_parse_class_mistaken_for_module
887    # The code below is not strictly legal Ruby (Foo must have been defined
888    # before Foo::Bar is encountered), but RDoc might encounter Foo::Bar
889    # before Foo if they live in different files.
890
891    code = <<-RUBY
892class Foo::Bar
893end
894
895module Foo::Baz
896end
897
898class Foo
899end
900    RUBY
901
902    util_parser code
903
904    @parser.scan
905
906    assert_equal %w[Foo::Baz], @store.modules_hash.keys
907    assert_empty @top_level.modules
908
909    foo = @top_level.classes.first
910    assert_equal 'Foo', foo.full_name
911
912    bar = foo.classes.first
913    assert_equal 'Foo::Bar', bar.full_name
914
915    baz = foo.modules.first
916    assert_equal 'Foo::Baz', baz.full_name
917  end
918
919  def test_parse_class_definition_encountered_after_class_reference
920    # The code below is not legal Ruby (Foo must have been defined before
921    # Foo.bar is encountered), but RDoc might encounter Foo.bar before Foo if
922    # they live in different files.
923
924    code = <<-EOF
925def Foo.bar
926end
927
928class Foo < IO
929end
930    EOF
931
932    util_parser code
933
934    @parser.scan
935
936    assert_empty @store.modules_hash
937    assert_empty @store.all_modules
938
939    foo = @top_level.classes.first
940    assert_equal 'Foo', foo.full_name
941    assert_equal 'IO', foo.superclass
942
943    bar = foo.method_list.first
944    assert_equal 'bar', bar.name
945  end
946
947  def test_parse_module_relative_to_top_level_namespace
948    comment = RDoc::Comment.new <<-EOF, @top_level
949#
950# Weirdly named module
951#
952EOF
953
954    code = <<-EOF
955#{comment.text}
956module ::Foo
957  class Helper
958  end
959end
960EOF
961
962    util_parser code
963    @parser.scan()
964
965    foo = @top_level.modules.first
966    assert_equal 'Foo', foo.full_name
967    assert_equal 'Weirdly named module', foo.comment.text
968
969    helper = foo.classes.first
970    assert_equal 'Foo::Helper', helper.full_name
971  end
972
973  def test_parse_comment_attr
974    klass = RDoc::NormalClass.new 'Foo'
975    klass.parent = @top_level
976
977    comment = RDoc::Comment.new "##\n# :attr: foo\n# my attr\n", @top_level
978
979    util_parser "\n"
980
981    tk = @parser.get_tk
982
983    @parser.parse_comment klass, tk, comment
984
985    foo = klass.attributes.first
986    assert_equal 'foo',      foo.name
987    assert_equal 'RW',       foo.rw
988    assert_equal 'my attr',  foo.comment.text
989    assert_equal @top_level, foo.file
990    assert_equal 0,          foo.offset
991    assert_equal 1,          foo.line
992
993    assert_equal nil,        foo.viewer
994    assert_equal true,       foo.document_children
995    assert_equal true,       foo.document_self
996    assert_equal false,      foo.done_documenting
997    assert_equal false,      foo.force_documentation
998    assert_equal klass,      foo.parent
999    assert_equal :public,    foo.visibility
1000    assert_equal "\n",       foo.text
1001
1002    assert_equal klass.current_section, foo.section
1003  end
1004
1005  def test_parse_comment_attr_stopdoc
1006    klass = RDoc::NormalClass.new 'Foo'
1007    klass.parent = @top_level
1008    klass.stop_doc
1009
1010    comment = RDoc::Comment.new "##\n# :attr: foo\n# my attr\n", @top_level
1011
1012    util_parser "\n"
1013
1014    tk = @parser.get_tk
1015
1016    @parser.parse_comment klass, tk, comment
1017
1018    assert_empty klass.attributes
1019  end
1020
1021  def test_parse_comment_method
1022    klass = RDoc::NormalClass.new 'Foo'
1023    klass.parent = @top_level
1024
1025    comment = RDoc::Comment.new "##\n# :method: foo\n# my method\n", @top_level
1026
1027    util_parser "\n"
1028
1029    tk = @parser.get_tk
1030
1031    @parser.parse_comment klass, tk, comment
1032
1033    foo = klass.method_list.first
1034    assert_equal 'foo',       foo.name
1035    assert_equal 'my method', foo.comment.text
1036    assert_equal @top_level,  foo.file
1037    assert_equal 0,           foo.offset
1038    assert_equal 1,           foo.line
1039
1040    assert_equal [],        foo.aliases
1041    assert_equal nil,       foo.block_params
1042    assert_equal nil,       foo.call_seq
1043    assert_equal nil,       foo.is_alias_for
1044    assert_equal nil,       foo.viewer
1045    assert_equal true,      foo.document_children
1046    assert_equal true,      foo.document_self
1047    assert_equal '',        foo.params
1048    assert_equal false,     foo.done_documenting
1049    assert_equal false,     foo.dont_rename_initialize
1050    assert_equal false,     foo.force_documentation
1051    assert_equal klass,     foo.parent
1052    assert_equal false,     foo.singleton
1053    assert_equal :public,   foo.visibility
1054    assert_equal "\n",      foo.text
1055    assert_equal klass.current_section, foo.section
1056
1057    stream = [
1058      tk(:COMMENT, 0, 1, 1, nil,
1059         "# File #{@top_level.relative_name}, line 1"),
1060      RDoc::Parser::Ruby::NEWLINE_TOKEN,
1061      tk(:SPACE,   0, 1, 1, nil, ''),
1062    ]
1063
1064    assert_equal stream, foo.token_stream
1065  end
1066
1067  def test_parse_comment_method_stopdoc
1068    klass = RDoc::NormalClass.new 'Foo'
1069    klass.parent = @top_level
1070    klass.stop_doc
1071
1072    comment = RDoc::Comment.new "##\n# :method: foo\n# my method\n", @top_level
1073
1074    util_parser "\n"
1075
1076    tk = @parser.get_tk
1077
1078    @parser.parse_comment klass, tk, comment
1079
1080    assert_empty klass.method_list
1081  end
1082
1083  def test_parse_constant
1084    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
1085
1086    util_parser "A = v"
1087
1088    tk = @parser.get_tk
1089
1090    @parser.parse_constant klass, tk, @comment
1091
1092    foo = klass.constants.first
1093
1094    assert_equal 'A', foo.name
1095    assert_equal @top_level, foo.file
1096    assert_equal 0, foo.offset
1097    assert_equal 1, foo.line
1098  end
1099
1100  def test_parse_constant_attrasgn
1101    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
1102
1103    util_parser "A[k] = v"
1104
1105    tk = @parser.get_tk
1106
1107    @parser.parse_constant klass, tk, @comment
1108
1109    assert klass.constants.empty?
1110  end
1111
1112  def test_parse_constant_alias
1113    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
1114    klass.add_class RDoc::NormalClass, 'B'
1115
1116    util_parser "A = B"
1117
1118    tk = @parser.get_tk
1119
1120    @parser.parse_constant klass, tk, @comment
1121
1122    assert_equal 'Foo::A', klass.find_module_named('A').full_name
1123  end
1124
1125  def test_parse_constant_alias_same_name
1126    foo = @top_level.add_class RDoc::NormalClass, 'Foo'
1127    @top_level.add_class RDoc::NormalClass, 'Bar'
1128    bar = foo.add_class RDoc::NormalClass, 'Bar'
1129
1130    assert @store.find_class_or_module('::Bar')
1131
1132    util_parser "A = ::Bar"
1133
1134    tk = @parser.get_tk
1135
1136    @parser.parse_constant foo, tk, @comment
1137
1138    assert_equal 'A', bar.find_module_named('A').full_name
1139  end
1140
1141  def test_parse_constant_in_method
1142    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
1143
1144    util_parser 'A::B = v'
1145
1146    tk = @parser.get_tk
1147
1148    @parser.parse_constant klass, tk, @comment, true
1149
1150    assert_empty klass.constants
1151
1152    assert_empty @store.modules_hash.keys
1153    assert_equal %w[Foo], @store.classes_hash.keys
1154  end
1155
1156  def test_parse_constant_rescue
1157    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
1158
1159    util_parser "A => e"
1160
1161    tk = @parser.get_tk
1162
1163    @parser.parse_constant klass, tk, @comment
1164
1165    assert_empty klass.constants
1166    assert_empty klass.modules
1167
1168    assert_empty @store.modules_hash.keys
1169    assert_equal %w[Foo], @store.classes_hash.keys
1170  end
1171
1172  def test_parse_constant_stopdoc
1173    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
1174    klass.stop_doc
1175
1176    util_parser "A = v"
1177
1178    tk = @parser.get_tk
1179
1180    @parser.parse_constant klass, tk, @comment
1181
1182    assert_empty klass.constants
1183  end
1184
1185  def test_parse_comment_nested
1186    content = <<-CONTENT
1187A::B::C = 1
1188    CONTENT
1189
1190    util_parser content
1191
1192    tk = @parser.get_tk
1193
1194    parsed = @parser.parse_constant @top_level, tk, 'comment'
1195
1196    assert parsed
1197
1198    a = @top_level.find_module_named 'A'
1199    b = a.find_module_named 'B'
1200    c = b.constants.first
1201
1202    assert_equal 'A::B::C', c.full_name
1203    assert_equal 'comment', c.comment
1204  end
1205
1206  def test_parse_include
1207    klass = RDoc::NormalClass.new 'C'
1208    klass.parent = @top_level
1209
1210    comment = RDoc::Comment.new "# my include\n", @top_level
1211
1212    util_parser "include I"
1213
1214    @parser.get_tk # include
1215
1216    @parser.parse_include klass, comment
1217
1218    assert_equal 1, klass.includes.length
1219
1220    incl = klass.includes.first
1221    assert_equal 'I', incl.name
1222    assert_equal 'my include', incl.comment.text
1223    assert_equal @top_level, incl.file
1224  end
1225
1226  def test_parse_extend
1227    klass = RDoc::NormalClass.new 'C'
1228    klass.parent = @top_level
1229
1230    comment = RDoc::Comment.new "# my extend\n", @top_level
1231
1232    util_parser "extend I"
1233
1234    @parser.get_tk # extend
1235
1236    @parser.parse_extend klass, comment
1237
1238    assert_equal 1, klass.extends.length
1239
1240    ext = klass.extends.first
1241    assert_equal 'I', ext.name
1242    assert_equal 'my extend', ext.comment.text
1243    assert_equal @top_level, ext.file
1244  end
1245
1246  def test_parse_meta_method
1247    klass = RDoc::NormalClass.new 'Foo'
1248    klass.parent = @top_level
1249
1250    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1251
1252    util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
1253
1254    tk = @parser.get_tk
1255
1256    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1257
1258    foo = klass.method_list.first
1259    assert_equal 'foo',       foo.name
1260    assert_equal 'my method', foo.comment.text
1261    assert_equal @top_level,  foo.file
1262    assert_equal 0,           foo.offset
1263    assert_equal 1,           foo.line
1264
1265    assert_equal [],      foo.aliases
1266    assert_equal nil,     foo.block_params
1267    assert_equal nil,     foo.call_seq
1268    assert_equal true,    foo.document_children
1269    assert_equal true,    foo.document_self
1270    assert_equal false,   foo.done_documenting
1271    assert_equal false,   foo.dont_rename_initialize
1272    assert_equal false,   foo.force_documentation
1273    assert_equal nil,     foo.is_alias_for
1274    assert_equal '',      foo.params
1275    assert_equal klass,   foo.parent
1276    assert_equal false,   foo.singleton
1277    assert_equal 'add_my_method :foo', foo.text
1278    assert_equal nil,     foo.viewer
1279    assert_equal :public, foo.visibility
1280    assert_equal klass.current_section, foo.section
1281
1282    stream = [
1283      tk(:COMMENT,     0, 1, 1,  nil,
1284         "# File #{@top_level.relative_name}, line 1"),
1285      RDoc::Parser::Ruby::NEWLINE_TOKEN,
1286      tk(:SPACE,       0, 1, 1,  nil, ''),
1287      tk(:IDENTIFIER,  0, 1, 0,  'add_my_method', 'add_my_method'),
1288      tk(:SPACE,       0, 1, 13, nil, ' '),
1289      tk(:SYMBOL,      0, 1, 14, nil, ':foo'),
1290      tk(:COMMA,       0, 1, 18, nil, ','),
1291      tk(:SPACE,       0, 1, 19, nil, ' '),
1292      tk(:SYMBOL,      0, 1, 20, nil, ':bar'),
1293      tk(:NL,          0, 1, 24, nil, "\n"),
1294    ]
1295
1296    assert_equal stream, foo.token_stream
1297  end
1298
1299  def test_parse_meta_method_block
1300    klass = RDoc::NormalClass.new 'Foo'
1301    klass.parent = @top_level
1302
1303    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1304
1305    content = <<-CONTENT
1306inline(:my_method) do |*args|
1307  "this method causes z to disappear"
1308end
1309    CONTENT
1310
1311    util_parser content
1312
1313    tk = @parser.get_tk
1314
1315    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1316
1317    assert_equal tk(:NL, 0, 3, 3, 3, "\n"), @parser.get_tk
1318  end
1319
1320  def test_parse_meta_method_define_method
1321    klass = RDoc::NormalClass.new 'Foo'
1322    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1323
1324    util_parser "define_method :foo do end"
1325
1326    tk = @parser.get_tk
1327
1328    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1329
1330    foo = klass.method_list.first
1331    assert_equal 'foo', foo.name
1332    assert_equal 'my method', foo.comment.text
1333    assert_equal @top_level,  foo.file
1334  end
1335
1336  def test_parse_meta_method_name
1337    klass = RDoc::NormalClass.new 'Foo'
1338    klass.parent = @top_level
1339
1340    comment =
1341      RDoc::Comment.new "##\n# :method: woo_hoo!\n# my method\n", @top_level
1342
1343    util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
1344
1345    tk = @parser.get_tk
1346
1347    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1348
1349    foo = klass.method_list.first
1350    assert_equal 'woo_hoo!',  foo.name
1351    assert_equal 'my method', foo.comment.text
1352    assert_equal @top_level,  foo.file
1353  end
1354
1355  def test_parse_meta_method_singleton
1356    klass = RDoc::NormalClass.new 'Foo'
1357    klass.parent = @top_level
1358
1359    comment =
1360      RDoc::Comment.new "##\n# :singleton-method:\n# my method\n", @top_level
1361
1362    util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
1363
1364    tk = @parser.get_tk
1365
1366    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1367
1368    foo = klass.method_list.first
1369    assert_equal 'foo', foo.name
1370    assert_equal true, foo.singleton, 'singleton method'
1371    assert_equal 'my method', foo.comment.text
1372    assert_equal @top_level,  foo.file
1373  end
1374
1375  def test_parse_meta_method_singleton_name
1376    klass = RDoc::NormalClass.new 'Foo'
1377    klass.parent = @top_level
1378
1379    comment =
1380      RDoc::Comment.new "##\n# :singleton-method: woo_hoo!\n# my method\n",
1381                        @top_level
1382
1383    util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
1384
1385    tk = @parser.get_tk
1386
1387    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1388
1389    foo = klass.method_list.first
1390    assert_equal 'woo_hoo!', foo.name
1391    assert_equal true, foo.singleton, 'singleton method'
1392    assert_equal 'my method', foo.comment.text
1393    assert_equal @top_level,  foo.file
1394  end
1395
1396  def test_parse_meta_method_string_name
1397    klass = RDoc::NormalClass.new 'Foo'
1398    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1399
1400    util_parser "add_my_method 'foo'"
1401
1402    tk = @parser.get_tk
1403
1404    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1405
1406    foo = klass.method_list.first
1407    assert_equal 'foo', foo.name
1408    assert_equal 'my method', foo.comment.text
1409    assert_equal @top_level,  foo.file
1410  end
1411
1412  def test_parse_meta_method_stopdoc
1413    klass = RDoc::NormalClass.new 'Foo'
1414    klass.parent = @top_level
1415    klass.stop_doc
1416
1417    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1418
1419    util_parser "add_my_method :foo, :bar\nadd_my_method :baz"
1420
1421    tk = @parser.get_tk
1422
1423    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1424
1425    assert_empty klass.method_list
1426  end
1427
1428  def test_parse_meta_method_unknown
1429    klass = RDoc::NormalClass.new 'Foo'
1430    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1431
1432    util_parser "add_my_method ('foo')"
1433
1434    tk = @parser.get_tk
1435
1436    @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1437
1438    foo = klass.method_list.first
1439    assert_equal 'unknown', foo.name
1440    assert_equal 'my method', foo.comment.text
1441    assert_equal @top_level,  foo.file
1442  end
1443
1444  def test_parse_method
1445    klass = RDoc::NormalClass.new 'Foo'
1446    klass.parent = @top_level
1447
1448    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1449
1450    util_parser "def foo() :bar end"
1451
1452    tk = @parser.get_tk
1453
1454    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1455
1456    foo = klass.method_list.first
1457    assert_equal 'foo',       foo.name
1458    assert_equal 'my method', foo.comment.text
1459    assert_equal @top_level,  foo.file
1460    assert_equal 0,           foo.offset
1461    assert_equal 1,           foo.line
1462
1463    assert_equal [],        foo.aliases
1464    assert_equal nil,       foo.block_params
1465    assert_equal nil,       foo.call_seq
1466    assert_equal nil,       foo.is_alias_for
1467    assert_equal nil,       foo.viewer
1468    assert_equal true,      foo.document_children
1469    assert_equal true,      foo.document_self
1470    assert_equal '()',      foo.params
1471    assert_equal false,     foo.done_documenting
1472    assert_equal false,     foo.dont_rename_initialize
1473    assert_equal false,     foo.force_documentation
1474    assert_equal klass,     foo.parent
1475    assert_equal false,     foo.singleton
1476    assert_equal :public,   foo.visibility
1477    assert_equal 'def foo', foo.text
1478    assert_equal klass.current_section, foo.section
1479
1480    stream = [
1481      tk(:COMMENT,     0, 1, 1,  nil,
1482         "# File #{@top_level.relative_name}, line 1"),
1483      RDoc::Parser::Ruby::NEWLINE_TOKEN,
1484      tk(:SPACE,       0, 1, 1,  nil,   ''),
1485      tk(:DEF,         0, 1, 0,  'def', 'def'),
1486      tk(:SPACE,       3, 1, 3,  nil,   ' '),
1487      tk(:IDENTIFIER,  4, 1, 4,  'foo', 'foo'),
1488      tk(:LPAREN,      7, 1, 7,  nil,   '('),
1489      tk(:RPAREN,      8, 1, 8,  nil,   ')'),
1490      tk(:SPACE,       9, 1, 9,  nil,   ' '),
1491      tk(:COLON,      10, 1, 10, nil,   ':'),
1492      tk(:IDENTIFIER, 11, 1, 11, 'bar', 'bar'),
1493      tk(:SPACE,      14, 1, 14, nil,   ' '),
1494      tk(:END,        15, 1, 15, 'end', 'end'),
1495    ]
1496
1497    assert_equal stream, foo.token_stream
1498  end
1499
1500  def test_parse_method_alias
1501    klass = RDoc::NormalClass.new 'Foo'
1502    klass.parent = @top_level
1503
1504    util_parser "def m() alias a b; end"
1505
1506    tk = @parser.get_tk
1507
1508    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1509
1510    assert klass.aliases.empty?
1511  end
1512
1513  def test_parse_method_ampersand
1514    klass = RDoc::NormalClass.new 'Foo'
1515    klass.parent = @top_level
1516
1517    util_parser "def self.&\nend"
1518
1519    tk = @parser.get_tk
1520
1521    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1522
1523    ampersand = klass.method_list.first
1524    assert_equal '&', ampersand.name
1525    assert            ampersand.singleton
1526  end
1527
1528  def test_parse_method_constant
1529    c = RDoc::Constant.new 'CONST', nil, ''
1530    m = @top_level.add_class RDoc::NormalModule, 'M'
1531    m.add_constant c
1532
1533    util_parser "def CONST.m() end"
1534
1535    tk = @parser.get_tk
1536
1537    @parser.parse_method m, RDoc::Parser::Ruby::NORMAL, tk, @comment
1538
1539    assert_empty @store.modules_hash.keys
1540    assert_equal %w[M], @store.classes_hash.keys
1541  end
1542
1543  def test_parse_method_false
1544    util_parser "def false.foo() :bar end"
1545
1546    tk = @parser.get_tk
1547
1548    @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
1549
1550    klass = @store.find_class_named 'FalseClass'
1551
1552    foo = klass.method_list.first
1553    assert_equal 'foo', foo.name
1554  end
1555
1556  def test_parse_method_funky
1557    klass = RDoc::NormalClass.new 'Foo'
1558    klass.parent = @top_level
1559
1560    util_parser "def (blah).foo() :bar end"
1561
1562    tk = @parser.get_tk
1563
1564    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1565
1566    assert_empty klass.method_list
1567  end
1568
1569  def test_parse_method_gvar
1570    util_parser "def $stdout.foo() :bar end"
1571
1572    tk = @parser.get_tk
1573
1574    @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
1575
1576    assert @top_level.method_list.empty?
1577  end
1578
1579  def test_parse_method_gvar_insane
1580    util_parser "def $stdout.foo() class << $other; end; end"
1581
1582    tk = @parser.get_tk
1583
1584    @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
1585
1586    assert @top_level.method_list.empty?
1587
1588    assert_empty @store.all_classes
1589
1590    assert_equal 1, @store.all_modules.length
1591
1592    refute @store.all_modules.first.document_self
1593  end
1594
1595  def test_parse_method_internal_gvar
1596    klass = RDoc::NormalClass.new 'Foo'
1597    klass.parent = @top_level
1598
1599    util_parser "def foo() def $blah.bar() end end"
1600
1601    tk = @parser.get_tk
1602
1603    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1604
1605    assert_equal 1, klass.method_list.length
1606  end
1607
1608  def test_parse_method_internal_ivar
1609    klass = RDoc::NormalClass.new 'Foo'
1610    klass.parent = @top_level
1611
1612    util_parser "def foo() def @blah.bar() end end"
1613
1614    tk = @parser.get_tk
1615
1616    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1617
1618    assert_equal 1, klass.method_list.length
1619  end
1620
1621  def test_parse_method_internal_lvar
1622    klass = RDoc::NormalClass.new 'Foo'
1623    klass.parent = @top_level
1624
1625    util_parser "def foo() def blah.bar() end end"
1626
1627    tk = @parser.get_tk
1628
1629    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1630
1631    assert_equal 1, klass.method_list.length
1632  end
1633
1634  def test_parse_method_nil
1635    util_parser "def nil.foo() :bar end"
1636
1637    tk = @parser.get_tk
1638
1639    @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
1640
1641    klass = @store.find_class_named 'NilClass'
1642
1643    foo = klass.method_list.first
1644    assert_equal 'foo', foo.name
1645  end
1646
1647  def test_parse_method_no_parens
1648    klass = RDoc::NormalClass.new 'Foo'
1649    klass.parent = @top_level
1650
1651    util_parser "def foo arg1, arg2 = {}\nend"
1652
1653    tk = @parser.get_tk
1654
1655    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1656
1657    foo = klass.method_list.first
1658    assert_equal '(arg1, arg2 = {})', foo.params
1659    assert_equal @top_level, foo.file
1660  end
1661
1662  def test_parse_method_parameters_comment
1663    klass = RDoc::NormalClass.new 'Foo'
1664    klass.parent = @top_level
1665
1666    util_parser "def foo arg1, arg2 # some useful comment\nend"
1667
1668    tk = @parser.get_tk
1669
1670    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1671
1672    foo = klass.method_list.first
1673    assert_equal '(arg1, arg2)', foo.params
1674  end
1675
1676  def test_parse_method_parameters_comment_continue
1677    klass = RDoc::NormalClass.new 'Foo'
1678    klass.parent = @top_level
1679
1680    util_parser "def foo arg1, arg2, # some useful comment\narg3\nend"
1681
1682    tk = @parser.get_tk
1683
1684    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1685
1686    foo = klass.method_list.first
1687    assert_equal '(arg1, arg2, arg3)', foo.params
1688  end
1689
1690  def test_parse_method_star
1691    klass = RDoc::NormalClass.new 'Foo'
1692    klass.parent = @top_level
1693
1694    util_parser "def self.*\nend"
1695
1696    tk = @parser.get_tk
1697
1698    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1699
1700    ampersand = klass.method_list.first
1701    assert_equal '*', ampersand.name
1702    assert            ampersand.singleton
1703  end
1704
1705  def test_parse_method_stopdoc
1706    klass = RDoc::NormalClass.new 'Foo'
1707    klass.parent = @top_level
1708    klass.stop_doc
1709
1710    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1711
1712    util_parser "def foo() :bar end"
1713
1714    tk = @parser.get_tk
1715
1716    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment
1717
1718    assert_empty klass.method_list
1719  end
1720
1721  def test_parse_method_toplevel
1722    klass = @top_level
1723
1724    util_parser "def foo arg1, arg2\nend"
1725
1726    tk = @parser.get_tk
1727
1728    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1729
1730    object = @store.find_class_named 'Object'
1731
1732    foo = object.method_list.first
1733    assert_equal 'Object#foo', foo.full_name
1734    assert_equal @top_level, foo.file
1735  end
1736
1737  def test_parse_method_toplevel_class
1738    klass = @top_level
1739
1740    util_parser "def Object.foo arg1, arg2\nend"
1741
1742    tk = @parser.get_tk
1743
1744    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1745
1746    object = @store.find_class_named 'Object'
1747
1748    foo = object.method_list.first
1749    assert_equal 'Object::foo', foo.full_name
1750  end
1751
1752  def test_parse_method_true
1753    util_parser "def true.foo() :bar end"
1754
1755    tk = @parser.get_tk
1756
1757    @parser.parse_method @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
1758
1759    klass = @store.find_class_named 'TrueClass'
1760
1761    foo = klass.method_list.first
1762    assert_equal 'foo', foo.name
1763  end
1764
1765  def test_parse_method_utf8
1766    klass = RDoc::NormalClass.new 'Foo'
1767    klass.parent = @top_level
1768
1769    method = "def ��() end"
1770
1771    assert_equal Encoding::UTF_8, method.encoding if
1772      Object.const_defined? :Encoding
1773
1774    util_parser method
1775
1776    tk = @parser.get_tk
1777
1778    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
1779
1780    omega = klass.method_list.first
1781    assert_equal "def \317\211", omega.text
1782  end
1783
1784  def test_parse_method_dummy
1785    util_parser ".method() end"
1786
1787    @parser.parse_method_dummy @top_level
1788
1789    assert_nil @parser.get_tk
1790  end
1791
1792  def test_parse_method_or_yield_parameters_hash
1793    util_parser "({})\n"
1794
1795    m = RDoc::AnyMethod.new nil, 'm'
1796
1797    result = @parser.parse_method_or_yield_parameters m
1798
1799    assert_equal '({})', result
1800  end
1801
1802  def test_parse_statements_class_if
1803    util_parser <<-CODE
1804module Foo
1805  X = if TRUE then
1806        ''
1807      end
1808
1809  def blah
1810  end
1811end
1812    CODE
1813
1814    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil
1815
1816    foo = @top_level.modules.first
1817    assert_equal 'Foo', foo.full_name, 'module Foo'
1818
1819    methods = foo.method_list
1820    assert_equal 1, methods.length
1821    assert_equal 'Foo#blah', methods.first.full_name
1822  end
1823
1824  def test_parse_statements_class_nested
1825    comment = RDoc::Comment.new "##\n# my method\n", @top_level
1826
1827    util_parser "module Foo\n#{comment.text}class Bar\nend\nend"
1828
1829    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
1830
1831    foo = @top_level.modules.first
1832    assert_equal 'Foo', foo.full_name, 'module Foo'
1833
1834    bar = foo.classes.first
1835    assert_equal 'Foo::Bar', bar.full_name, 'class Foo::Bar'
1836    assert_equal 'my method', bar.comment.text
1837  end
1838
1839  def test_parse_statements_def_percent_string_pound
1840    util_parser "class C\ndef a\n%r{#}\nend\ndef b() end\nend"
1841
1842    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
1843
1844    x = @top_level.classes.first
1845
1846    assert_equal 2, x.method_list.length
1847    a = x.method_list.first
1848
1849    expected = [
1850      tk(:COMMENT,     0, 2, 1, nil,   "# File #{@filename}, line 2"),
1851      tk(:NL,          0, 0, 0, nil,   "\n"),
1852      tk(:SPACE,       0, 1, 1, nil,   ''),
1853      tk(:DEF,         8, 2, 0, 'def', 'def'),
1854      tk(:SPACE,      11, 2, 3, nil,   ' '),
1855      tk(:IDENTIFIER, 12, 2, 4, 'a',   'a'),
1856      tk(:NL,         13, 2, 5, nil,   "\n"),
1857      tk(:DREGEXP,    14, 3, 0, nil,   '%r{#}'),
1858      tk(:NL,         19, 3, 5, nil,   "\n"),
1859      tk(:END,        20, 4, 0, 'end', 'end'),
1860    ]
1861
1862    assert_equal expected, a.token_stream
1863  end
1864
1865  def test_parse_statements_encoding
1866    skip "Encoding not implemented" unless Object.const_defined? :Encoding
1867    @options.encoding = Encoding::CP852
1868
1869    content = <<-EOF
1870class Foo
1871  ##
1872  # this is my method
1873  add_my_method :foo
1874end
1875    EOF
1876
1877    util_parser content
1878
1879    @parser.parse_statements @top_level
1880
1881    foo = @top_level.classes.first.method_list.first
1882    assert_equal 'foo', foo.name
1883    assert_equal 'this is my method', foo.comment.text
1884    assert_equal Encoding::CP852, foo.comment.text.encoding
1885  end
1886
1887  def test_parse_statements_identifier_meta_method
1888    content = <<-EOF
1889class Foo
1890  ##
1891  # this is my method
1892  add_my_method :foo
1893end
1894    EOF
1895
1896    util_parser content
1897
1898    @parser.parse_statements @top_level
1899
1900    foo = @top_level.classes.first.method_list.first
1901    assert_equal 'foo', foo.name
1902  end
1903
1904  def test_parse_statements_identifier_alias_method
1905    content = <<-RUBY
1906class Foo
1907  def foo() end
1908  alias_method :foo2, :foo
1909end
1910    RUBY
1911
1912    util_parser content
1913
1914    @parser.parse_statements @top_level
1915
1916    foo = @top_level.classes.first.method_list[0]
1917    assert_equal 'foo', foo.name
1918
1919    foo2 = @top_level.classes.first.method_list.last
1920    assert_equal 'foo2', foo2.name
1921    assert_equal 'foo', foo2.is_alias_for.name
1922    assert @top_level.classes.first.aliases.empty?
1923  end
1924
1925  def test_parse_statements_identifier_alias_method_before_original_method
1926    # This is not strictly legal Ruby code, but it simulates finding an alias
1927    # for a method before finding the original method, which might happen
1928    # to rdoc if the alias is in a different file than the original method
1929    # and rdoc processes the alias' file first.
1930    content = <<-EOF
1931class Foo
1932  alias_method :foo2, :foo
1933
1934  alias_method :foo3, :foo
1935
1936  def foo()
1937  end
1938
1939  alias_method :foo4, :foo
1940
1941  alias_method :foo5, :unknown
1942end
1943EOF
1944
1945    util_parser content
1946
1947    @parser.parse_statements @top_level
1948
1949    foo = @top_level.classes.first.method_list[0]
1950    assert_equal 'foo', foo.name
1951
1952    foo2 = @top_level.classes.first.method_list[1]
1953    assert_equal 'foo2', foo2.name
1954    assert_equal 'foo', foo2.is_alias_for.name
1955
1956    foo3 = @top_level.classes.first.method_list[2]
1957    assert_equal 'foo3', foo3.name
1958    assert_equal 'foo', foo3.is_alias_for.name
1959
1960    foo4 = @top_level.classes.first.method_list.last
1961    assert_equal 'foo4', foo4.name
1962    assert_equal 'foo', foo4.is_alias_for.name
1963
1964    assert_equal 'unknown', @top_level.classes.first.external_aliases[0].old_name
1965  end
1966
1967  def test_parse_statements_identifier_args
1968    comment = "##\n# :args: x\n# :method: b\n# my method\n"
1969
1970    util_parser "module M\n#{comment}def_delegator :a, :b, :b\nend"
1971
1972    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
1973
1974    m = @top_level.modules.first
1975    assert_equal 'M', m.full_name
1976
1977    b = m.method_list.first
1978    assert_equal 'M#b', b.full_name
1979    assert_equal 'x', b.params
1980    assert_equal 'my method', b.comment.text
1981
1982    assert_nil m.params, 'Module parameter not removed'
1983  end
1984
1985  def test_parse_statements_identifier_constant
1986    sixth_constant = <<-EOF
1987Class.new do
1988  rule :file do
1989    all(x, y, z) {
1990      def value
1991        find(:require).each {|r| require r.value }
1992        find(:grammar).map {|g| g.value }
1993      end
1994      def min; end
1995    }
1996  end
1997end
1998    EOF
1999
2000    content = <<-EOF
2001class Foo
2002  FIRST_CONSTANT = 5
2003
2004  SECOND_CONSTANT = [
2005     1,
2006     2,
2007     3
2008  ]
2009
2010  THIRD_CONSTANT = {
2011     :foo => 'bar',
2012     :x => 'y'
2013  }
2014
2015  FOURTH_CONSTANT = SECOND_CONSTANT.map do |element|
2016    element + 1
2017    element + 2
2018  end
2019
2020  FIFTH_CONSTANT = SECOND_CONSTANT.map { |element| element + 1 }
2021
2022  SIXTH_CONSTANT = #{sixth_constant}
2023
2024  SEVENTH_CONSTANT = proc { |i| begin i end }
2025end
2026EOF
2027
2028    util_parser content
2029
2030    @parser.parse_statements @top_level
2031
2032    constants = @top_level.classes.first.constants
2033
2034    constant = constants[0]
2035    assert_equal 'FIRST_CONSTANT', constant.name
2036    assert_equal '5', constant.value
2037    assert_equal @top_level, constant.file
2038
2039    constant = constants[1]
2040    assert_equal 'SECOND_CONSTANT', constant.name
2041    assert_equal "[\n1,\n2,\n3\n]", constant.value
2042    assert_equal @top_level, constant.file
2043
2044    constant = constants[2]
2045    assert_equal 'THIRD_CONSTANT', constant.name
2046    assert_equal "{\n:foo => 'bar',\n:x => 'y'\n}", constant.value
2047    assert_equal @top_level, constant.file
2048
2049    constant = constants[3]
2050    assert_equal 'FOURTH_CONSTANT', constant.name
2051    assert_equal "SECOND_CONSTANT.map do |element|\nelement + 1\nelement + 2\nend", constant.value
2052    assert_equal @top_level, constant.file
2053
2054    constant = constants[4]
2055    assert_equal 'FIFTH_CONSTANT', constant.name
2056    assert_equal 'SECOND_CONSTANT.map { |element| element + 1 }', constant.value
2057    assert_equal @top_level, constant.file
2058
2059    # TODO: parse as class
2060    constant = constants[5]
2061    assert_equal 'SIXTH_CONSTANT', constant.name
2062    assert_equal sixth_constant.lines.map(&:strip).join("\n"), constant.value
2063    assert_equal @top_level, constant.file
2064
2065    # TODO: parse as method
2066    constant = constants[6]
2067    assert_equal 'SEVENTH_CONSTANT', constant.name
2068    assert_equal "proc { |i| begin i end }", constant.value
2069    assert_equal @top_level, constant.file
2070  end
2071
2072  def test_parse_statements_identifier_attr
2073    content = "class Foo\nattr :foo\nend"
2074
2075    util_parser content
2076
2077    @parser.parse_statements @top_level
2078
2079    foo = @top_level.classes.first.attributes.first
2080    assert_equal 'foo', foo.name
2081    assert_equal 'R', foo.rw
2082  end
2083
2084  def test_parse_statements_identifier_attr_accessor
2085    content = "class Foo\nattr_accessor :foo\nend"
2086
2087    util_parser content
2088
2089    @parser.parse_statements @top_level
2090
2091    foo = @top_level.classes.first.attributes.first
2092    assert_equal 'foo', foo.name
2093    assert_equal 'RW', foo.rw
2094  end
2095
2096  def test_parse_statements_identifier_define_method
2097    util_parser <<-RUBY
2098class C
2099  ##
2100  # :method: a
2101  define_method :a do end
2102  ##
2103  # :method: b
2104  define_method :b do end
2105end
2106    RUBY
2107
2108    @parser.parse_statements @top_level
2109    c = @top_level.classes.first
2110
2111    assert_equal %w[a b], c.method_list.map { |m| m.name }
2112  end
2113
2114  def test_parse_statements_identifier_include
2115    content = "class Foo\ninclude Bar\nend"
2116
2117    util_parser content
2118
2119    @parser.parse_statements @top_level
2120
2121    foo = @top_level.classes.first
2122    assert_equal 'Foo', foo.name
2123    assert_equal 1, foo.includes.length
2124  end
2125
2126  def test_parse_statements_identifier_module_function
2127    content = "module Foo\ndef foo() end\nmodule_function :foo\nend"
2128
2129    util_parser content
2130
2131    @parser.parse_statements @top_level
2132
2133    foo, s_foo = @top_level.modules.first.method_list
2134    assert_equal 'foo',    foo.name,       'instance method name'
2135    assert_equal :private, foo.visibility, 'instance method visibility'
2136    assert_equal false,    foo.singleton,  'instance method singleton'
2137
2138    assert_equal 'foo',   s_foo.name,       'module function name'
2139    assert_equal :public, s_foo.visibility, 'module function visibility'
2140    assert_equal true,    s_foo.singleton,  'module function singleton'
2141  end
2142
2143  def test_parse_statements_identifier_private
2144    content = "class Foo\nprivate\ndef foo() end\nend"
2145
2146    util_parser content
2147
2148    @parser.parse_statements @top_level
2149
2150    foo = @top_level.classes.first.method_list.first
2151    assert_equal 'foo', foo.name
2152    assert_equal :private, foo.visibility
2153  end
2154
2155  def test_parse_statements_identifier_public_class_method
2156    content = <<-CONTENT
2157class Date
2158  def self.now; end
2159  private_class_method :now
2160end
2161
2162class DateTime < Date
2163  public_class_method :now
2164end
2165    CONTENT
2166
2167    util_parser content
2168
2169    @parser.parse_statements @top_level
2170
2171    date, date_time = @top_level.classes.sort_by { |c| c.full_name }
2172
2173    date_now      = date.method_list.first
2174    date_time_now = date_time.method_list.sort_by { |m| m.full_name }.first
2175
2176    assert_equal :private, date_now.visibility
2177    assert_equal :public,  date_time_now.visibility
2178  end
2179
2180  def test_parse_statements_identifier_private_class_method
2181    content = <<-CONTENT
2182class Date
2183  def self.now; end
2184  public_class_method :now
2185end
2186
2187class DateTime < Date
2188  private_class_method :now
2189end
2190    CONTENT
2191
2192    util_parser content
2193
2194    @parser.parse_statements @top_level
2195
2196    # TODO sort classes by default
2197    date, date_time = @top_level.classes.sort_by { |c| c.full_name }
2198
2199    date_now      = date.method_list.first
2200    date_time_now = date_time.method_list.sort_by { |m| m.full_name }.first
2201
2202    assert_equal :public,  date_now.visibility,      date_now.full_name
2203    assert_equal :private, date_time_now.visibility, date_time_now.full_name
2204  end
2205
2206  def test_parse_statements_identifier_require
2207    content = "require 'bar'"
2208
2209    util_parser content
2210
2211    @parser.parse_statements @top_level
2212
2213    assert_equal 1, @top_level.requires.length
2214  end
2215
2216  def test_parse_statements_identifier_yields
2217    comment = "##\n# :yields: x\n# :method: b\n# my method\n"
2218
2219    util_parser "module M\n#{comment}def_delegator :a, :b, :b\nend"
2220
2221    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL
2222
2223    m = @top_level.modules.first
2224    assert_equal 'M', m.full_name
2225
2226    b = m.method_list.first
2227    assert_equal 'M#b', b.full_name
2228    assert_equal 'x', b.block_params
2229    assert_equal 'my method', b.comment.text
2230
2231    assert_nil m.params, 'Module parameter not removed'
2232  end
2233
2234  def test_parse_statements_stopdoc_TkALIAS
2235    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
2236
2237    util_parser "\n# :stopdoc:\nalias old new"
2238
2239    @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil
2240
2241    assert_empty klass.aliases
2242    assert_empty klass.unmatched_alias_lists
2243  end
2244
2245  def test_parse_statements_stopdoc_TkIDENTIFIER_alias_method
2246    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
2247
2248    util_parser "\n# :stopdoc:\nalias_method :old :new"
2249
2250    @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil
2251
2252    assert_empty klass.aliases
2253    assert_empty klass.unmatched_alias_lists
2254  end
2255
2256  def test_parse_statements_stopdoc_TkIDENTIFIER_metaprogrammed
2257    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
2258
2259    util_parser "\n# :stopdoc:\n# attr :meta"
2260
2261    @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil
2262
2263    assert_empty klass.method_list
2264    assert_empty klass.attributes
2265  end
2266
2267  def test_parse_statements_stopdoc_TkCONSTANT
2268    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
2269
2270    util_parser "\n# :stopdoc:\nA = v"
2271
2272    @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil
2273
2274    assert_empty klass.constants
2275  end
2276
2277  def test_parse_statements_stopdoc_TkDEF
2278    klass = @top_level.add_class RDoc::NormalClass, 'Foo'
2279
2280    util_parser "\n# :stopdoc:\ndef m\n end"
2281
2282    @parser.parse_statements klass, RDoc::Parser::Ruby::NORMAL, nil
2283
2284    assert_empty klass.method_list
2285  end
2286
2287  def test_parse_statements_super
2288    m = RDoc::AnyMethod.new '', 'm'
2289    util_parser 'super'
2290
2291    @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, m
2292
2293    assert m.calls_super
2294  end
2295
2296  def test_parse_statements_super_no_method
2297    content = "super"
2298
2299    util_parser content
2300
2301    @parser.parse_statements @top_level
2302
2303    assert_nil @parser.get_tk
2304  end
2305
2306  def test_parse_statements_while_begin
2307    util_parser <<-RUBY
2308class A
2309  def a
2310    while begin a; b end
2311    end
2312  end
2313
2314  def b
2315  end
2316end
2317    RUBY
2318
2319    @parser.parse_statements @top_level
2320
2321    c_a = @top_level.classes.first
2322    assert_equal 'A', c_a.full_name
2323
2324    assert_equal 1, @top_level.classes.length
2325
2326    m_a = c_a.method_list.first
2327    m_b = c_a.method_list.last
2328
2329    assert_equal 'A#a', m_a.full_name
2330    assert_equal 'A#b', m_b.full_name
2331  end
2332
2333  def test_parse_symbol_in_arg
2334    util_parser ':blah "blah" "#{blah}" blah'
2335
2336    assert_equal 'blah', @parser.parse_symbol_in_arg
2337
2338    @parser.skip_tkspace
2339
2340    assert_equal 'blah', @parser.parse_symbol_in_arg
2341
2342    @parser.skip_tkspace
2343
2344    assert_equal nil, @parser.parse_symbol_in_arg
2345
2346    @parser.skip_tkspace
2347
2348    assert_equal nil, @parser.parse_symbol_in_arg
2349  end
2350
2351  def test_parse_statements_alias_method
2352    content = <<-CONTENT
2353class A
2354  alias_method :a, :[] unless c
2355end
2356
2357B = A
2358
2359class C
2360end
2361    CONTENT
2362
2363    util_parser content
2364
2365    @parser.parse_statements @top_level
2366
2367    # HACK where are the assertions?
2368  end
2369
2370  def test_parse_top_level_statements_stopdoc
2371    @top_level.stop_doc
2372    content = "# this is the top-level comment"
2373
2374    util_parser content
2375
2376    @parser.parse_top_level_statements @top_level
2377
2378    assert_empty @top_level.comment
2379  end
2380
2381  def test_parse_top_level_statements_stopdoc_integration
2382    content = <<-CONTENT
2383# :stopdoc:
2384
2385class Example
2386  def method_name
2387  end
2388end
2389    CONTENT
2390
2391    util_parser content
2392
2393    @parser.parse_top_level_statements @top_level
2394
2395    assert_equal 1, @top_level.classes.length
2396    assert_empty @top_level.modules
2397
2398    assert @top_level.find_module_named('Example').ignored?
2399  end
2400
2401  # This tests parse_comment
2402  def test_parse_top_level_statements_constant_nodoc_integration
2403    content = <<-CONTENT
2404class A
2405  C = A # :nodoc:
2406end
2407    CONTENT
2408
2409    util_parser content
2410
2411    @parser.parse_top_level_statements @top_level
2412
2413    klass = @top_level.find_module_named('A')
2414
2415    c = klass.constants.first
2416
2417    assert_nil c.document_self, 'C should not be documented'
2418  end
2419
2420  def test_parse_yield_in_braces_with_parens
2421    klass = RDoc::NormalClass.new 'Foo'
2422    klass.parent = @top_level
2423
2424    util_parser "def foo\nn.times { |i| yield nth(i) }\nend"
2425
2426    tk = @parser.get_tk
2427
2428    @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, @comment
2429
2430    foo = klass.method_list.first
2431    assert_equal 'nth(i)', foo.block_params
2432  end
2433
2434  def test_read_directive
2435    parser = util_parser '# :category: test'
2436
2437    directive, value = parser.read_directive %w[category]
2438
2439    assert_equal 'category', directive
2440    assert_equal 'test', value
2441
2442    assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
2443  end
2444
2445  def test_read_directive_allow
2446    parser = util_parser '# :category: test'
2447
2448    directive = parser.read_directive []
2449
2450    assert_nil directive
2451
2452    assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
2453  end
2454
2455  def test_read_directive_empty
2456    parser = util_parser '# test'
2457
2458    directive = parser.read_directive %w[category]
2459
2460    assert_nil directive
2461
2462    assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
2463  end
2464
2465  def test_read_directive_no_comment
2466    parser = util_parser ''
2467
2468    directive = parser.read_directive %w[category]
2469
2470    assert_nil directive
2471
2472    assert_kind_of RDoc::RubyToken::TkNL, parser.get_tk
2473  end
2474
2475  def test_read_directive_one_liner
2476    parser = util_parser '; end # :category: test'
2477
2478    directive, value = parser.read_directive %w[category]
2479
2480    assert_equal 'category', directive
2481    assert_equal 'test', value
2482
2483    assert_kind_of RDoc::RubyToken::TkSEMICOLON, parser.get_tk
2484  end
2485
2486  def test_read_documentation_modifiers
2487    c = RDoc::Context.new
2488
2489    parser = util_parser '# :category: test'
2490
2491    parser.read_documentation_modifiers c, %w[category]
2492
2493    assert_equal 'test', c.current_section.title
2494  end
2495
2496  def test_read_documentation_modifiers_notnew
2497    m = RDoc::AnyMethod.new nil, 'initialize'
2498
2499    parser = util_parser '# :notnew: test'
2500
2501    parser.read_documentation_modifiers m, %w[notnew]
2502
2503    assert m.dont_rename_initialize
2504  end
2505
2506  def test_read_documentation_modifiers_not_dash_new
2507    m = RDoc::AnyMethod.new nil, 'initialize'
2508
2509    parser = util_parser '# :not-new: test'
2510
2511    parser.read_documentation_modifiers m, %w[not-new]
2512
2513    assert m.dont_rename_initialize
2514  end
2515
2516  def test_read_documentation_modifiers_not_new
2517    m = RDoc::AnyMethod.new nil, 'initialize'
2518
2519    parser = util_parser '# :not_new: test'
2520
2521    parser.read_documentation_modifiers m, %w[not_new]
2522
2523    assert m.dont_rename_initialize
2524  end
2525
2526  def test_sanity_integer
2527    util_parser '1'
2528    assert_equal '1', @parser.get_tk.text
2529
2530    util_parser '1.0'
2531    assert_equal '1.0', @parser.get_tk.text
2532  end
2533
2534  def test_sanity_interpolation
2535    last_tk = nil
2536    util_parser 'class A; B = "#{c}"; end'
2537
2538    while tk = @parser.get_tk do last_tk = tk end
2539
2540    assert_equal "\n", last_tk.text
2541  end
2542
2543  # If you're writing code like this you're doing it wrong
2544
2545  def test_sanity_interpolation_crazy
2546    util_parser '"#{"#{"a")}" if b}"'
2547
2548    assert_equal '"#{"#{"a")}" if b}"', @parser.get_tk.text
2549    assert_equal RDoc::RubyToken::TkNL, @parser.get_tk.class
2550  end
2551
2552  def test_sanity_interpolation_curly
2553    util_parser '%{ #{} }'
2554
2555    assert_equal '%Q{ #{} }', @parser.get_tk.text
2556    assert_equal RDoc::RubyToken::TkNL, @parser.get_tk.class
2557  end
2558
2559  def test_sanity_interpolation_format
2560    util_parser '"#{stftime("%m-%d")}"'
2561
2562    while @parser.get_tk do end
2563  end
2564
2565  def test_sanity_symbol_interpolation
2566    util_parser ':"#{bar}="'
2567
2568    while @parser.get_tk do end
2569  end
2570
2571  def test_scan_cr
2572    content = <<-CONTENT
2573class C\r
2574  def m\r
2575    a=\\\r
2576      123\r
2577  end\r
2578end\r
2579    CONTENT
2580
2581    util_parser content
2582
2583    @parser.scan
2584
2585    c = @top_level.classes.first
2586
2587    assert_equal 1, c.method_list.length
2588  end
2589
2590  def test_scan_block_comment
2591    content = <<-CONTENT
2592=begin rdoc
2593Foo comment
2594=end
2595
2596class Foo
2597
2598=begin
2599m comment
2600=end
2601
2602  def m() end
2603end
2604    CONTENT
2605
2606    util_parser content
2607
2608    @parser.scan
2609
2610    foo = @top_level.classes.first
2611
2612    assert_equal 'Foo comment', foo.comment.text
2613
2614    m = foo.method_list.first
2615
2616    assert_equal 'm comment', m.comment.text
2617  end
2618
2619  def test_scan_block_comment_nested # Issue #41
2620    content = <<-CONTENT
2621require 'something'
2622=begin rdoc
2623findmeindoc
2624=end
2625module Foo
2626    class Bar
2627    end
2628end
2629    CONTENT
2630
2631    util_parser content
2632
2633    @parser.scan
2634
2635    foo = @top_level.modules.first
2636
2637    assert_equal 'Foo', foo.full_name
2638    assert_equal 'findmeindoc', foo.comment.text
2639
2640    bar = foo.classes.first
2641
2642    assert_equal 'Foo::Bar', bar.full_name
2643    assert_equal '', bar.comment.text
2644  end
2645
2646  def test_scan_block_comment_notflush
2647  ##
2648  #
2649  # The previous test assumes that between the =begin/=end blocs that there is
2650  # only one line, or minima formatting directives. This test tests for those
2651  # who use the =begin bloc with longer / more advanced formatting within.
2652  #
2653  ##
2654    content = <<-CONTENT
2655=begin rdoc
2656
2657= DESCRIPTION
2658
2659This is a simple test class
2660
2661= RUMPUS
2662
2663Is a silly word
2664
2665=end
2666class StevenSimpleClass
2667  # A band on my iPhone as I wrote this test
2668  FRUIT_BATS="Make nice music"
2669
2670=begin rdoc
2671A nice girl
2672=end
2673
2674  def lauren
2675    puts "Summoning Lauren!"
2676  end
2677end
2678    CONTENT
2679    util_parser content
2680
2681    @parser.scan
2682
2683    foo = @top_level.classes.first
2684
2685    assert_equal "= DESCRIPTION\n\nThis is a simple test class\n\n= RUMPUS\n\nIs a silly word",
2686      foo.comment.text
2687
2688    m = foo.method_list.first
2689
2690    assert_equal 'A nice girl', m.comment.text
2691  end
2692
2693  def test_scan_constant_in_method
2694    content = <<-CONTENT # newline is after M is important
2695module M
2696  def m
2697    A
2698    B::C
2699  end
2700end
2701    CONTENT
2702
2703    util_parser content
2704
2705    @parser.scan
2706
2707    m = @top_level.modules.first
2708
2709    assert_empty m.constants
2710
2711    assert_empty @store.classes_hash.keys
2712    assert_equal %w[M], @store.modules_hash.keys
2713  end
2714
2715  def test_scan_constant_in_rescue
2716    content = <<-CONTENT # newline is after M is important
2717module M
2718  def m
2719  rescue A::B
2720  rescue A::C => e
2721  rescue A::D, A::E
2722  rescue A::F,
2723         A::G
2724  rescue H
2725  rescue I => e
2726  rescue J, K
2727  rescue L =>
2728    e
2729  rescue M;
2730  rescue N,
2731         O => e
2732  end
2733end
2734    CONTENT
2735
2736    util_parser content
2737
2738    @parser.scan
2739
2740    m = @top_level.modules.first
2741
2742    assert_empty m.constants
2743
2744    assert_empty @store.classes_hash.keys
2745    assert_equal %w[M], @store.modules_hash.keys
2746  end
2747
2748  def test_scan_constant_nodoc
2749    content = <<-CONTENT # newline is after M is important
2750module M
2751
2752  C = v # :nodoc:
2753end
2754    CONTENT
2755
2756    util_parser content
2757
2758    @parser.scan
2759
2760    c = @top_level.modules.first.constants.first
2761
2762    assert c.documented?
2763  end
2764
2765  def test_scan_constant_nodoc_block
2766    content = <<-CONTENT # newline is after M is important
2767module M
2768
2769  C = v do # :nodoc:
2770  end
2771end
2772    CONTENT
2773
2774    util_parser content
2775
2776    @parser.scan
2777
2778    c = @top_level.modules.first.constants.first
2779
2780    assert c.documented?
2781  end
2782
2783  def test_scan_meta_method_block
2784    content = <<-CONTENT
2785class C
2786
2787  ##
2788  #  my method
2789
2790  inline(:my_method) do |*args|
2791    "this method used to cause z to disappear"
2792  end
2793
2794  def z
2795  end
2796    CONTENT
2797
2798    util_parser content
2799
2800    @parser.scan
2801
2802    assert_equal 2, @top_level.classes.first.method_list.length
2803  end
2804
2805  def test_scan_markup_override
2806    content = <<-CONTENT
2807# *awesome*
2808class C
2809  # :markup: rd
2810  # ((*radical*))
2811  def m
2812  end
2813end
2814    CONTENT
2815
2816    util_parser content
2817
2818    @parser.scan
2819
2820    c = @top_level.classes.first
2821
2822    assert_equal 'rdoc', c.comment.format
2823
2824    assert_equal 'rd', c.method_list.first.comment.format
2825  end
2826
2827  def test_scan_markup_first_comment
2828    content = <<-CONTENT
2829# :markup: rd
2830
2831# ((*awesome*))
2832class C
2833  # ((*radical*))
2834  def m
2835  end
2836end
2837    CONTENT
2838
2839    util_parser content
2840
2841    @parser.scan
2842
2843    c = @top_level.classes.first
2844
2845    assert_equal 'rd', c.comment.format
2846
2847    assert_equal 'rd', c.method_list.first.comment.format
2848  end
2849
2850  def test_scan_tomdoc_meta
2851    util_parser <<-RUBY
2852# :markup: tomdoc
2853
2854class C
2855
2856  # Signature
2857  #
2858  #   find_by_<field>[_and_<field>...](args)
2859  #
2860  # field - A field name.
2861
2862end
2863
2864    RUBY
2865
2866    @parser.scan
2867
2868    c = @top_level.classes.first
2869
2870    m = c.method_list.first
2871
2872    assert_equal "find_by_<field>[_and_<field>...]", m.name
2873    assert_equal "find_by_<field>[_and_<field>...](args)\n", m.call_seq
2874
2875    expected =
2876      doc(
2877        head(3, 'Signature'),
2878        list(:NOTE,
2879          item(%w[field],
2880            para('A field name.'))))
2881    expected.file = @top_level
2882
2883    assert_equal expected, m.comment.parse
2884  end
2885
2886  def test_scan_stopdoc
2887    util_parser <<-RUBY
2888class C
2889  # :stopdoc:
2890  class Hidden
2891  end
2892end
2893    RUBY
2894
2895    @parser.scan
2896
2897    c = @top_level.classes.first
2898
2899    hidden = c.classes.first
2900
2901    refute hidden.document_self
2902    assert hidden.ignored?
2903  end
2904
2905  def test_scan_stopdoc_class_alias
2906    util_parser <<-RUBY
2907# :stopdoc:
2908module A
2909  B = C
2910end
2911    RUBY
2912
2913    @parser.scan
2914
2915    assert_empty @store.all_classes
2916
2917    assert_equal 1, @store.all_modules.length
2918    m = @store.all_modules.first
2919
2920    assert m.ignored?
2921  end
2922
2923  def test_scan_stopdoc_nested
2924    util_parser <<-RUBY
2925# :stopdoc:
2926class A::B
2927end
2928    RUBY
2929
2930    @parser.scan
2931
2932    a   = @store.modules_hash['A']
2933    a_b = @store.classes_hash['A::B']
2934
2935    refute a.document_self, 'A is inside stopdoc'
2936    assert a.ignored?,      'A is inside stopdoc'
2937
2938    refute a_b.document_self, 'A::B is inside stopdoc'
2939    assert a_b.ignored?,      'A::B is inside stopdoc'
2940  end
2941
2942  def test_scan_struct_self_brackets
2943    util_parser <<-RUBY
2944class C < M.m
2945  def self.[]
2946  end
2947end
2948    RUBY
2949
2950    @parser.scan
2951
2952    c = @store.find_class_named 'C'
2953    assert_equal %w[C::[]], c.method_list.map { |m| m.full_name }
2954  end
2955
2956  def test_stopdoc_after_comment
2957    util_parser <<-EOS
2958      module Bar
2959        # hello
2960        module Foo
2961          # :stopdoc:
2962        end
2963        # there
2964        class Baz
2965          # :stopdoc:
2966        end
2967      end
2968    EOS
2969
2970    @parser.parse_statements @top_level
2971
2972    foo = @top_level.modules.first.modules.first
2973    assert_equal 'Foo', foo.name
2974    assert_equal 'hello', foo.comment.text
2975
2976    baz = @top_level.modules.first.classes.first
2977    assert_equal 'Baz', baz.name
2978    assert_equal 'there', baz.comment.text
2979  end
2980
2981  def tk klass, scan, line, char, name, text
2982    klass = RDoc::RubyToken.const_get "Tk#{klass.to_s.upcase}"
2983
2984    token = if klass.instance_method(:initialize).arity == 3 then
2985              raise ArgumentError, "name not used for #{klass}" if name
2986              klass.new scan, line, char
2987            else
2988              klass.new scan, line, char, name
2989            end
2990
2991    token.set_text text
2992
2993    token
2994  end
2995
2996  def util_parser(content)
2997    @parser = RDoc::Parser::Ruby.new @top_level, @filename, content, @options,
2998                                     @stats
2999  end
3000
3001  def util_two_parsers(first_file_content, second_file_content)
3002    util_parser first_file_content
3003
3004    @parser2 = RDoc::Parser::Ruby.new @top_level2, @filename,
3005                                      second_file_content, @options, @stats
3006  end
3007
3008end
3009
3010