/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
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
19
20
from bzrlib.branch import Branch
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
21
import bzrlib.errors as errors
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
22
from bzrlib.diff import internal_diff
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
23
from bzrlib.inventory import Inventory, ROOT_ID
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
24
import bzrlib.inventory as inventory
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 \
25
from bzrlib.osutils import has_symlinks, rename, pathjoin
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
26
from bzrlib.tests import TestCase, TestCaseWithTransport
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
27
from bzrlib.uncommit import uncommit
963 by Martin Pool
- add the start of a test for inventory file-id matching
28
969 by Martin Pool
- Add less-sucky is_within_any
29
1102 by Martin Pool
- merge test refactoring from robertc
30
class TestInventory(TestCase):
31
32
    def test_is_within(self):
968 by Martin Pool
- add some passing tests for is_inside_any
33
        from bzrlib.osutils import is_inside_any
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
34
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 \
35
        SRC_FOO_C = pathjoin('src', 'foo.c')
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
36
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
37
                         (['src'], SRC_FOO_C),
968 by Martin Pool
- add some passing tests for is_inside_any
38
                         (['src'], 'src'),
39
                         ]:
40
            self.assert_(is_inside_any(dirs, fn))
41
            
969 by Martin Pool
- Add less-sucky is_within_any
42
        for dirs, fn in [(['src'], 'srccontrol'),
43
                         (['src'], 'srccontrol/foo')]:
44
            self.assertFalse(is_inside_any(dirs, fn))
45
            
1102 by Martin Pool
- merge test refactoring from robertc
46
    def test_ids(self):
963 by Martin Pool
- add the start of a test for inventory file-id matching
47
        """Test detection of files within selected directories."""
48
        inv = Inventory()
49
        
50
        for args in [('src', 'directory', 'src-id'), 
51
                     ('doc', 'directory', 'doc-id'), 
52
                     ('src/hello.c', 'file'),
53
                     ('src/bye.c', 'file', 'bye-id'),
54
                     ('Makefile', 'file')]:
55
            inv.add_path(*args)
56
            
57
        self.assertEqual(inv.path2id('src'), 'src-id')
58
        self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
59
        
60
        self.assert_('src-id' in inv)
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
61
62
63
    def test_version(self):
64
        """Inventory remembers the text's version."""
65
        inv = Inventory()
66
        ie = inv.add_path('foo.txt', 'file')
67
        ## XXX
68
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
69
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
70
class TestInventoryEntry(TestCase):
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
71
72
    def test_file_kind_character(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
73
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
74
        self.assertEqual(file.kind_character(), '')
75
76
    def test_dir_kind_character(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
77
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
78
        self.assertEqual(dir.kind_character(), '/')
79
80
    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
81
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
82
        self.assertEqual(dir.kind_character(), '')
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
83
84
    def test_dir_detect_changes(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
85
        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
86
        left.text_sha1 = 123
87
        left.executable = True
88
        left.symlink_target='foo'
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
89
        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
90
        right.text_sha1 = 321
91
        right.symlink_target='bar'
92
        self.assertEqual((False, False), left.detect_changes(right))
93
        self.assertEqual((False, False), right.detect_changes(left))
94
95
    def test_file_detect_changes(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
96
        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
97
        left.text_sha1 = 123
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
98
        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
99
        right.text_sha1 = 123
100
        self.assertEqual((False, False), left.detect_changes(right))
101
        self.assertEqual((False, False), right.detect_changes(left))
102
        left.executable = True
103
        self.assertEqual((False, True), left.detect_changes(right))
104
        self.assertEqual((False, True), right.detect_changes(left))
105
        right.text_sha1 = 321
106
        self.assertEqual((True, True), left.detect_changes(right))
107
        self.assertEqual((True, True), right.detect_changes(left))
108
109
    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
110
        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
111
        left.text_sha1 = 123
112
        left.executable = True
113
        left.symlink_target='foo'
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
114
        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
115
        right.text_sha1 = 321
116
        right.symlink_target='foo'
117
        self.assertEqual((False, False), left.detect_changes(right))
118
        self.assertEqual((False, False), right.detect_changes(left))
119
        left.symlink_target = 'different'
120
        self.assertEqual((True, False), left.detect_changes(right))
121
        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
122
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
123
    def test_file_has_text(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
124
        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
125
        self.failUnless(file.has_text())
126
127
    def test_directory_has_text(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
128
        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
129
        self.failIf(dir.has_text())
130
131
    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
132
        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
133
        self.failIf(link.has_text())
134
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
135
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
136
class TestEntryDiffing(TestCaseWithTransport):
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
137
138
    def setUp(self):
139
        super(TestEntryDiffing, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
140
        self.wt = self.make_branch_and_tree('.')
141
        self.branch = self.wt.branch
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
142
        print >> open('file', 'wb'), 'foo'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
143
        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.
144
        self.wt.add(['file'], ['fileid'])
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
145
        self.wt.add(['binfile'], ['binfileid'])
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
146
        if has_symlinks():
147
            os.symlink('target1', 'symlink')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
148
            self.wt.add(['symlink'], ['linkid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
149
        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
150
        print >> open('file', 'wb'), 'bar'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
151
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
152
        if has_symlinks():
153
            os.unlink('symlink')
154
            os.symlink('target2', 'symlink')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
155
        self.tree_1 = self.branch.repository.revision_tree('1')
156
        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
157
        self.file_1 = self.inv_1['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
158
        self.file_1b = self.inv_1['binfileid']
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
159
        self.tree_2 = self.wt
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
160
        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
161
        self.file_2 = self.inv_2['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
162
        self.file_2b = self.inv_2['binfileid']
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
163
        if has_symlinks():
164
            self.link_1 = self.inv_1['linkid']
165
            self.link_2 = self.inv_2['linkid']
166
167
    def test_file_diff_deleted(self):
168
        output = StringIO()
169
        self.file_1.diff(internal_diff, 
170
                          "old_label", self.tree_1,
171
                          "/dev/null", None, None,
172
                          output)
1185.35.29 by Aaron Bentley
Support whitespace in diff filenames
173
        self.assertEqual(output.getvalue(), "--- old_label\t\n"
174
                                            "+++ /dev/null\t\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
175
                                            "@@ -1,1 +0,0 @@\n"
176
                                            "-foo\n"
177
                                            "\n")
178
179
    def test_file_diff_added(self):
180
        output = StringIO()
181
        self.file_1.diff(internal_diff, 
182
                          "new_label", self.tree_1,
183
                          "/dev/null", None, None,
184
                          output, reverse=True)
1185.35.29 by Aaron Bentley
Support whitespace in diff filenames
185
        self.assertEqual(output.getvalue(), "--- /dev/null\t\n"
186
                                            "+++ new_label\t\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
187
                                            "@@ -0,0 +1,1 @@\n"
188
                                            "+foo\n"
189
                                            "\n")
190
191
    def test_file_diff_changed(self):
192
        output = StringIO()
193
        self.file_1.diff(internal_diff, 
194
                          "/dev/null", self.tree_1, 
195
                          "new_label", self.file_2, self.tree_2,
196
                          output)
1185.35.29 by Aaron Bentley
Support whitespace in diff filenames
197
        self.assertEqual(output.getvalue(), "--- /dev/null\t\n"
198
                                            "+++ new_label\t\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
199
                                            "@@ -1,1 +1,1 @@\n"
200
                                            "-foo\n"
201
                                            "+bar\n"
202
                                            "\n")
203
        
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
204
    def test_file_diff_binary(self):
205
        output = StringIO()
206
        self.file_1.diff(internal_diff, 
207
                          "/dev/null", self.tree_1, 
208
                          "new_label", self.file_2b, self.tree_2,
209
                          output)
1558.15.11 by Aaron Bentley
Apply merge review suggestions
210
        self.assertEqual(output.getvalue(), 
211
                         "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
212
    def test_link_diff_deleted(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
213
        if not has_symlinks():
214
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
215
        output = StringIO()
216
        self.link_1.diff(internal_diff, 
217
                          "old_label", self.tree_1,
218
                          "/dev/null", None, None,
219
                          output)
220
        self.assertEqual(output.getvalue(),
221
                         "=== target was 'target1'\n")
222
223
    def test_link_diff_added(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
224
        if not has_symlinks():
225
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
226
        output = StringIO()
227
        self.link_1.diff(internal_diff, 
228
                          "new_label", self.tree_1,
229
                          "/dev/null", None, None,
230
                          output, reverse=True)
231
        self.assertEqual(output.getvalue(),
232
                         "=== target is 'target1'\n")
233
234
    def test_link_diff_changed(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
235
        if not has_symlinks():
236
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
237
        output = StringIO()
238
        self.link_1.diff(internal_diff, 
239
                          "/dev/null", self.tree_1, 
240
                          "new_label", self.link_2, self.tree_2,
241
                          output)
242
        self.assertEqual(output.getvalue(),
243
                         "=== target changed 'target1' => 'target2'\n")
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
244
245
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
246
class TestSnapshot(TestCaseWithTransport):
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
247
248
    def setUp(self):
249
        # for full testing we'll need a branch
250
        # with a subdir to test parent changes.
251
        # and a file, link and dir under that.
252
        # but right now I only need one attribute
253
        # to change, and then test merge patterns
254
        # with fake parent entries.
255
        super(TestSnapshot, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
256
        self.wt = self.make_branch_and_tree('.')
257
        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
258
        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.
259
        self.wt.add(['subdir', 'subdir/file'],
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
260
                                       ['dirid', 'fileid'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
261
        if has_symlinks():
262
            pass
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
263
        self.wt.commit('message_1', rev_id = '1')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
264
        self.tree_1 = self.branch.repository.revision_tree('1')
265
        self.inv_1 = self.branch.repository.get_inventory('1')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
266
        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.
267
        self.file_active = self.wt.inventory['fileid']
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
268
269
    def test_snapshot_new_revision(self):
270
        # This tests that a simple commit with no parents makes a new
271
        # revision value in the inventory entry
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
272
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, 
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
273
                                  self.branch.repository.weave_store,
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
274
                                  self.branch.get_transaction())
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
275
        # expected outcome - file_1 has a revision id of '2', and we can get
276
        # its text of 'file contents' out of the weave.
277
        self.assertEqual(self.file_1.revision, '1')
278
        self.assertEqual(self.file_active.revision, '2')
279
        # 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.
280
        lines = self.branch.repository.weave_store.get_weave(
281
            'fileid', 
282
            self.branch.get_transaction()).get_lines('2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
283
        self.assertEqual(lines, ['contents of subdir/file\n'])
284
285
    def test_snapshot_unchanged(self):
286
        #This tests that a simple commit does not make a new entry for
287
        # an unchanged inventory entry
288
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
1534.4.28 by Robert Collins
first cut at merge from integration.
289
                                  self.wt, 
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
290
                                  self.branch.repository.weave_store,
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
291
                                  self.branch.get_transaction())
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
292
        self.assertEqual(self.file_1.revision, '1')
293
        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.
294
        vf = self.branch.repository.weave_store.get_weave(
295
            'fileid', 
296
            self.branch.repository.get_transaction())
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
297
        self.assertRaises(errors.RevisionNotPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
298
                          vf.get_lines,
299
                          '2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
300
301
    def test_snapshot_merge_identical_different_revid(self):
302
        # This tests that a commit with two identical parents, one of which has
303
        # 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
304
        # 1->other, commit a merge of other against 1, results in 2.
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
305
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
306
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
307
        other_ie.revision = '1'
308
        other_ie.text_sha1 = self.file_1.text_sha1
309
        other_ie.text_size = self.file_1.text_size
310
        self.assertEqual(self.file_1, other_ie)
311
        other_ie.revision = 'other'
312
        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.
313
        versionfile = self.branch.repository.weave_store.get_weave(
314
            'fileid', self.branch.repository.get_transaction())
315
        versionfile.clone_text('other', '1', ['1'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
316
        self.file_active.snapshot('2', 'subdir/file', 
317
                                  {'1':self.file_1, 'other':other_ie},
1534.4.28 by Robert Collins
first cut at merge from integration.
318
                                  self.wt, 
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
319
                                  self.branch.repository.weave_store,
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
320
                                  self.branch.get_transaction())
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
321
        self.assertEqual(self.file_active.revision, '2')
322
323
    def test_snapshot_changed(self):
324
        # This tests that a commit with one different parent results in a new
325
        # revision id in the entry.
326
        self.file_active.name='newname'
327
        rename('subdir/file', 'subdir/newname')
328
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
1534.4.28 by Robert Collins
first cut at merge from integration.
329
                                  self.wt,
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
330
                                  self.branch.repository.weave_store,
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
331
                                  self.branch.get_transaction())
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
332
        # expected outcome - file_1 has a revision id of '2'
333
        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.
334
335
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
336
class TestPreviousHeads(TestCaseWithTransport):
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
337
338
    def setUp(self):
339
        # we want several inventories, that respectively
340
        # give use the following scenarios:
341
        # A) fileid not in any inventory (A),
342
        # B) fileid present in one inventory (B) and (A,B)
343
        # C) fileid present in two inventories, and they
344
        #   are not mutual descendents (B, C)
345
        # D) fileid present in two inventories and one is
346
        #   a descendent of the other. (B, D)
347
        super(TestPreviousHeads, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
348
        self.wt = self.make_branch_and_tree('.')
349
        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.
350
        self.build_tree(['file'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
351
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
352
        self.inv_A = self.branch.repository.get_inventory('A')
1185.65.13 by Robert Collins
Merge from integration
353
        self.wt.add(['file'], ['fileid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
354
        self.wt.commit('add file', rev_id='B')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
355
        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
356
        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.
357
        self.assertEqual(self.branch.revision_history(), ['A'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
358
        self.wt.commit('another add of file', rev_id='C')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
359
        self.inv_C = self.branch.repository.get_inventory('C')
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
360
        self.wt.add_pending_merge('B')
361
        self.wt.commit('merge in B', rev_id='D')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
362
        self.inv_D = self.branch.repository.get_inventory('D')
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
363
        self.file_active = self.wt.inventory['fileid']
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
364
        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.
365
            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.
366
        
367
    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.
368
        return self.file_active.find_previous_heads(
369
            inventories, 
370
            self.branch.repository.weave_store,
371
            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.
372
        
373
    def test_fileid_in_no_inventory(self):
374
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
375
376
    def test_fileid_in_one_inventory(self):
377
        self.assertEqual({'B':self.inv_B['fileid']},
378
                         self.get_previous_heads([self.inv_B]))
379
        self.assertEqual({'B':self.inv_B['fileid']},
380
                         self.get_previous_heads([self.inv_A, self.inv_B]))
381
        self.assertEqual({'B':self.inv_B['fileid']},
382
                         self.get_previous_heads([self.inv_B, self.inv_A]))
383
384
    def test_fileid_in_two_inventories_gives_both_entries(self):
385
        self.assertEqual({'B':self.inv_B['fileid'],
386
                          'C':self.inv_C['fileid']},
387
                          self.get_previous_heads([self.inv_B, self.inv_C]))
388
        self.assertEqual({'B':self.inv_B['fileid'],
389
                          'C':self.inv_C['fileid']},
390
                          self.get_previous_heads([self.inv_C, self.inv_B]))
391
392
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
393
        self.assertEqual({'D':self.inv_D['fileid']},
394
                         self.get_previous_heads([self.inv_B, self.inv_D]))
395
        self.assertEqual({'D':self.inv_D['fileid']},
396
                         self.get_previous_heads([self.inv_D, self.inv_B]))
397
398
    # 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
399
400
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
401
class TestExecutable(TestCaseWithTransport):
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
402
403
    def test_stays_executable(self):
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
404
        a_id = "a-20051208024829-849e76f7968d7a86"
405
        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.
406
        wt = self.make_branch_and_tree('b1')
407
        b = wt.branch
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
408
        open('b1/a', 'wb').write('a test\n')
409
        open('b1/b', 'wb').write('b test\n')
410
        os.chmod('b1/a', 0755)
411
        os.chmod('b1/b', 0644)
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
412
        wt.add(['a', 'b'], [a_id, b_id])
413
        wt.inventory[a_id].executable = True
414
        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
415
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
416
        # reopen the tree and ensure it stuck.
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
417
        wt = wt.bzrdir.open_workingtree()
418
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
419
420
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
421
        self.failIf(wt.is_executable(b_id), "'b' gained an execute bit")
422
423
        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
424
1185.65.17 by Robert Collins
Merge from integration, mode-changes are broken.
425
        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
426
        self.failUnless(rev_tree.is_executable(a_id), "'a' lost the execute bit")
427
        self.failIf(rev_tree.is_executable(b_id), "'b' gained an execute bit")
428
429
        self.failUnless(rev_tree.inventory[a_id].executable)
430
        self.failIf(rev_tree.inventory[b_id].executable)
431
432
        # Make sure the entries are gone
433
        os.remove('b1/a')
434
        os.remove('b1/b')
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
435
        self.failIf(wt.has_id(a_id))
436
        self.failIf(wt.has_filename('a'))
437
        self.failIf(wt.has_id(b_id))
438
        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
439
440
        # Make sure that revert is able to bring them back,
441
        # and sets 'a' back to being executable
442
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
443
        wt.revert(['a', 'b'], rev_tree, backups=False)
444
        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
445
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
446
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
447
        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
448
449
        # Now remove them again, and make sure that after a
450
        # commit, they are still marked correctly
451
        os.remove('b1/a')
452
        os.remove('b1/b')
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
453
        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
454
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
455
        self.assertEqual([], [cn for cn,ie in wt.inventory.iter_entries()])
456
        self.failIf(wt.has_id(a_id))
457
        self.failIf(wt.has_filename('a'))
458
        self.failIf(wt.has_id(b_id))
459
        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
460
461
        # Now revert back to the previous commit
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
462
        wt.revert([], rev_tree, backups=False)
463
        self.assertEqual(['a', 'b'], [cn for cn,ie in wt.inventory.iter_entries()])
464
465
        self.failUnless(wt.is_executable(a_id), "'a' lost the execute bit")
466
        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
467
468
        # Now make sure that 'bzr branch' also preserves the
469
        # executable bit
470
        # 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.
471
        d2 = b.bzrdir.clone('b2', revision_id='r1')
472
        t2 = d2.open_workingtree()
473
        b2 = t2.branch
1185.31.55 by John Arbash Meinel
Added (win32 failing) test to make sure is_executable is maintained over several operations
474
        self.assertEquals('r1', b2.last_revision())
475
476
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
477
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
478
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
479
480
        # Make sure pull will delete the files
481
        t2.pull(b)
482
        self.assertEquals('r2', b2.last_revision())
483
        self.assertEqual([], [cn for cn,ie in t2.inventory.iter_entries()])
484
485
        # Now commit the changes on the first branch
486
        # so that the second branch can pull the changes
487
        # 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.
488
        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
489
490
        t2.pull(b)
491
        self.assertEquals('r3', b2.last_revision())
492
        self.assertEqual(['a', 'b'], [cn for cn,ie in t2.inventory.iter_entries()])
493
494
        self.failUnless(t2.is_executable(a_id), "'a' lost the execute bit")
495
        self.failIf(t2.is_executable(b_id), "'b' gained an execute bit")
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
496
497
class TestRevert(TestCaseWithTransport):
498
    def test_dangling_id(self):
499
        wt = self.make_branch_and_tree('b1')
500
        self.assertEqual(len(wt.inventory), 1)
501
        open('b1/a', 'wb').write('a test\n')
502
        wt.add('a')
503
        self.assertEqual(len(wt.inventory), 2)
504
        os.unlink('b1/a')
505
        wt.revert([])
506
        self.assertEqual(len(wt.inventory), 1)
1534.7.193 by Aaron Bentley
Stopped revert from preserving file contents produced by merges
507
508