safety-pin 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/spec/node_spec.rb ADDED
@@ -0,0 +1,712 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe SafetyPin::Node do
4
+ describe ".find" do
5
+ context "given a node name" do
6
+ context "that exists" do
7
+ it "should return a node with a matching path" do
8
+ SafetyPin::Node.find("/content").path.should eql("/content")
9
+ end
10
+ end
11
+
12
+ context "that doesn't exist" do
13
+ it "should return nil" do
14
+ SafetyPin::Node.find("/foo/bar/baz").should be_nil
15
+ end
16
+ end
17
+ end
18
+
19
+ it "complains if the path isn't an absolute path" do
20
+ lambda { node = SafetyPin::Node.find("content") }.should raise_exception(ArgumentError)
21
+ end
22
+ end
23
+
24
+ describe ".find_or_create" do
25
+ context "given a node path that exists" do
26
+ it "should return the node at that path" do
27
+ SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
28
+ SafetyPin::Node.find_or_create("/content/foo").path.should eql "/content/foo"
29
+ end
30
+ end
31
+
32
+ context "when node doesn't exist" do
33
+ it "returns node created at path" do
34
+ SafetyPin::Node.find("/content/foo").should be_nil
35
+ SafetyPin::Node.find_or_create("/content/foo").path.should == "/content/foo"
36
+ end
37
+ end
38
+ end
39
+
40
+ describe ".exists?" do
41
+ it "returns true if node exists at path" do
42
+ SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
43
+ SafetyPin::Node.exists?("/content/foo").should be_true
44
+ end
45
+
46
+ it "returns false if node does not exist" do
47
+ SafetyPin::Node.exists?("/content/foo").should be_false
48
+ end
49
+ end
50
+
51
+ describe ".session" do
52
+ it "should return a session" do
53
+ SafetyPin::Node.session.should be_a(Java::JavaxJcr::Session)
54
+ end
55
+ end
56
+
57
+ describe "#session" do
58
+ it "should return a session" do
59
+ SafetyPin::Node.find("/content").session.should be_a(Java::JavaxJcr::Session)
60
+ end
61
+
62
+ it "should cache session in an instance variable" do
63
+ node = SafetyPin::Node.find("/content")
64
+ node.session
65
+ node.instance_eval { @session }.should be_a(Java::JavaxJcr::Session)
66
+ end
67
+ end
68
+
69
+ describe "#children" do
70
+ it "should return an array of child nodes" do
71
+ SafetyPin::Node.find("/content").children.first.should be_a(SafetyPin::Node)
72
+ end
73
+ end
74
+
75
+ describe "#child" do
76
+ context "given a node name" do
77
+ let(:node) { SafetyPin::Node.find("/") }
78
+
79
+ context "that exists" do
80
+ it "should return a child node with a matching name" do
81
+ node.child("content").name.should eql("content")
82
+ end
83
+
84
+ it "should return a grandchild node given a relative path" do
85
+ SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
86
+ node.child("content/foo").name.should eql("foo")
87
+ end
88
+ end
89
+
90
+ it "should coerce non-string name to string and return child" do
91
+ node.child(:content).name.should == "content"
92
+ end
93
+
94
+ context "that doesn't exist" do
95
+ it "should return nil" do
96
+ node.child("foobarbaz").should be_nil
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ describe ".create_or_update" do
103
+ let(:node_blueprint) { SafetyPin::NodeBlueprint.new(:path => "/content/foo") }
104
+
105
+ it "calls Node.create with arg when nothing exists at path" do
106
+ SafetyPin::Node.should_receive(:create).with(node_blueprint)
107
+ SafetyPin::Node.create_or_update(node_blueprint)
108
+ end
109
+
110
+ it "calls Node.update with arg when node exists at path" do
111
+ SafetyPin::Node.create(node_blueprint)
112
+ SafetyPin::Node.should_receive(:update).with(node_blueprint)
113
+ SafetyPin::Node.create_or_update(node_blueprint)
114
+ end
115
+
116
+ it "takes a node blueprint" do
117
+ SafetyPin::Node.create_or_update(node_blueprint)
118
+ SafetyPin::Node.exists?(node_blueprint.path).should be_true
119
+ end
120
+
121
+ it "takes an array of node blueprints" do
122
+ node_blueprints = [node_blueprint, SafetyPin::NodeBlueprint.new(:path => "/content/foo/bar")]
123
+ SafetyPin::Node.create_or_update(node_blueprints)
124
+ node_blueprints.each {|node_blueprint| SafetyPin::Node.exists?(node_blueprint.path).should be_true }
125
+ end
126
+ end
127
+
128
+ describe "#find_or_create_child" do
129
+ let(:parent) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
130
+
131
+ context "an existing node path" do
132
+ it "should return the child node" do
133
+ parent.create("bar")
134
+ parent.find_or_create("bar").path.should eql "/content/foo/bar"
135
+ end
136
+ end
137
+
138
+ context "a non-existing node path" do
139
+ it "should create a node and return it" do
140
+ parent.find_or_create("bar").path.should eql "/content/foo/bar"
141
+ end
142
+ end
143
+ end
144
+
145
+ describe "#name" do
146
+ it "should return a string name" do
147
+ SafetyPin::Node.find("/content").name.should eql("content")
148
+ end
149
+ end
150
+
151
+ describe "#save" do
152
+ context "on an existing node with changes" do
153
+ before do
154
+ @node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
155
+ @node["bar"] = "baz"
156
+ end
157
+
158
+ it "should save the changes to the JCR" do
159
+ @node.save
160
+ @node.reload
161
+ @node["bar"].should eql("baz")
162
+ end
163
+
164
+ it "should return true if the save was successful" do
165
+ save_successful = @node.save
166
+ (save_successful and not @node.changed?).should be_true
167
+ end
168
+ end
169
+
170
+ context "on a new node" do
171
+ it "should save the node" do
172
+ node = SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
173
+ node.save.should be_true
174
+ end
175
+
176
+ it "should save changes in parent node" do
177
+ parent_node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
178
+ node = SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "/content/foo/bar"))
179
+ parent_node["baz"] = "qux"
180
+ parent_node.should be_changed
181
+ node.save
182
+ parent_node.should_not be_changed
183
+ end
184
+ end
185
+ end
186
+
187
+ describe "#read_attribute" do
188
+ context "on an existing node" do
189
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
190
+
191
+ it "should return the string value of a string property" do
192
+ node["foo"] = "bar"
193
+ node.read_attribute("foo").should eql("bar")
194
+ end
195
+
196
+ it "should return the boolean value of a boolean property" do
197
+ node["foo"] = true
198
+ node.read_attribute("foo").should eql(true)
199
+ end
200
+
201
+ it "should return the double value of a double (or Ruby float) property" do
202
+ node["foo"] = 3.14
203
+ node.read_attribute("foo").should eql(3.14)
204
+ end
205
+
206
+ it "should return the long value of a long (or Ruby Fixnum) property" do
207
+ node["foo"] = 42
208
+ node.read_attribute("foo").should eql(42)
209
+ end
210
+
211
+ it "should return the time value of a date property" do
212
+ time = Time.now
213
+ node["foo"] = time
214
+ node.read_attribute("foo").to_s.should eql(time.to_s)
215
+ end
216
+
217
+ context "given a multi-value property" do
218
+ it "should return an array of values" do
219
+ node["foo"] = ["one", "two"]
220
+ node.read_attribute("foo").should eql(["one", "two"])
221
+ end
222
+ end
223
+
224
+ context "given a non-string name" do
225
+ it "should co-erce the name into a string and retrieve the property" do
226
+ node["foo"] = "bar"
227
+ node.read_attribute(:foo).should eql("bar")
228
+ end
229
+ end
230
+ end
231
+
232
+ it "should return the string value of a name property" do
233
+ SafetyPin::Node.find("/")["jcr:primaryType"].should eql("rep:root")
234
+ end
235
+
236
+ it "should throw an exception when accessing a non-existent (nil) property" do
237
+ lambda { SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "/content/foo")).read_attribute("foo-bar-baz") }.should raise_error(SafetyPin::NilPropertyError)
238
+ end
239
+ end
240
+
241
+ context "#write_attribute" do
242
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
243
+
244
+ context "given a single value" do
245
+ it "should set a string property value" do
246
+ node.write_attribute("foo", "bar")
247
+ node.save
248
+ node.reload
249
+ node["foo"].should eql("bar")
250
+ end
251
+
252
+ context "given a Time object value" do
253
+ it "should set a date property value" do
254
+ time = Time.now
255
+ node.write_attribute("foo", time)
256
+ node.save
257
+ node.reload
258
+ node["foo"].to_s.should eql(time.to_s)
259
+ end
260
+ end
261
+
262
+ context "given a symbol value" do
263
+ it "coerces value to string" do
264
+ node.write_attribute("foo", :bar)
265
+ node["foo"].should == "bar"
266
+ end
267
+ end
268
+
269
+ context "given another supported value" do
270
+ it "sets the property" do
271
+ node.write_attribute("foo", 1)
272
+ node["foo"].should == 1
273
+ node.write_attribute("foo", 1.1)
274
+ node["foo"].should == 1.1
275
+ node.write_attribute("foo", true)
276
+ node["foo"].should == true
277
+ node.write_attribute("foo", "bar")
278
+ node["foo"].should == "bar"
279
+ end
280
+ end
281
+
282
+ context "given an unsupported value" do
283
+ it "raises an error" do
284
+ lambda { node.write_attribute("foo", {unsupported: :value_type}) }.should raise_error(SafetyPin::PropertyTypeError)
285
+ end
286
+ end
287
+
288
+ context "given a non-string name" do
289
+ it "should co-erce name into string before setting property" do
290
+ node.write_attribute(:foo, "bar")
291
+ node.save
292
+ node.reload
293
+ node["foo"].should eql("bar")
294
+ end
295
+ end
296
+ end
297
+
298
+ context "given an array of values" do
299
+ context "of the same type" do
300
+ it "should set a multi-value string array" do
301
+ node.write_attribute("foo", ["one", "two"])
302
+ node.save
303
+ node.reload
304
+ node["foo"].should eql(["one", "two"])
305
+ end
306
+ end
307
+ end
308
+
309
+ context "given a null value" do
310
+ it "should remove the property" do
311
+ node["foo"] = "bar"
312
+ node.write_attribute("foo", nil)
313
+ lambda { node["foo"] }.should raise_error(SafetyPin::NilPropertyError)
314
+ end
315
+
316
+ context "given a non-existent property and a null value" do
317
+ it "should return nil" do
318
+ node.write_attribute("foo", nil).should be_nil
319
+ end
320
+ end
321
+ end
322
+
323
+ context "changing jcr:primaryType property" do
324
+ it "should raise an error" do
325
+ lambda { node.write_attribute("jcr:primaryType", "nt:folder") }.should raise_error(SafetyPin::PropertyError)
326
+ end
327
+ end
328
+ end
329
+
330
+ context "#reload" do
331
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
332
+
333
+ it "should discard pending changes" do
334
+ node["foo"] = "bar"
335
+ node.reload
336
+ lambda { node.read_attribute("foo") }.should raise_error(SafetyPin::NilPropertyError)
337
+ end
338
+
339
+ it "should not discard changes for another node" do
340
+ node["bar"] = "baz"
341
+ another_node = SafetyPin::Node.find("/content")
342
+ another_node["bar"] = "baz"
343
+ node.reload
344
+ lambda { node["bar"] }.should raise_error(SafetyPin::NilPropertyError)
345
+ another_node["bar"].should eql("baz")
346
+ end
347
+ end
348
+
349
+ describe "#[]" do
350
+ it "should return the value of a given property name" do
351
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
352
+ node.write_attribute("bar","baz")
353
+ node.save
354
+ node["bar"].should eql("baz")
355
+ end
356
+ end
357
+
358
+ describe "#[]=" do
359
+ it "should set the value of a given property name" do
360
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
361
+ node.write_attribute("bar","baz")
362
+ node["bar"] = "qux"
363
+ node["bar"].should eql("qux")
364
+ node.destroy
365
+ end
366
+ end
367
+
368
+ context "#changed?" do
369
+ let(:node) { SafetyPin::Node.find("/content") }
370
+
371
+ it "should return false if the node does not have unsaved changes" do
372
+ node.should_not be_changed
373
+ end
374
+
375
+ it "should return true if the node has unsaved changes" do
376
+ node["foo"] = "bar"
377
+ node.should be_changed
378
+ end
379
+ end
380
+
381
+ context "#new?" do
382
+ it "should return true if node has never been saved to JCR" do
383
+ SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "/content/foo")).should be_new
384
+ end
385
+
386
+ it "should return false if node has been saved to JCR" do
387
+ SafetyPin::Node.find("/content").should_not be_new
388
+ end
389
+ end
390
+
391
+ describe "#properties" do
392
+ it "should return hash of all unprotected properties" do
393
+ SafetyPin::Node.find("/").properties.should eql({"sling:target"=>"/index.html", "sling:resourceType"=>"sling:redirect"})
394
+ end
395
+ end
396
+
397
+ describe "#properties=" do
398
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
399
+
400
+ it "should set the properties of a node" do
401
+ node.properties = {"foo" => "bar"}
402
+ node.properties.should == {"foo" => "bar"}
403
+ end
404
+
405
+ it "should set unset properties not specified in hash" do
406
+ node["foo"] = "bar"
407
+ node.properties = {"baz" => "qux"}
408
+ node.properties.should eql({"baz" => "qux"})
409
+ end
410
+
411
+ it "creates child nodes for node blueprints" do
412
+ node_blueprint = SafetyPin::NodeBlueprint.new(:path => "/this/path/gets/thrown/away",
413
+ :primary_type => "sling:OrderedFolder",
414
+ :properties => {"bar" => "baz"})
415
+ node.properties = {"foo" => node_blueprint}
416
+ node.child("foo").properties.should == {"bar" => "baz"}
417
+ node.child("foo").primary_type.should == "sling:OrderedFolder"
418
+ end
419
+
420
+ xit "updates child nodes when they already exist" do
421
+ # Create /content/foo/bar and /content/foo/bar/baz
422
+ node.create(:bar, "nt:unstructured", {"bar" => "baz"})
423
+ node.child(:bar).create(:baz)
424
+ node.child(:bar).child(:baz).path.should == "/content/foo/bar/baz"
425
+ # Update /content/foo/bar by updating /content/foo properties
426
+ node.properties = {bar: SafetyPin::NodeBlueprint.new(:path => "/this/path/gets/thrown/away", :primary_type => "sling:OrderedFolder", :properties => {"updated" => "props"})}
427
+ node.child(:bar).properties.should == {"updated" => "props"}
428
+ node.child(:bar).primary_type.should == "sling:OrderedFolder"
429
+ node.child(:bar).child(:baz).path.should == "/content/foo/bar/baz"
430
+ end
431
+ end
432
+
433
+ describe "#protected_properties" do
434
+ it "should return hash of all protected properties" do
435
+ SafetyPin::Node.find("/").protected_properties.should eql({"jcr:primaryType"=>"rep:root", "jcr:mixinTypes"=>["rep:AccessControllable", "rep:RepoAccessControllable"]})
436
+ end
437
+ end
438
+
439
+ describe "#mixin_types" do
440
+ it "should return the mixin types of a node" do
441
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
442
+ node.j_node.add_mixin("mix:created")
443
+ node.save
444
+ node.mixin_types.should eql(["mix:created"])
445
+ end
446
+ end
447
+
448
+ describe "#add_mixin" do
449
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
450
+
451
+ it "should add a mixin type to node" do
452
+ node.add_mixin("mix:created")
453
+ node.save
454
+ node.mixin_types.should eql(["mix:created"])
455
+ end
456
+
457
+ it "should require a save before the mixin addition is detected" do
458
+ node.add_mixin("mix:created")
459
+ node.mixin_types.should eql([])
460
+ end
461
+ end
462
+
463
+ describe "#remove_mixin" do
464
+ let(:node) do
465
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
466
+ node.add_mixin("mix:created")
467
+ node.save
468
+ node
469
+ end
470
+
471
+ it "should remove a mixin type from a node" do
472
+ node.mixin_types.should eql(["mix:created"])
473
+ node.remove_mixin("mix:created")
474
+ node.save
475
+ node.mixin_types.should eql([])
476
+ end
477
+
478
+ it "should require a save before the mixin removal is detected" do
479
+ node.remove_mixin("mix:created")
480
+ node.mixin_types.should eql(["mix:created"])
481
+ node.reload
482
+ end
483
+ end
484
+
485
+ describe ".update" do
486
+ let(:node) do
487
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
488
+ node.save
489
+ node
490
+ end
491
+
492
+ it "updates a nodes properties" do
493
+ SafetyPin::Node.update(SafetyPin::NodeBlueprint.new(:path => node.path, :properties => {"foo" => "barbazbuzzzzz"}))
494
+ SafetyPin::Node.find(node.path).properties.should == {"foo" => "barbazbuzzzzz"}
495
+ end
496
+
497
+ it "preserves node children" do
498
+ node.create(:bar)
499
+ SafetyPin::Node.update(SafetyPin::NodeBlueprint.new(:path => node.path, :primary_type => "sling:OrderedFolder", :properties => {"foo" => "bar"}))
500
+ SafetyPin::Node.exists?("/content/foo/bar").should be_true
501
+ end
502
+
503
+ it "modifies the primary type" do
504
+ SafetyPin::Node.update(SafetyPin::NodeBlueprint.new(:path => node.path, :primary_type => "sling:OrderedFolder"))
505
+ SafetyPin::Node.find(node.path).primary_type.should == "sling:OrderedFolder"
506
+ end
507
+ end
508
+
509
+ describe "#primary_type=" do
510
+ let(:node) do
511
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
512
+ node.save
513
+ node
514
+ end
515
+
516
+ it "sets the primary type" do
517
+ node.primary_type.should == "nt:unstructured"
518
+ node.primary_type = "sling:OrderedFolder"
519
+ node.save
520
+ SafetyPin::Node.find(node.path).primary_type.should == "sling:OrderedFolder"
521
+ end
522
+ end
523
+
524
+ describe ".build" do
525
+ it "returns an unsaved node at path of a specified type with properties set" do
526
+ node = SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "/content/foo", :primary_type => "sling:OrderedFolder", :properties => {"foo" => "bar"}))
527
+ node.should be_new
528
+ node.primary_type.should == "sling:OrderedFolder"
529
+ node.properties.should == {"foo" => "bar"}
530
+ end
531
+
532
+ it "complains when the nodes already exists" do
533
+ node_blueprint = SafetyPin::NodeBlueprint.new(:path => "/content/foo")
534
+ SafetyPin::Node.create(node_blueprint)
535
+ lambda { SafetyPin::Node.build(node_blueprint) }.should raise_error(SafetyPin::NodeError)
536
+ end
537
+
538
+ it "complains when given a path with missing parents" do
539
+ lambda { SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "/content/foo/bar/baz/doesnt/exist")) }.should raise_error(SafetyPin::NodeError)
540
+ end
541
+
542
+ it "complains when given a relative path" do
543
+ lambda { SafetyPin::Node.build(SafetyPin::NodeBlueprint.new(:path => "foo/not/absolute")) }.should raise_error(SafetyPin::NodeError)
544
+ end
545
+
546
+ it "complains when given nil" do
547
+ lambda { SafetyPin::Node.build(nil) }.should raise_error(SafetyPin::NodeError)
548
+ end
549
+ end
550
+
551
+ describe ".create" do
552
+ it "creates a node" do
553
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
554
+ node.should be_a(SafetyPin::Node)
555
+ end
556
+
557
+ it "creates a node of a specific type" do
558
+ SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo", :primary_type => "sling:OrderedFolder"))
559
+ SafetyPin::Node.find("/content/foo").primary_type.should == "sling:OrderedFolder"
560
+ end
561
+ end
562
+
563
+ describe ".create_parents" do
564
+ it "creates parent nodes if they do not exist" do
565
+ SafetyPin::Node.create_parents("/content/foo/bar/baz")
566
+ SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo/bar/baz")).should_not be_nil
567
+ end
568
+ end
569
+
570
+ context "#value_factory" do
571
+ it "should return a value factory instance" do
572
+ SafetyPin::Node.find("/content").value_factory.should be_a(Java::JavaxJcr::ValueFactory)
573
+ end
574
+ end
575
+
576
+ describe "#property_is_multi_valued" do
577
+ it "should return true if property is multi-valued" do
578
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
579
+ node["bar"] = ["baz", "qux"]
580
+ node.save
581
+ property = node.j_node.get_property("bar")
582
+ node.property_is_multi_valued?(property).should be_true
583
+ end
584
+
585
+ it "should return false if property is not multi-valued" do
586
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
587
+ node["bar"] = "baz"
588
+ node.save
589
+ property = node.j_node.get_property("bar")
590
+ node.property_is_multi_valued?(property).should be_false
591
+ end
592
+ end
593
+
594
+ describe "#destroy" do
595
+ it "should remove node from JCR" do
596
+ path = "/content/foo"
597
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => path))
598
+ node.destroy
599
+ SafetyPin::Node.find(path).should be_nil
600
+ end
601
+
602
+ it "should save changes in parent node" do
603
+ parent_node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
604
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo/bar"))
605
+ parent_node["baz"] = "qux"
606
+ parent_node.should be_changed
607
+ node.destroy
608
+ parent_node.should_not be_changed
609
+ end
610
+
611
+ context "when it fails" do
612
+ it "should raise an error" do
613
+ node = SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo"))
614
+ node.add_mixin("mix:created")
615
+ node.save
616
+ node.remove_mixin("mix:created") # make node unremoveable
617
+ lambda { node.destroy }.should raise_error(SafetyPin::NodeError)
618
+ end
619
+ end
620
+ end
621
+
622
+ describe "#primary_type" do
623
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
624
+
625
+ it "should return the primary type of the node" do
626
+ node.primary_type.should eql("nt:unstructured")
627
+ end
628
+ end
629
+
630
+ describe "#build" do
631
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
632
+
633
+ it "should create a child node with a given name" do
634
+ node.build("bar").path.should == "/content/foo/bar"
635
+ end
636
+
637
+ it "should create a child node with a given name and node type" do
638
+ child_node = node.build("bar", SafetyPin::NodeBlueprint.new(:primary_type => "nt:folder", :path => :no_path))
639
+ child_node.should be_a(SafetyPin::Node)
640
+ child_node.primary_type.should == "nt:folder"
641
+ end
642
+
643
+ it "should create a child node with a name, node type, and properties" do
644
+ node.build("bar", SafetyPin::NodeBlueprint.new(:path => :no_path, :properties => {foo: "bar"})).properties.should == {"foo" => "bar"}
645
+ end
646
+ end
647
+
648
+ describe "#create" do
649
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
650
+
651
+ it "should create a child node with a given name" do
652
+ child_node = node.create("bar")
653
+ child_node.path.should == "/content/foo/bar"
654
+ child_node.should_not
655
+ end
656
+
657
+ it "should create a child node with a given name and node type" do
658
+ child_node = node.create("bar", SafetyPin::NodeBlueprint.new(:path => :no_path, :primary_type => "nt:folder"))
659
+ child_node.should_not be_new
660
+ child_node.primary_type.should eql("nt:folder")
661
+ end
662
+
663
+ it "should create a child node with a name, node type, and properties" do
664
+ child_node = node.create("bar", SafetyPin::NodeBlueprint.new(:path => :no_path, :properties => {foo: "bar"}))
665
+ child_node.should_not be_new
666
+ child_node.properties.should == {"foo" => "bar"}
667
+ end
668
+ end
669
+
670
+ describe "#==" do
671
+ it "finds two nodes with the same path to be the same" do
672
+ node1 = SafetyPin::Node.new(double(:j_node))
673
+ node1.should_receive(:path).and_return("/content/foo")
674
+ node2 = SafetyPin::Node.new(double(:j_node))
675
+ node2.should_receive(:path).and_return("/content/foo")
676
+
677
+ node1.should == node2
678
+ end
679
+
680
+ it "finds two nodes with different paths to be different" do
681
+ node1 = SafetyPin::Node.new(double(:j_node))
682
+ node1.should_receive(:path).and_return("/content/foo")
683
+ node2 = SafetyPin::Node.new(double(:j_node))
684
+ node2.should_receive(:path).and_return("/content/foo/bar")
685
+
686
+ node1.should_not == node2
687
+ end
688
+
689
+ it "returns false when passed an object that doesn't response to path" do
690
+ node1 = SafetyPin::Node.new(double(:j_node))
691
+ node1.stub(:path => "foo")
692
+ node1.should_not == Object.new
693
+ end
694
+
695
+ it "returns false when passed a nil object" do
696
+ node1 = SafetyPin::Node.new(double(:j_node))
697
+ node1.should_not == nil
698
+ end
699
+ end
700
+
701
+ describe "#parent", :focus => true do
702
+ let(:node) { SafetyPin::Node.create(SafetyPin::NodeBlueprint.new(:path => "/content/foo")) }
703
+
704
+ it "returns the parent node" do
705
+ node.parent.should == SafetyPin::Node.find("/content")
706
+ end
707
+
708
+ it "raises an error when called on the root node" do
709
+ expect { SafetyPin::Node.find("/").parent }.to raise_error(SafetyPin::NodeError)
710
+ end
711
+ end
712
+ end