/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
963 by Martin Pool
- add the start of a test for inventory file-id matching
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
963 by Martin Pool
- add the start of a test for inventory file-id matching
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
963 by Martin Pool
- add the start of a test for inventory file-id matching
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
1830.3.5 by John Arbash Meinel
make_entry refuses to create non-normalized entries.
21
from bzrlib import errors, inventory, osutils
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
22
from bzrlib.branch import Branch
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,
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
25
    InventoryDirectory, InventoryEntry, TreeReference)
1740.3.4 by Jelmer Vernooij
Move inventory to commit builder.
26
from bzrlib.osutils import (has_symlinks, rename, pathjoin, is_inside_any, 
27
    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.
28
from bzrlib.tests import TestCase, TestCaseWithTransport
1551.2.54 by abentley
Fixed executability test
29
from bzrlib.transform import TreeTransform
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
30
from bzrlib.uncommit import uncommit
963 by Martin Pool
- add the start of a test for inventory file-id matching
31
969 by Martin Pool
- Add less-sucky is_within_any
32
1102 by Martin Pool
- merge test refactoring from robertc
33
class TestInventory(TestCase):
34
2178.2.2 by Jelmer Vernooij
Make add_path() return inventory entry for root just like it does for other entries.
35
    def test_add_path(self):
36
37
        inv = Inventory(root_id=None)
38
        self.assertIs(None, inv.root)
39
        ie = inv.add_path("", "directory", "my-root")
40
        self.assertEqual("my-root", ie.file_id)
41
        self.assertIs(ie, inv.root)
42
1102 by Martin Pool
- merge test refactoring from robertc
43
    def test_is_within(self):
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
44
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 \
45
        SRC_FOO_C = pathjoin('src', 'foo.c')
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
46
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
47
                         (['src'], SRC_FOO_C),
968 by Martin Pool
- add some passing tests for is_inside_any
48
                         (['src'], 'src'),
49
                         ]:
50
            self.assert_(is_inside_any(dirs, fn))
51
            
969 by Martin Pool
- Add less-sucky is_within_any
52
        for dirs, fn in [(['src'], 'srccontrol'),
53
                         (['src'], 'srccontrol/foo')]:
54
            self.assertFalse(is_inside_any(dirs, fn))
1740.3.4 by Jelmer Vernooij
Move inventory to commit builder.
55
56
    def test_is_within_or_parent(self):
57
        for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
58
                         (['src'], 'src/foo.c'),
59
                         (['src/bar.c'], 'src'),
60
                         (['src/bar.c', 'bla/foo.c'], 'src'),
61
                         (['src'], 'src'),
62
                         ]:
63
            self.assert_(is_inside_or_parent_of_any(dirs, fn))
969 by Martin Pool
- Add less-sucky is_within_any
64
            
1740.3.4 by Jelmer Vernooij
Move inventory to commit builder.
65
        for dirs, fn in [(['src'], 'srccontrol'),
66
                         (['srccontrol/foo.c'], 'src'),
67
                         (['src'], 'srccontrol/foo')]:
68
            self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
69
1102 by Martin Pool
- merge test refactoring from robertc
70
    def test_ids(self):
963 by Martin Pool
- add the start of a test for inventory file-id matching
71
        """Test detection of files within selected directories."""
72
        inv = Inventory()
73
        
74
        for args in [('src', 'directory', 'src-id'), 
75
                     ('doc', 'directory', 'doc-id'), 
76
                     ('src/hello.c', 'file'),
77
                     ('src/bye.c', 'file', 'bye-id'),
78
                     ('Makefile', 'file')]:
79
            inv.add_path(*args)
80
            
81
        self.assertEqual(inv.path2id('src'), 'src-id')
82
        self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
83
        
84
        self.assert_('src-id' in inv)
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
85
2091.3.1 by Aaron Bentley
When 'directory' path element isn't a directory, return None from path2id
86
    def test_non_directory_children(self):
87
        """Test path2id when a parent directory has no children"""
88
        inv = inventory.Inventory('tree_root')
89
        inv.add(inventory.InventoryFile('file-id','file', 
90
                                        parent_id='tree_root'))
91
        inv.add(inventory.InventoryLink('link-id','link', 
92
                                        parent_id='tree_root'))
93
        self.assertIs(None, inv.path2id('file/subfile'))
94
        self.assertIs(None, inv.path2id('link/subfile'))
95
1732.1.23 by John Arbash Meinel
Switch iter_entries from being a recursive function and using pathjoin
96
    def test_iter_entries(self):
97
        inv = Inventory()
98
        
99
        for args in [('src', 'directory', 'src-id'), 
100
                     ('doc', 'directory', 'doc-id'), 
101
                     ('src/hello.c', 'file', 'hello-id'),
102
                     ('src/bye.c', 'file', 'bye-id'),
103
                     ('Makefile', 'file', 'makefile-id')]:
104
            inv.add_path(*args)
105
106
        self.assertEqual([
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
107
            ('', ROOT_ID),
1732.1.23 by John Arbash Meinel
Switch iter_entries from being a recursive function and using pathjoin
108
            ('Makefile', 'makefile-id'),
109
            ('doc', 'doc-id'),
110
            ('src', 'src-id'),
111
            ('src/bye.c', 'bye-id'),
112
            ('src/hello.c', 'hello-id'),
113
            ], [(path, ie.file_id) for path, ie in inv.iter_entries()])
114
            
1711.2.36 by John Arbash Meinel
Add an iter_entries_by_dir which returns directory children before their children.
115
    def test_iter_entries_by_dir(self):
116
        inv = Inventory()
117
        
118
        for args in [('src', 'directory', 'src-id'), 
119
                     ('doc', 'directory', 'doc-id'), 
120
                     ('src/hello.c', 'file', 'hello-id'),
121
                     ('src/bye.c', 'file', 'bye-id'),
122
                     ('zz', 'file', 'zz-id'),
123
                     ('src/sub/', 'directory', 'sub-id'),
124
                     ('src/zz.c', 'file', 'zzc-id'),
125
                     ('src/sub/a', 'file', 'a-id'),
126
                     ('Makefile', 'file', 'makefile-id')]:
127
            inv.add_path(*args)
128
129
        self.assertEqual([
1852.6.6 by Robert Collins
Finish updating iter_entries change to make all tests pass.
130
            ('', ROOT_ID),
1711.2.36 by John Arbash Meinel
Add an iter_entries_by_dir which returns directory children before their children.
131
            ('Makefile', 'makefile-id'),
132
            ('doc', 'doc-id'),
133
            ('src', 'src-id'),
134
            ('zz', 'zz-id'),
135
            ('src/bye.c', 'bye-id'),
136
            ('src/hello.c', 'hello-id'),
137
            ('src/sub', 'sub-id'),
138
            ('src/zz.c', 'zzc-id'),
139
            ('src/sub/a', 'a-id'),
140
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir()])
141
            
1551.9.29 by Aaron Bentley
Optimize Tree._iter_changes with specific file_ids
142
        self.assertEqual([
143
            ('', ROOT_ID),
144
            ('Makefile', 'makefile-id'),
145
            ('doc', 'doc-id'),
146
            ('src', 'src-id'),
147
            ('zz', 'zz-id'),
148
            ('src/bye.c', 'bye-id'),
149
            ('src/hello.c', 'hello-id'),
150
            ('src/sub', 'sub-id'),
151
            ('src/zz.c', 'zzc-id'),
152
            ('src/sub/a', 'a-id'),
153
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
154
                specific_file_ids=('a-id', 'zzc-id', 'doc-id', ROOT_ID,
155
                'hello-id', 'bye-id', 'zz-id', 'src-id', 'makefile-id', 
156
                'sub-id'))])
157
158
        self.assertEqual([
159
            ('Makefile', 'makefile-id'),
160
            ('doc', 'doc-id'),
161
            ('zz', 'zz-id'),
162
            ('src/bye.c', 'bye-id'),
163
            ('src/hello.c', 'hello-id'),
164
            ('src/zz.c', 'zzc-id'),
165
            ('src/sub/a', 'a-id'),
166
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
167
                specific_file_ids=('a-id', 'zzc-id', 'doc-id',
168
                'hello-id', 'bye-id', 'zz-id', 'makefile-id'))])
169
170
        self.assertEqual([
171
            ('Makefile', 'makefile-id'),
172
            ('src/bye.c', 'bye-id'),
173
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
174
                specific_file_ids=('bye-id', 'makefile-id'))])
175
176
        self.assertEqual([
177
            ('Makefile', 'makefile-id'),
178
            ('src/bye.c', 'bye-id'),
179
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
180
                specific_file_ids=('bye-id', 'makefile-id'))])
181
182
        self.assertEqual([
183
            ('src/bye.c', 'bye-id'),
184
            ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
185
                specific_file_ids=('bye-id',))])
186
2100.3.6 by Aaron Bentley
Make add recursive for children of added entries
187
    def test_add_recursive(self):
188
        parent = InventoryDirectory('src-id', 'src', ROOT_ID)
189
        child = InventoryFile('hello-id', 'hello.c', 'src-id')
190
        parent.children[child.file_id] = child
191
        inv = Inventory()
192
        inv.add(parent)
193
        self.assertEqual('src/hello.c', inv.id2path('hello-id'))
194
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
195
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
196
class TestInventoryEntry(TestCase):
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
197
198
    def test_file_kind_character(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
199
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
200
        self.assertEqual(file.kind_character(), '')
201
202
    def test_dir_kind_character(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
203
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
204
        self.assertEqual(dir.kind_character(), '/')
205
206
    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
207
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
208
        self.assertEqual(dir.kind_character(), '')
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
209
210
    def test_dir_detect_changes(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
211
        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
212
        left.text_sha1 = 123
213
        left.executable = True
214
        left.symlink_target='foo'
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
215
        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
216
        right.text_sha1 = 321
217
        right.symlink_target='bar'
218
        self.assertEqual((False, False), left.detect_changes(right))
219
        self.assertEqual((False, False), right.detect_changes(left))
220
221
    def test_file_detect_changes(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
222
        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
223
        left.text_sha1 = 123
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
224
        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
225
        right.text_sha1 = 123
226
        self.assertEqual((False, False), left.detect_changes(right))
227
        self.assertEqual((False, False), right.detect_changes(left))
228
        left.executable = True
229
        self.assertEqual((False, True), left.detect_changes(right))
230
        self.assertEqual((False, True), right.detect_changes(left))
231
        right.text_sha1 = 321
232
        self.assertEqual((True, True), left.detect_changes(right))
233
        self.assertEqual((True, True), right.detect_changes(left))
234
235
    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
236
        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
237
        left.text_sha1 = 123
238
        left.executable = True
239
        left.symlink_target='foo'
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
240
        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
241
        right.text_sha1 = 321
242
        right.symlink_target='foo'
243
        self.assertEqual((False, False), left.detect_changes(right))
244
        self.assertEqual((False, False), right.detect_changes(left))
245
        left.symlink_target = 'different'
246
        self.assertEqual((True, False), left.detect_changes(right))
247
        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
248
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
249
    def test_file_has_text(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
250
        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
251
        self.failUnless(file.has_text())
252
253
    def test_directory_has_text(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
254
        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
255
        self.failIf(dir.has_text())
256
257
    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
258
        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
259
        self.failIf(link.has_text())
260
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)
261
    def test_make_entry(self):
262
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
263
            inventory.InventoryFile)
264
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
265
            inventory.InventoryLink)
266
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
267
            inventory.InventoryDirectory)
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
268
1830.3.5 by John Arbash Meinel
make_entry refuses to create non-normalized entries.
269
    def test_make_entry_non_normalized(self):
270
        orig_normalized_filename = osutils.normalized_filename
271
272
        try:
273
            osutils.normalized_filename = osutils._accessible_normalized_filename
274
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
275
            self.assertEqual(u'\xe5', entry.name)
276
            self.assertIsInstance(entry, inventory.InventoryFile)
277
278
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
279
            self.assertRaises(errors.InvalidNormalization,
280
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
281
        finally:
282
            osutils.normalized_filename = orig_normalized_filename
283
284
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
285
class TestEntryDiffing(TestCaseWithTransport):
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
286
287
    def setUp(self):
288
        super(TestEntryDiffing, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
289
        self.wt = self.make_branch_and_tree('.')
290
        self.branch = self.wt.branch
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
291
        print >> open('file', 'wb'), 'foo'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
292
        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.
293
        self.wt.add(['file'], ['fileid'])
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
294
        self.wt.add(['binfile'], ['binfileid'])
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
295
        if has_symlinks():
296
            os.symlink('target1', 'symlink')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
297
            self.wt.add(['symlink'], ['linkid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
298
        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
299
        print >> open('file', 'wb'), 'bar'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
300
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
301
        if has_symlinks():
302
            os.unlink('symlink')
303
            os.symlink('target2', 'symlink')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
304
        self.tree_1 = self.branch.repository.revision_tree('1')
305
        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
306
        self.file_1 = self.inv_1['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
307
        self.file_1b = self.inv_1['binfileid']
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
308
        self.tree_2 = self.wt
2255.7.67 by Robert Collins
Fix test_inv - make setting WorkingTree4._dirty use a helper to reduce code duplication, and reset the inventory when we dont manually update it, if it exists.
309
        self.tree_2.lock_read()
310
        self.addCleanup(self.tree_2.unlock)
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
311
        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
312
        self.file_2 = self.inv_2['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
313
        self.file_2b = self.inv_2['binfileid']
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
314
        if has_symlinks():
315
            self.link_1 = self.inv_1['linkid']
316
            self.link_2 = self.inv_2['linkid']
317
318
    def test_file_diff_deleted(self):
319
        output = StringIO()
320
        self.file_1.diff(internal_diff, 
321
                          "old_label", self.tree_1,
322
                          "/dev/null", None, None,
323
                          output)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
324
        self.assertEqual(output.getvalue(), "--- old_label\n"
325
                                            "+++ /dev/null\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
326
                                            "@@ -1,1 +0,0 @@\n"
327
                                            "-foo\n"
328
                                            "\n")
329
330
    def test_file_diff_added(self):
331
        output = StringIO()
332
        self.file_1.diff(internal_diff, 
333
                          "new_label", self.tree_1,
334
                          "/dev/null", None, None,
335
                          output, reverse=True)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
336
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
337
                                            "+++ new_label\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
338
                                            "@@ -0,0 +1,1 @@\n"
339
                                            "+foo\n"
340
                                            "\n")
341
342
    def test_file_diff_changed(self):
343
        output = StringIO()
344
        self.file_1.diff(internal_diff, 
345
                          "/dev/null", self.tree_1, 
346
                          "new_label", self.file_2, self.tree_2,
347
                          output)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
348
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
349
                                            "+++ new_label\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
350
                                            "@@ -1,1 +1,1 @@\n"
351
                                            "-foo\n"
352
                                            "+bar\n"
353
                                            "\n")
354
        
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
355
    def test_file_diff_binary(self):
356
        output = StringIO()
357
        self.file_1.diff(internal_diff, 
358
                          "/dev/null", self.tree_1, 
359
                          "new_label", self.file_2b, self.tree_2,
360
                          output)
1558.15.11 by Aaron Bentley
Apply merge review suggestions
361
        self.assertEqual(output.getvalue(), 
362
                         "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
363
    def test_link_diff_deleted(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
364
        if not has_symlinks():
365
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
366
        output = StringIO()
367
        self.link_1.diff(internal_diff, 
368
                          "old_label", self.tree_1,
369
                          "/dev/null", None, None,
370
                          output)
371
        self.assertEqual(output.getvalue(),
372
                         "=== target was 'target1'\n")
373
374
    def test_link_diff_added(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
375
        if not has_symlinks():
376
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
377
        output = StringIO()
378
        self.link_1.diff(internal_diff, 
379
                          "new_label", self.tree_1,
380
                          "/dev/null", None, None,
381
                          output, reverse=True)
382
        self.assertEqual(output.getvalue(),
383
                         "=== target is 'target1'\n")
384
385
    def test_link_diff_changed(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
386
        if not has_symlinks():
387
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
388
        output = StringIO()
389
        self.link_1.diff(internal_diff, 
390
                          "/dev/null", self.tree_1, 
391
                          "new_label", self.link_2, self.tree_2,
392
                          output)
393
        self.assertEqual(output.getvalue(),
394
                         "=== target changed 'target1' => 'target2'\n")
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
395
396
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
397
class TestSnapshot(TestCaseWithTransport):
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
398
399
    def setUp(self):
400
        # for full testing we'll need a branch
401
        # with a subdir to test parent changes.
402
        # and a file, link and dir under that.
403
        # but right now I only need one attribute
404
        # to change, and then test merge patterns
405
        # with fake parent entries.
406
        super(TestSnapshot, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
407
        self.wt = self.make_branch_and_tree('.')
408
        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
409
        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.
410
        self.wt.add(['subdir', 'subdir/file'],
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
411
                                       ['dirid', 'fileid'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
412
        if has_symlinks():
413
            pass
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
414
        self.wt.commit('message_1', rev_id = '1')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
415
        self.tree_1 = self.branch.repository.revision_tree('1')
416
        self.inv_1 = self.branch.repository.get_inventory('1')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
417
        self.file_1 = self.inv_1['fileid']
2255.7.54 by Robert Collins
in test_inv, stop abusing the inventory interface to get tree alterations to occur.
418
        self.wt.lock_write()
419
        self.addCleanup(self.wt.unlock)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
420
        self.file_active = self.wt.inventory['fileid']
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
421
        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
422
423
    def test_snapshot_new_revision(self):
424
        # This tests that a simple commit with no parents makes a new
425
        # revision value in the inventory entry
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
426
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
427
        # expected outcome - file_1 has a revision id of '2', and we can get
428
        # its text of 'file contents' out of the weave.
429
        self.assertEqual(self.file_1.revision, '1')
430
        self.assertEqual(self.file_active.revision, '2')
431
        # 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.
432
        lines = self.branch.repository.weave_store.get_weave(
433
            'fileid', 
434
            self.branch.get_transaction()).get_lines('2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
435
        self.assertEqual(lines, ['contents of subdir/file\n'])
436
437
    def test_snapshot_unchanged(self):
438
        #This tests that a simple commit does not make a new entry for
439
        # an unchanged inventory entry
440
        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.
441
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
442
        self.assertEqual(self.file_1.revision, '1')
443
        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.
444
        vf = self.branch.repository.weave_store.get_weave(
445
            'fileid', 
446
            self.branch.repository.get_transaction())
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
447
        self.assertRaises(errors.RevisionNotPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
448
                          vf.get_lines,
449
                          '2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
450
451
    def test_snapshot_merge_identical_different_revid(self):
452
        # This tests that a commit with two identical parents, one of which has
453
        # 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
454
        # 1->other, commit a merge of other against 1, results in 2.
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
455
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
456
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
457
        other_ie.revision = '1'
458
        other_ie.text_sha1 = self.file_1.text_sha1
459
        other_ie.text_size = self.file_1.text_size
460
        self.assertEqual(self.file_1, other_ie)
461
        other_ie.revision = 'other'
462
        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.
463
        versionfile = self.branch.repository.weave_store.get_weave(
464
            'fileid', self.branch.repository.get_transaction())
465
        versionfile.clone_text('other', '1', ['1'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
466
        self.file_active.snapshot('2', 'subdir/file', 
467
                                  {'1':self.file_1, 'other':other_ie},
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
468
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
469
        self.assertEqual(self.file_active.revision, '2')
470
471
    def test_snapshot_changed(self):
472
        # This tests that a commit with one different parent results in a new
473
        # revision id in the entry.
2255.7.54 by Robert Collins
in test_inv, stop abusing the inventory interface to get tree alterations to occur.
474
        self.wt.rename_one('subdir/file', 'subdir/newname')
475
        self.file_active = self.wt.inventory['fileid']
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
476
        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.
477
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
478
        # expected outcome - file_1 has a revision id of '2'
479
        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.
480
481
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
482
class TestPreviousHeads(TestCaseWithTransport):
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
483
484
    def setUp(self):
485
        # we want several inventories, that respectively
486
        # give use the following scenarios:
487
        # A) fileid not in any inventory (A),
488
        # B) fileid present in one inventory (B) and (A,B)
489
        # C) fileid present in two inventories, and they
490
        #   are not mutual descendents (B, C)
491
        # D) fileid present in two inventories and one is
492
        #   a descendent of the other. (B, D)
493
        super(TestPreviousHeads, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
494
        self.wt = self.make_branch_and_tree('.')
495
        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.
496
        self.build_tree(['file'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
497
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
498
        self.inv_A = self.branch.repository.get_inventory('A')
1185.65.13 by Robert Collins
Merge from integration
499
        self.wt.add(['file'], ['fileid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
500
        self.wt.commit('add file', rev_id='B')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
501
        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
502
        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.
503
        self.assertEqual(self.branch.revision_history(), ['A'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
504
        self.wt.commit('another add of file', rev_id='C')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
505
        self.inv_C = self.branch.repository.get_inventory('C')
1908.6.7 by Robert Collins
Remove all users of set_pending_merges and add_pending_merge except tests that they work correctly.
506
        self.wt.add_parent_tree_id('B')
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
507
        self.wt.commit('merge in B', rev_id='D')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
508
        self.inv_D = self.branch.repository.get_inventory('D')
2255.7.67 by Robert Collins
Fix test_inv - make setting WorkingTree4._dirty use a helper to reduce code duplication, and reset the inventory when we dont manually update it, if it exists.
509
        self.wt.lock_read()
510
        self.addCleanup(self.wt.unlock)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
511
        self.file_active = self.wt.inventory['fileid']
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
512
        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.
513
            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.
514
        
515
    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.
516
        return self.file_active.find_previous_heads(
517
            inventories, 
518
            self.branch.repository.weave_store,
519
            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.
520
        
521
    def test_fileid_in_no_inventory(self):
522
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
523
524
    def test_fileid_in_one_inventory(self):
525
        self.assertEqual({'B':self.inv_B['fileid']},
526
                         self.get_previous_heads([self.inv_B]))
527
        self.assertEqual({'B':self.inv_B['fileid']},
528
                         self.get_previous_heads([self.inv_A, self.inv_B]))
529
        self.assertEqual({'B':self.inv_B['fileid']},
530
                         self.get_previous_heads([self.inv_B, self.inv_A]))
531
532
    def test_fileid_in_two_inventories_gives_both_entries(self):
533
        self.assertEqual({'B':self.inv_B['fileid'],
534
                          'C':self.inv_C['fileid']},
535
                          self.get_previous_heads([self.inv_B, self.inv_C]))
536
        self.assertEqual({'B':self.inv_B['fileid'],
537
                          'C':self.inv_C['fileid']},
538
                          self.get_previous_heads([self.inv_C, self.inv_B]))
539
540
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
541
        self.assertEqual({'D':self.inv_D['fileid']},
542
                         self.get_previous_heads([self.inv_B, self.inv_D]))
543
        self.assertEqual({'D':self.inv_D['fileid']},
544
                         self.get_previous_heads([self.inv_D, self.inv_B]))
545
546
    # 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
547
548
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
549
class TestDescribeChanges(TestCase):
550
551
    def test_describe_change(self):
552
        # we need to test the following change combinations:
553
        # rename
554
        # reparent
555
        # modify
556
        # gone
557
        # added
558
        # renamed/reparented and modified
559
        # change kind (perhaps can't be done yet?)
560
        # also, merged in combination with all of these?
561
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
562
        old_a.text_sha1 = '123132'
563
        old_a.text_size = 0
564
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
565
        new_a.text_sha1 = '123132'
566
        new_a.text_size = 0
567
568
        self.assertChangeDescription('unchanged', old_a, new_a)
569
570
        new_a.text_size = 10
571
        new_a.text_sha1 = 'abcabc'
572
        self.assertChangeDescription('modified', old_a, new_a)
573
574
        self.assertChangeDescription('added', None, new_a)
575
        self.assertChangeDescription('removed', old_a, None)
576
        # perhaps a bit questionable but seems like the most reasonable thing...
577
        self.assertChangeDescription('unchanged', None, None)
578
579
        # in this case it's both renamed and modified; show a rename and 
580
        # modification:
581
        new_a.name = 'newfilename'
582
        self.assertChangeDescription('modified and renamed', old_a, new_a)
583
584
        # reparenting is 'renaming'
585
        new_a.name = old_a.name
586
        new_a.parent_id = 'somedir-id'
587
        self.assertChangeDescription('modified and renamed', old_a, new_a)
588
589
        # reset the content values so its not modified
590
        new_a.text_size = old_a.text_size
591
        new_a.text_sha1 = old_a.text_sha1
592
        new_a.name = old_a.name
593
594
        new_a.name = 'newfilename'
595
        self.assertChangeDescription('renamed', old_a, new_a)
596
597
        # reparenting is 'renaming'
598
        new_a.name = old_a.name
599
        new_a.parent_id = 'somedir-id'
600
        self.assertChangeDescription('renamed', old_a, new_a)
601
602
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
603
        change = InventoryEntry.describe_change(old_ie, new_ie)
604
        self.assertEqual(expected_change, change)
605
606
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
607
class TestRevert(TestCaseWithTransport):
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
608
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
609
    def test_dangling_id(self):
610
        wt = self.make_branch_and_tree('b1')
2255.7.67 by Robert Collins
Fix test_inv - make setting WorkingTree4._dirty use a helper to reduce code duplication, and reset the inventory when we dont manually update it, if it exists.
611
        wt.lock_tree_write()
612
        self.addCleanup(wt.unlock)
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
613
        self.assertEqual(len(wt.inventory), 1)
614
        open('b1/a', 'wb').write('a test\n')
615
        wt.add('a')
616
        self.assertEqual(len(wt.inventory), 2)
2255.7.67 by Robert Collins
Fix test_inv - make setting WorkingTree4._dirty use a helper to reduce code duplication, and reset the inventory when we dont manually update it, if it exists.
617
        wt.flush() # workaround revert doing wt._write_inventory for now.
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
618
        os.unlink('b1/a')
619
        wt.revert([])
620
        self.assertEqual(len(wt.inventory), 1)
1731.1.39 by Aaron Bentley
Reject removing is_root
621
622
623
class TestIsRoot(TestCase):
624
    """Ensure our root-checking code is accurate."""
625
626
    def test_is_root(self):
627
        inv = Inventory('TREE_ROOT')
628
        self.assertTrue(inv.is_root('TREE_ROOT'))
629
        self.assertFalse(inv.is_root('booga'))
630
        inv.root.file_id = 'booga'
631
        self.assertFalse(inv.is_root('TREE_ROOT'))
632
        self.assertTrue(inv.is_root('booga'))
633
        # works properly even if no root is set
634
        inv.root = None
635
        self.assertFalse(inv.is_root('TREE_ROOT'))
636
        self.assertFalse(inv.is_root('booga'))
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
637
638
639
class TestTreeReference(TestCase):
640
    
641
    def test_create(self):
642
        inv = Inventory('tree-root-123')
643
        inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
644
                              revision='rev', reference_revision='rev2'))