rdf-spec 1.99.0 → 2.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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