blob: 00c0c0e8d1adbddf1f62a763c79786467d550b93 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Utility to display a summary of JSON-format GM results, and exit with
a nonzero errorcode if there were non-ignored failures in the GM results.
Usage:
python display_json_results.py <filename>
TODO(epoger): We may want to add flags to set the following:
- which error types cause a nonzero return code
- maximum number of tests to list for any one ResultAccumulator
(to keep the output reasonably short)
"""
__author__ = 'Elliot Poger'
import json
import sys
# These constants must be kept in sync with the kJsonKey_ constants in
# gm_expectations.cpp !
JSONKEY_ACTUALRESULTS = 'actual-results'
JSONKEY_ACTUALRESULTS_FAILED = 'failed'
JSONKEY_ACTUALRESULTS_FAILUREIGNORED = 'failure-ignored'
JSONKEY_ACTUALRESULTS_NOCOMPARISON = 'no-comparison'
JSONKEY_ACTUALRESULTS_SUCCEEDED = 'succeeded'
class ResultAccumulator(object):
"""Object that accumulates results of a given type, and can generate a
summary upon request."""
def __init__(self, name, do_list, do_fail):
"""name: name of the category this result type falls into
do_list: whether to list all of the tests with this results type
do_fail: whether to return with nonzero exit code if there are any
results of this type
"""
self._name = name
self._do_list = do_list
self._do_fail = do_fail
self._testnames = []
def AddResult(self, testname):
"""Adds a result of this particular type.
testname: (string) name of the test"""
self._testnames.append(testname)
def ShouldSignalFailure(self):
"""Returns true if this result type is serious (self._do_fail is True)
and there were any results of this type."""
if self._do_fail and self._testnames:
return True
else:
return False
def GetSummaryLine(self):
"""Returns a single-line string summary of all results added to this
accumulator so far."""
summary = ''
if self._do_fail:
summary += '[*] '
else:
summary += '[ ] '
summary += str(len(self._testnames))
summary += ' '
summary += self._name
if self._do_list:
summary += ': '
for testname in self._testnames:
summary += testname
summary += ' '
return summary
def Display(filepath):
"""Displays a summary of the results in a JSON file.
Returns True if the results are free of any significant failures.
filepath: (string) path to JSON file"""
# Map labels within the JSON file to the ResultAccumulator for each label.
results_map = {
JSONKEY_ACTUALRESULTS_FAILED:
ResultAccumulator(name='ExpectationsMismatch',
do_list=True, do_fail=True),
JSONKEY_ACTUALRESULTS_FAILUREIGNORED:
ResultAccumulator(name='IgnoredExpectationsMismatch',
do_list=True, do_fail=False),
JSONKEY_ACTUALRESULTS_NOCOMPARISON:
ResultAccumulator(name='MissingExpectations',
do_list=False, do_fail=False),
JSONKEY_ACTUALRESULTS_SUCCEEDED:
ResultAccumulator(name='Passed',
do_list=False, do_fail=False),
}
success = True
json_dict = json.load(open(filepath))
actual_results = json_dict[JSONKEY_ACTUALRESULTS]
for label, accumulator in results_map.iteritems():
results = actual_results[label]
if results:
for result in results:
accumulator.AddResult(result)
print accumulator.GetSummaryLine()
if accumulator.ShouldSignalFailure():
success = False
print '(results marked with [*] will cause nonzero return value)'
return success
if '__main__' == __name__:
if len(sys.argv) != 2:
raise Exception('usage: %s <input-json-filepath>' % sys.argv[0])
sys.exit(0 if Display(sys.argv[1]) else 1)