def test_representation(self): # With Unicode: string = String(u"caña") eq_(repr(string), '<String "caña">') # With ASCII string = String("cana") eq_(repr(string), '<String "cana">')
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_representation(self): set1 = Set(Number(3), Number(5)) eq_(repr(set1), "<Set <Number 3.0>, <Number 5.0>>") # Now with an empty set: set2 = Set() eq_(repr(set2), "<Set>") # Now with Unicode stuff in it: set3 = Set(String(u"España"), String(u"carabobeño")) eq_(repr(set3), '<Set <String "España">, <String "carabobeño">>')
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_python_strings(self): """Constant strings represent Python :class:`unicode` objects.""" ascii_text = String("tomorrow!") unicode_text = String(u"¡mañana!") py_ascii_text = ascii_text.get_as_string(None) py_unicode_text = unicode_text.get_as_string(None) ok_(isinstance(py_ascii_text, unicode)) ok_(isinstance(py_unicode_text, unicode)) eq_(py_ascii_text, u"tomorrow!") eq_(py_unicode_text, u"¡mañana!")
def test_equivalence(self): """ Two constant sets A and B are equivalent if they have the same cardinality and each element in A is equivalent to one element in B. """ set1 = Set(String("hi"), Set(Number(3), String("hello"))) set2 = Set(String("hi"), Number(3), String("hello")) set3 = Set(Set(String("hello"), Number(3)), String("hi")) set4 = Set(String("hi"), String("hello")) ok_(set1 == set1) assert_false(set1 == set2) ok_(set1 == set3) assert_false(set1 == set4) assert_false(set2 == set1) ok_(set2 == set2) assert_false(set2 == set3) assert_false(set2 == set4) ok_(set3 == set1) assert_false(set3 == set2) ok_(set3 == set3) assert_false(set3 == set4) assert_false(set4 == set1) assert_false(set4 == set2) assert_false(set4 == set3) ok_(set4 == set4)
def test_global_names(self): """When an operand is bound, its global name must be set accordingly.""" operand = String("hey there") bind1 = Bind("da_global_name", operand) bind2 = Bind("Da_Global_Name", operand) eq_(bind1.global_name, "da_global_name") eq_(bind1.global_name, bind2.global_name)
def test_constructor_with_objects(self): objects = [ Bind("greeting", String("hey")), Bind("traffic", TrafficLightVar()) ] st = SymbolTable("global", objects) eq_(st.objects, set(objects))
def test_retrieving_non_existing_object(self): global_objects = { 'foo': TrafficLightVar(), 'traffic-violation': TrafficViolationFunc(String("pedestrians")), } st = Namespace(global_objects, ) assert_raises(ScopeError, st.get_object, "bool")
def test_retrieving_object_in_non_existing_subtable(self): global_objects = { 'foo': TrafficLightVar(), 'traffic-violation': TrafficViolationFunc(String("pedestrians")), } st = Namespace(global_objects, ) assert_raises(ScopeError, st.get_object, "foo", ["doesn't", "exist"])
def test_parsing_with_no_localized_grammars(self): mgr = ConvertibleParseManager(Grammar()) parse_tree1 = mgr.parse('message == "2009-07-13"') parse_tree2 = mgr.parse('message == "2009-07-13"', None) expected_tree = ConvertibleParseTree( Equal(PlaceholderVariable("message"), String("2009-07-13"))) eq_(parse_tree1, parse_tree2) eq_(parse_tree1, expected_tree)
def test_duplicate_objects(self): """There must be no duplicate object.""" # In the constructor: objects1 = [ Bind("salutation", String("hey")), Bind("traffic", TrafficLightVar()), Bind("salutation", String("hey")) ] assert_raises(ScopeError, SymbolTable, "global", objects1) # Post-instantiation: objects2 = [ Bind("salutation", String("hey")), Bind("traffic", TrafficLightVar()) ] st = SymbolTable("global", objects2) assert_raises(ScopeError, st.add_object, Bind("salutation", String("hey")))
def test_equivalence(self): """ Two constant strings are equivalent if they represent the same string. """ text1 = String("hello world") text2 = String("hello earth") text3 = String("hello world") ok_(text1 == text1) assert_false(text1 == text2) ok_(text1 == text3) assert_false(text2 == text1) ok_(text2 == text2) assert_false(text2 == text3) ok_(text3 == text1) assert_false(text3 == text2) ok_(text3 == text3)
def test_instantiation(self): """All the members of a set must be operands""" # Instantiation with operands: Set(Number(3), String("hola")) # Instantiation with a non-operand value: try: Set(Number(3), "hola") assert False, "InvalidOperationError exception not raised" except InvalidOperationError, exc: assert 'Item "hola" is not an operand' in unicode(exc)
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, exc: eq_('"foo" represents a function, not a variable', unicode(exc)) else:
def test_names(self): """ When an operand is bound, its multiple names must be set accordingly. """ operand = String("Vive la france !") # No localized names: bind1 = Bind("foo", operand) eq_(bind1.names, {}) # Lower-case names: names0 = {'es_VE': "cartuchera", 'es_ES': "estuche"} bind2 = Bind("bar", operand, **names0) eq_(bind2.names, names0) # Mixed-case names -- must be converted to lower-case: names1 = {'es_VE': "Cartuchera", 'es_ES': "estuche"} bind2 = Bind("bar", operand, **names1) eq_(bind2.names, names0)
def test_retrieving_existing_3rd_level_object(self): third_level_objects = { 'bool': BoolVar(), } second_level_objects = { 'traffic': TrafficLightVar(), } global_objects = { 'foo': TrafficLightVar(), 'traffic-violation': TrafficViolationFunc(String("pedestrians")), } third_level_namespaces = {'sub2': Namespace(third_level_objects)} second_level_namespaces = { 'sub1': Namespace(second_level_objects, third_level_namespaces) } st = Namespace(global_objects, second_level_namespaces) requested_object = st.get_object("bool", ["sub1", "sub2"]) eq_(requested_object, BoolVar())
def test_retrieving_non_existing_localized_names(self): """ When a non-existing localized name is requested, a warning must be issued and the global name returned. """ bind = Bind("foo", String("hey"), es="fulano") logging_fixture = LoggingHandlerFixture() eq_(bind.get_localized_name("fr"), "foo") # Checking for the the warning: eq_(len(logging_fixture.handler.messages["warning"]), 1) warning = logging_fixture.handler.messages["warning"][0] eq_( warning, 'Operand "hey" bound as "foo" doesn\'t have a name in fr; ' 'using the global one') # Undoing it: logging_fixture.undo()
def test_equivalence(self): tree1 = ConvertibleParseTree(PlaceholderVariable("my_variable")) tree2 = ConvertibleParseTree(PlaceholderVariable("my_variable")) tree3 = ConvertibleParseTree(String("hello")) tree4 = EvaluableParseTree(BoolVar()) 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_node_type(self): """Strings are leaf nodes and implement the String datatype.""" string = String("greeting") ok_(string.is_leaf) ok_(isinstance(string, StringType))
def test_equivalence(self): objects1 = lambda: [ Bind("dish", String("cachapa")), Bind("drink", String("empanada")) ] objects2 = lambda: [ Bind("drink", String("empanada")), Bind("dish", String("cachapa")) ] objects3 = lambda: [Bind("pi", Number(3.1416))] st1 = SymbolTable("foo", objects1()) st2 = SymbolTable("foo", objects1()) st3 = SymbolTable("foo", objects1(), es="fulano") st4 = SymbolTable("foo", objects1(), es="fulano") st5 = SymbolTable("foo", objects2()) st6 = SymbolTable("foo", objects3()) st7 = SymbolTable("foo", objects2(), es="fulano") st8 = SymbolTable("foo", objects3(), es_VE="fulano") st9 = SymbolTable("bar", objects1()) st10 = SymbolTable("foo", objects1()) st11 = SymbolTable("foo", objects1(), SymbolTable("bar", []), SymbolTable("baz", [])) st12 = SymbolTable("foo", objects1(), SymbolTable("baz", []), SymbolTable("bar", [])) # Moving st10 into the "baz" symbol table: SymbolTable("baz", [], st10) ok_(st1 == st2) ok_(st1 == st5) ok_(st1 == st10) ok_(st2 == st1) ok_(st2 == st5) ok_(st2 == st10) ok_(st3 == st4) ok_(st3 == st7) ok_(st4 == st3) ok_(st4 == st7) ok_(st5 == st1) ok_(st5 == st2) ok_(st5 == st10) ok_(st7 == st3) ok_(st7 == st4) ok_(st10 == st1) ok_(st10 == st2) ok_(st10 == st5) ok_(st11 == st12) ok_(st12 == st11) ok_(st1 != None) ok_(st1 != Bind("foo", String("cachapa"))) ok_(st1 != st3) ok_(st1 != st4) ok_(st1 != st6) ok_(st1 != st7) ok_(st1 != st8) ok_(st1 != st9) ok_(st1 != st11) ok_(st1 != st12) ok_(st2 != st3) ok_(st2 != st4) ok_(st2 != st6) ok_(st2 != st7) ok_(st2 != st8) ok_(st2 != st9) ok_(st2 != st11) ok_(st2 != st12) ok_(st3 != st1) ok_(st3 != st2) ok_(st3 != st5) ok_(st3 != st6) ok_(st3 != st8) ok_(st3 != st9) ok_(st3 != st10) ok_(st3 != st11) ok_(st3 != st12) ok_(st4 != st1) ok_(st4 != st2) ok_(st4 != st5) ok_(st4 != st6) ok_(st4 != st8) ok_(st4 != st9) ok_(st4 != st10) ok_(st4 != st11) ok_(st4 != st12) ok_(st5 != st3) ok_(st5 != st4) ok_(st5 != st6) ok_(st5 != st7) ok_(st5 != st8) ok_(st5 != st9) ok_(st5 != st11) ok_(st5 != st12) ok_(st6 != st1) ok_(st6 != st2) ok_(st6 != st3) ok_(st6 != st4) ok_(st6 != st5) ok_(st6 != st7) ok_(st6 != st8) ok_(st6 != st9) ok_(st6 != st10) ok_(st6 != st11) ok_(st6 != st12) ok_(st7 != st1) ok_(st7 != st2) ok_(st7 != st5) ok_(st7 != st6) ok_(st7 != st8) ok_(st7 != st9) ok_(st7 != st10) ok_(st7 != st11) ok_(st7 != st12) ok_(st8 != st1) ok_(st8 != st2) ok_(st8 != st3) ok_(st8 != st4) ok_(st8 != st5) ok_(st8 != st6) ok_(st8 != st7) ok_(st8 != st9) ok_(st8 != st10) ok_(st8 != st11) ok_(st8 != st12) ok_(st9 != st1) ok_(st9 != st2) ok_(st9 != st3) ok_(st9 != st4) ok_(st9 != st5) ok_(st9 != st6) ok_(st9 != st7) ok_(st9 != st8) ok_(st9 != st10) ok_(st9 != st11) ok_(st9 != st12) ok_(st10 != st3) ok_(st10 != st4) ok_(st10 != st6) ok_(st10 != st7) ok_(st10 != st8) ok_(st10 != st9) ok_(st11 != st1) ok_(st11 != st2) ok_(st11 != st3) ok_(st11 != st4) ok_(st11 != st5) ok_(st11 != st6) ok_(st11 != st7) ok_(st11 != st8) ok_(st11 != st9) ok_(st11 != st10) ok_(st12 != st1) ok_(st12 != st2) ok_(st12 != st3) ok_(st12 != st4) ok_(st12 != st5) ok_(st12 != st6) ok_(st12 != st7) ok_(st12 != st8) ok_(st12 != st9) ok_(st12 != st10)
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 '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 '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)
def test_no_default_symbol_table(self): """Operand bindings must not be in a symbol table by default.""" bind = Bind("foo", String("whatever")) eq_(bind.symbol_table, None)
def test_retrieving_existing_localized_names(self): bind = Bind("foo", String("hey"), es="fulano") eq_(bind.get_localized_name("es"), "fulano")
def test_node_type(self): """Sets are branch nodes and implement the Set datatype.""" set_ = Set(String("arg0")) assert_false(set_.is_leaf) ok_(isinstance(set_, SetType))
def test_non_boolean_operands(self): """Only operands that support logical values are supported.""" operand = String("I'm a string") assert_raises(InvalidOperationError, EvaluableParseTree, operand)
def test_item_and_non_set(self): item = String("Paris") set_ = String("France") assert_raises(InvalidOperationError, BelongsTo, item, set_)
def test_constants_evaluation(self): operation1 = NotEqual(String("hola"), String("chao")) operation2 = NotEqual(String("hola"), String("hola")) ok_(operation1(None)) assert_false(operation2(None))
def make_string(self, tokens): """Make a String constant using the token passed.""" return String(tokens[0])
def convert_string(self, text): return String(text)