1#!/usr/bin/env vpython3 2 3# Copyright 2017 The WebRTC project authors. All Rights Reserved. 4# 5# Use of this source code is governed by a BSD-style license 6# that can be found in the LICENSE file in the root of the source 7# tree. An additional intellectual property rights grant can be found 8# in the file PATENTS. All contributing project authors may 9# be found in the AUTHORS file in the root of the source tree. 10 11from __future__ import absolute_import 12import os 13import shutil 14import tempfile 15import textwrap 16import unittest 17 18import PRESUBMIT 19# pylint: disable=line-too-long 20from presubmit_test_mocks import MockInputApi, MockOutputApi, MockFile, MockChange 21 22 23class CheckBugEntryFieldTest(unittest.TestCase): 24 def testCommitMessageBugEntryWithNoError(self): 25 mock_input_api = MockInputApi() 26 mock_output_api = MockOutputApi() 27 mock_input_api.change = MockChange([], ['webrtc:1234']) 28 errors = PRESUBMIT.CheckCommitMessageBugEntry(mock_input_api, 29 mock_output_api) 30 self.assertEqual(0, len(errors)) 31 32 def testCommitMessageBugEntryReturnError(self): 33 mock_input_api = MockInputApi() 34 mock_output_api = MockOutputApi() 35 mock_input_api.change = MockChange([], ['webrtc:1234', 'webrtc=4321']) 36 errors = PRESUBMIT.CheckCommitMessageBugEntry(mock_input_api, 37 mock_output_api) 38 self.assertEqual(1, len(errors)) 39 self.assertEqual(('Bogus Bug entry: webrtc=4321. Please specify' 40 ' the issue tracker prefix and the issue number,' 41 ' separated by a colon, e.g. webrtc:123 or' 42 ' chromium:12345.'), str(errors[0])) 43 44 def testCommitMessageBugEntryWithoutPrefix(self): 45 mock_input_api = MockInputApi() 46 mock_output_api = MockOutputApi() 47 mock_input_api.change = MockChange([], ['1234']) 48 errors = PRESUBMIT.CheckCommitMessageBugEntry(mock_input_api, 49 mock_output_api) 50 self.assertEqual(1, len(errors)) 51 self.assertEqual(('Bug entry requires issue tracker prefix, ' 52 'e.g. webrtc:1234'), str(errors[0])) 53 54 def testCommitMessageBugEntryIsNone(self): 55 mock_input_api = MockInputApi() 56 mock_output_api = MockOutputApi() 57 mock_input_api.change = MockChange([], ['None']) 58 errors = PRESUBMIT.CheckCommitMessageBugEntry(mock_input_api, 59 mock_output_api) 60 self.assertEqual(0, len(errors)) 61 62 def testCommitMessageBugEntrySupportInternalBugReference(self): 63 mock_input_api = MockInputApi() 64 mock_output_api = MockOutputApi() 65 mock_input_api.change.BUG = 'b/12345' 66 errors = PRESUBMIT.CheckCommitMessageBugEntry(mock_input_api, 67 mock_output_api) 68 self.assertEqual(0, len(errors)) 69 mock_input_api.change.BUG = 'b/12345, webrtc:1234' 70 errors = PRESUBMIT.CheckCommitMessageBugEntry(mock_input_api, 71 mock_output_api) 72 self.assertEqual(0, len(errors)) 73 74 75class CheckNewlineAtTheEndOfProtoFilesTest(unittest.TestCase): 76 def setUp(self): 77 self.tmp_dir = tempfile.mkdtemp() 78 self.proto_file_path = os.path.join(self.tmp_dir, 'foo.proto') 79 self.input_api = MockInputApi() 80 self.output_api = MockOutputApi() 81 82 def tearDown(self): 83 shutil.rmtree(self.tmp_dir, ignore_errors=True) 84 85 def testErrorIfProtoFileDoesNotEndWithNewline(self): 86 self._GenerateProtoWithoutNewlineAtTheEnd() 87 self.input_api.files = [MockFile(self.proto_file_path)] 88 errors = PRESUBMIT.CheckNewlineAtTheEndOfProtoFiles( 89 self.input_api, self.output_api, lambda x: True) 90 self.assertEqual(1, len(errors)) 91 self.assertEqual( 92 'File %s must end with exactly one newline.' % self.proto_file_path, 93 str(errors[0])) 94 95 def testNoErrorIfProtoFileEndsWithNewline(self): 96 self._GenerateProtoWithNewlineAtTheEnd() 97 self.input_api.files = [MockFile(self.proto_file_path)] 98 errors = PRESUBMIT.CheckNewlineAtTheEndOfProtoFiles( 99 self.input_api, self.output_api, lambda x: True) 100 self.assertEqual(0, len(errors)) 101 102 def _GenerateProtoWithNewlineAtTheEnd(self): 103 with open(self.proto_file_path, 'w') as f: 104 f.write( 105 textwrap.dedent(""" 106 syntax = "proto2"; 107 option optimize_for = LITE_RUNTIME; 108 package webrtc.audioproc; 109 """)) 110 111 def _GenerateProtoWithoutNewlineAtTheEnd(self): 112 with open(self.proto_file_path, 'w') as f: 113 f.write( 114 textwrap.dedent(""" 115 syntax = "proto2"; 116 option optimize_for = LITE_RUNTIME; 117 package webrtc.audioproc;""")) 118 119 120class CheckNoMixingSourcesTest(unittest.TestCase): 121 def setUp(self): 122 self.tmp_dir = tempfile.mkdtemp() 123 self.file_path = os.path.join(self.tmp_dir, 'BUILD.gn') 124 self.input_api = MockInputApi() 125 self.output_api = MockOutputApi() 126 127 def tearDown(self): 128 shutil.rmtree(self.tmp_dir, ignore_errors=True) 129 130 def testErrorIfCAndCppAreMixed(self): 131 self._AssertNumberOfErrorsWithSources(1, ['foo.c', 'bar.cc', 'bar.h']) 132 133 def testErrorIfCAndObjCAreMixed(self): 134 self._AssertNumberOfErrorsWithSources(1, ['foo.c', 'bar.m', 'bar.h']) 135 136 def testErrorIfCAndObjCppAreMixed(self): 137 self._AssertNumberOfErrorsWithSources(1, ['foo.c', 'bar.mm', 'bar.h']) 138 139 def testErrorIfCppAndObjCAreMixed(self): 140 self._AssertNumberOfErrorsWithSources(1, ['foo.cc', 'bar.m', 'bar.h']) 141 142 def testErrorIfCppAndObjCppAreMixed(self): 143 self._AssertNumberOfErrorsWithSources(1, ['foo.cc', 'bar.mm', 'bar.h']) 144 145 def testNoErrorIfOnlyC(self): 146 self._AssertNumberOfErrorsWithSources(0, ['foo.c', 'bar.c', 'bar.h']) 147 148 def testNoErrorIfOnlyCpp(self): 149 self._AssertNumberOfErrorsWithSources(0, ['foo.cc', 'bar.cc', 'bar.h']) 150 151 def testNoErrorIfOnlyObjC(self): 152 self._AssertNumberOfErrorsWithSources(0, ['foo.m', 'bar.m', 'bar.h']) 153 154 def testNoErrorIfOnlyObjCpp(self): 155 self._AssertNumberOfErrorsWithSources(0, ['foo.mm', 'bar.mm', 'bar.h']) 156 157 def testNoErrorIfObjCAndObjCppAreMixed(self): 158 self._AssertNumberOfErrorsWithSources(0, ['foo.m', 'bar.mm', 'bar.h']) 159 160 def testNoErrorIfSourcesAreInExclusiveIfBranches(self): 161 self._GenerateBuildFile( 162 textwrap.dedent(""" 163 rtc_library("bar_foo") { 164 if (is_win) { 165 sources = [ 166 "bar.cc", 167 ], 168 } 169 if (is_ios) { 170 sources = [ 171 "bar.mm", 172 ], 173 } 174 } 175 rtc_library("foo_bar") { 176 if (is_win) { 177 sources = [ 178 "foo.cc", 179 ], 180 } 181 if (is_ios) { 182 sources = [ 183 "foo.mm", 184 ], 185 } 186 } 187 """)) 188 self.input_api.files = [MockFile(self.file_path)] 189 errors = PRESUBMIT.CheckNoMixingSources(self.input_api, 190 [MockFile(self.file_path)], 191 self.output_api) 192 self.assertEqual(0, len(errors)) 193 194 def testErrorIfSourcesAreNotInExclusiveIfBranches(self): 195 self._GenerateBuildFile( 196 textwrap.dedent(""" 197 rtc_library("bar_foo") { 198 if (is_win) { 199 sources = [ 200 "bar.cc", 201 ], 202 } 203 if (foo_bar) { 204 sources += [ 205 "bar.mm", 206 ], 207 } 208 } 209 rtc_library("foo_bar") { 210 if (is_win) { 211 sources = [ 212 "foo.cc", 213 ], 214 } 215 if (foo_bar) { 216 sources += [ 217 "foo.mm", 218 ], 219 } 220 if (is_ios) { 221 sources = [ 222 "bar.m", 223 "bar.c", 224 ], 225 } 226 } 227 """)) 228 self.input_api.files = [MockFile(self.file_path)] 229 errors = PRESUBMIT.CheckNoMixingSources(self.input_api, 230 [MockFile(self.file_path)], 231 self.output_api) 232 self.assertEqual(1, len(errors)) 233 self.assertTrue('bar.cc' in str(errors[0])) 234 self.assertTrue('bar.mm' in str(errors[0])) 235 self.assertTrue('foo.cc' in str(errors[0])) 236 self.assertTrue('foo.mm' in str(errors[0])) 237 self.assertTrue('bar.m' in str(errors[0])) 238 self.assertTrue('bar.c' in str(errors[0])) 239 240 def _AssertNumberOfErrorsWithSources(self, number_of_errors, sources): 241 assert len(sources) == 3, 'This function accepts a list of 3 source files' 242 self._GenerateBuildFile( 243 textwrap.dedent(""" 244 rtc_static_library("bar_foo") { 245 sources = [ 246 "%s", 247 "%s", 248 "%s", 249 ], 250 } 251 rtc_library("foo_bar") { 252 sources = [ 253 "%s", 254 "%s", 255 "%s", 256 ], 257 } 258 """ % (tuple(sources) * 2))) 259 self.input_api.files = [MockFile(self.file_path)] 260 errors = PRESUBMIT.CheckNoMixingSources(self.input_api, 261 [MockFile(self.file_path)], 262 self.output_api) 263 self.assertEqual(number_of_errors, len(errors)) 264 if number_of_errors == 1: 265 for source in sources: 266 if not source.endswith('.h'): 267 self.assertTrue(source in str(errors[0])) 268 269 def _GenerateBuildFile(self, content): 270 with open(self.file_path, 'w') as f: 271 f.write(content) 272 273 274class CheckAssertUsageTest(unittest.TestCase): 275 def setUp(self): 276 self.input_api = MockInputApi() 277 self.output_api = MockOutputApi() 278 self._content_with_assert = ['void Foo() {', ' assert(true);', '}'] 279 self._content_without_assert = ['void Foo() {', ' RTC_CHECK(true);', '}'] 280 281 def testDetectsAssertInCcFile(self): 282 self.input_api.files = [ 283 MockFile('with_assert.cc', self._content_with_assert), 284 MockFile('without_assert.cc', self._content_without_assert), 285 ] 286 errors = PRESUBMIT.CheckAssertUsage(self.input_api, 287 self.output_api, lambda x: True) 288 self.assertEqual(1, len(errors)) 289 self.assertEqual('with_assert.cc', errors[0].items[0]) 290 291 def testDetectsAssertInHeaderFile(self): 292 self.input_api.files = [ 293 MockFile('with_assert.h', self._content_with_assert), 294 MockFile('without_assert.h', self._content_without_assert), 295 ] 296 errors = PRESUBMIT.CheckAssertUsage(self.input_api, 297 self.output_api, lambda x: True) 298 self.assertEqual(1, len(errors)) 299 self.assertEqual('with_assert.h', errors[0].items[0]) 300 301 def testDetectsAssertInObjCFile(self): 302 self.input_api.files = [ 303 MockFile('with_assert.m', self._content_with_assert), 304 MockFile('without_assert.m', self._content_without_assert), 305 ] 306 errors = PRESUBMIT.CheckAssertUsage(self.input_api, 307 self.output_api, lambda x: True) 308 self.assertEqual(1, len(errors)) 309 self.assertEqual('with_assert.m', errors[0].items[0]) 310 311 def testDetectsAssertInObjCppFile(self): 312 self.input_api.files = [ 313 MockFile('with_assert.mm', self._content_with_assert), 314 MockFile('without_assert.mm', self._content_without_assert), 315 ] 316 errors = PRESUBMIT.CheckAssertUsage(self.input_api, 317 self.output_api, lambda x: True) 318 self.assertEqual(1, len(errors)) 319 self.assertEqual('with_assert.mm', errors[0].items[0]) 320 321 def testDoesntDetectAssertInOtherFiles(self): 322 self.input_api.files = [ 323 MockFile('with_assert.cpp', self._content_with_assert), 324 ] 325 errors = PRESUBMIT.CheckAssertUsage(self.input_api, 326 self.output_api, lambda x: True) 327 self.assertEqual(0, len(errors)) 328 329 330if __name__ == '__main__': 331 unittest.main() 332