def testInfix(self): self.assertQueryMatches( "x == 'foo' and y.z contains 'bar'", ast.Intersection( ast.Equivalence(ast.Var("x"), ast.Literal("foo")), ast.Membership(ast.Literal("bar"), ast.Resolve(ast.Var("y"), ast.Literal("z")))))
def testMembership(self): # Support tuples (lists): self.assertTrue( solve.solve(q.Query("x in [1, 2, 3, 4]"), { "x": 2 }).value) self.assertFalse(solve.solve(q.Query("5 in [1, 2, 3, 4]"), {}).value) # Support tuples of strings: self.assertTrue( solve.solve(q.Query("'foo' in ['bar', 'foo']"), {}).value) self.assertTrue( solve.solve(q.Query("'baz' not in ['bar', 'foo']"), {}).value) # Repeated values: self.assertTrue( solve.solve(q.Query("'foo' in ('bar', 'foo')"), {}).value) # Strings can be in strings: self.assertTrue(solve.solve(q.Query("'foo' in 'foobar'"), {}).value) self.assertTrue(solve.solve(q.Query("'foo' in ('foobar')"), {}).value) self.assertTrue( solve.solve(q.Query("'baz' not in 'foobar'"), {}).value) # This should behave as expected - a singleton string is distinct from a # string if in a list, but not in a repeated value. self.assertTrue(solve.solve(q.Query("'foo' in ['foobar']"), {}).value) # All this should be true for vars as well as literals: self.assertTrue( solve.solve(q.Query("'foo' in [x]"), { "x": "foobar" }).value) self.assertTrue( solve.solve(q.Query("'foo' in x"), { "x": "foobar" }).value) self.assertTrue( solve.solve(q.Query("'foo' in (x)"), { "x": "foobar" }).value) # Make sure this is all working for unicode strings as well. self.assertTrue( solve.solve(q.Query("'foo' in (x)"), { "x": u"foobar" }).value) self.assertTrue( solve.solve( q.Query( ast.Membership(ast.Literal(u"foo"), ast.Literal(u"foobar"))), {}).value) # Repeated values behave correctly. self.assertTrue( solve.solve(q.Query("'foo' in x"), { "x": repeated.meld("foo", "bar") }).value) self.assertTrue( solve.solve(q.Query("'foo' in x"), { "x": repeated.meld("foobar", "bar") }).value) # Membership operator on a repeated string is equivalent to # the substring of each member. self.assertTrue( solve.solve(q.Query("'foo' in ('foobar', 'bar')"), {}).value) self.assertTrue(solve.solve(q.Query("'foo' in ('foobar')"), {}).value) # Single characters should behave correctly. self.assertTrue(solve.solve(q.Query("'f' in 'foo'"), {}).value)
def testMultiWordOperators(self): self.assertQueryMatches( "x not in y", ast.Complement(ast.Membership(ast.Var("x"), ast.Var("y"))))
def testLists(self): self.assertQueryMatches( "x inset [1, 2, 3]", ast.Membership( ast.Var("x"), ast.Tuple(ast.Literal(1), ast.Literal(2), ast.Literal(3))))
def testMembership(self): # Support tuples (lists): self.assertTrue( solve.solve(q.Query("x in [1, 2, 3, 4]"), { "x": 2 }).value) self.assertFalse(solve.solve(q.Query("5 in [1, 2, 3, 4]"), {}).value) # Support tuples of strings: self.assertTrue( solve.solve(q.Query("'foo' in ['bar', 'foo']"), {}).value) self.assertTrue( solve.solve(q.Query("'baz' not in ['bar', 'foo']"), {}).value) # Repeated values: self.assertTrue( solve.solve(q.Query("'foo' in ('bar', 'foo')"), {}).value) # Strings can be in strings: self.assertTrue(solve.solve(q.Query("'foo' in 'foobar'"), {}).value) self.assertTrue(solve.solve(q.Query("'foo' in ('foobar')"), {}).value) self.assertTrue( solve.solve(q.Query("'baz' not in 'foobar'"), {}).value) # This should behave as expected - a singleton string is distinct from a # string if in a list, but not in a repeated value. self.assertTrue( solve.solve(q.Query("'foo' not in ['foobar']"), {}).value) # All this should be true for vars as well as literals: self.assertTrue( solve.solve(q.Query("'foo' not in [x]"), { "x": "foobar" }).value) self.assertTrue( solve.solve(q.Query("'foo' in x"), { "x": "foobar" }).value) self.assertTrue( solve.solve(q.Query("'foo' in (x)"), { "x": "foobar" }).value) # Make sure this is all working for unicode strings as well. self.assertTrue( solve.solve(q.Query("'foo' in (x)"), { "x": u"foobar" }).value) self.assertTrue( solve.solve( q.Query( ast.Membership(ast.Literal(u"foo"), ast.Literal(u"foobar"))), {}).value) # Repeated values behave correctly. self.assertTrue( solve.solve(q.Query("'foo' in x"), { "x": repeated.meld("foo", "bar") }).value) self.assertTrue( solve.solve(q.Query("'foo' not in x"), { "x": repeated.meld("foobar", "bar") }).value) # This is where it gets tricky: a repeated value of a single value is # equal to the single value - this is how EFILTER is supposed to work. # In this case it may be unexpected, but them's the breaks. self.assertTrue( solve.solve(q.Query("'foo' not in ('foobar', 'bar')"), {}).value) self.assertTrue(solve.solve(q.Query("'foo' in ('foobar')"), {}).value) # Single characters should behave correctly. self.assertTrue(solve.solve(q.Query("'f' in 'foo'"), {}).value)
def ReverseComplementMembership(x, y, **kwargs): """Change (x doesn't contain y) to not(y in x).""" return ast.Complement( ast.Membership(y, x, **kwargs), **kwargs)
def ReverseMembership(x, y, **kwargs): """Change (x contains y) to y in x.""" return ast.Membership(y, x, **kwargs)
def ComplementMembership(*args, **kwargs): """Change (x not in y) to not(x in y).""" return ast.Complement( ast.Membership(*args, **kwargs), **kwargs)