~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_source.py

  • Committer: John Arbash Meinel
  • Date: 2008-08-18 22:34:21 UTC
  • mto: (3606.5.6 1.6)
  • mto: This revision was merged to the branch mainline in revision 3641.
  • Revision ID: john@arbash-meinel.com-20080818223421-todjny24vj4faj4t
Add tests for the fetching behavior.

The proper parameter passed is 'unordered' add an assert for it, and
fix callers that were passing 'unsorted' instead.
Add tests that we make the right get_record_stream call based
on the value of _fetch_uses_deltas.
Fix the fetch request for signatures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
3
#            and others
3
4
#
4
5
# This program is free software; you can redistribute it and/or modify
5
6
# it under the terms of the GNU General Public License as published by
22
23
 
23
24
# import system imports here
24
25
import os
 
26
import parser
 
27
import re
 
28
import symbol
25
29
import sys
 
30
import token
26
31
 
27
32
#import bzrlib specific imports here
28
 
from bzrlib.tests import TestCase
 
33
from bzrlib import (
 
34
    osutils,
 
35
    )
29
36
import bzrlib.branch
30
 
 
31
 
 
32
 
class TestApiUsage(TestCase):
 
37
from bzrlib.tests import (
 
38
    KnownFailure,
 
39
    TestCase,
 
40
    TestSkipped,
 
41
    )
 
42
 
 
43
 
 
44
# Files which are listed here will be skipped when testing for Copyright (or
 
45
# GPL) statements.
 
46
COPYRIGHT_EXCEPTIONS = ['bzrlib/lsprof.py']
 
47
 
 
48
LICENSE_EXCEPTIONS = ['bzrlib/lsprof.py']
 
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.
 
52
 
 
53
 
 
54
class TestSourceHelper(TestCase):
 
55
 
 
56
    def source_file_name(self, package):
 
57
        """Return the path of the .py file for package."""
 
58
        path = package.__file__
 
59
        if path[-1] in 'co':
 
60
            return path[:-1]
 
61
        else:
 
62
            return path
 
63
 
 
64
 
 
65
class TestApiUsage(TestSourceHelper):
33
66
 
34
67
    def find_occurences(self, rule, filename):
35
68
        """Find the number of occurences of rule in a file."""
40
73
                occurences += 1
41
74
        return occurences
42
75
 
43
 
    def source_file_name(self, package):
44
 
        """Return the path of the .py file for package."""
45
 
        path = package.__file__
46
 
        if path[-1] in 'co':
47
 
            return path[:-1]
48
 
        else:
49
 
            return path
50
 
 
51
76
    def test_branch_working_tree(self):
52
77
        """Test that the number of uses of working_tree in branch is stable."""
53
78
        occurences = self.find_occurences('self.working_tree()',
63
88
        """Test that the number of uses of working_tree in branch is stable."""
64
89
        occurences = self.find_occurences('WorkingTree',
65
90
                                          self.source_file_name(bzrlib.branch))
66
 
        # do not even think of increasing this number. If you think you need to
 
91
        # Do not even think of increasing this number. If you think you need to
67
92
        # increase it, then you almost certainly are doing something wrong as
68
93
        # the relationship from working_tree to branch is one way.
69
 
        # This number should be 4 (import NoWorkingTree and WorkingTree, 
70
 
        # raise NoWorkingTree from working_tree(), and construct a working tree
71
 
        # there) but a merge that regressed this was done before this test was
72
 
        # written. Note that this is an exact equality so that when the number
73
 
        # drops, it is not given a buffer but rather this test updated
74
 
        # immediately.
75
 
        self.assertEqual(4, occurences)
 
94
        # As of 20070809, there are no longer any mentions at all.
 
95
        self.assertEqual(0, occurences)
 
96
 
 
97
 
 
98
class TestSource(TestSourceHelper):
 
99
 
 
100
    def get_bzrlib_dir(self):
 
101
        """Get the path to the root of bzrlib"""
 
102
        source = self.source_file_name(bzrlib)
 
103
        source_dir = os.path.dirname(source)
 
104
 
 
105
        # Avoid the case when bzrlib is packaged in a zip file
 
106
        if not os.path.isdir(source_dir):
 
107
            raise TestSkipped('Cannot find bzrlib source directory. Expected %s'
 
108
                              % source_dir)
 
109
        return source_dir
 
110
 
 
111
    def get_source_files(self):
 
112
        """Yield all source files for bzr and bzrlib
 
113
        
 
114
        :param our_files_only: If true, exclude files from included libraries
 
115
            or plugins.
 
116
        """
 
117
        bzrlib_dir = self.get_bzrlib_dir()
 
118
 
 
119
        # This is the front-end 'bzr' script
 
120
        bzr_path = self.get_bzr_path()
 
121
        yield bzr_path
 
122
 
 
123
        for root, dirs, files in os.walk(bzrlib_dir):
 
124
            for d in dirs:
 
125
                if d.endswith('.tmp'):
 
126
                    dirs.remove(d)
 
127
            for f in files:
 
128
                if not f.endswith('.py'):
 
129
                    continue
 
130
                yield osutils.pathjoin(root, f)
 
131
 
 
132
    def get_source_file_contents(self):
 
133
        for fname in self.get_source_files():
 
134
            f = open(fname, 'rb')
 
135
            try:
 
136
                text = f.read()
 
137
            finally:
 
138
                f.close()
 
139
            yield fname, text
 
140
 
 
141
    def is_our_code(self, fname):
 
142
        """Return true if it's a "real" part of bzrlib rather than external code"""
 
143
        if '/util/' in fname or '/plugins/' in fname:
 
144
            return False
 
145
        else:
 
146
            return True
 
147
 
 
148
    def is_copyright_exception(self, fname):
 
149
        """Certain files are allowed to be different"""
 
150
        if not self.is_our_code(fname):
 
151
            # We don't ask that external utilities or plugins be
 
152
            # (C) Canonical Ltd
 
153
            return True
 
154
        for exc in COPYRIGHT_EXCEPTIONS:
 
155
            if fname.endswith(exc):
 
156
                return True
 
157
        return False
 
158
 
 
159
    def is_license_exception(self, fname):
 
160
        """Certain files are allowed to be different"""
 
161
        if not self.is_our_code(fname):
 
162
            return True
 
163
        for exc in LICENSE_EXCEPTIONS:
 
164
            if fname.endswith(exc):
 
165
                return True
 
166
        return False
 
167
 
 
168
    def test_tmpdir_not_in_source_files(self):
 
169
        """When scanning for source files, we don't descend test tempdirs"""
 
170
        for filename in self.get_source_files():
 
171
            if re.search(r'test....\.tmp', filename):
 
172
                self.fail("get_source_file() returned filename %r "
 
173
                          "from within a temporary directory"
 
174
                          % filename)
 
175
 
 
176
    def test_copyright(self):
 
177
        """Test that all .py files have a valid copyright statement"""
 
178
        # These are files which contain a different copyright statement
 
179
        # and that is okay.
 
180
        incorrect = []
 
181
 
 
182
        copyright_re = re.compile('#\\s*copyright.*(?=\n)', re.I)
 
183
        copyright_canonical_re = re.compile(
 
184
            r'# Copyright \(C\) ' # Opening "# Copyright (C)"
 
185
            r'(\d+)(, \d+)*' # Followed by a series of dates
 
186
            r'.*Canonical Ltd' # And containing 'Canonical Ltd'
 
187
            )
 
188
 
 
189
        for fname, text in self.get_source_file_contents():
 
190
            if self.is_copyright_exception(fname):
 
191
                continue
 
192
            match = copyright_canonical_re.search(text)
 
193
            if not match:
 
194
                match = copyright_re.search(text)
 
195
                if match:
 
196
                    incorrect.append((fname, 'found: %s' % (match.group(),)))
 
197
                else:
 
198
                    incorrect.append((fname, 'no copyright line found\n'))
 
199
            else:
 
200
                if 'by Canonical' in match.group():
 
201
                    incorrect.append((fname,
 
202
                        'should not have: "by Canonical": %s'
 
203
                        % (match.group(),)))
 
204
 
 
205
        if incorrect:
 
206
            help_text = ["Some files have missing or incorrect copyright"
 
207
                         " statements.",
 
208
                         "",
 
209
                         "Please either add them to the list of"
 
210
                         " COPYRIGHT_EXCEPTIONS in"
 
211
                         " bzrlib/tests/test_source.py",
 
212
                         # this is broken to prevent a false match
 
213
                         "or add '# Copyright (C)"
 
214
                         " 2007 Canonical Ltd' to these files:",
 
215
                         "",
 
216
                        ]
 
217
            for fname, comment in incorrect:
 
218
                help_text.append(fname)
 
219
                help_text.append((' '*4) + comment)
 
220
 
 
221
            self.fail('\n'.join(help_text))
 
222
 
 
223
    def test_gpl(self):
 
224
        """Test that all .py files have a GPL disclaimer"""
 
225
        incorrect = []
 
226
 
 
227
        gpl_txt = """
 
228
# This program is free software; you can redistribute it and/or modify
 
229
# it under the terms of the GNU General Public License as published by
 
230
# the Free Software Foundation; either version 2 of the License, or
 
231
# (at your option) any later version.
 
232
#
 
233
# This program is distributed in the hope that it will be useful,
 
234
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
235
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
236
# GNU General Public License for more details.
 
237
#
 
238
# You should have received a copy of the GNU General Public License
 
239
# along with this program; if not, write to the Free Software
 
240
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
241
"""
 
242
        gpl_re = re.compile(re.escape(gpl_txt), re.MULTILINE)
 
243
 
 
244
        for fname, text in self.get_source_file_contents():
 
245
            if self.is_license_exception(fname):
 
246
                continue
 
247
            if not gpl_re.search(text):
 
248
                incorrect.append(fname)
 
249
 
 
250
        if incorrect:
 
251
            help_text = ['Some files have missing or incomplete GPL statement',
 
252
                         "",
 
253
                         "Please either add them to the list of"
 
254
                         " LICENSE_EXCEPTIONS in"
 
255
                         " bzrlib/tests/test_source.py",
 
256
                         "Or add the following text to the beginning:",
 
257
                         gpl_txt
 
258
                        ]
 
259
            for fname in incorrect:
 
260
                help_text.append((' '*4) + fname)
 
261
 
 
262
            self.fail('\n'.join(help_text))
 
263
 
 
264
    def test_no_tabs(self):
 
265
        """bzrlib source files should not contain any tab characters."""
 
266
        incorrect = []
 
267
 
 
268
        for fname, text in self.get_source_file_contents():
 
269
            if not self.is_our_code(fname):
 
270
                continue
 
271
            if '\t' in text:
 
272
                incorrect.append(fname)
 
273
 
 
274
        if incorrect:
 
275
            self.fail('Tab characters were found in the following source files.'
 
276
              '\nThey should either be replaced by "\\t" or by spaces:'
 
277
              '\n\n    %s'
 
278
              % ('\n    '.join(incorrect)))
 
279
 
 
280
    def test_no_asserts(self):
 
281
        """bzr shouldn't use the 'assert' statement."""
 
282
        # assert causes too much variation between -O and not, and tends to
 
283
        # give bad errors to the user
 
284
        def search(x):
 
285
            # scan down through x for assert statements, report any problems
 
286
            # this is a bit cheesy; it may get some false positives?
 
287
            if x[0] == symbol.assert_stmt:
 
288
                return True
 
289
            elif x[0] == token.NAME:
 
290
                # can't search further down
 
291
                return False
 
292
            for sub in x[1:]:
 
293
                if sub and search(sub):
 
294
                    return True
 
295
            return False
 
296
        badfiles = []
 
297
        for fname, text in self.get_source_file_contents():
 
298
            if not self.is_our_code(fname):
 
299
                continue
 
300
            ast = parser.ast2tuple(parser.suite(''.join(text)))
 
301
            if search(ast):
 
302
                badfiles.append(fname)
 
303
        if badfiles:
 
304
            self.fail(
 
305
                "these files contain an assert statement and should not:\n%s"
 
306
                % '\n'.join(badfiles))