William Liu | a296a00 | 2022-08-08 15:22:29 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Avi Drissman | 73a09d1 | 2022-09-08 20:33:38 | [diff] [blame] | 2 | # Copyright 2012 The Chromium Authors |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """Tests for checkdeps. |
| 7 | """ |
| 8 | |
| 9 | import os |
| 10 | import unittest |
| 11 | |
| 12 | |
| 13 | import builddeps |
| 14 | import checkdeps |
| 15 | import results |
| 16 | |
| 17 | |
| 18 | class CheckDepsTest(unittest.TestCase): |
| 19 | |
| 20 | def setUp(self): |
| 21 | self.deps_checker = checkdeps.DepsChecker( |
| 22 | being_tested=True, |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 23 | base_directory=os.path.join(os.path.dirname(__file__), '..', '..')) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 24 | |
| 25 | def ImplTestRegularCheckDepsRun(self, ignore_temp_rules, skip_tests): |
| 26 | self.deps_checker._ignore_temp_rules = ignore_temp_rules |
| 27 | self.deps_checker._skip_tests = skip_tests |
| 28 | self.deps_checker.CheckDirectory( |
| 29 | os.path.join(self.deps_checker.base_directory, |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 30 | 'buildtools/checkdeps/testdata')) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 31 | |
| 32 | problems = self.deps_checker.results_formatter.GetResults() |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 33 | |
| 34 | def VerifySubstringsInProblems(key_path, substrings_in_sequence): |
| 35 | """Finds the problem in |problems| that contains |key_path|, |
| 36 | then verifies that each of |substrings_in_sequence| occurs in |
| 37 | that problem, in the order they appear in |
| 38 | |substrings_in_sequence|. |
| 39 | """ |
| 40 | found = False |
| 41 | key_path = os.path.normpath(key_path) |
| 42 | for problem in problems: |
| 43 | index = problem.find(key_path) |
| 44 | if index != -1: |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 45 | if substrings_in_sequence is None: |
| 46 | self.fail( |
| 47 | f'Expected no problems for {key_path}, but found: {problem}') |
| 48 | |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 49 | for substring in substrings_in_sequence: |
| 50 | index = problem.find(substring, index + 1) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 51 | self.assertTrue(index != -1, '%s in %s' % (substring, problem)) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 52 | found = True |
| 53 | break |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 54 | if not found and substrings_in_sequence is not None: |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 55 | self.fail('Found no problem for file %s' % key_path) |
| 56 | |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 57 | def VerifyNoProblems(key_path): |
| 58 | VerifySubstringsInProblems(key_path, None) |
| 59 | |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 60 | if ignore_temp_rules: |
| 61 | VerifySubstringsInProblems('testdata/allowed/test.h', |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 62 | ['-buildtools/checkdeps/testdata/disallowed', |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 63 | 'temporarily_allowed.h', |
| 64 | '-third_party/explicitly_disallowed', |
| 65 | 'Because of no rule applying']) |
| 66 | else: |
| 67 | VerifySubstringsInProblems('testdata/allowed/test.h', |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 68 | ['-buildtools/checkdeps/testdata/disallowed', |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 69 | '-third_party/explicitly_disallowed', |
| 70 | 'Because of no rule applying']) |
| 71 | |
| 72 | VerifySubstringsInProblems('testdata/disallowed/test.h', |
| 73 | ['-third_party/explicitly_disallowed', |
| 74 | 'Because of no rule applying', |
| 75 | 'Because of no rule applying']) |
| 76 | VerifySubstringsInProblems('disallowed/allowed/test.h', |
| 77 | ['-third_party/explicitly_disallowed', |
| 78 | 'Because of no rule applying', |
| 79 | 'Because of no rule applying']) |
| 80 | VerifySubstringsInProblems('testdata/noparent/test.h', |
| 81 | ['allowed/bad.h', |
| 82 | 'Because of no rule applying']) |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 83 | VerifySubstringsInProblems('testdata/requires_review_users/usage.cc', [ |
| 84 | 'testdata/requires_review/sub/foo.h"', |
| 85 | 'requires_review/sub", which is marked']) |
| 86 | VerifyNoProblems('requires_review_users/sub/includes_okay/usage.cc') |
| 87 | VerifySubstringsInProblems( |
| 88 | 'requires_review_users/sub/includes_only_sub/usage.cc', |
| 89 | [ |
| 90 | 'testdata/requires_review/sub/foo.h"', |
| 91 | 'requires_review/sub", which is', |
| 92 | 'testdata/requires_review/sub/inherited/foo.h"', |
| 93 | 'testdata/requires_review/sub/sub/inherited/bar.h"', |
| 94 | 'requires_review/sub/sub", which is', |
| 95 | ]) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 96 | |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 97 | if skip_tests: |
| 98 | VerifyNoProblems('allowed/not_a_test.cc') |
| 99 | else: |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 100 | VerifySubstringsInProblems('allowed/not_a_test.cc', |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 101 | ['-buildtools/checkdeps/testdata/disallowed']) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 102 | |
| 103 | def testRegularCheckDepsRun(self): |
| 104 | self.ImplTestRegularCheckDepsRun(False, False) |
| 105 | |
| 106 | def testRegularCheckDepsRunIgnoringTempRules(self): |
| 107 | self.ImplTestRegularCheckDepsRun(True, False) |
| 108 | |
| 109 | def testRegularCheckDepsRunSkipTests(self): |
| 110 | self.ImplTestRegularCheckDepsRun(False, True) |
| 111 | |
| 112 | def testRegularCheckDepsRunIgnoringTempRulesSkipTests(self): |
| 113 | self.ImplTestRegularCheckDepsRun(True, True) |
| 114 | |
| 115 | def CountViolations(self, ignore_temp_rules): |
| 116 | self.deps_checker._ignore_temp_rules = ignore_temp_rules |
| 117 | self.deps_checker.results_formatter = results.CountViolationsFormatter() |
| 118 | self.deps_checker.CheckDirectory( |
| 119 | os.path.join(self.deps_checker.base_directory, |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 120 | 'buildtools/checkdeps/testdata')) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 121 | return self.deps_checker.results_formatter.GetResults() |
| 122 | |
| 123 | def testCountViolations(self): |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 124 | self.assertEqual('16', self.CountViolations(False)) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 125 | |
| 126 | def testCountViolationsIgnoringTempRules(self): |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 127 | self.assertEqual('17', self.CountViolations(True)) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 128 | |
| 129 | def testCountViolationsWithRelativePath(self): |
| 130 | self.deps_checker.results_formatter = results.CountViolationsFormatter() |
| 131 | self.deps_checker.CheckDirectory( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 132 | os.path.join('buildtools', 'checkdeps', 'testdata', 'allowed')) |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 133 | self.assertEqual('5', self.deps_checker.results_formatter.GetResults()) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 134 | |
| 135 | def testTempRulesGenerator(self): |
| 136 | self.deps_checker.results_formatter = results.TemporaryRulesFormatter() |
| 137 | self.deps_checker.CheckDirectory( |
| 138 | os.path.join(self.deps_checker.base_directory, |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 139 | 'buildtools/checkdeps/testdata/allowed')) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 140 | temp_rules = self.deps_checker.results_formatter.GetResults() |
Andrew Grieve | cabf120 | 2024-11-25 22:22:05 | [diff] [blame] | 141 | expected = [' "!/does_not_exist.h",', |
| 142 | ' "!buildtools/checkdeps/testdata/disallowed/bad.h",', |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 143 | ' "!buildtools/checkdeps/testdata/disallowed/teststuff/bad.h",', |
| 144 | ' "!third_party/explicitly_disallowed/bad.h",', |
| 145 | ' "!third_party/no_rule/bad.h",'] |
| 146 | self.assertEqual(expected, temp_rules) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 147 | |
Riley | a95a72ef | 2024-05-08 15:00:00 | [diff] [blame] | 148 | @unittest.skipIf(os.getcwd().startswith('/google/cog/cloud'), |
| 149 | "Skip if not git") |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 150 | def testBadBaseDirectoryNotCheckoutRoot(self): |
| 151 | # This assumes git. It's not a valid test if buildtools is fetched via svn. |
| 152 | with self.assertRaises(builddeps.DepsBuilderError): |
| 153 | checkdeps.DepsChecker(being_tested=True, |
| 154 | base_directory=os.path.dirname(__file__)) |
| 155 | |
| 156 | def testCheckAddedIncludesAllGood(self): |
| 157 | problems = self.deps_checker.CheckAddedCppIncludes( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 158 | [['buildtools/checkdeps/testdata/allowed/test.cc', |
| 159 | ['#include "buildtools/checkdeps/testdata/allowed/good.h"', |
| 160 | '#include "buildtools/checkdeps/testdata/disallowed/allowed/good.h"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 161 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 162 | self.assertFalse(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 163 | |
| 164 | def testCheckAddedIncludesManyGarbageLines(self): |
| 165 | garbage_lines = ["My name is Sam%d\n" % num for num in range(50)] |
| 166 | problems = self.deps_checker.CheckAddedCppIncludes( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 167 | [['buildtools/checkdeps/testdata/allowed/test.cc', garbage_lines]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 168 | self.assertFalse(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 169 | |
| 170 | def testCheckAddedIncludesNoRule(self): |
| 171 | problems = self.deps_checker.CheckAddedCppIncludes( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 172 | [['buildtools/checkdeps/testdata/allowed/test.cc', |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 173 | ['#include "no_rule_for_this/nogood.h"'] |
| 174 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 175 | self.assertTrue(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 176 | |
| 177 | def testCheckAddedIncludesSkippedDirectory(self): |
| 178 | problems = self.deps_checker.CheckAddedCppIncludes( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 179 | [['buildtools/checkdeps/testdata/disallowed/allowed/skipped/test.cc', |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 180 | ['#include "whatever/whocares.h"'] |
| 181 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 182 | self.assertFalse(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 183 | |
| 184 | def testCheckAddedIncludesTempAllowed(self): |
| 185 | problems = self.deps_checker.CheckAddedCppIncludes( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 186 | [['buildtools/checkdeps/testdata/allowed/test.cc', |
| 187 | ['#include "buildtools/checkdeps/testdata/disallowed/temporarily_allowed.h"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 188 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 189 | self.assertTrue(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 190 | |
| 191 | def testCopyIsDeep(self): |
| 192 | # Regression test for a bug where we were making shallow copies of |
| 193 | # Rules objects and therefore all Rules objects shared the same |
| 194 | # dictionary for specific rules. |
| 195 | # |
| 196 | # The first pair should bring in a rule from testdata/allowed/DEPS |
| 197 | # into that global dictionary that allows the |
| 198 | # temp_allowed_for_tests.h file to be included in files ending |
| 199 | # with _unittest.cc, and the second pair should completely fail |
| 200 | # once the bug is fixed, but succeed (with a temporary allowance) |
| 201 | # if the bug is in place. |
| 202 | problems = self.deps_checker.CheckAddedCppIncludes( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 203 | [['buildtools/checkdeps/testdata/allowed/test.cc', |
| 204 | ['#include "buildtools/checkdeps/testdata/disallowed/temporarily_allowed.h"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 205 | ], |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 206 | ['buildtools/checkdeps/testdata/disallowed/foo_unittest.cc', |
| 207 | ['#include "buildtools/checkdeps/testdata/bongo/temp_allowed_for_tests.h"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 208 | ]]) |
| 209 | # With the bug in place, there would be two problems reported, and |
| 210 | # the second would be for foo_unittest.cc. |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 211 | self.assertTrue(len(problems) == 1) |
| 212 | self.assertTrue(problems[0][0].endswith('/test.cc')) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 213 | |
| 214 | def testTraversalIsOrdered(self): |
| 215 | dirs_traversed = [] |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 216 | for rules, filenames in self.deps_checker.GetAllRulesAndFiles(dir_name='buildtools'): |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 217 | self.assertEqual(type(filenames), list) |
| 218 | self.assertEqual(filenames, sorted(filenames)) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 219 | if filenames: |
| 220 | dir_names = set(os.path.dirname(file) for file in filenames) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 221 | self.assertEqual(1, len(dir_names)) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 222 | dirs_traversed.append(dir_names.pop()) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 223 | self.assertEqual(dirs_traversed, sorted(dirs_traversed)) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 224 | |
| 225 | def testCheckPartialImportsAreAllowed(self): |
| 226 | problems = self.deps_checker.CheckAddedProtoImports( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 227 | [['buildtools/checkdeps/testdata/test.proto', |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 228 | ['import "no_rule_for_this/nogood.proto"'] |
| 229 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 230 | self.assertFalse(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 231 | |
| 232 | def testCheckAddedFullPathImportsAllowed(self): |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 233 | problems = self.deps_checker.CheckAddedProtoImports( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 234 | [['buildtools/checkdeps/testdata/test.proto', |
| 235 | ['import "buildtools/checkdeps/testdata/allowed/good.proto"', |
| 236 | 'import "buildtools/checkdeps/testdata/disallowed/sub_folder/good.proto"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 237 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 238 | self.assertFalse(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 239 | |
| 240 | def testCheckAddedFullPathImportsDisallowed(self): |
| 241 | problems = self.deps_checker.CheckAddedProtoImports( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 242 | [['buildtools/checkdeps/testdata/test.proto', |
| 243 | ['import "buildtools/checkdeps/testdata/disallowed/bad.proto"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 244 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 245 | self.assertTrue(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 246 | |
| 247 | def testCheckAddedFullPathImportsManyGarbageLines(self): |
| 248 | garbage_lines = ["My name is Sam%d\n" % num for num in range(50)] |
| 249 | problems = self.deps_checker.CheckAddedProtoImports( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 250 | [['buildtools/checkdeps/testdata/test.proto', |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 251 | garbage_lines]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 252 | self.assertFalse(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 253 | |
| 254 | def testCheckAddedIncludesNoRuleFullPath(self): |
| 255 | problems = self.deps_checker.CheckAddedProtoImports( |
John Budorick | fd4b2b63 | 2019-05-13 19:54:06 | [diff] [blame] | 256 | [['buildtools/checkdeps/testdata/test.proto', |
| 257 | ['import "tools/some.proto"'] |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 258 | ]]) |
Fabrice de Gans | e06b1fa | 2021-06-24 02:10:49 | [diff] [blame] | 259 | self.assertTrue(problems) |
Tom Anderson | e7001969 | 2019-02-06 01:38:04 | [diff] [blame] | 260 | |
| 261 | if __name__ == '__main__': |
| 262 | unittest.main() |