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.15
by John Arbash Meinel Allow setting the commit message. | 133 | def test_commit_message_default(self): | 
| 134 | builder = BranchBuilder(self.get_transport().clone('foo')) | |
| 135 | rev_id = builder.build_snapshot(None, None, | |
| 136 | [('add', (u'', None, 'directory', None))]) | |
| 137 | branch = builder.get_branch() | |
| 138 | rev = branch.repository.get_revision(rev_id) | |
| 139 | self.assertEqual(u'commit 1', rev.message) | |
| 140 | ||
| 141 | def test_commit_message_supplied(self): | |
| 142 | builder = BranchBuilder(self.get_transport().clone('foo')) | |
| 143 | rev_id = builder.build_snapshot(None, None, | |
| 144 | [('add', (u'', None, 'directory', None))], | |
| 145 | message=u'Foo') | |
| 146 | branch = builder.get_branch() | |
| 147 | rev = branch.repository.get_revision(rev_id) | |
| 148 | self.assertEqual(u'Foo', rev.message) | |
| 149 | ||
| 3567.4.3
by John Arbash Meinel Add an action for modifying an existing file | 150 | def test_modify_file(self): | 
| 151 | builder = self.build_a_rev() | |
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 152 | rev_id2 = builder.build_snapshot('B-id', None, | 
| 3567.4.3
by John Arbash Meinel Add an action for modifying an existing file | 153 | [('modify', ('a-id', 'new\ncontent\n'))]) | 
| 154 | self.assertEqual('B-id', rev_id2) | |
| 155 | branch = builder.get_branch() | |
| 156 | rev_tree = branch.repository.revision_tree(rev_id2) | |
| 157 | rev_tree.lock_read() | |
| 158 | self.addCleanup(rev_tree.unlock) | |
| 159 | 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. | 160 | |
| 161 | def test_delete_file(self): | |
| 162 | builder = self.build_a_rev() | |
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 163 | 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. | 164 | [('unversion', 'a-id')]) | 
| 165 | self.assertEqual('B-id', rev_id2) | |
| 166 | branch = builder.get_branch() | |
| 167 | rev_tree = branch.repository.revision_tree(rev_id2) | |
| 168 | rev_tree.lock_read() | |
| 169 | self.addCleanup(rev_tree.unlock) | |
| 170 | self.assertTreeShape([(u'', 'a-root-id', 'directory')], rev_tree) | |
| 171 | ||
| 3567.4.5
by John Arbash Meinel MemoryTree.add(directory) will now create a directory node in the Transport | 172 | def test_delete_directory(self): | 
| 173 | builder = self.build_a_rev() | |
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 174 | 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 | 175 | [('add', ('b', 'b-id', 'directory', None)), | 
| 176 | ('add', ('b/c', 'c-id', 'file', 'foo\n')), | |
| 177 | ('add', ('b/d', 'd-id', 'directory', None)), | |
| 178 | ('add', ('b/d/e', 'e-id', 'file', 'eff\n')), | |
| 179 |             ])
 | |
| 180 | rev_tree = builder.get_branch().repository.revision_tree('B-id') | |
| 181 | self.assertTreeShape([(u'', 'a-root-id', 'directory'), | |
| 182 | (u'a', 'a-id', 'file'), | |
| 183 | (u'b', 'b-id', 'directory'), | |
| 184 | (u'b/c', 'c-id', 'file'), | |
| 185 | (u'b/d', 'd-id', 'directory'), | |
| 186 | (u'b/d/e', 'e-id', 'file')], rev_tree) | |
| 3567.4.6
by John Arbash Meinel unversioning a directory is recursive. | 187 |         # Removing a directory removes all child dirs
 | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 188 | builder.build_snapshot('C-id', None, [('unversion', 'b-id')]) | 
| 3567.4.6
by John Arbash Meinel unversioning a directory is recursive. | 189 | rev_tree = builder.get_branch().repository.revision_tree('C-id') | 
| 190 | self.assertTreeShape([(u'', 'a-root-id', 'directory'), | |
| 191 | (u'a', 'a-id', 'file'), | |
| 192 | ], rev_tree) | |
| 3567.4.5
by John Arbash Meinel MemoryTree.add(directory) will now create a directory node in the Transport | 193 | |
| 3567.4.4
by John Arbash Meinel Add the ability to 'unversion' files, and handle unknown actions. | 194 | def test_unknown_action(self): | 
| 195 | builder = self.build_a_rev() | |
| 3567.4.18
by John Arbash Meinel Apply the review changes from Martin to the exact patch he approved. | 196 | e = self.assertRaises(ValueError, | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 197 | builder.build_snapshot, 'B-id', None, [('weirdo', ('foo',))]) | 
| 3567.4.18
by John Arbash Meinel Apply the review changes from Martin to the exact patch he approved. | 198 | self.assertEqual('Unknown build action: "weirdo"', str(e)) | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 199 | |
| 200 |     # TODO: rename a file/directory, but rename isn't supported by the
 | |
| 201 |     #       MemoryTree api yet, so for now we wait until it is used
 | |
| 202 | ||
| 203 | def test_set_parent(self): | |
| 204 | builder = self.build_a_rev() | |
| 3567.4.17
by John Arbash Meinel Add the ability to define a series of commits, which allows us to hold open the locks. | 205 | builder.start_series() | 
| 206 | self.addCleanup(builder.finish_series) | |
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 207 | builder.build_snapshot('B-id', ['A-id'], | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 208 | [('modify', ('a-id', 'new\ncontent\n'))]) | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 209 | builder.build_snapshot('C-id', ['A-id'], | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 210 | [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))]) | 
| 211 |         # We should now have a graph:
 | |
| 212 |         #   A
 | |
| 213 |         #   |\
 | |
| 214 |         #   C B
 | |
| 215 |         # And not A => B => C
 | |
| 216 | repo = builder.get_branch().repository | |
| 217 | self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',)}, | |
| 218 | repo.get_parent_map(['B-id', 'C-id'])) | |
| 219 | b_tree = repo.revision_tree('B-id') | |
| 220 | self.assertTreeShape([(u'', 'a-root-id', 'directory'), | |
| 221 | (u'a', 'a-id', 'file'), | |
| 222 | ], b_tree) | |
| 223 | self.assertEqual('new\ncontent\n', b_tree.get_file_text('a-id')) | |
| 224 | ||
| 225 |         # We should still be using the content from A in C, not from B
 | |
| 226 | c_tree = repo.revision_tree('C-id') | |
| 227 | self.assertTreeShape([(u'', 'a-root-id', 'directory'), | |
| 228 | (u'a', 'a-id', 'file'), | |
| 229 | (u'c', 'c-id', 'file'), | |
| 230 | ], c_tree) | |
| 231 | self.assertEqual('contents', c_tree.get_file_text('a-id')) | |
| 232 | self.assertEqual('alt\ncontent\n', c_tree.get_file_text('c-id')) | |
| 233 | ||
| 234 | def test_set_merge_parent(self): | |
| 235 | builder = self.build_a_rev() | |
| 3567.4.17
by John Arbash Meinel Add the ability to define a series of commits, which allows us to hold open the locks. | 236 | builder.start_series() | 
| 237 | self.addCleanup(builder.finish_series) | |
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 238 | builder.build_snapshot('B-id', ['A-id'], | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 239 | [('add', ('b', 'b-id', 'file', 'b\ncontent\n'))]) | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 240 | builder.build_snapshot('C-id', ['A-id'], | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 241 | [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))]) | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 242 | 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. | 243 | repo = builder.get_branch().repository | 
| 244 | self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',), | |
| 245 | 'D-id': ('B-id', 'C-id')}, | |
| 246 | repo.get_parent_map(['B-id', 'C-id', 'D-id'])) | |
| 247 | d_tree = repo.revision_tree('D-id') | |
| 248 |         # Note: by default a merge node does *not* pull in the changes from the
 | |
| 249 |         #       merged tree, you have to supply it yourself.
 | |
| 250 | self.assertTreeShape([(u'', 'a-root-id', 'directory'), | |
| 251 | (u'a', 'a-id', 'file'), | |
| 252 | (u'b', 'b-id', 'file'), | |
| 253 | ], d_tree) | |
| 254 | ||
| 255 | def test_set_merge_parent_and_contents(self): | |
| 256 | builder = self.build_a_rev() | |
| 3567.4.17
by John Arbash Meinel Add the ability to define a series of commits, which allows us to hold open the locks. | 257 | builder.start_series() | 
| 258 | self.addCleanup(builder.finish_series) | |
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 259 | builder.build_snapshot('B-id', ['A-id'], | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 260 | [('add', ('b', 'b-id', 'file', 'b\ncontent\n'))]) | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 261 | builder.build_snapshot('C-id', ['A-id'], | 
| 3567.4.8
by John Arbash Meinel Add the ability to force a basis for a revision. | 262 | [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))]) | 
| 3567.4.10
by John Arbash Meinel Clean up the build_snapshot api a bit. | 263 | 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. | 264 | [('add', ('c', 'c-id', 'file', 'alt\ncontent\n'))]) | 
| 265 | repo = builder.get_branch().repository | |
| 266 | self.assertEqual({'B-id': ('A-id',), 'C-id': ('A-id',), | |
| 267 | 'D-id': ('B-id', 'C-id')}, | |
| 268 | repo.get_parent_map(['B-id', 'C-id', 'D-id'])) | |
| 269 | d_tree = repo.revision_tree('D-id') | |
| 270 | self.assertTreeShape([(u'', 'a-root-id', 'directory'), | |
| 271 | (u'a', 'a-id', 'file'), | |
| 272 | (u'b', 'b-id', 'file'), | |
| 273 | (u'c', 'c-id', 'file'), | |
| 274 | ], d_tree) | |
| 275 |         # Because we copied the exact text into *this* tree, the 'c' file
 | |
| 276 |         # should look like it was not modified in the merge
 | |
| 277 | self.assertEqual('C-id', d_tree.inventory['c-id'].revision) | |
| 3567.4.17
by John Arbash Meinel Add the ability to define a series of commits, which allows us to hold open the locks. | 278 | |
| 279 | def test_start_finish_series(self): | |
| 280 | builder = BranchBuilder(self.get_transport().clone('foo')) | |
| 281 | builder.start_series() | |
| 282 | try: | |
| 283 | self.assertIsNot(None, builder._tree) | |
| 284 | self.assertEqual('w', builder._tree._lock_mode) | |
| 285 | self.assertTrue(builder._branch.is_locked()) | |
| 286 | finally: | |
| 287 | builder.finish_series() | |
| 288 | self.assertIs(None, builder._tree) | |
| 289 | self.assertFalse(builder._branch.is_locked()) |