def test_engine_builtins(self): builtins = engine.Builtins.from_defaults( {'test': { 'one': 1.0, 'two': 2.0 }}) self.assertIsInstance(builtins, engine.Builtins) self.assertIsNone(builtins.namespace) self.assertRegex( repr(builtins), r'<Builtins namespace=None keys=\(\'\S+\'(, \'\S+\')*\)') self.assertIn('test', builtins) test_builtins = builtins['test'] self.assertIsInstance(test_builtins, engine.Builtins) self.assertEqual(test_builtins.namespace, 'test') self.assertIn('today', builtins) today = builtins['today'] self.assertIsInstance(today, datetime.date) # test that builtins have correct type hints builtins = engine.Builtins.from_defaults( {'name': 'Alice'}, value_types={'name': ast.DataType.STRING}) self.assertEqual(builtins.resolve_type('name'), ast.DataType.STRING) self.assertEqual(builtins.resolve_type('missing'), ast.DataType.UNDEFINED) context = engine.Context() context.builtins = builtins engine.Rule('$name =~ ""') with self.assertRaises(errors.EvaluationError): engine.Rule('$name + 1', context=context)
def test_engine_resolve_item_with_defaults(self): thing = {'name': 'Alice'} context = engine.Context(resolver=engine.resolve_item, default_value=None) self.assertEqual(engine.Rule('name', context=context).evaluate(thing), thing['name']) self.assertIsNone(engine.Rule('name.first', context=context).evaluate(thing)) self.assertIsNone(engine.Rule('address', context=context).evaluate(thing)) self.assertIsNone(engine.Rule('address.city', context=context).evaluate(thing))
def test_engine_resolve_attribute_with_defaults(self): thing = collections.namedtuple('Person', ('name',))(name='alice') context = engine.Context(resolver=engine.resolve_attribute, default_value=None) self.assertEqual(engine.Rule('name', context=context).evaluate(thing), thing.name) self.assertIsNone(engine.Rule('name.first', context=context).evaluate(thing)) self.assertIsNone(engine.Rule('address', context=context).evaluate(thing)) self.assertIsNone(engine.Rule('address.city', context=context).evaluate(thing))
def test_number_10(self): value = random.randint(1, 10000) thing = { 'c': { 'c1': value, } } rule_text = 'c.c1 == ' + str(value) rule1 = engine.Rule(rule_text, context=engine.Context()) rule2 = engine.Rule(rule_text, context=engine.Context(default_value=None)) self.assertEqual(rule1.evaluate(thing), rule2.evaluate(thing))
def test_engine_rule_filter(self, rule=None): rule = rule or engine.Rule(self.rule_text) result = rule.filter([self.true_item, self.false_item]) self.assertIsInstance(result, types.GeneratorType) result = tuple(result) self.assertIn(self.true_item, result) self.assertNotIn(self.false_item, result)
def test_tls_for_comprehension(self): context = engine.Context() rule = engine.Rule('[word for word in words][0]', context=context) rule.evaluate({'words': ('MainThread', 'Test')}) # this isn't exactly a thread test since the assignment scope should be cleared after the comprehension is # complete self.assertEqual(len(context._tls.assignment_scopes), 0)
def test_tls_for_regex1(self): context = engine.Context() rule = engine.Rule('words =~ "(\w+) \w+"', context=context) rule.evaluate({'words': 'MainThread Test'}) self.assertEqual(context._tls.regex_groups, ('MainThread', )) RuleThread(rule, {'words': 'AlternateThread Test'}).join() self.assertEqual(context._tls.regex_groups, ('MainThread', ))
def test_engine_builtins_re_groups(self): context = engine.Context() rule = engine.Rule( 'words =~ "(\\w+) (\\w+) (\\w+)" and $re_groups[0] == word0', context=context) self.assertIsNone(context._tls.regex_groups) words = (''.join( random.choice(string.ascii_letters) for _ in range(random.randint(4, 12))), ''.join( random.choice(string.ascii_letters) for _ in range(random.randint(4, 12))), ''.join( random.choice(string.ascii_letters) for _ in range(random.randint(4, 12)))) self.assertTrue( rule.matches({ 'words': ' '.join(words), 'word0': words[0] })) self.assertEqual(context._tls.regex_groups, words) self.assertFalse( rule.matches({ 'words': ''.join(words), 'word0': words[0] })) self.assertIsNone(context._tls.regex_groups)
def test_engine_rule_matches(self, rule=None): rule = rule or engine.Rule(self.rule_text) result = rule.matches(self.true_item) self.assertIsInstance(result, bool) self.assertTrue(result) result = rule.matches(self.false_item) self.assertIsInstance(result, bool) self.assertFalse(result)
def test_number_19(self): context = engine.Context(type_resolver=engine.type_resolver_from_dict({ 'facts': ast.DataType.MAPPING(key_type=ast.DataType.STRING, value_type=ast.DataType.STRING) })) rule = engine.Rule('facts.abc == "def"', context=context) self.assertTrue(rule.matches({'facts': {'abc': 'def'}}))
def test_number_14(self): context = engine.Context(type_resolver=engine.type_resolver_from_dict({ 'TEST_FLOAT': ast.DataType.FLOAT, })) rule = engine.Rule('(TEST_FLOAT == null ? 0 : TEST_FLOAT) < 42', context=context) rule.matches({'TEST_FLOAT': None})
def test_tls_for_regex2(self): lock = threading.RLock() context = engine.Context( resolver=functools.partial(testing_resolver, lock)) rule = engine.Rule( 'words =~ "(\w+) \w+" and lock and $re_groups[0] == "MainThread"', context=context) self.assertTrue(rule.evaluate({'words': 'MainThread Test'})) lock.release() with lock: thread = RuleThread(rule, {'words': 'AlternateThread Test'}) self.assertTrue(rule.evaluate({'words': 'MainThread Test'})) lock.release() self.assertFalse(thread.join())
def test_engine_rule_evaluate_attributes(self): # ensure that multiple levels can be evaluated as attributes rule = engine.Rule('a.b.c') self.assertTrue(rule.evaluate({'a': {'b': {'c': True}}})) value = rule.evaluate({'a': {'b': {'c': 1}}}) self.assertIsInstance(value, float) self.assertEqual(value, 1.0) value = rule.evaluate({'a': {'b': {'c': {'d': None}}}}) self.assertIsInstance(value, dict) self.assertIn('d', value) with self.assertRaises(errors.AttributeResolutionError): rule.evaluate({'a': {}})
def test_engine_rule_to_graphviz_3(self): rule = engine.Rule('[member for member in iterable if member]') digraph = rule.to_graphviz() self.assertIsInstance(digraph, graphviz.Digraph)
def test_engine_rule_raises(self): with self.assertRaises(errors.RuleSyntaxError): engine.Rule('test ==')
def test_number_20(self): rule = engine.Rule('a / b ** 2') self.assertEqual(rule.evaluate({'a': 8, 'b': 4}), 0.5)
def test_engine_rule_to_graphviz_1(self): rule = engine.Rule(self.rule_text) digraph = rule.to_graphviz() self.assertIsInstance(digraph, graphviz.Digraph) self.assertEqual(digraph.comment, self.rule_text)
def test_engine_rule_evaluate(self): rule = engine.Rule('"string"') self.assertEqual(rule.evaluate(None), 'string')
def test_engine_rule_to_graphviz_2(self): rule = engine.Rule( 'null in [foo.length % [2, 4, 6][boz] ? (bar > baz) : (bar < -baz)]' ) digraph = rule.to_graphviz() self.assertIsInstance(digraph, graphviz.Digraph)
def test_engine_rule_to_strings(self): rule = engine.Rule(self.rule_text) self.assertEqual(str(rule), self.rule_text) self.assertRegex( repr(rule), "<Rule text='{0}' >".format(re.escape(self.rule_text)))