/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/matchers.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
"""Matchers for breezy.
 
17
"""Matchers for bzrlib.
18
18
 
19
 
Primarily test support, Matchers are used by self.assertThat in the breezy
 
19
Primarily test support, Matchers are used by self.assertThat in the bzrlib
20
20
test suite. A matcher is a stateful test helper which can be used to determine
21
21
if a passed object 'matches', much like a regex. If the object does not match
22
22
the mismatch can be described in a human readable fashion. assertThat then
28
28
 
29
29
__all__ = [
30
30
    'HasLayout',
31
 
    'HasPathRelations',
32
31
    'MatchesAncestry',
 
32
    'ContainsNoVfsCalls',
33
33
    'ReturnsUnlockable',
34
34
    'RevisionHistoryMatches',
35
35
    ]
36
36
 
37
 
from .. import (
 
37
from bzrlib import (
38
38
    osutils,
39
39
    revision as _mod_revision,
40
40
    )
41
 
 
42
 
from ..tree import InterTree
 
41
from bzrlib import lazy_import
 
42
lazy_import.lazy_import(globals(),
 
43
"""
 
44
from bzrlib.smart.request import request_handlers as smart_request_handlers
 
45
from bzrlib.smart import vfs
 
46
""")
43
47
 
44
48
from testtools.matchers import Equals, Mismatch, Matcher
45
49
 
60
64
 
61
65
    def __str__(self):
62
66
        return ('ReturnsUnlockable(lockable_thing=%s)' %
63
 
                self.lockable_thing)
 
67
            self.lockable_thing)
64
68
 
65
69
    def match(self, lock_method):
66
70
        lock_method().unlock()
109
113
            self.repository, self.revision_id))
110
114
 
111
115
    def match(self, expected):
112
 
        with self.repository.lock_read():
 
116
        self.repository.lock_read()
 
117
        try:
113
118
            graph = self.repository.get_graph()
114
119
            got = [r for r, p in graph.iter_ancestry([self.revision_id])]
115
120
            if _mod_revision.NULL_REVISION in got:
116
121
                got.remove(_mod_revision.NULL_REVISION)
 
122
        finally:
 
123
            self.repository.unlock()
117
124
        if sorted(got) != sorted(expected):
118
125
            return _AncestryMismatch(self.revision_id, sorted(got),
119
 
                                     sorted(expected))
 
126
                sorted(expected))
120
127
 
121
128
 
122
129
class HasLayout(Matcher):
129
136
        Matcher.__init__(self)
130
137
        self.entries = entries
131
138
 
132
 
    def get_tree_layout(self, tree, include_file_ids):
 
139
    def get_tree_layout(self, tree):
133
140
        """Get the (path, file_id) pairs for the current tree."""
134
 
        with tree.lock_read():
 
141
        tree.lock_read()
 
142
        try:
135
143
            for path, ie in tree.iter_entries_by_dir():
136
 
                if path != u'':
137
 
                    path += ie.kind_character()
138
 
                if include_file_ids:
139
 
                    yield (path, ie.file_id)
 
144
                if ie.parent_id is None:
 
145
                    yield (u"", ie.file_id)
140
146
                else:
141
 
                    yield path
 
147
                    yield (path+ie.kind_character(), ie.file_id)
 
148
        finally:
 
149
            tree.unlock()
142
150
 
143
151
    @staticmethod
144
152
    def _strip_unreferenced_directories(entries):
148
156
        """
149
157
        directories = []
150
158
        for entry in entries:
151
 
            if isinstance(entry, str):
 
159
            if isinstance(entry, basestring):
152
160
                path = entry
153
161
            else:
154
162
                path = entry[0]
167
175
        return 'HasLayout(%r)' % self.entries
168
176
 
169
177
    def match(self, tree):
170
 
        include_file_ids = self.entries and not isinstance(
171
 
            self.entries[0], str)
172
 
        actual = list(self.get_tree_layout(
173
 
            tree, include_file_ids=include_file_ids))
 
178
        actual = list(self.get_tree_layout(tree))
 
179
        if self.entries and isinstance(self.entries[0], basestring):
 
180
            actual = [path for (path, fileid) in actual]
174
181
        if not tree.has_versioned_directories():
175
182
            entries = list(self._strip_unreferenced_directories(self.entries))
176
183
        else:
178
185
        return Equals(entries).match(actual)
179
186
 
180
187
 
181
 
class HasPathRelations(Matcher):
182
 
    """Matcher verifies that paths have a relation to those in another tree.
183
 
 
184
 
    :ivar previous_tree: tree to compare to
185
 
    :ivar previous_entries: List of expected entries, as (path, previous_path) pairs.
186
 
    """
187
 
 
188
 
    def __init__(self, previous_tree, previous_entries):
189
 
        Matcher.__init__(self)
190
 
        self.previous_tree = previous_tree
191
 
        self.previous_entries = previous_entries
192
 
 
193
 
    def get_path_map(self, tree):
194
 
        """Get the (path, previous_path) pairs for the current tree."""
195
 
        previous_intertree = InterTree.get(self.previous_tree, tree)
196
 
        with tree.lock_read(), self.previous_tree.lock_read():
197
 
            for path, ie in tree.iter_entries_by_dir():
198
 
                if tree.supports_rename_tracking():
199
 
                    previous_path = previous_intertree.find_source_path(path)
200
 
                else:
201
 
                    if self.previous_tree.is_versioned(path):
202
 
                        previous_path = path
203
 
                    else:
204
 
                        previous_path = None
205
 
                if previous_path:
206
 
                    kind = self.previous_tree.kind(previous_path)
207
 
                    if kind == 'directory':
208
 
                        previous_path += '/'
209
 
                if path == u'':
210
 
                    yield (u"", previous_path)
211
 
                else:
212
 
                    yield (path + ie.kind_character(), previous_path)
213
 
 
214
 
    @staticmethod
215
 
    def _strip_unreferenced_directories(entries):
216
 
        """Strip all directories that don't (in)directly contain any files.
217
 
 
218
 
        :param entries: List of path strings or (path, previous_path) tuples to process
219
 
        """
220
 
        directory_used = set()
221
 
        directories = []
222
 
        for (path, previous_path) in entries:
223
 
            if not path or path[-1] == "/":
224
 
                # directory
225
 
                directories.append((path, previous_path))
226
 
            else:
227
 
                # Yield the referenced parent directories
228
 
                for direntry in directories:
229
 
                    if osutils.is_inside(direntry[0], path):
230
 
                        directory_used.add(direntry[0])
231
 
        for (path, previous_path) in entries:
232
 
            if (not path.endswith("/")) or path in directory_used:
233
 
                yield (path, previous_path)
234
 
 
235
 
    def __str__(self):
236
 
        return 'HasPathRelations(%r, %r)' % (self.previous_tree, self.previous_entries)
237
 
 
238
 
    def match(self, tree):
239
 
        actual = list(self.get_path_map(tree))
240
 
        if not tree.has_versioned_directories():
241
 
            entries = list(self._strip_unreferenced_directories(
242
 
                self.previous_entries))
243
 
        else:
244
 
            entries = self.previous_entries
245
 
        if not tree.supports_rename_tracking():
246
 
            entries = [
247
 
                (path, path if self.previous_tree.is_versioned(path) else None)
248
 
                for (path, previous_path) in entries]
249
 
        return Equals(entries).match(actual)
250
 
 
251
 
 
252
188
class RevisionHistoryMatches(Matcher):
253
189
    """A matcher that checks if a branch has a specific revision history.
254
190
 
263
199
        return 'RevisionHistoryMatches(%r)' % self.expected
264
200
 
265
201
    def match(self, branch):
266
 
        with branch.lock_read():
 
202
        branch.lock_read()
 
203
        try:
267
204
            graph = branch.repository.get_graph()
268
205
            history = list(graph.iter_lefthand_ancestry(
269
206
                branch.last_revision(), [_mod_revision.NULL_REVISION]))
270
207
            history.reverse()
 
208
        finally:
 
209
            branch.unlock()
271
210
        return Equals(self.expected).match(history)
 
211
 
 
212
 
 
213
class _NoVfsCallsMismatch(Mismatch):
 
214
    """Mismatch describing a list of HPSS calls which includes VFS requests."""
 
215
 
 
216
    def __init__(self, vfs_calls):
 
217
        self.vfs_calls = vfs_calls
 
218
 
 
219
    def describe(self):
 
220
        return "no VFS calls expected, got: %s" % ",".join([
 
221
            "%s(%s)" % (c.method,
 
222
                ", ".join([repr(a) for a in c.args])) for c in self.vfs_calls])
 
223
 
 
224
 
 
225
class ContainsNoVfsCalls(Matcher):
 
226
    """Ensure that none of the specified calls are HPSS calls."""
 
227
 
 
228
    def __str__(self):
 
229
        return 'ContainsNoVfsCalls()'
 
230
 
 
231
    @classmethod
 
232
    def match(cls, hpss_calls):
 
233
        vfs_calls = []
 
234
        for call in hpss_calls:
 
235
            try:
 
236
                request_method = smart_request_handlers.get(call.call.method)
 
237
            except KeyError:
 
238
                # A method we don't know about doesn't count as a VFS method.
 
239
                continue
 
240
            if issubclass(request_method, vfs.VfsRequest):
 
241
                vfs_calls.append(call.call)
 
242
        if len(vfs_calls) == 0:
 
243
            return None
 
244
        return _NoVfsCallsMismatch(vfs_calls)