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
17
"""Matchers for breezy.
17
"""Matchers for bzrlib.
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
33
32
'ContainsNoVfsCalls',
34
33
'ReturnsUnlockable',
35
34
'RevisionHistoryMatches',
40
39
revision as _mod_revision,
42
from .. import lazy_import
41
from bzrlib import lazy_import
43
42
lazy_import.lazy_import(globals(),
45
from breezy.bzr.smart.request import request_handlers as smart_request_handlers
46
from breezy.bzr.smart import vfs
44
from bzrlib.smart.request import request_handlers as smart_request_handlers
45
from bzrlib.smart import vfs
48
from ..sixish import (
51
from ..tree import find_previous_path
53
48
from testtools.matchers import Equals, Mismatch, Matcher
118
113
self.repository, self.revision_id))
120
115
def match(self, expected):
121
with self.repository.lock_read():
116
self.repository.lock_read()
122
118
graph = self.repository.get_graph()
123
119
got = [r for r, p in graph.iter_ancestry([self.revision_id])]
124
120
if _mod_revision.NULL_REVISION in got:
125
121
got.remove(_mod_revision.NULL_REVISION)
123
self.repository.unlock()
126
124
if sorted(got) != sorted(expected):
127
125
return _AncestryMismatch(self.revision_id, sorted(got),
128
126
sorted(expected))
176
177
def match(self, tree):
177
178
actual = list(self.get_tree_layout(tree))
178
if self.entries and isinstance(self.entries[0], (str, text_type)):
179
if self.entries and isinstance(self.entries[0], basestring):
179
180
actual = [path for (path, fileid) in actual]
180
181
if not tree.has_versioned_directories():
181
182
entries = list(self._strip_unreferenced_directories(self.entries))
184
185
return Equals(entries).match(actual)
187
class HasPathRelations(Matcher):
188
"""Matcher verifies that paths have a relation to those in another tree.
190
:ivar previous_tree: tree to compare to
191
:ivar previous_entries: List of expected entries, as (path, previous_path) pairs.
194
def __init__(self, previous_tree, previous_entries):
195
Matcher.__init__(self)
196
self.previous_tree = previous_tree
197
self.previous_entries = previous_entries
199
def get_path_map(self, tree):
200
"""Get the (path, previous_path) pairs for the current tree."""
201
with tree.lock_read(), self.previous_tree.lock_read():
202
for path, ie in tree.iter_entries_by_dir():
203
if tree.supports_rename_tracking():
204
previous_path = find_previous_path(tree, self.previous_tree, path)
206
if self.previous_tree.is_versioned(path):
211
kind = self.previous_tree.kind(previous_path)
212
if kind == 'directory':
214
if ie.parent_id is None:
215
yield (u"", previous_path)
217
yield (path+ie.kind_character(), previous_path)
220
def _strip_unreferenced_directories(entries):
221
"""Strip all directories that don't (in)directly contain any files.
223
:param entries: List of path strings or (path, previous_path) tuples to process
225
directory_used = set()
227
for (path, previous_path) in entries:
228
if not path or path[-1] == "/":
230
directories.append((path, previous_path))
232
# Yield the referenced parent directories
233
for direntry in directories:
234
if osutils.is_inside(direntry[0], path):
235
directory_used.add(direntry[0])
236
for (path, previous_path) in entries:
237
if (not path.endswith("/")) or path in directory_used:
238
yield (path, previous_path)
241
return 'HasPathRelations(%r, %r)' % (self.previous_tree, self.previous_entries)
243
def match(self, tree):
244
actual = list(self.get_path_map(tree))
245
if not tree.has_versioned_directories():
246
entries = list(self._strip_unreferenced_directories(self.previous_entries))
248
entries = self.previous_entries
249
if not tree.supports_rename_tracking():
251
(path, path if self.previous_tree.is_versioned(path) else None)
252
for (path, previous_path) in entries]
253
return Equals(entries).match(actual)
256
188
class RevisionHistoryMatches(Matcher):
257
189
"""A matcher that checks if a branch has a specific revision history.