Skip to content

Commit af51bf7

Browse files
committed
feat: implemented-new-in-and-fixed-remaining-tests
1 parent da08e8e commit af51bf7

File tree

6 files changed

+53
-20
lines changed

6 files changed

+53
-20
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "spec/engine-test-data"]
22
path = spec/engine-test-data
33
url = [email protected]:Flagsmith/engine-test-data.git
4-
branch = v3.1.0
4+
branch = main

lib/flagsmith/engine/evaluation/core.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ def evaluate_segments(evaluation_context)
3737

3838
segments = identity_segments.map do |segment|
3939
result = {
40-
key: segment[:key],
4140
name: segment[:name]
4241
}
4342

@@ -103,9 +102,9 @@ def evaluate_features(evaluation_context, segment_overrides)
103102

104103
# Set reason
105104
flag_result[:reason] = evaluated[:reason] ||
106-
get_targeting_match_reason({ type: 'SEGMENT', override: segment_override })
105+
get_targeting_match_reason({ type: 'SEGMENT', override: segment_override })
107106

108-
flags[final_feature[:name]] = flag_result
107+
flags[final_feature[:name].to_sym] = flag_result
109108
end
110109

111110
flags
@@ -153,7 +152,10 @@ def should_apply_override(override, existing_overrides)
153152
# @param evaluation_context [Hash] The evaluation context
154153
# @return [String, nil] The identity key or nil if no identity
155154
def get_identity_key(evaluation_context)
156-
evaluation_context.dig(:identity, :key)
155+
return nil unless evaluation_context[:identity]
156+
157+
evaluation_context[:identity][:key] ||
158+
"#{evaluation_context[:environment][:key]}_#{evaluation_context[:identity][:identifier]}"
157159
end
158160

159161
# returns boolean

lib/flagsmith/engine/segments/evaluator.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ module Evaluator
2121
def get_identity_segments_from_context(context)
2222
return [] unless context[:identity] && context[:segments]
2323

24-
context[:segments].values.select do |segment|
24+
matching_segments = context[:segments].values.select do |segment|
2525
next false if segment[:rules].nil? || segment[:rules].empty?
2626

27-
segment[:rules].all? { |rule| traits_match_segment_rule_from_context(rule, segment[:key], context) }
27+
matches = segment[:rules].all? { |rule| traits_match_segment_rule_from_context(rule, segment[:key], context) }
28+
matches
2829
end
30+
31+
matching_segments
2932
end
3033

3134
# Model-based segment evaluation (existing approach)
@@ -190,15 +193,15 @@ def evaluate_rule_conditions(rule_type, condition_results)
190193
# @param context [Hash] The evaluation context
191194
# @return [Object, nil] The trait value or nil
192195
def get_trait_value(property, context)
193-
# Check if it's a JSONPath expression
194196
if property.start_with?('$.')
195197
context_value = get_context_value(property, context)
196-
return context_value unless non_primitive?(context_value)
198+
if !context_value.nil? && !non_primitive?(context_value)
199+
return context_value
200+
end
197201
end
198202

199-
# Otherwise look in traits
200203
traits = context.dig(:identity, :traits) || {}
201-
traits[property]
204+
traits[property] || traits[property.to_sym]
202205
end
203206

204207
# Get value from context using JSONPath-like syntax

lib/flagsmith/engine/segments/models.rb

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class Condition
4545
CONTAINS => ->(other_value, self_value) { (other_value || false) && other_value.include?(self_value) },
4646

4747
NOT_CONTAINS => ->(other_value, self_value) { (other_value || false) && !other_value.include?(self_value) },
48-
REGEX => ->(other_value, self_value) { (other_value || false) && other_value.match?(self_value) }
48+
REGEX => ->(other_value, self_value) { (other_value || false) && other_value.to_s.match?(self_value) }
4949
}.freeze
5050

5151
def initialize(operator:, value:, property: nil)
@@ -55,11 +55,17 @@ def initialize(operator:, value:, property: nil)
5555
end
5656

5757
def match_trait_value?(trait_value)
58-
# handle some exceptions
59-
trait_value = Semantic::Version.new(trait_value.gsub(/:semver$/, '')) if @value.is_a?(String) && @value.match?(/:semver$/)
58+
if @value.is_a?(String) && @value.match?(/:semver$/)
59+
begin
60+
trait_value = Semantic::Version.new(trait_value.to_s.gsub(/:semver$/, ''))
61+
rescue StandardError
62+
return false
63+
end
64+
end
6065

6166
return match_in_value(trait_value) if @operator == IN
6267
return match_modulo_value(trait_value) if @operator == MODULO
68+
return MATCHING_FUNCTIONS[REGEX]&.call(trait_value, @value) if @operator == REGEX
6369

6470
type_as_trait_value = format_to_type_of(trait_value)
6571
formatted_value = type_as_trait_value ? type_as_trait_value.call(@value) : @value
@@ -72,10 +78,17 @@ def format_to_type_of(input)
7278
{
7379
'String' => ->(v) { v.to_s },
7480
'Semantic::Version' => ->(v) { Semantic::Version.new(v.to_s.gsub(/:semver$/, '')) },
81+
# Double check this is the desired behavior between SDKs
7582
'TrueClass' => ->(v) { ['True', 'true', 'TRUE', true, 1, '1'].include?(v) },
76-
'FalseClass' => ->(v) { !['False', 'false', 'FALSE', false, 0, '0'].include?(v) },
77-
'Integer' => ->(v) { v.to_i },
78-
'Float' => ->(v) { v.to_f }
83+
'FalseClass' => ->(v) { !['False', 'false', 'FALSE', false].include?(v) },
84+
'Integer' => ->(v) {
85+
i = v.to_i;
86+
i.to_s == v.to_s ? i : v
87+
},
88+
'Float' => ->(v) {
89+
f = v.to_f;
90+
f.to_s == v.to_s ? f : v
91+
}
7992
}[input.class.to_s]
8093
end
8194
# rubocop:enable Metrics/AbcSize
@@ -88,9 +101,23 @@ def match_modulo_value(trait_value)
88101
end
89102

90103
def match_in_value(trait_value)
91-
return @value.split(',').include?(trait_value.to_s) if trait_value.is_a?(String) || trait_value.is_a?(Integer)
104+
return false if trait_value.nil? || trait_value.is_a?(TrueClass) || trait_value.is_a?(FalseClass)
92105

93-
false
106+
if @value.is_a?(Array)
107+
return @value.include?(trait_value.to_s)
108+
end
109+
110+
if @value.is_a?(String)
111+
begin
112+
parsed = JSON.parse(@value)
113+
if parsed.is_a?(Array)
114+
return parsed.include?(trait_value.to_s)
115+
end
116+
rescue JSON::ParserError
117+
end
118+
end
119+
120+
@value.to_s.split(',').include?(trait_value.to_s)
94121
end
95122

96123
class << self

spec/engine-test-data

Submodule engine-test-data updated 156 files

spec/engine/e2e/engine_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def load_test_file(filepath)
4040

4141
# TODO: Uncomment when evaluation is implemented
4242
expect(evaluation_result[:flags]).to eq(test_expected_result[:flags])
43+
expect(evaluation_result[:segments]).to eq(test_expected_result[:segments])
4344
end
4445
end
4546
end

0 commit comments

Comments
 (0)