Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 ''' | 3 ''' |
| 4 Copyright 2013 Google Inc. | 4 Copyright 2013 Google Inc. |
| 5 | 5 |
| 6 Use of this source code is governed by a BSD-style license that can be | 6 Use of this source code is governed by a BSD-style license that can be |
| 7 found in the LICENSE file. | 7 found in the LICENSE file. |
| 8 ''' | 8 ''' |
| 9 | 9 |
| 10 ''' | 10 ''' |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 47 pass | 47 pass |
| 48 | 48 |
| 49 def _GetFileContentsAsString(self, filepath): | 49 def _GetFileContentsAsString(self, filepath): |
| 50 """Returns the full contents of a file, as a single string. | 50 """Returns the full contents of a file, as a single string. |
| 51 If the filename looks like a URL, download its contents...""" | 51 If the filename looks like a URL, download its contents...""" |
| 52 if filepath.startswith('http:') or filepath.startswith('https:'): | 52 if filepath.startswith('http:') or filepath.startswith('https:'): |
| 53 return urllib2.urlopen(filepath).read() | 53 return urllib2.urlopen(filepath).read() |
| 54 else: | 54 else: |
| 55 return open(filepath, 'r').read() | 55 return open(filepath, 'r').read() |
| 56 | 56 |
| 57 def _GetExpectedResults(self, filepath): | 57 def _GetExpectedResults(self, contents): |
| 58 """Returns the dictionary of expected results from a JSON file, | 58 """Returns the dictionary of expected results from a JSON string, |
| 59 in this form: | 59 in this form: |
| 60 | 60 |
| 61 { | 61 { |
| 62 'test1' : 14760033689012826769, | 62 'test1' : 14760033689012826769, |
| 63 'test2' : 9151974350149210736, | 63 'test2' : 9151974350149210736, |
| 64 ... | 64 ... |
| 65 } | 65 } |
| 66 | 66 |
| 67 We make these simplifying assumptions: | 67 We make these simplifying assumptions: |
| 68 1. Each test has either 0 or 1 allowed results. | 68 1. Each test has either 0 or 1 allowed results. |
| 69 2. All expectations are of type JSONKEY_HASHTYPE_BITMAP_64BITMD5. | 69 2. All expectations are of type JSONKEY_HASHTYPE_BITMAP_64BITMD5. |
| 70 | 70 |
| 71 Any tests which violate those assumptions will cause an exception to | 71 Any tests which violate those assumptions will cause an exception to |
| 72 be raised. | 72 be raised. |
| 73 | 73 |
| 74 Any tests for which we have no expectations will be left out of the | 74 Any tests for which we have no expectations will be left out of the |
| 75 returned dictionary. | 75 returned dictionary. |
| 76 """ | 76 """ |
| 77 result_dict = {} | 77 result_dict = {} |
| 78 contents = self._GetFileContentsAsString(filepath) | |
| 79 json_dict = gm_json.LoadFromString(contents) | 78 json_dict = gm_json.LoadFromString(contents) |
| 80 all_expectations = json_dict[gm_json.JSONKEY_EXPECTEDRESULTS] | 79 all_expectations = json_dict[gm_json.JSONKEY_EXPECTEDRESULTS] |
| 81 for test_name in all_expectations.keys(): | 80 for test_name in all_expectations.keys(): |
| 82 test_expectations = all_expectations[test_name] | 81 test_expectations = all_expectations[test_name] |
| 83 allowed_digests = test_expectations[ | 82 allowed_digests = test_expectations[ |
| 84 gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS] | 83 gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS] |
| 85 if allowed_digests: | 84 if allowed_digests: |
| 86 num_allowed_digests = len(allowed_digests) | 85 num_allowed_digests = len(allowed_digests) |
| 87 if num_allowed_digests > 1: | 86 if num_allowed_digests > 1: |
| 88 raise ValueError( | 87 raise ValueError( |
| 89 'test %s in file %s has %d allowed digests' % ( | 88 'test %s in file %s has %d allowed digests' % ( |
| 90 test_name, filepath, num_allowed_digests)) | 89 test_name, filepath, num_allowed_digests)) |
| 91 digest_pair = allowed_digests[0] | 90 digest_pair = allowed_digests[0] |
| 92 if digest_pair[0] != gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5: | 91 if digest_pair[0] != gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5: |
| 93 raise ValueError( | 92 raise ValueError( |
| 94 'test %s in file %s has unsupported hashtype %s' % ( | 93 'test %s in file %s has unsupported hashtype %s' % ( |
| 95 test_name, filepath, digest_pair[0])) | 94 test_name, filepath, digest_pair[0])) |
| 96 result_dict[test_name] = digest_pair[1] | 95 result_dict[test_name] = digest_pair[1] |
| 97 return result_dict | 96 return result_dict |
| 98 | 97 |
| 99 def _GetActualResults(self, filepath): | 98 def _GetActualResults(self, contents): |
| 100 """Returns the dictionary of actual results from a JSON file, | 99 """Returns the dictionary of actual results from a JSON string, |
| 101 in this form: | 100 in this form: |
| 102 | 101 |
| 103 { | 102 { |
| 104 'test1' : 14760033689012826769, | 103 'test1' : 14760033689012826769, |
| 105 'test2' : 9151974350149210736, | 104 'test2' : 9151974350149210736, |
| 106 ... | 105 ... |
| 107 } | 106 } |
| 108 | 107 |
| 109 We make these simplifying assumptions: | 108 We make these simplifying assumptions: |
| 110 1. All results are of type JSONKEY_HASHTYPE_BITMAP_64BITMD5. | 109 1. All results are of type JSONKEY_HASHTYPE_BITMAP_64BITMD5. |
| 111 | 110 |
| 112 Any tests which violate those assumptions will cause an exception to | 111 Any tests which violate those assumptions will cause an exception to |
| 113 be raised. | 112 be raised. |
| 114 | 113 |
| 115 Any tests for which we have no actual results will be left out of the | 114 Any tests for which we have no actual results will be left out of the |
| 116 returned dictionary. | 115 returned dictionary. |
| 117 """ | 116 """ |
| 118 result_dict = {} | 117 result_dict = {} |
| 119 contents = self._GetFileContentsAsString(filepath) | |
| 120 json_dict = gm_json.LoadFromString(contents) | 118 json_dict = gm_json.LoadFromString(contents) |
| 121 all_result_types = json_dict[gm_json.JSONKEY_ACTUALRESULTS] | 119 all_result_types = json_dict[gm_json.JSONKEY_ACTUALRESULTS] |
| 122 for result_type in all_result_types.keys(): | 120 for result_type in all_result_types.keys(): |
| 123 results_of_this_type = all_result_types[result_type] | 121 results_of_this_type = all_result_types[result_type] |
| 124 if results_of_this_type: | 122 if results_of_this_type: |
| 125 for test_name in results_of_this_type.keys(): | 123 for test_name in results_of_this_type.keys(): |
| 126 digest_pair = results_of_this_type[test_name] | 124 digest_pair = results_of_this_type[test_name] |
| 127 if digest_pair[0] != gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD 5: | 125 if digest_pair[0] != gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD 5: |
| 128 raise ValueError( | 126 raise ValueError( |
| 129 'test %s in file %s has unsupported hashtype %s' % ( | 127 'test %s in file %s has unsupported hashtype %s' % ( |
| 130 test_name, filepath, digest_pair[0])) | 128 test_name, filepath, digest_pair[0])) |
|
Zach Reizner
2013/08/02 21:30:58
Just a quick thing my linter caught: filepath does
epoger
2013/08/06 15:26:43
Ah. That's because, before this CL, filepath was
epoger
2013/08/06 15:28:06
P.S. I'm not suggesting you take the time to add s
| |
| 131 result_dict[test_name] = digest_pair[1] | 129 result_dict[test_name] = digest_pair[1] |
| 132 return result_dict | 130 return result_dict |
| 133 | 131 |
| 134 def _DictionaryDiff(self, old_dict, new_dict): | 132 def _DictionaryDiff(self, old_dict, new_dict): |
| 135 """Generate a dictionary showing the diffs between old_dict and new_dict . | 133 """Generate a dictionary showing the diffs between old_dict and new_dict . |
| 136 Any entries which are identical across them will be left out.""" | 134 Any entries which are identical across them will be left out.""" |
| 137 diff_dict = {} | 135 diff_dict = {} |
| 138 all_keys = set(old_dict.keys() + new_dict.keys()) | 136 all_keys = set(old_dict.keys() + new_dict.keys()) |
| 139 for key in all_keys: | 137 for key in all_keys: |
| 140 if old_dict.get(key) != new_dict.get(key): | 138 if old_dict.get(key) != new_dict.get(key): |
| 141 new_entry = {} | 139 new_entry = {} |
| 142 new_entry['old'] = old_dict.get(key) | 140 new_entry['old'] = old_dict.get(key) |
| 143 new_entry['new'] = new_dict.get(key) | 141 new_entry['new'] = new_dict.get(key) |
| 144 diff_dict[key] = new_entry | 142 diff_dict[key] = new_entry |
| 145 return diff_dict | 143 return diff_dict |
| 146 | 144 |
| 147 def GenerateDiffDict(self, oldfile, newfile=None): | 145 def GenerateDiffDict(self, oldfile, newfile=None): |
| 148 """Generate a dictionary showing the diffs: | 146 """Generate a dictionary showing the diffs: |
| 149 old = expectations within oldfile | 147 old = expectations within oldfile |
| 150 new = expectations within newfile | 148 new = expectations within newfile |
| 151 | 149 |
| 152 If newfile is not specified, then 'new' is the actual results within | 150 If newfile is not specified, then 'new' is the actual results within |
| 153 oldfile. | 151 oldfile. |
| 154 """ | 152 """ |
| 155 old_results = self._GetExpectedResults(oldfile) | 153 old_results = self._GetExpectedResults(self._GetFileContentsAsString(old file)) |
|
epoger
2013/08/02 14:33:06
I think it would be a bit cleaner to have this met
Zach Reizner
2013/08/02 21:30:58
Done.
| |
| 156 if newfile: | 154 if newfile: |
| 157 new_results = self._GetExpectedResults(newfile) | 155 new_results = self._GetExpectedResults(self._GetFileContentsAsString (newfile)) |
| 158 else: | 156 else: |
| 159 new_results = self._GetActualResults(oldfile) | 157 new_results = self._GetActualResults(self._GetFileContentsAsString(o ldfile)) |
| 158 return self._DictionaryDiff(old_results, new_results) | |
| 159 | |
| 160 def GenerateDiffDictFromStrings(self, oldjson, newjson=None): | |
| 161 """Generate a dictionary showing the diffs: | |
| 162 old = expectations within oldjson | |
| 163 new = expectations within newjson | |
| 164 | |
| 165 If newfile is not specified, then 'new' is the actual results within | |
| 166 oldfile. | |
| 167 """ | |
| 168 old_results = self._GetExpectedResults(oldjson) | |
| 169 if newjson: | |
| 170 new_results = self._GetExpectedResults(newjson) | |
| 171 else: | |
| 172 new_results = self._GetActualResults(oldjson) | |
| 160 return self._DictionaryDiff(old_results, new_results) | 173 return self._DictionaryDiff(old_results, new_results) |
| 161 | 174 |
| 162 | 175 |
| 163 def _Main(): | 176 def _Main(): |
| 164 parser = argparse.ArgumentParser() | 177 parser = argparse.ArgumentParser() |
| 165 parser.add_argument( | 178 parser.add_argument( |
| 166 'old', | 179 'old', |
| 167 help='Path to JSON file whose expectations to display on ' + | 180 help='Path to JSON file whose expectations to display on ' + |
| 168 'the "old" side of the diff. This can be a filepath on ' + | 181 'the "old" side of the diff. This can be a filepath on ' + |
| 169 'local storage, or a URL.') | 182 'local storage, or a URL.') |
| 170 parser.add_argument( | 183 parser.add_argument( |
| 171 'new', nargs='?', | 184 'new', nargs='?', |
| 172 help='Path to JSON file whose expectations to display on ' + | 185 help='Path to JSON file whose expectations to display on ' + |
| 173 'the "new" side of the diff; if not specified, uses the ' + | 186 'the "new" side of the diff; if not specified, uses the ' + |
| 174 'ACTUAL results from the "old" JSON file. This can be a ' + | 187 'ACTUAL results from the "old" JSON file. This can be a ' + |
| 175 'filepath on local storage, or a URL.') | 188 'filepath on local storage, or a URL.') |
| 176 args = parser.parse_args() | 189 args = parser.parse_args() |
| 177 differ = GMDiffer() | 190 differ = GMDiffer() |
| 178 diffs = differ.GenerateDiffDict(oldfile=args.old, newfile=args.new) | 191 diffs = differ.GenerateDiffDict(oldfile=args.old, newfile=args.new) |
| 179 json.dump(diffs, sys.stdout, sort_keys=True, indent=2) | 192 json.dump(diffs, sys.stdout, sort_keys=True, indent=2) |
| 180 | 193 |
| 181 | 194 |
| 182 if __name__ == '__main__': | 195 if __name__ == '__main__': |
| 183 _Main() | 196 _Main() |
| OLD | NEW |