def test_includes_rendering(): common_include = model.Include("foo", [ model.Constant("symbol_1", 1), model.Constant("number_12", 12), ]) nodes = [ common_include, model.Include("root/ni_knights", [ model.Include("../root/rabbit", [ common_include, model.Constant("pi", "3.14159"), model.Typedef("definition", "things", "r32", "docstring"), ]), model.Constant("symbol_2", 2), ]), model.Include("../root/baz_bar", []), model.Include( "many/numbers", [model.Constant("number_%s" % n, n) for n in reversed(range(20))]), ] ref = """\ from foo import number_12, symbol_1 from ni_knights import definition, pi, symbol_2 from numbers import ( number_0, number_1, number_10, number_11, number_13, number_14, number_15, number_16, number_17, number_18, number_19, number_2, number_3, number_4, number_5, number_6, number_7, number_8, number_9 ) """ # call twice to check if 'duplication avoidance' machinery in _PythonTranslator.translate_include works ok assert serialize(nodes) == ref assert serialize(nodes) == ref
def test_cross_reference_array_size_from_includes(): nodes = [ model.Include('x', [ model.Include('y', [ model.Constant('NUM_HEX', '0xf'), model.Constant('NUM_DEC', '3'), ]), model.Enum('E', [ model.EnumMember('E1', 'NUM_HEX'), model.EnumMember('E3', 'NUM_DEC'), ]), ]), model.Struct('X', [ model.StructMember('x', 'u32', size='NUM_DEC'), model.StructMember('y', 'u32', size='E1'), model.StructMember('z', 'u32', size='UNKNOWN'), model.StructMember('a', 'u32', size='E3'), ]) ] constants = model.cross_reference(nodes) assert nodes[1].members[0].numeric_size == 3 assert nodes[1].members[1].numeric_size == 15 assert nodes[1].members[2].numeric_size is None assert nodes[1].members[3].numeric_size == 3 assert constants == { 'E1': 15, 'E3': 3, 'NUM_DEC': 3, 'NUM_HEX': 15, }
def test_constants_rendering(): nodes = [model.Constant("CONST_A", "0"), model.Constant("CONST_B", "31")] ref = """\ CONST_A = 0 CONST_B = 31 """ assert ref == serialize(nodes)
def test_model_sort_constants(): nodes = [model.Constant("C_C", "C_A + C_B"), model.Constant("C_A", "1"), model.Constant("C_B", "2")] model.topological_sort(nodes) assert [("C_A", "1"), ("C_B", "2"), ("C_C", "C_A + C_B")] == nodes
def test_definitions_constants(): nodes = process([ model.Constant("CONST_A", "0"), model.Constant("CONST_B", "31"), model.Constant("CONST_B", "0x123"), model.Constant("CONST_B", "0o741") ]) assert generate_definitions(nodes) == """\
def test_cross_reference_numeric_size_of_expression(): nodes = [ model.Constant('A', 12), model.Constant('B', 15), model.Constant('C', 'A*B'), model.Struct('X', [ model.StructMember('x', 'u32', size = 'C'), ]) ] model.cross_reference(nodes) assert nodes[3].members[0].numeric_size == 180
def test_constants_rendering(): nodes = [ model.Constant("CONST_A", "0", "first constant"), model.Constant("CONST_B", "31", "second constant") ] ref = """\ '''first constant''' CONST_A = 0 '''second constant''' CONST_B = 31 """ assert serialize(nodes) == ref
def test_constants_parsing(): content = """\ const CONST_A = 31; const CONST_B = 0x31; const CONST_C = 031; const CONST_D = -1; """ assert parse(content) == [ model.Constant("CONST_A", "31"), model.Constant("CONST_B", "49"), model.Constant("CONST_C", "25"), model.Constant("CONST_D", "-1") ]
def test_definitions_newlines(): nodes = [ model.Typedef("a", "b"), model.Typedef("c", "d"), model.Enum("E1", [model.EnumMember("E1_A", "0")]), model.Enum("E2", [model.EnumMember("E2_A", "0")]), model.Constant("CONST_A", "0"), model.Typedef("e", "f"), model.Constant("CONST_B", "0"), model.Constant("CONST_C", "0"), model.Struct("A", [model.StructMember("a", "u32")]), model.Struct("B", [model.StructMember("b", "u32")]) ] assert generate_definitions(nodes) == """\
def test_constant_expressions(): content = """\ const A = 1; const B = A * 2; const C = (B - A) * 3; const D = -C; const E = D << 2; """ assert parse(content) == [ model.Constant("A", "1"), model.Constant("B", "2"), model.Constant("C", "3"), model.Constant("D", "-3"), model.Constant("E", "-12") ]
def test_cross_reference_array_size_from_includes(): nodes = [ model.Include('x', [ model.Include('y', [ model.Constant('NUM', '3'), ]), model.Enum('E', [ model.EnumMember('E1', '1'), model.EnumMember('E3', 'NUM') ]), ]), model.Struct('X', [ model.StructMember('x', 'u32', size = 'NUM'), model.StructMember('y', 'u32', size = 'E1'), model.StructMember('z', 'u32', size = 'UNKNOWN'), model.StructMember('a', 'u32', size = 'E3') ]) ] model.cross_reference(nodes) assert nodes[1].members[0].numeric_size == 3 assert nodes[1].members[1].numeric_size == 1 assert nodes[1].members[2].numeric_size == None assert nodes[1].members[3].numeric_size == 3
def test_parsing_with_unicode_in_value(): xml = u"""\ <x> <constant name="CONST_VALUE" value="…ñ"/> </x> """ assert parse(xml) == [model.Constant('CONST_VALUE', u'…ñ')]
def test_parsing_with_unicode_in_name(): xml = u"""\ <x> <constant name="CONST_NAME_Jalapeño" value="31"/> </x> """ assert parse(xml) == [model.Constant(u'CONST_NAME_Jalapeño', '31')]
def test_evaluate_sizes_array_with_named_size(): nodes = process([ model.Constant('NUM', '3'), model.Enum('E', [ model.EnumMember('E1', '1'), model.EnumMember('E3', 'NUM') ]), model.Struct('X', [ model.StructMember('x', 'u32', size = 'NUM'), model.StructMember('y', 'u32', size = 'E1'), model.StructMember('z', 'u32', size = 'E3') ]), model.Struct('Y', [ model.StructMember('x', 'u32', size = 'UNKNOWN'), model.StructMember('y', 'u32') ]) ]) assert list(map(get_size_alignment_padding, get_members_and_node(nodes[2]))) == [ (12, 4, 0), (4, 4, 0), (12, 4, 0), (28, 4) ] assert list(map(get_size_alignment_padding, get_members_and_node(nodes[3]))) == [ (None, None, None), (4, 4, None), (None, None) ]
def test_parsing_with_unicode_in_comment(): xml = u"""\ <x> <constant name="CONST_COMMENT" value="0" comment="it's …Jalapeño in comment"/> </x> """ assert parse(xml) == [ model.Constant('CONST_COMMENT', '0', u"it's …Jalapeño in comment") ]
def test_definitions_struct_with_fixed_array(): nodes = process([ model.Constant("NUM_OF_ARRAY_ELEMS", "3"), model.Struct( "Struct", [model.StructMember("a", "u8", size="NUM_OF_ARRAY_ELEMS")]) ]) assert generate_definitions(nodes[-1:]) == """\
def test_definitions_struct_with_limited_array(): nodes = process([ model.Constant('NUM_OF_ARRAY_ELEMS', '1'), model.Struct("Struct", [ model.StructMember("a_len", "u8"), model.StructMember( "a", "u8", bound="a_len", size="NUM_OF_ARRAY_ELEMS") ]) ]) assert generate_definitions(nodes[-1:]) == """\
def test_struct_parsing_with_constant(): xml = """\ <x> <struct name="Struct"> <member name="a" type="u8"> <constant name="THE_CONSTANT" value="0"/> </member> </struct> </x> """ assert parse(xml) == [ model.Constant("THE_CONSTANT", "0"), model.Struct("Struct", [model.StructMember("a", "u8")]) ]
def test_cross_reference_quadratic_complexity_include_performance_bug(): """ If type and numeric definitions from includes are processed each time, compilation times can skyrocket... """ FACTOR = 10 nodes = [model.Constant('X', 42), model.Typedef('Y', 'u8')] * FACTOR for i in range(FACTOR): nodes = [model.Include('inc%s' % i, nodes)] * FACTOR nodes.append(model.Struct('Z', [model.StructMember('x', 'u8', size='X')])) """This line will kill your cpu if cross-referencing algorithm is quadratic""" model.cross_reference(nodes) assert nodes[-1].members[0].numeric_size == 42
def test_constants_layout(schema_gen): input_model = [ model.Constant('CONSTANT_0', "NULL"), model.Constant('CONST_D', "1", "This one gets a description."), model.Constant('CONST_E', "512"), model.Constant('CONSTANT_B', "23", "This one gets longer description. " * 4), model.Constant('CONST_C', "NO DESC"), model.Constant('D', "CONSTANT_B"), ] assert schema_gen(input_model) == """\
def test_structs_with_fixed_array_parsing(): content = """\ const max = 5; struct test { u32 x[3]; u32 y[max]; bytes z[10]; }; """ assert parse(content) == [ model.Constant('max', '5'), model.Struct('test', [ model.StructMember('x', 'u32', size = '3'), model.StructMember('y', 'u32', size = '5'), model.StructMember('z', 'byte', size = '10') ]) ]
def test_unions_parsing(): content = """\ const three = 3; typedef u32 z_t; union test { 1: u32 x; 2: u32 y; three: z_t z; }; """ assert parse(content) == [ model.Constant('three', '3'), model.Typedef('z_t', 'u32'), model.Union('test', [ model.UnionMember('x', 'u32', '1'), model.UnionMember('y', 'u32', '2'), model.UnionMember('z', 'z_t', '3') ]) ]
def make_constant(xml_elem): return model.Constant(xml_elem.get("name"), expand_operators(xml_elem.get("value")), docstring=get_docstr(xml_elem))
def test_python_translator_1(): ih = [] th = [] for x in range(20, 200, 60): ih.append( model.Include("test_include_" + str(x), [model.Constant("n_%s" % x, x, "doc")])) th.append( model.Typedef("td_elem_name_" + str(x), "td_elem_val_" + str(x))) th.append( model.Typedef("td_elem_name_" + str(x), "i_td_elem_val_" + str(x))) th.append( model.Typedef("td_elem_name_" + str(x), "u_td_elem_val_" + str(x))) enum = [] for x in range(1, 100, 30): enum.append((model.EnumMember("elem_" + str(x), "val_" + str(x)))) name = "MAC_L2CallConfigResp" members = [model.StructMember('messageResult', 'SMessageResult')] msg_h = model.Struct(name, members) nodes = [] nodes += ih nodes += [ model.Constant("C_A", "5"), model.Constant("C_B", "5"), model.Constant("C_C", "C_B + C_A") ] nodes += th nodes += [model.Enum("test", enum)] nodes += [msg_h] python_translator = _PythonTranslator() output = python_translator(nodes, "") ref = """\ # -*- encoding: utf-8 -*- # This file has been generated by prophyc. import sys import prophy if sys.version_info < (3,): from test_include_20 import n_20 else: from .test_include_20 import n_20 if sys.version_info < (3,): from test_include_80 import n_80 else: from .test_include_80 import n_80 if sys.version_info < (3,): from test_include_140 import n_140 else: from .test_include_140 import n_140 C_A = 5 C_B = 5 C_C = C_B + C_A td_elem_name_20 = td_elem_val_20 td_elem_name_20 = i_td_elem_val_20 td_elem_name_20 = u_td_elem_val_20 td_elem_name_80 = td_elem_val_80 td_elem_name_80 = i_td_elem_val_80 td_elem_name_80 = u_td_elem_val_80 td_elem_name_140 = td_elem_val_140 td_elem_name_140 = i_td_elem_val_140 td_elem_name_140 = u_td_elem_val_140 class test(prophy.with_metaclass(prophy.enum_generator, prophy.enum)): _enumerators = [ ('elem_1', val_1), ('elem_31', val_31), ('elem_61', val_61), ('elem_91', val_91), ] elem_1 = val_1 elem_31 = val_31 elem_61 = val_61 elem_91 = val_91 class MAC_L2CallConfigResp(prophy.with_metaclass(prophy.struct_generator, prophy.struct)): _descriptor = [ ('messageResult', SMessageResult), ] """ assert output == ref
def make_constant(elem): return model.Constant(elem.get("name"), expand_operators(elem.get("value")))
def test_definitions_constants(): nodes = [model.Constant("CONST_A", "0"), model.Constant("CONST_B", "31")] assert generate_definitions(nodes) == """\
def test_constant_with_newline(): assert parse("const \nCONST = 0;") == [model.Constant("CONST", "0")]
def larger_model(lorem_with_breaks): return [ model.Typedef('a', 'i16'), model.Typedef('c', 'a'), model.Include('some_defs', [ model.Struct('IncludedStruct', [ model.StructMember( 'member1', 'r32', docstring='doc for member1'), model.StructMember( 'member2', 'u64', docstring='docstring for member1') ]), model.Typedef('c', 'a'), ]), model.Include('cplx', [ model.Struct('cint16_t', [ model.StructMember('re', 'i16', docstring='real'), model.StructMember('im', 'i16', docstring='imaginary') ]), model.Struct('cint32_t', [ model.StructMember('re', 'i32', docstring='real'), model.StructMember('im', 'i32', docstring='imaginary') ]), ]), model.Union('the_union', [ model.UnionMember('a', 'IncludedStruct', 0), model.UnionMember( 'field_with_a_long_name', 'cint16_t', 1, docstring="Shorter"), model.UnionMember('field_with_a_longer_name', 'cint32_t', 2, docstring="Longer description"), model.UnionMember('other', 'i32', 4090, docstring='This one has larger discriminator'), ], "spec for that union"), model.Enum( 'E1', [ model.EnumMember('E1_A', '0', 'enum1 constant value A'), model.EnumMember('E1_B_has_a_long_name', '1', 'enum1 constant va3lue B'), model.EnumMember('E1_C_desc', '2', lorem_with_breaks[:150]), ], "Enumerator is a model type that is not supposed to be serialized. Its definition represents yet another " "syntax variation for typing a constant. Of course elements of it's type are serializable " "(as int32)"), model.Enum('E2', [ model.EnumMember('E2_A', '0', "Short\nmultiline\ndoc"), ]), model.Constant('CONST_A', '6'), model.Constant('CONST_B', '0'), model.Struct('StructMemberKinds', [ model.StructMember('member_without_docstring', 'i16'), model.StructMember('ext_size', 'i16', docstring='arbitrary sizer for dynamic arrays'), model.StructMember('optional_element', 'cint16_t', optional=True, docstring='optional array'), model.StructMember('fixed_array', 'cint16_t', size=3, docstring='Array with static size.'), model.StructMember('samples', 'cint16_t', bound='ext_size', docstring='dynamic (ext.sized) array'), model.StructMember('limited_array', 'r64', size=4, bound='ext_size', docstring='Has statically ' 'evaluable maximum size.'), model.StructMember('greedy', 'cint16_t', greedy=True, docstring='Represents array of arbitrary ' 'number of elements. Buffer size ' 'must be multiply of element size.'), ], lorem_with_breaks[:400]), ]
def test_include_no_error_with_constant(): content = """\ #include "test.prophy" const Y = X; """ parse(content, lambda path: [model.Constant('X', '42')])
def test_of_PythonGenerator(): ih = [] th = [] for x in range(20, 200, 60): ih.append(model.Include("test_include_" + str(x))) th.append( model.Typedef("td_elem_name_" + str(x), "td_elem_val_" + str(x))) th.append( model.Typedef("td_elem_name_" + str(x), "i_td_elem_val_" + str(x))) th.append( model.Typedef("td_elem_name_" + str(x), "u_td_elem_val_" + str(x))) enum = [] for x in range(1, 100, 30): enum.append(("elem_" + str(x), "val_" + str(x))) name = "MAC_L2CallConfigResp" members = [model.StructMember('messageResult', 'SMessageResult')] msg_h = model.Struct(name, members) nodes = [] nodes += ih nodes += [ model.Constant("C_A", "5"), model.Constant("C_B", "5"), model.Constant("C_C", "C_B + C_A") ] nodes += th nodes += [model.Enum("test", enum)] nodes += [msg_h] ps = PythonGenerator() output = ps.serialize_string(nodes) ref = """\ import prophy from test_include_20 import * from test_include_80 import * from test_include_140 import * C_A = 5 C_B = 5 C_C = C_B + C_A td_elem_name_20 = td_elem_val_20 td_elem_name_20 = i_td_elem_val_20 td_elem_name_20 = u_td_elem_val_20 td_elem_name_80 = td_elem_val_80 td_elem_name_80 = i_td_elem_val_80 td_elem_name_80 = u_td_elem_val_80 td_elem_name_140 = td_elem_val_140 td_elem_name_140 = i_td_elem_val_140 td_elem_name_140 = u_td_elem_val_140 class test(prophy.enum): __metaclass__ = prophy.enum_generator _enumerators = [('elem_1', val_1), ('elem_31', val_31), ('elem_61', val_61), ('elem_91', val_91)] elem_1 = val_1 elem_31 = val_31 elem_61 = val_61 elem_91 = val_91 class MAC_L2CallConfigResp(prophy.struct): __metaclass__ = prophy.struct_generator _descriptor = [('messageResult', SMessageResult)] """ assert ref == output