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) |