spec/unit/identifier_spec.rb in ezid-client-1.3.0 vs spec/unit/identifier_spec.rb in ezid-client-1.4.0

- old
+ new

@@ -1,283 +1,349 @@ module Ezid RSpec.describe Identifier do - - describe ".create" do - let(:attrs) { {shoulder: TEST_ARK_SHOULDER, profile: "dc", target: "http://example.com"} } - it "instantiates a new Identifier and saves it" do - expect(described_class).to receive(:new).with(attrs).and_call_original - expect_any_instance_of(described_class).to receive(:save) { double } - described_class.create(attrs) + describe "class methods" do + describe ".create" do + let(:args) { ["id", {profile: "dc", target: "http://example.com"}] } + it "instantiates a new Identifier and saves it" do + expect_any_instance_of(described_class).to receive(:save) { double(id: "id") } + described_class.create(*args) + end end - end - - describe ".find" do - it "instantiates a new identifier and loads the metadata" do - expect(described_class).to receive(:new).with(id: "id").and_call_original - expect_any_instance_of(described_class).to receive(:load_metadata) { double } - described_class.find("id") + describe ".mint" do + let(:attrs) { {profile: "dc", target: "http://example.com"} } + let(:args) { [TEST_ARK_SHOULDER, attrs] } + it "instantiates a new Identifier and saves it" do + expect_any_instance_of(described_class).to receive(:save) { double(id: "id") } + described_class.mint(*args) + end end - end - - describe ".defaults" do - before { @original_defaults = described_class.defaults } - after { described_class.defaults = @original_defaults } - it "can be set via client config" do - Client.config.identifier.defaults = {status: "reserved"} - expect(described_class.defaults).to eq({status: "reserved"}) + describe ".modify" do + let(:args) { ["id", {profile: "dc", target: "http://example.com"}] } + it "instantiates a new Indentifier and modifies it" do + expect_any_instance_of(described_class).not_to receive(:save) + expect_any_instance_of(described_class).to receive(:modify!) + described_class.modify(*args) + end end + describe ".find" do + it "instantiates a new identifier and loads the metadata" do + expect_any_instance_of(described_class).to receive(:id=).with("id").and_call_original + expect_any_instance_of(described_class).to receive(:load_metadata) { + double(id: "id", metadata: nil) + } + described_class.find("id") + end + end + describe ".defaults" do + before { @original_defaults = described_class.defaults } + after { described_class.defaults = @original_defaults } + it "can be set via client config" do + Client.config.identifier.defaults = {status: "reserved"} + expect(described_class.defaults).to eq({status: "reserved"}) + end + end end - describe "#initialize" do - describe "with metadata" do - describe "via the :metadata argument" do - subject { described_class.new(metadata: "_profile: dc\n_target: http://example.com") } - it "sets the metadata" do - expect(subject.profile).to eq("dc") - expect(subject.target).to eq("http://example.com") + describe "instance methods" do + describe "#initialize" do + before { + allow(described_class).to receive(:defaults) { defaults } + } + let(:defaults) { {} } + describe "with no arguments" do + its(:id) { is_expected.to be_nil } + describe "and no default metadata" do + its(:metadata) { is_expected.to be_empty } end + describe "and with default metadata" do + let(:defaults) { {export: "no"} } + its(:metadata) { is_expected.to eq({"_export"=>"no"}) } + end end - describe "via keyword arguments" do - subject { described_class.new(profile: "dc", target: "http://example.com") } - it "sets the metadata" do - expect(subject.profile).to eq("dc") - expect(subject.target).to eq("http://example.com") + describe "with an id and no metadata" do + subject { described_class.new("id") } + its(:id) { is_expected.to eq("id") } + describe "and no default metadata" do + its(:metadata) { is_expected.to be_empty } end + describe "and with default metadata" do + let(:defaults) { {export: "no"} } + its(:metadata) { is_expected.to eq({"_export"=>"no"}) } + end end - end - describe "default metadata" do - before do - allow(described_class).to receive(:defaults) { {profile: "dc", status: "reserved"} } + describe "with an id and metadata" do + subject { described_class.new("id", metadata: "_profile: dc\n_target: http://example.com", status: "reserved") } + its(:id) { is_expected.to eq("id") } + describe "and no default metadata" do + its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved") } + end + describe "and with default metadata" do + let(:defaults) { {export: "no", status: "public"} } + its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved", "_export"=>"no") } + end end - it "sets the default metadata" do - expect(subject.profile).to eq("dc") - expect(subject.status).to eq("reserved") - end - context "when explicit arguments override the defaults" do - subject { described_class.new(shoulder: TEST_ARK_SHOULDER, status: "public") } - it "overrides the defaults" do - expect(subject.profile).to eq("dc") - expect(subject.status).to eq("public") + describe "with only metadata" do + subject { described_class.new(metadata: "_profile: dc\n_target: http://example.com", status: "reserved") } + its(:id) { is_expected.to be_nil } + describe "and no default metadata" do + its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved") } end + describe "and with default metadata" do + let(:defaults) { {export: "no", status: "public"} } + its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved", "_export"=>"no") } + end end end - end - describe "#update" do - let(:metadata) { {"status" => "unavailable"} } - subject { described_class.new(id: "id") } - it "updates the metadata and saves" do - expect(subject).to receive(:update_metadata).with(metadata) - expect(subject).to receive(:save) { double } - subject.update(metadata) + describe "#update" do + let(:metadata) { {"status" => "unavailable"} } + subject { described_class.new(id: "id") } + it "updates the metadata and saves" do + expect(subject).to receive(:update_metadata).with(metadata) + expect(subject).to receive(:save) { double } + subject.update(metadata) + end end - end - describe "#update_metadata" do - it "updates the metadata" do - subject.update_metadata(:status => "public", _target: "localhost", "dc.creator" => "Me") - expect(subject.metadata.to_h).to eq({"_status"=>"public", "_target"=>"localhost", "dc.creator"=>"Me"}) + describe "#modify!" do + describe "when the Identifier has no id" do + specify { + expect { subject.modify! }.to raise_error(Error) + } + end + describe "when the Identifier has an id" do + specify { + subject.id = "id" + expect(subject).not_to receive(:save) + expect(subject).to receive(:modify) + subject.modify! + } + describe "when the identifier does not exist" do + specify { + subject.id = "id" + allow(subject.client).to receive(:modify_identifier).and_raise(IdentifierNotFoundError) + expect { subject.modify! }.to raise_error(IdentifierNotFoundError) + } + end + end end - end - describe "#load_metadata" do - let(:metadata) { "_profile: erc" } - before { allow(subject).to receive(:id) { "id" } } - it "initializes the metadata from EZID" do - expect(subject.client).to receive(:get_identifier_metadata).with("id") { double(id: "id", metadata: metadata) } - expect(Metadata).to receive(:new).with(metadata) - subject.load_metadata + describe "#update_metadata" do + it "updates the metadata" do + subject.update_metadata(:status => "public", _target: "localhost", "dc.creator" => "Me") + expect(subject.metadata.to_h).to eq({"_status"=>"public", "_target"=>"localhost", "dc.creator"=>"Me"}) + end end - end - describe "#reset" do - before { subject.metadata = Metadata.new(status: "public") } - it "clears the local metadata" do - expect { subject.reset }.to change { subject.metadata.empty? }.from(false).to(true) + describe "#load_metadata" do + let(:metadata) { "_profile: erc" } + before { allow(subject).to receive(:id) { "id" } } + it "replaces the remote metadata with metadata from EZID" do + expect(subject.client).to receive(:get_identifier_metadata).with("id") { double(id: "id", metadata: metadata) } + expect(subject.remote_metadata).to receive(:replace).with(metadata) + subject.load_metadata + end end - end - describe "#persisted?" do - describe "after initialization" do - it { is_expected.not_to be_persisted } - end - describe "when saving an unpersisted object" do - before { allow(subject).to receive(:create_or_mint) { nil } } - it "marks it as persisted" do - expect { subject.save }.to change(subject, :persisted?).from(false).to(true) + describe "#reset_metadata" do + before { + subject.status = "public" + subject.remote_metadata.profile = "dc" + } + it "clears the local metadata" do + expect { subject.reset_metadata } + .to change { subject.metadata.empty? } + .from(false).to(true) end + it "clears the remote metadata" do + expect { subject.reset_metadata } + .to change { subject.remote_metadata.empty? } + .from(false).to(true) + end end - describe "when saving a persisted object" do - before do - allow(subject).to receive(:persisted?) { true } - allow(subject).to receive(:modify) { nil } + + describe "#persisted?" do + describe "after initialization" do + it { is_expected.not_to be_persisted } end - it "does not change the persisted status" do - expect { subject.save }.not_to change(subject, :persisted?) + describe "when saving an unpersisted object" do + before { + allow(subject.client).to receive(:mint_identifier) { double(id: "id") } + subject.save + } + it { is_expected.to be_persisted } end + describe "when saving a persisted object" do + before do + allow(subject).to receive(:persisted?) { true } + allow(subject).to receive(:modify) { nil } + end + it "does not change the persisted status" do + expect { subject.save }.not_to change(subject, :persisted?) + end + end end - end - describe "#delete" do - context "when the identifier is reserved" do - subject { described_class.new(id: "id", status: Status::RESERVED) } - context "and is persisted" do - before { allow(subject).to receive(:persisted?) { true } } - it "deletes the identifier" do - expect(subject.client).to receive(:delete_identifier).with("id") { double(id: "id") } - subject.delete - expect(subject).to be_deleted + describe "#delete" do + context "when the identifier is reserved" do + subject { described_class.new("id", status: Status::RESERVED) } + context "and is persisted" do + before { allow(subject).to receive(:persisted?) { true } } + it "deletes the identifier" do + expect(subject.client).to receive(:delete_identifier).with("id") { double(id: "id") } + subject.delete + expect(subject).to be_deleted + end end + context "and is not persisted" do + before { allow(subject).to receive(:persisted?) { false } } + it "raises an exception" do + expect { subject.delete }.to raise_error(Error) + end + end end - context "and is not persisted" do - before { allow(subject).to receive(:persisted?) { false } } + context "when identifier is not reserved" do + subject { described_class.new(id: "id", status: Status::PUBLIC) } it "raises an exception" do expect { subject.delete }.to raise_error(Error) end end end - context "when identifier is not reserved" do - subject { described_class.new(id: "id", status: Status::PUBLIC) } - it "raises an exception" do - expect { subject.delete }.to raise_error(Error) - end - end - end - describe "#save" do - context "when the identifier is persisted" do - let(:metadata) { Metadata.new } - before do - allow(subject).to receive(:id) { "id" } - allow(subject).to receive(:persisted?) { true } - allow(subject).to receive(:metadata) { metadata } - end - it "modifies the identifier" do - expect(subject.client).to receive(:modify_identifier).with("id", metadata) { double(id: "id") } - subject.save - end - end - context "when the identifier is not persisted" do - before do - allow(subject).to receive(:persisted?) { false } - end - context "and `id' is present" do - before { allow(subject).to receive(:id) { "id" } } - it "creates the identifier" do - expect(subject.client).to receive(:create_identifier).with("id", subject.metadata) { double(id: "id") } + describe "#save" do + context "when the identifier is persisted" do + let(:metadata) { Metadata.new } + before do + allow(subject).to receive(:id) { "id" } + allow(subject).to receive(:persisted?) { true } + allow(subject).to receive(:metadata) { metadata } + end + it "modifies the identifier" do + expect(subject.client).to receive(:modify_identifier).with("id", metadata) { double(id: "id") } subject.save end end - context "and `id' is not present" do - context "and `shoulder' is present" do - before { allow(subject).to receive(:shoulder) { TEST_ARK_SHOULDER } } - it "mints the identifier" do - expect(subject.client).to receive(:mint_identifier).with(TEST_ARK_SHOULDER, subject.metadata) { double(id: "id") } + context "when the identifier is not persisted" do + before do + allow(subject).to receive(:persisted?) { false } + end + context "and `id' is present" do + before { allow(subject).to receive(:id) { "id" } } + it "creates the identifier" do + expect(subject.client).to receive(:create_identifier).with("id", subject.metadata) { double(id: "id") } subject.save end end - context "and `shoulder' is not present" do - before { allow(Client.config).to receive(:default_shoulder) { nil } } - it "raises an exception" do - expect { subject.save }.to raise_error(Error) + context "and `id' is not present" do + context "and `shoulder' is present" do + before { allow(subject).to receive(:shoulder) { TEST_ARK_SHOULDER } } + it "mints the identifier" do + expect(subject.client).to receive(:mint_identifier).with(TEST_ARK_SHOULDER, subject.metadata) { double(id: "id") } + subject.save + end end + context "and `shoulder' is not present" do + before { allow(Client.config).to receive(:default_shoulder) { nil } } + it "raises an exception" do + expect { subject.save }.to raise_error(Error) + end + end end end end - end - describe "boolean status methods" do - context "when the identifier is public" do - before { subject.public! } - it { is_expected.to be_public } - it { is_expected.not_to be_reserved } - it { is_expected.not_to be_unavailable } - end - context "when the identifier is reserved" do - before { subject.status = Status::RESERVED } - it { is_expected.not_to be_public } - it { is_expected.to be_reserved } - it { is_expected.not_to be_unavailable } - end - context "when the identifier is unavailable" do - context "and it has no reason" do - before { subject.unavailable! } - it { is_expected.not_to be_public } + describe "boolean status methods" do + context "when the identifier is public" do + before { subject.public! } + it { is_expected.to be_public } it { is_expected.not_to be_reserved } - it { is_expected.to be_unavailable } + it { is_expected.not_to be_unavailable } end - context "and it has a reason" do - before { subject.unavailable!("withdrawn") } + context "when the identifier is reserved" do + before { subject.status = Status::RESERVED } it { is_expected.not_to be_public } - it { is_expected.not_to be_reserved } - it { is_expected.to be_unavailable } + it { is_expected.to be_reserved } + it { is_expected.not_to be_unavailable } end + context "when the identifier is unavailable" do + context "and it has no reason" do + before { subject.unavailable! } + it { is_expected.not_to be_public } + it { is_expected.not_to be_reserved } + it { is_expected.to be_unavailable } + end + context "and it has a reason" do + before { subject.unavailable!("withdrawn") } + it { is_expected.not_to be_public } + it { is_expected.not_to be_reserved } + it { is_expected.to be_unavailable } + end + end end - end - describe "status-changing methods" do - subject { described_class.new(id: "id", status: status) } - describe "#unavailable!" do - context "when the status is \"unavailable\"" do - let(:status) { "#{Status::UNAVAILABLE} | whatever" } - context "and no reason is given" do - it "logs a warning" do - pending "https://github.com/duke-libraries/ezid-client/issues/46" - allow_message_expectations_on_nil - expect(subject.logger).to receive(:warn) - subject.unavailable! + describe "status-changing methods" do + subject { described_class.new(id: "id", status: status) } + describe "#unavailable!" do + context "when the status is \"unavailable\"" do + let(:status) { "#{Status::UNAVAILABLE} | whatever" } + context "and no reason is given" do + it "logs a warning" do + pending "https://github.com/duke-libraries/ezid-client/issues/46" + allow_message_expectations_on_nil + expect(subject.logger).to receive(:warn) + subject.unavailable! + end + it "does not change the status" do + expect { subject.unavailable! }.not_to change(subject, :status) + end end - it "does not change the status" do - expect { subject.unavailable! }.not_to change(subject, :status) + context "and a reason is given" do + it "logs a warning" do + pending "https://github.com/duke-libraries/ezid-client/issues/46" + allow_message_expectations_on_nil + expect(subject.logger).to receive(:warn) + subject.unavailable!("because") + end + it "should change the status" do + expect { subject.unavailable!("because") }.to change(subject, :status).from(status).to("#{Status::UNAVAILABLE} | because") + end end end - context "and a reason is given" do - it "logs a warning" do - pending "https://github.com/duke-libraries/ezid-client/issues/46" - allow_message_expectations_on_nil - expect(subject.logger).to receive(:warn) - subject.unavailable!("because") + context "when the status is \"reserved\"" do + let(:status) { Status::RESERVED } + context "and persisted" do + before { allow(subject).to receive(:persisted?) { true } } + it "raises an exception" do + expect { subject.unavailable! }.to raise_error(Error) + end end - it "should change the status" do - expect { subject.unavailable!("because") }.to change(subject, :status).from(status).to("#{Status::UNAVAILABLE} | because") + context "and not persisted" do + before { allow(subject).to receive(:persisted?) { false } } + it "changes the status" do + expect { subject.unavailable! }.to change(subject, :status).from(Status::RESERVED).to(Status::UNAVAILABLE) + end end end - end - context "when the status is \"reserved\"" do - let(:status) { Status::RESERVED } - context "and persisted" do - before { allow(subject).to receive(:persisted?) { true } } - it "raises an exception" do - expect { subject.unavailable! }.to raise_error(Error) + context "when the status is \"public\"" do + let(:status) { Status::PUBLIC } + context "and no reason is given" do + it "changes the status" do + expect { subject.unavailable! }.to change(subject, :status).from(Status::PUBLIC).to(Status::UNAVAILABLE) + end end - end - context "and not persisted" do - before { allow(subject).to receive(:persisted?) { false } } - it "changes the status" do - expect { subject.unavailable! }.to change(subject, :status).from(Status::RESERVED).to(Status::UNAVAILABLE) + context "and a reason is given" do + it "changes the status and appends the reason" do + expect { subject.unavailable!("withdrawn") }.to change(subject, :status).from(Status::PUBLIC).to("#{Status::UNAVAILABLE} | withdrawn") + end end end end - context "when the status is \"public\"" do - let(:status) { Status::PUBLIC } - context "and no reason is given" do - it "changes the status" do - expect { subject.unavailable! }.to change(subject, :status).from(Status::PUBLIC).to(Status::UNAVAILABLE) - end + describe "#public!" do + subject { described_class.new(id: "id", status: Status::UNAVAILABLE) } + it "changes the status" do + expect { subject.public! }.to change(subject, :status).from(Status::UNAVAILABLE).to(Status::PUBLIC) end - context "and a reason is given" do - it "changes the status and appends the reason" do - expect { subject.unavailable!("withdrawn") }.to change(subject, :status).from(Status::PUBLIC).to("#{Status::UNAVAILABLE} | withdrawn") - end - end end end - describe "#public!" do - subject { described_class.new(id: "id", status: Status::UNAVAILABLE) } - it "changes the status" do - expect { subject.public! }.to change(subject, :status).from(Status::UNAVAILABLE).to(Status::PUBLIC) - end - end end - end end