rdf-spec 1.99.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/{README → README.md} +2 -0
  3. data/VERSION +1 -1
  4. data/lib/rdf/spec.rb +18 -0
  5. data/lib/rdf/spec/countable.rb +5 -28
  6. data/lib/rdf/spec/dataset.rb +47 -0
  7. data/lib/rdf/spec/durable.rb +8 -23
  8. data/lib/rdf/spec/enumerable.rb +118 -102
  9. data/lib/rdf/spec/format.rb +4 -26
  10. data/lib/rdf/spec/http_adapter.rb +1 -23
  11. data/lib/rdf/spec/indexable.rb +1 -23
  12. data/lib/rdf/spec/inferable.rb +0 -16
  13. data/lib/rdf/spec/inspects.rb +4 -5
  14. data/lib/rdf/spec/matchers.rb +95 -4
  15. data/lib/rdf/spec/mutable.rb +227 -81
  16. data/lib/rdf/spec/queryable.rb +122 -165
  17. data/lib/rdf/spec/readable.rb +0 -22
  18. data/lib/rdf/spec/reader.rb +21 -29
  19. data/lib/rdf/spec/repository.rb +80 -40
  20. data/lib/rdf/spec/transactable.rb +43 -0
  21. data/lib/rdf/spec/transaction.rb +294 -71
  22. data/lib/rdf/spec/version.rb +2 -2
  23. data/lib/rdf/spec/writable.rb +78 -100
  24. data/lib/rdf/spec/writer.rb +51 -28
  25. data/spec/countable_spec.rb +11 -0
  26. data/spec/dataset_spec.rb +14 -0
  27. data/spec/durable_spec.rb +12 -0
  28. data/spec/enumerable_spec.rb +11 -0
  29. data/spec/format_spec.rb +12 -0
  30. data/spec/http_adapter_spec.rb +15 -0
  31. data/spec/indexable.rb +15 -0
  32. data/spec/literal_spec.rb +75 -0
  33. data/spec/mutable_spec.rb +11 -0
  34. data/spec/queryable_spec.rb +13 -0
  35. data/spec/readable.rb +11 -0
  36. data/spec/reader_spec.rb +17 -0
  37. data/spec/repository_spec.rb +11 -0
  38. data/spec/spec_helper.rb +13 -0
  39. data/spec/transaction_spec.rb +7 -0
  40. data/spec/version_spec.rb +2 -0
  41. data/spec/writable_spec.rb +13 -0
  42. data/spec/writer_spec.rb +11 -0
  43. metadata +56 -12
@@ -13,21 +13,21 @@ RSpec.shared_examples 'an RDF::Format' do
13
13
  describe ".for" do
14
14
  RDF::Format.file_extensions.each do |ext, formats|
15
15
  it "detects #{formats.first} using file path foo.#{ext}" do
16
- expect(RDF::Format.for("foo.#{ext}")).to eq formats.first
16
+ expect(RDF::Format.for("foo.#{ext}")).to eq formats.last
17
17
  end
18
18
 
19
19
  it "detects #{formats.first} using file_name foo.#{ext}" do
20
- expect(RDF::Format.for(file_name: "foo.#{ext}")).to eq formats.first
20
+ expect(RDF::Format.for(file_name: "foo.#{ext}")).to eq formats.last
21
21
  end
22
22
 
23
23
  it "detects #{formats.first} using file_extension #{ext}" do
24
- expect(RDF::Format.for(file_extension: ext)).to eq formats.first
24
+ expect(RDF::Format.for(file_extension: ext)).to eq formats.last
25
25
  end
26
26
  end
27
27
 
28
28
  RDF::Format.content_types.each do |content_type, formats|
29
29
  it "detects #{formats.first} using content_type #{content_type}" do
30
- expect(RDF::Format.for(content_type: content_type)).to eq formats.first
30
+ expect(RDF::Format.for(content_type: content_type)).to eq formats.last
31
31
  end
32
32
  end
33
33
  end
@@ -51,25 +51,3 @@ RSpec.shared_examples 'an RDF::Format' do
51
51
  end
52
52
  end
53
53
  end
54
-
55
- ##
56
- # @deprecated use `it_behaves_like "an RDF::Format"` instead
57
- module RDF_Format
58
- extend RSpec::SharedContext
59
- include RDF::Spec::Matchers
60
-
61
- def self.included(mod)
62
- warn "[DEPRECATION] `RDF_Format` is deprecated. "\
63
- "Please use `it_behaves_like 'an RDF::Format'`"
64
- end
65
-
66
- describe 'examples for' do
67
- include_examples 'an RDF::Format' do
68
- let(:format_class) { @format_class }
69
-
70
- before do
71
- raise '@format_class must be defined' unless defined?(format_class)
72
- end
73
- end
74
- end
75
- end
@@ -214,7 +214,7 @@ RSpec.shared_examples 'an RDF::HttpAdapter' do
214
214
  end
215
215
  expect(WebMock).to have_requested(:get, uri)
216
216
  end
217
- end
217
+ end unless ENV['CI']
218
218
 
219
219
  context "https" do
220
220
  let(:uri) {"https://some/secure/uri"}
@@ -291,25 +291,3 @@ RSpec.shared_examples 'an RDF::HttpAdapter' do
291
291
  end
292
292
 
293
293
  end
294
-
295
- ##
296
- # @deprecated use `it_behaves_like "an RDF::HttpAdapter"` instead
297
- module RDF_HttpAdapter
298
- extend RSpec::SharedContext
299
- include RDF::Spec::Matchers
300
-
301
- def self.included(mod)
302
- warn "[DEPRECATION] `RDF_HttpAdapter` is deprecated. "\
303
- "Please use `it_behaves_like 'an RDF::HttpAdapter'`"
304
- end
305
-
306
- describe 'examples for' do
307
- include_examples 'an RDF::HttpAdapter' do
308
- let(:http_adapter) { @http_adapter }
309
-
310
- before do
311
- raise '@http_adapter must be defined' unless defined?(http_adapter)
312
- end
313
- end
314
- end
315
- end
@@ -18,28 +18,6 @@ RSpec.shared_examples 'an RDF::Indexable' do
18
18
  end
19
19
 
20
20
  it "returns self on #index!" do
21
- expect(subject.index!).to be
22
- end
23
- end
24
-
25
- ##
26
- # @deprecated use `it_behaves_like "an RDF::Indexable"` instead
27
- module RDF_Indexable
28
- extend RSpec::SharedContext
29
- include RDF::Spec::Matchers
30
-
31
- def self.included(mod)
32
- warn "[DEPRECATION] `RDF_Indexable` is deprecated. "\
33
- "Please use `it_behaves_like 'an RDF::Indexable'`"
34
- end
35
-
36
- describe 'examples for' do
37
- include_examples 'an RDF::Indexable' do
38
- let(:indexable) { @indexable }
39
-
40
- before do
41
- raise '@indexable must be defined' unless defined?(indexable)
42
- end
43
- end
21
+ expect(subject.index!).to eql(subject)
44
22
  end
45
23
  end
@@ -5,19 +5,3 @@ RSpec.shared_examples 'an RDF::Inferable' do
5
5
 
6
6
  it "is_expected.to implement specs" #TODO
7
7
  end
8
-
9
- ##
10
- # @deprecated use `it_behaves_like "an RDF::Inferable"` instead
11
- module RDF_Inferable
12
- extend RSpec::SharedContext
13
- include RDF::Spec::Matchers
14
-
15
- def self.included(mod)
16
- warn "[DEPRECATION] `RDF_Inferable` is deprecated. "\
17
- "Please use `it_behaves_like 'an RDF::Inferable'`"
18
- end
19
-
20
- describe 'examples for' do
21
- include_examples 'an RDF::Inferable'
22
- end
23
- end
@@ -1,28 +1,27 @@
1
1
  require 'rdf'
2
- require 'rdf/ntriples'
3
2
  # override several inspect functions to improve output for what we're doing
4
3
 
5
4
  class RDF::Literal
6
5
  def inspect
7
- RDF::NTriples::Writer.serialize(self) + " R:L:(#{self.class.to_s.match(/([^:]*)$/)})"
6
+ "\"#{escape(value)}\" R:L:(#{self.class.to_s.match(/([^:]*)$/)})"
8
7
  end
9
8
  end
10
9
 
11
10
  class RDF::URI
12
11
  def inspect
13
- RDF::NTriples::Writer.serialize(self)
12
+ "RDF::URI(#{to_base})"
14
13
  end
15
14
  end
16
15
 
17
16
  class RDF::Node
18
17
  def inspect
19
- RDF::NTriples::Writer.serialize(self) + "(#{object_id})"
18
+ "RDF::Node(#{to_base})"
20
19
  end
21
20
  end
22
21
 
23
22
  class RDF::Graph
24
23
  def inspect
25
- "\n" + dump(RDF.const_defined?(:Turtle) ? :ttl : :ntriples, standard_prefixes: true) + "\n"
24
+ "RDF::Graph(graph_name: #{self.graph_name || 'nil'})"
26
25
  end
27
26
  end
28
27
 
@@ -184,12 +184,18 @@ module RDF; module Spec
184
184
  end
185
185
  end
186
186
 
187
- RSpec::Matchers.define :write do |message|
188
- chain(:to) do |io|
189
- @io = io
187
+ RSpec::Matchers.define :write_each do |*messages|
188
+ supports_block_expectations { true }
189
+
190
+ match do |block|
191
+ messages.each { |message| expect(&block).to write(message) }
190
192
  end
193
+ end
191
194
 
192
- supports_block_expectations {true}
195
+ RSpec::Matchers.define :write do |message|
196
+ chain(:to) { |io| @io = io }
197
+
198
+ supports_block_expectations { true }
193
199
 
194
200
  match do |block|
195
201
  @output =
@@ -258,6 +264,91 @@ module RDF; module Spec
258
264
  {:output => "standard output", :error => "standard error"}[io]
259
265
  end
260
266
  end
267
+
268
+ Info = Struct.new(:id, :logger, :action, :result)
269
+
270
+ RSpec::Matchers.define :be_equivalent_graph do |expected, info|
271
+ match do |actual|
272
+ def normalize(graph)
273
+ case graph
274
+ when RDF::Enumerable then graph
275
+ when IO, StringIO
276
+ RDF::Repository.new(graph, base_uri: @info.action)
277
+ else
278
+ # Figure out which parser to use
279
+ r = RDF::Repository.new
280
+ reader_class = RDF::Reader.for() {graph}
281
+ reader_class.new(graph, base_uri: @info.action).each {|s| r << s}
282
+ r
283
+ end
284
+ end
285
+
286
+ @info = if (info.id rescue false)
287
+ info
288
+ elsif info.is_a?(Logger)
289
+ Info.new("", info)
290
+ elsif info.is_a?(Hash)
291
+ Info.new(info[:id], info[:logger], info[:action], info[:result])
292
+ else
293
+ Info.new(info)
294
+ end
295
+ @expected = normalize(expected)
296
+ @actual = normalize(actual)
297
+ @actual.isomorphic_with?(@expected) rescue false
298
+ end
299
+
300
+ failure_message do |actual|
301
+ format = case
302
+ when RDF.const_defined?(:TriG) then :trig
303
+ when RDF.const_defined?(:Turtle) then :ttl
304
+ else :nquads
305
+ end
306
+ info = @info.respond_to?(:information) ? @info.information : @info.inspect
307
+ if @expected.is_a?(RDF::Enumerable) && @actual.size != @expected.size
308
+ "Graph entry counts differ:\nexpected: #{@expected.size}\nactual: #{@actual.size}\n"
309
+ else
310
+ "Graphs differ\n"
311
+ end +
312
+ "\n#{info + "\n" unless info.empty?}" +
313
+ "Expected:\n#{@expected.dump(format, standard_prefixes: true, literal_shorthand: false, validate: false) rescue @expected.inspect}" +
314
+ "Results:\n#{@actual.dump(format, standard_prefixes: true, literal_shorthand: false, validate: false) rescue @actual.inspect}" +
315
+ "\nDebug:\n#{@info.logger}"
316
+ end
317
+ end
318
+
319
+ require 'json'
320
+ JSON_STATE = ::JSON::State.new(
321
+ indent: " ",
322
+ space: " ",
323
+ space_before: "",
324
+ object_nl: "\n",
325
+ array_nl: "\n"
326
+ )
327
+
328
+ RSpec::Matchers.define :produce do |expected, info|
329
+ match do |actual|
330
+ @info = if (info.id rescue false)
331
+ info
332
+ elsif info.is_a?(Logger)
333
+ Info.new("", info)
334
+ elsif info.is_a?(Hash)
335
+ Info.new(info[:id], info[:logger], info[:action], info[:result])
336
+ else
337
+ Info.new(info)
338
+ end
339
+ expect(actual).to eq expected
340
+ end
341
+
342
+ failure_message do |actual|
343
+ info = @info.respond_to?(:information) ? @info.information : @info.inspect
344
+
345
+ "Expected: #{expected.is_a?(String) ? expected : expected.to_json(JSON_STATE) rescue 'malformed json'}\n" +
346
+ "Actual : #{actual.is_a?(String) ? actual : actual.to_json(JSON_STATE) rescue 'malformed json'}\n" +
347
+ "\n#{info + "\n" unless info.empty?}" +
348
+ "\nDebug:\n#{@info.logger}"
349
+ end
350
+ end
351
+
261
352
  end # Matchers
262
353
  end; end # RDF::Spec
263
354
 
@@ -8,11 +8,15 @@ RSpec.shared_examples 'an RDF::Mutable' do
8
8
  raise 'mutable must be defined with let(:mutable)' unless
9
9
  defined? mutable
10
10
 
11
+ skip "Immutable resource" unless mutable.mutable?
12
+ @statements = RDF::Spec.triples
11
13
  @supports_named_graphs = mutable.respond_to?(:supports?) && mutable.supports?(:graph_name)
14
+ @supports_literal_equality = mutable.respond_to?(:supports?) && mutable.supports?(:literal_equality)
12
15
  end
13
16
 
14
17
  let(:resource) { RDF::URI('http://rubygems.org/gems/rdf') }
15
18
  let(:graph_name) { RDF::URI('http://example.org/graph_name') }
19
+ let(:non_bnode_statements) {@statements.reject(&:node?)}
16
20
 
17
21
  describe RDF::Mutable do
18
22
  subject { mutable }
@@ -43,36 +47,26 @@ RSpec.shared_examples 'an RDF::Mutable' do
43
47
  its(:count) {is_expected.to be_zero}
44
48
 
45
49
  context "#load" do
46
- it "is_expected.to require an argument" do
50
+ it "should require an argument" do
47
51
  expect { subject.load }.to raise_error(ArgumentError)
48
52
  end
49
53
 
50
- it "is_expected.to accept a string filename argument" do
51
- expect { subject.load(RDF::Spec::TRIPLES_FILE) }.not_to raise_error if subject.mutable?
54
+ it "should accept a string filename argument" do
55
+ expect { subject.load(RDF::Spec::TRIPLES_FILE) }.not_to raise_error
52
56
  end
53
57
 
54
- it "is_expected.to accept an optional hash argument" do
55
- expect { subject.load(RDF::Spec::TRIPLES_FILE, {}) }.not_to raise_error if subject.mutable?
58
+ it "should accept an optional hash argument" do
59
+ expect { subject.load(RDF::Spec::TRIPLES_FILE, {}) }.not_to raise_error
56
60
  end
57
61
 
58
- it "is_expected.to load statements" do
59
- if subject.mutable?
60
- subject.load RDF::Spec::TRIPLES_FILE
61
- expect(subject.size).to eq File.readlines(RDF::Spec::TRIPLES_FILE).size
62
- is_expected.to have_subject(resource)
63
- end
64
- end
65
-
66
- it "is_expected.to load statements with a context override", unless: RDF::VERSION.to_s >= "1.99" do
67
- if subject.mutable? && @supports_named_graphs
68
- subject.load RDF::Spec::TRIPLES_FILE, context: graph_name
69
- is_expected.to have_context(graph_name)
70
- expect(subject.query(context: graph_name).size).to eq subject.size
71
- end
62
+ it "should load statements" do
63
+ subject.load RDF::Spec::TRIPLES_FILE
64
+ expect(subject.size).to eq File.readlines(RDF::Spec::TRIPLES_FILE).size
65
+ is_expected.to have_subject(resource)
72
66
  end
73
67
 
74
- it "is_expected.to load statements with a graph_name override", if: RDF::VERSION.to_s >= "1.99" do
75
- if subject.mutable? && @supports_named_graphs
68
+ it "should load statements with a graph_name override" do
69
+ if @supports_named_graphs
76
70
  subject.load RDF::Spec::TRIPLES_FILE, graph_name: graph_name
77
71
  is_expected.to have_graph(graph_name)
78
72
  expect(subject.query(graph_name: graph_name).size).to eq subject.size
@@ -81,7 +75,7 @@ RSpec.shared_examples 'an RDF::Mutable' do
81
75
  end
82
76
 
83
77
  context "#from_{reader}" do
84
- it "is_expected.to instantiate a reader" do
78
+ it "should instantiate a reader" do
85
79
  reader = double("reader")
86
80
  expect(reader).to receive(:new).and_return(RDF::Spec.quads.first)
87
81
  allow(RDF::Reader).to receive(:for).and_call_original
@@ -90,89 +84,241 @@ RSpec.shared_examples 'an RDF::Mutable' do
90
84
  end
91
85
  end
92
86
 
87
+ context "when updating statements" do
88
+ let(:s1) { RDF::Statement(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:1")) }
89
+ let(:s2) { RDF::Statement(resource, RDF::URI.new("urn:predicate:2"), RDF::URI.new("urn:object:2")) }
90
+
91
+ before :each do
92
+ subject.insert(*[s1,s2])
93
+ end
94
+
95
+ after :each do
96
+ subject.delete(*[s1,s2])
97
+ end
98
+
99
+ it "should not raise errors" do
100
+ s1_updated = RDF::Statement(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:2"))
101
+ expect { subject.update(s1_updated) }.not_to raise_error
102
+ end
103
+
104
+ it "should support updating one statement at a time with an object" do
105
+ s1_updated = RDF::Statement(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:2"))
106
+ subject.update(s1_updated)
107
+ expect(subject.has_statement?(s1_updated)).to be true
108
+ expect(subject.has_statement?(s1)).to be false
109
+ end
110
+
111
+ it "should support updating one statement at a time without an object" do
112
+ s1_deleted = RDF::Statement(resource, RDF::URI.new("urn:predicate:1"), nil)
113
+ subject.update(s1_deleted)
114
+ expect(subject.has_statement?(s1)).to be false
115
+ end
116
+
117
+ it "should support updating an array of statements at a time" do
118
+ s1_updated = RDF::Statement(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:2"))
119
+ s2_updated = RDF::Statement(resource, RDF::URI.new("urn:predicate:2"), RDF::URI.new("urn:object:3"))
120
+ subject.update(*[s1_updated, s2_updated])
121
+ expect(subject.has_statement?(s1_updated)).to be true
122
+ expect(subject.has_statement?(s2_updated)).to be true
123
+ expect(subject.has_statement?(s1)).to be false
124
+ expect(subject.has_statement?(s2)).to be false
125
+ end
126
+
127
+ it "should support updating an enumerable of statements at a time" do
128
+ s1_updated = RDF::Statement(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:2"))
129
+ s2_updated = RDF::Statement(resource, RDF::URI.new("urn:predicate:2"), RDF::URI.new("urn:object:3"))
130
+ updates = [s1_updated, s2_updated]
131
+ updates.extend(RDF::Enumerable)
132
+ subject.update(updates)
133
+ expect(subject.has_statement?(s1_updated)).to be true
134
+ expect(subject.has_statement?(s2_updated)).to be true
135
+ expect(subject.has_statement?(s1)).to be false
136
+ expect(subject.has_statement?(s2)).to be false
137
+ end
138
+ end
139
+
93
140
  context "when deleting statements" do
94
141
  before :each do
95
- @statements = RDF::NTriples::Reader.new(File.open(RDF::Spec::TRIPLES_FILE)).to_a
96
142
  subject.insert(*@statements)
97
143
  end
98
144
 
99
- it "is_expected.to not raise errors" do
100
- expect { subject.delete(@statements.first) }.not_to raise_error if subject.mutable?
145
+ it "should not raise errors" do
146
+ expect { subject.delete(non_bnode_statements.first) }.not_to raise_error
147
+ end
148
+
149
+ it "should support deleting one statement at a time" do
150
+ subject.delete(non_bnode_statements.first)
151
+ is_expected.not_to have_statement(non_bnode_statements.first)
101
152
  end
102
153
 
103
- it "is_expected.to support deleting one statement at a time" do
154
+ it "should support deleting multiple statements at a time" do
155
+ subject.delete(*@statements)
156
+ expect(subject.find { |s| subject.has_statement?(s) }).to be_nil
157
+ end
158
+
159
+ it "should support wildcard deletions" do
160
+ # nothing deleted
161
+ require 'digest/sha1'
162
+ count = subject.count
163
+ subject.delete([nil, nil, Digest::SHA1.hexdigest(File.read(__FILE__))])
164
+ is_expected.not_to be_empty
165
+ expect(subject.count).to eq count
166
+
167
+ # everything deleted
168
+ subject.delete([nil, nil, nil])
169
+ is_expected.to be_empty
170
+ end
171
+
172
+ it "should only delete statements when the graph_name matches" do
173
+ # Setup three statements identical except for graph_name
174
+ count = subject.count + (@supports_named_graphs ? 3 : 1)
175
+ s1 = RDF::Statement.new(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:1"))
176
+ s2 = s1.dup
177
+ s2.graph_name = RDF::URI.new("urn:graph_name:1")
178
+ s3 = s1.dup
179
+ s3.graph_name = RDF::URI.new("urn:graph_name:2")
180
+ subject.insert(s1)
181
+ subject.insert(s2)
182
+ subject.insert(s3)
183
+ expect(subject.count).to eq count
184
+
185
+ # Delete one by one
186
+ subject.delete(s1)
187
+ expect(subject.count).to eq count - (@supports_named_graphs ? 1 : 1)
188
+ subject.delete(s2)
189
+ expect(subject.count).to eq count - (@supports_named_graphs ? 2 : 1)
190
+ subject.delete(s3)
191
+ expect(subject.count).to eq count - (@supports_named_graphs ? 3 : 1)
192
+ end
193
+
194
+ it 'does not delete literal with different language' do
104
195
  if subject.mutable?
105
- subject.delete(@statements.first)
106
- is_expected.not_to have_statement(@statements.first)
196
+ en = RDF::Literal('abc', language: 'en')
197
+ fi = RDF::Literal('abc', language: 'fi')
198
+
199
+ subject.insert([RDF::URI('http://example.com/s'), RDF::URI('http://example.com/p'), en])
200
+ expect { subject.delete([RDF::URI('http://example.com/s'), RDF::URI('http://example.com/p'), fi]) }
201
+ .not_to change { subject.count }
107
202
  end
108
203
  end
109
204
 
110
- it "is_expected.to support deleting multiple statements at a time" do
111
- if subject.mutable?
112
- subject.delete(*@statements)
113
- expect(subject.find { |s| subject.has_statement?(s) }).to be_nil
205
+ it 'does not delete literal with different datatype' do
206
+ if subject.mutable? && @supports_literal_equality
207
+ dec = RDF::Literal::Decimal.new(1)
208
+ int = RDF::Literal::Integer.new(1)
209
+
210
+ subject.insert([RDF::URI('http://example.com/s'), RDF::URI('http://example.com/p'), dec])
211
+
212
+ expect { subject.delete([RDF::URI('http://example.com/s'), RDF::URI('http://example.com/p'), int]) }
213
+ .not_to change { subject.count }
114
214
  end
115
215
  end
116
216
 
117
- it "is_expected.to support wildcard deletions" do
118
- if subject.mutable?
119
- # nothing deleted
120
- require 'digest/sha1'
121
- count = subject.count
122
- subject.delete([nil, nil, Digest::SHA1.hexdigest(File.read(__FILE__))])
123
- is_expected.not_to be_empty
124
- expect(subject.count).to eq count
125
-
126
- # everything deleted
127
- subject.delete([nil, nil, nil])
128
- is_expected.to be_empty
217
+ it 'does not delete literal with different lexical value' do
218
+ if subject.mutable? && @supports_literal_equality
219
+ one = RDF::Literal::Integer.new("1")
220
+ zero_one = RDF::Literal::Integer.new("01")
221
+
222
+ subject.insert([RDF::URI('http://example.com/s'), RDF::URI('http://example.com/p'), one])
223
+
224
+ expect { subject.delete([RDF::URI('http://example.com/s'), RDF::URI('http://example.com/p'), zero_one]) }
225
+ .not_to change { subject.count }
129
226
  end
130
227
  end
131
228
 
132
- it "is_expected.to only delete statements when the graph_name matches" do
133
- if subject.mutable?
134
- # Setup three statements identical except for graph_name
135
- count = subject.count + (@supports_named_graphs ? 3 : 1)
136
- s1 = RDF::Statement.new(resource, RDF::URI.new("urn:predicate:1"), RDF::URI.new("urn:object:1"))
137
- s2 = s1.dup
138
- s2.graph_name = RDF::URI.new("urn:graph_name:1")
139
- s3 = s1.dup
140
- s3.graph_name = RDF::URI.new("urn:graph_name:2")
141
- subject.insert(s1)
142
- subject.insert(s2)
143
- subject.insert(s3)
144
- expect(subject.count).to eq count
145
-
146
- # Delete one by one
147
- subject.delete(s1)
148
- expect(subject.count).to eq count - (@supports_named_graphs ? 1 : 1)
149
- subject.delete(s2)
150
- expect(subject.count).to eq count - (@supports_named_graphs ? 2 : 1)
151
- subject.delete(s3)
152
- expect(subject.count).to eq count - (@supports_named_graphs ? 3 : 1)
229
+ describe '#delete_insert' do
230
+ let(:statement) do
231
+ RDF::Statement.new(resource,
232
+ RDF::URI.new("urn:predicate:1"),
233
+ RDF::URI.new("urn:object:1"))
234
+ end
235
+
236
+ it 'deletes and inserts' do
237
+ subject.delete_insert(@statements, [statement])
238
+ is_expected.to contain_exactly statement
239
+ end
240
+
241
+ it 'deletes before inserting' do
242
+ subject.delete_insert(@statements, [@statements.first])
243
+ is_expected.to contain_exactly @statements.first
244
+ end
245
+
246
+ it 'deletes patterns' do
247
+ pattern = [non_bnode_statements.first.subject, nil, nil]
248
+ expect { subject.delete_insert([pattern], []) }
249
+ .to change { subject.has_subject?(non_bnode_statements.first.subject) }
250
+ .from(true).to(false)
251
+ end
252
+
253
+ it 'handles Enumerables' do
254
+ dels = non_bnode_statements.take(10)
255
+ dels.extend(RDF::Enumerable)
256
+ ins = RDF::Graph.new << statement
257
+ expect { subject.delete_insert(dels, ins) }
258
+ .to change { dels.find { |s| subject.include?(s) } }.to be_nil
259
+ is_expected.to include statement
260
+ end
261
+
262
+ it 'handles Graph names' do
263
+ if @supports_named_graphs
264
+ dels = non_bnode_statements.take(10).map do |st|
265
+ RDF::Statement.from(st.to_hash.merge(graph_name: RDF::URI('http://example.com/fake')))
266
+ end
267
+ dels.map! { |st| st.graph_name = RDF::URI('http://example.com/fake'); st }
268
+ dels.extend(RDF::Enumerable)
269
+ expect { subject.delete_insert(dels, []) }
270
+ .not_to change { subject.statements.count }
271
+ end
272
+ end
273
+
274
+ context 'when transactions are supported' do
275
+ it 'updates atomically' do
276
+ if subject.mutable? && subject.supports?(:atomic_write)
277
+ contents = subject.statements.to_a
278
+
279
+ expect { subject.delete_insert(@statements, [nil]) }
280
+ .to raise_error ArgumentError
281
+ expect(subject.statements).to contain_exactly(*contents)
282
+ end
283
+ end
153
284
  end
154
285
  end
155
286
  end
156
- end
157
- end
287
+
288
+ describe '#apply_changeset' do
289
+ let(:changeset) { RDF::Changeset.new }
158
290
 
159
- ##
160
- # @deprecated use `it_behaves_like "an RDF::Mutable"` instead
161
- module RDF_Mutable
162
- extend RSpec::SharedContext
163
- include RDF::Spec::Matchers
291
+ it 'is a no-op when changeset is empty' do
292
+ expect { subject.apply_changeset(changeset) }
293
+ .not_to change { subject.statements }
294
+ end
164
295
 
165
- def self.included(mod)
166
- warn "[DEPRECATION] `RDF_Mutable` is deprecated. "\
167
- "Please use `it_behaves_like 'an RDF::Mutable'`"
168
- end
296
+ it 'inserts statements' do
297
+ changeset.insert(*non_bnode_statements)
298
+
299
+ expect { subject.apply_changeset(changeset) }
300
+ .to change { subject.statements }
301
+ .to contain_exactly(*non_bnode_statements)
302
+ end
303
+
304
+ it 'deletes statements' do
305
+ subject.insert(*non_bnode_statements)
306
+ deletes = non_bnode_statements.take(10)
307
+
308
+ changeset.delete(*deletes)
309
+ subject.apply_changeset(changeset)
310
+
311
+ expect(subject).not_to include(*deletes)
312
+ end
169
313
 
170
- describe 'examples for' do
171
- include_examples 'an RDF::Mutable' do
172
- let(:mutable) { @mutable }
314
+ it 'deletes before inserting' do
315
+ statement = non_bnode_statements.first
316
+
317
+ changeset.insert(statement)
318
+ changeset.delete(statement)
319
+ subject.apply_changeset(changeset)
173
320
 
174
- before do
175
- raise '@mutable must be defined' unless defined?(mutable)
321
+ expect(subject).to include(statement)
176
322
  end
177
323
  end
178
324
  end