~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testinv.py

- avoid warning about log not being registered during startup

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
from cStringIO import StringIO
18
18
import os
19
 
import time
20
19
 
21
 
from bzrlib import errors, inventory, osutils
22
20
from bzrlib.branch import Branch
 
21
from bzrlib.clone import copy_branch
 
22
import bzrlib.errors as errors
23
23
from bzrlib.diff import internal_diff
24
 
from bzrlib.inventory import (Inventory, ROOT_ID, InventoryFile,
25
 
    InventoryDirectory, InventoryEntry)
26
 
from bzrlib.osutils import (has_symlinks, rename, pathjoin, is_inside_any, 
27
 
    is_inside_or_parent_of_any)
28
 
from bzrlib.tests import TestCase, TestCaseWithTransport
29
 
from bzrlib.transform import TreeTransform
30
 
from bzrlib.uncommit import uncommit
 
24
from bzrlib.inventory import Inventory, ROOT_ID
 
25
import bzrlib.inventory as inventory
 
26
from bzrlib.osutils import has_symlinks, rename
 
27
from bzrlib.selftest import TestCase, TestCaseInTempDir
31
28
 
32
29
 
33
30
class TestInventory(TestCase):
34
31
 
35
32
    def test_is_within(self):
 
33
        from bzrlib.osutils import is_inside_any
36
34
 
37
 
        SRC_FOO_C = pathjoin('src', 'foo.c')
 
35
        SRC_FOO_C = os.path.join('src', 'foo.c')
38
36
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
39
37
                         (['src'], SRC_FOO_C),
40
38
                         (['src'], 'src'),
44
42
        for dirs, fn in [(['src'], 'srccontrol'),
45
43
                         (['src'], 'srccontrol/foo')]:
46
44
            self.assertFalse(is_inside_any(dirs, fn))
47
 
 
48
 
    def test_is_within_or_parent(self):
49
 
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
50
 
                         (['src'], 'src/foo.c'),
51
 
                         (['src/bar.c'], 'src'),
52
 
                         (['src/bar.c', 'bla/foo.c'], 'src'),
53
 
                         (['src'], 'src'),
54
 
                         ]:
55
 
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
56
45
            
57
 
        for dirs, fn in [(['src'], 'srccontrol'),
58
 
                         (['srccontrol/foo.c'], 'src'),
59
 
                         (['src'], 'srccontrol/foo')]:
60
 
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
61
 
 
62
46
    def test_ids(self):
63
47
        """Test detection of files within selected directories."""
64
48
        inv = Inventory()
75
59
        
76
60
        self.assert_('src-id' in inv)
77
61
 
78
 
    def test_non_directory_children(self):
79
 
        """Test path2id when a parent directory has no children"""
80
 
        inv = inventory.Inventory('tree_root')
81
 
        inv.add(inventory.InventoryFile('file-id','file', 
82
 
                                        parent_id='tree_root'))
83
 
        inv.add(inventory.InventoryLink('link-id','link', 
84
 
                                        parent_id='tree_root'))
85
 
        self.assertIs(None, inv.path2id('file/subfile'))
86
 
        self.assertIs(None, inv.path2id('link/subfile'))
87
 
 
88
 
    def test_iter_entries(self):
89
 
        inv = Inventory()
90
 
        
91
 
        for args in [('src', 'directory', 'src-id'), 
92
 
                     ('doc', 'directory', 'doc-id'), 
93
 
                     ('src/hello.c', 'file', 'hello-id'),
94
 
                     ('src/bye.c', 'file', 'bye-id'),
95
 
                     ('Makefile', 'file', 'makefile-id')]:
96
 
            inv.add_path(*args)
97
 
 
98
 
        self.assertEqual([
99
 
            ('', ROOT_ID),
100
 
            ('Makefile', 'makefile-id'),
101
 
            ('doc', 'doc-id'),
102
 
            ('src', 'src-id'),
103
 
            ('src/bye.c', 'bye-id'),
104
 
            ('src/hello.c', 'hello-id'),
105
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries()])
106
 
            
107
 
    def test_iter_entries_by_dir(self):
108
 
        inv = Inventory()
109
 
        
110
 
        for args in [('src', 'directory', 'src-id'), 
111
 
                     ('doc', 'directory', 'doc-id'), 
112
 
                     ('src/hello.c', 'file', 'hello-id'),
113
 
                     ('src/bye.c', 'file', 'bye-id'),
114
 
                     ('zz', 'file', 'zz-id'),
115
 
                     ('src/sub/', 'directory', 'sub-id'),
116
 
                     ('src/zz.c', 'file', 'zzc-id'),
117
 
                     ('src/sub/a', 'file', 'a-id'),
118
 
                     ('Makefile', 'file', 'makefile-id')]:
119
 
            inv.add_path(*args)
120
 
 
121
 
        self.assertEqual([
122
 
            ('', ROOT_ID),
123
 
            ('Makefile', 'makefile-id'),
124
 
            ('doc', 'doc-id'),
125
 
            ('src', 'src-id'),
126
 
            ('zz', 'zz-id'),
127
 
            ('src/bye.c', 'bye-id'),
128
 
            ('src/hello.c', 'hello-id'),
129
 
            ('src/sub', 'sub-id'),
130
 
            ('src/zz.c', 'zzc-id'),
131
 
            ('src/sub/a', 'a-id'),
132
 
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir()])
133
 
            
 
62
 
134
63
    def test_version(self):
135
64
        """Inventory remembers the text's version."""
136
65
        inv = Inventory()
203
132
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
204
133
        self.failIf(link.has_text())
205
134
 
206
 
    def test_make_entry(self):
207
 
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
208
 
            inventory.InventoryFile)
209
 
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
210
 
            inventory.InventoryLink)
211
 
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
212
 
            inventory.InventoryDirectory)
213
 
 
214
 
    def test_make_entry_non_normalized(self):
215
 
        orig_normalized_filename = osutils.normalized_filename
216
 
 
217
 
        try:
218
 
            osutils.normalized_filename = osutils._accessible_normalized_filename
219
 
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
220
 
            self.assertEqual(u'\xe5', entry.name)
221
 
            self.assertIsInstance(entry, inventory.InventoryFile)
222
 
 
223
 
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
224
 
            self.assertRaises(errors.InvalidNormalization,
225
 
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
226
 
        finally:
227
 
            osutils.normalized_filename = orig_normalized_filename
228
 
 
229
 
 
230
 
class TestEntryDiffing(TestCaseWithTransport):
 
135
 
 
136
class TestEntryDiffing(TestCaseInTempDir):
231
137
 
232
138
    def setUp(self):
233
139
        super(TestEntryDiffing, self).setUp()
234
 
        self.wt = self.make_branch_and_tree('.')
235
 
        self.branch = self.wt.branch
 
140
        self.branch = Branch.initialize('.')
236
141
        print >> open('file', 'wb'), 'foo'
237
 
        print >> open('binfile', 'wb'), 'foo'
238
 
        self.wt.add(['file'], ['fileid'])
239
 
        self.wt.add(['binfile'], ['binfileid'])
 
142
        self.branch.add(['file'], ['fileid'])
240
143
        if has_symlinks():
241
144
            os.symlink('target1', 'symlink')
242
 
            self.wt.add(['symlink'], ['linkid'])
243
 
        self.wt.commit('message_1', rev_id = '1')
 
145
            self.branch.add(['symlink'], ['linkid'])
 
146
        self.branch.commit('message_1', rev_id = '1')
244
147
        print >> open('file', 'wb'), 'bar'
245
 
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
246
148
        if has_symlinks():
247
149
            os.unlink('symlink')
248
150
            os.symlink('target2', 'symlink')
249
 
        self.tree_1 = self.branch.repository.revision_tree('1')
250
 
        self.inv_1 = self.branch.repository.get_inventory('1')
 
151
        self.tree_1 = self.branch.revision_tree('1')
 
152
        self.inv_1 = self.branch.get_inventory('1')
251
153
        self.file_1 = self.inv_1['fileid']
252
 
        self.file_1b = self.inv_1['binfileid']
253
 
        self.tree_2 = self.wt
254
 
        self.inv_2 = self.tree_2.read_working_inventory()
 
154
        self.tree_2 = self.branch.working_tree()
 
155
        self.inv_2 = self.branch.inventory
255
156
        self.file_2 = self.inv_2['fileid']
256
 
        self.file_2b = self.inv_2['binfileid']
257
157
        if has_symlinks():
258
158
            self.link_1 = self.inv_1['linkid']
259
159
            self.link_2 = self.inv_2['linkid']
295
195
                                            "+bar\n"
296
196
                                            "\n")
297
197
        
298
 
    def test_file_diff_binary(self):
299
 
        output = StringIO()
300
 
        self.file_1.diff(internal_diff, 
301
 
                          "/dev/null", self.tree_1, 
302
 
                          "new_label", self.file_2b, self.tree_2,
303
 
                          output)
304
 
        self.assertEqual(output.getvalue(), 
305
 
                         "Binary files /dev/null and new_label differ\n")
306
198
    def test_link_diff_deleted(self):
307
199
        if not has_symlinks():
308
200
            return
337
229
                         "=== target changed 'target1' => 'target2'\n")
338
230
 
339
231
 
340
 
class TestSnapshot(TestCaseWithTransport):
 
232
class TestSnapshot(TestCaseInTempDir):
341
233
 
342
234
    def setUp(self):
343
235
        # for full testing we'll need a branch
347
239
        # to change, and then test merge patterns
348
240
        # with fake parent entries.
349
241
        super(TestSnapshot, self).setUp()
350
 
        self.wt = self.make_branch_and_tree('.')
351
 
        self.branch = self.wt.branch
352
 
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
353
 
        self.wt.add(['subdir', 'subdir/file'],
354
 
                                       ['dirid', 'fileid'])
 
242
        self.branch = Branch.initialize('.')
 
243
        self.build_tree(['subdir/', 'subdir/file'])
 
244
        self.branch.add(['subdir', 'subdir/file'], ['dirid', 'fileid'])
355
245
        if has_symlinks():
356
246
            pass
357
 
        self.wt.commit('message_1', rev_id = '1')
358
 
        self.tree_1 = self.branch.repository.revision_tree('1')
359
 
        self.inv_1 = self.branch.repository.get_inventory('1')
 
247
        self.branch.commit('message_1', rev_id = '1')
 
248
        self.tree_1 = self.branch.revision_tree('1')
 
249
        self.inv_1 = self.branch.get_inventory('1')
360
250
        self.file_1 = self.inv_1['fileid']
361
 
        self.file_active = self.wt.inventory['fileid']
362
 
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
 
251
        self.work_tree = self.branch.working_tree()
 
252
        self.file_active = self.work_tree.inventory['fileid']
363
253
 
364
254
    def test_snapshot_new_revision(self):
365
255
        # This tests that a simple commit with no parents makes a new
366
256
        # revision value in the inventory entry
367
 
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
 
257
        self.file_active.snapshot('2', 'subdir/file', {}, self.work_tree, 
 
258
                                  self.branch.weave_store,
 
259
                                  self.branch.get_transaction())
368
260
        # expected outcome - file_1 has a revision id of '2', and we can get
369
261
        # its text of 'file contents' out of the weave.
370
262
        self.assertEqual(self.file_1.revision, '1')
371
263
        self.assertEqual(self.file_active.revision, '2')
372
264
        # this should be a separate test probably, but lets check it once..
373
 
        lines = self.branch.repository.weave_store.get_weave(
374
 
            'fileid', 
375
 
            self.branch.get_transaction()).get_lines('2')
 
265
        lines = self.branch.weave_store.get_lines('fileid','2',
 
266
            self.branch.get_transaction())
376
267
        self.assertEqual(lines, ['contents of subdir/file\n'])
377
268
 
378
269
    def test_snapshot_unchanged(self):
379
270
        #This tests that a simple commit does not make a new entry for
380
271
        # an unchanged inventory entry
381
272
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
382
 
                                  self.wt, self.builder)
 
273
                                  self.work_tree, self.branch.weave_store,
 
274
                                  self.branch.get_transaction())
383
275
        self.assertEqual(self.file_1.revision, '1')
384
276
        self.assertEqual(self.file_active.revision, '1')
385
 
        vf = self.branch.repository.weave_store.get_weave(
386
 
            'fileid', 
387
 
            self.branch.repository.get_transaction())
388
 
        self.assertRaises(errors.RevisionNotPresent,
389
 
                          vf.get_lines,
390
 
                          '2')
 
277
        self.assertRaises(errors.WeaveError,
 
278
                          self.branch.weave_store.get_lines, 'fileid', '2',
 
279
                          self.branch.get_transaction())
391
280
 
392
281
    def test_snapshot_merge_identical_different_revid(self):
393
282
        # This tests that a commit with two identical parents, one of which has
401
290
        self.assertEqual(self.file_1, other_ie)
402
291
        other_ie.revision = 'other'
403
292
        self.assertNotEqual(self.file_1, other_ie)
404
 
        versionfile = self.branch.repository.weave_store.get_weave(
405
 
            'fileid', self.branch.repository.get_transaction())
406
 
        versionfile.clone_text('other', '1', ['1'])
 
293
        self.branch.weave_store.add_identical_text('fileid', '1', 'other', ['1'],
 
294
            self.branch.get_transaction())
407
295
        self.file_active.snapshot('2', 'subdir/file', 
408
296
                                  {'1':self.file_1, 'other':other_ie},
409
 
                                  self.wt, self.builder)
 
297
                                  self.work_tree, self.branch.weave_store,
 
298
                                  self.branch.get_transaction())
410
299
        self.assertEqual(self.file_active.revision, '2')
411
300
 
412
301
    def test_snapshot_changed(self):
415
304
        self.file_active.name='newname'
416
305
        rename('subdir/file', 'subdir/newname')
417
306
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
418
 
                                  self.wt, self.builder)
 
307
                                  self.work_tree, 
 
308
                                  self.branch.weave_store,
 
309
                                  self.branch.get_transaction())
419
310
        # expected outcome - file_1 has a revision id of '2'
420
311
        self.assertEqual(self.file_active.revision, '2')
421
312
 
422
313
 
423
 
class TestPreviousHeads(TestCaseWithTransport):
 
314
class TestPreviousHeads(TestCaseInTempDir):
424
315
 
425
316
    def setUp(self):
426
317
        # we want several inventories, that respectively
432
323
        # D) fileid present in two inventories and one is
433
324
        #   a descendent of the other. (B, D)
434
325
        super(TestPreviousHeads, self).setUp()
435
 
        self.wt = self.make_branch_and_tree('.')
436
 
        self.branch = self.wt.branch
437
326
        self.build_tree(['file'])
438
 
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
439
 
        self.inv_A = self.branch.repository.get_inventory('A')
440
 
        self.wt.add(['file'], ['fileid'])
441
 
        self.wt.commit('add file', rev_id='B')
442
 
        self.inv_B = self.branch.repository.get_inventory('B')
443
 
        uncommit(self.branch, tree=self.wt)
 
327
        self.branch = Branch.initialize('.')
 
328
        self.branch.commit('new branch', allow_pointless=True, rev_id='A')
 
329
        self.inv_A = self.branch.get_inventory('A')
 
330
        self.branch.add(['file'], ['fileid'])
 
331
        self.branch.commit('add file', rev_id='B')
 
332
        self.inv_B = self.branch.get_inventory('B')
 
333
        self.branch.put_controlfile('revision-history', 'A\n')
444
334
        self.assertEqual(self.branch.revision_history(), ['A'])
445
 
        self.wt.commit('another add of file', rev_id='C')
446
 
        self.inv_C = self.branch.repository.get_inventory('C')
447
 
        self.wt.add_parent_tree_id('B')
448
 
        self.wt.commit('merge in B', rev_id='D')
449
 
        self.inv_D = self.branch.repository.get_inventory('D')
450
 
        self.file_active = self.wt.inventory['fileid']
451
 
        self.weave = self.branch.repository.weave_store.get_weave('fileid',
452
 
            self.branch.repository.get_transaction())
 
335
        self.branch.commit('another add of file', rev_id='C')
 
336
        self.inv_C = self.branch.get_inventory('C')
 
337
        self.branch.add_pending_merge('B')
 
338
        self.branch.commit('merge in B', rev_id='D')
 
339
        self.inv_D = self.branch.get_inventory('D')
 
340
        self.file_active = self.branch.working_tree().inventory['fileid']
 
341
        self.weave = self.branch.weave_store.get_weave('fileid',
 
342
            self.branch.get_transaction())
453
343
        
454
344
    def get_previous_heads(self, inventories):
455
 
        return self.file_active.find_previous_heads(
456
 
            inventories, 
457
 
            self.branch.repository.weave_store,
458
 
            self.branch.repository.get_transaction())
 
345
        return self.file_active.find_previous_heads(inventories, self.weave)
459
346
        
460
347
    def test_fileid_in_no_inventory(self):
461
348
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
483
370
                         self.get_previous_heads([self.inv_D, self.inv_B]))
484
371
 
485
372
    # TODO: test two inventories with the same file revision 
486
 
 
487
 
 
488
 
class TestDescribeChanges(TestCase):
489
 
 
490
 
    def test_describe_change(self):
491
 
        # we need to test the following change combinations:
492
 
        # rename
493
 
        # reparent
494
 
        # modify
495
 
        # gone
496
 
        # added
497
 
        # renamed/reparented and modified
498
 
        # change kind (perhaps can't be done yet?)
499
 
        # also, merged in combination with all of these?
500
 
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
501
 
        old_a.text_sha1 = '123132'
502
 
        old_a.text_size = 0
503
 
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
504
 
        new_a.text_sha1 = '123132'
505
 
        new_a.text_size = 0
506
 
 
507
 
        self.assertChangeDescription('unchanged', old_a, new_a)
508
 
 
509
 
        new_a.text_size = 10
510
 
        new_a.text_sha1 = 'abcabc'
511
 
        self.assertChangeDescription('modified', old_a, new_a)
512
 
 
513
 
        self.assertChangeDescription('added', None, new_a)
514
 
        self.assertChangeDescription('removed', old_a, None)
515
 
        # perhaps a bit questionable but seems like the most reasonable thing...
516
 
        self.assertChangeDescription('unchanged', None, None)
517
 
 
518
 
        # in this case it's both renamed and modified; show a rename and 
519
 
        # modification:
520
 
        new_a.name = 'newfilename'
521
 
        self.assertChangeDescription('modified and renamed', old_a, new_a)
522
 
 
523
 
        # reparenting is 'renaming'
524
 
        new_a.name = old_a.name
525
 
        new_a.parent_id = 'somedir-id'
526
 
        self.assertChangeDescription('modified and renamed', old_a, new_a)
527
 
 
528
 
        # reset the content values so its not modified
529
 
        new_a.text_size = old_a.text_size
530
 
        new_a.text_sha1 = old_a.text_sha1
531
 
        new_a.name = old_a.name
532
 
 
533
 
        new_a.name = 'newfilename'
534
 
        self.assertChangeDescription('renamed', old_a, new_a)
535
 
 
536
 
        # reparenting is 'renaming'
537
 
        new_a.name = old_a.name
538
 
        new_a.parent_id = 'somedir-id'
539
 
        self.assertChangeDescription('renamed', old_a, new_a)
540
 
 
541
 
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
542
 
        change = InventoryEntry.describe_change(old_ie, new_ie)
543
 
        self.assertEqual(expected_change, change)
544
 
 
545
 
 
546
 
class TestRevert(TestCaseWithTransport):
547
 
 
548
 
    def test_dangling_id(self):
549
 
        wt = self.make_branch_and_tree('b1')
550
 
        self.assertEqual(len(wt.inventory), 1)
551
 
        open('b1/a', 'wb').write('a test\n')
552
 
        wt.add('a')
553
 
        self.assertEqual(len(wt.inventory), 2)
554
 
        os.unlink('b1/a')
555
 
        wt.revert([])
556
 
        self.assertEqual(len(wt.inventory), 1)
557
 
 
558
 
 
559
 
class TestIsRoot(TestCase):
560
 
    """Ensure our root-checking code is accurate."""
561
 
 
562
 
    def test_is_root(self):
563
 
        inv = Inventory('TREE_ROOT')
564
 
        self.assertTrue(inv.is_root('TREE_ROOT'))
565
 
        self.assertFalse(inv.is_root('booga'))
566
 
        inv.root.file_id = 'booga'
567
 
        self.assertFalse(inv.is_root('TREE_ROOT'))
568
 
        self.assertTrue(inv.is_root('booga'))
569
 
        # works properly even if no root is set
570
 
        inv.root = None
571
 
        self.assertFalse(inv.is_root('TREE_ROOT'))
572
 
        self.assertFalse(inv.is_root('booga'))