OLD | NEW |
| (Empty) |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 import logging | |
6 import re | |
7 | |
8 # http://developer.android.com/reference/android/test/InstrumentationTestRunner.
html | |
9 STATUS_CODE_START = 1 | |
10 STATUS_CODE_OK = 0 | |
11 STATUS_CODE_ERROR = -1 | |
12 STATUS_CODE_FAILURE = -2 | |
13 | |
14 # http://developer.android.com/reference/android/app/Activity.html | |
15 RESULT_CODE_OK = -1 | |
16 RESULT_CODE_CANCELED = 0 | |
17 | |
18 _INSTR_LINE_RE = re.compile('^\s*INSTRUMENTATION_([A-Z_]+): (.*)$') | |
19 | |
20 | |
21 class InstrumentationParser(object): | |
22 | |
23 def __init__(self, stream): | |
24 """An incremental parser for the output of Android instrumentation tests. | |
25 | |
26 Example: | |
27 | |
28 stream = adb.IterShell('am instrument -r ...') | |
29 parser = InstrumentationParser(stream) | |
30 | |
31 for code, bundle in parser.IterStatus(): | |
32 # do something with each instrumentation status | |
33 print 'status:', code, bundle | |
34 | |
35 # do something with the final instrumentation result | |
36 code, bundle = parser.GetResult() | |
37 print 'result:', code, bundle | |
38 | |
39 Args: | |
40 stream: a sequence of lines as produced by the raw output of an | |
41 instrumentation test (e.g. by |am instrument -r| or |uiautomator|). | |
42 """ | |
43 self._stream = stream | |
44 self._code = None | |
45 self._bundle = None | |
46 | |
47 def IterStatus(self): | |
48 """Iterate over statuses as they are produced by the instrumentation test. | |
49 | |
50 Yields: | |
51 A tuple (code, bundle) for each instrumentation status found in the | |
52 output. | |
53 """ | |
54 def join_bundle_values(bundle): | |
55 for key in bundle: | |
56 bundle[key] = '\n'.join(bundle[key]) | |
57 return bundle | |
58 | |
59 bundle = {'STATUS': {}, 'RESULT': {}} | |
60 header = None | |
61 key = None | |
62 for line in self._stream: | |
63 m = _INSTR_LINE_RE.match(line) | |
64 if m: | |
65 header, value = m.groups() | |
66 key = None | |
67 if header in ['STATUS', 'RESULT'] and '=' in value: | |
68 key, value = value.split('=', 1) | |
69 bundle[header][key] = [value] | |
70 elif header == 'STATUS_CODE': | |
71 yield int(value), join_bundle_values(bundle['STATUS']) | |
72 bundle['STATUS'] = {} | |
73 elif header == 'CODE': | |
74 self._code = int(value) | |
75 else: | |
76 logging.warning('Unknown INSTRUMENTATION_%s line: %s', header, value) | |
77 elif key is not None: | |
78 bundle[header][key].append(line) | |
79 | |
80 self._bundle = join_bundle_values(bundle['RESULT']) | |
81 | |
82 def GetResult(self): | |
83 """Return the final instrumentation result. | |
84 | |
85 Returns: | |
86 A pair (code, bundle) with the final instrumentation result. The |code| | |
87 may be None if no instrumentation result was found in the output. | |
88 | |
89 Raises: | |
90 AssertionError if attempting to get the instrumentation result before | |
91 exhausting |IterStatus| first. | |
92 """ | |
93 assert self._bundle is not None, ( | |
94 'The IterStatus generator must be exhausted before reading the final' | |
95 ' instrumentation result.') | |
96 return self._code, self._bundle | |
OLD | NEW |