1# Copyright 2015-2017 the openage authors. See copying.md for legal info. 2 3""" 4Generates code for C++ testing, mostly the table to look up symbols from test 5names. 6""" 7 8import collections 9 10 11class Namespace: 12 """ 13 Represents a C++ namespace, which contains other namespaces and functions. 14 15 gen_prototypes() generates the code for the namespace. 16 """ 17 def __init__(self): 18 self.namespaces = collections.defaultdict(self.__class__) 19 self.functions = [] 20 21 def add_functionname(self, path): 22 """ 23 Adds a function to the namespace. 24 25 Path is the qualified function "path" (e.g., openage::test::foo) 26 has the path ["openage", "test", "foo"]. 27 28 Descends recursively, creating subnamespaces as required. 29 """ 30 if len(path) == 1: 31 self.functions.append(path[0]) 32 else: 33 subnamespace = self.namespaces[path[0]] 34 subnamespace.add_functionname(path[1:]) 35 36 def gen_prototypes(self): 37 """ 38 Generates the actual C++ code for this namespace, 39 including all sub-namespaces and function prototypes. 40 """ 41 for name in self.functions: 42 yield "void %s();\n" % name 43 44 for namespacename, namespace in sorted(self.namespaces.items()): 45 yield "namespace %s {\n" % namespacename 46 for line in namespace.gen_prototypes(): 47 yield line 48 yield "} // %s\n\n" % namespacename 49 50 def get_functionnames(self): 51 """ 52 Yields all function names in this namespace, 53 as well as all subnamespaces. 54 """ 55 for name in self.functions: 56 yield name 57 58 for namespacename, namespace in sorted(self.namespaces.items()): 59 for name in namespace.get_functionnames(): 60 yield namespacename + "::" + name 61 62 63def generate_testlist(projectdir): 64 """ 65 Generates the test/demo method symbol lookup file from tests_cpp. 66 67 projectdir is a util.fslike.path.Path. 68 """ 69 root_namespace = Namespace() 70 71 from ..testing.list_processor import list_targets_cpp 72 73 for testname, _, _, _ in list_targets_cpp(): 74 root_namespace.add_functionname(testname.split('::')) 75 76 func_prototypes = list(root_namespace.gen_prototypes()) 77 78 method_mappings = [ 79 "{\"%s\", ::%s}" % (functionname, functionname) 80 for functionname in root_namespace.get_functionnames()] 81 82 tmpl_path = projectdir.joinpath("libopenage/testing/testlist.cpp.template") 83 with tmpl_path.open() as tmpl: 84 content = tmpl.read() 85 86 content = content.replace('FUNCTION_PROTOTYPES', "".join(func_prototypes)) 87 content = content.replace('METHOD_MAPPINGS', ",\n\t".join(method_mappings)) 88 89 gen_path = projectdir.joinpath("libopenage/testing/testlist.gen.cpp") 90 with gen_path.open("w") as gen: 91 gen.write(content) 92