1# Copyright (C) 2005, 2006, 2007 Canonical Ltd 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 17"""Tests for different inventory implementations""" 18 19# NOTE: Don't import Inventory here, to make sure that we don't accidentally 20# hardcode that when we should be using self.make_inventory 21 22from breezy import ( 23 errors, 24 osutils, 25 ) 26from breezy.bzr import ( 27 inventory, 28 ) 29 30from breezy.bzr.inventory import ( 31 InventoryDirectory, 32 InventoryEntry, 33 InventoryFile, 34 InventoryLink, 35 TreeReference, 36 ) 37 38from breezy.bzr.tests.per_inventory import TestCaseWithInventory 39 40 41class TestInventory(TestCaseWithInventory): 42 43 def make_init_inventory(self): 44 inv = inventory.Inventory(b'tree-root') 45 inv.revision = b'initial-rev' 46 inv.root.revision = b'initial-rev' 47 return self.inv_to_test_inv(inv) 48 49 def make_file(self, file_id, name, parent_id, content=b'content\n', 50 revision=b'new-test-rev'): 51 ie = InventoryFile(file_id, name, parent_id) 52 ie.text_sha1 = osutils.sha_string(content) 53 ie.text_size = len(content) 54 ie.revision = revision 55 return ie 56 57 def make_link(self, file_id, name, parent_id, target='link-target\n'): 58 ie = InventoryLink(file_id, name, parent_id) 59 ie.symlink_target = target 60 return ie 61 62 def prepare_inv_with_nested_dirs(self): 63 inv = inventory.Inventory(b'tree-root') 64 inv.root.revision = b'revision' 65 for args in [('src', 'directory', b'src-id'), 66 ('doc', 'directory', b'doc-id'), 67 ('src/hello.c', 'file', b'hello-id'), 68 ('src/bye.c', 'file', b'bye-id'), 69 ('zz', 'file', b'zz-id'), 70 ('src/sub/', 'directory', b'sub-id'), 71 ('src/zz.c', 'file', b'zzc-id'), 72 ('src/sub/a', 'file', b'a-id'), 73 ('Makefile', 'file', b'makefile-id')]: 74 ie = inv.add_path(*args) 75 ie.revision = b'revision' 76 if args[1] == 'file': 77 ie.text_sha1 = osutils.sha_string(b'content\n') 78 ie.text_size = len(b'content\n') 79 return self.inv_to_test_inv(inv) 80 81 82class TestInventoryCreateByApplyDelta(TestInventory): 83 """A subset of the inventory delta application tests. 84 85 See test_inv which has comprehensive delta application tests for 86 inventories, dirstate, and repository based inventories. 87 """ 88 89 def test_add(self): 90 inv = self.make_init_inventory() 91 inv = inv.create_by_apply_delta([ 92 (None, "a", b"a-id", self.make_file(b'a-id', 'a', b'tree-root')), 93 ], b'new-test-rev') 94 self.assertEqual('a', inv.id2path(b'a-id')) 95 96 def test_delete(self): 97 inv = self.make_init_inventory() 98 inv = inv.create_by_apply_delta([ 99 (None, "a", b"a-id", self.make_file(b'a-id', 'a', b'tree-root')), 100 ], b'new-rev-1') 101 self.assertEqual('a', inv.id2path(b'a-id')) 102 inv = inv.create_by_apply_delta([ 103 ("a", None, b"a-id", None), 104 ], b'new-rev-2') 105 self.assertRaises(errors.NoSuchId, inv.id2path, b'a-id') 106 107 def test_rename(self): 108 inv = self.make_init_inventory() 109 inv = inv.create_by_apply_delta([ 110 (None, "a", b"a-id", self.make_file(b'a-id', 'a', b'tree-root')), 111 ], b'new-rev-1') 112 self.assertEqual('a', inv.id2path(b'a-id')) 113 a_ie = inv.get_entry(b'a-id') 114 b_ie = self.make_file(a_ie.file_id, "b", a_ie.parent_id) 115 inv = inv.create_by_apply_delta( 116 [("a", "b", b"a-id", b_ie)], b'new-rev-2') 117 self.assertEqual("b", inv.id2path(b'a-id')) 118 119 def test_illegal(self): 120 # A file-id cannot appear in a delta more than once 121 inv = self.make_init_inventory() 122 self.assertRaises(errors.InconsistentDelta, inv.create_by_apply_delta, [ 123 (None, "a", b"id-1", self.make_file(b'id-1', 'a', b'tree-root')), 124 (None, "b", b"id-1", self.make_file(b'id-1', 'b', b'tree-root')), 125 ], b'new-rev-1') 126 127 128class TestInventoryReads(TestInventory): 129 130 def test_is_root(self): 131 """Ensure our root-checking code is accurate.""" 132 inv = self.make_init_inventory() 133 self.assertTrue(inv.is_root(b'tree-root')) 134 self.assertFalse(inv.is_root(b'booga')) 135 ie = inv.get_entry(b'tree-root').copy() 136 ie.file_id = b'booga' 137 inv = inv.create_by_apply_delta([("", None, b"tree-root", None), 138 (None, "", b"booga", ie)], b'new-rev-2') 139 self.assertFalse(inv.is_root(b'TREE_ROOT')) 140 self.assertTrue(inv.is_root(b'booga')) 141 142 def test_ids(self): 143 """Test detection of files within selected directories.""" 144 inv = inventory.Inventory(b'TREE_ROOT') 145 inv.root.revision = b'revision' 146 for args in [('src', 'directory', b'src-id'), 147 ('doc', 'directory', b'doc-id'), 148 ('src/hello.c', 'file'), 149 ('src/bye.c', 'file', b'bye-id'), 150 ('Makefile', 'file')]: 151 ie = inv.add_path(*args) 152 ie.revision = b'revision' 153 if args[1] == 'file': 154 ie.text_sha1 = osutils.sha_string(b'content\n') 155 ie.text_size = len(b'content\n') 156 inv = self.inv_to_test_inv(inv) 157 self.assertEqual(inv.path2id('src'), b'src-id') 158 self.assertEqual(inv.path2id('src/bye.c'), b'bye-id') 159 160 def test_get_entry_by_path_partial(self): 161 inv = inventory.Inventory(b'TREE_ROOT') 162 inv.root.revision = b'revision' 163 for args in [('src', 'directory', b'src-id'), 164 ('doc', 'directory', b'doc-id'), 165 ('src/hello.c', 'file'), 166 ('src/bye.c', 'file', b'bye-id'), 167 ('Makefile', 'file'), 168 ('external', 'tree-reference', b'other-root')]: 169 ie = inv.add_path(*args) 170 ie.revision = b'revision' 171 if args[1] == 'file': 172 ie.text_sha1 = osutils.sha_string(b'content\n') 173 ie.text_size = len(b'content\n') 174 if args[1] == 'tree-reference': 175 ie.reference_revision = b'reference' 176 inv = self.inv_to_test_inv(inv) 177 178 # Standard lookups 179 ie, resolved, remaining = inv.get_entry_by_path_partial('') 180 self.assertEqual((ie.file_id, resolved, remaining), (b'TREE_ROOT', [], [])) 181 ie, resolved, remaining = inv.get_entry_by_path_partial('src') 182 self.assertEqual((ie.file_id, resolved, remaining), (b'src-id', ['src'], [])) 183 ie, resolved, remaining = inv.get_entry_by_path_partial('src/bye.c') 184 self.assertEqual((ie.file_id, resolved, remaining), (b'bye-id', ['src', 'bye.c'], [])) 185 186 # Paths in the external tree 187 ie, resolved, remaining = inv.get_entry_by_path_partial('external') 188 self.assertEqual((ie.file_id, resolved, remaining), (b'other-root', ['external'], [])) 189 ie, resolved, remaining = inv.get_entry_by_path_partial('external/blah') 190 self.assertEqual((ie.file_id, resolved, remaining), (b'other-root', ['external'], ['blah'])) 191 192 # Nonexistant paths 193 ie, resolved, remaining = inv.get_entry_by_path_partial('foo.c') 194 self.assertEqual((ie, resolved, remaining), (None, None, None)) 195 196 def test_non_directory_children(self): 197 """Test path2id when a parent directory has no children""" 198 inv = inventory.Inventory(b'tree-root') 199 inv.add(self.make_file(b'file-id', 'file', b'tree-root')) 200 inv.add(self.make_link(b'link-id', 'link', b'tree-root')) 201 self.assertIs(None, inv.path2id('file/subfile')) 202 self.assertIs(None, inv.path2id('link/subfile')) 203 204 def test_is_unmodified(self): 205 f1 = self.make_file(b'file-id', 'file', b'tree-root') 206 f1.revision = b'rev' 207 self.assertTrue(f1.is_unmodified(f1)) 208 f2 = self.make_file(b'file-id', 'file', b'tree-root') 209 f2.revision = b'rev' 210 self.assertTrue(f1.is_unmodified(f2)) 211 f3 = self.make_file(b'file-id', 'file', b'tree-root') 212 self.assertFalse(f1.is_unmodified(f3)) 213 f4 = self.make_file(b'file-id', 'file', b'tree-root') 214 f4.revision = b'rev1' 215 self.assertFalse(f1.is_unmodified(f4)) 216 217 def test_iter_entries(self): 218 inv = self.prepare_inv_with_nested_dirs() 219 220 # Test all entries 221 self.assertEqual([ 222 ('', b'tree-root'), 223 ('Makefile', b'makefile-id'), 224 ('doc', b'doc-id'), 225 ('src', b'src-id'), 226 ('src/bye.c', b'bye-id'), 227 ('src/hello.c', b'hello-id'), 228 ('src/sub', b'sub-id'), 229 ('src/sub/a', b'a-id'), 230 ('src/zz.c', b'zzc-id'), 231 ('zz', b'zz-id'), 232 ], [(path, ie.file_id) for path, ie in inv.iter_entries()]) 233 234 # Test a subdirectory 235 self.assertEqual([ 236 ('bye.c', b'bye-id'), 237 ('hello.c', b'hello-id'), 238 ('sub', b'sub-id'), 239 ('sub/a', b'a-id'), 240 ('zz.c', b'zzc-id'), 241 ], [(path, ie.file_id) for path, ie in inv.iter_entries( 242 from_dir=b'src-id')]) 243 244 # Test not recursing at the root level 245 self.assertEqual([ 246 ('', b'tree-root'), 247 ('Makefile', b'makefile-id'), 248 ('doc', b'doc-id'), 249 ('src', b'src-id'), 250 ('zz', b'zz-id'), 251 ], [(path, ie.file_id) for path, ie in inv.iter_entries( 252 recursive=False)]) 253 254 # Test not recursing at a subdirectory level 255 self.assertEqual([ 256 ('bye.c', b'bye-id'), 257 ('hello.c', b'hello-id'), 258 ('sub', b'sub-id'), 259 ('zz.c', b'zzc-id'), 260 ], [(path, ie.file_id) for path, ie in inv.iter_entries( 261 from_dir=b'src-id', recursive=False)]) 262 263 def test_iter_just_entries(self): 264 inv = self.prepare_inv_with_nested_dirs() 265 self.assertEqual([ 266 b'a-id', 267 b'bye-id', 268 b'doc-id', 269 b'hello-id', 270 b'makefile-id', 271 b'src-id', 272 b'sub-id', 273 b'tree-root', 274 b'zz-id', 275 b'zzc-id', 276 ], sorted([ie.file_id for ie in inv.iter_just_entries()])) 277 278 def test_iter_entries_by_dir(self): 279 inv = self. prepare_inv_with_nested_dirs() 280 self.assertEqual([ 281 ('', b'tree-root'), 282 ('Makefile', b'makefile-id'), 283 ('doc', b'doc-id'), 284 ('src', b'src-id'), 285 ('zz', b'zz-id'), 286 ('src/bye.c', b'bye-id'), 287 ('src/hello.c', b'hello-id'), 288 ('src/sub', b'sub-id'), 289 ('src/zz.c', b'zzc-id'), 290 ('src/sub/a', b'a-id'), 291 ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir()]) 292 self.assertEqual([ 293 ('', b'tree-root'), 294 ('Makefile', b'makefile-id'), 295 ('doc', b'doc-id'), 296 ('src', b'src-id'), 297 ('zz', b'zz-id'), 298 ('src/bye.c', b'bye-id'), 299 ('src/hello.c', b'hello-id'), 300 ('src/sub', b'sub-id'), 301 ('src/zz.c', b'zzc-id'), 302 ('src/sub/a', b'a-id'), 303 ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir( 304 specific_file_ids=(b'a-id', b'zzc-id', b'doc-id', b'tree-root', 305 b'hello-id', b'bye-id', b'zz-id', b'src-id', b'makefile-id', 306 b'sub-id'))]) 307 308 self.assertEqual([ 309 ('Makefile', b'makefile-id'), 310 ('doc', b'doc-id'), 311 ('zz', b'zz-id'), 312 ('src/bye.c', b'bye-id'), 313 ('src/hello.c', b'hello-id'), 314 ('src/zz.c', b'zzc-id'), 315 ('src/sub/a', b'a-id'), 316 ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir( 317 specific_file_ids=(b'a-id', b'zzc-id', b'doc-id', 318 b'hello-id', b'bye-id', b'zz-id', b'makefile-id'))]) 319 320 self.assertEqual([ 321 ('Makefile', b'makefile-id'), 322 ('src/bye.c', b'bye-id'), 323 ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir( 324 specific_file_ids=(b'bye-id', b'makefile-id'))]) 325 326 self.assertEqual([ 327 ('Makefile', b'makefile-id'), 328 ('src/bye.c', b'bye-id'), 329 ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir( 330 specific_file_ids=(b'bye-id', b'makefile-id'))]) 331 332 self.assertEqual([ 333 ('src/bye.c', b'bye-id'), 334 ], [(path, ie.file_id) for path, ie in inv.iter_entries_by_dir( 335 specific_file_ids=(b'bye-id',))]) 336 337 338class TestInventoryFiltering(TestInventory): 339 340 def test_inv_filter_empty(self): 341 inv = self.prepare_inv_with_nested_dirs() 342 new_inv = inv.filter([]) 343 self.assertEqual([ 344 ('', b'tree-root'), 345 ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()]) 346 347 def test_inv_filter_files(self): 348 inv = self.prepare_inv_with_nested_dirs() 349 new_inv = inv.filter([b'zz-id', b'hello-id', b'a-id']) 350 self.assertEqual([ 351 ('', b'tree-root'), 352 ('src', b'src-id'), 353 ('src/hello.c', b'hello-id'), 354 ('src/sub', b'sub-id'), 355 ('src/sub/a', b'a-id'), 356 ('zz', b'zz-id'), 357 ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()]) 358 359 def test_inv_filter_dirs(self): 360 inv = self.prepare_inv_with_nested_dirs() 361 new_inv = inv.filter([b'doc-id', b'sub-id']) 362 self.assertEqual([ 363 ('', b'tree-root'), 364 ('doc', b'doc-id'), 365 ('src', b'src-id'), 366 ('src/sub', b'sub-id'), 367 ('src/sub/a', b'a-id'), 368 ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()]) 369 370 def test_inv_filter_files_and_dirs(self): 371 inv = self.prepare_inv_with_nested_dirs() 372 new_inv = inv.filter([b'makefile-id', b'src-id']) 373 self.assertEqual([ 374 ('', b'tree-root'), 375 ('Makefile', b'makefile-id'), 376 ('src', b'src-id'), 377 ('src/bye.c', b'bye-id'), 378 ('src/hello.c', b'hello-id'), 379 ('src/sub', b'sub-id'), 380 ('src/sub/a', b'a-id'), 381 ('src/zz.c', b'zzc-id'), 382 ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()]) 383 384 def test_inv_filter_entry_not_present(self): 385 inv = self.prepare_inv_with_nested_dirs() 386 new_inv = inv.filter([b'not-present-id']) 387 self.assertEqual([ 388 ('', b'tree-root'), 389 ], [(path, ie.file_id) for path, ie in new_inv.iter_entries()]) 390