~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testinv.py

  • Committer: Robert Collins
  • Date: 2005-10-18 13:11:57 UTC
  • mfrom: (1185.16.72) (0.2.1)
  • Revision ID: robertc@robertcollins.net-20051018131157-76a9970aa78e927e
Merged Martin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 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
17
from cStringIO import StringIO
18
18
import os
19
 
import time
20
19
 
21
 
from bzrlib import errors, inventory, osutils
22
20
from bzrlib.branch import Branch
 
21
from bzrlib.clone import copy_branch
 
22
import bzrlib.errors as errors
23
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
 
24
from bzrlib.inventory import Inventory, ROOT_ID
 
25
import bzrlib.inventory as inventory
 
26
from bzrlib.osutils import has_symlinks, rename
 
27
from bzrlib.selftest import TestCase, TestCaseInTempDir
31
28
 
32
29
 
33
30
class TestInventory(TestCase):
34
31
 
35
 
    def test_add_path(self):
36
 
 
37
 
        inv = Inventory(root_id=None)
38
 
        self.assertIs(None, inv.root)
39
 
        ie = inv.add_path("", "directory", "my-root")
40
 
        self.assertEqual("my-root", ie.file_id)
41
 
        self.assertIs(ie, inv.root)
42
 
 
43
32
    def test_is_within(self):
 
33
        from bzrlib.osutils import is_inside_any
44
34
 
45
 
        SRC_FOO_C = pathjoin('src', 'foo.c')
 
35
        SRC_FOO_C = os.path.join('src', 'foo.c')
46
36
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
47
37
                         (['src'], SRC_FOO_C),
48
38
                         (['src'], 'src'),
52
42
        for dirs, fn in [(['src'], 'srccontrol'),
53
43
                         (['src'], 'srccontrol/foo')]:
54
44
            self.assertFalse(is_inside_any(dirs, fn))
55
 
 
56
 
    def test_is_within_or_parent(self):
57
 
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
58
 
                         (['src'], 'src/foo.c'),
59
 
                         (['src/bar.c'], 'src'),
60
 
                         (['src/bar.c', 'bla/foo.c'], 'src'),
61
 
                         (['src'], 'src'),
62
 
                         ]:
63
 
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
64
45
            
65
 
        for dirs, fn in [(['src'], 'srccontrol'),
66
 
                         (['srccontrol/foo.c'], 'src'),
67
 
                         (['src'], 'srccontrol/foo')]:
68
 
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
69
 
 
70
46
    def test_ids(self):
71
47
        """Test detection of files within selected directories."""
72
48
        inv = Inventory()
83
59
        
84
60
        self.assert_('src-id' in inv)
85
61
 
86
 
    def test_non_directory_children(self):
87
 
        """Test path2id when a parent directory has no children"""
88
 
        inv = inventory.Inventory('tree_root')
89
 
        inv.add(inventory.InventoryFile('file-id','file', 
90
 
                                        parent_id='tree_root'))
91
 
        inv.add(inventory.InventoryLink('link-id','link', 
92
 
                                        parent_id='tree_root'))
93
 
        self.assertIs(None, inv.path2id('file/subfile'))
94
 
        self.assertIs(None, inv.path2id('link/subfile'))
95
 
 
96
 
    def test_iter_entries(self):
97
 
        inv = Inventory()
98
 
        
99
 
        for args in [('src', 'directory', 'src-id'), 
100
 
                     ('doc', 'directory', 'doc-id'), 
101
 
                     ('src/hello.c', 'file', 'hello-id'),
102
 
                     ('src/bye.c', 'file', 'bye-id'),
103
 
                     ('Makefile', 'file', 'makefile-id')]:
104
 
            inv.add_path(*args)
105
 
 
106
 
        self.assertEqual([
107
 
            ('', ROOT_ID),
108
 
            ('Makefile', 'makefile-id'),
109
 
            ('doc', 'doc-id'),
110
 
            ('src', 'src-id'),
111
 
            ('src/bye.c', 'bye-id'),
112
 
            ('src/hello.c', 'hello-id'),
113
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries()])
114
 
            
115
 
    def test_iter_entries_by_dir(self):
116
 
        inv = Inventory()
117
 
        
118
 
        for args in [('src', 'directory', 'src-id'), 
119
 
                     ('doc', 'directory', 'doc-id'), 
120
 
                     ('src/hello.c', 'file', 'hello-id'),
121
 
                     ('src/bye.c', 'file', 'bye-id'),
122
 
                     ('zz', 'file', 'zz-id'),
123
 
                     ('src/sub/', 'directory', 'sub-id'),
124
 
                     ('src/zz.c', 'file', 'zzc-id'),
125
 
                     ('src/sub/a', 'file', 'a-id'),
126
 
                     ('Makefile', 'file', 'makefile-id')]:
127
 
            inv.add_path(*args)
128
 
 
129
 
        self.assertEqual([
130
 
            ('', ROOT_ID),
131
 
            ('Makefile', 'makefile-id'),
132
 
            ('doc', 'doc-id'),
133
 
            ('src', 'src-id'),
134
 
            ('zz', 'zz-id'),
135
 
            ('src/bye.c', 'bye-id'),
136
 
            ('src/hello.c', 'hello-id'),
137
 
            ('src/sub', 'sub-id'),
138
 
            ('src/zz.c', 'zzc-id'),
139
 
            ('src/sub/a', 'a-id'),
140
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir()])
141
 
            
142
 
        self.assertEqual([
143
 
            ('', ROOT_ID),
144
 
            ('Makefile', 'makefile-id'),
145
 
            ('doc', 'doc-id'),
146
 
            ('src', 'src-id'),
147
 
            ('zz', 'zz-id'),
148
 
            ('src/bye.c', 'bye-id'),
149
 
            ('src/hello.c', 'hello-id'),
150
 
            ('src/sub', 'sub-id'),
151
 
            ('src/zz.c', 'zzc-id'),
152
 
            ('src/sub/a', 'a-id'),
153
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
154
 
                specific_file_ids=('a-id', 'zzc-id', 'doc-id', ROOT_ID,
155
 
                'hello-id', 'bye-id', 'zz-id', 'src-id', 'makefile-id', 
156
 
                'sub-id'))])
157
 
 
158
 
        self.assertEqual([
159
 
            ('Makefile', 'makefile-id'),
160
 
            ('doc', 'doc-id'),
161
 
            ('zz', 'zz-id'),
162
 
            ('src/bye.c', 'bye-id'),
163
 
            ('src/hello.c', 'hello-id'),
164
 
            ('src/zz.c', 'zzc-id'),
165
 
            ('src/sub/a', 'a-id'),
166
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
167
 
                specific_file_ids=('a-id', 'zzc-id', 'doc-id',
168
 
                'hello-id', 'bye-id', 'zz-id', 'makefile-id'))])
169
 
 
170
 
        self.assertEqual([
171
 
            ('Makefile', 'makefile-id'),
172
 
            ('src/bye.c', 'bye-id'),
173
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
174
 
                specific_file_ids=('bye-id', 'makefile-id'))])
175
 
 
176
 
        self.assertEqual([
177
 
            ('Makefile', 'makefile-id'),
178
 
            ('src/bye.c', 'bye-id'),
179
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
180
 
                specific_file_ids=('bye-id', 'makefile-id'))])
181
 
 
182
 
        self.assertEqual([
183
 
            ('src/bye.c', 'bye-id'),
184
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
185
 
                specific_file_ids=('bye-id',))])
186
62
 
187
63
    def test_version(self):
188
64
        """Inventory remembers the text's version."""
256
132
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
257
133
        self.failIf(link.has_text())
258
134
 
259
 
    def test_make_entry(self):
260
 
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
261
 
            inventory.InventoryFile)
262
 
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
263
 
            inventory.InventoryLink)
264
 
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
265
 
            inventory.InventoryDirectory)
266
 
 
267
 
    def test_make_entry_non_normalized(self):
268
 
        orig_normalized_filename = osutils.normalized_filename
269
 
 
270
 
        try:
271
 
            osutils.normalized_filename = osutils._accessible_normalized_filename
272
 
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
273
 
            self.assertEqual(u'\xe5', entry.name)
274
 
            self.assertIsInstance(entry, inventory.InventoryFile)
275
 
 
276
 
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
277
 
            self.assertRaises(errors.InvalidNormalization,
278
 
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
279
 
        finally:
280
 
            osutils.normalized_filename = orig_normalized_filename
281
 
 
282
 
 
283
 
class TestEntryDiffing(TestCaseWithTransport):
 
135
 
 
136
class TestEntryDiffing(TestCaseInTempDir):
284
137
 
285
138
    def setUp(self):
286
139
        super(TestEntryDiffing, self).setUp()
287
 
        self.wt = self.make_branch_and_tree('.')
288
 
        self.branch = self.wt.branch
 
140
        self.branch = Branch.initialize('.')
289
141
        print >> open('file', 'wb'), 'foo'
290
 
        print >> open('binfile', 'wb'), 'foo'
291
 
        self.wt.add(['file'], ['fileid'])
292
 
        self.wt.add(['binfile'], ['binfileid'])
 
142
        self.branch.add(['file'], ['fileid'])
293
143
        if has_symlinks():
294
144
            os.symlink('target1', 'symlink')
295
 
            self.wt.add(['symlink'], ['linkid'])
296
 
        self.wt.commit('message_1', rev_id = '1')
 
145
            self.branch.add(['symlink'], ['linkid'])
 
146
        self.branch.commit('message_1', rev_id = '1')
297
147
        print >> open('file', 'wb'), 'bar'
298
 
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
299
148
        if has_symlinks():
300
149
            os.unlink('symlink')
301
150
            os.symlink('target2', 'symlink')
302
 
        self.tree_1 = self.branch.repository.revision_tree('1')
303
 
        self.inv_1 = self.branch.repository.get_inventory('1')
 
151
        self.tree_1 = self.branch.revision_tree('1')
 
152
        self.inv_1 = self.branch.get_inventory('1')
304
153
        self.file_1 = self.inv_1['fileid']
305
 
        self.file_1b = self.inv_1['binfileid']
306
 
        self.tree_2 = self.wt
307
 
        self.inv_2 = self.tree_2.read_working_inventory()
 
154
        self.tree_2 = self.branch.working_tree()
 
155
        self.inv_2 = self.branch.inventory
308
156
        self.file_2 = self.inv_2['fileid']
309
 
        self.file_2b = self.inv_2['binfileid']
310
157
        if has_symlinks():
311
158
            self.link_1 = self.inv_1['linkid']
312
159
            self.link_2 = self.inv_2['linkid']
348
195
                                            "+bar\n"
349
196
                                            "\n")
350
197
        
351
 
    def test_file_diff_binary(self):
352
 
        output = StringIO()
353
 
        self.file_1.diff(internal_diff, 
354
 
                          "/dev/null", self.tree_1, 
355
 
                          "new_label", self.file_2b, self.tree_2,
356
 
                          output)
357
 
        self.assertEqual(output.getvalue(), 
358
 
                         "Binary files /dev/null and new_label differ\n")
359
198
    def test_link_diff_deleted(self):
360
199
        if not has_symlinks():
361
200
            return
390
229
                         "=== target changed 'target1' => 'target2'\n")
391
230
 
392
231
 
393
 
class TestSnapshot(TestCaseWithTransport):
 
232
class TestSnapshot(TestCaseInTempDir):
394
233
 
395
234
    def setUp(self):
396
235
        # for full testing we'll need a branch
400
239
        # to change, and then test merge patterns
401
240
        # with fake parent entries.
402
241
        super(TestSnapshot, self).setUp()
403
 
        self.wt = self.make_branch_and_tree('.')
404
 
        self.branch = self.wt.branch
405
 
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
406
 
        self.wt.add(['subdir', 'subdir/file'],
407
 
                                       ['dirid', 'fileid'])
 
242
        self.branch = Branch.initialize('.')
 
243
        self.build_tree(['subdir/', 'subdir/file'])
 
244
        self.branch.add(['subdir', 'subdir/file'], ['dirid', 'fileid'])
408
245
        if has_symlinks():
409
246
            pass
410
 
        self.wt.commit('message_1', rev_id = '1')
411
 
        self.tree_1 = self.branch.repository.revision_tree('1')
412
 
        self.inv_1 = self.branch.repository.get_inventory('1')
 
247
        self.branch.commit('message_1', rev_id = '1')
 
248
        self.tree_1 = self.branch.revision_tree('1')
 
249
        self.inv_1 = self.branch.get_inventory('1')
413
250
        self.file_1 = self.inv_1['fileid']
414
 
        self.file_active = self.wt.inventory['fileid']
415
 
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
 
251
        self.work_tree = self.branch.working_tree()
 
252
        self.file_active = self.work_tree.inventory['fileid']
416
253
 
417
254
    def test_snapshot_new_revision(self):
418
255
        # This tests that a simple commit with no parents makes a new
419
256
        # revision value in the inventory entry
420
 
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
 
257
        self.file_active.snapshot('2', 'subdir/file', {}, self.work_tree, 
 
258
                                  self.branch.weave_store,
 
259
                                  self.branch.get_transaction())
421
260
        # expected outcome - file_1 has a revision id of '2', and we can get
422
261
        # its text of 'file contents' out of the weave.
423
262
        self.assertEqual(self.file_1.revision, '1')
424
263
        self.assertEqual(self.file_active.revision, '2')
425
264
        # this should be a separate test probably, but lets check it once..
426
 
        lines = self.branch.repository.weave_store.get_weave(
427
 
            'fileid', 
428
 
            self.branch.get_transaction()).get_lines('2')
 
265
        lines = self.branch.weave_store.get_lines('fileid','2',
 
266
            self.branch.get_transaction())
429
267
        self.assertEqual(lines, ['contents of subdir/file\n'])
430
268
 
431
269
    def test_snapshot_unchanged(self):
432
270
        #This tests that a simple commit does not make a new entry for
433
271
        # an unchanged inventory entry
434
272
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
435
 
                                  self.wt, self.builder)
 
273
                                  self.work_tree, self.branch.weave_store,
 
274
                                  self.branch.get_transaction())
436
275
        self.assertEqual(self.file_1.revision, '1')
437
276
        self.assertEqual(self.file_active.revision, '1')
438
 
        vf = self.branch.repository.weave_store.get_weave(
439
 
            'fileid', 
440
 
            self.branch.repository.get_transaction())
441
 
        self.assertRaises(errors.RevisionNotPresent,
442
 
                          vf.get_lines,
443
 
                          '2')
 
277
        self.assertRaises(errors.WeaveError,
 
278
                          self.branch.weave_store.get_lines, 'fileid', '2',
 
279
                          self.branch.get_transaction())
444
280
 
445
281
    def test_snapshot_merge_identical_different_revid(self):
446
282
        # This tests that a commit with two identical parents, one of which has
454
290
        self.assertEqual(self.file_1, other_ie)
455
291
        other_ie.revision = 'other'
456
292
        self.assertNotEqual(self.file_1, other_ie)
457
 
        versionfile = self.branch.repository.weave_store.get_weave(
458
 
            'fileid', self.branch.repository.get_transaction())
459
 
        versionfile.clone_text('other', '1', ['1'])
 
293
        self.branch.weave_store.add_identical_text('fileid', '1', 'other', ['1'],
 
294
            self.branch.get_transaction())
460
295
        self.file_active.snapshot('2', 'subdir/file', 
461
296
                                  {'1':self.file_1, 'other':other_ie},
462
 
                                  self.wt, self.builder)
 
297
                                  self.work_tree, self.branch.weave_store,
 
298
                                  self.branch.get_transaction())
463
299
        self.assertEqual(self.file_active.revision, '2')
464
300
 
465
301
    def test_snapshot_changed(self):
468
304
        self.file_active.name='newname'
469
305
        rename('subdir/file', 'subdir/newname')
470
306
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
471
 
                                  self.wt, self.builder)
 
307
                                  self.work_tree, 
 
308
                                  self.branch.weave_store,
 
309
                                  self.branch.get_transaction())
472
310
        # expected outcome - file_1 has a revision id of '2'
473
311
        self.assertEqual(self.file_active.revision, '2')
474
312
 
475
313
 
476
 
class TestPreviousHeads(TestCaseWithTransport):
 
314
class TestPreviousHeads(TestCaseInTempDir):
477
315
 
478
316
    def setUp(self):
479
317
        # we want several inventories, that respectively
485
323
        # D) fileid present in two inventories and one is
486
324
        #   a descendent of the other. (B, D)
487
325
        super(TestPreviousHeads, self).setUp()
488
 
        self.wt = self.make_branch_and_tree('.')
489
 
        self.branch = self.wt.branch
490
326
        self.build_tree(['file'])
491
 
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
492
 
        self.inv_A = self.branch.repository.get_inventory('A')
493
 
        self.wt.add(['file'], ['fileid'])
494
 
        self.wt.commit('add file', rev_id='B')
495
 
        self.inv_B = self.branch.repository.get_inventory('B')
496
 
        uncommit(self.branch, tree=self.wt)
 
327
        self.branch = Branch.initialize('.')
 
328
        self.branch.commit('new branch', allow_pointless=True, rev_id='A')
 
329
        self.inv_A = self.branch.get_inventory('A')
 
330
        self.branch.add(['file'], ['fileid'])
 
331
        self.branch.commit('add file', rev_id='B')
 
332
        self.inv_B = self.branch.get_inventory('B')
 
333
        self.branch.put_controlfile('revision-history', 'A\n')
497
334
        self.assertEqual(self.branch.revision_history(), ['A'])
498
 
        self.wt.commit('another add of file', rev_id='C')
499
 
        self.inv_C = self.branch.repository.get_inventory('C')
500
 
        self.wt.add_parent_tree_id('B')
501
 
        self.wt.commit('merge in B', rev_id='D')
502
 
        self.inv_D = self.branch.repository.get_inventory('D')
503
 
        self.file_active = self.wt.inventory['fileid']
504
 
        self.weave = self.branch.repository.weave_store.get_weave('fileid',
505
 
            self.branch.repository.get_transaction())
 
335
        self.branch.commit('another add of file', rev_id='C')
 
336
        self.inv_C = self.branch.get_inventory('C')
 
337
        self.branch.add_pending_merge('B')
 
338
        self.branch.commit('merge in B', rev_id='D')
 
339
        self.inv_D = self.branch.get_inventory('D')
 
340
        self.file_active = self.branch.working_tree().inventory['fileid']
 
341
        self.weave = self.branch.weave_store.get_weave('fileid',
 
342
            self.branch.get_transaction())
506
343
        
507
344
    def get_previous_heads(self, inventories):
508
 
        return self.file_active.find_previous_heads(
509
 
            inventories, 
510
 
            self.branch.repository.weave_store,
511
 
            self.branch.repository.get_transaction())
 
345
        return self.file_active.find_previous_heads(inventories, self.weave)
512
346
        
513
347
    def test_fileid_in_no_inventory(self):
514
348
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
536
370
                         self.get_previous_heads([self.inv_D, self.inv_B]))
537
371
 
538
372
    # TODO: test two inventories with the same file revision 
539
 
 
540
 
 
541
 
class TestDescribeChanges(TestCase):
542
 
 
543
 
    def test_describe_change(self):
544
 
        # we need to test the following change combinations:
545
 
        # rename
546
 
        # reparent
547
 
        # modify
548
 
        # gone
549
 
        # added
550
 
        # renamed/reparented and modified
551
 
        # change kind (perhaps can't be done yet?)
552
 
        # also, merged in combination with all of these?
553
 
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
554
 
        old_a.text_sha1 = '123132'
555
 
        old_a.text_size = 0
556
 
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
557
 
        new_a.text_sha1 = '123132'
558
 
        new_a.text_size = 0
559
 
 
560
 
        self.assertChangeDescription('unchanged', old_a, new_a)
561
 
 
562
 
        new_a.text_size = 10
563
 
        new_a.text_sha1 = 'abcabc'
564
 
        self.assertChangeDescription('modified', old_a, new_a)
565
 
 
566
 
        self.assertChangeDescription('added', None, new_a)
567
 
        self.assertChangeDescription('removed', old_a, None)
568
 
        # perhaps a bit questionable but seems like the most reasonable thing...
569
 
        self.assertChangeDescription('unchanged', None, None)
570
 
 
571
 
        # in this case it's both renamed and modified; show a rename and 
572
 
        # modification:
573
 
        new_a.name = 'newfilename'
574
 
        self.assertChangeDescription('modified and renamed', old_a, new_a)
575
 
 
576
 
        # reparenting is 'renaming'
577
 
        new_a.name = old_a.name
578
 
        new_a.parent_id = 'somedir-id'
579
 
        self.assertChangeDescription('modified and renamed', old_a, new_a)
580
 
 
581
 
        # reset the content values so its not modified
582
 
        new_a.text_size = old_a.text_size
583
 
        new_a.text_sha1 = old_a.text_sha1
584
 
        new_a.name = old_a.name
585
 
 
586
 
        new_a.name = 'newfilename'
587
 
        self.assertChangeDescription('renamed', old_a, new_a)
588
 
 
589
 
        # reparenting is 'renaming'
590
 
        new_a.name = old_a.name
591
 
        new_a.parent_id = 'somedir-id'
592
 
        self.assertChangeDescription('renamed', old_a, new_a)
593
 
 
594
 
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
595
 
        change = InventoryEntry.describe_change(old_ie, new_ie)
596
 
        self.assertEqual(expected_change, change)
597
 
 
598
 
 
599
 
class TestRevert(TestCaseWithTransport):
600
 
 
601
 
    def test_dangling_id(self):
602
 
        wt = self.make_branch_and_tree('b1')
603
 
        self.assertEqual(len(wt.inventory), 1)
604
 
        open('b1/a', 'wb').write('a test\n')
605
 
        wt.add('a')
606
 
        self.assertEqual(len(wt.inventory), 2)
607
 
        os.unlink('b1/a')
608
 
        wt.revert([])
609
 
        self.assertEqual(len(wt.inventory), 1)
610
 
 
611
 
 
612
 
class TestIsRoot(TestCase):
613
 
    """Ensure our root-checking code is accurate."""
614
 
 
615
 
    def test_is_root(self):
616
 
        inv = Inventory('TREE_ROOT')
617
 
        self.assertTrue(inv.is_root('TREE_ROOT'))
618
 
        self.assertFalse(inv.is_root('booga'))
619
 
        inv.root.file_id = 'booga'
620
 
        self.assertFalse(inv.is_root('TREE_ROOT'))
621
 
        self.assertTrue(inv.is_root('booga'))
622
 
        # works properly even if no root is set
623
 
        inv.root = None
624
 
        self.assertFalse(inv.is_root('TREE_ROOT'))
625
 
        self.assertFalse(inv.is_root('booga'))