1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/python3 2*795d594fSAndroid Build Coastguard Worker# 3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2015 The Android Open Source Project 4*795d594fSAndroid Build Coastguard Worker# 5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*795d594fSAndroid Build Coastguard Worker# 9*795d594fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*795d594fSAndroid Build Coastguard Worker# 11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*795d594fSAndroid Build Coastguard Worker# limitations under the License. 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker""" 18*795d594fSAndroid Build Coastguard WorkerGenerate Java Main file from a classes.xml file. 19*795d594fSAndroid Build Coastguard Worker""" 20*795d594fSAndroid Build Coastguard Worker 21*795d594fSAndroid Build Coastguard Workerimport os 22*795d594fSAndroid Build Coastguard Workerimport sys 23*795d594fSAndroid Build Coastguard Workerfrom pathlib import Path 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard WorkerBUILD_TOP = os.getenv("ANDROID_BUILD_TOP") 26*795d594fSAndroid Build Coastguard Workerif BUILD_TOP is None: 27*795d594fSAndroid Build Coastguard Worker print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) 28*795d594fSAndroid Build Coastguard Worker sys.exit(1) 29*795d594fSAndroid Build Coastguard Worker 30*795d594fSAndroid Build Coastguard Worker# Allow us to import utils and mixins. 31*795d594fSAndroid Build Coastguard Workersys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python")) 32*795d594fSAndroid Build Coastguard Worker 33*795d594fSAndroid Build Coastguard Workerfrom testgen.utils import get_copyright 34*795d594fSAndroid Build Coastguard Workerimport testgen.mixins as mixins 35*795d594fSAndroid Build Coastguard Worker 36*795d594fSAndroid Build Coastguard Workerfrom collections import namedtuple 37*795d594fSAndroid Build Coastguard Workerimport itertools 38*795d594fSAndroid Build Coastguard Workerimport functools 39*795d594fSAndroid Build Coastguard Workerimport xml.etree.ElementTree as ET 40*795d594fSAndroid Build Coastguard Worker 41*795d594fSAndroid Build Coastguard Workerclass MainClass(mixins.DumpMixin, mixins.Named, mixins.JavaFileMixin): 42*795d594fSAndroid Build Coastguard Worker """ 43*795d594fSAndroid Build Coastguard Worker A mainclass and main method for this test. 44*795d594fSAndroid Build Coastguard Worker """ 45*795d594fSAndroid Build Coastguard Worker 46*795d594fSAndroid Build Coastguard Worker MAIN_CLASS_TEMPLATE = """{copyright} 47*795d594fSAndroid Build Coastguard Workerclass Main {{ 48*795d594fSAndroid Build Coastguard Worker{test_groups} 49*795d594fSAndroid Build Coastguard Worker{test_funcs} 50*795d594fSAndroid Build Coastguard Worker{main_func} 51*795d594fSAndroid Build Coastguard Worker}} 52*795d594fSAndroid Build Coastguard Worker""" 53*795d594fSAndroid Build Coastguard Worker 54*795d594fSAndroid Build Coastguard Worker MAIN_FUNCTION_TEMPLATE = """ 55*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) {{ 56*795d594fSAndroid Build Coastguard Worker {test_group_invoke} 57*795d594fSAndroid Build Coastguard Worker }} 58*795d594fSAndroid Build Coastguard Worker""" 59*795d594fSAndroid Build Coastguard Worker 60*795d594fSAndroid Build Coastguard Worker TEST_GROUP_INVOKE_TEMPLATE = """ 61*795d594fSAndroid Build Coastguard Worker {test_name}(); 62*795d594fSAndroid Build Coastguard Worker""" 63*795d594fSAndroid Build Coastguard Worker 64*795d594fSAndroid Build Coastguard Worker def __init__(self): 65*795d594fSAndroid Build Coastguard Worker """ 66*795d594fSAndroid Build Coastguard Worker Initialize this MainClass 67*795d594fSAndroid Build Coastguard Worker """ 68*795d594fSAndroid Build Coastguard Worker self.tests = set() 69*795d594fSAndroid Build Coastguard Worker self.global_funcs = set() 70*795d594fSAndroid Build Coastguard Worker 71*795d594fSAndroid Build Coastguard Worker def add_instance(self, it): 72*795d594fSAndroid Build Coastguard Worker """ 73*795d594fSAndroid Build Coastguard Worker Add an instance test for the given class 74*795d594fSAndroid Build Coastguard Worker """ 75*795d594fSAndroid Build Coastguard Worker self.tests.add(it) 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker def add_func(self, f): 78*795d594fSAndroid Build Coastguard Worker """ 79*795d594fSAndroid Build Coastguard Worker Add a function to the class 80*795d594fSAndroid Build Coastguard Worker """ 81*795d594fSAndroid Build Coastguard Worker self.global_funcs.add(f) 82*795d594fSAndroid Build Coastguard Worker 83*795d594fSAndroid Build Coastguard Worker def get_name(self): 84*795d594fSAndroid Build Coastguard Worker """ 85*795d594fSAndroid Build Coastguard Worker Get the name of this class 86*795d594fSAndroid Build Coastguard Worker """ 87*795d594fSAndroid Build Coastguard Worker return "Main" 88*795d594fSAndroid Build Coastguard Worker 89*795d594fSAndroid Build Coastguard Worker def __str__(self): 90*795d594fSAndroid Build Coastguard Worker """ 91*795d594fSAndroid Build Coastguard Worker Print this class 92*795d594fSAndroid Build Coastguard Worker """ 93*795d594fSAndroid Build Coastguard Worker all_tests = sorted(self.tests) 94*795d594fSAndroid Build Coastguard Worker test_invoke = "" 95*795d594fSAndroid Build Coastguard Worker test_groups = "" 96*795d594fSAndroid Build Coastguard Worker for t in all_tests: 97*795d594fSAndroid Build Coastguard Worker test_groups += str(t) 98*795d594fSAndroid Build Coastguard Worker for t in sorted(all_tests): 99*795d594fSAndroid Build Coastguard Worker test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) 100*795d594fSAndroid Build Coastguard Worker main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) 101*795d594fSAndroid Build Coastguard Worker 102*795d594fSAndroid Build Coastguard Worker funcs = "" 103*795d594fSAndroid Build Coastguard Worker for f in sorted(self.global_funcs): 104*795d594fSAndroid Build Coastguard Worker funcs += str(f) 105*795d594fSAndroid Build Coastguard Worker return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright('java'), 106*795d594fSAndroid Build Coastguard Worker test_groups=test_groups, 107*795d594fSAndroid Build Coastguard Worker main_func=main_func, test_funcs=funcs) 108*795d594fSAndroid Build Coastguard Worker 109*795d594fSAndroid Build Coastguard Worker 110*795d594fSAndroid Build Coastguard Workerclass InstanceTest(mixins.Named, mixins.NameComparableMixin): 111*795d594fSAndroid Build Coastguard Worker """ 112*795d594fSAndroid Build Coastguard Worker A method that runs tests for a particular concrete type, It calls the test 113*795d594fSAndroid Build Coastguard Worker cases for running it in all possible ways. 114*795d594fSAndroid Build Coastguard Worker """ 115*795d594fSAndroid Build Coastguard Worker 116*795d594fSAndroid Build Coastguard Worker INSTANCE_TEST_TEMPLATE = """ 117*795d594fSAndroid Build Coastguard Worker public static void {test_name}() {{ 118*795d594fSAndroid Build Coastguard Worker System.out.println("Testing for type {ty}"); 119*795d594fSAndroid Build Coastguard Worker String s = "{ty}"; 120*795d594fSAndroid Build Coastguard Worker {ty} v = new {ty}(); 121*795d594fSAndroid Build Coastguard Worker 122*795d594fSAndroid Build Coastguard Worker {invokes} 123*795d594fSAndroid Build Coastguard Worker 124*795d594fSAndroid Build Coastguard Worker System.out.println("End testing for type {ty}"); 125*795d594fSAndroid Build Coastguard Worker }} 126*795d594fSAndroid Build Coastguard Worker""" 127*795d594fSAndroid Build Coastguard Worker 128*795d594fSAndroid Build Coastguard Worker TEST_INVOKE_TEMPLATE = """ 129*795d594fSAndroid Build Coastguard Worker {fname}(s, v); 130*795d594fSAndroid Build Coastguard Worker""" 131*795d594fSAndroid Build Coastguard Worker 132*795d594fSAndroid Build Coastguard Worker def __init__(self, main, ty): 133*795d594fSAndroid Build Coastguard Worker """ 134*795d594fSAndroid Build Coastguard Worker Initialize this test group for the given type 135*795d594fSAndroid Build Coastguard Worker """ 136*795d594fSAndroid Build Coastguard Worker self.ty = ty 137*795d594fSAndroid Build Coastguard Worker self.main = main 138*795d594fSAndroid Build Coastguard Worker self.funcs = set() 139*795d594fSAndroid Build Coastguard Worker self.main.add_instance(self) 140*795d594fSAndroid Build Coastguard Worker 141*795d594fSAndroid Build Coastguard Worker def get_name(self): 142*795d594fSAndroid Build Coastguard Worker """ 143*795d594fSAndroid Build Coastguard Worker Get the name of this test group 144*795d594fSAndroid Build Coastguard Worker """ 145*795d594fSAndroid Build Coastguard Worker return "TEST_NAME_"+self.ty 146*795d594fSAndroid Build Coastguard Worker 147*795d594fSAndroid Build Coastguard Worker def add_func(self, f): 148*795d594fSAndroid Build Coastguard Worker """ 149*795d594fSAndroid Build Coastguard Worker Add a test function to this test group 150*795d594fSAndroid Build Coastguard Worker """ 151*795d594fSAndroid Build Coastguard Worker self.main.add_func(f) 152*795d594fSAndroid Build Coastguard Worker self.funcs.add(f) 153*795d594fSAndroid Build Coastguard Worker 154*795d594fSAndroid Build Coastguard Worker def __str__(self): 155*795d594fSAndroid Build Coastguard Worker """ 156*795d594fSAndroid Build Coastguard Worker Returns the java code for this function 157*795d594fSAndroid Build Coastguard Worker """ 158*795d594fSAndroid Build Coastguard Worker func_invokes = "" 159*795d594fSAndroid Build Coastguard Worker for f in sorted(self.funcs, key=lambda a: (a.func, a.farg)): 160*795d594fSAndroid Build Coastguard Worker func_invokes += self.TEST_INVOKE_TEMPLATE.format(fname=f.get_name(), 161*795d594fSAndroid Build Coastguard Worker farg=f.farg) 162*795d594fSAndroid Build Coastguard Worker 163*795d594fSAndroid Build Coastguard Worker return self.INSTANCE_TEST_TEMPLATE.format(test_name=self.get_name(), ty=self.ty, 164*795d594fSAndroid Build Coastguard Worker invokes=func_invokes) 165*795d594fSAndroid Build Coastguard Worker 166*795d594fSAndroid Build Coastguard Workerclass Func(mixins.Named, mixins.NameComparableMixin): 167*795d594fSAndroid Build Coastguard Worker """ 168*795d594fSAndroid Build Coastguard Worker A single test case that attempts to invoke a function on receiver of a given type. 169*795d594fSAndroid Build Coastguard Worker """ 170*795d594fSAndroid Build Coastguard Worker 171*795d594fSAndroid Build Coastguard Worker TEST_FUNCTION_TEMPLATE = """ 172*795d594fSAndroid Build Coastguard Worker public static void {fname}(String s, {farg} v) {{ 173*795d594fSAndroid Build Coastguard Worker try {{ 174*795d594fSAndroid Build Coastguard Worker System.out.printf("%s-{invoke_type:<9} {farg:>9}.{callfunc}()='%s'\\n", s, v.{callfunc}()); 175*795d594fSAndroid Build Coastguard Worker return; 176*795d594fSAndroid Build Coastguard Worker }} catch (Error e) {{ 177*795d594fSAndroid Build Coastguard Worker System.out.printf("%s-{invoke_type} on {farg}: {callfunc}() threw exception!\\n", s); 178*795d594fSAndroid Build Coastguard Worker if (e instanceof IncompatibleClassChangeError) {{ 179*795d594fSAndroid Build Coastguard Worker System.out.printf("Exception is of type %s\\n", e.getClass().getName()); 180*795d594fSAndroid Build Coastguard Worker }} else {{ 181*795d594fSAndroid Build Coastguard Worker e.printStackTrace(System.out); 182*795d594fSAndroid Build Coastguard Worker }} 183*795d594fSAndroid Build Coastguard Worker }} 184*795d594fSAndroid Build Coastguard Worker }} 185*795d594fSAndroid Build Coastguard Worker""" 186*795d594fSAndroid Build Coastguard Worker 187*795d594fSAndroid Build Coastguard Worker def __init__(self, func, farg, invoke): 188*795d594fSAndroid Build Coastguard Worker """ 189*795d594fSAndroid Build Coastguard Worker Initialize this test function for the given invoke type and argument 190*795d594fSAndroid Build Coastguard Worker """ 191*795d594fSAndroid Build Coastguard Worker self.func = func 192*795d594fSAndroid Build Coastguard Worker self.farg = farg 193*795d594fSAndroid Build Coastguard Worker self.invoke = invoke 194*795d594fSAndroid Build Coastguard Worker 195*795d594fSAndroid Build Coastguard Worker def get_name(self): 196*795d594fSAndroid Build Coastguard Worker """ 197*795d594fSAndroid Build Coastguard Worker Get the name of this test 198*795d594fSAndroid Build Coastguard Worker """ 199*795d594fSAndroid Build Coastguard Worker return "Test_Func_{}_{}_{}".format(self.func, self.farg, self.invoke) 200*795d594fSAndroid Build Coastguard Worker 201*795d594fSAndroid Build Coastguard Worker def __str__(self): 202*795d594fSAndroid Build Coastguard Worker """ 203*795d594fSAndroid Build Coastguard Worker Get the java code for this test function 204*795d594fSAndroid Build Coastguard Worker """ 205*795d594fSAndroid Build Coastguard Worker return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(), 206*795d594fSAndroid Build Coastguard Worker farg=self.farg, 207*795d594fSAndroid Build Coastguard Worker invoke_type=self.invoke, 208*795d594fSAndroid Build Coastguard Worker callfunc=self.func) 209*795d594fSAndroid Build Coastguard Worker 210*795d594fSAndroid Build Coastguard Workerdef flatten_classes(classes, c): 211*795d594fSAndroid Build Coastguard Worker """ 212*795d594fSAndroid Build Coastguard Worker Iterate over all the classes 'c' can be used as 213*795d594fSAndroid Build Coastguard Worker """ 214*795d594fSAndroid Build Coastguard Worker while c: 215*795d594fSAndroid Build Coastguard Worker yield c 216*795d594fSAndroid Build Coastguard Worker c = classes.get(c.super_class) 217*795d594fSAndroid Build Coastguard Worker 218*795d594fSAndroid Build Coastguard Workerdef flatten_class_methods(classes, c): 219*795d594fSAndroid Build Coastguard Worker """ 220*795d594fSAndroid Build Coastguard Worker Iterate over all the methods 'c' can call 221*795d594fSAndroid Build Coastguard Worker """ 222*795d594fSAndroid Build Coastguard Worker for c1 in flatten_classes(classes, c): 223*795d594fSAndroid Build Coastguard Worker yield from c1.methods 224*795d594fSAndroid Build Coastguard Worker 225*795d594fSAndroid Build Coastguard Workerdef flatten_interfaces(dat, c): 226*795d594fSAndroid Build Coastguard Worker """ 227*795d594fSAndroid Build Coastguard Worker Iterate over all the interfaces 'c' transitively implements 228*795d594fSAndroid Build Coastguard Worker """ 229*795d594fSAndroid Build Coastguard Worker def get_ifaces(cl): 230*795d594fSAndroid Build Coastguard Worker for i2 in cl.implements: 231*795d594fSAndroid Build Coastguard Worker yield dat.interfaces[i2] 232*795d594fSAndroid Build Coastguard Worker yield from get_ifaces(dat.interfaces[i2]) 233*795d594fSAndroid Build Coastguard Worker 234*795d594fSAndroid Build Coastguard Worker for cl in flatten_classes(dat.classes, c): 235*795d594fSAndroid Build Coastguard Worker yield from get_ifaces(cl) 236*795d594fSAndroid Build Coastguard Worker 237*795d594fSAndroid Build Coastguard Workerdef flatten_interface_methods(dat, i): 238*795d594fSAndroid Build Coastguard Worker """ 239*795d594fSAndroid Build Coastguard Worker Iterate over all the interface methods 'c' can call 240*795d594fSAndroid Build Coastguard Worker """ 241*795d594fSAndroid Build Coastguard Worker yield from i.methods 242*795d594fSAndroid Build Coastguard Worker for i2 in flatten_interfaces(dat, i): 243*795d594fSAndroid Build Coastguard Worker yield from i2.methods 244*795d594fSAndroid Build Coastguard Worker 245*795d594fSAndroid Build Coastguard Workerdef make_main_class(dat): 246*795d594fSAndroid Build Coastguard Worker """ 247*795d594fSAndroid Build Coastguard Worker Creates a Main.java file that runs all the tests 248*795d594fSAndroid Build Coastguard Worker """ 249*795d594fSAndroid Build Coastguard Worker m = MainClass() 250*795d594fSAndroid Build Coastguard Worker for c in dat.classes.values(): 251*795d594fSAndroid Build Coastguard Worker i = InstanceTest(m, c.name) 252*795d594fSAndroid Build Coastguard Worker for clazz in flatten_classes(dat.classes, c): 253*795d594fSAndroid Build Coastguard Worker for meth in flatten_class_methods(dat.classes, clazz): 254*795d594fSAndroid Build Coastguard Worker i.add_func(Func(meth, clazz.name, 'virtual')) 255*795d594fSAndroid Build Coastguard Worker for iface in flatten_interfaces(dat, clazz): 256*795d594fSAndroid Build Coastguard Worker for meth in flatten_interface_methods(dat, iface): 257*795d594fSAndroid Build Coastguard Worker i.add_func(Func(meth, clazz.name, 'virtual')) 258*795d594fSAndroid Build Coastguard Worker i.add_func(Func(meth, iface.name, 'interface')) 259*795d594fSAndroid Build Coastguard Worker return m 260*795d594fSAndroid Build Coastguard Worker 261*795d594fSAndroid Build Coastguard Workerclass TestData(namedtuple("TestData", ['classes', 'interfaces'])): 262*795d594fSAndroid Build Coastguard Worker """ 263*795d594fSAndroid Build Coastguard Worker A class representing the classes.xml document. 264*795d594fSAndroid Build Coastguard Worker """ 265*795d594fSAndroid Build Coastguard Worker pass 266*795d594fSAndroid Build Coastguard Worker 267*795d594fSAndroid Build Coastguard Workerclass Clazz(namedtuple("Clazz", ["name", "methods", "super_class", "implements"])): 268*795d594fSAndroid Build Coastguard Worker """ 269*795d594fSAndroid Build Coastguard Worker A class representing a class element in the classes.xml document. 270*795d594fSAndroid Build Coastguard Worker """ 271*795d594fSAndroid Build Coastguard Worker pass 272*795d594fSAndroid Build Coastguard Worker 273*795d594fSAndroid Build Coastguard Workerclass IFace(namedtuple("IFace", ["name", "methods", "super_class", "implements"])): 274*795d594fSAndroid Build Coastguard Worker """ 275*795d594fSAndroid Build Coastguard Worker A class representing an interface element in the classes.xml document. 276*795d594fSAndroid Build Coastguard Worker """ 277*795d594fSAndroid Build Coastguard Worker pass 278*795d594fSAndroid Build Coastguard Worker 279*795d594fSAndroid Build Coastguard Workerdef parse_xml(xml): 280*795d594fSAndroid Build Coastguard Worker """ 281*795d594fSAndroid Build Coastguard Worker Parse the xml description of this test. 282*795d594fSAndroid Build Coastguard Worker """ 283*795d594fSAndroid Build Coastguard Worker classes = dict() 284*795d594fSAndroid Build Coastguard Worker ifaces = dict() 285*795d594fSAndroid Build Coastguard Worker root = ET.fromstring(xml) 286*795d594fSAndroid Build Coastguard Worker for iface in root.find("interfaces"): 287*795d594fSAndroid Build Coastguard Worker name = iface.attrib['name'] 288*795d594fSAndroid Build Coastguard Worker implements = [a.text for a in iface.find("implements")] 289*795d594fSAndroid Build Coastguard Worker methods = [a.text for a in iface.find("methods")] 290*795d594fSAndroid Build Coastguard Worker ifaces[name] = IFace(name = name, 291*795d594fSAndroid Build Coastguard Worker super_class = iface.attrib['super'], 292*795d594fSAndroid Build Coastguard Worker methods = methods, 293*795d594fSAndroid Build Coastguard Worker implements = implements) 294*795d594fSAndroid Build Coastguard Worker for clazz in root.find('classes'): 295*795d594fSAndroid Build Coastguard Worker name = clazz.attrib['name'] 296*795d594fSAndroid Build Coastguard Worker implements = [a.text for a in clazz.find("implements")] 297*795d594fSAndroid Build Coastguard Worker methods = [a.text for a in clazz.find("methods")] 298*795d594fSAndroid Build Coastguard Worker classes[name] = Clazz(name = name, 299*795d594fSAndroid Build Coastguard Worker super_class = clazz.attrib['super'], 300*795d594fSAndroid Build Coastguard Worker methods = methods, 301*795d594fSAndroid Build Coastguard Worker implements = implements) 302*795d594fSAndroid Build Coastguard Worker return TestData(classes, ifaces) 303*795d594fSAndroid Build Coastguard Worker 304*795d594fSAndroid Build Coastguard Workerdef main(argv): 305*795d594fSAndroid Build Coastguard Worker java_dir = Path(argv[1]) 306*795d594fSAndroid Build Coastguard Worker if not java_dir.exists() or not java_dir.is_dir(): 307*795d594fSAndroid Build Coastguard Worker print("{} is not a valid java dir".format(java_dir), file=sys.stderr) 308*795d594fSAndroid Build Coastguard Worker sys.exit(1) 309*795d594fSAndroid Build Coastguard Worker class_data = parse_xml((java_dir / "classes.xml").open().read()) 310*795d594fSAndroid Build Coastguard Worker make_main_class(class_data).dump(java_dir) 311*795d594fSAndroid Build Coastguard Worker 312*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__': 313*795d594fSAndroid Build Coastguard Worker main(sys.argv) 314