~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/matchers.py

Abbreviate pack_stat struct format to '>6L'

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
"""
28
28
 
29
29
__all__ = [
 
30
    'HasLayout',
 
31
    'MatchesAncestry',
30
32
    'ReturnsUnlockable',
31
33
    ]
32
34
 
33
 
from testtools.matchers import Mismatch, Matcher
 
35
from bzrlib import (
 
36
    osutils,
 
37
    revision as _mod_revision,
 
38
    )
 
39
 
 
40
from testtools.matchers import Equals, Mismatch, Matcher
34
41
 
35
42
 
36
43
class ReturnsUnlockable(Matcher):
48
55
        self.lockable_thing = lockable_thing
49
56
 
50
57
    def __str__(self):
51
 
        return ('ReturnsUnlockable(lockable_thing=%s)' % 
 
58
        return ('ReturnsUnlockable(lockable_thing=%s)' %
52
59
            self.lockable_thing)
53
60
 
54
61
    def match(self, lock_method):
66
73
 
67
74
    def describe(self):
68
75
        return "%s is locked" % self.lockable_thing
 
76
 
 
77
 
 
78
class _AncestryMismatch(Mismatch):
 
79
    """Ancestry matching mismatch."""
 
80
 
 
81
    def __init__(self, tip_revision, got, expected):
 
82
        self.tip_revision = tip_revision
 
83
        self.got = got
 
84
        self.expected = expected
 
85
 
 
86
    def describe(self):
 
87
        return "mismatched ancestry for revision %r was %r, expected %r" % (
 
88
            self.tip_revision, self.got, self.expected)
 
89
 
 
90
 
 
91
class MatchesAncestry(Matcher):
 
92
    """A matcher that checks the ancestry of a particular revision.
 
93
 
 
94
    :ivar graph: Graph in which to check the ancestry
 
95
    :ivar revision_id: Revision id of the revision
 
96
    """
 
97
 
 
98
    def __init__(self, repository, revision_id):
 
99
        Matcher.__init__(self)
 
100
        self.repository = repository
 
101
        self.revision_id = revision_id
 
102
 
 
103
    def __str__(self):
 
104
        return ('MatchesAncestry(repository=%r, revision_id=%r)' % (
 
105
            self.repository, self.revision_id))
 
106
 
 
107
    def match(self, expected):
 
108
        self.repository.lock_read()
 
109
        try:
 
110
            graph = self.repository.get_graph()
 
111
            got = [r for r, p in graph.iter_ancestry([self.revision_id])]
 
112
            if _mod_revision.NULL_REVISION in got:
 
113
                got.remove(_mod_revision.NULL_REVISION)
 
114
        finally:
 
115
            self.repository.unlock()
 
116
        if sorted(got) != sorted(expected):
 
117
            return _AncestryMismatch(self.revision_id, sorted(got),
 
118
                sorted(expected))
 
119
 
 
120
 
 
121
class HasLayout(Matcher):
 
122
    """A matcher that checks if a tree has a specific layout.
 
123
 
 
124
    :ivar entries: List of expected entries, as (path, file_id) pairs.
 
125
    """
 
126
 
 
127
    def __init__(self, entries):
 
128
        Matcher.__init__(self)
 
129
        self.entries = entries
 
130
 
 
131
    def get_tree_layout(self, tree):
 
132
        """Get the (path, file_id) pairs for the current tree."""
 
133
        tree.lock_read()
 
134
        try:
 
135
            for path, ie in tree.iter_entries_by_dir():
 
136
                if ie.parent_id is None:
 
137
                    yield (u"", ie.file_id)
 
138
                else:
 
139
                    yield (path+ie.kind_character(), ie.file_id)
 
140
        finally:
 
141
            tree.unlock()
 
142
 
 
143
    @staticmethod
 
144
    def _strip_unreferenced_directories(entries):
 
145
        """Strip all directories that don't (in)directly contain any files.
 
146
 
 
147
        :param entries: List of path strings or (path, ie) tuples to process
 
148
        """
 
149
        directories = []
 
150
        for entry in entries:
 
151
            if isinstance(entry, basestring):
 
152
                path = entry
 
153
            else:
 
154
                path = entry[0]
 
155
            if not path or path[-1] == "/":
 
156
                # directory
 
157
                directories.append((path, entry))
 
158
            else:
 
159
                # Yield the referenced parent directories
 
160
                for dirpath, direntry in directories:
 
161
                    if osutils.is_inside(dirpath, path):
 
162
                        yield direntry
 
163
                directories = []
 
164
                yield entry
 
165
 
 
166
    def __str__(self):
 
167
        return 'HasLayout(%r)' % self.entries
 
168
 
 
169
    def match(self, tree):
 
170
        actual = list(self.get_tree_layout(tree))
 
171
        if self.entries and isinstance(self.entries[0], basestring):
 
172
            actual = [path for (path, fileid) in actual]
 
173
        if not tree.has_versioned_directories():
 
174
            entries = list(self._strip_unreferenced_directories(self.entries))
 
175
        else:
 
176
            entries = self.entries
 
177
        return Equals(entries).match(actual)