xref: /aosp_15_r20/art/test/971-iface-super/util-src/generate_smali.py (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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 967.
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 enum import Enum
37*795d594fSAndroid Build Coastguard Workerfrom functools import total_ordering
38*795d594fSAndroid Build Coastguard Workerimport itertools
39*795d594fSAndroid Build Coastguard Workerimport string
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker# The max depth the type tree can have.
42*795d594fSAndroid Build Coastguard WorkerMAX_IFACE_DEPTH = 2
43*795d594fSAndroid Build Coastguard Worker
44*795d594fSAndroid Build Coastguard Workerclass MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin):
45*795d594fSAndroid Build Coastguard Worker  """
46*795d594fSAndroid Build Coastguard Worker  A Main.smali file containing the Main class and the main function. It will run
47*795d594fSAndroid Build Coastguard Worker  all the test functions we have.
48*795d594fSAndroid Build Coastguard Worker  """
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker  MAIN_CLASS_TEMPLATE = """{copyright}
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker.class public LMain;
53*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object;
54*795d594fSAndroid Build Coastguard Worker
55*795d594fSAndroid Build Coastguard Worker# class Main {{
56*795d594fSAndroid Build Coastguard Worker
57*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V
58*795d594fSAndroid Build Coastguard Worker    .registers 1
59*795d594fSAndroid Build Coastguard Worker    invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
60*795d594fSAndroid Build Coastguard Worker    return-void
61*795d594fSAndroid Build Coastguard Worker.end method
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker{test_funcs}
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker{main_func}
66*795d594fSAndroid Build Coastguard Worker
67*795d594fSAndroid Build Coastguard Worker# }}
68*795d594fSAndroid Build Coastguard Worker"""
69*795d594fSAndroid Build Coastguard Worker
70*795d594fSAndroid Build Coastguard Worker  MAIN_FUNCTION_TEMPLATE = """
71*795d594fSAndroid Build Coastguard Worker#   public static void main(String[] args) {{
72*795d594fSAndroid Build Coastguard Worker.method public static main([Ljava/lang/String;)V
73*795d594fSAndroid Build Coastguard Worker    .locals 0
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker    {test_group_invoke}
76*795d594fSAndroid Build Coastguard Worker
77*795d594fSAndroid Build Coastguard Worker    return-void
78*795d594fSAndroid Build Coastguard Worker.end method
79*795d594fSAndroid Build Coastguard Worker#   }}
80*795d594fSAndroid Build Coastguard Worker"""
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker  TEST_GROUP_INVOKE_TEMPLATE = """
83*795d594fSAndroid Build Coastguard Worker#     {test_name}();
84*795d594fSAndroid Build Coastguard Worker    invoke-static {{}}, {test_name}()V
85*795d594fSAndroid Build Coastguard Worker"""
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker  def __init__(self):
88*795d594fSAndroid Build Coastguard Worker    """
89*795d594fSAndroid Build Coastguard Worker    Initialize this MainClass. We start out with no tests.
90*795d594fSAndroid Build Coastguard Worker    """
91*795d594fSAndroid Build Coastguard Worker    self.tests = set()
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard Worker  def get_expected(self):
94*795d594fSAndroid Build Coastguard Worker    """
95*795d594fSAndroid Build Coastguard Worker    Get the expected output of this test.
96*795d594fSAndroid Build Coastguard Worker    """
97*795d594fSAndroid Build Coastguard Worker    all_tests = sorted(self.tests)
98*795d594fSAndroid Build Coastguard Worker    return filter_blanks("\n".join(a.get_expected() for a in all_tests))
99*795d594fSAndroid Build Coastguard Worker
100*795d594fSAndroid Build Coastguard Worker  def add_test(self, ty):
101*795d594fSAndroid Build Coastguard Worker    """
102*795d594fSAndroid Build Coastguard Worker    Add a test for the concrete type 'ty'
103*795d594fSAndroid Build Coastguard Worker    """
104*795d594fSAndroid Build Coastguard Worker    self.tests.add(Func(ty))
105*795d594fSAndroid Build Coastguard Worker
106*795d594fSAndroid Build Coastguard Worker  def get_name(self):
107*795d594fSAndroid Build Coastguard Worker    """
108*795d594fSAndroid Build Coastguard Worker    Get the name of this class
109*795d594fSAndroid Build Coastguard Worker    """
110*795d594fSAndroid Build Coastguard Worker    return "Main"
111*795d594fSAndroid Build Coastguard Worker
112*795d594fSAndroid Build Coastguard Worker  def __str__(self):
113*795d594fSAndroid Build Coastguard Worker    """
114*795d594fSAndroid Build Coastguard Worker    Print the MainClass smali code.
115*795d594fSAndroid Build Coastguard Worker    """
116*795d594fSAndroid Build Coastguard Worker    all_tests = sorted(self.tests)
117*795d594fSAndroid Build Coastguard Worker    test_invoke = ""
118*795d594fSAndroid Build Coastguard Worker    test_funcs = ""
119*795d594fSAndroid Build Coastguard Worker    for t in all_tests:
120*795d594fSAndroid Build Coastguard Worker      test_funcs += str(t)
121*795d594fSAndroid Build Coastguard Worker    for t in all_tests:
122*795d594fSAndroid Build Coastguard Worker      test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name())
123*795d594fSAndroid Build Coastguard Worker    main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke)
124*795d594fSAndroid Build Coastguard Worker
125*795d594fSAndroid Build Coastguard Worker    return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright("smali"),
126*795d594fSAndroid Build Coastguard Worker                                           test_funcs = test_funcs,
127*795d594fSAndroid Build Coastguard Worker                                           main_func = main_func)
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Workerclass Func(mixins.Named, mixins.NameComparableMixin):
130*795d594fSAndroid Build Coastguard Worker  """
131*795d594fSAndroid Build Coastguard Worker  A function that tests the functionality of a concrete type. Should only be
132*795d594fSAndroid Build Coastguard Worker  constructed by MainClass.add_test.
133*795d594fSAndroid Build Coastguard Worker  """
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker  TEST_FUNCTION_TEMPLATE = """
136*795d594fSAndroid Build Coastguard Worker#   public static void {fname}() {{
137*795d594fSAndroid Build Coastguard Worker#     {farg} v = null;
138*795d594fSAndroid Build Coastguard Worker#     try {{
139*795d594fSAndroid Build Coastguard Worker#       v = new {farg}();
140*795d594fSAndroid Build Coastguard Worker#     }} catch (Throwable e) {{
141*795d594fSAndroid Build Coastguard Worker#       System.out.println("Unexpected error occurred which creating {farg} instance");
142*795d594fSAndroid Build Coastguard Worker#       e.printStackTrace(System.out);
143*795d594fSAndroid Build Coastguard Worker#       return;
144*795d594fSAndroid Build Coastguard Worker#     }}
145*795d594fSAndroid Build Coastguard Worker#     try {{
146*795d594fSAndroid Build Coastguard Worker#       v.callSupers();
147*795d594fSAndroid Build Coastguard Worker#       return;
148*795d594fSAndroid Build Coastguard Worker#     }} catch (Throwable e) {{
149*795d594fSAndroid Build Coastguard Worker#       e.printStackTrace(System.out);
150*795d594fSAndroid Build Coastguard Worker#       return;
151*795d594fSAndroid Build Coastguard Worker#     }}
152*795d594fSAndroid Build Coastguard Worker#   }}
153*795d594fSAndroid Build Coastguard Worker.method public static {fname}()V
154*795d594fSAndroid Build Coastguard Worker    .locals 7
155*795d594fSAndroid Build Coastguard Worker    sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream;
156*795d594fSAndroid Build Coastguard Worker
157*795d594fSAndroid Build Coastguard Worker    :new_{fname}_try_start
158*795d594fSAndroid Build Coastguard Worker      new-instance v0, L{farg};
159*795d594fSAndroid Build Coastguard Worker      invoke-direct {{v0}}, L{farg};-><init>()V
160*795d594fSAndroid Build Coastguard Worker      goto :call_{fname}_try_start
161*795d594fSAndroid Build Coastguard Worker    :new_{fname}_try_end
162*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/Throwable; {{:new_{fname}_try_start .. :new_{fname}_try_end}} :new_error_{fname}_start
163*795d594fSAndroid Build Coastguard Worker    :new_error_{fname}_start
164*795d594fSAndroid Build Coastguard Worker      move-exception v6
165*795d594fSAndroid Build Coastguard Worker      const-string v5, "Unexpected error occurred which creating {farg} instance"
166*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
167*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
168*795d594fSAndroid Build Coastguard Worker      return-void
169*795d594fSAndroid Build Coastguard Worker    :call_{fname}_try_start
170*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0}}, L{farg};->callSupers()V
171*795d594fSAndroid Build Coastguard Worker      return-void
172*795d594fSAndroid Build Coastguard Worker    :call_{fname}_try_end
173*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/Throwable; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start
174*795d594fSAndroid Build Coastguard Worker    :error_{fname}_start
175*795d594fSAndroid Build Coastguard Worker      move-exception v6
176*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V
177*795d594fSAndroid Build Coastguard Worker      return-void
178*795d594fSAndroid Build Coastguard Worker.end method
179*795d594fSAndroid Build Coastguard Worker"""
180*795d594fSAndroid Build Coastguard Worker
181*795d594fSAndroid Build Coastguard Worker  def __init__(self, farg):
182*795d594fSAndroid Build Coastguard Worker    """
183*795d594fSAndroid Build Coastguard Worker    Initialize a test function for the given argument
184*795d594fSAndroid Build Coastguard Worker    """
185*795d594fSAndroid Build Coastguard Worker    self.farg = farg
186*795d594fSAndroid Build Coastguard Worker
187*795d594fSAndroid Build Coastguard Worker  def get_expected(self):
188*795d594fSAndroid Build Coastguard Worker    """
189*795d594fSAndroid Build Coastguard Worker    Get the expected output calling this function.
190*795d594fSAndroid Build Coastguard Worker    """
191*795d594fSAndroid Build Coastguard Worker    return "\n".join(self.farg.get_expected())
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker  def get_name(self):
194*795d594fSAndroid Build Coastguard Worker    """
195*795d594fSAndroid Build Coastguard Worker    Get the name of this function
196*795d594fSAndroid Build Coastguard Worker    """
197*795d594fSAndroid Build Coastguard Worker    return "TEST_FUNC_{}".format(self.farg.get_name())
198*795d594fSAndroid Build Coastguard Worker
199*795d594fSAndroid Build Coastguard Worker  def __str__(self):
200*795d594fSAndroid Build Coastguard Worker    """
201*795d594fSAndroid Build Coastguard Worker    Print the smali code of this function.
202*795d594fSAndroid Build Coastguard Worker    """
203*795d594fSAndroid Build Coastguard Worker    return self.TEST_FUNCTION_TEMPLATE.format(fname = self.get_name(),
204*795d594fSAndroid Build Coastguard Worker                                              farg = self.farg.get_name())
205*795d594fSAndroid Build Coastguard Worker
206*795d594fSAndroid Build Coastguard Workerclass InterfaceCallResponse(Enum):
207*795d594fSAndroid Build Coastguard Worker  """
208*795d594fSAndroid Build Coastguard Worker  An enumeration of all the different types of responses to an interface call we can have
209*795d594fSAndroid Build Coastguard Worker  """
210*795d594fSAndroid Build Coastguard Worker  NoError = 0
211*795d594fSAndroid Build Coastguard Worker  NoSuchMethodError = 1
212*795d594fSAndroid Build Coastguard Worker  AbstractMethodError = 2
213*795d594fSAndroid Build Coastguard Worker  IncompatibleClassChangeError = 3
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker  def get_output_format(self):
216*795d594fSAndroid Build Coastguard Worker    if self == InterfaceCallResponse.NoError:
217*795d594fSAndroid Build Coastguard Worker      return "No exception thrown for {iface_name}.super.call() on {tree}\n"
218*795d594fSAndroid Build Coastguard Worker    elif self == InterfaceCallResponse.AbstractMethodError:
219*795d594fSAndroid Build Coastguard Worker      return "AbstractMethodError thrown for {iface_name}.super.call() on {tree}\n"
220*795d594fSAndroid Build Coastguard Worker    elif self == InterfaceCallResponse.NoSuchMethodError:
221*795d594fSAndroid Build Coastguard Worker      return "NoSuchMethodError thrown for {iface_name}.super.call() on {tree}\n"
222*795d594fSAndroid Build Coastguard Worker    else:
223*795d594fSAndroid Build Coastguard Worker      return "IncompatibleClassChangeError thrown for {iface_name}.super.call() on {tree}\n"
224*795d594fSAndroid Build Coastguard Worker
225*795d594fSAndroid Build Coastguard Workerclass TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
226*795d594fSAndroid Build Coastguard Worker  """
227*795d594fSAndroid Build Coastguard Worker  A class that will be instantiated to test interface super behavior.
228*795d594fSAndroid Build Coastguard Worker  """
229*795d594fSAndroid Build Coastguard Worker
230*795d594fSAndroid Build Coastguard Worker  TEST_CLASS_TEMPLATE = """{copyright}
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker.class public L{class_name};
233*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object;
234*795d594fSAndroid Build Coastguard Worker{implements_spec}
235*795d594fSAndroid Build Coastguard Worker
236*795d594fSAndroid Build Coastguard Worker# public class {class_name} implements {ifaces} {{
237*795d594fSAndroid Build Coastguard Worker
238*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V
239*795d594fSAndroid Build Coastguard Worker  .registers 1
240*795d594fSAndroid Build Coastguard Worker  invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V
241*795d594fSAndroid Build Coastguard Worker  return-void
242*795d594fSAndroid Build Coastguard Worker.end method
243*795d594fSAndroid Build Coastguard Worker
244*795d594fSAndroid Build Coastguard Worker#   public void call() {{
245*795d594fSAndroid Build Coastguard Worker#     throw new Error("{class_name}.call(v) should never get called!");
246*795d594fSAndroid Build Coastguard Worker#   }}
247*795d594fSAndroid Build Coastguard Worker.method public call()V
248*795d594fSAndroid Build Coastguard Worker  .locals 2
249*795d594fSAndroid Build Coastguard Worker  new-instance v0, Ljava/lang/Error;
250*795d594fSAndroid Build Coastguard Worker  const-string v1, "{class_name}.call(v) should never get called!"
251*795d594fSAndroid Build Coastguard Worker  invoke-direct {{v0, v1}}, Ljava/lang/Error;-><init>(Ljava/lang/String;)V
252*795d594fSAndroid Build Coastguard Worker  throw v0
253*795d594fSAndroid Build Coastguard Worker.end method
254*795d594fSAndroid Build Coastguard Worker
255*795d594fSAndroid Build Coastguard Worker#   public void callSupers() {{
256*795d594fSAndroid Build Coastguard Worker.method public callSupers()V
257*795d594fSAndroid Build Coastguard Worker  .locals 4
258*795d594fSAndroid Build Coastguard Worker  sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
259*795d594fSAndroid Build Coastguard Worker
260*795d594fSAndroid Build Coastguard Worker  {super_calls}
261*795d594fSAndroid Build Coastguard Worker
262*795d594fSAndroid Build Coastguard Worker  return-void
263*795d594fSAndroid Build Coastguard Worker.end method
264*795d594fSAndroid Build Coastguard Worker#   }}
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker# }}
267*795d594fSAndroid Build Coastguard Worker"""
268*795d594fSAndroid Build Coastguard Worker  SUPER_CALL_TEMPLATE = """
269*795d594fSAndroid Build Coastguard Worker#     try {{
270*795d594fSAndroid Build Coastguard Worker#       System.out.println("Calling {iface_name}.super.call() on {tree}");
271*795d594fSAndroid Build Coastguard Worker#       {iface_name}.super.call();
272*795d594fSAndroid Build Coastguard Worker#       System.out.println("No exception thrown for {iface_name}.super.call() on {tree}");
273*795d594fSAndroid Build Coastguard Worker#     }} catch (AbstractMethodError ame) {{
274*795d594fSAndroid Build Coastguard Worker#       System.out.println("AbstractMethodError thrown for {iface_name}.super.call() on {tree}");
275*795d594fSAndroid Build Coastguard Worker#     }} catch (NoSuchMethodError nsme) {{
276*795d594fSAndroid Build Coastguard Worker#       System.out.println("NoSuchMethodError thrown for {iface_name}.super.call() on {tree}");
277*795d594fSAndroid Build Coastguard Worker#     }} catch (IncompatibleClassChangeError icce) {{
278*795d594fSAndroid Build Coastguard Worker#       System.out.println("IncompatibleClassChangeError thrown for {iface_name}.super.call() on {tree}");
279*795d594fSAndroid Build Coastguard Worker#     }} catch (Throwable t) {{
280*795d594fSAndroid Build Coastguard Worker#       System.out.println("Unknown error thrown for {iface_name}.super.call() on {tree}");
281*795d594fSAndroid Build Coastguard Worker#       throw t;
282*795d594fSAndroid Build Coastguard Worker#     }}
283*795d594fSAndroid Build Coastguard Worker    :call_{class_name}_{iface_name}_try_start
284*795d594fSAndroid Build Coastguard Worker      const-string v1, "Calling {iface_name}.super.call() on {tree}"
285*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
286*795d594fSAndroid Build Coastguard Worker      invoke-super {{p0}}, L{iface_name};->call()V
287*795d594fSAndroid Build Coastguard Worker      const-string v1, "No exception thrown for {iface_name}.super.call() on {tree}"
288*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
289*795d594fSAndroid Build Coastguard Worker      goto :call_{class_name}_{iface_name}_end
290*795d594fSAndroid Build Coastguard Worker    :call_{class_name}_{iface_name}_try_end
291*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/AbstractMethodError; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :AME_{class_name}_{iface_name}_start
292*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/NoSuchMethodError; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :NSME_{class_name}_{iface_name}_start
293*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/IncompatibleClassChangeError; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :ICCE_{class_name}_{iface_name}_start
294*795d594fSAndroid Build Coastguard Worker    .catch Ljava/lang/Throwable; {{:call_{class_name}_{iface_name}_try_start .. :call_{class_name}_{iface_name}_try_end}} :error_{class_name}_{iface_name}_start
295*795d594fSAndroid Build Coastguard Worker    :AME_{class_name}_{iface_name}_start
296*795d594fSAndroid Build Coastguard Worker      const-string v1, "AbstractMethodError thrown for {iface_name}.super.call() on {tree}"
297*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
298*795d594fSAndroid Build Coastguard Worker      goto :call_{class_name}_{iface_name}_end
299*795d594fSAndroid Build Coastguard Worker    :NSME_{class_name}_{iface_name}_start
300*795d594fSAndroid Build Coastguard Worker      const-string v1, "NoSuchMethodError thrown for {iface_name}.super.call() on {tree}"
301*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
302*795d594fSAndroid Build Coastguard Worker      goto :call_{class_name}_{iface_name}_end
303*795d594fSAndroid Build Coastguard Worker    :ICCE_{class_name}_{iface_name}_start
304*795d594fSAndroid Build Coastguard Worker      const-string v1, "IncompatibleClassChangeError thrown for {iface_name}.super.call() on {tree}"
305*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
306*795d594fSAndroid Build Coastguard Worker      goto :call_{class_name}_{iface_name}_end
307*795d594fSAndroid Build Coastguard Worker    :error_{class_name}_{iface_name}_start
308*795d594fSAndroid Build Coastguard Worker      move-exception v2
309*795d594fSAndroid Build Coastguard Worker      const-string v1, "Unknown error thrown for {iface_name}.super.call() on {tree}"
310*795d594fSAndroid Build Coastguard Worker      invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
311*795d594fSAndroid Build Coastguard Worker      throw v2
312*795d594fSAndroid Build Coastguard Worker    :call_{class_name}_{iface_name}_end
313*795d594fSAndroid Build Coastguard Worker"""
314*795d594fSAndroid Build Coastguard Worker
315*795d594fSAndroid Build Coastguard Worker  IMPLEMENTS_TEMPLATE = """
316*795d594fSAndroid Build Coastguard Worker.implements L{iface_name};
317*795d594fSAndroid Build Coastguard Worker"""
318*795d594fSAndroid Build Coastguard Worker
319*795d594fSAndroid Build Coastguard Worker  OUTPUT_PREFIX = "Calling {iface_name}.super.call() on {tree}\n"
320*795d594fSAndroid Build Coastguard Worker
321*795d594fSAndroid Build Coastguard Worker  def __init__(self, ifaces):
322*795d594fSAndroid Build Coastguard Worker    """
323*795d594fSAndroid Build Coastguard Worker    Initialize this test class which implements the given interfaces
324*795d594fSAndroid Build Coastguard Worker    """
325*795d594fSAndroid Build Coastguard Worker    self.ifaces = ifaces
326*795d594fSAndroid Build Coastguard Worker    self.class_name = "CLASS_"+gensym()
327*795d594fSAndroid Build Coastguard Worker
328*795d594fSAndroid Build Coastguard Worker  def get_name(self):
329*795d594fSAndroid Build Coastguard Worker    """
330*795d594fSAndroid Build Coastguard Worker    Get the name of this class
331*795d594fSAndroid Build Coastguard Worker    """
332*795d594fSAndroid Build Coastguard Worker    return self.class_name
333*795d594fSAndroid Build Coastguard Worker
334*795d594fSAndroid Build Coastguard Worker  def get_tree(self):
335*795d594fSAndroid Build Coastguard Worker    """
336*795d594fSAndroid Build Coastguard Worker    Print out a representation of the type tree of this class
337*795d594fSAndroid Build Coastguard Worker    """
338*795d594fSAndroid Build Coastguard Worker    return "[{class_name} {iface_tree}]".format(class_name = self.class_name,
339*795d594fSAndroid Build Coastguard Worker                                                iface_tree = print_tree(self.ifaces))
340*795d594fSAndroid Build Coastguard Worker
341*795d594fSAndroid Build Coastguard Worker  def __iter__(self):
342*795d594fSAndroid Build Coastguard Worker    """
343*795d594fSAndroid Build Coastguard Worker    Step through all interfaces implemented transitively by this class
344*795d594fSAndroid Build Coastguard Worker    """
345*795d594fSAndroid Build Coastguard Worker    for i in self.ifaces:
346*795d594fSAndroid Build Coastguard Worker      yield i
347*795d594fSAndroid Build Coastguard Worker      yield from i
348*795d594fSAndroid Build Coastguard Worker
349*795d594fSAndroid Build Coastguard Worker  def get_expected(self):
350*795d594fSAndroid Build Coastguard Worker    for iface in self.ifaces:
351*795d594fSAndroid Build Coastguard Worker      yield self.OUTPUT_PREFIX.format(iface_name = iface.get_name(), tree = self.get_tree())
352*795d594fSAndroid Build Coastguard Worker      yield from iface.get_expected()
353*795d594fSAndroid Build Coastguard Worker      yield iface.get_response().get_output_format().format(iface_name = iface.get_name(),
354*795d594fSAndroid Build Coastguard Worker                                                            tree = self.get_tree())
355*795d594fSAndroid Build Coastguard Worker
356*795d594fSAndroid Build Coastguard Worker  def __str__(self):
357*795d594fSAndroid Build Coastguard Worker    """
358*795d594fSAndroid Build Coastguard Worker    Print the smali code of this class.
359*795d594fSAndroid Build Coastguard Worker    """
360*795d594fSAndroid Build Coastguard Worker    s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()),
361*795d594fSAndroid Build Coastguard Worker                             self.ifaces))
362*795d594fSAndroid Build Coastguard Worker    j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces))
363*795d594fSAndroid Build Coastguard Worker    super_template = self.SUPER_CALL_TEMPLATE
364*795d594fSAndroid Build Coastguard Worker    super_calls = "\n".join(super_template.format(iface_name = iface.get_name(),
365*795d594fSAndroid Build Coastguard Worker                                                  class_name = self.get_name(),
366*795d594fSAndroid Build Coastguard Worker                                                  tree = self.get_tree()) for iface in self.ifaces)
367*795d594fSAndroid Build Coastguard Worker    return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'),
368*795d594fSAndroid Build Coastguard Worker                                           ifaces = j_ifaces,
369*795d594fSAndroid Build Coastguard Worker                                           implements_spec = s_ifaces,
370*795d594fSAndroid Build Coastguard Worker                                           tree = self.get_tree(),
371*795d594fSAndroid Build Coastguard Worker                                           class_name = self.class_name,
372*795d594fSAndroid Build Coastguard Worker                                           super_calls = super_calls)
373*795d594fSAndroid Build Coastguard Worker
374*795d594fSAndroid Build Coastguard Workerclass InterfaceType(Enum):
375*795d594fSAndroid Build Coastguard Worker  """
376*795d594fSAndroid Build Coastguard Worker  An enumeration of all the different types of interfaces we can have.
377*795d594fSAndroid Build Coastguard Worker
378*795d594fSAndroid Build Coastguard Worker  default: It has a default method
379*795d594fSAndroid Build Coastguard Worker  abstract: It has a method declared but not defined
380*795d594fSAndroid Build Coastguard Worker  empty: It does not have the method
381*795d594fSAndroid Build Coastguard Worker  """
382*795d594fSAndroid Build Coastguard Worker  default = 0
383*795d594fSAndroid Build Coastguard Worker  abstract = 1
384*795d594fSAndroid Build Coastguard Worker  empty = 2
385*795d594fSAndroid Build Coastguard Worker
386*795d594fSAndroid Build Coastguard Worker  def get_suffix(self):
387*795d594fSAndroid Build Coastguard Worker    if self == InterfaceType.default:
388*795d594fSAndroid Build Coastguard Worker      return "_DEFAULT"
389*795d594fSAndroid Build Coastguard Worker    elif self == InterfaceType.abstract:
390*795d594fSAndroid Build Coastguard Worker      return "_ABSTRACT"
391*795d594fSAndroid Build Coastguard Worker    elif self == InterfaceType.empty:
392*795d594fSAndroid Build Coastguard Worker      return "_EMPTY"
393*795d594fSAndroid Build Coastguard Worker    else:
394*795d594fSAndroid Build Coastguard Worker      raise TypeError("Interface type had illegal value.")
395*795d594fSAndroid Build Coastguard Worker
396*795d594fSAndroid Build Coastguard Workerclass ConflictInterface:
397*795d594fSAndroid Build Coastguard Worker  """
398*795d594fSAndroid Build Coastguard Worker  A singleton representing a conflict of default methods.
399*795d594fSAndroid Build Coastguard Worker  """
400*795d594fSAndroid Build Coastguard Worker
401*795d594fSAndroid Build Coastguard Worker  def is_conflict(self):
402*795d594fSAndroid Build Coastguard Worker    """
403*795d594fSAndroid Build Coastguard Worker    Returns true if this is a conflict interface and calling the method on this interface will
404*795d594fSAndroid Build Coastguard Worker    result in an IncompatibleClassChangeError.
405*795d594fSAndroid Build Coastguard Worker    """
406*795d594fSAndroid Build Coastguard Worker    return True
407*795d594fSAndroid Build Coastguard Worker
408*795d594fSAndroid Build Coastguard Worker  def is_abstract(self):
409*795d594fSAndroid Build Coastguard Worker    """
410*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
411*795d594fSAndroid Build Coastguard Worker    result in an AbstractMethodError.
412*795d594fSAndroid Build Coastguard Worker    """
413*795d594fSAndroid Build Coastguard Worker    return False
414*795d594fSAndroid Build Coastguard Worker
415*795d594fSAndroid Build Coastguard Worker  def is_empty(self):
416*795d594fSAndroid Build Coastguard Worker    """
417*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
418*795d594fSAndroid Build Coastguard Worker    result in a NoSuchMethodError.
419*795d594fSAndroid Build Coastguard Worker    """
420*795d594fSAndroid Build Coastguard Worker    return False
421*795d594fSAndroid Build Coastguard Worker
422*795d594fSAndroid Build Coastguard Worker  def is_default(self):
423*795d594fSAndroid Build Coastguard Worker    """
424*795d594fSAndroid Build Coastguard Worker    Returns true if this is a default interface and calling the method on this interface will
425*795d594fSAndroid Build Coastguard Worker    result in a method actually being called.
426*795d594fSAndroid Build Coastguard Worker    """
427*795d594fSAndroid Build Coastguard Worker    return False
428*795d594fSAndroid Build Coastguard Worker
429*795d594fSAndroid Build Coastguard Worker  def get_response(self):
430*795d594fSAndroid Build Coastguard Worker    return InterfaceCallResponse.IncompatibleClassChangeError
431*795d594fSAndroid Build Coastguard Worker
432*795d594fSAndroid Build Coastguard WorkerCONFLICT_TYPE = ConflictInterface()
433*795d594fSAndroid Build Coastguard Worker
434*795d594fSAndroid Build Coastguard Workerclass TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin):
435*795d594fSAndroid Build Coastguard Worker  """
436*795d594fSAndroid Build Coastguard Worker  An interface that will be used to test default method resolution order.
437*795d594fSAndroid Build Coastguard Worker  """
438*795d594fSAndroid Build Coastguard Worker
439*795d594fSAndroid Build Coastguard Worker  TEST_INTERFACE_TEMPLATE = """{copyright}
440*795d594fSAndroid Build Coastguard Worker.class public abstract interface L{class_name};
441*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object;
442*795d594fSAndroid Build Coastguard Worker{implements_spec}
443*795d594fSAndroid Build Coastguard Worker
444*795d594fSAndroid Build Coastguard Worker# public interface {class_name} {extends} {ifaces} {{
445*795d594fSAndroid Build Coastguard Worker
446*795d594fSAndroid Build Coastguard Worker{func}
447*795d594fSAndroid Build Coastguard Worker
448*795d594fSAndroid Build Coastguard Worker# }}
449*795d594fSAndroid Build Coastguard Worker"""
450*795d594fSAndroid Build Coastguard Worker
451*795d594fSAndroid Build Coastguard Worker  SUPER_CALL_TEMPLATE = TestClass.SUPER_CALL_TEMPLATE
452*795d594fSAndroid Build Coastguard Worker  OUTPUT_PREFIX = TestClass.OUTPUT_PREFIX
453*795d594fSAndroid Build Coastguard Worker
454*795d594fSAndroid Build Coastguard Worker  DEFAULT_FUNC_TEMPLATE = """
455*795d594fSAndroid Build Coastguard Worker#   public default void call() {{
456*795d594fSAndroid Build Coastguard Worker.method public call()V
457*795d594fSAndroid Build Coastguard Worker  .locals 4
458*795d594fSAndroid Build Coastguard Worker  sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
459*795d594fSAndroid Build Coastguard Worker
460*795d594fSAndroid Build Coastguard Worker  {super_calls}
461*795d594fSAndroid Build Coastguard Worker
462*795d594fSAndroid Build Coastguard Worker  return-void
463*795d594fSAndroid Build Coastguard Worker.end method
464*795d594fSAndroid Build Coastguard Worker#   }}
465*795d594fSAndroid Build Coastguard Worker"""
466*795d594fSAndroid Build Coastguard Worker
467*795d594fSAndroid Build Coastguard Worker  ABSTRACT_FUNC_TEMPLATE = """
468*795d594fSAndroid Build Coastguard Worker#   public void call();
469*795d594fSAndroid Build Coastguard Worker.method public abstract call()V
470*795d594fSAndroid Build Coastguard Worker.end method
471*795d594fSAndroid Build Coastguard Worker"""
472*795d594fSAndroid Build Coastguard Worker
473*795d594fSAndroid Build Coastguard Worker  EMPTY_FUNC_TEMPLATE = """"""
474*795d594fSAndroid Build Coastguard Worker
475*795d594fSAndroid Build Coastguard Worker  IMPLEMENTS_TEMPLATE = """
476*795d594fSAndroid Build Coastguard Worker.implements L{iface_name};
477*795d594fSAndroid Build Coastguard Worker"""
478*795d594fSAndroid Build Coastguard Worker
479*795d594fSAndroid Build Coastguard Worker  def __init__(self, ifaces, iface_type, full_name = None):
480*795d594fSAndroid Build Coastguard Worker    """
481*795d594fSAndroid Build Coastguard Worker    Initialize interface with the given super-interfaces
482*795d594fSAndroid Build Coastguard Worker    """
483*795d594fSAndroid Build Coastguard Worker    self.ifaces = sorted(ifaces)
484*795d594fSAndroid Build Coastguard Worker    self.iface_type = iface_type
485*795d594fSAndroid Build Coastguard Worker    if full_name is None:
486*795d594fSAndroid Build Coastguard Worker      end = self.iface_type.get_suffix()
487*795d594fSAndroid Build Coastguard Worker      self.class_name = "INTERFACE_"+gensym()+end
488*795d594fSAndroid Build Coastguard Worker    else:
489*795d594fSAndroid Build Coastguard Worker      self.class_name = full_name
490*795d594fSAndroid Build Coastguard Worker
491*795d594fSAndroid Build Coastguard Worker  def get_specific_version(self, v):
492*795d594fSAndroid Build Coastguard Worker    """
493*795d594fSAndroid Build Coastguard Worker    Returns a copy of this interface of the given type for use in partial compilation.
494*795d594fSAndroid Build Coastguard Worker    """
495*795d594fSAndroid Build Coastguard Worker    return TestInterface(self.ifaces, v, full_name = self.class_name)
496*795d594fSAndroid Build Coastguard Worker
497*795d594fSAndroid Build Coastguard Worker  def get_super_types(self):
498*795d594fSAndroid Build Coastguard Worker    """
499*795d594fSAndroid Build Coastguard Worker    Returns a set of all the supertypes of this interface
500*795d594fSAndroid Build Coastguard Worker    """
501*795d594fSAndroid Build Coastguard Worker    return set(i2 for i2 in self)
502*795d594fSAndroid Build Coastguard Worker
503*795d594fSAndroid Build Coastguard Worker  def is_conflict(self):
504*795d594fSAndroid Build Coastguard Worker    """
505*795d594fSAndroid Build Coastguard Worker    Returns true if this is a conflict interface and calling the method on this interface will
506*795d594fSAndroid Build Coastguard Worker    result in an IncompatibleClassChangeError.
507*795d594fSAndroid Build Coastguard Worker    """
508*795d594fSAndroid Build Coastguard Worker    return False
509*795d594fSAndroid Build Coastguard Worker
510*795d594fSAndroid Build Coastguard Worker  def is_abstract(self):
511*795d594fSAndroid Build Coastguard Worker    """
512*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
513*795d594fSAndroid Build Coastguard Worker    result in an AbstractMethodError.
514*795d594fSAndroid Build Coastguard Worker    """
515*795d594fSAndroid Build Coastguard Worker    return self.iface_type == InterfaceType.abstract
516*795d594fSAndroid Build Coastguard Worker
517*795d594fSAndroid Build Coastguard Worker  def is_empty(self):
518*795d594fSAndroid Build Coastguard Worker    """
519*795d594fSAndroid Build Coastguard Worker    Returns true if this is an abstract interface and calling the method on this interface will
520*795d594fSAndroid Build Coastguard Worker    result in a NoSuchMethodError.
521*795d594fSAndroid Build Coastguard Worker    """
522*795d594fSAndroid Build Coastguard Worker    return self.iface_type == InterfaceType.empty
523*795d594fSAndroid Build Coastguard Worker
524*795d594fSAndroid Build Coastguard Worker  def is_default(self):
525*795d594fSAndroid Build Coastguard Worker    """
526*795d594fSAndroid Build Coastguard Worker    Returns true if this is a default interface and calling the method on this interface will
527*795d594fSAndroid Build Coastguard Worker    result in a method actually being called.
528*795d594fSAndroid Build Coastguard Worker    """
529*795d594fSAndroid Build Coastguard Worker    return self.iface_type == InterfaceType.default
530*795d594fSAndroid Build Coastguard Worker
531*795d594fSAndroid Build Coastguard Worker  def get_expected(self):
532*795d594fSAndroid Build Coastguard Worker    response = self.get_response()
533*795d594fSAndroid Build Coastguard Worker    if response == InterfaceCallResponse.NoError:
534*795d594fSAndroid Build Coastguard Worker      for iface in self.ifaces:
535*795d594fSAndroid Build Coastguard Worker        if self.is_default():
536*795d594fSAndroid Build Coastguard Worker          yield self.OUTPUT_PREFIX.format(iface_name = iface.get_name(), tree = self.get_tree())
537*795d594fSAndroid Build Coastguard Worker        yield from iface.get_expected()
538*795d594fSAndroid Build Coastguard Worker        if self.is_default():
539*795d594fSAndroid Build Coastguard Worker          yield iface.get_response().get_output_format().format(iface_name = iface.get_name(),
540*795d594fSAndroid Build Coastguard Worker                                                                tree = self.get_tree())
541*795d594fSAndroid Build Coastguard Worker
542*795d594fSAndroid Build Coastguard Worker  def get_response(self):
543*795d594fSAndroid Build Coastguard Worker    if self.is_default():
544*795d594fSAndroid Build Coastguard Worker      return InterfaceCallResponse.NoError
545*795d594fSAndroid Build Coastguard Worker    elif self.is_abstract():
546*795d594fSAndroid Build Coastguard Worker      return InterfaceCallResponse.AbstractMethodError
547*795d594fSAndroid Build Coastguard Worker    elif len(self.ifaces) == 0:
548*795d594fSAndroid Build Coastguard Worker      return InterfaceCallResponse.NoSuchMethodError
549*795d594fSAndroid Build Coastguard Worker    else:
550*795d594fSAndroid Build Coastguard Worker      return self.get_called().get_response()
551*795d594fSAndroid Build Coastguard Worker
552*795d594fSAndroid Build Coastguard Worker  def get_called(self):
553*795d594fSAndroid Build Coastguard Worker    """
554*795d594fSAndroid Build Coastguard Worker    Returns the interface that will be called when the method on this class is invoked or
555*795d594fSAndroid Build Coastguard Worker    CONFLICT_TYPE if there is no interface that will be called.
556*795d594fSAndroid Build Coastguard Worker    """
557*795d594fSAndroid Build Coastguard Worker    if not self.is_empty() or len(self.ifaces) == 0:
558*795d594fSAndroid Build Coastguard Worker      return self
559*795d594fSAndroid Build Coastguard Worker    else:
560*795d594fSAndroid Build Coastguard Worker      best = self
561*795d594fSAndroid Build Coastguard Worker      for super_iface in self.ifaces:
562*795d594fSAndroid Build Coastguard Worker        super_best = super_iface.get_called()
563*795d594fSAndroid Build Coastguard Worker        if super_best.is_conflict():
564*795d594fSAndroid Build Coastguard Worker          return CONFLICT_TYPE
565*795d594fSAndroid Build Coastguard Worker        elif best.is_default():
566*795d594fSAndroid Build Coastguard Worker          if super_best.is_default():
567*795d594fSAndroid Build Coastguard Worker            return CONFLICT_TYPE
568*795d594fSAndroid Build Coastguard Worker        elif best.is_abstract():
569*795d594fSAndroid Build Coastguard Worker          if super_best.is_default():
570*795d594fSAndroid Build Coastguard Worker            best = super_best
571*795d594fSAndroid Build Coastguard Worker        else:
572*795d594fSAndroid Build Coastguard Worker          assert best.is_empty()
573*795d594fSAndroid Build Coastguard Worker          best = super_best
574*795d594fSAndroid Build Coastguard Worker      return best
575*795d594fSAndroid Build Coastguard Worker
576*795d594fSAndroid Build Coastguard Worker  def get_name(self):
577*795d594fSAndroid Build Coastguard Worker    """
578*795d594fSAndroid Build Coastguard Worker    Get the name of this class
579*795d594fSAndroid Build Coastguard Worker    """
580*795d594fSAndroid Build Coastguard Worker    return self.class_name
581*795d594fSAndroid Build Coastguard Worker
582*795d594fSAndroid Build Coastguard Worker  def get_tree(self):
583*795d594fSAndroid Build Coastguard Worker    """
584*795d594fSAndroid Build Coastguard Worker    Print out a representation of the type tree of this class
585*795d594fSAndroid Build Coastguard Worker    """
586*795d594fSAndroid Build Coastguard Worker    return "[{class_name} {iftree}]".format(class_name = self.get_name(),
587*795d594fSAndroid Build Coastguard Worker                                            iftree = print_tree(self.ifaces))
588*795d594fSAndroid Build Coastguard Worker
589*795d594fSAndroid Build Coastguard Worker  def __iter__(self):
590*795d594fSAndroid Build Coastguard Worker    """
591*795d594fSAndroid Build Coastguard Worker    Performs depth-first traversal of the interface tree this interface is the
592*795d594fSAndroid Build Coastguard Worker    root of. Does not filter out repeats.
593*795d594fSAndroid Build Coastguard Worker    """
594*795d594fSAndroid Build Coastguard Worker    for i in self.ifaces:
595*795d594fSAndroid Build Coastguard Worker      yield i
596*795d594fSAndroid Build Coastguard Worker      yield from i
597*795d594fSAndroid Build Coastguard Worker
598*795d594fSAndroid Build Coastguard Worker  def __str__(self):
599*795d594fSAndroid Build Coastguard Worker    """
600*795d594fSAndroid Build Coastguard Worker    Print the smali code of this interface.
601*795d594fSAndroid Build Coastguard Worker    """
602*795d594fSAndroid Build Coastguard Worker    s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()),
603*795d594fSAndroid Build Coastguard Worker                             self.ifaces))
604*795d594fSAndroid Build Coastguard Worker    j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces))
605*795d594fSAndroid Build Coastguard Worker    if self.is_default():
606*795d594fSAndroid Build Coastguard Worker      super_template = self.SUPER_CALL_TEMPLATE
607*795d594fSAndroid Build Coastguard Worker      super_calls ="\n".join(super_template.format(iface_name = iface.get_name(),
608*795d594fSAndroid Build Coastguard Worker                                                   class_name = self.get_name(),
609*795d594fSAndroid Build Coastguard Worker                                                   tree = self.get_tree()) for iface in self.ifaces)
610*795d594fSAndroid Build Coastguard Worker      funcs = self.DEFAULT_FUNC_TEMPLATE.format(super_calls = super_calls)
611*795d594fSAndroid Build Coastguard Worker    elif self.is_abstract():
612*795d594fSAndroid Build Coastguard Worker      funcs = self.ABSTRACT_FUNC_TEMPLATE.format()
613*795d594fSAndroid Build Coastguard Worker    else:
614*795d594fSAndroid Build Coastguard Worker      funcs = ""
615*795d594fSAndroid Build Coastguard Worker    return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'),
616*795d594fSAndroid Build Coastguard Worker                                               implements_spec = s_ifaces,
617*795d594fSAndroid Build Coastguard Worker                                               extends = "extends" if len(self.ifaces) else "",
618*795d594fSAndroid Build Coastguard Worker                                               ifaces = j_ifaces,
619*795d594fSAndroid Build Coastguard Worker                                               func = funcs,
620*795d594fSAndroid Build Coastguard Worker                                               tree = self.get_tree(),
621*795d594fSAndroid Build Coastguard Worker                                               class_name = self.class_name)
622*795d594fSAndroid Build Coastguard Worker
623*795d594fSAndroid Build Coastguard Workerdef print_tree(ifaces):
624*795d594fSAndroid Build Coastguard Worker  """
625*795d594fSAndroid Build Coastguard Worker  Prints a list of iface trees
626*795d594fSAndroid Build Coastguard Worker  """
627*795d594fSAndroid Build Coastguard Worker  return " ".join(i.get_tree() for i in ifaces)
628*795d594fSAndroid Build Coastguard Worker
629*795d594fSAndroid Build Coastguard Worker# The deduplicated output of subtree_sizes for each size up to
630*795d594fSAndroid Build Coastguard Worker# MAX_LEAF_IFACE_PER_OBJECT.
631*795d594fSAndroid Build Coastguard WorkerSUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i))
632*795d594fSAndroid Build Coastguard Worker            for i in range(MAX_IFACE_DEPTH + 1)]
633*795d594fSAndroid Build Coastguard Worker
634*795d594fSAndroid Build Coastguard Workerdef create_test_classes():
635*795d594fSAndroid Build Coastguard Worker  """
636*795d594fSAndroid Build Coastguard Worker  Yield all the test classes with the different interface trees
637*795d594fSAndroid Build Coastguard Worker  """
638*795d594fSAndroid Build Coastguard Worker  for num in range(1, MAX_IFACE_DEPTH + 1):
639*795d594fSAndroid Build Coastguard Worker    for split in SUBTREES[num]:
640*795d594fSAndroid Build Coastguard Worker      ifaces = []
641*795d594fSAndroid Build Coastguard Worker      for sub in split:
642*795d594fSAndroid Build Coastguard Worker        ifaces.append(list(create_interface_trees(sub)))
643*795d594fSAndroid Build Coastguard Worker      for supers in itertools.product(*ifaces):
644*795d594fSAndroid Build Coastguard Worker        yield TestClass(supers)
645*795d594fSAndroid Build Coastguard Worker
646*795d594fSAndroid Build Coastguard Workerdef create_interface_trees(num):
647*795d594fSAndroid Build Coastguard Worker  """
648*795d594fSAndroid Build Coastguard Worker  Yield all the interface trees up to 'num' depth.
649*795d594fSAndroid Build Coastguard Worker  """
650*795d594fSAndroid Build Coastguard Worker  if num == 0:
651*795d594fSAndroid Build Coastguard Worker    for iftype in InterfaceType:
652*795d594fSAndroid Build Coastguard Worker      yield TestInterface(tuple(), iftype)
653*795d594fSAndroid Build Coastguard Worker    return
654*795d594fSAndroid Build Coastguard Worker  for split in SUBTREES[num]:
655*795d594fSAndroid Build Coastguard Worker    ifaces = []
656*795d594fSAndroid Build Coastguard Worker    for sub in split:
657*795d594fSAndroid Build Coastguard Worker      ifaces.append(list(create_interface_trees(sub)))
658*795d594fSAndroid Build Coastguard Worker    for supers in itertools.product(*ifaces):
659*795d594fSAndroid Build Coastguard Worker      for iftype in InterfaceType:
660*795d594fSAndroid Build Coastguard Worker        yield TestInterface(supers, iftype)
661*795d594fSAndroid Build Coastguard Worker
662*795d594fSAndroid Build Coastguard Workerdef create_all_test_files():
663*795d594fSAndroid Build Coastguard Worker  """
664*795d594fSAndroid Build Coastguard Worker  Creates all the objects representing the files in this test. They just need to
665*795d594fSAndroid Build Coastguard Worker  be dumped.
666*795d594fSAndroid Build Coastguard Worker  """
667*795d594fSAndroid Build Coastguard Worker  mc = MainClass()
668*795d594fSAndroid Build Coastguard Worker  classes = {mc}
669*795d594fSAndroid Build Coastguard Worker  for clazz in create_test_classes():
670*795d594fSAndroid Build Coastguard Worker    classes.add(clazz)
671*795d594fSAndroid Build Coastguard Worker    for i in clazz:
672*795d594fSAndroid Build Coastguard Worker      classes.add(i)
673*795d594fSAndroid Build Coastguard Worker    mc.add_test(clazz)
674*795d594fSAndroid Build Coastguard Worker  return mc, classes
675*795d594fSAndroid Build Coastguard Worker
676*795d594fSAndroid Build Coastguard Workerdef main(argv):
677*795d594fSAndroid Build Coastguard Worker  smali_dir = Path(argv[1])
678*795d594fSAndroid Build Coastguard Worker  if not smali_dir.exists() or not smali_dir.is_dir():
679*795d594fSAndroid Build Coastguard Worker    print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr)
680*795d594fSAndroid Build Coastguard Worker    sys.exit(1)
681*795d594fSAndroid Build Coastguard Worker  expected_txt = Path(argv[2])
682*795d594fSAndroid Build Coastguard Worker  mainclass, all_files = create_all_test_files()
683*795d594fSAndroid Build Coastguard Worker  with expected_txt.open('w') as out:
684*795d594fSAndroid Build Coastguard Worker    print(mainclass.get_expected(), file=out)
685*795d594fSAndroid Build Coastguard Worker  for f in all_files:
686*795d594fSAndroid Build Coastguard Worker    f.dump(smali_dir)
687*795d594fSAndroid Build Coastguard Worker
688*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__':
689*795d594fSAndroid Build Coastguard Worker  main(sys.argv)
690