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