prefab-cloud-ruby 1.8.7 → 1.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -238,6 +238,131 @@ class TestCriteriaEvaluator < Minitest::Test
238
238
  assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { email: 'example@hotmail.com' })).unwrapped_value
239
239
  end
240
240
 
241
+ def test_prop_starts_with_one_of
242
+ config = PrefabProto::Config.new(
243
+ key: KEY,
244
+ rows: [
245
+ DEFAULT_ROW,
246
+ PrefabProto::ConfigRow.new(
247
+ project_env_id: PROJECT_ENV_ID,
248
+ values: [
249
+ PrefabProto::ConditionalValue.new(
250
+ criteria: [
251
+ PrefabProto::Criterion.new(
252
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_STARTS_WITH_ONE_OF,
253
+ value_to_match: string_list(['one', 'two']),
254
+ property_name: 'user.testProperty'
255
+ )
256
+ ],
257
+ value: DESIRED_VALUE_CONFIG
258
+ )
259
+ ]
260
+ )
261
+ ]
262
+ )
263
+
264
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
265
+ namespace: nil)
266
+
267
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
268
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'three dogs' })).unwrapped_value
269
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: { testProperty: 'one tree' })).unwrapped_value
270
+ end
271
+
272
+ def test_prop_does_not_start_with_one_of
273
+ config = PrefabProto::Config.new(
274
+ key: KEY,
275
+ rows: [
276
+ DEFAULT_ROW,
277
+ PrefabProto::ConfigRow.new(
278
+ project_env_id: PROJECT_ENV_ID,
279
+ values: [
280
+ PrefabProto::ConditionalValue.new(
281
+ criteria: [
282
+ PrefabProto::Criterion.new(
283
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_DOES_NOT_START_WITH_ONE_OF,
284
+ value_to_match: string_list(['one', 'two']),
285
+ property_name: 'user.testProperty'
286
+ )
287
+ ],
288
+ value: DESIRED_VALUE_CONFIG
289
+ )
290
+ ]
291
+ )
292
+ ]
293
+ )
294
+
295
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
296
+ namespace: nil)
297
+
298
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context({})).unwrapped_value
299
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: { testProperty: 'three dogs' })).unwrapped_value
300
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'one tree' })).unwrapped_value
301
+ end
302
+
303
+
304
+ def test_prop_contains_one_of
305
+ config = PrefabProto::Config.new(
306
+ key: KEY,
307
+ rows: [
308
+ DEFAULT_ROW,
309
+ PrefabProto::ConfigRow.new(
310
+ project_env_id: PROJECT_ENV_ID,
311
+ values: [
312
+ PrefabProto::ConditionalValue.new(
313
+ criteria: [
314
+ PrefabProto::Criterion.new(
315
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_CONTAINS_ONE_OF,
316
+ value_to_match: string_list(['one', 'two']),
317
+ property_name: 'user.testProperty'
318
+ )
319
+ ],
320
+ value: DESIRED_VALUE_CONFIG
321
+ )
322
+ ]
323
+ )
324
+ ]
325
+ )
326
+
327
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
328
+ namespace: nil)
329
+
330
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
331
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'three dogs' })).unwrapped_value
332
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: { testProperty: 'see one tree' })).unwrapped_value
333
+ end
334
+
335
+ def test_prop_does_not_contain_one_of
336
+ config = PrefabProto::Config.new(
337
+ key: KEY,
338
+ rows: [
339
+ DEFAULT_ROW,
340
+ PrefabProto::ConfigRow.new(
341
+ project_env_id: PROJECT_ENV_ID,
342
+ values: [
343
+ PrefabProto::ConditionalValue.new(
344
+ criteria: [
345
+ PrefabProto::Criterion.new(
346
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_DOES_NOT_CONTAIN_ONE_OF,
347
+ value_to_match: string_list(['one', 'two']),
348
+ property_name: 'user.testProperty'
349
+ )
350
+ ],
351
+ value: DESIRED_VALUE_CONFIG
352
+ )
353
+ ]
354
+ )
355
+ ]
356
+ )
357
+
358
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
359
+ namespace: nil)
360
+
361
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context({})).unwrapped_value
362
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: { testProperty: 'three dogs' })).unwrapped_value
363
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'see one tree' })).unwrapped_value
364
+ end
365
+
241
366
  def test_in_seg
242
367
  segment_key = 'segment_key'
243
368
 
@@ -683,6 +808,266 @@ class TestCriteriaEvaluator < Minitest::Test
683
808
  assert_equal 'ghi', evaluator.evaluate(context).unwrapped_value
684
809
  end
685
810
 
811
+ def test_prop_regex_matches
812
+ config = PrefabProto::Config.new(
813
+ key: KEY,
814
+ rows: [
815
+ DEFAULT_ROW,
816
+ PrefabProto::ConfigRow.new(
817
+ project_env_id: PROJECT_ENV_ID,
818
+ values: [
819
+ PrefabProto::ConditionalValue.new(
820
+ criteria: [
821
+ PrefabProto::Criterion.new(
822
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_MATCHES,
823
+ value_to_match: PrefabProto::ConfigValue.new(string: "a+b+"),
824
+ property_name: 'user.testProperty'
825
+ )
826
+ ],
827
+ value: DESIRED_VALUE_CONFIG
828
+ )
829
+ ]
830
+ )
831
+ ]
832
+ )
833
+
834
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
835
+ namespace: nil)
836
+
837
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
838
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'abc' })).unwrapped_value
839
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: { testProperty: 'aabb' })).unwrapped_value
840
+ end
841
+
842
+ def test_prop_regex_does_not_match
843
+ config = PrefabProto::Config.new(
844
+ key: KEY,
845
+ rows: [
846
+ DEFAULT_ROW,
847
+ PrefabProto::ConfigRow.new(
848
+ project_env_id: PROJECT_ENV_ID,
849
+ values: [
850
+ PrefabProto::ConditionalValue.new(
851
+ criteria: [
852
+ PrefabProto::Criterion.new(
853
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_DOES_NOT_MATCH,
854
+ value_to_match: PrefabProto::ConfigValue.new(string: "a+b+"),
855
+ property_name: 'user.testProperty'
856
+ )
857
+ ],
858
+ value: DESIRED_VALUE_CONFIG
859
+ )
860
+ ]
861
+ )
862
+ ]
863
+ )
864
+
865
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
866
+ namespace: nil)
867
+
868
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context({})).unwrapped_value
869
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: { testProperty: 'abc' })).unwrapped_value
870
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'aabb' })).unwrapped_value
871
+ end
872
+
873
+ def test_prop_regex_does_not_match_returns_false_bad_regex
874
+ config = PrefabProto::Config.new(
875
+ key: KEY,
876
+ rows: [
877
+ DEFAULT_ROW,
878
+ PrefabProto::ConfigRow.new(
879
+ project_env_id: PROJECT_ENV_ID,
880
+ values: [
881
+ PrefabProto::ConditionalValue.new(
882
+ criteria: [
883
+ PrefabProto::Criterion.new(
884
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_DOES_NOT_MATCH,
885
+ value_to_match: PrefabProto::ConfigValue.new(string: "[a+b+"),
886
+ property_name: 'user.testProperty'
887
+ )
888
+ ],
889
+ value: DESIRED_VALUE_CONFIG
890
+ )
891
+ ]
892
+ )
893
+ ]
894
+ )
895
+
896
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
897
+ namespace: nil)
898
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
899
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'abc' })).unwrapped_value
900
+
901
+ assert_stderr [ "warning: character class has duplicated range: /^[a+b+$/" ]
902
+ end
903
+
904
+
905
+ def test_prop_regex_match_returns_false_bad_regex
906
+ config = PrefabProto::Config.new(
907
+ key: KEY,
908
+ rows: [
909
+ DEFAULT_ROW,
910
+ PrefabProto::ConfigRow.new(
911
+ project_env_id: PROJECT_ENV_ID,
912
+ values: [
913
+ PrefabProto::ConditionalValue.new(
914
+ criteria: [
915
+ PrefabProto::Criterion.new(
916
+ operator: PrefabProto::Criterion::CriterionOperator::PROP_MATCHES,
917
+ value_to_match: PrefabProto::ConfigValue.new(string: "[a+b+"),
918
+ property_name: 'user.testProperty'
919
+ )
920
+ ],
921
+ value: DESIRED_VALUE_CONFIG
922
+ )
923
+ ]
924
+ )
925
+ ]
926
+ )
927
+
928
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
929
+ namespace: nil)
930
+
931
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
932
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: { testProperty: 'abc' })).unwrapped_value
933
+
934
+ assert_stderr [ "warning: character class has duplicated range: /^[a+b+$/" ]
935
+ end
936
+
937
+ def test_less_than_works
938
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_LESS_THAN, property_name: 'user.age', value_to_match: 10)
939
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
940
+ namespace: nil)
941
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
942
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 10})).unwrapped_value
943
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 9})).unwrapped_value
944
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 9.5})).unwrapped_value
945
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 10.1})).unwrapped_value
946
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "9"})).unwrapped_value
947
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "9.2"})).unwrapped_value
948
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "not a number"})).unwrapped_value
949
+ end
950
+
951
+ def test_less_or_equal_to_works
952
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_LESS_THAN_OR_EQUAL, property_name: 'user.age', value_to_match: 10)
953
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
954
+ namespace: nil)
955
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
956
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 10})).unwrapped_value
957
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 9})).unwrapped_value
958
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 9.5})).unwrapped_value
959
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 10.1})).unwrapped_value
960
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "9"})).unwrapped_value
961
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "not a number"})).unwrapped_value
962
+ end
963
+
964
+
965
+ def test_greater_than_works
966
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_GREATER_THAN, property_name: 'user.age', value_to_match: 10)
967
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
968
+ namespace: nil)
969
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
970
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 10})).unwrapped_value
971
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 9})).unwrapped_value
972
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 9.5})).unwrapped_value
973
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 10.1})).unwrapped_value
974
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 12})).unwrapped_value
975
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "19"})).unwrapped_value
976
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "not a number"})).unwrapped_value
977
+ end
978
+
979
+ def test_greater_than_or_equal_to_works
980
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_GREATER_THAN_OR_EQUAL, property_name: 'user.age', value_to_match: 10)
981
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
982
+ namespace: nil)
983
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
984
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 10})).unwrapped_value
985
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 9})).unwrapped_value
986
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: 9.5})).unwrapped_value
987
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 10.1})).unwrapped_value
988
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user: {age: 12})).unwrapped_value
989
+
990
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "19"})).unwrapped_value
991
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user: {age: "not a number"})).unwrapped_value
992
+ end
993
+
994
+ def test_date_before_works
995
+ date = "2024-12-01T00:00:00Z"
996
+ millis = Time.iso8601(date).utc.to_i * 1000
997
+ config_with_string = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_BEFORE, property_name: 'user.joinDate', value_to_match: date)
998
+ evaluator_with_string_config = Prefab::CriteriaEvaluator.new(config_with_string, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
999
+ namespace: nil)
1000
+ config_with_millis = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_BEFORE, property_name: 'user.joinDate', value_to_match: millis)
1001
+ evaluator_with_millis_config = Prefab::CriteriaEvaluator.new(config_with_millis, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
1002
+ namespace: nil)
1003
+ assert_equal DEFAULT_VALUE, evaluator_with_millis_config.evaluate(context({})).unwrapped_value
1004
+ assert_equal DESIRED_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: millis-10000})).unwrapped_value
1005
+ assert_equal DESIRED_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: "2024-11-01T00:00:00Z"})).unwrapped_value
1006
+ assert_equal DEFAULT_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: millis+10000})).unwrapped_value
1007
+ assert_equal DEFAULT_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: "2024-12-02T00:00:00Z"})).unwrapped_value
1008
+
1009
+ assert_equal DEFAULT_VALUE, evaluator_with_string_config.evaluate(context({})).unwrapped_value
1010
+ assert_equal DESIRED_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: millis-10000})).unwrapped_value
1011
+ assert_equal DESIRED_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: "2024-11-01T00:00:00Z"})).unwrapped_value
1012
+ assert_equal DEFAULT_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: millis+10000})).unwrapped_value
1013
+ assert_equal DEFAULT_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: "2024-12-02T00:00:00Z"})).unwrapped_value
1014
+ end
1015
+
1016
+ def test_date_after_works
1017
+ date = "2024-12-01T00:00:00Z"
1018
+ millis = Time.iso8601(date).utc.to_i * 1000
1019
+ config_with_string = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_AFTER, property_name: 'user.joinDate', value_to_match: date)
1020
+ evaluator_with_string_config = Prefab::CriteriaEvaluator.new(config_with_string, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
1021
+ namespace: nil)
1022
+ config_with_millis = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_AFTER, property_name: 'user.joinDate', value_to_match: millis)
1023
+ evaluator_with_millis_config = Prefab::CriteriaEvaluator.new(config_with_millis, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client,
1024
+ namespace: nil)
1025
+ assert_equal DEFAULT_VALUE, evaluator_with_millis_config.evaluate(context({})).unwrapped_value
1026
+ assert_equal DEFAULT_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: millis-10000})).unwrapped_value
1027
+ assert_equal DEFAULT_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: "2024-11-01T00:00:00Z"})).unwrapped_value
1028
+ assert_equal DESIRED_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: millis+10000})).unwrapped_value
1029
+ assert_equal DESIRED_VALUE, evaluator_with_millis_config.evaluate(context(user: {joinDate: "2024-12-02T00:00:00Z"})).unwrapped_value
1030
+
1031
+ assert_equal DEFAULT_VALUE, evaluator_with_string_config.evaluate(context({})).unwrapped_value
1032
+ assert_equal DEFAULT_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: millis-10000})).unwrapped_value
1033
+ assert_equal DEFAULT_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: "2024-11-01T00:00:00Z"})).unwrapped_value
1034
+ assert_equal DESIRED_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: millis+10000})).unwrapped_value
1035
+ assert_equal DESIRED_VALUE, evaluator_with_string_config.evaluate(context(user: {joinDate: "2024-12-02T00:00:00Z"})).unwrapped_value
1036
+ end
1037
+
1038
+ def test_semver_less_than
1039
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_SEMVER_LESS_THAN, property_name: 'user.version', value_to_match: "2.0.0")
1040
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client, namespace: nil)
1041
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
1042
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "nonsense"})).unwrapped_value
1043
+
1044
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user:{version: "1.0.0"})).unwrapped_value
1045
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "2.0.0"})).unwrapped_value
1046
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "3.0.0"})).unwrapped_value
1047
+ end
1048
+
1049
+ def test_semver_equal_to
1050
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_SEMVER_EQUAL, property_name: 'user.version', value_to_match: "2.0.0")
1051
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client, namespace: nil)
1052
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
1053
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "nonsense"})).unwrapped_value
1054
+
1055
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "1.0.0"})).unwrapped_value
1056
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user:{version: "2.0.0"})).unwrapped_value
1057
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "3.0.0"})).unwrapped_value
1058
+ end
1059
+
1060
+ def test_semver_greater_than
1061
+ config = create_prefab_config(operator: PrefabProto::Criterion::CriterionOperator::PROP_SEMVER_GREATER_THAN, property_name: 'user.version', value_to_match: "2.0.0")
1062
+ evaluator = Prefab::CriteriaEvaluator.new(config, project_env_id: PROJECT_ENV_ID, resolver: nil, base_client: @base_client, namespace: nil)
1063
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context({})).unwrapped_value
1064
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "nonsense"})).unwrapped_value
1065
+
1066
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "1.0.0"})).unwrapped_value
1067
+ assert_equal DEFAULT_VALUE, evaluator.evaluate(context(user:{version: "2.0.0"})).unwrapped_value
1068
+ assert_equal DESIRED_VALUE, evaluator.evaluate(context(user:{version: "3.0.0"})).unwrapped_value
1069
+ end
1070
+
686
1071
  private
687
1072
 
688
1073
  def string_list(values)
@@ -719,4 +1104,55 @@ class TestCriteriaEvaluator < Minitest::Test
719
1104
  'fake-base-client-instance_hash'
720
1105
  end
721
1106
  end
1107
+
1108
+
1109
+ def create_prefab_config(
1110
+ key: KEY,
1111
+ project_env_id: PROJECT_ENV_ID,
1112
+ operator:,
1113
+ value_to_match:,
1114
+ property_name:,
1115
+ desired_value_config: DESIRED_VALUE_CONFIG
1116
+ )
1117
+ PrefabProto::Config.new(
1118
+ key: key,
1119
+ rows: [
1120
+ DEFAULT_ROW,
1121
+ PrefabProto::ConfigRow.new(
1122
+ project_env_id: project_env_id,
1123
+ values: [
1124
+ PrefabProto::ConditionalValue.new(
1125
+ criteria: [
1126
+ PrefabProto::Criterion.new(
1127
+ operator: operator,
1128
+ value_to_match: build_config_value(value_to_match),
1129
+ property_name: property_name
1130
+ )
1131
+ ],
1132
+ value: desired_value_config
1133
+ )
1134
+ ]
1135
+ )
1136
+ ]
1137
+ )
1138
+ end
1139
+
1140
+ def build_config_value(value)
1141
+ case value
1142
+ when Integer
1143
+ PrefabProto::ConfigValue.new(int: value)
1144
+ when Float
1145
+ PrefabProto::ConfigValue.new(double: value)
1146
+ when String
1147
+ PrefabProto::ConfigValue.new(string: value)
1148
+ when Array
1149
+ if value.all? { |v| v.is_a?(String) }
1150
+ PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: value))
1151
+ else
1152
+ raise ArgumentError, "Unsupported array type: Only arrays of strings are supported."
1153
+ end
1154
+ else
1155
+ raise ArgumentError, "Unsupported value type: #{value.class}"
1156
+ end
1157
+ end
722
1158
  end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'test_helper'
5
+
6
+ module Prefab
7
+ class FixedSizeHashTest < Minitest::Test
8
+ def setup
9
+ @max_size = 3
10
+ @hash = FixedSizeHash.new(@max_size)
11
+ end
12
+
13
+ def test_acts_like_a_regular_hash_when_under_max_size
14
+ @hash[:a] = 1
15
+ @hash[:b] = 2
16
+
17
+ assert_equal 1, @hash[:a]
18
+ assert_equal 2, @hash[:b]
19
+ assert_equal 2, @hash.size
20
+ end
21
+
22
+ def test_enforces_max_size_by_evicting_first_added_item
23
+ @hash[:a] = 1
24
+ @hash[:b] = 2
25
+ @hash[:c] = 3
26
+ assert_equal @max_size, @hash.size
27
+
28
+ @hash[:d] = 4
29
+ assert_equal @max_size, @hash.size
30
+ assert_nil @hash[:a] # First item should be evicted
31
+ assert_equal 4, @hash[:d]
32
+ end
33
+
34
+ def test_updating_existing_key_does_not_trigger_eviction
35
+ @hash[:a] = 1
36
+ @hash[:b] = 2
37
+ @hash[:c] = 3
38
+
39
+ @hash[:b] = 'new value' # Update existing key
40
+
41
+ assert_equal @max_size, @hash.size
42
+ assert_equal 1, @hash[:a] # First item should still be present
43
+ assert_equal 'new value', @hash[:b]
44
+ assert_equal 3, @hash[:c]
45
+ end
46
+
47
+ def test_handles_nil_values
48
+ @hash[:a] = nil
49
+ @hash[:b] = 2
50
+ @hash[:c] = 3
51
+ @hash[:d] = 4
52
+
53
+ assert_nil @hash[:a] # First item should be evicted
54
+ assert_equal 4, @hash[:d]
55
+ end
56
+
57
+ def test_preserves_hash_methods
58
+ @hash[:a] = 1
59
+ @hash[:b] = 2
60
+
61
+ assert_equal [:a, :b], @hash.keys
62
+ assert_equal [1, 2], @hash.values
63
+ assert @hash.key?(:a)
64
+ refute @hash.key?(:z)
65
+ end
66
+
67
+ def test_handles_string_keys
68
+ @hash['a'] = 1
69
+ @hash['b'] = 2
70
+ @hash['c'] = 3
71
+ @hash['d'] = 4
72
+
73
+ assert_nil @hash['a'] # First item should be evicted
74
+ assert_equal 4, @hash['d']
75
+ end
76
+
77
+ def test_handles_object_keys
78
+ key1 = Object.new
79
+ key2 = Object.new
80
+ key3 = Object.new
81
+ key4 = Object.new
82
+
83
+ @hash[key1] = 1
84
+ @hash[key2] = 2
85
+ @hash[key3] = 3
86
+ @hash[key4] = 4
87
+
88
+ assert_nil @hash[key1] # First item should be evicted
89
+ assert_equal 4, @hash[key4]
90
+ end
91
+
92
+ def test_can_be_initialized_empty
93
+ assert_equal 0, @hash.size
94
+ end
95
+
96
+ def test_enumerable_methods
97
+ @hash[:a] = 1
98
+ @hash[:b] = 2
99
+
100
+ mapped = @hash.map { |k, v| [k, v * 2] }.to_h
101
+ assert_equal({ a: 2, b: 4 }, mapped)
102
+
103
+ filtered = @hash.select { |_, v| v > 1 }
104
+ assert_equal({ b: 2 }, filtered.to_h)
105
+ end
106
+
107
+ def test_clear_maintains_max_size_constraint
108
+ @hash[:a] = 1
109
+ @hash[:b] = 2
110
+ @hash.clear
111
+
112
+ assert_equal 0, @hash.size
113
+
114
+ # Should still enforce max size after clear
115
+ (@max_size + 1).times { |i| @hash[i] = i }
116
+ assert_equal @max_size, @hash.size
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,108 @@
1
+ require 'test_helper'
2
+ class TestSemanticVersion < Minitest::Test
3
+ def test_parse_valid_version
4
+ version = SemanticVersion.parse('1.2.3')
5
+ assert_equal 1, version.major
6
+ assert_equal 2, version.minor
7
+ assert_equal 3, version.patch
8
+ assert_nil version.prerelease
9
+ assert_nil version.build_metadata
10
+ end
11
+
12
+ def test_parse_version_with_prerelease
13
+ version = SemanticVersion.parse('1.2.3-alpha.1')
14
+ assert_equal 1, version.major
15
+ assert_equal 2, version.minor
16
+ assert_equal 3, version.patch
17
+ assert_equal 'alpha.1', version.prerelease
18
+ assert_nil version.build_metadata
19
+ end
20
+
21
+ def test_parse_version_with_build_metadata
22
+ version = SemanticVersion.parse('1.2.3+build.123')
23
+ assert_equal 1, version.major
24
+ assert_equal 2, version.minor
25
+ assert_equal 3, version.patch
26
+ assert_nil version.prerelease
27
+ assert_equal 'build.123', version.build_metadata
28
+ end
29
+
30
+ def test_parse_full_version
31
+ version = SemanticVersion.parse('1.2.3-alpha.1+build.123')
32
+ assert_equal 1, version.major
33
+ assert_equal 2, version.minor
34
+ assert_equal 3, version.patch
35
+ assert_equal 'alpha.1', version.prerelease
36
+ assert_equal 'build.123', version.build_metadata
37
+ end
38
+
39
+ def test_parse_invalid_version
40
+ assert_raises(ArgumentError) { SemanticVersion.parse('invalid') }
41
+ assert_raises(ArgumentError) { SemanticVersion.parse('1.2') }
42
+ assert_raises(ArgumentError) { SemanticVersion.parse('1.2.3.4') }
43
+ assert_raises(ArgumentError) { SemanticVersion.parse('') }
44
+ end
45
+
46
+ def test_parse_quietly
47
+ assert_nil SemanticVersion.parse_quietly('invalid')
48
+ refute_nil SemanticVersion.parse_quietly('1.2.3')
49
+ end
50
+
51
+ def test_to_string
52
+ assert_equal '1.2.3', SemanticVersion.parse('1.2.3').to_s
53
+ assert_equal '1.2.3-alpha.1', SemanticVersion.parse('1.2.3-alpha.1').to_s
54
+ assert_equal '1.2.3+build.123', SemanticVersion.parse('1.2.3+build.123').to_s
55
+ assert_equal '1.2.3-alpha.1+build.123', SemanticVersion.parse('1.2.3-alpha.1+build.123').to_s
56
+ end
57
+
58
+ def test_equality
59
+ v1 = SemanticVersion.parse('1.2.3')
60
+ v2 = SemanticVersion.parse('1.2.3')
61
+ v3 = SemanticVersion.parse('1.2.4')
62
+ v4 = SemanticVersion.parse('1.2.3-alpha')
63
+ v5 = SemanticVersion.parse('1.2.3+build.123')
64
+
65
+ assert_equal v1, v2
66
+ refute_equal v1, v3
67
+ refute_equal v1, v4
68
+ assert_equal v1, v5 # build metadata is ignored in equality
69
+ end
70
+
71
+ def test_comparison
72
+ versions = [
73
+ '1.0.0-alpha',
74
+ '1.0.0-alpha.1',
75
+ '1.0.0-beta.2',
76
+ '1.0.0-beta.11',
77
+ '1.0.0-rc.1',
78
+ '1.0.0',
79
+ '2.0.0',
80
+ '2.1.0',
81
+ '2.1.1'
82
+ ].map { |v| SemanticVersion.parse(v) }
83
+
84
+ # Test that each version is less than the next version
85
+ (versions.length - 1).times do |i|
86
+ assert versions[i] < versions[i + 1], "Expected #{versions[i]} < #{versions[i + 1]}"
87
+ end
88
+ end
89
+
90
+ def test_prerelease_comparison
91
+ # Test specific prerelease comparison cases
92
+ cases = [
93
+ ['1.0.0-alpha', '1.0.0-alpha.1', -1],
94
+ ['1.0.0-alpha.1', '1.0.0-alpha.beta', -1],
95
+ ['1.0.0-alpha.beta', '1.0.0-beta', -1],
96
+ ['1.0.0-beta', '1.0.0-beta.2', -1],
97
+ ['1.0.0-beta.2', '1.0.0-beta.11', -1],
98
+ ['1.0.0-beta.11', '1.0.0-rc.1', -1],
99
+ ['1.0.0-rc.1', '1.0.0', -1]
100
+ ]
101
+
102
+ cases.each do |v1_str, v2_str, expected|
103
+ v1 = SemanticVersion.parse(v1_str)
104
+ v2 = SemanticVersion.parse(v2_str)
105
+ assert_equal expected, (v1 <=> v2), "Expected #{v1} <=> #{v2} to be #{expected}"
106
+ end
107
+ end
108
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'test_helper'
4
4
  require 'webrick'
5
+ require 'ostruct'
5
6
 
6
7
  class TestSSEConfigClient < Minitest::Test
7
8
  def test_client