Index: build/android/pylib/instrumentation/test_jar.py |
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py |
index d83d00a150e3178f29f4818eb9610b133798520c..a3d8849d3808a52cffc15ef45b1ffc0e4852ae1b 100644 |
--- a/build/android/pylib/instrumentation/test_jar.py |
+++ b/build/android/pylib/instrumentation/test_jar.py |
@@ -10,11 +10,11 @@ import os |
import pickle |
import re |
import sys |
-import tempfile |
from pylib import cmd_helper |
from pylib import constants |
from pylib.device import device_utils |
+from pylib.utils import proguard |
sys.path.insert(0, |
os.path.join(constants.DIR_SOURCE_ROOT, |
@@ -23,7 +23,7 @@ sys.path.insert(0, |
import unittest_util # pylint: disable=F0401 |
# If you change the cached output of proguard, increment this number |
-PICKLE_FORMAT_VERSION = 3 |
+PICKLE_FORMAT_VERSION = 4 |
class TestJar(object): |
@@ -86,111 +86,30 @@ class TestJar(object): |
def _GetProguardData(self): |
logging.info('Retrieving test methods via proguard.') |
- with tempfile.NamedTemporaryFile() as proguard_output: |
- cmd_helper.RunCmd(['java', '-jar', |
- self._PROGUARD_PATH, |
- '-injars', self._jar_path, |
- '-dontshrink', |
- '-dontoptimize', |
- '-dontobfuscate', |
- '-dontpreverify', |
- '-dump', proguard_output.name]) |
- |
- clazzez = {} |
- |
- annotation = None |
- annotation_has_value = False |
- clazz = None |
- method = None |
- |
- for line in proguard_output: |
- if len(line) == 0: |
- annotation = None |
- annotation_has_value = False |
- method = None |
- continue |
- |
- m = self._PROGUARD_CLASS_RE.match(line) |
- if m: |
- clazz = m.group(1).replace('/', '.') |
- clazzez[clazz] = { |
- 'methods': {}, |
- 'annotations': {} |
- } |
- annotation = None |
- annotation_has_value = False |
- method = None |
- continue |
- |
- if not clazz: |
- continue |
- |
- m = self._PROGUARD_SUPERCLASS_RE.match(line) |
- if m: |
- clazzez[clazz]['superclass'] = m.group(1).replace('/', '.') |
- continue |
- |
- if clazz.endswith('Test'): |
- m = self._PROGUARD_METHOD_RE.match(line) |
- if m: |
- method = m.group(1) |
- clazzez[clazz]['methods'][method] = {'annotations': {}} |
- annotation = None |
- annotation_has_value = False |
- continue |
- |
- m = self._PROGUARD_ANNOTATION_RE.match(line) |
- if m: |
- # Ignore the annotation package. |
- annotation = m.group(1).split('/')[-1] |
- if method: |
- clazzez[clazz]['methods'][method]['annotations'][annotation] = None |
- else: |
- clazzez[clazz]['annotations'][annotation] = None |
- continue |
- |
- if annotation: |
- if not annotation_has_value: |
- m = self._PROGUARD_ANNOTATION_CONST_RE.match(line) |
- annotation_has_value = bool(m) |
- else: |
- m = self._PROGUARD_ANNOTATION_VALUE_RE.match(line) |
- if m: |
- if method: |
- clazzez[clazz]['methods'][method]['annotations'][annotation] = ( |
- m.group(1)) |
- else: |
- clazzez[clazz]['annotations'][annotation] = m.group(1) |
- annotation_has_value = None |
- |
- test_clazzez = ((n, i) for n, i in clazzez.items() if n.endswith('Test')) |
- for clazz_name, clazz_info in test_clazzez: |
- logging.info('Processing %s' % clazz_name) |
- c = clazz_name |
- min_sdk_level = None |
- |
- while c in clazzez: |
- c_info = clazzez[c] |
- if not min_sdk_level: |
- min_sdk_level = c_info['annotations'].get('MinAndroidSdkLevel', None) |
- c = c_info.get('superclass', None) |
- |
- for method_name, method_info in clazz_info['methods'].items(): |
- if method_name.startswith('test'): |
- qualified_method = '%s#%s' % (clazz_name, method_name) |
- method_annotations = [] |
- for annotation_name, annotation_value in ( |
- method_info['annotations'].items()): |
- method_annotations.append(annotation_name) |
- if annotation_value: |
- method_annotations.append( |
- annotation_name + ':' + annotation_value) |
- self._test_methods[qualified_method] = { |
- 'annotations': method_annotations |
- } |
- if min_sdk_level is not None: |
- self._test_methods[qualified_method]['min_sdk_level'] = ( |
- int(min_sdk_level)) |
+ p = proguard.Dump(self._jar_path) |
+ |
+ class_lookup = dict((c['class'], c) for c in p['classes']) |
+ def recursive_get_annotations(c): |
+ s = c['superclass'] |
+ if s in class_lookup: |
+ a = recursive_get_annotations(class_lookup[s]) |
+ else: |
+ a = {} |
+ a.update(c['annotations']) |
+ return a |
+ |
+ test_classes = (c for c in p['classes'] |
+ if c['class'].endswith('Test')) |
+ for c in test_classes: |
+ class_annotations = recursive_get_annotations(c) |
+ test_methods = (m for m in c['methods'] |
+ if m['method'].startswith('test')) |
+ for m in test_methods: |
+ qualified_method = '%s#%s' % (c['class'], m['method']) |
+ annotations = dict(class_annotations) |
+ annotations.update(m['annotations']) |
+ self._test_methods[qualified_method] = m |
+ self._test_methods[qualified_method]['annotations'] = annotations |
logging.info('Storing proguard output to %s', self._pickled_proguard_name) |
d = {'VERSION': PICKLE_FORMAT_VERSION, |
@@ -199,7 +118,6 @@ class TestJar(object): |
with open(self._pickled_proguard_name, 'w') as f: |
f.write(pickle.dumps(d)) |
- |
@staticmethod |
def _IsTestMethod(test): |
class_name, method = test.split('#') |
@@ -222,7 +140,7 @@ class TestJar(object): |
key = filters[0] |
value_list = filters[1].split(',') |
for value in value_list: |
- if key + ':' + value in annotations: |
+ if key in annotations and value == annotations['key']: |
return True |
elif annotation_filter in annotations: |
return True |
@@ -230,9 +148,9 @@ class TestJar(object): |
def GetAnnotatedTests(self, annotation_filter_list): |
"""Returns a list of all tests that match the given annotation filters.""" |
- return [test for test, attr in self.GetTestMethods().iteritems() |
+ return [test for test in self.GetTestMethods() |
if self._IsTestMethod(test) and self._AnnotationsMatchFilters( |
- annotation_filter_list, attr['annotations'])] |
+ annotation_filter_list, self.GetTestAnnotations(test))] |
def GetTestMethods(self): |
"""Returns a dict of all test methods and relevant attributes. |
@@ -245,15 +163,15 @@ class TestJar(object): |
"""Get a list of test methods with no known annotations.""" |
tests_missing_annotations = [] |
for test_method in self.GetTestMethods().iterkeys(): |
- annotations_ = frozenset(self.GetTestAnnotations(test_method)) |
+ annotations_ = frozenset(self.GetTestAnnotations(test_method).iterkeys()) |
if (annotations_.isdisjoint(self._ANNOTATIONS) and |
not self.IsHostDrivenTest(test_method)): |
tests_missing_annotations.append(test_method) |
return sorted(tests_missing_annotations) |
def _IsTestValidForSdkRange(self, test_name, attached_min_sdk_level): |
- required_min_sdk_level = self.GetTestMethods()[test_name].get( |
- 'min_sdk_level', None) |
+ required_min_sdk_level = int( |
+ self.GetTestAnnotations(test_name).get('MinAndroidSdkLevel', 0)) |
return (required_min_sdk_level is None or |
attached_min_sdk_level >= required_min_sdk_level) |