| #!/usr/bin/env python3 |
| # Copyright (c) 2021 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os.path |
| import subprocess |
| import sys |
| import unittest |
| |
| ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| sys.path.insert(0, ROOT_DIR) |
| |
| from testing_support.presubmit_canned_checks_test_mocks import MockFile |
| from testing_support.presubmit_canned_checks_test_mocks import (MockInputApi, |
| MockOutputApi) |
| from testing_support.presubmit_canned_checks_test_mocks import MockChange |
| |
| import presubmit_canned_checks |
| |
| # TODO: Should fix these warnings. |
| # pylint: disable=line-too-long |
| |
| |
| class InclusiveLanguageCheckTest(unittest.TestCase): |
| def testBlockedTerms(self): |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.presubmit_local_path = '' |
| |
| input_api.files = [ |
| MockFile( |
| os.path.normpath( |
| 'infra/inclusive_language_presubmit_exempt_dirs.txt'), [ |
| 'some/dir 2 1', |
| 'some/other/dir 2 1', |
| ]), |
| MockFile( |
| os.path.normpath('some/ios/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, blacklist) {', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('some/mac/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, BlackList) {', # nocheck |
| '}' |
| ]), |
| MockFile(os.path.normpath('another/ios_file.mm'), |
| ['class SomeTest : public testing::Test blocklist {};']), |
| MockFile(os.path.normpath('some/ios/file_egtest.mm'), |
| ['- (void)testSomething { V(whitelist); }']), # nocheck |
| MockFile( |
| os.path.normpath('some/ios/file_unittest.mm'), |
| ['TEST_F(SomeTest, Whitelist) { V(allowlist); }']), # nocheck |
| MockFile( |
| os.path.normpath('some/doc/file.md'), |
| [ |
| '# Title', |
| 'Some markdown text includes master.', # nocheck |
| ]), |
| MockFile( |
| os.path.normpath('some/doc/ok_file.md'), |
| [ |
| '# Title', |
| # This link contains a '//' which the matcher thinks is a |
| # C-style comment, and the 'master' term appears after the |
| # '//' in the URL, so it gets ignored as a side-effect. |
| '[Ignored](https://git/project.git/+/master/foo)', # nocheck |
| ]), |
| MockFile( |
| os.path.normpath('some/doc/branch_name_file.md'), |
| [ |
| '# Title', |
| # Matches appearing before `//` still trigger the check. |
| '[src/master](https://git/p.git/+/master/foo)', # nocheck |
| ]), |
| MockFile( |
| os.path.normpath('some/java/file/TestJavaDoc.java'), |
| [ |
| '/**', |
| ' * This line contains the word master,', # nocheck |
| '* ignored because this is a comment. See {@link', |
| ' * https://s/src/+/master:tools/README.md}', # nocheck |
| ' */' |
| ]), |
| MockFile( |
| os.path.normpath('some/java/file/TestJava.java'), |
| [ |
| 'class TestJava {', |
| ' public String master;', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('some/html/file.html'), |
| [ |
| '<-- an existing html multiline comment', |
| 'says "master" here', # nocheck |
| 'in the comment -->' |
| ]) |
| ] |
| |
| errors = presubmit_canned_checks.CheckInclusiveLanguage( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(errors)) |
| self.assertTrue( |
| os.path.normpath('some/ios/file.mm') in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('another/ios_file.mm') not in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/mac/file.mm') in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/ios/file_egtest.mm') in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/ios/file_unittest.mm') in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/doc/file.md') not in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/doc/ok_file.md') not in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/doc/branch_name_file.md') not in |
| errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/java/file/TestJavaDoc.java') not in |
| errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/java/file/TestJava.java') not in |
| errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/html/file.html') not in errors[0].message) |
| |
| def testBlockedTermsWithLegacy(self): |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.presubmit_local_path = '' |
| |
| input_api.files = [ |
| MockFile( |
| os.path.normpath( |
| 'infra/inclusive_language_presubmit_exempt_dirs.txt'), [ |
| 'some/ios 2 1', |
| 'some/other/dir 2 1', |
| ]), |
| MockFile( |
| os.path.normpath('some/ios/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, blacklist) {', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('some/ios/subdir/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, blacklist) {', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('some/mac/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, BlackList) {', # nocheck |
| '}' |
| ]), |
| MockFile(os.path.normpath('another/ios_file.mm'), |
| ['class SomeTest : public testing::Test blocklist {};']), |
| MockFile(os.path.normpath('some/ios/file_egtest.mm'), |
| ['- (void)testSomething { V(whitelist); }']), # nocheck |
| MockFile( |
| os.path.normpath('some/ios/file_unittest.mm'), |
| ['TEST_F(SomeTest, Whitelist) { V(allowlist); }']), # nocheck |
| ] |
| |
| errors = presubmit_canned_checks.CheckInclusiveLanguage( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(errors)) |
| self.assertTrue( |
| os.path.normpath('some/ios/file.mm') not in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/ios/subdir/file.mm') in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('another/ios_file.mm') not in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/mac/file.mm') in errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/ios/file_egtest.mm') not in |
| errors[0].message) |
| self.assertTrue( |
| os.path.normpath('some/ios/file_unittest.mm') not in |
| errors[0].message) |
| |
| def testBlockedTermsWithNocheck(self): |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.presubmit_local_path = '' |
| |
| input_api.files = [ |
| MockFile( |
| os.path.normpath( |
| 'infra/inclusive_language_presubmit_exempt_dirs.txt'), [ |
| 'some/dir 2 1', |
| 'some/other/dir 2 1', |
| ]), |
| MockFile( |
| os.path.normpath('some/ios/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, ', |
| ' blacklist) { // nocheck', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('some/mac/file.mm'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, ', |
| 'BlackList) { // nocheck', # nocheck |
| '}' |
| ]), |
| MockFile(os.path.normpath('another/ios_file.mm'), |
| ['class SomeTest : public testing::Test blocklist {};']), |
| MockFile(os.path.normpath('some/ios/file_egtest.mm'), |
| ['- (void)testSomething { ', 'V(whitelist); } // nocheck' |
| ]), # nocheck |
| MockFile( |
| os.path.normpath('some/ios/file_unittest.mm'), |
| [ |
| 'TEST_F(SomeTest, Whitelist) // nocheck', # nocheck |
| ' { V(allowlist); }' |
| ]), |
| MockFile( |
| os.path.normpath('some/doc/file.md'), |
| [ |
| 'Master in markdown <!-- nocheck -->', # nocheck |
| '## Subheading is okay' |
| ]), |
| MockFile( |
| os.path.normpath('some/java/file/TestJava.java'), |
| [ |
| 'class TestJava {', |
| ' public String master; // nocheck', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('some/html/file.html'), |
| [ |
| '<-- an existing html multiline comment', |
| 'says "master" here --><!-- nocheck -->', # nocheck |
| '<!-- in the comment -->' |
| ]) |
| ] |
| |
| errors = presubmit_canned_checks.CheckInclusiveLanguage( |
| input_api, MockOutputApi()) |
| self.assertEqual(0, len(errors)) |
| |
| def testTopLevelDirExcempt(self): |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.presubmit_local_path = '' |
| |
| input_api.files = [ |
| MockFile( |
| os.path.normpath( |
| 'infra/inclusive_language_presubmit_exempt_dirs.txt'), [ |
| '. 2 1', |
| 'some/other/dir 2 1', |
| ]), |
| MockFile( |
| os.path.normpath('presubmit_canned_checks_test.py'), |
| [ |
| 'TEST(SomeClassTest, SomeInteraction, blacklist) {', # nocheck |
| '}' |
| ]), |
| MockFile( |
| os.path.normpath('presubmit_canned_checks.py'), |
| ['- (void)testSth { V(whitelist); } // nocheck']), # nocheck |
| ] |
| |
| errors = presubmit_canned_checks.CheckInclusiveLanguage( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(errors)) |
| self.assertTrue( |
| os.path.normpath('presubmit_canned_checks_test.py') in |
| errors[0].message) |
| self.assertTrue( |
| os.path.normpath('presubmit_canned_checks.py') not in |
| errors[0].message) |
| |
| def testChangeIsForSomeOtherRepo(self): |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: 'v8' |
| input_api.presubmit_local_path = '' |
| |
| input_api.files = [ |
| MockFile( |
| os.path.normpath('some_file'), |
| [ |
| '# this is a blacklist', # nocheck |
| ]), |
| ] |
| errors = presubmit_canned_checks.CheckInclusiveLanguage( |
| input_api, MockOutputApi()) |
| self.assertEqual([], errors) |
| |
| |
| class DescriptionChecksTest(unittest.TestCase): |
| def testCheckDescriptionUsesColonInsteadOfEquals(self): |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.presubmit_local_path = '' |
| |
| # Verify error in case of the attempt to use "Bug=". |
| input_api.change = MockChange([], 'Broken description\nBug=123') |
| errors = presubmit_canned_checks.CheckDescriptionUsesColonInsteadOfEquals( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(errors)) |
| self.assertTrue('Bug=' in errors[0].message) |
| |
| # Verify error in case of the attempt to use "Fixed=". |
| input_api.change = MockChange([], 'Broken description\nFixed=123') |
| errors = presubmit_canned_checks.CheckDescriptionUsesColonInsteadOfEquals( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(errors)) |
| self.assertTrue('Fixed=' in errors[0].message) |
| |
| # Verify error in case of the attempt to use the lower case "bug=". |
| input_api.change = MockChange([], |
| 'Broken description lowercase\nbug=123') |
| errors = presubmit_canned_checks.CheckDescriptionUsesColonInsteadOfEquals( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(errors)) |
| self.assertTrue('Bug=' in errors[0].message) |
| |
| # Verify no error in case of "Bug:" |
| input_api.change = MockChange([], 'Correct description\nBug: 123') |
| errors = presubmit_canned_checks.CheckDescriptionUsesColonInsteadOfEquals( |
| input_api, MockOutputApi()) |
| self.assertEqual(0, len(errors)) |
| |
| # Verify no error in case of "Fixed:" |
| input_api.change = MockChange([], 'Correct description\nFixed: 123') |
| errors = presubmit_canned_checks.CheckDescriptionUsesColonInsteadOfEquals( |
| input_api, MockOutputApi()) |
| self.assertEqual(0, len(errors)) |
| |
| |
| class ChromiumDependencyMetadataCheckTest(unittest.TestCase): |
| def testDefaultFileFilter(self): |
| """Checks the default file filter limits the scope to Chromium dependency |
| metadata files. |
| """ |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.files = [ |
| MockFile(os.path.normpath('foo/README.md'), ['Shipped: no?']), |
| MockFile(os.path.normpath('foo/main.py'), ['Shipped: yes?']), |
| ] |
| results = presubmit_canned_checks.CheckChromiumDependencyMetadata( |
| input_api, MockOutputApi()) |
| self.assertEqual(len(results), 0) |
| |
| def testSkipDeletedFiles(self): |
| """Checks validation is skipped for deleted files.""" |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.files = [ |
| MockFile(os.path.normpath('foo/README.chromium'), ['No fields'], |
| action='D'), |
| ] |
| results = presubmit_canned_checks.CheckChromiumDependencyMetadata( |
| input_api, MockOutputApi()) |
| self.assertEqual(len(results), 0) |
| |
| def testFeedbackForNoMetadata(self): |
| """Checks presubmit results are returned for files without any metadata.""" |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| input_api.files = [ |
| MockFile(os.path.normpath('foo/README.chromium'), ['No fields']), |
| ] |
| results = presubmit_canned_checks.CheckChromiumDependencyMetadata( |
| input_api, MockOutputApi()) |
| self.assertEqual(len(results), 1) |
| self.assertTrue("No dependency metadata" in results[0].message) |
| |
| def testFeedbackForInvalidMetadata(self): |
| """Checks presubmit results are returned for files with invalid metadata.""" |
| input_api = MockInputApi() |
| input_api.change.RepositoryRoot = lambda: '' |
| test_file = MockFile(os.path.normpath('foo/README.chromium'), |
| ['Shipped: yes?']) |
| input_api.files = [test_file] |
| results = presubmit_canned_checks.CheckChromiumDependencyMetadata( |
| input_api, MockOutputApi()) |
| |
| # There should be 9 results due to |
| # - missing 5 mandatory fields: Name, URL, Version, License, and |
| # Security Critical |
| # - 1 error for insufficent versioning info |
| # - missing 2 required fields: License File, and |
| # License Android Compatible |
| # - Shipped should be only 'yes' or 'no'. |
| self.assertEqual(len(results), 9) |
| |
| # Check each presubmit result is associated with the test file. |
| for result in results: |
| self.assertEqual(len(result.items), 1) |
| self.assertEqual(result.items[0], test_file) |
| |
| |
| class CheckUpdateOwnersFileReferences(unittest.TestCase): |
| def testShowsWarningIfDeleting(self): |
| input_api = MockInputApi() |
| input_api.files = [ |
| MockFile(os.path.normpath('foo/OWNERS'), [], [], action='D'), |
| ] |
| results = presubmit_canned_checks.CheckUpdateOwnersFileReferences( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(results)) |
| self.assertEqual('warning', results[0].type) |
| self.assertEqual(1, len(results[0].items)) |
| |
| def testShowsWarningIfMoving(self): |
| input_api = MockInputApi() |
| input_api.files = [ |
| MockFile(os.path.normpath('new_directory/OWNERS'), [], [], |
| action='A'), |
| MockFile(os.path.normpath('old_directory/OWNERS'), [], [], |
| action='D'), |
| ] |
| results = presubmit_canned_checks.CheckUpdateOwnersFileReferences( |
| input_api, MockOutputApi()) |
| self.assertEqual(1, len(results)) |
| self.assertEqual('warning', results[0].type) |
| self.assertEqual(1, len(results[0].items)) |
| |
| def testNoWarningIfAdding(self): |
| input_api = MockInputApi() |
| input_api.files = [ |
| MockFile(os.path.normpath('foo/OWNERS'), [], [], action='A'), |
| ] |
| results = presubmit_canned_checks.CheckUpdateOwnersFileReferences( |
| input_api, MockOutputApi()) |
| self.assertEqual(0, len(results)) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |