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