@@ -31,16 +31,64 @@ import (
3131
3232func TestCompile (t * testing.T ) {
3333 for _ , tst := range policyTests {
34- t .Run (tst .name , func (t * testing.T ) {
35- r := newRunner (t , tst .name , tst .expr , tst .parseOpts , tst .envOpts ... )
34+ tc := tst
35+ t .Run (tc .name , func (t * testing.T ) {
36+ r := newRunner (tc .name , tc .expr , tc .parseOpts )
37+ env , ast , iss := r .compile (t , tc .envOpts , []CompilerOption {})
38+ if iss .Err () != nil {
39+ t .Fatalf ("Compile(%s) failed: %v" , r .name , iss .Err ())
40+ }
41+ r .setup (t , env , ast )
42+ r .run (t )
43+ })
44+ }
45+ }
46+
47+ func TestRuleComposerError (t * testing.T ) {
48+ env , err := cel .NewEnv ()
49+ if err != nil {
50+ t .Fatalf ("NewEnv() failed: %v" , err )
51+ }
52+ _ , err = NewRuleComposer (env , ExpressionUnnestHeight (- 1 ))
53+ if err == nil || ! strings .Contains (err .Error (), "invalid unnest" ) {
54+ t .Errorf ("NewRuleComposer() got %v, wanted 'invalid unnest'" , err )
55+ }
56+ }
57+
58+ func TestRuleComposerUnnest (t * testing.T ) {
59+ for _ , tst := range composerUnnestTests {
60+ tc := tst
61+ t .Run (tc .name , func (t * testing.T ) {
62+ r := newRunner (tc .name , tc .expr , []ParserOption {})
63+ env , rule , iss := r .compileRule (t )
64+ if iss .Err () != nil {
65+ t .Fatalf ("CompileRule() failed: %v" , iss .Err ())
66+ }
67+ rc , err := NewRuleComposer (env , tc .composerOpts ... )
68+ if err != nil {
69+ t .Fatalf ("NewRuleComposer() failed: %v" , err )
70+ }
71+ ast , iss := rc .Compose (rule )
72+ if iss .Err () != nil {
73+ t .Fatalf ("Compose(rule) failed: %v" , iss .Err ())
74+ }
75+ unparsed , err := cel .AstToString (ast )
76+ if err != nil {
77+ t .Fatalf ("cel.AstToString() failed: %v" , err )
78+ }
79+ if normalize (unparsed ) != normalize (tc .composed ) {
80+ t .Errorf ("cel.AstToString() got %s, wanted %s" , unparsed , tc .composed )
81+ }
82+ r .setup (t , env , ast )
3683 r .run (t )
3784 })
3885 }
3986}
4087
4188func TestCompileError (t * testing.T ) {
4289 for _ , tst := range policyErrorTests {
43- _ , _ , iss := compile (t , tst .name , []ParserOption {}, []cel.EnvOption {}, tst .compilerOpts )
90+ policy := parsePolicy (t , tst .name , []ParserOption {})
91+ _ , _ , iss := compile (t , tst .name , policy , []cel.EnvOption {}, tst .compilerOpts )
4492 if iss .Err () == nil {
4593 t .Fatalf ("compile(%s) did not error, wanted %s" , tst .name , tst .err )
4694 }
@@ -98,7 +146,8 @@ func TestMaxNestedExpressions_Error(t *testing.T) {
98146 wantError := `ERROR: testdata/required_labels/policy.yaml:15:8: error configuring compiler option: nested expression limit must be non-negative, non-zero value: -1
99147 | name: "required_labels"
100148 | .......^`
101- _ , _ , iss := compile (t , policyName , []ParserOption {}, []cel.EnvOption {}, []CompilerOption {MaxNestedExpressions (- 1 )})
149+ policy := parsePolicy (t , policyName , []ParserOption {})
150+ _ , _ , iss := compile (t , policyName , policy , []cel.EnvOption {}, []CompilerOption {MaxNestedExpressions (- 1 )})
102151 if iss .Err () == nil {
103152 t .Fatalf ("compile(%s) did not error, wanted %s" , policyName , wantError )
104153 }
@@ -109,55 +158,40 @@ func TestMaxNestedExpressions_Error(t *testing.T) {
109158
110159func BenchmarkCompile (b * testing.B ) {
111160 for _ , tst := range policyTests {
112- r := newRunner (b , tst .name , tst .expr , tst .parseOpts , tst .envOpts ... )
161+ r := newRunner (tst .name , tst .expr , tst .parseOpts )
162+ env , ast , iss := r .compile (b , tst .envOpts , []CompilerOption {})
163+ if iss .Err () != nil {
164+ b .Fatalf ("Compile() failed: %v" , iss .Err ())
165+ }
166+ r .setup (b , env , ast )
113167 r .bench (b )
114168 }
115169}
116170
117- func newRunner (t testing. TB , name , expr string , parseOpts []ParserOption , opts ... cel.EnvOption ) * runner {
118- r := & runner {
171+ func newRunner (name , expr string , parseOpts []ParserOption , opts ... cel.EnvOption ) * runner {
172+ return & runner {
119173 name : name ,
120- envOpts : opts ,
121174 parseOpts : parseOpts ,
122175 expr : expr }
123- r .setup (t )
124- return r
125176}
126177
127178type runner struct {
128- name string
129- envOpts []cel.EnvOption
130- parseOpts []ParserOption
131- compilerOpts []CompilerOption
132- env * cel.Env
133- expr string
134- prg cel.Program
179+ name string
180+ parseOpts []ParserOption
181+ env * cel.Env
182+ expr string
183+ prg cel.Program
135184}
136185
137- func mustCompileExpr (t testing.TB , env * cel.Env , expr string ) * cel.Ast {
138- t .Helper ()
139- out , iss := env .Compile (expr )
140- if iss .Err () != nil {
141- t .Fatalf ("env.Compile(%s) failed: %v" , expr , iss .Err ())
142- }
143- return out
186+ func (r * runner ) compile (t testing.TB , envOpts []cel.EnvOption , compilerOpts []CompilerOption ) (* cel.Env , * cel.Ast , * cel.Issues ) {
187+ policy := parsePolicy (t , r .name , r .parseOpts )
188+ return compile (t , r .name , policy , envOpts , compilerOpts )
144189}
145190
146- func compile ( t testing.TB , name string , parseOpts [] ParserOption , envOpts []cel. EnvOption , compilerOpts [] CompilerOption ) (* cel.Env , * cel. Ast , * cel.Issues ) {
191+ func ( r * runner ) compileRule ( t testing.TB ) (* cel.Env , * CompiledRule , * cel.Issues ) {
147192 t .Helper ()
148- config := readPolicyConfig (t , fmt .Sprintf ("testdata/%s/config.yaml" , name ))
149- srcFile := readPolicy (t , fmt .Sprintf ("testdata/%s/policy.yaml" , name ))
150- parser , err := NewParser (parseOpts ... )
151- if err != nil {
152- t .Fatalf ("NewParser() failed: %v" , err )
153- }
154- policy , iss := parser .Parse (srcFile )
155- if iss .Err () != nil {
156- t .Fatalf ("Parse() failed: %v" , iss .Err ())
157- }
158- if policy .name .Value != name {
159- t .Errorf ("policy name is %v, wanted %q" , policy .name , name )
160- }
193+ config := readPolicyConfig (t , fmt .Sprintf ("testdata/%s/config.yaml" , r .name ))
194+ policy := parsePolicy (t , r .name , r .parseOpts )
161195 env , err := cel .NewCustomEnv (
162196 cel .OptionalTypes (),
163197 cel .EnableMacroCallTracking (),
@@ -166,26 +200,17 @@ func compile(t testing.TB, name string, parseOpts []ParserOption, envOpts []cel.
166200 if err != nil {
167201 t .Fatalf ("cel.NewEnv() failed: %v" , err )
168202 }
169- // Configure any custom environment options.
170- env , err = env .Extend (envOpts ... )
171- if err != nil {
172- t .Fatalf ("env.Extend() with env options %v, failed: %v" , config , err )
173- }
174203 // Configure declarations
175204 env , err = env .Extend (FromConfig (config ))
176205 if err != nil {
177206 t .Fatalf ("env.Extend() with config options %v, failed: %v" , config , err )
178207 }
179- ast , iss := Compile (env , policy , compilerOpts ... )
180- return env , ast , iss
208+ rule , iss := CompileRule (env , policy )
209+ return env , rule , iss
181210}
182211
183- func (r * runner ) setup (t testing.TB ) {
212+ func (r * runner ) setup (t testing.TB , env * cel. Env , ast * cel. Ast ) {
184213 t .Helper ()
185- env , ast , iss := compile (t , r .name , r .parseOpts , r .envOpts , r .compilerOpts )
186- if iss .Err () != nil {
187- t .Fatalf ("Compile(%s) failed: %v" , r .name , iss .Err ())
188- }
189214 pExpr , err := cel .AstToString (ast )
190215 if err != nil {
191216 t .Fatalf ("cel.AstToString() failed: %v" , err )
@@ -323,6 +348,56 @@ func (r *runner) eval(t testing.TB, expr string) ref.Val {
323348 return out
324349}
325350
351+ func mustCompileExpr (t testing.TB , env * cel.Env , expr string ) * cel.Ast {
352+ t .Helper ()
353+ out , iss := env .Compile (expr )
354+ if iss .Err () != nil {
355+ t .Fatalf ("env.Compile(%s) failed: %v" , expr , iss .Err ())
356+ }
357+ return out
358+ }
359+
360+ func parsePolicy (t testing.TB , name string , parseOpts []ParserOption ) * Policy {
361+ t .Helper ()
362+ srcFile := readPolicy (t , fmt .Sprintf ("testdata/%s/policy.yaml" , name ))
363+ parser , err := NewParser (parseOpts ... )
364+ if err != nil {
365+ t .Fatalf ("NewParser() failed: %v" , err )
366+ }
367+ policy , iss := parser .Parse (srcFile )
368+ if iss .Err () != nil {
369+ t .Fatalf ("Parse() failed: %v" , iss .Err ())
370+ }
371+ if policy .name .Value != name {
372+ t .Errorf ("policy name is %v, wanted %q" , policy .name , name )
373+ }
374+ return policy
375+ }
376+
377+ func compile (t testing.TB , name string , policy * Policy , envOpts []cel.EnvOption , compilerOpts []CompilerOption ) (* cel.Env , * cel.Ast , * cel.Issues ) {
378+ config := readPolicyConfig (t , fmt .Sprintf ("testdata/%s/config.yaml" , name ))
379+ env , err := cel .NewCustomEnv (
380+ cel .OptionalTypes (),
381+ cel .EnableMacroCallTracking (),
382+ cel .ExtendedValidations (),
383+ ext .Bindings ())
384+ if err != nil {
385+ t .Fatalf ("cel.NewEnv() failed: %v" , err )
386+ }
387+ // Configure any custom environment options.
388+ env , err = env .Extend (envOpts ... )
389+ if err != nil {
390+ t .Fatalf ("env.Extend() with env options %v, failed: %v" , config , err )
391+ }
392+ // Configure declarations
393+ env , err = env .Extend (FromConfig (config ))
394+ if err != nil {
395+ t .Fatalf ("env.Extend() with config options %v, failed: %v" , config , err )
396+ }
397+ ast , iss := Compile (env , policy , compilerOpts ... )
398+ return env , ast , iss
399+ }
400+
326401func normalize (s string ) string {
327402 return strings .ReplaceAll (
328403 strings .ReplaceAll (
0 commit comments