treequel 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/ChangeLog +130 -1
  2. data/Rakefile +8 -3
  3. data/Rakefile.local +2 -0
  4. data/bin/treeirb +6 -2
  5. data/bin/treequel +5 -4
  6. data/lib/treequel/branch.rb +133 -72
  7. data/lib/treequel/branchcollection.rb +16 -5
  8. data/lib/treequel/branchset.rb +37 -6
  9. data/lib/treequel/constants.rb +12 -0
  10. data/lib/treequel/directory.rb +96 -41
  11. data/lib/treequel/filter.rb +42 -1
  12. data/lib/treequel/model/objectclass.rb +111 -0
  13. data/lib/treequel/model.rb +363 -0
  14. data/lib/treequel/monkeypatches.rb +65 -0
  15. data/lib/treequel/schema/attributetype.rb +108 -18
  16. data/lib/treequel/schema/ldapsyntax.rb +15 -0
  17. data/lib/treequel/schema/matchingrule.rb +24 -0
  18. data/lib/treequel/schema/matchingruleuse.rb +24 -0
  19. data/lib/treequel/schema/objectclass.rb +70 -5
  20. data/lib/treequel/schema/table.rb +5 -15
  21. data/lib/treequel/schema.rb +64 -1
  22. data/lib/treequel.rb +5 -5
  23. data/rake/documentation.rb +27 -0
  24. data/rake/hg.rb +14 -2
  25. data/rake/manual.rb +1 -1
  26. data/spec/lib/constants.rb +9 -7
  27. data/spec/lib/control_behavior.rb +1 -0
  28. data/spec/lib/matchers.rb +1 -0
  29. data/spec/treequel/branch_spec.rb +229 -20
  30. data/spec/treequel/branchcollection_spec.rb +73 -39
  31. data/spec/treequel/branchset_spec.rb +59 -8
  32. data/spec/treequel/control_spec.rb +1 -0
  33. data/spec/treequel/controls/contentsync_spec.rb +1 -0
  34. data/spec/treequel/controls/pagedresults_spec.rb +1 -0
  35. data/spec/treequel/controls/sortedresults_spec.rb +1 -0
  36. data/spec/treequel/directory_spec.rb +46 -10
  37. data/spec/treequel/filter_spec.rb +28 -5
  38. data/spec/treequel/mixins_spec.rb +7 -14
  39. data/spec/treequel/model/objectclass_spec.rb +330 -0
  40. data/spec/treequel/model_spec.rb +433 -0
  41. data/spec/treequel/monkeypatches_spec.rb +118 -0
  42. data/spec/treequel/schema/attributetype_spec.rb +116 -0
  43. data/spec/treequel/schema/ldapsyntax_spec.rb +8 -0
  44. data/spec/treequel/schema/matchingrule_spec.rb +6 -1
  45. data/spec/treequel/schema/matchingruleuse_spec.rb +5 -0
  46. data/spec/treequel/schema/objectclass_spec.rb +41 -3
  47. data/spec/treequel/schema/table_spec.rb +31 -18
  48. data/spec/treequel/schema_spec.rb +13 -16
  49. data/spec/treequel_spec.rb +22 -0
  50. data.tar.gz.sig +1 -0
  51. metadata +40 -7
  52. metadata.gz.sig +0 -0
  53. data/spec/treequel/utils_spec.rb +0 -49
@@ -6,6 +6,7 @@ BEGIN {
6
6
 
7
7
  libdir = basedir + "lib"
8
8
 
9
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
9
10
  $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
10
11
  }
11
12
 
@@ -29,6 +30,7 @@ describe Treequel::Branch do
29
30
  include Treequel::SpecHelpers,
30
31
  Treequel::Matchers
31
32
 
33
+
32
34
  before( :all ) do
33
35
  setup_logging( :fatal )
34
36
  end
@@ -68,6 +70,12 @@ describe Treequel::Branch do
68
70
  branch.entry.should == entry
69
71
  end
70
72
 
73
+ it "raises an exception if constructed with something other than a Hash entry" do
74
+ expect {
75
+ Treequel::Branch.new( @directory, TEST_PEOPLE_DN, 18 )
76
+ }.to raise_exception( ArgumentError, /can't cast/i )
77
+ end
78
+
71
79
  it "can be configured to include operational attributes for all future instances" do
72
80
  Treequel::Branch.include_operational_attrs = false
73
81
  Treequel::Branch.new( @directory, TEST_PEOPLE_DN ).include_operational_attrs?.should be_false
@@ -89,7 +97,8 @@ describe Treequel::Branch do
89
97
  @schema.stub!( :attribute_types ).
90
98
  and_return({ :cn => :a_value, :ou => :a_value })
91
99
 
92
- @attribute_type = mock( "schema attribute type object" )
100
+ @syntax = stub( "attribute ldapSyntax object", :oid => OIDS::STRING_SYNTAX )
101
+ @attribute_type = mock( "schema attribute type object", :syntax => @syntax )
93
102
  end
94
103
 
95
104
 
@@ -110,6 +119,11 @@ describe Treequel::Branch do
110
119
  @branch.split_dn( 2 ).should include( TEST_HOSTS_RDN, TEST_BASE_DN )
111
120
  end
112
121
 
122
+ it "can return itself as an ldap:// URI" do
123
+ @directory.should_receive( :uri ).and_return( URI.parse("ldap://#{TEST_HOST}/#{TEST_BASE_DN}") )
124
+ @branch.uri.to_s.should == "ldap://#{TEST_HOST}/#{TEST_HOSTS_DN}?"
125
+ end
126
+
113
127
  it "are Comparable if they are siblings" do
114
128
  sibling = Treequel::Branch.new( @directory, TEST_PEOPLE_DN )
115
129
 
@@ -182,6 +196,19 @@ describe Treequel::Branch do
182
196
  end
183
197
 
184
198
 
199
+ it "can fetch a child entry by RDN" do
200
+ res = @branch.get_child( 'cn=surprise' )
201
+ res.should be_a( Treequel::Branch )
202
+ res.dn.should == [ 'cn=surprise', @branch.dn ].join( ',' )
203
+ end
204
+
205
+ it "can fetch a child entry by RDN if its DN is the empty String" do
206
+ @branch.dn = ''
207
+ res = @branch.get_child( 'cn=surprise' )
208
+ res.should be_a( Treequel::Branch )
209
+ res.dn.should == 'cn=surprise'
210
+ end
211
+
185
212
  it "create sub-branches for messages that match valid attributeType OIDs" do
186
213
  @schema.should_receive( :attribute_types ).twice.
187
214
  and_return({ :cn => :a_value, :ou => :a_value })
@@ -287,17 +314,19 @@ describe Treequel::Branch do
287
314
 
288
315
  it "knows which objectClasses it has" do
289
316
  oc_attr = mock( "objectClass attributeType object" )
317
+ string_syntax = stub( "string ldapSyntax object", :oid => OIDS::STRING_SYNTAX )
290
318
  @schema.should_receive( :attribute_types ).and_return({ :objectClass => oc_attr })
291
319
  oc_attr.should_receive( :single? ).and_return( false )
292
- oc_attr.should_receive( :syntax_oid ).and_return( OIDS::STRING_SYNTAX )
320
+ oc_attr.should_receive( :syntax ).at_least( :once ).
321
+ and_return( string_syntax )
293
322
 
294
323
  @entry.should_receive( :[] ).with( 'objectClass' ).at_least( :once ).
295
324
  and_return([ 'organizationalUnit', 'extensibleObject' ])
296
325
 
297
- @directory.should_receive( :convert_syntax_value ).
326
+ @directory.should_receive( :convert_to_object ).
298
327
  with( OIDS::STRING_SYNTAX, 'organizationalUnit' ).
299
328
  and_return( 'organizationalUnit' )
300
- @directory.should_receive( :convert_syntax_value ).
329
+ @directory.should_receive( :convert_to_object ).
301
330
  with( OIDS::STRING_SYNTAX, 'extensibleObject' ).
302
331
  and_return( 'extensibleObject' )
303
332
 
@@ -309,6 +338,42 @@ describe Treequel::Branch do
309
338
  @branch.object_classes.should == [ :ou_objectclass, :extobj_objectclass ]
310
339
  end
311
340
 
341
+ it "knows what operational attributes it has" do
342
+ op_attrs = MINIMAL_OPERATIONAL_ATTRIBUTES.inject({}) do |hash, oa|
343
+ hash[ oa ] = mock("#{oa} attributeType object")
344
+ hash
345
+ end
346
+ @schema.should_receive( :operational_attribute_types ).and_return( op_attrs.values )
347
+
348
+ @branch.operational_attribute_types.should == op_attrs.values
349
+ end
350
+
351
+ it "knows what the OIDs of its operational attributes are" do
352
+ op_attrs = MINIMAL_OPERATIONAL_ATTRIBUTES.inject({}) do |hash, oa|
353
+ hash[ oa ] = stub("#{oa} attributeType object", :oid => :an_oid )
354
+ hash
355
+ end
356
+ @schema.should_receive( :operational_attribute_types ).at_least( :once ).
357
+ and_return( op_attrs.values )
358
+
359
+ @branch.operational_attribute_oids.should have( op_attrs.length ).members
360
+ @branch.operational_attribute_oids.should include( :an_oid )
361
+ end
362
+
363
+ it "can return the set of all its MUST attributes' OIDs based on which objectClasses " +
364
+ "it has" do
365
+ oc1 = mock( "first objectclass" )
366
+ oc2 = mock( "second objectclass" )
367
+
368
+ @branch.should_receive( :object_classes ).and_return([ oc1, oc2 ])
369
+ oc1.should_receive( :must_oids ).at_least( :once ).and_return([ :oid1, :oid2 ])
370
+ oc2.should_receive( :must_oids ).at_least( :once ).and_return([ :oid1, :oid3 ])
371
+
372
+ must_oids = @branch.must_oids
373
+ must_oids.should have( 3 ).members
374
+ must_oids.should include( :oid1, :oid2, :oid3 )
375
+ end
376
+
312
377
  it "can return the set of all its MUST attributeTypes based on which objectClasses it has" do
313
378
  oc1 = mock( "first objectclass" )
314
379
  oc2 = mock( "second objectclass" )
@@ -323,7 +388,7 @@ describe Treequel::Branch do
323
388
  end
324
389
 
325
390
  it "can return a Hash pre-populated with pairs that correspond to its MUST attributes" do
326
- cn_attrtype = mock( "cn attribute type", :single? => true )
391
+ cn_attrtype = mock( "cn attribute type", :single? => false )
327
392
  l_attrtype = mock( "l attribute type", :single? => true )
328
393
  objectClass_attrtype = mock( "objectClass attribute type", :single? => false )
329
394
 
@@ -335,10 +400,24 @@ describe Treequel::Branch do
335
400
  and_return([ cn_attrtype, l_attrtype, objectClass_attrtype ])
336
401
 
337
402
  @branch.must_attributes_hash.
338
- should == { :cn => '', :l => '', :objectClass => [:top] }
403
+ should == { :cn => [''], :l => '', :objectClass => [:top] }
339
404
  end
340
405
 
341
406
 
407
+ it "can return the set of all its MAY attributes' OIDs based on which objectClasses " +
408
+ "it has" do
409
+ oc1 = mock( "first objectclass" )
410
+ oc2 = mock( "second objectclass" )
411
+
412
+ @branch.should_receive( :object_classes ).and_return([ oc1, oc2 ])
413
+ oc1.should_receive( :may_oids ).at_least( :once ).and_return([ :oid1, :oid2 ])
414
+ oc2.should_receive( :may_oids ).at_least( :once ).and_return([ :oid1, :oid3 ])
415
+
416
+ must_oids = @branch.may_oids
417
+ must_oids.should have( 3 ).members
418
+ must_oids.should include( :oid1, :oid2, :oid3 )
419
+ end
420
+
342
421
  it "can return the set of all its MAY attributeTypes based on which objectClasses it has" do
343
422
  oc1 = mock( "first objectclass" )
344
423
  oc2 = mock( "second objectclass" )
@@ -352,20 +431,67 @@ describe Treequel::Branch do
352
431
  must_attrs.should include( :description, :mobilePhone, :chunktype )
353
432
  end
354
433
 
434
+ it "can return a Hash pre-populated with pairs that correspond to its MAY attributes" do
435
+ cn_attrtype = mock( "cn attribute type", :single? => false )
436
+ l_attrtype = mock( "l attribute type", :single? => true )
437
+
438
+ cn_attrtype.should_receive( :name ).at_least( :once ).and_return( :cn )
439
+ l_attrtype.should_receive( :name ).at_least( :once ).and_return( :l )
440
+
441
+ @branch.should_receive( :may_attribute_types ).at_least( :once ).
442
+ and_return([ cn_attrtype, l_attrtype ])
443
+
444
+ @branch.may_attributes_hash.
445
+ should == { :cn => [], :l => nil }
446
+ end
447
+
355
448
  it "can return the set of all of its valid attributeTypes, which is a union of its " +
356
- "MUST and MAY attributes" do
449
+ "MUST and MAY attributes plus the directory's operational attributes" do
357
450
  @branch.should_receive( :must_attribute_types ).
358
451
  and_return([ :cn, :l, :uid ])
359
452
  @branch.should_receive( :may_attribute_types ).
360
453
  and_return([ :description, :mobilePhone, :chunktype ])
454
+ @branch.should_receive( :operational_attribute_types ).
455
+ and_return([ :createTimestamp, :creatorsName ])
361
456
 
362
457
  all_attrs = @branch.valid_attribute_types
363
458
 
364
- all_attrs.should have( 6 ).members
365
- all_attrs.should include( :cn, :uid, :l, :description, :mobilePhone, :chunktype )
459
+ all_attrs.should have( 8 ).members
460
+ all_attrs.should include( :cn, :uid, :l, :description, :mobilePhone,
461
+ :chunktype, :createTimestamp, :creatorsName )
462
+ end
463
+
464
+ it "can return a Hash pre-populated with pairs that correspond to all of its valid " +
465
+ "attributes" do
466
+ @branch.should_receive( :must_attributes_hash ).at_least( :once ).
467
+ and_return({ :cn => [''], :l => '', :objectClass => [:top] })
468
+ @branch.should_receive( :may_attributes_hash ).at_least( :once ).
469
+ and_return({ :description => nil, :givenName => [], :cn => nil })
470
+
471
+ @branch.valid_attributes_hash.should == {
472
+ :cn => [''],
473
+ :l => '',
474
+ :objectClass => [:top],
475
+ :description => nil,
476
+ :givenName => [],
477
+ }
478
+ end
479
+
480
+
481
+ it "can return the set of all of its valid attribute OIDs, which is a union of its " +
482
+ "MUST and MAY attribute OIDs" do
483
+ @branch.should_receive( :must_oids ).
484
+ and_return([ :must_oid1, :must_oid2 ])
485
+ @branch.should_receive( :may_oids ).
486
+ and_return([ :may_oid1, :may_oid2, :must_oid1 ])
487
+
488
+ all_attr_oids = @branch.valid_attribute_oids
489
+
490
+ all_attr_oids.should have( 4 ).members
491
+ all_attr_oids.should include( :must_oid1, :must_oid2, :may_oid1, :may_oid2 )
366
492
  end
367
493
 
368
- it "knows if a attribute is valid given its objectClasses" do
494
+ it "knows if an attribute is valid given its objectClasses" do
369
495
  attrtype = mock( "attribute type object" )
370
496
 
371
497
  @branch.should_receive( :valid_attribute_types ).
@@ -487,6 +613,12 @@ describe Treequel::Branch do
487
613
  @branch.delete( :objectClass => ['apple-user',:inetOrgPerson], :cn => [] )
488
614
  end
489
615
 
616
+ it "deletes its entry entirely if no attributes are specified" do
617
+ @directory.should_receive( :delete ).with( @branch )
618
+ @branch.delete
619
+ end
620
+
621
+
490
622
  it "knows how to represent its DN as an RFC1781-style UFN" do
491
623
  @branch.to_ufn.should =~ /Hosts, acme\.com/i
492
624
  end
@@ -505,6 +637,82 @@ describe Treequel::Branch do
505
637
  end
506
638
 
507
639
 
640
+ LONG_TEST_VALUE = 'A poet once said, "The whole universe is in ' +
641
+ 'a glass of wine." We will probably never know in what sense ' +
642
+ 'he meant that, for poets do not write to be understood. But ' +
643
+ 'it is true that if we look at a glass of wine closely enough ' +
644
+ 'we see the entire universe.'
645
+
646
+ it "knows how to split long lines in LDIF output" do
647
+ @entry.should_receive( :keys ).and_return([ 'description', 'l' ])
648
+ @entry.should_receive( :[] ).with( 'description' ).
649
+ and_return([ LONG_TEST_VALUE ])
650
+ @entry.should_receive( :[] ).with( 'l' ).
651
+ and_return([ 'Antartica', 'Galapagos' ])
652
+
653
+ ldif = @branch.to_ldif( 20 )
654
+ val = ldif[ /(description: (?:[^\n]|\n )+)/, 1 ]
655
+ lines = val.split( /\n/ )
656
+
657
+ lines.first.should =~ /.{20}/
658
+ lines[1..-2].each do |line|
659
+ line.should =~ / .{19}/
660
+ end
661
+ lines.last.should =~ / .{1,19}/
662
+ end
663
+
664
+
665
+ LONG_BINARY_TEST_VALUE = ( <<-END_VALUE ).gsub( /^\t{2}/, '' )
666
+ Once there came a man
667
+ Who said,
668
+ "Range me all men of the world in rows."
669
+ And instantly
670
+ There was terrific clamour among the people
671
+ Against being ranged in rows.
672
+ There was a loud quarrel, world-wide.
673
+ It endured for ages;
674
+ And blood was shed
675
+ By those who would not stand in rows,
676
+ And by those who pined to stand in rows.
677
+ Eventually, the man went to death, weeping.
678
+ And those who staid in bloody scuffle
679
+ Knew not the great simplicity.
680
+ END_VALUE
681
+
682
+ it "knows how to split long binary lines in LDIF output" do
683
+ @entry.should_receive( :keys ).and_return([ 'description', 'l' ])
684
+ @entry.should_receive( :[] ).with( 'description' ).
685
+ and_return([ LONG_BINARY_TEST_VALUE ])
686
+ @entry.should_receive( :[] ).with( 'l' ).
687
+ and_return([ 'Antartica', 'Galapagos' ])
688
+
689
+ ldif = @branch.to_ldif( 20 )
690
+ ldif.scan( /^description/ ).length.should == 1
691
+
692
+ val = ldif[ /^(description:: (?:[^\n]|\n )+)/, 1 ]
693
+ lines = val.split( /\n/ )
694
+ lines.first.should =~ /.{20}/
695
+ lines[1..-2].each do |line|
696
+ line.should =~ / .{19}/
697
+ end
698
+ lines.last.should =~ / .{1,19}/
699
+ end
700
+
701
+
702
+ it "knows how to represent itself as a Hash" do
703
+ @entry.should_receive( :keys ).and_return([ 'description', 'dn', 'l' ])
704
+ @entry.should_receive( :[] ).with( 'description' ).
705
+ and_return([ 'A chilly little penguin.' ])
706
+ @entry.should_receive( :[] ).with( 'l' ).
707
+ and_return([ 'Antartica', 'Galapagos' ])
708
+
709
+ @branch.to_hash.should == {
710
+ 'description' => ['A chilly little penguin.'],
711
+ 'l' => [ 'Antartica', 'Galapagos' ],
712
+ 'dn' => TEST_HOSTS_DN,
713
+ }
714
+ end
715
+
508
716
  it "returns a Treequel::BranchCollection with equivalent Branchsets if added to another " +
509
717
  "Branch" do
510
718
  other_branch = Treequel::Branch.new( @directory, TEST_SUBHOSTS_DN )
@@ -527,8 +735,8 @@ describe Treequel::Branch do
527
735
  @entry.should_receive( :[] ).with( 'glumpy' ).at_least( :once ).
528
736
  and_return([ 'glumpa1', 'glumpa2' ])
529
737
 
530
- @attribute_type.stub!( :syntax_oid ).and_return( OIDS::STRING_SYNTAX )
531
- @directory.stub!( :convert_syntax_value ).and_return {|_,str| str }
738
+ @attribute_type.stub!( :syntax ).and_return( @syntax )
739
+ @directory.stub!( :convert_to_object ).and_return {|_,str| str }
532
740
 
533
741
  @branch[ :glumpy ].should == [ 'glumpa1', 'glumpa2' ]
534
742
  end
@@ -539,8 +747,8 @@ describe Treequel::Branch do
539
747
  @entry.should_receive( :[] ).with( 'glumpy' ).at_least( :once ).
540
748
  and_return([ 'glumpa1' ])
541
749
 
542
- @attribute_type.stub!( :syntax_oid ).and_return( OIDS::STRING_SYNTAX )
543
- @directory.stub!( :convert_syntax_value ).and_return {|_,str| str }
750
+ @attribute_type.stub!( :syntax ).and_return( @syntax )
751
+ @directory.stub!( :convert_to_object ).and_return {|_,str| str }
544
752
 
545
753
  @branch[ :glumpy ].should == 'glumpa1'
546
754
  end
@@ -560,8 +768,8 @@ describe Treequel::Branch do
560
768
  it "caches the value fetched from its entry" do
561
769
  @schema.stub!( :attribute_types ).and_return({ :glump => @attribute_type })
562
770
  @attribute_type.stub!( :single? ).and_return( true )
563
- @attribute_type.stub!( :syntax_oid ).and_return( OIDS::STRING_SYNTAX )
564
- @directory.stub!( :convert_syntax_value ).and_return {|_,str| str }
771
+ @attribute_type.stub!( :syntax ).and_return( @syntax )
772
+ @directory.stub!( :convert_to_object ).and_return {|_,str| str }
565
773
  @entry.should_receive( :[] ).with( 'glump' ).once.and_return( [:a_value] )
566
774
  2.times { @branch[ :glump ] }
567
775
  end
@@ -571,8 +779,8 @@ describe Treequel::Branch do
571
779
  @attribute_type.should_receive( :single? ).and_return( true )
572
780
  @entry.should_receive( :[] ).with( 'bvector' ).at_least( :once ).
573
781
  and_return([ '010011010101B' ])
574
- @attribute_type.should_receive( :syntax_oid ).and_return( OIDS::BIT_STRING_SYNTAX )
575
- @directory.should_receive( :convert_syntax_value ).
782
+ @syntax.stub!( :oid ).and_return( OIDS::BIT_STRING_SYNTAX )
783
+ @directory.should_receive( :convert_to_object ).
576
784
  with( OIDS::BIT_STRING_SYNTAX, '010011010101B' ).
577
785
  and_return( 1237 )
578
786
 
@@ -599,11 +807,12 @@ describe Treequel::Branch do
599
807
  it "clears the cache after a successful write" do
600
808
  @schema.stub!( :attribute_types ).and_return({ :glorpy => @attribute_type })
601
809
  @attribute_type.stub!( :single? ).and_return( true )
602
- @attribute_type.stub!( :syntax_oid ).and_return( OIDS::STRING_SYNTAX )
603
- @directory.stub!( :convert_syntax_value ).and_return {|_,val| val }
810
+ @attribute_type.stub!( :syntax ).and_return( @syntax )
811
+ @directory.stub!( :convert_to_object ).and_return {|_,val| val }
604
812
  @entry.should_receive( :[] ).with( 'glorpy' ).and_return( [:firstval], [:secondval] )
605
813
 
606
814
  @directory.should_receive( :modify ).with( @branch, {'glorpy' => ['chunks']} )
815
+ @directory.stub!( :convert_to_attribute ).and_return {|_,val| val }
607
816
  @entry.should_receive( :[]= ).with( 'glorpy', ['chunks'] )
608
817
 
609
818
  @branch[ :glorpy ].should == :firstval
@@ -6,22 +6,15 @@ BEGIN {
6
6
 
7
7
  libdir = basedir + "lib"
8
8
 
9
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
9
10
  $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
10
11
  }
11
12
 
12
- begin
13
- require 'spec'
14
- require 'spec/lib/constants'
15
- require 'spec/lib/helpers'
13
+ require 'spec'
14
+ require 'spec/lib/constants'
15
+ require 'spec/lib/helpers'
16
16
 
17
- require 'treequel/branchcollection'
18
- rescue LoadError
19
- unless Object.const_defined?( :Gem )
20
- require 'rubygems'
21
- retry
22
- end
23
- raise
24
- end
17
+ require 'treequel/branchcollection'
25
18
 
26
19
 
27
20
  include Treequel::TestConstants
@@ -42,7 +35,7 @@ describe Treequel::BranchCollection do
42
35
  end
43
36
 
44
37
  before( :each ) do
45
- @directory = mock( "treequel directory ")
38
+ @directory = mock( "treequel directory", :registered_controls => [] )
46
39
  end
47
40
 
48
41
  it "can be instantiated without any branchsets" do
@@ -51,8 +44,10 @@ describe Treequel::BranchCollection do
51
44
  end
52
45
 
53
46
  it "can be instantiated with one or more branchsets" do
54
- branchset1 = stub( "branchset 1", :dn => 'cn=example1,dc=acme,dc=com', :each => 1 )
55
- branchset2 = stub( "branchset 2", :dn => 'cn=example2,dc=acme,dc=com', :each => 1 )
47
+ branch1 = stub( "branch for branchset 1", :directory => @directory )
48
+ branchset1 = Treequel::Branchset.new( branch1 )
49
+ branch2 = stub( "branch for branchset 2", :directory => @directory )
50
+ branchset2 = Treequel::Branchset.new( branch2 )
56
51
 
57
52
  collection = Treequel::BranchCollection.new( branchset1, branchset2 )
58
53
 
@@ -60,17 +55,17 @@ describe Treequel::BranchCollection do
60
55
  end
61
56
 
62
57
  it "wraps any object that doesn't have an #each in a Branchset" do
63
- non_branchset1 = stub( "non-branchset 1" )
64
- non_branchset2 = stub( "non-branchset 2" )
65
- branchset1 = stub( "branchset 1", :dn => 'cn=example1,dc=acme,dc=com' )
66
- branchset2 = stub( "branchset 2", :dn => 'cn=example2,dc=acme,dc=com' )
58
+ branch1 = stub( "branch for branchset 1", :directory => @directory )
59
+ branchset1 = Treequel::Branchset.new( branch1 )
60
+ branch2 = stub( "branch for branchset 2", :directory => @directory )
61
+ branchset2 = Treequel::Branchset.new( branch2 )
67
62
 
68
- Treequel::Branchset.should_receive( :new ).with( non_branchset1 ).
63
+ Treequel::Branchset.should_receive( :new ).with( :non_branchset1 ).
69
64
  and_return( branchset1 )
70
- Treequel::Branchset.should_receive( :new ).with( non_branchset2 ).
65
+ Treequel::Branchset.should_receive( :new ).with( :non_branchset2 ).
71
66
  and_return( branchset2 )
72
67
 
73
- collection = Treequel::BranchCollection.new( non_branchset1, non_branchset2 )
68
+ collection = Treequel::BranchCollection.new( :non_branchset1, :non_branchset2 )
74
69
 
75
70
  collection.branchsets.should include( branchset1, branchset2 )
76
71
  end
@@ -99,8 +94,13 @@ describe Treequel::BranchCollection do
99
94
  describe "instance with two Branchsets" do
100
95
 
101
96
  before( :each ) do
102
- @branchset1 = mock( "branchset 1", :dn => 'cn=example1,dc=acme,dc=com', :each => 1 )
103
- @branchset2 = mock( "branchset 2", :dn => 'cn=example2,dc=acme,dc=com', :each => 1 )
97
+ # @branchset1 = mock( "branchset 1", :dn => 'cn=example1,dc=acme,dc=com', :each => 1 )
98
+ # @branchset2 = mock( "branchset 2", :dn => 'cn=example2,dc=acme,dc=com', :each => 1 )
99
+ @branch1 = mock( "branch1", :directory => @directory )
100
+ @branchset1 = Treequel::Branchset.new( @branch1 )
101
+
102
+ @branch2 = mock( "branch2", :directory => @directory )
103
+ @branchset2 = Treequel::Branchset.new( @branch2 )
104
104
 
105
105
  @collection = Treequel::BranchCollection.new( @branchset1, @branchset2 )
106
106
  end
@@ -134,26 +134,51 @@ describe Treequel::BranchCollection do
134
134
  end
135
135
 
136
136
  it "returns a clone of itself with an additional Branchset if a Branchset is added to it" do
137
- branchset3 = mock( "branchset 3", :dn => 'cn=example3,dc=acme,dc=com', :each => 1 )
137
+ branch3 = mock( "branch 3", :directory => @directory )
138
+ branchset3 = Treequel::Branchset.new( branch3 )
139
+
138
140
  new_collection = @collection + branchset3
139
141
 
140
142
  new_collection.should be_an_instance_of( Treequel::BranchCollection )
141
143
  new_collection.should include( @branchset1, @branchset2, branchset3 )
142
144
  end
143
145
 
144
- it "returns a clone of itself with an additional Branchset if a Branch is added to it" do
145
- branchset3 = mock( "branchset 3", :dn => 'cn=example3,dc=acme,dc=com', :each => 1 )
146
- branch3 = mock( "branch 3", :branchset => branchset3 )
147
- new_collection = @collection + branch3
146
+ it "returns all of the results from each of its branchsets plus the added branch if a " +
147
+ "Branch is added to it" do
148
+ @branchset1.should_receive( :each ).and_yield( :bs1_stuff )
149
+ @branchset2.should_receive( :each ).and_yield( :bs2_stuff )
150
+ added_branch = stub( "added branch", :directory => @directory )
151
+ added_branch.stub!( :to_ary ).and_return( [added_branch] )
148
152
 
149
- new_collection.should be_an_instance_of( Treequel::BranchCollection )
150
- new_collection.should include( @branchset1, @branchset2, branchset3 )
153
+ results = @collection + added_branch
154
+
155
+ results.should have( 3 ).members
156
+ results.should include( :bs1_stuff, :bs2_stuff, added_branch )
157
+ end
158
+
159
+ it "returns all of the results from each of its branchsets minus the subtracted branch " +
160
+ "if a Branch is subtracted from it" do
161
+ results_branch1 = stub( "results branch 1", :dn => TEST_PERSON_DN )
162
+ results_branch2 = stub( "results branch 2", :dn => TEST_PERSON2_DN )
163
+ subtracted_branch = stub( "subtracted branch", :dn => TEST_PERSON_DN )
164
+
165
+ @branchset1.should_receive( :each ).and_yield( results_branch1 )
166
+ @branchset2.should_receive( :each ).and_yield( results_branch2 )
167
+
168
+ results = @collection - subtracted_branch
169
+
170
+ results.should have( 1 ).members
171
+ results.should_not include( subtracted_branch )
172
+ results.should_not include( results_branch1 )
151
173
  end
152
174
 
153
175
  it "returns a clone of itself with both collections' Branchsets if a BranchCollection is " +
154
176
  "added to it" do
155
- branchset3 = stub( "branchset 3", :dn => 'cn=example3,dc=acme,dc=com', :each => 1 )
156
- branchset4 = stub( "branchset 4", :dn => 'cn=example4,dc=acme,dc=com', :each => 1 )
177
+ branch3 = stub( "branch for branchset 3", :directory => @directory )
178
+ branchset3 = Treequel::Branchset.new( branch3 )
179
+ branch4 = stub( "branch for branchset 4", :directory => @directory )
180
+ branchset4 = Treequel::Branchset.new( branch4 )
181
+
157
182
  other_collection = Treequel::BranchCollection.new( branchset3, branchset4 )
158
183
 
159
184
  new_collection = @collection + other_collection
@@ -164,8 +189,11 @@ describe Treequel::BranchCollection do
164
189
 
165
190
  it "returns a new BranchCollection with the union of Branchsets if it is ORed with " +
166
191
  "another BranchCollection" do
167
- branchset3 = stub( "branchset 3", :dn => 'cn=example3,dc=acme,dc=com', :each => 1 )
168
- branchset4 = stub( "branchset 4", :dn => 'cn=example4,dc=acme,dc=com', :each => 1 )
192
+ branch3 = stub( "branch for branchset 3", :directory => @directory )
193
+ branchset3 = Treequel::Branchset.new( branch3 )
194
+ branch4 = stub( "branch for branchset 4", :directory => @directory )
195
+ branchset4 = Treequel::Branchset.new( branch4 )
196
+
169
197
  other_collection = Treequel::BranchCollection.new( branchset3, branchset4 )
170
198
 
171
199
  new_collection = @collection | other_collection
@@ -176,8 +204,11 @@ describe Treequel::BranchCollection do
176
204
 
177
205
  it "returns a new BranchCollection with the intersection of Branchsets if it is ANDed with " +
178
206
  "another BranchCollection" do
179
- branchset3 = stub( "branchset 3", :dn => 'cn=example3,dc=acme,dc=com', :each => 1 )
180
- branchset4 = stub( "branchset 4", :dn => 'cn=example4,dc=acme,dc=com', :each => 1 )
207
+ branch3 = stub( "branch for branchset 3", :directory => @directory )
208
+ branchset3 = Treequel::Branchset.new( branch3 )
209
+ branch4 = stub( "branch for branchset 4", :directory => @directory )
210
+ branchset4 = Treequel::Branchset.new( branch4 )
211
+
181
212
  other_collection = Treequel::BranchCollection.new( @branchset2, branchset3, branchset4 )
182
213
  @collection << branchset4
183
214
 
@@ -188,8 +219,11 @@ describe Treequel::BranchCollection do
188
219
  end
189
220
 
190
221
  it "can create a clone of itself with filtered branchsets" do
191
- filtered_branchset1 = stub( "branchset 3", :dn => 'cn=example3,dc=acme,dc=com', :each => 1 )
192
- filtered_branchset2 = stub( "branchset 4", :dn => 'cn=example4,dc=acme,dc=com', :each => 1 )
222
+ branch3 = stub( "branch for branchset 3", :directory => @directory )
223
+ filtered_branchset1 = Treequel::Branchset.new( branch3 )
224
+ branch4 = stub( "branch for branchset 4", :directory => @directory )
225
+ filtered_branchset2 = Treequel::Branchset.new( branch4 )
226
+
193
227
  @branchset1.should_receive( :filter ).with( :cn => 'chunkalicious' ).
194
228
  and_return( filtered_branchset1 )
195
229
  @branchset2.should_receive( :filter ).with( :cn => 'chunkalicious' ).