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