/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: Martin Pool
  • Date: 2006-10-06 02:04:17 UTC
  • mfrom: (1908.10.1 bench_usecases.merge2)
  • mto: This revision was merged to the branch mainline in revision 2068.
  • Revision ID: mbp@sourcefrog.net-20061006020417-4949ca86f4417a4d
merge additional fix from cfbolz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 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
19
20
 
 
21
from bzrlib import errors, inventory, osutils
20
22
from bzrlib.branch import Branch
21
 
import bzrlib.errors as errors
22
23
from bzrlib.diff import internal_diff
23
 
from bzrlib.inventory import Inventory, ROOT_ID
24
 
import bzrlib.inventory as inventory
25
 
from bzrlib.osutils import has_symlinks, rename, pathjoin
 
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)
26
28
from bzrlib.tests import TestCase, TestCaseWithTransport
 
29
from bzrlib.transform import TreeTransform
 
30
from bzrlib.uncommit import uncommit
27
31
 
28
32
 
29
33
class TestInventory(TestCase):
30
34
 
31
35
    def test_is_within(self):
32
 
        from bzrlib.osutils import is_inside_any
33
36
 
34
37
        SRC_FOO_C = pathjoin('src', 'foo.c')
35
38
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
41
44
        for dirs, fn in [(['src'], 'srccontrol'),
42
45
                         (['src'], 'srccontrol/foo')]:
43
46
            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))
44
56
            
 
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
 
45
62
    def test_ids(self):
46
63
        """Test detection of files within selected directories."""
47
64
        inv = Inventory()
58
75
        
59
76
        self.assert_('src-id' in inv)
60
77
 
61
 
 
 
78
    def test_iter_entries(self):
 
79
        inv = Inventory()
 
80
        
 
81
        for args in [('src', 'directory', 'src-id'), 
 
82
                     ('doc', 'directory', 'doc-id'), 
 
83
                     ('src/hello.c', 'file', 'hello-id'),
 
84
                     ('src/bye.c', 'file', 'bye-id'),
 
85
                     ('Makefile', 'file', 'makefile-id')]:
 
86
            inv.add_path(*args)
 
87
 
 
88
        self.assertEqual([
 
89
            ('', ROOT_ID),
 
90
            ('Makefile', 'makefile-id'),
 
91
            ('doc', 'doc-id'),
 
92
            ('src', 'src-id'),
 
93
            ('src/bye.c', 'bye-id'),
 
94
            ('src/hello.c', 'hello-id'),
 
95
            ], [(path, ie.file_id) for path, ie in inv.iter_entries()])
 
96
            
 
97
    def test_iter_entries_by_dir(self):
 
98
        inv = Inventory()
 
99
        
 
100
        for args in [('src', 'directory', 'src-id'), 
 
101
                     ('doc', 'directory', 'doc-id'), 
 
102
                     ('src/hello.c', 'file', 'hello-id'),
 
103
                     ('src/bye.c', 'file', 'bye-id'),
 
104
                     ('zz', 'file', 'zz-id'),
 
105
                     ('src/sub/', 'directory', 'sub-id'),
 
106
                     ('src/zz.c', 'file', 'zzc-id'),
 
107
                     ('src/sub/a', 'file', 'a-id'),
 
108
                     ('Makefile', 'file', 'makefile-id')]:
 
109
            inv.add_path(*args)
 
110
 
 
111
        self.assertEqual([
 
112
            ('', ROOT_ID),
 
113
            ('Makefile', 'makefile-id'),
 
114
            ('doc', 'doc-id'),
 
115
            ('src', 'src-id'),
 
116
            ('zz', 'zz-id'),
 
117
            ('src/bye.c', 'bye-id'),
 
118
            ('src/hello.c', 'hello-id'),
 
119
            ('src/sub', 'sub-id'),
 
120
            ('src/zz.c', 'zzc-id'),
 
121
            ('src/sub/a', 'a-id'),
 
122
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir()])
 
123
            
62
124
    def test_version(self):
63
125
        """Inventory remembers the text's version."""
64
126
        inv = Inventory()
131
193
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
132
194
        self.failIf(link.has_text())
133
195
 
 
196
    def test_make_entry(self):
 
197
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
 
198
            inventory.InventoryFile)
 
199
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
 
200
            inventory.InventoryLink)
 
201
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
 
202
            inventory.InventoryDirectory)
 
203
 
 
204
    def test_make_entry_non_normalized(self):
 
205
        orig_normalized_filename = osutils.normalized_filename
 
206
 
 
207
        try:
 
208
            osutils.normalized_filename = osutils._accessible_normalized_filename
 
209
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
 
210
            self.assertEqual(u'\xe5', entry.name)
 
211
            self.assertIsInstance(entry, inventory.InventoryFile)
 
212
 
 
213
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
 
214
            self.assertRaises(errors.InvalidNormalization,
 
215
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
 
216
        finally:
 
217
            osutils.normalized_filename = orig_normalized_filename
 
218
 
134
219
 
135
220
class TestEntryDiffing(TestCaseWithTransport):
136
221
 
139
224
        self.wt = self.make_branch_and_tree('.')
140
225
        self.branch = self.wt.branch
141
226
        print >> open('file', 'wb'), 'foo'
 
227
        print >> open('binfile', 'wb'), 'foo'
142
228
        self.wt.add(['file'], ['fileid'])
 
229
        self.wt.add(['binfile'], ['binfileid'])
143
230
        if has_symlinks():
144
231
            os.symlink('target1', 'symlink')
145
232
            self.wt.add(['symlink'], ['linkid'])
146
233
        self.wt.commit('message_1', rev_id = '1')
147
234
        print >> open('file', 'wb'), 'bar'
 
235
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
148
236
        if has_symlinks():
149
237
            os.unlink('symlink')
150
238
            os.symlink('target2', 'symlink')
151
239
        self.tree_1 = self.branch.repository.revision_tree('1')
152
240
        self.inv_1 = self.branch.repository.get_inventory('1')
153
241
        self.file_1 = self.inv_1['fileid']
 
242
        self.file_1b = self.inv_1['binfileid']
154
243
        self.tree_2 = self.wt
155
244
        self.inv_2 = self.tree_2.read_working_inventory()
156
245
        self.file_2 = self.inv_2['fileid']
 
246
        self.file_2b = self.inv_2['binfileid']
157
247
        if has_symlinks():
158
248
            self.link_1 = self.inv_1['linkid']
159
249
            self.link_2 = self.inv_2['linkid']
164
254
                          "old_label", self.tree_1,
165
255
                          "/dev/null", None, None,
166
256
                          output)
167
 
        self.assertEqual(output.getvalue(), "--- old_label\t\n"
168
 
                                            "+++ /dev/null\t\n"
 
257
        self.assertEqual(output.getvalue(), "--- old_label\n"
 
258
                                            "+++ /dev/null\n"
169
259
                                            "@@ -1,1 +0,0 @@\n"
170
260
                                            "-foo\n"
171
261
                                            "\n")
176
266
                          "new_label", self.tree_1,
177
267
                          "/dev/null", None, None,
178
268
                          output, reverse=True)
179
 
        self.assertEqual(output.getvalue(), "--- /dev/null\t\n"
180
 
                                            "+++ new_label\t\n"
 
269
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
 
270
                                            "+++ new_label\n"
181
271
                                            "@@ -0,0 +1,1 @@\n"
182
272
                                            "+foo\n"
183
273
                                            "\n")
188
278
                          "/dev/null", self.tree_1, 
189
279
                          "new_label", self.file_2, self.tree_2,
190
280
                          output)
191
 
        self.assertEqual(output.getvalue(), "--- /dev/null\t\n"
192
 
                                            "+++ new_label\t\n"
 
281
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
 
282
                                            "+++ new_label\n"
193
283
                                            "@@ -1,1 +1,1 @@\n"
194
284
                                            "-foo\n"
195
285
                                            "+bar\n"
196
286
                                            "\n")
197
287
        
 
288
    def test_file_diff_binary(self):
 
289
        output = StringIO()
 
290
        self.file_1.diff(internal_diff, 
 
291
                          "/dev/null", self.tree_1, 
 
292
                          "new_label", self.file_2b, self.tree_2,
 
293
                          output)
 
294
        self.assertEqual(output.getvalue(), 
 
295
                         "Binary files /dev/null and new_label differ\n")
198
296
    def test_link_diff_deleted(self):
199
297
        if not has_symlinks():
200
298
            return
251
349
        self.inv_1 = self.branch.repository.get_inventory('1')
252
350
        self.file_1 = self.inv_1['fileid']
253
351
        self.file_active = self.wt.inventory['fileid']
 
352
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
254
353
 
255
354
    def test_snapshot_new_revision(self):
256
355
        # This tests that a simple commit with no parents makes a new
257
356
        # revision value in the inventory entry
258
 
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, 
259
 
                                  self.branch.repository.weave_store,
260
 
                                  self.branch.get_transaction())
 
357
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
261
358
        # expected outcome - file_1 has a revision id of '2', and we can get
262
359
        # its text of 'file contents' out of the weave.
263
360
        self.assertEqual(self.file_1.revision, '1')
272
369
        #This tests that a simple commit does not make a new entry for
273
370
        # an unchanged inventory entry
274
371
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
275
 
                                  self.wt, 
276
 
                                  self.branch.repository.weave_store,
277
 
                                  self.branch.get_transaction())
 
372
                                  self.wt, self.builder)
278
373
        self.assertEqual(self.file_1.revision, '1')
279
374
        self.assertEqual(self.file_active.revision, '1')
280
375
        vf = self.branch.repository.weave_store.get_weave(
301
396
        versionfile.clone_text('other', '1', ['1'])
302
397
        self.file_active.snapshot('2', 'subdir/file', 
303
398
                                  {'1':self.file_1, 'other':other_ie},
304
 
                                  self.wt, 
305
 
                                  self.branch.repository.weave_store,
306
 
                                  self.branch.get_transaction())
 
399
                                  self.wt, self.builder)
307
400
        self.assertEqual(self.file_active.revision, '2')
308
401
 
309
402
    def test_snapshot_changed(self):
312
405
        self.file_active.name='newname'
313
406
        rename('subdir/file', 'subdir/newname')
314
407
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
315
 
                                  self.wt,
316
 
                                  self.branch.repository.weave_store,
317
 
                                  self.branch.get_transaction())
 
408
                                  self.wt, self.builder)
318
409
        # expected outcome - file_1 has a revision id of '2'
319
410
        self.assertEqual(self.file_active.revision, '2')
320
411
 
339
430
        self.wt.add(['file'], ['fileid'])
340
431
        self.wt.commit('add file', rev_id='B')
341
432
        self.inv_B = self.branch.repository.get_inventory('B')
342
 
        self.branch.lock_write()
343
 
        try:
344
 
            self.branch.control_files.put_utf8('revision-history', 'A\n')
345
 
        finally:
346
 
            self.branch.unlock()
 
433
        uncommit(self.branch, tree=self.wt)
347
434
        self.assertEqual(self.branch.revision_history(), ['A'])
348
435
        self.wt.commit('another add of file', rev_id='C')
349
436
        self.inv_C = self.branch.repository.get_inventory('C')
350
 
        self.wt.add_pending_merge('B')
 
437
        self.wt.add_parent_tree_id('B')
351
438
        self.wt.commit('merge in B', rev_id='D')
352
439
        self.inv_D = self.branch.repository.get_inventory('D')
353
440
        self.file_active = self.wt.inventory['fileid']
388
475
    # TODO: test two inventories with the same file revision 
389
476
 
390
477
 
391
 
class TestExecutable(TestCaseWithTransport):
392
 
 
393
 
    def test_stays_executable(self):
394
 
        basic_inv = """<inventory format="5">
395
 
<file file_id="a-20051208024829-849e76f7968d7a86" name="a" executable="yes" />
396
 
<file file_id="b-20051208024829-849e76f7968d7a86" name="b" />
397
 
</inventory>
398
 
"""
399
 
        wt = self.make_branch_and_tree('b1')
400
 
        b = wt.branch
401
 
        open('b1/a', 'wb').write('a test\n')
402
 
        open('b1/b', 'wb').write('b test\n')
403
 
        os.chmod('b1/a', 0755)
404
 
        os.chmod('b1/b', 0644)
405
 
        # Manually writing the inventory, to ensure that
406
 
        # the executable="yes" entry is set for 'a' and not for 'b'
407
 
        open('b1/.bzr/inventory', 'wb').write(basic_inv)
408
 
 
409
 
        a_id = "a-20051208024829-849e76f7968d7a86"
410
 
        b_id = "b-20051208024829-849e76f7968d7a86"
411
 
        wt = wt.bzrdir.open_workingtree()
412
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
413
 
 
414
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
415
 
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
416
 
 
417
 
        wt.commit('adding a,b', rev_id='r1')
418
 
 
419
 
        rev_tree = b.repository.revision_tree('r1')
420
 
        self.failUnless(rev_tree.is_executable(a_id), "'a' lost the execute bit")
421
 
        self.failIf(rev_tree.is_executable(b_id), "'b' gained an execute bit")
422
 
 
423
 
        self.failUnless(rev_tree.inventory[a_id].executable)
424
 
        self.failIf(rev_tree.inventory[b_id].executable)
425
 
 
426
 
        # Make sure the entries are gone
427
 
        os.remove('b1/a')
428
 
        os.remove('b1/b')
429
 
        self.failIf(wt.has_id(a_id))
430
 
        self.failIf(wt.has_filename('a'))
431
 
        self.failIf(wt.has_id(b_id))
432
 
        self.failIf(wt.has_filename('b'))
433
 
 
434
 
        # Make sure that revert is able to bring them back,
435
 
        # and sets 'a' back to being executable
436
 
 
437
 
        wt.revert(['a', 'b'], rev_tree, backups=False)
438
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
439
 
 
440
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
441
 
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
442
 
 
443
 
        # Now remove them again, and make sure that after a
444
 
        # commit, they are still marked correctly
445
 
        os.remove('b1/a')
446
 
        os.remove('b1/b')
447
 
        wt.commit('removed', rev_id='r2')
448
 
 
449
 
        self.assertEqual([], [cn for cn,ie in wt.inventory.iter_entries()])
450
 
        self.failIf(wt.has_id(a_id))
451
 
        self.failIf(wt.has_filename('a'))
452
 
        self.failIf(wt.has_id(b_id))
453
 
        self.failIf(wt.has_filename('b'))
454
 
 
455
 
        # Now revert back to the previous commit
456
 
        wt.revert([], rev_tree, backups=False)
457
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
458
 
 
459
 
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
460
 
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
461
 
 
462
 
        # Now make sure that 'bzr branch' also preserves the
463
 
        # executable bit
464
 
        # TODO: Maybe this should be a blackbox test
465
 
        d2 = b.bzrdir.clone('b2', revision_id='r1')
466
 
        t2 = d2.open_workingtree()
467
 
        b2 = t2.branch
468
 
        self.assertEquals('r1', b2.last_revision())
469
 
 
470
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
471
 
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
472
 
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
473
 
 
474
 
        # Make sure pull will delete the files
475
 
        t2.pull(b)
476
 
        self.assertEquals('r2', b2.last_revision())
477
 
        self.assertEqual([], [cn for cn,ie in t2.inventory.iter_entries()])
478
 
 
479
 
        # Now commit the changes on the first branch
480
 
        # so that the second branch can pull the changes
481
 
        # and make sure that the executable bit has been copied
482
 
        wt.commit('resurrected', rev_id='r3')
483
 
 
484
 
        t2.pull(b)
485
 
        self.assertEquals('r3', b2.last_revision())
486
 
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
487
 
 
488
 
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
489
 
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
 
478
class TestDescribeChanges(TestCase):
 
479
 
 
480
    def test_describe_change(self):
 
481
        # we need to test the following change combinations:
 
482
        # rename
 
483
        # reparent
 
484
        # modify
 
485
        # gone
 
486
        # added
 
487
        # renamed/reparented and modified
 
488
        # change kind (perhaps can't be done yet?)
 
489
        # also, merged in combination with all of these?
 
490
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
 
491
        old_a.text_sha1 = '123132'
 
492
        old_a.text_size = 0
 
493
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
 
494
        new_a.text_sha1 = '123132'
 
495
        new_a.text_size = 0
 
496
 
 
497
        self.assertChangeDescription('unchanged', old_a, new_a)
 
498
 
 
499
        new_a.text_size = 10
 
500
        new_a.text_sha1 = 'abcabc'
 
501
        self.assertChangeDescription('modified', old_a, new_a)
 
502
 
 
503
        self.assertChangeDescription('added', None, new_a)
 
504
        self.assertChangeDescription('removed', old_a, None)
 
505
        # perhaps a bit questionable but seems like the most reasonable thing...
 
506
        self.assertChangeDescription('unchanged', None, None)
 
507
 
 
508
        # in this case it's both renamed and modified; show a rename and 
 
509
        # modification:
 
510
        new_a.name = 'newfilename'
 
511
        self.assertChangeDescription('modified and renamed', old_a, new_a)
 
512
 
 
513
        # reparenting is 'renaming'
 
514
        new_a.name = old_a.name
 
515
        new_a.parent_id = 'somedir-id'
 
516
        self.assertChangeDescription('modified and renamed', old_a, new_a)
 
517
 
 
518
        # reset the content values so its not modified
 
519
        new_a.text_size = old_a.text_size
 
520
        new_a.text_sha1 = old_a.text_sha1
 
521
        new_a.name = old_a.name
 
522
 
 
523
        new_a.name = 'newfilename'
 
524
        self.assertChangeDescription('renamed', old_a, new_a)
 
525
 
 
526
        # reparenting is 'renaming'
 
527
        new_a.name = old_a.name
 
528
        new_a.parent_id = 'somedir-id'
 
529
        self.assertChangeDescription('renamed', old_a, new_a)
 
530
 
 
531
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
 
532
        change = InventoryEntry.describe_change(old_ie, new_ie)
 
533
        self.assertEqual(expected_change, change)
 
534
 
490
535
 
491
536
class TestRevert(TestCaseWithTransport):
 
537
 
492
538
    def test_dangling_id(self):
493
539
        wt = self.make_branch_and_tree('b1')
494
540
        self.assertEqual(len(wt.inventory), 1)
498
544
        os.unlink('b1/a')
499
545
        wt.revert([])
500
546
        self.assertEqual(len(wt.inventory), 1)
501
 
 
502