~bzr-pqm/bzr/bzr.dev

3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
1
# Copyright (C) 2005, 2006, 2008 Canonical Ltd
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
3
#            and others
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
18
19
"""These tests are tests about the source code of bzrlib itself.
20
21
They are useful for testing code quality, checking coverage metric etc.
22
"""
23
24
# import system imports here
25
import os
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
26
import parser
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
27
import re
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
28
import symbol
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
29
import sys
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
30
import token
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
31
32
#import bzrlib specific imports here
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
33
from bzrlib import (
34
    osutils,
35
    )
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
36
import bzrlib.branch
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
37
from bzrlib.tests import (
4115.1.1 by Robert Collins
Turn test_coding_style into a KnownFailure until it gets fixed as per the list.
38
    KnownFailure,
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
39
    TestCase,
40
    TestSkipped,
41
    )
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
42
43
2052.3.8 by John Arbash Meinel
Better documentation about the exception variables
44
# Files which are listed here will be skipped when testing for Copyright (or
45
# GPL) statements.
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
46
COPYRIGHT_EXCEPTIONS = ['bzrlib/lsprof.py']
47
48
LICENSE_EXCEPTIONS = ['bzrlib/lsprof.py']
2052.3.8 by John Arbash Meinel
Better documentation about the exception variables
49
# Technically, 'bzrlib/lsprof.py' should be 'bzrlib/util/lsprof.py',
50
# (we do not check bzrlib/util/, since that is code bundled from elsewhere)
51
# but for compatibility with previous releases, we don't want to move it.
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
52
3572.1.7 by Marius Kruger
Code style and minor changes as per review.
53
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
54
class TestSourceHelper(TestCase):
55
56
    def source_file_name(self, package):
57
        """Return the path of the .py file for package."""
3616.2.7 by Mark Hammond
prefer getattr() over hasattr()
58
        if getattr(sys, "frozen", None) is not None:
3616.2.5 by Mark Hammond
don't try and test source code when we are frozen.
59
            raise TestSkipped("can't test sources in frozen distributions.")
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
60
        path = package.__file__
61
        if path[-1] in 'co':
62
            return path[:-1]
63
        else:
64
            return path
65
66
67
class TestApiUsage(TestSourceHelper):
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
68
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
69
    def find_occurences(self, rule, filename):
70
        """Find the number of occurences of rule in a file."""
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
71
        occurences = 0
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
72
        source = file(filename, 'r')
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
73
        for line in source:
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
74
            if line.find(rule) > -1:
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
75
                occurences += 1
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
76
        return occurences
77
78
    def test_branch_working_tree(self):
79
        """Test that the number of uses of working_tree in branch is stable."""
80
        occurences = self.find_occurences('self.working_tree()',
1526 by Robert Collins
Bugfix to source testing logic to get the right path when .py is returned by __file__
81
                                          self.source_file_name(bzrlib.branch))
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
82
        # do not even think of increasing this number. If you think you need to
83
        # increase it, then you almost certainly are doing something wrong as
84
        # the relationship from working_tree to branch is one way.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
85
        # Note that this is an exact equality so that when the number drops,
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
86
        #it is not given a buffer but rather has this test updated immediately.
87
        self.assertEqual(0, occurences)
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
88
89
    def test_branch_WorkingTree(self):
90
        """Test that the number of uses of working_tree in branch is stable."""
91
        occurences = self.find_occurences('WorkingTree',
1526 by Robert Collins
Bugfix to source testing logic to get the right path when .py is returned by __file__
92
                                          self.source_file_name(bzrlib.branch))
2696.1.1 by Martin Pool
Remove things deprecated in 0.11 and earlier
93
        # Do not even think of increasing this number. If you think you need to
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
94
        # increase it, then you almost certainly are doing something wrong as
95
        # the relationship from working_tree to branch is one way.
2696.1.1 by Martin Pool
Remove things deprecated in 0.11 and earlier
96
        # As of 20070809, there are no longer any mentions at all.
97
        self.assertEqual(0, occurences)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
98
99
100
class TestSource(TestSourceHelper):
101
102
    def get_bzrlib_dir(self):
103
        """Get the path to the root of bzrlib"""
104
        source = self.source_file_name(bzrlib)
105
        source_dir = os.path.dirname(source)
106
107
        # Avoid the case when bzrlib is packaged in a zip file
108
        if not os.path.isdir(source_dir):
109
            raise TestSkipped('Cannot find bzrlib source directory. Expected %s'
110
                              % source_dir)
111
        return source_dir
112
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
113
    def get_source_files(self, extensions=None):
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
114
        """Yield all source files for bzr and bzrlib
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
115
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
116
        :param our_files_only: If true, exclude files from included libraries
117
            or plugins.
118
        """
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
119
        bzrlib_dir = self.get_bzrlib_dir()
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
120
        if extensions is None:
121
            extensions = ('.py',)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
122
123
        # This is the front-end 'bzr' script
124
        bzr_path = self.get_bzr_path()
125
        yield bzr_path
126
127
        for root, dirs, files in os.walk(bzrlib_dir):
2102.3.1 by mbp at sourcefrog
test_source should avoid walking into tempdirs
128
            for d in dirs:
129
                if d.endswith('.tmp'):
130
                    dirs.remove(d)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
131
            for f in files:
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
132
                for extension in extensions:
133
                    if f.endswith(extension):
134
                        break
135
                else:
136
                    # Did not match the accepted extensions
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
137
                    continue
138
                yield osutils.pathjoin(root, f)
139
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
140
    def get_source_file_contents(self, extensions=None):
141
        for fname in self.get_source_files(extensions=extensions):
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
142
            f = open(fname, 'rb')
143
            try:
144
                text = f.read()
145
            finally:
146
                f.close()
147
            yield fname, text
148
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
149
    def is_our_code(self, fname):
150
        """Return true if it's a "real" part of bzrlib rather than external code"""
151
        if '/util/' in fname or '/plugins/' in fname:
152
            return False
153
        else:
154
            return True
155
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
156
    def is_copyright_exception(self, fname):
157
        """Certain files are allowed to be different"""
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
158
        if not self.is_our_code(fname):
2084.1.5 by John Arbash Meinel
Don't check plugins for copyright or license
159
            # We don't ask that external utilities or plugins be
160
            # (C) Canonical Ltd
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
161
            return True
162
        for exc in COPYRIGHT_EXCEPTIONS:
163
            if fname.endswith(exc):
164
                return True
165
        return False
166
167
    def is_license_exception(self, fname):
168
        """Certain files are allowed to be different"""
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
169
        if not self.is_our_code(fname):
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
170
            return True
171
        for exc in LICENSE_EXCEPTIONS:
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
172
            if fname.endswith(exc):
173
                return True
174
        return False
175
2102.3.1 by mbp at sourcefrog
test_source should avoid walking into tempdirs
176
    def test_tmpdir_not_in_source_files(self):
177
        """When scanning for source files, we don't descend test tempdirs"""
178
        for filename in self.get_source_files():
179
            if re.search(r'test....\.tmp', filename):
180
                self.fail("get_source_file() returned filename %r "
181
                          "from within a temporary directory"
182
                          % filename)
183
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
184
    def test_copyright(self):
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
185
        """Test that all .py and .pyx files have a valid copyright statement"""
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
186
        incorrect = []
187
2052.3.7 by John Arbash Meinel
Use positive lookahead to avoid extra newlines
188
        copyright_re = re.compile('#\\s*copyright.*(?=\n)', re.I)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
189
        copyright_canonical_re = re.compile(
190
            r'# Copyright \(C\) ' # Opening "# Copyright (C)"
191
            r'(\d+)(, \d+)*' # Followed by a series of dates
192
            r'.*Canonical Ltd' # And containing 'Canonical Ltd'
193
            )
194
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
195
        for fname, text in self.get_source_file_contents(
196
                extensions=('.py', '.pyx')):
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
197
            if self.is_copyright_exception(fname):
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
198
                continue
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
199
            match = copyright_canonical_re.search(text)
200
            if not match:
201
                match = copyright_re.search(text)
202
                if match:
203
                    incorrect.append((fname, 'found: %s' % (match.group(),)))
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
204
                else:
205
                    incorrect.append((fname, 'no copyright line found\n'))
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
206
            else:
207
                if 'by Canonical' in match.group():
208
                    incorrect.append((fname,
209
                        'should not have: "by Canonical": %s'
210
                        % (match.group(),)))
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
211
212
        if incorrect:
213
            help_text = ["Some files have missing or incorrect copyright"
214
                         " statements.",
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
215
                         "",
216
                         "Please either add them to the list of"
217
                         " COPYRIGHT_EXCEPTIONS in"
218
                         " bzrlib/tests/test_source.py",
219
                         # this is broken to prevent a false match
220
                         "or add '# Copyright (C)"
2613.1.2 by Martin Pool
Move bencode tests into util.tests
221
                         " 2007 Canonical Ltd' to these files:",
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
222
                         "",
223
                        ]
224
            for fname, comment in incorrect:
225
                help_text.append(fname)
226
                help_text.append((' '*4) + comment)
227
228
            self.fail('\n'.join(help_text))
229
230
    def test_gpl(self):
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
231
        """Test that all .py and .pyx files have a GPL disclaimer."""
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
232
        incorrect = []
233
234
        gpl_txt = """
235
# This program is free software; you can redistribute it and/or modify
236
# it under the terms of the GNU General Public License as published by
237
# the Free Software Foundation; either version 2 of the License, or
238
# (at your option) any later version.
239
#
240
# This program is distributed in the hope that it will be useful,
241
# but WITHOUT ANY WARRANTY; without even the implied warranty of
242
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
243
# GNU General Public License for more details.
244
#
245
# You should have received a copy of the GNU General Public License
246
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
247
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
248
"""
249
        gpl_re = re.compile(re.escape(gpl_txt), re.MULTILINE)
250
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
251
        for fname, text in self.get_source_file_contents(
252
                extensions=('.py', '.pyx')):
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
253
            if self.is_license_exception(fname):
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
254
                continue
255
            if not gpl_re.search(text):
256
                incorrect.append(fname)
257
258
        if incorrect:
259
            help_text = ['Some files have missing or incomplete GPL statement',
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
260
                         "",
261
                         "Please either add them to the list of"
262
                         " LICENSE_EXCEPTIONS in"
263
                         " bzrlib/tests/test_source.py",
264
                         "Or add the following text to the beginning:",
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
265
                         gpl_txt
266
                        ]
267
            for fname in incorrect:
268
                help_text.append((' '*4) + fname)
269
270
            self.fail('\n'.join(help_text))
2120.2.1 by John Arbash Meinel
Remove tabs from source files, and add a test to keep it that way.
271
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
272
    def _push_file(self, dict_, fname, line_no):
273
        if fname not in dict_:
274
            dict_[fname] = [line_no]
275
        else:
276
            dict_[fname].append(line_no)
277
278
    def _format_message(self, dict_, message):
279
        files = ["%s: %s" % (f, ', '.join([str(i+1) for i in lines]))
280
                for f, lines in dict_.items()]
3943.7.3 by Marius Kruger
sort error output
281
        files.sort()
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
282
        return message + '\n\n    %s' % ('\n    '.join(files))
283
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
284
    def test_coding_style(self):
285
        """Check if bazaar code conforms to some coding style conventions.
286
287
        Currently we check for:
288
         * any tab characters
289
         * trailing white space
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
290
         * non-unix newlines
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
291
         * no newline at end of files
3943.7.5 by Marius Kruger
* test_source also notes how many longlines exist
292
         * lines longer than 79 chars
293
           (only print how many files and lines are in violation)
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
294
        """
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
295
        tabs = {}
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
296
        trailing_ws = {}
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
297
        illegal_newlines = {}
3943.7.5 by Marius Kruger
* test_source also notes how many longlines exist
298
        long_lines = {}
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
299
        no_newline_at_eof = []
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
300
        for fname, text in self.get_source_file_contents(
301
                extensions=('.py', '.pyx')):
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
302
            if not self.is_our_code(fname):
2234.4.1 by Wouter van Heyst
(John Arbash Meinel) Fix selftest for installed bzr (#80330)
303
                continue
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
304
            lines = text.splitlines(True)
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
305
            last_line_no = len(lines) - 1
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
306
            for line_no, line in enumerate(lines):
307
                if '\t' in line:
308
                    self._push_file(tabs, fname, line_no)
309
                if not line.endswith('\n') or line.endswith('\r\n'):
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
310
                    if line_no != last_line_no: # not no_newline_at_eof
311
                        self._push_file(illegal_newlines, fname, line_no)
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
312
                if line.endswith(' \n'):
313
                    self._push_file(trailing_ws, fname, line_no)
3943.7.5 by Marius Kruger
* test_source also notes how many longlines exist
314
                if len(line) > 80:
315
                    self._push_file(long_lines, fname, line_no)
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
316
            if not lines[-1].endswith('\n'):
317
                no_newline_at_eof.append(fname)
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
318
        problems = []
319
        if tabs:
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
320
            problems.append(self._format_message(tabs,
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
321
                'Tab characters were found in the following source files.'
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
322
                '\nThey should either be replaced by "\\t" or by spaces:'))
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
323
        if trailing_ws:
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
324
            problems.append(self._format_message(trailing_ws,
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
325
                'Trailing white space was found in the following source files:'
326
                ))
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
327
        if illegal_newlines:
328
            problems.append(self._format_message(illegal_newlines,
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
329
                'Non-unix newlines were found in the following source files:'))
3943.7.5 by Marius Kruger
* test_source also notes how many longlines exist
330
        if long_lines:
331
            print ("There are %i lines longer than 79 characters in %i files."
332
                % (sum([len(lines) for f, lines in long_lines.items()]),
333
                    len(long_lines)))
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
334
        if no_newline_at_eof:
335
            no_newline_at_eof.sort()
336
            problems.append("The following source files doesn't have a "
337
                "newline at the end:"
338
               '\n\n    %s'
339
               % ('\n    '.join(no_newline_at_eof)))
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
340
        if problems:
4115.1.1 by Robert Collins
Turn test_coding_style into a KnownFailure until it gets fixed as per the list.
341
            raise KnownFailure("test_coding_style has failed")
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
342
            self.fail('\n\n'.join(problems))
3572.1.3 by Marius Kruger
* move test_coding_style into test_source
343
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
344
    def test_no_asserts(self):
345
        """bzr shouldn't use the 'assert' statement."""
346
        # assert causes too much variation between -O and not, and tends to
347
        # give bad errors to the user
348
        def search(x):
349
            # scan down through x for assert statements, report any problems
350
            # this is a bit cheesy; it may get some false positives?
351
            if x[0] == symbol.assert_stmt:
352
                return True
353
            elif x[0] == token.NAME:
354
                # can't search further down
355
                return False
356
            for sub in x[1:]:
357
                if sub and search(sub):
358
                    return True
359
            return False
360
        badfiles = []
361
        for fname, text in self.get_source_file_contents():
362
            if not self.is_our_code(fname):
363
                continue
364
            ast = parser.ast2tuple(parser.suite(''.join(text)))
365
            if search(ast):
366
                badfiles.append(fname)
367
        if badfiles:
3376.2.7 by Martin Pool
Treat assert statements in our code as a hard error
368
            self.fail(
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
369
                "these files contain an assert statement and should not:\n%s"
370
                % '\n'.join(badfiles))