1
- /****************************************************************************
2
- * Copyright 2018, 2020-2021, Optimizely, Inc. and contributors *
3
- * *
4
- * Licensed under the Apache License, Version 2.0 (the "License"); *
5
- * you may not use this file except in compliance with the License. *
6
- * You may obtain a copy of the License at *
7
- * *
8
- * http ://www.apache.org/licenses/LICENSE-2.0 *
9
- * *
10
- * Unless required by applicable law or agreed to in writing, software *
11
- * distributed under the License is distributed on an "AS IS" BASIS, *
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13
- * See the License for the specific language governing permissions and *
14
- * limitations under the License. *
15
- *************************************************************************** /
1
+ /**
2
+ * Copyright 2025, Optimizely
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https ://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
16
import { describe , it , vi , expect } from 'vitest' ;
17
17
18
18
import * as conditionTreeEvaluator from '.' ;
@@ -33,198 +33,186 @@ const conditionC = {
33
33
type : 'custom_attribute' ,
34
34
value : 'CA' ,
35
35
} ;
36
+ describe ( 'evaluate' , function ( ) {
37
+ it ( 'should return true for a leaf condition when the leaf condition evaluator returns true' , function ( ) {
38
+ expect (
39
+ conditionTreeEvaluator . evaluate ( conditionA , function ( ) {
40
+ return true ;
41
+ } )
42
+ ) . toBe ( true ) ;
43
+ } ) ;
44
+
45
+ it ( 'should return false for a leaf condition when the leaf condition evaluator returns false' , function ( ) {
46
+ expect (
47
+ conditionTreeEvaluator . evaluate ( conditionA , function ( ) {
48
+ return false ;
49
+ } )
50
+ ) . toBe ( false ) ;
51
+ } ) ;
36
52
37
- describe ( 'lib/core/condition_tree_evaluator' , function ( ) {
38
- describe ( 'APIs' , function ( ) {
39
- describe ( 'evaluate' , function ( ) {
40
- it ( 'should return true for a leaf condition when the leaf condition evaluator returns true' , function ( ) {
53
+ describe ( 'and evaluation' , function ( ) {
54
+ it ( 'should return true when ALL conditions evaluate to true' , function ( ) {
55
+ expect (
56
+ conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , function ( ) {
57
+ return true ;
58
+ } )
59
+ ) . toBe ( true ) ;
60
+ } ) ;
61
+
62
+ it ( 'should return false if one condition evaluates to false' , function ( ) {
63
+ const leafEvaluator = vi . fn ( ) ;
64
+ leafEvaluator . mockImplementationOnce ( ( ) => true ) . mockImplementationOnce ( ( ) => false ) ;
65
+ expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( false ) ;
66
+ } ) ;
67
+
68
+ describe ( 'null handling' , function ( ) {
69
+ it ( 'should return null when all operands evaluate to null' , function ( ) {
41
70
expect (
42
- conditionTreeEvaluator . evaluate ( conditionA , function ( ) {
43
- return true ;
71
+ conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , function ( ) {
72
+ return null ;
44
73
} )
45
- ) . toBe ( true ) ;
74
+ ) . toBeNull ( ) ;
75
+ } ) ;
76
+
77
+ it ( 'should return null when operands evaluate to trues and nulls' , function ( ) {
78
+ const leafEvaluator = vi . fn ( ) ;
79
+ leafEvaluator . mockImplementationOnce ( ( ) => true ) . mockImplementationOnce ( ( ) => null ) ;
80
+ expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBeNull ( ) ;
46
81
} ) ;
47
82
48
- it ( 'should return false for a leaf condition when the leaf condition evaluator returns false' , function ( ) {
83
+ it ( 'should return false when operands evaluate to falses and nulls' , function ( ) {
84
+ const leafEvaluator = vi . fn ( ) ;
85
+ leafEvaluator . mockImplementationOnce ( ( ) => false ) . mockImplementationOnce ( ( ) => null ) ;
86
+ expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( false ) ;
87
+
88
+ leafEvaluator . mockReset ( ) ;
89
+ leafEvaluator . mockImplementationOnce ( ( ) => null ) . mockImplementationOnce ( ( ) => false ) ;
90
+ expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( false ) ;
91
+ } ) ;
92
+
93
+ it ( 'should return false when operands evaluate to trues, falses, and nulls' , function ( ) {
94
+ const leafEvaluator = vi . fn ( ) ;
95
+ leafEvaluator
96
+ . mockImplementationOnce ( ( ) => true )
97
+ . mockImplementationOnce ( ( ) => false )
98
+ . mockImplementationOnce ( ( ) => null ) ;
99
+ expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB , conditionC ] , leafEvaluator ) ) . toBe ( false ) ;
100
+ } ) ;
101
+ } ) ;
102
+ } ) ;
103
+
104
+ describe ( 'or evaluation' , function ( ) {
105
+ it ( 'should return true if any condition evaluates to true' , function ( ) {
106
+ const leafEvaluator = vi . fn ( ) ;
107
+ leafEvaluator . mockImplementationOnce ( ( ) => false ) . mockImplementationOnce ( ( ) => true ) ;
108
+ expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( true ) ;
109
+ } ) ;
110
+
111
+ it ( 'should return false if all conditions evaluate to false' , function ( ) {
112
+ expect (
113
+ conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , function ( ) {
114
+ return false ;
115
+ } )
116
+ ) . toBe ( false ) ;
117
+ } ) ;
118
+
119
+ describe ( 'null handling' , function ( ) {
120
+ it ( 'should return null when all operands evaluate to null' , function ( ) {
49
121
expect (
50
- conditionTreeEvaluator . evaluate ( conditionA , function ( ) {
51
- return false ;
122
+ conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , function ( ) {
123
+ return null ;
52
124
} )
53
- ) . toBe ( false )
125
+ ) . toBeNull ( ) ;
54
126
} ) ;
55
127
56
- describe ( 'and evaluation' , function ( ) {
57
- it ( 'should return true when ALL conditions evaluate to true' , function ( ) {
58
- expect (
59
- conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , function ( ) {
60
- return true ;
61
- } )
62
- ) . toBe ( true ) ;
63
- } ) ;
64
-
65
- it ( 'should return false if one condition evaluates to false' , function ( ) {
66
- const leafEvaluator = vi . fn ( ) ;
67
- leafEvaluator . mockImplementationOnce ( ( ) => true )
68
- . mockImplementationOnce ( ( ) => false ) ;
69
- expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( false ) ;
70
- } ) ;
71
-
72
- describe ( 'null handling' , function ( ) {
73
- it ( 'should return null when all operands evaluate to null' , function ( ) {
74
- expect (
75
- conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , function ( ) {
76
- return null ;
77
- } )
78
- ) . toBeNull ( ) ;
79
- } ) ;
80
-
81
- it ( 'should return null when operands evaluate to trues and nulls' , function ( ) {
82
- const leafEvaluator = vi . fn ( ) ;
83
- leafEvaluator . mockImplementationOnce ( ( ) => true )
84
- . mockImplementationOnce ( ( ) => null ) ;
85
- expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBeNull ( ) ;
86
- } ) ;
87
-
88
- it ( 'should return false when operands evaluate to falses and nulls' , function ( ) {
89
- const leafEvaluator = vi . fn ( ) ;
90
- leafEvaluator . mockImplementationOnce ( ( ) => false )
91
- . mockImplementationOnce ( ( ) => null ) ;
92
- expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( false ) ;
93
-
94
- leafEvaluator . mockReset ( ) ;
95
- leafEvaluator . mockImplementationOnce ( ( ) => null )
96
- . mockImplementationOnce ( ( ) => false ) ;
97
- expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( false ) ;
98
- } ) ;
99
-
100
- it ( 'should return false when operands evaluate to trues, falses, and nulls' , function ( ) {
101
- const leafEvaluator = vi . fn ( ) ;
102
- leafEvaluator . mockImplementationOnce ( ( ) => true )
103
- . mockImplementationOnce ( ( ) => false )
104
- . mockImplementationOnce ( ( ) => null ) ;
105
- expect ( conditionTreeEvaluator . evaluate ( [ 'and' , conditionA , conditionB , conditionC ] , leafEvaluator ) ) . toBe ( false ) ;
106
- } ) ;
107
- } ) ;
128
+ it ( 'should return true when operands evaluate to trues and nulls' , function ( ) {
129
+ const leafEvaluator = vi . fn ( ) ;
130
+ leafEvaluator . mockImplementationOnce ( ( ) => true ) . mockImplementationOnce ( ( ) => null ) ;
131
+ expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( true ) ;
108
132
} ) ;
109
133
110
- describe ( 'or evaluation' , function ( ) {
111
- it ( 'should return true if any condition evaluates to true' , function ( ) {
112
- const leafEvaluator = vi . fn ( ) ;
113
- leafEvaluator . mockImplementationOnce ( ( ) => false )
114
- . mockImplementationOnce ( ( ) => true ) ;
115
- expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( true ) ;
116
- } ) ;
117
-
118
- it ( 'should return false if all conditions evaluate to false' , function ( ) {
119
- expect (
120
- conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , function ( ) {
121
- return false ;
122
- } )
123
- ) . toBe ( false ) ;
124
- } ) ;
125
-
126
- describe ( 'null handling' , function ( ) {
127
- it ( 'should return null when all operands evaluate to null' , function ( ) {
128
- expect (
129
- conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , function ( ) {
130
- return null ;
131
- } )
132
- ) . toBeNull ( ) ;
133
- } ) ;
134
-
135
- it ( 'should return true when operands evaluate to trues and nulls' , function ( ) {
136
- const leafEvaluator = vi . fn ( ) ;
137
- leafEvaluator . mockImplementationOnce ( ( ) => true )
138
- . mockImplementationOnce ( ( ) => null ) ;
139
- expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBe ( true ) ;
140
- } ) ;
141
-
142
- it ( 'should return null when operands evaluate to falses and nulls' , function ( ) {
143
- const leafEvaluator = vi . fn ( ) ;
144
- leafEvaluator . mockImplementationOnce ( ( ) => null )
145
- . mockImplementationOnce ( ( ) => false ) ;
146
- expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBeNull ( ) ;
147
-
148
- leafEvaluator . mockReset ( ) ;
149
- leafEvaluator . mockImplementationOnce ( ( ) => false )
150
- . mockImplementationOnce ( ( ) => null ) ;
151
- expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBeNull ( ) ;
152
- } ) ;
153
-
154
- it ( 'should return true when operands evaluate to trues, falses, and nulls' , function ( ) {
155
- const leafEvaluator = vi . fn ( ) ;
156
- leafEvaluator . mockImplementationOnce ( ( ) => true )
157
- . mockImplementationOnce ( ( ) => null )
158
- . mockImplementationOnce ( ( ) => false ) ;
159
- expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB , conditionC ] , leafEvaluator ) ) . toBe ( true ) ;
160
- } ) ;
161
- } ) ;
134
+ it ( 'should return null when operands evaluate to falses and nulls' , function ( ) {
135
+ const leafEvaluator = vi . fn ( ) ;
136
+ leafEvaluator . mockImplementationOnce ( ( ) => null ) . mockImplementationOnce ( ( ) => false ) ;
137
+ expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBeNull ( ) ;
138
+
139
+ leafEvaluator . mockReset ( ) ;
140
+ leafEvaluator . mockImplementationOnce ( ( ) => false ) . mockImplementationOnce ( ( ) => null ) ;
141
+ expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB ] , leafEvaluator ) ) . toBeNull ( ) ;
162
142
} ) ;
163
143
164
- describe ( 'not evaluation' , function ( ) {
165
- it ( 'should return true if the condition evaluates to false' , function ( ) {
166
- expect (
167
- conditionTreeEvaluator . evaluate ( [ 'not' , conditionA ] , function ( ) {
168
- return false ;
169
- } )
170
- ) . toBe ( true ) ;
171
- } ) ;
172
-
173
- it ( 'should return false if the condition evaluates to true' , function ( ) {
174
- expect (
175
- conditionTreeEvaluator . evaluate ( [ 'not' , conditionB ] , function ( ) {
176
- return true ;
177
- } )
178
- ) . toBe ( false ) ;
179
- } ) ;
180
-
181
- it ( 'should return the result of negating the first condition, and ignore any additional conditions' , function ( ) {
182
- let result = conditionTreeEvaluator . evaluate ( [ 'not' , '1' , '2' , '1' ] , function ( id ) {
183
- return String ( id ) === '1' ;
184
- } ) ;
185
- expect ( result ) . toBe ( false ) ;
186
- result = conditionTreeEvaluator . evaluate ( [ 'not' , '1' , '2' , '1' ] , function ( id ) {
187
- return String ( id ) === '2' ;
188
- } ) ;
189
- expect ( result ) . toBe ( true ) ;
190
- result = conditionTreeEvaluator . evaluate ( [ 'not' , '1' , '2' , '3' ] , function ( id ) {
191
- return String ( id ) === '1' ? null : String ( id ) === '3' ;
192
- } ) ;
193
- expect ( result ) . toBeNull ( ) ;
194
- } ) ;
195
-
196
- describe ( 'null handling' , function ( ) {
197
- it ( 'should return null when operand evaluates to null' , function ( ) {
198
- expect (
199
- conditionTreeEvaluator . evaluate ( [ 'not' , conditionA ] , function ( ) {
200
- return null ;
201
- } )
202
- ) . toBeNull ( ) ;
203
- } ) ;
204
-
205
- it ( 'should return null when there are no operands' , function ( ) {
206
- expect (
207
- conditionTreeEvaluator . evaluate ( [ 'not' ] , function ( ) {
208
- return null ;
209
- } )
210
- ) . toBeNull ( ) ;
211
- } ) ;
212
- } ) ;
144
+ it ( 'should return true when operands evaluate to trues, falses, and nulls' , function ( ) {
145
+ const leafEvaluator = vi . fn ( ) ;
146
+ leafEvaluator
147
+ . mockImplementationOnce ( ( ) => true )
148
+ . mockImplementationOnce ( ( ) => null )
149
+ . mockImplementationOnce ( ( ) => false ) ;
150
+ expect ( conditionTreeEvaluator . evaluate ( [ 'or' , conditionA , conditionB , conditionC ] , leafEvaluator ) ) . toBe ( true ) ;
151
+ } ) ;
152
+ } ) ;
153
+ } ) ;
154
+
155
+ describe ( 'not evaluation' , function ( ) {
156
+ it ( 'should return true if the condition evaluates to false' , function ( ) {
157
+ expect (
158
+ conditionTreeEvaluator . evaluate ( [ 'not' , conditionA ] , function ( ) {
159
+ return false ;
160
+ } )
161
+ ) . toBe ( true ) ;
162
+ } ) ;
163
+
164
+ it ( 'should return false if the condition evaluates to true' , function ( ) {
165
+ expect (
166
+ conditionTreeEvaluator . evaluate ( [ 'not' , conditionB ] , function ( ) {
167
+ return true ;
168
+ } )
169
+ ) . toBe ( false ) ;
170
+ } ) ;
171
+
172
+ it ( 'should return the result of negating the first condition, and ignore any additional conditions' , function ( ) {
173
+ let result = conditionTreeEvaluator . evaluate ( [ 'not' , '1' , '2' , '1' ] , function ( id : string ) {
174
+ return id === '1' ;
175
+ } ) ;
176
+ expect ( result ) . toBe ( false ) ;
177
+ result = conditionTreeEvaluator . evaluate ( [ 'not' , '1' , '2' , '1' ] , function ( id : string ) {
178
+ return id === '2' ;
179
+ } ) ;
180
+ expect ( result ) . toBe ( true ) ;
181
+ result = conditionTreeEvaluator . evaluate ( [ 'not' , '1' , '2' , '3' ] , function ( id : string ) {
182
+ return id === '1' ? null : id === '3' ;
183
+ } ) ;
184
+ expect ( result ) . toBeNull ( ) ;
185
+ } ) ;
186
+
187
+ describe ( 'null handling' , function ( ) {
188
+ it ( 'should return null when operand evaluates to null' , function ( ) {
189
+ expect (
190
+ conditionTreeEvaluator . evaluate ( [ 'not' , conditionA ] , function ( ) {
191
+ return null ;
192
+ } )
193
+ ) . toBeNull ( ) ;
213
194
} ) ;
214
195
215
- describe ( 'implicit operator' , function ( ) {
216
- it ( 'should behave like an "or" operator when the first item in the array is not a recognized operator' , function ( ) {
217
- const leafEvaluator = vi . fn ( ) ;
218
- leafEvaluator . mockImplementationOnce ( ( ) => true )
219
- . mockImplementationOnce ( ( ) => false ) ;
220
- expect ( conditionTreeEvaluator . evaluate ( [ conditionA , conditionB ] , leafEvaluator ) ) . toBe ( true ) ;
221
- expect (
222
- conditionTreeEvaluator . evaluate ( [ conditionA , conditionB ] , function ( ) {
223
- return false ;
224
- } )
225
- ) . toBe ( false ) ;
226
- } ) ;
196
+ it ( 'should return null when there are no operands' , function ( ) {
197
+ expect (
198
+ conditionTreeEvaluator . evaluate ( [ 'not' ] , function ( ) {
199
+ return null ;
200
+ } )
201
+ ) . toBeNull ( ) ;
227
202
} ) ;
228
203
} ) ;
229
204
} ) ;
205
+
206
+ describe ( 'implicit operator' , function ( ) {
207
+ it ( 'should behave like an "or" operator when the first item in the array is not a recognized operator' , function ( ) {
208
+ const leafEvaluator = vi . fn ( ) ;
209
+ leafEvaluator . mockImplementationOnce ( ( ) => true ) . mockImplementationOnce ( ( ) => false ) ;
210
+ expect ( conditionTreeEvaluator . evaluate ( [ conditionA , conditionB ] , leafEvaluator ) ) . toBe ( true ) ;
211
+ expect (
212
+ conditionTreeEvaluator . evaluate ( [ conditionA , conditionB ] , function ( ) {
213
+ return false ;
214
+ } )
215
+ ) . toBe ( false ) ;
216
+ } ) ;
217
+ } ) ;
230
218
} ) ;
0 commit comments