/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
1
# Copyright (C) 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for the BranchBuilder class."""
18
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
19
from bzrlib import (
20
    branch as _mod_branch,
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
21
    errors,
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
22
    revision as _mod_revision,
23
    tests,
24
    )
2466.7.3 by Robert Collins
Create bzrlib.branchbuilder.
25
from bzrlib.branchbuilder import BranchBuilder
26
27
28
class TestBranchBuilder(tests.TestCaseWithMemoryTransport):
29
    
30
    def test_create(self):
31
        """Test the constructor api."""
32
        builder = BranchBuilder(self.get_transport().clone('foo'))
33
        # we dont care if the branch has been built or not at this point.
2466.7.4 by Robert Collins
Add BranchBuilder.get_branch().
34
35
    def test_get_branch(self):
36
        """get_branch returns the created branch."""
37
        builder = BranchBuilder(self.get_transport().clone('foo'))
38
        branch = builder.get_branch()
39
        self.assertIsInstance(branch, _mod_branch.Branch)
40
        self.assertEqual(self.get_transport().clone('foo').base,
41
            branch.base)
42
        self.assertEqual(
43
            (0, _mod_revision.NULL_REVISION),
44
            branch.last_revision_info())
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
45
2466.7.10 by Robert Collins
Add a format parameter to BranchBuilder.
46
    def test_format(self):
47
        """Making a BranchBuilder with a format option sets the branch type."""
48
        builder = BranchBuilder(self.get_transport(), format='dirstate-tags')
49
        branch = builder.get_branch()
50
        self.assertIsInstance(branch, _mod_branch.BzrBranch6)
51
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
52
    def test_build_one_commit(self):
53
        """doing build_commit causes a commit to happen."""
54
        builder = BranchBuilder(self.get_transport().clone('foo'))
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
55
        rev_id = builder.build_commit()
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
56
        branch = builder.get_branch()
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
57
        self.assertEqual((1, rev_id), branch.last_revision_info())
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
58
        self.assertEqual(
59
            'commit 1',
60
            branch.repository.get_revision(branch.last_revision()).message)
61
62
    def test_build_two_commits(self):
63
        """The second commit has the right parents and message."""
64
        builder = BranchBuilder(self.get_transport().clone('foo'))
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
65
        rev_id1 = builder.build_commit()
66
        rev_id2 = builder.build_commit()
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
67
        branch = builder.get_branch()
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
68
        self.assertEqual((2, rev_id2), branch.last_revision_info())
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
69
        self.assertEqual(
70
            'commit 2',
71
            branch.repository.get_revision(branch.last_revision()).message)
72
        self.assertEqual(
2466.7.9 by Robert Collins
Return the commited revision id from BranchBuilder.build_commit to save later instrospection.
73
            [rev_id1],
2466.7.6 by Robert Collins
Add BranchBuilder.build_commit.
74
            branch.repository.get_revision(branch.last_revision()).parent_ids)
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
75
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
76
77
class TestBranchBuilderBuildSnapshot(tests.TestCaseWithMemoryTransport):
78
79
    def assertTreeShape(self, expected_shape, tree):
80
        """Check that the tree shape matches expectations."""
81
        tree.lock_read()
82
        try:
83
            entries = [(path, ie.file_id, ie.kind)
84
                       for path, ie in tree.iter_entries_by_dir()]
85
        finally:
86
            tree.unlock()
87
        self.assertEqual(expected_shape, entries)
88
89
    def build_a_rev(self):
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
90
        builder = BranchBuilder(self.get_transport().clone('foo'))
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
91
        rev_id1 = builder.build_snapshot('A-id', None,
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
92
            [('add', ('', 'a-root-id', 'directory', None)),
93
             ('add', ('a', 'a-id', 'file', 'contents'))])
94
        self.assertEqual('A-id', rev_id1)
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
95
        return builder
96
97
    def test_add_one_file(self):
98
        builder = self.build_a_rev()
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
99
        branch = builder.get_branch()
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
100
        self.assertEqual((1, 'A-id'), branch.last_revision_info())
101
        rev_tree = branch.repository.revision_tree('A-id')
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
102
        rev_tree.lock_read()
103
        self.addCleanup(rev_tree.unlock)
3567.4.2 by John Arbash Meinel
test that we can add more files into an existing build
104
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
105
                              (u'a', 'a-id', 'file')], rev_tree)
3567.4.1 by John Arbash Meinel
Initial work to have BranchBuilder allow us to do tree-shape work.
106
        self.assertEqual('contents', rev_tree.get_file_text('a-id'))
3567.4.2 by John Arbash Meinel
test that we can add more files into an existing build
107
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
108
    def test_add_second_file(self):
109
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
110
        rev_id2 = builder.build_snapshot('B-id', None,
3567.4.2 by John Arbash Meinel
test that we can add more files into an existing build
111
            [('add', ('b', 'b-id', 'file', 'content_b'))])
112
        self.assertEqual('B-id', rev_id2)
113
        branch = builder.get_branch()
114
        self.assertEqual((2, rev_id2), branch.last_revision_info())
115
        rev_tree = branch.repository.revision_tree(rev_id2)
116
        rev_tree.lock_read()
117
        self.addCleanup(rev_tree.unlock)
118
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
119
                              (u'a', 'a-id', 'file'),
120
                              (u'b', 'b-id', 'file')], rev_tree)
121
        self.assertEqual('content_b', rev_tree.get_file_text('b-id'))
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
122
3567.4.7 by John Arbash Meinel
Revert back to using MemoryTree.mkdir() rather than creating the directory during add().
123
    def test_add_empty_dir(self):
124
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
125
        rev_id2 = builder.build_snapshot('B-id', None,
3567.4.7 by John Arbash Meinel
Revert back to using MemoryTree.mkdir() rather than creating the directory during add().
126
            [('add', ('b', 'b-id', 'directory', None))])
127
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
128
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
129
                              (u'a', 'a-id', 'file'),
130
                              (u'b', 'b-id', 'directory'),
131
                             ], rev_tree)
132
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
133
    def test_modify_file(self):
134
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
135
        rev_id2 = builder.build_snapshot('B-id', None,
3567.4.3 by John Arbash Meinel
Add an action for modifying an existing file
136
            [('modify', ('a-id', 'new\ncontent\n'))])
137
        self.assertEqual('B-id', rev_id2)
138
        branch = builder.get_branch()
139
        rev_tree = branch.repository.revision_tree(rev_id2)
140
        rev_tree.lock_read()
141
        self.addCleanup(rev_tree.unlock)
142
        self.assertEqual('new\ncontent\n', rev_tree.get_file_text('a-id'))
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
143
144
    def test_delete_file(self):
145
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
146
        rev_id2 = builder.build_snapshot('B-id', None,
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
147
            [('unversion', 'a-id')])
148
        self.assertEqual('B-id', rev_id2)
149
        branch = builder.get_branch()
150
        rev_tree = branch.repository.revision_tree(rev_id2)
151
        rev_tree.lock_read()
152
        self.addCleanup(rev_tree.unlock)
153
        self.assertTreeShape([(u'', 'a-root-id', 'directory')], rev_tree)
154
3567.4.5 by John Arbash Meinel
MemoryTree.add(directory) will now create a directory node in the Transport
155
    def test_delete_directory(self):
156
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
157
        rev_id2 = builder.build_snapshot('B-id', None,
3567.4.5 by John Arbash Meinel
MemoryTree.add(directory) will now create a directory node in the Transport
158
            [('add', ('b', 'b-id', 'directory', None)),
159
             ('add', ('b/c', 'c-id', 'file', 'foo\n')),
160
             ('add', ('b/d', 'd-id', 'directory', None)),
161
             ('add', ('b/d/e', 'e-id', 'file', 'eff\n')),
162
            ])
163
        rev_tree = builder.get_branch().repository.revision_tree('B-id')
164
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
165
                              (u'a', 'a-id', 'file'),
166
                              (u'b', 'b-id', 'directory'),
167
                              (u'b/c', 'c-id', 'file'),
168
                              (u'b/d', 'd-id', 'directory'),
169
                              (u'b/d/e', 'e-id', 'file')], rev_tree)
3567.4.6 by John Arbash Meinel
unversioning a directory is recursive.
170
        # Removing a directory removes all child dirs
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
171
        builder.build_snapshot('C-id', None, [('unversion', 'b-id')])
3567.4.6 by John Arbash Meinel
unversioning a directory is recursive.
172
        rev_tree = builder.get_branch().repository.revision_tree('C-id')
173
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
174
                              (u'a', 'a-id', 'file'),
175
                             ], rev_tree)
3567.4.5 by John Arbash Meinel
MemoryTree.add(directory) will now create a directory node in the Transport
176
3567.4.4 by John Arbash Meinel
Add the ability to 'unversion' files, and handle unknown actions.
177
    def test_unknown_action(self):
178
        builder = self.build_a_rev()
179
        self.assertRaises(errors.UnknownBuildAction,
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
180
            builder.build_snapshot, 'B-id', None, [('weirdo', ('foo',))])
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
181
182
    # TODO: rename a file/directory, but rename isn't supported by the
183
    #       MemoryTree api yet, so for now we wait until it is used
184
185
    def test_set_parent(self):
186
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
187
        builder.build_snapshot('B-id', ['A-id'],
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
188
            [('modify', ('a-id', 'new\ncontent\n'))])
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
189
        builder.build_snapshot('C-id', ['A-id'], 
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
190
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
191
        # We should now have a graph:
192
        #   A
193
        #   |\
194
        #   C B
195
        # And not A => B => C
196
        repo = builder.get_branch().repository
197
        repo.lock_read()
198
        self.addCleanup(repo.unlock)
199
        self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',)},
200
                         repo.get_parent_map(['B-id', 'C-id']))
201
        b_tree = repo.revision_tree('B-id')
202
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
203
                              (u'a', 'a-id', 'file'),
204
                             ], b_tree)
205
        self.assertEqual('new\ncontent\n', b_tree.get_file_text('a-id'))
206
207
        # We should still be using the content from A in C, not from B
208
        c_tree = repo.revision_tree('C-id')
209
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
210
                              (u'a', 'a-id', 'file'),
211
                              (u'c', 'c-id', 'file'),
212
                             ], c_tree)
213
        self.assertEqual('contents', c_tree.get_file_text('a-id'))
214
        self.assertEqual('alt\ncontent\n', c_tree.get_file_text('c-id'))
215
216
    def test_set_merge_parent(self):
217
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
218
        builder.build_snapshot('B-id', ['A-id'],
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
219
            [('add', ('b', 'b-id', 'file', 'b\ncontent\n'))])
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
220
        builder.build_snapshot('C-id', ['A-id'],
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
221
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
222
        builder.build_snapshot('D-id', ['B-id', 'C-id'], [])
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
223
        repo = builder.get_branch().repository
224
        repo.lock_read()
225
        self.addCleanup(repo.unlock)
226
        self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',),
227
                          'D-id': ('B-id', 'C-id')},
228
                         repo.get_parent_map(['B-id', 'C-id', 'D-id']))
229
        d_tree = repo.revision_tree('D-id')
230
        # Note: by default a merge node does *not* pull in the changes from the
231
        #       merged tree, you have to supply it yourself.
232
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
233
                              (u'a', 'a-id', 'file'),
234
                              (u'b', 'b-id', 'file'),
235
                             ], d_tree)
236
237
    def test_set_merge_parent_and_contents(self):
238
        builder = self.build_a_rev()
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
239
        builder.build_snapshot('B-id', ['A-id'],
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
240
            [('add', ('b', 'b-id', 'file', 'b\ncontent\n'))])
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
241
        builder.build_snapshot('C-id', ['A-id'],
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
242
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
3567.4.10 by John Arbash Meinel
Clean up the build_snapshot api a bit.
243
        builder.build_snapshot('D-id', ['B-id', 'C-id'],
3567.4.8 by John Arbash Meinel
Add the ability to force a basis for a revision.
244
            [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))])
245
        repo = builder.get_branch().repository
246
        repo.lock_read()
247
        self.addCleanup(repo.unlock)
248
        self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',),
249
                          'D-id': ('B-id', 'C-id')},
250
                         repo.get_parent_map(['B-id', 'C-id', 'D-id']))
251
        d_tree = repo.revision_tree('D-id')
252
        self.assertTreeShape([(u'', 'a-root-id', 'directory'),
253
                              (u'a', 'a-id', 'file'),
254
                              (u'b', 'b-id', 'file'),
255
                              (u'c', 'c-id', 'file'),
256
                             ], d_tree)
257
        # Because we copied the exact text into *this* tree, the 'c' file
258
        # should look like it was not modified in the merge
259
        self.assertEqual('C-id', d_tree.inventory['c-id'].revision)