~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testinv.py

  • Committer: Martin Pool
  • Date: 2005-09-16 08:23:10 UTC
  • Revision ID: mbp@sourcefrog.net-20050916082310-ecb5a25c40253839
- wrap wide strings when showing exceptions

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
from cStringIO import StringIO
18
 
import os
 
17
from bzrlib.selftest import TestCase
19
18
 
20
 
from bzrlib.branch import Branch
21
 
import bzrlib.errors as errors
22
 
from bzrlib.diff import internal_diff
23
 
from bzrlib.inventory import (Inventory, ROOT_ID, InventoryFile,
24
 
    InventoryDirectory, InventoryEntry)
25
 
import bzrlib.inventory as inventory
26
 
from bzrlib.osutils import has_symlinks, rename, pathjoin
27
 
from bzrlib.tests import TestCase, TestCaseWithTransport
28
 
from bzrlib.transform import TreeTransform
29
 
from bzrlib.uncommit import uncommit
 
19
from bzrlib.inventory import Inventory, InventoryEntry
30
20
 
31
21
 
32
22
class TestInventory(TestCase):
33
23
 
34
24
    def test_is_within(self):
35
25
        from bzrlib.osutils import is_inside_any
36
 
 
37
 
        SRC_FOO_C = pathjoin('src', 'foo.c')
38
 
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
39
 
                         (['src'], SRC_FOO_C),
 
26
        
 
27
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
 
28
                         (['src'], 'src/foo.c'),
40
29
                         (['src'], 'src'),
41
30
                         ]:
42
31
            self.assert_(is_inside_any(dirs, fn))
61
50
        
62
51
        self.assert_('src-id' in inv)
63
52
 
 
53
 
64
54
    def test_version(self):
65
55
        """Inventory remembers the text's version."""
66
56
        inv = Inventory()
67
57
        ie = inv.add_path('foo.txt', 'file')
68
58
        ## XXX
69
59
 
70
 
 
71
 
class TestInventoryEntry(TestCase):
72
 
 
73
 
    def test_file_kind_character(self):
74
 
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
75
 
        self.assertEqual(file.kind_character(), '')
76
 
 
77
 
    def test_dir_kind_character(self):
78
 
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
79
 
        self.assertEqual(dir.kind_character(), '/')
80
 
 
81
 
    def test_link_kind_character(self):
82
 
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
83
 
        self.assertEqual(dir.kind_character(), '')
84
 
 
85
 
    def test_dir_detect_changes(self):
86
 
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
87
 
        left.text_sha1 = 123
88
 
        left.executable = True
89
 
        left.symlink_target='foo'
90
 
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
91
 
        right.text_sha1 = 321
92
 
        right.symlink_target='bar'
93
 
        self.assertEqual((False, False), left.detect_changes(right))
94
 
        self.assertEqual((False, False), right.detect_changes(left))
95
 
 
96
 
    def test_file_detect_changes(self):
97
 
        left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
98
 
        left.text_sha1 = 123
99
 
        right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
100
 
        right.text_sha1 = 123
101
 
        self.assertEqual((False, False), left.detect_changes(right))
102
 
        self.assertEqual((False, False), right.detect_changes(left))
103
 
        left.executable = True
104
 
        self.assertEqual((False, True), left.detect_changes(right))
105
 
        self.assertEqual((False, True), right.detect_changes(left))
106
 
        right.text_sha1 = 321
107
 
        self.assertEqual((True, True), left.detect_changes(right))
108
 
        self.assertEqual((True, True), right.detect_changes(left))
109
 
 
110
 
    def test_symlink_detect_changes(self):
111
 
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
112
 
        left.text_sha1 = 123
113
 
        left.executable = True
114
 
        left.symlink_target='foo'
115
 
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
116
 
        right.text_sha1 = 321
117
 
        right.symlink_target='foo'
118
 
        self.assertEqual((False, False), left.detect_changes(right))
119
 
        self.assertEqual((False, False), right.detect_changes(left))
120
 
        left.symlink_target = 'different'
121
 
        self.assertEqual((True, False), left.detect_changes(right))
122
 
        self.assertEqual((True, False), right.detect_changes(left))
123
 
 
124
 
    def test_file_has_text(self):
125
 
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
126
 
        self.failUnless(file.has_text())
127
 
 
128
 
    def test_directory_has_text(self):
129
 
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
130
 
        self.failIf(dir.has_text())
131
 
 
132
 
    def test_link_has_text(self):
133
 
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
134
 
        self.failIf(link.has_text())
135
 
 
136
 
    def test_make_entry(self):
137
 
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
138
 
            inventory.InventoryFile)
139
 
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
140
 
            inventory.InventoryLink)
141
 
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
142
 
            inventory.InventoryDirectory)
143
 
 
144
 
class TestEntryDiffing(TestCaseWithTransport):
145
 
 
146
 
    def setUp(self):
147
 
        super(TestEntryDiffing, self).setUp()
148
 
        self.wt = self.make_branch_and_tree('.')
149
 
        self.branch = self.wt.branch
150
 
        print >> open('file', 'wb'), 'foo'
151
 
        print >> open('binfile', 'wb'), 'foo'
152
 
        self.wt.add(['file'], ['fileid'])
153
 
        self.wt.add(['binfile'], ['binfileid'])
154
 
        if has_symlinks():
155
 
            os.symlink('target1', 'symlink')
156
 
            self.wt.add(['symlink'], ['linkid'])
157
 
        self.wt.commit('message_1', rev_id = '1')
158
 
        print >> open('file', 'wb'), 'bar'
159
 
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
160
 
        if has_symlinks():
161
 
            os.unlink('symlink')
162
 
            os.symlink('target2', 'symlink')
163
 
        self.tree_1 = self.branch.repository.revision_tree('1')
164
 
        self.inv_1 = self.branch.repository.get_inventory('1')
165
 
        self.file_1 = self.inv_1['fileid']
166
 
        self.file_1b = self.inv_1['binfileid']
167
 
        self.tree_2 = self.wt
168
 
        self.inv_2 = self.tree_2.read_working_inventory()
169
 
        self.file_2 = self.inv_2['fileid']
170
 
        self.file_2b = self.inv_2['binfileid']
171
 
        if has_symlinks():
172
 
            self.link_1 = self.inv_1['linkid']
173
 
            self.link_2 = self.inv_2['linkid']
174
 
 
175
 
    def test_file_diff_deleted(self):
176
 
        output = StringIO()
177
 
        self.file_1.diff(internal_diff, 
178
 
                          "old_label", self.tree_1,
179
 
                          "/dev/null", None, None,
180
 
                          output)
181
 
        self.assertEqual(output.getvalue(), "--- old_label\t\n"
182
 
                                            "+++ /dev/null\t\n"
183
 
                                            "@@ -1,1 +0,0 @@\n"
184
 
                                            "-foo\n"
185
 
                                            "\n")
186
 
 
187
 
    def test_file_diff_added(self):
188
 
        output = StringIO()
189
 
        self.file_1.diff(internal_diff, 
190
 
                          "new_label", self.tree_1,
191
 
                          "/dev/null", None, None,
192
 
                          output, reverse=True)
193
 
        self.assertEqual(output.getvalue(), "--- /dev/null\t\n"
194
 
                                            "+++ new_label\t\n"
195
 
                                            "@@ -0,0 +1,1 @@\n"
196
 
                                            "+foo\n"
197
 
                                            "\n")
198
 
 
199
 
    def test_file_diff_changed(self):
200
 
        output = StringIO()
201
 
        self.file_1.diff(internal_diff, 
202
 
                          "/dev/null", self.tree_1, 
203
 
                          "new_label", self.file_2, self.tree_2,
204
 
                          output)
205
 
        self.assertEqual(output.getvalue(), "--- /dev/null\t\n"
206
 
                                            "+++ new_label\t\n"
207
 
                                            "@@ -1,1 +1,1 @@\n"
208
 
                                            "-foo\n"
209
 
                                            "+bar\n"
210
 
                                            "\n")
211
 
        
212
 
    def test_file_diff_binary(self):
213
 
        output = StringIO()
214
 
        self.file_1.diff(internal_diff, 
215
 
                          "/dev/null", self.tree_1, 
216
 
                          "new_label", self.file_2b, self.tree_2,
217
 
                          output)
218
 
        self.assertEqual(output.getvalue(), 
219
 
                         "Binary files /dev/null and new_label differ\n")
220
 
    def test_link_diff_deleted(self):
221
 
        if not has_symlinks():
222
 
            return
223
 
        output = StringIO()
224
 
        self.link_1.diff(internal_diff, 
225
 
                          "old_label", self.tree_1,
226
 
                          "/dev/null", None, None,
227
 
                          output)
228
 
        self.assertEqual(output.getvalue(),
229
 
                         "=== target was 'target1'\n")
230
 
 
231
 
    def test_link_diff_added(self):
232
 
        if not has_symlinks():
233
 
            return
234
 
        output = StringIO()
235
 
        self.link_1.diff(internal_diff, 
236
 
                          "new_label", self.tree_1,
237
 
                          "/dev/null", None, None,
238
 
                          output, reverse=True)
239
 
        self.assertEqual(output.getvalue(),
240
 
                         "=== target is 'target1'\n")
241
 
 
242
 
    def test_link_diff_changed(self):
243
 
        if not has_symlinks():
244
 
            return
245
 
        output = StringIO()
246
 
        self.link_1.diff(internal_diff, 
247
 
                          "/dev/null", self.tree_1, 
248
 
                          "new_label", self.link_2, self.tree_2,
249
 
                          output)
250
 
        self.assertEqual(output.getvalue(),
251
 
                         "=== target changed 'target1' => 'target2'\n")
252
 
 
253
 
 
254
 
class TestSnapshot(TestCaseWithTransport):
255
 
 
256
 
    def setUp(self):
257
 
        # for full testing we'll need a branch
258
 
        # with a subdir to test parent changes.
259
 
        # and a file, link and dir under that.
260
 
        # but right now I only need one attribute
261
 
        # to change, and then test merge patterns
262
 
        # with fake parent entries.
263
 
        super(TestSnapshot, self).setUp()
264
 
        self.wt = self.make_branch_and_tree('.')
265
 
        self.branch = self.wt.branch
266
 
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
267
 
        self.wt.add(['subdir', 'subdir/file'],
268
 
                                       ['dirid', 'fileid'])
269
 
        if has_symlinks():
270
 
            pass
271
 
        self.wt.commit('message_1', rev_id = '1')
272
 
        self.tree_1 = self.branch.repository.revision_tree('1')
273
 
        self.inv_1 = self.branch.repository.get_inventory('1')
274
 
        self.file_1 = self.inv_1['fileid']
275
 
        self.file_active = self.wt.inventory['fileid']
276
 
 
277
 
    def test_snapshot_new_revision(self):
278
 
        # This tests that a simple commit with no parents makes a new
279
 
        # revision value in the inventory entry
280
 
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, 
281
 
                                  self.branch.repository.weave_store,
282
 
                                  self.branch.get_transaction())
283
 
        # expected outcome - file_1 has a revision id of '2', and we can get
284
 
        # its text of 'file contents' out of the weave.
285
 
        self.assertEqual(self.file_1.revision, '1')
286
 
        self.assertEqual(self.file_active.revision, '2')
287
 
        # this should be a separate test probably, but lets check it once..
288
 
        lines = self.branch.repository.weave_store.get_weave(
289
 
            'fileid', 
290
 
            self.branch.get_transaction()).get_lines('2')
291
 
        self.assertEqual(lines, ['contents of subdir/file\n'])
292
 
 
293
 
    def test_snapshot_unchanged(self):
294
 
        #This tests that a simple commit does not make a new entry for
295
 
        # an unchanged inventory entry
296
 
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
297
 
                                  self.wt, 
298
 
                                  self.branch.repository.weave_store,
299
 
                                  self.branch.get_transaction())
300
 
        self.assertEqual(self.file_1.revision, '1')
301
 
        self.assertEqual(self.file_active.revision, '1')
302
 
        vf = self.branch.repository.weave_store.get_weave(
303
 
            'fileid', 
304
 
            self.branch.repository.get_transaction())
305
 
        self.assertRaises(errors.RevisionNotPresent,
306
 
                          vf.get_lines,
307
 
                          '2')
308
 
 
309
 
    def test_snapshot_merge_identical_different_revid(self):
310
 
        # This tests that a commit with two identical parents, one of which has
311
 
        # a different revision id, results in a new revision id in the entry.
312
 
        # 1->other, commit a merge of other against 1, results in 2.
313
 
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
314
 
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
315
 
        other_ie.revision = '1'
316
 
        other_ie.text_sha1 = self.file_1.text_sha1
317
 
        other_ie.text_size = self.file_1.text_size
318
 
        self.assertEqual(self.file_1, other_ie)
319
 
        other_ie.revision = 'other'
320
 
        self.assertNotEqual(self.file_1, other_ie)
321
 
        versionfile = self.branch.repository.weave_store.get_weave(
322
 
            'fileid', self.branch.repository.get_transaction())
323
 
        versionfile.clone_text('other', '1', ['1'])
324
 
        self.file_active.snapshot('2', 'subdir/file', 
325
 
                                  {'1':self.file_1, 'other':other_ie},
326
 
                                  self.wt, 
327
 
                                  self.branch.repository.weave_store,
328
 
                                  self.branch.get_transaction())
329
 
        self.assertEqual(self.file_active.revision, '2')
330
 
 
331
 
    def test_snapshot_changed(self):
332
 
        # This tests that a commit with one different parent results in a new
333
 
        # revision id in the entry.
334
 
        self.file_active.name='newname'
335
 
        rename('subdir/file', 'subdir/newname')
336
 
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
337
 
                                  self.wt,
338
 
                                  self.branch.repository.weave_store,
339
 
                                  self.branch.get_transaction())
340
 
        # expected outcome - file_1 has a revision id of '2'
341
 
        self.assertEqual(self.file_active.revision, '2')
342
 
 
343
 
 
344
 
class TestPreviousHeads(TestCaseWithTransport):
345
 
 
346
 
    def setUp(self):
347
 
        # we want several inventories, that respectively
348
 
        # give use the following scenarios:
349
 
        # A) fileid not in any inventory (A),
350
 
        # B) fileid present in one inventory (B) and (A,B)
351
 
        # C) fileid present in two inventories, and they
352
 
        #   are not mutual descendents (B, C)
353
 
        # D) fileid present in two inventories and one is
354
 
        #   a descendent of the other. (B, D)
355
 
        super(TestPreviousHeads, self).setUp()
356
 
        self.wt = self.make_branch_and_tree('.')
357
 
        self.branch = self.wt.branch
358
 
        self.build_tree(['file'])
359
 
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
360
 
        self.inv_A = self.branch.repository.get_inventory('A')
361
 
        self.wt.add(['file'], ['fileid'])
362
 
        self.wt.commit('add file', rev_id='B')
363
 
        self.inv_B = self.branch.repository.get_inventory('B')
364
 
        uncommit(self.branch, tree=self.wt)
365
 
        self.assertEqual(self.branch.revision_history(), ['A'])
366
 
        self.wt.commit('another add of file', rev_id='C')
367
 
        self.inv_C = self.branch.repository.get_inventory('C')
368
 
        self.wt.add_pending_merge('B')
369
 
        self.wt.commit('merge in B', rev_id='D')
370
 
        self.inv_D = self.branch.repository.get_inventory('D')
371
 
        self.file_active = self.wt.inventory['fileid']
372
 
        self.weave = self.branch.repository.weave_store.get_weave('fileid',
373
 
            self.branch.repository.get_transaction())
374
 
        
375
 
    def get_previous_heads(self, inventories):
376
 
        return self.file_active.find_previous_heads(
377
 
            inventories, 
378
 
            self.branch.repository.weave_store,
379
 
            self.branch.repository.get_transaction())
380
 
        
381
 
    def test_fileid_in_no_inventory(self):
382
 
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
383
 
 
384
 
    def test_fileid_in_one_inventory(self):
385
 
        self.assertEqual({'B':self.inv_B['fileid']},
386
 
                         self.get_previous_heads([self.inv_B]))
387
 
        self.assertEqual({'B':self.inv_B['fileid']},
388
 
                         self.get_previous_heads([self.inv_A, self.inv_B]))
389
 
        self.assertEqual({'B':self.inv_B['fileid']},
390
 
                         self.get_previous_heads([self.inv_B, self.inv_A]))
391
 
 
392
 
    def test_fileid_in_two_inventories_gives_both_entries(self):
393
 
        self.assertEqual({'B':self.inv_B['fileid'],
394
 
                          'C':self.inv_C['fileid']},
395
 
                          self.get_previous_heads([self.inv_B, self.inv_C]))
396
 
        self.assertEqual({'B':self.inv_B['fileid'],
397
 
                          'C':self.inv_C['fileid']},
398
 
                          self.get_previous_heads([self.inv_C, self.inv_B]))
399
 
 
400
 
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
401
 
        self.assertEqual({'D':self.inv_D['fileid']},
402
 
                         self.get_previous_heads([self.inv_B, self.inv_D]))
403
 
        self.assertEqual({'D':self.inv_D['fileid']},
404
 
                         self.get_previous_heads([self.inv_D, self.inv_B]))
405
 
 
406
 
    # TODO: test two inventories with the same file revision 
407
 
 
408
 
 
409
 
class TestDescribeChanges(TestCase):
410
 
 
411
 
    def test_describe_change(self):
412
 
        # we need to test the following change combinations:
413
 
        # rename
414
 
        # reparent
415
 
        # modify
416
 
        # gone
417
 
        # added
418
 
        # renamed/reparented and modified
419
 
        # change kind (perhaps can't be done yet?)
420
 
        # also, merged in combination with all of these?
421
 
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
422
 
        old_a.text_sha1 = '123132'
423
 
        old_a.text_size = 0
424
 
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
425
 
        new_a.text_sha1 = '123132'
426
 
        new_a.text_size = 0
427
 
 
428
 
        self.assertChangeDescription('unchanged', old_a, new_a)
429
 
 
430
 
        new_a.text_size = 10
431
 
        new_a.text_sha1 = 'abcabc'
432
 
        self.assertChangeDescription('modified', old_a, new_a)
433
 
 
434
 
        self.assertChangeDescription('added', None, new_a)
435
 
        self.assertChangeDescription('removed', old_a, None)
436
 
        # perhaps a bit questionable but seems like the most reasonable thing...
437
 
        self.assertChangeDescription('unchanged', None, None)
438
 
 
439
 
        # in this case it's both renamed and modified; show a rename and 
440
 
        # modification:
441
 
        new_a.name = 'newfilename'
442
 
        self.assertChangeDescription('modified and renamed', old_a, new_a)
443
 
 
444
 
        # reparenting is 'renaming'
445
 
        new_a.name = old_a.name
446
 
        new_a.parent_id = 'somedir-id'
447
 
        self.assertChangeDescription('modified and renamed', old_a, new_a)
448
 
 
449
 
        # reset the content values so its not modified
450
 
        new_a.text_size = old_a.text_size
451
 
        new_a.text_sha1 = old_a.text_sha1
452
 
        new_a.name = old_a.name
453
 
 
454
 
        new_a.name = 'newfilename'
455
 
        self.assertChangeDescription('renamed', old_a, new_a)
456
 
 
457
 
        # reparenting is 'renaming'
458
 
        new_a.name = old_a.name
459
 
        new_a.parent_id = 'somedir-id'
460
 
        self.assertChangeDescription('renamed', old_a, new_a)
461
 
 
462
 
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
463
 
        change = InventoryEntry.describe_change(old_ie, new_ie)
464
 
        self.assertEqual(expected_change, change)
465
 
 
466
 
 
467
 
class TestExecutable(TestCaseWithTransport):
468
 
 
469
 
    def test_stays_executable(self):
470
 
        a_id = "a-20051208024829-849e76f7968d7a86"
471
 
        b_id = "b-20051208024829-849e76f7968d7a86"
472
 
        wt = self.make_branch_and_tree('b1')
473
 
        b = wt.branch
474
 
        tt = TreeTransform(wt)
475
 
        tt.new_file('a', tt.root, 'a test\n', a_id, True)
476
 
        tt.new_file('b', tt.root, 'b test\n', b_id, False)
477
 
        tt.apply()
478
 
 
479
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
480
 
 
481
 
        # reopen the tree and ensure it stuck.
482
 
        wt = wt.bzrdir.open_workingtree()
483
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
484
 
 
485
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
486
 
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
487
 
 
488
 
        wt.commit('adding a,b', rev_id='r1')
489
 
 
490
 
        rev_tree = b.repository.revision_tree('r1')
491
 
        self.failUnless(rev_tree.is_executable(a_id), "'a' lost the execute bit")
492
 
        self.failIf(rev_tree.is_executable(b_id), "'b' gained an execute bit")
493
 
 
494
 
        self.failUnless(rev_tree.inventory[a_id].executable)
495
 
        self.failIf(rev_tree.inventory[b_id].executable)
496
 
 
497
 
        # Make sure the entries are gone
498
 
        os.remove('b1/a')
499
 
        os.remove('b1/b')
500
 
        self.failIf(wt.has_id(a_id))
501
 
        self.failIf(wt.has_filename('a'))
502
 
        self.failIf(wt.has_id(b_id))
503
 
        self.failIf(wt.has_filename('b'))
504
 
 
505
 
        # Make sure that revert is able to bring them back,
506
 
        # and sets 'a' back to being executable
507
 
 
508
 
        wt.revert(['a', 'b'], rev_tree, backups=False)
509
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
510
 
 
511
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
512
 
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
513
 
 
514
 
        # Now remove them again, and make sure that after a
515
 
        # commit, they are still marked correctly
516
 
        os.remove('b1/a')
517
 
        os.remove('b1/b')
518
 
        wt.commit('removed', rev_id='r2')
519
 
 
520
 
        self.assertEqual([], [cn for cn,ie in wt.inventory.iter_entries()])
521
 
        self.failIf(wt.has_id(a_id))
522
 
        self.failIf(wt.has_filename('a'))
523
 
        self.failIf(wt.has_id(b_id))
524
 
        self.failIf(wt.has_filename('b'))
525
 
 
526
 
        # Now revert back to the previous commit
527
 
        wt.revert([], rev_tree, backups=False)
528
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
529
 
 
530
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
531
 
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
532
 
 
533
 
        # Now make sure that 'bzr branch' also preserves the
534
 
        # executable bit
535
 
        # TODO: Maybe this should be a blackbox test
536
 
        d2 = b.bzrdir.clone('b2', revision_id='r1')
537
 
        t2 = d2.open_workingtree()
538
 
        b2 = t2.branch
539
 
        self.assertEquals('r1', b2.last_revision())
540
 
 
541
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
542
 
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
543
 
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
544
 
 
545
 
        # Make sure pull will delete the files
546
 
        t2.pull(b)
547
 
        self.assertEquals('r2', b2.last_revision())
548
 
        self.assertEqual([], [cn for cn,ie in t2.inventory.iter_entries()])
549
 
 
550
 
        # Now commit the changes on the first branch
551
 
        # so that the second branch can pull the changes
552
 
        # and make sure that the executable bit has been copied
553
 
        wt.commit('resurrected', rev_id='r3')
554
 
 
555
 
        t2.pull(b)
556
 
        self.assertEquals('r3', b2.last_revision())
557
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
558
 
 
559
 
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
560
 
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
561
 
 
562
 
 
563
 
class TestRevert(TestCaseWithTransport):
564
 
 
565
 
    def test_dangling_id(self):
566
 
        wt = self.make_branch_and_tree('b1')
567
 
        self.assertEqual(len(wt.inventory), 1)
568
 
        open('b1/a', 'wb').write('a test\n')
569
 
        wt.add('a')
570
 
        self.assertEqual(len(wt.inventory), 2)
571
 
        os.unlink('b1/a')
572
 
        wt.revert([])
573
 
        self.assertEqual(len(wt.inventory), 1)