/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
963 by Martin Pool
- add the start of a test for inventory file-id matching
1
# Copyright (C) 2005 by 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
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
17
from cStringIO import StringIO
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
18
import os
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
19
import time
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
20
21
from bzrlib.branch import Branch
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
22
import bzrlib.errors as errors
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
23
from bzrlib.diff import internal_diff
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
24
from bzrlib.inventory import (Inventory, ROOT_ID, InventoryFile,
25
    InventoryDirectory, InventoryEntry)
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
26
import bzrlib.inventory as inventory
1740.3.4 by Jelmer Vernooij
Move inventory to commit builder.
27
from bzrlib.osutils import (has_symlinks, rename, pathjoin, is_inside_any, 
28
    is_inside_or_parent_of_any)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
29
from bzrlib.tests import TestCase, TestCaseWithTransport
1551.2.54 by abentley
Fixed executability test
30
from bzrlib.transform import TreeTransform
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
31
from bzrlib.uncommit import uncommit
963 by Martin Pool
- add the start of a test for inventory file-id matching
32
969 by Martin Pool
- Add less-sucky is_within_any
33
1102 by Martin Pool
- merge test refactoring from robertc
34
class TestInventory(TestCase):
35
36
    def test_is_within(self):
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
37
1185.31.32 by John Arbash Meinel
Updated the bzr sourcecode to use bzrlib.osutils.pathjoin rather than os.path.join to enforce internal use of / instead of \
38
        SRC_FOO_C = pathjoin('src', 'foo.c')
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
39
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
40
                         (['src'], SRC_FOO_C),
968 by Martin Pool
- add some passing tests for is_inside_any
41
                         (['src'], 'src'),
42
                         ]:
43
            self.assert_(is_inside_any(dirs, fn))
44
            
969 by Martin Pool
- Add less-sucky is_within_any
45
        for dirs, fn in [(['src'], 'srccontrol'),
46
                         (['src'], 'srccontrol/foo')]:
47
            self.assertFalse(is_inside_any(dirs, fn))
1740.3.4 by Jelmer Vernooij
Move inventory to commit builder.
48
49
    def test_is_within_or_parent(self):
50
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
51
                         (['src'], 'src/foo.c'),
52
                         (['src/bar.c'], 'src'),
53
                         (['src/bar.c', 'bla/foo.c'], 'src'),
54
                         (['src'], 'src'),
55
                         ]:
56
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
969 by Martin Pool
- Add less-sucky is_within_any
57
            
1740.3.4 by Jelmer Vernooij
Move inventory to commit builder.
58
        for dirs, fn in [(['src'], 'srccontrol'),
59
                         (['srccontrol/foo.c'], 'src'),
60
                         (['src'], 'srccontrol/foo')]:
61
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
62
1102 by Martin Pool
- merge test refactoring from robertc
63
    def test_ids(self):
963 by Martin Pool
- add the start of a test for inventory file-id matching
64
        """Test detection of files within selected directories."""
65
        inv = Inventory()
66
        
67
        for args in [('src', 'directory', 'src-id'), 
68
                     ('doc', 'directory', 'doc-id'), 
69
                     ('src/hello.c', 'file'),
70
                     ('src/bye.c', 'file', 'bye-id'),
71
                     ('Makefile', 'file')]:
72
            inv.add_path(*args)
73
            
74
        self.assertEqual(inv.path2id('src'), 'src-id')
75
        self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
76
        
77
        self.assert_('src-id' in inv)
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
78
1732.1.23 by John Arbash Meinel
Switch iter_entries from being a recursive function and using pathjoin
79
    def test_iter_entries(self):
80
        inv = Inventory()
81
        
82
        for args in [('src', 'directory', 'src-id'), 
83
                     ('doc', 'directory', 'doc-id'), 
84
                     ('src/hello.c', 'file', 'hello-id'),
85
                     ('src/bye.c', 'file', 'bye-id'),
86
                     ('Makefile', 'file', 'makefile-id')]:
87
            inv.add_path(*args)
88
89
        self.assertEqual([
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
            
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
97
    def test_version(self):
98
        """Inventory remembers the text's version."""
99
        inv = Inventory()
100
        ie = inv.add_path('foo.txt', 'file')
101
        ## XXX
102
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
103
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
104
class TestInventoryEntry(TestCase):
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
105
106
    def test_file_kind_character(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
107
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
108
        self.assertEqual(file.kind_character(), '')
109
110
    def test_dir_kind_character(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
111
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
112
        self.assertEqual(dir.kind_character(), '/')
113
114
    def test_link_kind_character(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
115
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
116
        self.assertEqual(dir.kind_character(), '')
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
117
118
    def test_dir_detect_changes(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
119
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
120
        left.text_sha1 = 123
121
        left.executable = True
122
        left.symlink_target='foo'
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
123
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
124
        right.text_sha1 = 321
125
        right.symlink_target='bar'
126
        self.assertEqual((False, False), left.detect_changes(right))
127
        self.assertEqual((False, False), right.detect_changes(left))
128
129
    def test_file_detect_changes(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
130
        left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
131
        left.text_sha1 = 123
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
132
        right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
133
        right.text_sha1 = 123
134
        self.assertEqual((False, False), left.detect_changes(right))
135
        self.assertEqual((False, False), right.detect_changes(left))
136
        left.executable = True
137
        self.assertEqual((False, True), left.detect_changes(right))
138
        self.assertEqual((False, True), right.detect_changes(left))
139
        right.text_sha1 = 321
140
        self.assertEqual((True, True), left.detect_changes(right))
141
        self.assertEqual((True, True), right.detect_changes(left))
142
143
    def test_symlink_detect_changes(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
144
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
145
        left.text_sha1 = 123
146
        left.executable = True
147
        left.symlink_target='foo'
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
148
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
149
        right.text_sha1 = 321
150
        right.symlink_target='foo'
151
        self.assertEqual((False, False), left.detect_changes(right))
152
        self.assertEqual((False, False), right.detect_changes(left))
153
        left.symlink_target = 'different'
154
        self.assertEqual((True, False), left.detect_changes(right))
155
        self.assertEqual((True, False), right.detect_changes(left))
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
156
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
157
    def test_file_has_text(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
158
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
159
        self.failUnless(file.has_text())
160
161
    def test_directory_has_text(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
162
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
163
        self.failIf(dir.has_text())
164
165
    def test_link_has_text(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
166
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
167
        self.failIf(link.has_text())
168
1713.1.11 by Robert Collins
refactor smart_add to pass around the parent inventory entry and use that, resulting in another 100bzrlib/inventory.py performance improvement, and making inventory writing the dominating factory in add. (Robert Collins)
169
    def test_make_entry(self):
170
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
171
            inventory.InventoryFile)
172
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
173
            inventory.InventoryLink)
174
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
175
            inventory.InventoryDirectory)
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
176
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
177
class TestEntryDiffing(TestCaseWithTransport):
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
178
179
    def setUp(self):
180
        super(TestEntryDiffing, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
181
        self.wt = self.make_branch_and_tree('.')
182
        self.branch = self.wt.branch
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
183
        print >> open('file', 'wb'), 'foo'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
184
        print >> open('binfile', 'wb'), 'foo'
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
185
        self.wt.add(['file'], ['fileid'])
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
186
        self.wt.add(['binfile'], ['binfileid'])
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
187
        if has_symlinks():
188
            os.symlink('target1', 'symlink')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
189
            self.wt.add(['symlink'], ['linkid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
190
        self.wt.commit('message_1', rev_id = '1')
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
191
        print >> open('file', 'wb'), 'bar'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
192
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
193
        if has_symlinks():
194
            os.unlink('symlink')
195
            os.symlink('target2', 'symlink')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
196
        self.tree_1 = self.branch.repository.revision_tree('1')
197
        self.inv_1 = self.branch.repository.get_inventory('1')
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
198
        self.file_1 = self.inv_1['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
199
        self.file_1b = self.inv_1['binfileid']
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
200
        self.tree_2 = self.wt
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
201
        self.inv_2 = self.tree_2.read_working_inventory()
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
202
        self.file_2 = self.inv_2['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
203
        self.file_2b = self.inv_2['binfileid']
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
204
        if has_symlinks():
205
            self.link_1 = self.inv_1['linkid']
206
            self.link_2 = self.inv_2['linkid']
207
208
    def test_file_diff_deleted(self):
209
        output = StringIO()
210
        self.file_1.diff(internal_diff, 
211
                          "old_label", self.tree_1,
212
                          "/dev/null", None, None,
213
                          output)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
214
        self.assertEqual(output.getvalue(), "--- old_label\n"
215
                                            "+++ /dev/null\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
216
                                            "@@ -1,1 +0,0 @@\n"
217
                                            "-foo\n"
218
                                            "\n")
219
220
    def test_file_diff_added(self):
221
        output = StringIO()
222
        self.file_1.diff(internal_diff, 
223
                          "new_label", self.tree_1,
224
                          "/dev/null", None, None,
225
                          output, reverse=True)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
226
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
227
                                            "+++ new_label\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
228
                                            "@@ -0,0 +1,1 @@\n"
229
                                            "+foo\n"
230
                                            "\n")
231
232
    def test_file_diff_changed(self):
233
        output = StringIO()
234
        self.file_1.diff(internal_diff, 
235
                          "/dev/null", self.tree_1, 
236
                          "new_label", self.file_2, self.tree_2,
237
                          output)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
238
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
239
                                            "+++ new_label\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
240
                                            "@@ -1,1 +1,1 @@\n"
241
                                            "-foo\n"
242
                                            "+bar\n"
243
                                            "\n")
244
        
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
245
    def test_file_diff_binary(self):
246
        output = StringIO()
247
        self.file_1.diff(internal_diff, 
248
                          "/dev/null", self.tree_1, 
249
                          "new_label", self.file_2b, self.tree_2,
250
                          output)
1558.15.11 by Aaron Bentley
Apply merge review suggestions
251
        self.assertEqual(output.getvalue(), 
252
                         "Binary files /dev/null and new_label differ\n")
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
253
    def test_link_diff_deleted(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
254
        if not has_symlinks():
255
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
256
        output = StringIO()
257
        self.link_1.diff(internal_diff, 
258
                          "old_label", self.tree_1,
259
                          "/dev/null", None, None,
260
                          output)
261
        self.assertEqual(output.getvalue(),
262
                         "=== target was 'target1'\n")
263
264
    def test_link_diff_added(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
265
        if not has_symlinks():
266
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
267
        output = StringIO()
268
        self.link_1.diff(internal_diff, 
269
                          "new_label", self.tree_1,
270
                          "/dev/null", None, None,
271
                          output, reverse=True)
272
        self.assertEqual(output.getvalue(),
273
                         "=== target is 'target1'\n")
274
275
    def test_link_diff_changed(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
276
        if not has_symlinks():
277
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
278
        output = StringIO()
279
        self.link_1.diff(internal_diff, 
280
                          "/dev/null", self.tree_1, 
281
                          "new_label", self.link_2, self.tree_2,
282
                          output)
283
        self.assertEqual(output.getvalue(),
284
                         "=== target changed 'target1' => 'target2'\n")
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
285
286
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
287
class TestSnapshot(TestCaseWithTransport):
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
288
289
    def setUp(self):
290
        # for full testing we'll need a branch
291
        # with a subdir to test parent changes.
292
        # and a file, link and dir under that.
293
        # but right now I only need one attribute
294
        # to change, and then test merge patterns
295
        # with fake parent entries.
296
        super(TestSnapshot, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
297
        self.wt = self.make_branch_and_tree('.')
298
        self.branch = self.wt.branch
1185.38.7 by John Arbash Meinel
Updated build_tree to use fixed line-endings for tests which read the file contents and compare
299
        self.build_tree(['subdir/', 'subdir/file'], line_endings='binary')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
300
        self.wt.add(['subdir', 'subdir/file'],
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
301
                                       ['dirid', 'fileid'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
302
        if has_symlinks():
303
            pass
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
304
        self.wt.commit('message_1', rev_id = '1')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
305
        self.tree_1 = self.branch.repository.revision_tree('1')
306
        self.inv_1 = self.branch.repository.get_inventory('1')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
307
        self.file_1 = self.inv_1['fileid']
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
308
        self.file_active = self.wt.inventory['fileid']
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
309
        self.builder = self.branch.get_commit_builder([], timestamp=time.time(), revision_id='2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
310
311
    def test_snapshot_new_revision(self):
312
        # This tests that a simple commit with no parents makes a new
313
        # revision value in the inventory entry
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
314
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
315
        # expected outcome - file_1 has a revision id of '2', and we can get
316
        # its text of 'file contents' out of the weave.
317
        self.assertEqual(self.file_1.revision, '1')
318
        self.assertEqual(self.file_active.revision, '2')
319
        # this should be a separate test probably, but lets check it once..
1563.2.30 by Robert Collins
Remove all but fetch references to revision_store, making the repository references that are weave specific use the RevisionTextStore.text_store attribute.
320
        lines = self.branch.repository.weave_store.get_weave(
321
            'fileid', 
322
            self.branch.get_transaction()).get_lines('2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
323
        self.assertEqual(lines, ['contents of subdir/file\n'])
324
325
    def test_snapshot_unchanged(self):
326
        #This tests that a simple commit does not make a new entry for
327
        # an unchanged inventory entry
328
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
329
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
330
        self.assertEqual(self.file_1.revision, '1')
331
        self.assertEqual(self.file_active.revision, '1')
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
332
        vf = self.branch.repository.weave_store.get_weave(
333
            'fileid', 
334
            self.branch.repository.get_transaction())
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
335
        self.assertRaises(errors.RevisionNotPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
336
                          vf.get_lines,
337
                          '2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
338
339
    def test_snapshot_merge_identical_different_revid(self):
340
        # This tests that a commit with two identical parents, one of which has
341
        # a different revision id, results in a new revision id in the entry.
1408 by Robert Collins
we do not need revision_trees in commit, parent inventories are sufficient
342
        # 1->other, commit a merge of other against 1, results in 2.
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
343
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
344
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
345
        other_ie.revision = '1'
346
        other_ie.text_sha1 = self.file_1.text_sha1
347
        other_ie.text_size = self.file_1.text_size
348
        self.assertEqual(self.file_1, other_ie)
349
        other_ie.revision = 'other'
350
        self.assertNotEqual(self.file_1, other_ie)
1563.2.10 by Robert Collins
Change weave store to be a versioned store, using WeaveFiles which maintain integrity without needing explicit 'put' operations.
351
        versionfile = self.branch.repository.weave_store.get_weave(
352
            'fileid', self.branch.repository.get_transaction())
353
        versionfile.clone_text('other', '1', ['1'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
354
        self.file_active.snapshot('2', 'subdir/file', 
355
                                  {'1':self.file_1, 'other':other_ie},
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
356
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
357
        self.assertEqual(self.file_active.revision, '2')
358
359
    def test_snapshot_changed(self):
360
        # This tests that a commit with one different parent results in a new
361
        # revision id in the entry.
362
        self.file_active.name='newname'
363
        rename('subdir/file', 'subdir/newname')
364
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
365
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
366
        # expected outcome - file_1 has a revision id of '2'
367
        self.assertEqual(self.file_active.revision, '2')
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
368
369
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
370
class TestPreviousHeads(TestCaseWithTransport):
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
371
372
    def setUp(self):
373
        # we want several inventories, that respectively
374
        # give use the following scenarios:
375
        # A) fileid not in any inventory (A),
376
        # B) fileid present in one inventory (B) and (A,B)
377
        # C) fileid present in two inventories, and they
378
        #   are not mutual descendents (B, C)
379
        # D) fileid present in two inventories and one is
380
        #   a descendent of the other. (B, D)
381
        super(TestPreviousHeads, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
382
        self.wt = self.make_branch_and_tree('.')
383
        self.branch = self.wt.branch
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
384
        self.build_tree(['file'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
385
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
386
        self.inv_A = self.branch.repository.get_inventory('A')
1185.65.13 by Robert Collins
Merge from integration
387
        self.wt.add(['file'], ['fileid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
388
        self.wt.commit('add file', rev_id='B')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
389
        self.inv_B = self.branch.repository.get_inventory('B')
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
390
        uncommit(self.branch, tree=self.wt)
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
391
        self.assertEqual(self.branch.revision_history(), ['A'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
392
        self.wt.commit('another add of file', rev_id='C')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
393
        self.inv_C = self.branch.repository.get_inventory('C')
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
394
        self.wt.add_pending_merge('B')
395
        self.wt.commit('merge in B', rev_id='D')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
396
        self.inv_D = self.branch.repository.get_inventory('D')
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
397
        self.file_active = self.wt.inventory['fileid']
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
398
        self.weave = self.branch.repository.weave_store.get_weave('fileid',
1596.2.20 by Robert Collins
optimise commit to only access weaves for merged, or altered files during commit.
399
            self.branch.repository.get_transaction())
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
400
        
401
    def get_previous_heads(self, inventories):
1596.2.20 by Robert Collins
optimise commit to only access weaves for merged, or altered files during commit.
402
        return self.file_active.find_previous_heads(
403
            inventories, 
404
            self.branch.repository.weave_store,
405
            self.branch.repository.get_transaction())
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
406
        
407
    def test_fileid_in_no_inventory(self):
408
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
409
410
    def test_fileid_in_one_inventory(self):
411
        self.assertEqual({'B':self.inv_B['fileid']},
412
                         self.get_previous_heads([self.inv_B]))
413
        self.assertEqual({'B':self.inv_B['fileid']},
414
                         self.get_previous_heads([self.inv_A, self.inv_B]))
415
        self.assertEqual({'B':self.inv_B['fileid']},
416
                         self.get_previous_heads([self.inv_B, self.inv_A]))
417
418
    def test_fileid_in_two_inventories_gives_both_entries(self):
419
        self.assertEqual({'B':self.inv_B['fileid'],
420
                          'C':self.inv_C['fileid']},
421
                          self.get_previous_heads([self.inv_B, self.inv_C]))
422
        self.assertEqual({'B':self.inv_B['fileid'],
423
                          'C':self.inv_C['fileid']},
424
                          self.get_previous_heads([self.inv_C, self.inv_B]))
425
426
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
427
        self.assertEqual({'D':self.inv_D['fileid']},
428
                         self.get_previous_heads([self.inv_B, self.inv_D]))
429
        self.assertEqual({'D':self.inv_D['fileid']},
430
                         self.get_previous_heads([self.inv_D, self.inv_B]))
431
432
    # TODO: test two inventories with the same file revision 
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
433
434
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
435
class TestDescribeChanges(TestCase):
436
437
    def test_describe_change(self):
438
        # we need to test the following change combinations:
439
        # rename
440
        # reparent
441
        # modify
442
        # gone
443
        # added
444
        # renamed/reparented and modified
445
        # change kind (perhaps can't be done yet?)
446
        # also, merged in combination with all of these?
447
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
448
        old_a.text_sha1 = '123132'
449
        old_a.text_size = 0
450
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
451
        new_a.text_sha1 = '123132'
452
        new_a.text_size = 0
453
454
        self.assertChangeDescription('unchanged', old_a, new_a)
455
456
        new_a.text_size = 10
457
        new_a.text_sha1 = 'abcabc'
458
        self.assertChangeDescription('modified', old_a, new_a)
459
460
        self.assertChangeDescription('added', None, new_a)
461
        self.assertChangeDescription('removed', old_a, None)
462
        # perhaps a bit questionable but seems like the most reasonable thing...
463
        self.assertChangeDescription('unchanged', None, None)
464
465
        # in this case it's both renamed and modified; show a rename and 
466
        # modification:
467
        new_a.name = 'newfilename'
468
        self.assertChangeDescription('modified and renamed', old_a, new_a)
469
470
        # reparenting is 'renaming'
471
        new_a.name = old_a.name
472
        new_a.parent_id = 'somedir-id'
473
        self.assertChangeDescription('modified and renamed', old_a, new_a)
474
475
        # reset the content values so its not modified
476
        new_a.text_size = old_a.text_size
477
        new_a.text_sha1 = old_a.text_sha1
478
        new_a.name = old_a.name
479
480
        new_a.name = 'newfilename'
481
        self.assertChangeDescription('renamed', old_a, new_a)
482
483
        # reparenting is 'renaming'
484
        new_a.name = old_a.name
485
        new_a.parent_id = 'somedir-id'
486
        self.assertChangeDescription('renamed', old_a, new_a)
487
488
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
489
        change = InventoryEntry.describe_change(old_ie, new_ie)
490
        self.assertEqual(expected_change, change)
491
492
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
493
class TestExecutable(TestCaseWithTransport):
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
494
495
    def test_stays_executable(self):
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
496
        a_id = "a-20051208024829-849e76f7968d7a86"
497
        b_id = "b-20051208024829-849e76f7968d7a86"
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
498
        wt = self.make_branch_and_tree('b1')
499
        b = wt.branch
1551.2.54 by abentley
Fixed executability test
500
        tt = TreeTransform(wt)
501
        tt.new_file('a', tt.root, 'a test\n', a_id, True)
502
        tt.new_file('b', tt.root, 'b test\n', b_id, False)
503
        tt.apply()
504
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
505
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
506
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
507
        # reopen the tree and ensure it stuck.
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
508
        wt = wt.bzrdir.open_workingtree()
509
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
510
511
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
512
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
513
514
        wt.commit('adding a,b', rev_id='r1')
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
515
1185.65.17 by Robert Collins
Merge from integration, mode-changes are broken.
516
        rev_tree = b.repository.revision_tree('r1')
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
517
        self.failUnless(rev_tree.is_executable(a_id), "'a' lost the execute bit")
518
        self.failIf(rev_tree.is_executable(b_id), "'b' gained an execute bit")
519
520
        self.failUnless(rev_tree.inventory[a_id].executable)
521
        self.failIf(rev_tree.inventory[b_id].executable)
522
523
        # Make sure the entries are gone
524
        os.remove('b1/a')
525
        os.remove('b1/b')
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
526
        self.failIf(wt.has_id(a_id))
527
        self.failIf(wt.has_filename('a'))
528
        self.failIf(wt.has_id(b_id))
529
        self.failIf(wt.has_filename('b'))
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
530
531
        # Make sure that revert is able to bring them back,
532
        # and sets 'a' back to being executable
533
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
534
        wt.revert(['a', 'b'], rev_tree, backups=False)
535
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
536
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
537
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
538
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
539
540
        # Now remove them again, and make sure that after a
541
        # commit, they are still marked correctly
542
        os.remove('b1/a')
543
        os.remove('b1/b')
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
544
        wt.commit('removed', rev_id='r2')
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
545
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
546
        self.assertEqual([], [cn for cn,ie in wt.inventory.iter_entries()])
547
        self.failIf(wt.has_id(a_id))
548
        self.failIf(wt.has_filename('a'))
549
        self.failIf(wt.has_id(b_id))
550
        self.failIf(wt.has_filename('b'))
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
551
552
        # Now revert back to the previous commit
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
553
        wt.revert([], rev_tree, backups=False)
554
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
555
556
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
557
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
558
559
        # Now make sure that 'bzr branch' also preserves the
560
        # executable bit
561
        # TODO: Maybe this should be a blackbox test
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
562
        d2 = b.bzrdir.clone('b2', revision_id='r1')
563
        t2 = d2.open_workingtree()
564
        b2 = t2.branch
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
565
        self.assertEquals('r1', b2.last_revision())
566
567
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
568
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
569
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
570
571
        # Make sure pull will delete the files
572
        t2.pull(b)
573
        self.assertEquals('r2', b2.last_revision())
574
        self.assertEqual([], [cn for cn,ie in t2.inventory.iter_entries()])
575
576
        # Now commit the changes on the first branch
577
        # so that the second branch can pull the changes
578
        # and make sure that the executable bit has been copied
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
579
        wt.commit('resurrected', rev_id='r3')
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
580
581
        t2.pull(b)
582
        self.assertEquals('r3', b2.last_revision())
583
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
584
585
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
586
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
587
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
588
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
589
class TestRevert(TestCaseWithTransport):
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
590
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
591
    def test_dangling_id(self):
592
        wt = self.make_branch_and_tree('b1')
593
        self.assertEqual(len(wt.inventory), 1)
594
        open('b1/a', 'wb').write('a test\n')
595
        wt.add('a')
596
        self.assertEqual(len(wt.inventory), 2)
597
        os.unlink('b1/a')
598
        wt.revert([])
599
        self.assertEqual(len(wt.inventory), 1)