~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_inv.py

  • Committer: Aaron Bentley
  • Date: 2007-02-06 14:52:16 UTC
  • mfrom: (2266 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2268.
  • Revision ID: abentley@panoramicfeedback.com-20070206145216-fcpi8o3ufvuzwbp9
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
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
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
from cStringIO import StringIO
 
18
import os
 
19
import time
17
20
 
18
21
from bzrlib import errors, inventory, osutils
 
22
from bzrlib.branch import Branch
 
23
from bzrlib.diff import internal_diff
19
24
from bzrlib.inventory import (Inventory, ROOT_ID, InventoryFile,
20
 
    InventoryDirectory, InventoryEntry, TreeReference)
21
 
from bzrlib.tests import TestCase
 
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
        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
22
192
 
23
193
 
24
194
class TestInventoryEntry(TestCase):
110
280
            osutils.normalized_filename = orig_normalized_filename
111
281
 
112
282
 
 
283
class TestEntryDiffing(TestCaseWithTransport):
 
284
 
 
285
    def setUp(self):
 
286
        super(TestEntryDiffing, self).setUp()
 
287
        self.wt = self.make_branch_and_tree('.')
 
288
        self.branch = self.wt.branch
 
289
        print >> open('file', 'wb'), 'foo'
 
290
        print >> open('binfile', 'wb'), 'foo'
 
291
        self.wt.add(['file'], ['fileid'])
 
292
        self.wt.add(['binfile'], ['binfileid'])
 
293
        if has_symlinks():
 
294
            os.symlink('target1', 'symlink')
 
295
            self.wt.add(['symlink'], ['linkid'])
 
296
        self.wt.commit('message_1', rev_id = '1')
 
297
        print >> open('file', 'wb'), 'bar'
 
298
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
 
299
        if has_symlinks():
 
300
            os.unlink('symlink')
 
301
            os.symlink('target2', 'symlink')
 
302
        self.tree_1 = self.branch.repository.revision_tree('1')
 
303
        self.inv_1 = self.branch.repository.get_inventory('1')
 
304
        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()
 
308
        self.file_2 = self.inv_2['fileid']
 
309
        self.file_2b = self.inv_2['binfileid']
 
310
        if has_symlinks():
 
311
            self.link_1 = self.inv_1['linkid']
 
312
            self.link_2 = self.inv_2['linkid']
 
313
 
 
314
    def test_file_diff_deleted(self):
 
315
        output = StringIO()
 
316
        self.file_1.diff(internal_diff, 
 
317
                          "old_label", self.tree_1,
 
318
                          "/dev/null", None, None,
 
319
                          output)
 
320
        self.assertEqual(output.getvalue(), "--- old_label\n"
 
321
                                            "+++ /dev/null\n"
 
322
                                            "@@ -1,1 +0,0 @@\n"
 
323
                                            "-foo\n"
 
324
                                            "\n")
 
325
 
 
326
    def test_file_diff_added(self):
 
327
        output = StringIO()
 
328
        self.file_1.diff(internal_diff, 
 
329
                          "new_label", self.tree_1,
 
330
                          "/dev/null", None, None,
 
331
                          output, reverse=True)
 
332
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
 
333
                                            "+++ new_label\n"
 
334
                                            "@@ -0,0 +1,1 @@\n"
 
335
                                            "+foo\n"
 
336
                                            "\n")
 
337
 
 
338
    def test_file_diff_changed(self):
 
339
        output = StringIO()
 
340
        self.file_1.diff(internal_diff, 
 
341
                          "/dev/null", self.tree_1, 
 
342
                          "new_label", self.file_2, self.tree_2,
 
343
                          output)
 
344
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
 
345
                                            "+++ new_label\n"
 
346
                                            "@@ -1,1 +1,1 @@\n"
 
347
                                            "-foo\n"
 
348
                                            "+bar\n"
 
349
                                            "\n")
 
350
        
 
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
    def test_link_diff_deleted(self):
 
360
        if not has_symlinks():
 
361
            return
 
362
        output = StringIO()
 
363
        self.link_1.diff(internal_diff, 
 
364
                          "old_label", self.tree_1,
 
365
                          "/dev/null", None, None,
 
366
                          output)
 
367
        self.assertEqual(output.getvalue(),
 
368
                         "=== target was 'target1'\n")
 
369
 
 
370
    def test_link_diff_added(self):
 
371
        if not has_symlinks():
 
372
            return
 
373
        output = StringIO()
 
374
        self.link_1.diff(internal_diff, 
 
375
                          "new_label", self.tree_1,
 
376
                          "/dev/null", None, None,
 
377
                          output, reverse=True)
 
378
        self.assertEqual(output.getvalue(),
 
379
                         "=== target is 'target1'\n")
 
380
 
 
381
    def test_link_diff_changed(self):
 
382
        if not has_symlinks():
 
383
            return
 
384
        output = StringIO()
 
385
        self.link_1.diff(internal_diff, 
 
386
                          "/dev/null", self.tree_1, 
 
387
                          "new_label", self.link_2, self.tree_2,
 
388
                          output)
 
389
        self.assertEqual(output.getvalue(),
 
390
                         "=== target changed 'target1' => 'target2'\n")
 
391
 
 
392
 
 
393
class TestSnapshot(TestCaseWithTransport):
 
394
 
 
395
    def setUp(self):
 
396
        # for full testing we'll need a branch
 
397
        # with a subdir to test parent changes.
 
398
        # and a file, link and dir under that.
 
399
        # but right now I only need one attribute
 
400
        # to change, and then test merge patterns
 
401
        # with fake parent entries.
 
402
        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'])
 
408
        if has_symlinks():
 
409
            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')
 
413
        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')
 
416
 
 
417
    def test_snapshot_new_revision(self):
 
418
        # This tests that a simple commit with no parents makes a new
 
419
        # revision value in the inventory entry
 
420
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
 
421
        # expected outcome - file_1 has a revision id of '2', and we can get
 
422
        # its text of 'file contents' out of the weave.
 
423
        self.assertEqual(self.file_1.revision, '1')
 
424
        self.assertEqual(self.file_active.revision, '2')
 
425
        # 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')
 
429
        self.assertEqual(lines, ['contents of subdir/file\n'])
 
430
 
 
431
    def test_snapshot_unchanged(self):
 
432
        #This tests that a simple commit does not make a new entry for
 
433
        # an unchanged inventory entry
 
434
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
 
435
                                  self.wt, self.builder)
 
436
        self.assertEqual(self.file_1.revision, '1')
 
437
        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')
 
444
 
 
445
    def test_snapshot_merge_identical_different_revid(self):
 
446
        # This tests that a commit with two identical parents, one of which has
 
447
        # a different revision id, results in a new revision id in the entry.
 
448
        # 1->other, commit a merge of other against 1, results in 2.
 
449
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
 
450
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
 
451
        other_ie.revision = '1'
 
452
        other_ie.text_sha1 = self.file_1.text_sha1
 
453
        other_ie.text_size = self.file_1.text_size
 
454
        self.assertEqual(self.file_1, other_ie)
 
455
        other_ie.revision = 'other'
 
456
        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'])
 
460
        self.file_active.snapshot('2', 'subdir/file', 
 
461
                                  {'1':self.file_1, 'other':other_ie},
 
462
                                  self.wt, self.builder)
 
463
        self.assertEqual(self.file_active.revision, '2')
 
464
 
 
465
    def test_snapshot_changed(self):
 
466
        # This tests that a commit with one different parent results in a new
 
467
        # revision id in the entry.
 
468
        self.file_active.name='newname'
 
469
        rename('subdir/file', 'subdir/newname')
 
470
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
 
471
                                  self.wt, self.builder)
 
472
        # expected outcome - file_1 has a revision id of '2'
 
473
        self.assertEqual(self.file_active.revision, '2')
 
474
 
 
475
 
 
476
class TestPreviousHeads(TestCaseWithTransport):
 
477
 
 
478
    def setUp(self):
 
479
        # we want several inventories, that respectively
 
480
        # give use the following scenarios:
 
481
        # A) fileid not in any inventory (A),
 
482
        # B) fileid present in one inventory (B) and (A,B)
 
483
        # C) fileid present in two inventories, and they
 
484
        #   are not mutual descendents (B, C)
 
485
        # D) fileid present in two inventories and one is
 
486
        #   a descendent of the other. (B, D)
 
487
        super(TestPreviousHeads, self).setUp()
 
488
        self.wt = self.make_branch_and_tree('.')
 
489
        self.branch = self.wt.branch
 
490
        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)
 
497
        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())
 
506
        
 
507
    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())
 
512
        
 
513
    def test_fileid_in_no_inventory(self):
 
514
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
 
515
 
 
516
    def test_fileid_in_one_inventory(self):
 
517
        self.assertEqual({'B':self.inv_B['fileid']},
 
518
                         self.get_previous_heads([self.inv_B]))
 
519
        self.assertEqual({'B':self.inv_B['fileid']},
 
520
                         self.get_previous_heads([self.inv_A, self.inv_B]))
 
521
        self.assertEqual({'B':self.inv_B['fileid']},
 
522
                         self.get_previous_heads([self.inv_B, self.inv_A]))
 
523
 
 
524
    def test_fileid_in_two_inventories_gives_both_entries(self):
 
525
        self.assertEqual({'B':self.inv_B['fileid'],
 
526
                          'C':self.inv_C['fileid']},
 
527
                          self.get_previous_heads([self.inv_B, self.inv_C]))
 
528
        self.assertEqual({'B':self.inv_B['fileid'],
 
529
                          'C':self.inv_C['fileid']},
 
530
                          self.get_previous_heads([self.inv_C, self.inv_B]))
 
531
 
 
532
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
 
533
        self.assertEqual({'D':self.inv_D['fileid']},
 
534
                         self.get_previous_heads([self.inv_B, self.inv_D]))
 
535
        self.assertEqual({'D':self.inv_D['fileid']},
 
536
                         self.get_previous_heads([self.inv_D, self.inv_B]))
 
537
 
 
538
    # TODO: test two inventories with the same file revision 
 
539
 
 
540
 
113
541
class TestDescribeChanges(TestCase):
114
542
 
115
543
    def test_describe_change(self):
166
594
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
167
595
        change = InventoryEntry.describe_change(old_ie, new_ie)
168
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'))