@@ -995,4 +995,198 @@ def test__operators_preserve_original_object(self):
995995 _ = (original == __ (score = __GREATER_THAN__ (80 ), duration = __LESS_THAN__ (0.5 )))
996996
997997 assert original .score == 85 # Original unchanged
998- assert original .duration == 0.234 # Original unchanged
998+ assert original .duration == 0.234 # Original unchanged
999+
1000+ def test_contains__with_kwargs__basic (self ): # Test contains with kwargs syntax
1001+ with __ (id = '123' , name = 'Test' , age = 25 , status = 'active' ) as _ :
1002+ assert _ .contains (id = '123' ) # Single field as kwarg
1003+ assert _ .contains (id = '123' , name = 'Test' ) # Multiple fields as kwargs
1004+ assert _ .contains (id = '123' , name = 'Test' , age = 25 ) # More fields as kwargs
1005+ assert not _ .contains (id = '456' ) # Wrong value
1006+ assert not _ .contains (missing_field = 'value' ) # Non-existent field
1007+
1008+ def test_contains__with_kwargs__vs_object_syntax (self ): # Test both syntaxes produce same results
1009+ with __ (a = 1 , b = 2 , c = 3 ) as _ :
1010+ # Both syntaxes should work identically
1011+ assert _ .contains (__ (a = 1 , b = 2 )) == _ .contains (a = 1 , b = 2 )
1012+ assert _ .contains (__ (a = 1 )) == _ .contains (a = 1 )
1013+ assert _ .contains (__ (c = 3 )) == _ .contains (c = 3 )
1014+
1015+ def test_contains__with_kwargs__with_operators (self ): # Test kwargs with comparison operators
1016+ with __ (score = 85 , duration = 0.234 , count = 100 ) as _ :
1017+ assert _ .contains (score = __GREATER_THAN__ (80 )) # Single operator
1018+ assert _ .contains (duration = __LESS_THAN__ (0.5 )) # Different operator
1019+ assert _ .contains (count = __BETWEEN__ (50 , 150 )) # Range operator
1020+
1021+ # Multiple operators
1022+ assert _ .contains (score = __GREATER_THAN__ (80 ),
1023+ duration = __LESS_THAN__ (0.5 ))
1024+
1025+ # Mix operators and exact values
1026+ assert _ .contains (score = __GREATER_THAN__ (80 ),
1027+ count = 100 )
1028+
1029+ def test_contains__with_kwargs__with_skip (self ): # Test kwargs with __SKIP__ marker
1030+ with __ (id = '123' , name = 'Test' , timestamp = 999 ) as _ :
1031+ assert _ .contains (id = '123' , timestamp = __SKIP__ ) # Skip timestamp
1032+ assert _ .contains (id = __SKIP__ , name = 'Test' ) # Skip id
1033+ assert _ .contains (id = __SKIP__ , name = 'Test' , timestamp = __SKIP__ ) # Skip multiple
1034+
1035+ def test_contains__with_kwargs__nested_objects (self ): # Test kwargs doesn't work with nested (by design)
1036+ with __ (user = __ (id = 'u1' , name = 'Alice' ), settings = __ (theme = 'dark' )) as _ :
1037+ # Kwargs can only check top-level fields
1038+ assert _ .contains (user = __ (id = 'u1' )) # Must use __ for nested
1039+ # Can't do: _.contains(user=id='u1') # This would fail - nested needs __
1040+
1041+ def test_contains__with_kwargs__empty (self ): # Test contains with no arguments
1042+ with __ (a = 1 , b = 2 ) as _ :
1043+ result = _ .contains () # Empty kwargs should return False
1044+ assert result == False # Should match empty
1045+
1046+ def test_contains__kwargs_cannot_mix_with_positional (self ): # Test you can't mix both syntaxes
1047+ with __ (a = 1 , b = 2 , c = 3 ) as _ :
1048+ assert _ .contains (__ (a = 1 , b = 2 )) # Positional __ object
1049+ assert _ .contains (a = 1 , b = 2 ) # Kwargs
1050+ error_message = ("Cannot mix positional and keyword arguments in contains(). "
1051+ "Use either _.contains(__(a=1, b=2)) or _.contains(a=1, b=2), not both." )
1052+ with pytest .raises (ValueError , match = re .escape (error_message )) :
1053+ assert _ .contains (__ (a = 1 ), b = 2 ) # we can't use both techniques
1054+
1055+
1056+ def test_contains__with_kwargs__real_world_example (self ): # Real-world pattern test
1057+ api_response = __ (status = 200 ,
1058+ headers = __ (content_type = 'application/json' , x_request_id = 'req-123' ),
1059+ data = __ (items = [1 , 2 , 3 ], total = 3 ),
1060+ timing = __ (duration = 0.234 , cached = False ))
1061+
1062+ # Old syntax (still works)
1063+ assert api_response .contains (__ (status = 200 ))
1064+
1065+ # New syntax (cleaner!)
1066+ assert api_response .contains (status = 200 )
1067+ assert api_response .contains (status = 200 , timing = __ (duration = __LESS_THAN__ (0.5 )))
1068+
1069+ def test_contains__with_kwargs__all_types (self ): # Test kwargs with various Python types
1070+ with __ (
1071+ string = 'test' ,
1072+ integer = 42 ,
1073+ floating = 3.14 ,
1074+ boolean = True ,
1075+ none_val = None ,
1076+ list_val = [1 , 2 , 3 ],
1077+ dict_val = {'key' : 'value' }
1078+ ) as _ :
1079+ assert _ .contains (string = 'test' ) # String
1080+ assert _ .contains (integer = 42 ) # Int
1081+ assert _ .contains (floating = 3.14 ) # Float
1082+ assert _ .contains (boolean = True ) # Bool
1083+ assert _ .contains (none_val = None ) # None
1084+ assert _ .contains (list_val = [1 , 2 , 3 ]) # List
1085+ assert _ .contains (dict_val = {'key' : 'value' }) # Dict
1086+
1087+ def test_contains__with_kwargs__operators_all_types (self ): # Test all operators with kwargs syntax
1088+ with __ (
1089+ score = 85 ,
1090+ duration = 0.234 ,
1091+ probability = 0.753 ,
1092+ count = 42
1093+ ) as _ :
1094+ # Greater than
1095+ assert _ .contains (score = __GREATER_THAN__ (80 ))
1096+
1097+ # Less than
1098+ assert _ .contains (duration = __LESS_THAN__ (0.5 ))
1099+
1100+ # Between
1101+ assert _ .contains (probability = __BETWEEN__ (0.7 , 0.8 ))
1102+
1103+ # Close to
1104+ assert _ .contains (probability = __CLOSE_TO__ (0.75 , tolerance = 0.01 ))
1105+
1106+ # Multiple operators
1107+ assert _ .contains (score = __GREATER_THAN__ (80 ),
1108+ duration = __LESS_THAN__ (0.5 ),
1109+ count = __BETWEEN__ (40 , 50 ))
1110+
1111+ def test_contains__with_kwargs__partial_match (self ): # Test partial matching with kwargs
1112+ with __ (
1113+ id = 'test-123' ,
1114+ name = 'Test User' ,
1115+ 1116+ age = 25 ,
1117+ status = 'active' ,
1118+ created_at = '2024-01-01'
1119+ ) as _ :
1120+ # Can check any subset of fields
1121+ assert _ .contains (id = 'test-123' ) # Just one field
1122+ assert _ .contains (name = 'Test User' , status = 'active' ) # Two fields
1123+ assert _ .
contains (
email = '[email protected] ' ,
age = 25 ,
status = 'active' )
# Three fields 1124+
1125+ def test_contains__with_kwargs__comparison_with_object_syntax_operators (self ): # Compare both syntaxes with operators
1126+ with __ (score = 85 , duration = 0.234 , count = 100 , status = 'active' ) as _ :
1127+ # Both syntaxes should behave identically
1128+
1129+ # Greater than
1130+ assert _ .contains (__ (score = __GREATER_THAN__ (80 )))
1131+ assert _ .contains (score = __GREATER_THAN__ (80 ))
1132+
1133+ # Multiple with operators
1134+ old_syntax = _ .contains (__ (
1135+ score = __GREATER_THAN__ (80 ),
1136+ duration = __LESS_THAN__ (0.5 ),
1137+ status = 'active'
1138+ ))
1139+
1140+ new_syntax = _ .contains (
1141+ score = __GREATER_THAN__ (80 ),
1142+ duration = __LESS_THAN__ (0.5 ),
1143+ status = 'active'
1144+ )
1145+
1146+ assert old_syntax == new_syntax == True
1147+
1148+ def test_contains__with_kwargs__failure_cases (self ): # Test failure cases with kwargs
1149+ with __ (score = 85 , name = 'test' , status = 'active' ) as _ :
1150+ assert not _ .contains (score = 90 ) # Wrong value
1151+ assert not _ .contains (missing = 'value' ) # Missing field
1152+ assert not _ .contains (score = __GREATER_THAN__ (90 )) # Operator fails
1153+ assert not _ .contains (name = 'test' , score = 90 ) # One field wrong
1154+
1155+ def test_contains__with_kwargs__integration_test (self ): # Integration test combining features
1156+ complex_obj = __ (
1157+ request_id = 'req-abc-123' ,
1158+ timestamp = 1234567890 ,
1159+ status = 200 ,
1160+ timing = __ (
1161+ total = 0.456 ,
1162+ db_query = 0.234 ,
1163+ render = 0.111
1164+ ),
1165+ metrics = __ (
1166+ accuracy = 0.953 ,
1167+ score = 87.5 ,
1168+ count = 1024
1169+ ),
1170+ metadata = __ (
1171+ version = '2.1.0' ,
1172+ cached = False
1173+ )
1174+ )
1175+
1176+ # Old syntax still works
1177+ assert complex_obj .contains (__ (status = 200 , request_id = __SKIP__ ))
1178+
1179+ # New syntax is cleaner for top-level checks
1180+ assert complex_obj .contains (status = 200 , request_id = __SKIP__ )
1181+ assert complex_obj .contains (
1182+ status = 200 ,
1183+ timestamp = __SKIP__ ,
1184+ timing = __ (total = __LESS_THAN__ (0.5 ))
1185+ )
1186+
1187+ # With operators
1188+ assert complex_obj .contains (
1189+ status = __BETWEEN__ (200 , 299 ),
1190+ request_id = __SKIP__ ,
1191+ metrics = __ (score = __GREATER_THAN__ (85 ))
1192+ )
0 commit comments