1#!/usr/bin/env python3 2# Copyright 2020 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. 5""" 6angle_presubmit_utils_unittest.py: Top-level unittest script for ANGLE presubmit checks. 7""" 8 9import importlib.machinery 10import os 11import pathlib 12import sys 13import tempfile 14import unittest 15from angle_presubmit_utils import * 16 17def SetCWDToAngleFolder(): 18 angle_folder = "angle" 19 cwd = os.path.dirname(os.path.abspath(__file__)) 20 cwd = cwd.split(angle_folder)[0] + angle_folder 21 os.chdir(cwd) 22 23 24SetCWDToAngleFolder() 25 26loader = importlib.machinery.SourceFileLoader('PRESUBMIT', 'PRESUBMIT.py') 27PRESUBMIT = loader.load_module() 28 29 30class CommitMessageFormattingCheckTest(unittest.TestCase): 31 32 def __init__(self, *args, **kwargs): 33 super(CommitMessageFormattingCheckTest, self).__init__(*args, **kwargs) 34 self.output_api = OutputAPI_mock() 35 36 def run_check_commit_message_formatting(self, commit_msg): 37 input_api = InputAPI_mock(commit_msg) 38 return PRESUBMIT._CheckCommitMessageFormatting(input_api, self.output_api) 39 40 def test_correct_commit_message(self): 41 commit_msg = """a 42 43b 44 45Bug: angleproject:4662 46Change-Id: I966c79d96175da9eee92ef6da20db50d488137b2 47""" 48 errors = self.run_check_commit_message_formatting(commit_msg) 49 self.assertEqual(len(errors), 0) 50 51 def test_missing_description_body_and_description_summary(self): 52 commit_msg = """Change-Id: I966c79d96175da9eee92ef6da20db50d488137b2""" 53 errors = self.run_check_commit_message_formatting(commit_msg) 54 self.assertEqual(len(errors), 1) 55 self.assertEqual( 56 errors[0], 57 self.output_api.PresubmitError( 58 "Commit 1:Please ensure that your" + 59 " description summary and description body are not blank.")) 60 61 def test_missing_description_body(self): 62 commit_msg = """ 63 a 64 65b: d 66c: e 67""" 68 errors = self.run_check_commit_message_formatting(commit_msg) 69 self.assertEqual(len(errors), 0) 70 71 def test_missing_tag_paragraph(self): 72 commit_msg = """a 73 74bd 75efgh""" 76 errors = self.run_check_commit_message_formatting(commit_msg) 77 self.assertEqual(len(errors), 1) 78 self.assertEqual( 79 errors[0], 80 self.output_api.PresubmitError( 81 "Commit 1:Please ensure that there are tags (e.g., Bug:, Test:) in your description." 82 )) 83 84 def test_missing_tag_paragraph_and_description_body(self): 85 commit_msg = "a" 86 errors = self.run_check_commit_message_formatting(commit_msg) 87 self.assertEqual(len(errors), 1) 88 self.assertEqual( 89 errors[0], 90 self.output_api.PresubmitError( 91 "Commit 1:Please ensure that there are tags (e.g., Bug:, Test:) in your description." 92 )) 93 94 def test_missing_blank_line_between_description_summary_and_description_body(self): 95 commit_msg = """a 96b 97 98Change-Id: I925cdb45779a9cdebe4e14f9e81e4211ade37c12""" 99 errors = self.run_check_commit_message_formatting(commit_msg) 100 self.assertEqual(len(errors), 1) 101 self.assertEqual(errors[0], self.output_api.PresubmitError( 102 "Commit 1:Please ensure the summary is only 1 line and there is 1 blank line" + \ 103 " between the summary and description body.")) 104 105 def test_missing_blank_line_between_description_body_and_tags_paragraph(self): 106 commit_msg = """a 107 108b 109Change-Id: I925cdb45779a9cdebe4e14f9e81e4211ade37c12""" 110 errors = self.run_check_commit_message_formatting(commit_msg) 111 self.assertEqual(len(errors), 0) 112 113 def test_multiple_blank_lines_before_and_after_commit_message(self): 114 commit_msg = """ 115 116 117 a 118 119 b 120 121Change-Id: I925cdb45779a9cdebe4e14f9e81e4211ade37c12 122""" 123 errors = self.run_check_commit_message_formatting(commit_msg) 124 self.assertEqual(len(errors), 0) 125 126 def test_newlines_within_description_body(self): 127 commit_msg = """a 128 129b 130 131d 132 133e 134 135for 136 137Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 138 errors = self.run_check_commit_message_formatting(commit_msg) 139 self.assertEqual(len(errors), 0) 140 141 # Summary description in warning threshold(at 65 characters) 142 def test_summmary_description_in_warning_thresholds(self): 143 commit_msg = """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 144 145b 146 147Change-Id: I925cdb45779a9cdebe4e14f9e81e4211ade37c12 148""" 149 errors = self.run_check_commit_message_formatting(commit_msg) 150 self.assertEqual(len(errors), 1) 151 self.assertEqual( 152 errors[0], 153 self.output_api.PresubmitPromptWarning( 154 "Commit 1:Your description summary should be on one line of 64 or less characters." 155 )) 156 157 # Summary description in error threshold(at 71 characters) 158 def test_summary_description_in_error_threshold(self): 159 commit_msg = """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 160 161b 162 163Change-Id: I925cdb45779a9cdebe4e14f9e81e4211ade37c12""" 164 errors = self.run_check_commit_message_formatting(commit_msg) 165 self.assertEqual(len(errors), 1) 166 self.assertEqual( 167 errors[0], 168 self.output_api.PresubmitError( 169 "Commit 1:Please ensure that your description summary is on one line of 64 or less characters." 170 )) 171 172 def test_description_body_exceeds_line_count_limit(self): 173 commit_msg = """a 174 175bbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 176 177 178Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 179 errors = self.run_check_commit_message_formatting(commit_msg) 180 self.assertEqual(len(errors), 2) 181 self.assertEqual( 182 errors[0], 183 self.output_api.PresubmitError( 184 "Commit 1:Please ensure that there exists only 1 blank line between tags and description body." 185 )) 186 self.assertEqual( 187 errors[1], 188 self.output_api.PresubmitError("""Commit 1:Line 3 is too long. 189"bbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 190Please wrap it to 72 characters. Lines without spaces or lines starting with 4 spaces are exempt.""" 191 )) 192 193 def test_description_body_exceeds_line_count_limit_but_with_4_spaces_prefix(self): 194 commit_msg = """a 195 196cc 197 198dddd 199 200 bbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 201 202Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 203 errors = self.run_check_commit_message_formatting(commit_msg) 204 self.assertEqual(len(errors), 0) 205 206 def test_description_body_exceeds_line_count_limit_but_without_space(self): 207 commit_msg = """a 208 209cc 210 211dddd 212 213bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 214 215a: d""" 216 errors = self.run_check_commit_message_formatting(commit_msg) 217 self.assertEqual(len(errors), 0) 218 219 def test_description_body_exceeds_line_count_limit_but_in_quote(self): 220 commit_msg = """a 221 222cc 223 224dddd 225 226> bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 227 228a: d""" 229 errors = self.run_check_commit_message_formatting(commit_msg) 230 self.assertEqual(len(errors), 0) 231 232 def test_tabs_in_commit_message(self): 233 commit_msg = """ a 234 235bbbbbbbbbbbbbbbbbbbb 236 237Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 238 errors = self.run_check_commit_message_formatting(commit_msg) 239 self.assertEqual(len(errors), 1) 240 self.assertEqual( 241 errors[0], 242 self.output_api.PresubmitError("Commit 1:Tabs are not allowed in commit message.")) 243 244 def test_allowlist_revert(self): 245 commit_msg = """Revert "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssa 246 247bbbbbbbbbbbbbbbbbbbb 248 249Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 250 errors = self.run_check_commit_message_formatting(commit_msg) 251 self.assertEqual(len(errors), 0) 252 253 def test_allowlist_roll(self): 254 commit_msg = """Roll sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssadd 255 256bbbbbbbbbbbbbbbbbbbb 257 258Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 259 errors = self.run_check_commit_message_formatting(commit_msg) 260 self.assertEqual(len(errors), 0) 261 262 def test_allowlist_reland(self): 263 commit_msg = """Reland sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssadd 264 265bbbbbbbbbbbbbbbbbbbb 266 267Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 268 errors = self.run_check_commit_message_formatting(commit_msg) 269 self.assertEqual(len(errors), 0) 270 271 def test_allowlist_reland2(self): 272 commit_msg = """Reland: sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssadd 273 274bbbbbbbbbbbbbbbbbbbb 275 276Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 277 errors = self.run_check_commit_message_formatting(commit_msg) 278 self.assertEqual(len(errors), 0) 279 280 def test_multiple_commits_with_errors_in_multiple_commits(self): 281 commit_msg = """a 282 283bbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 284 285Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b 286 287a 288 289cccccccccccccccccccccccccccccc cccccccccccccccccccccccccccccccccccccccccccc 290 291Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 292 errors = self.run_check_commit_message_formatting(commit_msg) 293 self.assertEqual(len(errors), 2) 294 self.assertEqual( 295 errors[0], 296 self.output_api.PresubmitError("""Commit 2:Line 3 is too long. 297"bbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 298Please wrap it to 72 characters. Lines without spaces or lines starting with 4 spaces are exempt.""" 299 )) 300 self.assertEqual( 301 errors[1], 302 self.output_api.PresubmitError("""Commit 1:Line 4 is too long. 303"cccccccccccccccccccccccccccccc cccccccccccccccccccccccccccccccccccccccccccc" 304Please wrap it to 72 characters. Lines without spaces or lines starting with 4 spaces are exempt.""" 305 )) 306 307 def test_multiple_commits_with_error_in_one_commit(self): 308 commit_msg = """a 309 310bbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 311 312Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b 313 314Roll sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssadd 315 316bbbbbbbbbbbbbbbbbbbb 317 318Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 319 errors = self.run_check_commit_message_formatting(commit_msg) 320 self.assertEqual(len(errors), 1) 321 self.assertEqual( 322 errors[0], 323 self.output_api.PresubmitError("""Commit 2:Line 3 is too long. 324"bbbbbbbb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 325Please wrap it to 72 characters. Lines without spaces or lines starting with 4 spaces are exempt.""" 326 )) 327 328 def test_multiple_commits_with_no_error(self): 329 commit_msg = """Reland sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssadd 330 331bbbbbbbbbbbbbbbbbbbb 332 333Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b 334 335Roll sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssadd 336 337bbbbbbbbbbbbbbbbbbbb 338 339Change-Id: I443c36aaa8956c20da1abddf7aea613659e2cd5b""" 340 errors = self.run_check_commit_message_formatting(commit_msg) 341 self.assertEqual(len(errors), 0) 342 343 344class GClientFileExistenceCheck(unittest.TestCase): 345 346 def __init__(self, *args, **kwargs): 347 super(GClientFileExistenceCheck, self).__init__(*args, **kwargs) 348 self.output_api = OutputAPI_mock() 349 350 def run_gclient_presubmit(self, cwd, search_limit): 351 input_api = InputAPI_mock('') 352 input_api.cwd = cwd 353 return PRESUBMIT._CheckGClientExists(input_api, self.output_api, 354 pathlib.Path(search_limit)) 355 356 def test_gclient_in_cwd(self): 357 with tempfile.TemporaryDirectory() as cwd: 358 pathlib.Path(cwd).joinpath('.gclient').touch() 359 errors = self.run_gclient_presubmit(cwd, cwd) 360 self.assertEqual(len(errors), 0) 361 362 def test_missing_gclient(self): 363 with tempfile.TemporaryDirectory() as cwd: 364 errors = self.run_gclient_presubmit(cwd, cwd) 365 self.assertEqual(len(errors), 1) 366 self.assertEqual(errors[0], self.output_api.PresubmitError('Missing .gclient file.')) 367 368 def test_gclient_in_parent(self): 369 with tempfile.TemporaryDirectory() as cwd: 370 cwd = pathlib.Path(cwd) 371 cwd.joinpath('.gclient').touch() 372 inner = cwd.joinpath('inner') 373 inner.mkdir() 374 errors = self.run_gclient_presubmit(str(inner), str(cwd)) 375 self.assertEqual(len(errors), 0) 376 377 378class CheckShaderVersionInShaderLangHeaderTest(unittest.TestCase): 379 380 def __init__(self, *args, **kwargs): 381 super(CheckShaderVersionInShaderLangHeaderTest, self).__init__(*args, **kwargs) 382 self.output_api = OutputAPI_mock() 383 384 def run_shader_version_check_presubmit(self, commit_msg, diffs): 385 affected_files = [AffectedFile_mock(diff) for diff in diffs] 386 input_api = InputAPI_mock(commit_msg, affected_files) 387 return PRESUBMIT._CheckShaderVersionInShaderLangHeader(input_api, self.output_api) 388 389 def test_headers_not_changed(self): 390 errors = self.run_shader_version_check_presubmit('', []) 391 self.assertEqual(len(errors), 0) 392 393 def test_shader_lang_changed_with_version_change(self): 394 shader_lang_diff = """-#define ANGLE_SH_VERSION 100 395+#define ANGLE_SH_VERSION 101 396""" 397 398 errors = self.run_shader_version_check_presubmit('', [shader_lang_diff]) 399 self.assertEqual(len(errors), 0) 400 401 def test_both_changed_with_version_change(self): 402 shader_lang_diff = """-#define ANGLE_SH_VERSION 100 403+#define ANGLE_SH_VERSION 101 404""" 405 shader_vars_diff = """-any change""" 406 407 errors = self.run_shader_version_check_presubmit('', [shader_lang_diff, shader_vars_diff]) 408 self.assertEqual(len(errors), 0) 409 410 def test_shader_lang_changed_with_no_version_change(self): 411 shader_lang_diff = """+some change""" 412 413 errors = self.run_shader_version_check_presubmit('', [shader_lang_diff]) 414 self.assertEqual(len(errors), 1) 415 self.assertEqual( 416 errors[0], 417 self.output_api.PresubmitError( 418 'ANGLE_SH_VERSION should be incremented when ShaderLang.h or ShaderVars.h change.') 419 ) 420 421 def test_shader_lang_changed_with_no_version_change(self): 422 shader_lang_diff = """+some change 423 #define ANGLE_SH_VERSION 100 424-other changes""" 425 426 errors = self.run_shader_version_check_presubmit('', [shader_lang_diff]) 427 self.assertEqual(len(errors), 1) 428 self.assertEqual( 429 errors[0], 430 self.output_api.PresubmitError( 431 'ANGLE_SH_VERSION should be incremented when ShaderLang.h or ShaderVars.h change.') 432 ) 433 434 def test_shader_lang_changed_with_version_cosmetic_change(self): 435 shader_lang_diff = """-#define ANGLE_SH_VERSION 100 436+#define ANGLE_SH_VERSION 100 // cosmetic change 437""" 438 439 errors = self.run_shader_version_check_presubmit('', [shader_lang_diff]) 440 self.assertEqual(len(errors), 1) 441 self.assertEqual( 442 errors[0], 443 self.output_api.PresubmitError( 444 'ANGLE_SH_VERSION should be incremented when ShaderLang.h or ShaderVars.h change.') 445 ) 446 447 def test_shader_lang_changed_with_version_decrement(self): 448 shader_lang_diff = """-#define ANGLE_SH_VERSION 100 449+#define ANGLE_SH_VERSION 99 450""" 451 452 errors = self.run_shader_version_check_presubmit('', [shader_lang_diff]) 453 self.assertEqual(len(errors), 1) 454 self.assertEqual( 455 errors[0], 456 self.output_api.PresubmitError( 457 'ANGLE_SH_VERSION should be incremented when ShaderLang.h or ShaderVars.h change.') 458 ) 459 460 def test_shader_lang_changed_in_revert(self): 461 shader_lang_diff = """-#define ANGLE_SH_VERSION 100 462+#define ANGLE_SH_VERSION 99 463""" 464 465 errors = self.run_shader_version_check_presubmit('Revert some change', [shader_lang_diff]) 466 self.assertEqual(len(errors), 0) 467 468 469if __name__ == '__main__': 470 unittest.main() 471