# imports import operator import unittest # bsfs imports from bsfs.namespace import ns from bsfs.query import ast from bsfs.utils import errors # objects to test from bsfs.query.matcher import Any, Filter, Partial, Rest, _set_matcher ## code ## class TestAny(unittest.TestCase): def test_essentials(self): # comparison a = Any() b = Any() self.assertNotEqual(Any(), Any()) self.assertNotEqual(hash(Any()), hash(Any())) self.assertNotEqual(a, Any()) self.assertNotEqual(hash(a), hash(Any())) self.assertNotEqual(a, b) self.assertNotEqual(hash(a), hash(b)) # comparison within sets self.assertEqual(len({Any(), Any(), Any(), Any()}), 4) self.assertEqual(len({Any() for _ in range(1000)}), 1000) # string representation self.assertEqual(str(Any()), 'Any()') self.assertEqual(repr(Any()), 'Any()') class TestRest(unittest.TestCase): def test_essentials(self): expr = ast.filter.Equals('hello') # comparison self.assertEqual(Rest(expr), Rest(expr)) self.assertEqual(hash(Rest(expr)), hash(Rest(expr))) # comparison respects type class Foo(): pass self.assertNotEqual(Rest(expr), 1234) self.assertNotEqual(hash(Rest(expr)), hash(1234)) self.assertNotEqual(Rest(expr), Foo()) self.assertNotEqual(hash(Rest(expr)), hash(Foo())) # comparison respects expr self.assertNotEqual(Rest(expr), Rest(ast.filter.Equals('world'))) self.assertNotEqual(hash(Rest(expr)), hash(Rest(ast.filter.Equals('world')))) # default constructor -> Any -> Not equal self.assertNotEqual(Rest(), Rest()) self.assertNotEqual(hash(Rest()), hash(Rest())) # string representation self.assertEqual(str(Rest()), 'Rest(Any())') self.assertEqual(str(Rest(expr)), 'Rest(Equals(hello))') self.assertEqual(repr(Rest()), 'Rest(Any())') self.assertEqual(repr(Rest(expr)), 'Rest(Equals(hello))') class TestPartial(unittest.TestCase): def test_match(self): p0 = Partial(ast.filter.LessThan) p1 = Partial(ast.filter.LessThan, threshold=3) p2 = Partial(ast.filter.LessThan, strict=False) p3 = Partial(ast.filter.LessThan, threshold=3, strict=False) # match respects name self.assertTrue(p0.match('foo', None)) self.assertTrue(p1.match('foo', None)) self.assertTrue(p2.match('foo', None)) self.assertTrue(p3.match('foo', None)) # match respects correct value self.assertTrue(p0.match('threshold', 3)) self.assertTrue(p1.match('threshold', 3)) self.assertTrue(p2.match('threshold', 3)) self.assertTrue(p3.match('threshold', 3)) self.assertTrue(p0.match('strict', False)) self.assertTrue(p1.match('strict', False)) self.assertTrue(p2.match('strict', False)) self.assertTrue(p3.match('strict', False)) # match respects incorrect value self.assertTrue(p0.match('threshold', 5)) self.assertFalse(p1.match('threshold', 5)) self.assertTrue(p2.match('threshold', 5)) self.assertFalse(p3.match('threshold', 5)) self.assertTrue(p0.match('strict', True)) self.assertTrue(p1.match('strict', True)) self.assertFalse(p2.match('strict', True)) self.assertFalse(p3.match('strict', True)) def test_members(self): # node returns expression self.assertEqual(Partial(ast.filter.Equals).node, ast.filter.Equals) self.assertEqual(Partial(ast.filter.LessThan).node, ast.filter.LessThan) # kwargs returns arguments self.assertDictEqual(Partial(ast.filter.Equals, value='hello').kwargs, {'value': 'hello'}) self.assertDictEqual(Partial(ast.filter.LessThan, threshold=3, strict=False).kwargs, {'threshold': 3, 'strict': False}) # Partial does not check about kwargs self.assertDictEqual(Partial(ast.filter.LessThan, value='hello').kwargs, {'value': 'hello'}) self.assertDictEqual(Partial(ast.filter.Equals, threshold=3, strict=False).kwargs, {'threshold': 3, 'strict': False}) def test_essentials(self): # comparison respects type class Foo(): pass self.assertNotEqual(Partial(ast.filter.Equals), 1234) self.assertNotEqual(hash(Partial(ast.filter.Equals)), hash(1234)) self.assertNotEqual(Partial(ast.filter.Equals), Foo()) self.assertNotEqual(hash(Partial(ast.filter.Equals)), hash(Foo())) self.assertNotEqual(Partial(ast.filter.Equals), ast.filter.Equals) self.assertNotEqual(hash(Partial(ast.filter.Equals)), hash(ast.filter.Equals)) self.assertNotEqual(Partial(ast.filter.Equals), ast.filter.Equals('hello')) self.assertNotEqual(hash(Partial(ast.filter.Equals)), hash(ast.filter.Equals('hello'))) # comparison respects node self.assertEqual(Partial(ast.filter.Equals), Partial(ast.filter.Equals)) self.assertEqual(hash(Partial(ast.filter.Equals)), hash(Partial(ast.filter.Equals))) self.assertEqual(Partial(ast.filter.LessThan), Partial(ast.filter.LessThan)) self.assertEqual(hash(Partial(ast.filter.LessThan)), hash(Partial(ast.filter.LessThan))) self.assertNotEqual(Partial(ast.filter.Equals), Partial(ast.filter.LessThan)) self.assertNotEqual(hash(Partial(ast.filter.Equals)), hash(Partial(ast.filter.LessThan))) # comparison respects kwargs self.assertEqual( Partial(ast.filter.Equals, value='hello'), Partial(ast.filter.Equals, value='hello')) self.assertEqual( hash(Partial(ast.filter.Equals, value='hello')), hash(Partial(ast.filter.Equals, value='hello'))) self.assertEqual( Partial(ast.filter.LessThan, threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=3, strict=False)) self.assertEqual( hash(Partial(ast.filter.LessThan, threshold=3, strict=False)), hash(Partial(ast.filter.LessThan, threshold=3, strict=False))) self.assertNotEqual( Partial(ast.filter.Equals, value='hello'), Partial(ast.filter.Equals)) self.assertNotEqual( hash(Partial(ast.filter.Equals, value='hello')), hash(Partial(ast.filter.Equals))) self.assertNotEqual( Partial(ast.filter.Equals, value='hello'), Partial(ast.filter.Equals, value='world')) self.assertNotEqual( hash(Partial(ast.filter.Equals, value='hello')), hash(Partial(ast.filter.Equals, value='world'))) self.assertNotEqual( Partial(ast.filter.LessThan, threshold=3, strict=False), Partial(ast.filter.LessThan)) self.assertNotEqual( hash(Partial(ast.filter.LessThan, threshold=3, strict=False)), hash(Partial(ast.filter.LessThan))) self.assertNotEqual( Partial(ast.filter.LessThan, threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=5)) self.assertNotEqual( hash(Partial(ast.filter.LessThan, threshold=3, strict=False)), hash(Partial(ast.filter.LessThan, threshold=5))) self.assertNotEqual( Partial(ast.filter.LessThan, threshold=3, strict=False), Partial(ast.filter.LessThan, strict=False)) self.assertNotEqual( hash(Partial(ast.filter.LessThan, threshold=3, strict=False)), hash(Partial(ast.filter.LessThan, strict=False))) self.assertNotEqual( Partial(ast.filter.LessThan, threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=3, strict=True)) self.assertNotEqual( hash(Partial(ast.filter.LessThan, threshold=3, strict=False)), hash(Partial(ast.filter.LessThan, threshold=3, strict=True))) self.assertNotEqual( Partial(ast.filter.LessThan, threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=5, strict=False)) self.assertNotEqual( hash(Partial(ast.filter.LessThan, threshold=3, strict=False)), hash(Partial(ast.filter.LessThan, threshold=5, strict=False))) # string representation self.assertEqual(str(Partial(ast.filter.Equals)), 'Partial(Equals, {})') self.assertEqual(repr(Partial(ast.filter.Equals)), 'Partial(Equals, {})') self.assertEqual(str(Partial(ast.filter.LessThan)), 'Partial(LessThan, {})') self.assertEqual(repr(Partial(ast.filter.LessThan)), 'Partial(LessThan, {})') self.assertEqual(str(Partial(ast.filter.Equals, value='hello')), "Partial(Equals, {'value': 'hello'})") self.assertEqual(repr(Partial(ast.filter.Equals, value='hello')), "Partial(Equals, {'value': 'hello'})") self.assertEqual(str(Partial(ast.filter.LessThan, threshold=3)), "Partial(LessThan, {'threshold': 3})") self.assertEqual(repr(Partial(ast.filter.LessThan, threshold=3)), "Partial(LessThan, {'threshold': 3})") self.assertEqual(str(Partial(ast.filter.LessThan, strict=False)), "Partial(LessThan, {'strict': False})") self.assertEqual(repr(Partial(ast.filter.LessThan, strict=False)), "Partial(LessThan, {'strict': False})") self.assertEqual(str(Partial(ast.filter.LessThan, threshold=3, strict=False)), "Partial(LessThan, {'threshold': 3, 'strict': False})") self.assertEqual(repr(Partial(ast.filter.LessThan, threshold=3, strict=False)), "Partial(LessThan, {'threshold': 3, 'strict': False})") class TestSetMatcher(unittest.TestCase): def test_set_matcher(self): # setup A = ast.filter.Equals('A') B = ast.filter.Equals('B') C = ast.filter.Equals('C') D = ast.filter.Equals('D') matcher = Filter() # identical sets match self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, C), matcher._parse_filter_expression, )) # order is irrelevant self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(B, C, A), matcher._parse_filter_expression, )) # all reference items must be present self.assertFalse(_set_matcher( ast.filter.And(A, B), ast.filter.And(A, B, C), matcher._parse_filter_expression, )) # all reference items must have a match self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(D, B, C), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, D, C), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, D), matcher._parse_filter_expression, )) # Any matches every item self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Any(), B, C), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, Any(), C), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Any()), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, D), ast.filter.And(A, B, Any()), matcher._parse_filter_expression, )) # there can be multiple Any's self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, Any(), Any()), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Any(), B, Any()), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Any(), Any(), C), matcher._parse_filter_expression, )) # Any covers exactly one element self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Any()), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, D), ast.filter.And(A, B, Any()), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B), ast.filter.And(A, B, Any()), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C, D), ast.filter.And(A, B, Any()), matcher._parse_filter_expression, )) # each Any covers exactly one element self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Any(), Any(), Any()), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Any(), Any()), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B), ast.filter.And(Any(), Any(), Any()), matcher._parse_filter_expression, )) # Rest captures remainder self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest()), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, C, D), ast.filter.And(A, B, Rest()), matcher._parse_filter_expression, )) # remainder matches the empty set self.assertTrue(_set_matcher( ast.filter.And(A, B), ast.filter.And(A, B, Rest()), matcher._parse_filter_expression, )) # Rest does not absolve other refernce items from having a match self.assertFalse(_set_matcher( ast.filter.And(A, C, D), ast.filter.And(A, B, Rest()), matcher._parse_filter_expression, )) # Rest can be combined with Any ... self.assertTrue(_set_matcher( ast.filter.And(A, C, D), ast.filter.And(A, Any(), Rest()), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, C, D), ast.filter.And(A, Any(), Rest()), matcher._parse_filter_expression, )) # ... explicit items still need to match self.assertFalse(_set_matcher( ast.filter.And(A, C, D), ast.filter.And(B, Any(), Rest()), matcher._parse_filter_expression, )) # ... Any still determines minimum element count self.assertTrue(_set_matcher( ast.filter.And(A, B), ast.filter.And(A, Any(), Rest()), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B), ast.filter.And(A, Any(), Any(), Rest()), matcher._parse_filter_expression, )) # Rest cannot be repeated ... self.assertRaises(errors.BackendError, _set_matcher, ast.filter.And(A, B, C), ast.filter.And(A, Rest(), Rest(ast.filter.Equals('hello'))), matcher._parse_filter_expression, ) # ... unless they are identical self.assertRaises(errors.BackendError, _set_matcher, ast.filter.And(A, B, C), ast.filter.And(A, Rest(), Rest()), # Any instances are different! matcher._parse_filter_expression, ) # ... unless they are identical self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest(C), Rest(C)), matcher._parse_filter_expression, )) # Rest can mandate a specific expression self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest(C)), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest(D)), matcher._parse_filter_expression, )) # Rest can mandate a partial expression self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest(Partial(ast.filter.Equals))), matcher._parse_filter_expression, )) self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, Rest(Partial(ast.filter.Equals))), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest(Partial(ast.filter.Substring))), matcher._parse_filter_expression, )) self.assertFalse(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(A, B, Rest(Partial(ast.filter.Equals, value='D'))), matcher._parse_filter_expression, )) # Rest can be the only expression self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Rest(Partial(ast.filter.Equals))), matcher._parse_filter_expression, )) # Rest's expression defaults to Any self.assertTrue(_set_matcher( ast.filter.And(A, B, C), ast.filter.And(Rest()), matcher._parse_filter_expression, )) class TestFilter(unittest.TestCase): def setUp(self): self.match = Filter() def test_call(self): # query must be a filter expression self.assertRaises(errors.BackendError, self.match, 1234, Any()) self.assertRaises(errors.BackendError, self.match, ast.filter.Predicate(ns.bse.filename), Any()) # reference must be a filter expression self.assertRaises(errors.BackendError, self.match, ast.filter.Equals('hello'), 1234) self.assertRaises(errors.BackendError, self.match, ast.filter.Equals('hello'), ast.filter.Predicate(ns.bse.filename)) # reference can be Any or Partial self.assertTrue(self.match( ast.filter.Equals('hello'), Any(), )) self.assertTrue(self.match( ast.filter.Equals('hello'), Partial(ast.filter.Equals), )) # call parses expression self.assertTrue(self.match( # query ast.filter.And( ast.filter.Any(ns.bse.tag, ast.filter.All(ns.bse.label, ast.filter.Or( ast.filter.Equals('hello'), ast.filter.Equals('world'), ast.filter.StartsWith('foo'), ast.filter.EndsWith('bar'), ) ) ), ast.filter.Any(ns.bse.iso, ast.filter.And( ast.filter.GreaterThan(100, strict=True), ast.filter.LessThan(200, strict=False), ) ), ast.filter.Any(ast.filter.OneOf(ns.bse.featureA, ns.bse.featureB), ast.filter.Distance([1,2,3], 1) ), ), # reference ast.filter.And( ast.filter.Any(Any(), ast.filter.All(Partial(ast.filter.Predicate, reverse=False), ast.filter.Or( Partial(ast.filter.StartsWith), ast.filter.EndsWith('bar'), Rest(Partial(ast.filter.Equals)), ) ) ), ast.filter.Any(ns.bse.iso, ast.filter.And( Partial(ast.filter.GreaterThan, strict=True), Any(), Rest(), ) ), ast.filter.Any(ast.filter.OneOf(Rest()), Partial(ast.filter.Distance) ), ), )) self.assertFalse(self.match( # query ast.filter.Any(ns.bse.tag, ast.filter.And( ast.filter.Any(ns.bse.label, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.collection, ast.filter.Is('http://example.com/col#123')), ast.filter.Not(ast.filter.Has(ns.bse.label)), ) ), # reference ast.filter.Any(ns.bse.tag, ast.filter.And( Any(), ast.filter.Any(Partial(ast.filter.Predicate, reverse=True), # reverse mismatch Partial(ast.filter.Is)), ast.filter.Not(ast.filter.Has(Any(), Any())), ) ) )) def test_parse_filter_expression(self): # Any matches every filter expression self.assertTrue(self.match._parse_filter_expression( ast.filter.Not(ast.filter.FilterExpression()), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Has(ns.bse.filename), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Distance([1,2,3], 1.0), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.And(ast.filter.Equals('hello')), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Or(ast.filter.Equals('hello')), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Equals('hello'), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Substring('hello'), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.StartsWith('hello'), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.EndsWith('hello'), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.Is('hello'), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.LessThan(3), Any())) self.assertTrue(self.match._parse_filter_expression( ast.filter.GreaterThan(3), Any())) # Any matches invalid filter expressions self.assertTrue(self.match._parse_filter_expression( ast.filter.FilterExpression(), Any())) # node must be an appropriate filter expression self.assertRaises(errors.BackendError, self.match._parse_filter_expression, ast.filter.FilterExpression(), ast.filter.FilterExpression()) self.assertRaises(errors.BackendError, self.match._parse_filter_expression, 1234, ast.filter.FilterExpression()) def test_parse_predicate_expression(self): # Any matches every predicate expression self.assertTrue(self.match._parse_predicate_expression( ast.filter.Predicate(ns.bse.filename), Any())) self.assertTrue(self.match._parse_predicate_expression( ast.filter.OneOf(ns.bse.filename), Any())) # Any matches invalid predicate expression self.assertTrue(self.match._parse_predicate_expression( ast.filter.FilterExpression(), Any())) # node must be an appropriate predicate expression self.assertRaises(errors.BackendError, self.match._parse_predicate_expression, ast.filter.PredicateExpression(), ast.filter.PredicateExpression()) self.assertRaises(errors.BackendError, self.match._parse_predicate_expression, 1234, ast.filter.PredicateExpression()) def test_predicate(self): # identical expressions match self.assertTrue(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), ast.filter.Predicate(ns.bse.filename, reverse=False), )) # _predicate respects type self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), ast.filter.FilterExpression(), )) # _predicate respects predicate self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), ast.filter.Predicate(ns.bse.filesize, reverse=False), )) # _predicate respects reverse self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), ast.filter.Predicate(ns.bse.filename, reverse=True), )) # Partial requires ast.filter.Predicate self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Equals), )) # predicate and reverse can be specified self.assertTrue(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Predicate, predicate=ns.bse.filename, reverse=False), )) self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Predicate, predicate=ns.bse.filesize, reverse=False), )) self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Predicate, predicate=ns.bse.filename, reverse=True), )) # predicate can remain unspecified self.assertTrue(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Predicate, reverse=False), )) self.assertTrue(self.match._predicate( ast.filter.Predicate(ns.bse.filesize, reverse=False), Partial(ast.filter.Predicate, reverse=False), )) self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filesize, reverse=False), Partial(ast.filter.Predicate, reverse=True), )) # reverse can remain unspecified self.assertTrue(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Predicate, predicate=ns.bse.filename), )) self.assertTrue(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=True), Partial(ast.filter.Predicate, predicate=ns.bse.filename), )) self.assertFalse(self.match._predicate( ast.filter.Predicate(ns.bse.filename, reverse=False), Partial(ast.filter.Predicate, predicate=ns.bse.filesize), )) def test_one_of(self): A = ast.filter.Predicate(ns.bse.filename) B = ast.filter.Predicate(ns.bse.filesize) C = ast.filter.Predicate(ns.bse.filename, reverse=True) # identical expressions match self.assertTrue(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(A, B), )) # _one_of respects type self.assertFalse(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.Predicate(ns.bse.filesize, reverse=True), )) # _one_of respects child expressions self.assertFalse(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(A, C), )) self.assertFalse(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(A), )) self.assertFalse(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(A, B, C), )) self.assertTrue(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(B, A), )) self.assertTrue(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(A, Any()), )) self.assertTrue(self.match._one_of( ast.filter.OneOf(A, B), ast.filter.OneOf(B, Rest()), )) def test_branch(self): # identical expressions match self.assertTrue(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), )) self.assertTrue(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), )) # _agg respects type self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Equals('hello'), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Equals('hello'), )) # _agg respects predicate expression self.assertTrue(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ast.filter.Predicate(ns.bse.filename), ast.filter.Equals('hello')), )) self.assertTrue(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ast.filter.Predicate(ns.bse.filename), ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filesize, ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filesize, ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ast.filter.OneOf(ns.bse.filename), ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ast.filter.OneOf(ns.bse.filename), ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ast.filter.Predicate(ns.bse.filename, reverse=True), ast.filter.Equals('hello')), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ast.filter.Predicate(ns.bse.filename, reverse=True), ast.filter.Equals('hello')), )) self.assertTrue(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(Any(), ast.filter.Equals('hello')), )) self.assertTrue(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(Any(), ast.filter.Equals('hello')), )) self.assertTrue(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(Partial(ast.filter.Predicate), ast.filter.Equals('hello')), )) self.assertTrue(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(Partial(ast.filter.Predicate), ast.filter.Equals('hello')), )) # _agg respects filter expression self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, ast.filter.Substring('hello')), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, ast.filter.Substring('hello')), )) self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, ast.filter.Any(Any(), Any())), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, ast.filter.All(Any(), Any())), )) self.assertTrue(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, Any()), )) self.assertTrue(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, Any()), )) self.assertTrue(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, Partial(ast.filter.Equals)), )) self.assertTrue(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, Partial(ast.filter.Equals)), )) self.assertFalse(self.match._branch( ast.filter.Any(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.Any(ns.bse.filename, Partial(ast.filter.Equals, value='world')), )) self.assertFalse(self.match._branch( ast.filter.All(ns.bse.filename, ast.filter.Equals('hello')), ast.filter.All(ns.bse.filename, Partial(ast.filter.Equals, value='world')), )) def test_agg(self): A = ast.filter.Equals('hello') B = ast.filter.Equals('world') C = ast.filter.Equals('foobar') # identical expressions match self.assertTrue(self.match._agg( ast.filter.And(A, B), ast.filter.And(A, B), )) self.assertTrue(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(A, B), )) # _agg respects type self.assertFalse(self.match._agg( ast.filter.And(A, B), ast.filter.Or(A, B), )) self.assertFalse(self.match._agg( ast.filter.Or(A, B), ast.filter.And(A, B), )) self.assertFalse(self.match._agg( ast.filter.And(A, B), ast.filter.Equals('hello'), )) self.assertFalse(self.match._agg( ast.filter.Or(A, B), ast.filter.Equals('hello'), )) # _agg respects child expressions self.assertFalse(self.match._agg( ast.filter.And(A, B), ast.filter.And(A, ast.filter.Equals('bar')), )) self.assertFalse(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(A, ast.filter.Equals('bar')), )) self.assertFalse(self.match._agg( ast.filter.And(A, B), ast.filter.And(A), )) self.assertFalse(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(A), )) self.assertFalse(self.match._agg( ast.filter.And(A, B), ast.filter.And(A, B, C), )) self.assertFalse(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(A, B, C), )) self.assertTrue(self.match._agg( ast.filter.And(A, B), ast.filter.And(B, A), )) self.assertTrue(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(B, A), )) self.assertTrue(self.match._agg( ast.filter.And(A, B), ast.filter.And(A, Any()), )) self.assertTrue(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(A, Any()), )) self.assertTrue(self.match._agg( ast.filter.And(A, B), ast.filter.And(B, Rest()), )) self.assertTrue(self.match._agg( ast.filter.Or(A, B), ast.filter.Or(B, Rest()), )) def test_not(self): # identical expressions match self.assertTrue(self.match._not( ast.filter.Not(ast.filter.Equals('hello')), ast.filter.Not(ast.filter.Equals('hello')), )) # _not respects type self.assertFalse(self.match._not( ast.filter.Not(ast.filter.Equals('hello')), ast.filter.Equals('hello'), )) # _not respects child expression self.assertFalse(self.match._not( ast.filter.Not(ast.filter.Equals('hello')), ast.filter.Not(ast.filter.Equals('world')), )) self.assertFalse(self.match._not( ast.filter.Not(ast.filter.Equals('hello')), ast.filter.Not(ast.filter.Substring('hello')), )) self.assertTrue(self.match._not( ast.filter.Not(ast.filter.Equals('hello')), ast.filter.Not(Any()), )) def test_has(self): # identical expressions match self.assertTrue(self.match._has( ast.filter.Has(ns.bse.filesize), ast.filter.Has(ns.bse.filesize), )) self.assertTrue(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), )) # _has respects type self.assertFalse(self.match._has( ast.filter.Has(ns.bse.filesize), ast.filter.Equals('hello'), )) self.assertFalse(self.match._has( ast.filter.Has(ns.bse.filesize), ast.filter.Equals('hello'), )) # _has respects predicate self.assertFalse(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(ns.bse.iso, ast.filter.LessThan(3)), )) self.assertTrue(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(Any(), ast.filter.LessThan(3)), )) self.assertTrue(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(Partial(ast.filter.Predicate), ast.filter.LessThan(3)), )) # _has respects count self.assertFalse(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(ns.bse.filesize, ast.filter.GreaterThan(3)), )) self.assertFalse(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(5)), )) self.assertTrue(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(ns.bse.filesize, Any()), )) self.assertTrue(self.match._has( ast.filter.Has(ns.bse.filesize, ast.filter.LessThan(3)), ast.filter.Has(ns.bse.filesize, Partial(ast.filter.LessThan)), )) def test_distance(self): # identical expressions match self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), ast.filter.Distance([1,2,3], 5, True), )) # _distance respects type self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), ast.filter.Equals('hello'), )) self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Equals), )) # _distance respects reference value self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), ast.filter.Distance([3,2,1], 5, True), )) self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, threshold=5, strict=True), )) self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], threshold=5, strict=True), )) self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[3,2,1], threshold=5, strict=True), )) # _distance respects threshold self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), ast.filter.Distance([1,2,3], 8, True), )) self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], strict=True), )) self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], threshold=5, strict=True), )) self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], threshold=8, strict=True), )) # _distance respects strict self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), ast.filter.Distance([1,2,3], 5, False), )) self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], threshold=5), )) self.assertTrue(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], threshold=5, strict=True), )) self.assertFalse(self.match._distance( ast.filter.Distance([1,2,3], 5, True), Partial(ast.filter.Distance, reference=[1,2,3], threshold=5, strict=False), )) def test_value(self): # identical expressions match self.assertTrue(self.match._value(ast.filter.Equals('hello'), ast.filter.Equals('hello'))) self.assertTrue(self.match._value(ast.filter.Substring('hello'), ast.filter.Substring('hello'))) self.assertTrue(self.match._value(ast.filter.StartsWith('hello'), ast.filter.StartsWith('hello'))) self.assertTrue(self.match._value(ast.filter.EndsWith('hello'), ast.filter.EndsWith('hello'))) self.assertTrue(self.match._value(ast.filter.Is('hello'), ast.filter.Is('hello'))) # _value respects type self.assertFalse(self.match._value(ast.filter.Equals('hello'), ast.filter.Is('hello'))) self.assertFalse(self.match._value(ast.filter.Substring('hello'), ast.filter.Is('hello'))) self.assertFalse(self.match._value(ast.filter.StartsWith('hello'), ast.filter.Is('hello'))) self.assertFalse(self.match._value(ast.filter.EndsWith('hello'), ast.filter.Is('hello'))) self.assertFalse(self.match._value(ast.filter.Is('hello'), ast.filter.Equals('hello'))) # _value respects value self.assertFalse(self.match._value(ast.filter.Equals('hello'), ast.filter.Equals('world'))) self.assertFalse(self.match._value(ast.filter.Substring('hello'), ast.filter.Substring('world'))) self.assertFalse(self.match._value(ast.filter.StartsWith('hello'), ast.filter.StartsWith('world'))) self.assertFalse(self.match._value(ast.filter.EndsWith('hello'), ast.filter.EndsWith('world'))) self.assertFalse(self.match._value(ast.filter.Is('hello'), ast.filter.Is('world'))) # Partial requires correct type self.assertFalse(self.match._value(ast.filter.Equals('hello'), Partial(ast.filter.Is))) self.assertFalse(self.match._value(ast.filter.Substring('hello'), Partial(ast.filter.Is))) self.assertFalse(self.match._value(ast.filter.StartsWith('hello'), Partial(ast.filter.Is))) self.assertFalse(self.match._value(ast.filter.EndsWith('hello'), Partial(ast.filter.Is))) self.assertFalse(self.match._value(ast.filter.Is('hello'), Partial(ast.filter.Equals))) # value can be specified self.assertTrue(self.match._value(ast.filter.Equals('hello'), Partial(ast.filter.Equals, value='hello'))) self.assertFalse(self.match._value(ast.filter.Equals('hello'), Partial(ast.filter.Equals, value='world'))) self.assertTrue(self.match._value(ast.filter.Substring('hello'), Partial(ast.filter.Substring, value='hello'))) self.assertFalse(self.match._value(ast.filter.Substring('hello'), Partial(ast.filter.Substring, value='world'))) self.assertTrue(self.match._value(ast.filter.StartsWith('hello'), Partial(ast.filter.StartsWith, value='hello'))) self.assertFalse(self.match._value(ast.filter.StartsWith('hello'), Partial(ast.filter.StartsWith, value='world'))) self.assertTrue(self.match._value(ast.filter.EndsWith('hello'), Partial(ast.filter.EndsWith, value='hello'))) self.assertFalse(self.match._value(ast.filter.EndsWith('hello'), Partial(ast.filter.EndsWith, value='world'))) self.assertTrue(self.match._value(ast.filter.Is('hello'), Partial(ast.filter.Is, value='hello'))) self.assertFalse(self.match._value(ast.filter.Is('hello'), Partial(ast.filter.Is, value='world'))) # value can remain unspecified self.assertTrue(self.match._value(ast.filter.Equals('hello'), Partial(ast.filter.Equals))) self.assertTrue(self.match._value(ast.filter.Substring('hello'), Partial(ast.filter.Substring))) self.assertTrue(self.match._value(ast.filter.StartsWith('hello'), Partial(ast.filter.StartsWith))) self.assertTrue(self.match._value(ast.filter.EndsWith('hello'), Partial(ast.filter.EndsWith))) self.assertTrue(self.match._value(ast.filter.Is('hello'), Partial(ast.filter.Is))) def test_bounded(self): # identical expressions match self.assertTrue(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), ast.filter.LessThan(threshold=3, strict=False), )) self.assertTrue(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), ast.filter.GreaterThan(threshold=3, strict=False), )) # _bounded respects type self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), ast.filter.GreaterThan(threshold=3, strict=False), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), ast.filter.LessThan(threshold=3, strict=False), )) # _bounded respects threshold self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), ast.filter.LessThan(threshold=4, strict=False), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), ast.filter.GreaterThan(threshold=4, strict=False), )) # _bounded respects strict self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), ast.filter.LessThan(threshold=3, strict=True), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), ast.filter.GreaterThan(threshold=3, strict=True), )) # Partial requires correct type self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.LessThan), )) # threshold and strict can be specified self.assertTrue(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=3, strict=False), )) self.assertTrue(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, threshold=3, strict=False), )) self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=4, strict=False), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, threshold=4, strict=False), )) self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=3, strict=True), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, threshold=3, strict=True), )) # threshold can remain unspecified self.assertTrue(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, strict=False), )) self.assertTrue(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, strict=False), )) self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, strict=True), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, strict=True), )) # strict can remain unspecified self.assertTrue(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=3), )) self.assertTrue(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, threshold=3), )) self.assertFalse(self.match._bounded( ast.filter.LessThan(threshold=3, strict=False), Partial(ast.filter.LessThan, threshold=4), )) self.assertFalse(self.match._bounded( ast.filter.GreaterThan(threshold=3, strict=False), Partial(ast.filter.GreaterThan, threshold=4), )) ## main ## if __name__ == '__main__': unittest.main() ## EOF ##