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 Smali test files for test 966. 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, subtree_sizes, gensym, filter_blanks 34*795d594fSAndroid Build Coastguard Workerimport testgen.mixins as mixins 35*795d594fSAndroid Build Coastguard Worker 36*795d594fSAndroid Build Coastguard Workerfrom functools import total_ordering 37*795d594fSAndroid Build Coastguard Workerimport itertools 38*795d594fSAndroid Build Coastguard Workerimport string 39*795d594fSAndroid Build Coastguard Worker 40*795d594fSAndroid Build Coastguard Worker# The max depth the tree can have. 41*795d594fSAndroid Build Coastguard WorkerMAX_IFACE_DEPTH = 3 42*795d594fSAndroid Build Coastguard Worker 43*795d594fSAndroid Build Coastguard Workerclass MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): 44*795d594fSAndroid Build Coastguard Worker """ 45*795d594fSAndroid Build Coastguard Worker A Main.smali file containing the Main class and the main function. It will run 46*795d594fSAndroid Build Coastguard Worker all the test functions we have. 47*795d594fSAndroid Build Coastguard Worker """ 48*795d594fSAndroid Build Coastguard Worker 49*795d594fSAndroid Build Coastguard Worker MAIN_CLASS_TEMPLATE = """{copyright} 50*795d594fSAndroid Build Coastguard Worker 51*795d594fSAndroid Build Coastguard Worker.class public LMain; 52*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object; 53*795d594fSAndroid Build Coastguard Worker 54*795d594fSAndroid Build Coastguard Worker# class Main {{ 55*795d594fSAndroid Build Coastguard Worker 56*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V 57*795d594fSAndroid Build Coastguard Worker .registers 1 58*795d594fSAndroid Build Coastguard Worker invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V 59*795d594fSAndroid Build Coastguard Worker return-void 60*795d594fSAndroid Build Coastguard Worker.end method 61*795d594fSAndroid Build Coastguard Worker 62*795d594fSAndroid Build Coastguard Worker{test_groups} 63*795d594fSAndroid Build Coastguard Worker 64*795d594fSAndroid Build Coastguard Worker{main_func} 65*795d594fSAndroid Build Coastguard Worker 66*795d594fSAndroid Build Coastguard Worker# }} 67*795d594fSAndroid Build Coastguard Worker""" 68*795d594fSAndroid Build Coastguard Worker 69*795d594fSAndroid Build Coastguard Worker MAIN_FUNCTION_TEMPLATE = """ 70*795d594fSAndroid Build Coastguard Worker# public static void main(String[] args) {{ 71*795d594fSAndroid Build Coastguard Worker.method public static main([Ljava/lang/String;)V 72*795d594fSAndroid Build Coastguard Worker .locals 2 73*795d594fSAndroid Build Coastguard Worker 74*795d594fSAndroid Build Coastguard Worker {test_group_invoke} 75*795d594fSAndroid Build Coastguard Worker 76*795d594fSAndroid Build Coastguard Worker return-void 77*795d594fSAndroid Build Coastguard Worker.end method 78*795d594fSAndroid Build Coastguard Worker# }} 79*795d594fSAndroid Build Coastguard Worker""" 80*795d594fSAndroid Build Coastguard Worker 81*795d594fSAndroid Build Coastguard Worker TEST_GROUP_INVOKE_TEMPLATE = """ 82*795d594fSAndroid Build Coastguard Worker# {test_name}(); 83*795d594fSAndroid Build Coastguard Worker invoke-static {{}}, {test_name}()V 84*795d594fSAndroid Build Coastguard Worker""" 85*795d594fSAndroid Build Coastguard Worker 86*795d594fSAndroid Build Coastguard Worker def __init__(self): 87*795d594fSAndroid Build Coastguard Worker """ 88*795d594fSAndroid Build Coastguard Worker Initialize this MainClass. We start out with no tests. 89*795d594fSAndroid Build Coastguard Worker """ 90*795d594fSAndroid Build Coastguard Worker self.tests = set() 91*795d594fSAndroid Build Coastguard Worker 92*795d594fSAndroid Build Coastguard Worker def add_test(self, ty): 93*795d594fSAndroid Build Coastguard Worker """ 94*795d594fSAndroid Build Coastguard Worker Add a test for the concrete type 'ty' 95*795d594fSAndroid Build Coastguard Worker """ 96*795d594fSAndroid Build Coastguard Worker self.tests.add(Func(ty)) 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Worker def get_expected(self): 99*795d594fSAndroid Build Coastguard Worker """ 100*795d594fSAndroid Build Coastguard Worker Get the expected output of this test. 101*795d594fSAndroid Build Coastguard Worker """ 102*795d594fSAndroid Build Coastguard Worker all_tests = sorted(self.tests) 103*795d594fSAndroid Build Coastguard Worker return filter_blanks("\n".join(a.get_expected() for a in all_tests)) 104*795d594fSAndroid Build Coastguard Worker 105*795d594fSAndroid Build Coastguard Worker def initial_build_different(self): 106*795d594fSAndroid Build Coastguard Worker return False 107*795d594fSAndroid Build Coastguard Worker 108*795d594fSAndroid Build Coastguard Worker def get_name(self): 109*795d594fSAndroid Build Coastguard Worker """ 110*795d594fSAndroid Build Coastguard Worker Gets the name of this class 111*795d594fSAndroid Build Coastguard Worker """ 112*795d594fSAndroid Build Coastguard Worker return "Main" 113*795d594fSAndroid Build Coastguard Worker 114*795d594fSAndroid Build Coastguard Worker def __str__(self): 115*795d594fSAndroid Build Coastguard Worker """ 116*795d594fSAndroid Build Coastguard Worker Print the smali code for this test. 117*795d594fSAndroid Build Coastguard Worker """ 118*795d594fSAndroid Build Coastguard Worker all_tests = sorted(self.tests) 119*795d594fSAndroid Build Coastguard Worker test_invoke = "" 120*795d594fSAndroid Build Coastguard Worker test_groups = "" 121*795d594fSAndroid Build Coastguard Worker for t in all_tests: 122*795d594fSAndroid Build Coastguard Worker test_groups += str(t) 123*795d594fSAndroid Build Coastguard Worker for t in all_tests: 124*795d594fSAndroid Build Coastguard Worker test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) 125*795d594fSAndroid Build Coastguard Worker main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) 126*795d594fSAndroid Build Coastguard Worker 127*795d594fSAndroid Build Coastguard Worker return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), 128*795d594fSAndroid Build Coastguard Worker test_groups = test_groups, 129*795d594fSAndroid Build Coastguard Worker main_func = main_func) 130*795d594fSAndroid Build Coastguard Worker 131*795d594fSAndroid Build Coastguard Workerclass Func(mixins.Named, mixins.NameComparableMixin): 132*795d594fSAndroid Build Coastguard Worker """ 133*795d594fSAndroid Build Coastguard Worker A function that tests the functionality of a concrete type. Should only be 134*795d594fSAndroid Build Coastguard Worker constructed by MainClass.add_test. 135*795d594fSAndroid Build Coastguard Worker """ 136*795d594fSAndroid Build Coastguard Worker 137*795d594fSAndroid Build Coastguard Worker TEST_FUNCTION_TEMPLATE = """ 138*795d594fSAndroid Build Coastguard Worker# public static void {fname}() {{ 139*795d594fSAndroid Build Coastguard Worker# try {{ 140*795d594fSAndroid Build Coastguard Worker# {farg} v = new {farg}(); 141*795d594fSAndroid Build Coastguard Worker# System.out.println("Testing {tree}"); 142*795d594fSAndroid Build Coastguard Worker# v.testAll(); 143*795d594fSAndroid Build Coastguard Worker# System.out.println("Success: testing {tree}"); 144*795d594fSAndroid Build Coastguard Worker# return; 145*795d594fSAndroid Build Coastguard Worker# }} catch (Exception e) {{ 146*795d594fSAndroid Build Coastguard Worker# System.out.println("Failure: testing {tree}"); 147*795d594fSAndroid Build Coastguard Worker# e.printStackTrace(System.out); 148*795d594fSAndroid Build Coastguard Worker# return; 149*795d594fSAndroid Build Coastguard Worker# }} 150*795d594fSAndroid Build Coastguard Worker# }} 151*795d594fSAndroid Build Coastguard Worker.method public static {fname}()V 152*795d594fSAndroid Build Coastguard Worker .locals 7 153*795d594fSAndroid Build Coastguard Worker :call_{fname}_try_start 154*795d594fSAndroid Build Coastguard Worker sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; 155*795d594fSAndroid Build Coastguard Worker 156*795d594fSAndroid Build Coastguard Worker new-instance v6, L{farg}; 157*795d594fSAndroid Build Coastguard Worker invoke-direct {{v6}}, L{farg};-><init>()V 158*795d594fSAndroid Build Coastguard Worker 159*795d594fSAndroid Build Coastguard Worker const-string v3, "Testing {tree}" 160*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 161*795d594fSAndroid Build Coastguard Worker 162*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v6}}, L{farg};->testAll()V 163*795d594fSAndroid Build Coastguard Worker 164*795d594fSAndroid Build Coastguard Worker const-string v3, "Success: testing {tree}" 165*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 166*795d594fSAndroid Build Coastguard Worker 167*795d594fSAndroid Build Coastguard Worker return-void 168*795d594fSAndroid Build Coastguard Worker :call_{fname}_try_end 169*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/Exception; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start 170*795d594fSAndroid Build Coastguard Worker :error_{fname}_start 171*795d594fSAndroid Build Coastguard Worker move-exception v3 172*795d594fSAndroid Build Coastguard Worker sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; 173*795d594fSAndroid Build Coastguard Worker const-string v4, "Failure: testing {tree}" 174*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 175*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V 176*795d594fSAndroid Build Coastguard Worker return-void 177*795d594fSAndroid Build Coastguard Worker.end method 178*795d594fSAndroid Build Coastguard Worker""" 179*795d594fSAndroid Build Coastguard Worker 180*795d594fSAndroid Build Coastguard Worker OUTPUT_FORMAT = """ 181*795d594fSAndroid Build Coastguard WorkerTesting {tree} 182*795d594fSAndroid Build Coastguard Worker{test_output} 183*795d594fSAndroid Build Coastguard WorkerSuccess: testing {tree} 184*795d594fSAndroid Build Coastguard Worker""".strip() 185*795d594fSAndroid Build Coastguard Worker 186*795d594fSAndroid Build Coastguard Worker def __init__(self, farg): 187*795d594fSAndroid Build Coastguard Worker """ 188*795d594fSAndroid Build Coastguard Worker Initialize a test function for the given argument 189*795d594fSAndroid Build Coastguard Worker """ 190*795d594fSAndroid Build Coastguard Worker self.farg = farg 191*795d594fSAndroid Build Coastguard Worker 192*795d594fSAndroid Build Coastguard Worker def __str__(self): 193*795d594fSAndroid Build Coastguard Worker """ 194*795d594fSAndroid Build Coastguard Worker Print the smali code for this test function. 195*795d594fSAndroid Build Coastguard Worker """ 196*795d594fSAndroid Build Coastguard Worker return self.TEST_FUNCTION_TEMPLATE.format(fname = self.get_name(), 197*795d594fSAndroid Build Coastguard Worker farg = self.farg.get_name(), 198*795d594fSAndroid Build Coastguard Worker tree = self.farg.get_tree()) 199*795d594fSAndroid Build Coastguard Worker 200*795d594fSAndroid Build Coastguard Worker def get_name(self): 201*795d594fSAndroid Build Coastguard Worker """ 202*795d594fSAndroid Build Coastguard Worker Gets the name of this test function 203*795d594fSAndroid Build Coastguard Worker """ 204*795d594fSAndroid Build Coastguard Worker return "TEST_FUNC_{}".format(self.farg.get_name()) 205*795d594fSAndroid Build Coastguard Worker 206*795d594fSAndroid Build Coastguard Worker def get_expected(self): 207*795d594fSAndroid Build Coastguard Worker """ 208*795d594fSAndroid Build Coastguard Worker Get the expected output of this function. 209*795d594fSAndroid Build Coastguard Worker """ 210*795d594fSAndroid Build Coastguard Worker return self.OUTPUT_FORMAT.format( 211*795d594fSAndroid Build Coastguard Worker tree = self.farg.get_tree(), 212*795d594fSAndroid Build Coastguard Worker test_output = self.farg.get_test_output().strip()) 213*795d594fSAndroid Build Coastguard Worker 214*795d594fSAndroid Build Coastguard Workerclass TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): 215*795d594fSAndroid Build Coastguard Worker """ 216*795d594fSAndroid Build Coastguard Worker A class that will be instantiated to test interface initialization order. 217*795d594fSAndroid Build Coastguard Worker """ 218*795d594fSAndroid Build Coastguard Worker 219*795d594fSAndroid Build Coastguard Worker TEST_CLASS_TEMPLATE = """{copyright} 220*795d594fSAndroid Build Coastguard Worker 221*795d594fSAndroid Build Coastguard Worker.class public L{class_name}; 222*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object; 223*795d594fSAndroid Build Coastguard Worker{implements_spec} 224*795d594fSAndroid Build Coastguard Worker 225*795d594fSAndroid Build Coastguard Worker# public class {class_name} implements {ifaces} {{ 226*795d594fSAndroid Build Coastguard Worker# 227*795d594fSAndroid Build Coastguard Worker# public {class_name}() {{ 228*795d594fSAndroid Build Coastguard Worker# }} 229*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V 230*795d594fSAndroid Build Coastguard Worker .locals 2 231*795d594fSAndroid Build Coastguard Worker invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V 232*795d594fSAndroid Build Coastguard Worker return-void 233*795d594fSAndroid Build Coastguard Worker.end method 234*795d594fSAndroid Build Coastguard Worker 235*795d594fSAndroid Build Coastguard Worker# public String getCalledInterface() {{ 236*795d594fSAndroid Build Coastguard Worker# throw new Error("Should not be called"); 237*795d594fSAndroid Build Coastguard Worker# }} 238*795d594fSAndroid Build Coastguard Worker.method public getCalledInterface()V 239*795d594fSAndroid Build Coastguard Worker .locals 2 240*795d594fSAndroid Build Coastguard Worker const-string v0, "Should not be called" 241*795d594fSAndroid Build Coastguard Worker new-instance v1, Ljava/lang/Error; 242*795d594fSAndroid Build Coastguard Worker invoke-direct {{v1, v0}}, Ljava/lang/Error;-><init>(Ljava/lang/String;)V 243*795d594fSAndroid Build Coastguard Worker throw v1 244*795d594fSAndroid Build Coastguard Worker.end method 245*795d594fSAndroid Build Coastguard Worker 246*795d594fSAndroid Build Coastguard Worker# public void testAll() {{ 247*795d594fSAndroid Build Coastguard Worker# boolean failed = false; 248*795d594fSAndroid Build Coastguard Worker# Error exceptions = new Error("Test failures"); 249*795d594fSAndroid Build Coastguard Worker.method public testAll()V 250*795d594fSAndroid Build Coastguard Worker .locals 5 251*795d594fSAndroid Build Coastguard Worker const/4 v0, 0 252*795d594fSAndroid Build Coastguard Worker const-string v1, "Test failures" 253*795d594fSAndroid Build Coastguard Worker new-instance v2, Ljava/lang/Error; 254*795d594fSAndroid Build Coastguard Worker invoke-direct {{v2, v1}}, Ljava/lang/Error;-><init>(Ljava/lang/String;)V 255*795d594fSAndroid Build Coastguard Worker 256*795d594fSAndroid Build Coastguard Worker {test_calls} 257*795d594fSAndroid Build Coastguard Worker 258*795d594fSAndroid Build Coastguard Worker# if (failed) {{ 259*795d594fSAndroid Build Coastguard Worker if-eqz v0, :end 260*795d594fSAndroid Build Coastguard Worker# throw exceptions; 261*795d594fSAndroid Build Coastguard Worker throw v2 262*795d594fSAndroid Build Coastguard Worker :end 263*795d594fSAndroid Build Coastguard Worker# }} 264*795d594fSAndroid Build Coastguard Worker return-void 265*795d594fSAndroid Build Coastguard Worker# }} 266*795d594fSAndroid Build Coastguard Worker.end method 267*795d594fSAndroid Build Coastguard Worker 268*795d594fSAndroid Build Coastguard Worker{test_funcs} 269*795d594fSAndroid Build Coastguard Worker 270*795d594fSAndroid Build Coastguard Worker# }} 271*795d594fSAndroid Build Coastguard Worker""" 272*795d594fSAndroid Build Coastguard Worker 273*795d594fSAndroid Build Coastguard Worker IMPLEMENTS_TEMPLATE = """ 274*795d594fSAndroid Build Coastguard Worker.implements L{iface_name}; 275*795d594fSAndroid Build Coastguard Worker""" 276*795d594fSAndroid Build Coastguard Worker 277*795d594fSAndroid Build Coastguard Worker TEST_CALL_TEMPLATE = """ 278*795d594fSAndroid Build Coastguard Worker# try {{ 279*795d594fSAndroid Build Coastguard Worker# test_{iface}_super(); 280*795d594fSAndroid Build Coastguard Worker# }} catch (Throwable t) {{ 281*795d594fSAndroid Build Coastguard Worker# exceptions.addSuppressed(t); 282*795d594fSAndroid Build Coastguard Worker# failed = true; 283*795d594fSAndroid Build Coastguard Worker# }} 284*795d594fSAndroid Build Coastguard Worker :try_{iface}_start 285*795d594fSAndroid Build Coastguard Worker invoke-virtual {{p0}}, L{class_name};->test_{iface}_super()V 286*795d594fSAndroid Build Coastguard Worker goto :error_{iface}_end 287*795d594fSAndroid Build Coastguard Worker :try_{iface}_end 288*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/Throwable; {{:try_{iface}_start .. :try_{iface}_end}} :error_{iface}_start 289*795d594fSAndroid Build Coastguard Worker :error_{iface}_start 290*795d594fSAndroid Build Coastguard Worker move-exception v3 291*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v2, v3}}, Ljava/lang/Throwable;->addSuppressed(Ljava/lang/Throwable;)V 292*795d594fSAndroid Build Coastguard Worker const/4 v0, 1 293*795d594fSAndroid Build Coastguard Worker :error_{iface}_end 294*795d594fSAndroid Build Coastguard Worker""" 295*795d594fSAndroid Build Coastguard Worker 296*795d594fSAndroid Build Coastguard Worker TEST_FUNC_TEMPLATE = """ 297*795d594fSAndroid Build Coastguard Worker# public void test_{iface}_super() {{ 298*795d594fSAndroid Build Coastguard Worker# try {{ 299*795d594fSAndroid Build Coastguard Worker# System.out.println("{class_name} -> {iface}.super.getCalledInterface(): " + 300*795d594fSAndroid Build Coastguard Worker# {iface}.super.getCalledInterface()); 301*795d594fSAndroid Build Coastguard Worker# }} catch (NoSuchMethodError e) {{ 302*795d594fSAndroid Build Coastguard Worker# System.out.println("{class_name} -> {iface}.super.getCalledInterface(): NoSuchMethodError"); 303*795d594fSAndroid Build Coastguard Worker# }} catch (IncompatibleClassChangeError e) {{ 304*795d594fSAndroid Build Coastguard Worker# System.out.println("{class_name} -> {iface}.super.getCalledInterface(): IncompatibleClassChangeError"); 305*795d594fSAndroid Build Coastguard Worker# }} catch (Throwable t) {{ 306*795d594fSAndroid Build Coastguard Worker# System.out.println("{class_name} -> {iface}.super.getCalledInterface(): Unknown error occurred"); 307*795d594fSAndroid Build Coastguard Worker# throw t; 308*795d594fSAndroid Build Coastguard Worker# }} 309*795d594fSAndroid Build Coastguard Worker# }} 310*795d594fSAndroid Build Coastguard Worker.method public test_{iface}_super()V 311*795d594fSAndroid Build Coastguard Worker .locals 3 312*795d594fSAndroid Build Coastguard Worker sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; 313*795d594fSAndroid Build Coastguard Worker :try_start 314*795d594fSAndroid Build Coastguard Worker const-string v1, "{class_name} -> {iface}.super.getCalledInterface(): " 315*795d594fSAndroid Build Coastguard Worker invoke-super {{p0}}, L{iface};->getCalledInterface()Ljava/lang/String; 316*795d594fSAndroid Build Coastguard Worker move-result-object v2 317*795d594fSAndroid Build Coastguard Worker 318*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v1, v2}}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; 319*795d594fSAndroid Build Coastguard Worker move-result-object v1 320*795d594fSAndroid Build Coastguard Worker 321*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 322*795d594fSAndroid Build Coastguard Worker 323*795d594fSAndroid Build Coastguard Worker return-void 324*795d594fSAndroid Build Coastguard Worker :try_end 325*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/NoSuchMethodError; {{:try_start .. :try_end}} :AME_catch 326*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/IncompatibleClassChangeError; {{:try_start .. :try_end}} :ICCE_catch 327*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/Throwable; {{:try_start .. :try_end}} :throwable_catch 328*795d594fSAndroid Build Coastguard Worker :AME_catch 329*795d594fSAndroid Build Coastguard Worker const-string v1, "{class_name} -> {iface}.super.getCalledInterface(): NoSuchMethodError" 330*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 331*795d594fSAndroid Build Coastguard Worker return-void 332*795d594fSAndroid Build Coastguard Worker :ICCE_catch 333*795d594fSAndroid Build Coastguard Worker const-string v1, "{class_name} -> {iface}.super.getCalledInterface(): IncompatibleClassChangeError" 334*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 335*795d594fSAndroid Build Coastguard Worker return-void 336*795d594fSAndroid Build Coastguard Worker :throwable_catch 337*795d594fSAndroid Build Coastguard Worker move-exception v2 338*795d594fSAndroid Build Coastguard Worker const-string v1, "{class_name} -> {iface}.super.getCalledInterface(): Unknown error occurred" 339*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 340*795d594fSAndroid Build Coastguard Worker throw v2 341*795d594fSAndroid Build Coastguard Worker.end method 342*795d594fSAndroid Build Coastguard Worker""".strip() 343*795d594fSAndroid Build Coastguard Worker 344*795d594fSAndroid Build Coastguard Worker OUTPUT_TEMPLATE = "{class_name} -> {iface}.super.getCalledInterface(): {result}" 345*795d594fSAndroid Build Coastguard Worker 346*795d594fSAndroid Build Coastguard Worker def __init__(self, ifaces, name = None): 347*795d594fSAndroid Build Coastguard Worker """ 348*795d594fSAndroid Build Coastguard Worker Initialize this test class which implements the given interfaces 349*795d594fSAndroid Build Coastguard Worker """ 350*795d594fSAndroid Build Coastguard Worker self.ifaces = ifaces 351*795d594fSAndroid Build Coastguard Worker if name is None: 352*795d594fSAndroid Build Coastguard Worker self.class_name = "CLASS_"+gensym() 353*795d594fSAndroid Build Coastguard Worker else: 354*795d594fSAndroid Build Coastguard Worker self.class_name = name 355*795d594fSAndroid Build Coastguard Worker 356*795d594fSAndroid Build Coastguard Worker def get_initial_build_version(self): 357*795d594fSAndroid Build Coastguard Worker """ 358*795d594fSAndroid Build Coastguard Worker Returns a version of this class that can be used for the initial build (meaning no compiler 359*795d594fSAndroid Build Coastguard Worker checks will be triggered). 360*795d594fSAndroid Build Coastguard Worker """ 361*795d594fSAndroid Build Coastguard Worker return TestClass([i.get_initial_build_version() for i in self.ifaces], self.class_name) 362*795d594fSAndroid Build Coastguard Worker 363*795d594fSAndroid Build Coastguard Worker def initial_build_different(self): 364*795d594fSAndroid Build Coastguard Worker return False 365*795d594fSAndroid Build Coastguard Worker 366*795d594fSAndroid Build Coastguard Worker def get_name(self): 367*795d594fSAndroid Build Coastguard Worker """ 368*795d594fSAndroid Build Coastguard Worker Gets the name of this interface 369*795d594fSAndroid Build Coastguard Worker """ 370*795d594fSAndroid Build Coastguard Worker return self.class_name 371*795d594fSAndroid Build Coastguard Worker 372*795d594fSAndroid Build Coastguard Worker def get_tree(self): 373*795d594fSAndroid Build Coastguard Worker """ 374*795d594fSAndroid Build Coastguard Worker Print out a representation of the type tree of this class 375*795d594fSAndroid Build Coastguard Worker """ 376*795d594fSAndroid Build Coastguard Worker return "[{fname} {iftree}]".format(fname = self.get_name(), iftree = print_tree(self.ifaces)) 377*795d594fSAndroid Build Coastguard Worker 378*795d594fSAndroid Build Coastguard Worker def get_test_output(self): 379*795d594fSAndroid Build Coastguard Worker return '\n'.join(map(lambda a: self.OUTPUT_TEMPLATE.format(class_name = self.get_name(), 380*795d594fSAndroid Build Coastguard Worker iface = a.get_name(), 381*795d594fSAndroid Build Coastguard Worker result = a.get_output()), 382*795d594fSAndroid Build Coastguard Worker self.ifaces)) 383*795d594fSAndroid Build Coastguard Worker 384*795d594fSAndroid Build Coastguard Worker def __str__(self): 385*795d594fSAndroid Build Coastguard Worker """ 386*795d594fSAndroid Build Coastguard Worker Print the smali code for this class. 387*795d594fSAndroid Build Coastguard Worker """ 388*795d594fSAndroid Build Coastguard Worker funcs = '\n'.join(map(lambda a: self.TEST_FUNC_TEMPLATE.format(iface = a.get_name(), 389*795d594fSAndroid Build Coastguard Worker class_name = self.get_name()), 390*795d594fSAndroid Build Coastguard Worker self.ifaces)) 391*795d594fSAndroid Build Coastguard Worker calls = '\n'.join(map(lambda a: self.TEST_CALL_TEMPLATE.format(iface = a.get_name(), 392*795d594fSAndroid Build Coastguard Worker class_name = self.get_name()), 393*795d594fSAndroid Build Coastguard Worker self.ifaces)) 394*795d594fSAndroid Build Coastguard Worker s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()), 395*795d594fSAndroid Build Coastguard Worker self.ifaces)) 396*795d594fSAndroid Build Coastguard Worker j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces)) 397*795d594fSAndroid Build Coastguard Worker return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), 398*795d594fSAndroid Build Coastguard Worker implements_spec = s_ifaces, 399*795d594fSAndroid Build Coastguard Worker ifaces = j_ifaces, 400*795d594fSAndroid Build Coastguard Worker class_name = self.class_name, 401*795d594fSAndroid Build Coastguard Worker test_funcs = funcs, 402*795d594fSAndroid Build Coastguard Worker test_calls = calls) 403*795d594fSAndroid Build Coastguard Worker 404*795d594fSAndroid Build Coastguard Workerclass IncompatibleClassChangeErrorResult(mixins.Named): 405*795d594fSAndroid Build Coastguard Worker def get_name(self): 406*795d594fSAndroid Build Coastguard Worker return "IncompatibleClassChangeError" 407*795d594fSAndroid Build Coastguard Worker 408*795d594fSAndroid Build Coastguard WorkerICCE = IncompatibleClassChangeErrorResult() 409*795d594fSAndroid Build Coastguard Worker 410*795d594fSAndroid Build Coastguard Workerclass NoSuchMethodErrorResult(mixins.Named): 411*795d594fSAndroid Build Coastguard Worker def get_name(self): 412*795d594fSAndroid Build Coastguard Worker return "NoSuchMethodError" 413*795d594fSAndroid Build Coastguard Worker 414*795d594fSAndroid Build Coastguard WorkerNSME = NoSuchMethodErrorResult() 415*795d594fSAndroid Build Coastguard Worker 416*795d594fSAndroid Build Coastguard Workerclass TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): 417*795d594fSAndroid Build Coastguard Worker """ 418*795d594fSAndroid Build Coastguard Worker An interface that will be used to test default method resolution order. 419*795d594fSAndroid Build Coastguard Worker """ 420*795d594fSAndroid Build Coastguard Worker 421*795d594fSAndroid Build Coastguard Worker TEST_INTERFACE_TEMPLATE = """{copyright} 422*795d594fSAndroid Build Coastguard Worker.class public abstract interface L{class_name}; 423*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object; 424*795d594fSAndroid Build Coastguard Worker{implements_spec} 425*795d594fSAndroid Build Coastguard Worker 426*795d594fSAndroid Build Coastguard Worker# public interface {class_name} {extends} {ifaces} {{ 427*795d594fSAndroid Build Coastguard Worker 428*795d594fSAndroid Build Coastguard Worker{funcs} 429*795d594fSAndroid Build Coastguard Worker 430*795d594fSAndroid Build Coastguard Worker# }} 431*795d594fSAndroid Build Coastguard Worker""" 432*795d594fSAndroid Build Coastguard Worker 433*795d594fSAndroid Build Coastguard Worker ABSTRACT_FUNC_TEMPLATE = """ 434*795d594fSAndroid Build Coastguard Worker""" 435*795d594fSAndroid Build Coastguard Worker 436*795d594fSAndroid Build Coastguard Worker DEFAULT_FUNC_TEMPLATE = """ 437*795d594fSAndroid Build Coastguard Worker# public default String getCalledInterface() {{ 438*795d594fSAndroid Build Coastguard Worker# return "{class_name}"; 439*795d594fSAndroid Build Coastguard Worker# }} 440*795d594fSAndroid Build Coastguard Worker.method public getCalledInterface()Ljava/lang/String; 441*795d594fSAndroid Build Coastguard Worker .locals 1 442*795d594fSAndroid Build Coastguard Worker const-string v0, "{class_name}" 443*795d594fSAndroid Build Coastguard Worker return-object v0 444*795d594fSAndroid Build Coastguard Worker.end method 445*795d594fSAndroid Build Coastguard Worker""" 446*795d594fSAndroid Build Coastguard Worker 447*795d594fSAndroid Build Coastguard Worker IMPLEMENTS_TEMPLATE = """ 448*795d594fSAndroid Build Coastguard Worker.implements L{iface_name}; 449*795d594fSAndroid Build Coastguard Worker""" 450*795d594fSAndroid Build Coastguard Worker 451*795d594fSAndroid Build Coastguard Worker def __init__(self, ifaces, default, name = None): 452*795d594fSAndroid Build Coastguard Worker """ 453*795d594fSAndroid Build Coastguard Worker Initialize interface with the given super-interfaces 454*795d594fSAndroid Build Coastguard Worker """ 455*795d594fSAndroid Build Coastguard Worker self.ifaces = ifaces 456*795d594fSAndroid Build Coastguard Worker self.default = default 457*795d594fSAndroid Build Coastguard Worker if name is None: 458*795d594fSAndroid Build Coastguard Worker end = "_DEFAULT" if default else "" 459*795d594fSAndroid Build Coastguard Worker self.class_name = "INTERFACE_"+gensym()+end 460*795d594fSAndroid Build Coastguard Worker else: 461*795d594fSAndroid Build Coastguard Worker self.class_name = name 462*795d594fSAndroid Build Coastguard Worker 463*795d594fSAndroid Build Coastguard Worker def get_initial_build_version(self): 464*795d594fSAndroid Build Coastguard Worker """ 465*795d594fSAndroid Build Coastguard Worker Returns a version of this class that can be used for the initial build (meaning no compiler 466*795d594fSAndroid Build Coastguard Worker checks will be triggered). 467*795d594fSAndroid Build Coastguard Worker """ 468*795d594fSAndroid Build Coastguard Worker return TestInterface([i.get_initial_build_version() for i in self.ifaces], 469*795d594fSAndroid Build Coastguard Worker True, 470*795d594fSAndroid Build Coastguard Worker self.class_name) 471*795d594fSAndroid Build Coastguard Worker 472*795d594fSAndroid Build Coastguard Worker def initial_build_different(self): 473*795d594fSAndroid Build Coastguard Worker return not self.default 474*795d594fSAndroid Build Coastguard Worker 475*795d594fSAndroid Build Coastguard Worker def get_name(self): 476*795d594fSAndroid Build Coastguard Worker """ 477*795d594fSAndroid Build Coastguard Worker Gets the name of this interface 478*795d594fSAndroid Build Coastguard Worker """ 479*795d594fSAndroid Build Coastguard Worker return self.class_name 480*795d594fSAndroid Build Coastguard Worker 481*795d594fSAndroid Build Coastguard Worker def __iter__(self): 482*795d594fSAndroid Build Coastguard Worker """ 483*795d594fSAndroid Build Coastguard Worker Performs depth-first traversal of the interface tree this interface is the 484*795d594fSAndroid Build Coastguard Worker root of. Does not filter out repeats. 485*795d594fSAndroid Build Coastguard Worker """ 486*795d594fSAndroid Build Coastguard Worker for i in self.ifaces: 487*795d594fSAndroid Build Coastguard Worker yield i 488*795d594fSAndroid Build Coastguard Worker yield from i 489*795d594fSAndroid Build Coastguard Worker 490*795d594fSAndroid Build Coastguard Worker def get_called(self): 491*795d594fSAndroid Build Coastguard Worker """ 492*795d594fSAndroid Build Coastguard Worker Get the interface whose default method would be called when calling the 493*795d594fSAndroid Build Coastguard Worker CalledInterfaceName function. 494*795d594fSAndroid Build Coastguard Worker """ 495*795d594fSAndroid Build Coastguard Worker all_ifaces = set(iface for iface in self if iface.default) 496*795d594fSAndroid Build Coastguard Worker for i in all_ifaces: 497*795d594fSAndroid Build Coastguard Worker if all(map(lambda j: i not in j.get_super_types(), all_ifaces)): 498*795d594fSAndroid Build Coastguard Worker return i 499*795d594fSAndroid Build Coastguard Worker return ICCE if any(map(lambda i: i.default, all_ifaces)) else NSME 500*795d594fSAndroid Build Coastguard Worker 501*795d594fSAndroid Build Coastguard Worker def get_super_types(self): 502*795d594fSAndroid Build Coastguard Worker """ 503*795d594fSAndroid Build Coastguard Worker Returns a set of all the supertypes of this interface 504*795d594fSAndroid Build Coastguard Worker """ 505*795d594fSAndroid Build Coastguard Worker return set(i2 for i2 in self) 506*795d594fSAndroid Build Coastguard Worker 507*795d594fSAndroid Build Coastguard Worker def get_output(self): 508*795d594fSAndroid Build Coastguard Worker if self.default: 509*795d594fSAndroid Build Coastguard Worker return self.get_name() 510*795d594fSAndroid Build Coastguard Worker else: 511*795d594fSAndroid Build Coastguard Worker return self.get_called().get_name() 512*795d594fSAndroid Build Coastguard Worker 513*795d594fSAndroid Build Coastguard Worker def get_tree(self): 514*795d594fSAndroid Build Coastguard Worker """ 515*795d594fSAndroid Build Coastguard Worker Print out a representation of the type tree of this class 516*795d594fSAndroid Build Coastguard Worker """ 517*795d594fSAndroid Build Coastguard Worker return "[{class_name} {iftree}]".format(class_name = self.get_name(), 518*795d594fSAndroid Build Coastguard Worker iftree = print_tree(self.ifaces)) 519*795d594fSAndroid Build Coastguard Worker def __str__(self): 520*795d594fSAndroid Build Coastguard Worker """ 521*795d594fSAndroid Build Coastguard Worker Print the smali code for this interface. 522*795d594fSAndroid Build Coastguard Worker """ 523*795d594fSAndroid Build Coastguard Worker s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()), 524*795d594fSAndroid Build Coastguard Worker self.ifaces)) 525*795d594fSAndroid Build Coastguard Worker j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces)) 526*795d594fSAndroid Build Coastguard Worker if self.default: 527*795d594fSAndroid Build Coastguard Worker funcs = self.DEFAULT_FUNC_TEMPLATE.format(class_name = self.class_name) 528*795d594fSAndroid Build Coastguard Worker else: 529*795d594fSAndroid Build Coastguard Worker funcs = self.ABSTRACT_FUNC_TEMPLATE 530*795d594fSAndroid Build Coastguard Worker return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'), 531*795d594fSAndroid Build Coastguard Worker implements_spec = s_ifaces, 532*795d594fSAndroid Build Coastguard Worker extends = "extends" if len(self.ifaces) else "", 533*795d594fSAndroid Build Coastguard Worker ifaces = j_ifaces, 534*795d594fSAndroid Build Coastguard Worker funcs = funcs, 535*795d594fSAndroid Build Coastguard Worker class_name = self.class_name) 536*795d594fSAndroid Build Coastguard Worker 537*795d594fSAndroid Build Coastguard Workerdef dump_tree(ifaces): 538*795d594fSAndroid Build Coastguard Worker """ 539*795d594fSAndroid Build Coastguard Worker Yields all the interfaces transitively implemented by the set in 540*795d594fSAndroid Build Coastguard Worker reverse-depth-first order 541*795d594fSAndroid Build Coastguard Worker """ 542*795d594fSAndroid Build Coastguard Worker for i in ifaces: 543*795d594fSAndroid Build Coastguard Worker yield from dump_tree(i.ifaces) 544*795d594fSAndroid Build Coastguard Worker yield i 545*795d594fSAndroid Build Coastguard Worker 546*795d594fSAndroid Build Coastguard Workerdef print_tree(ifaces): 547*795d594fSAndroid Build Coastguard Worker """ 548*795d594fSAndroid Build Coastguard Worker Prints the tree for the given ifaces. 549*795d594fSAndroid Build Coastguard Worker """ 550*795d594fSAndroid Build Coastguard Worker return " ".join(i.get_tree() for i in ifaces) 551*795d594fSAndroid Build Coastguard Worker 552*795d594fSAndroid Build Coastguard Worker# Cached output of subtree_sizes for speed of access. 553*795d594fSAndroid Build Coastguard WorkerSUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i)) for i in range(MAX_IFACE_DEPTH + 1)] 554*795d594fSAndroid Build Coastguard Worker 555*795d594fSAndroid Build Coastguard Workerdef create_test_classes(): 556*795d594fSAndroid Build Coastguard Worker """ 557*795d594fSAndroid Build Coastguard Worker Yield all the test classes with the different interface trees 558*795d594fSAndroid Build Coastguard Worker """ 559*795d594fSAndroid Build Coastguard Worker for num in range(1, MAX_IFACE_DEPTH + 1): 560*795d594fSAndroid Build Coastguard Worker for split in SUBTREES[num]: 561*795d594fSAndroid Build Coastguard Worker ifaces = [] 562*795d594fSAndroid Build Coastguard Worker for sub in split: 563*795d594fSAndroid Build Coastguard Worker ifaces.append(list(create_interface_trees(sub))) 564*795d594fSAndroid Build Coastguard Worker for supers in itertools.product(*ifaces): 565*795d594fSAndroid Build Coastguard Worker yield TestClass(supers) 566*795d594fSAndroid Build Coastguard Worker 567*795d594fSAndroid Build Coastguard Workerdef create_interface_trees(num): 568*795d594fSAndroid Build Coastguard Worker """ 569*795d594fSAndroid Build Coastguard Worker Yield all the interface trees up to 'num' depth. 570*795d594fSAndroid Build Coastguard Worker """ 571*795d594fSAndroid Build Coastguard Worker if num == 0: 572*795d594fSAndroid Build Coastguard Worker yield TestInterface(tuple(), False) 573*795d594fSAndroid Build Coastguard Worker yield TestInterface(tuple(), True) 574*795d594fSAndroid Build Coastguard Worker return 575*795d594fSAndroid Build Coastguard Worker for split in SUBTREES[num]: 576*795d594fSAndroid Build Coastguard Worker ifaces = [] 577*795d594fSAndroid Build Coastguard Worker for sub in split: 578*795d594fSAndroid Build Coastguard Worker ifaces.append(list(create_interface_trees(sub))) 579*795d594fSAndroid Build Coastguard Worker for supers in itertools.product(*ifaces): 580*795d594fSAndroid Build Coastguard Worker yield TestInterface(supers, False) 581*795d594fSAndroid Build Coastguard Worker yield TestInterface(supers, True) 582*795d594fSAndroid Build Coastguard Worker for selected in (set(dump_tree(supers)) - set(supers)): 583*795d594fSAndroid Build Coastguard Worker yield TestInterface(tuple([selected] + list(supers)), True) 584*795d594fSAndroid Build Coastguard Worker yield TestInterface(tuple([selected] + list(supers)), False) 585*795d594fSAndroid Build Coastguard Worker # TODO Should add on some from higher up the tree. 586*795d594fSAndroid Build Coastguard Worker 587*795d594fSAndroid Build Coastguard Workerdef create_all_test_files(): 588*795d594fSAndroid Build Coastguard Worker """ 589*795d594fSAndroid Build Coastguard Worker Creates all the objects representing the files in this test. They just need to 590*795d594fSAndroid Build Coastguard Worker be dumped. 591*795d594fSAndroid Build Coastguard Worker """ 592*795d594fSAndroid Build Coastguard Worker mc = MainClass() 593*795d594fSAndroid Build Coastguard Worker classes = {mc} 594*795d594fSAndroid Build Coastguard Worker for clazz in create_test_classes(): 595*795d594fSAndroid Build Coastguard Worker classes.add(clazz) 596*795d594fSAndroid Build Coastguard Worker for i in dump_tree(clazz.ifaces): 597*795d594fSAndroid Build Coastguard Worker classes.add(i) 598*795d594fSAndroid Build Coastguard Worker mc.add_test(clazz) 599*795d594fSAndroid Build Coastguard Worker return mc, classes 600*795d594fSAndroid Build Coastguard Worker 601*795d594fSAndroid Build Coastguard Workerdef main(argv): 602*795d594fSAndroid Build Coastguard Worker smali_dir = Path(argv[1]) 603*795d594fSAndroid Build Coastguard Worker if not smali_dir.exists() or not smali_dir.is_dir(): 604*795d594fSAndroid Build Coastguard Worker print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr) 605*795d594fSAndroid Build Coastguard Worker sys.exit(1) 606*795d594fSAndroid Build Coastguard Worker expected_txt = Path(argv[2]) 607*795d594fSAndroid Build Coastguard Worker mainclass, all_files = create_all_test_files() 608*795d594fSAndroid Build Coastguard Worker with expected_txt.open('w') as out: 609*795d594fSAndroid Build Coastguard Worker print(mainclass.get_expected(), file=out) 610*795d594fSAndroid Build Coastguard Worker for f in all_files: 611*795d594fSAndroid Build Coastguard Worker f.dump(smali_dir) 612*795d594fSAndroid Build Coastguard Worker 613*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__': 614*795d594fSAndroid Build Coastguard Worker main(sys.argv) 615