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 brzlib.
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 brzlib
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 brzlib 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 brzlib.smart.request import request_handlers as smart_request_handlers
45
from brzlib.smart import vfs
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),
131
129
class HasLayout(Matcher):
138
136
Matcher.__init__(self)
139
137
self.entries = entries
141
def get_tree_layout(self, tree, include_file_ids):
139
def get_tree_layout(self, tree):
142
140
"""Get the (path, file_id) pairs for the current tree."""
143
with tree.lock_read():
144
143
for path, ie in tree.iter_entries_by_dir():
146
path += ie.kind_character()
148
yield (path, ie.file_id)
144
if ie.parent_id is None:
145
yield (u"", ie.file_id)
147
yield (path+ie.kind_character(), ie.file_id)
153
152
def _strip_unreferenced_directories(entries):
176
175
return 'HasLayout(%r)' % self.entries
178
177
def match(self, tree):
179
include_file_ids = self.entries and not isinstance(
180
self.entries[0], str)
181
actual = list(self.get_tree_layout(
182
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]
183
181
if not tree.has_versioned_directories():
184
182
entries = list(self._strip_unreferenced_directories(self.entries))
187
185
return Equals(entries).match(actual)
190
class HasPathRelations(Matcher):
191
"""Matcher verifies that paths have a relation to those in another tree.
193
:ivar previous_tree: tree to compare to
194
:ivar previous_entries: List of expected entries, as (path, previous_path) pairs.
197
def __init__(self, previous_tree, previous_entries):
198
Matcher.__init__(self)
199
self.previous_tree = previous_tree
200
self.previous_entries = previous_entries
202
def get_path_map(self, tree):
203
"""Get the (path, previous_path) pairs for the current tree."""
204
previous_intertree = InterTree.get(self.previous_tree, tree)
205
with tree.lock_read(), self.previous_tree.lock_read():
206
for path, ie in tree.iter_entries_by_dir():
207
if tree.supports_rename_tracking():
208
previous_path = previous_intertree.find_source_path(path)
210
if self.previous_tree.is_versioned(path):
215
kind = self.previous_tree.kind(previous_path)
216
if kind == 'directory':
219
yield (u"", previous_path)
221
yield (path + ie.kind_character(), previous_path)
224
def _strip_unreferenced_directories(entries):
225
"""Strip all directories that don't (in)directly contain any files.
227
:param entries: List of path strings or (path, previous_path) tuples to process
229
directory_used = set()
231
for (path, previous_path) in entries:
232
if not path or path[-1] == "/":
234
directories.append((path, previous_path))
236
# Yield the referenced parent directories
237
for direntry in directories:
238
if osutils.is_inside(direntry[0], path):
239
directory_used.add(direntry[0])
240
for (path, previous_path) in entries:
241
if (not path.endswith("/")) or path in directory_used:
242
yield (path, previous_path)
245
return 'HasPathRelations(%r, %r)' % (self.previous_tree, self.previous_entries)
247
def match(self, tree):
248
actual = list(self.get_path_map(tree))
249
if not tree.has_versioned_directories():
250
entries = list(self._strip_unreferenced_directories(
251
self.previous_entries))
253
entries = self.previous_entries
254
if not tree.supports_rename_tracking():
256
(path, path if self.previous_tree.is_versioned(path) else None)
257
for (path, previous_path) in entries]
258
return Equals(entries).match(actual)
261
188
class RevisionHistoryMatches(Matcher):
262
189
"""A matcher that checks if a branch has a specific revision history.