1# Copyright (C) 2005-2011 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 17from io import BytesIO 18 19from ... import ( 20 errors, 21 fifo_cache, 22 ) 23from .. import ( 24 inventory, 25 serializer, 26 xml6, 27 xml7, 28 xml8, 29 ) 30from ..inventory import Inventory 31from . import TestCase 32import breezy.bzr.xml5 33 34_revision_v5 = b"""<revision committer="Martin Pool <mbp@sourcefrog.net>" 35 inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" 36 revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" 37 timestamp="1125907235.212" 38 timezone="36000"> 39<message>- start splitting code for xml (de)serialization away from objects 40 preparatory to supporting multiple formats by a single library 41</message> 42<parents> 43<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"/> 44</parents> 45</revision> 46""" 47 48_revision_v5_utc = b"""\ 49<revision committer="Martin Pool <mbp@sourcefrog.net>" 50 inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" 51 revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" 52 timestamp="1125907235.212" 53 timezone="0"> 54<message>- start splitting code for xml (de)serialization away from objects 55 preparatory to supporting multiple formats by a single library 56</message> 57<parents> 58<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"/> 59</parents> 60</revision> 61""" 62 63_committed_inv_v5 = b"""<inventory> 64<file file_id="bar-20050901064931-73b4b1138abc9cd2" 65 name="bar" parent_id="TREE_ROOT" 66 revision="mbp@foo-123123" 67 text_sha1="A" text_size="1"/> 68<directory name="subdir" 69 file_id="foo-20050801201819-4139aa4a272f4250" 70 parent_id="TREE_ROOT" 71 revision="mbp@foo-00"/> 72<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" 73 name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 74 revision="mbp@foo-00" 75 text_sha1="B" text_size="0"/> 76</inventory> 77""" 78 79_basis_inv_v5 = b"""<inventory revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92"> 80<file file_id="bar-20050901064931-73b4b1138abc9cd2" 81 name="bar" parent_id="TREE_ROOT" 82 revision="mbp@foo-123123"/> 83<directory name="subdir" 84 file_id="foo-20050801201819-4139aa4a272f4250" 85 parent_id="TREE_ROOT" 86 revision="mbp@foo-00"/> 87<file file_id="bar-20050824000535-6bc48cfad47ed134" 88 name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" 89 revision="mbp@foo-00"/> 90</inventory> 91""" 92 93 94# DO NOT REFLOW THIS. Its the exact revision we want. 95_expected_rev_v5 = b"""<revision committer="Martin Pool <mbp@sourcefrog.net>" format="5" inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" timestamp="1125907235.212" timezone="36000"> 96<message>- start splitting code for xml (de)serialization away from objects 97 preparatory to supporting multiple formats by a single library 98</message> 99<parents> 100<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" /> 101</parents> 102</revision> 103""" 104 105 106# DO NOT REFLOW THIS. Its the exact inventory we want. 107_expected_inv_v5 = b"""<inventory format="5"> 108<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" revision="mbp@foo-123123" text_sha1="A" text_size="1" /> 109<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" revision="mbp@foo-00" /> 110<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" text_sha1="B" text_size="0" /> 111</inventory> 112""" 113 114 115_expected_inv_v5_root = b"""<inventory file_id="f<" format="5" revision_id="mother!"> 116<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" parent_id="f<" revision="mbp@foo-123123" text_sha1="A" text_size="1" /> 117<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" parent_id="f<" revision="mbp@foo-00" /> 118<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" text_sha1="B" text_size="0" /> 119<symlink file_id="link-1" name="link" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" symlink_target="a" /> 120</inventory> 121""" 122 123_expected_inv_v6 = b"""<inventory format="6" revision_id="rev_outer"> 124<directory file_id="tree-root-321" name="" revision="rev_outer" /> 125<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" /> 126<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" text_sha1="A" text_size="1" /> 127<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" symlink_target="a" /> 128</inventory> 129""" 130 131_expected_inv_v7 = b"""<inventory format="7" revision_id="rev_outer"> 132<directory file_id="tree-root-321" name="" revision="rev_outer" /> 133<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" /> 134<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" text_sha1="A" text_size="1" /> 135<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" symlink_target="a" /> 136<tree-reference file_id="nested-id" name="nested" parent_id="tree-root-321" revision="rev_outer" reference_revision="rev_inner" /> 137</inventory> 138""" 139 140_expected_rev_v8 = b"""<revision committer="Martin Pool <mbp@sourcefrog.net>" format="8" inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" timestamp="1125907235.212" timezone="36000"> 141<message>- start splitting code for xml (de)serialization away from objects 142 preparatory to supporting multiple formats by a single library 143</message> 144<parents> 145<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" /> 146</parents> 147</revision> 148""" 149 150_expected_inv_v8 = b"""<inventory format="8" revision_id="rev_outer"> 151<directory file_id="tree-root-321" name="" revision="rev_outer" /> 152<directory file_id="dir-id" name="dir" parent_id="tree-root-321" revision="rev_outer" /> 153<file file_id="file-id" name="file" parent_id="tree-root-321" revision="rev_outer" text_sha1="A" text_size="1" /> 154<symlink file_id="link-id" name="link" parent_id="tree-root-321" revision="rev_outer" symlink_target="a" /> 155</inventory> 156""" 157 158_revision_utf8_v5 = b"""<revision committer="Erik Bågfors <erik@foo.net>" 159 inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" 160 revision_id="erik@bågfors-02" 161 timestamp="1125907235.212" 162 timezone="36000"> 163<message>Include µnicode characters 164</message> 165<parents> 166<revision_ref revision_id="erik@bågfors-01"/> 167</parents> 168</revision> 169""" 170 171_expected_rev_v8_complex = b"""<revision committer="Erik Bågfors <erik@foo.net>" format="8" inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" revision_id="erik@bågfors-02" timestamp="1125907235.212" timezone="36000"> 172<message>Include µnicode characters 173</message> 174<parents> 175<revision_ref revision_id="erik@bågfors-01" /> 176<revision_ref revision_id="erik@bagfors-02" /> 177</parents> 178<properties><property name="bar" /> 179<property name="foo">this has a 180newline in it</property> 181</properties> 182</revision> 183""" 184 185 186 187_inventory_utf8_v5 = b"""<inventory file_id="TREé_ROOT" format="5" 188 revision_id="erik@bågfors-02"> 189<file file_id="bår-01" 190 name="bår" parent_id="TREé_ROOT" 191 revision="erik@bågfors-01"/> 192<directory name="sµbdir" 193 file_id="sµbdir-01" 194 parent_id="TREé_ROOT" 195 revision="erik@bågfors-01"/> 196<file executable="yes" file_id="bår-02" 197 name="bår" parent_id="sµbdir-01" 198 revision="erik@bågfors-02"/> 199</inventory> 200""" 201 202# Before revision_id was always stored as an attribute 203_inventory_v5a = b"""<inventory format="5"> 204</inventory> 205""" 206 207# Before revision_id was always stored as an attribute 208_inventory_v5b = b"""<inventory format="5" revision_id="a-rev-id"> 209</inventory> 210""" 211 212 213class TestSerializer(TestCase): 214 """Test XML serialization""" 215 216 def test_unpack_revision_5(self): 217 """Test unpacking a canned revision v5""" 218 inp = BytesIO(_revision_v5) 219 rev = breezy.bzr.xml5.serializer_v5.read_revision(inp) 220 eq = self.assertEqual 221 eq(rev.committer, 222 "Martin Pool <mbp@sourcefrog.net>") 223 eq(len(rev.parent_ids), 1) 224 eq(rev.timezone, 36000) 225 eq(rev.parent_ids[0], 226 b"mbp@sourcefrog.net-20050905063503-43948f59fa127d92") 227 228 def test_unpack_revision_5_utc(self): 229 inp = BytesIO(_revision_v5_utc) 230 rev = breezy.bzr.xml5.serializer_v5.read_revision(inp) 231 eq = self.assertEqual 232 eq(rev.committer, 233 "Martin Pool <mbp@sourcefrog.net>") 234 eq(len(rev.parent_ids), 1) 235 eq(rev.timezone, 0) 236 eq(rev.parent_ids[0], 237 b"mbp@sourcefrog.net-20050905063503-43948f59fa127d92") 238 239 def test_unpack_inventory_5(self): 240 """Unpack canned new-style inventory""" 241 inp = BytesIO(_committed_inv_v5) 242 inv = breezy.bzr.xml5.serializer_v5.read_inventory(inp) 243 eq = self.assertEqual 244 eq(len(inv), 4) 245 ie = inv.get_entry(b'bar-20050824000535-6bc48cfad47ed134') 246 eq(ie.kind, 'file') 247 eq(ie.revision, b'mbp@foo-00') 248 eq(ie.name, 'bar') 249 eq(inv.get_entry(ie.parent_id).kind, 'directory') 250 251 def test_unpack_basis_inventory_5(self): 252 """Unpack canned new-style inventory""" 253 inv = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 254 breezy.osutils.split_lines(_basis_inv_v5)) 255 eq = self.assertEqual 256 eq(len(inv), 4) 257 eq(inv.revision_id, 258 b'mbp@sourcefrog.net-20050905063503-43948f59fa127d92') 259 ie = inv.get_entry(b'bar-20050824000535-6bc48cfad47ed134') 260 eq(ie.kind, 'file') 261 eq(ie.revision, b'mbp@foo-00') 262 eq(ie.name, 'bar') 263 eq(inv.get_entry(ie.parent_id).kind, 'directory') 264 265 def test_unpack_inventory_5a(self): 266 inv = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 267 breezy.osutils.split_lines(_inventory_v5a), revision_id=b'test-rev-id') 268 self.assertEqual(b'test-rev-id', inv.root.revision) 269 270 def test_unpack_inventory_5a_cache_and_copy(self): 271 # Passing an entry_cache should get populated with the objects 272 # But the returned objects should be copies if return_from_cache is 273 # False 274 entry_cache = fifo_cache.FIFOCache() 275 inv = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 276 breezy.osutils.split_lines(_inventory_v5a), revision_id=b'test-rev-id', 277 entry_cache=entry_cache, return_from_cache=False) 278 for entry in inv.iter_just_entries(): 279 key = (entry.file_id, entry.revision) 280 if entry.file_id is inv.root.file_id: 281 # The root id is inferred for xml v5 282 self.assertFalse(key in entry_cache) 283 else: 284 self.assertIsNot(entry, entry_cache[key]) 285 286 def test_unpack_inventory_5a_cache_no_copy(self): 287 # Passing an entry_cache should get populated with the objects 288 # The returned objects should be exact if return_from_cache is 289 # True 290 entry_cache = fifo_cache.FIFOCache() 291 inv = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 292 breezy.osutils.split_lines(_inventory_v5a), revision_id=b'test-rev-id', 293 entry_cache=entry_cache, return_from_cache=True) 294 for entry in inv.iter_just_entries(): 295 key = (entry.file_id, entry.revision) 296 if entry.file_id is inv.root.file_id: 297 # The root id is inferred for xml v5 298 self.assertFalse(key in entry_cache) 299 else: 300 self.assertIs(entry, entry_cache[key]) 301 302 def test_unpack_inventory_5b(self): 303 inv = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 304 breezy.osutils.split_lines(_inventory_v5b), revision_id=b'test-rev-id') 305 self.assertEqual(b'a-rev-id', inv.root.revision) 306 307 def test_repack_inventory_5(self): 308 inv = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 309 breezy.osutils.split_lines(_committed_inv_v5)) 310 outp = BytesIO() 311 breezy.bzr.xml5.serializer_v5.write_inventory(inv, outp) 312 self.assertEqualDiff(_expected_inv_v5, outp.getvalue()) 313 inv2 = breezy.bzr.xml5.serializer_v5.read_inventory_from_lines( 314 breezy.osutils.split_lines(outp.getvalue())) 315 self.assertEqual(inv, inv2) 316 317 def assertRoundTrips(self, xml_string): 318 inp = BytesIO(xml_string) 319 inv = breezy.bzr.xml5.serializer_v5.read_inventory(inp) 320 outp = BytesIO() 321 breezy.bzr.xml5.serializer_v5.write_inventory(inv, outp) 322 self.assertEqualDiff(xml_string, outp.getvalue()) 323 lines = breezy.bzr.xml5.serializer_v5.write_inventory_to_lines(inv) 324 outp.seek(0) 325 self.assertEqual(outp.readlines(), lines) 326 inv2 = breezy.bzr.xml5.serializer_v5.read_inventory( 327 BytesIO(outp.getvalue())) 328 self.assertEqual(inv, inv2) 329 330 def tests_serialize_inventory_v5_with_root(self): 331 self.assertRoundTrips(_expected_inv_v5_root) 332 333 def check_repack_revision(self, txt): 334 """Check that repacking a revision yields the same information""" 335 inp = BytesIO(txt) 336 rev = breezy.bzr.xml5.serializer_v5.read_revision(inp) 337 outfile_contents = breezy.bzr.xml5.serializer_v5.write_revision_to_string(rev) 338 rev2 = breezy.bzr.xml5.serializer_v5.read_revision( 339 BytesIO(outfile_contents)) 340 self.assertEqual(rev, rev2) 341 342 def test_repack_revision_5(self): 343 """Round-trip revision to XML v5""" 344 self.check_repack_revision(_revision_v5) 345 346 def test_repack_revision_5_utc(self): 347 self.check_repack_revision(_revision_v5_utc) 348 349 def test_pack_revision_5(self): 350 """Pack revision to XML v5""" 351 # fixed 20051025, revisions should have final newline 352 rev = breezy.bzr.xml5.serializer_v5.read_revision_from_string( 353 _revision_v5) 354 outfile_contents = breezy.bzr.xml5.serializer_v5.write_revision_to_string(rev) 355 self.assertEqual(outfile_contents[-1:], b'\n') 356 self.assertEqualDiff( 357 outfile_contents, 358 b''.join(breezy.bzr.xml5.serializer_v5.write_revision_to_lines(rev))) 359 self.assertEqualDiff(outfile_contents, _expected_rev_v5) 360 361 def test_empty_property_value(self): 362 """Create an empty property value check that it serializes correctly""" 363 s_v5 = breezy.bzr.xml5.serializer_v5 364 rev = s_v5.read_revision_from_string(_revision_v5) 365 props = {'empty': '', 'one': 'one'} 366 rev.properties = props 367 txt = b''.join(s_v5.write_revision_to_lines(rev)) 368 new_rev = s_v5.read_revision_from_string(txt) 369 self.assertEqual(props, new_rev.properties) 370 371 def get_sample_inventory(self): 372 inv = Inventory(b'tree-root-321', revision_id=b'rev_outer') 373 inv.add(inventory.InventoryFile(b'file-id', 'file', b'tree-root-321')) 374 inv.add(inventory.InventoryDirectory(b'dir-id', 'dir', 375 b'tree-root-321')) 376 inv.add(inventory.InventoryLink(b'link-id', 'link', b'tree-root-321')) 377 inv.get_entry(b'tree-root-321').revision = b'rev_outer' 378 inv.get_entry(b'dir-id').revision = b'rev_outer' 379 inv.get_entry(b'file-id').revision = b'rev_outer' 380 inv.get_entry(b'file-id').text_sha1 = b'A' 381 inv.get_entry(b'file-id').text_size = 1 382 inv.get_entry(b'link-id').revision = b'rev_outer' 383 inv.get_entry(b'link-id').symlink_target = 'a' 384 return inv 385 386 def test_roundtrip_inventory_v7(self): 387 inv = self.get_sample_inventory() 388 inv.add(inventory.TreeReference(b'nested-id', 'nested', b'tree-root-321', 389 b'rev_outer', b'rev_inner')) 390 lines = xml7.serializer_v7.write_inventory_to_lines(inv) 391 self.assertEqualDiff(_expected_inv_v7, b''.join(lines)) 392 inv2 = xml7.serializer_v7.read_inventory_from_lines(lines) 393 self.assertEqual(5, len(inv2)) 394 for path, ie in inv.iter_entries(): 395 self.assertEqual(ie, inv2.get_entry(ie.file_id)) 396 397 def test_roundtrip_inventory_v6(self): 398 inv = self.get_sample_inventory() 399 lines = xml6.serializer_v6.write_inventory_to_lines(inv) 400 self.assertEqualDiff(_expected_inv_v6, b''.join(lines)) 401 inv2 = xml6.serializer_v6.read_inventory_from_lines(lines) 402 self.assertEqual(4, len(inv2)) 403 for path, ie in inv.iter_entries(): 404 self.assertEqual(ie, inv2.get_entry(ie.file_id)) 405 406 def test_wrong_format_v7(self): 407 """Can't accidentally open a file with wrong serializer""" 408 s_v6 = breezy.bzr.xml6.serializer_v6 409 s_v7 = xml7.serializer_v7 410 self.assertRaises(serializer.UnexpectedInventoryFormat, 411 s_v7.read_inventory_from_lines, 412 breezy.osutils.split_lines(_expected_inv_v5)) 413 self.assertRaises(serializer.UnexpectedInventoryFormat, 414 s_v6.read_inventory_from_lines, 415 breezy.osutils.split_lines(_expected_inv_v7)) 416 417 def test_tree_reference(self): 418 s_v5 = breezy.bzr.xml5.serializer_v5 419 s_v6 = breezy.bzr.xml6.serializer_v6 420 s_v7 = xml7.serializer_v7 421 inv = Inventory(b'tree-root-321', revision_id=b'rev-outer') 422 inv.root.revision = b'root-rev' 423 inv.add(inventory.TreeReference(b'nested-id', 'nested', b'tree-root-321', 424 b'rev-outer', b'rev-inner')) 425 self.assertRaises(serializer.UnsupportedInventoryKind, 426 s_v5.write_inventory_to_lines, inv) 427 self.assertRaises(serializer.UnsupportedInventoryKind, 428 s_v6.write_inventory_to_lines, inv) 429 lines = s_v7.write_inventory_to_chunks(inv) 430 inv2 = s_v7.read_inventory_from_lines(lines) 431 self.assertEqual(b'tree-root-321', 432 inv2.get_entry(b'nested-id').parent_id) 433 self.assertEqual(b'rev-outer', inv2.get_entry(b'nested-id').revision) 434 self.assertEqual( 435 b'rev-inner', inv2.get_entry(b'nested-id').reference_revision) 436 437 def test_roundtrip_inventory_v8(self): 438 inv = self.get_sample_inventory() 439 lines = xml8.serializer_v8.write_inventory_to_lines(inv) 440 inv2 = xml8.serializer_v8.read_inventory_from_lines(lines) 441 self.assertEqual(4, len(inv2)) 442 for path, ie in inv.iter_entries(): 443 self.assertEqual(ie, inv2.get_entry(ie.file_id)) 444 445 def test_inventory_text_v8(self): 446 inv = self.get_sample_inventory() 447 lines = xml8.serializer_v8.write_inventory_to_lines(inv) 448 self.assertEqualDiff(_expected_inv_v8, b''.join(lines)) 449 450 def test_revision_text_v6(self): 451 """Pack revision to XML v6""" 452 rev = breezy.bzr.xml6.serializer_v6.read_revision_from_string( 453 _expected_rev_v5) 454 serialized = breezy.bzr.xml6.serializer_v6.write_revision_to_lines( 455 rev) 456 self.assertEqualDiff(b''.join(serialized), _expected_rev_v5) 457 458 def test_revision_text_v7(self): 459 """Pack revision to XML v7""" 460 rev = breezy.bzr.xml7.serializer_v7.read_revision_from_string( 461 _expected_rev_v5) 462 serialized = breezy.bzr.xml7.serializer_v7.write_revision_to_lines( 463 rev) 464 self.assertEqualDiff(b''.join(serialized), _expected_rev_v5) 465 466 def test_revision_text_v8(self): 467 """Pack revision to XML v8""" 468 rev = breezy.bzr.xml8.serializer_v8.read_revision_from_string( 469 _expected_rev_v8) 470 serialized = breezy.bzr.xml8.serializer_v8.write_revision_to_lines( 471 rev) 472 self.assertEqualDiff(b''.join(serialized), _expected_rev_v8) 473 474 def test_revision_text_v8_complex(self): 475 """Pack revision to XML v8""" 476 rev = breezy.bzr.xml8.serializer_v8.read_revision_from_string( 477 _expected_rev_v8_complex) 478 serialized = breezy.bzr.xml8.serializer_v8.write_revision_to_lines( 479 rev) 480 self.assertEqualDiff(b''.join(serialized), _expected_rev_v8_complex) 481 482 def test_revision_ids_are_utf8(self): 483 """Parsed revision_ids should all be utf-8 strings, not unicode.""" 484 s_v5 = breezy.bzr.xml5.serializer_v5 485 rev = s_v5.read_revision_from_string(_revision_utf8_v5) 486 self.assertEqual(b'erik@b\xc3\xa5gfors-02', rev.revision_id) 487 self.assertIsInstance(rev.revision_id, bytes) 488 self.assertEqual([b'erik@b\xc3\xa5gfors-01'], rev.parent_ids) 489 for parent_id in rev.parent_ids: 490 self.assertIsInstance(parent_id, bytes) 491 self.assertEqual(u'Include \xb5nicode characters\n', rev.message) 492 self.assertIsInstance(rev.message, str) 493 494 # ie.revision should either be None or a utf-8 revision id 495 inv = s_v5.read_inventory_from_lines(breezy.osutils.split_lines(_inventory_utf8_v5)) 496 rev_id_1 = u'erik@b\xe5gfors-01'.encode('utf8') 497 rev_id_2 = u'erik@b\xe5gfors-02'.encode('utf8') 498 fid_root = u'TRE\xe9_ROOT'.encode('utf8') 499 fid_bar1 = u'b\xe5r-01'.encode('utf8') 500 fid_sub = u's\xb5bdir-01'.encode('utf8') 501 fid_bar2 = u'b\xe5r-02'.encode('utf8') 502 expected = [(u'', fid_root, None, rev_id_2), 503 (u'b\xe5r', fid_bar1, fid_root, rev_id_1), 504 (u's\xb5bdir', fid_sub, fid_root, rev_id_1), 505 (u's\xb5bdir/b\xe5r', fid_bar2, fid_sub, rev_id_2), 506 ] 507 self.assertEqual(rev_id_2, inv.revision_id) 508 self.assertIsInstance(inv.revision_id, bytes) 509 510 actual = list(inv.iter_entries_by_dir()) 511 for ((exp_path, exp_file_id, exp_parent_id, exp_rev_id), 512 (act_path, act_ie)) in zip(expected, actual): 513 self.assertEqual(exp_path, act_path) 514 self.assertIsInstance(act_path, str) 515 self.assertEqual(exp_file_id, act_ie.file_id) 516 self.assertIsInstance(act_ie.file_id, bytes) 517 self.assertEqual(exp_parent_id, act_ie.parent_id) 518 if exp_parent_id is not None: 519 self.assertIsInstance(act_ie.parent_id, bytes) 520 self.assertEqual(exp_rev_id, act_ie.revision) 521 if exp_rev_id is not None: 522 self.assertIsInstance(act_ie.revision, bytes) 523 524 self.assertEqual(len(expected), len(actual)) 525 526 def test_serialization_error(self): 527 s_v5 = breezy.bzr.xml5.serializer_v5 528 e = self.assertRaises( 529 serializer.UnexpectedInventoryFormat, 530 s_v5.read_inventory_from_lines, [b"<Notquitexml"]) 531 self.assertEqual(str(e), "unclosed token: line 1, column 0") 532 533 534class TestEncodeAndEscape(TestCase): 535 """Whitebox testing of the _encode_and_escape function.""" 536 537 def setUp(self): 538 super(TestEncodeAndEscape, self).setUp() 539 # Keep the cache clear before and after the test 540 breezy.bzr.xml_serializer._clear_cache() 541 self.addCleanup(breezy.bzr.xml_serializer._clear_cache) 542 543 def test_simple_ascii(self): 544 # _encode_and_escape always appends a final ", because these parameters 545 # are being used in xml attributes, and by returning it now, we have to 546 # do fewer string operations later. 547 val = breezy.bzr.xml_serializer.encode_and_escape('foo bar') 548 self.assertEqual(b'foo bar', val) 549 # The second time should be cached 550 val2 = breezy.bzr.xml_serializer.encode_and_escape('foo bar') 551 self.assertIs(val2, val) 552 553 def test_ascii_with_xml(self): 554 self.assertEqual(b'&'"<>', 555 breezy.bzr.xml_serializer.encode_and_escape('&\'"<>')) 556 557 def test_utf8_with_xml(self): 558 # u'\xb5\xe5&\u062c' 559 utf8_str = b'\xc2\xb5\xc3\xa5&\xd8\xac' 560 self.assertEqual(b'µå&ج', 561 breezy.bzr.xml_serializer.encode_and_escape(utf8_str)) 562 563 def test_unicode(self): 564 uni_str = u'\xb5\xe5&\u062c' 565 self.assertEqual(b'µå&ج', 566 breezy.bzr.xml_serializer.encode_and_escape(uni_str)) 567 568 569class TestMisc(TestCase): 570 571 def test_unescape_xml(self): 572 """We get some kind of error when malformed entities are passed""" 573 self.assertRaises(KeyError, breezy.bzr.xml8._unescape_xml, b'foo&bar;') 574