1
# Copyright (C) 2005 Canonical Ltd
1
# Copyright (C) 2005 by Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
from cStringIO import StringIO
19
from bzrlib.tests import TestCase
19
from bzrlib.selftest import TestCase
20
20
from bzrlib.inventory import Inventory, InventoryEntry
21
21
from bzrlib.xml4 import serializer_v4
22
from bzrlib.xml5 import serializer_v5
24
24
_working_inventory_v4 = """<inventory file_id="TREE_ROOT">
25
25
<entry file_id="bar-20050901064931-73b4b1138abc9cd2" kind="file" name="bar" parent_id="TREE_ROOT" />
80
65
file_id="foo-20050801201819-4139aa4a272f4250"
81
66
parent_id="TREE_ROOT"
82
67
revision="mbp@foo-00"/>
83
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134"
84
name="bar" parent_id="foo-20050801201819-4139aa4a272f4250"
85
revision="mbp@foo-00"/>
89
_basis_inv_v5 = """<inventory revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92">
90
<file file_id="bar-20050901064931-73b4b1138abc9cd2"
91
name="bar" parent_id="TREE_ROOT"
92
revision="mbp@foo-123123"/>
93
<directory name="subdir"
94
file_id="foo-20050801201819-4139aa4a272f4250"
96
revision="mbp@foo-00"/>
97
68
<file file_id="bar-20050824000535-6bc48cfad47ed134"
98
69
name="bar" parent_id="foo-20050801201819-4139aa4a272f4250"
99
70
revision="mbp@foo-00"/>
104
# DO NOT REFLOW THIS. Its the exact revision we want.
105
_expected_rev_v5 = """<revision committer="Martin Pool <mbp@sourcefrog.net>" format="5" inventory_sha1="e79c31c1deb64c163cf660fdedd476dd579ffd41" revision_id="mbp@sourcefrog.net-20050905080035-e0439293f8b6b9f9" timestamp="1125907235.212" timezone="36000">
106
<message>- start splitting code for xml (de)serialization away from objects
107
preparatory to supporting multiple formats by a single library
110
<revision_ref revision_id="mbp@sourcefrog.net-20050905063503-43948f59fa127d92" />
116
# DO NOT REFLOW THIS. Its the exact inventory we want.
117
_expected_inv_v5 = """<inventory format="5">
118
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" revision="mbp@foo-123123" />
119
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" revision="mbp@foo-00" />
120
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
125
_expected_inv_v5_root = """<inventory file_id="f<" format="5" revision_id="mother!">
126
<file file_id="bar-20050901064931-73b4b1138abc9cd2" name="bar" parent_id="f<" revision="mbp@foo-123123" />
127
<directory file_id="foo-20050801201819-4139aa4a272f4250" name="subdir" parent_id="f<" revision="mbp@foo-00" />
128
<file executable="yes" file_id="bar-20050824000535-6bc48cfad47ed134" name="bar" parent_id="foo-20050801201819-4139aa4a272f4250" revision="mbp@foo-00" />
133
74
class TestSerializer(TestCase):
134
75
"""Test XML serialization"""
135
76
def test_canned_inventory(self):
164
105
eq(rev.parent_ids[0],
165
106
"mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
167
def test_unpack_revision_5_utc(self):
168
inp = StringIO(_revision_v5_utc)
169
rev = bzrlib.xml5.serializer_v5.read_revision(inp)
170
eq = self.assertEqual
172
"Martin Pool <mbp@sourcefrog.net>")
173
eq(len(rev.parent_ids), 1)
175
eq(rev.parent_ids[0],
176
"mbp@sourcefrog.net-20050905063503-43948f59fa127d92")
178
108
def test_unpack_inventory_5(self):
179
109
"""Unpack canned new-style inventory"""
180
110
inp = StringIO(_committed_inv_v5)
181
inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
182
eq = self.assertEqual
184
ie = inv['bar-20050824000535-6bc48cfad47ed134']
186
eq(ie.revision, 'mbp@foo-00')
188
eq(inv[ie.parent_id].kind, 'directory')
190
def test_unpack_basis_inventory_5(self):
191
"""Unpack canned new-style inventory"""
192
inp = StringIO(_basis_inv_v5)
193
inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
194
eq = self.assertEqual
196
eq(inv.revision_id, 'mbp@sourcefrog.net-20050905063503-43948f59fa127d92')
111
inv = serializer_v5.read_inventory(inp)
112
eq = self.assertEqual
197
114
ie = inv['bar-20050824000535-6bc48cfad47ed134']
198
115
eq(ie.kind, 'file')
199
116
eq(ie.revision, 'mbp@foo-00')
203
120
def test_repack_inventory_5(self):
204
121
inp = StringIO(_committed_inv_v5)
205
inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
207
bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
208
self.assertEqualDiff(_expected_inv_v5, outp.getvalue())
209
inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
210
self.assertEqual(inv, inv2)
212
def assertRoundTrips(self, xml_string):
213
inp = StringIO(xml_string)
214
inv = bzrlib.xml5.serializer_v5.read_inventory(inp)
216
bzrlib.xml5.serializer_v5.write_inventory(inv, outp)
217
self.assertEqualDiff(xml_string, outp.getvalue())
218
inv2 = bzrlib.xml5.serializer_v5.read_inventory(StringIO(outp.getvalue()))
219
self.assertEqual(inv, inv2)
221
def tests_serialize_inventory_v5_with_root(self):
222
self.assertRoundTrips(_expected_inv_v5_root)
224
def check_repack_revision(self, txt):
225
"""Check that repacking a revision yields the same information"""
227
rev = bzrlib.xml5.serializer_v5.read_revision(inp)
229
bzrlib.xml5.serializer_v5.write_revision(rev, outp)
230
outfile_contents = outp.getvalue()
231
rev2 = bzrlib.xml5.serializer_v5.read_revision(StringIO(outfile_contents))
122
inv = serializer_v5.read_inventory(inp)
124
serializer_v5.write_inventory(inv, outp)
125
inv2 = serializer_v5.read_inventory(StringIO(outp.getvalue()))
126
self.assertEqual(inv, inv2)
128
def test_repack_revision_5(self):
129
inp = StringIO(_revision_v5)
130
rev = serializer_v5.read_revision(inp)
132
serializer_v5.write_revision(rev, outp)
133
rev2 = serializer_v5.read_revision(StringIO(outp.getvalue()))
232
134
self.assertEqual(rev, rev2)
234
def test_repack_revision_5(self):
235
"""Round-trip revision to XML v5"""
236
self.check_repack_revision(_revision_v5)
238
def test_repack_revision_5_utc(self):
239
self.check_repack_revision(_revision_v5_utc)
241
def test_pack_revision_5(self):
242
"""Pack revision to XML v5"""
243
# fixed 20051025, revisions should have final newline
244
rev = bzrlib.xml5.serializer_v5.read_revision_from_string(_revision_v5)
246
bzrlib.xml5.serializer_v5.write_revision(rev, outp)
247
outfile_contents = outp.getvalue()
248
self.assertEqual(outfile_contents[-1], '\n')
249
self.assertEqualDiff(outfile_contents, bzrlib.xml5.serializer_v5.write_revision_to_string(rev))
250
self.assertEqualDiff(outfile_contents, _expected_rev_v5)
252
def test_empty_property_value(self):
253
"""Create an empty property value check that it serializes correctly"""
254
s_v5 = bzrlib.xml5.serializer_v5
255
rev = s_v5.read_revision_from_string(_revision_v5)
257
props = {'empty':'', 'one':'one'}
258
rev.properties = props
259
txt = s_v5.write_revision_to_string(rev)
260
new_rev = s_v5.read_revision_from_string(txt)
261
self.assertEqual(props, new_rev.properties)
263
def test_revision_ids_are_utf8(self):
264
"""Parsed revision_ids should all be utf-8 strings, not unicode."""
265
s_v5 = bzrlib.xml5.serializer_v5
266
rev = s_v5.read_revision_from_string(_revision_v5)
267
self.assertIsInstance(rev.revision_id, str)
268
for parent_id in rev.parent_ids:
269
self.assertIsInstance(parent_id, str)
271
# ie.revision should either be None or a utf-8 revision id
272
inv = s_v5.read_inventory_from_string(_committed_inv_v5)
273
for path, ie in inv.iter_entries():
274
if ie.revision is None:
276
self.assertIsInstance(ie.revision, str)
279
class TestEncodeAndEscape(TestCase):
280
"""Whitebox testing of the _encode_and_escape function."""
283
# Keep the cache clear before and after the test
284
bzrlib.xml5._ensure_utf8_re()
285
bzrlib.xml5._clear_cache()
286
self.addCleanup(bzrlib.xml5._clear_cache)
288
def test_simple_ascii(self):
289
# _encode_and_escape always appends a final ", because these parameters
290
# are being used in xml attributes, and by returning it now, we have to
291
# do fewer string operations later.
292
val = bzrlib.xml5._encode_and_escape('foo bar')
293
self.assertEqual('foo bar"', val)
294
# The second time should be cached
295
val2 = bzrlib.xml5._encode_and_escape('foo bar')
296
self.assertIs(val2, val)
298
def test_ascii_with_xml(self):
299
self.assertEqual('&'"<>"',
300
bzrlib.xml5._encode_and_escape('&\'"<>'))
302
def test_utf8_with_xml(self):
304
utf8_str = '\xc2\xb5\xc3\xa5&\xd8\xac'
305
self.assertEqual('µå&ج"',
306
bzrlib.xml5._encode_and_escape(utf8_str))
308
def test_unicode(self):
309
uni_str = u'\xb5\xe5&\u062c'
310
self.assertEqual('µå&ج"',
311
bzrlib.xml5._encode_and_escape(uni_str))