def test_invalid_xor(self): with self.assertRaises(ValueError): K(['^', [['?', 'a'], ['?', 'b'], ['?', 'c']]]) with self.assertRaises(ValueError): K(['^', [ ['?', 'a'], ]])
def test_xor_true(self): self.assertTrue( K(['^', [['?', 'email'], ['?', 'e-mail']]]).match({'email': '*****@*****.**'})) self.assertTrue( K(['^', [['?', 'email'], ['?', 'e-mail']]]).match({'e-mail': '*****@*****.**'}))
def test_save_k(self): """ Tests that compiled k patterns can be saved and accessed. """ k = K(['==', 'a', 1]) test_obj = KModel.objects.create(k=k) self.assertTrue(test_obj.k.match({'a': 1})) self.assertFalse(test_obj.k.match({'a': 2})) # Set the value of the test obj and call save. Verify the function can still be loaded properly test_obj.k = K(['==', 'z', 2]) test_obj.save() test_obj = KModel.objects.get(id=test_obj.id) self.assertTrue(test_obj.k.match({'z': 2})) self.assertFalse(test_obj.k.match({'z': 3}))
def test_get_field_keys_invalid_pattern(self): """ Verifies that an error is raised for invalid patterns """ pattern = ['&', [['invalid', 'one', 'one value']]] with self.assertRaises(ValueError): K(pattern).get_field_keys()
def test_compound_and_lte_gte_double_field_true(self): self.assertTrue(K([ '&', [ ['>=', 'f1', 3], ['<=', 'f2', 7], ] ]).match({'f1': 5, 'f2': 0}))
def test_compound_or_regex_double_field_false(self): self.assertFalse(K([ '|', [ ['=~', 'f1', '^Email$'], ['=~', 'f2', '^Call$'], ] ]).match({'f1': 'Emails', 'f2': 'Reminder'}))
def test_compound_and_lte_gte_single_field_true(self): self.assertTrue(K([ '&', [ ['>=', 'f', 3], ['<=', 'f', 7], ] ]).match({'f': 5}))
def test_compound_existence_gte_true(self): self.assertTrue(K([ '&', [ ['?', 'f'], ['>', 'f', 5], ] ]).match({'f': 6}))
def test_triply_nested_list_of_dicts(self, mock_compile): k = K([ '&', [['=~', 'f', 'hi'], ['=~', 'f', 'hello'], [ '|', [['=~', 'f', 'or_hi'], ['=~', 'f', 'or_hello'], ['&', [ ['=~', 'f', 'and_hi'], ]]] ]] ]) self.assertEquals(mock_compile.call_count, 5) self.assertEquals(k._compiled_pattern, [ '&', [['=~', 'f', 'hi_compiled'], ['=~', 'f', 'hello_compiled'], [ '|', [['=~', 'f', 'or_hi_compiled'], ['=~', 'f', 'or_hello_compiled'], ['&', [ ['=~', 'f', 'and_hi_compiled'], ]]] ]] ])
def test_get_field_keys(self): """ Verifies that all field keys are returned """ pattern = [ '&', [ ['?', 'foo'], ['=~', 'one', 'one value'], ['=~', 'two', 'two value'], [ '|', [['=~', 'three', 'three value'], ['!', ['=~', 'one', 'other one value']], [ '^', [['==', 'five', 'five value'], ['==', 'five', 'five value']] ], ['&', [ ['=~', 'four', 'four value'], ]]] ], ] ] self.assertEqual( K(pattern).get_field_keys(), set(['one', 'two', 'three', 'four', 'five', 'foo']))
def test_compound_suppress_key_errors_gte_true(self): self.assertTrue( K(['|', [ ['==', 'f1', 5], ['>', 'f', 5], ]], suppress_key_errors=True).match({'f': 6}))
def test_string_choice_or_true(self): self.assertTrue(K([ '|', [ ['==', 'f1', 'Email'], ['==', 'f1', 'Call'], ['==', 'f1', 'Task'], ] ]).match({'f1': 'Task', 'f2': 2}))
def pre_init(self, value, obj): """ Used to obtain a K object for a provided pattern. Normally this is done in the to_python method of a Django custom field. However, this field inherits JSONField, and JSONField had to do conversions in the pre_init method. """ value = super(KField, self).pre_init(value, obj) return K( value) if not isinstance(value, K) and value is not None else value
def test_two_nested_ors_false(self): self.assertFalse(K([ '&', [ ['|', [ ['=~', 'f1', '^Email$'], ['=~', 'f1', '^Call$'], ]], ['!', ['>=', 'f2', 3]], ] ]).match({'f1': 'Call', 'f2': 4}))
def test_nested_compound_or_and_regex_double_field_false(self): self.assertFalse(K([ '&', [ ['>=', 'f2', 10], [ '|', [ ['=~', 'f1', '^Email$'], ['=~', 'f1', '^Call$'], ] ] ] ]).match({'f1': 'Email', 'f2': 2}))
def test_two_nested_ors_true(self): self.assertTrue(K([ '&', [ ['|', [ ['=~', 'f1', '^Email$'], ['=~', 'f1', '^Call$'], ]], ['|', [ ['>=', 'f2', 3], ['>=', 'f3', 1], ]] ] ]).match({'f1': 'Call', 'f2': 5, 'f3': 2}))
def __init__(self, name, *, kmatch=None, kmatch_path=None, suppress_key_errors=True): super().__init__(name) if kmatch is None: with open(kmatch_path) as fob: kmatch = json.load(fob) self.kmatch = K(kmatch, suppress_key_errors=suppress_key_errors)
def test_basic_suppress_key_errors(self): self.assertFalse(K(['==', 'k', 3], suppress_key_errors=True).match({}))
def test_basic_nonexistence_false(self): self.assertFalse(K(['!?', 'k']).match({'k': 'val'}))
def test_basic_nonexistence_true(self): self.assertTrue(K(['!?', 'k']).match({'k1': 'val'}))
def test_basic_not_equals_non_extant(self): with self.assertRaises(KeyError): self.assertFalse(K(['!=', 'f', None]).match({}))
def test_basic_regex_non_extant(self): with self.assertRaises(KeyError): self.assertFalse(K(['=~', 'f', '^hi$']).match({}))
def test_basic_regex_false(self): self.assertFalse(K(['=~', 'f', '^hi$']).match({'f': ' hi'}))
def test_basic_gt_non_extant(self): with self.assertRaises(KeyError): self.assertFalse(K(['>', 'f', 0]).match({}))
def test_basic_gte_false(self): self.assertFalse(K(['>=', 'f', 0]).match({'f': -1}))
def test_basic_gte_true(self): self.assertTrue(K(['>=', 'f', 0]).match({'f': 0}))
def test_basic_eq_false(self): self.assertFalse(K(['==', 'f', 0]).match({'f': 1}))
def test_not_field_true(self): self.assertTrue(K([ '!', ['>=', 'f', 3], ]).match({'f': 1}))
def test_nested_list_of_lists(self, mock_compile): k = K(['&', [['=~', 'f', 'hi'], ['=~', 'f', 'hello']]]) self.assertEquals(mock_compile.call_count, 2) self.assertEquals( k._compiled_pattern, ['&', [['=~', 'f', 'hi_compiled'], ['=~', 'f', 'hello_compiled']]])
def test_null_regex_match_false(self): self.assertFalse(K(['=~', 'f', '^hi$']).match({'f': None}))