/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

  • Committer: Aaron Bentley
  • Date: 2007-02-21 06:06:06 UTC
  • mto: (2255.6.1 dirstate)
  • mto: This revision was merged to the branch mainline in revision 2322.
  • Revision ID: aaron.bentley@utoronto.ca-20070221060606-unjaailciijp12ab
rename working tree format 4 to AB1 everywhere

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, 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
 
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
        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_version(self):
 
188
        """Inventory remembers the text's version."""
 
189
        inv = Inventory()
 
190
        ie = inv.add_path('foo.txt', 'file')
 
191
        ## XXX
 
192
 
 
193
    def test_add_recursive(self):
 
194
        parent = InventoryDirectory('src-id', 'src', ROOT_ID)
 
195
        child = InventoryFile('hello-id', 'hello.c', 'src-id')
 
196
        parent.children[child.file_id] = child
 
197
        inv = Inventory()
 
198
        inv.add(parent)
 
199
        self.assertEqual('src/hello.c', inv.id2path('hello-id'))
 
200
 
 
201
 
 
202
class TestInventoryEntry(TestCase):
 
203
 
 
204
    def test_file_kind_character(self):
 
205
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
206
        self.assertEqual(file.kind_character(), '')
 
207
 
 
208
    def test_dir_kind_character(self):
 
209
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
 
210
        self.assertEqual(dir.kind_character(), '/')
 
211
 
 
212
    def test_link_kind_character(self):
 
213
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
 
214
        self.assertEqual(dir.kind_character(), '')
 
215
 
 
216
    def test_dir_detect_changes(self):
 
217
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
 
218
        left.text_sha1 = 123
 
219
        left.executable = True
 
220
        left.symlink_target='foo'
 
221
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
 
222
        right.text_sha1 = 321
 
223
        right.symlink_target='bar'
 
224
        self.assertEqual((False, False), left.detect_changes(right))
 
225
        self.assertEqual((False, False), right.detect_changes(left))
 
226
 
 
227
    def test_file_detect_changes(self):
 
228
        left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
229
        left.text_sha1 = 123
 
230
        right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
231
        right.text_sha1 = 123
 
232
        self.assertEqual((False, False), left.detect_changes(right))
 
233
        self.assertEqual((False, False), right.detect_changes(left))
 
234
        left.executable = True
 
235
        self.assertEqual((False, True), left.detect_changes(right))
 
236
        self.assertEqual((False, True), right.detect_changes(left))
 
237
        right.text_sha1 = 321
 
238
        self.assertEqual((True, True), left.detect_changes(right))
 
239
        self.assertEqual((True, True), right.detect_changes(left))
 
240
 
 
241
    def test_symlink_detect_changes(self):
 
242
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
 
243
        left.text_sha1 = 123
 
244
        left.executable = True
 
245
        left.symlink_target='foo'
 
246
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
 
247
        right.text_sha1 = 321
 
248
        right.symlink_target='foo'
 
249
        self.assertEqual((False, False), left.detect_changes(right))
 
250
        self.assertEqual((False, False), right.detect_changes(left))
 
251
        left.symlink_target = 'different'
 
252
        self.assertEqual((True, False), left.detect_changes(right))
 
253
        self.assertEqual((True, False), right.detect_changes(left))
 
254
 
 
255
    def test_file_has_text(self):
 
256
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
 
257
        self.failUnless(file.has_text())
 
258
 
 
259
    def test_directory_has_text(self):
 
260
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
 
261
        self.failIf(dir.has_text())
 
262
 
 
263
    def test_link_has_text(self):
 
264
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
 
265
        self.failIf(link.has_text())
 
266
 
 
267
    def test_make_entry(self):
 
268
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
 
269
            inventory.InventoryFile)
 
270
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
 
271
            inventory.InventoryLink)
 
272
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
 
273
            inventory.InventoryDirectory)
 
274
 
 
275
    def test_make_entry_non_normalized(self):
 
276
        orig_normalized_filename = osutils.normalized_filename
 
277
 
 
278
        try:
 
279
            osutils.normalized_filename = osutils._accessible_normalized_filename
 
280
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
 
281
            self.assertEqual(u'\xe5', entry.name)
 
282
            self.assertIsInstance(entry, inventory.InventoryFile)
 
283
 
 
284
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
 
285
            self.assertRaises(errors.InvalidNormalization,
 
286
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
 
287
        finally:
 
288
            osutils.normalized_filename = orig_normalized_filename
 
289
 
 
290
 
 
291
class TestEntryDiffing(TestCaseWithTransport):
 
292
 
 
293
    def setUp(self):
 
294
        super(TestEntryDiffing, self).setUp()
 
295
        self.wt = self.make_branch_and_tree('.')
 
296
        self.branch = self.wt.branch
 
297
        print >> open('file', 'wb'), 'foo'
 
298
        print >> open('binfile', 'wb'), 'foo'
 
299
        self.wt.add(['file'], ['fileid'])
 
300
        self.wt.add(['binfile'], ['binfileid'])
 
301
        if has_symlinks():
 
302
            os.symlink('target1', 'symlink')
 
303
            self.wt.add(['symlink'], ['linkid'])
 
304
        self.wt.commit('message_1', rev_id = '1')
 
305
        print >> open('file', 'wb'), 'bar'
 
306
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
 
307
        if has_symlinks():
 
308
            os.unlink('symlink')
 
309
            os.symlink('target2', 'symlink')
 
310
        self.tree_1 = self.branch.repository.revision_tree('1')
 
311
        self.inv_1 = self.branch.repository.get_inventory('1')
 
312
        self.file_1 = self.inv_1['fileid']
 
313
        self.file_1b = self.inv_1['binfileid']
 
314
        self.tree_2 = self.wt
 
315
        self.inv_2 = self.tree_2.read_working_inventory()
 
316
        self.file_2 = self.inv_2['fileid']
 
317
        self.file_2b = self.inv_2['binfileid']
 
318
        if has_symlinks():
 
319
            self.link_1 = self.inv_1['linkid']
 
320
            self.link_2 = self.inv_2['linkid']
 
321
 
 
322
    def test_file_diff_deleted(self):
 
323
        output = StringIO()
 
324
        self.file_1.diff(internal_diff, 
 
325
                          "old_label", self.tree_1,
 
326
                          "/dev/null", None, None,
 
327
                          output)
 
328
        self.assertEqual(output.getvalue(), "--- old_label\n"
 
329
                                            "+++ /dev/null\n"
 
330
                                            "@@ -1,1 +0,0 @@\n"
 
331
                                            "-foo\n"
 
332
                                            "\n")
 
333
 
 
334
    def test_file_diff_added(self):
 
335
        output = StringIO()
 
336
        self.file_1.diff(internal_diff, 
 
337
                          "new_label", self.tree_1,
 
338
                          "/dev/null", None, None,
 
339
                          output, reverse=True)
 
340
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
 
341
                                            "+++ new_label\n"
 
342
                                            "@@ -0,0 +1,1 @@\n"
 
343
                                            "+foo\n"
 
344
                                            "\n")
 
345
 
 
346
    def test_file_diff_changed(self):
 
347
        output = StringIO()
 
348
        self.file_1.diff(internal_diff, 
 
349
                          "/dev/null", self.tree_1, 
 
350
                          "new_label", self.file_2, self.tree_2,
 
351
                          output)
 
352
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
 
353
                                            "+++ new_label\n"
 
354
                                            "@@ -1,1 +1,1 @@\n"
 
355
                                            "-foo\n"
 
356
                                            "+bar\n"
 
357
                                            "\n")
 
358
        
 
359
    def test_file_diff_binary(self):
 
360
        output = StringIO()
 
361
        self.file_1.diff(internal_diff, 
 
362
                          "/dev/null", self.tree_1, 
 
363
                          "new_label", self.file_2b, self.tree_2,
 
364
                          output)
 
365
        self.assertEqual(output.getvalue(), 
 
366
                         "Binary files /dev/null and new_label differ\n")
 
367
    def test_link_diff_deleted(self):
 
368
        if not has_symlinks():
 
369
            return
 
370
        output = StringIO()
 
371
        self.link_1.diff(internal_diff, 
 
372
                          "old_label", self.tree_1,
 
373
                          "/dev/null", None, None,
 
374
                          output)
 
375
        self.assertEqual(output.getvalue(),
 
376
                         "=== target was 'target1'\n")
 
377
 
 
378
    def test_link_diff_added(self):
 
379
        if not has_symlinks():
 
380
            return
 
381
        output = StringIO()
 
382
        self.link_1.diff(internal_diff, 
 
383
                          "new_label", self.tree_1,
 
384
                          "/dev/null", None, None,
 
385
                          output, reverse=True)
 
386
        self.assertEqual(output.getvalue(),
 
387
                         "=== target is 'target1'\n")
 
388
 
 
389
    def test_link_diff_changed(self):
 
390
        if not has_symlinks():
 
391
            return
 
392
        output = StringIO()
 
393
        self.link_1.diff(internal_diff, 
 
394
                          "/dev/null", self.tree_1, 
 
395
                          "new_label", self.link_2, self.tree_2,
 
396
                          output)
 
397
        self.assertEqual(output.getvalue(),
 
398
                         "=== target changed 'target1' => 'target2'\n")
 
399
 
 
400
 
 
401
class TestSnapshot(TestCaseWithTransport):
 
402
 
 
403
    def setUp(self):
 
404
        # for full testing we'll need a branch
 
405
        # with a subdir to test parent changes.
 
406
        # and a file, link and dir under that.
 
407
        # but right now I only need one attribute
 
408
        # to change, and then test merge patterns
 
409
        # with fake parent entries.
 
410
        super(TestSnapshot, self).setUp()
 
411
        self.wt = self.make_branch_and_tree('.')
 
412
        self.branch = self.wt.branch
 
413
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
 
414
        self.wt.add(['subdir', 'subdir/file'],
 
415
                                       ['dirid', 'fileid'])
 
416
        if has_symlinks():
 
417
            pass
 
418
        self.wt.commit('message_1', rev_id = '1')
 
419
        self.tree_1 = self.branch.repository.revision_tree('1')
 
420
        self.inv_1 = self.branch.repository.get_inventory('1')
 
421
        self.file_1 = self.inv_1['fileid']
 
422
        self.file_active = self.wt.inventory['fileid']
 
423
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
 
424
 
 
425
    def test_snapshot_new_revision(self):
 
426
        # This tests that a simple commit with no parents makes a new
 
427
        # revision value in the inventory entry
 
428
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
 
429
        # expected outcome - file_1 has a revision id of '2', and we can get
 
430
        # its text of 'file contents' out of the weave.
 
431
        self.assertEqual(self.file_1.revision, '1')
 
432
        self.assertEqual(self.file_active.revision, '2')
 
433
        # this should be a separate test probably, but lets check it once..
 
434
        lines = self.branch.repository.weave_store.get_weave(
 
435
            'fileid', 
 
436
            self.branch.get_transaction()).get_lines('2')
 
437
        self.assertEqual(lines, ['contents of subdir/file\n'])
 
438
 
 
439
    def test_snapshot_unchanged(self):
 
440
        #This tests that a simple commit does not make a new entry for
 
441
        # an unchanged inventory entry
 
442
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
 
443
                                  self.wt, self.builder)
 
444
        self.assertEqual(self.file_1.revision, '1')
 
445
        self.assertEqual(self.file_active.revision, '1')
 
446
        vf = self.branch.repository.weave_store.get_weave(
 
447
            'fileid', 
 
448
            self.branch.repository.get_transaction())
 
449
        self.assertRaises(errors.RevisionNotPresent,
 
450
                          vf.get_lines,
 
451
                          '2')
 
452
 
 
453
    def test_snapshot_merge_identical_different_revid(self):
 
454
        # This tests that a commit with two identical parents, one of which has
 
455
        # a different revision id, results in a new revision id in the entry.
 
456
        # 1->other, commit a merge of other against 1, results in 2.
 
457
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
 
458
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
 
459
        other_ie.revision = '1'
 
460
        other_ie.text_sha1 = self.file_1.text_sha1
 
461
        other_ie.text_size = self.file_1.text_size
 
462
        self.assertEqual(self.file_1, other_ie)
 
463
        other_ie.revision = 'other'
 
464
        self.assertNotEqual(self.file_1, other_ie)
 
465
        versionfile = self.branch.repository.weave_store.get_weave(
 
466
            'fileid', self.branch.repository.get_transaction())
 
467
        versionfile.clone_text('other', '1', ['1'])
 
468
        self.file_active.snapshot('2', 'subdir/file', 
 
469
                                  {'1':self.file_1, 'other':other_ie},
 
470
                                  self.wt, self.builder)
 
471
        self.assertEqual(self.file_active.revision, '2')
 
472
 
 
473
    def test_snapshot_changed(self):
 
474
        # This tests that a commit with one different parent results in a new
 
475
        # revision id in the entry.
 
476
        self.file_active.name='newname'
 
477
        rename('subdir/file', 'subdir/newname')
 
478
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
 
479
                                  self.wt, self.builder)
 
480
        # expected outcome - file_1 has a revision id of '2'
 
481
        self.assertEqual(self.file_active.revision, '2')
 
482
 
 
483
 
 
484
class TestPreviousHeads(TestCaseWithTransport):
 
485
 
 
486
    def setUp(self):
 
487
        # we want several inventories, that respectively
 
488
        # give use the following scenarios:
 
489
        # A) fileid not in any inventory (A),
 
490
        # B) fileid present in one inventory (B) and (A,B)
 
491
        # C) fileid present in two inventories, and they
 
492
        #   are not mutual descendents (B, C)
 
493
        # D) fileid present in two inventories and one is
 
494
        #   a descendent of the other. (B, D)
 
495
        super(TestPreviousHeads, self).setUp()
 
496
        self.wt = self.make_branch_and_tree('.')
 
497
        self.branch = self.wt.branch
 
498
        self.build_tree(['file'])
 
499
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
 
500
        self.inv_A = self.branch.repository.get_inventory('A')
 
501
        self.wt.add(['file'], ['fileid'])
 
502
        self.wt.commit('add file', rev_id='B')
 
503
        self.inv_B = self.branch.repository.get_inventory('B')
 
504
        uncommit(self.branch, tree=self.wt)
 
505
        self.assertEqual(self.branch.revision_history(), ['A'])
 
506
        self.wt.commit('another add of file', rev_id='C')
 
507
        self.inv_C = self.branch.repository.get_inventory('C')
 
508
        self.wt.add_parent_tree_id('B')
 
509
        self.wt.commit('merge in B', rev_id='D')
 
510
        self.inv_D = self.branch.repository.get_inventory('D')
 
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())
 
514
        
 
515
    def get_previous_heads(self, inventories):
 
516
        return self.file_active.find_previous_heads(
 
517
            inventories, 
 
518
            self.branch.repository.weave_store,
 
519
            self.branch.repository.get_transaction())
 
520
        
 
521
    def test_fileid_in_no_inventory(self):
 
522
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
 
523
 
 
524
    def test_fileid_in_one_inventory(self):
 
525
        self.assertEqual({'B':self.inv_B['fileid']},
 
526
                         self.get_previous_heads([self.inv_B]))
 
527
        self.assertEqual({'B':self.inv_B['fileid']},
 
528
                         self.get_previous_heads([self.inv_A, self.inv_B]))
 
529
        self.assertEqual({'B':self.inv_B['fileid']},
 
530
                         self.get_previous_heads([self.inv_B, self.inv_A]))
 
531
 
 
532
    def test_fileid_in_two_inventories_gives_both_entries(self):
 
533
        self.assertEqual({'B':self.inv_B['fileid'],
 
534
                          'C':self.inv_C['fileid']},
 
535
                          self.get_previous_heads([self.inv_B, self.inv_C]))
 
536
        self.assertEqual({'B':self.inv_B['fileid'],
 
537
                          'C':self.inv_C['fileid']},
 
538
                          self.get_previous_heads([self.inv_C, self.inv_B]))
 
539
 
 
540
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
 
541
        self.assertEqual({'D':self.inv_D['fileid']},
 
542
                         self.get_previous_heads([self.inv_B, self.inv_D]))
 
543
        self.assertEqual({'D':self.inv_D['fileid']},
 
544
                         self.get_previous_heads([self.inv_D, self.inv_B]))
 
545
 
 
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
        self.assertEqual(len(wt.inventory), 1)
 
612
        open('b1/a', 'wb').write('a test\n')
 
613
        wt.add('a')
 
614
        self.assertEqual(len(wt.inventory), 2)
 
615
        os.unlink('b1/a')
 
616
        wt.revert([])
 
617
        self.assertEqual(len(wt.inventory), 1)
 
618
 
 
619
 
 
620
class TestIsRoot(TestCase):
 
621
    """Ensure our root-checking code is accurate."""
 
622
 
 
623
    def test_is_root(self):
 
624
        inv = Inventory('TREE_ROOT')
 
625
        self.assertTrue(inv.is_root('TREE_ROOT'))
 
626
        self.assertFalse(inv.is_root('booga'))
 
627
        inv.root.file_id = 'booga'
 
628
        self.assertFalse(inv.is_root('TREE_ROOT'))
 
629
        self.assertTrue(inv.is_root('booga'))
 
630
        # works properly even if no root is set
 
631
        inv.root = None
 
632
        self.assertFalse(inv.is_root('TREE_ROOT'))
 
633
        self.assertFalse(inv.is_root('booga'))
 
634
 
 
635
 
 
636
class TestTreeReference(TestCase):
 
637
    
 
638
    def test_create(self):
 
639
        inv = Inventory('tree-root-123')
 
640
        inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
 
641
                              revision='rev', reference_revision='rev2'))