ruby/test/rdoc/test_rdoc_ri_driver.rb

837 строки
19 KiB
Ruby

require 'pp'
require 'rubygems'
require 'minitest/autorun'
require 'tmpdir'
require 'fileutils'
require 'rdoc/ri/driver'
class TestRDocRIDriver < MiniTest::Unit::TestCase
def setup
@RM = RDoc::Markup
@tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_driver_#{$$}"
@home_ri = File.join @tmpdir, 'dot_ri'
FileUtils.mkdir_p @tmpdir
FileUtils.mkdir_p @home_ri
@orig_ri = ENV['RI']
@orig_home = ENV['HOME']
ENV['HOME'] = @tmpdir
ENV.delete 'RI'
options = RDoc::RI::Driver.process_args []
options[:home] = @tmpdir
options[:use_stdout] = true
options[:formatter] = @RM::ToRdoc
@driver = RDoc::RI::Driver.new options
end
def teardown
ENV['HOME'] = @orig_home
ENV['RI'] = @orig_ri
FileUtils.rm_rf @tmpdir
end
DUMMY_PAGER = ":;\n"
def with_dummy_pager
pager_env, ENV['RI_PAGER'] = ENV['RI_PAGER'], DUMMY_PAGER
yield
ensure
ENV['RI_PAGER'] = pager_env
end
def mu_pp(obj)
s = ''
s = PP.pp obj, s
s = s.force_encoding(Encoding.default_external) if defined? Encoding
s.chomp
end
def test_self_dump
util_store
out, err = capture_io do
RDoc::RI::Driver.dump @store.cache_path
end
assert_match %r%:class_methods%, out
assert_match %r%:modules%, out
assert_match %r%:instance_methods%, out
assert_match %r%:ancestors%, out
end
def test_add_also_in_empty
out = @RM::Document.new
@driver.add_also_in out, []
assert_empty out
end
def test_add_also_in
util_multi_store
@store1.type = :system
@store2.type = :home
out = @RM::Document.new
@driver.add_also_in out, [@store1, @store2]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Paragraph.new('Also found in:'),
@RM::Verbatim.new(' ', 'ruby core', "\n",
' ', '~/.ri', "\n"))
assert_equal expected, out
end
def test_add_class
util_multi_store
out = @RM::Document.new
@driver.add_class out, 'Bar', [@cBar]
expected = @RM::Document.new(
@RM::Heading.new(1, 'Bar < Foo'),
@RM::BlankLine.new)
assert_equal expected, out
end
def test_add_from
util_store
@store.type = :system
out = @RM::Document.new
@driver.add_from out, @store
expected = @RM::Document.new @RM::Paragraph.new("(from ruby core)")
assert_equal expected, out
end
def test_add_includes_empty
out = @RM::Document.new
@driver.add_includes out, []
assert_empty out
end
def test_add_includes_many
util_store
out = @RM::Document.new
enum = RDoc::Include.new 'Enumerable', nil
@cFoo.add_include enum
@driver.add_includes out, [[[@cFooInc, enum], @store]]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
@RM::Paragraph.new("(from #{@store.friendly_path})"),
@RM::BlankLine.new,
@RM::Paragraph.new("Inc"),
@RM::BlankLine.new,
@RM::Paragraph.new("Include thingy"),
@RM::BlankLine.new,
@RM::Verbatim.new(' ', 'Enumerable', "\n"))
assert_equal expected, out
end
def test_add_includes_many_no_doc
util_store
out = @RM::Document.new
enum = RDoc::Include.new 'Enumerable', nil
@cFoo.add_include enum
@cFooInc.instance_variable_set :@comment, ''
@driver.add_includes out, [[[@cFooInc, enum], @store]]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
@RM::Paragraph.new("(from #{@store.friendly_path})"),
@RM::Verbatim.new(' ', 'Inc', "\n",
' ', 'Enumerable', "\n"))
assert_equal expected, out
end
def test_add_includes_one
util_store
out = @RM::Document.new
@driver.add_includes out, [[[@cFooInc], @store]]
expected = @RM::Document.new(
@RM::Rule.new(1),
@RM::Heading.new(1, "Includes:"),
@RM::Paragraph.new("Inc (from #{@store.friendly_path})"),
@RM::BlankLine.new,
@RM::Paragraph.new("Include thingy"),
@RM::BlankLine.new)
assert_equal expected, out
end
def test_add_method_list
out = @RM::Document.new
@driver.add_method_list out, %w[new], 'Class methods'
expected = @RM::Document.new(
@RM::Heading.new(1, 'Class methods:'),
@RM::BlankLine.new,
@RM::Verbatim.new(' ', 'new'),
@RM::BlankLine.new)
assert_equal expected, out
end
def test_add_method_list_none
out = @RM::Document.new
@driver.add_method_list out, nil, 'Class'
assert_equal @RM::Document.new, out
end
def test_ancestors_of
util_ancestors_store
assert_equal %w[X Mixin Object Foo], @driver.ancestors_of('Foo::Bar')
end
def test_classes
util_multi_store
expected = {
'Ambiguous' => [@store1, @store2],
'Bar' => [@store2],
'Foo' => [@store1],
'Foo::Bar' => [@store1],
'Foo::Baz' => [@store1, @store2],
'Inc' => [@store1],
}
assert_equal expected, @driver.classes
end
def test_complete
store = RDoc::RI::Store.new @home_ri
store.cache[:ancestors] = {
'Foo' => %w[Object],
'Foo::Bar' => %w[Object],
}
store.cache[:class_methods] = {
'Foo' => %w[bar]
}
store.cache[:instance_methods] = {
'Foo' => %w[Bar]
}
store.cache[:modules] = %w[
Foo
Foo::Bar
]
@driver.stores = [store]
assert_equal %w[Foo Foo::Bar], @driver.complete('F')
assert_equal %w[ Foo::Bar], @driver.complete('Foo::B')
assert_equal %w[Foo#Bar], @driver.complete('Foo#'), 'Foo#'
assert_equal %w[Foo#Bar Foo::bar], @driver.complete('Foo.'), 'Foo.'
assert_equal %w[Foo::Bar Foo::bar], @driver.complete('Foo::'), 'Foo::'
end
def test_complete_ancestor
util_ancestors_store
assert_equal %w[Foo::Bar#i_method], @driver.complete('Foo::Bar#')
assert_equal %w[Foo::Bar#i_method Foo::Bar::c_method Foo::Bar::new],
@driver.complete('Foo::Bar.')
end
def test_complete_classes
util_store
assert_equal %w[Foo Foo::Bar Foo::Baz], @driver.complete('F')
assert_equal %w[Foo:: Foo::Bar Foo::Baz], @driver.complete('Foo::')
assert_equal %w[ Foo::Bar Foo::Baz], @driver.complete('Foo::B')
end
def test_complete_multistore
util_multi_store
assert_equal %w[Bar], @driver.complete('B')
assert_equal %w[Foo Foo::Bar Foo::Baz], @driver.complete('F')
end
def test_display
doc = @RM::Document.new(
@RM::Paragraph.new('hi'))
out, err = capture_io do
@driver.display doc
end
assert_equal "hi\n", out
end
def test_display_class
util_store
out, err = capture_io do
@driver.display_class 'Foo::Bar'
end
assert_match %r%^= Foo::Bar%, out
assert_match %r%^\(from%, out # )
assert_match %r%^= Class methods:%, out
assert_match %r%^ new%, out
assert_match %r%^= Instance methods:%, out
assert_match %r%^ blah%, out
assert_match %r%^= Attributes:%, out
assert_match %r%^ attr_accessor attr%, out
assert_equal 1, out.scan(/-\n/).length
end
def test_display_class_ambiguous
util_multi_store
out, err = capture_io do
@driver.display_class 'Ambiguous'
end
assert_match %r%^= Ambiguous < Object$%, out
end
def test_display_class_multi_no_doc
util_multi_store
out, err = capture_io do
@driver.display_class 'Foo::Baz'
end
assert_match %r%^= Foo::Baz%, out
assert_match %r%-\n%, out
assert_match %r%Also found in:%, out
assert_match %r%#{Regexp.escape @home_ri}%, out
assert_match %r%#{Regexp.escape @home_ri2}%, out
end
def test_display_class_superclass
util_multi_store
out, err = capture_io do
@driver.display_class 'Bar'
end
assert_match %r%^= Bar < Foo%, out
end
def test_display_class_module
util_store
out, err = capture_io do
@driver.display_class 'Inc'
end
assert_match %r%^= Inc$%, out
end
def test_display_method
util_store
out, err = capture_io do
@driver.display_method 'Foo::Bar#blah'
end
assert_match %r%Foo::Bar#blah%, out
assert_match %r%blah.5%, out
assert_match %r%blah.6%, out
end
def test_display_method_attribute
util_store
out, err = capture_io do
@driver.display_method 'Foo::Bar#attr'
end
assert_match %r%Foo::Bar#attr%, out
refute_match %r%Implementation from%, out
end
def test_display_method_inherited
util_multi_store
out, err = capture_io do
@driver.display_method 'Bar#inherit'
end
assert_match %r%^= Bar#inherit%, out
assert_match %r%^=== Implementation from Foo%, out
end
def test_display_name_not_found_class
util_store
out, err = capture_io do
assert_equal false, @driver.display_name('Foo::B')
end
expected = <<-EXPECTED
Foo::B not found, maybe you meant:
Foo::Bar
Foo::Baz
EXPECTED
assert_equal expected, out
end
def test_display_name_not_found_method
util_store
out, err = capture_io do
assert_equal false, @driver.display_name('Foo::Bar#b')
end
expected = <<-EXPECTED
Foo::Bar#b not found, maybe you meant:
Foo::Bar#blah
Foo::Bar#bother
EXPECTED
assert_equal expected, out
end
def test_display_method_params
util_store
out, err = capture_io do
@driver.display_method 'Foo::Bar#bother'
end
assert_match %r%things.*stuff%, out
end
def test_expand_class
util_store
assert_equal 'Foo', @driver.expand_class('F')
assert_equal 'Foo::Bar', @driver.expand_class('F::Bar')
assert_raises RDoc::RI::Driver::NotFoundError do
@driver.expand_class 'F::B'
end
end
def test_expand_name
util_store
assert_equal '.b', @driver.expand_name('b')
assert_equal 'Foo', @driver.expand_name('F')
assert_equal 'Foo::Bar#', @driver.expand_name('F::Bar#')
e = assert_raises RDoc::RI::Driver::NotFoundError do
@driver.expand_name 'Z'
end
assert_equal 'Z', e.name
end
def test_find_methods
util_store
items = []
@driver.find_methods 'Foo::Bar.' do |store, klass, ancestor, types, method|
items << [store, klass, ancestor, types, method]
end
expected = [
[@store, 'Foo::Bar', 'Foo::Bar', :both, nil],
]
assert_equal expected, items
end
def test_find_methods_method
util_store
items = []
@driver.find_methods '.blah' do |store, klass, ancestor, types, method|
items << [store, klass, ancestor, types, method]
end
expected = [
[@store, 'Ambiguous', 'Ambiguous', :both, 'blah'],
[@store, 'Foo', 'Foo', :both, 'blah'],
[@store, 'Foo::Bar', 'Foo::Bar', :both, 'blah'],
[@store, 'Foo::Baz', 'Foo::Baz', :both, 'blah'],
[@store, 'Inc', 'Inc', :both, 'blah'],
]
assert_equal expected, items
end
def test_formatter
driver = RDoc::RI::Driver.new
io = Object.new
def io.tty?; false; end
assert_instance_of @RM::ToBs, driver.formatter(io)
def io.tty?; true; end
assert_instance_of @RM::ToAnsi, driver.formatter(io)
driver.instance_variable_set :@paging, true
assert_instance_of @RM::ToBs, driver.formatter(io)
driver.instance_variable_set :@formatter_klass, @RM::ToHtml
assert_instance_of @RM::ToHtml, driver.formatter(io)
end
def test_method_type
assert_equal :both, @driver.method_type(nil)
assert_equal :both, @driver.method_type('.')
assert_equal :instance, @driver.method_type('#')
assert_equal :class, @driver.method_type('::')
end
def test_list_known_classes
util_store
out, err = capture_io do
@driver.list_known_classes
end
assert_equal "Ambiguous\nFoo\nFoo::Bar\nFoo::Baz\nInc\n", out
end
def test_list_methods_matching
util_store
assert_equal %w[Foo::Bar#attr Foo::Bar#blah Foo::Bar#bother Foo::Bar::new],
@driver.list_methods_matching('Foo::Bar.')
end
def test_load_method
util_store
method = @driver.load_method(@store, :instance_methods, 'Foo', '#',
'inherit')
assert_equal @inherit, method
end
def test_load_method_inherited
util_multi_store
method = @driver.load_method(@store2, :instance_methods, 'Bar', '#',
'inherit')
assert_equal nil, method
end
def test_load_methods_matching
util_store
expected = [[@store, [@inherit]]]
assert_equal expected, @driver.load_methods_matching('Foo#inherit')
expected = [[@store, [@blah]]]
assert_equal expected, @driver.load_methods_matching('.blah')
assert_empty @driver.load_methods_matching('.b')
end
def test_load_methods_matching_inherited
util_multi_store
expected = [[@store1, [@inherit]]]
assert_equal expected, @driver.load_methods_matching('Bar#inherit')
end
def _test_page # this test doesn't do anything anymore :(
@driver.use_stdout = false
with_dummy_pager do
@driver.page do |io|
skip "couldn't find a standard pager" if io == $stdout
assert @driver.paging?
end
end
refute @driver.paging?
end
def test_page_stdout
@driver.use_stdout = true
@driver.page do |io|
assert_equal $stdout, io
end
refute @driver.paging?
end
def test_parse_name_method
klass, type, meth = @driver.parse_name 'foo'
assert_equal '', klass, 'foo class'
assert_equal '.', type, 'foo type'
assert_equal 'foo', meth, 'foo method'
klass, type, meth = @driver.parse_name '#foo'
assert_equal '', klass, '#foo class'
assert_equal '#', type, '#foo type'
assert_equal 'foo', meth, '#foo method'
klass, type, meth = @driver.parse_name '::foo'
assert_equal '', klass, '::foo class'
assert_equal '::', type, '::foo type'
assert_equal 'foo', meth, '::foo method'
end
def test_parse_name_single_class
klass, type, meth = @driver.parse_name 'Foo'
assert_equal 'Foo', klass, 'Foo class'
assert_equal nil, type, 'Foo type'
assert_equal nil, meth, 'Foo method'
klass, type, meth = @driver.parse_name 'Foo#'
assert_equal 'Foo', klass, 'Foo# class'
assert_equal '#', type, 'Foo# type'
assert_equal nil, meth, 'Foo# method'
klass, type, meth = @driver.parse_name 'Foo::'
assert_equal 'Foo', klass, 'Foo:: class'
assert_equal '::', type, 'Foo:: type'
assert_equal nil, meth, 'Foo:: method'
klass, type, meth = @driver.parse_name 'Foo.'
assert_equal 'Foo', klass, 'Foo. class'
assert_equal '.', type, 'Foo. type'
assert_equal nil, meth, 'Foo. method'
klass, type, meth = @driver.parse_name 'Foo#Bar'
assert_equal 'Foo', klass, 'Foo#Bar class'
assert_equal '#', type, 'Foo#Bar type'
assert_equal 'Bar', meth, 'Foo#Bar method'
klass, type, meth = @driver.parse_name 'Foo.Bar'
assert_equal 'Foo', klass, 'Foo.Bar class'
assert_equal '.', type, 'Foo.Bar type'
assert_equal 'Bar', meth, 'Foo.Bar method'
klass, type, meth = @driver.parse_name 'Foo::bar'
assert_equal 'Foo', klass, 'Foo::bar class'
assert_equal '::', type, 'Foo::bar type'
assert_equal 'bar', meth, 'Foo::bar method'
end
def test_parse_name_namespace
klass, type, meth = @driver.parse_name 'Foo::Bar'
assert_equal 'Foo::Bar', klass, 'Foo::Bar class'
assert_equal nil, type, 'Foo::Bar type'
assert_equal nil, meth, 'Foo::Bar method'
klass, type, meth = @driver.parse_name 'Foo::Bar#'
assert_equal 'Foo::Bar', klass, 'Foo::Bar# class'
assert_equal '#', type, 'Foo::Bar# type'
assert_equal nil, meth, 'Foo::Bar# method'
klass, type, meth = @driver.parse_name 'Foo::Bar#baz'
assert_equal 'Foo::Bar', klass, 'Foo::Bar#baz class'
assert_equal '#', type, 'Foo::Bar#baz type'
assert_equal 'baz', meth, 'Foo::Bar#baz method'
end
def _test_setup_pager # this test doesn't do anything anymore :(
@driver.use_stdout = false
pager = with_dummy_pager do @driver.setup_pager end
skip "couldn't find a standard pager" unless pager
assert @driver.paging?
ensure
pager.close if pager
end
def util_ancestors_store
store1 = RDoc::RI::Store.new @home_ri
store1.cache[:ancestors] = {
'Foo' => %w[Object],
'Foo::Bar' => %w[Foo],
}
store1.cache[:class_methods] = {
'Foo' => %w[c_method new],
'Foo::Bar' => %w[new],
}
store1.cache[:instance_methods] = {
'Foo' => %w[i_method],
}
store1.cache[:modules] = %w[
Foo
Foo::Bar
]
store2 = RDoc::RI::Store.new @home_ri
store2.cache[:ancestors] = {
'Foo' => %w[Mixin Object],
'Mixin' => %w[],
'Object' => %w[X Object],
'X' => %w[Object],
}
store2.cache[:class_methods] = {
'Foo' => %w[c_method new],
'Mixin' => %w[],
'X' => %w[],
'Object' => %w[],
}
store2.cache[:instance_methods] = {
'Foo' => %w[i_method],
'Mixin' => %w[],
}
store2.cache[:modules] = %w[
Foo
Mixin
Object
X
]
@driver.stores = store1, store2
end
def util_multi_store
util_store
@store1 = @store
@home_ri2 = "#{@home_ri}2"
@store2 = RDoc::RI::Store.new @home_ri2
# as if seen in a namespace like class Ambiguous::Other
@mAmbiguous = RDoc::NormalModule.new 'Ambiguous'
@cFoo = RDoc::NormalClass.new 'Foo'
@cBar = RDoc::NormalClass.new 'Bar'
@cBar.superclass = 'Foo'
@cFoo_Baz = RDoc::NormalClass.new 'Baz'
@cFoo_Baz.parent = @cFoo
@baz = RDoc::AnyMethod.new nil, 'baz'
@cBar.add_method @baz
@store2.save_class @mAmbiguous
@store2.save_class @cBar
@store2.save_class @cFoo_Baz
@store2.save_method @cBar, @baz
@store2.save_cache
@driver.stores = [@store1, @store2]
end
def util_store
@store = RDoc::RI::Store.new @home_ri
@cFoo = RDoc::NormalClass.new 'Foo'
@mInc = RDoc::NormalModule.new 'Inc'
@cAmbiguous = RDoc::NormalClass.new 'Ambiguous'
doc = @RM::Document.new @RM::Paragraph.new('Include thingy')
@cFooInc = RDoc::Include.new 'Inc', doc
@cFoo.add_include @cFooInc
@cFoo_Bar = RDoc::NormalClass.new 'Bar'
@cFoo_Bar.parent = @cFoo
@blah = RDoc::AnyMethod.new nil, 'blah'
@blah.call_seq = "blah(5) => 5\nblah(6) => 6\n"
@bother = RDoc::AnyMethod.new nil, 'bother'
@bother.params = "(things)"
@bother.block_params = "stuff"
@new = RDoc::AnyMethod.new nil, 'new'
@new.singleton = true
@cFoo_Bar.add_method @blah
@cFoo_Bar.add_method @bother
@cFoo_Bar.add_method @new
@attr = RDoc::Attr.new nil, 'attr', 'RW', ''
@cFoo_Bar.add_attribute @attr
@cFoo_Baz = RDoc::NormalClass.new 'Baz'
@cFoo_Baz.parent = @cFoo
@inherit = RDoc::AnyMethod.new nil, 'inherit'
@cFoo.add_method @inherit
@store.save_class @cFoo
@store.save_class @cFoo_Bar
@store.save_class @cFoo_Baz
@store.save_class @mInc
@store.save_class @cAmbiguous
@store.save_method @cFoo_Bar, @blah
@store.save_method @cFoo_Bar, @bother
@store.save_method @cFoo_Bar, @new
@store.save_method @cFoo_Bar, @attr
@store.save_method @cFoo, @inherit
@store.save_cache
@driver.stores = [@store]
end
end