~bzr-pqm/bzr/bzr.dev

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,
25
    InventoryDirectory, InventoryEntry)
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
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
187
    def test_version(self):
188
        """Inventory remembers the text's version."""
189
        inv = Inventory()
190
        ie = inv.add_path('foo.txt', 'file')
191
        ## XXX
192
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
193
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
194
class TestInventoryEntry(TestCase):
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
195
196
    def test_file_kind_character(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
197
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
198
        self.assertEqual(file.kind_character(), '')
199
200
    def test_dir_kind_character(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
201
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
202
        self.assertEqual(dir.kind_character(), '/')
203
204
    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
205
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
206
        self.assertEqual(dir.kind_character(), '')
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
207
208
    def test_dir_detect_changes(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
209
        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
210
        left.text_sha1 = 123
211
        left.executable = True
212
        left.symlink_target='foo'
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
213
        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
214
        right.text_sha1 = 321
215
        right.symlink_target='bar'
216
        self.assertEqual((False, False), left.detect_changes(right))
217
        self.assertEqual((False, False), right.detect_changes(left))
218
219
    def test_file_detect_changes(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
220
        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
221
        left.text_sha1 = 123
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
222
        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
223
        right.text_sha1 = 123
224
        self.assertEqual((False, False), left.detect_changes(right))
225
        self.assertEqual((False, False), right.detect_changes(left))
226
        left.executable = True
227
        self.assertEqual((False, True), left.detect_changes(right))
228
        self.assertEqual((False, True), right.detect_changes(left))
229
        right.text_sha1 = 321
230
        self.assertEqual((True, True), left.detect_changes(right))
231
        self.assertEqual((True, True), right.detect_changes(left))
232
233
    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
234
        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
235
        left.text_sha1 = 123
236
        left.executable = True
237
        left.symlink_target='foo'
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
238
        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
239
        right.text_sha1 = 321
240
        right.symlink_target='foo'
241
        self.assertEqual((False, False), left.detect_changes(right))
242
        self.assertEqual((False, False), right.detect_changes(left))
243
        left.symlink_target = 'different'
244
        self.assertEqual((True, False), left.detect_changes(right))
245
        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
246
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
247
    def test_file_has_text(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
248
        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
249
        self.failUnless(file.has_text())
250
251
    def test_directory_has_text(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
252
        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
253
        self.failIf(dir.has_text())
254
255
    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
256
        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
257
        self.failIf(link.has_text())
258
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)
259
    def test_make_entry(self):
260
        self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
261
            inventory.InventoryFile)
262
        self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
263
            inventory.InventoryLink)
264
        self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
265
            inventory.InventoryDirectory)
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
266
1830.3.5 by John Arbash Meinel
make_entry refuses to create non-normalized entries.
267
    def test_make_entry_non_normalized(self):
268
        orig_normalized_filename = osutils.normalized_filename
269
270
        try:
271
            osutils.normalized_filename = osutils._accessible_normalized_filename
272
            entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
273
            self.assertEqual(u'\xe5', entry.name)
274
            self.assertIsInstance(entry, inventory.InventoryFile)
275
276
            osutils.normalized_filename = osutils._inaccessible_normalized_filename
277
            self.assertRaises(errors.InvalidNormalization,
278
                    inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
279
        finally:
280
            osutils.normalized_filename = orig_normalized_filename
281
282
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
283
class TestEntryDiffing(TestCaseWithTransport):
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
284
285
    def setUp(self):
286
        super(TestEntryDiffing, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
287
        self.wt = self.make_branch_and_tree('.')
288
        self.branch = self.wt.branch
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
289
        print >> open('file', 'wb'), 'foo'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
290
        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.
291
        self.wt.add(['file'], ['fileid'])
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
292
        self.wt.add(['binfile'], ['binfileid'])
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
293
        if has_symlinks():
294
            os.symlink('target1', 'symlink')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
295
            self.wt.add(['symlink'], ['linkid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
296
        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
297
        print >> open('file', 'wb'), 'bar'
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
298
        print >> open('binfile', 'wb'), 'x' * 1023 + '\x00'
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
299
        if has_symlinks():
300
            os.unlink('symlink')
301
            os.symlink('target2', 'symlink')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
302
        self.tree_1 = self.branch.repository.revision_tree('1')
303
        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
304
        self.file_1 = self.inv_1['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
305
        self.file_1b = self.inv_1['binfileid']
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
306
        self.tree_2 = self.wt
1497 by Robert Collins
Move Branch.read_working_inventory to WorkingTree.
307
        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
308
        self.file_2 = self.inv_2['fileid']
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
309
        self.file_2b = self.inv_2['binfileid']
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
310
        if has_symlinks():
311
            self.link_1 = self.inv_1['linkid']
312
            self.link_2 = self.inv_2['linkid']
313
314
    def test_file_diff_deleted(self):
315
        output = StringIO()
316
        self.file_1.diff(internal_diff, 
317
                          "old_label", self.tree_1,
318
                          "/dev/null", None, None,
319
                          output)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
320
        self.assertEqual(output.getvalue(), "--- old_label\n"
321
                                            "+++ /dev/null\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
322
                                            "@@ -1,1 +0,0 @@\n"
323
                                            "-foo\n"
324
                                            "\n")
325
326
    def test_file_diff_added(self):
327
        output = StringIO()
328
        self.file_1.diff(internal_diff, 
329
                          "new_label", self.tree_1,
330
                          "/dev/null", None, None,
331
                          output, reverse=True)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
332
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
333
                                            "+++ new_label\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
334
                                            "@@ -0,0 +1,1 @@\n"
335
                                            "+foo\n"
336
                                            "\n")
337
338
    def test_file_diff_changed(self):
339
        output = StringIO()
340
        self.file_1.diff(internal_diff, 
341
                          "/dev/null", self.tree_1, 
342
                          "new_label", self.file_2, self.tree_2,
343
                          output)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
344
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
345
                                            "+++ new_label\n"
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
346
                                            "@@ -1,1 +1,1 @@\n"
347
                                            "-foo\n"
348
                                            "+bar\n"
349
                                            "\n")
350
        
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
351
    def test_file_diff_binary(self):
352
        output = StringIO()
353
        self.file_1.diff(internal_diff, 
354
                          "/dev/null", self.tree_1, 
355
                          "new_label", self.file_2b, self.tree_2,
356
                          output)
1558.15.11 by Aaron Bentley
Apply merge review suggestions
357
        self.assertEqual(output.getvalue(), 
358
                         "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
359
    def test_link_diff_deleted(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
360
        if not has_symlinks():
361
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
362
        output = StringIO()
363
        self.link_1.diff(internal_diff, 
364
                          "old_label", self.tree_1,
365
                          "/dev/null", None, None,
366
                          output)
367
        self.assertEqual(output.getvalue(),
368
                         "=== target was 'target1'\n")
369
370
    def test_link_diff_added(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
371
        if not has_symlinks():
372
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
373
        output = StringIO()
374
        self.link_1.diff(internal_diff, 
375
                          "new_label", self.tree_1,
376
                          "/dev/null", None, None,
377
                          output, reverse=True)
378
        self.assertEqual(output.getvalue(),
379
                         "=== target is 'target1'\n")
380
381
    def test_link_diff_changed(self):
1431 by Robert Collins
BUGFIX: disable symlink support tests when no symlink support is present on the system.
382
        if not has_symlinks():
383
            return
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
384
        output = StringIO()
385
        self.link_1.diff(internal_diff, 
386
                          "/dev/null", self.tree_1, 
387
                          "new_label", self.link_2, self.tree_2,
388
                          output)
389
        self.assertEqual(output.getvalue(),
390
                         "=== target changed 'target1' => 'target2'\n")
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
391
392
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
393
class TestSnapshot(TestCaseWithTransport):
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
394
395
    def setUp(self):
396
        # for full testing we'll need a branch
397
        # with a subdir to test parent changes.
398
        # and a file, link and dir under that.
399
        # but right now I only need one attribute
400
        # to change, and then test merge patterns
401
        # with fake parent entries.
402
        super(TestSnapshot, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
403
        self.wt = self.make_branch_and_tree('.')
404
        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
405
        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.
406
        self.wt.add(['subdir', 'subdir/file'],
1508.1.5 by Robert Collins
Move add from Branch to WorkingTree.
407
                                       ['dirid', 'fileid'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
408
        if has_symlinks():
409
            pass
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
410
        self.wt.commit('message_1', rev_id = '1')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
411
        self.tree_1 = self.branch.repository.revision_tree('1')
412
        self.inv_1 = self.branch.repository.get_inventory('1')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
413
        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.
414
        self.file_active = self.wt.inventory['fileid']
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
415
        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
416
417
    def test_snapshot_new_revision(self):
418
        # This tests that a simple commit with no parents makes a new
419
        # revision value in the inventory entry
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
420
        self.file_active.snapshot('2', 'subdir/file', {}, self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
421
        # expected outcome - file_1 has a revision id of '2', and we can get
422
        # its text of 'file contents' out of the weave.
423
        self.assertEqual(self.file_1.revision, '1')
424
        self.assertEqual(self.file_active.revision, '2')
425
        # 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.
426
        lines = self.branch.repository.weave_store.get_weave(
427
            'fileid', 
428
            self.branch.get_transaction()).get_lines('2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
429
        self.assertEqual(lines, ['contents of subdir/file\n'])
430
431
    def test_snapshot_unchanged(self):
432
        #This tests that a simple commit does not make a new entry for
433
        # an unchanged inventory entry
434
        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.
435
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
436
        self.assertEqual(self.file_1.revision, '1')
437
        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.
438
        vf = self.branch.repository.weave_store.get_weave(
439
            'fileid', 
440
            self.branch.repository.get_transaction())
1563.2.1 by Robert Collins
Merge in a variation of the versionedfile api from versioned-file.
441
        self.assertRaises(errors.RevisionNotPresent,
1563.2.35 by Robert Collins
cleanup deprecation warnings and finish conversion so the inventory is knit based too.
442
                          vf.get_lines,
443
                          '2')
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
444
445
    def test_snapshot_merge_identical_different_revid(self):
446
        # This tests that a commit with two identical parents, one of which has
447
        # 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
448
        # 1->other, commit a merge of other against 1, results in 2.
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
449
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
450
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
451
        other_ie.revision = '1'
452
        other_ie.text_sha1 = self.file_1.text_sha1
453
        other_ie.text_size = self.file_1.text_size
454
        self.assertEqual(self.file_1, other_ie)
455
        other_ie.revision = 'other'
456
        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.
457
        versionfile = self.branch.repository.weave_store.get_weave(
458
            'fileid', self.branch.repository.get_transaction())
459
        versionfile.clone_text('other', '1', ['1'])
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
460
        self.file_active.snapshot('2', 'subdir/file', 
461
                                  {'1':self.file_1, 'other':other_ie},
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
462
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
463
        self.assertEqual(self.file_active.revision, '2')
464
465
    def test_snapshot_changed(self):
466
        # This tests that a commit with one different parent results in a new
467
        # revision id in the entry.
468
        self.file_active.name='newname'
469
        rename('subdir/file', 'subdir/newname')
470
        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.
471
                                  self.wt, self.builder)
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
472
        # expected outcome - file_1 has a revision id of '2'
473
        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.
474
475
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
476
class TestPreviousHeads(TestCaseWithTransport):
1411 by Robert Collins
use weave ancestry to determine inventory entry previous heads, prevent propogating 'I did a merge' merges.
477
478
    def setUp(self):
479
        # we want several inventories, that respectively
480
        # give use the following scenarios:
481
        # A) fileid not in any inventory (A),
482
        # B) fileid present in one inventory (B) and (A,B)
483
        # C) fileid present in two inventories, and they
484
        #   are not mutual descendents (B, C)
485
        # D) fileid present in two inventories and one is
486
        #   a descendent of the other. (B, D)
487
        super(TestPreviousHeads, self).setUp()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
488
        self.wt = self.make_branch_and_tree('.')
489
        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.
490
        self.build_tree(['file'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
491
        self.wt.commit('new branch', allow_pointless=True, rev_id='A')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
492
        self.inv_A = self.branch.repository.get_inventory('A')
1185.65.13 by Robert Collins
Merge from integration
493
        self.wt.add(['file'], ['fileid'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
494
        self.wt.commit('add file', rev_id='B')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
495
        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
496
        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.
497
        self.assertEqual(self.branch.revision_history(), ['A'])
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
498
        self.wt.commit('another add of file', rev_id='C')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
499
        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.
500
        self.wt.add_parent_tree_id('B')
1457.1.17 by Robert Collins
Branch.commit() has moved to WorkingTree.commit(). (Robert Collins)
501
        self.wt.commit('merge in B', rev_id='D')
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
502
        self.inv_D = self.branch.repository.get_inventory('D')
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
503
        self.file_active = self.wt.inventory['fileid']
1185.67.2 by Aaron Bentley
Renamed Branch.storage to Branch.repository
504
        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.
505
            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.
506
        
507
    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.
508
        return self.file_active.find_previous_heads(
509
            inventories, 
510
            self.branch.repository.weave_store,
511
            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.
512
        
513
    def test_fileid_in_no_inventory(self):
514
        self.assertEqual({}, self.get_previous_heads([self.inv_A]))
515
516
    def test_fileid_in_one_inventory(self):
517
        self.assertEqual({'B':self.inv_B['fileid']},
518
                         self.get_previous_heads([self.inv_B]))
519
        self.assertEqual({'B':self.inv_B['fileid']},
520
                         self.get_previous_heads([self.inv_A, self.inv_B]))
521
        self.assertEqual({'B':self.inv_B['fileid']},
522
                         self.get_previous_heads([self.inv_B, self.inv_A]))
523
524
    def test_fileid_in_two_inventories_gives_both_entries(self):
525
        self.assertEqual({'B':self.inv_B['fileid'],
526
                          'C':self.inv_C['fileid']},
527
                          self.get_previous_heads([self.inv_B, self.inv_C]))
528
        self.assertEqual({'B':self.inv_B['fileid'],
529
                          'C':self.inv_C['fileid']},
530
                          self.get_previous_heads([self.inv_C, self.inv_B]))
531
532
    def test_fileid_in_two_inventories_already_merged_gives_head(self):
533
        self.assertEqual({'D':self.inv_D['fileid']},
534
                         self.get_previous_heads([self.inv_B, self.inv_D]))
535
        self.assertEqual({'D':self.inv_D['fileid']},
536
                         self.get_previous_heads([self.inv_D, self.inv_B]))
537
538
    # 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
539
540
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
541
class TestDescribeChanges(TestCase):
542
543
    def test_describe_change(self):
544
        # we need to test the following change combinations:
545
        # rename
546
        # reparent
547
        # modify
548
        # gone
549
        # added
550
        # renamed/reparented and modified
551
        # change kind (perhaps can't be done yet?)
552
        # also, merged in combination with all of these?
553
        old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
554
        old_a.text_sha1 = '123132'
555
        old_a.text_size = 0
556
        new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
557
        new_a.text_sha1 = '123132'
558
        new_a.text_size = 0
559
560
        self.assertChangeDescription('unchanged', old_a, new_a)
561
562
        new_a.text_size = 10
563
        new_a.text_sha1 = 'abcabc'
564
        self.assertChangeDescription('modified', old_a, new_a)
565
566
        self.assertChangeDescription('added', None, new_a)
567
        self.assertChangeDescription('removed', old_a, None)
568
        # perhaps a bit questionable but seems like the most reasonable thing...
569
        self.assertChangeDescription('unchanged', None, None)
570
571
        # in this case it's both renamed and modified; show a rename and 
572
        # modification:
573
        new_a.name = 'newfilename'
574
        self.assertChangeDescription('modified and renamed', old_a, new_a)
575
576
        # reparenting is 'renaming'
577
        new_a.name = old_a.name
578
        new_a.parent_id = 'somedir-id'
579
        self.assertChangeDescription('modified and renamed', old_a, new_a)
580
581
        # reset the content values so its not modified
582
        new_a.text_size = old_a.text_size
583
        new_a.text_sha1 = old_a.text_sha1
584
        new_a.name = old_a.name
585
586
        new_a.name = 'newfilename'
587
        self.assertChangeDescription('renamed', old_a, new_a)
588
589
        # reparenting is 'renaming'
590
        new_a.name = old_a.name
591
        new_a.parent_id = 'somedir-id'
592
        self.assertChangeDescription('renamed', old_a, new_a)
593
594
    def assertChangeDescription(self, expected_change, old_ie, new_ie):
595
        change = InventoryEntry.describe_change(old_ie, new_ie)
596
        self.assertEqual(expected_change, change)
597
598
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
599
class TestRevert(TestCaseWithTransport):
1668.1.5 by Martin Pool
[broken] fix up display of files changed by a commit
600
1534.7.178 by Aaron Bentley
Fixed dangling inventory ids in revert
601
    def test_dangling_id(self):
602
        wt = self.make_branch_and_tree('b1')
603
        self.assertEqual(len(wt.inventory), 1)
604
        open('b1/a', 'wb').write('a test\n')
605
        wt.add('a')
606
        self.assertEqual(len(wt.inventory), 2)
607
        os.unlink('b1/a')
608
        wt.revert([])
609
        self.assertEqual(len(wt.inventory), 1)
1731.1.39 by Aaron Bentley
Reject removing is_root
610
611
612
class TestIsRoot(TestCase):
613
    """Ensure our root-checking code is accurate."""
614
615
    def test_is_root(self):
616
        inv = Inventory('TREE_ROOT')
617
        self.assertTrue(inv.is_root('TREE_ROOT'))
618
        self.assertFalse(inv.is_root('booga'))
619
        inv.root.file_id = 'booga'
620
        self.assertFalse(inv.is_root('TREE_ROOT'))
621
        self.assertTrue(inv.is_root('booga'))
622
        # works properly even if no root is set
623
        inv.root = None
624
        self.assertFalse(inv.is_root('TREE_ROOT'))
625
        self.assertFalse(inv.is_root('booga'))