~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testinv.py

  • Committer: Robert Collins
  • Date: 2005-10-06 22:15:52 UTC
  • mfrom: (1185.13.2)
  • mto: This revision was merged to the branch mainline in revision 1420.
  • Revision ID: robertc@robertcollins.net-20051006221552-9b15c96fa504e0ad
mergeĀ fromĀ upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 by 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_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
63
    def test_version(self):
125
64
        """Inventory remembers the text's version."""
126
65
        inv = Inventory()
193
132
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
194
133
        self.failIf(link.has_text())
195
134
 
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
 
 
219
 
 
220
 
class TestEntryDiffing(TestCaseWithTransport):
 
135
 
 
136
class TestEntryDiffing(TestCaseInTempDir):
221
137
 
222
138
    def setUp(self):
223
139
        super(TestEntryDiffing, self).setUp()
224
 
        self.wt = self.make_branch_and_tree('.')
225
 
        self.branch = self.wt.branch
 
140
        self.branch = Branch.initialize('.')
226
141
        print >> open('file', 'wb'), 'foo'
227
 
        print >> open('binfile', 'wb'), 'foo'
228
 
        self.wt.add(['file'], ['fileid'])
229
 
        self.wt.add(['binfile'], ['binfileid'])
 
142
        self.branch.add(['file'], ['fileid'])
230
143
        if has_symlinks():
231
144
            os.symlink('target1', 'symlink')
232
 
            self.wt.add(['symlink'], ['linkid'])
233
 
        self.wt.commit('message_1', rev_id = '1')
 
145
            self.branch.add(['symlink'], ['linkid'])
 
146
        self.branch.commit('message_1', rev_id = '1')
234
147
        print >> open('file', 'wb'), 'bar'
235
 
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
236
148
        if has_symlinks():
237
149
            os.unlink('symlink')
238
150
            os.symlink('target2', 'symlink')
239
 
        self.tree_1 = self.branch.repository.revision_tree('1')
240
 
        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')
241
153
        self.file_1 = self.inv_1['fileid']
242
 
        self.file_1b = self.inv_1['binfileid']
243
 
        self.tree_2 = self.wt
244
 
        self.inv_2 = self.tree_2.read_working_inventory()
 
154
        self.tree_2 = self.branch.working_tree()
 
155
        self.inv_2 = self.branch.inventory
245
156
        self.file_2 = self.inv_2['fileid']
246
 
        self.file_2b = self.inv_2['binfileid']
247
157
        if has_symlinks():
248
158
            self.link_1 = self.inv_1['linkid']
249
159
            self.link_2 = self.inv_2['linkid']
285
195
                                            "+bar\n"
286
196
                                            "\n")
287
197
        
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")
296
198
    def test_link_diff_deleted(self):
297
 
        if not has_symlinks():
298
 
            return
299
199
        output = StringIO()
300
200
        self.link_1.diff(internal_diff, 
301
201
                          "old_label", self.tree_1,
305
205
                         "=== target was 'target1'\n")
306
206
 
307
207
    def test_link_diff_added(self):
308
 
        if not has_symlinks():
309
 
            return
310
208
        output = StringIO()
311
209
        self.link_1.diff(internal_diff, 
312
210
                          "new_label", self.tree_1,
316
214
                         "=== target is 'target1'\n")
317
215
 
318
216
    def test_link_diff_changed(self):
319
 
        if not has_symlinks():
320
 
            return
321
217
        output = StringIO()
322
218
        self.link_1.diff(internal_diff, 
323
219
                          "/dev/null", self.tree_1, 
327
223
                         "=== target changed 'target1' => 'target2'\n")
328
224
 
329
225
 
330
 
class TestSnapshot(TestCaseWithTransport):
 
226
class TestSnapshot(TestCaseInTempDir):
331
227
 
332
228
    def setUp(self):
333
229
        # for full testing we'll need a branch
337
233
        # to change, and then test merge patterns
338
234
        # with fake parent entries.
339
235
        super(TestSnapshot, self).setUp()
340
 
        self.wt = self.make_branch_and_tree('.')
341
 
        self.branch = self.wt.branch
342
 
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
343
 
        self.wt.add(['subdir', 'subdir/file'],
344
 
                                       ['dirid', 'fileid'])
 
236
        self.branch = Branch.initialize('.')
 
237
        self.build_tree(['subdir/', 'subdir/file'])
 
238
        self.branch.add(['subdir', 'subdir/file'], ['dirid', 'fileid'])
345
239
        if has_symlinks():
346
240
            pass
347
 
        self.wt.commit('message_1', rev_id = '1')
348
 
        self.tree_1 = self.branch.repository.revision_tree('1')
349
 
        self.inv_1 = self.branch.repository.get_inventory('1')
 
241
        self.branch.commit('message_1', rev_id = '1')
 
242
        self.tree_1 = self.branch.revision_tree('1')
 
243
        self.inv_1 = self.branch.get_inventory('1')
350
244
        self.file_1 = self.inv_1['fileid']
351
 
        self.file_active = self.wt.inventory['fileid']
352
 
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
 
245
        self.work_tree = self.branch.working_tree()
 
246
        self.file_active = self.work_tree.inventory['fileid']
353
247
 
354
248
    def test_snapshot_new_revision(self):
355
249
        # This tests that a simple commit with no parents makes a new
356
250
        # revision value in the inventory entry
357
 
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
 
251
        self.file_active.snapshot('2', 'subdir/file', {}, self.work_tree, 
 
252
                                  self.branch.weave_store)
358
253
        # expected outcome - file_1 has a revision id of '2', and we can get
359
254
        # its text of 'file contents' out of the weave.
360
255
        self.assertEqual(self.file_1.revision, '1')
361
256
        self.assertEqual(self.file_active.revision, '2')
362
257
        # this should be a separate test probably, but lets check it once..
363
 
        lines = self.branch.repository.weave_store.get_weave(
364
 
            'fileid', 
365
 
            self.branch.get_transaction()).get_lines('2')
 
258
        lines = self.branch.weave_store.get_lines('fileid','2')
366
259
        self.assertEqual(lines, ['contents of subdir/file\n'])
367
260
 
368
261
    def test_snapshot_unchanged(self):
369
262
        #This tests that a simple commit does not make a new entry for
370
263
        # an unchanged inventory entry
371
264
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
372
 
                                  self.wt, self.builder)
 
265
                                  self.work_tree, self.branch.weave_store)
373
266
        self.assertEqual(self.file_1.revision, '1')
374
267
        self.assertEqual(self.file_active.revision, '1')
375
 
        vf = self.branch.repository.weave_store.get_weave(
376
 
            'fileid', 
377
 
            self.branch.repository.get_transaction())
378
 
        self.assertRaises(errors.RevisionNotPresent,
379
 
                          vf.get_lines,
380
 
                          '2')
 
268
        self.assertRaises(errors.WeaveError,
 
269
                          self.branch.weave_store.get_lines, 'fileid', '2')
381
270
 
382
271
    def test_snapshot_merge_identical_different_revid(self):
383
272
        # This tests that a commit with two identical parents, one of which has
391
280
        self.assertEqual(self.file_1, other_ie)
392
281
        other_ie.revision = 'other'
393
282
        self.assertNotEqual(self.file_1, other_ie)
394
 
        versionfile = self.branch.repository.weave_store.get_weave(
395
 
            'fileid', self.branch.repository.get_transaction())
396
 
        versionfile.clone_text('other', '1', ['1'])
 
283
        self.branch.weave_store.add_identical_text('fileid', '1', 'other', ['1'])
397
284
        self.file_active.snapshot('2', 'subdir/file', 
398
285
                                  {'1':self.file_1, 'other':other_ie},
399
 
                                  self.wt, self.builder)
 
286
                                  self.work_tree, self.branch.weave_store)
400
287
        self.assertEqual(self.file_active.revision, '2')
401
288
 
402
289
    def test_snapshot_changed(self):
405
292
        self.file_active.name='newname'
406
293
        rename('subdir/file', 'subdir/newname')
407
294
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
408
 
                                  self.wt, self.builder)
 
295
                                  self.work_tree, 
 
296
                                  self.branch.weave_store)
409
297
        # expected outcome - file_1 has a revision id of '2'
410
298
        self.assertEqual(self.file_active.revision, '2')
411
299
 
412
300
 
413
 
class TestPreviousHeads(TestCaseWithTransport):
 
301
class TestPreviousHeads(TestCaseInTempDir):
414
302
 
415
303
    def setUp(self):
416
304
        # we want several inventories, that respectively
422
310
        # D) fileid present in two inventories and one is
423
311
        #   a descendent of the other. (B, D)
424
312
        super(TestPreviousHeads, self).setUp()
425
 
        self.wt = self.make_branch_and_tree('.')
426
 
        self.branch = self.wt.branch
427
313
        self.build_tree(['file'])
428
 
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
429
 
        self.inv_A = self.branch.repository.get_inventory('A')
430
 
        self.wt.add(['file'], ['fileid'])
431
 
        self.wt.commit('add file', rev_id='B')
432
 
        self.inv_B = self.branch.repository.get_inventory('B')
433
 
        uncommit(self.branch, tree=self.wt)
 
314
        self.branch = Branch.initialize('.')
 
315
        self.branch.commit('new branch', allow_pointless=True, rev_id='A')
 
316
        self.inv_A = self.branch.get_inventory('A')
 
317
        self.branch.add(['file'], ['fileid'])
 
318
        self.branch.commit('add file', rev_id='B')
 
319
        self.inv_B = self.branch.get_inventory('B')
 
320
        self.branch.put_controlfile('revision-history', 'A\n')
434
321
        self.assertEqual(self.branch.revision_history(), ['A'])
435
 
        self.wt.commit('another add of file', rev_id='C')
436
 
        self.inv_C = self.branch.repository.get_inventory('C')
437
 
        self.wt.add_parent_tree_id('B')
438
 
        self.wt.commit('merge in B', rev_id='D')
439
 
        self.inv_D = self.branch.repository.get_inventory('D')
440
 
        self.file_active = self.wt.inventory['fileid']
441
 
        self.weave = self.branch.repository.weave_store.get_weave('fileid',
442
 
            self.branch.repository.get_transaction())
 
322
        self.branch.commit('another add of file', rev_id='C')
 
323
        self.inv_C = self.branch.get_inventory('C')
 
324
        self.branch.add_pending_merge('B')
 
325
        self.branch.commit('merge in B', rev_id='D')
 
326
        self.inv_D = self.branch.get_inventory('D')
 
327
        self.file_active = self.branch.working_tree().inventory['fileid']
 
328
        self.weave = self.branch.weave_store.get_weave('fileid')
443
329
        
444
330
    def get_previous_heads(self, inventories):
445
 
        return self.file_active.find_previous_heads(
446
 
            inventories, 
447
 
            self.branch.repository.weave_store,
448
 
            self.branch.repository.get_transaction())
 
331
        return self.file_active.find_previous_heads(inventories, self.weave)
449
332
        
450
333
    def test_fileid_in_no_inventory(self):
451
334
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
473
356
                         self.get_previous_heads([self.inv_D, self.inv_B]))
474
357
 
475
358
    # TODO: test two inventories with the same file revision 
476
 
 
477
 
 
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
 
 
535
 
 
536
 
class TestRevert(TestCaseWithTransport):
537
 
 
538
 
    def test_dangling_id(self):
539
 
        wt = self.make_branch_and_tree('b1')
540
 
        self.assertEqual(len(wt.inventory), 1)
541
 
        open('b1/a', 'wb').write('a test\n')
542
 
        wt.add('a')
543
 
        self.assertEqual(len(wt.inventory), 2)
544
 
        os.unlink('b1/a')
545
 
        wt.revert([])
546
 
        self.assertEqual(len(wt.inventory), 1)