1
# Copyright (C) 2005, 2006 Canonical Ltd
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.
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.
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
17
from bzrlib import errors, inventory, osutils
18
from bzrlib.inventory import (Inventory, ROOT_ID, InventoryFile,
19
InventoryDirectory, InventoryEntry, TreeReference)
20
from bzrlib.osutils import (pathjoin, is_inside_any,
21
is_inside_or_parent_of_any)
22
from bzrlib.tests import TestCase
25
class TestInventory(TestCase):
27
def test_add_path(self):
29
inv = Inventory(root_id=None)
30
self.assertIs(None, inv.root)
31
ie = inv.add_path("", "directory", "my-root")
32
self.assertEqual("my-root", ie.file_id)
33
self.assertIs(ie, inv.root)
35
def test_is_within(self):
37
SRC_FOO_C = pathjoin('src', 'foo.c')
38
for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
42
self.assert_(is_inside_any(dirs, fn))
44
for dirs, fn in [(['src'], 'srccontrol'),
45
(['src'], 'srccontrol/foo')]:
46
self.assertFalse(is_inside_any(dirs, fn))
48
def test_is_within_or_parent(self):
49
for dirs, fn in [(['src', 'doc'], 'src/foo.c'),
50
(['src'], 'src/foo.c'),
51
(['src/bar.c'], 'src'),
52
(['src/bar.c', 'bla/foo.c'], 'src'),
55
self.assert_(is_inside_or_parent_of_any(dirs, fn))
57
for dirs, fn in [(['src'], 'srccontrol'),
58
(['srccontrol/foo.c'], 'src'),
59
(['src'], 'srccontrol/foo')]:
60
self.assertFalse(is_inside_or_parent_of_any(dirs, fn))
63
"""Test detection of files within selected directories."""
66
for args in [('src', 'directory', 'src-id'),
67
('doc', 'directory', 'doc-id'),
68
('src/hello.c', 'file'),
69
('src/bye.c', 'file', 'bye-id'),
70
('Makefile', 'file')]:
73
self.assertEqual(inv.path2id('src'), 'src-id')
74
self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
76
self.assert_('src-id' in inv)
78
def test_non_directory_children(self):
79
"""Test path2id when a parent directory has no children"""
80
inv = inventory.Inventory('tree_root')
81
inv.add(inventory.InventoryFile('file-id','file',
82
parent_id='tree_root'))
83
inv.add(inventory.InventoryLink('link-id','link',
84
parent_id='tree_root'))
85
self.assertIs(None, inv.path2id('file/subfile'))
86
self.assertIs(None, inv.path2id('link/subfile'))
88
def test_iter_entries(self):
91
for args in [('src', 'directory', 'src-id'),
92
('doc', 'directory', 'doc-id'),
93
('src/hello.c', 'file', 'hello-id'),
94
('src/bye.c', 'file', 'bye-id'),
95
('Makefile', 'file', 'makefile-id')]:
100
('Makefile', 'makefile-id'),
103
('src/bye.c', 'bye-id'),
104
('src/hello.c', 'hello-id'),
105
], [(path, ie.file_id) for path, ie in inv.iter_entries()])
107
def test_iter_entries_by_dir(self):
110
for args in [('src', 'directory', 'src-id'),
111
('doc', 'directory', 'doc-id'),
112
('src/hello.c', 'file', 'hello-id'),
113
('src/bye.c', 'file', 'bye-id'),
114
('zz', 'file', 'zz-id'),
115
('src/sub/', 'directory', 'sub-id'),
116
('src/zz.c', 'file', 'zzc-id'),
117
('src/sub/a', 'file', 'a-id'),
118
('Makefile', 'file', 'makefile-id')]:
123
('Makefile', 'makefile-id'),
127
('src/bye.c', 'bye-id'),
128
('src/hello.c', 'hello-id'),
129
('src/sub', 'sub-id'),
130
('src/zz.c', 'zzc-id'),
131
('src/sub/a', 'a-id'),
132
], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir()])
136
('Makefile', 'makefile-id'),
140
('src/bye.c', 'bye-id'),
141
('src/hello.c', 'hello-id'),
142
('src/sub', 'sub-id'),
143
('src/zz.c', 'zzc-id'),
144
('src/sub/a', 'a-id'),
145
], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
146
specific_file_ids=('a-id', 'zzc-id', 'doc-id', ROOT_ID,
147
'hello-id', 'bye-id', 'zz-id', 'src-id', 'makefile-id',
151
('Makefile', 'makefile-id'),
154
('src/bye.c', 'bye-id'),
155
('src/hello.c', 'hello-id'),
156
('src/zz.c', 'zzc-id'),
157
('src/sub/a', 'a-id'),
158
], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
159
specific_file_ids=('a-id', 'zzc-id', 'doc-id',
160
'hello-id', 'bye-id', 'zz-id', 'makefile-id'))])
163
('Makefile', 'makefile-id'),
164
('src/bye.c', 'bye-id'),
165
], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
166
specific_file_ids=('bye-id', 'makefile-id'))])
169
('Makefile', 'makefile-id'),
170
('src/bye.c', 'bye-id'),
171
], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
172
specific_file_ids=('bye-id', 'makefile-id'))])
175
('src/bye.c', 'bye-id'),
176
], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir(
177
specific_file_ids=('bye-id',))])
179
def test_add_recursive(self):
180
parent = InventoryDirectory('src-id', 'src', ROOT_ID)
181
child = InventoryFile('hello-id', 'hello.c', 'src-id')
182
parent.children[child.file_id] = child
185
self.assertEqual('src/hello.c', inv.id2path('hello-id'))
188
class TestInventoryEntry(TestCase):
190
def test_file_kind_character(self):
191
file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
192
self.assertEqual(file.kind_character(), '')
194
def test_dir_kind_character(self):
195
dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
196
self.assertEqual(dir.kind_character(), '/')
198
def test_link_kind_character(self):
199
dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
200
self.assertEqual(dir.kind_character(), '')
202
def test_dir_detect_changes(self):
203
left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
205
left.executable = True
206
left.symlink_target='foo'
207
right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
208
right.text_sha1 = 321
209
right.symlink_target='bar'
210
self.assertEqual((False, False), left.detect_changes(right))
211
self.assertEqual((False, False), right.detect_changes(left))
213
def test_file_detect_changes(self):
214
left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
216
right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
217
right.text_sha1 = 123
218
self.assertEqual((False, False), left.detect_changes(right))
219
self.assertEqual((False, False), right.detect_changes(left))
220
left.executable = True
221
self.assertEqual((False, True), left.detect_changes(right))
222
self.assertEqual((False, True), right.detect_changes(left))
223
right.text_sha1 = 321
224
self.assertEqual((True, True), left.detect_changes(right))
225
self.assertEqual((True, True), right.detect_changes(left))
227
def test_symlink_detect_changes(self):
228
left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
230
left.executable = True
231
left.symlink_target='foo'
232
right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
233
right.text_sha1 = 321
234
right.symlink_target='foo'
235
self.assertEqual((False, False), left.detect_changes(right))
236
self.assertEqual((False, False), right.detect_changes(left))
237
left.symlink_target = 'different'
238
self.assertEqual((True, False), left.detect_changes(right))
239
self.assertEqual((True, False), right.detect_changes(left))
241
def test_file_has_text(self):
242
file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
243
self.failUnless(file.has_text())
245
def test_directory_has_text(self):
246
dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
247
self.failIf(dir.has_text())
249
def test_link_has_text(self):
250
link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
251
self.failIf(link.has_text())
253
def test_make_entry(self):
254
self.assertIsInstance(inventory.make_entry("file", "name", ROOT_ID),
255
inventory.InventoryFile)
256
self.assertIsInstance(inventory.make_entry("symlink", "name", ROOT_ID),
257
inventory.InventoryLink)
258
self.assertIsInstance(inventory.make_entry("directory", "name", ROOT_ID),
259
inventory.InventoryDirectory)
261
def test_make_entry_non_normalized(self):
262
orig_normalized_filename = osutils.normalized_filename
265
osutils.normalized_filename = osutils._accessible_normalized_filename
266
entry = inventory.make_entry("file", u'a\u030a', ROOT_ID)
267
self.assertEqual(u'\xe5', entry.name)
268
self.assertIsInstance(entry, inventory.InventoryFile)
270
osutils.normalized_filename = osutils._inaccessible_normalized_filename
271
self.assertRaises(errors.InvalidNormalization,
272
inventory.make_entry, 'file', u'a\u030a', ROOT_ID)
274
osutils.normalized_filename = orig_normalized_filename
277
class TestDescribeChanges(TestCase):
279
def test_describe_change(self):
280
# we need to test the following change combinations:
286
# renamed/reparented and modified
287
# change kind (perhaps can't be done yet?)
288
# also, merged in combination with all of these?
289
old_a = InventoryFile('a-id', 'a_file', ROOT_ID)
290
old_a.text_sha1 = '123132'
292
new_a = InventoryFile('a-id', 'a_file', ROOT_ID)
293
new_a.text_sha1 = '123132'
296
self.assertChangeDescription('unchanged', old_a, new_a)
299
new_a.text_sha1 = 'abcabc'
300
self.assertChangeDescription('modified', old_a, new_a)
302
self.assertChangeDescription('added', None, new_a)
303
self.assertChangeDescription('removed', old_a, None)
304
# perhaps a bit questionable but seems like the most reasonable thing...
305
self.assertChangeDescription('unchanged', None, None)
307
# in this case it's both renamed and modified; show a rename and
309
new_a.name = 'newfilename'
310
self.assertChangeDescription('modified and renamed', old_a, new_a)
312
# reparenting is 'renaming'
313
new_a.name = old_a.name
314
new_a.parent_id = 'somedir-id'
315
self.assertChangeDescription('modified and renamed', old_a, new_a)
317
# reset the content values so its not modified
318
new_a.text_size = old_a.text_size
319
new_a.text_sha1 = old_a.text_sha1
320
new_a.name = old_a.name
322
new_a.name = 'newfilename'
323
self.assertChangeDescription('renamed', old_a, new_a)
325
# reparenting is 'renaming'
326
new_a.name = old_a.name
327
new_a.parent_id = 'somedir-id'
328
self.assertChangeDescription('renamed', old_a, new_a)
330
def assertChangeDescription(self, expected_change, old_ie, new_ie):
331
change = InventoryEntry.describe_change(old_ie, new_ie)
332
self.assertEqual(expected_change, change)
335
class TestIsRoot(TestCase):
336
"""Ensure our root-checking code is accurate."""
338
def test_is_root(self):
339
inv = Inventory('TREE_ROOT')
340
self.assertTrue(inv.is_root('TREE_ROOT'))
341
self.assertFalse(inv.is_root('booga'))
342
inv.root.file_id = 'booga'
343
self.assertFalse(inv.is_root('TREE_ROOT'))
344
self.assertTrue(inv.is_root('booga'))
345
# works properly even if no root is set
347
self.assertFalse(inv.is_root('TREE_ROOT'))
348
self.assertFalse(inv.is_root('booga'))
351
class TestTreeReference(TestCase):
353
def test_create(self):
354
inv = Inventory('tree-root-123')
355
inv.add(TreeReference('nested-id', 'nested', parent_id='tree-root-123',
356
revision='rev', reference_revision='rev2'))
359
class TestEncoding(TestCase):
361
def test_error_encoding(self):
362
inv = Inventory('tree-root')
363
inv.add(InventoryFile('a-id', u'\u1234', 'tree-root'))
365
inv.add(InventoryFile('b-id', u'\u1234', 'tree-root'))
366
except errors.BzrError, e:
367
self.assertContainsRe(str(e), u'\u1234'.encode('utf-8'))
369
self.fail('BzrError not raised')