/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
1
# Copyright (C) 2005-2011 Canonical Ltd
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# 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
16
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
17
"""These tests are tests about the source code of breezy itself.
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
18
19
They are useful for testing code quality, checking coverage metric etc.
20
"""
21
22
import os
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
23
import parser
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
24
import re
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
25
import symbol
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
26
import sys
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
27
import token
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
28
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
29
from breezy import (
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
30
    osutils,
31
    )
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
32
import breezy.branch
33
from breezy.tests import (
7167.1.2 by Jelmer Vernooij
Add test_flake8.
34
    features,
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
35
    TestCase,
36
    TestSkipped,
37
    )
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
38
39
2052.3.8 by John Arbash Meinel
Better documentation about the exception variables
40
# Files which are listed here will be skipped when testing for Copyright (or
41
# GPL) statements.
5193.6.24 by Vincent Ladeuil
Add copyrights in placeholder __init__.py files and fix the fallout from bzrlib/doc_generate/conf.py rename.
42
COPYRIGHT_EXCEPTIONS = [
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
43
    'breezy/_bencode_py.py',
44
    'breezy/doc_generate/conf.py',
45
    'breezy/lsprof.py',
5193.6.24 by Vincent Ladeuil
Add copyrights in placeholder __init__.py files and fix the fallout from bzrlib/doc_generate/conf.py rename.
46
    ]
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
47
5193.6.24 by Vincent Ladeuil
Add copyrights in placeholder __init__.py files and fix the fallout from bzrlib/doc_generate/conf.py rename.
48
LICENSE_EXCEPTIONS = [
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
49
    'breezy/_bencode_py.py',
50
    'breezy/doc_generate/conf.py',
51
    'breezy/lsprof.py',
5193.6.24 by Vincent Ladeuil
Add copyrights in placeholder __init__.py files and fix the fallout from bzrlib/doc_generate/conf.py rename.
52
    ]
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
53
# Technically, 'breezy/lsprof.py' should be 'breezy/util/lsprof.py',
54
# (we do not check breezy/util/, since that is code bundled from elsewhere)
2052.3.8 by John Arbash Meinel
Better documentation about the exception variables
55
# but for compatibility with previous releases, we don't want to move it.
4634.37.3 by Martin Pool
sphinx autogenerate configuration is exempt from test_source
56
#
57
# sphinx_conf is semi-autogenerated.
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
58
3572.1.7 by Marius Kruger
Code style and minor changes as per review.
59
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
60
class TestSourceHelper(TestCase):
61
62
    def source_file_name(self, package):
63
        """Return the path of the .py file for package."""
3616.2.7 by Mark Hammond
prefer getattr() over hasattr()
64
        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.
65
            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
66
        path = package.__file__
67
        if path[-1] in 'co':
68
            return path[:-1]
69
        else:
70
            return path
71
72
73
class TestApiUsage(TestSourceHelper):
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
74
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
75
    def find_occurences(self, rule, filename):
76
        """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
77
        occurences = 0
6973.7.5 by Jelmer Vernooij
s/file/open.
78
        source = open(filename, 'r')
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
79
        for line in source:
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
80
            if line.find(rule) > -1:
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
81
                occurences += 1
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
82
        return occurences
83
84
    def test_branch_working_tree(self):
85
        """Test that the number of uses of working_tree in branch is stable."""
86
        occurences = self.find_occurences('self.working_tree()',
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
87
                                          self.source_file_name(breezy.branch))
1523 by Robert Collins
Test for the number of uses of self.working_tree() in branch.py
88
        # do not even think of increasing this number. If you think you need to
89
        # increase it, then you almost certainly are doing something wrong as
90
        # the relationship from working_tree to branch is one way.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
91
        # Note that this is an exact equality so that when the number drops,
7143.15.2 by Jelmer Vernooij
Run autopep8.
92
        # it is not given a buffer but rather has this test updated immediately.
1534.4.35 by Robert Collins
Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()
93
        self.assertEqual(0, occurences)
1524 by Robert Collins
Test the uses of WorkingTree from branch.py
94
95
    def test_branch_WorkingTree(self):
96
        """Test that the number of uses of working_tree in branch is stable."""
97
        occurences = self.find_occurences('WorkingTree',
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
98
                                          self.source_file_name(breezy.branch))
2696.1.1 by Martin Pool
Remove things deprecated in 0.11 and earlier
99
        # 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
100
        # increase it, then you almost certainly are doing something wrong as
101
        # the relationship from working_tree to branch is one way.
2696.1.1 by Martin Pool
Remove things deprecated in 0.11 and earlier
102
        # As of 20070809, there are no longer any mentions at all.
103
        self.assertEqual(0, occurences)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
104
105
106
class TestSource(TestSourceHelper):
107
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
108
    def get_breezy_dir(self):
109
        """Get the path to the root of breezy"""
110
        source = self.source_file_name(breezy)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
111
        source_dir = os.path.dirname(source)
112
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
113
        # Avoid the case when breezy is packaged in a zip file
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
114
        if not os.path.isdir(source_dir):
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
115
            raise TestSkipped(
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
116
                'Cannot find breezy source directory. Expected %s'
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
117
                % source_dir)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
118
        return source_dir
119
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
120
    def get_source_files(self, extensions=None):
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
121
        """Yield all source files for bzr and breezy
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
122
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
123
        :param our_files_only: If true, exclude files from included libraries
124
            or plugins.
125
        """
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
126
        breezy_dir = self.get_breezy_dir()
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
127
        if extensions is None:
128
            extensions = ('.py',)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
129
130
        # This is the front-end 'bzr' script
6622.1.1 by Jelmer Vernooij
Rename bzrlib => brzlib, bzr => brz.
131
        bzr_path = self.get_brz_path()
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
132
        yield bzr_path
133
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
134
        for root, dirs, files in os.walk(breezy_dir):
2102.3.1 by mbp at sourcefrog
test_source should avoid walking into tempdirs
135
            for d in dirs:
136
                if d.endswith('.tmp'):
137
                    dirs.remove(d)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
138
            for f in files:
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
139
                for extension in extensions:
140
                    if f.endswith(extension):
141
                        break
142
                else:
143
                    # Did not match the accepted extensions
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
144
                    continue
145
                yield osutils.pathjoin(root, f)
146
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
147
    def get_source_file_contents(self, extensions=None):
148
        for fname in self.get_source_files(extensions=extensions):
7045.4.10 by Jelmer Vernooij
Fix a couple more tests.
149
            with open(fname, 'r') as f:
150
                yield fname, f.read()
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
151
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
152
    def is_our_code(self, fname):
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
153
        """True if it's a "real" part of breezy rather than external code"""
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
154
        if '/util/' in fname or '/plugins/' in fname:
155
            return False
156
        else:
157
            return True
158
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
159
    def is_copyright_exception(self, fname):
160
        """Certain files are allowed to be different"""
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
161
        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
162
            return True
163
        for exc in COPYRIGHT_EXCEPTIONS:
164
            if fname.endswith(exc):
165
                return True
166
        return False
167
168
    def is_license_exception(self, fname):
169
        """Certain files are allowed to be different"""
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
170
        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
171
            return True
172
        for exc in LICENSE_EXCEPTIONS:
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
173
            if fname.endswith(exc):
174
                return True
175
        return False
176
2102.3.1 by mbp at sourcefrog
test_source should avoid walking into tempdirs
177
    def test_tmpdir_not_in_source_files(self):
178
        """When scanning for source files, we don't descend test tempdirs"""
179
        for filename in self.get_source_files():
180
            if re.search(r'test....\.tmp', filename):
181
                self.fail("get_source_file() returned filename %r "
182
                          "from within a temporary directory"
183
                          % filename)
184
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
185
    def test_copyright(self):
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
186
        """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
187
        incorrect = []
188
2052.3.7 by John Arbash Meinel
Use positive lookahead to avoid extra newlines
189
        copyright_re = re.compile('#\\s*copyright.*(?=\n)', re.I)
6621.21.1 by Martin
Update bt.test_source copyright test to accept other copyright holders
190
        copyright_statement_re = re.compile(
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
191
            r'# Copyright \(C\) '  # Opening "# Copyright (C)"
6621.21.1 by Martin
Update bt.test_source copyright test to accept other copyright holders
192
            r'(\d+?)((, |-)\d+)*'  # followed by a series of dates
193
            r' [^ ]*')             # and then whoever.
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
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
6621.21.1 by Martin
Update bt.test_source copyright test to accept other copyright holders
199
            match = copyright_statement_re.search(text)
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
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,
7143.15.2 by Jelmer Vernooij
Run autopep8.
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"
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
218
                         " breezy/tests/test_source.py",
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
219
                         # this is broken to prevent a false match
220
                         "or add '# Copyright (C)"
6621.21.1 by Martin
Update bt.test_source copyright test to accept other copyright holders
221
                         " 2007 Bazaar hackers' to these files:",
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
222
                         "",
7143.15.2 by Jelmer Vernooij
Run autopep8.
223
                         ]
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
224
            for fname, comment in incorrect:
225
                help_text.append(fname)
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
226
                help_text.append((' ' * 4) + comment)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
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"
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
263
                         " breezy/tests/test_source.py",
2052.3.5 by John Arbash Meinel
Guide people to how to add files to the list of exceptions
264
                         "Or add the following text to the beginning:",
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
265
                         gpl_txt]
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
266
            for fname in incorrect:
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
267
                help_text.append((' ' * 4) + fname)
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
268
269
            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.
270
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
271
    def _push_file(self, dict_, fname, line_no):
272
        if fname not in dict_:
273
            dict_[fname] = [line_no]
274
        else:
275
            dict_[fname].append(line_no)
276
277
    def _format_message(self, dict_, message):
6619.3.18 by Jelmer Vernooij
Run 2to3 idioms fixer.
278
        files = sorted(["%s: %s" % (f, ', '.join([str(i + 1) for i in lines]))
7143.15.2 by Jelmer Vernooij
Run autopep8.
279
                        for f, lines in dict_.items()])
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
280
        return message + '\n\n    %s' % ('\n    '.join(files))
281
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
282
    def test_coding_style(self):
283
        """Check if bazaar code conforms to some coding style conventions.
284
5967.5.1 by Martin Pool
Don't print a message about long lines or trailing newlines.
285
        Generally we expect PEP8, but we do not generally strictly enforce
286
        this, and there are existing files that do not comply.  The 'pep8'
287
        tool, available separately, will check for more cases.
4210.5.1 by Marius Kruger
don't raise KnownFailure for all coding_style regressions,
288
5967.5.1 by Martin Pool
Don't print a message about long lines or trailing newlines.
289
        This test only enforces conditions that are globally true at the
290
        moment, and that should cause a patch to be rejected: spaces rather
291
        than tabs, unix newlines, and a newline at the end of the file.
3943.7.1 by Marius Kruger
* Change test_no_tabs to test_coding_style and let it check for trailing newlines too.
292
        """
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
293
        tabs = {}
294
        illegal_newlines = {}
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
295
        no_newline_at_eof = []
4198.1.1 by John Arbash Meinel
Include pyrex files in our source testing for GPL and Copyright checks.
296
        for fname, text in self.get_source_file_contents(
297
                extensions=('.py', '.pyx')):
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
298
            if not self.is_our_code(fname):
2234.4.1 by Wouter van Heyst
(John Arbash Meinel) Fix selftest for installed bzr (#80330)
299
                continue
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
300
            lines = text.splitlines(True)
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
301
            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.
302
            for line_no, line in enumerate(lines):
303
                if '\t' in line:
304
                    self._push_file(tabs, fname, line_no)
305
                if not line.endswith('\n') or line.endswith('\r\n'):
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
306
                    if line_no != last_line_no:  # not no_newline_at_eof
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
307
                        self._push_file(illegal_newlines, fname, line_no)
308
            if not lines[-1].endswith('\n'):
309
                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.
310
        problems = []
311
        if tabs:
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
312
            problems.append(self._format_message(tabs,
7143.15.2 by Jelmer Vernooij
Run autopep8.
313
                                                 'Tab characters were found in the following source files.'
314
                                                 '\nThey should either be replaced by "\\t" or by spaces:'))
3943.7.2 by Marius Kruger
* also check for unix style newlines and note in HACKING that this is what we use.
315
        if illegal_newlines:
316
            problems.append(self._format_message(illegal_newlines,
7143.15.2 by Jelmer Vernooij
Run autopep8.
317
                                                 'Non-unix newlines were found in the following source files:'))
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
318
        if no_newline_at_eof:
319
            no_newline_at_eof.sort()
320
            problems.append("The following source files doesn't have a "
7143.15.2 by Jelmer Vernooij
Run autopep8.
321
                            "newline at the end:"
322
                            '\n\n    %s'
323
                            % ('\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.
324
        if problems:
3943.7.4 by Marius Kruger
now also check for 'no newline at end of files'
325
            self.fail('\n\n'.join(problems))
3572.1.3 by Marius Kruger
* move test_coding_style into test_source
326
7167.1.2 by Jelmer Vernooij
Add test_flake8.
327
    def test_flake8(self):
7167.1.3 by Jelmer Vernooij
Use addCleanup.
328
        self.requireFeature(features.flake8)
329
        # Older versions of flake8 don't support the 'paths'
330
        # variable
331
        new_path = list(sys.path)
332
        new_path.insert(
333
            0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools'))
334
        self.overrideAttr(sys, 'path', new_path)
7290.49.3 by Jelmer Vernooij
Cope with broken versions of flake8.
335
        import argparse
7296.1.4 by Jelmer Vernooij
Avoid using legacy API for flake8.
336
        from flake8.main.application import Application
337
        from flake8.formatting.base import BaseFormatter
338
        app = Application()
339
        app.config = u'setup.cfg'
340
        app.jobs = 1
341
342
        class Formatter(BaseFormatter):
343
344
            def __init__(self):
345
                self.errors = []
346
347
            def start(self):
348
                pass
349
350
            def stop(self):
351
                app.file_checker_manager.report()
352
353
            def handle(self, error):
354
                self.errors.append(error)
355
7290.49.3 by Jelmer Vernooij
Cope with broken versions of flake8.
356
        try:
357
            app.initialize([])
358
        except argparse.ArgumentError as e:
359
            self.skipTest('broken flake8: %r' % e)
7296.1.4 by Jelmer Vernooij
Avoid using legacy API for flake8.
360
        app.formatter = Formatter()
361
        app.run_checks()
362
        app.report()
363
        self.assertEqual(app.formatter.errors, [])
7167.1.2 by Jelmer Vernooij
Add test_flake8.
364
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
365
    def test_no_asserts(self):
366
        """bzr shouldn't use the 'assert' statement."""
367
        # assert causes too much variation between -O and not, and tends to
368
        # give bad errors to the user
369
        def search(x):
370
            # scan down through x for assert statements, report any problems
371
            # this is a bit cheesy; it may get some false positives?
372
            if x[0] == symbol.assert_stmt:
373
                return True
374
            elif x[0] == token.NAME:
375
                # can't search further down
376
                return False
377
            for sub in x[1:]:
378
                if sub and search(sub):
379
                    return True
380
            return False
381
        badfiles = []
4699.1.1 by Harald Meland
Make test_no_asserts quicker by doing a regexp check for the presence of any 'assert' word before doing any expensive AST stuff
382
        assert_re = re.compile(r'\bassert\b')
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
383
        for fname, text in self.get_source_file_contents():
384
            if not self.is_our_code(fname):
385
                continue
4699.1.1 by Harald Meland
Make test_no_asserts quicker by doing a regexp check for the presence of any 'assert' word before doing any expensive AST stuff
386
            if not assert_re.search(text):
387
                continue
7045.4.10 by Jelmer Vernooij
Fix a couple more tests.
388
            st = parser.suite(text)
389
            code = parser.st2tuple(st)
390
            if search(code):
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
391
                badfiles.append(fname)
392
        if badfiles:
3376.2.7 by Martin Pool
Treat assert statements in our code as a hard error
393
            self.fail(
3376.2.1 by Martin Pool
Add test_no_asserts and cleanup test_source
394
                "these files contain an assert statement and should not:\n%s"
395
                % '\n'.join(badfiles))
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
396
397
    def test_extension_exceptions(self):
398
        """Extension functions should propagate exceptions.
399
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
400
        Either they should return an object, have an 'except' clause, or
401
        have a "# cannot_raise" to indicate that we've audited them and
402
        defined them as not raising exceptions.
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
403
        """
404
        both_exc_and_no_exc = []
405
        missing_except = []
7038.1.5 by Martin
Fix test_source failure after removing magic comment
406
        common_classes = ('StaticTuple',)
5365.5.29 by John Arbash Meinel
Handle test_source and extensions. Also define an 'extern' protocol, to allow
407
        class_re = re.compile(r'^(cdef\s+)?(public\s+)?'
408
                              r'(api\s+)?class (\w+).*:', re.MULTILINE)
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
409
        except_re = re.compile(
410
            r'cdef\s+'        # start with cdef
411
            r'([\w *]*?)\s*'  # this is the return signature
412
            r'(\w+)\s*\('     # the function name
413
            r'[^)]*\)\s*'     # parameters
414
            r'(.*)\s*:'       # the except clause
415
            r'\s*(#\s*cannot[- _]raise)?')  # cannot raise comment
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
416
        for fname, text in self.get_source_file_contents(
417
                extensions=('.pyx',)):
6619.3.12 by Jelmer Vernooij
Use 2to3 set_literal fixer.
418
            known_classes = {m[-1] for m in class_re.findall(text)}
7038.1.5 by Martin
Fix test_source failure after removing magic comment
419
            known_classes.update(common_classes)
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
420
            cdefs = except_re.findall(text)
421
            for sig, func, exc_clause, no_exc_comment in cdefs:
4932.1.2 by John Arbash Meinel
Clean up _simple_set.pyx, and handle 'nogil'.
422
                if sig.startswith('api '):
423
                    sig = sig[4:]
4634.117.8 by John Arbash Meinel
Use a class regex to find other signatures to exclude.
424
                if not sig or sig in known_classes:
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
425
                    sig = 'object'
4932.1.2 by John Arbash Meinel
Clean up _simple_set.pyx, and handle 'nogil'.
426
                if 'nogil' in exc_clause:
427
                    exc_clause = exc_clause.replace('nogil', '').strip()
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
428
                if exc_clause and no_exc_comment:
429
                    both_exc_and_no_exc.append((fname, func))
430
                if sig != 'object' and not (exc_clause or no_exc_comment):
431
                    missing_except.append((fname, func))
432
        error_msg = []
433
        if both_exc_and_no_exc:
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
434
            error_msg.append(
435
                'The following functions had "cannot raise" comments'
436
                ' but did have an except clause set:')
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
437
            for fname, func in both_exc_and_no_exc:
438
                error_msg.append('%s:%s' % (fname, func))
439
            error_msg.extend(('', ''))
440
        if missing_except:
5967.5.2 by Martin Pool
Make test_source actually comply with pep8 itself
441
            error_msg.append(
442
                'The following functions have fixed return types,'
443
                ' but no except clause.')
444
            error_msg.append(
445
                'Either add an except or append "# cannot_raise".')
4634.117.5 by John Arbash Meinel
Add a test_source test, to ensure that all funcs have either an except
446
            for fname, func in missing_except:
447
                error_msg.append('%s:%s' % (fname, func))
448
            error_msg.extend(('', ''))
449
        if error_msg:
450
            self.fail('\n'.join(error_msg))
6379.6.2 by Jelmer Vernooij
add test to make sure absolute_import is enabled.
451
452
    def test_feature_absolute_import(self):
453
        """Using absolute imports means avoiding unnecesary stat and
454
        open calls.
455
456
        Make sure that all non-test files have absolute imports enabled.
457
        """
458
        missing_absolute_import = []
459
        for fname, text in self.get_source_file_contents(
6665.1.2 by Jelmer Vernooij
Require absolute_import in pyx files.
460
                extensions=('.py', '.pyx')):
6379.6.3 by Jelmer Vernooij
Use absolute_import.
461
            if "/tests/" in fname or "test_" in fname:
6379.6.2 by Jelmer Vernooij
add test to make sure absolute_import is enabled.
462
                # We don't really care about tests
463
                continue
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
464
            if "from __future__ import absolute_import" not in text:
6379.6.2 by Jelmer Vernooij
add test to make sure absolute_import is enabled.
465
                missing_absolute_import.append(fname)
466
467
        if missing_absolute_import:
468
            self.fail(
469
                'The following files do not have absolute_import enabled:\n'
470
                '\n' + '\n'.join(missing_absolute_import))