~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_repository/test_fileid_involved.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
import sys
18
 
 
19
 
from bzrlib import (
20
 
    errors,
21
 
    tests,
22
 
    transform,
23
 
    )
24
 
from bzrlib.tests import per_repository
25
 
 
26
 
 
27
 
class FileIdInvolvedBase(per_repository.TestCaseWithRepository):
28
 
 
29
 
    def touch(self, tree, filename):
30
 
        # use the trees transport to not depend on the tree's location or type.
31
 
        tree.bzrdir.root_transport.append_bytes(filename, "appended line\n")
32
 
 
33
 
    def compare_tree_fileids(self, branch, old_rev, new_rev):
34
 
        old_tree = self.branch.repository.revision_tree(old_rev)
35
 
        new_tree = self.branch.repository.revision_tree(new_rev)
36
 
        delta = new_tree.changes_from(old_tree)
37
 
 
38
 
        l2 = [id for path, id, kind in delta.added] + \
39
 
             [id for oldpath, newpath, id, kind, text_modified, \
40
 
                meta_modified in delta.renamed] + \
41
 
             [id for path, id, kind, text_modified, meta_modified in \
42
 
                delta.modified]
43
 
        return set(l2)
44
 
 
45
 
 
46
 
class TestFileIdInvolved(FileIdInvolvedBase):
47
 
 
48
 
    def setUp(self):
49
 
        super(TestFileIdInvolved, self).setUp()
50
 
        # create three branches, and merge it
51
 
        #
52
 
        #          ,-->J------>K                (branch2)
53
 
        #         /             \
54
 
        #  A --->B --->C---->D-->G              (main)
55
 
        #  \          /     /
56
 
        #   '--->E---+---->F                    (branch1)
57
 
 
58
 
        # A changes:
59
 
        # B changes: 'a-file-id-2006-01-01-abcd'
60
 
        # C changes:  Nothing (perfect merge)
61
 
        # D changes: 'b-file-id-2006-01-01-defg'
62
 
        # E changes: 'file-d'
63
 
        # F changes: 'file-d'
64
 
        # G changes: 'b-file-id-2006-01-01-defg'
65
 
        # J changes: 'b-file-id-2006-01-01-defg'
66
 
        # K changes: 'c-funky<file-id>quiji%bo'
67
 
 
68
 
        main_wt = self.make_branch_and_tree('main')
69
 
        main_branch = main_wt.branch
70
 
        self.build_tree(["main/a","main/b","main/c"])
71
 
 
72
 
        main_wt.add(['a', 'b', 'c'], ['a-file-id-2006-01-01-abcd',
73
 
                                 'b-file-id-2006-01-01-defg',
74
 
                                 'c-funky<file-id>quiji%bo'])
75
 
        try:
76
 
            main_wt.commit("Commit one", rev_id="rev-A")
77
 
        except errors.IllegalPath:
78
 
            # TODO: jam 20060701 Consider raising a different exception
79
 
            #       newer formats do support this, and nothin can done to
80
 
            #       correct this test - its not a bug.
81
 
            if sys.platform == 'win32':
82
 
                raise tests.TestSkipped('Old repository formats do not'
83
 
                                        ' support file ids with <> on win32')
84
 
            # This is not a known error condition
85
 
            raise
86
 
 
87
 
        #-------- end A -----------
88
 
 
89
 
        bt1 = self.make_branch_and_tree('branch1')
90
 
        bt1.pull(main_branch)
91
 
        b1 = bt1.branch
92
 
        self.build_tree(["branch1/d"])
93
 
        bt1.add(['d'], ['file-d'])
94
 
        bt1.commit("branch1, Commit one", rev_id="rev-E")
95
 
 
96
 
        #-------- end E -----------
97
 
 
98
 
        self.touch(main_wt, "a")
99
 
        main_wt.commit("Commit two", rev_id="rev-B")
100
 
 
101
 
        #-------- end B -----------
102
 
 
103
 
        bt2 = self.make_branch_and_tree('branch2')
104
 
        bt2.pull(main_branch)
105
 
        branch2_branch = bt2.branch
106
 
        set_executability(bt2, 'b', True)
107
 
        bt2.commit("branch2, Commit one", rev_id="rev-J")
108
 
 
109
 
        #-------- end J -----------
110
 
 
111
 
        main_wt.merge_from_branch(b1)
112
 
        main_wt.commit("merge branch1, rev-11", rev_id="rev-C")
113
 
 
114
 
        #-------- end C -----------
115
 
 
116
 
        bt1.rename_one("d","e")
117
 
        bt1.commit("branch1, commit two", rev_id="rev-F")
118
 
 
119
 
        #-------- end F -----------
120
 
 
121
 
        self.touch(bt2, "c")
122
 
        bt2.commit("branch2, commit two", rev_id="rev-K")
123
 
 
124
 
        #-------- end K -----------
125
 
 
126
 
        main_wt.merge_from_branch(b1)
127
 
        self.touch(main_wt, "b")
128
 
        # D gets some funky characters to make sure the unescaping works
129
 
        main_wt.commit("merge branch1, rev-12", rev_id="rev-<D>")
130
 
 
131
 
        # end D
132
 
 
133
 
        main_wt.merge_from_branch(branch2_branch)
134
 
        main_wt.commit("merge branch1, rev-22",  rev_id="rev-G")
135
 
 
136
 
        # end G
137
 
        self.branch = main_branch
138
 
 
139
 
    def test_fileids_altered_between_two_revs(self):
140
 
        self.branch.lock_read()
141
 
        self.addCleanup(self.branch.unlock)
142
 
        self.branch.repository.fileids_altered_by_revision_ids(["rev-J","rev-K"])
143
 
        self.assertEqual(
144
 
            {'b-file-id-2006-01-01-defg':set(['rev-J']),
145
 
             'c-funky<file-id>quiji%bo':set(['rev-K'])
146
 
             },
147
 
            self.branch.repository.fileids_altered_by_revision_ids(["rev-J","rev-K"]))
148
 
 
149
 
        self.assertEqual(
150
 
            {'b-file-id-2006-01-01-defg': set(['rev-<D>']),
151
 
             'file-d': set(['rev-F']),
152
 
             },
153
 
            self.branch.repository.fileids_altered_by_revision_ids(['rev-<D>', 'rev-F']))
154
 
 
155
 
        self.assertEqual(
156
 
            {
157
 
             'b-file-id-2006-01-01-defg': set(['rev-<D>', 'rev-G', 'rev-J']),
158
 
             'c-funky<file-id>quiji%bo': set(['rev-K']),
159
 
             'file-d': set(['rev-F']),
160
 
             },
161
 
            self.branch.repository.fileids_altered_by_revision_ids(
162
 
                ['rev-<D>', 'rev-G', 'rev-F', 'rev-K', 'rev-J']))
163
 
 
164
 
        self.assertEqual(
165
 
            {'a-file-id-2006-01-01-abcd': set(['rev-B']),
166
 
             'b-file-id-2006-01-01-defg': set(['rev-<D>', 'rev-G', 'rev-J']),
167
 
             'c-funky<file-id>quiji%bo': set(['rev-K']),
168
 
             'file-d': set(['rev-F']),
169
 
             },
170
 
            self.branch.repository.fileids_altered_by_revision_ids(
171
 
                ['rev-G', 'rev-F', 'rev-C', 'rev-B', 'rev-<D>', 'rev-K', 'rev-J']))
172
 
 
173
 
    def fileids_altered_by_revision_ids(self, revision_ids):
174
 
        """This is a wrapper to strip TREE_ROOT if it occurs"""
175
 
        repo = self.branch.repository
176
 
        root_id = self.branch.basis_tree().get_root_id()
177
 
        result = repo.fileids_altered_by_revision_ids(revision_ids)
178
 
        if root_id in result:
179
 
            del result[root_id]
180
 
        return result
181
 
 
182
 
    def test_fileids_altered_by_revision_ids(self):
183
 
        self.branch.lock_read()
184
 
        self.addCleanup(self.branch.unlock)
185
 
        self.assertEqual(
186
 
            {'a-file-id-2006-01-01-abcd':set(['rev-A']),
187
 
             'b-file-id-2006-01-01-defg': set(['rev-A']),
188
 
             'c-funky<file-id>quiji%bo': set(['rev-A']),
189
 
             },
190
 
            self.fileids_altered_by_revision_ids(["rev-A"]))
191
 
        self.assertEqual(
192
 
            {'a-file-id-2006-01-01-abcd':set(['rev-B'])
193
 
             },
194
 
            self.branch.repository.fileids_altered_by_revision_ids(["rev-B"]))
195
 
        self.assertEqual(
196
 
            {'b-file-id-2006-01-01-defg':set(['rev-<D>'])
197
 
             },
198
 
            self.branch.repository.fileids_altered_by_revision_ids(["rev-<D>"]))
199
 
 
200
 
    def test_fileids_involved_full_compare(self):
201
 
        # this tests that the result of each fileid_involved calculation
202
 
        # along a revision history selects only the fileids selected by
203
 
        # comparing the trees - no less, and no more. This is correct
204
 
        # because in our sample data we do not revert any file ids along
205
 
        # the revision history.
206
 
        self.branch.lock_read()
207
 
        self.addCleanup(self.branch.unlock)
208
 
        pp=[]
209
 
        history = self.branch.revision_history( )
210
 
 
211
 
        if len(history) < 2: return
212
 
 
213
 
        graph = self.branch.repository.get_graph()
214
 
        for start in range(0,len(history)-1):
215
 
            start_id = history[start]
216
 
            for end in range(start+1,len(history)):
217
 
                end_id = history[end]
218
 
                unique_revs = graph.find_unique_ancestors(end_id, [start_id])
219
 
                l1 = self.branch.repository.fileids_altered_by_revision_ids(
220
 
                    unique_revs)
221
 
                l1 = set(l1.keys())
222
 
                l2 = self.compare_tree_fileids(self.branch, start_id, end_id)
223
 
                self.assertEquals(l1, l2)
224
 
 
225
 
 
226
 
class TestFileIdInvolvedNonAscii(FileIdInvolvedBase):
227
 
 
228
 
    def test_utf8_file_ids_and_revision_ids(self):
229
 
        main_wt = self.make_branch_and_tree('main')
230
 
        main_branch = main_wt.branch
231
 
        self.build_tree(["main/a"])
232
 
 
233
 
        file_id = u'a-f\xedle-id'.encode('utf8')
234
 
        main_wt.add(['a'], [file_id])
235
 
        revision_id = u'r\xe9v-a'.encode('utf8')
236
 
        try:
237
 
            main_wt.commit('a', rev_id=revision_id)
238
 
        except errors.NonAsciiRevisionId:
239
 
            raise tests.TestSkipped('non-ascii revision ids not supported by %s'
240
 
                                    % self.repository_format)
241
 
 
242
 
        repo = main_wt.branch.repository
243
 
        repo.lock_read()
244
 
        self.addCleanup(repo.unlock)
245
 
        file_ids = repo.fileids_altered_by_revision_ids([revision_id])
246
 
        root_id = main_wt.basis_tree().get_root_id()
247
 
        if root_id in file_ids:
248
 
            self.assertEqual({file_id:set([revision_id]),
249
 
                              root_id:set([revision_id])
250
 
                             }, file_ids)
251
 
        else:
252
 
            self.assertEqual({file_id:set([revision_id])}, file_ids)
253
 
 
254
 
 
255
 
class TestFileIdInvolvedSuperset(FileIdInvolvedBase):
256
 
 
257
 
    def setUp(self):
258
 
        super(TestFileIdInvolvedSuperset, self).setUp()
259
 
 
260
 
        self.branch = None
261
 
        main_wt = self.make_branch_and_tree('main')
262
 
        main_branch = main_wt.branch
263
 
        self.build_tree(["main/a","main/b","main/c"])
264
 
 
265
 
        main_wt.add(['a', 'b', 'c'], ['a-file-id-2006-01-01-abcd',
266
 
                                 'b-file-id-2006-01-01-defg',
267
 
                                 'c-funky<file-id>quiji\'"%bo'])
268
 
        try:
269
 
            main_wt.commit("Commit one", rev_id="rev-A")
270
 
        except errors.IllegalPath:
271
 
            # TODO: jam 20060701 Consider raising a different exception
272
 
            #       newer formats do support this, and nothin can done to
273
 
            #       correct this test - its not a bug.
274
 
            if sys.platform == 'win32':
275
 
                raise tests.TestSkipped('Old repository formats do not'
276
 
                                        ' support file ids with <> on win32')
277
 
            # This is not a known error condition
278
 
            raise
279
 
 
280
 
        branch2_wt = self.make_branch_and_tree('branch2')
281
 
        branch2_wt.pull(main_branch)
282
 
        branch2_bzrdir = branch2_wt.bzrdir
283
 
        branch2_branch = branch2_bzrdir.open_branch()
284
 
        set_executability(branch2_wt, 'b', True)
285
 
        branch2_wt.commit("branch2, Commit one", rev_id="rev-J")
286
 
 
287
 
        main_wt.merge_from_branch(branch2_branch)
288
 
        set_executability(main_wt, 'b', False)
289
 
        main_wt.commit("merge branch1, rev-22",  rev_id="rev-G")
290
 
 
291
 
        # end G
292
 
        self.branch = main_branch
293
 
 
294
 
    def test_fileid_involved_full_compare2(self):
295
 
        # this tests that fileids_altered_by_revision_ids returns
296
 
        # more information than compare_tree can, because it
297
 
        # sees each change rather than the aggregate delta.
298
 
        self.branch.lock_read()
299
 
        self.addCleanup(self.branch.unlock)
300
 
        history = self.branch.revision_history()
301
 
        old_rev = history[0]
302
 
        new_rev = history[1]
303
 
        graph = self.branch.repository.get_graph()
304
 
        unique_revs = graph.find_unique_ancestors(new_rev, [old_rev])
305
 
 
306
 
        l1 = self.branch.repository.fileids_altered_by_revision_ids(
307
 
            unique_revs)
308
 
        l1 = set(l1.keys())
309
 
 
310
 
        l2 = self.compare_tree_fileids(self.branch, old_rev, new_rev)
311
 
        self.assertNotEqual(l2, l1)
312
 
        self.assertSubset(l2, l1)
313
 
 
314
 
 
315
 
def set_executability(wt, path, executable=True):
316
 
    """Set the executable bit for the file at path in the working tree
317
 
 
318
 
    os.chmod() doesn't work on windows. But TreeTransform can mark or
319
 
    unmark a file as executable.
320
 
    """
321
 
    file_id = wt.path2id(path)
322
 
    tt = transform.TreeTransform(wt)
323
 
    try:
324
 
        tt.set_executability(executable, tt.trans_id_tree_file_id(file_id))
325
 
        tt.apply()
326
 
    finally:
327
 
        tt.finalize()