require 'spec_helper'
describe Rubydora::DigitalObject do
before do
@mock_repository = Rubydora::Fc3Service.new({})
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
it "should throw exceptions that arise" do
@mock_repository.should_receive(:object).with(:pid => 'pid').and_raise(Net::HTTPBadResponse)
expect { @object.profile }.to raise_error(Net::HTTPBadResponse)
end
end
describe "initialize" do
before(:each) do
@mock_repository.stub(:object) { raise RestClient::ResourceNotFound }
end
subject { Rubydora::DigitalObject.new 'pid', @mock_repository }
it "should load a DigitalObject instance" do
expect(subject).to be_a_kind_of(Rubydora::DigitalObject)
end
it "should be new" do
expect(subject).to be_new
end
it "should be new_record" do
expect(subject).to be_new_record
end
it "should call ingest on save" do
subject.stub(:datastreams) { {} }
expect(@mock_repository).to receive(:ingest).with(hash_including(:pid => 'pid')).and_return('pid')
subject.save
end
describe "without a provided pid" do
subject { Rubydora::DigitalObject.new nil, @mock_repository }
it "should create a new Fedora object with a generated PID if no PID is provided" do
@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)
subject.save
subject.pid.should == 'pid'
end
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
@object.stub(:new_record? => false)
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 = double(Rubydora::Datastream)
@new_ds.stub(:new? => true, :changed? => true, :content_changed? => true, :content => 'XXX')
@new_empty_ds = double(Rubydora::Datastream)
@new_empty_ds.stub(:new? => true, :changed? => false, :content_changed? => false, :content => nil)
@existing_ds = double(Rubydora::Datastream)
@existing_ds.stub(:new? => false, :changed? => false, :content_changed? => false, :content => 'YYY')
@changed_attr_ds = double(Rubydora::Datastream)
@changed_attr_ds.stub(:new? => false, :changed? => true, :content_changed? => false, :content => 'YYY')
@changed_ds = double(Rubydora::Datastream)
@changed_ds.stub(:new? => false, :changed? => true, :content_changed? => true, :content => 'ZZZ')
@changed_empty_ds = double(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.stub(:profile).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.stub(:profile).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 = double(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 = double(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
@mock_repository.should_receive(:object).with(:pid=>"pid").and_raise(RestClient::ResourceNotFound)
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
@mock_repository.should_receive(:object).with(:pid=>"pid").and_raise(RestClient::ResourceNotFound)
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'))
@mock_repository.should_receive(:object).with(:pid=>"pid").and_raise(RestClient::ResourceNotFound)
subject.send("#{method}=", 'new_value')
subject.save
end
end
end
describe "#state" do
subject { Rubydora::DigitalObject.new 'pid', @mock_repository }
describe "getter" do
it "should return the value" do
subject.instance_variable_set("@state", 'asdf')
subject.state.should == 'asdf'
end
it "should look in the object profile" do
subject.should_receive(:profile) { { Rubydora::DigitalObject::OBJ_ATTRIBUTES[:state].to_s => 'qwerty' } }
subject.state.should == 'qwerty'
end
it "should fall-back to the set of default attributes" do
@mock_repository.should_receive(:object).with(:pid=>"pid").and_raise(RestClient::ResourceNotFound)
Rubydora::DigitalObject::OBJ_DEFAULT_ATTRIBUTES.should_receive(:[]).with(:state) { 'zxcv'}
subject.state.should == 'zxcv'
end
end
describe "setter" do
before do
subject.stub(:datastreams => [])
end
it "should mark the object as changed after setting" do
@mock_repository.should_receive(:object).with(:pid=>"pid").and_raise(RestClient::ResourceNotFound)
subject.state= 'D'
subject.should be_changed
end
it "should raise an error when setting an invalid value" do
expect {subject.state= 'Q'}.to raise_error ArgumentError, "Allowed values for state are 'I', 'A' and 'D'. You provided 'Q'"
end
it "should not mark the object as changed if the value does not change" do
subject.should_receive(:state) { 'A' }
subject.state= 'A'
subject.should_not be_changed
end
it "should appear in the save request" do
@mock_repository.should_receive(:ingest).with(hash_including(:state => 'A'))
@mock_repository.should_receive(:object).with(:pid=>"pid").and_raise(RestClient::ResourceNotFound)
subject.state='A'
subject.save
end
end
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
describe "#createdDate" do
it_behaves_like "an object attribute"
let(:method) { 'createdDate' }
end
end