require 'spec_helper'
describe Rubydora::DigitalObject do
before do
@mock_repository = mock(Rubydora::Repository, :config=>{})
end
describe "new" do
it "should load a DigitalObject instance" do
Rubydora::DigitalObject.new("pid").should be_a_kind_of(Rubydora::DigitalObject)
end
end
describe "profile" do
before(:each) do
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should convert object profile to a simple hash" do
@mock_repository.should_receive(:object).with(:pid => 'pid').and_return("1234")
h = @object.profile
h.should have_key("a")
h['a'].should == '1'
h.should have_key("b")
h['b'].should == '2'
h.should have_key("objModels")
h['objModels'].should == ['3', '4']
end
it "should be frozen (to prevent modification)" do
@mock_repository.should_receive(:object).with(:pid => 'pid').and_return("1234")
h = @object.profile
expect { h['asdf'] = 'asdf' }.to raise_error
end
it "should return nil for empty profile fields" do
@mock_repository.should_receive(:object).with(:pid => 'pid').and_return("")
@object.profile['a'].should be_nil
end
end
describe "new" do
before(:each) do
@mock_repository.stub(:object) { raise "" }
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should be new" do
@object.new?.should == true
end
it "should call ingest on save" do
@object.stub(:datastreams) { {} }
@mock_repository.should_receive(:ingest).with(hash_including(:pid => 'pid')).and_return('pid')
@object.save
end
it "should create a new Fedora object with a generated PID if no PID is provided" do
object = Rubydora::DigitalObject.new nil, @mock_repository
@mock_repository.should_receive(:ingest).with(hash_including(:pid => nil)).and_return('pid')
@mock_repository.should_receive(:datastreams).with(hash_including(:pid => 'pid')).and_raise(RestClient::ResourceNotFound)
object.save
object.pid.should == 'pid'
end
end
describe "create" do
it "should call the Fedora REST API to create a new object" do
@mock_repository.should_receive(:ingest).with(instance_of(Hash)).and_return("pid")
obj = Rubydora::DigitalObject.create "pid", { :a => 1, :b => 2}, @mock_repository
obj.should be_a_kind_of(Rubydora::DigitalObject)
end
it "should return a new object with the Fedora response pid when no pid is provided" do
@mock_repository.should_receive(:ingest).with(instance_of(Hash)).and_return("pid")
obj = Rubydora::DigitalObject.create "new", { :a => 1, :b => 2}, @mock_repository
obj.should be_a_kind_of(Rubydora::DigitalObject)
obj.pid.should == "pid"
end
end
describe "retreive" do
before(:each) do
@mock_repository.stub :datastreams do |hash|
">>"
end
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
describe "datastreams" do
it "should provide a hash populated by the existing datastreams" do
@object.datastreams.should have_key("a")
@object.datastreams.should have_key("b")
@object.datastreams.should have_key("c")
end
it "should allow other datastreams to be added" do
@mock_repository.should_receive(:datastream).with(:pid => 'pid', :dsid => 'z').and_raise(RestClient::ResourceNotFound)
@object.datastreams.length.should == 3
ds = @object.datastreams["z"]
ds.should be_a_kind_of(Rubydora::Datastream)
ds.new?.should == true
@object.datastreams.length.should == 4
end
it "should let datastreams be accessed via hash notation" do
@object['a'].should be_a_kind_of(Rubydora::Datastream)
@object['a'].should == @object.datastreams['a']
end
it "should provide a way to override the type of datastream object to use" do
class MyCustomDatastreamClass < Rubydora::Datastream; end
object = Rubydora::DigitalObject.new 'pid', @mock_repository
object.stub(:datastream_object_for) do |dsid|
MyCustomDatastreamClass.new(self, dsid)
end
object.datastreams['asdf'].should be_a_kind_of(MyCustomDatastreamClass)
end
end
end
describe "update" do
before(:each) do
@mock_repository.stub(:object) { <<-XML
label
XML
}
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should not say changed if the value is set the same" do
@object.label = "label"
@object.should_not be_changed
end
end
describe "retrieve" do
end
describe "save" do
before(:each) do
@mock_repository.stub(:object) { <<-XML
empty
XML
}
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
describe "saving an object's datastreams" do
before do
@new_ds = mock(Rubydora::Datastream)
@new_ds.stub(:new? => true, :changed? => true, :content_changed? => true, :content => 'XXX')
@new_empty_ds = mock(Rubydora::Datastream)
@new_empty_ds.stub(:new? => true, :changed? => false, :content_changed? => false, :content => nil)
@existing_ds = mock(Rubydora::Datastream)
@existing_ds.stub(:new? => false, :changed? => false, :content_changed? => false, :content => 'YYY')
@changed_attr_ds = mock(Rubydora::Datastream)
@changed_attr_ds.stub(:new? => false, :changed? => true, :content_changed? => false, :content => 'YYY')
@changed_ds = mock(Rubydora::Datastream)
@changed_ds.stub(:new? => false, :changed? => true, :content_changed? => true, :content => 'ZZZ')
@changed_empty_ds = mock(Rubydora::Datastream)
@changed_empty_ds.stub(:new? => false, :changed? => true, :content_changed? => true, :content => nil)
end
it "should save a new datastream with content" do
@object.stub(:datastreams) { { :new_ds => @new_ds } }
@new_ds.should_receive(:save)
@object.save
end
it "should save a datastream whose content has changed" do
@object.stub(:datastreams) { { :changed_ds => @changed_ds } }
@changed_ds.should_receive(:save)
@object.save
end
it "should save a datastream whose attributes have changed" do
@object.stub(:datastreams) { { :changed_attr_ds => @changed_attr_ds } }
@changed_attr_ds.should_receive(:save)
@object.save
end
it "should save an existing datastream whose content is nil" do
@object.stub(:datastreams) { { :changed_empty_ds => @changed_empty_ds } }
@changed_empty_ds.should_receive(:save)
@object.save
end
it "should not save a datastream that is unchanged" do
@object.stub(:datastreams) { { :existing_ds => @existing_ds } }
@existing_ds.should_not_receive(:save)
@object.save
end
it "should not save a new datastream that never received content" do
@object.stub(:datastreams) { { :new_empty_ds => @new_empty_ds } }
@new_empty_ds.should_not_receive(:save)
@object.save
end
end
it "should save all changed attributes" do
@object.label = "asdf"
@object.should_receive(:datastreams).and_return({})
@mock_repository.should_receive(:modify_object).with(hash_including(:pid => 'pid'))
@object.save
end
end
describe "delete" do
before(:each) do
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should call the Fedora REST API" do
@mock_repository.should_receive(:purge_object).with({:pid => 'pid'})
@object.delete
end
end
describe "models" do
before(:each) do
@mock_repository.stub(:object) { <<-XML
XML
}
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should add models to fedora" do
@mock_repository.should_receive(:add_relationship) do |params|
params.should have_key(:subject)
params[:predicate].should == 'info:fedora/fedora-system:def/model#hasModel'
params[:object].should == 'asdf'
end
@object.models << "asdf"
end
it "should remove models from fedora" do
@object.should_receive(:profile).any_number_of_times.and_return({"objModels" => ['asdf']})
@mock_repository.should_receive(:purge_relationship) do |params|
params.should have_key(:subject)
params[:predicate].should == 'info:fedora/fedora-system:def/model#hasModel'
params[:object].should == 'asdf'
end
@object.models.delete("asdf")
end
it "should be able to handle complete model replacemenet" do
@object.should_receive(:profile).any_number_of_times.and_return({"objModels" => ['asdf']})
@mock_repository.should_receive(:add_relationship).with(instance_of(Hash))
@mock_repository.should_receive(:purge_relationship).with(instance_of(Hash))
@object.models = '1234'
end
end
describe "relations" do
before(:each) do
@mock_repository.stub(:object) { <<-XML
XML
}
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should fetch related objects using sparql" do
@mock_repository.should_receive(:find_by_sparql_relationship).with('info:fedora/pid', 'info:fedora/fedora-system:def/relations-external#hasPart').and_return([1])
@object.parts.should == [1]
end
it "should add related objects" do
@mock_repository.should_receive(:add_relationship) do |params|
params.should have_key(:subject)
params[:predicate].should == 'info:fedora/fedora-system:def/relations-external#hasPart'
params[:object].should == 'asdf'
end
@mock_object = mock(Rubydora::DigitalObject)
@mock_object.should_receive(:fqpid).and_return('asdf')
@mock_repository.should_receive(:find_by_sparql_relationship).with('info:fedora/pid', 'info:fedora/fedora-system:def/relations-external#hasPart').and_return([])
@object.parts << @mock_object
end
it "should remove related objects" do
@mock_repository.should_receive(:purge_relationship) do |params|
params.should have_key(:subject)
params[:predicate].should == 'info:fedora/fedora-system:def/relations-external#hasPart'
params[:object].should == 'asdf'
end
@mock_object = mock(Rubydora::DigitalObject)
@mock_object.should_receive(:fqpid).and_return('asdf')
@mock_repository.should_receive(:find_by_sparql_relationship).with('info:fedora/pid', 'info:fedora/fedora-system:def/relations-external#hasPart').and_return([@mock_object])
@object.parts.delete(@mock_object)
end
end
describe "versions" do
before(:each) do
@mock_repository.stub(:object) { <<-XML
XML
}
@mock_repository.stub(:object_versions) { <<-XML
2011-09-26T20:41:02.450Z
2011-10-11T21:17:48.124Z
XML
}
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should have a list of previous versions" do
@object.versions.should have(2).items
@object.versions.first.asOfDateTime.should == '2011-09-26T20:41:02.450Z'
end
it "should access versions as read-only copies" do
expect { @object.versions.first.label = "asdf" }.to raise_error
end
it "should lookup content of datastream using the asOfDateTime parameter" do
@mock_repository.should_receive(:datastreams).with(hash_including(:asOfDateTime => '2011-09-26T20:41:02.450Z')).and_return('')
Rubydora::Datastream.should_receive(:new).with(anything, 'my_ds', hash_including(:asOfDateTime => '2011-09-26T20:41:02.450Z'))
ds = @object.versions.first['my_ds']
end
end
describe "to_api_params" do
before(:each) do
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
end
it "should compile parameters to hash" do
@object.send(:to_api_params).should == {}
end
end
shared_examples "an object attribute" do
subject { Rubydora::DigitalObject.new 'pid', @mock_repository }
describe "getter" do
it "should return the value" do
subject.instance_variable_set("@#{method}", 'asdf')
subject.send(method).should == 'asdf'
end
it "should look in the object profile" do
subject.should_receive(:profile) { { Rubydora::DigitalObject::OBJ_ATTRIBUTES[method.to_sym].to_s => 'qwerty' } }
subject.send(method).should == 'qwerty'
end
it "should fall-back to the set of default attributes" do
Rubydora::DigitalObject::OBJ_DEFAULT_ATTRIBUTES.should_receive(:[]).with(method.to_sym) { 'zxcv'}
subject.send(method).should == 'zxcv'
end
end
describe "setter" do
before do
subject.stub(:datastreams => [])
end
it "should mark the object as changed after setting" do
subject.send("#{method}=", 'new_value')
subject.should be_changed
end
it "should not mark the object as changed if the value does not change" do
subject.should_receive(method) { 'zxcv' }
subject.send("#{method}=", 'zxcv')
end
it "should appear in the save request" do
@mock_repository.should_receive(:ingest).with(hash_including(method.to_sym => 'new_value'))
subject.send("#{method}=", 'new_value')
subject.save
end
end
end
describe "#state" do
it_behaves_like "an object attribute"
let(:method) { 'state' }
end
describe "#ownerId" do
it_behaves_like "an object attribute"
let(:method) { 'ownerId' }
end
describe "#label" do
it_behaves_like "an object attribute"
let(:method) { 'label' }
end
describe "#logMessage" do
it_behaves_like "an object attribute"
let(:method) { 'logMessage' }
end
describe "#lastModifiedDate" do
it_behaves_like "an object attribute"
let(:method) { 'lastModifiedDate' }
end
end