require File.join(File.dirname(__FILE__), "spec_helper") describe YARD::RegistryStore do before do FileUtils.rm_rf("foo") @store = RegistryStore.new @serializer = Serializers::YardocSerializer.new('foo') @foo = CodeObjects::MethodObject.new(nil, :foo) @bar = CodeObjects::ClassObject.new(nil, :Bar) Serializers::YardocSerializer.stub!(:new).and_return(@serializer) end describe '#load' do it "should load root.dat as full object list if it is a Hash" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) @serializer.should_receive(:deserialize).with('root').and_return({:root => @foo, :A => @bar}) @store.load('foo').should == true @store.root.should == @foo @store.get('A').should == @bar end it "should load old yardoc format if .yardoc is a file" do File.should_receive(:directory?).with('foo').and_return(false) File.should_receive(:file?).with('foo').and_return(true) File.should_receive(:read_binary).with('foo').and_return('FOO') Marshal.should_receive(:load).with('FOO') @store.load('foo') end it "should load new yardoc format if .yardoc is a directory" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) @store.load('foo').should == true end it "should return true if .yardoc is loaded (file)" do File.should_receive(:directory?).with('myyardoc').and_return(false) File.should_receive(:file?).with('myyardoc').and_return(true) File.should_receive(:read_binary).with('myyardoc').and_return(Marshal.dump('')) @store.load('myyardoc').should == true end it "should return true if .yardoc is loaded (directory)" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) @store.load('foo').should == true end it "should return false if .yardoc does not exist" do @store.load('NONEXIST').should == false end it "should return false if there is no file to load" do @store.load(nil).should == false end it "should load checksums if they exist" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(true) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:readlines).with('foo/checksums').and_return([ 'file1 CHECKSUM1', ' file2 CHECKSUM2 ' ]) @store.load('foo').should == true @store.checksums.should == {'file1' => 'CHECKSUM1', 'file2' => 'CHECKSUM2'} end it "should load proxy_types if they exist" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(true) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) File.should_receive(:read_binary).with('foo/proxy_types').and_return(Marshal.dump({'a' => 'b'})) @store.load('foo').should == true @store.proxy_types.should == {'a' => 'b'} end it "should load root object if it exists" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(true) File.should_receive(:read_binary).with('foo/objects/root.dat').and_return(Marshal.dump(@foo)) @store.load('foo').should == true @store.root.should == @foo end end describe '#save' do before do @store.stub!(:write_proxy_types) @store.stub!(:write_checksums) @store.stub!(:destroy) end after do Registry.single_object_db = nil end def saves_to_singledb @serializer.should_receive(:serialize).once.with(instance_of(Hash)) @store.save(true, 'foo') end def add_items(n) n.times {|i| @store[i.to_s] = @foo } end def saves_to_multidb times = @store.keys.size @serializer.should_receive(:serialize).exactly(times).times @store.save(true, 'foo') @last = times end it "should save as single object db if single_object_db is nil and there are less than 3000 objects" do Registry.single_object_db = nil add_items(100) saves_to_singledb end it "should save as single object db if single_object_db is nil and there are more than 3000 objects" do Registry.single_object_db = nil add_items(5000) saves_to_singledb end it "should save as single object db if single_object_db is true (and any amount of objects)" do Registry.single_object_db = true add_items(100) saves_to_singledb add_items(5000) saves_to_singledb end it "should never save as single object db if single_object_db is false" do Registry.single_object_db = false add_items(100) saves_to_multidb add_items(5000) saves_to_multidb end end describe '#put' do it "should assign values" do @store.put(:YARD, @foo) @store.get(:YARD).should == @foo end it "should treat '' as root" do @store.put('', @foo) @store.get(:root).should == @foo end end describe '#get' do it "should hit cache if object exists" do @store.put(:YARD, @foo) @store.get(:YARD).should == @foo end it "should hit backstore on cache miss and cache is not fully loaded" do serializer = mock(:serializer) serializer.should_receive(:deserialize).once.with(:YARD).and_return(@foo) @store.load('foo') @store.instance_variable_set("@loaded_objects", 0) @store.instance_variable_set("@available_objects", 100) @store.instance_variable_set("@serializer", serializer) @store.get(:YARD).should == @foo @store.get(:YARD).should == @foo @store.instance_variable_get("@loaded_objects").should == 1 end end [:keys, :values].each do |item| describe "##{item}" do it "should load entire database if reload=true" do File.should_receive(:directory?).with('foo').and_return(true) @store.load('foo') @store.should_receive(:load_all) @store.send(item, true) end it "should not load entire database if reload=false" do File.should_receive(:directory?).with('foo').and_return(true) @store.load('foo') @store.should_not_receive(:load_all) @store.send(item, false) end end end describe '#paths_for_type' do after { Registry.clear } it "should set all object types if not set by object_types" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) @serializer.should_receive(:deserialize).with('root').and_return({:'A#foo' => @foo, :A => @bar}) @store.load('foo') @store.paths_for_type(:method).should == ['#foo'] @store.paths_for_type(:class).should == ['Bar'] end it "should keep track of types when assigning values" do @store.put(:abc, @foo) @store.paths_for_type(@foo.type).should == ['abc'] end it "should reassign path if type changes" do foo = CodeObjects::ClassObject.new(:root, :Foo) @store.put('Foo', foo) @store.get('Foo').type.should == :class @store.paths_for_type(:class).should == ["Foo"] foo = CodeObjects::ModuleObject.new(:root, :Foo) @store.put('Foo', foo) @store.get('Foo').type.should == :module @store.paths_for_type(:class).should == [] @store.paths_for_type(:module).should == ["Foo"] end end describe '#values_for_type' do it "should return all objects with type" do @store.put(:abc, @foo) @store.values_for_type(@foo.type).should == [@foo] end end describe '#load_all' do it "should load the entire database" do foomock = mock(:Foo) barmock = mock(:Bar) foomock.stub!(:type).and_return(:class) barmock.stub!(:type).and_return(:class) foomock.should_receive(:path).and_return('Foo') barmock.should_receive(:path).and_return('Bar') File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) @store.should_receive(:all_disk_objects).at_least(1).times.and_return(['foo/objects/foo', 'foo/objects/bar']) @store.load('foo') serializer = @store.instance_variable_get("@serializer") serializer.should_receive(:deserialize).with('foo/objects/foo', true).and_return(foomock) serializer.should_receive(:deserialize).with('foo/objects/bar', true).and_return(barmock) @store.send(:load_all) @store.instance_variable_get("@available_objects").should == 2 @store.instance_variable_get("@loaded_objects").should == 2 @store[:Foo].should == foomock @store[:Bar].should == barmock end end describe '#destroy' do it "should destroy file ending in .yardoc when force=false" do File.should_receive(:file?).with('foo.yardoc').and_return(true) File.should_receive(:unlink).with('foo.yardoc') @store.instance_variable_set("@file", 'foo.yardoc') @store.destroy.should == true end it "should destroy dir ending in .yardoc when force=false" do File.should_receive(:directory?).with('foo.yardoc').and_return(true) FileUtils.should_receive(:rm_rf).with('foo.yardoc') @store.instance_variable_set("@file", 'foo.yardoc') @store.destroy.should == true end it "should not destroy file/dir not ending in .yardoc when force=false" do File.should_not_receive(:file?).with('foo') File.should_not_receive(:directory?).with('foo') File.should_not_receive(:unlink).with('foo') FileUtils.should_not_receive(:rm_rf).with('foo') @store.instance_variable_set("@file", 'foo') @store.destroy.should == false end it "should destroy any file/dir when force=true" do File.should_receive(:file?).with('foo').and_return(true) File.should_receive(:unlink).with('foo') @store.instance_variable_set("@file", 'foo') @store.destroy(true).should == true end end describe '#locale' do it "should load ./po/LOCALE_NAME.po" do fr_locale = I18n::Locale.new("fr") I18n::Locale.should_receive(:new).with("fr").and_return(fr_locale) Registry.should_receive(:po_dir).and_return("po") fr_locale.should_receive(:load).with("po") @store.locale("fr").should == fr_locale end end end