| Index: gm/display_json_results.py
|
| ===================================================================
|
| --- gm/display_json_results.py (revision 9180)
|
| +++ gm/display_json_results.py (working copy)
|
| @@ -3,10 +3,16 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -"""Utility to confirm that a JSON summary written by GM contains no failures.
|
| +"""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 confirm_no_failures_in_json.py <filename>
|
| + 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'
|
| @@ -20,28 +26,95 @@
|
| # 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'
|
|
|
| -# This is the same indent level as used by jsoncpp, just for consistency.
|
| -JSON_INDENTLEVEL = 3
|
|
|
| +class ResultAccumulator(object):
|
| + """Object that accumulates results of a given type, and can generate a
|
| + summary upon request."""
|
|
|
| -def Assert(filepath):
|
| - """Raises an exception if the JSON summary at filepath contains any failed
|
| - tests, or if we were unable to read the JSON summary."""
|
| - failed_tests = GetFailedTests(filepath)
|
| - if failed_tests:
|
| - raise Exception('JSON file %s contained these test failures...\n%s' % (
|
| - filepath, json.dumps(failed_tests, indent=JSON_INDENTLEVEL)))
|
| + 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 GetFailedTests(filepath):
|
| - """Returns the dictionary of failed tests from the JSON file at filepath."""
|
| + 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]
|
| - return actual_results[JSONKEY_ACTUALRESULTS_FAILED]
|
| + 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])
|
| - Assert(sys.argv[1])
|
| + sys.exit(0 if Display(sys.argv[1]) else 1)
|
|
|