om 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,399 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
- require "om"
3
-
4
- describe "OM::XML::PropertyValueOperators" do
5
-
6
- before(:all) do
7
- #ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
8
- class PropertiesValueOperatorsTest
9
-
10
- include OM::XML::Container
11
- include OM::XML::Accessors
12
- include OM::XML::Properties
13
- include OM::XML::PropertyValueOperators
14
-
15
-
16
- # Could add support for multiple root declarations.
17
- # For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
18
- # root :mods_collection, :path=>"modsCollection",
19
- # :attributes=>[],
20
- # :subelements => :mods
21
-
22
- root_property :mods, "mods", "http://www.loc.gov/mods/v3", :attributes=>["id", "version"], :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
23
-
24
- property :title_info, :path=>"titleInfo",
25
- :convenience_methods => {
26
- :main_title => {:path=>"title"},
27
- :language => {:path=>"@lang"},
28
- }
29
-
30
- property :name_, :path=>"name",
31
- :attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
32
- :subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
33
- :default_content_path => "namePart",
34
- :convenience_methods => {
35
- :date => {:path=>"namePart", :attributes=>{:type=>"date"}},
36
- :family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
37
- :first_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
38
- :terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
39
- }
40
-
41
- property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
42
-
43
- property :role, :path=>"role",
44
- :parents=>[:name_],
45
- :attributes=>[ { "type"=>["text", "code"] } , "authority"],
46
- :convenience_methods => {
47
- :text => {:path=>"roleTerm", :attributes=>{:type=>"text"}},
48
- :code => {:path=>"roleTerm", :attributes=>{:type=>"code"}},
49
- }
50
-
51
- generate_accessors_from_properties
52
-
53
- end
54
-
55
- end
56
-
57
- before(:each) do
58
- @sample = PropertiesValueOperatorsTest.from_xml( fixture( File.join("test_dummy_mods.xml") ) )
59
- end
60
-
61
- after(:all) do
62
- Object.send(:remove_const, :PropertiesValueOperatorsTest)
63
- end
64
-
65
- describe ".property_values" do
66
-
67
- it "should call .lookup and then build an array of values from the returned nodeset (using default_node, etc as nessesary)" do
68
- lookup_opts = "insert args here"
69
- mock_node = mock("node")
70
- mock_node.expects(:text).returns("sample value").times(3)
71
- mock_nodeset = [mock_node, mock_node, mock_node]
72
- @sample.expects(:retrieve).with(*lookup_opts).returns(mock_nodeset)
73
-
74
- @sample.property_values(lookup_opts).should == ["sample value","sample value","sample value"]
75
- end
76
-
77
- end
78
-
79
-
80
- describe ".update_properties" do
81
- before(:each) do
82
- @article = PropertiesValueOperatorsTest.from_xml( fixture( File.join("mods_articles","hydrangea_article1.xml") ) )
83
- end
84
- it "should update the xml according to the lookups in the given hash" do
85
- properties_update_hash = {[{":person"=>"0"}, "affiliation"]=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, [{:person=>1}, :family_name]=>"Andronicus", [{"person"=>"1"},:first_name]=>["Titus"],[{:person=>1},:role]=>["otherrole1","otherrole2"] }
86
- result = @article.update_properties(properties_update_hash)
87
- result.should == {"person_0_affiliation"=>{"0"=>"affiliation1", "1"=>"affiliation2", "2"=>"affiliation3"}, "person_1_family_name"=>{"0"=>"Andronicus"},"person_1_first_name"=>{"0"=>"Titus"}, "person_1_role"=>{"0"=>"otherrole1","1"=>"otherrole2"}}
88
- person_0_affiliation = @article.retrieve({:person=>0}, :affiliation)
89
- person_0_affiliation[0].text.should == "affiliation1"
90
- person_0_affiliation[1].text.should == "affiliation2"
91
- person_0_affiliation[2].text.should == "affiliation3"
92
-
93
- person_1_family_names = @article.retrieve({:person=>1}, :family_name)
94
- person_1_family_names.length.should == 1
95
- person_1_family_names.first.text.should == "Andronicus"
96
-
97
- person_1_first_names = @article.retrieve({:person=>1}, :first_name)
98
- person_1_first_names.first.text.should == "Titus"
99
-
100
- person_1_roles = @article.retrieve({:person=>1}, :role)
101
- person_1_roles[0].text.should == "otherrole1"
102
- person_1_roles[1].text.should == "otherrole2"
103
- end
104
- it "should call property_value_update if the corresponding node already exists" do
105
- @article.expects(:property_value_update).with('//oxns:titleInfo/oxns:title', 0, "My New Title")
106
- @article.update_properties( {[:title_info, :main_title] => "My New Title"} )
107
- end
108
- it "should call property_values_append if the corresponding node does not already exist or if the requested index is -1" do
109
- expected_args = {
110
- :parent_select => PropertiesValueOperatorsTest.accessor_xpath(*[{:person=>0}]) ,
111
- :child_index => 0,
112
- :template => [:person, :role],
113
- :values => "My New Role"
114
- }
115
- @article.expects(:property_values_append).with(expected_args).times(2)
116
- @article.update_properties( {[{:person=>0}, :role] => {"4"=>"My New Role"}} )
117
- @article.update_properties( {[{:person=>0}, :role] => {"-1"=>"My New Role"}} )
118
- end
119
- it "should call property_value_delete where appropriate"
120
-
121
- it "should destringify the field key/lookup pointer" do
122
- PropertiesValueOperatorsTest.expects(:accessor_xpath).with( *[{:person=>0}, :role]).times(10).returns("//oxns:name[@type=\"personal\"][1]/oxns:role")
123
- PropertiesValueOperatorsTest.stubs(:accessor_xpath).with( *[{:person=>0}]).returns("//oxns:name[@type=\"personal\"][1]")
124
- @article.update_properties( { [{":person"=>"0"}, "role"]=>"the role" } )
125
- @article.update_properties( { [{"person"=>"0"}, "role"]=>"the role" } )
126
- @article.update_properties( { [{:person=>0}, :role]=>"the role" } )
127
- end
128
-
129
- ### Examples copied over form nokogiri_datastream_spec
130
-
131
- it "should apply submitted hash to corresponding datastream field values" do
132
- result = @article.update_properties( {[{":person"=>"0"}, "first_name"]=>{"0"=>"Billy", "1"=>"Bob", "2"=>"Joe"} })
133
- result.should == {"person_0_first_name"=>{"0"=>"Billy", "1"=>"Bob", "2"=>"Joe"}}
134
- # xpath = ds.class.accessor_xpath(*field_key)
135
- # result = ds.property_values(xpath)
136
- @article.property_values({:person=>0}, :first_name).should == ["Billy","Bob","Joe"]
137
- @article.property_values('//oxns:name[@type="personal"][1]/oxns:namePart[@type="given"]').should == ["Billy","Bob","Joe"]
138
- end
139
- it "should support single-value arguments (as opposed to a hash of values with array indexes as keys)" do
140
- # In other words, { "fubar"=>"dork" } should have the same effect as { "fubar"=>{"0"=>"dork"} }
141
- result = @article.update_properties( { [{":person"=>"0"}, "role"]=>"the role" } )
142
- result.should == {"person_0_role"=>{"0"=>"the role"}}
143
- @article.property_values({:person=>0}, :role).first.should == "the role"
144
- @article.property_values('//oxns:name[@type="personal"][1]/oxns:role').first.should == "the role"
145
- end
146
- it "should do nothing if field key is a string (must be an array or symbol). Will not accept xpath queries!" do
147
- xml_before = @article.to_xml
148
- @article.update_properties( { "fubar"=>"the role" } ).should == {}
149
- @article.to_xml.should == xml_before
150
- end
151
- it "should do nothing if there is no accessor corresponding to the given field key" do
152
- xml_before = @article.to_xml
153
- @article.update_properties( { [{"fubar"=>"0"}]=>"the role" } ).should == {}
154
- @article.to_xml.should == xml_before
155
- end
156
-
157
- ### Examples copied over form metadata_datastream_spec
158
-
159
- # it "should support single-value arguments (as opposed to a hash of values with array indexes as keys)" do
160
- # # In other words, { "fubar"=>"dork" } should have the same effect as { "fubar"=>{"0"=>"dork"} }
161
- # pending "this should be working, but for some reason, the updates don't stick"
162
- # result = @test_ds.update_indexed_attributes( { "fubar"=>"dork" } )
163
- # result.should == {"fubar"=>{"0"=>"dork"}}
164
- # @test_ds.fubar_values.should == ["dork"]
165
- # end
166
- #
167
- it "should work for text fields" do
168
- att= {[{"person"=>"0"},"description"]=>{"-1"=>"mork", "1"=>"york"}}
169
- result = @article.update_properties(att)
170
- result.should == {"person_0_description"=>{"0"=>"mork","1"=>"york"}}
171
- @article.property_values({:person=>0},:description).should == ['mork', 'york']
172
- att= {[{"person"=>"0"},"description"]=>{"-1"=>"dork"}}
173
- result2 = @article.update_properties(att)
174
- result2.should == {"person_0_description"=>{"2"=>"dork"}}
175
- @article.property_values({:person=>0},:description).should == ['mork', 'york', 'dork']
176
- end
177
-
178
- it "should return the new index of any added values" do
179
- @article.property_values({:title_info=>0},:main_title).should == ["ARTICLE TITLE HYDRANGEA ARTICLE 1", "TITLE OF HOST JOURNAL"]
180
- result = @article.update_properties [{"title_info"=>"0"},"main_title"]=>{"-1"=>"mork"}
181
- result.should == {"title_info_0_main_title"=>{"2"=>"mork"}}
182
- end
183
- #
184
- # it "should return accurate response when multiple values have been added in a single run" do
185
- # pending
186
- # att= {"swank"=>{"-1"=>"mork", "0"=>"york"}}
187
- # @test_ds.update_indexed_attributes(att).should == {"swank"=>{"0"=>"york", "1"=>"mork"}}
188
- # end
189
-
190
- # it "should deal gracefully with adding new values at explicitly declared indexes" do
191
- # @article.update_properties([:journal, :title]=>["all", "for", "the"]
192
- # att = {"fubar"=>{"3"=>'glory'}}
193
- # result = @test_ds.update_indexed_attributes(att)
194
- # result.should == {"fubar"=>{"3"=>"glory"}}
195
- # @test_ds.fubar_values.should == ["all", "for", "the", "glory"]
196
- #
197
- # @test_ds.fubar_values = []
198
- # result = @test_ds.update_indexed_attributes(att)
199
- # result.should == {"fubar"=>{"0"=>"glory"}}
200
- # @test_ds.fubar_values.should == ["glory"]
201
- # end
202
- #
203
- # it "should allow deleting of values and should delete values so that to_xml does not return emtpy nodes" do
204
- # att= {"fubar"=>{"-1"=>"mork", "0"=>"york", "1"=>"mangle"}}
205
- # @test_ds.update_indexed_attributes(att)
206
- # @test_ds.fubar_values.should == ['mork', 'york', 'mangle']
207
- # rexml = REXML::Document.new(@test_ds.to_xml)
208
- # #puts rexml.root.elements.each {|el| el.to_s}
209
- # #puts rexml.root.elements.to_a.inspect
210
- # rexml.root.elements.to_a.length.should == 3
211
- # @test_ds.update_indexed_attributes({"fubar"=>{"1"=>""}})
212
- # @test_ds.fubar_values.should == ['mork', 'mangle']
213
- # rexml = REXML::Document.new(@test_ds.to_xml)
214
- # rexml.root.elements.to_a.length.should == 2
215
- # @test_ds.update_indexed_attributes({"fubar"=>{"0"=>:delete}})
216
- # @test_ds.fubar_values.should == ['mangle']
217
- # rexml = REXML::Document.new(@test_ds.to_xml)
218
- # rexml.root.elements.to_a.length.should == 1
219
- #
220
- # @test_ds.fubar_values = ["val1", nil, "val2"]
221
- # @test_ds.update_indexed_attributes({"fubar"=>{"1"=>""}})
222
- # @test_ds.fubar_values.should == ["val1", "val2"]
223
- # end
224
-
225
- end
226
-
227
- describe ".property_values_append" do
228
-
229
- it "looks up the parent using :parent_select, uses :child_index to choose the parent node from the result set, uses :template to build the node(s) to be inserted, inserts the :values(s) into the node(s) and adds the node(s) to the parent" do
230
- @sample.property_values_append(
231
- :parent_select => [:person, {:first_name=>"Tim", :family_name=>"Berners-Lee"}] ,
232
- :child_index => :first,
233
- :template => [:person, :affiliation],
234
- :values => ["my new value", "another new value"]
235
- )
236
- end
237
-
238
- it "should accept parent_select and template [property_reference, lookup_opts] as argument arrays for generators/lookups" do
239
- # this appends two affiliation nodes into the first person node whose name is Tim Berners-Lee
240
- expected_result = '<ns3:name type="personal">
241
- <ns3:namePart type="family">Berners-Lee</ns3:namePart>
242
- <ns3:namePart type="given">Tim</ns3:namePart>
243
- <ns3:role>
244
- <ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
245
- <ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
246
- </ns3:role>
247
- <ns3:affiliation>my new value</ns3:affiliation><ns3:affiliation>another new value</ns3:affiliation></ns3:name>'
248
-
249
- @sample.property_values_append(
250
- :parent_select => [:person, {:first_name=>"Tim", :family_name=>"Berners-Lee"}] ,
251
- :child_index => :first,
252
- :template => [:person, :affiliation],
253
- :values => ["my new value", "another new value"]
254
- ).to_xml.should == expected_result
255
-
256
- @sample.lookup(:person, {:first_name=>"Tim", :family_name=>"Berners-Lee"}).first.to_xml.should == expected_result
257
- end
258
-
259
- it "should accept symbols as arguments for generators/lookups" do
260
- # this appends a role of "my role" into the third "person" node in the document
261
- @sample.property_values_append(
262
- :parent_select => :person ,
263
- :child_index => 3,
264
- :template => :role,
265
- :values => "my role"
266
- ).to_xml.should #== expected_result
267
- @sample.lookup(:person)[3].search("./ns3:role[3]").first.text.should == "my role"
268
- end
269
-
270
- it "should accept parent_select as an (xpath) string and template as a (template) string" do
271
- # this uses the provided template to add a node into the first node resulting from the xpath '//oxns:name[@type="personal"]'
272
- expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Berners-Lee</ns3:namePart>\n <ns3:namePart type=\"given\">Tim</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"code\" authority=\"marcrelator\"><ns3:roleTerm>creator</ns3:roleTerm></ns3:role></ns3:name>"
273
-
274
- @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 1
275
-
276
- @sample.property_values_append(
277
- :parent_select =>'//oxns:name[@type="personal"]',
278
- :child_index => 0,
279
- :template => 'xml.role { xml.roleTerm( \'#{builder_new_value}\', :type=>\'code\', :authority=>\'marcrelator\') }',
280
- :values => "founder"
281
- )
282
-
283
- @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 2
284
- @sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role[last()]/oxns:roleTerm', @sample.ox_namespaces).first.text.should == "founder"
285
-
286
- # @sample.lookup(:person).first.to_xml.should == expected_result
287
- end
288
-
289
- it "should support more complex mixing & matching" do
290
- pending "not working because builder_template is not returning the correct template (returns builder for role instead of roleTerm)"
291
- @sample.ng_xml.xpath('//oxns:name[@type="personal"][2]/oxns:role[1]/oxns:roleTerm', @sample.ox_namespaces).length.should == 2
292
- @sample.property_values_append(
293
- :parent_select =>'//oxns:name[@type="personal"][2]/oxns:role',
294
- :child_index => 0,
295
- :template => [ :person, :role, :text, {:attributes=>{"authority"=>"marcrelator"}} ],
296
- :values => "foo"
297
- )
298
-
299
- @sample.ng_xml.xpath('//oxns:name[@type="personal"][2]/oxns:role[1]/oxns:roleTerm', @sample.ox_namespaces).length.should == 3
300
- @sample.retrieve({:person=>1},:role)[0].search("./oxns:roleTerm[@type=\"text\" and @authority=\"marcrelator\"]", @sample.ox_namespaces).first.text.should == "foo"
301
- end
302
-
303
- it "should raise exception if no node corresponds to the provided :parent_select and :child_index"
304
-
305
- end
306
-
307
- describe ".property_value_update" do
308
-
309
- it "should accept an xpath as :parent_select" do
310
- sample_xpath = '//oxns:name[@type="personal"][4]/oxns:role/oxns:roleTerm[@type="text"]'
311
- @sample.property_value_update(sample_xpath,1,"artist")
312
-
313
- # @sample.property_value_update(
314
- # :parent_select =>sample_xpath,
315
- # :child_index => 1,
316
- # :value => "donor"
317
- # )
318
-
319
- @sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces)[1].text.should == "artist"
320
- end
321
-
322
- it "if :select is provided, should update the first node provided by that xpath statement" do
323
- sample_xpath = '//oxns:name[@type="personal"][1]/oxns:namePart[@type="given"]'
324
- @sample.property_value_update(sample_xpath,0,"Timmeh")
325
- @sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces).first.text.should == "Timmeh"
326
- end
327
-
328
- it "should replace the existing node if you pass a template and values" do
329
- pending
330
- @sample.property_value_update(
331
- :parent_select =>'//oxns:name[@type="personal"]',
332
- :child_index => 1,
333
- :template => [ :person, :role, {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ],
334
- :value => "foo"
335
- )
336
- 1.should == 2
337
- end
338
- end
339
-
340
- describe ".property_value_delete" do
341
- it "should accept an xpath query as :select option" do
342
- generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role'
343
- specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
344
- select_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[last()]'
345
-
346
- # Check that we're starting with 2 roles
347
- # Check that the specific node we want to delete exists
348
- @sample.lookup(generic_xpath).length.should == 2
349
- @sample.lookup(specific_xpath).length.should == 1
350
-
351
- @sample.property_value_delete(
352
- :select =>select_xpath
353
- )
354
- # Check that we're finishing with 1 role
355
- @sample.lookup(generic_xpath).length.should == 1
356
- # Check that the specific node we want to delete no longer exists
357
- @sample.lookup(specific_xpath).length.should == 0
358
- end
359
- it "should accept :parent_select, :parent_index and :child_index options instead of a :select" do
360
-
361
- generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role/oxns:roleTerm'
362
- specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
363
-
364
- # Check that we're starting with 2 roles
365
- # Check that the specific node we want to delete exists
366
- @sample.lookup(generic_xpath).length.should == 4
367
- @sample.lookup(specific_xpath).length.should == 1
368
-
369
- # this is attempting to delete the last child (in this case roleTerm) from the 3rd role in the document.
370
- @sample.property_value_delete(
371
- :parent_select => [:person, :role],
372
- :parent_index => 3,
373
- :child_index => :last
374
- )
375
-
376
- # Check that we're finishing with 1 role
377
- @sample.lookup(generic_xpath).length.should == 3
378
- # Check that the specific node we want to delete no longer exists
379
- @sample.lookup(specific_xpath).length.should == 1
380
- end
381
- it "should work if only :parent_select and :child_index are provided" do
382
- generic_xpath = '//oxns:name[@type="personal"]/oxns:role'
383
- # specific_xpath = '//oxns:name[@type="personal"]/oxns:role'
384
-
385
- # Check that we're starting with 2 roles
386
- # Check that the specific node we want to delete exists
387
- @sample.lookup(generic_xpath).length.should == 4
388
- # @sample.lookup(specific_xpath).length.should == 1
389
-
390
- @sample.property_value_delete(
391
- :parent_select => [:person, :role],
392
- :child_index => 3
393
- )
394
- # Check that we're finishing with 1 role
395
- @sample.lookup(generic_xpath).length.should == 3
396
- end
397
- end
398
-
399
- end