1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# found in the LICENSE file. 4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import os 5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import re 6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import unittest 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import PRESUBMIT 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockInputApi(object): 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self): 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.re = re 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.os_path = os.path 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.files = [] 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.is_committing = False 16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def AffectedFiles(self): 18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self.files 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def AffectedSourceFiles(self, fn): 21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # we'll just pretend everything is a source file for the sake of simplicity 22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self.files 23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def ReadFile(self, f): 25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return f.NewContents() 26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockOutputApi(object): 29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) class PresubmitResult(object): 30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, message, items=None, long_text=''): 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.message = message 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.items = items 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.long_text = long_text 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) class PresubmitError(PresubmitResult): 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, message, items, long_text=''): 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.type = 'error' 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) class PresubmitPromptWarning(PresubmitResult): 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, message, items, long_text=''): 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.type = 'warning' 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) class PresubmitNotifyResult(PresubmitResult): 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, message, items, long_text=''): 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.type = 'notify' 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) class PresubmitPromptOrNotify(PresubmitResult): 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, message, items, long_text=''): 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) MockOutputApi.PresubmitResult.__init__(self, message, items, long_text) 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.type = 'promptOrNotify' 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockFile(object): 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, local_path, new_contents): 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._local_path = local_path 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._new_contents = new_contents 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)] 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def ChangedContents(self): 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._changed_contents 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def NewContents(self): 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._new_contents 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def LocalPath(self): 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._local_path 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MockChange(object): 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def __init__(self, changed_files): 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._changed_files = changed_files 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def LocalPaths(self): 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return self._changed_files 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class HistogramOffByOneTest(unittest.TestCase): 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) # Take an input and make sure the problems found equals the expectation. 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def simpleCheck(self, contents, expected_errors): 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) input_api = MockInputApi() 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) input_api.files.append(MockFile('test.cc', contents)) 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) results = PRESUBMIT._CheckForHistogramOffByOne(input_api, MockOutputApi()) 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if expected_errors: 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.assertEqual(1, len(results)) 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.assertEqual(expected_errors, len(results[0].items)) 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) else: 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.assertEqual(0, len(results)) 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testValid(self): 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);', 0) 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testValidComments(self): 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/ kFoo, /*...*/' 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'kFooMax + 1);', 0) 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testValidMultiLine(self): 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n' 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFoo,\n' 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFooMax + 1);', 0) 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testValidMultiLineComments(self): 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", // This is the name\n' 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFoo, /* The value */\n' 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFooMax + 1 /* The max */ );', 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 0) 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testNoPlusOne(self): 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax);', 1) 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testInvalidWithIgnore(self): 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax); ' 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) '// PRESUBMIT_IGNORE_UMA_MAX', 0) 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testNoMax(self): 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo + 1);', 1) 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testNoMaxNoPlusOne(self): 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);', 1) 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testMultipleErrors(self): 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n' 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'printf("hello, world!");\n' 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2) 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testValidAndInvalid(self): 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFoo);\n' 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'UMA_HISTOGRAM_ENUMERATION("test", kFoo, kFooMax + 1);' 132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'UMA_HISTOGRAM_ENUMERATION("test", kBar, kBarMax);', 2) 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testInvalidMultiLine(self): 135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test",\n' 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFoo,\n' 137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFooMax + 2);', 1) 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testInvalidComments(self): 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", /*...*/, val, /*...*/,' 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 'Max);\n', 1) 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def testInvalidMultiLineComments(self): 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self.simpleCheck('UMA_HISTOGRAM_ENUMERATION("test", // This is the name\n' 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFoo, /* The value */\n' 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ' kFooMax + 2 /* The max */ );', 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1) 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)if __name__ == '__main__': 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unittest.main() 151