def test_constructor_with_variables(self): """The order must not change when the parameters are variables.""" l_op = PedestriansCrossingRoad() r_op = DriversAwaitingGreenLightVar() operation = LessThan(l_op, r_op) eq_(l_op, operation.master_operand) eq_(r_op, operation.slave_operand)
def test_constructor_with_constant_before_variable(self): """ The order *must* change when the first parameter is a constant and the second is a variable. """ l_op = Number(2) r_op = PedestriansCrossingRoad() operation = GreaterThan(l_op, r_op) eq_(r_op, operation.master_operand) eq_(l_op, operation.slave_operand)
def test_constructor_with_variable_before_constant(self): """ The order must not change when the first parameter is a variable and the second is a constant. """ l_op = PedestriansCrossingRoad() r_op = Number(2) operation = LessThan(l_op, r_op) eq_(l_op, operation.master_operand) eq_(r_op, operation.slave_operand)
def test_mixed_evaluation(self): operation = NotEqual(PedestriansCrossingRoad(), Set(String("gustavo"), String("carla"))) # Other people: context = {'pedestrians_crossroad': ("liliana", "carlos")} ok_(operation(context)) # The same people: context = {'pedestrians_crossroad': ("gustavo", "carla")} assert_false(operation(context))
def test_equivalent(self): """Two conjunctions are equivalent if they have the same operands.""" op1 = And(BoolVar(), PedestriansCrossingRoad()) op2 = And(PedestriansCrossingRoad(), BoolVar()) op3 = And(DriversAwaitingGreenLightVar(), BoolVar()) op1.check_equivalence(op2) op2.check_equivalence(op1) assert_raises(AssertionError, op1.check_equivalence, op3) assert_raises(AssertionError, op2.check_equivalence, op3) assert_raises(AssertionError, op3.check_equivalence, op1) assert_raises(AssertionError, op3.check_equivalence, op2) ok_(op1 == op2) ok_(op2 == op1) ok_(op1 != op3) ok_(op2 != op3) ok_(op3 != op1) ok_(op3 != op2)
def test_adding_grammar(self): """It should be possible to add grammars after instantiation.""" castilian_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar()) mgr.add_parser("es", castilian_grammar) parse_tree = mgr.parse(u'tráfico:peatones_cruzando_calle <= 3,00', "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3.0))) eq_(parse_tree, expected_tree)
def test_parsing_with_localized_grammars(self): castilian_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar(), es=castilian_grammar) parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3,00", "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3.0))) eq_(parse_tree, expected_tree)
def test_mixed_arguments(self): l_op = PedestriansCrossingRoad() r_op = Number(2) operation = GreaterEqual(l_op, r_op) # |{"carla", "yolmary", "manuel"}| > 2 <=> 3 > 2 context = {'pedestrians_crossroad': ("carla", "yolmary", "manuel")} ok_(operation(context)) # |{"carla"}| > 2 <=> 1 > 2 context = {'pedestrians_crossroad': ("carla", )} assert_false(operation(context))
def test_mixed_arguments(self): l_op = PedestriansCrossingRoad() r_op = Number(2) operation = LessEqual(l_op, r_op) # |{"carla"}| < 2 <=> 1 < 2 context = {'pedestrians_crossroad': ("carla", )} ok_(operation(context)) # |{"carla", "carlos", "liliana"}| < 2 <=> 1 < 2 context = {'pedestrians_crossroad': ("carla", "carlos", "liliana")} assert_false(operation(context))
def test_operation(self): """Operations are valid evaluable parse trees.""" operation = And(PedestriansCrossingRoad(), DriversAwaitingGreenLightVar()) tree = EvaluableParseTree(operation) # True context = { 'pedestrians_crossroad': ("gustavo", "carla"), 'drivers_trafficlight': ("andreina", "juan") } ok_(tree(context)) # False context = {'pedestrians_crossroad': (), 'drivers_traffic_light': ()} assert_false(tree(context))
def test_variable_evaluation(self): item = NumVar() set_ = PedestriansCrossingRoad() operation = BelongsTo(item, set_) # 4 ∈ {"madrid", 4} context = {'num': 4, 'pedestrians_crossroad': ("madrid", 4)} ok_(operation(context)) # 4 ∈ {"madrid", "paris", "london"} context = { 'num': 4, 'pedestrians_crossroad': ("madrid", "paris", "london") } assert_false(operation(context))
def test_two_variables(self): l_op = PedestriansCrossingRoad() r_op = NumVar() operation = GreaterEqual(l_op, r_op) # |{"carla", "yolmary"}| > 1 <=> 2 > 1 context = { 'pedestrians_crossroad': ("carla", "yolmary"), 'num': 1, } ok_(operation(context)) # |{"carla", "carlos"}| > 3 <=> 2 > 3 context = { 'pedestrians_crossroad': ("carla", "carlos"), 'num': 3, } assert_false(operation(context))
def test_parsing_with_defined_grammar_but_no_available_translations(self): """ When an expression is written in an supported grammar but there are no translated bindings, the default names must be used along with the custom grammar. """ french_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar(), fr=french_grammar) # French grammar is not supported: parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3,0", "fr") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree)
def test_variable_evaluation(self): subset = DriversAwaitingGreenLightVar() set_ = PedestriansCrossingRoad() operation = IsSubset(subset, set_) # {"carla"} ⊂ {"carla", "andreina"} context = { 'drivers_trafficlight': ("carla", ), 'pedestrians_crossroad': ("andreina", "carla") } ok_(operation(context)) # {"liliana", "carlos"} ⊂ {"manuel", "yolmary", "carla"} context = { 'drivers_trafficlight': ("liliana", "carlos"), 'pedestrians_crossroad': ("manuel", "yolmary", "carla") } assert_false(operation(context))
def test_variables_evaluation(self): operation = NotEqual(PedestriansCrossingRoad(), DriversAwaitingGreenLightVar()) # The pedestrians are different from the drivers... That's my universe! context = { 'pedestrians_crossroad': ("gustavo", "carla"), 'drivers_trafficlight': ("liliana", "carlos") } ok_(operation(context)) # The pedestrians awaiting the green light to cross the street are # the same drivers... Must be a parallel universe! context = { 'pedestrians_crossroad': ("gustavo", "carla"), 'drivers_trafficlight': ("carla", "gustavo") } assert_false(operation(context))
def test_two_variables(self): l_op = PedestriansCrossingRoad() r_op = NumVar() operation = LessEqual(l_op, r_op) # |{"carla"}| < 2 <=> 1 < 2 context = { 'pedestrians_crossroad': ("carla", ), 'num': 2, } ok_(operation(context)) # |{"carla", "carlos"}| < 1 <=> 2 < 1 context = { 'pedestrians_crossroad': ("carla", "carlos"), 'num': 1, } assert_false(operation(context))
def test_parsing_with_undefined_grammar_and_no_translated_bindings(self): """ When an expression is written in an unsupported grammar, a parser based on the generic grammar must be created and used. If there are no translated bindings, the default names must be used. """ log_handler = LoggingHandlerFixture() mgr = EvaluableParseManager(self.symbol_table, Grammar()) # French grammar is not supported: parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3.0", "fr") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) # Checking the log: info = "Generated parser for unknown grammar %s" % repr('fr') ok_(info in log_handler.handler.messages['info']) log_handler.undo()
def test_parsing_with_undefined_grammar_but_available_translations(self): """ When an expression is written in an unsupported grammar, a parser based on the generic grammar must be created and used. The respective translated bindings must be used if available. """ log_handler = LoggingHandlerFixture() mgr = EvaluableParseManager(self.symbol_table, Grammar()) # Castilian grammar is not supported: parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3.0", "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) # Checking the log: info = "Generated parser for unknown grammar %s" % repr(u'es') ok_(info in log_handler.handler.messages['info']) log_handler.undo()
def test_equivalence(self): tree1 = EvaluableParseTree(BoolVar()) tree2 = EvaluableParseTree(BoolVar()) tree3 = EvaluableParseTree(PedestriansCrossingRoad()) tree4 = ConvertibleParseTree(PlaceholderVariable("my_variable")) ok_(tree1 == tree2) ok_(tree2 == tree1) ok_(tree1 != None) ok_(tree1 != tree3) ok_(tree1 != tree4) ok_(tree2 != tree3) ok_(tree2 != tree4) ok_(tree3 != tree1) ok_(tree3 != tree2) ok_(tree3 != tree4) ok_(tree4 != tree1) ok_(tree4 != tree2) ok_(tree4 != tree3)
def test_equivalent(self): """ Two negation operations are equivalent if they evaluate the same operand. """ op1 = Not(BoolVar()) op2 = Not(BoolVar()) op3 = Not(PedestriansCrossingRoad()) op1.check_equivalence(op2) op2.check_equivalence(op1) assert_raises(AssertionError, op1.check_equivalence, op3) assert_raises(AssertionError, op2.check_equivalence, op3) assert_raises(AssertionError, op3.check_equivalence, op1) assert_raises(AssertionError, op3.check_equivalence, op2) ok_(op1 == op2) ok_(op2 == op1) ok_(op1 != op3) ok_(op2 != op3) ok_(op3 != op1) ok_(op3 != op2)
class TestEvaluableParseManager(object): """ Tests for the :class:`EvaluableParseManager` with caching disabled. """ # A symbol table to be used across the tests: symbol_table = SymbolTable( "root", ( Bind("boolean", BoolVar(), es="booleano"), Bind("message", String("Hello world"), es="mensaje"), Bind("foo", PermissiveFunction, es="fulano"), ), SymbolTable("traffic", ( Bind("traffic_light", TrafficLightVar(), es=u"semáforo"), Bind("pedestrians_crossing_road", PedestriansCrossingRoad(), es="peatones_cruzando_calle"), Bind("drivers_awaiting_green", DriversAwaitingGreenLightVar(), es="conductores_esperando_verde"), Bind("traffic_violation", TrafficViolationFunc, es=u"infracción"), ), es=u"tráfico"), ) def test_parsing_with_no_localized_grammars(self): mgr = EvaluableParseManager(self.symbol_table, Grammar()) parse_tree1 = mgr.parse('message == "2009-07-13"') parse_tree2 = mgr.parse('message == "2009-07-13"', None) expected_tree = EvaluableParseTree( Equal(String("Hello world"), String("2009-07-13"))) eq_(parse_tree1, parse_tree2) eq_(parse_tree1, expected_tree) def test_parsing_with_localized_grammars(self): castilian_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar(), es=castilian_grammar) parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3,00", "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3.0))) eq_(parse_tree, expected_tree) def test_parsing_with_undefined_grammar_but_available_translations(self): """ When an expression is written in an unsupported grammar, a parser based on the generic grammar must be created and used. The respective translated bindings must be used if available. """ log_handler = LoggingHandlerFixture() mgr = EvaluableParseManager(self.symbol_table, Grammar()) # Castilian grammar is not supported: parse_tree = mgr.parse(u"tráfico:peatones_cruzando_calle <= 3.0", "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) # Checking the log: info = "Generated parser for unknown grammar %s" % repr(u'es') ok_(info in log_handler.handler.messages['info']) log_handler.undo() def test_parsing_with_undefined_grammar_and_no_translated_bindings(self): """ When an expression is written in an unsupported grammar, a parser based on the generic grammar must be created and used. If there are no translated bindings, the default names must be used. """ log_handler = LoggingHandlerFixture() mgr = EvaluableParseManager(self.symbol_table, Grammar()) # French grammar is not supported: parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3.0", "fr") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) # Checking the log: info = "Generated parser for unknown grammar %s" % repr('fr') ok_(info in log_handler.handler.messages['info']) log_handler.undo() def test_parsing_with_defined_grammar_but_no_available_translations(self): """ When an expression is written in an supported grammar but there are no translated bindings, the default names must be used along with the custom grammar. """ french_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar(), fr=french_grammar) # French grammar is not supported: parse_tree = mgr.parse("traffic:pedestrians_crossing_road <= 3,0", "fr") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3))) eq_(parse_tree, expected_tree) def test_adding_grammar(self): """It should be possible to add grammars after instantiation.""" castilian_grammar = Grammar(decimal_separator=",", thousands_separator=".") mgr = EvaluableParseManager(self.symbol_table, Grammar()) mgr.add_parser("es", castilian_grammar) parse_tree = mgr.parse(u'tráfico:peatones_cruzando_calle <= 3,00', "es") expected_tree = EvaluableParseTree( LessEqual(PedestriansCrossingRoad(), Number(3.0))) eq_(parse_tree, expected_tree) def test_adding_existing_grammar(self): """There can't be duplicate/overlapped parsers.""" mgr = EvaluableParseManager(self.symbol_table, Grammar(), es=Grammar()) assert_raises(GrammarError, mgr.add_parser, "es", Grammar()) def test_evaluating_expressions(self): """Managers should be able to evaluate the expressions too.""" mgr = EvaluableParseManager(self.symbol_table, Grammar()) context = {'pedestrians_crossroad': (u"gustavo", u"carla")} evaluation1 = mgr.evaluate("traffic:pedestrians_crossing_road <= 3", None, context) evaluation2 = mgr.evaluate( u'"carla" ∈ traffic:pedestrians_crossing_road', None, context) evaluation3 = mgr.evaluate("traffic:pedestrians_crossing_road > 2", None, context) ok_(evaluation1) ok_(evaluation2) assert_false(evaluation3)
class TestEvaluableParser(object): """Tests for the evaluable parser.""" global_objects = { 'bool': BoolVar(), 'message': String("Hello world"), 'foo': PermissiveFunction, } traffic_objects = { 'traffic_light': TrafficLightVar(), 'pedestrians_crossing_road': PedestriansCrossingRoad(), 'drivers_awaiting_green_light': DriversAwaitingGreenLightVar(), 'traffic_violation': TrafficViolationFunc, } root_namespace = Namespace(global_objects, { 'traffic': Namespace(traffic_objects), }) parser = EvaluableParser(Grammar(), root_namespace) # Tests for the parse action that makes the variables def test_existing_variable_without_namespace(self): parse_tree = self.parser("~ bool") eq_(parse_tree.root_node, Not(self.global_objects['bool'])) def test_existing_variable_with_namespace(self): parse_tree = self.parser('traffic:traffic_light == "green"') expected_node = Equal(self.traffic_objects['traffic_light'], String("green")) eq_(parse_tree.root_node, expected_node) def test_non_existing_variable_without_namespace(self): assert_raises(ScopeError, self.parser, "~ non_existing_var") def test_non_existing_variable_with_namespace(self): assert_raises(ScopeError, self.parser, "~ traffic:non_existing_var") def test_variable_in_non_existing_namespace(self): assert_raises(ScopeError, self.parser, "~ bar:foo") def test_function_instead_of_variable(self): # "foo" is a function, so it cannot be used as a variable (without # parenthesis): try: self.parser('~ foo') except BadExpressionError as exc: eq_('"foo" represents a function, not a variable', six.text_type(exc)) else: assert 0, '"foo" is a function, not a variable!' def test_named_constant(self): """Named constants must be supported.""" parse_tree = self.parser('message == "Hello earth"') expected_node = Equal(String("Hello world"), String("Hello earth")) eq_(parse_tree.root_node, expected_node) # Tests for the parse action that makes the functions def test_existing_function_without_namespace(self): parse_tree = self.parser('~ foo("baz")') eq_(parse_tree.root_node, Not(PermissiveFunction(String("baz")))) def test_existing_function_with_namespace(self): parse_tree = self.parser('~ traffic:traffic_violation("pedestrians")') expected_node = Not(TrafficViolationFunc(String("pedestrians"))) eq_(parse_tree.root_node, expected_node) def test_non_existing_function_without_namespace(self): assert_raises(ScopeError, self.parser, "~ non_existing_function()") def test_non_existing_function_with_namespace(self): assert_raises(ScopeError, self.parser, "~ traffic:non_existing_func()") def test_function_in_non_existing_namespace(self): assert_raises(ScopeError, self.parser, "~ bar:foo(123)") def test_variable_instead_of_function(self): # "bool" is a variable, so it cannot be used as a function (with # parenthesis): try: self.parser('~ bool()') except BadExpressionError as exc: eq_('"bool" is not a function', six.text_type(exc)) else: assert 0, '"bool" is a variable, not a function!'