blob: 961410d83156d1e78c6912c340dd1510559f492f [file] [log] [blame]
Igor Murashkin0b4e1362016-04-07 16:54:33 -07001#!/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
41import argparse
42import sys
43
44INDENTATION_INCREASE=2
45
46class 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
116class _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
137class 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
150class 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
164class TestCase(BaseNode):
165 def add_method(self, method_name):
166 tst = Test(name=method_name)
167 self.append_child(tst)
168 return tst
169
170class Test(BaseNode):
171 def __init__(self, name):
172 super(Test, self).__init__(name)
173 self._children = None
174
175def debug_print(x):
176 #print x
177 pass
178
179def 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
192def write_xml(out, test_package):
193 out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
194 test_package.write_xml(out)
195
196def 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
247if __name__ == "__main__":
248 main()