1# ldap.test - Copyright (C) 2006 Michael Schlenker <mic42@user.sourceforge.net>
2#
3# Tests for the Tcllib ldap package
4#
5# -------------------------------------------------------------------------
6# See the file "license.terms" for information on usage and redistribution
7# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
8# -------------------------------------------------------------------------
9# RCS: @(#) $Id: ldap.test,v 1.5 2008/07/20 19:50:55 mic42 Exp $
10
11# -------------------------------------------------------------------------
12
13source [file join \
14	[file dirname [file dirname [file join [pwd] [info script]]]] \
15	devtools testutilities.tcl]
16
17testsNeedTcl     8.4
18testsNeedTcltest 2.0
19
20testing {
21    useLocal ldap.tcl ldap
22    useLocal ../asn/asn.tcl asn
23}
24
25
26namespace import ::asn::*
27
28# -------------------------------------------------------------------------
29# Tests
30# -------------------------------------------------------------------------
31
32test ldap-2.0 {check info ip subcommand error handling
33} -body {
34   ldap::info ip
35} -returnCodes {error} \
36  -result {Wrong # of arguments. Usage: ldap::info ip handle}
37
38test ldap-2.1 {check info ip subcommand error handling
39} -body {
40   ldap::info ip foobar
41} -returnCodes {error} \
42  -result {Not a valid LDAP connection handle: foobar}
43
44test ldap-3.0 {check info connections subcommand error handling
45} -body {
46   ldap::info connections foo
47} -returnCodes {error} \
48  -result {Wrong # of arguments. Usage: ldap::info connections}
49
50test ldap-4.0 {check info bound subcommand error handling
51} -body {
52   ldap::info bound
53} -returnCodes {error} \
54  -result {Wrong # of arguments. Usage: ldap::info bound handle}
55
56test ldap-4.1 {check info bound subcommand error handling
57} -body {
58   ldap::info bound foobar
59} -returnCodes {error} \
60  -result {Not a valid LDAP connection handle: foobar}
61
62test ldap-5.0 {check info tls subcommand error handling
63} -body {
64   ldap::info tls
65} -returnCodes {error} \
66  -result {Wrong # of arguments. Usage: ldap::info tls handle}
67
68test ldap-5.1 {check info tls subcommand error handling
69} -body {
70   ldap::info tls foobar
71} -returnCodes {error} \
72  -result {Not a valid LDAP connection handle: foobar}
73
74test ldap-6.0 {check info bounduser subcommand error handling
75} -body {
76   ldap::info bounduser
77} -returnCodes {error} \
78  -result {Wrong # of arguments. Usage: ldap::info bounduser handle}
79
80test ldap-6.1 {check info bounduser subcommand error handling
81} -body {
82   ldap::info bounduser foobar
83} -returnCodes {error} \
84  -result {Not a valid LDAP connection handle: foobar}
85
86test ldap-7.0 {check info saslmechanisms subcommand error handling
87} -body {
88   ldap::info saslmechanisms
89} -returnCodes {error} \
90  -result {Wrong # of arguments. Usage: ldap::info saslmechanisms handle}
91
92test ldap-7.1 {check info saslmechanisms subcommand error handling
93} -body {
94   ldap::info saslmechanisms foobar
95} -returnCodes {error} \
96  -result {Not a valid LDAP connection handle: foobar}
97
98test ldap-8.0 {check info extensions subcommand error handling
99} -body {
100   ldap::info extensions
101} -returnCodes {error} \
102  -result {Wrong # of arguments. Usage: ldap::info extensions handle}
103
104test ldap-8.1 {check info extensions subcommand error handling
105} -body {
106   ldap::info extensions foobar
107} -returnCodes {error} \
108  -result {Not a valid LDAP connection handle: foobar}
109
110test ldap-9.0 {check info control subcommand error handling
111} -body {
112   ldap::info control
113} -returnCodes {error} \
114  -result {Wrong # of arguments. Usage: ldap::info control handle}
115
116test ldap-9.1 {check info control subcommand error handling
117} -body {
118   ldap::info control foobar
119} -returnCodes {error} \
120  -result {Not a valid LDAP connection handle: foobar}
121
122test ldap-10.0 {check info features subcommand error handling
123} -body {
124   ldap::info features
125} -returnCodes {error} \
126  -result {Wrong # of arguments. Usage: ldap::info features handle}
127
128test ldap-10.1 {check info features subcommand error handling
129} -body {
130   ldap::info features foobar
131} -returnCodes {error} \
132  -result {Not a valid LDAP connection handle: foobar}
133
134test ldap-11.0 {check info whoami subcommand error handling
135} -body {
136    ldap::info whoami
137} -returnCodes {error} \
138  -result {Wrong # of arguments. Usage: ldap::info whoami handle}
139
140test ldap-11.1 {check info whoami subcommand error handling
141} -body {
142    ldap::info whoami foobar
143} -returnCodes {error} \
144  -result {Not a valid LDAP connection handle: foobar}
145
146test ldap-12.0 {check wrong num args for ldap::connect
147} -body {
148    ldap::connect
149} -returnCodes {error} \
150  -result [tcltest::wrongNumArgs \
151	{ldap::connect} {host ?port?} 0]
152
153test ldap-13.0 {check wrong num args for ldap::secure_connect
154} -body {
155   ldap::secure_connect
156} -returnCodes {error} \
157  -result [tcltest::wrongNumArgs \
158	{ldap::secure_connect} {host ?port?} 0]
159
160test ldap-14.0 {check wrong num args for ldap::starttls
161} -body {
162   ldap::starttls
163} -returnCodes {error} \
164  -result [tcltest::wrongNumArgs {ldap::starttls} \
165	{handle ?cafile? ?certfile? ?keyfile?} 0]
166
167test ldap-15.0 {check wrong num args for ldap::bindSASL
168} -body {
169   ldap::bindSASL
170} -returnCodes {error} \
171  -result  [tcltest::wrongNumArgs {ldap::bindSASL} {handle ?name? ?password?} 0]
172
173test ldap-16.0 {check wrong num args for ldap::bind
174} -body {
175   ldap::bind
176} -returnCodes {error} \
177  -result [tcltest::wrongNumArgs {ldap::bind} {handle ?name? ?password?} 0]
178
179test ldap-17.0 {check wrong num args for ldap::unbind
180} -body { 
181   ldap::unbind
182} -returnCodes {error} \
183  -result [tcltest::wrongNumArgs {ldap::unbind} {handle} 1 ]
184
185test ldap-18.0 {check wrong num args for ldap::search
186} -body {
187   ldap::search
188} -returnCodes {error} \
189  -result [tcltest::wrongNumArgs {ldap::search} \
190	{handle baseObject filterString attributes args} 0]
191
192test ldap-19.0 {check wrong num args for ldap::searchInit
193} -body {
194   ldap::searchInit
195} -returnCodes {error} \
196  -result [tcltest::wrongNumArgs {ldap::searchInit} \
197	{handle baseObject filterString attributes opt} 0]
198
199test ldap-20.0 {check wrong num args for ldap::searchNext
200} -body {
201   ldap::searchNext
202} -returnCodes {error} \
203  -result [tcltest::wrongNumArgs {ldap::searchNext} {handle} 0 ]
204
205test ldap-21.0 {check wrong num args for ldap::searchEnd
206} -body {
207   ldap::searchEnd
208} -returnCodes {error} \
209  -result [tcltest::wrongNumArgs {ldap::searchEnd} {handle} 0 ]
210
211test ldap-22.0 {check wrong num args for ldap::modify
212} -body {
213   ldap::modify
214} -returnCodes {error} \
215  -result [tcltest::wrongNumArgs {ldap::modify} \
216	{handle dn attrValToReplace ?attrToDelete? ?attrValToAdd?} 0 ]
217
218test ldap-23.0 {check wrong num args for ldap::modifyMulti
219} -body {
220   ldap::modifyMulti
221} -returnCodes {error} \
222  -result [tcltest::wrongNumArgs {ldap::modifyMulti} \
223	{handle dn attrValToReplace ?attrValToDelete? ?attrValToAdd?} 0 ]
224
225test ldap-24.0 {check wrong num args for ldap::add
226} -body {
227   ldap::add
228} -returnCodes {error} \
229  -result [tcltest::wrongNumArgs {ldap::add} \
230	{handle dn attrValueTuples} 0 ]
231
232test ldap-25.0 {check wrong num args for ldap::addMulti
233} -body {
234   ldap::addMulti
235} -returnCodes {error} \
236  -result [tcltest::wrongNumArgs {ldap::addMulti} \
237	{handle dn attrValueTuples} 0 ]
238
239test ldap-26.0 {check wrong num args for ldap::delete
240} -body {
241   ldap::delete
242} -returnCodes {error} \
243  -result [tcltest::wrongNumArgs {ldap::delete} \
244	{handle dn} 0 ]
245
246test ldap-27.0 {check wrong num args for ldap::modifyDN
247} -body {
248   ldap::modifyDN
249} -returnCodes {error} \
250  -result [tcltest::wrongNumArgs {ldap::modifyDN} \
251	{handle dn newrdn ?deleteOld? ?newSuperior?} 0 ]
252
253test ldap-28.0 {check wrong num args for ldap::disconnect
254} -body {
255   ldap::disconnect
256} -returnCodes {error} \
257  -result [tcltest::wrongNumArgs {ldap::disconnect} \
258	{handle} 0 ]
259# -------------------------------------------------------------------------
260# Handling of string representation of filters (RFC 4515):
261# -------------------------------------------------------------------------
262
263proc glue args {
264    join $args ""
265}
266
267test filter-0.0 {[glue] should concatenate its string arguments} -body {
268    glue a b c d \0 foo
269} -result abcd\0foo
270
271test filter-1.0 {LDAPString produces packed UTF-8} -body {
272    binary scan [ldap::filter::LDAPString \u043a\u0430\u0448\u0430] H* foo
273    set foo
274} -result d0bad0b0d188d0b0 -cleanup { unset foo }
275
276test filter-1.1 {AssertionValue produces packed UTF-8} -body {
277    binary scan [ldap::filter::AssertionValue \u043a\u0430\u0448\u0430] H* foo
278    set foo
279} -result d0bad0b0d188d0b0 -cleanup { unset foo }
280
281test filter-1.2 {AssertionValue produces packed UTF-8
282	but allows embedding of arbitrary bytes via escaping} -body {
283    binary scan [ldap::filter::AssertionValue \u043a\\FF\u0430\\ab\u0448\\de\u0430\\Fe] H* foo
284    set foo
285} -result d0baffd0b0abd188ded0b0fe -cleanup { unset foo }
286
287test filter-1.3 {LDAPString produces packed UTF-8, all characters pass as is} -body {
288    binary scan [ldap::filter::LDAPString \u043a\\FF\u0430\\ab\u0448\\de\u0430\\Fe] H* foo
289    set foo
290} -result d0ba5c4646d0b05c6162d1885c6465d0b05c4665 -cleanup { unset foo }
291
292test filter-2.0 {Backslash escaping in assertion values} -body {
293    set a ""
294    set b ""
295    for {set i 0} {$i <= 255} {incr i} {
296	append a [format \\%02x $i] ;# lowercase hex
297	append b [format %c $i]
298    }
299    string equal [ldap::filter::AssertionValue $a] $b
300} -result 1 -cleanup { unset a b i }
301
302test filter-2.1 {Backslash escaping in assertion values} -body {
303    set a ""
304    set b ""
305    for {set i 0} {$i <= 255} {incr i} {
306	append a [format \\%02X $i] ;# uppercase hex
307	append b [format %c $i]
308    }
309    string equal [ldap::filter::AssertionValue $a] $b
310} -result 1 -cleanup { unset a b i }
311
312test filter-3.1 {Malformed backslash escaping in assertion values} -body {
313    ldap::filter::AssertionValue foo\\0
314} -returnCodes error -result {Invalid filter: malformed assertion value}
315
316test filter-3.2 {Malformed backslash escaping in assertion values} -body {
317    ldap::filter::AssertionValue \\foo
318} -returnCodes error -result {Invalid filter: malformed assertion value}
319
320test filter-3.3 {Malformed backslash escaping in assertion values} -body {
321    ldap::filter::AssertionValue hA\\1x0rz
322} -returnCodes error -result {Invalid filter: malformed assertion value}
323
324test filter-3.4 {Malformed backslash escaping in assertion values} -body {
325    ldap::filter::AssertionValue \\value
326} -returnCodes error -result {Invalid filter: malformed assertion value}
327
328test filter-3.5 {Malformed backslash escaping in assertion values} -body {
329    ldap::filter::AssertionValue end\\
330} -returnCodes error -result {Invalid filter: malformed assertion value}
331
332test filter-4.0 {Presence match} -body {
333    ldap::filter::encode (Certificates=*)
334} -result [asnChoice 7 [ldap::filter::LDAPString Certificates]]
335
336test filter-4.1 {Presence match + attribute options} -body {
337    ldap::filter::encode (Certificates\;binary\;X-FooBar=*)
338} -result [asnChoice 7 [ldap::filter::LDAPString Certificates\;binary\;X-FooBar]]
339
340test filter-5.0 {Equality match} -body {
341    ldap::filter::encode (foo=bar)
342} -result [asnChoiceConstr 3 [glue \
343    [asnOctetString [ldap::filter::LDAPString foo]] \
344    [asnOctetString [ldap::filter::AssertionValue bar]]]]
345
346test filter-5.1 {Equality match with empty assertion value} -body {
347    ldap::filter::encode (seeAlso=)
348} -result [asnChoiceConstr 3 [glue \
349    [asnOctetString [ldap::filter::LDAPString seeAlso]] \
350    [asnOctetString [ldap::filter::AssertionValue ""]]]]
351
352test filter-5.2 {Equality match + attribute options} -body {
353    ldap::filter::encode (foo\;X-option=bar)
354} -result [asnChoiceConstr 3 [glue \
355    [asnOctetString [ldap::filter::LDAPString foo\;X-option]] \
356    [asnOctetString [ldap::filter::AssertionValue bar]]]]
357
358test filter-5.3 {Equality match, spaces in assertion value} -body {
359    ldap::filter::encode {(personName=Jane W. Random)}
360} -result [asnChoiceConstr 3 [glue \
361    [asnOctetString [ldap::filter::LDAPString personName]] \
362    [asnOctetString [ldap::filter::AssertionValue "Jane W. Random"]]]]
363
364test filter-6.0 {Approx match} -body {
365    ldap::filter::encode (descr~=val)
366} -result [asnChoiceConstr 8 [glue \
367    [asnOctetString [ldap::filter::LDAPString descr]] \
368    [asnOctetString [ldap::filter::AssertionValue val]]]]
369
370test filter-6.1 {Approx match with empty assertion value} -body {
371    ldap::filter::encode (cn~=)
372} -result [asnChoiceConstr 8 [glue \
373    [asnOctetString [ldap::filter::LDAPString cn]] \
374    [asnOctetString [ldap::filter::AssertionValue ""]]]]
375
376test filter-6.2 {Approx match + attribute options} -body {
377    ldap::filter::encode (binaryCert\;binary~=0000)
378} -result [asnChoiceConstr 8 [glue \
379    [asnOctetString [ldap::filter::LDAPString binaryCert\;binary]] \
380    [asnOctetString [ldap::filter::AssertionValue 0000]]]]
381
382test filter-7.0 {Less or equal match} -body {
383    ldap::filter::encode (attr<=string)
384} -result [asnChoiceConstr 6 [glue \
385    [asnOctetString [ldap::filter::LDAPString attr]] \
386    [asnOctetString [ldap::filter::AssertionValue string]]]]
387
388test filter-7.1 {Less or equal match with empty assertion value} -body {
389    ldap::filter::encode (attr<=)
390} -result [asnChoiceConstr 6 [glue \
391    [asnOctetString [ldap::filter::LDAPString attr]] \
392    [asnOctetString [ldap::filter::AssertionValue ""]]]]
393
394test filter-7.2 {Less or equal match + attribute options} -body {
395    ldap::filter::encode (binaryCert\;binary<=01234)
396} -result [asnChoiceConstr 6 [glue \
397    [asnOctetString [ldap::filter::LDAPString binaryCert\;binary]] \
398    [asnOctetString [ldap::filter::AssertionValue 01234]]]]
399
400test filter-8.0 {Greater or equal match} -body {
401    ldap::filter::encode (one>=two)
402} -result [asnChoiceConstr 5 [glue \
403    [asnOctetString [ldap::filter::LDAPString one]] \
404    [asnOctetString [ldap::filter::AssertionValue two]]]]
405
406test filter-8.1 {Greater or equal match with empty attribute} -body {
407    ldap::filter::encode (one>=)
408} -result [asnChoiceConstr 5 [glue \
409    [asnOctetString [ldap::filter::LDAPString one]] \
410    [asnOctetString [ldap::filter::AssertionValue ""]]]]
411
412test filter-8.2 {Greater or equal match + attribute options} -body {
413    ldap::filter::encode (exampleAttr\;X-experimental>=value)
414} -result [asnChoiceConstr 5 [glue \
415    [asnOctetString [ldap::filter::LDAPString exampleAttr\;X-experimental]] \
416    [asnOctetString [ldap::filter::AssertionValue value]]]]
417
418test filter-9.0 {Substrings match: only initial string} -body {
419    ldap::filter::encode (sAMAccountName=management-*)
420} -result [asnChoiceConstr 4 [glue \
421    [asnOctetString [ldap::filter::LDAPString sAMAccountName]] \
422    [asnSequence [asnChoice 0 [ldap::filter::AssertionValue management-]]]]]
423
424test filter-9.1 {Substrings match: only final string} -body {
425    ldap::filter::encode (User=*ish)
426} -result [asnChoiceConstr 4 [glue \
427    [asnOctetString [ldap::filter::LDAPString User]] \
428    [asnSequence [asnChoice 2 [ldap::filter::AssertionValue ish]]]]]
429
430test filter-9.2 {Substrings match: initial and final strings} -body {
431    ldap::filter::encode (OU=F*off)
432} -result [asnChoiceConstr 4 [glue \
433    [asnOctetString [ldap::filter::LDAPString OU]] \
434    [asnSequence \
435	[asnChoice 0 [ldap::filter::AssertionValue F]] \
436	[asnChoice 2 [ldap::filter::AssertionValue off]]]]]
437
438test filter-9.3 {Substrings match: initial, any and final strings} -body {
439    ldap::filter::encode (mail=Schlenk*@uni-*.de)
440} -result [asnChoiceConstr 4 [glue \
441    [asnOctetString [ldap::filter::LDAPString mail]] \
442    [asnSequence \
443	[asnChoice 0 [ldap::filter::AssertionValue Schlenk]] \
444	[asnChoice 1 [ldap::filter::AssertionValue @uni-]] \
445	[asnChoice 2 [ldap::filter::AssertionValue .de]]]]]
446
447test filter-9.4 {Substrings match: multiple any strings} -body {
448    ldap::filter::encode (Something=a*b*c*d*e)
449} -result [asnChoiceConstr 4 [glue \
450    [asnOctetString [ldap::filter::LDAPString Something]] \
451    [asnSequence \
452	[asnChoice 0 [ldap::filter::AssertionValue a]] \
453	[asnChoice 1 [ldap::filter::AssertionValue b]] \
454	[asnChoice 1 [ldap::filter::AssertionValue c]] \
455	[asnChoice 1 [ldap::filter::AssertionValue d]] \
456	[asnChoice 2 [ldap::filter::AssertionValue e]]]]]
457
458test filter-9.5 {Substrings match: no initial and final strings} -body {
459    ldap::filter::encode (Whatever=*foo*)
460} -result [asnChoiceConstr 4 [glue \
461    [asnOctetString [ldap::filter::LDAPString Whatever]] \
462    [asnSequence \
463	[asnChoice 1 [ldap::filter::AssertionValue foo]]]]]
464
465test filter-9.6 {Substrings match: empty any string prevention} -body {
466    ldap::filter::encode {(Person=J.Ra***m Hacker)}
467} -result [asnChoiceConstr 4 [glue \
468    [asnOctetString [ldap::filter::LDAPString Person]] \
469    [asnSequence \
470	[asnChoice 0 [ldap::filter::AssertionValue J.Ra]] \
471	[asnChoice 2 [ldap::filter::AssertionValue {m Hacker}]]]]]
472
473test filter-9.7 {Substrings match: empty any string prevention} -body {
474    ldap::filter::encode (SomeType=***foo***bar***baz**********)
475} -result [asnChoiceConstr 4 [glue \
476    [asnOctetString [ldap::filter::LDAPString SomeType]] \
477    [asnSequence \
478	[asnChoice 1 [ldap::filter::AssertionValue foo]] \
479	[asnChoice 1 [ldap::filter::AssertionValue bar]] \
480	[asnChoice 1 [ldap::filter::AssertionValue baz]]]]]
481
482test filter-9.8 {Substrings match: parsing to zero parts} -body {
483    ldap::filter::encode (SomeType=**)
484} -returnCodes error -result {Invalid filter: substrings match parses to zero parts}
485
486test filter-9.10 {Substrings match: parsing to zero parts} -body {
487    ldap::filter::encode (SomeOtherType=*****)
488} -returnCodes error -result {Invalid filter: substrings match parses to zero parts}
489
490test filter-9.11 {Substrings match: spaces in assertion value} -body {
491    ldap::filter::encode {(Something=Jane Random*and*J. Random Hacker)}
492} -result [asnChoiceConstr 4 [glue \
493    [asnOctetString [ldap::filter::LDAPString Something]] \
494    [asnSequence \
495	[asnChoice 0 [ldap::filter::AssertionValue "Jane Random"]] \
496	[asnChoice 1 [ldap::filter::AssertionValue and]] \
497	[asnChoice 2 [ldap::filter::AssertionValue "J. Random Hacker"]]]]]
498
499test filter-10.0 {Extensible match: only attribute description} -body {
500    ldap::filter::encode (AttrDesc:=10)
501} -result [asnChoiceConstr 9 [glue \
502    [asnChoice 2 [ldap::filter::LDAPString AttrDesc]] \
503    [asnChoice 3 [ldap::filter::AssertionValue 10]]]]
504
505test filter-10.1 {Extensible match: attribute description + matching rule} -body {
506    ldap::filter::encode (personKind:caseIgnoreMatch:=bad)
507} -result [asnChoiceConstr 9 [glue \
508    [asnChoice 1 [ldap::filter::LDAPString caseIgnoreMatch]] \
509    [asnChoice 2 [ldap::filter::LDAPString personKind]] \
510    [asnChoice 3 [ldap::filter::AssertionValue bad]]]]
511
512test filter-10.2 {Extensible match: attribute description
513	+ matching rule in form of numericoid} -body {
514    ldap::filter::encode (personKind:1.3.6.1.4.1.1466.115.121.1.15:=good)
515} -result [asnChoiceConstr 9 [glue \
516    [asnChoice 1 [ldap::filter::LDAPString 1.3.6.1.4.1.1466.115.121.1.15]] \
517    [asnChoice 2 [ldap::filter::LDAPString personKind]] \
518    [asnChoice 3 [ldap::filter::AssertionValue good]]]]
519
520test filter-10.3 {Extensible match: attribute description + DN flag} -body {
521    ldap::filter::encode (Foobar:dn:=345)
522} -result [asnChoiceConstr 9 [glue \
523    [asnChoice 2 [ldap::filter::LDAPString Foobar]] \
524    [asnChoice 3 [ldap::filter::AssertionValue 345]] \
525    [asnChoice 4 [binary format cc 1 1]]]]
526
527test filter-10.4 {Extensible match: attribute description + DN flag + matching rule} -body {
528    ldap::filter::encode (NamelessOne:dn:caseIgnoreIA5Match:=who)
529} -result [asnChoiceConstr 9 [glue \
530    [asnChoice 1 [ldap::filter::LDAPString caseIgnoreIA5Match]] \
531    [asnChoice 2 [ldap::filter::LDAPString NamelessOne]] \
532    [asnChoice 3 [ldap::filter::AssertionValue who]] \
533    [asnChoice 4 [binary format cc 1 1]]]]
534
535test filter-10.5 {Extensible match: attribute description + DN flag
536	+ matching rule numericoid} -body {
537    ldap::filter::encode (OU:dn:111.222.333.444:=test)
538} -result [asnChoiceConstr 9 [glue \
539    [asnChoice 1 [ldap::filter::LDAPString 111.222.333.444]] \
540    [asnChoice 2 [ldap::filter::LDAPString OU]] \
541    [asnChoice 3 [ldap::filter::AssertionValue test]] \
542    [asnChoice 4 [binary format cc 1 1]]]]
543
544test filter-10.6 {Extensible match: matching rule alone} -body {
545    ldap::filter::encode (:caseIgnoreIA5Match:=they)
546} -result [asnChoiceConstr 9 [glue \
547    [asnChoice 1 [ldap::filter::LDAPString caseIgnoreIA5Match]] \
548    [asnChoice 3 [ldap::filter::AssertionValue they]]]]
549
550test filter-10.7 {Extensible match: matching rule alone, in form of numericoid} -body {
551    ldap::filter::encode (:874.274.378.432:=value)
552} -result [asnChoiceConstr 9 [glue \
553    [asnChoice 1 [ldap::filter::LDAPString 874.274.378.432]] \
554    [asnChoice 3 [ldap::filter::AssertionValue value]]]]
555
556test filter-10.8 {Extensible match: matching rule + DN flag} -body {
557    ldap::filter::encode (:dn:caseIgnoreIA5Match:=they)
558} -result [asnChoiceConstr 9 [glue \
559    [asnChoice 1 [ldap::filter::LDAPString caseIgnoreIA5Match]] \
560    [asnChoice 3 [ldap::filter::AssertionValue they]] \
561    [asnChoice 4 [binary format cc 1 1]]]]
562
563test filter-10.9 {Extensible match: matching rule (numericoid) + DN flag} -body {
564    ldap::filter::encode (:dn:111.222.333.444:=value)
565} -result [asnChoiceConstr 9 [glue \
566    [asnChoice 1 [ldap::filter::LDAPString 111.222.333.444]] \
567    [asnChoice 3 [ldap::filter::AssertionValue value]] \
568    [asnChoice 4 [binary format cc 1 1]]]]
569
570test filter-10.10 {Extensible match: empty assertion value} -body {
571    ldap::filter::encode (AttrDesc:=)
572} -result [asnChoiceConstr 9 [glue \
573    [asnChoice 2 [ldap::filter::LDAPString AttrDesc]] \
574    [asnChoice 3 [ldap::filter::AssertionValue ""]]]]
575
576test filter-10.11 {Extensible match: empty assertion value, DN flag} -body {
577    ldap::filter::encode (AttrDesc:dn:=)
578} -result [asnChoiceConstr 9 [glue \
579    [asnChoice 2 [ldap::filter::LDAPString AttrDesc]] \
580    [asnChoice 3 [ldap::filter::AssertionValue ""]] \
581    [asnChoice 4 [binary format cc 1 1]]]]
582
583test filter-10.11 {Extensible match: matching rule with empty assertion value} -body {
584    ldap::filter::encode (:caseIgnoreIA5Match:=)
585} -result [asnChoiceConstr 9 [glue \
586    [asnChoice 1 [ldap::filter::LDAPString caseIgnoreIA5Match]] \
587    [asnChoice 3 [ldap::filter::AssertionValue ""]]]]
588
589test filter-10.12 {Extensible match: empty LHS} -body {
590    ldap::filter::encode (:=foo)
591} -returnCodes error -result {Invalid filter: malformed attribute description}
592
593test filter-10.12 {Extensible match: empty DN flag or matching rule OID} -body {
594    ldap::filter::encode (attrDesc::=bar)
595} -returnCodes error -result {Invalid filter: malformed attribute description}
596
597test filter-10.12 {Extensible match: empty matching rule OID} -body {
598    ldap::filter::encode (attrDesc:dn::=baz)
599} -returnCodes error -result {Invalid filter: malformed attribute description}
600
601test filter-10.13 {Extensible match: empty DN flag} -body {
602    ldap::filter::encode (attrDesc::caseIgnoreMatch:=quux)
603} -returnCodes error -result {Invalid filter: malformed attribute description}
604
605test filter-10.14 {Extensible match: empty DN flag} -body {
606    ldap::filter::encode (::caseIgnoreMatch:=foo)
607} -returnCodes error -result {Invalid filter: malformed attribute description}
608
609test filter-10.15 {Extensible match: empty matching rule OID} -body {
610    ldap::filter::encode (::=bar)
611} -returnCodes error -result {Invalid filter: malformed attribute description}
612
613test filter-10.16 {Extensible match: malformed matching rule numericoid} -body {
614    ldap::filter::encode (:111.222.333.xxx:=baz)
615} -returnCodes error -result {Invalid filter: malformed attribute description}
616
617test filter-10.17 {Extensible match: malformed matching rule numericoid} -body {
618    ldap::filter::encode (userCategory:111.222.333.444\;binary:=baz)
619} -returnCodes error -result {Invalid filter: malformed attribute description}
620
621test filter-10.18 {Extensible match: malformed matching rule numericoid} -body {
622    ldap::filter::encode (userCategory:dn:111.222.333.444\;x-bar:=foo)
623} -returnCodes error -result {Invalid filter: malformed attribute description}
624
625test filter-10.19 {Extensible match: malformed matching rule numericoid} -body {
626    ldap::filter::encode (:caseIgnoreIA5Match\;lang-ru:=quux)
627} -returnCodes error -result {Invalid filter: malformed attribute description}
628
629test filter-10.20 {Extensible match: camel-cased DN flag} -body {
630    ldap::filter::encode (attrDesc:Dn:caseIgnoreMatch:=quux)
631} -returnCodes error -result {Invalid filter: malformed attribute description}
632
633test filter-10.21 {Extensible match: prohibited character in attribute description} -body {
634    ldap::filter::encode (4cast:=foo)
635} -returnCodes error -result {Invalid filter: malformed attribute description}
636
637test filter-10.22 {Extensible match: gibberish in place of DN flag} -body {
638    ldap::filter::encode (OU:gibberish:caseIgnoreIA5Match:=bar)
639} -returnCodes error -result {Invalid filter: malformed attribute description}
640
641test filter-10.23 {Extensible match: options in attribute description} -body {
642    ldap::filter::encode (personAge\;lang-ru\;x-foo:numericMatch:=99)
643} -result [asnChoiceConstr 9 [glue \
644    [asnChoice 1 [ldap::filter::LDAPString numericMatch]] \
645    [asnChoice 2 [ldap::filter::LDAPString personAge\;lang-ru\;x-foo]] \
646    [asnChoice 3 [ldap::filter::AssertionValue 99]]]]
647
648test filter-10.24 {Extensible match: options in attribute description} -body {
649    ldap::filter::encode (111.222.333.444\;x-bar:dn:555.666.777.888:=foo)
650} -result [asnChoiceConstr 9 [glue \
651    [asnChoice 1 [ldap::filter::LDAPString 555.666.777.888]] \
652    [asnChoice 2 [ldap::filter::LDAPString 111.222.333.444\;x-bar]] \
653    [asnChoice 3 [ldap::filter::AssertionValue foo]] \
654    [asnChoice 4 [binary format cc 1 1]]]]
655
656test filter-11.1 {Prohibited characters in argument value} -body {
657    ldap::filter::encode (foo=bar(and)baz)
658} -returnCodes error -result {Invalid filter: malformed assertion value}
659
660test filter-11.2 {Prohibited characters in argument value} -body {
661    ldap::filter::encode (zero=lurks\0here)
662} -returnCodes error -result {Invalid filter: malformed assertion value}
663
664test filter-11.3 {Prohibited characters in argument value} -body {
665    ldap::filter::encode (extensible:=asterisk*)
666} -returnCodes error -result {Invalid filter: malformed assertion value}
667
668test filter-12.0 {Malformed attribute description: empty} -body {
669    ldap::filter::encode (=foo)
670} -returnCodes error -result {Invalid filter: malformed attribute description}
671
672test filter-12.1 {Malformed attribute description: doesn't start with a letter} -body {
673    ldap::filter::encode (2forTheRoad=bar)
674} -returnCodes error -result {Invalid filter: malformed attribute description}
675
676test filter-12.2 {Malformed attribute description: mix of descr and numericoid} -body {
677    ldap::filter::encode (foo.12.13=bar)
678} -returnCodes error -result {Invalid filter: malformed attribute description}
679
680test filter-12.3 {Malformed attribute description: bad numericoid} -body {
681    ldap::filter::encode (.11.12.13=bar)
682} -returnCodes error -result {Invalid filter: malformed attribute description}
683
684test filter-12.4 {Malformed attribute description: bad numericoid} -body {
685    ldap::filter::encode (11.12.13.=bar)
686} -returnCodes error -result {Invalid filter: malformed attribute description}
687
688test filter-12.5 {Malformed attribute description: prohibited character in descr} -body {
689    ldap::filter::encode (cn_2=bar)
690} -returnCodes error -result {Invalid filter: malformed attribute description}
691
692test filter-12.6 {Malformed attribute description: prohibited character in option} -body {
693    ldap::filter::encode (OU\;lang_en=bar)
694} -returnCodes error -result {Invalid filter: malformed attribute description}
695
696test filter-12.7 {Malformed attribute description:
697	colon in an LHS part of a rule which doesn't represent an extensible match} -body {
698    ldap::filter::encode (phoneNumber:dn=value)
699} -returnCodes error -result {Invalid filter: malformed attribute description}
700
701test filter-12.8 {Malformed attribute description: empty option} -body {
702    ldap::filter::encode (CN\;\;lang-ru=?)
703} -returnCodes error -result {Invalid filter: malformed attribute description}
704
705test filter-13.1 {Malformed assertion value: prohibited characters} -body {
706    ldap::filter::encode (foo<=*)
707} -returnCodes error -result {Invalid filter: malformed assertion value}
708
709test filter-13.2 {Malformed assertion value: prohibited characters} -body {
710    ldap::filter::encode (foo=()
711} -returnCodes error -result {Invalid filter: malformed assertion value}
712
713test filter-13.3 {Malformed assertion value: prohibited characters} -body {
714    ldap::filter::encode (foo=))
715} -returnCodes error -result {Invalid filter: malformed assertion value}
716
717test filter-13.4 {Malformed assertion value: prohibited characters} -body {
718    ldap::filter::encode (foo=\\)
719} -returnCodes error -result {Invalid filter: malformed assertion value}
720
721test filter-13.5 {Malformed assertion value: prohibited characters} -body {
722    ldap::filter::encode (foo=\0)
723} -returnCodes error -result {Invalid filter: malformed assertion value}
724
725test filter-15.0 {No match rule operator} -body {
726    ldap::filter::encode ()
727} -returnCodes error -result {Invalid filter: no match operator in item}
728
729test filter-15.1 {No match rule operator} -body {
730    ldap::filter::encode (11.12.14~value)
731} -returnCodes error -result {Invalid filter: no match operator in item}
732
733test filter-16.0 {Duplicated match rule operator} -body {
734    ldap::filter::encode (attrDesc=foo=bar)
735} -result [asnChoiceConstr 3 [glue \
736    [asnOctetString [ldap::filter::LDAPString attrDesc]] \
737    [asnOctetString [ldap::filter::AssertionValue foo=bar]]]]
738
739test filter-16.1 {Duplicated match rule operator} -body {
740    ldap::filter::encode (attrDesc~=foo~=)
741} -result [asnChoiceConstr 8 [glue \
742    [asnOctetString [ldap::filter::LDAPString attrDesc]] \
743    [asnOctetString [ldap::filter::AssertionValue foo~=]]]]
744
745test filter-16.2 {Duplicated match rule operator} -body {
746    ldap::filter::encode (attrDesc<=<=bar)
747} -result [asnChoiceConstr 6 [glue \
748    [asnOctetString [ldap::filter::LDAPString attrDesc]] \
749    [asnOctetString [ldap::filter::AssertionValue <=bar]]]]
750
751test filter-16.3 {Duplicated match rule operator} -body {
752    ldap::filter::encode (attrDesc>=>=>=)
753} -result [asnChoiceConstr 5 [glue \
754    [asnOctetString [ldap::filter::LDAPString attrDesc]] \
755    [asnOctetString [ldap::filter::AssertionValue >=>=]]]]
756
757test filter-16.4 {Duplicated match rule operator} -body {
758    ldap::filter::encode (AttrDesc:=:=what?:=)
759} -result [asnChoiceConstr 9 [glue \
760    [asnChoice 2 [ldap::filter::LDAPString AttrDesc]] \
761    [asnChoice 3 [ldap::filter::AssertionValue :=what?:=]]]]
762
763test filter-17.0 {Compound filters: negation} -body {
764    ldap::filter::encode (!(foo=bar))
765} -result [asnChoiceConstr 2 [asnChoiceConstr 3 [glue \
766    [asnOctetString [ldap::filter::LDAPString foo]] \
767    [asnOctetString [ldap::filter::AssertionValue bar]]]]]
768
769test filter-17.1 {Compound filters: AND} -body {
770    ldap::filter::encode (&(one=two)(three<=four)(five>=six))
771} -result [asnChoiceConstr 0 [glue \
772    [asnChoiceConstr 3 [glue \
773	[asnOctetString [ldap::filter::LDAPString one]] \
774	[asnOctetString [ldap::filter::AssertionValue two]]]] \
775    [asnChoiceConstr 6 [glue \
776	[asnOctetString [ldap::filter::LDAPString three]] \
777	[asnOctetString [ldap::filter::AssertionValue four]]]] \
778    [asnChoiceConstr 5 [glue \
779	[asnOctetString [ldap::filter::LDAPString five]] \
780	[asnOctetString [ldap::filter::AssertionValue six]]]]]]
781
782test filter-17.2 {Compound filters: OR} -body {
783    ldap::filter::encode (|(foo=bar)(baz:fuzzyMatch:=quux)(key~=value))
784} -result [asnChoiceConstr 1 [glue \
785    [asnChoiceConstr 3 [glue \
786	[asnOctetString [ldap::filter::LDAPString foo]] \
787	[asnOctetString [ldap::filter::AssertionValue bar]]]] \
788    [asnChoiceConstr 9 [glue \
789	[asnChoice 1 [ldap::filter::LDAPString fuzzyMatch]] \
790	[asnChoice 2 [ldap::filter::LDAPString baz]] \
791	[asnChoice 3 [ldap::filter::AssertionValue quux]]]] \
792    [asnChoiceConstr 8 [glue \
793	[asnOctetString [ldap::filter::LDAPString key]] \
794	[asnOctetString [ldap::filter::AssertionValue value]]]]]]
795
796test filter-17.3 {Compound filters: AND, spaces in assertion values} -body {
797    ldap::filter::encode {(&(OU=Research & Development)(DN=Rube Goldberg))}
798} -result [asnChoiceConstr 0 [glue \
799    [asnChoiceConstr 3 [glue \
800	[asnOctetString [ldap::filter::LDAPString OU]] \
801	[asnOctetString [ldap::filter::AssertionValue "Research & Development"]]]] \
802    [asnChoiceConstr 3 [glue \
803	[asnOctetString [ldap::filter::LDAPString DN]] \
804	[asnOctetString [ldap::filter::AssertionValue "Rube Goldberg"]]]]]]
805
806test filter-18.1 {Compound filters: unbalanced parenthesis} -body {
807    ldap::filter::encode (&(foo=bar)(baz=quux)
808} -returnCodes error -result {Invalid filter: unbalanced parenthesis}
809
810test filter-18.2 {Compound filters: unbalanced parenthesis} -body {
811    ldap::filter::encode (!(&(a=b)c=d))
812} -returnCodes error -result {Invalid filter: malformed compound filter expression}
813
814test filter-18.2 {Compound filters: unbalanced parenthesis} -body {
815    ldap::filter::encode (!(&(a=b)))c=d))
816} -returnCodes error -result {Invalid filter: malformed compound filter expression}
817
818test filter-18.3 {Compound filters: unbalanced parenthesis} -body {
819    ldap::filter::encode (!()
820} -returnCodes error -result {Invalid filter:\
821    filter expression must be surrounded by parentheses}
822
823test filter-19.1 {Compound filters: junk in expression} -body {
824    ldap::filter::encode {(& (foo=bar)(baz=quux))}
825} -returnCodes error -result {Invalid filter: malformed compound filter expression}
826
827test filter-19.2 {Compound filters: junk in expression} -body {
828    ldap::filter::encode {(&(foo=bar) (baz=quux))}
829} -returnCodes error -result {Invalid filter: malformed compound filter expression}
830
831test filter-19.3 {Compound filters: junk in expression} -body {
832    ldap::filter::encode {(|(foo=bar)(baz=quux) )}
833} -returnCodes error -result {Invalid filter: malformed compound filter expression}
834
835test filter-19.3 {Compound filters: junk in expression} -body {
836    ldap::filter::encode {(&&(foo=bar)(baz=quux))}
837} -returnCodes error -result {Invalid filter: malformed compound filter expression}
838
839test filter-19.4 {Compound filters: junk in expression} -body {
840    ldap::filter::encode {((foo=bar)&(baz=quux))}
841} -returnCodes error -match glob -result {Invalid filter: malformed attribute *}
842
843test filter-20.0 {Missing elements in filter composition} -body {
844    ldap::filter::encode (!)
845} -returnCodes error -result {Invalid filter:\
846    filter expression must be surrounded by parentheses}
847
848test filter-20.1 {Missing elements in filter composition} -body {
849    ldap::filter::encode (&)
850} -returnCodes error -result {Invalid filter: malformed compound filter expression}
851
852test filter-20.2 {Missing elements in filter composition} -body {
853    ldap::filter::encode (|)
854} -returnCodes error -result {Invalid filter: malformed compound filter expression}
855
856test filter-21.0 {Torture test} -body {
857    ldap::filter::encode [regsub -all \\s+ {
858	(|
859	    (&
860		(userName=Jane\20Random\00)
861		(userCategory;x-lang-ru~=human)
862	    )
863	    (!
864		(|
865		    (!
866			(salary=*)
867		    )
868		    (&
869			(personAge>=80)
870			(yearsEmployed<=70)
871			(employeeName=Joe*a**nd**Hacker)
872		    )
873		)
874	    )
875	    (|
876		(11.22.33.44;x-files:dn:=value)
877		(:567.34.56:=\28\2a\29)
878	    )
879	    (foo=bar)
880	)
881    } ""]
882} -result [asnChoiceConstr 1 [glue \
883    [asnChoiceConstr 0 [glue \
884	[asnChoiceConstr 3 [glue \
885	    [asnOctetString [ldap::filter::LDAPString userName]] \
886	    [asnOctetString [encoding convertto utf-8 "Jane Random\0"]]]] \
887	[asnChoiceConstr 8 [glue \
888	    [asnOctetString [ldap::filter::LDAPString userCategory\;x-lang-ru]] \
889	    [asnOctetString [ldap::filter::AssertionValue human]]]]]] \
890    [asnChoiceConstr 2 \
891	[asnChoiceConstr 1 [glue \
892	    [asnChoiceConstr 2 \
893		[asnChoice 7 [ldap::filter::LDAPString salary]]] \
894	    [asnChoiceConstr 0 [glue \
895		[asnChoiceConstr 5 [glue \
896		    [asnOctetString [ldap::filter::LDAPString personAge]] \
897		    [asnOctetString [ldap::filter::AssertionValue 80]]]] \
898		[asnChoiceConstr 6 [glue \
899		    [asnOctetString [ldap::filter::LDAPString yearsEmployed]] \
900		    [asnOctetString [ldap::filter::AssertionValue 70]]]] \
901		[asnChoiceConstr 4 [glue \
902		    [asnOctetString [ldap::filter::LDAPString employeeName]] \
903		    [asnSequence [glue \
904			[asnChoice 0 [ldap::filter::AssertionValue Joe]] \
905			[asnChoice 1 [ldap::filter::AssertionValue a]] \
906			[asnChoice 1 [ldap::filter::AssertionValue nd]] \
907			[asnChoice 2 [ldap::filter::AssertionValue Hacker]]]]]]]]]]] \
908    [asnChoiceConstr 1 [glue \
909	[asnChoiceConstr 9 [glue \
910	    [asnChoice 2 [ldap::filter::LDAPString 11.22.33.44\;x-files]] \
911	    [asnChoice 3 [ldap::filter::AssertionValue value]] \
912	    [asnChoice 4 [binary format cc 1 1]]]] \
913	[asnChoiceConstr 9 [glue \
914	    [asnChoice 1 [ldap::filter::LDAPString 567.34.56]] \
915	    [asnChoice 3 [encoding convertto utf-8 (*)]]]]]] \
916    [asnChoiceConstr 3 [glue \
917	[asnOctetString [ldap::filter::LDAPString foo]] \
918	[asnOctetString [ldap::filter::AssertionValue bar]]]] \
919    ]]
920
921# -------------------------------------------------------------------------
922testsuiteCleanup
923
924# Local Variables:
925#  mode: tcl
926#  indent-tabs-mode: nil
927# End:
928# vim:ts=8:sw=4:sts=4:noet:syntax=tcl
929