Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions lib/rdf/spec/mutable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,42 @@
end
end
end

describe '#apply_changeset' do
let(:changeset) { RDF::Changeset.new }

it 'is a no-op when changeset is empty' do
expect { subject.apply_changeset(changeset) }
.not_to change { subject.statements }
end

it 'inserts statements' do
changeset.insert(*non_bnode_statements)

expect { subject.apply_changeset(changeset) }
.to change { subject.statements }
.to contain_exactly(*non_bnode_statements)
end

it 'deletes statements' do
subject.insert(*non_bnode_statements)
deletes = non_bnode_statements.take(10)

changeset.delete(*deletes)
subject.apply_changeset(changeset)

expect(subject).not_to include(*deletes)
end

it 'deletes before inserting' do
statement = non_bnode_statements.first

changeset.insert(statement)
changeset.delete(statement)
subject.apply_changeset(changeset)

expect(subject).to include(statement)
end
end
end
end
26 changes: 25 additions & 1 deletion lib/rdf/spec/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

it_behaves_like 'an RDF::Mutable'
end

# FIXME: This should be condition on the repository being mutable
context "as a durable repository" do
require 'rdf/spec/durable'
Expand All @@ -55,4 +55,28 @@

it_behaves_like 'an RDF::Durable'
end

context "with snapshot support" do
it 'returns a queryable #snapshot' do
if repository.supports? :snapshots
expect(repository.snapshot).to be_a RDF::Queryable
end
end

it 'gives an accurate snapshot' do
if repository.supports? :snapshots
snap = repository.snapshot
expect(snap.query([:s, :p, :o]))
.to contain_exactly(*repository.query([:s, :p, :o]))
end
end

it 'gives static snapshot' do
if repository.supports? :snapshots
snap = repository.snapshot
expect { repository.clear }
.not_to change { snap.query([:s, :p, :o]).to_a }
end
end
end
end
211 changes: 106 additions & 105 deletions lib/rdf/spec/transaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,153 +6,154 @@
shared_examples "an RDF::Transaction" do |klass|
include RDF::Spec::Matchers

subject { klass.new(graph_name: RDF::URI("name")) }
before do
raise 'repository must be set with `let(:repository)' unless
defined? repository
end

describe "#initialize" do
subject {klass}
it "accepts a graph" do
g = double("graph")
this = subject.new(graph: g)
expect(this.graph).to eq g
subject { klass.new(repository, mutable: true) }

it { is_expected.to be_readable }
it { is_expected.to be_queryable }

context "when querying statements" do
require 'rdf/spec/queryable'
let(:queryable) do
repository.insert(*RDF::Spec.quads)
q = klass.new(repository, mutable: true)
end
it_behaves_like 'an RDF::Queryable'
end

it "accepts a graph_name" do
c = double("graph_name")
this = subject.new(graph: c)
expect(this.graph).to eq c
expect(this.graph_name).to eq c
describe "#initialize" do
it 'accepts a repository' do
repo = double('repository')
allow(repo).to receive_messages(:supports? => false)

this = subject.new(graph_name: c)
expect(this.graph).to eq c
expect(this.graph_name).to eq c
expect(klass.new(repo).repository).to eq repo
end

it "accepts inserts" do
g = double("inserts")
this = subject.new(insert: g)
expect(this.inserts).to eq g
it 'defaults immutable (read only)' do
expect(klass.new(repository).mutable?).to be false
end

it "accepts deletes" do
g = double("deletes")
this = subject.new(delete: g)
expect(this.deletes).to eq g
it 'allows mutability' do
expect(klass.new(repository, mutable: true)).to be_mutable
end
end

its(:deletes) {is_expected.to be_a(RDF::Enumerable)}
its(:inserts) {is_expected.to be_a(RDF::Enumerable)}
it {is_expected.to be_mutable}
it {is_expected.to_not be_readable}

it "does not respond to #load" do
expect {subject.load("http://example/")}.to raise_error(NoMethodError)
expect { subject.load("http://example/") }.to raise_error(NoMethodError)
end

it "does not respond to #update" do
expect {subject.update(RDF::Statement.new)}.to raise_error(NoMethodError)
expect { subject.update(RDF::Statement.new) }.to raise_error(NoMethodError)
end

it "does not respond to #clear" do
expect {subject.clear}.to raise_error(NoMethodError)
expect { subject.clear }.to raise_error(NoMethodError)
end

describe "#execute" do
let(:s) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"))}
let(:r) {double("repository")}

it "deletes statements" do
statement = s.dup
statement.graph_name = (subject.graph_name rescue nil)
expect(r).to receive(:delete).with(statement)
expect(r).not_to receive(:insert)
subject.delete(s)
subject.execute(r)
describe '#buffered?' do
it 'is false when changeset is empty' do
expect(subject).not_to be_buffered
end
end

it "inserts statements" do
statement = s.dup
statement.graph_name = (subject.graph_name rescue nil)
expect(r).not_to receive(:delete)
expect(r).to receive(:insert).with(statement)
subject.insert(s)
subject.execute(r)
describe '#changes' do
it 'is a changeset' do
expect(subject.changes).to be_a RDF::Changeset
end

context 'with graph names' do
let(:s) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"))}
let(:s_with_c) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"), graph_name: RDF::URI('c_st'))}

it "deletes statements" do
statement = s.dup
statement.graph_name = subject.graph_name
expect(r).to receive(:delete).with(statement, s_with_c)
expect(r).not_to receive(:insert)
subject.delete(s)
subject.delete(s_with_c)
subject.execute(r)
end

it "inserts statements" do
statement = s.dup
statement.graph_name = subject.graph_name
expect(r).not_to receive(:delete)
expect(r).to receive(:insert).with(statement, s_with_c)
subject.insert(s)
subject.insert(s_with_c)
subject.execute(r)
end
it 'is initially empty' do
expect(subject.changes).to be_empty
end
end

describe "#delete" do
let(:st) { RDF::Statement(:s, RDF::URI('p'), 'o') }

it 'adds to deletes' do
subject.repository.insert(st)

it "calls before_execute" do
is_expected.to receive(:before_execute).with(r, {})
subject.execute(r)
expect do
subject.delete(st)
subject.execute
end.to change { subject.repository.empty? }.from(false).to(true)
end

it "calls after_execute" do
is_expected.to receive(:after_execute).with(r, {})
subject.execute(r)
it 'adds multiple to deletes' do
sts = [st] << RDF::Statement(:x, RDF::URI('y'), 'z')
subject.repository.insert(*sts)

expect do
subject.delete(*sts)
subject.execute
end.to change { subject.repository.empty? }.from(false).to(true)
end

it "returns self" do
expect(subject.execute(r)).to eq subject
it 'adds enumerable to deletes' do
sts = [st] << RDF::Statement(:x, RDF::URI('y'), 'z')
sts.extend(RDF::Enumerable)
subject.repository.insert(sts)

expect do
subject.delete(sts)
subject.execute
end.to change { subject.repository.empty? }.from(false).to(true)
end
end

describe "#delete_statement" do
let(:s) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"))}
it "adds statement to #deletes" do
subject.delete(s)
expect(subject.deletes.to_a).to eq [s]
describe "#insert" do
let(:st) { RDF::Statement(:s, RDF::URI('p'), 'o') }

it 'adds to inserts' do
expect do
subject.insert(st)
subject.execute
end.to change { subject.repository.statements }
.to contain_exactly(st)
end
end

describe "#insert_statement" do
let(:s) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"))}
it "adds statement to #inserts" do
subject.insert(s)
expect(subject.inserts.to_a).to eq [s]
it 'adds multiple to inserts' do
sts = [st] << RDF::Statement(:x, RDF::URI('y'), 'z')

expect do
subject.insert(*sts)
subject.execute
end.to change { subject.repository.statements }
.to contain_exactly(*sts)
end

it 'adds enumerable to inserts' do
sts = [st] << RDF::Statement(:x, RDF::URI('y'), 'z')
sts.extend(RDF::Enumerable)

expect do
subject.insert(sts)
subject.execute
end.to change { subject.repository.statements }
.to contain_exactly(*sts)
end
end

context 'with graph names' do
let(:s) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"))}
let(:s_with_c) {RDF::Statement.new(RDF::URI("s"), RDF::URI("p"), RDF::URI("o"), graph_name: RDF::URI('c_st'))}
describe '#execute' do
context 'after rollback' do
before { subject.rollback }

describe "#delete_statement" do
it "adds statement to #deletes" do
subject.delete(s)
subject.delete(s_with_c)
expect(subject.deletes.to_a).to contain_exactly(s, s_with_c)
it 'does not execute' do
expect { subject.execute }
.to raise_error RDF::Transaction::TransactionError
end
end
end

describe "#insert_statement" do
it "adds statement to #inserts" do
subject.insert(s)
subject.insert(s_with_c)
expect(subject.inserts.to_a).to contain_exactly(s, s_with_c)
end
describe '#rollback' do
before { subject.insert(st); subject.delete(st) }
let(:st) { RDF::Statement(:s, RDF::URI('p'), 'o') }

it 'empties changes when available' do
expect { subject.rollback }.to change { subject.changes }.to be_empty
end
end
end
Expand Down