treequel 1.0.1 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +176 -14
- data/LICENSE +1 -1
- data/Rakefile +61 -45
- data/Rakefile.local +20 -0
- data/bin/treequel +502 -269
- data/examples/ldap-rack-auth.rb +2 -0
- data/lib/treequel.rb +221 -18
- data/lib/treequel/branch.rb +410 -201
- data/lib/treequel/branchcollection.rb +25 -13
- data/lib/treequel/branchset.rb +42 -40
- data/lib/treequel/constants.rb +233 -3
- data/lib/treequel/control.rb +95 -0
- data/lib/treequel/controls/contentsync.rb +138 -0
- data/lib/treequel/controls/pagedresults.rb +162 -0
- data/lib/treequel/controls/sortedresults.rb +216 -0
- data/lib/treequel/directory.rb +212 -65
- data/lib/treequel/exceptions.rb +11 -12
- data/lib/treequel/filter.rb +1 -12
- data/lib/treequel/mixins.rb +83 -47
- data/lib/treequel/monkeypatches.rb +29 -0
- data/lib/treequel/schema.rb +23 -19
- data/lib/treequel/schema/attributetype.rb +33 -3
- data/lib/treequel/schema/ldapsyntax.rb +0 -11
- data/lib/treequel/schema/matchingrule.rb +0 -11
- data/lib/treequel/schema/matchingruleuse.rb +0 -11
- data/lib/treequel/schema/objectclass.rb +36 -10
- data/lib/treequel/schema/table.rb +159 -0
- data/lib/treequel/sequel_integration.rb +7 -7
- data/lib/treequel/utils.rb +4 -66
- data/rake/documentation.rb +89 -0
- data/rake/helpers.rb +375 -307
- data/rake/hg.rb +16 -2
- data/rake/manual.rb +11 -6
- data/rake/packaging.rb +20 -35
- data/rake/publishing.rb +22 -62
- data/spec/lib/constants.rb +20 -0
- data/spec/lib/control_behavior.rb +44 -0
- data/spec/lib/matchers.rb +51 -0
- data/spec/treequel/branch_spec.rb +88 -29
- data/spec/treequel/branchcollection_spec.rb +24 -1
- data/spec/treequel/branchset_spec.rb +123 -51
- data/spec/treequel/control_spec.rb +48 -0
- data/spec/treequel/controls/contentsync_spec.rb +38 -0
- data/spec/treequel/controls/pagedresults_spec.rb +138 -0
- data/spec/treequel/controls/sortedresults_spec.rb +171 -0
- data/spec/treequel/directory_spec.rb +186 -16
- data/spec/treequel/mixins_spec.rb +42 -3
- data/spec/treequel/schema/attributetype_spec.rb +22 -20
- data/spec/treequel/schema/objectclass_spec.rb +67 -46
- data/spec/treequel/schema/table_spec.rb +134 -0
- data/spec/treequel_spec.rb +277 -15
- metadata +89 -108
- data/bin/treequel.orig +0 -963
- data/examples/ldap-monitor.rb +0 -143
- data/examples/ldap-monitor/public/css/master.css +0 -328
- data/examples/ldap-monitor/public/images/card_small.png +0 -0
- data/examples/ldap-monitor/public/images/chain_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small_green.png +0 -0
- data/examples/ldap-monitor/public/images/plug.png +0 -0
- data/examples/ldap-monitor/public/images/shadows/large-30-down.png +0 -0
- data/examples/ldap-monitor/public/images/tick.png +0 -0
- data/examples/ldap-monitor/public/images/tick_circle.png +0 -0
- data/examples/ldap-monitor/public/images/treequel-favicon.png +0 -0
- data/examples/ldap-monitor/views/backends.erb +0 -41
- data/examples/ldap-monitor/views/connections.erb +0 -74
- data/examples/ldap-monitor/views/databases.erb +0 -39
- data/examples/ldap-monitor/views/dump_subsystem.erb +0 -14
- data/examples/ldap-monitor/views/index.erb +0 -14
- data/examples/ldap-monitor/views/layout.erb +0 -35
- data/examples/ldap-monitor/views/listeners.erb +0 -30
- data/rake/rdoc.rb +0 -30
- data/rake/win32.rb +0 -190
@@ -0,0 +1,171 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'spec'
|
13
|
+
require 'spec/lib/constants'
|
14
|
+
require 'spec/lib/helpers'
|
15
|
+
require 'spec/lib/control_behavior'
|
16
|
+
|
17
|
+
require 'treequel'
|
18
|
+
require 'treequel/branchset'
|
19
|
+
require 'treequel/controls/sortedresults'
|
20
|
+
|
21
|
+
include Treequel::TestConstants
|
22
|
+
include Treequel::Constants
|
23
|
+
|
24
|
+
#####################################################################
|
25
|
+
### C O N T E X T S
|
26
|
+
#####################################################################
|
27
|
+
describe Treequel::SortedResultsControl do
|
28
|
+
include Treequel::SpecHelpers
|
29
|
+
|
30
|
+
before( :all ) do
|
31
|
+
setup_logging( :fatal )
|
32
|
+
end
|
33
|
+
|
34
|
+
before( :each ) do
|
35
|
+
# Used by the shared behavior
|
36
|
+
@control = Treequel::SortedResultsControl
|
37
|
+
@branch = mock( "Branch", :dn => 'cn=example,dc=acme,dc=com' )
|
38
|
+
@directory = mock( "Directory" )
|
39
|
+
|
40
|
+
@branch.stub!( :directory ).and_return( @directory )
|
41
|
+
@directory.stub!( :registered_controls ).and_return([ Treequel::SortedResultsControl ])
|
42
|
+
@branchset = Treequel::Branchset.new( @branch )
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
after( :all ) do
|
47
|
+
reset_logging()
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
it_should_behave_like "A Treequel::Control"
|
52
|
+
|
53
|
+
|
54
|
+
it "adds a sort_order_criteria attribute to extended branchsets" do
|
55
|
+
@branchset.should respond_to( :sort_order_criteria )
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
it "can add the listed attributes as ascending sort order criteria via an #order mutator " +
|
60
|
+
"with Symbol attribute names" do
|
61
|
+
criteria = @branchset.order( :attr1, :attr2 ).sort_order_criteria
|
62
|
+
criteria.should have( 2 ).members
|
63
|
+
|
64
|
+
criteria[0].type.should == 'attr1'
|
65
|
+
criteria[0].ordering_rule.should == nil
|
66
|
+
criteria[0].reverse_order.should be_false()
|
67
|
+
|
68
|
+
criteria[1].type.should == 'attr2'
|
69
|
+
criteria[1].ordering_rule.should == nil
|
70
|
+
criteria[1].reverse_order.should be_false()
|
71
|
+
end
|
72
|
+
|
73
|
+
it "can add the listed attributes as descending sort order criteria via an #order mutator " +
|
74
|
+
"with Sequel::SQL::Expressions" do
|
75
|
+
pending "requires the 'sequel' library" unless Sequel.const_defined?( :Model )
|
76
|
+
criteria = @branchset.order( :attr1.desc ).sort_order_criteria
|
77
|
+
|
78
|
+
criteria.should have( 1 ).member
|
79
|
+
criteria[0].type.should == 'attr1'
|
80
|
+
criteria[0].ordering_rule.should == nil
|
81
|
+
criteria[0].reverse_order.should be_true()
|
82
|
+
end
|
83
|
+
|
84
|
+
it "can remove existing sort order criteria via the #order mutator with no arguments" do
|
85
|
+
ordered_branchset = @branchset.order( :attr1 )
|
86
|
+
ordered_branchset.order().sort_order_criteria.should be_empty()
|
87
|
+
end
|
88
|
+
|
89
|
+
it "can remove any existing sort order criteria via an #unordered mutator" do
|
90
|
+
ordered_branchset = @branchset.order( :attr1 )
|
91
|
+
ordered_branchset.unordered.sort_order_criteria.should be_empty()
|
92
|
+
end
|
93
|
+
|
94
|
+
it "can remove any existing sort order criteria from the receiver via the #unordered! " +
|
95
|
+
"imperative method" do
|
96
|
+
ordered_branchset = @branchset.order( :attr1 )
|
97
|
+
ordered_branchset.unordered!
|
98
|
+
ordered_branchset.sort_order_criteria.should be_empty()
|
99
|
+
end
|
100
|
+
|
101
|
+
it "injects the correct server-control structure into the search when iterating" do
|
102
|
+
oid = Treequel::SortedResultsControl::OID
|
103
|
+
expected_asn1_string = "0\x060\x04\x04\x02cn"
|
104
|
+
expected_control = LDAP::Control.new( oid, expected_asn1_string, true )
|
105
|
+
|
106
|
+
resultbranch = mock( "Sorted result branch" )
|
107
|
+
resultcontrol = mock( "Sorted result control" )
|
108
|
+
|
109
|
+
@branch.should_receive( :search ).with( :subtree,
|
110
|
+
instance_of(Treequel::Filter),
|
111
|
+
{
|
112
|
+
:limit => 0,
|
113
|
+
:selectattrs => [],
|
114
|
+
:timeout => 0,
|
115
|
+
:server_controls => [ expected_control ],
|
116
|
+
:client_controls => []
|
117
|
+
}
|
118
|
+
).and_yield( resultbranch )
|
119
|
+
|
120
|
+
resultbranch.should_receive( :controls ).and_return([ resultcontrol ])
|
121
|
+
resultcontrol.should_receive( :oid ).
|
122
|
+
and_return( Treequel::SortedResultsControl::RESPONSE_OID )
|
123
|
+
resultcontrol.should_receive( :decode ).
|
124
|
+
and_return([ 0, :ignored ]) # 0 == Success
|
125
|
+
|
126
|
+
@branchset.order( :cn ).each do |*args|
|
127
|
+
args.should == [ resultbranch ]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it "raises an exception if the server returned an error in the response control" do
|
132
|
+
resultbranch = mock( "Sorted result branch" )
|
133
|
+
resultcontrol = mock( "Sorted result control" )
|
134
|
+
|
135
|
+
@branch.should_receive( :search ).and_yield( resultbranch )
|
136
|
+
|
137
|
+
resultbranch.should_receive( :controls ).and_return([ resultcontrol ])
|
138
|
+
resultcontrol.should_receive( :oid ).
|
139
|
+
and_return( Treequel::SortedResultsControl::RESPONSE_OID )
|
140
|
+
resultcontrol.should_receive( :decode ).
|
141
|
+
and_return([ 16, :ignored ]) # 16 == 'No such attribute'
|
142
|
+
|
143
|
+
expect {
|
144
|
+
@branchset.order( :cn ).each {}
|
145
|
+
}.to raise_exception( Treequel::ControlError, /no such attribute/i )
|
146
|
+
end
|
147
|
+
|
148
|
+
it "doesn't add a sort control if no sort order criteria have been set" do
|
149
|
+
resultbranch = mock( "Result branch" )
|
150
|
+
|
151
|
+
@branch.should_receive( :search ).with( :subtree,
|
152
|
+
instance_of(Treequel::Filter),
|
153
|
+
{
|
154
|
+
:limit => 0,
|
155
|
+
:selectattrs => [],
|
156
|
+
:timeout => 0,
|
157
|
+
:server_controls => [],
|
158
|
+
:client_controls => []
|
159
|
+
}
|
160
|
+
).and_yield( resultbranch )
|
161
|
+
|
162
|
+
resultbranch.should_receive( :controls ).and_return( [] )
|
163
|
+
|
164
|
+
@branchset.unordered.each do |*args|
|
165
|
+
args.should == [ resultbranch ]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
# vim: set nosta noet ts=4 sw=4:
|
@@ -9,20 +9,13 @@ BEGIN {
|
|
9
9
|
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
10
|
}
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
rescue LoadError
|
20
|
-
unless Object.const_defined?( :Gem )
|
21
|
-
require 'rubygems'
|
22
|
-
retry
|
23
|
-
end
|
24
|
-
raise
|
25
|
-
end
|
12
|
+
require 'spec'
|
13
|
+
require 'spec/lib/constants'
|
14
|
+
require 'spec/lib/helpers'
|
15
|
+
|
16
|
+
require 'treequel/directory'
|
17
|
+
require 'treequel/branch'
|
18
|
+
require 'treequel/control'
|
26
19
|
|
27
20
|
|
28
21
|
include Treequel::TestConstants
|
@@ -82,8 +75,8 @@ describe Treequel::Directory do
|
|
82
75
|
and_return( conn )
|
83
76
|
conn.should_receive( :bind ).with( TEST_BIND_DN, TEST_BIND_PASS )
|
84
77
|
|
85
|
-
dir = Treequel::Directory.new( @options.merge(
|
86
|
-
dir.
|
78
|
+
dir = Treequel::Directory.new( @options.merge(:bind_dn => TEST_BIND_DN, :pass => TEST_BIND_PASS) )
|
79
|
+
dir.bound_user.should == TEST_BIND_DN
|
87
80
|
end
|
88
81
|
|
89
82
|
it "uses the first namingContext from the Root DSE if no base is specified" do
|
@@ -282,6 +275,48 @@ describe Treequel::Directory do
|
|
282
275
|
end
|
283
276
|
|
284
277
|
|
278
|
+
it "returns branches with operational attributes enabled if the base is a branch with " +
|
279
|
+
"operational attributes enabled" do
|
280
|
+
base = TEST_PEOPLE_DN
|
281
|
+
filter = '(|(uid=jonlong)(uid=margento))'
|
282
|
+
|
283
|
+
branch = mock( "branch", :dn => TEST_PEOPLE_DN )
|
284
|
+
branch.should_receive( :respond_to? ).with( :include_operational_attrs? ).
|
285
|
+
at_least( :once ).
|
286
|
+
and_return( true )
|
287
|
+
branch.should_receive( :respond_to? ).with( :dn ).
|
288
|
+
and_return( true )
|
289
|
+
branch.stub!( :include_operational_attrs? ).and_return( true )
|
290
|
+
|
291
|
+
found_branch1 = stub( "entry1 branch" )
|
292
|
+
found_branch2 = stub( "entry2 branch" )
|
293
|
+
|
294
|
+
# Do the search
|
295
|
+
entries = [
|
296
|
+
{ 'dn' => ["uid=jonlong,#{TEST_PEOPLE_DN}"] },
|
297
|
+
{ 'dn' => ["uid=margento,#{TEST_PEOPLE_DN}"] },
|
298
|
+
]
|
299
|
+
@conn.should_receive( :search_ext2 ).
|
300
|
+
with( base, LDAP::LDAP_SCOPE_BASE, filter, ['*'], false, nil, nil, 0, 0, 0, '', nil ).
|
301
|
+
and_return( entries )
|
302
|
+
|
303
|
+
# Turn found entries into Branch objects
|
304
|
+
Treequel::Branch.should_receive( :new_from_entry ).with( entries[0], @dir ).
|
305
|
+
and_return( found_branch1 )
|
306
|
+
found_branch1.should_receive( :include_operational_attrs= ).with( true )
|
307
|
+
Treequel::Branch.should_receive( :new_from_entry ).with( entries[1], @dir ).
|
308
|
+
and_return( found_branch2 )
|
309
|
+
found_branch2.should_receive( :include_operational_attrs= ).with( true )
|
310
|
+
|
311
|
+
results = []
|
312
|
+
@dir.search( branch, :base, filter ) do |branch|
|
313
|
+
results << branch
|
314
|
+
end
|
315
|
+
|
316
|
+
results.should == [ found_branch1, found_branch2 ]
|
317
|
+
end
|
318
|
+
|
319
|
+
|
285
320
|
it "catches plain RuntimeErrors raised by #search2 and re-casts them as " +
|
286
321
|
"more-interesting errors" do
|
287
322
|
@conn.should_receive( :search_ext2 ).
|
@@ -406,6 +441,16 @@ describe Treequel::Directory do
|
|
406
441
|
@dir.modify( branch, 'cn' => ['nomblywob'] )
|
407
442
|
end
|
408
443
|
|
444
|
+
it "can modify the record corresponding to a Branch in the directory via LDAP::Mods" do
|
445
|
+
branch = mock( "branch" )
|
446
|
+
branch.should_receive( :dn ).at_least( :once ).and_return( :the_branches_dn )
|
447
|
+
delmod = LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, 'displayName', ['georgina boots'] )
|
448
|
+
|
449
|
+
@conn.should_receive( :modify ).with( :the_branches_dn, [delmod] )
|
450
|
+
|
451
|
+
@dir.modify( branch, [delmod] )
|
452
|
+
end
|
453
|
+
|
409
454
|
it "can delete the record corresponding to a Branch from the directory" do
|
410
455
|
branch = mock( "branch" )
|
411
456
|
branch.should_receive( :dn ).at_least( :once ).and_return( :the_branches_dn )
|
@@ -446,6 +491,38 @@ describe Treequel::Directory do
|
|
446
491
|
end
|
447
492
|
|
448
493
|
|
494
|
+
it "doesn't include duplicates when smushing RDN attributes" do
|
495
|
+
newattrs = {
|
496
|
+
TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE],
|
497
|
+
:cn => 'Chilly T',
|
498
|
+
:desc => 'Audi like Jetta',
|
499
|
+
:objectClass => :room,
|
500
|
+
}
|
501
|
+
rdn_attrs = {
|
502
|
+
TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE]
|
503
|
+
}
|
504
|
+
addattrs = {
|
505
|
+
'cn' => ['Chilly T'],
|
506
|
+
'desc' => ['Audi like Jetta'],
|
507
|
+
'objectClass' => ['room'],
|
508
|
+
TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE],
|
509
|
+
}
|
510
|
+
|
511
|
+
branch = mock( "new person branch" )
|
512
|
+
branch.should_receive( :dn ).and_return( TEST_PERSON_DN )
|
513
|
+
branch.should_receive( :rdn_attributes ).at_least( :once ).and_return( rdn_attrs )
|
514
|
+
|
515
|
+
room_objectclass = stub( 'room objectClass', :structural? => true )
|
516
|
+
@schema.should_receive( :object_classes ).at_least( :once ).and_return({
|
517
|
+
:room => room_objectclass,
|
518
|
+
})
|
519
|
+
|
520
|
+
@conn.should_receive( :add ).with( TEST_PERSON_DN, addattrs )
|
521
|
+
|
522
|
+
@dir.create( branch, newattrs )
|
523
|
+
end
|
524
|
+
|
525
|
+
|
449
526
|
it "can move a record to a new dn within the same branch" do
|
450
527
|
@dir.stub!( :bound? ).and_return( false )
|
451
528
|
branch = mock( "sibling branch obj" )
|
@@ -480,6 +557,99 @@ describe Treequel::Directory do
|
|
480
557
|
@dir.convert_syntax_value( OIDS::BOOLEAN_SYNTAX, 'true' ).should == 'true'
|
481
558
|
end
|
482
559
|
|
560
|
+
|
561
|
+
### Controls support
|
562
|
+
describe "to a server that supports controls introspection" do
|
563
|
+
before( :each ) do
|
564
|
+
@control = Module.new { include Treequel::Control }
|
565
|
+
@conn.should_receive( :root_dse ).and_return( TEST_DSE )
|
566
|
+
end
|
567
|
+
|
568
|
+
|
569
|
+
it "allows one to fetch the list of supported controls as OIDs" do
|
570
|
+
@dir.supported_control_oids.should == TEST_DSE.first['supportedControl']
|
571
|
+
end
|
572
|
+
|
573
|
+
it "allows one to fetch the list of supported controls as control names" do
|
574
|
+
@dir.supported_controls.should == TEST_DSE.first['supportedControl'].
|
575
|
+
collect {|oid| Treequel::Constants::CONTROL_NAMES[oid] }
|
576
|
+
end
|
577
|
+
|
578
|
+
it "allows the registration of one or more Treequel::Control modules" do
|
579
|
+
@control.const_set( :OID, TEST_DSE.first['supportedControl'].first )
|
580
|
+
@dir.register_controls( @control )
|
581
|
+
@dir.registered_controls.should == [ @control ]
|
582
|
+
end
|
583
|
+
|
584
|
+
it "raises an exception if the directory doesn't support registered controls" do
|
585
|
+
@control.const_set( :OID, '8.6.7.5.309' )
|
586
|
+
expect {
|
587
|
+
@dir.register_controls( @control )
|
588
|
+
}.to raise_error( Treequel::UnsupportedControl, /not supported/i )
|
589
|
+
|
590
|
+
@dir.registered_controls.should == []
|
591
|
+
end
|
592
|
+
|
593
|
+
it "raises an exception if a registered control doesn't define an OID" do
|
594
|
+
expect {
|
595
|
+
@dir.register_controls( @control )
|
596
|
+
}.to raise_error( NotImplementedError, /doesn't define/i )
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
|
601
|
+
describe "to a server that supports extensions introspection" do
|
602
|
+
before( :each ) do
|
603
|
+
@conn.should_receive( :root_dse ).and_return( TEST_DSE )
|
604
|
+
end
|
605
|
+
|
606
|
+
|
607
|
+
it "allows one to fetch the list of supported extensions as OIDs" do
|
608
|
+
@dir.supported_extension_oids.should == TEST_DSE.first['supportedExtension']
|
609
|
+
end
|
610
|
+
|
611
|
+
it "allows one to fetch the list of supported extensions as extension names" do
|
612
|
+
@dir.supported_extensions.should == TEST_DSE.first['supportedExtension'].
|
613
|
+
collect {|oid| Treequel::Constants::EXTENSION_NAMES[oid] }
|
614
|
+
end
|
615
|
+
|
616
|
+
end
|
617
|
+
|
618
|
+
|
619
|
+
describe "to a server that supports features introspection" do
|
620
|
+
before( :each ) do
|
621
|
+
@conn.should_receive( :root_dse ).and_return( TEST_DSE )
|
622
|
+
end
|
623
|
+
|
624
|
+
|
625
|
+
it "allows one to fetch the list of supported features as OIDs" do
|
626
|
+
@dir.supported_feature_oids.should == TEST_DSE.first['supportedFeatures']
|
627
|
+
end
|
628
|
+
|
629
|
+
it "allows one to fetch the list of supported features as feature names" do
|
630
|
+
@dir.supported_features.should == TEST_DSE.first['supportedFeatures'].
|
631
|
+
collect {|oid| Treequel::Constants::FEATURE_NAMES[oid] }
|
632
|
+
end
|
633
|
+
|
634
|
+
end
|
635
|
+
|
636
|
+
describe "to a server that doesn't support features introspection" do
|
637
|
+
before( :each ) do
|
638
|
+
@conn.should_receive( :root_dse ).and_return( TEST_DSE )
|
639
|
+
end
|
640
|
+
|
641
|
+
|
642
|
+
it "allows one to fetch the list of supported features as OIDs" do
|
643
|
+
@dir.supported_feature_oids.should == TEST_DSE.first['supportedFeatures']
|
644
|
+
end
|
645
|
+
|
646
|
+
it "allows one to fetch the list of supported features as feature names" do
|
647
|
+
@dir.supported_features.should == TEST_DSE.first['supportedFeatures'].
|
648
|
+
collect {|oid| Treequel::Constants::FEATURE_NAMES[oid] }
|
649
|
+
end
|
650
|
+
|
651
|
+
end
|
652
|
+
|
483
653
|
end
|
484
654
|
end
|
485
655
|
|
@@ -152,6 +152,7 @@ describe Treequel, "mixin" do
|
|
152
152
|
end
|
153
153
|
|
154
154
|
describe Treequel::ArrayUtilities do
|
155
|
+
|
155
156
|
it "includes a function for stringifying Array elements" do
|
156
157
|
testarray = [:a, :b, :c, [:d, :e, [:f, :g]]]
|
157
158
|
|
@@ -174,10 +175,9 @@ describe Treequel, "mixin" do
|
|
174
175
|
end
|
175
176
|
end
|
176
177
|
|
177
|
-
|
178
178
|
describe Treequel::AttributeDeclarations do
|
179
179
|
before( :all ) do
|
180
|
-
setup_logging( :
|
180
|
+
setup_logging( :fatal )
|
181
181
|
end
|
182
182
|
after( :all ) do
|
183
183
|
reset_logging()
|
@@ -216,7 +216,7 @@ describe Treequel, "mixin" do
|
|
216
216
|
describe Treequel::Delegation do
|
217
217
|
|
218
218
|
before( :all ) do
|
219
|
-
setup_logging( :
|
219
|
+
setup_logging( :fatal )
|
220
220
|
end
|
221
221
|
after( :all ) do
|
222
222
|
reset_logging()
|
@@ -325,6 +325,45 @@ describe Treequel, "mixin" do
|
|
325
325
|
|
326
326
|
end
|
327
327
|
|
328
|
+
describe Treequel::Normalization do
|
329
|
+
|
330
|
+
describe "key normalization" do
|
331
|
+
it "downcases" do
|
332
|
+
Treequel::Normalization.normalize_key( :logonTime ).should == :logontime
|
333
|
+
end
|
334
|
+
|
335
|
+
it "symbolifies" do
|
336
|
+
Treequel::Normalization.normalize_key( 'cn' ).should == :cn
|
337
|
+
end
|
338
|
+
|
339
|
+
it "strips invalid characters" do
|
340
|
+
Treequel::Normalization.normalize_key( 'given name' ).should == :givenname
|
341
|
+
end
|
342
|
+
|
343
|
+
it "converts hyphens to underscores" do
|
344
|
+
Treequel::Normalization.normalize_key( 'apple-nickname' ).should == :apple_nickname
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe "hash normalization" do
|
349
|
+
it "applies key-normalization to the keys of a hash" do
|
350
|
+
hash = {
|
351
|
+
:logonTime => 'a logon time',
|
352
|
+
'cn' => 'a common name',
|
353
|
+
'given name' => 'a given name',
|
354
|
+
'apple-nickname' => 'a nickname',
|
355
|
+
}
|
356
|
+
|
357
|
+
Treequel::Normalization.normalize_hash( hash ).should == {
|
358
|
+
:logontime => 'a logon time',
|
359
|
+
:cn => 'a common name',
|
360
|
+
:givenname => 'a given name',
|
361
|
+
:apple_nickname => 'a nickname',
|
362
|
+
}
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
328
367
|
end
|
329
368
|
|
330
369
|
# vim: set nosta noet ts=4 sw=4:
|