127
127
mtree.add_dir("b", "grandparent/parent")
128
128
mtree.add_file("c", "grandparent/parent/file", "Hello\n")
129
129
mtree.add_dir("d", "grandparent/alt_parent")
130
return ChangesetTree(mtree, ''), mtree
130
return BundleTree(mtree, ''), mtree
132
132
def test_renames(self):
133
133
"""Ensure that file renames have the proper effect on children"""
134
ctree = self.make_tree_1()[0]
135
self.assertEqual(ctree.old_path("grandparent"), "grandparent")
136
self.assertEqual(ctree.old_path("grandparent/parent"), "grandparent/parent")
137
self.assertEqual(ctree.old_path("grandparent/parent/file"),
138
"grandparent/parent/file")
140
self.assertEqual(ctree.id2path("a"), "grandparent")
141
self.assertEqual(ctree.id2path("b"), "grandparent/parent")
142
self.assertEqual(ctree.id2path("c"), "grandparent/parent/file")
144
self.assertEqual(ctree.path2id("grandparent"), "a")
145
self.assertEqual(ctree.path2id("grandparent/parent"), "b")
146
self.assertEqual(ctree.path2id("grandparent/parent/file"), "c")
148
assert ctree.path2id("grandparent2") is None
149
assert ctree.path2id("grandparent2/parent") is None
150
assert ctree.path2id("grandparent2/parent/file") is None
152
ctree.note_rename("grandparent", "grandparent2")
153
assert ctree.old_path("grandparent") is None
154
assert ctree.old_path("grandparent/parent") is None
155
assert ctree.old_path("grandparent/parent/file") is None
157
self.assertEqual(ctree.id2path("a"), "grandparent2")
158
self.assertEqual(ctree.id2path("b"), "grandparent2/parent")
159
self.assertEqual(ctree.id2path("c"), "grandparent2/parent/file")
161
self.assertEqual(ctree.path2id("grandparent2"), "a")
162
self.assertEqual(ctree.path2id("grandparent2/parent"), "b")
163
self.assertEqual(ctree.path2id("grandparent2/parent/file"), "c")
165
assert ctree.path2id("grandparent") is None
166
assert ctree.path2id("grandparent/parent") is None
167
assert ctree.path2id("grandparent/parent/file") is None
169
ctree.note_rename("grandparent/parent", "grandparent2/parent2")
170
self.assertEqual(ctree.id2path("a"), "grandparent2")
171
self.assertEqual(ctree.id2path("b"), "grandparent2/parent2")
172
self.assertEqual(ctree.id2path("c"), "grandparent2/parent2/file")
174
self.assertEqual(ctree.path2id("grandparent2"), "a")
175
self.assertEqual(ctree.path2id("grandparent2/parent2"), "b")
176
self.assertEqual(ctree.path2id("grandparent2/parent2/file"), "c")
178
assert ctree.path2id("grandparent2/parent") is None
179
assert ctree.path2id("grandparent2/parent/file") is None
181
ctree.note_rename("grandparent/parent/file",
134
btree = self.make_tree_1()[0]
135
self.assertEqual(btree.old_path("grandparent"), "grandparent")
136
self.assertEqual(btree.old_path("grandparent/parent"),
137
"grandparent/parent")
138
self.assertEqual(btree.old_path("grandparent/parent/file"),
139
"grandparent/parent/file")
141
self.assertEqual(btree.id2path("a"), "grandparent")
142
self.assertEqual(btree.id2path("b"), "grandparent/parent")
143
self.assertEqual(btree.id2path("c"), "grandparent/parent/file")
145
self.assertEqual(btree.path2id("grandparent"), "a")
146
self.assertEqual(btree.path2id("grandparent/parent"), "b")
147
self.assertEqual(btree.path2id("grandparent/parent/file"), "c")
149
assert btree.path2id("grandparent2") is None
150
assert btree.path2id("grandparent2/parent") is None
151
assert btree.path2id("grandparent2/parent/file") is None
153
btree.note_rename("grandparent", "grandparent2")
154
assert btree.old_path("grandparent") is None
155
assert btree.old_path("grandparent/parent") is None
156
assert btree.old_path("grandparent/parent/file") is None
158
self.assertEqual(btree.id2path("a"), "grandparent2")
159
self.assertEqual(btree.id2path("b"), "grandparent2/parent")
160
self.assertEqual(btree.id2path("c"), "grandparent2/parent/file")
162
self.assertEqual(btree.path2id("grandparent2"), "a")
163
self.assertEqual(btree.path2id("grandparent2/parent"), "b")
164
self.assertEqual(btree.path2id("grandparent2/parent/file"), "c")
166
assert btree.path2id("grandparent") is None
167
assert btree.path2id("grandparent/parent") is None
168
assert btree.path2id("grandparent/parent/file") is None
170
btree.note_rename("grandparent/parent", "grandparent2/parent2")
171
self.assertEqual(btree.id2path("a"), "grandparent2")
172
self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
173
self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file")
175
self.assertEqual(btree.path2id("grandparent2"), "a")
176
self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
177
self.assertEqual(btree.path2id("grandparent2/parent2/file"), "c")
179
assert btree.path2id("grandparent2/parent") is None
180
assert btree.path2id("grandparent2/parent/file") is None
182
btree.note_rename("grandparent/parent/file",
182
183
"grandparent2/parent2/file2")
183
self.assertEqual(ctree.id2path("a"), "grandparent2")
184
self.assertEqual(ctree.id2path("b"), "grandparent2/parent2")
185
self.assertEqual(ctree.id2path("c"), "grandparent2/parent2/file2")
187
self.assertEqual(ctree.path2id("grandparent2"), "a")
188
self.assertEqual(ctree.path2id("grandparent2/parent2"), "b")
189
self.assertEqual(ctree.path2id("grandparent2/parent2/file2"), "c")
191
assert ctree.path2id("grandparent2/parent2/file") is None
184
self.assertEqual(btree.id2path("a"), "grandparent2")
185
self.assertEqual(btree.id2path("b"), "grandparent2/parent2")
186
self.assertEqual(btree.id2path("c"), "grandparent2/parent2/file2")
188
self.assertEqual(btree.path2id("grandparent2"), "a")
189
self.assertEqual(btree.path2id("grandparent2/parent2"), "b")
190
self.assertEqual(btree.path2id("grandparent2/parent2/file2"), "c")
192
assert btree.path2id("grandparent2/parent2/file") is None
193
194
def test_moves(self):
194
195
"""Ensure that file moves have the proper effect on children"""
195
ctree = self.make_tree_1()[0]
196
ctree.note_rename("grandparent/parent/file",
196
btree = self.make_tree_1()[0]
197
btree.note_rename("grandparent/parent/file",
197
198
"grandparent/alt_parent/file")
198
self.assertEqual(ctree.id2path("c"), "grandparent/alt_parent/file")
199
self.assertEqual(ctree.path2id("grandparent/alt_parent/file"), "c")
200
assert ctree.path2id("grandparent/parent/file") is None
199
self.assertEqual(btree.id2path("c"), "grandparent/alt_parent/file")
200
self.assertEqual(btree.path2id("grandparent/alt_parent/file"), "c")
201
assert btree.path2id("grandparent/parent/file") is None
202
203
def unified_diff(self, old, new):
206
207
return out.read()
208
209
def make_tree_2(self):
209
ctree = self.make_tree_1()[0]
210
ctree.note_rename("grandparent/parent/file",
210
btree = self.make_tree_1()[0]
211
btree.note_rename("grandparent/parent/file",
211
212
"grandparent/alt_parent/file")
212
assert ctree.id2path("e") is None
213
assert ctree.path2id("grandparent/parent/file") is None
214
ctree.note_id("e", "grandparent/parent/file")
213
assert btree.id2path("e") is None
214
assert btree.path2id("grandparent/parent/file") is None
215
btree.note_id("e", "grandparent/parent/file")
217
218
def test_adds(self):
218
219
"""File/inventory adds"""
219
ctree = self.make_tree_2()
220
btree = self.make_tree_2()
220
221
add_patch = self.unified_diff([], ["Extra cheese\n"])
221
ctree.note_patch("grandparent/parent/file", add_patch)
222
ctree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
223
ctree.note_target('grandparent/parent/symlink', 'venus')
224
self.adds_test(ctree)
222
btree.note_patch("grandparent/parent/file", add_patch)
223
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
224
btree.note_target('grandparent/parent/symlink', 'venus')
225
self.adds_test(btree)
226
def adds_test(self, ctree):
227
self.assertEqual(ctree.id2path("e"), "grandparent/parent/file")
228
self.assertEqual(ctree.path2id("grandparent/parent/file"), "e")
229
self.assertEqual(ctree.get_file("e").read(), "Extra cheese\n")
230
self.assertEqual(ctree.get_symlink_target('f'), 'venus')
227
def adds_test(self, btree):
228
self.assertEqual(btree.id2path("e"), "grandparent/parent/file")
229
self.assertEqual(btree.path2id("grandparent/parent/file"), "e")
230
self.assertEqual(btree.get_file("e").read(), "Extra cheese\n")
231
self.assertEqual(btree.get_symlink_target('f'), 'venus')
232
233
def test_adds2(self):
233
234
"""File/inventory adds, with patch-compatibile renames"""
234
ctree = self.make_tree_2()
235
ctree.contents_by_id = False
235
btree = self.make_tree_2()
236
btree.contents_by_id = False
236
237
add_patch = self.unified_diff(["Hello\n"], ["Extra cheese\n"])
237
ctree.note_patch("grandparent/parent/file", add_patch)
238
ctree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
239
ctree.note_target('grandparent/parent/symlink', 'venus')
240
self.adds_test(ctree)
238
btree.note_patch("grandparent/parent/file", add_patch)
239
btree.note_id('f', 'grandparent/parent/symlink', kind='symlink')
240
btree.note_target('grandparent/parent/symlink', 'venus')
241
self.adds_test(btree)
242
243
def make_tree_3(self):
243
ctree, mtree = self.make_tree_1()
244
btree, mtree = self.make_tree_1()
244
245
mtree.add_file("e", "grandparent/parent/topping", "Anchovies\n")
245
ctree.note_rename("grandparent/parent/file",
246
btree.note_rename("grandparent/parent/file",
246
247
"grandparent/alt_parent/file")
247
ctree.note_rename("grandparent/parent/topping",
248
btree.note_rename("grandparent/parent/topping",
248
249
"grandparent/alt_parent/stopping")
251
def get_file_test(self, ctree):
252
self.assertEqual(ctree.get_file("e").read(), "Lemon\n")
253
self.assertEqual(ctree.get_file("c").read(), "Hello\n")
252
def get_file_test(self, btree):
253
self.assertEqual(btree.get_file("e").read(), "Lemon\n")
254
self.assertEqual(btree.get_file("c").read(), "Hello\n")
255
256
def test_get_file(self):
256
257
"""Get file contents"""
257
ctree = self.make_tree_3()
258
btree = self.make_tree_3()
258
259
mod_patch = self.unified_diff(["Anchovies\n"], ["Lemon\n"])
259
ctree.note_patch("grandparent/alt_parent/stopping", mod_patch)
260
self.get_file_test(ctree)
260
btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
261
self.get_file_test(btree)
262
263
def test_get_file2(self):
263
264
"""Get file contents, with patch-compatibile renames"""
264
ctree = self.make_tree_3()
265
ctree.contents_by_id = False
265
btree = self.make_tree_3()
266
btree.contents_by_id = False
266
267
mod_patch = self.unified_diff([], ["Lemon\n"])
267
ctree.note_patch("grandparent/alt_parent/stopping", mod_patch)
268
btree.note_patch("grandparent/alt_parent/stopping", mod_patch)
268
269
mod_patch = self.unified_diff([], ["Hello\n"])
269
ctree.note_patch("grandparent/alt_parent/file", mod_patch)
270
self.get_file_test(ctree)
270
btree.note_patch("grandparent/alt_parent/file", mod_patch)
271
self.get_file_test(btree)
272
273
def test_delete(self):
273
"Deletion by changeset"
274
ctree = self.make_tree_1()[0]
275
self.assertEqual(ctree.get_file("c").read(), "Hello\n")
276
ctree.note_deletion("grandparent/parent/file")
277
assert ctree.id2path("c") is None
278
assert ctree.path2id("grandparent/parent/file") is None
275
btree = self.make_tree_1()[0]
276
self.assertEqual(btree.get_file("c").read(), "Hello\n")
277
btree.note_deletion("grandparent/parent/file")
278
assert btree.id2path("c") is None
279
assert btree.path2id("grandparent/parent/file") is None
280
281
def sorted_ids(self, tree):
285
286
def test_iteration(self):
286
287
"""Ensure that iteration through ids works properly"""
287
ctree = self.make_tree_1()[0]
288
self.assertEqual(self.sorted_ids(ctree), ['a', 'b', 'c', 'd'])
289
ctree.note_deletion("grandparent/parent/file")
290
ctree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
291
ctree.note_last_changed("grandparent/alt_parent/fool",
288
btree = self.make_tree_1()[0]
289
self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'c', 'd'])
290
btree.note_deletion("grandparent/parent/file")
291
btree.note_id("e", "grandparent/alt_parent/fool", kind="directory")
292
btree.note_last_changed("grandparent/alt_parent/fool",
292
293
"revisionidiguess")
293
self.assertEqual(self.sorted_ids(ctree), ['a', 'b', 'd', 'e'])
294
self.assertEqual(self.sorted_ids(btree), ['a', 'b', 'd', 'e'])
296
297
class CSetTester(TestCaseInTempDir):
298
def get_valid_cset(self, base_rev_id, rev_id,
299
checkout_dir=None, message=None):
300
"""Create a changeset from base_rev_id -> rev_id in built-in branch.
299
def get_valid_bundle(self, base_rev_id, rev_id, checkout_dir=None,
301
"""Create a bundle from base_rev_id -> rev_id in built-in branch.
301
302
Make sure that the text generated is valid, and that it
302
303
can be applied against the base, and generate the same information.
304
:return: The in-memory changeset
305
:return: The in-memory bundle
306
307
from cStringIO import StringIO
308
cset_txt = StringIO()
309
rev_ids = write_changeset(self.b1.repository, rev_id, base_rev_id,
312
self.assertEqual(cset_txt.readline(), '# Bazaar changeset v0.7\n')
313
self.assertEqual(cset_txt.readline(), '#\n')
309
bundle_txt = StringIO()
310
rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id,
313
self.assertEqual(bundle_txt.readline(),
314
'# Bazaar revision bundle v0.7\n')
315
self.assertEqual(bundle_txt.readline(), '#\n')
315
317
rev = self.b1.repository.get_revision(rev_id)
316
self.assertEqual(cset_txt.readline().decode('utf-8'),
318
self.assertEqual(bundle_txt.readline().decode('utf-8'),
319
open(',,cset', 'wb').write(cset_txt.getvalue())
321
# This should also validate the generate changeset
322
cset = ChangesetReader(cset_txt)
323
for cset_rev in cset.info.real_revisions:
324
# These really should have already been checked in read_changeset
325
# since it computes the sha1 hash for the revision, which
326
# only will match if everything is okay, but lets be
328
branch_rev = self.b1.repository.get_revision(cset_rev.revision_id)
321
open(',,bundle', 'wb').write(bundle_txt.getvalue())
323
# This should also validate the generated bundle
324
bundle = BundleReader(bundle_txt)
325
repository = self.b1.repository
326
for bundle_rev in bundle.info.real_revisions:
327
# These really should have already been checked when we read the
328
# bundle, since it computes the sha1 hash for the revision, which
329
# only will match if everything is okay, but lets be explicit about
331
branch_rev = repository.get_revision(bundle_rev.revision_id)
329
332
for a in ('inventory_sha1', 'revision_id', 'parent_ids',
330
333
'timestamp', 'timezone', 'message', 'committer',
331
334
'parent_ids', 'properties'):
332
self.assertEqual(getattr(branch_rev, a), getattr(cset_rev, a))
333
self.assertEqual(len(branch_rev.parent_ids), len(cset_rev.parent_ids))
335
self.assertEqual(getattr(branch_rev, a),
336
getattr(bundle_rev, a))
337
self.assertEqual(len(branch_rev.parent_ids),
338
len(bundle_rev.parent_ids))
334
339
self.assertEqual(rev_ids,
335
[r.revision_id for r in cset.info.real_revisions])
336
self.valid_apply_changeset(base_rev_id, cset,
340
[r.revision_id for r in bundle.info.real_revisions])
341
self.valid_apply_bundle(base_rev_id, bundle,
337
342
checkout_dir=checkout_dir)
341
def get_invalid_cset(self, base_rev_id, rev_id):
342
"""Create a changeset from base_rev_id -> rev_id in built-in branch.
346
def get_invalid_bundle(self, base_rev_id, rev_id):
347
"""Create a bundle from base_rev_id -> rev_id in built-in branch.
343
348
Munge the text so that it's invalid.
345
:return: The in-memory changeset
350
:return: The in-memory bundle
347
352
from cStringIO import StringIO
349
cset_txt = StringIO()
350
rev_ids = write_changeset(self.b1.repository, rev_id, base_rev_id,
353
open(',,cset', 'wb').write(cset_txt.getvalue())
355
new_text = cset_txt.getvalue().replace('executable:no',
354
bundle_txt = StringIO()
355
rev_ids = write_bundle(self.b1.repository, rev_id, base_rev_id,
358
open(',,bundle', 'wb').write(bundle_txt.getvalue())
360
new_text = bundle_txt.getvalue().replace('executable:no',
356
361
'executable:yes')
357
cset_txt = StringIO(new_text)
358
cset = ChangesetReader(cset_txt)
359
self.valid_apply_changeset(base_rev_id, cset)
362
bundle_txt = StringIO(new_text)
363
bundle = BundleReader(bundle_txt)
364
self.valid_apply_bundle(base_rev_id, bundle)
362
367
def get_checkout(self, rev_id, checkout_dir=None):
363
368
"""Get a new tree, with the specified revision in it.
544
549
self.tree1.commit(u'i18n commit from William Dod\xe9',
545
550
rev_id='a@cset-0-6', committer=u'William Dod\xe9',
547
cset = self.get_valid_cset('a@cset-0-5', 'a@cset-0-6')
552
bundle = self.get_valid_bundle('a@cset-0-5', 'a@cset-0-6')
548
553
self.tree1.rename_one('sub/dir/WithCaps.txt', 'temp')
549
554
self.tree1.rename_one('with space.txt', 'WithCaps.txt')
550
555
self.tree1.rename_one('temp', 'with space.txt')
551
556
self.tree1.commit(u'swap filenames', rev_id='a@cset-0-7',
553
cset = self.get_valid_cset('a@cset-0-6', 'a@cset-0-7')
558
bundle = self.get_valid_bundle('a@cset-0-6', 'a@cset-0-7')
554
559
other = self.get_checkout('a@cset-0-6')
555
560
other.rename_one('sub/dir/nolastnewline.txt', 'sub/nolastnewline.txt')
556
561
other.commit('rename file', rev_id='a@cset-0-7b')
557
562
merge([other.basedir, -1], [None, None], this_dir=self.tree1.basedir)
558
563
self.tree1.commit(u'Merge', rev_id='a@cset-0-8',
560
cset = self.get_valid_cset('a@cset-0-7', 'a@cset-0-8')
565
bundle = self.get_valid_bundle('a@cset-0-7', 'a@cset-0-8')
562
def test_symlink_cset(self):
567
def test_symlink_bundle(self):
563
568
if not has_symlinks():
564
569
raise TestSkipped("No symlink support")
565
570
self.tree1 = BzrDir.create_standalone_workingtree('b1')
576
581
tt.create_symlink('mars', trans_id)
578
583
self.tree1.commit('rename and change symlink', rev_id='l@cset-0-2')
579
self.get_valid_cset('l@cset-0-1', 'l@cset-0-2')
584
self.get_valid_bundle('l@cset-0-1', 'l@cset-0-2')
580
585
tt = TreeTransform(self.tree1)
581
586
trans_id = tt.trans_id_tree_file_id('link-1')
582
587
tt.delete_contents(trans_id)
583
588
tt.create_symlink('jupiter', trans_id)
585
590
self.tree1.commit('just change symlink target', rev_id='l@cset-0-3')
586
self.get_valid_cset('l@cset-0-2', 'l@cset-0-3')
591
self.get_valid_bundle('l@cset-0-2', 'l@cset-0-3')
587
592
tt = TreeTransform(self.tree1)
588
593
trans_id = tt.trans_id_tree_file_id('link-1')
589
594
tt.delete_contents(trans_id)
591
596
self.tree1.commit('Delete symlink', rev_id='l@cset-0-4')
592
self.get_valid_cset('l@cset-0-3', 'l@cset-0-4')
597
self.get_valid_bundle('l@cset-0-3', 'l@cset-0-4')
594
def test_binary_cset(self):
599
def test_binary_bundle(self):
595
600
self.tree1 = BzrDir.create_standalone_workingtree('b1')
596
601
self.b1 = self.tree1.branch
597
602
tt = TreeTransform(self.tree1)