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