1705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light#!/usr/bin/python3 2705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# 3705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# Copyright (C) 2015 The Android Open Source Project 4705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# 5705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# Licensed under the Apache License, Version 2.0 (the "License"); 6705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# you may not use this file except in compliance with the License. 7705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# You may obtain a copy of the License at 8705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# 9705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# http://www.apache.org/licenses/LICENSE-2.0 10705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# 11705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# Unless required by applicable law or agreed to in writing, software 12705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# distributed under the License is distributed on an "AS IS" BASIS, 13705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# See the License for the specific language governing permissions and 15705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# limitations under the License. 16705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 17705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 18705ad49f353d3f90d8b63625aca2c2035bacdbefAlex LightGenerate Smali test files for test 967. 19705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 20705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 21705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightimport os 22705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightimport sys 23705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightfrom pathlib import Path 24705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 25705ad49f353d3f90d8b63625aca2c2035bacdbefAlex LightBUILD_TOP = os.getenv("ANDROID_BUILD_TOP") 26705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightif BUILD_TOP is None: 27705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) 28705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light sys.exit(1) 29705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 30705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# Allow us to import utils and mixins. 31705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightsys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python")) 32705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 33705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightfrom testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks 34705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightimport testgen.mixins as mixins 35705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 36705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightfrom enum import Enum 37705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightfrom functools import total_ordering 38705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightimport itertools 39705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightimport string 40705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 41705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# The max depth the type tree can have. 426157a5d56d310d781ea61d2fd686dfe2ea2d301cAlex LightMAX_IFACE_DEPTH = 2 43705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 44705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): 45705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 46705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light A Main.smali file containing the Main class and the main function. It will run 47705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light all the test functions we have. 48705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 49705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 50705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light MAIN_CLASS_TEMPLATE = """{copyright} 51705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 52705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.class public LMain; 53705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.super Ljava/lang/Object; 54705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 55705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# class Main {{ 56705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 57705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public constructor <init>()V 58705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .registers 1 59705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V 60705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 61705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 62705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 63705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light{test_funcs} 64705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 65705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light{main_func} 66705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 67705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 68705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 69705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 70705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light MAIN_FUNCTION_TEMPLATE = """ 71705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public static void main(String[] args) {{ 72705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public static main([Ljava/lang/String;)V 73705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .locals 0 74705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 75705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light {test_group_invoke} 76705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 77705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 78705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 79705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 80705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 81705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 82705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light TEST_GROUP_INVOKE_TEMPLATE = """ 83705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# {test_name}(); 84705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-static {{}}, {test_name}()V 85705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 86705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 87705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __init__(self): 88705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 89705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Initialize this MainClass. We start out with no tests. 90705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 91705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.tests = set() 92705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 93705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_expected(self): 94705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 95705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Get the expected output of this test. 96705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 97705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light all_tests = sorted(self.tests) 98705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return filter_blanks("\n".join(a.get_expected() for a in all_tests)) 99705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 100705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def add_test(self, ty): 101705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 102705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Add a test for the concrete type 'ty' 103705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 104705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.tests.add(Func(ty)) 105705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 106705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_name(self): 107705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 108705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Get the name of this class 109705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 110705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "Main" 111705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 112705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __str__(self): 113705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 114705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Print the MainClass smali code. 115705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 116705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light all_tests = sorted(self.tests) 117705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light test_invoke = "" 118705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light test_funcs = "" 119705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for t in all_tests: 120705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light test_funcs += str(t) 121705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for t in all_tests: 122705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) 123705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) 124705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 125705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright("smali"), 126705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light test_funcs = test_funcs, 127705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light main_func = main_func) 128705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 129705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass Func(mixins.Named, mixins.NameComparableMixin): 130705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 131705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light A function that tests the functionality of a concrete type. Should only be 132705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light constructed by MainClass.add_test. 133705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 134705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 135705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light TEST_FUNCTION_TEMPLATE = """ 136705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public static void {fname}() {{ 137705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# {farg} v = null; 138705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# try {{ 139705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# v = new {farg}(); 140705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} catch (Throwable e) {{ 141705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("Unexpected error occurred which creating {farg} instance"); 142705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# e.printStackTrace(System.out); 143705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# return; 144705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 145705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# try {{ 146705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# v.callSupers(); 147705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# return; 148705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} catch (Throwable e) {{ 149705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# e.printStackTrace(System.out); 150705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# return; 151705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 152705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 153705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public static {fname}()V 154705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .locals 7 155705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream; 156705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 157705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :new_{fname}_try_start 158705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light new-instance v0, L{farg}; 159705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-direct {{v0}}, L{farg};-><init>()V 160705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light goto :call_{fname}_try_start 161705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :new_{fname}_try_end 162705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .catch Ljava/lang/Throwable; {{:new_{fname}_try_start .. :new_{fname}_try_end}} :new_error_{fname}_start 163705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :new_error_{fname}_start 164705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light move-exception v6 165705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v5, "Unexpected error occurred which creating {farg} instance" 166705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 167705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V 168705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 169705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :call_{fname}_try_start 170705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0}}, L{farg};->callSupers()V 171705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 172705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :call_{fname}_try_end 173705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .catch Ljava/lang/Throwable; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start 174705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :error_{fname}_start 175705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light move-exception v6 176705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V 177705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 178705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 179705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 180705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 181705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __init__(self, farg): 182705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 183705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Initialize a test function for the given argument 184705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 185705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.farg = farg 186705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 187705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_expected(self): 188705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 189705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Get the expected output calling this function. 190705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 191705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "\n".join(self.farg.get_expected()) 192705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 193705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_name(self): 194705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 195705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Get the name of this function 196705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 197705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "TEST_FUNC_{}".format(self.farg.get_name()) 198705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 199705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __str__(self): 200705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 201705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Print the smali code of this function. 202705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 203705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.TEST_FUNCTION_TEMPLATE.format(fname = self.get_name(), 204705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light farg = self.farg.get_name()) 205705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 206705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass InterfaceCallResponse(Enum): 207705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 208705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light An enumeration of all the different types of responses to an interface call we can have 209705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 210705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light NoError = 0 211705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light NoSuchMethodError = 1 212705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light AbstractMethodError = 2 213705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light IncompatibleClassChangeError = 3 214705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 215705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_output_format(self): 216705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if self == InterfaceCallResponse.NoError: 217705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "No exception thrown for {iface_name}.super.call() on {tree}\n" 218705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif self == InterfaceCallResponse.AbstractMethodError: 219705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "AbstractMethodError thrown for {iface_name}.super.call() on {tree}\n" 220705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif self == InterfaceCallResponse.NoSuchMethodError: 221705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "NoSuchMethodError thrown for {iface_name}.super.call() on {tree}\n" 222705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 223705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "IncompatibleClassChangeError thrown for {iface_name}.super.call() on {tree}\n" 224705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 225705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): 226705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 227705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light A class that will be instantiated to test interface super behavior. 228705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 229705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 230705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light TEST_CLASS_TEMPLATE = """{copyright} 231705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 232705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.class public L{class_name}; 233705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.super Ljava/lang/Object; 234705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light{implements_spec} 235705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 236705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public class {class_name} implements {ifaces} {{ 237705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 238705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public constructor <init>()V 239705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .registers 1 240705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V 241705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 242705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 243705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 244705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public void call() {{ 245705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# throw new Error("{class_name}.call(v) should never get called!"); 246705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 247705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public call()V 248705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .locals 2 249705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light new-instance v0, Ljava/lang/Error; 250705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "{class_name}.call(v) should never get called!" 251705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-direct {{v0, v1}}, Ljava/lang/Error;-><init>(Ljava/lang/String;)V 252705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light throw v0 253705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 254705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 255705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public void callSupers() {{ 256705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public callSupers()V 257705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .locals 4 258705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; 259705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 260705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light {super_calls} 261705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 262705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 263705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 264705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 265705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 266705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 267705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 268705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light SUPER_CALL_TEMPLATE = """ 269705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# try {{ 270705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("Calling {iface_name}.super.call() on {tree}"); 271705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# {iface_name}.super.call(); 272705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("No exception thrown for {iface_name}.super.call() on {tree}"); 273705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} catch (AbstractMethodError ame) {{ 274705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("AbstractMethodError thrown for {iface_name}.super.call() on {tree}"); 275705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} catch (NoSuchMethodError nsme) {{ 276705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("NoSuchMethodError thrown for {iface_name}.super.call() on {tree}"); 277705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} catch (IncompatibleClassChangeError icce) {{ 278705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("IncompatibleClassChangeError thrown for {iface_name}.super.call() on {tree}"); 279705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} catch (Throwable t) {{ 280705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# System.out.println("Unknown error thrown for {iface_name}.super.call() on {tree}"); 281705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# throw t; 282705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 283705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :call_{class_name}_{iface_name}_try_start 284705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "Calling {iface_name}.super.call() on {tree}" 285705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 286705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-super {{p0}}, L{iface_name};->call()V 287705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "No exception thrown for {iface_name}.super.call() on {tree}" 288705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 289705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light goto :call_{class_name}_{iface_name}_end 290705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :call_{class_name}_{iface_name}_try_end 291705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .catch Ljava/lang/AbstractMethodError; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :AME_{class_name}_{iface_name}_start 292705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .catch Ljava/lang/NoSuchMethodError; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :NSME_{class_name}_{iface_name}_start 293705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .catch Ljava/lang/IncompatibleClassChangeError; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :ICCE_{class_name}_{iface_name}_start 294705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .catch Ljava/lang/Throwable; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :error_{class_name}_{iface_name}_start 295705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :AME_{class_name}_{iface_name}_start 296705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "AbstractMethodError thrown for {iface_name}.super.call() on {tree}" 297705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 298705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light goto :call_{class_name}_{iface_name}_end 299705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :NSME_{class_name}_{iface_name}_start 300705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "NoSuchMethodError thrown for {iface_name}.super.call() on {tree}" 301705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 302705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light goto :call_{class_name}_{iface_name}_end 303705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :ICCE_{class_name}_{iface_name}_start 304705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "IncompatibleClassChangeError thrown for {iface_name}.super.call() on {tree}" 305705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 306705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light goto :call_{class_name}_{iface_name}_end 307705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :error_{class_name}_{iface_name}_start 308705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light move-exception v2 309705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light const-string v1, "Unknown error thrown for {iface_name}.super.call() on {tree}" 310705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 311705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light throw v2 312705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light :call_{class_name}_{iface_name}_end 313705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 314705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 315705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light IMPLEMENTS_TEMPLATE = """ 316705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.implements L{iface_name}; 317705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 318705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 319705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light OUTPUT_PREFIX = "Calling {iface_name}.super.call() on {tree}\n" 320705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 321705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __init__(self, ifaces): 322705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 323705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Initialize this test class which implements the given interfaces 324705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 325705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.ifaces = ifaces 326705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.class_name = "CLASS_"+gensym() 327705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 328705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_name(self): 329705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 330705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Get the name of this class 331705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 332705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.class_name 333705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 334705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_tree(self): 335705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 336705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Print out a representation of the type tree of this class 337705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 338705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "[{class_name} {iface_tree}]".format(class_name = self.class_name, 339705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light iface_tree = print_tree(self.ifaces)) 340705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 341705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __iter__(self): 342705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 343705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Step through all interfaces implemented transitively by this class 344705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 345705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for i in self.ifaces: 346705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield i 347705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield from i 348705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 349705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_expected(self): 350705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for iface in self.ifaces: 351705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield self.OUTPUT_PREFIX.format(iface_name = iface.get_name(), tree = self.get_tree()) 352705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield from iface.get_expected() 353705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield iface.get_response().get_output_format().format(iface_name = iface.get_name(), 354705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light tree = self.get_tree()) 355705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 356705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __str__(self): 357705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 358705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Print the smali code of this class. 359705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 360705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()), 361705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.ifaces)) 362705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces)) 363705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light super_template = self.SUPER_CALL_TEMPLATE 364705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light super_calls = "\n".join(super_template.format(iface_name = iface.get_name(), 365705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light class_name = self.get_name(), 366705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light tree = self.get_tree()) for iface in self.ifaces) 367705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), 368705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ifaces = j_ifaces, 369705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light implements_spec = s_ifaces, 370705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light tree = self.get_tree(), 371705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light class_name = self.class_name, 372705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light super_calls = super_calls) 373705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 374705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass InterfaceType(Enum): 375705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 376705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light An enumeration of all the different types of interfaces we can have. 377705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 378705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light default: It has a default method 379705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light abstract: It has a method declared but not defined 380705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light empty: It does not have the method 381705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 382705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light default = 0 383705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light abstract = 1 384705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light empty = 2 385705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 386705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_suffix(self): 387705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if self == InterfaceType.default: 388705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "_DEFAULT" 389705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif self == InterfaceType.abstract: 390705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "_ABSTRACT" 391705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif self == InterfaceType.empty: 392705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "_EMPTY" 393705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 394705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light raise TypeError("Interface type had illegal value.") 395705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 396705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass ConflictInterface: 397705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 398705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light A singleton representing a conflict of default methods. 399705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 400705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 401705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_conflict(self): 402705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 403705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is a conflict interface and calling the method on this interface will 404705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in an IncompatibleClassChangeError. 405705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 406705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return True 407705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 408705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_abstract(self): 409705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 410705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is an abstract interface and calling the method on this interface will 411705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in an AbstractMethodError. 412705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 413705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return False 414705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 415705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_empty(self): 416705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 417705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is an abstract interface and calling the method on this interface will 418705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in a NoSuchMethodError. 419705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 420705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return False 421705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 422705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_default(self): 423705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 424705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is a default interface and calling the method on this interface will 425705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in a method actually being called. 426705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 427705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return False 428705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 429705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_response(self): 430705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return InterfaceCallResponse.IncompatibleClassChangeError 431705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 432705ad49f353d3f90d8b63625aca2c2035bacdbefAlex LightCONFLICT_TYPE = ConflictInterface() 433705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 434705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightclass TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): 435705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 436705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light An interface that will be used to test default method resolution order. 437705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 438705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 439705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light TEST_INTERFACE_TEMPLATE = """{copyright} 440705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.class public abstract interface L{class_name}; 441705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.super Ljava/lang/Object; 442705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light{implements_spec} 443705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 444705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public interface {class_name} {extends} {ifaces} {{ 445705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 446705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light{func} 447705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 448705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 449705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 450705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 451705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light SUPER_CALL_TEMPLATE = TestClass.SUPER_CALL_TEMPLATE 452705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light OUTPUT_PREFIX = TestClass.OUTPUT_PREFIX 453705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 454705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light DEFAULT_FUNC_TEMPLATE = """ 455705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public default void call() {{ 456705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public call()V 457705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light .locals 4 458705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; 459705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 460705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light {super_calls} 461705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 462705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return-void 463705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 464705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# }} 465705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 466705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 467705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ABSTRACT_FUNC_TEMPLATE = """ 468705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# public void call(); 469705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.method public abstract call()V 470705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.end method 471705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 472705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 473705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light EMPTY_FUNC_TEMPLATE = """""" 474705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 475705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light IMPLEMENTS_TEMPLATE = """ 476705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light.implements L{iface_name}; 477705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light""" 478705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 479705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __init__(self, ifaces, iface_type, full_name = None): 480705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 481705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Initialize interface with the given super-interfaces 482705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 483705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.ifaces = sorted(ifaces) 484705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.iface_type = iface_type 485705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if full_name is None: 486705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light end = self.iface_type.get_suffix() 487705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.class_name = "INTERFACE_"+gensym()+end 488705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 489705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.class_name = full_name 490705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 491705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_specific_version(self, v): 492705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 493705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns a copy of this interface of the given type for use in partial compilation. 494705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 495705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return TestInterface(self.ifaces, v, full_name = self.class_name) 496705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 497705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_super_types(self): 498705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 499705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns a set of all the supertypes of this interface 500705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 501705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return set(i2 for i2 in self) 502705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 503705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_conflict(self): 504705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 505705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is a conflict interface and calling the method on this interface will 506705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in an IncompatibleClassChangeError. 507705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 508705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return False 509705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 510705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_abstract(self): 511705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 512705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is an abstract interface and calling the method on this interface will 513705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in an AbstractMethodError. 514705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 515705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.iface_type == InterfaceType.abstract 516705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 517705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_empty(self): 518705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 519705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is an abstract interface and calling the method on this interface will 520705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in a NoSuchMethodError. 521705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 522705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.iface_type == InterfaceType.empty 523705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 524705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def is_default(self): 525705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 526705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns true if this is a default interface and calling the method on this interface will 527705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light result in a method actually being called. 528705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 529705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.iface_type == InterfaceType.default 530705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 531705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_expected(self): 532705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light response = self.get_response() 533705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if response == InterfaceCallResponse.NoError: 534705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for iface in self.ifaces: 535705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if self.is_default(): 536705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield self.OUTPUT_PREFIX.format(iface_name = iface.get_name(), tree = self.get_tree()) 537705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield from iface.get_expected() 538705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if self.is_default(): 539705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield iface.get_response().get_output_format().format(iface_name = iface.get_name(), 540705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light tree = self.get_tree()) 541705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 542705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_response(self): 543705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if self.is_default(): 544705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return InterfaceCallResponse.NoError 545705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif self.is_abstract(): 546705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return InterfaceCallResponse.AbstractMethodError 547705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif len(self.ifaces) == 0: 548705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return InterfaceCallResponse.NoSuchMethodError 549705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 550705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.get_called().get_response() 551705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 552705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_called(self): 553705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 554705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Returns the interface that will be called when the method on this class is invoked or 555705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light CONFLICT_TYPE if there is no interface that will be called. 556705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 557705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if not self.is_empty() or len(self.ifaces) == 0: 558705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self 559705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 560705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light best = self 561705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for super_iface in self.ifaces: 562705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light super_best = super_iface.get_called() 563705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if super_best.is_conflict(): 564705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return CONFLICT_TYPE 565705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif best.is_default(): 566705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if super_best.is_default(): 567705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return CONFLICT_TYPE 568705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif best.is_abstract(): 569705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if super_best.is_default(): 570705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light best = super_best 571705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 572705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light assert best.is_empty() 573705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light best = super_best 574705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return best 575705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 576705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_name(self): 577705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 578705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Get the name of this class 579705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 580705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.class_name 581705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 582705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def get_tree(self): 583705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 584705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Print out a representation of the type tree of this class 585705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 586705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return "[{class_name} {iftree}]".format(class_name = self.get_name(), 587705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light iftree = print_tree(self.ifaces)) 588705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 589705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __iter__(self): 590705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 591705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Performs depth-first traversal of the interface tree this interface is the 592705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light root of. Does not filter out repeats. 593705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 594705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for i in self.ifaces: 595705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield i 596705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield from i 597705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 598705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light def __str__(self): 599705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 600705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Print the smali code of this interface. 601705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 602705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()), 603705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light self.ifaces)) 604705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces)) 605705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if self.is_default(): 606705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light super_template = self.SUPER_CALL_TEMPLATE 607705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light super_calls ="\n".join(super_template.format(iface_name = iface.get_name(), 608705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light class_name = self.get_name(), 609705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light tree = self.get_tree()) for iface in self.ifaces) 610705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light funcs = self.DEFAULT_FUNC_TEMPLATE.format(super_calls = super_calls) 611705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light elif self.is_abstract(): 612705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light funcs = self.ABSTRACT_FUNC_TEMPLATE.format() 613705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light else: 614705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light funcs = "" 615705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'), 616705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light implements_spec = s_ifaces, 617705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light extends = "extends" if len(self.ifaces) else "", 618705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ifaces = j_ifaces, 619705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light func = funcs, 620705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light tree = self.get_tree(), 621705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light class_name = self.class_name) 622705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 623705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightdef print_tree(ifaces): 624705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 625705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Prints a list of iface trees 626705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 627705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return " ".join(i.get_tree() for i in ifaces) 628705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 629705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# The deduplicated output of subtree_sizes for each size up to 630705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light# MAX_LEAF_IFACE_PER_OBJECT. 631705ad49f353d3f90d8b63625aca2c2035bacdbefAlex LightSUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i)) 632705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for i in range(MAX_IFACE_DEPTH + 1)] 633705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 634705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightdef create_test_classes(): 635705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 636705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Yield all the test classes with the different interface trees 637705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 638705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for num in range(1, MAX_IFACE_DEPTH + 1): 639705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for split in SUBTREES[num]: 640705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ifaces = [] 641705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for sub in split: 642705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ifaces.append(list(create_interface_trees(sub))) 643705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for supers in itertools.product(*ifaces): 644705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield TestClass(supers) 645705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 646705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightdef create_interface_trees(num): 647705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 648705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Yield all the interface trees up to 'num' depth. 649705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 650705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if num == 0: 651705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for iftype in InterfaceType: 652705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield TestInterface(tuple(), iftype) 653705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return 654705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for split in SUBTREES[num]: 655705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ifaces = [] 656705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for sub in split: 657705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light ifaces.append(list(create_interface_trees(sub))) 658705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for supers in itertools.product(*ifaces): 659705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for iftype in InterfaceType: 660705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light yield TestInterface(supers, iftype) 661705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 662705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightdef create_all_test_files(): 663705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 664705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light Creates all the objects representing the files in this test. They just need to 665705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light be dumped. 666705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light """ 667705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light mc = MainClass() 668705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light classes = {mc} 669705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for clazz in create_test_classes(): 670705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light classes.add(clazz) 671705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for i in clazz: 672705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light classes.add(i) 673705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light mc.add_test(clazz) 674705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light return mc, classes 675705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 676705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightdef main(argv): 677705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light smali_dir = Path(argv[1]) 678705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light if not smali_dir.exists() or not smali_dir.is_dir(): 679705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr) 680705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light sys.exit(1) 681705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light expected_txt = Path(argv[2]) 682705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light mainclass, all_files = create_all_test_files() 683705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light with expected_txt.open('w') as out: 684705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light print(mainclass.get_expected(), file=out) 685705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light for f in all_files: 686705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light f.dump(smali_dir) 687705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light 688705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Lightif __name__ == '__main__': 689705ad49f353d3f90d8b63625aca2c2035bacdbefAlex Light main(sys.argv) 690