Home | History | Annotate | Download | only in testng
      1 #!/usr/bin/python2.7
      2 
      3 # Copyright (C) 2016 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #     http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 #
     18 # Generate a CTS test XML file from a text file containing every single class#method per line
     19 #
     20 # For example, given an input file:
     21 #
     22 #          foo.txt:
     23 #                com.android.ClassName#methodNameA
     24 #                com.android.ClassName#methodNameB
     25 #
     26 # Will generate the output file:
     27 #
     28 #          TestPackage.xml:
     29 #                <TestPackage>
     30 #                  <TestSuite name="com">
     31 #                    <TestSuite name="android">
     32 #                      <TestCase name="ClassName">
     33 #                        <Test name="methodNameA" />
     34 #                        <Test name="methodNameB" />
     35 #                      </TestCase>
     36 #                    </TestSuite>
     37 #                  </TestSuite>
     38 #                </TestPackage>
     39 #
     40 
     41 import argparse
     42 import sys
     43 
     44 INDENTATION_INCREASE=2
     45 
     46 class BaseNode(object):
     47     def __init__(self, name=None):
     48         self._children = []
     49         self._name = name
     50         self._properties = []
     51 
     52     def _get_children(self):
     53         return self._children
     54 
     55     def _set_children(self, value):
     56         self._children = value
     57 
     58     children = property(_get_children, _set_children, doc="Get/set list of children BaseNode")
     59 
     60     def append_child(self, child):
     61         self._children.append(child)
     62 
     63     def has_children(self):
     64         return not not self._children
     65 
     66     def _get_name(self):
     67         return self._name
     68 
     69     def _set_name(self, value):
     70         self._name = value
     71 
     72     name = property(_get_name, _set_name, doc="Get/set the name property of the current XML node")
     73 
     74     def _get_type_name(self):
     75         return type(self).__name__
     76 
     77     type_name = property(_get_type_name, doc="Get the name of the current XML node")
     78 
     79     def _set_properties(self, value):
     80         self._properties = value
     81 
     82     def _get_properties(self):
     83         return self._properties
     84 
     85     properties = property(_get_properties, _set_properties, doc="Get/set additional XML properties such as appPackageName (as a dict)")
     86 
     87     def write_xml(self, out, indent=0):
     88         out.write(' ' * indent)
     89         out.write('<' + self.type_name)
     90 
     91         if self.name is not None:
     92             out.write(' name="')
     93             out.write(self.name)
     94             out.write('"')
     95 
     96         if self.properties:
     97             for key, value in self.properties.iteritems():
     98                 out.write(' ' + key + '="' + value + '"')
     99 
    100         if not self.has_children():
    101             out.write(' />')
    102             out.write('\n')
    103             return
    104 
    105         out.write('>\n')
    106 
    107         #TODO: print all the properties
    108 
    109         for child in self.children:
    110             child.write_xml(out, indent + INDENTATION_INCREASE)
    111 
    112         out.write(' ' * indent)
    113         out.write('</' + self.type_name + '>')
    114         out.write('\n')
    115 
    116 class _SuiteContainer(BaseNode):
    117     def get_or_create_suite(self, package_list):
    118         debug_print("get_or_create_suite, package_list = " + str(package_list))
    119         debug_print("name = " + self.name)
    120         # If we are empty, then we just reached the TestSuite which we actually wanted. Return.
    121         if not package_list:
    122             return self
    123 
    124         current_package = package_list[0]
    125         rest_of_packages = package_list[1:]
    126 
    127         # If a suite already exists for the requested package, then have it look/create recursively.
    128         for child in self.children:
    129             if child.name == current_package:
    130                 return child.get_or_create_suite(rest_of_packages)
    131 
    132         # No suite exists yet, create it recursively
    133         new_suite = TestSuite(name=current_package)
    134         self.append_child(new_suite)
    135         return new_suite.get_or_create_suite(rest_of_packages)
    136 
    137 class TestPackage(_SuiteContainer):
    138     def add_class_and_method(self, fq_class_name, method):
    139         debug_print("add_class_and_method, fq_class_name=" + fq_class_name + ", method=" + method)
    140         package_list = fq_class_name.split(".")[:-1] # a.b.c -> ['a', 'b']
    141         just_class_name = fq_class_name.split(".")[-1] # a.b.c -> 'c'
    142 
    143         test_suite = self.get_or_create_suite(package_list)
    144 
    145         if test_suite == self:
    146             raise Exception("The suite cannot be the package")
    147 
    148         return test_suite.add_class_and_method(just_class_name, method)
    149 
    150 class TestSuite(_SuiteContainer):
    151     def add_class_and_method(self, just_class_name, method_name):
    152         test_case = self.get_or_create_test_case(just_class_name)
    153         return test_case.add_method(method_name)
    154 
    155     def get_or_create_test_case(self, just_class_name):
    156         for child in self.children:
    157             if child.name == just_class_name:
    158                 return child
    159 
    160         new_test_case = TestCase(name=just_class_name)
    161         self.append_child(new_test_case)
    162         return new_test_case
    163 
    164 class TestCase(BaseNode):
    165     def add_method(self, method_name):
    166         tst = Test(name=method_name)
    167         self.append_child(tst)
    168         return tst
    169 
    170 class Test(BaseNode):
    171     def __init__(self, name):
    172         super(Test, self).__init__(name)
    173         self._children = None
    174 
    175 def debug_print(x):
    176     #print x
    177     pass
    178 
    179 def build_xml_test_package(input, name, xml_properties):
    180     root = TestPackage(name=name)
    181 
    182     for line in input:
    183         class_and_method_name = line.split('#')
    184         fq_class_name = class_and_method_name[0].strip()
    185         method_name = class_and_method_name[1].strip()
    186 
    187         root.add_class_and_method(fq_class_name, method_name)
    188 
    189     root.properties = xml_properties
    190     return root
    191 
    192 def write_xml(out, test_package):
    193     out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    194     test_package.write_xml(out)
    195 
    196 def main():
    197     parser = argparse.ArgumentParser(description='Process a test methods list file to generate CTS test xml.')
    198 
    199     # Named required
    200     parser.add_argument('--cts-name', help="name (e.g. CtsJdwp)", required=True)
    201     parser.add_argument('--app-package-name', help="appPackageName (e.g. android.jdwp)", required=True)
    202     parser.add_argument('--jar-path', help="jarPath (e.g. CtsJdwp.jar)", required=True)
    203 
    204     # Named optionals
    205     parser.add_argument('--test-type', help="testType (default testNGDeviceTest)",
    206                         default="testNGDeviceTest")
    207     parser.add_argument('--runtime-args', help="runtimeArgs (e.g. -XXlib:libart.so)")
    208     parser.add_argument('--version', help="version (default 1.0)", default="1.0")
    209 
    210     # Positional optionals
    211     parser.add_argument('input-filename', nargs='?',
    212                                help='name of the cts test file (stdin by default)')
    213     parser.add_argument('output-filename', nargs='?',
    214                                help='name of the cts output file (stdout by default)')
    215 
    216     # Map named arguments into the xml <TestPackage> property key name
    217     argv_to_xml = {
    218             'app_package_name' : 'appPackageName',
    219             'jar_path' : 'jarPath',
    220             'test_type' : 'testType',
    221             'runtime_args' : 'runtimeArgs',
    222             'version' : 'version'
    223     }
    224 
    225     args = parser.parse_args()
    226     argv = vars(args) # convert Namespace to Dict
    227 
    228     xml_properties = {}
    229     for key, value in argv_to_xml.iteritems():
    230         if argv.get(key):
    231             xml_properties[value] = argv[key]
    232 
    233     debug_print(argv['input-filename'])
    234     debug_print(argv['output-filename'])
    235 
    236     name_in = argv['input-filename']
    237     name_out = argv['output-filename']
    238 
    239     file_in = name_in and open(name_in, "r") or sys.stdin
    240     file_out = name_out and open(name_out, "w+") or sys.stdout
    241 
    242     # read all the input
    243     test_package = build_xml_test_package(file_in, args.cts_name, xml_properties)
    244     # write all the output
    245     write_xml(file_out, test_package)
    246 
    247 if __name__ == "__main__":
    248     main()
    249