• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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