/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

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