~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-01-03 07:39:47 UTC
  • mfrom: (2215.5.1 bzr_man.rstx)
  • Revision ID: pqm@pqm.ubuntu.com-20070103073947-f9906c0b1f425aa9
(bialix) Fix generation of rstx man page

Show diffs side-by-side

added added

removed removed

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