1515# See the License for the specific language governing permissions and
1616# limitations under the License.
1717#
18+ require_relative 'helpers/constants'
1819require_relative 'helpers/validator'
1920
2021module Optimizely
@@ -38,8 +39,9 @@ class CustomAttributeConditionEvaluator
3839
3940 attr_reader :user_attributes
4041
41- def initialize ( user_attributes )
42+ def initialize ( user_attributes , logger )
4243 @user_attributes = user_attributes
44+ @logger = logger
4345 end
4446
4547 def evaluate ( leaf_condition )
@@ -51,11 +53,47 @@ def evaluate(leaf_condition)
5153 # Returns boolean if the given user attributes match/don't match the given conditions,
5254 # nil if the given conditions can't be evaluated.
5355
54- return nil unless leaf_condition [ 'type' ] == CUSTOM_ATTRIBUTE_CONDITION_TYPE
56+ unless leaf_condition [ 'type' ] == CUSTOM_ATTRIBUTE_CONDITION_TYPE
57+ @logger . log (
58+ Logger ::WARN ,
59+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_TYPE' ] , leaf_condition )
60+ )
61+ return nil
62+ end
5563
5664 condition_match = leaf_condition [ 'match' ] || EXACT_MATCH_TYPE
5765
58- return nil unless EVALUATORS_BY_MATCH_TYPE . include? ( condition_match )
66+ if !@user_attributes . key? ( leaf_condition [ 'name' ] ) && condition_match != EXISTS_MATCH_TYPE
67+ @logger . log (
68+ Logger ::DEBUG ,
69+ format (
70+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'MISSING_ATTRIBUTE_VALUE' ] ,
71+ leaf_condition ,
72+ leaf_condition [ 'name' ]
73+ )
74+ )
75+ return nil
76+ end
77+
78+ if @user_attributes [ leaf_condition [ 'name' ] ] . nil? && condition_match != EXISTS_MATCH_TYPE
79+ @logger . log (
80+ Logger ::DEBUG ,
81+ format (
82+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'NULL_ATTRIBUTE_VALUE' ] ,
83+ leaf_condition ,
84+ leaf_condition [ 'name' ]
85+ )
86+ )
87+ return nil
88+ end
89+
90+ unless EVALUATORS_BY_MATCH_TYPE . include? ( condition_match )
91+ @logger . log (
92+ Logger ::WARN ,
93+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_MATCH_TYPE' ] , leaf_condition )
94+ )
95+ return nil
96+ end
5997
6098 send ( EVALUATORS_BY_MATCH_TYPE [ condition_match ] , leaf_condition )
6199 end
@@ -73,13 +111,40 @@ def exact_evaluator(condition)
73111
74112 user_provided_value = @user_attributes [ condition [ 'name' ] ]
75113
76- if user_provided_value . is_a? ( Numeric ) && condition_value . is_a? ( Numeric )
77- return true if condition_value . to_f == user_provided_value . to_f
114+ if !value_type_valid_for_exact_conditions? ( condition_value ) ||
115+ ( condition_value . is_a? ( Numeric ) && !Helpers ::Validator . finite_number? ( condition_value ) )
116+ @logger . log (
117+ Logger ::WARN ,
118+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_VALUE' ] , condition )
119+ )
120+ return nil
78121 end
79122
80- return nil if !value_valid_for_exact_conditions? ( user_provided_value ) ||
81- !value_valid_for_exact_conditions? ( condition_value ) ||
82- !Helpers ::Validator . same_types? ( condition_value , user_provided_value )
123+ if !value_type_valid_for_exact_conditions? ( user_provided_value ) ||
124+ !Helpers ::Validator . same_types? ( condition_value , user_provided_value )
125+ @logger . log (
126+ Logger ::WARN ,
127+ format (
128+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNEXPECTED_TYPE' ] ,
129+ condition ,
130+ user_provided_value . class ,
131+ condition [ 'name' ]
132+ )
133+ )
134+ return nil
135+ end
136+
137+ if user_provided_value . is_a? ( Numeric ) && !Helpers ::Validator . finite_number? ( user_provided_value )
138+ @logger . log (
139+ Logger ::WARN ,
140+ format (
141+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'INFINITE_ATTRIBUTE_VALUE' ] ,
142+ condition ,
143+ condition [ 'name' ]
144+ )
145+ )
146+ return nil
147+ end
83148
84149 condition_value == user_provided_value
85150 end
@@ -103,8 +168,7 @@ def greater_than_evaluator(condition)
103168 condition_value = condition [ 'value' ]
104169 user_provided_value = @user_attributes [ condition [ 'name' ] ]
105170
106- return nil if !Helpers ::Validator . finite_number? ( user_provided_value ) ||
107- !Helpers ::Validator . finite_number? ( condition_value )
171+ return nil unless valid_numeric_values? ( user_provided_value , condition_value , condition )
108172
109173 user_provided_value > condition_value
110174 end
@@ -118,8 +182,7 @@ def less_than_evaluator(condition)
118182 condition_value = condition [ 'value' ]
119183 user_provided_value = @user_attributes [ condition [ 'name' ] ]
120184
121- return nil if !Helpers ::Validator . finite_number? ( user_provided_value ) ||
122- !Helpers ::Validator . finite_number? ( condition_value )
185+ return nil unless valid_numeric_values? ( user_provided_value , condition_value , condition )
123186
124187 user_provided_value < condition_value
125188 end
@@ -133,20 +196,78 @@ def substring_evaluator(condition)
133196 condition_value = condition [ 'value' ]
134197 user_provided_value = @user_attributes [ condition [ 'name' ] ]
135198
136- return nil unless user_provided_value . is_a? ( String ) && condition_value . is_a? ( String )
199+ unless condition_value . is_a? ( String )
200+ @logger . log (
201+ Logger ::WARN ,
202+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_VALUE' ] , condition )
203+ )
204+ return nil
205+ end
206+
207+ unless user_provided_value . is_a? ( String )
208+ @logger . log (
209+ Logger ::WARN ,
210+ format (
211+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNEXPECTED_TYPE' ] ,
212+ condition ,
213+ user_provided_value . class ,
214+ condition [ 'name' ]
215+ )
216+ )
217+ return nil
218+ end
137219
138220 user_provided_value . include? condition_value
139221 end
140222
141223 private
142224
143- def value_valid_for_exact_conditions? ( value )
144- # Returns true if the value is valid for exact conditions. Valid values include
145- # strings, booleans, and numbers that aren't NaN, -Infinity, or Infinity.
225+ def valid_numeric_values? ( user_value , condition_value , condition )
226+ # Returns true if user and condition values are valid numeric.
227+ # false otherwise.
228+
229+ unless Helpers ::Validator . finite_number? ( condition_value )
230+ @logger . log (
231+ Logger ::WARN ,
232+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_VALUE' ] , condition )
233+ )
234+ return false
235+ end
236+
237+ unless user_value . is_a? ( Numeric )
238+ @logger . log (
239+ Logger ::WARN ,
240+ format (
241+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNEXPECTED_TYPE' ] ,
242+ condition ,
243+ user_value . class ,
244+ condition [ 'name' ]
245+ )
246+ )
247+ return false
248+ end
146249
147- return Helpers ::Validator . finite_number? ( value ) if value . is_a? Numeric
250+ unless Helpers ::Validator . finite_number? ( user_value )
251+ @logger . log (
252+ Logger ::WARN ,
253+ format (
254+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'INFINITE_ATTRIBUTE_VALUE' ] ,
255+ condition ,
256+ condition [ 'name' ]
257+ )
258+ )
259+ return false
260+ end
261+
262+ true
263+ end
264+
265+ def value_type_valid_for_exact_conditions? ( value )
266+ # Returns true if the value is valid for exact conditions. Valid values include
267+ # strings or booleans or is a number.
268+ # false otherwise.
148269
149- ( Helpers ::Validator . boolean? value ) || ( value . is_a? String )
270+ ( Helpers ::Validator . boolean? value ) || ( value . is_a? String ) || value . is_a? ( Numeric )
150271 end
151272 end
152273end
0 commit comments