~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

Make lsprof test handle more lsprof variants

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