forked from JesseCoretta/go-aci
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bind_test.go
1050 lines (908 loc) · 30.6 KB
/
bind_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package aci
import (
"fmt"
"testing"
)
func TestBindRuleMethods(t *testing.T) {
var brm BindRuleMethods
_ = brm.Len()
_ = brm.IsZero()
_, _ = brm.Index(0)
brm = newBindRuleMethods(bindRuleFuncMap{})
_ = brm.Len()
_ = brm.IsZero()
_, _ = brm.Index(0)
ssf := SSF(256)
brm = ssf.BRM()
for i := 0; i < brm.Len(); i++ {
if cop, meth := brm.Index(i + 1); meth().String() != fmt.Sprintf("ssf %s %q", cop, `256`) {
t.Errorf("%s failed: failed to call index %d [%s] non-nil %T (got %s)", t.Name(), i, cop.Context(), brm, meth())
return
}
}
}
func TestBindRules_wordToStack(t *testing.T) {
for word, expect := range map[string]bool{
`BAND`: false,
`AND`: true,
`aNd`: true,
`and`: true,
`andy`: false,
`OR`: true,
`or`: true,
`oR`: true,
`orwellian`: false,
`NOT`: true,
`not`: true,
`nOT`: true,
`AND NOT`: true,
`and not`: true,
`aNd NoT`: true,
`andnot`: true,
`and not a moment too soon...`: false,
``: false,
`&*#($`: false,
} {
if _, result := wordToStack(word); expect != result {
t.Errorf("%s unexpected result: want %t, got %t",
t.Name(), expect, result)
return
}
}
}
// mainly this exists to satisfy codecov, but also
// aid in identifying panic points.
func TestBindRule_bogus(t *testing.T) {
var br BindRule
br.isBindContextQualifier() // just to satisfy codecov.
_ = br.ID()
_ = br.Index(0)
_ = br.Category()
_ = br.IsZero()
_ = br.Paren()
_ = br.Len()
_ = br.Kind()
_ = br.Valid()
_ = br.Paren()
_ = br.Operator()
_ = br.IsNesting()
_ = br.NoPadding()
_ = br.Expression()
_ = br.Keyword()
_ = br.SetQuoteStyle(1)
_ = br.String()
_ = badCond(nil)
_ = castAsBindRule(nil)
_ = castAsBindRules(nil)
_ = castAsBindRule(float64(0))
_ = castAsBindRules(float64(0))
}
// mainly this exists to satisfy codecov, but also
// aid in identifying panic points.
func TestBindRules_bogus(t *testing.T) {
var br BindRules
br.isBindContextQualifier() // just to satisfy codecov.
_ = br.ID()
_ = br.Category()
_ = br.IsNesting()
_ = br.IsZero()
_ = br.Len()
_ = br.Fold()
_ = br.Valid()
_ = br.Paren()
_ = br.ReadOnly()
_ = br.NoPadding()
_ = br.String()
_ = br.Push(nil)
_ = br.Pop()
_ = br.Index(-100)
_ = br.Traverse([]int{1, 2, 3, 4}...)
br.reset()
br = And(
SSF(128).Ge(),
GDN(`cn=Executives,ou=Groups,dc=example,dc=com`).Ne(),
UDNs("uid=jesse,ou=People,dc=example,dc=com", "uid=courtney,ou=People,dc=example,dc=com").Eq(),
)
_ = br.Kind()
_ = br.IsNesting()
_ = br.Keyword()
_ = br.Pop()
_ = br.Push()
_ = br.insert(`fnord`, 0)
_ = br.Index(1)
replacer := GDN(`cn=Executive Assistants,ou=Groups,dc=example,dc=com`).Ne()
br.Replace(replacer, 1)
replaced := br.Index(1)
if replacer.String() != replaced.String() {
t.Errorf("%s failed: %T.Replace did not replace specified slice value, want '%s', got '%s'",
t.Name(), br, replacer, replaced)
return
}
ctx := br.Traverse(1)
if ctx.String() != replaced.String() {
t.Errorf("%s failed: %T.Traverse did not return replaced slice value, want '%s', got '%s'",
t.Name(), br, replaced, ctx)
return
}
}
/*
This example demonstrates the useless nature of the Traverse method for a receiver
that is an instance of BindRule. As BindRule is logically "singular", there is no
structure in which a traversal would be possible. The Traverse method only exists
to satisfy Go's interface signature requirements as they pertain to the BindContext
type, and this test exists only to maintain code coverage and to convey this message.
Execution of this method simply returns the receiver.
*/
func ExampleBindRule_Traverse() {
br := SSF(71).Eq()
fmt.Printf("%T", br.Traverse(1, 2, 3, 4, 5))
// Output: aci.BindRule
}
/*
This example demonstrates the traversal of a BindRules structure to obtain a specific
nested element, in this case the 'ssf >= "128"' expression.
*/
func ExampleBindRules_Traverse() {
// And() is the variable for the outermost stack, don't count it as an index.
// Rather, begin counting its children instead.
rules := And(
GDN(`cn=X.500 Administrators,ou=Groups,dc=example,dc=com`).Eq().Paren(),
Timeframe(ToD(`1730`), ToD(`2330`)).Paren(),
// Enter the Or stack by descending within the third element (AND slice #2)
Or(
UAT(`manager`, `LDAPURL`).Eq().Paren(),
GAT(`owner`, SELFDN).Eq().Paren(),
URI(UDN(`ou=People,dc=example,dc=com`), Subtree).Eq().Paren(),
// OR slice #3. This is ILLOGICAL because
// there's no benefit to placing an AND in
// this rule, as it does not produce what
// would be viewed as a "sensible" statement
// of evaluation.
And(
// Inner AND slice #0
SSF(128).Ge(),
),
),
)
ssf := rules.Traverse(2, 3, 0)
fmt.Printf("%s", ssf)
// Output: ssf >= "128"
}
/*
This is an identical scenario to the above Traverse example, except in this scenario we
will be writing to the slice returned.
*/
func ExampleBindRules_Traverse_andWrite() {
// And() is the variable for the outermost stack, don't count it as an index.
// Rather, begin counting its children instead.
rules := And(
GDN(`cn=X.500 Administrators,ou=Groups,dc=example,dc=com`).Eq().Paren(),
Timeframe(ToD(`1730`), ToD(`2330`)).Paren(),
// Enter the Or stack by descending within the third element (AND slice #2)
Or(
UAT(`manager`, `LDAPURL`).Eq().Paren(),
GAT(`owner`, SELFDN).Eq().Paren(),
URI(UDN(`ou=People,dc=example,dc=com`), Subtree).Eq().Paren(),
// OR slice #3
And(
// Inner AND slice #0
SSF(128).Ge(),
),
),
)
// Call the specific stack/slice we want. Remember,
// Traverse returns a BindContext interface, which
// will be either BindRule OR BindRules. In this
// demonstration, we know what it is, thus we need
// not perform type switching in a case statement.
raw := rules.Traverse(2, 3, 0)
asserted, ok := raw.(BindRule)
if !ok {
fmt.Printf("Failed to assert %T", asserted)
return
}
// Because go-stackage is so heavily pointer-based,
// we need not worry about "writing the updated SSF
// value back to the stack". Just make the changes
// to the condition itself, and be done with it.
asserted.SetExpression(SSF(164)) // set to 164 because I'm so arbitrary
// Do the stack walk again to see if the pointer updated ...
fmt.Printf("%s", rules.Traverse(2, 3, 0))
// Output: ssf >= "164"
}
/*
This example demonstrates the union between a group distinguished name and a timeframe,
expressed as a BindRules instance. Parenthetical encapsulation is enabled for inner stack
elements, but not the outer (AND) stack itself.
*/
func ExampleAnd() {
and := And(
GDN(`cn=X.500 Administrators,ou=Groups,dc=example,dc=com`).Eq().Paren(),
Timeframe(ToD(`1730`), ToD(`2330`)).Paren(),
)
fmt.Printf("%s", and)
// Output: ( groupdn = "ldap:///cn=X.500 Administrators,ou=Groups,dc=example,dc=com" ) AND ( timeofday >= "1730" AND timeofday < "2330" )
}
/*
This example demonstrates a logical OR between a value matching bind rule and an LDAP URI
bearing the userdn keyword context. Parentheticals are enabled at every point.
*/
func ExampleOr() {
or := Or(
UAT(`manager`, `LDAPURL`).Eq().Paren(),
URI(UDN(`ou=People,dc=example,dc=com`), Subtree).Eq().Paren(),
)
fmt.Printf("%s", or.Paren())
// Output: ( ( userattr = "manager#LDAPURL" ) OR ( userdn = "ldap:///ou=People,dc=example,dc=com??sub?" ) )
}
/*
This example demonstrates a logical NOT that excludes a value matching userattr context or
an LDAPURI bearing the userdn key context. The NOT operation should generally encompass one
(1) or more conditions within an OR context. Additionally, NOT operations generally reside
within an outer AND context as shown. YMMV.
*/
func ExampleNot() {
and := And(
IP(`192.168.`).Eq().Paren(),
Not(Or(
UAT(`manager`, `LDAPURL`).Eq().Paren(),
URI(UDN(`ou=People,dc=example,dc=com`), Subtree).Eq().Paren(),
).Paren()),
)
fmt.Printf("%s", and)
// Output: ( ip = "192.168." ) AND NOT ( ( userattr = "manager#LDAPURL" ) OR ( userdn = "ldap:///ou=People,dc=example,dc=com??sub?" ) )
}
/*
This example demonstrates the indexing, iteration and execution of the available [ComparisonOperator] methods for the [BindDistinguishedName] type.
*/
func ExampleBindRuleMethods() {
var dn BindDistinguishedName = GDN(`cn=X.500 Administrators,ou=Groups,dc=example,dc=com`)
brm := dn.BRM()
for i := 0; i < brm.Len(); i++ {
cop, meth := brm.Index(i + 1) // zero (0) should never be accessed, start at 1
fmt.Printf("[%s] %s\n", cop.Description(), meth().Paren()) // enable parentheticals, because why not
}
// Output:
// [Equal To] ( groupdn = "ldap:///cn=X.500 Administrators,ou=Groups,dc=example,dc=com" )
// [Not Equal To] ( groupdn != "ldap:///cn=X.500 Administrators,ou=Groups,dc=example,dc=com" )
}
func ExampleBindRuleMethods_Index() {
ssf := SSF(256)
brm := ssf.BRM()
for i := 0; i < brm.Len(); i++ {
// IMPORTANT: Do not call index 0. Either adjust your
// loop variable (i) to begin at 1, and terminate at
// brm.Len()+1 --OR-- simply +1 the index call as we
// are doing here (seems easier). The reason for this
// is because there is no valid ComparisonOperator
// with an underlying uint8 value of zero (0). See
// the ComparisonOperator constants for details.
idx := i + 1
cop, meth := brm.Index(idx)
// execute method to create the bindrule, while
// also enabling the (optional) parenthetical bit
rule := meth().Paren()
// grab the raw string output
fmt.Printf("[%d] %T instance [%s] execution returned %T: %s\n", idx, meth, cop.Context(), rule, rule)
}
// Output:
// [1] aci.BindRuleMethod instance [Eq] execution returned aci.BindRule: ( ssf = "256" )
// [2] aci.BindRuleMethod instance [Ne] execution returned aci.BindRule: ( ssf != "256" )
// [3] aci.BindRuleMethod instance [Lt] execution returned aci.BindRule: ( ssf < "256" )
// [4] aci.BindRuleMethod instance [Gt] execution returned aci.BindRule: ( ssf > "256" )
// [5] aci.BindRuleMethod instance [Le] execution returned aci.BindRule: ( ssf <= "256" )
// [6] aci.BindRuleMethod instance [Ge] execution returned aci.BindRule: ( ssf >= "256" )
}
func ExampleBindRuleMethods_Index_byText() {
ssf := SSF(256)
brm := ssf.BRM()
// Here, we demonstrate calling a particular BindRuleMethod
// not by its numerical index, but rather by its actual
// "symbolic" operator representation. Keep in mind these
// options for text-based searches:
//
// - symbols (e.g.: '=', '>') are available via ComparisonOperator.String()
// - func names (e.g.: 'Eq', 'Gt') are available via ComparisonOperator.Context()
// - descriptions (e.g.: 'Not Equal To', 'Less Than') are available via ComparisonOperator.Description()
//
// As such, feel free to replace these list items with one of the above methods,
// but keep in mind that text based searches are more resource intensive than as
// compared to direct ComparisonOperator numeric calls. If you have performance
// concerns, avoid this text based procedure.
for i, term := range []string{
`=`,
`!=`,
`<`,
`>`,
`<=`,
`>=`,
} {
// IMPORTANT: Do not call index 0. Either adjust your
// loop variable (i) to begin at 1, and terminate at
// brm.Len()+1 --OR-- simply +1 the index call as we
// are doing here (seems easier). The reason for this
// is because there is no valid ComparisonOperator
// with an underlying uint8 value of zero (0). See
// the ComparisonOperator constants for details.
cop, meth := brm.Index(term)
// execute method to create the bindrule, while
// also enabling the (optional) parenthetical bit
rule := meth().Paren()
// grab the raw string output
fmt.Printf("[%d] %T instance [%s] execution returned %T: %s\n", i+1, meth, cop.Context(), rule, rule)
}
// Output:
// [1] aci.BindRuleMethod instance [Eq] execution returned aci.BindRule: ( ssf = "256" )
// [2] aci.BindRuleMethod instance [Ne] execution returned aci.BindRule: ( ssf != "256" )
// [3] aci.BindRuleMethod instance [Lt] execution returned aci.BindRule: ( ssf < "256" )
// [4] aci.BindRuleMethod instance [Gt] execution returned aci.BindRule: ( ssf > "256" )
// [5] aci.BindRuleMethod instance [Le] execution returned aci.BindRule: ( ssf <= "256" )
// [6] aci.BindRuleMethod instance [Ge] execution returned aci.BindRule: ( ssf >= "256" )
}
func ExampleBindRuleMethods_IsZero() {
var brm BindRuleMethods
fmt.Printf("Zero: %t", brm.IsZero())
// Output: Zero: true
}
func ExampleBindRuleMethods_Valid() {
var brm BindRuleMethods
fmt.Printf("Error: %v", brm.Valid())
// Output: Error: aci.BindRuleMethods instance is nil
}
func ExampleBindRuleMethods_Len() {
// Note: we need not populate the value to get a
// BRM list, but the methods in that list won't
// actually work until the instance (ssf) is in
// an acceptable state. Since all we're doing
// here is checking the length, a receiver that
// is nil/zero is totally fine.
var ssf SecurityStrengthFactor // not init'd
total := ssf.BRM().Len()
fmt.Printf("There are %d available aci.BindRuleMethod instances for creating %T BindRules", total, ssf)
// Output: There are 6 available aci.BindRuleMethod instances for creating aci.SecurityStrengthFactor BindRules
}
func ExampleBindRuleMethod() {
ssf := SSF(256)
brm := ssf.BRM()
// verify that the receiver (ssf) is copacetic
// and will produce a legal expression if meth
// is executed
if err := brm.Valid(); err != nil {
fmt.Println(err)
return
}
for i := 0; i < brm.Len(); i++ {
// IMPORTANT: Do not call index 0. Either adjust your
// loop variable (i) to begin at 1, and terminate at
// brm.Len()+1 --OR-- simply +1 the index call as we
// are doing here (seems easier). The reason for this
// is because there is no valid ComparisonOperator
// with an underlying uint8 value of zero (0). See
// the ComparisonOperator constants for details.
idx := i + 1
cop, meth := brm.Index(idx)
// execute method to create the bindrule, while
// also enabling the (optional) parenthetical bit
rule := meth().Paren()
// grab the raw string output
fmt.Printf("[%d] %T instance [%s] execution returned %T: %s\n", idx, meth, cop.Context(), rule, rule)
}
// Output:
// [1] aci.BindRuleMethod instance [Eq] execution returned aci.BindRule: ( ssf = "256" )
// [2] aci.BindRuleMethod instance [Ne] execution returned aci.BindRule: ( ssf != "256" )
// [3] aci.BindRuleMethod instance [Lt] execution returned aci.BindRule: ( ssf < "256" )
// [4] aci.BindRuleMethod instance [Gt] execution returned aci.BindRule: ( ssf > "256" )
// [5] aci.BindRuleMethod instance [Le] execution returned aci.BindRule: ( ssf <= "256" )
// [6] aci.BindRuleMethod instance [Ge] execution returned aci.BindRule: ( ssf >= "256" )
}
func ExampleBindRule_Compare() {
ssf1 := SSF(128).Eq()
ssf2 := SSF(127).Eq()
fmt.Printf("Equal: %t", ssf1.Compare(ssf2))
// Output: Equal: false
}
func ExampleBindRules_Compare() {
tf1 := Timeframe(ToD(`0130`), ToD(`1605`))
tf2 := Timeframe(ToD(`1215`), ToD(`1605`))
fmt.Printf("Equal: %t", tf1.Compare(tf2))
// Output: Equal: false
}
func ExampleBindRule_Category() {
fmt.Printf("%s", SSF(71).Eq().Category())
// Output: ssf
}
func ExampleBindRules_Category() {
fmt.Printf("%s", And(SSF(71).Eq()).Category())
// Output: and
}
func ExampleBindRule_Keyword() {
fmt.Printf("%s", SSF(0).Ne().Keyword())
// Output: ssf
}
func ExampleBindRule_Kind() {
var tr BindRule
fmt.Printf("%s", tr.Kind())
// Output: condition
}
func ExampleBindRule_ID() {
fmt.Printf("%s", IP(`192.168.`).Ne().ID())
// Output: bind
}
func ExampleBindRule_Expression() {
dn := `uid=jesse,ou=Contractors,ou=People,dc=example,dc=com`
fmt.Printf("%s", UDN(dn).Eq().Expression())
// Output: ldap:///uid=jesse,ou=Contractors,ou=People,dc=example,dc=com
}
func ExampleBindRule_IsZero() {
var tr BindRule
fmt.Printf("Zero: %t", tr.IsZero())
// Output: Zero: true
}
func ExampleBindRule_Valid() {
var tr BindRule
fmt.Printf("Valid: %t", tr.Valid() == nil)
// Output: Valid: false
}
func ExampleBindRule_SetQuoteStyle() {
var tgt BindRule
tgt.SetKeyword(BindUDN)
tgt.Init()
tgt.SetKeyword(BindUDN)
tgt.SetOperator(`!=`)
tgt.SetOperator(2)
tgt.SetOperator(54738372)
tgt.SetOperator(Ne)
tgt.SetExpression(UDNs(
UDN(`ldap:///uid=jesse,ou=People,dc=example,dc=com`),
UDN(`ldap:///uid=courtney,ou=People,dc=example,dc=com`),
UDN(`ldap:///uid=jimmy,ou=People,dc=example,dc=com`),
))
tgt.Paren() // optional
tgt.SetQuoteStyle(0)
style1 := tgt.String()
tgt.SetQuoteStyle(1)
style2 := tgt.String()
fmt.Printf("\n0: %s\n1: %s", style1, style2)
// Output:
// 0: ( userdn != "ldap:///uid=jesse,ou=People,dc=example,dc=com" || "ldap:///uid=courtney,ou=People,dc=example,dc=com" || "ldap:///uid=jimmy,ou=People,dc=example,dc=com" )
// 1: ( userdn != "ldap:///uid=jesse,ou=People,dc=example,dc=com || ldap:///uid=courtney,ou=People,dc=example,dc=com || ldap:///uid=jimmy,ou=People,dc=example,dc=com" )
}
/*
This example demonstrates the various capabilities of a BindRules instance, as well as
the use of some so-called "prefabricator" functions for additional convenience.
Note that BindRules should always be initialized before use. The reason for this is
because it may be required to set a logical Boolean operating mode, such as 'AND',
'OR' and '(AND) NOT'. This governs how the individual slices (which may descend into
other stacks) are string represented in a Boolean expressive statement.
*/
func ExampleBindRules() {
// Outer BindRules structure (a.k.a.: the "top")
// is a non-parenthetical ORed BindRules stack.
var brs BindRules = Or(
// First ORed condition (slice #0) is a
// non-parenthetical ANDed BindRules stack
// with operator folding enabled.
And(
// A single non-parenthetical groupdn
// equality assertion BindRule occupies
// slice #0 of the current stack. Note
// that in this case, calling the needed
// operator method is necessary, as GDN
// is not a prefab function.
//
// Result:
GDN(`cn=Accounting,ou=Groups,dc=example,dc=com`).Eq(), // groupdn
// Timeframe is a BindRules prefab function
// used to conveniently produce a pair of
// `timeofday` conditions within an ANDed
// logical context in order to specify a
// "time-window" during which access will
// be granted or withheld in some manner.
//
// This expression occupies slice #1 of the
// current stack and is parenthetical. There
// is no need to execute the operator method
// (e.g.: Eq) manually, as this function is
// a prefabricator and does this for us 😎.
// Additionally, toggle the Fold bit for the
// return instance.
//
// Result: ( timeofday >= "0900" and timeofday < "1830" )
Timeframe(
ToD(`0900`), // notBefore
ToD(`1830`), // notAfter
).Paren().Fold(),
// Weekdays is a BindRule prefab to conveniently
// produce a sequence of Day instances expressing
// Monday through Friday. See also Weekend for an
// inverse of this functionality.
//
// This expression occupies slice #2 of the current
// stack and is parenthetical. There is no need to
// execute the operator method (e.g:. Eq) manually,
// as this function automatically crafts the BindRule.
//
// Result: ( dayofweek = "Mon,Tues,Wed,Thur,Fri" )
Weekdays(`=`).Paren(), // comparison operator could also be 1, `eq` or `equal to`
).Fold(),
// Second ORed condition (slice #1) is a
// parenthetically ANDed BindRules stack.
And(
// Two (2) individual BindRule instances
// circumscribed within a parenthetical
// AND context. Note that in this case,
// calling the comparison method manually
// is required, as RDN and GAT (among
// others) are not prefab functions.
//
// result: ( roledn = "ldap:///cn=Superusers,ou=Groups,dc=example,dc=com`" AND groupattr = "privilegeLevel#GAMMA5" )
RDN(`cn=Superusers,ou=Groups,dc=example,dc=com`).Eq(), // roledn
GAT(`privilegeLevel`, `GAMMA5`).Eq(), // groupattr
).Paren(),
)
// Let's make some arbitrary changes ...
//
// Make the outer stack (OR) parenthetical
brs.Paren() // no arg = toggle state, else use true/false for explicit set.
fmt.Printf("%s", brs)
// Output: ( groupdn = "ldap:///cn=Accounting,ou=Groups,dc=example,dc=com" and ( timeofday >= "0900" and timeofday < "1830" ) and ( dayofweek = "Mon,Tues,Wed,Thur,Fri" ) OR ( roledn = "ldap:///cn=Superusers,ou=Groups,dc=example,dc=com" AND groupattr = "privilegeLevel#GAMMA5" ) )
}
/*
This example demonstrates the toggling of Boolean WORD operator case-folding
of a BindRules instance.
*/
func ExampleBindRules_Fold() {
strong := And(SSF(128).Ge(), EXTERNAL.Eq())
strong.Fold() // we want `AND` to be `and`
fmt.Printf("%s", strong)
// Output: ssf >= "128" and authmethod = "SASL EXTERNAL"
}
func ExampleBindRules_ID() {
var brs BindRules
fmt.Printf("%s", brs.ID())
// Output: bind
}
func ExampleBindRules_IsZero() {
var brs BindRules
fmt.Printf("Zero: %t", brs.IsZero())
// Output: Zero: true
}
func ExampleBindRules_Valid() {
var brs BindRules
fmt.Printf("Valid: %t", brs.Valid() == nil)
// Output: Valid: false
}
func ExampleBindRules_String() {
strong := And(SSF(128).Ge(), EXTERNAL.Eq())
fmt.Printf("%s", strong)
// Output: ssf >= "128" AND authmethod = "SASL EXTERNAL"
}
/*
This example demonstrates the selective replacement of
a specific BindRules stack slice.
*/
func ExampleBindRules_Replace() {
strong := And(
SSF(128).Ge(), // slice #0
DIGESTMD5.Eq(), // slice #1
)
// Replace awful Digest-MD5 with the
// SASL/EXTERNAL mechanism.
strong.Replace(EXTERNAL.Eq(), 1) // <x> replace slice #1
fmt.Printf("%s", strong)
// Output: ssf >= "128" AND authmethod = "SASL EXTERNAL"
}
/*
This example demonstrates an attempt to modify a BindRules
stack instance while its ReadOnly bit is enabled.
*/
func ExampleBindRules_ReadOnly() {
strong := And(
SSF(128).Ge(), // slice #0
DIGESTMD5.Eq(), // slice #1
)
strong.ReadOnly()
// Try to replace awful Digest-MD5 with
// the SASL/EXTERNAL mechanism.
strong.Replace(EXTERNAL.Eq(), 1)
fmt.Printf("%s", strong)
// Output: ssf >= "128" AND authmethod = "SASL DIGEST-MD5"
}
/*
This example demonstrates the addition of new slice elements
to a BindRules instance using its Push method.
*/
func ExampleBindRules_Push() {
// create a single BindRules instance
// with only one (1) slice (Timeframe
// BindRule) ...
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
)
// Add a Weekdays BindRule prefab
brs.Push(Weekdays(Eq))
fmt.Printf("%s", brs)
// Output: timeofday >= "0900" AND timeofday < "1830" AND dayofweek = "Mon,Tues,Wed,Thur,Fri"
}
/*
This example demonstrates the removal of a single slice
within a BindRules instance in LIFO fashion using its
Pop method.
*/
func ExampleBindRules_Pop() {
// create a single BindRules instance
// with two (2) slices ...
brs := And(
Timeframe(
ToD(`0900`), // slice #0
ToD(`1830`), // slice #1
),
Weekdays(Eq),
)
// Remove (by Pop) the Weekdays slice (slice #1)
popped := brs.Pop()
fmt.Printf("%s", popped)
// Output: dayofweek = "Mon,Tues,Wed,Thur,Fri"
}
/*
This example demonstrates the interrogation of a BindRules
instance to determine whether any of its immediate slice
members are other stack elements, thereby indicating that
a "nesting condition" is in effect.
*/
func ExampleBindRules_IsNesting() {
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
Weekdays(Eq),
)
fmt.Printf("Contains nesting elements: %t", brs.IsNesting())
// Output: Contains nesting elements: true
}
/*
This example demonstrates the calling of a specific slice
member by its numerical index using the BindRules.Index
method.
*/
func ExampleBindRules_Index() {
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
Weekdays(Eq),
)
fmt.Printf("%s", brs.Index(0))
// Output: timeofday >= "0900" AND timeofday < "1830"
}
/*
This example demonstrates the use of the NoPadding method
to remove the outer padding of a BindRules instance. Note
that parentheticals are enabled for visual aid.
*/
func ExampleBindRules_NoPadding() {
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
Weekdays(Eq),
)
brs.Paren().NoPadding()
fmt.Printf("%s", brs)
// Output: (timeofday >= "0900" AND timeofday < "1830" AND dayofweek = "Mon,Tues,Wed,Thur,Fri")
}
/*
This example demonstrates the interrogation of a BindRules
instance to determine its integer length using its Len
method. The return value describes the number of slice
elements present within the instance.
*/
func ExampleBindRules_Len() {
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
Weekdays(Eq),
)
fmt.Printf("Contains %d elements", brs.Len())
// Output: Contains 2 elements
}
/*
This example demonstrates the use of the Kind method to
reveal the underlying type of the receiver. This is for
use during the handling of a combination of BindRules
and BindRule instances under the BindContext interface
context.
*/
func ExampleBindRules_Kind() {
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
Weekdays(Eq),
)
fmt.Printf("%s", brs.Kind())
// Output: stack
}
/*
This example demonstrates the use of the useless Keyword method
that returns a bogus keyword in string representation. Keywords
are only directly applicable to BindRule instances.
*/
func ExampleBindRules_Keyword() {
tf := Timeframe(
ToD(`0900`),
ToD(`1830`),
)
fmt.Printf("%s", tf.Keyword())
// Output: <invalid_bind_keyword>
}
/*
This example demonstrates the use of the Paren method to
enable the parenthetical setting for the receiver instance.
*/
func ExampleBindRules_Paren() {
brs := And(
Timeframe(
ToD(`0900`),
ToD(`1830`),
),
Weekdays(Eq),
)
brs.Paren()
fmt.Printf("%s", brs)
// Output: ( timeofday >= "0900" AND timeofday < "1830" AND dayofweek = "Mon,Tues,Wed,Thur,Fri" )
}
/*
This example demonstrates the use of the package-level BR function
for quick assembly of an instance of BindRule.
This is usually not necessary, and would only be practical when the
input and type information is known in advance. It is also nowhere
near as safe (regarding the specification of illegal constructs) as
the use of type-extended comparison operator methods. See the BRM
method extended by such types for further details.
*/
func ExampleBR() {
kw := BindUDN
op := Eq
ex := UDN(`uid=jesse,ou=People,dc=example,dc=com`)
fmt.Printf("%s", BR(kw, op, ex))
// Output: userdn = "ldap:///uid=jesse,ou=People,dc=example,dc=com"
}
func ExampleWeekdays() {
fmt.Printf("%s", Weekdays(Eq))
// Output: dayofweek = "Mon,Tues,Wed,Thur,Fri"
}
func ExampleWeekend() {
fmt.Printf("%s", Weekend(Ne))
// Output: dayofweek != "Sun,Sat"
}
func ExampleBindRule_Init() {
var br BindRule
br.Init() // required when assembly through "piecemeal"
// ... later in your code ...
br.SetKeyword(BindUDN) // set keyword ...
br.SetOperator(Ne) // ... so operator can be evaluated
fmt.Printf("Operator: %s", br.Operator().Description())
// Output: Operator: Not Equal To
}
func ExampleBindRule_Operator() {
var br BindRule
br.Init() // required when assembly through "piecemeal"
// ... later in your code ...
br.SetKeyword(BindUDN) // set keyword ...
br.SetOperator(Ne) // ... so operator can be evaluated
fmt.Printf("Operator: %s", br.Operator().Description())
// Output: Operator: Not Equal To
}
func ExampleBindRule_SetOperator() {
var br BindRule
br.Init() // required when assembly through "piecemeal"
// ... later in your code ...
br.SetKeyword(BindUDN) // set keyword ...
br.SetOperator(Ne) // ... so operator can be evaluated
fmt.Printf("Operator: %s", br.Operator().Description())
// Output: Operator: Not Equal To
}
func ExampleBindRule_SetKeyword() {
var br BindRule
br.Init() // required when assembly through "piecemeal"
// ... later in your code ...
br.SetKeyword(BindGDN) // set keyword ...
fmt.Printf("Keyword: %s", br.Keyword())
// Output: Keyword: groupdn
}
func ExampleBindRule_SetExpression() {
var br BindRule
br.Init() // required when assembly through "piecemeal"
// ... later in your code ...
br.SetExpression(UDN(`uid=jesse,ou=People,dc=example,dc=com`))
fmt.Printf("Expression: %s", br.Expression().(BindDistinguishedName))
// Output: Expression: ldap:///uid=jesse,ou=People,dc=example,dc=com
}
func ExampleBindRule_IsParen() {
var br BindRule
if err := br.Parse(`(timeofday>="0415")`); err != nil {
fmt.Println(err) // always check your parser errors
return
}
fmt.Printf("%T.IsParen: %t", br, br.IsParen())
// Output: aci.BindRule.IsParen: true
}
func ExampleBindRules_IsParen() {
// Use the convenient timeframe prefabber to
// create a BindRules instance, for which we
// engage parentheticals, all in one shot.
tf := Timeframe(ToD(`0700`), ToD(`1800`)).Paren()
fmt.Printf("%T.IsParen: %t", tf, tf.IsParen())
// Output: aci.BindRules.IsParen: true
}
func ExampleBindRule_String() {
var br BindRule
if err := br.Parse(`(timeofday>="0415")`); err != nil {
fmt.Println(err) // always check your parser errors
return
}
fmt.Printf("%s", br)
// Output: ( timeofday >= "0415" )
}
func ExampleBindRule_Paren() {
var br BindRule
if err := br.Parse(`(timeofday>="0415")`); err != nil {
fmt.Println(err) // always check your parser errors
return
}
// Here we'll turn off parenthetical encaps
// and then verify it was turned off in one
// fmt.Printf call.