def test_imp_none_in_subroutine(): ''' test that implicit none can be added to a subroutine ''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine") module.add(subroutine) subroutine.add(ImplicitNoneGen(subroutine)) assert 'IMPLICIT NONE' in str(subroutine.root)
def test_basegen_start_parent_loop_omp_end_dbg(capsys): '''Check the debug option to the start_parent_loop method when we have an OpenMP end directive''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dgen = DirectiveGen(sub, "omp", "end", "do", "") sub.add(dgen) loop = DoGen(sub, "it", "1", "10") sub.add(loop) call = CallGen(loop, "testcall") loop.add(call) call.start_parent_loop(debug=True) out, _ = capsys.readouterr() print out expected = ("Parent is a do loop so moving to the parent\n" "The type of the current node is now <class " "'fparser.block_statements.Do'>\n" "The type of parent is <class " "'fparser.block_statements.Subroutine'>\n" "Finding the loops position in its parent ...\n" "The loop's index is 1\n" "The type of the object at the index is <class " "'fparser.block_statements.Do'>\n" "If preceding node is a directive then move back one\n" "preceding node is a directive so find out what type ...\n") assert expected in out
def test_progunitgen_multiple_use1(): '''Check that we correctly handle the case where duplicate use statements are added but one is specific''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(UseGen(sub, name="fred")) sub.add(UseGen(sub, name="fred", only=True, funcnames=["astaire"])) assert count_lines(sub.root, "USE fred") == 1
def test_progunitgen_multiple_generic_use(): '''Check that we correctly handle the case where duplicate use statements are added''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(UseGen(sub, name="fred")) sub.add(UseGen(sub, name="fred")) assert count_lines(sub.root, "USE fred") == 1
def test_do_loop_with_increment(): ''' Test that we correctly generate code for a do loop with non-unit increment ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsub") module.add(sub) dogen = DoGen(sub, "it", "1", "10", step="2") sub.add(dogen) count = count_lines(sub.root, "DO it=1,10,2") assert count == 1
def test_imp_none_in_subroutine_already_exists(): ''' test that implicit none is not added to a subroutine when one already exists''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine", implicitnone=True) module.add(sub) sub.add(ImplicitNoneGen(sub)) count = count_lines(sub.root, "IMPLICIT NONE") assert count == 1, \ "There should only be one instance of IMPLICIT NONE"
def test_imp_none_exception_if_wrong_parent(): ''' test that an exception is thrown if implicit none is added and the parent is not a module or a subroutine ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dogen = DoGen(sub, "i", "1", "10") sub.add(dogen) with pytest.raises(Exception): dogen.add(ImplicitNoneGen(dogen))
def test_basegen_first(): '''Check that we can insert an object as the first child''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(CommentGen(sub, " hello"), position=["first"]) cindex = line_number(sub.root, "hello") assert cindex == 1
def test_basegen_append(): '''Check that we can append an object to the tree''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(CommentGen(sub, " hello"), position=["append"]) cindex = line_number(sub.root, "hello") assert cindex == 3
def test_typedeclgen_names(): ''' Check that the names method of TypeDeclGen works as expected ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dgen = TypeDeclGen(sub, datatype="my_type", entity_decls=["type1"]) sub.add(dgen) names = dgen.names assert len(names) == 1 assert names[0] == "type1"
def test_progunitgen_multiple_use2(): '''Check that we correctly handle the case where the same module appears in two use statements but, because the first use is specific, the second, generic use is included. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(UseGen(sub, name="fred", only=True, funcnames=["astaire"])) sub.add(UseGen(sub, name="fred")) assert count_lines(sub.root, "USE fred") == 2
def test_adduse_default_funcnames(): ''' Test that the adduse module method works correctly when we do not specify a list of funcnames ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) call = CallGen(sub, name="testcall", args=["a", "b"]) sub.add(call) adduse("fred", call.root) gen = str(sub.root) expected = (" SUBROUTINE testsubroutine()\n" " USE fred\n") assert expected in gen
def test_basegen_start_parent_loop_no_loop_dbg(): '''Check the debug option to the start_parent_loop method when we have no loop''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dgen = DirectiveGen(sub, "omp", "end", "do", "") sub.add(dgen) call = CallGen(sub, name="testcall", args=["a", "b"]) sub.add(call) with pytest.raises(RuntimeError) as err: call.start_parent_loop(debug=True) assert "This node has no enclosing Do loop" in str(err)
def test_adduse(): ''' Test that the adduse module method works correctly when we use a call object as our starting point ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) call = CallGen(sub, name="testcall", args=["a", "b"]) sub.add(call) adduse("fred", call.root, only=True, funcnames=["astaire"]) gen = str(sub.root) expected = (" SUBROUTINE testsubroutine()\n" " USE fred, ONLY: astaire\n") assert expected in gen
def test_subroutine_var_with_implicit_none(): ''' test that a variable is added after an implicit none statement in a subroutine''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine", implicitnone=True) module.add(subroutine) subroutine.add(DeclGen(subroutine, datatype="integer", entity_decls=["var1"])) idx_var = line_number(subroutine.root, "INTEGER var1") idx_imp_none = line_number(subroutine.root, "IMPLICIT NONE") print str(module.root) assert idx_var - idx_imp_none == 1, \ "variable declation must be after implicit none"
def test_typeselectiongen(): ''' Check that SelectionGen works as expected for a type ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sgen = SelectionGen(sub, expr="my_var=>another_var", typeselect=True) sub.add(sgen) agen = AssignGen(sgen, lhs="happy", rhs=".TRUE.") sgen.addcase("fspace", [agen]) sgen.adddefault() gen = str(sub.root) print gen assert "SELECT TYPE ( my_var=>another_var )" in gen assert "TYPE IS ( fspace )" in gen
def test_selectiongen_addcase(): ''' Check that SelectionGen.addcase() works as expected when no content is supplied''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sgen = SelectionGen(sub, expr="my_var") sub.add(sgen) sgen.addcase("1") gen = str(sub.root) print gen expected = ("SELECT CASE ( my_var )\n" "CASE ( 1 )\n" " END SELECT") assert expected in gen
def test_do_loop_add_after(): ''' Test that we correctly generate code for a do loop when adding a child to it with position *after* ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsub") module.add(sub) dogen = DoGen(sub, "it", "1", "10", step="2") sub.add(dogen) assign1 = AssignGen(dogen, lhs="happy", rhs=".TRUE.") dogen.add(assign1) assign2 = AssignGen(dogen, lhs="sad", rhs=".FALSE.") dogen.add(assign2, position=["before", assign1.root]) a1_line = line_number(sub.root, "happy = ") a2_line = line_number(sub.root, "sad = ") assert a1_line > a2_line
def test_add_before(): ''' add the new code before a particular object ''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine") module.add(subroutine) loop = DoGen(subroutine, "it", "1", "10") subroutine.add(loop) call = CallGen(subroutine, "testcall") subroutine.add(call, position=["before", loop.root]) lines = str(module.root).splitlines() # the call should be inserted before the loop print lines assert "SUBROUTINE testsubroutine" in lines[3] assert "CALL testcall" in lines[4] assert "DO it=1,10" in lines[5]
def test_subroutine_var_intent_in_with_directive(): ''' test that a variable declared as intent in is added before a directive in a subroutine''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine", implicitnone=False) module.add(subroutine) subroutine.add(DirectiveGen(subroutine, "omp", "begin", "parallel", "")) subroutine.add(DeclGen(subroutine, datatype="integer", intent="in", entity_decls=["var1"])) idx_par = line_number(subroutine.root, "!$omp parallel") idx_var = line_number(subroutine.root, "INTEGER, intent(in) :: var1") print str(module.root) assert idx_par - idx_var == 1, \ "variable declaration must be before directive"
def test_imp_none_in_subroutine_with_use_and_decs_and_comments(): ''' test that implicit none is added after any use statements and before any declarations in a subroutine in the presence of comments when auto (the default) is used for insertion''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(TypeDeclGen(sub, datatype="my_type", entity_decls=["type1"])) sub.add(UseGen(sub, "fred")) for idx in [0, 1, 2, 3]: sub.add(CommentGen(sub, " hello "+str(idx)), position=["before_index", 2*idx]) sub.add(ImplicitNoneGen(sub)) in_idx = line_number(sub.root, "IMPLICIT NONE") assert in_idx == 3
def test_decl_no_replication_types(): '''Check that the same array variable will only get declared once in a module and a subroutine''' variable_name = "arg_name" datatype = "field_type" module = ModuleGen(name="testmodule") module.add(TypeDeclGen(module, datatype=datatype, entity_decls=[variable_name])) module.add(TypeDeclGen(module, datatype=datatype, entity_decls=[variable_name])) subroutine = SubroutineGen(module, name="testsubroutine") module.add(subroutine) subroutine.add(TypeDeclGen(subroutine, datatype=datatype, entity_decls=[variable_name])) subroutine.add(TypeDeclGen(subroutine, datatype=datatype, entity_decls=[variable_name])) generated_code = str(module.root) assert generated_code.count(variable_name) == 2
def test_selectiongen(): ''' Check that SelectionGen works as expected ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sgen = SelectionGen(sub, expr="my_var") sub.add(sgen) agen = AssignGen(sgen, lhs="happy", rhs=".TRUE.") sgen.addcase("1", [agen]) # TODO how do we specify what happens in the default case? sgen.adddefault() gen = str(sub.root) print gen expected = ("SELECT CASE ( my_var )\n" "CASE ( 1 )\n" " happy = .TRUE.\n" "CASE DEFAULT\n" " END SELECT") assert expected in gen assert False
def test_basegen_start_parent_loop_dbg(capsys): '''Check the debug option to the start_parent_loop method''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) loop = DoGen(sub, "it", "1", "10") sub.add(loop) call = CallGen(loop, "testcall") loop.add(call) call.start_parent_loop(debug=True) out, _ = capsys.readouterr() print out expected = ("Parent is a do loop so moving to the parent\n" "The type of the current node is now <class " "'fparser.block_statements.Do'>\n" "The type of parent is <class " "'fparser.block_statements.Subroutine'>\n" "Finding the loops position in its parent ...\n" "The loop's index is 0\n") assert expected in out
def test_progunit_multiple_use3(): '''Check that we correctly handle the case where the same module is specified in two UseGen objects statements both of which are specific and they have overlapping variable names. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) funcnames = ["a", "b", "c"] sub.add(UseGen(sub, name="fred", only=True, funcnames=funcnames)) funcnames = ["c", "d"] sub.add(UseGen(sub, name="fred", only=True, funcnames=funcnames)) gen = str(sub.root) expected = ( " USE fred, ONLY: d\n" " USE fred, ONLY: a, b, c") assert expected in gen assert count_lines(sub.root, "USE fred") == 2 # ensure that the input list does not get modified assert funcnames == ["c", "d"]
def test_imp_none_in_subroutine_with_use_and_decs(): ''' test that implicit none is added after any use statements and before any declarations in a subroutine when auto (the default) is used for insertion''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(TypeDeclGen(sub, datatype="my_type", entity_decls=["type1"])) sub.add(UseGen(sub, "fred")) sub.add(ImplicitNoneGen(sub)) in_idx = line_number(sub.root, "IMPLICIT NONE") assert in_idx == 2
def test_typedeclgen_multiple_use2(): '''Check that we do not correctly handle the case where data of a different type with the same name has already been declared.''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) # first declaration datanames = ["type1"] sub.add(TypeDeclGen(sub, datatype="my_type", entity_decls=datanames)) gen = str(sub.root) # second declaration datanames = ["type1", "type2"] sub.add(TypeDeclGen(sub, datatype="my_type2", entity_decls=datanames)) gen = str(sub.root) print gen expected = ( " TYPE(my_type2) type1, type2\n" " TYPE(my_type) type1") assert expected in gen # check input data is not modified assert datanames == ["type1", "type2"]
def test_declgen_multiple_use2(): '''Check that we don't correctly handle the case where data of a different type has already been delared. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) # first declaration datanames = ["data1"] sub.add(DeclGen(sub, datatype="real", entity_decls=datanames)) gen = str(sub.root) # second declaration datanames = ["data1", "data2"] sub.add(DeclGen(sub, datatype="integer", entity_decls=datanames)) gen = str(sub.root) print gen expected = ( " INTEGER data1, data2\n" " REAL data1") assert expected in gen # check input data is not modified assert datanames == ["data1", "data2"]
def test_basegen_after_index(): '''Check that we can insert an object using "after_index"''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var2"])) sub.add(CommentGen(sub, " hello"), position=["after_index", 1]) # The code checked by line_number() *includes* the SUBROUTINE # statement (which is obviously not a child of the SubroutineGen # object) and therefore the index it returns is 1 greater than we # might expect. assert line_number(sub.root, "hello") == 3
def test_basegen_before_error(): '''Check that we raise an error when attempting to insert an object before another object that is not present in the tree''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var2"])) # Create an object but do not add it as a child of sub dgen = DeclGen(sub, datatype="real", entity_decls=["rvar1"]) # Try to add an object before the orphan dgen with pytest.raises(RuntimeError) as err: sub.add(CommentGen(sub, " hello"), position=["before", dgen]) assert "Failed to find supplied object" in str(err)