~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

  • Committer: Alexander Belchenko
  • Date: 2006-07-30 16:43:12 UTC
  • mto: (1711.2.111 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060730164312-b025fd3ff0cee59e
rename  gpl.txt => COPYING.txt

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
            ('', 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
            
 
124
    def test_version(self):
 
125
        """Inventory remembers the text's version."""
 
126
        inv = Inventory()
 
127
        ie = inv.add_path('foo.txt', 'file')
 
128
        ## XXX
 
129
 
 
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_pending_merge('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)