def testEscaping(self): parser = objectfilter.Parser(r"a is '\n'").Parse() self.assertEqual(parser.args[0], "\n") # Invalid escape sequence parser = objectfilter.Parser(r"a is '\z'") self.assertRaises(objectfilter.ParseError, parser.Parse) # Can escape the backslash parser = objectfilter.Parser(r"a is '\\'").Parse() self.assertEqual(parser.args[0], "\\") ## HEX ESCAPING # This fails as it's not really a hex escaped string parser = objectfilter.Parser(r"a is '\xJZ'") self.assertRaises(objectfilter.ParseError, parser.Parse) # Instead, this is what one should write parser = objectfilter.Parser(r"a is '\\xJZ'").Parse() self.assertEqual(parser.args[0], r"\xJZ") # Standard hex-escape parser = objectfilter.Parser(r"a is '\x41\x41\x41'").Parse() self.assertEqual(parser.args[0], "AAA") # Hex-escape + a character parser = objectfilter.Parser(r"a is '\x414'").Parse() self.assertEqual(parser.args[0], r"A4") # How to include r'\x41' parser = objectfilter.Parser(r"a is '\\x41'").Parse() self.assertEqual(parser.args[0], r"\x41")
def testCompile(self): obj = DummyObject("something", "Blue") query = "something == 'Blue'" self.assertObjectMatches(obj, query) query = "something == 'Red'" self.assertObjectMatches(obj, query, match_is=False) query = "something == \"Red\"" self.assertObjectMatches(obj, query, match_is=False) obj = DummyObject("size", 4) parser = objectfilter.Parser("size < 3").Parse() filter_ = parser.Compile(self.filter_imp) self.assertEqual(filter_.Matches(obj), False) parser = objectfilter.Parser("size == 4").Parse() filter_ = parser.Compile(self.filter_imp) self.assertEqual(filter_.Matches(obj), True) query = "something is 'Blue' and size notcontains 3" self.assertObjectMatches(obj, query, match_is=False) query = """ @imported_dlls ( name is 'a.dll' AND imported_functions contains 'CreateFileA' ) AND name is "yay.exe" AND size is 10 """ self.assertObjectMatches(self.file, query) query = """ @imported_dlls ( name is 'a.dll' AND imported_functions contains 'CreateFileB' ) AND name is "yay.exe" AND size is 10 """ self.assertObjectMatches(self.file, query, match_is=False) obj = DummyObject("list", [1, 2]) self.assertObjectMatches(obj, "list is [1,2]") self.assertObjectMatches(obj, "list is [5,6]", match_is=False) self.assertObjectMatches(obj, "list isnot [1,3]") self.assertObjectMatches(obj, "list inset [1,2,3]") obj = DummyObject("list", []) self.assertObjectMatches(obj, "list is []") self.assertObjectMatches(obj, "list inset []") # An empty set [] is a subset of any set. Hence this is False. self.assertObjectMatches(obj, "list notinset [2]", match_is=False) obj = DummyObject("single_element", 1) self.assertObjectMatches(obj, "single_element inset [1,2,3]") # 1 != [1] self.assertObjectMatches(obj, "single_element isnot [1]") obj = DummyObject("os", "windows") self.assertObjectMatches(obj, 'os inset ["windows", "mac"]') # "a" != ["a"] self.assertObjectMatches(obj, 'os isnot ["windows"]')
def testParse(self): # We need to complete a basic expression self.assertParseRaises(" ") self.assertParseRaises("attribute") self.assertParseRaises("attribute is") # We have to go from an expression to the ANDOR state self.assertParseRaises("attribute is 3 really") self.assertParseRaises("attribute is 3 AND") self.assertParseRaises("attribute is 3 AND bla") self.assertParseRaises("attribute is 3 AND bla contains") # Two complete expressions parse fine query = "attribute is 3 AND name contains 'atthew'" self.assertQueryParses(query) # Arguments are either int, float or quoted string self.assertQueryParses("attribute == 1") self.assertQueryParses("attribute == 0x10") self.assertParseRaises("attribute == 1a") self.assertQueryParses("attribute == 1.2") self.assertParseRaises("attribute == 1.2a3") # Scientific notation is not accepted... self.assertParseRaises("attribute == 1e3") # Test both quoted strings self.assertQueryParses("attribute == 'bla'") self.assertQueryParses("attribute == \"bla\"") # Unquoted strings fail self.assertParseRaises("something == red") # Can't start with AND self.assertParseRaises("and something is 'Blue'") # Need to match parentheses self.assertParseRaises("(a is 3") self.assertParseRaises("((a is 3") self.assertParseRaises("((a is 3)") self.assertParseRaises("a is 3)") self.assertParseRaises("a is 3))") self.assertParseRaises("(a is 3))") # Need to put parentheses in the right place self.assertParseRaises("()a is 3") self.assertParseRaises("(a) is 3") self.assertParseRaises("(a is) 3") self.assertParseRaises("a (is) 3") self.assertParseRaises("a is() 3") self.assertParseRaises("a is (3)") self.assertParseRaises("a is 3()") self.assertParseRaises("a (is 3 AND) b is 4 ") # In the right places, parentheses are accepted self.assertQueryParses("(a is 3)") self.assertQueryParses("(a is 3 AND b is 4)") # Context Operator alone is not accepted self.assertParseRaises("@attributes") # Accepted only with braces (not necessary but forced by the grammar # to be explicit) objectfilter.Parser("@attributes( name is 'adrien')").Parse() # Not without them self.assertParseRaises("@attributes name is 'adrien'") # Or in the wrong place self.assertParseRaises("@attributes (name is) 'adrien'") # Can nest context operators query = "@imported_dlls( @imported_function( name is 'OpenFileA'))" self.assertQueryParses(query) # Can nest context operators and mix braces without it messing up query = "@imported_dlls( @imported_function( name is 'OpenFileA'))" self.assertQueryParses(query) query = """ @imported_dlls ( @imported_function ( name is 'OpenFileA' ) ) """ self.assertQueryParses(query) # Mix context and binary operators query = """ @imported_dlls ( @imported_function ( name is 'OpenFileA' ) AND num_functions == 2 ) """ self.assertQueryParses(query) # Also on the right query = """ @imported_dlls ( num_functions == 2 AND @imported_function ( name is 'OpenFileA' ) ) """ query = "b is 3 AND c is 4 AND d is 5" self.assertQueryParses(query) query = "@a(b is 3) AND @b(c is 4)" self.assertQueryParses(query) query = "@a(b is 3) AND @b(c is 4) AND @d(e is 5)" self.assertQueryParses(query) query = "@a(@b(c is 3)) AND @b(d is 4)" self.assertQueryParses(query) query = """ @imported_dlls( @imported_function ( name is 'OpenFileA' ) ) AND @imported_dlls( name regexp '(?i)advapi32.dll' AND @imported_function ( name is 'RegQueryValueEx' ) ) AND @exported_symbols(name is 'inject') """ self.assertQueryParses(query) self.assertQueryParses("a is ['blue', 'dot']") self.assertQueryParses("a is ['blue', 1]") self.assertQueryParses("a is [1]") # This is an empty list self.assertQueryParses("a is []") # While weird, the current parser allows this. Same as an empty list self.assertQueryParses("a is [,,]") # Unifinished expressions shouldn't parse self.assertParseRaises("a is [") self.assertParseRaises("a is [,,") self.assertParseRaises("a is [,']") # Malformed expressions shouldn't parse self.assertParseRaises("a is [[]") self.assertParseRaises("a is []]") # We do not support nested lists at the moment self.assertParseRaises("a is ['cannot', ['nest', 'lists']]")
def assertParseRaises(self, query, exception=objectfilter.ParseError): parser = objectfilter.Parser(query) self.assertRaises(exception, parser.Parse)
def ParseQuery(self, query): return objectfilter.Parser(query).Parse()