~vcs-imports/reviewboard/trunk

« back to all changes in this revision

Viewing changes to reviewboard/diffviewer/tests/test_diffx_parser.py

  • Committer: David Trowbridge
  • Date: 2021-08-17 05:08:34 UTC
  • mfrom: (4677.3.232)
  • Revision ID: git-v1:8d3e7034e141704fb932064aa596548fcea20fea
Merge remote-tracking branch 'origin/release-4.0.x'

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Unit tests for reviewboard.diffviewer.parser.DiffXParser."""
 
2
 
 
3
from __future__ import unicode_literals
 
4
 
 
5
from djblets.testing.decorators import add_fixtures
 
6
 
 
7
from reviewboard.diffviewer.errors import DiffParserError
 
8
from reviewboard.diffviewer.parser import DiffXParser
 
9
from reviewboard.scmtools.core import HEAD, PRE_CREATION, UNKNOWN
 
10
from reviewboard.testing import TestCase
 
11
 
 
12
 
 
13
class DiffXParserTests(TestCase):
 
14
    """Unit tests for reviewboard.diffviewer.parser.DiffXParser."""
 
15
 
 
16
    def test_parse_diff_with_basic_diff(self):
 
17
        """Testing DiffXParser.parse_diff with a basic DiffX file"""
 
18
        parser = DiffXParser(
 
19
            b'#diffx: encoding=utf-8, version=1.0\n'
 
20
            b'#.change:\n'
 
21
            b'#..file:\n'
 
22
            b'#...meta: format=json, length=156\n'
 
23
            b'{\n'
 
24
            b'    "path": {\n'
 
25
            b'        "new": "message2.py",\n'
 
26
            b'        "old": "message.py"\n'
 
27
            b'    },\n'
 
28
            b'    "revision": {\n'
 
29
            b'        "new": "def456",\n'
 
30
            b'        "old": "abc123"\n'
 
31
            b'    }\n'
 
32
            b'}\n'
 
33
            b'#...diff: length=693, line_endings=unix\n'
 
34
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
35
            b'+++ message2.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
36
            b'@@ -164,10 +164,10 @@\n'
 
37
            b'             not isinstance(headers, MultiValueDict)):\n'
 
38
            b'             # Instantiating a MultiValueDict from a dict does '
 
39
            b'not ensure that\n'
 
40
            b'             # values are lists, so we have to ensure that '
 
41
            b'ourselves.\n'
 
42
            b'-            headers = MultiValueDict(dict(\n'
 
43
            b'-                (key, [value])\n'
 
44
            b'-                for key, value in six.iteritems(headers)\n'
 
45
            b'-            ))\n'
 
46
            b'+            headers = MultiValueDict({\n'
 
47
            b'+                key: [value]\n'
 
48
            b'+                for key, value in headers.items()\n'
 
49
            b'+            })\n'
 
50
            b' \n'
 
51
            b'         if in_reply_to:\n'
 
52
            b'             headers["In-Reply-To"] = in_reply_to\n'
 
53
        )
 
54
 
 
55
        parsed_diff = parser.parse_diff()
 
56
        self.assertEqual(len(parsed_diff.changes), 1)
 
57
        self.assertEqual(parsed_diff.extra_data, {
 
58
            'diffx': {
 
59
                'options': {
 
60
                    'encoding': 'utf-8',
 
61
                    'version': '1.0',
 
62
                },
 
63
            },
 
64
        })
 
65
        self.assertIs(parsed_diff.parser, parser)
 
66
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
67
 
 
68
        parsed_change = parsed_diff.changes[0]
 
69
        self.assertIsNone(parsed_change.commit_id)
 
70
        self.assertIsNone(parsed_change.parent_commit_id)
 
71
        self.assertEqual(parsed_change.extra_data, {})
 
72
 
 
73
        self.assertEqual(len(parsed_change.files), 1)
 
74
 
 
75
        parsed_file = parsed_change.files[0]
 
76
        self.assertEqual(parsed_file.extra_data, {
 
77
            'diffx': {
 
78
                'diff_options': {
 
79
                    'line_endings': 'unix',
 
80
                },
 
81
                'metadata': {
 
82
                    'path': {
 
83
                        'old': 'message.py',
 
84
                        'new': 'message2.py',
 
85
                    },
 
86
                    'revision': {
 
87
                        'old': 'abc123',
 
88
                        'new': 'def456',
 
89
                    },
 
90
                },
 
91
                'metadata_options': {
 
92
                    'format': 'json',
 
93
                },
 
94
            },
 
95
        })
 
96
        self.assertEqual(
 
97
            parsed_file.data,
 
98
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
99
            b'+++ message2.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
100
            b'@@ -164,10 +164,10 @@\n'
 
101
            b'             not isinstance(headers, MultiValueDict)):\n'
 
102
            b'             # Instantiating a MultiValueDict from a dict does '
 
103
            b'not ensure that\n'
 
104
            b'             # values are lists, so we have to ensure that '
 
105
            b'ourselves.\n'
 
106
            b'-            headers = MultiValueDict(dict(\n'
 
107
            b'-                (key, [value])\n'
 
108
            b'-                for key, value in six.iteritems(headers)\n'
 
109
            b'-            ))\n'
 
110
            b'+            headers = MultiValueDict({\n'
 
111
            b'+                key: [value]\n'
 
112
            b'+                for key, value in headers.items()\n'
 
113
            b'+            })\n'
 
114
            b' \n'
 
115
            b'         if in_reply_to:\n'
 
116
            b'             headers["In-Reply-To"] = in_reply_to\n')
 
117
        self.assertEqual(parsed_file.orig_filename, b'message.py')
 
118
        self.assertEqual(parsed_file.orig_file_details, b'abc123')
 
119
        self.assertEqual(parsed_file.modified_filename, b'message2.py')
 
120
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
121
        self.assertEqual(parsed_file.insert_count, 4)
 
122
        self.assertEqual(parsed_file.delete_count, 4)
 
123
        self.assertFalse(parsed_file.binary)
 
124
        self.assertFalse(parsed_file.deleted)
 
125
        self.assertFalse(parsed_file.moved)
 
126
        self.assertFalse(parsed_file.copied)
 
127
        self.assertFalse(parsed_file.is_symlink)
 
128
 
 
129
    def test_parse_diff_with_complex_diff(self):
 
130
        """Testing DiffXParser.parse_diff with a complex DiffX file"""
 
131
        parser = DiffXParser(
 
132
            b'#diffx: encoding=utf-16, version=1.0\n'
 
133
            b'#.preamble: encoding=ascii, indent=2, length=36,'
 
134
            b' line_endings=dos, mimetype=text/plain\n'
 
135
            b'  This is the file-level preamble.\r\n'
 
136
            b'#.meta: encoding=utf-32, format=json, length=96\n'
 
137
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00'
 
138
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"'
 
139
            b'\x00\x00\x00k\x00\x00\x00e\x00\x00\x00y\x00\x00\x00"'
 
140
            b'\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00v'
 
141
            b'\x00\x00\x00a\x00\x00\x00l\x00\x00\x00u\x00\x00\x00e'
 
142
            b'\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00}\x00\x00\x00'
 
143
            b'\n\x00\x00\x00'
 
144
            b'#.change:\n'
 
145
            b'#..preamble: indent=2, length=14, line_endings=unix, '
 
146
            b'mimetype=text/markdown\n'
 
147
            b'  \xff\xfet\x00e\x00s\x00t\x00\n\x00'
 
148
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
149
            b'{\n'
 
150
            b'    "author": "Test User <test@example.com>",\n'
 
151
            b'    "author date": "2021-06-01T13:12:06-07:00",\n'
 
152
            b'    "committer": "Test User <test@example.com>",\n'
 
153
            b'    "date": "2021-06-02T19:26:31-07:00",\n'
 
154
            b'    "id": "a25e7b28af5e3184946068f432122c68c1a30b23",\n'
 
155
            b'    "parent id": "b892d5f833474c59d7851ff46a4b0bd919017e97"\n'
 
156
            b'}\n'
 
157
            b'#..file:\n'
 
158
            b'#...meta: encoding=latin1, format=json, length=166\n'
 
159
            b'{\n'
 
160
            b'    "path": "file1",\n'
 
161
            b'    "revision": {\n'
 
162
            b'        "new": "eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef",\n'
 
163
            b'        "old": "c8839177d1a5605aa60abe69db95c84183f0eebe"\n'
 
164
            b'    }\n'
 
165
            b'}\n'
 
166
            b'#...diff: length=60, line_endings=unix\n'
 
167
            b'--- /file1\n'
 
168
            b'+++ /file1\n'
 
169
            b'@@ -498,7 +498,7 @@\n'
 
170
            b' ... diff content\n'
 
171
            b'#.change:\n'
 
172
            b'#..preamble: encoding=utf-8, indent=4, length=56, '
 
173
            b'line_endings=unix\n'
 
174
            b'    Summary of commit #2\n'
 
175
            b'    \n'
 
176
            b'    Here\'s a description.\n'
 
177
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
178
            b'{\n'
 
179
            b'    "author": "Test User <test@example.com>",\n'
 
180
            b'    "author date": "2021-06-01T19:46:22-07:00",\n'
 
181
            b'    "committer": "Test User <test@example.com>",\n'
 
182
            b'    "date": "2021-06-02T19:46:25-07:00",\n'
 
183
            b'    "id": "91127b687f583184144161f432222748c1a30b23",\n'
 
184
            b'    "parent id": "a25e7b28af5e3184946068f432122c68c1a30b23"\n'
 
185
            b'}\n'
 
186
            b'#..file:\n'
 
187
            b'#...meta: encoding=utf-32, format=json, length=668\n'
 
188
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
189
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
190
            b'p\x00\x00\x00a\x00\x00\x00t\x00\x00\x00h\x00\x00\x00'
 
191
            b'"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
192
            b'f\x00\x00\x00i\x00\x00\x00l\x00\x00\x00e\x00\x00\x00'
 
193
            b'2\x00\x00\x00"\x00\x00\x00,\x00\x00\x00\n\x00\x00\x00'
 
194
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
195
            b'"\x00\x00\x00r\x00\x00\x00e\x00\x00\x00v\x00\x00\x00'
 
196
            b'i\x00\x00\x00s\x00\x00\x00i\x00\x00\x00o\x00\x00\x00'
 
197
            b'n\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
198
            b'{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
199
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
200
            b' \x00\x00\x00 \x00\x00\x00"\x00\x00\x00n\x00\x00\x00'
 
201
            b'e\x00\x00\x00w\x00\x00\x00"\x00\x00\x00:\x00\x00\x00'
 
202
            b' \x00\x00\x00"\x00\x00\x003\x00\x00\x008\x00\x00\x00'
 
203
            b'9\x00\x00\x00c\x00\x00\x00c\x00\x00\x006\x00\x00\x00'
 
204
            b'b\x00\x00\x007\x00\x00\x00a\x00\x00\x00e\x00\x00\x00'
 
205
            b'5\x00\x00\x00a\x00\x00\x006\x00\x00\x005\x00\x00\x00'
 
206
            b'9\x00\x00\x003\x00\x00\x008\x00\x00\x003\x00\x00\x00'
 
207
            b'e\x00\x00\x00a\x00\x00\x00b\x00\x00\x005\x00\x00\x00'
 
208
            b'd\x00\x00\x00f\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
209
            b'5\x00\x00\x003\x00\x00\x007\x00\x00\x006\x00\x00\x00'
 
210
            b'4\x00\x00\x00e\x00\x00\x00c\x00\x00\x00c\x00\x00\x00'
 
211
            b'f\x00\x00\x008\x00\x00\x004\x00\x00\x007\x00\x00\x00'
 
212
            b'3\x00\x00\x002\x00\x00\x00"\x00\x00\x00,\x00\x00\x00'
 
213
            b'\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
214
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
215
            b' \x00\x00\x00"\x00\x00\x00o\x00\x00\x00l\x00\x00\x00'
 
216
            b'd\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
217
            b'"\x00\x00\x002\x00\x00\x008\x00\x00\x001\x00\x00\x00'
 
218
            b'b\x00\x00\x00a\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
219
            b'b\x00\x00\x007\x00\x00\x000\x00\x00\x004\x00\x00\x00'
 
220
            b'6\x00\x00\x001\x00\x00\x007\x00\x00\x00e\x00\x00\x00'
 
221
            b'8\x00\x00\x000\x00\x00\x007\x00\x00\x008\x00\x00\x00'
 
222
            b'5\x00\x00\x000\x00\x00\x00e\x00\x00\x000\x00\x00\x00'
 
223
            b'7\x00\x00\x00e\x00\x00\x005\x00\x00\x004\x00\x00\x00'
 
224
            b'b\x00\x00\x00a\x00\x00\x00e\x00\x00\x003\x00\x00\x00'
 
225
            b'4\x00\x00\x006\x00\x00\x009\x00\x00\x00f\x00\x00\x00'
 
226
            b'6\x00\x00\x00a\x00\x00\x002\x00\x00\x00e\x00\x00\x00'
 
227
            b'7\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
228
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00}\x00\x00\x00'
 
229
            b'\n\x00\x00\x00}\x00\x00\x00\n\x00\x00\x00'
 
230
            b'#...diff: encoding=utf-16, length=22, line_endings=unix\n'
 
231
            b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00'
 
232
            b'#..file:\n'
 
233
            b'#...meta: encoding=utf-8, format=json, length=166\n'
 
234
            b'{\n'
 
235
            b'    "path": "file3",\n'
 
236
            b'    "revision": {\n'
 
237
            b'        "new": "0d4a0fb8d62b762a26e13591d06d93d79d61102f",\n'
 
238
            b'        "old": "be089b7197974703c83682088a068bef3422c6c2"\n'
 
239
            b'    }\n'
 
240
            b'}\n'
 
241
            b'#...diff: length=87, line_endings=dos\n'
 
242
            b'--- a/file3\r\n'
 
243
            b'+++ b/file3\r\n'
 
244
            b'@@ -258,1 +258,2 @@\r\n'
 
245
            b'- old line\r\n'
 
246
            b'+ new line 1\r\n'
 
247
            b'+ new line 2\r\n'
 
248
        )
 
249
 
 
250
        parsed_diff = parser.parse_diff()
 
251
        self.assertEqual(len(parsed_diff.changes), 2)
 
252
        self.assertEqual(parsed_diff.extra_data, {
 
253
            'diffx': {
 
254
                'metadata': {
 
255
                    'key': 'value',
 
256
                },
 
257
                'metadata_options': {
 
258
                    'encoding': 'utf-32',
 
259
                    'format': 'json',
 
260
                },
 
261
                'options': {
 
262
                    'encoding': 'utf-16',
 
263
                    'version': '1.0',
 
264
                },
 
265
                'preamble': 'This is the file-level preamble.\r\n',
 
266
                'preamble_options': {
 
267
                    'encoding': 'ascii',
 
268
                    'indent': 2,
 
269
                    'line_endings': 'dos',
 
270
                    'mimetype': 'text/plain',
 
271
                },
 
272
            },
 
273
        })
 
274
        self.assertIs(parsed_diff.parser, parser)
 
275
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
276
 
 
277
        # Inspect change #1.
 
278
        parsed_change = parsed_diff.changes[0]
 
279
        self.assertEqual(parsed_change.commit_id,
 
280
                         b'a25e7b28af5e3184946068f432122c68c1a30b23')
 
281
        self.assertIsNone(parsed_change.parent_commit_id,
 
282
                          b'b892d5f833474c59d7851ff46a4b0bd919017e97')
 
283
        self.assertEqual(parsed_change.extra_data, {
 
284
            'diffx': {
 
285
                'metadata': {
 
286
                    'author': 'Test User <test@example.com>',
 
287
                    'author date': '2021-06-01T13:12:06-07:00',
 
288
                    'committer': 'Test User <test@example.com>',
 
289
                    'date': '2021-06-02T19:26:31-07:00',
 
290
                    'id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
291
                    'parent id': 'b892d5f833474c59d7851ff46a4b0bd919017e97',
 
292
                },
 
293
                'metadata_options': {
 
294
                    'encoding': 'utf-8',
 
295
                    'format': 'json',
 
296
                },
 
297
                'preamble': 'test\n',
 
298
                'preamble_options': {
 
299
                    'indent': 2,
 
300
                    'line_endings': 'unix',
 
301
                    'mimetype': 'text/markdown',
 
302
                },
 
303
            },
 
304
        })
 
305
 
 
306
        self.assertEqual(len(parsed_change.files), 1)
 
307
 
 
308
        # Inspect change #1, file #1
 
309
        parsed_file = parsed_change.files[0]
 
310
        self.assertEqual(parsed_file.extra_data, {
 
311
            'diffx': {
 
312
                'diff_options': {
 
313
                    'line_endings': 'unix',
 
314
                },
 
315
                'metadata': {
 
316
                    'path': 'file1',
 
317
                    'revision': {
 
318
                        'old': 'c8839177d1a5605aa60abe69db95c84183f0eebe',
 
319
                        'new': 'eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
320
                    },
 
321
                },
 
322
                'metadata_options': {
 
323
                    'encoding': 'latin1',
 
324
                    'format': 'json',
 
325
                },
 
326
            },
 
327
        })
 
328
        self.assertEqual(
 
329
            parsed_file.data,
 
330
            b'--- /file1\n'
 
331
            b'+++ /file1\n'
 
332
            b'@@ -498,7 +498,7 @@\n'
 
333
            b' ... diff content\n')
 
334
        self.assertEqual(parsed_file.orig_filename, b'file1')
 
335
        self.assertEqual(parsed_file.orig_file_details,
 
336
                         b'c8839177d1a5605aa60abe69db95c84183f0eebe')
 
337
        self.assertEqual(parsed_file.modified_filename, b'file1')
 
338
        self.assertEqual(parsed_file.modified_file_details,
 
339
                         b'eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef')
 
340
        self.assertEqual(parsed_file.insert_count, 0)
 
341
        self.assertEqual(parsed_file.delete_count, 0)
 
342
        self.assertFalse(parsed_file.binary)
 
343
        self.assertFalse(parsed_file.deleted)
 
344
        self.assertFalse(parsed_file.moved)
 
345
        self.assertFalse(parsed_file.copied)
 
346
        self.assertFalse(parsed_file.is_symlink)
 
347
 
 
348
        # Inspect change #2.
 
349
        parsed_change = parsed_diff.changes[1]
 
350
        self.assertEqual(parsed_change.commit_id,
 
351
                         b'91127b687f583184144161f432222748c1a30b23')
 
352
        self.assertIsNone(parsed_change.parent_commit_id,
 
353
                          b'a25e7b28af5e3184946068f432122c68c1a30b23')
 
354
        self.assertEqual(parsed_change.extra_data, {
 
355
            'diffx': {
 
356
                'metadata': {
 
357
                    'author': 'Test User <test@example.com>',
 
358
                    'author date': '2021-06-01T19:46:22-07:00',
 
359
                    'committer': 'Test User <test@example.com>',
 
360
                    'date': '2021-06-02T19:46:25-07:00',
 
361
                    'id': '91127b687f583184144161f432222748c1a30b23',
 
362
                    'parent id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
363
                },
 
364
                'metadata_options': {
 
365
                    'encoding': 'utf-8',
 
366
                    'format': 'json',
 
367
                },
 
368
                'preamble': (
 
369
                    "Summary of commit #2\n"
 
370
                    "\n"
 
371
                    "Here's a description.\n"
 
372
                ),
 
373
                'preamble_options': {
 
374
                    'encoding': 'utf-8',
 
375
                    'indent': 4,
 
376
                    'line_endings': 'unix',
 
377
                },
 
378
            },
 
379
        })
 
380
 
 
381
        self.assertEqual(len(parsed_change.files), 2)
 
382
 
 
383
        # Inspect change #2, file #1
 
384
        parsed_file = parsed_change.files[0]
 
385
        self.assertEqual(parsed_file.extra_data, {
 
386
            'diffx': {
 
387
                'diff_options': {
 
388
                    'encoding': 'utf-16',
 
389
                    'line_endings': 'unix',
 
390
                },
 
391
                'metadata': {
 
392
                    'path': 'file2',
 
393
                    'revision': {
 
394
                        'old': '281bac2b704617e807850e07e54bae3469f6a2e7',
 
395
                        'new': '389cc6b7ae5a659383eab5dfc253764eccf84732',
 
396
                    },
 
397
                },
 
398
                'metadata_options': {
 
399
                    'encoding': 'utf-32',
 
400
                    'format': 'json',
 
401
                },
 
402
            },
 
403
            'encoding': 'utf-16',
 
404
        })
 
405
        self.assertEqual(
 
406
            parsed_file.data,
 
407
            b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00')
 
408
        self.assertEqual(parsed_file.orig_filename, b'file2')
 
409
        self.assertEqual(parsed_file.orig_file_details,
 
410
                         b'281bac2b704617e807850e07e54bae3469f6a2e7')
 
411
        self.assertEqual(parsed_file.modified_filename, b'file2')
 
412
        self.assertEqual(parsed_file.modified_file_details,
 
413
                         b'389cc6b7ae5a659383eab5dfc253764eccf84732')
 
414
        self.assertEqual(parsed_file.insert_count, 0)
 
415
        self.assertEqual(parsed_file.delete_count, 0)
 
416
        self.assertFalse(parsed_file.binary)
 
417
        self.assertFalse(parsed_file.deleted)
 
418
        self.assertFalse(parsed_file.moved)
 
419
        self.assertFalse(parsed_file.copied)
 
420
        self.assertFalse(parsed_file.is_symlink)
 
421
 
 
422
        # Inspect change #2, file #2
 
423
        parsed_file = parsed_change.files[1]
 
424
        self.assertEqual(parsed_file.extra_data, {
 
425
            'diffx': {
 
426
                'diff_options': {
 
427
                    'line_endings': 'dos',
 
428
                },
 
429
                'metadata': {
 
430
                    'path': 'file3',
 
431
                    'revision': {
 
432
                        'old': 'be089b7197974703c83682088a068bef3422c6c2',
 
433
                        'new': '0d4a0fb8d62b762a26e13591d06d93d79d61102f',
 
434
                    },
 
435
                },
 
436
                'metadata_options': {
 
437
                    'encoding': 'utf-8',
 
438
                    'format': 'json',
 
439
                },
 
440
            },
 
441
        })
 
442
        self.assertEqual(
 
443
            parsed_file.data,
 
444
            b'--- a/file3\r\n'
 
445
            b'+++ b/file3\r\n'
 
446
            b'@@ -258,1 +258,2 @@\r\n'
 
447
            b'- old line\r\n'
 
448
            b'+ new line 1\r\n'
 
449
            b'+ new line 2\r\n')
 
450
        self.assertEqual(parsed_file.orig_filename, b'file3')
 
451
        self.assertEqual(parsed_file.orig_file_details,
 
452
                         b'be089b7197974703c83682088a068bef3422c6c2')
 
453
        self.assertEqual(parsed_file.modified_filename, b'file3')
 
454
        self.assertEqual(parsed_file.modified_file_details,
 
455
                         b'0d4a0fb8d62b762a26e13591d06d93d79d61102f')
 
456
        self.assertEqual(parsed_file.insert_count, 2)
 
457
        self.assertEqual(parsed_file.delete_count, 1)
 
458
        self.assertFalse(parsed_file.binary)
 
459
        self.assertFalse(parsed_file.deleted)
 
460
        self.assertFalse(parsed_file.moved)
 
461
        self.assertFalse(parsed_file.copied)
 
462
        self.assertFalse(parsed_file.is_symlink)
 
463
 
 
464
    def test_parse_diff_with_path_string(self):
 
465
        """Testing DiffXParser.parse_diff with file's meta.path as single
 
466
        string
 
467
        """
 
468
        parser = DiffXParser(
 
469
            b'#diffx: encoding=utf-8, version=1.0\n'
 
470
            b'#.change:\n'
 
471
            b'#..file:\n'
 
472
            b'#...meta: format=json, length=103\n'
 
473
            b'{\n'
 
474
            b'    "path": "message.py",\n'
 
475
            b'    "revision": {\n'
 
476
            b'        "new": "def456",\n'
 
477
            b'        "old": "abc123"\n'
 
478
            b'    }\n'
 
479
            b'}\n'
 
480
            b'#...diff: length=692, line_endings=unix\n'
 
481
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
482
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
483
            b'@@ -164,10 +164,10 @@\n'
 
484
            b'             not isinstance(headers, MultiValueDict)):\n'
 
485
            b'             # Instantiating a MultiValueDict from a dict does '
 
486
            b'not ensure that\n'
 
487
            b'             # values are lists, so we have to ensure that '
 
488
            b'ourselves.\n'
 
489
            b'-            headers = MultiValueDict(dict(\n'
 
490
            b'-                (key, [value])\n'
 
491
            b'-                for key, value in six.iteritems(headers)\n'
 
492
            b'-            ))\n'
 
493
            b'+            headers = MultiValueDict({\n'
 
494
            b'+                key: [value]\n'
 
495
            b'+                for key, value in headers.items()\n'
 
496
            b'+            })\n'
 
497
            b' \n'
 
498
            b'         if in_reply_to:\n'
 
499
            b'             headers["In-Reply-To"] = in_reply_to\n'
 
500
        )
 
501
 
 
502
        parsed_diff = parser.parse_diff()
 
503
        self.assertEqual(len(parsed_diff.changes), 1)
 
504
        self.assertEqual(parsed_diff.extra_data, {
 
505
            'diffx': {
 
506
                'options': {
 
507
                    'encoding': 'utf-8',
 
508
                    'version': '1.0',
 
509
                },
 
510
            },
 
511
        })
 
512
        self.assertIs(parsed_diff.parser, parser)
 
513
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
514
 
 
515
        parsed_change = parsed_diff.changes[0]
 
516
        self.assertIsNone(parsed_change.commit_id)
 
517
        self.assertIsNone(parsed_change.parent_commit_id)
 
518
        self.assertEqual(parsed_change.extra_data, {})
 
519
 
 
520
        self.assertEqual(len(parsed_change.files), 1)
 
521
 
 
522
        parsed_file = parsed_change.files[0]
 
523
        self.assertEqual(parsed_file.extra_data, {
 
524
            'diffx': {
 
525
                'diff_options': {
 
526
                    'line_endings': 'unix',
 
527
                },
 
528
                'metadata': {
 
529
                    'path': 'message.py',
 
530
                    'revision': {
 
531
                        'old': 'abc123',
 
532
                        'new': 'def456',
 
533
                    },
 
534
                },
 
535
                'metadata_options': {
 
536
                    'format': 'json',
 
537
                },
 
538
            },
 
539
        })
 
540
        self.assertEqual(
 
541
            parsed_file.data,
 
542
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
543
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
544
            b'@@ -164,10 +164,10 @@\n'
 
545
            b'             not isinstance(headers, MultiValueDict)):\n'
 
546
            b'             # Instantiating a MultiValueDict from a dict does '
 
547
            b'not ensure that\n'
 
548
            b'             # values are lists, so we have to ensure that '
 
549
            b'ourselves.\n'
 
550
            b'-            headers = MultiValueDict(dict(\n'
 
551
            b'-                (key, [value])\n'
 
552
            b'-                for key, value in six.iteritems(headers)\n'
 
553
            b'-            ))\n'
 
554
            b'+            headers = MultiValueDict({\n'
 
555
            b'+                key: [value]\n'
 
556
            b'+                for key, value in headers.items()\n'
 
557
            b'+            })\n'
 
558
            b' \n'
 
559
            b'         if in_reply_to:\n'
 
560
            b'             headers["In-Reply-To"] = in_reply_to\n')
 
561
        self.assertEqual(parsed_file.orig_filename, b'message.py')
 
562
        self.assertEqual(parsed_file.orig_file_details, b'abc123')
 
563
        self.assertEqual(parsed_file.modified_filename, b'message.py')
 
564
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
565
        self.assertEqual(parsed_file.insert_count, 4)
 
566
        self.assertEqual(parsed_file.delete_count, 4)
 
567
        self.assertFalse(parsed_file.binary)
 
568
        self.assertFalse(parsed_file.deleted)
 
569
        self.assertFalse(parsed_file.moved)
 
570
        self.assertFalse(parsed_file.copied)
 
571
        self.assertFalse(parsed_file.is_symlink)
 
572
 
 
573
    def test_parse_diff_with_revision_old_only(self):
 
574
        """Testing DiffXParser.parse_diff with file's revision.old and no
 
575
        revision.new
 
576
        """
 
577
        parser = DiffXParser(
 
578
            b'#diffx: encoding=utf-8, version=1.0\n'
 
579
            b'#.change:\n'
 
580
            b'#..file:\n'
 
581
            b'#...meta: format=json, length=78\n'
 
582
            b'{\n'
 
583
            b'    "path": "message.py",\n'
 
584
            b'    "revision": {\n'
 
585
            b'        "old": "abc123"\n'
 
586
            b'    }\n'
 
587
            b'}\n'
 
588
            b'#...diff: length=692, line_endings=unix\n'
 
589
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
590
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
591
            b'@@ -164,10 +164,10 @@\n'
 
592
            b'             not isinstance(headers, MultiValueDict)):\n'
 
593
            b'             # Instantiating a MultiValueDict from a dict does '
 
594
            b'not ensure that\n'
 
595
            b'             # values are lists, so we have to ensure that '
 
596
            b'ourselves.\n'
 
597
            b'-            headers = MultiValueDict(dict(\n'
 
598
            b'-                (key, [value])\n'
 
599
            b'-                for key, value in six.iteritems(headers)\n'
 
600
            b'-            ))\n'
 
601
            b'+            headers = MultiValueDict({\n'
 
602
            b'+                key: [value]\n'
 
603
            b'+                for key, value in headers.items()\n'
 
604
            b'+            })\n'
 
605
            b' \n'
 
606
            b'         if in_reply_to:\n'
 
607
            b'             headers["In-Reply-To"] = in_reply_to\n'
 
608
        )
 
609
 
 
610
        parsed_diff = parser.parse_diff()
 
611
        self.assertEqual(len(parsed_diff.changes), 1)
 
612
        self.assertEqual(parsed_diff.extra_data, {
 
613
            'diffx': {
 
614
                'options': {
 
615
                    'encoding': 'utf-8',
 
616
                    'version': '1.0',
 
617
                },
 
618
            },
 
619
        })
 
620
        self.assertIs(parsed_diff.parser, parser)
 
621
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
622
 
 
623
        parsed_change = parsed_diff.changes[0]
 
624
        self.assertIsNone(parsed_change.commit_id)
 
625
        self.assertIsNone(parsed_change.parent_commit_id)
 
626
        self.assertEqual(parsed_change.extra_data, {})
 
627
 
 
628
        self.assertEqual(len(parsed_change.files), 1)
 
629
 
 
630
        parsed_file = parsed_change.files[0]
 
631
        self.assertEqual(parsed_file.extra_data, {
 
632
            'diffx': {
 
633
                'diff_options': {
 
634
                    'line_endings': 'unix',
 
635
                },
 
636
                'metadata': {
 
637
                    'path': 'message.py',
 
638
                    'revision': {
 
639
                        'old': 'abc123',
 
640
                    },
 
641
                },
 
642
                'metadata_options': {
 
643
                    'format': 'json',
 
644
                },
 
645
            },
 
646
        })
 
647
        self.assertEqual(
 
648
            parsed_file.data,
 
649
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
650
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
651
            b'@@ -164,10 +164,10 @@\n'
 
652
            b'             not isinstance(headers, MultiValueDict)):\n'
 
653
            b'             # Instantiating a MultiValueDict from a dict does '
 
654
            b'not ensure that\n'
 
655
            b'             # values are lists, so we have to ensure that '
 
656
            b'ourselves.\n'
 
657
            b'-            headers = MultiValueDict(dict(\n'
 
658
            b'-                (key, [value])\n'
 
659
            b'-                for key, value in six.iteritems(headers)\n'
 
660
            b'-            ))\n'
 
661
            b'+            headers = MultiValueDict({\n'
 
662
            b'+                key: [value]\n'
 
663
            b'+                for key, value in headers.items()\n'
 
664
            b'+            })\n'
 
665
            b' \n'
 
666
            b'         if in_reply_to:\n'
 
667
            b'             headers["In-Reply-To"] = in_reply_to\n')
 
668
        self.assertEqual(parsed_file.orig_filename, b'message.py')
 
669
        self.assertEqual(parsed_file.orig_file_details, b'abc123')
 
670
        self.assertEqual(parsed_file.modified_filename, b'message.py')
 
671
        self.assertEqual(parsed_file.modified_file_details, HEAD)
 
672
        self.assertEqual(parsed_file.insert_count, 4)
 
673
        self.assertEqual(parsed_file.delete_count, 4)
 
674
        self.assertFalse(parsed_file.binary)
 
675
        self.assertFalse(parsed_file.deleted)
 
676
        self.assertFalse(parsed_file.moved)
 
677
        self.assertFalse(parsed_file.copied)
 
678
        self.assertFalse(parsed_file.is_symlink)
 
679
 
 
680
    def test_parse_diff_with_revision_new_only(self):
 
681
        """Testing DiffXParser.parse_diff with file's revision.new and no
 
682
        revision.old
 
683
        """
 
684
        parser = DiffXParser(
 
685
            b'#diffx: encoding=utf-8, version=1.0\n'
 
686
            b'#.change:\n'
 
687
            b'#..file:\n'
 
688
            b'#...meta: format=json, length=78\n'
 
689
            b'{\n'
 
690
            b'    "path": "message.py",\n'
 
691
            b'    "revision": {\n'
 
692
            b'        "new": "def456"\n'
 
693
            b'    }\n'
 
694
            b'}\n'
 
695
            b'#...diff: length=692, line_endings=unix\n'
 
696
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
697
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
698
            b'@@ -164,10 +164,10 @@\n'
 
699
            b'             not isinstance(headers, MultiValueDict)):\n'
 
700
            b'             # Instantiating a MultiValueDict from a dict does '
 
701
            b'not ensure that\n'
 
702
            b'             # values are lists, so we have to ensure that '
 
703
            b'ourselves.\n'
 
704
            b'-            headers = MultiValueDict(dict(\n'
 
705
            b'-                (key, [value])\n'
 
706
            b'-                for key, value in six.iteritems(headers)\n'
 
707
            b'-            ))\n'
 
708
            b'+            headers = MultiValueDict({\n'
 
709
            b'+                key: [value]\n'
 
710
            b'+                for key, value in headers.items()\n'
 
711
            b'+            })\n'
 
712
            b' \n'
 
713
            b'         if in_reply_to:\n'
 
714
            b'             headers["In-Reply-To"] = in_reply_to\n'
 
715
        )
 
716
 
 
717
        parsed_diff = parser.parse_diff()
 
718
        self.assertEqual(len(parsed_diff.changes), 1)
 
719
        self.assertEqual(parsed_diff.extra_data, {
 
720
            'diffx': {
 
721
                'options': {
 
722
                    'encoding': 'utf-8',
 
723
                    'version': '1.0',
 
724
                },
 
725
            },
 
726
        })
 
727
        self.assertIs(parsed_diff.parser, parser)
 
728
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
729
 
 
730
        parsed_change = parsed_diff.changes[0]
 
731
        self.assertIsNone(parsed_change.commit_id)
 
732
        self.assertIsNone(parsed_change.parent_commit_id)
 
733
        self.assertEqual(parsed_change.extra_data, {})
 
734
 
 
735
        self.assertEqual(len(parsed_change.files), 1)
 
736
 
 
737
        parsed_file = parsed_change.files[0]
 
738
        self.assertEqual(parsed_file.extra_data, {
 
739
            'diffx': {
 
740
                'diff_options': {
 
741
                    'line_endings': 'unix',
 
742
                },
 
743
                'metadata': {
 
744
                    'path': 'message.py',
 
745
                    'revision': {
 
746
                        'new': 'def456',
 
747
                    },
 
748
                },
 
749
                'metadata_options': {
 
750
                    'format': 'json',
 
751
                },
 
752
            },
 
753
        })
 
754
        self.assertEqual(
 
755
            parsed_file.data,
 
756
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
757
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
758
            b'@@ -164,10 +164,10 @@\n'
 
759
            b'             not isinstance(headers, MultiValueDict)):\n'
 
760
            b'             # Instantiating a MultiValueDict from a dict does '
 
761
            b'not ensure that\n'
 
762
            b'             # values are lists, so we have to ensure that '
 
763
            b'ourselves.\n'
 
764
            b'-            headers = MultiValueDict(dict(\n'
 
765
            b'-                (key, [value])\n'
 
766
            b'-                for key, value in six.iteritems(headers)\n'
 
767
            b'-            ))\n'
 
768
            b'+            headers = MultiValueDict({\n'
 
769
            b'+                key: [value]\n'
 
770
            b'+                for key, value in headers.items()\n'
 
771
            b'+            })\n'
 
772
            b' \n'
 
773
            b'         if in_reply_to:\n'
 
774
            b'             headers["In-Reply-To"] = in_reply_to\n')
 
775
        self.assertEqual(parsed_file.orig_filename, b'message.py')
 
776
        self.assertEqual(parsed_file.orig_file_details, UNKNOWN)
 
777
        self.assertEqual(parsed_file.modified_filename, b'message.py')
 
778
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
779
        self.assertEqual(parsed_file.insert_count, 4)
 
780
        self.assertEqual(parsed_file.delete_count, 4)
 
781
        self.assertFalse(parsed_file.binary)
 
782
        self.assertFalse(parsed_file.deleted)
 
783
        self.assertFalse(parsed_file.moved)
 
784
        self.assertFalse(parsed_file.copied)
 
785
        self.assertFalse(parsed_file.is_symlink)
 
786
 
 
787
    def test_parse_diff_with_revision_new_only_op_create(self):
 
788
        """Testing DiffXParser.parse_diff with file's revision.new and no
 
789
        revision.old and op=create
 
790
        """
 
791
        parser = DiffXParser(
 
792
            b'#diffx: encoding=utf-8, version=1.0\n'
 
793
            b'#.change:\n'
 
794
            b'#..file:\n'
 
795
            b'#...meta: format=json, length=98\n'
 
796
            b'{\n'
 
797
            b'    "op": "create",\n'
 
798
            b'    "path": "message.py",\n'
 
799
            b'    "revision": {\n'
 
800
            b'        "new": "def456"\n'
 
801
            b'    }\n'
 
802
            b'}\n'
 
803
            b'#...diff: length=692, line_endings=unix\n'
 
804
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
805
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
806
            b'@@ -164,10 +164,10 @@\n'
 
807
            b'             not isinstance(headers, MultiValueDict)):\n'
 
808
            b'             # Instantiating a MultiValueDict from a dict does '
 
809
            b'not ensure that\n'
 
810
            b'             # values are lists, so we have to ensure that '
 
811
            b'ourselves.\n'
 
812
            b'-            headers = MultiValueDict(dict(\n'
 
813
            b'-                (key, [value])\n'
 
814
            b'-                for key, value in six.iteritems(headers)\n'
 
815
            b'-            ))\n'
 
816
            b'+            headers = MultiValueDict({\n'
 
817
            b'+                key: [value]\n'
 
818
            b'+                for key, value in headers.items()\n'
 
819
            b'+            })\n'
 
820
            b' \n'
 
821
            b'         if in_reply_to:\n'
 
822
            b'             headers["In-Reply-To"] = in_reply_to\n'
 
823
        )
 
824
 
 
825
        parsed_diff = parser.parse_diff()
 
826
        self.assertEqual(len(parsed_diff.changes), 1)
 
827
        self.assertEqual(parsed_diff.extra_data, {
 
828
            'diffx': {
 
829
                'options': {
 
830
                    'encoding': 'utf-8',
 
831
                    'version': '1.0',
 
832
                },
 
833
            },
 
834
        })
 
835
        self.assertIs(parsed_diff.parser, parser)
 
836
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
837
 
 
838
        parsed_change = parsed_diff.changes[0]
 
839
        self.assertIsNone(parsed_change.commit_id)
 
840
        self.assertIsNone(parsed_change.parent_commit_id)
 
841
        self.assertEqual(parsed_change.extra_data, {})
 
842
 
 
843
        self.assertEqual(len(parsed_change.files), 1)
 
844
 
 
845
        parsed_file = parsed_change.files[0]
 
846
        self.assertEqual(parsed_file.extra_data, {
 
847
            'diffx': {
 
848
                'diff_options': {
 
849
                    'line_endings': 'unix',
 
850
                },
 
851
                'metadata': {
 
852
                    'op': 'create',
 
853
                    'path': 'message.py',
 
854
                    'revision': {
 
855
                        'new': 'def456',
 
856
                    },
 
857
                },
 
858
                'metadata_options': {
 
859
                    'format': 'json',
 
860
                },
 
861
            },
 
862
        })
 
863
        self.assertEqual(
 
864
            parsed_file.data,
 
865
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
866
            b'+++ message.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
867
            b'@@ -164,10 +164,10 @@\n'
 
868
            b'             not isinstance(headers, MultiValueDict)):\n'
 
869
            b'             # Instantiating a MultiValueDict from a dict does '
 
870
            b'not ensure that\n'
 
871
            b'             # values are lists, so we have to ensure that '
 
872
            b'ourselves.\n'
 
873
            b'-            headers = MultiValueDict(dict(\n'
 
874
            b'-                (key, [value])\n'
 
875
            b'-                for key, value in six.iteritems(headers)\n'
 
876
            b'-            ))\n'
 
877
            b'+            headers = MultiValueDict({\n'
 
878
            b'+                key: [value]\n'
 
879
            b'+                for key, value in headers.items()\n'
 
880
            b'+            })\n'
 
881
            b' \n'
 
882
            b'         if in_reply_to:\n'
 
883
            b'             headers["In-Reply-To"] = in_reply_to\n')
 
884
        self.assertEqual(parsed_file.orig_filename, b'message.py')
 
885
        self.assertEqual(parsed_file.orig_file_details, PRE_CREATION)
 
886
        self.assertEqual(parsed_file.modified_filename, b'message.py')
 
887
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
888
        self.assertEqual(parsed_file.insert_count, 4)
 
889
        self.assertEqual(parsed_file.delete_count, 4)
 
890
        self.assertFalse(parsed_file.binary)
 
891
        self.assertFalse(parsed_file.deleted)
 
892
        self.assertFalse(parsed_file.moved)
 
893
        self.assertFalse(parsed_file.copied)
 
894
        self.assertFalse(parsed_file.is_symlink)
 
895
 
 
896
    def test_parse_diff_with_binary_file(self):
 
897
        """Testing DiffXParser.parse_diff with binary file"""
 
898
        parser = DiffXParser(
 
899
            b'#diffx: encoding=utf-8, version=1.0\n'
 
900
            b'#.change:\n'
 
901
            b'#..file:\n'
 
902
            b'#...meta: format=json, length=104\n'
 
903
            b'{\n'
 
904
            b'    "path": "message.bin",\n'
 
905
            b'    "revision": {\n'
 
906
            b'        "old": "abc123",\n'
 
907
            b'        "new": "def456"\n'
 
908
            b'    }\n'
 
909
            b'}\n'
 
910
            b'#...diff: length=23, type=binary, line_endings=unix\n'
 
911
            b'This is a binary file.\n'
 
912
        )
 
913
 
 
914
        parsed_diff = parser.parse_diff()
 
915
        self.assertEqual(len(parsed_diff.changes), 1)
 
916
        self.assertEqual(parsed_diff.extra_data, {
 
917
            'diffx': {
 
918
                'options': {
 
919
                    'encoding': 'utf-8',
 
920
                    'version': '1.0',
 
921
                },
 
922
            },
 
923
        })
 
924
        self.assertIs(parsed_diff.parser, parser)
 
925
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
926
 
 
927
        parsed_change = parsed_diff.changes[0]
 
928
        self.assertIsNone(parsed_change.commit_id)
 
929
        self.assertIsNone(parsed_change.parent_commit_id)
 
930
        self.assertEqual(parsed_change.extra_data, {})
 
931
 
 
932
        self.assertEqual(len(parsed_change.files), 1)
 
933
 
 
934
        parsed_file = parsed_change.files[0]
 
935
        self.assertEqual(parsed_file.extra_data, {
 
936
            'diffx': {
 
937
                'diff_options': {
 
938
                    'line_endings': 'unix',
 
939
                    'type': 'binary',
 
940
                },
 
941
                'metadata': {
 
942
                    'path': 'message.bin',
 
943
                    'revision': {
 
944
                        'old': 'abc123',
 
945
                        'new': 'def456',
 
946
                    },
 
947
                },
 
948
                'metadata_options': {
 
949
                    'format': 'json',
 
950
                },
 
951
            },
 
952
        })
 
953
        self.assertEqual(
 
954
            parsed_file.data,
 
955
            b'This is a binary file.\n')
 
956
        self.assertEqual(parsed_file.orig_filename, b'message.bin')
 
957
        self.assertEqual(parsed_file.orig_file_details, b'abc123')
 
958
        self.assertEqual(parsed_file.modified_filename, b'message.bin')
 
959
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
960
        self.assertEqual(parsed_file.insert_count, 0)
 
961
        self.assertEqual(parsed_file.delete_count, 0)
 
962
        self.assertTrue(parsed_file.binary)
 
963
        self.assertFalse(parsed_file.deleted)
 
964
        self.assertFalse(parsed_file.moved)
 
965
        self.assertFalse(parsed_file.copied)
 
966
        self.assertFalse(parsed_file.is_symlink)
 
967
 
 
968
    def test_parse_diff_with_file_op_delete(self):
 
969
        """Testing DiffXParser.parse_diff with file op=delete"""
 
970
        parser = DiffXParser(
 
971
            b'#diffx: encoding=utf-8, version=1.0\n'
 
972
            b'#.change:\n'
 
973
            b'#..file:\n'
 
974
            b'#...meta: format=json, length=123\n'
 
975
            b'{\n'
 
976
            b'    "op": "delete",\n'
 
977
            b'    "path": "message.py",\n'
 
978
            b'    "revision": {\n'
 
979
            b'        "old": "abc123",\n'
 
980
            b'        "new": "def456"\n'
 
981
            b'    }\n'
 
982
            b'}\n'
 
983
            b'#...diff: length=29, line_endings=unix\n'
 
984
            b'@@ -1 +0,0 @@\n'
 
985
            b'-Goodbye, file\n'
 
986
        )
 
987
 
 
988
        parsed_diff = parser.parse_diff()
 
989
        self.assertEqual(len(parsed_diff.changes), 1)
 
990
        self.assertEqual(parsed_diff.extra_data, {
 
991
            'diffx': {
 
992
                'options': {
 
993
                    'encoding': 'utf-8',
 
994
                    'version': '1.0',
 
995
                },
 
996
            },
 
997
        })
 
998
        self.assertIs(parsed_diff.parser, parser)
 
999
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1000
 
 
1001
        parsed_change = parsed_diff.changes[0]
 
1002
        self.assertIsNone(parsed_change.commit_id)
 
1003
        self.assertIsNone(parsed_change.parent_commit_id)
 
1004
        self.assertEqual(parsed_change.extra_data, {})
 
1005
 
 
1006
        self.assertEqual(len(parsed_change.files), 1)
 
1007
 
 
1008
        parsed_file = parsed_change.files[0]
 
1009
        self.assertEqual(parsed_file.extra_data, {
 
1010
            'diffx': {
 
1011
                'diff_options': {
 
1012
                    'line_endings': 'unix',
 
1013
                },
 
1014
                'metadata': {
 
1015
                    'op': 'delete',
 
1016
                    'path': 'message.py',
 
1017
                    'revision': {
 
1018
                        'old': 'abc123',
 
1019
                        'new': 'def456',
 
1020
                    },
 
1021
                },
 
1022
                'metadata_options': {
 
1023
                    'format': 'json',
 
1024
                },
 
1025
            },
 
1026
        })
 
1027
        self.assertEqual(
 
1028
            parsed_file.data,
 
1029
            b'@@ -1 +0,0 @@\n'
 
1030
            b'-Goodbye, file\n')
 
1031
        self.assertEqual(parsed_file.orig_filename, b'message.py')
 
1032
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1033
        self.assertEqual(parsed_file.modified_filename, b'message.py')
 
1034
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1035
        self.assertEqual(parsed_file.insert_count, 0)
 
1036
        self.assertEqual(parsed_file.delete_count, 1)
 
1037
        self.assertTrue(parsed_file.deleted)
 
1038
        self.assertFalse(parsed_file.binary)
 
1039
        self.assertFalse(parsed_file.moved)
 
1040
        self.assertFalse(parsed_file.copied)
 
1041
        self.assertFalse(parsed_file.is_symlink)
 
1042
 
 
1043
    def test_parse_diff_with_op_move(self):
 
1044
        """Testing DiffXParser.parse_diff with file op=move"""
 
1045
        parser = DiffXParser(
 
1046
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1047
            b'#.change:\n'
 
1048
            b'#..file:\n'
 
1049
            b'#...meta: format=json, length=169\n'
 
1050
            b'{\n'
 
1051
            b'    "op": "move",\n'
 
1052
            b'    "path": {\n'
 
1053
            b'        "old": "old-name",\n'
 
1054
            b'        "new": "new-name"\n'
 
1055
            b'    },\n'
 
1056
            b'    "revision": {\n'
 
1057
            b'        "old": "abc123",\n'
 
1058
            b'        "new": "def456"\n'
 
1059
            b'    }\n'
 
1060
            b'}\n'
 
1061
        )
 
1062
 
 
1063
        parsed_diff = parser.parse_diff()
 
1064
        self.assertEqual(len(parsed_diff.changes), 1)
 
1065
        self.assertEqual(parsed_diff.extra_data, {
 
1066
            'diffx': {
 
1067
                'options': {
 
1068
                    'encoding': 'utf-8',
 
1069
                    'version': '1.0',
 
1070
                },
 
1071
            },
 
1072
        })
 
1073
        self.assertIs(parsed_diff.parser, parser)
 
1074
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1075
 
 
1076
        parsed_change = parsed_diff.changes[0]
 
1077
        self.assertIsNone(parsed_change.commit_id)
 
1078
        self.assertIsNone(parsed_change.parent_commit_id)
 
1079
        self.assertEqual(parsed_change.extra_data, {})
 
1080
 
 
1081
        self.assertEqual(len(parsed_change.files), 1)
 
1082
 
 
1083
        parsed_file = parsed_change.files[0]
 
1084
        self.assertEqual(parsed_file.extra_data, {
 
1085
            'diffx': {
 
1086
                'metadata': {
 
1087
                    'op': 'move',
 
1088
                    'path': {
 
1089
                        'old': 'old-name',
 
1090
                        'new': 'new-name',
 
1091
                    },
 
1092
                    'revision': {
 
1093
                        'old': 'abc123',
 
1094
                        'new': 'def456',
 
1095
                    },
 
1096
                },
 
1097
                'metadata_options': {
 
1098
                    'format': 'json',
 
1099
                },
 
1100
            },
 
1101
        })
 
1102
        self.assertEqual(parsed_file.data, b'')
 
1103
        self.assertEqual(parsed_file.orig_filename, b'old-name')
 
1104
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1105
        self.assertEqual(parsed_file.modified_filename, b'new-name')
 
1106
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1107
        self.assertEqual(parsed_file.insert_count, 0)
 
1108
        self.assertEqual(parsed_file.delete_count, 0)
 
1109
        self.assertTrue(parsed_file.moved)
 
1110
        self.assertFalse(parsed_file.binary)
 
1111
        self.assertFalse(parsed_file.copied)
 
1112
        self.assertFalse(parsed_file.deleted)
 
1113
        self.assertFalse(parsed_file.is_symlink)
 
1114
 
 
1115
    def test_parse_diff_with_op_move_modify(self):
 
1116
        """Testing DiffXParser.parse_diff with file op=move-modify"""
 
1117
        parser = DiffXParser(
 
1118
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1119
            b'#.change:\n'
 
1120
            b'#..file:\n'
 
1121
            b'#...meta: format=json, length=176\n'
 
1122
            b'{\n'
 
1123
            b'    "op": "move-modify",\n'
 
1124
            b'    "path": {\n'
 
1125
            b'        "old": "old-name",\n'
 
1126
            b'        "new": "new-name"\n'
 
1127
            b'    },\n'
 
1128
            b'    "revision": {\n'
 
1129
            b'        "old": "abc123",\n'
 
1130
            b'        "new": "def456"\n'
 
1131
            b'    }\n'
 
1132
            b'}\n'
 
1133
            b'#...diff: length=58, line_endings=unix\n'
 
1134
            b'--- old-name\n'
 
1135
            b'+++ new-name\n'
 
1136
            b'@@ -1 +1 @@\n'
 
1137
            b'-old line\n'
 
1138
            b'+new line\n'
 
1139
        )
 
1140
 
 
1141
        parsed_diff = parser.parse_diff()
 
1142
        self.assertEqual(len(parsed_diff.changes), 1)
 
1143
        self.assertEqual(parsed_diff.extra_data, {
 
1144
            'diffx': {
 
1145
                'options': {
 
1146
                    'encoding': 'utf-8',
 
1147
                    'version': '1.0',
 
1148
                },
 
1149
            },
 
1150
        })
 
1151
        self.assertIs(parsed_diff.parser, parser)
 
1152
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1153
 
 
1154
        parsed_change = parsed_diff.changes[0]
 
1155
        self.assertIsNone(parsed_change.commit_id)
 
1156
        self.assertIsNone(parsed_change.parent_commit_id)
 
1157
        self.assertEqual(parsed_change.extra_data, {})
 
1158
 
 
1159
        self.assertEqual(len(parsed_change.files), 1)
 
1160
 
 
1161
        parsed_file = parsed_change.files[0]
 
1162
        self.assertEqual(parsed_file.extra_data, {
 
1163
            'diffx': {
 
1164
                'diff_options': {
 
1165
                    'line_endings': 'unix',
 
1166
                },
 
1167
                'metadata': {
 
1168
                    'op': 'move-modify',
 
1169
                    'path': {
 
1170
                        'old': 'old-name',
 
1171
                        'new': 'new-name',
 
1172
                    },
 
1173
                    'revision': {
 
1174
                        'old': 'abc123',
 
1175
                        'new': 'def456',
 
1176
                    },
 
1177
                },
 
1178
                'metadata_options': {
 
1179
                    'format': 'json',
 
1180
                },
 
1181
            },
 
1182
        })
 
1183
        self.assertEqual(
 
1184
            parsed_file.data,
 
1185
            b'--- old-name\n'
 
1186
            b'+++ new-name\n'
 
1187
            b'@@ -1 +1 @@\n'
 
1188
            b'-old line\n'
 
1189
            b'+new line\n')
 
1190
        self.assertEqual(parsed_file.orig_filename, b'old-name')
 
1191
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1192
        self.assertEqual(parsed_file.modified_filename, b'new-name')
 
1193
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1194
        self.assertEqual(parsed_file.insert_count, 1)
 
1195
        self.assertEqual(parsed_file.delete_count, 1)
 
1196
        self.assertTrue(parsed_file.moved)
 
1197
        self.assertFalse(parsed_file.binary)
 
1198
        self.assertFalse(parsed_file.copied)
 
1199
        self.assertFalse(parsed_file.deleted)
 
1200
        self.assertFalse(parsed_file.is_symlink)
 
1201
 
 
1202
    def test_parse_diff_with_op_copy(self):
 
1203
        """Testing DiffXParser.parse_diff with file op=copy"""
 
1204
        parser = DiffXParser(
 
1205
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1206
            b'#.change:\n'
 
1207
            b'#..file:\n'
 
1208
            b'#...meta: format=json, length=169\n'
 
1209
            b'{\n'
 
1210
            b'    "op": "copy",\n'
 
1211
            b'    "path": {\n'
 
1212
            b'        "old": "old-name",\n'
 
1213
            b'        "new": "new-name"\n'
 
1214
            b'    },\n'
 
1215
            b'    "revision": {\n'
 
1216
            b'        "old": "abc123",\n'
 
1217
            b'        "new": "def456"\n'
 
1218
            b'    }\n'
 
1219
            b'}\n'
 
1220
        )
 
1221
 
 
1222
        parsed_diff = parser.parse_diff()
 
1223
        self.assertEqual(len(parsed_diff.changes), 1)
 
1224
        self.assertEqual(parsed_diff.extra_data, {
 
1225
            'diffx': {
 
1226
                'options': {
 
1227
                    'encoding': 'utf-8',
 
1228
                    'version': '1.0',
 
1229
                },
 
1230
            },
 
1231
        })
 
1232
        self.assertIs(parsed_diff.parser, parser)
 
1233
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1234
 
 
1235
        parsed_change = parsed_diff.changes[0]
 
1236
        self.assertIsNone(parsed_change.commit_id)
 
1237
        self.assertIsNone(parsed_change.parent_commit_id)
 
1238
        self.assertEqual(parsed_change.extra_data, {})
 
1239
 
 
1240
        self.assertEqual(len(parsed_change.files), 1)
 
1241
 
 
1242
        parsed_file = parsed_change.files[0]
 
1243
        self.assertEqual(parsed_file.extra_data, {
 
1244
            'diffx': {
 
1245
                'metadata': {
 
1246
                    'op': 'copy',
 
1247
                    'path': {
 
1248
                        'old': 'old-name',
 
1249
                        'new': 'new-name',
 
1250
                    },
 
1251
                    'revision': {
 
1252
                        'old': 'abc123',
 
1253
                        'new': 'def456',
 
1254
                    },
 
1255
                },
 
1256
                'metadata_options': {
 
1257
                    'format': 'json',
 
1258
                },
 
1259
            },
 
1260
        })
 
1261
        self.assertEqual(parsed_file.data, b'')
 
1262
        self.assertEqual(parsed_file.orig_filename, b'old-name')
 
1263
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1264
        self.assertEqual(parsed_file.modified_filename, b'new-name')
 
1265
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1266
        self.assertEqual(parsed_file.insert_count, 0)
 
1267
        self.assertEqual(parsed_file.delete_count, 0)
 
1268
        self.assertTrue(parsed_file.copied)
 
1269
        self.assertFalse(parsed_file.binary)
 
1270
        self.assertFalse(parsed_file.deleted)
 
1271
        self.assertFalse(parsed_file.is_symlink)
 
1272
        self.assertFalse(parsed_file.moved)
 
1273
 
 
1274
    def test_parse_diff_with_op_copy_modify(self):
 
1275
        """Testing DiffXParser.parse_diff with file op=copy-modify"""
 
1276
        parser = DiffXParser(
 
1277
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1278
            b'#.change:\n'
 
1279
            b'#..file:\n'
 
1280
            b'#...meta: format=json, length=176\n'
 
1281
            b'{\n'
 
1282
            b'    "op": "copy-modify",\n'
 
1283
            b'    "path": {\n'
 
1284
            b'        "old": "old-name",\n'
 
1285
            b'        "new": "new-name"\n'
 
1286
            b'    },\n'
 
1287
            b'    "revision": {\n'
 
1288
            b'        "old": "abc123",\n'
 
1289
            b'        "new": "def456"\n'
 
1290
            b'    }\n'
 
1291
            b'}\n'
 
1292
            b'#...diff: length=58, line_endings=unix\n'
 
1293
            b'--- old-name\n'
 
1294
            b'+++ new-name\n'
 
1295
            b'@@ -1 +1 @@\n'
 
1296
            b'-old line\n'
 
1297
            b'+new line\n'
 
1298
        )
 
1299
 
 
1300
        parsed_diff = parser.parse_diff()
 
1301
        self.assertEqual(len(parsed_diff.changes), 1)
 
1302
        self.assertEqual(parsed_diff.extra_data, {
 
1303
            'diffx': {
 
1304
                'options': {
 
1305
                    'encoding': 'utf-8',
 
1306
                    'version': '1.0',
 
1307
                },
 
1308
            },
 
1309
        })
 
1310
        self.assertIs(parsed_diff.parser, parser)
 
1311
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1312
 
 
1313
        parsed_change = parsed_diff.changes[0]
 
1314
        self.assertIsNone(parsed_change.commit_id)
 
1315
        self.assertIsNone(parsed_change.parent_commit_id)
 
1316
        self.assertEqual(parsed_change.extra_data, {})
 
1317
 
 
1318
        self.assertEqual(len(parsed_change.files), 1)
 
1319
 
 
1320
        parsed_file = parsed_change.files[0]
 
1321
        self.assertEqual(parsed_file.extra_data, {
 
1322
            'diffx': {
 
1323
                'diff_options': {
 
1324
                    'line_endings': 'unix',
 
1325
                },
 
1326
                'metadata': {
 
1327
                    'op': 'copy-modify',
 
1328
                    'path': {
 
1329
                        'old': 'old-name',
 
1330
                        'new': 'new-name',
 
1331
                    },
 
1332
                    'revision': {
 
1333
                        'old': 'abc123',
 
1334
                        'new': 'def456',
 
1335
                    },
 
1336
                },
 
1337
                'metadata_options': {
 
1338
                    'format': 'json',
 
1339
                },
 
1340
            },
 
1341
        })
 
1342
        self.assertEqual(
 
1343
            parsed_file.data,
 
1344
            b'--- old-name\n'
 
1345
            b'+++ new-name\n'
 
1346
            b'@@ -1 +1 @@\n'
 
1347
            b'-old line\n'
 
1348
            b'+new line\n')
 
1349
        self.assertEqual(parsed_file.orig_filename, b'old-name')
 
1350
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1351
        self.assertEqual(parsed_file.modified_filename, b'new-name')
 
1352
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1353
        self.assertEqual(parsed_file.insert_count, 1)
 
1354
        self.assertEqual(parsed_file.delete_count, 1)
 
1355
        self.assertTrue(parsed_file.copied)
 
1356
        self.assertFalse(parsed_file.binary)
 
1357
        self.assertFalse(parsed_file.deleted)
 
1358
        self.assertFalse(parsed_file.is_symlink)
 
1359
        self.assertFalse(parsed_file.moved)
 
1360
 
 
1361
    def test_parse_diff_with_existing_stats(self):
 
1362
        """Testing DiffXParser.parse_diff with existing file stats"""
 
1363
        parser = DiffXParser(
 
1364
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1365
            b'#.change:\n'
 
1366
            b'#..file:\n'
 
1367
            b'#...meta: format=json, length=225\n'
 
1368
            b'{\n'
 
1369
            b'    "path": {\n'
 
1370
            b'        "old": "old-name",\n'
 
1371
            b'        "new": "new-name"\n'
 
1372
            b'    },\n'
 
1373
            b'    "revision": {\n'
 
1374
            b'        "old": "abc123",\n'
 
1375
            b'        "new": "def456"\n'
 
1376
            b'    },\n'
 
1377
            b'    "stats": {\n'
 
1378
            b'        "deletions": 100,\n'
 
1379
            b'        "insertions": 200\n'
 
1380
            b'    }\n'
 
1381
            b'}\n'
 
1382
            b'#...diff: length=58, line_endings=unix\n'
 
1383
            b'--- old-name\n'
 
1384
            b'+++ new-name\n'
 
1385
            b'@@ -1 +1 @@\n'
 
1386
            b'-old line\n'
 
1387
            b'+new line\n'
 
1388
        )
 
1389
 
 
1390
        parsed_diff = parser.parse_diff()
 
1391
        self.assertEqual(len(parsed_diff.changes), 1)
 
1392
        self.assertEqual(parsed_diff.extra_data, {
 
1393
            'diffx': {
 
1394
                'options': {
 
1395
                    'encoding': 'utf-8',
 
1396
                    'version': '1.0',
 
1397
                },
 
1398
            },
 
1399
        })
 
1400
        self.assertIs(parsed_diff.parser, parser)
 
1401
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1402
 
 
1403
        parsed_change = parsed_diff.changes[0]
 
1404
        self.assertIsNone(parsed_change.commit_id)
 
1405
        self.assertIsNone(parsed_change.parent_commit_id)
 
1406
        self.assertEqual(parsed_change.extra_data, {})
 
1407
 
 
1408
        self.assertEqual(len(parsed_change.files), 1)
 
1409
 
 
1410
        parsed_file = parsed_change.files[0]
 
1411
        self.assertEqual(parsed_file.extra_data, {
 
1412
            'diffx': {
 
1413
                'diff_options': {
 
1414
                    'line_endings': 'unix',
 
1415
                },
 
1416
                'metadata': {
 
1417
                    'path': {
 
1418
                        'old': 'old-name',
 
1419
                        'new': 'new-name',
 
1420
                    },
 
1421
                    'revision': {
 
1422
                        'old': 'abc123',
 
1423
                        'new': 'def456',
 
1424
                    },
 
1425
                    'stats': {
 
1426
                        'deletions': 100,
 
1427
                        'insertions': 200,
 
1428
                    },
 
1429
                },
 
1430
                'metadata_options': {
 
1431
                    'format': 'json',
 
1432
                },
 
1433
            },
 
1434
        })
 
1435
        self.assertEqual(
 
1436
            parsed_file.data,
 
1437
            b'--- old-name\n'
 
1438
            b'+++ new-name\n'
 
1439
            b'@@ -1 +1 @@\n'
 
1440
            b'-old line\n'
 
1441
            b'+new line\n')
 
1442
        self.assertEqual(parsed_file.orig_filename, b'old-name')
 
1443
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1444
        self.assertEqual(parsed_file.modified_filename, b'new-name')
 
1445
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1446
        self.assertEqual(parsed_file.insert_count, 200)
 
1447
        self.assertEqual(parsed_file.delete_count, 100)
 
1448
        self.assertFalse(parsed_file.binary)
 
1449
        self.assertFalse(parsed_file.copied)
 
1450
        self.assertFalse(parsed_file.deleted)
 
1451
        self.assertFalse(parsed_file.is_symlink)
 
1452
        self.assertFalse(parsed_file.moved)
 
1453
 
 
1454
    def test_parse_diff_with_type_symlink(self):
 
1455
        """Testing DiffXParser.parse_diff with file type=symlink"""
 
1456
        parser = DiffXParser(
 
1457
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1458
            b'#.change:\n'
 
1459
            b'#..file:\n'
 
1460
            b'#...meta: format=json, length=212\n'
 
1461
            b'{\n'
 
1462
            b'    "path": {\n'
 
1463
            b'        "old": "old-name",\n'
 
1464
            b'        "new": "new-name"\n'
 
1465
            b'    },\n'
 
1466
            b'    "revision": {\n'
 
1467
            b'        "old": "abc123",\n'
 
1468
            b'        "new": "def456"\n'
 
1469
            b'    },\n'
 
1470
            b'    "type": "symlink",\n'
 
1471
            b'    "symlink target": "target/path/"\n'
 
1472
            b'}\n'
 
1473
            b'#...diff: length=58, line_endings=unix\n'
 
1474
            b'--- old-name\n'
 
1475
            b'+++ new-name\n'
 
1476
            b'@@ -1 +1 @@\n'
 
1477
            b'-old line\n'
 
1478
            b'+new line\n'
 
1479
        )
 
1480
 
 
1481
        parsed_diff = parser.parse_diff()
 
1482
        self.assertEqual(len(parsed_diff.changes), 1)
 
1483
        self.assertEqual(parsed_diff.extra_data, {
 
1484
            'diffx': {
 
1485
                'options': {
 
1486
                    'encoding': 'utf-8',
 
1487
                    'version': '1.0',
 
1488
                },
 
1489
            },
 
1490
        })
 
1491
        self.assertIs(parsed_diff.parser, parser)
 
1492
        self.assertFalse(parsed_diff.uses_commit_ids_as_revisions)
 
1493
 
 
1494
        parsed_change = parsed_diff.changes[0]
 
1495
        self.assertIsNone(parsed_change.commit_id)
 
1496
        self.assertIsNone(parsed_change.parent_commit_id)
 
1497
        self.assertEqual(parsed_change.extra_data, {})
 
1498
 
 
1499
        self.assertEqual(len(parsed_change.files), 1)
 
1500
 
 
1501
        parsed_file = parsed_change.files[0]
 
1502
        self.assertEqual(parsed_file.extra_data, {
 
1503
            'diffx': {
 
1504
                'diff_options': {
 
1505
                    'line_endings': 'unix',
 
1506
                },
 
1507
                'metadata': {
 
1508
                    'path': {
 
1509
                        'old': 'old-name',
 
1510
                        'new': 'new-name',
 
1511
                    },
 
1512
                    'revision': {
 
1513
                        'old': 'abc123',
 
1514
                        'new': 'def456',
 
1515
                    },
 
1516
                    'type': 'symlink',
 
1517
                    'symlink target': 'target/path/',
 
1518
                },
 
1519
                'metadata_options': {
 
1520
                    'format': 'json',
 
1521
                },
 
1522
            },
 
1523
        })
 
1524
        self.assertEqual(
 
1525
            parsed_file.data,
 
1526
            b'--- old-name\n'
 
1527
            b'+++ new-name\n'
 
1528
            b'@@ -1 +1 @@\n'
 
1529
            b'-old line\n'
 
1530
            b'+new line\n')
 
1531
        self.assertEqual(parsed_file.orig_filename, b'old-name')
 
1532
        self.assertEqual(parsed_file.orig_file_details, 'abc123')
 
1533
        self.assertEqual(parsed_file.modified_filename, b'new-name')
 
1534
        self.assertEqual(parsed_file.modified_file_details, b'def456')
 
1535
        self.assertEqual(parsed_file.insert_count, 1)
 
1536
        self.assertEqual(parsed_file.delete_count, 1)
 
1537
        self.assertTrue(parsed_file.is_symlink)
 
1538
        self.assertFalse(parsed_file.binary)
 
1539
        self.assertFalse(parsed_file.copied)
 
1540
        self.assertFalse(parsed_file.deleted)
 
1541
        self.assertFalse(parsed_file.moved)
 
1542
 
 
1543
    def test_parse_diff_with_invalid_diffx(self):
 
1544
        """Testing DiffXParser.parse_diff with invalid DiffX file contents"""
 
1545
        parser = DiffXParser(
 
1546
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1547
            b'BLARGH\n'
 
1548
        )
 
1549
 
 
1550
        message = (
 
1551
            "Error on line 2: Unexpected or improperly formatted header: %r"
 
1552
            % b'BLARGH'
 
1553
        )
 
1554
 
 
1555
        with self.assertRaisesMessage(DiffParserError, message):
 
1556
            parser.parse_diff()
 
1557
 
 
1558
    def test_parse_diff_with_path_invalid_type(self):
 
1559
        """Testing DiffXParser.parse_diff with invalid file path type"""
 
1560
        parser = DiffXParser(
 
1561
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1562
            b'#.change:\n'
 
1563
            b'#..file:\n'
 
1564
            b'#...meta: format=json, length=94\n'
 
1565
            b'{\n'
 
1566
            b'    "path": 123,\n'
 
1567
            b'    "revision": {\n'
 
1568
            b'        "new": "def456",\n'
 
1569
            b'        "old": "abc123"\n'
 
1570
            b'    }\n'
 
1571
            b'}\n'
 
1572
        )
 
1573
 
 
1574
        message = (
 
1575
            'Unexpected type %s for "path" key in change 1, file 1'
 
1576
            % int
 
1577
        )
 
1578
 
 
1579
        with self.assertRaisesMessage(DiffParserError, message):
 
1580
            parser.parse_diff()
 
1581
 
 
1582
    def test_parse_diff_with_path_dict_missing_old(self):
 
1583
        """Testing DiffXParser.parse_diff with file path as dictionary with
 
1584
        missing "old" key
 
1585
        """
 
1586
        parser = DiffXParser(
 
1587
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1588
            b'#.change:\n'
 
1589
            b'#..file:\n'
 
1590
            b'#...meta: format=json, length=120\n'
 
1591
            b'{\n'
 
1592
            b'    "path": {\n'
 
1593
            b'        "new": "file"\n'
 
1594
            b'    },\n'
 
1595
            b'    "revision": {\n'
 
1596
            b'        "new": "def456",\n'
 
1597
            b'        "old": "abc123"\n'
 
1598
            b'    }\n'
 
1599
            b'}\n'
 
1600
        )
 
1601
 
 
1602
        message = 'Missing the "path.old" key in change 1, file 1'
 
1603
 
 
1604
        with self.assertRaisesMessage(DiffParserError, message):
 
1605
            parser.parse_diff()
 
1606
 
 
1607
    def test_parse_diff_with_path_dict_missing_new(self):
 
1608
        """Testing DiffXParser.parse_diff with file path as dictionary with
 
1609
        missing "new" key
 
1610
        """
 
1611
        parser = DiffXParser(
 
1612
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1613
            b'#.change:\n'
 
1614
            b'#..file:\n'
 
1615
            b'#...meta: format=json, length=120\n'
 
1616
            b'{\n'
 
1617
            b'    "path": {\n'
 
1618
            b'        "old": "file"\n'
 
1619
            b'    },\n'
 
1620
            b'    "revision": {\n'
 
1621
            b'        "new": "def456",\n'
 
1622
            b'        "old": "abc123"\n'
 
1623
            b'    }\n'
 
1624
            b'}\n'
 
1625
        )
 
1626
 
 
1627
        message = 'Missing the "path.new" key in change 1, file 1'
 
1628
 
 
1629
        with self.assertRaisesMessage(DiffParserError, message):
 
1630
            parser.parse_diff()
 
1631
 
 
1632
    def test_parse_diff_with_revision_invalid_type(self):
 
1633
        """Testing DiffXParser.parse_diff with invalid file revision type"""
 
1634
        parser = DiffXParser(
 
1635
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1636
            b'#.change:\n'
 
1637
            b'#..file:\n'
 
1638
            b'#...meta: format=json, length=44\n'
 
1639
            b'{\n'
 
1640
            b'    "path": "file",\n'
 
1641
            b'    "revision": 123\n'
 
1642
            b'}\n'
 
1643
        )
 
1644
 
 
1645
        message = (
 
1646
            'Unexpected type %s for "revision" key in change 1, file 1'
 
1647
            % int
 
1648
        )
 
1649
 
 
1650
        with self.assertRaisesMessage(DiffParserError, message):
 
1651
            parser.parse_diff()
 
1652
 
 
1653
    @add_fixtures(['test_scmtools'])
 
1654
    def test_raw_diff_with_diffset_simple(self):
 
1655
        """Testing DiffXParser.raw_diff with DiffSet and simple diff"""
 
1656
        repository = self.create_repository(tool_name='Test')
 
1657
        diffset = self.create_diffset(repository=repository)
 
1658
        diffset.extra_data = {
 
1659
            'diffx': {
 
1660
                'options': {
 
1661
                    'encoding': 'utf-8',
 
1662
                    'version': '1.0',
 
1663
                },
 
1664
            },
 
1665
        }
 
1666
        diffset.save(update_fields=('extra_data',))
 
1667
 
 
1668
        diffcommit = self.create_diffcommit(diffset=diffset,
 
1669
                                            with_diff=False)
 
1670
 
 
1671
        filediff = self.create_filediff(
 
1672
            diffset=diffset,
 
1673
            commit=diffcommit,
 
1674
            save=False,
 
1675
            diff=(
 
1676
                b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
1677
                b'+++ message2.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
1678
                b'@@ -164,10 +164,10 @@\n'
 
1679
                b'             not isinstance(headers, MultiValueDict)):\n'
 
1680
                b'             # Instantiating a MultiValueDict from a dict '
 
1681
                b'does not ensure that\n'
 
1682
                b'             # values are lists, so we have to ensure that '
 
1683
                b'ourselves.\n'
 
1684
                b'-            headers = MultiValueDict(dict(\n'
 
1685
                b'-                (key, [value])\n'
 
1686
                b'-                for key, value in six.iteritems(headers)\n'
 
1687
                b'-            ))\n'
 
1688
                b'+            headers = MultiValueDict({\n'
 
1689
                b'+                key: [value]\n'
 
1690
                b'+                for key, value in headers.items()\n'
 
1691
                b'+            })\n'
 
1692
                b' \n'
 
1693
                b'         if in_reply_to:\n'
 
1694
                b'             headers["In-Reply-To"] = in_reply_to\n'
 
1695
            ))
 
1696
        filediff.extra_data = {
 
1697
            'diffx': {
 
1698
                'diff_options': {
 
1699
                    'line_endings': 'unix',
 
1700
                },
 
1701
                'metadata': {
 
1702
                    'path': {
 
1703
                        'old': 'message.py',
 
1704
                        'new': 'message2.py',
 
1705
                    },
 
1706
                    'revision': {
 
1707
                        'old': 'abc123',
 
1708
                        'new': 'def456',
 
1709
                    },
 
1710
                },
 
1711
                'metadata_options': {
 
1712
                    'format': 'json',
 
1713
                },
 
1714
            },
 
1715
        }
 
1716
        filediff.save()
 
1717
 
 
1718
        parser = DiffXParser(b'')
 
1719
        self.assertEqual(
 
1720
            parser.raw_diff(diffset),
 
1721
            b'#diffx: encoding=utf-8, version=1.0\n'
 
1722
            b'#.change:\n'
 
1723
            b'#..file:\n'
 
1724
            b'#...meta: format=json, length=156\n'
 
1725
            b'{\n'
 
1726
            b'    "path": {\n'
 
1727
            b'        "new": "message2.py",\n'
 
1728
            b'        "old": "message.py"\n'
 
1729
            b'    },\n'
 
1730
            b'    "revision": {\n'
 
1731
            b'        "new": "def456",\n'
 
1732
            b'        "old": "abc123"\n'
 
1733
            b'    }\n'
 
1734
            b'}\n'
 
1735
            b'#...diff: length=693, line_endings=unix\n'
 
1736
            b'--- message.py\t2021-07-02 13:20:12.285875444 -0700\n'
 
1737
            b'+++ message2.py\t2021-07-02 13:21:31.428383873 -0700\n'
 
1738
            b'@@ -164,10 +164,10 @@\n'
 
1739
            b'             not isinstance(headers, MultiValueDict)):\n'
 
1740
            b'             # Instantiating a MultiValueDict from a dict does '
 
1741
            b'not ensure that\n'
 
1742
            b'             # values are lists, so we have to ensure that '
 
1743
            b'ourselves.\n'
 
1744
            b'-            headers = MultiValueDict(dict(\n'
 
1745
            b'-                (key, [value])\n'
 
1746
            b'-                for key, value in six.iteritems(headers)\n'
 
1747
            b'-            ))\n'
 
1748
            b'+            headers = MultiValueDict({\n'
 
1749
            b'+                key: [value]\n'
 
1750
            b'+                for key, value in headers.items()\n'
 
1751
            b'+            })\n'
 
1752
            b' \n'
 
1753
            b'         if in_reply_to:\n'
 
1754
            b'             headers["In-Reply-To"] = in_reply_to\n')
 
1755
 
 
1756
    @add_fixtures(['test_scmtools'])
 
1757
    def test_raw_diff_with_diffset_complex(self):
 
1758
        """Testing DiffXParser.raw_diff with DiffSet and complex diff"""
 
1759
        repository = self.create_repository(tool_name='Test')
 
1760
        diffset = self.create_diffset(repository=repository)
 
1761
        diffset.extra_data = {
 
1762
            'diffx': {
 
1763
                'metadata': {
 
1764
                    'key': 'value',
 
1765
                },
 
1766
                'metadata_options': {
 
1767
                    'encoding': 'utf-32',
 
1768
                    'format': 'json',
 
1769
                },
 
1770
                'options': {
 
1771
                    'encoding': 'utf-16',
 
1772
                    'version': '1.0',
 
1773
                },
 
1774
                'preamble': 'This is the file-level preamble.\r\n',
 
1775
                'preamble_options': {
 
1776
                    'encoding': 'ascii',
 
1777
                    'indent': 2,
 
1778
                    'line_endings': 'dos',
 
1779
                    'mimetype': 'text/plain',
 
1780
                },
 
1781
            },
 
1782
        }
 
1783
        diffset.save(update_fields=('extra_data',))
 
1784
 
 
1785
        # Create DiffCommit #1.
 
1786
        diffcommit = self.create_diffcommit(
 
1787
            diffset=diffset,
 
1788
            commit_id='a25e7b28af5e3184946068f432122c68c1a30b23',
 
1789
            with_diff=False)
 
1790
        diffcommit.extra_data = {
 
1791
            'diffx': {
 
1792
                'metadata': {
 
1793
                    'author': 'Test User <test@example.com>',
 
1794
                    'author date': '2021-06-01T13:12:06-07:00',
 
1795
                    'committer': 'Test User <test@example.com>',
 
1796
                    'date': '2021-06-02T19:26:31-07:00',
 
1797
                    'id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
1798
                    'parent id': 'b892d5f833474c59d7851ff46a4b0bd919017e97',
 
1799
                },
 
1800
                'metadata_options': {
 
1801
                    'encoding': 'utf-8',
 
1802
                    'format': 'json',
 
1803
                },
 
1804
                'preamble': 'test\n',
 
1805
                'preamble_options': {
 
1806
                    'indent': 2,
 
1807
                    'line_endings': 'unix',
 
1808
                    'mimetype': 'text/markdown',
 
1809
                },
 
1810
            },
 
1811
        }
 
1812
        diffcommit.save(update_fields=('extra_data',))
 
1813
 
 
1814
        filediff = self.create_filediff(
 
1815
            diffset=diffset,
 
1816
            commit=diffcommit,
 
1817
            source_file='file1',
 
1818
            source_revision='c8839177d1a5605aa60abe69db95c84183f0eebe',
 
1819
            dest_file='file1',
 
1820
            dest_detail='eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
1821
            save=False,
 
1822
            diff=(
 
1823
                b'--- /file1\n'
 
1824
                b'+++ /file1\n'
 
1825
                b'@@ -498,7 +498,7 @@\n'
 
1826
                b' ... diff content\n'
 
1827
            ))
 
1828
        filediff.extra_data = {
 
1829
            'diffx': {
 
1830
                'diff_options': {
 
1831
                    'line_endings': 'unix',
 
1832
                },
 
1833
                'metadata': {
 
1834
                    'path': 'file1',
 
1835
                    'revision': {
 
1836
                        'old': 'c8839177d1a5605aa60abe69db95c84183f0eebe',
 
1837
                        'new': 'eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
1838
                    },
 
1839
                },
 
1840
                'metadata_options': {
 
1841
                    'encoding': 'latin1',
 
1842
                    'format': 'json',
 
1843
                },
 
1844
            },
 
1845
        }
 
1846
        filediff.save()
 
1847
 
 
1848
        # Create DiffCommit #2.
 
1849
        diffcommit = self.create_diffcommit(
 
1850
            diffset=diffset,
 
1851
            commit_id='91127b687f583184144161f432222748c1a30b23',
 
1852
            with_diff=False)
 
1853
        diffcommit.extra_data = {
 
1854
            'diffx': {
 
1855
                'metadata': {
 
1856
                    'author': 'Test User <test@example.com>',
 
1857
                    'author date': '2021-06-01T19:46:22-07:00',
 
1858
                    'committer': 'Test User <test@example.com>',
 
1859
                    'date': '2021-06-02T19:46:25-07:00',
 
1860
                    'id': '91127b687f583184144161f432222748c1a30b23',
 
1861
                    'parent id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
1862
                },
 
1863
                'metadata_options': {
 
1864
                    'encoding': 'utf-8',
 
1865
                    'format': 'json',
 
1866
                },
 
1867
                'preamble': (
 
1868
                    "Summary of commit #2\n"
 
1869
                    "\n"
 
1870
                    "Here's a description.\n"
 
1871
                ),
 
1872
                'preamble_options': {
 
1873
                    'encoding': 'utf-8',
 
1874
                    'indent': 4,
 
1875
                    'line_endings': 'unix',
 
1876
                },
 
1877
            },
 
1878
        }
 
1879
        diffcommit.save(update_fields=('extra_data',))
 
1880
 
 
1881
        filediff = self.create_filediff(
 
1882
            diffset=diffset,
 
1883
            commit=diffcommit,
 
1884
            source_file='file2',
 
1885
            source_revision='281bac2b704617e807850e07e54bae3469f6a2e7',
 
1886
            dest_file='file2',
 
1887
            dest_detail='389cc6b7ae5a659383eab5dfc253764eccf84732',
 
1888
            save=False,
 
1889
            diff=(
 
1890
                b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00'
 
1891
            ))
 
1892
        filediff.extra_data = {
 
1893
            'diffx': {
 
1894
                'diff_options': {
 
1895
                    'encoding': 'utf-16',
 
1896
                    'line_endings': 'unix',
 
1897
                },
 
1898
                'metadata': {
 
1899
                    'path': 'file2',
 
1900
                    'revision': {
 
1901
                        'old': '281bac2b704617e807850e07e54bae3469f6a2e7',
 
1902
                        'new': '389cc6b7ae5a659383eab5dfc253764eccf84732',
 
1903
                    },
 
1904
                },
 
1905
                'metadata_options': {
 
1906
                    'encoding': 'utf-32',
 
1907
                    'format': 'json',
 
1908
                },
 
1909
            },
 
1910
            'encoding': 'utf-16',
 
1911
        }
 
1912
        filediff.save()
 
1913
 
 
1914
        filediff = self.create_filediff(
 
1915
            diffset=diffset,
 
1916
            commit=diffcommit,
 
1917
            source_file='file3',
 
1918
            source_revision='be089b7197974703c83682088a068bef3422c6c2',
 
1919
            dest_file='file3',
 
1920
            dest_detail='0d4a0fb8d62b762a26e13591d06d93d79d61102f',
 
1921
            save=False,
 
1922
            diff=(
 
1923
                b'--- a/file3\r\n'
 
1924
                b'+++ b/file3\r\n'
 
1925
                b'@@ -258,1 +258,2 @@\r\n'
 
1926
                b'- old line\r\n'
 
1927
                b'+ new line 1\r\n'
 
1928
                b'+ new line 2\r\n'
 
1929
            ))
 
1930
        filediff.extra_data = {
 
1931
            'diffx': {
 
1932
                'diff_options': {
 
1933
                    'line_endings': 'dos',
 
1934
                },
 
1935
                'metadata': {
 
1936
                    'path': 'file3',
 
1937
                    'revision': {
 
1938
                        'old': 'be089b7197974703c83682088a068bef3422c6c2',
 
1939
                        'new': '0d4a0fb8d62b762a26e13591d06d93d79d61102f',
 
1940
                    },
 
1941
                },
 
1942
                'metadata_options': {
 
1943
                    'encoding': 'utf-8',
 
1944
                    'format': 'json',
 
1945
                },
 
1946
            },
 
1947
        }
 
1948
        filediff.save()
 
1949
 
 
1950
        parser = DiffXParser(b'')
 
1951
        self.assertEqual(
 
1952
            parser.raw_diff(diffset),
 
1953
            b'#diffx: encoding=utf-16, version=1.0\n'
 
1954
            b'#.preamble: encoding=ascii, indent=2, length=36,'
 
1955
            b' line_endings=dos, mimetype=text/plain\n'
 
1956
            b'  This is the file-level preamble.\r\n'
 
1957
            b'#.meta: encoding=utf-32, format=json, length=96\n'
 
1958
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00'
 
1959
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"'
 
1960
            b'\x00\x00\x00k\x00\x00\x00e\x00\x00\x00y\x00\x00\x00"'
 
1961
            b'\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00v'
 
1962
            b'\x00\x00\x00a\x00\x00\x00l\x00\x00\x00u\x00\x00\x00e'
 
1963
            b'\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00}\x00\x00\x00'
 
1964
            b'\n\x00\x00\x00'
 
1965
            b'#.change:\n'
 
1966
            b'#..preamble: indent=2, length=14, line_endings=unix, '
 
1967
            b'mimetype=text/markdown\n'
 
1968
            b'  \xff\xfet\x00e\x00s\x00t\x00\n\x00'
 
1969
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
1970
            b'{\n'
 
1971
            b'    "author": "Test User <test@example.com>",\n'
 
1972
            b'    "author date": "2021-06-01T13:12:06-07:00",\n'
 
1973
            b'    "committer": "Test User <test@example.com>",\n'
 
1974
            b'    "date": "2021-06-02T19:26:31-07:00",\n'
 
1975
            b'    "id": "a25e7b28af5e3184946068f432122c68c1a30b23",\n'
 
1976
            b'    "parent id": "b892d5f833474c59d7851ff46a4b0bd919017e97"\n'
 
1977
            b'}\n'
 
1978
            b'#..file:\n'
 
1979
            b'#...meta: encoding=latin1, format=json, length=166\n'
 
1980
            b'{\n'
 
1981
            b'    "path": "file1",\n'
 
1982
            b'    "revision": {\n'
 
1983
            b'        "new": "eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef",\n'
 
1984
            b'        "old": "c8839177d1a5605aa60abe69db95c84183f0eebe"\n'
 
1985
            b'    }\n'
 
1986
            b'}\n'
 
1987
            b'#...diff: length=60, line_endings=unix\n'
 
1988
            b'--- /file1\n'
 
1989
            b'+++ /file1\n'
 
1990
            b'@@ -498,7 +498,7 @@\n'
 
1991
            b' ... diff content\n'
 
1992
            b'#.change:\n'
 
1993
            b'#..preamble: encoding=utf-8, indent=4, length=56, '
 
1994
            b'line_endings=unix\n'
 
1995
            b'    Summary of commit #2\n'
 
1996
            b'    \n'
 
1997
            b'    Here\'s a description.\n'
 
1998
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
1999
            b'{\n'
 
2000
            b'    "author": "Test User <test@example.com>",\n'
 
2001
            b'    "author date": "2021-06-01T19:46:22-07:00",\n'
 
2002
            b'    "committer": "Test User <test@example.com>",\n'
 
2003
            b'    "date": "2021-06-02T19:46:25-07:00",\n'
 
2004
            b'    "id": "91127b687f583184144161f432222748c1a30b23",\n'
 
2005
            b'    "parent id": "a25e7b28af5e3184946068f432122c68c1a30b23"\n'
 
2006
            b'}\n'
 
2007
            b'#..file:\n'
 
2008
            b'#...meta: encoding=utf-32, format=json, length=668\n'
 
2009
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
2010
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
2011
            b'p\x00\x00\x00a\x00\x00\x00t\x00\x00\x00h\x00\x00\x00'
 
2012
            b'"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
2013
            b'f\x00\x00\x00i\x00\x00\x00l\x00\x00\x00e\x00\x00\x00'
 
2014
            b'2\x00\x00\x00"\x00\x00\x00,\x00\x00\x00\n\x00\x00\x00'
 
2015
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2016
            b'"\x00\x00\x00r\x00\x00\x00e\x00\x00\x00v\x00\x00\x00'
 
2017
            b'i\x00\x00\x00s\x00\x00\x00i\x00\x00\x00o\x00\x00\x00'
 
2018
            b'n\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
2019
            b'{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2020
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2021
            b' \x00\x00\x00 \x00\x00\x00"\x00\x00\x00n\x00\x00\x00'
 
2022
            b'e\x00\x00\x00w\x00\x00\x00"\x00\x00\x00:\x00\x00\x00'
 
2023
            b' \x00\x00\x00"\x00\x00\x003\x00\x00\x008\x00\x00\x00'
 
2024
            b'9\x00\x00\x00c\x00\x00\x00c\x00\x00\x006\x00\x00\x00'
 
2025
            b'b\x00\x00\x007\x00\x00\x00a\x00\x00\x00e\x00\x00\x00'
 
2026
            b'5\x00\x00\x00a\x00\x00\x006\x00\x00\x005\x00\x00\x00'
 
2027
            b'9\x00\x00\x003\x00\x00\x008\x00\x00\x003\x00\x00\x00'
 
2028
            b'e\x00\x00\x00a\x00\x00\x00b\x00\x00\x005\x00\x00\x00'
 
2029
            b'd\x00\x00\x00f\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
2030
            b'5\x00\x00\x003\x00\x00\x007\x00\x00\x006\x00\x00\x00'
 
2031
            b'4\x00\x00\x00e\x00\x00\x00c\x00\x00\x00c\x00\x00\x00'
 
2032
            b'f\x00\x00\x008\x00\x00\x004\x00\x00\x007\x00\x00\x00'
 
2033
            b'3\x00\x00\x002\x00\x00\x00"\x00\x00\x00,\x00\x00\x00'
 
2034
            b'\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2035
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2036
            b' \x00\x00\x00"\x00\x00\x00o\x00\x00\x00l\x00\x00\x00'
 
2037
            b'd\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
2038
            b'"\x00\x00\x002\x00\x00\x008\x00\x00\x001\x00\x00\x00'
 
2039
            b'b\x00\x00\x00a\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
2040
            b'b\x00\x00\x007\x00\x00\x000\x00\x00\x004\x00\x00\x00'
 
2041
            b'6\x00\x00\x001\x00\x00\x007\x00\x00\x00e\x00\x00\x00'
 
2042
            b'8\x00\x00\x000\x00\x00\x007\x00\x00\x008\x00\x00\x00'
 
2043
            b'5\x00\x00\x000\x00\x00\x00e\x00\x00\x000\x00\x00\x00'
 
2044
            b'7\x00\x00\x00e\x00\x00\x005\x00\x00\x004\x00\x00\x00'
 
2045
            b'b\x00\x00\x00a\x00\x00\x00e\x00\x00\x003\x00\x00\x00'
 
2046
            b'4\x00\x00\x006\x00\x00\x009\x00\x00\x00f\x00\x00\x00'
 
2047
            b'6\x00\x00\x00a\x00\x00\x002\x00\x00\x00e\x00\x00\x00'
 
2048
            b'7\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
2049
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00}\x00\x00\x00'
 
2050
            b'\n\x00\x00\x00}\x00\x00\x00\n\x00\x00\x00'
 
2051
            b'#...diff: encoding=utf-16, length=22, line_endings=unix\n'
 
2052
            b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00'
 
2053
            b'#..file:\n'
 
2054
            b'#...meta: encoding=utf-8, format=json, length=166\n'
 
2055
            b'{\n'
 
2056
            b'    "path": "file3",\n'
 
2057
            b'    "revision": {\n'
 
2058
            b'        "new": "0d4a0fb8d62b762a26e13591d06d93d79d61102f",\n'
 
2059
            b'        "old": "be089b7197974703c83682088a068bef3422c6c2"\n'
 
2060
            b'    }\n'
 
2061
            b'}\n'
 
2062
            b'#...diff: length=87, line_endings=dos\n'
 
2063
            b'--- a/file3\r\n'
 
2064
            b'+++ b/file3\r\n'
 
2065
            b'@@ -258,1 +258,2 @@\r\n'
 
2066
            b'- old line\r\n'
 
2067
            b'+ new line 1\r\n'
 
2068
            b'+ new line 2\r\n')
 
2069
 
 
2070
    @add_fixtures(['test_scmtools'])
 
2071
    def test_raw_diff_with_diffset_no_diffcommits(self):
 
2072
        """Testing DiffXParser.raw_diff with DiffSet and no DiffCommits"""
 
2073
        repository = self.create_repository(tool_name='Test')
 
2074
        diffset = self.create_diffset(repository=repository)
 
2075
        diffset.extra_data = {
 
2076
            'diffx': {
 
2077
                'metadata': {
 
2078
                    'key': 'value',
 
2079
                },
 
2080
                'metadata_options': {
 
2081
                    'encoding': 'utf-32',
 
2082
                    'format': 'json',
 
2083
                },
 
2084
                'options': {
 
2085
                    'encoding': 'utf-16',
 
2086
                    'version': '1.0',
 
2087
                },
 
2088
                'preamble': 'This is the file-level preamble.\r\n',
 
2089
                'preamble_options': {
 
2090
                    'encoding': 'ascii',
 
2091
                    'indent': 2,
 
2092
                    'line_endings': 'dos',
 
2093
                    'mimetype': 'text/plain',
 
2094
                },
 
2095
            },
 
2096
            'change_extra_data': {
 
2097
                'diffx': {
 
2098
                    'metadata': {
 
2099
                        'author': 'Test User <test@example.com>',
 
2100
                        'author date': '2021-06-01T13:12:06-07:00',
 
2101
                        'committer': 'Test User <test@example.com>',
 
2102
                        'date': '2021-06-02T19:26:31-07:00',
 
2103
                        'id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
2104
                        'parent id':
 
2105
                            'b892d5f833474c59d7851ff46a4b0bd919017e97',
 
2106
                    },
 
2107
                    'metadata_options': {
 
2108
                        'encoding': 'utf-8',
 
2109
                        'format': 'json',
 
2110
                    },
 
2111
                    'preamble': 'test\n',
 
2112
                    'preamble_options': {
 
2113
                        'indent': 2,
 
2114
                        'line_endings': 'unix',
 
2115
                        'mimetype': 'text/markdown',
 
2116
                    },
 
2117
                },
 
2118
            },
 
2119
        }
 
2120
        diffset.save(update_fields=('extra_data',))
 
2121
 
 
2122
        filediff = self.create_filediff(
 
2123
            diffset=diffset,
 
2124
            source_file='file1',
 
2125
            source_revision='c8839177d1a5605aa60abe69db95c84183f0eebe',
 
2126
            dest_file='file1',
 
2127
            dest_detail='eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
2128
            save=False,
 
2129
            diff=(
 
2130
                b'--- /file1\n'
 
2131
                b'+++ /file1\n'
 
2132
                b'@@ -498,7 +498,7 @@\n'
 
2133
                b' ... diff content\n'
 
2134
            ))
 
2135
        filediff.extra_data = {
 
2136
            'diffx': {
 
2137
                'diff_options': {
 
2138
                    'line_endings': 'unix',
 
2139
                },
 
2140
                'metadata': {
 
2141
                    'path': 'file1',
 
2142
                    'revision': {
 
2143
                        'old': 'c8839177d1a5605aa60abe69db95c84183f0eebe',
 
2144
                        'new': 'eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
2145
                    },
 
2146
                },
 
2147
                'metadata_options': {
 
2148
                    'encoding': 'latin1',
 
2149
                    'format': 'json',
 
2150
                },
 
2151
            },
 
2152
        }
 
2153
        filediff.save()
 
2154
 
 
2155
        filediff = self.create_filediff(
 
2156
            diffset=diffset,
 
2157
            source_file='file2',
 
2158
            source_revision='281bac2b704617e807850e07e54bae3469f6a2e7',
 
2159
            dest_file='file2',
 
2160
            dest_detail='389cc6b7ae5a659383eab5dfc253764eccf84732',
 
2161
            save=False,
 
2162
            diff=(
 
2163
                b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00'
 
2164
            ))
 
2165
        filediff.extra_data = {
 
2166
            'diffx': {
 
2167
                'diff_options': {
 
2168
                    'encoding': 'utf-16',
 
2169
                    'line_endings': 'unix',
 
2170
                },
 
2171
                'metadata': {
 
2172
                    'path': 'file2',
 
2173
                    'revision': {
 
2174
                        'old': '281bac2b704617e807850e07e54bae3469f6a2e7',
 
2175
                        'new': '389cc6b7ae5a659383eab5dfc253764eccf84732',
 
2176
                    },
 
2177
                },
 
2178
                'metadata_options': {
 
2179
                    'encoding': 'utf-32',
 
2180
                    'format': 'json',
 
2181
                },
 
2182
            },
 
2183
            'encoding': 'utf-16',
 
2184
        }
 
2185
        filediff.save()
 
2186
 
 
2187
        parser = DiffXParser(b'')
 
2188
        self.assertEqual(
 
2189
            parser.raw_diff(diffset),
 
2190
            b'#diffx: encoding=utf-16, version=1.0\n'
 
2191
            b'#.preamble: encoding=ascii, indent=2, length=36,'
 
2192
            b' line_endings=dos, mimetype=text/plain\n'
 
2193
            b'  This is the file-level preamble.\r\n'
 
2194
            b'#.meta: encoding=utf-32, format=json, length=96\n'
 
2195
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00'
 
2196
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"'
 
2197
            b'\x00\x00\x00k\x00\x00\x00e\x00\x00\x00y\x00\x00\x00"'
 
2198
            b'\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00v'
 
2199
            b'\x00\x00\x00a\x00\x00\x00l\x00\x00\x00u\x00\x00\x00e'
 
2200
            b'\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00}\x00\x00\x00'
 
2201
            b'\n\x00\x00\x00'
 
2202
            b'#.change:\n'
 
2203
            b'#..preamble: indent=2, length=14, line_endings=unix, '
 
2204
            b'mimetype=text/markdown\n'
 
2205
            b'  \xff\xfet\x00e\x00s\x00t\x00\n\x00'
 
2206
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
2207
            b'{\n'
 
2208
            b'    "author": "Test User <test@example.com>",\n'
 
2209
            b'    "author date": "2021-06-01T13:12:06-07:00",\n'
 
2210
            b'    "committer": "Test User <test@example.com>",\n'
 
2211
            b'    "date": "2021-06-02T19:26:31-07:00",\n'
 
2212
            b'    "id": "a25e7b28af5e3184946068f432122c68c1a30b23",\n'
 
2213
            b'    "parent id": "b892d5f833474c59d7851ff46a4b0bd919017e97"\n'
 
2214
            b'}\n'
 
2215
            b'#..file:\n'
 
2216
            b'#...meta: encoding=latin1, format=json, length=166\n'
 
2217
            b'{\n'
 
2218
            b'    "path": "file1",\n'
 
2219
            b'    "revision": {\n'
 
2220
            b'        "new": "eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef",\n'
 
2221
            b'        "old": "c8839177d1a5605aa60abe69db95c84183f0eebe"\n'
 
2222
            b'    }\n'
 
2223
            b'}\n'
 
2224
            b'#...diff: length=60, line_endings=unix\n'
 
2225
            b'--- /file1\n'
 
2226
            b'+++ /file1\n'
 
2227
            b'@@ -498,7 +498,7 @@\n'
 
2228
            b' ... diff content\n'
 
2229
            b'#..file:\n'
 
2230
            b'#...meta: encoding=utf-32, format=json, length=668\n'
 
2231
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
2232
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
2233
            b'p\x00\x00\x00a\x00\x00\x00t\x00\x00\x00h\x00\x00\x00'
 
2234
            b'"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
2235
            b'f\x00\x00\x00i\x00\x00\x00l\x00\x00\x00e\x00\x00\x00'
 
2236
            b'2\x00\x00\x00"\x00\x00\x00,\x00\x00\x00\n\x00\x00\x00'
 
2237
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2238
            b'"\x00\x00\x00r\x00\x00\x00e\x00\x00\x00v\x00\x00\x00'
 
2239
            b'i\x00\x00\x00s\x00\x00\x00i\x00\x00\x00o\x00\x00\x00'
 
2240
            b'n\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
2241
            b'{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2242
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2243
            b' \x00\x00\x00 \x00\x00\x00"\x00\x00\x00n\x00\x00\x00'
 
2244
            b'e\x00\x00\x00w\x00\x00\x00"\x00\x00\x00:\x00\x00\x00'
 
2245
            b' \x00\x00\x00"\x00\x00\x003\x00\x00\x008\x00\x00\x00'
 
2246
            b'9\x00\x00\x00c\x00\x00\x00c\x00\x00\x006\x00\x00\x00'
 
2247
            b'b\x00\x00\x007\x00\x00\x00a\x00\x00\x00e\x00\x00\x00'
 
2248
            b'5\x00\x00\x00a\x00\x00\x006\x00\x00\x005\x00\x00\x00'
 
2249
            b'9\x00\x00\x003\x00\x00\x008\x00\x00\x003\x00\x00\x00'
 
2250
            b'e\x00\x00\x00a\x00\x00\x00b\x00\x00\x005\x00\x00\x00'
 
2251
            b'd\x00\x00\x00f\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
2252
            b'5\x00\x00\x003\x00\x00\x007\x00\x00\x006\x00\x00\x00'
 
2253
            b'4\x00\x00\x00e\x00\x00\x00c\x00\x00\x00c\x00\x00\x00'
 
2254
            b'f\x00\x00\x008\x00\x00\x004\x00\x00\x007\x00\x00\x00'
 
2255
            b'3\x00\x00\x002\x00\x00\x00"\x00\x00\x00,\x00\x00\x00'
 
2256
            b'\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2257
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2258
            b' \x00\x00\x00"\x00\x00\x00o\x00\x00\x00l\x00\x00\x00'
 
2259
            b'd\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
2260
            b'"\x00\x00\x002\x00\x00\x008\x00\x00\x001\x00\x00\x00'
 
2261
            b'b\x00\x00\x00a\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
2262
            b'b\x00\x00\x007\x00\x00\x000\x00\x00\x004\x00\x00\x00'
 
2263
            b'6\x00\x00\x001\x00\x00\x007\x00\x00\x00e\x00\x00\x00'
 
2264
            b'8\x00\x00\x000\x00\x00\x007\x00\x00\x008\x00\x00\x00'
 
2265
            b'5\x00\x00\x000\x00\x00\x00e\x00\x00\x000\x00\x00\x00'
 
2266
            b'7\x00\x00\x00e\x00\x00\x005\x00\x00\x004\x00\x00\x00'
 
2267
            b'b\x00\x00\x00a\x00\x00\x00e\x00\x00\x003\x00\x00\x00'
 
2268
            b'4\x00\x00\x006\x00\x00\x009\x00\x00\x00f\x00\x00\x00'
 
2269
            b'6\x00\x00\x00a\x00\x00\x002\x00\x00\x00e\x00\x00\x00'
 
2270
            b'7\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
2271
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00}\x00\x00\x00'
 
2272
            b'\n\x00\x00\x00}\x00\x00\x00\n\x00\x00\x00'
 
2273
            b'#...diff: encoding=utf-16, length=22, line_endings=unix\n'
 
2274
            b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00')
 
2275
 
 
2276
    @add_fixtures(['test_scmtools'])
 
2277
    def test_raw_diff_with_diffcommit(self):
 
2278
        """Testing DiffXParser.raw_diff with DiffCommit"""
 
2279
        repository = self.create_repository(tool_name='Test')
 
2280
        diffset = self.create_diffset(repository=repository)
 
2281
        diffset.extra_data = {
 
2282
            'diffx': {
 
2283
                'metadata': {
 
2284
                    'key': 'value',
 
2285
                },
 
2286
                'metadata_options': {
 
2287
                    'encoding': 'utf-32',
 
2288
                    'format': 'json',
 
2289
                },
 
2290
                'options': {
 
2291
                    'encoding': 'utf-16',
 
2292
                    'version': '1.0',
 
2293
                },
 
2294
                'preamble': 'This is the file-level preamble.\r\n',
 
2295
                'preamble_options': {
 
2296
                    'encoding': 'ascii',
 
2297
                    'indent': 2,
 
2298
                    'line_endings': 'dos',
 
2299
                    'mimetype': 'text/plain',
 
2300
                },
 
2301
            },
 
2302
        }
 
2303
        diffset.save(update_fields=('extra_data',))
 
2304
 
 
2305
        # Create DiffCommit #1.
 
2306
        diffcommit1 = self.create_diffcommit(
 
2307
            diffset=diffset,
 
2308
            commit_id='a25e7b28af5e3184946068f432122c68c1a30b23',
 
2309
            with_diff=False)
 
2310
        diffcommit1.extra_data = {
 
2311
            'diffx': {
 
2312
                'metadata': {
 
2313
                    'author': 'Test User <test@example.com>',
 
2314
                    'author date': '2021-06-01T13:12:06-07:00',
 
2315
                    'committer': 'Test User <test@example.com>',
 
2316
                    'date': '2021-06-02T19:26:31-07:00',
 
2317
                    'id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
2318
                    'parent id': 'b892d5f833474c59d7851ff46a4b0bd919017e97',
 
2319
                },
 
2320
                'metadata_options': {
 
2321
                    'encoding': 'utf-8',
 
2322
                    'format': 'json',
 
2323
                },
 
2324
                'preamble': 'test\n',
 
2325
                'preamble_options': {
 
2326
                    'indent': 2,
 
2327
                    'line_endings': 'unix',
 
2328
                    'mimetype': 'text/markdown',
 
2329
                },
 
2330
            },
 
2331
        }
 
2332
        diffcommit1.save(update_fields=('extra_data',))
 
2333
 
 
2334
        filediff = self.create_filediff(
 
2335
            diffset=diffset,
 
2336
            commit=diffcommit1,
 
2337
            source_file='file1',
 
2338
            source_revision='c8839177d1a5605aa60abe69db95c84183f0eebe',
 
2339
            dest_file='file1',
 
2340
            dest_detail='eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
2341
            save=False,
 
2342
            diff=(
 
2343
                b'--- /file1\n'
 
2344
                b'+++ /file1\n'
 
2345
                b'@@ -498,7 +498,7 @@\n'
 
2346
                b' ... diff content\n'
 
2347
            ))
 
2348
        filediff.extra_data = {
 
2349
            'diffx': {
 
2350
                'diff_options': {
 
2351
                    'line_endings': 'unix',
 
2352
                },
 
2353
                'metadata': {
 
2354
                    'path': 'file1',
 
2355
                    'revision': {
 
2356
                        'old': 'c8839177d1a5605aa60abe69db95c84183f0eebe',
 
2357
                        'new': 'eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef',
 
2358
                    },
 
2359
                },
 
2360
                'metadata_options': {
 
2361
                    'encoding': 'latin1',
 
2362
                    'format': 'json',
 
2363
                },
 
2364
            },
 
2365
        }
 
2366
        filediff.save()
 
2367
 
 
2368
        # Create DiffCommit #2. This one won't be used.
 
2369
        diffcommit2 = self.create_diffcommit(
 
2370
            diffset=diffset,
 
2371
            commit_id='91127b687f583184144161f432222748c1a30b23',
 
2372
            with_diff=False)
 
2373
        diffcommit2.extra_data = {
 
2374
            'diffx': {
 
2375
                'metadata': {
 
2376
                    'author': 'Test User <test@example.com>',
 
2377
                    'author date': '2021-06-01T19:46:22-07:00',
 
2378
                    'committer': 'Test User <test@example.com>',
 
2379
                    'date': '2021-06-02T19:46:25-07:00',
 
2380
                    'id': '91127b687f583184144161f432222748c1a30b23',
 
2381
                    'parent id': 'a25e7b28af5e3184946068f432122c68c1a30b23',
 
2382
                },
 
2383
                'metadata_options': {
 
2384
                    'encoding': 'utf-8',
 
2385
                    'format': 'json',
 
2386
                },
 
2387
                'preamble': (
 
2388
                    "Summary of commit #2\n"
 
2389
                    "\n"
 
2390
                    "Here's a description.\n"
 
2391
                ),
 
2392
                'preamble_options': {
 
2393
                    'encoding': 'utf-8',
 
2394
                    'indent': 4,
 
2395
                    'line_endings': 'unix',
 
2396
                },
 
2397
            },
 
2398
        }
 
2399
        diffcommit2.save(update_fields=('extra_data',))
 
2400
 
 
2401
        filediff = self.create_filediff(
 
2402
            diffset=diffset,
 
2403
            commit=diffcommit2,
 
2404
            source_file='file2',
 
2405
            source_revision='281bac2b704617e807850e07e54bae3469f6a2e7',
 
2406
            dest_file='file2',
 
2407
            dest_detail='389cc6b7ae5a659383eab5dfc253764eccf84732',
 
2408
            save=False,
 
2409
            diff=(
 
2410
                b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00'
 
2411
            ))
 
2412
        filediff.extra_data = {
 
2413
            'diffx': {
 
2414
                'diff_options': {
 
2415
                    'encoding': 'utf-16',
 
2416
                    'line_endings': 'unix',
 
2417
                },
 
2418
                'metadata': {
 
2419
                    'path': 'file2',
 
2420
                    'revision': {
 
2421
                        'old': '281bac2b704617e807850e07e54bae3469f6a2e7',
 
2422
                        'new': '389cc6b7ae5a659383eab5dfc253764eccf84732',
 
2423
                    },
 
2424
                },
 
2425
                'metadata_options': {
 
2426
                    'encoding': 'utf-32',
 
2427
                    'format': 'json',
 
2428
                },
 
2429
            },
 
2430
            'encoding': 'utf-16',
 
2431
        }
 
2432
        filediff.save()
 
2433
 
 
2434
        filediff = self.create_filediff(
 
2435
            diffset=diffset,
 
2436
            commit=diffcommit2,
 
2437
            source_file='file3',
 
2438
            source_revision='be089b7197974703c83682088a068bef3422c6c2',
 
2439
            dest_file='file3',
 
2440
            dest_detail='0d4a0fb8d62b762a26e13591d06d93d79d61102f',
 
2441
            save=False,
 
2442
            diff=(
 
2443
                b'--- a/file3\r\n'
 
2444
                b'+++ b/file3\r\n'
 
2445
                b'@@ -258,1 +258,2 @@\r\n'
 
2446
                b'- old line\r\n'
 
2447
                b'+ new line 1\r\n'
 
2448
                b'+ new line 2\r\n'
 
2449
            ))
 
2450
        filediff.extra_data = {
 
2451
            'diffx': {
 
2452
                'diff_options': {
 
2453
                    'line_endings': 'dos',
 
2454
                },
 
2455
                'metadata': {
 
2456
                    'path': 'file3',
 
2457
                    'revision': {
 
2458
                        'old': 'be089b7197974703c83682088a068bef3422c6c2',
 
2459
                        'new': '0d4a0fb8d62b762a26e13591d06d93d79d61102f',
 
2460
                    },
 
2461
                },
 
2462
                'metadata_options': {
 
2463
                    'encoding': 'utf-8',
 
2464
                    'format': 'json',
 
2465
                },
 
2466
            },
 
2467
        }
 
2468
        filediff.save()
 
2469
 
 
2470
        parser = DiffXParser(b'')
 
2471
        self.assertEqual(
 
2472
            parser.raw_diff(diffcommit1),
 
2473
            b'#diffx: encoding=utf-16, version=1.0\n'
 
2474
            b'#.change:\n'
 
2475
            b'#..preamble: indent=2, length=14, line_endings=unix, '
 
2476
            b'mimetype=text/markdown\n'
 
2477
            b'  \xff\xfet\x00e\x00s\x00t\x00\n\x00'
 
2478
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
2479
            b'{\n'
 
2480
            b'    "author": "Test User <test@example.com>",\n'
 
2481
            b'    "author date": "2021-06-01T13:12:06-07:00",\n'
 
2482
            b'    "committer": "Test User <test@example.com>",\n'
 
2483
            b'    "date": "2021-06-02T19:26:31-07:00",\n'
 
2484
            b'    "id": "a25e7b28af5e3184946068f432122c68c1a30b23",\n'
 
2485
            b'    "parent id": "b892d5f833474c59d7851ff46a4b0bd919017e97"\n'
 
2486
            b'}\n'
 
2487
            b'#..file:\n'
 
2488
            b'#...meta: encoding=latin1, format=json, length=166\n'
 
2489
            b'{\n'
 
2490
            b'    "path": "file1",\n'
 
2491
            b'    "revision": {\n'
 
2492
            b'        "new": "eed8df7f1400a95cdf5a87ddb947e7d9c5a19cef",\n'
 
2493
            b'        "old": "c8839177d1a5605aa60abe69db95c84183f0eebe"\n'
 
2494
            b'    }\n'
 
2495
            b'}\n'
 
2496
            b'#...diff: length=60, line_endings=unix\n'
 
2497
            b'--- /file1\n'
 
2498
            b'+++ /file1\n'
 
2499
            b'@@ -498,7 +498,7 @@\n'
 
2500
            b' ... diff content\n')
 
2501
 
 
2502
        self.assertEqual(
 
2503
            parser.raw_diff(diffcommit2),
 
2504
            b'#diffx: encoding=utf-16, version=1.0\n'
 
2505
            b'#.change:\n'
 
2506
            b'#..preamble: encoding=utf-8, indent=4, length=56, '
 
2507
            b'line_endings=unix\n'
 
2508
            b'    Summary of commit #2\n'
 
2509
            b'    \n'
 
2510
            b'    Here\'s a description.\n'
 
2511
            b'#..meta: encoding=utf-8, format=json, length=302\n'
 
2512
            b'{\n'
 
2513
            b'    "author": "Test User <test@example.com>",\n'
 
2514
            b'    "author date": "2021-06-01T19:46:22-07:00",\n'
 
2515
            b'    "committer": "Test User <test@example.com>",\n'
 
2516
            b'    "date": "2021-06-02T19:46:25-07:00",\n'
 
2517
            b'    "id": "91127b687f583184144161f432222748c1a30b23",\n'
 
2518
            b'    "parent id": "a25e7b28af5e3184946068f432122c68c1a30b23"\n'
 
2519
            b'}\n'
 
2520
            b'#..file:\n'
 
2521
            b'#...meta: encoding=utf-32, format=json, length=668\n'
 
2522
            b'\xff\xfe\x00\x00{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
2523
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
2524
            b'p\x00\x00\x00a\x00\x00\x00t\x00\x00\x00h\x00\x00\x00'
 
2525
            b'"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00"\x00\x00\x00'
 
2526
            b'f\x00\x00\x00i\x00\x00\x00l\x00\x00\x00e\x00\x00\x00'
 
2527
            b'2\x00\x00\x00"\x00\x00\x00,\x00\x00\x00\n\x00\x00\x00'
 
2528
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2529
            b'"\x00\x00\x00r\x00\x00\x00e\x00\x00\x00v\x00\x00\x00'
 
2530
            b'i\x00\x00\x00s\x00\x00\x00i\x00\x00\x00o\x00\x00\x00'
 
2531
            b'n\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
2532
            b'{\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2533
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2534
            b' \x00\x00\x00 \x00\x00\x00"\x00\x00\x00n\x00\x00\x00'
 
2535
            b'e\x00\x00\x00w\x00\x00\x00"\x00\x00\x00:\x00\x00\x00'
 
2536
            b' \x00\x00\x00"\x00\x00\x003\x00\x00\x008\x00\x00\x00'
 
2537
            b'9\x00\x00\x00c\x00\x00\x00c\x00\x00\x006\x00\x00\x00'
 
2538
            b'b\x00\x00\x007\x00\x00\x00a\x00\x00\x00e\x00\x00\x00'
 
2539
            b'5\x00\x00\x00a\x00\x00\x006\x00\x00\x005\x00\x00\x00'
 
2540
            b'9\x00\x00\x003\x00\x00\x008\x00\x00\x003\x00\x00\x00'
 
2541
            b'e\x00\x00\x00a\x00\x00\x00b\x00\x00\x005\x00\x00\x00'
 
2542
            b'd\x00\x00\x00f\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
2543
            b'5\x00\x00\x003\x00\x00\x007\x00\x00\x006\x00\x00\x00'
 
2544
            b'4\x00\x00\x00e\x00\x00\x00c\x00\x00\x00c\x00\x00\x00'
 
2545
            b'f\x00\x00\x008\x00\x00\x004\x00\x00\x007\x00\x00\x00'
 
2546
            b'3\x00\x00\x002\x00\x00\x00"\x00\x00\x00,\x00\x00\x00'
 
2547
            b'\n\x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2548
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00 \x00\x00\x00'
 
2549
            b' \x00\x00\x00"\x00\x00\x00o\x00\x00\x00l\x00\x00\x00'
 
2550
            b'd\x00\x00\x00"\x00\x00\x00:\x00\x00\x00 \x00\x00\x00'
 
2551
            b'"\x00\x00\x002\x00\x00\x008\x00\x00\x001\x00\x00\x00'
 
2552
            b'b\x00\x00\x00a\x00\x00\x00c\x00\x00\x002\x00\x00\x00'
 
2553
            b'b\x00\x00\x007\x00\x00\x000\x00\x00\x004\x00\x00\x00'
 
2554
            b'6\x00\x00\x001\x00\x00\x007\x00\x00\x00e\x00\x00\x00'
 
2555
            b'8\x00\x00\x000\x00\x00\x007\x00\x00\x008\x00\x00\x00'
 
2556
            b'5\x00\x00\x000\x00\x00\x00e\x00\x00\x000\x00\x00\x00'
 
2557
            b'7\x00\x00\x00e\x00\x00\x005\x00\x00\x004\x00\x00\x00'
 
2558
            b'b\x00\x00\x00a\x00\x00\x00e\x00\x00\x003\x00\x00\x00'
 
2559
            b'4\x00\x00\x006\x00\x00\x009\x00\x00\x00f\x00\x00\x00'
 
2560
            b'6\x00\x00\x00a\x00\x00\x002\x00\x00\x00e\x00\x00\x00'
 
2561
            b'7\x00\x00\x00"\x00\x00\x00\n\x00\x00\x00 \x00\x00\x00'
 
2562
            b' \x00\x00\x00 \x00\x00\x00 \x00\x00\x00}\x00\x00\x00'
 
2563
            b'\n\x00\x00\x00}\x00\x00\x00\n\x00\x00\x00'
 
2564
            b'#...diff: encoding=utf-16, length=22, line_endings=unix\n'
 
2565
            b'\xff\xfe \x00.\x00.\x00.\x00 \x00d\x00i\x00f\x00f\x00\n\x00'
 
2566
            b'#..file:\n'
 
2567
            b'#...meta: encoding=utf-8, format=json, length=166\n'
 
2568
            b'{\n'
 
2569
            b'    "path": "file3",\n'
 
2570
            b'    "revision": {\n'
 
2571
            b'        "new": "0d4a0fb8d62b762a26e13591d06d93d79d61102f",\n'
 
2572
            b'        "old": "be089b7197974703c83682088a068bef3422c6c2"\n'
 
2573
            b'    }\n'
 
2574
            b'}\n'
 
2575
            b'#...diff: length=87, line_endings=dos\n'
 
2576
            b'--- a/file3\r\n'
 
2577
            b'+++ b/file3\r\n'
 
2578
            b'@@ -258,1 +258,2 @@\r\n'
 
2579
            b'- old line\r\n'
 
2580
            b'+ new line 1\r\n'
 
2581
            b'+ new line 2\r\n')