~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

  • Committer: Robert Collins
  • Date: 2007-03-11 23:34:27 UTC
  • mto: This revision was merged to the branch mainline in revision 2442.
  • Revision ID: robertc@robertcollins.net-20070311233427-z8skxqrx8shqy1de
Fix building of C modules without pyrex installed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 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
19
20
 
 
21
from bzrlib import errors, inventory, osutils
20
22
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
25
 
import bzrlib.inventory as inventory
26
 
from bzrlib.osutils import has_symlinks, rename
27
 
from bzrlib.selftest import TestCase, TestCaseInTempDir
 
24
from bzrlib.inventory import (Inventory, ROOT_ID, InventoryFile,
 
25
    InventoryDirectory, InventoryEntry, TreeReference)
 
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
28
31
 
29
32
 
30
33
class TestInventory(TestCase):
31
34
 
 
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
 
32
43
    def test_is_within(self):
33
 
        from bzrlib.osutils import is_inside_any
34
44
 
35
 
        SRC_FOO_C = os.path.join('src', 'foo.c')
 
45
        SRC_FOO_C = pathjoin('src', 'foo.c')
36
46
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
37
47
                         (['src'], SRC_FOO_C),
38
48
                         (['src'], 'src'),
42
52
        for dirs, fn in [(['src'], 'srccontrol'),
43
53
                         (['src'], 'srccontrol/foo')]:
44
54
            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))
45
64
            
 
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
 
46
70
    def test_ids(self):
47
71
        """Test detection of files within selected directories."""
48
72
        inv = Inventory()
59
83
        
60
84
        self.assert_('src-id' in inv)
61
85
 
62
 
 
63
 
    def test_version(self):
64
 
        """Inventory remembers the text's version."""
65
 
        inv = Inventory()
66
 
        ie = inv.add_path('foo.txt', 'file')
67
 
        ## XXX
 
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
 
 
187
    def test_add_recursive(self):
 
188
        parent = InventoryDirectory('src-id', 'src', ROOT_ID)
 
189
        child = InventoryFile('hello-id', 'hello.c', 'src-id')
 
190
        parent.children[child.file_id] = child
 
191
        inv = Inventory()
 
192
        inv.add(parent)
 
193
        self.assertEqual('src/hello.c', inv.id2path('hello-id'))
68
194
 
69
195
 
70
196
class TestInventoryEntry(TestCase):
132
258
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
133
259
        self.failIf(link.has_text())
134
260
 
135
 
 
136
 
class TestEntryDiffing(TestCaseInTempDir):
 
261
    def test_make_entry(self):
 
262
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
 
263
            inventory.InventoryFile)
 
264
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
 
265
            inventory.InventoryLink)
 
266
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
 
267
            inventory.InventoryDirectory)
 
268
 
 
269
    def test_make_entry_non_normalized(self):
 
270
        orig_normalized_filename = osutils.normalized_filename
 
271
 
 
272
        try:
 
273
            osutils.normalized_filename = osutils._accessible_normalized_filename
 
274
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
 
275
            self.assertEqual(u'\xe5', entry.name)
 
276
            self.assertIsInstance(entry, inventory.InventoryFile)
 
277
 
 
278
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
 
279
            self.assertRaises(errors.InvalidNormalization,
 
280
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
 
281
        finally:
 
282
            osutils.normalized_filename = orig_normalized_filename
 
283
 
 
284
 
 
285
class TestEntryDiffing(TestCaseWithTransport):
137
286
 
138
287
    def setUp(self):
139
288
        super(TestEntryDiffing, self).setUp()
140
 
        self.branch = Branch.initialize('.')
 
289
        self.wt = self.make_branch_and_tree('.')
 
290
        self.branch = self.wt.branch
141
291
        print >> open('file', 'wb'), 'foo'
142
 
        self.branch.add(['file'], ['fileid'])
 
292
        print >> open('binfile', 'wb'), 'foo'
 
293
        self.wt.add(['file'], ['fileid'])
 
294
        self.wt.add(['binfile'], ['binfileid'])
143
295
        if has_symlinks():
144
296
            os.symlink('target1', 'symlink')
145
 
            self.branch.add(['symlink'], ['linkid'])
146
 
        self.branch.commit('message_1', rev_id = '1')
 
297
            self.wt.add(['symlink'], ['linkid'])
 
298
        self.wt.commit('message_1', rev_id = '1')
147
299
        print >> open('file', 'wb'), 'bar'
 
300
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
148
301
        if has_symlinks():
149
302
            os.unlink('symlink')
150
303
            os.symlink('target2', 'symlink')
151
 
        self.tree_1 = self.branch.revision_tree('1')
152
 
        self.inv_1 = self.branch.get_inventory('1')
 
304
        self.tree_1 = self.branch.repository.revision_tree('1')
 
305
        self.inv_1 = self.branch.repository.get_inventory('1')
153
306
        self.file_1 = self.inv_1['fileid']
154
 
        self.tree_2 = self.branch.working_tree()
155
 
        self.inv_2 = self.branch.inventory
 
307
        self.file_1b = self.inv_1['binfileid']
 
308
        self.tree_2 = self.wt
 
309
        self.tree_2.lock_read()
 
310
        self.addCleanup(self.tree_2.unlock)
 
311
        self.inv_2 = self.tree_2.read_working_inventory()
156
312
        self.file_2 = self.inv_2['fileid']
 
313
        self.file_2b = self.inv_2['binfileid']
157
314
        if has_symlinks():
158
315
            self.link_1 = self.inv_1['linkid']
159
316
            self.link_2 = self.inv_2['linkid']
195
352
                                            "+bar\n"
196
353
                                            "\n")
197
354
        
 
355
    def test_file_diff_binary(self):
 
356
        output = StringIO()
 
357
        self.file_1.diff(internal_diff, 
 
358
                          "/dev/null", self.tree_1, 
 
359
                          "new_label", self.file_2b, self.tree_2,
 
360
                          output)
 
361
        self.assertEqual(output.getvalue(), 
 
362
                         "Binary files /dev/null and new_label differ\n")
198
363
    def test_link_diff_deleted(self):
 
364
        if not has_symlinks():
 
365
            return
199
366
        output = StringIO()
200
367
        self.link_1.diff(internal_diff, 
201
368
                          "old_label", self.tree_1,
205
372
                         "=== target was 'target1'\n")
206
373
 
207
374
    def test_link_diff_added(self):
 
375
        if not has_symlinks():
 
376
            return
208
377
        output = StringIO()
209
378
        self.link_1.diff(internal_diff, 
210
379
                          "new_label", self.tree_1,
214
383
                         "=== target is 'target1'\n")
215
384
 
216
385
    def test_link_diff_changed(self):
 
386
        if not has_symlinks():
 
387
            return
217
388
        output = StringIO()
218
389
        self.link_1.diff(internal_diff, 
219
390
                          "/dev/null", self.tree_1, 
223
394
                         "=== target changed 'target1' => 'target2'\n")
224
395
 
225
396
 
226
 
class TestSnapshot(TestCaseInTempDir):
 
397
class TestSnapshot(TestCaseWithTransport):
227
398
 
228
399
    def setUp(self):
229
400
        # for full testing we'll need a branch
233
404
        # to change, and then test merge patterns
234
405
        # with fake parent entries.
235
406
        super(TestSnapshot, self).setUp()
236
 
        self.branch = Branch.initialize('.')
237
 
        self.build_tree(['subdir/', 'subdir/file'])
238
 
        self.branch.add(['subdir', 'subdir/file'], ['dirid', 'fileid'])
 
407
        self.wt = self.make_branch_and_tree('.')
 
408
        self.branch = self.wt.branch
 
409
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
 
410
        self.wt.add(['subdir', 'subdir/file'],
 
411
                                       ['dirid', 'fileid'])
239
412
        if has_symlinks():
240
413
            pass
241
 
        self.branch.commit('message_1', rev_id = '1')
242
 
        self.tree_1 = self.branch.revision_tree('1')
243
 
        self.inv_1 = self.branch.get_inventory('1')
 
414
        self.wt.commit('message_1', rev_id = '1')
 
415
        self.tree_1 = self.branch.repository.revision_tree('1')
 
416
        self.inv_1 = self.branch.repository.get_inventory('1')
244
417
        self.file_1 = self.inv_1['fileid']
245
 
        self.work_tree = self.branch.working_tree()
246
 
        self.file_active = self.work_tree.inventory['fileid']
 
418
        self.wt.lock_write()
 
419
        self.addCleanup(self.wt.unlock)
 
420
        self.file_active = self.wt.inventory['fileid']
 
421
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
247
422
 
248
423
    def test_snapshot_new_revision(self):
249
424
        # This tests that a simple commit with no parents makes a new
250
425
        # revision value in the inventory entry
251
 
        self.file_active.snapshot('2', 'subdir/file', {}, self.work_tree, 
252
 
                                  self.branch.weave_store)
 
426
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
253
427
        # expected outcome - file_1 has a revision id of '2', and we can get
254
428
        # its text of 'file contents' out of the weave.
255
429
        self.assertEqual(self.file_1.revision, '1')
256
430
        self.assertEqual(self.file_active.revision, '2')
257
431
        # this should be a separate test probably, but lets check it once..
258
 
        lines = self.branch.weave_store.get_lines('fileid','2')
 
432
        lines = self.branch.repository.weave_store.get_weave(
 
433
            'fileid', 
 
434
            self.branch.get_transaction()).get_lines('2')
259
435
        self.assertEqual(lines, ['contents of subdir/file\n'])
260
436
 
261
437
    def test_snapshot_unchanged(self):
262
438
        #This tests that a simple commit does not make a new entry for
263
439
        # an unchanged inventory entry
264
440
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
265
 
                                  self.work_tree, self.branch.weave_store)
 
441
                                  self.wt, self.builder)
266
442
        self.assertEqual(self.file_1.revision, '1')
267
443
        self.assertEqual(self.file_active.revision, '1')
268
 
        self.assertRaises(errors.WeaveError,
269
 
                          self.branch.weave_store.get_lines, 'fileid', '2')
 
444
        vf = self.branch.repository.weave_store.get_weave(
 
445
            'fileid', 
 
446
            self.branch.repository.get_transaction())
 
447
        self.assertRaises(errors.RevisionNotPresent,
 
448
                          vf.get_lines,
 
449
                          '2')
270
450
 
271
451
    def test_snapshot_merge_identical_different_revid(self):
272
452
        # This tests that a commit with two identical parents, one of which has
280
460
        self.assertEqual(self.file_1, other_ie)
281
461
        other_ie.revision = 'other'
282
462
        self.assertNotEqual(self.file_1, other_ie)
283
 
        self.branch.weave_store.add_identical_text('fileid', '1', 'other', ['1'])
 
463
        versionfile = self.branch.repository.weave_store.get_weave(
 
464
            'fileid', self.branch.repository.get_transaction())
 
465
        versionfile.clone_text('other', '1', ['1'])
284
466
        self.file_active.snapshot('2', 'subdir/file', 
285
467
                                  {'1':self.file_1, 'other':other_ie},
286
 
                                  self.work_tree, self.branch.weave_store)
 
468
                                  self.wt, self.builder)
287
469
        self.assertEqual(self.file_active.revision, '2')
288
470
 
289
471
    def test_snapshot_changed(self):
290
472
        # This tests that a commit with one different parent results in a new
291
473
        # revision id in the entry.
292
 
        self.file_active.name='newname'
293
 
        rename('subdir/file', 'subdir/newname')
 
474
        self.wt.rename_one('subdir/file', 'subdir/newname')
 
475
        self.file_active = self.wt.inventory['fileid']
294
476
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
295
 
                                  self.work_tree, 
296
 
                                  self.branch.weave_store)
 
477
                                  self.wt, self.builder)
297
478
        # expected outcome - file_1 has a revision id of '2'
298
479
        self.assertEqual(self.file_active.revision, '2')
299
480
 
300
481
 
301
 
class TestPreviousHeads(TestCaseInTempDir):
 
482
class TestPreviousHeads(TestCaseWithTransport):
302
483
 
303
484
    def setUp(self):
304
485
        # we want several inventories, that respectively
310
491
        # D) fileid present in two inventories and one is
311
492
        #   a descendent of the other. (B, D)
312
493
        super(TestPreviousHeads, self).setUp()
 
494
        self.wt = self.make_branch_and_tree('.')
 
495
        self.branch = self.wt.branch
313
496
        self.build_tree(['file'])
314
 
        self.branch = Branch.initialize('.')
315
 
        self.branch.commit('new branch', allow_pointless=True, rev_id='A')
316
 
        self.inv_A = self.branch.get_inventory('A')
317
 
        self.branch.add(['file'], ['fileid'])
318
 
        self.branch.commit('add file', rev_id='B')
319
 
        self.inv_B = self.branch.get_inventory('B')
320
 
        self.branch.put_controlfile('revision-history', 'A\n')
 
497
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
 
498
        self.inv_A = self.branch.repository.get_inventory('A')
 
499
        self.wt.add(['file'], ['fileid'])
 
500
        self.wt.commit('add file', rev_id='B')
 
501
        self.inv_B = self.branch.repository.get_inventory('B')
 
502
        uncommit(self.branch, tree=self.wt)
321
503
        self.assertEqual(self.branch.revision_history(), ['A'])
322
 
        self.branch.commit('another add of file', rev_id='C')
323
 
        self.inv_C = self.branch.get_inventory('C')
324
 
        self.branch.add_pending_merge('B')
325
 
        self.branch.commit('merge in B', rev_id='D')
326
 
        self.inv_D = self.branch.get_inventory('D')
327
 
        self.file_active = self.branch.working_tree().inventory['fileid']
328
 
        self.weave = self.branch.weave_store.get_weave('fileid')
 
504
        self.wt.commit('another add of file', rev_id='C')
 
505
        self.inv_C = self.branch.repository.get_inventory('C')
 
506
        self.wt.add_parent_tree_id('B')
 
507
        self.wt.commit('merge in B', rev_id='D')
 
508
        self.inv_D = self.branch.repository.get_inventory('D')
 
509
        self.wt.lock_read()
 
510
        self.addCleanup(self.wt.unlock)
 
511
        self.file_active = self.wt.inventory['fileid']
 
512
        self.weave = self.branch.repository.weave_store.get_weave('fileid',
 
513
            self.branch.repository.get_transaction())
329
514
        
330
515
    def get_previous_heads(self, inventories):
331
 
        return self.file_active.find_previous_heads(inventories, self.weave)
 
516
        return self.file_active.find_previous_heads(
 
517
            inventories, 
 
518
            self.branch.repository.weave_store,
 
519
            self.branch.repository.get_transaction())
332
520
        
333
521
    def test_fileid_in_no_inventory(self):
334
522
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
356
544
                         self.get_previous_heads([self.inv_D, self.inv_B]))
357
545
 
358
546
    # TODO: test two inventories with the same file revision 
 
547
 
 
548
 
 
549
class TestDescribeChanges(TestCase):
 
550
 
 
551
    def test_describe_change(self):
 
552
        # we need to test the following change combinations:
 
553
        # rename
 
554
        # reparent
 
555
        # modify
 
556
        # gone
 
557
        # added
 
558
        # renamed/reparented and modified
 
559
        # change kind (perhaps can't be done yet?)
 
560
        # also, merged in combination with all of these?
 
561
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
 
562
        old_a.text_sha1 = '123132'
 
563
        old_a.text_size = 0
 
564
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
 
565
        new_a.text_sha1 = '123132'
 
566
        new_a.text_size = 0
 
567
 
 
568
        self.assertChangeDescription('unchanged', old_a, new_a)
 
569
 
 
570
        new_a.text_size = 10
 
571
        new_a.text_sha1 = 'abcabc'
 
572
        self.assertChangeDescription('modified', old_a, new_a)
 
573
 
 
574
        self.assertChangeDescription('added', None, new_a)
 
575
        self.assertChangeDescription('removed', old_a, None)
 
576
        # perhaps a bit questionable but seems like the most reasonable thing...
 
577
        self.assertChangeDescription('unchanged', None, None)
 
578
 
 
579
        # in this case it's both renamed and modified; show a rename and 
 
580
        # modification:
 
581
        new_a.name = 'newfilename'
 
582
        self.assertChangeDescription('modified and renamed', old_a, new_a)
 
583
 
 
584
        # reparenting is 'renaming'
 
585
        new_a.name = old_a.name
 
586
        new_a.parent_id = 'somedir-id'
 
587
        self.assertChangeDescription('modified and renamed', old_a, new_a)
 
588
 
 
589
        # reset the content values so its not modified
 
590
        new_a.text_size = old_a.text_size
 
591
        new_a.text_sha1 = old_a.text_sha1
 
592
        new_a.name = old_a.name
 
593
 
 
594
        new_a.name = 'newfilename'
 
595
        self.assertChangeDescription('renamed', old_a, new_a)
 
596
 
 
597
        # reparenting is 'renaming'
 
598
        new_a.name = old_a.name
 
599
        new_a.parent_id = 'somedir-id'
 
600
        self.assertChangeDescription('renamed', old_a, new_a)
 
601
 
 
602
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
 
603
        change = InventoryEntry.describe_change(old_ie, new_ie)
 
604
        self.assertEqual(expected_change, change)
 
605
 
 
606
 
 
607
class TestRevert(TestCaseWithTransport):
 
608
 
 
609
    def test_dangling_id(self):
 
610
        wt = self.make_branch_and_tree('b1')
 
611
        wt.lock_tree_write()
 
612
        self.addCleanup(wt.unlock)
 
613
        self.assertEqual(len(wt.inventory), 1)
 
614
        open('b1/a', 'wb').write('a test\n')
 
615
        wt.add('a')
 
616
        self.assertEqual(len(wt.inventory), 2)
 
617
        wt.flush() # workaround revert doing wt._write_inventory for now.
 
618
        os.unlink('b1/a')
 
619
        wt.revert([])
 
620
        self.assertEqual(len(wt.inventory), 1)
 
621
 
 
622
 
 
623
class TestIsRoot(TestCase):
 
624
    """Ensure our root-checking code is accurate."""
 
625
 
 
626
    def test_is_root(self):
 
627
        inv = Inventory('TREE_ROOT')
 
628
        self.assertTrue(inv.is_root('TREE_ROOT'))
 
629
        self.assertFalse(inv.is_root('booga'))
 
630
        inv.root.file_id = 'booga'
 
631
        self.assertFalse(inv.is_root('TREE_ROOT'))
 
632
        self.assertTrue(inv.is_root('booga'))
 
633
        # works properly even if no root is set
 
634
        inv.root = None
 
635
        self.assertFalse(inv.is_root('TREE_ROOT'))
 
636
        self.assertFalse(inv.is_root('booga'))
 
637
 
 
638
 
 
639
class TestTreeReference(TestCase):
 
640
    
 
641
    def test_create(self):
 
642
        inv = Inventory('tree-root-123')
 
643
        inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
 
644
                              revision='rev', reference_revision='rev2'))