~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-13 02:11:41 UTC
  • Revision ID: mbp@sourcefrog.net-20050913021141-263bfc2655ac3ed2
- store inventories in weave

- put more intelligence into WeaveStore

Show diffs side-by-side

added added

removed removed

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