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