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.
8 # http://developer.android.com/reference/android/test/InstrumentationTestRunner.html
11 STATUS_CODE_ERROR
= -1
12 STATUS_CODE_FAILURE
= -2
14 # http://developer.android.com/reference/android/app/Activity.html
16 RESULT_CODE_CANCELED
= 0
18 _INSTR_LINE_RE
= re
.compile(r
'^\s*INSTRUMENTATION_([A-Z_]+): (.*)$')
21 class InstrumentationParser(object):
23 def __init__(self
, stream
):
24 """An incremental parser for the output of Android instrumentation tests.
28 stream = adb.IterShell('am instrument -r ...')
29 parser = InstrumentationParser(stream)
31 for code, bundle in parser.IterStatus():
32 # do something with each instrumentation status
33 print 'status:', code, bundle
35 # do something with the final instrumentation result
36 code, bundle = parser.GetResult()
37 print 'result:', code, bundle
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|).
48 """Iterate over statuses as they are produced by the instrumentation test.
51 A tuple (code, bundle) for each instrumentation status found in the
54 def join_bundle_values(bundle
):
56 bundle
[key
] = '\n'.join(bundle
[key
])
59 bundle
= {'STATUS': {}, 'RESULT': {}}
62 for line
in self
._stream
:
63 m
= _INSTR_LINE_RE
.match(line
)
65 header
, value
= m
.groups()
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'])
73 elif header
== 'CODE':
74 self
._code
= int(value
)
76 logging
.warning('Unknown INSTRUMENTATION_%s line: %s', header
, value
)
78 bundle
[header
][key
].append(line
)
80 self
._bundle
= join_bundle_values(bundle
['RESULT'])
83 """Return the final instrumentation result.
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.
90 AssertionError if attempting to get the instrumentation result before
91 exhausting |IterStatus| first.
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