~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/matchers.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-05-11 11:47:36 UTC
  • mfrom: (5200.3.8 lock_return)
  • Revision ID: pqm@pqm.ubuntu.com-20100511114736-mc1sq9zyo3vufec7
(lifeless) Provide a consistent interface to Tree, Branch,
 Repository where lock methods return an object with an unlock method to
 unlock the lock. This breaks the API for Branch,
 Repository on their lock_write methods. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
"""
28
28
 
29
29
__all__ = [
30
 
    'HasLayout',
31
 
    'MatchesAncestry',
32
30
    'ReturnsUnlockable',
33
31
    ]
34
32
 
35
 
from bzrlib import (
36
 
    osutils,
37
 
    revision as _mod_revision,
38
 
    )
39
 
 
40
 
from testtools.matchers import Equals, Mismatch, Matcher
 
33
from testtools.matchers import Mismatch, Matcher
41
34
 
42
35
 
43
36
class ReturnsUnlockable(Matcher):
55
48
        self.lockable_thing = lockable_thing
56
49
 
57
50
    def __str__(self):
58
 
        return ('ReturnsUnlockable(lockable_thing=%s)' %
 
51
        return ('ReturnsUnlockable(lockable_thing=%s)' % 
59
52
            self.lockable_thing)
60
53
 
61
54
    def match(self, lock_method):
73
66
 
74
67
    def describe(self):
75
68
        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)