~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge_directive.py

  • Committer: Robert Collins
  • Date: 2007-11-09 17:50:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2988.
  • Revision ID: robertc@robertcollins.net-20071109175031-agaiy6530rvbprmb
Change (without backwards compatibility) the
iter_lines_added_or_present_in_versions VersionedFile API to yield the
text version that each line is being returned from. This is useful for
reconcile in determining what inventories reference what texts.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
import re
 
18
 
 
19
from bzrlib import (
 
20
    errors,
 
21
    gpg,
 
22
    merge_directive,
 
23
    tests,
 
24
    )
 
25
 
 
26
 
 
27
OUTPUT1 = """# Bazaar merge directive format 1
 
28
# revision_id: example:
 
29
# target_branch: http://example.com
 
30
# testament_sha1: sha
 
31
# timestamp: 1970-01-01 00:09:33 +0002
 
32
#\x20
 
33
booga"""
 
34
 
 
35
OUTPUT1_2 = """# Bazaar merge directive format 2 (Bazaar 0.90)
 
36
# revision_id: example:
 
37
# target_branch: http://example.com
 
38
# testament_sha1: sha
 
39
# timestamp: 1970-01-01 00:09:33 +0002
 
40
# base_revision_id: null:
 
41
#\x20
 
42
# Begin bundle
 
43
booga"""
 
44
 
 
45
OUTPUT2 = """# Bazaar merge directive format 1
 
46
# revision_id: example:
 
47
# target_branch: http://example.com
 
48
# testament_sha1: sha
 
49
# timestamp: 1970-01-01 00:09:33 +0002
 
50
# source_branch: http://example.org
 
51
# message: Hi mom!
 
52
#\x20
 
53
booga"""
 
54
 
 
55
OUTPUT2_2 = """# Bazaar merge directive format 2 (Bazaar 0.90)
 
56
# revision_id: example:
 
57
# target_branch: http://example.com
 
58
# testament_sha1: sha
 
59
# timestamp: 1970-01-01 00:09:33 +0002
 
60
# source_branch: http://example.org
 
61
# message: Hi mom!
 
62
# base_revision_id: null:
 
63
#\x20
 
64
# Begin patch
 
65
booga"""
 
66
 
 
67
INPUT1 = """
 
68
I was thinking today about creating a merge directive.
 
69
 
 
70
So I did.
 
71
 
 
72
Here it is.
 
73
 
 
74
(I've pasted it in the body of this message)
 
75
 
 
76
Aaron
 
77
 
 
78
# Bazaar merge directive format 1\r
 
79
# revision_id: example:
 
80
# target_branch: http://example.com
 
81
# testament_sha1: sha
 
82
# timestamp: 1970-01-01 00:09:33 +0002
 
83
# source_branch: http://example.org
 
84
# message: Hi mom!
 
85
#\x20
 
86
booga""".splitlines(True)
 
87
 
 
88
 
 
89
INPUT1_2 = """
 
90
I was thinking today about creating a merge directive.
 
91
 
 
92
So I did.
 
93
 
 
94
Here it is.
 
95
 
 
96
(I've pasted it in the body of this message)
 
97
 
 
98
Aaron
 
99
 
 
100
# Bazaar merge directive format 2 (Bazaar 0.90)\r
 
101
# revision_id: example:
 
102
# target_branch: http://example.com
 
103
# testament_sha1: sha
 
104
# timestamp: 1970-01-01 00:09:33 +0002
 
105
# source_branch: http://example.org
 
106
# base_revision_id: null:
 
107
# message: Hi mom!
 
108
#\x20
 
109
# Begin patch
 
110
booga""".splitlines(True)
 
111
 
 
112
 
 
113
INPUT1_2_OLD = """
 
114
I was thinking today about creating a merge directive.
 
115
 
 
116
So I did.
 
117
 
 
118
Here it is.
 
119
 
 
120
(I've pasted it in the body of this message)
 
121
 
 
122
Aaron
 
123
 
 
124
# Bazaar merge directive format 2 (Bazaar 0.19)\r
 
125
# revision_id: example:
 
126
# target_branch: http://example.com
 
127
# testament_sha1: sha
 
128
# timestamp: 1970-01-01 00:09:33 +0002
 
129
# source_branch: http://example.org
 
130
# base_revision_id: null:
 
131
# message: Hi mom!
 
132
#\x20
 
133
# Begin patch
 
134
booga""".splitlines(True)
 
135
 
 
136
 
 
137
OLD_DIRECTIVE_2 = """# Bazaar merge directive format 2 (Bazaar 0.19)
 
138
# revision_id: abentley@panoramicfeedback.com-20070807234458-\
 
139
#   nzhkoyza56lan7z5
 
140
# target_branch: http://panoramicfeedback.com/opensource/bzr/repo\
 
141
#   /bzr.ab
 
142
# testament_sha1: d825a5cdb267a90ec2ba86b00895f3d8a9bed6bf
 
143
# timestamp: 2007-08-10 16:15:02 -0400
 
144
# source_branch: http://panoramicfeedback.com/opensource/bzr/repo\
 
145
#   /bzr.ab
 
146
# base_revision_id: abentley@panoramicfeedback.com-20070731163346-\
 
147
#   623xwcycwij91xen
 
148
#
 
149
""".splitlines(True)
 
150
 
 
151
 
 
152
class TestMergeDirective(object):
 
153
 
 
154
    def test_merge_source(self):
 
155
        time = 500000.0
 
156
        timezone = 5 * 3600
 
157
        self.assertRaises(errors.NoMergeSource, self.make_merge_directive,
 
158
            'example:', 'sha', time, timezone, 'http://example.com')
 
159
        self.assertRaises(errors.NoMergeSource, self.make_merge_directive,
 
160
            'example:', 'sha', time, timezone, 'http://example.com',
 
161
            patch_type='diff')
 
162
        self.make_merge_directive('example:', 'sha', time, timezone,
 
163
            'http://example.com', source_branch='http://example.org')
 
164
        md = self.make_merge_directive('null:', 'sha', time, timezone,
 
165
            'http://example.com', patch='blah', patch_type='bundle')
 
166
        self.assertIs(None, md.source_branch)
 
167
        md2 = self.make_merge_directive('null:', 'sha', time, timezone,
 
168
            'http://example.com', patch='blah', patch_type='bundle',
 
169
            source_branch='bar')
 
170
        self.assertEqual('bar', md2.source_branch)
 
171
 
 
172
    def test_serialization(self):
 
173
        time = 453
 
174
        timezone = 120
 
175
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
176
            'http://example.com', patch='booga', patch_type='bundle')
 
177
        self.assertEqualDiff(self.OUTPUT1, ''.join(md.to_lines()))
 
178
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
179
            'http://example.com', source_branch="http://example.org",
 
180
            patch='booga', patch_type='diff', message="Hi mom!")
 
181
        self.assertEqualDiff(self.OUTPUT2, ''.join(md.to_lines()))
 
182
 
 
183
    def test_deserialize_junk(self):
 
184
        time = 501
 
185
        self.assertRaises(errors.NotAMergeDirective,
 
186
                          merge_directive.MergeDirective.from_lines, 'lala')
 
187
 
 
188
    def test_deserialize_empty(self):
 
189
        self.assertRaises(errors.NotAMergeDirective,
 
190
                          merge_directive.MergeDirective.from_lines, [])
 
191
 
 
192
    def test_deserialize_leading_junk(self):
 
193
        md = merge_directive.MergeDirective.from_lines(self.INPUT1)
 
194
        self.assertEqual('example:', md.revision_id)
 
195
        self.assertEqual('sha', md.testament_sha1)
 
196
        self.assertEqual('http://example.com', md.target_branch)
 
197
        self.assertEqual('http://example.org', md.source_branch)
 
198
        self.assertEqual(453, md.time)
 
199
        self.assertEqual(120, md.timezone)
 
200
        self.assertEqual('booga', md.patch)
 
201
        self.assertEqual('diff', md.patch_type)
 
202
        self.assertEqual('Hi mom!', md.message)
 
203
 
 
204
    def test_roundtrip(self):
 
205
        time = 500000
 
206
        timezone = 7.5 * 3600
 
207
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
208
            'http://example.com', source_branch="http://example.org",
 
209
            patch='booga', patch_type='diff')
 
210
        md2 = merge_directive.MergeDirective.from_lines(md.to_lines())
 
211
        self.assertEqual('example:', md2.revision_id)
 
212
        self.assertIsInstance(md2.revision_id, str)
 
213
        self.assertEqual('sha', md2.testament_sha1)
 
214
        self.assertEqual('http://example.com', md2.target_branch)
 
215
        self.assertEqual('http://example.org', md2.source_branch)
 
216
        self.assertEqual(time, md2.time)
 
217
        self.assertEqual(timezone, md2.timezone)
 
218
        self.assertEqual('diff', md2.patch_type)
 
219
        self.assertEqual('booga', md2.patch)
 
220
        self.assertEqual(None, md2.message)
 
221
        self.set_bundle(md, "# Bazaar revision bundle v0.9\n#\n")
 
222
        md.message = "Hi mom!"
 
223
        lines = md.to_lines()
 
224
        md3 = merge_directive.MergeDirective.from_lines(lines)
 
225
        self.assertEqual("# Bazaar revision bundle v0.9\n#\n", md3.bundle)
 
226
        self.assertEqual("bundle", md3.patch_type)
 
227
        self.assertContainsRe(md3.to_lines()[0],
 
228
            '^# Bazaar merge directive format ')
 
229
        self.assertEqual("Hi mom!", md3.message)
 
230
        md3.clear_payload()
 
231
        self.assertIs(None, md3.get_raw_bundle())
 
232
        md4 = merge_directive.MergeDirective.from_lines(md3.to_lines())
 
233
        self.assertIs(None, md4.patch_type)
 
234
 
 
235
 
 
236
class TestMergeDirective1(tests.TestCase, TestMergeDirective):
 
237
    """Test merge directive format 1"""
 
238
 
 
239
    INPUT1 = INPUT1
 
240
 
 
241
    OUTPUT1 = OUTPUT1
 
242
 
 
243
    OUTPUT2 = OUTPUT2
 
244
 
 
245
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
 
246
                 target_branch, patch=None, patch_type=None,
 
247
                 source_branch=None, message=None):
 
248
        return merge_directive.MergeDirective(revision_id, testament_sha1,
 
249
                 time, timezone, target_branch, patch, patch_type,
 
250
                 source_branch, message)
 
251
 
 
252
    @staticmethod
 
253
    def set_bundle(md, value):
 
254
        md.patch = value
 
255
 
 
256
    def test_require_patch(self):
 
257
        time = 500.0
 
258
        timezone = 120
 
259
        self.assertRaises(errors.PatchMissing, merge_directive.MergeDirective,
 
260
            'example:', 'sha', time, timezone, 'http://example.com',
 
261
            patch_type='bundle')
 
262
        md = merge_directive.MergeDirective('example:', 'sha1', time, timezone,
 
263
            'http://example.com', source_branch="http://example.org",
 
264
            patch='', patch_type='diff')
 
265
        self.assertEqual(md.patch, '')
 
266
 
 
267
 
 
268
class TestMergeDirective2(tests.TestCase, TestMergeDirective):
 
269
    """Test merge directive format 2"""
 
270
 
 
271
    INPUT1 = INPUT1_2
 
272
 
 
273
    OUTPUT1 = OUTPUT1_2
 
274
 
 
275
    OUTPUT2 = OUTPUT2_2
 
276
 
 
277
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
 
278
                 target_branch, patch=None, patch_type=None,
 
279
                 source_branch=None, message=None, base_revision_id='null:'):
 
280
        if patch_type == 'bundle':
 
281
            bundle = patch
 
282
            patch = None
 
283
        else:
 
284
            bundle = None
 
285
        return merge_directive.MergeDirective2(revision_id, testament_sha1,
 
286
            time, timezone, target_branch, patch, source_branch, message,
 
287
            bundle, base_revision_id)
 
288
 
 
289
    @staticmethod
 
290
    def set_bundle(md, value):
 
291
        md.bundle = value
 
292
 
 
293
 
 
294
EMAIL1 = """From: "J. Random Hacker" <jrandom@example.com>
 
295
Subject: Commit of rev2a
 
296
To: pqm@example.com
 
297
User-Agent: Bazaar \(.*\)
 
298
 
 
299
# Bazaar merge directive format 1
 
300
# revision_id: rev2a
 
301
# target_branch: (.|\n)*
 
302
# testament_sha1: .*
 
303
# timestamp: 1970-01-01 00:08:56 \\+0001
 
304
# source_branch: (.|\n)*
 
305
"""
 
306
 
 
307
 
 
308
EMAIL1_2 = """From: "J. Random Hacker" <jrandom@example.com>
 
309
Subject: Commit of rev2a
 
310
To: pqm@example.com
 
311
User-Agent: Bazaar \(.*\)
 
312
 
 
313
# Bazaar merge directive format 2 \\(Bazaar 0.90\\)
 
314
# revision_id: rev2a
 
315
# target_branch: (.|\n)*
 
316
# testament_sha1: .*
 
317
# timestamp: 1970-01-01 00:08:56 \\+0001
 
318
# source_branch: (.|\n)*
 
319
"""
 
320
 
 
321
 
 
322
EMAIL2 = """From: "J. Random Hacker" <jrandom@example.com>
 
323
Subject: Commit of rev2a with special message
 
324
To: pqm@example.com
 
325
User-Agent: Bazaar \(.*\)
 
326
 
 
327
# Bazaar merge directive format 1
 
328
# revision_id: rev2a
 
329
# target_branch: (.|\n)*
 
330
# testament_sha1: .*
 
331
# timestamp: 1970-01-01 00:08:56 \\+0001
 
332
# source_branch: (.|\n)*
 
333
# message: Commit of rev2a with special message
 
334
"""
 
335
 
 
336
EMAIL2_2 = """From: "J. Random Hacker" <jrandom@example.com>
 
337
Subject: Commit of rev2a with special message
 
338
To: pqm@example.com
 
339
User-Agent: Bazaar \(.*\)
 
340
 
 
341
# Bazaar merge directive format 2 \\(Bazaar 0.90\\)
 
342
# revision_id: rev2a
 
343
# target_branch: (.|\n)*
 
344
# testament_sha1: .*
 
345
# timestamp: 1970-01-01 00:08:56 \\+0001
 
346
# source_branch: (.|\n)*
 
347
# message: Commit of rev2a with special message
 
348
"""
 
349
 
 
350
class TestMergeDirectiveBranch(object):
 
351
 
 
352
    def make_trees(self):
 
353
        tree_a = self.make_branch_and_tree('tree_a')
 
354
        tree_a.branch.get_config().set_user_option('email',
 
355
            'J. Random Hacker <jrandom@example.com>')
 
356
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_b\n'),
 
357
                                  ('tree_a/file_2', 'content_x\rcontent_y\r')])
 
358
        tree_a.add(['file', 'file_2'])
 
359
        tree_a.commit('message', rev_id='rev1')
 
360
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
 
361
        branch_c = tree_a.bzrdir.sprout('branch_c').open_branch()
 
362
        tree_b.commit('message', rev_id='rev2b')
 
363
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_c \n'),
 
364
                                  ('tree_a/file_2', 'content_x\rcontent_z\r')])
 
365
        tree_a.commit('Commit of rev2a', rev_id='rev2a')
 
366
        return tree_a, tree_b, branch_c
 
367
 
 
368
    def test_empty_target(self):
 
369
        tree_a, tree_b, branch_c = self.make_trees()
 
370
        tree_d = self.make_branch_and_tree('tree_d')
 
371
        md2 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
 
372
            tree_d.branch.base, patch_type='diff',
 
373
            public_branch=tree_a.branch.base)
 
374
 
 
375
    def test_generate_patch(self):
 
376
        tree_a, tree_b, branch_c = self.make_trees()
 
377
        md2 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
 
378
            tree_b.branch.base, patch_type='diff',
 
379
            public_branch=tree_a.branch.base)
 
380
        self.assertNotContainsRe(md2.patch, 'Bazaar revision bundle')
 
381
        self.assertContainsRe(md2.patch, '\\+content_c')
 
382
        self.assertNotContainsRe(md2.patch, '\\+\\+\\+ b/')
 
383
        self.assertContainsRe(md2.patch, '\\+\\+\\+ file')
 
384
 
 
385
    def test_public_branch(self):
 
386
        tree_a, tree_b, branch_c = self.make_trees()
 
387
        self.assertRaises(errors.PublicBranchOutOfDate,
 
388
            self.from_objects, tree_a.branch.repository, 'rev2a', 500, 144,
 
389
            tree_b.branch.base, public_branch=branch_c.base, patch_type='diff')
 
390
        self.assertRaises(errors.PublicBranchOutOfDate,
 
391
            self.from_objects, tree_a.branch.repository, 'rev2a', 500, 144,
 
392
            tree_b.branch.base, public_branch=branch_c.base, patch_type=None)
 
393
        # public branch is not checked if patch format is bundle.
 
394
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
 
395
            tree_b.branch.base, public_branch=branch_c.base)
 
396
        # public branch is provided with a bundle, despite possibly being out
 
397
        # of date, because it's not required if a bundle is present.
 
398
        self.assertEqual(md1.source_branch, branch_c.base)
 
399
        # Once we update the public branch, we can generate a diff.
 
400
        branch_c.pull(tree_a.branch)
 
401
        md3 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
 
402
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base)
 
403
 
 
404
    def test_use_public_submit_branch(self):
 
405
        tree_a, tree_b, branch_c = self.make_trees()
 
406
        branch_c.pull(tree_a.branch)
 
407
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
 
408
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base)
 
409
        self.assertEqual(md.target_branch, tree_b.branch.base)
 
410
        tree_b.branch.set_public_branch('http://example.com')
 
411
        md2 = self.from_objects(
 
412
              tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
 
413
              patch_type=None, public_branch=branch_c.base)
 
414
        self.assertEqual(md2.target_branch, 'http://example.com')
 
415
 
 
416
    def test_message(self):
 
417
        tree_a, tree_b, branch_c = self.make_trees()
 
418
        md3 = self.from_objects(tree_a.branch.repository, 'rev1', 500, 120,
 
419
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base,
 
420
            message='Merge message')
 
421
        md3.to_lines()
 
422
        self.assertIs(None, md3.patch)
 
423
        self.assertEqual('Merge message', md3.message)
 
424
 
 
425
    def test_generate_bundle(self):
 
426
        tree_a, tree_b, branch_c = self.make_trees()
 
427
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
 
428
            tree_b.branch.base, public_branch=branch_c.base)
 
429
 
 
430
        self.assertContainsRe(md1.get_raw_bundle(), 'Bazaar revision bundle')
 
431
        self.assertContainsRe(md1.patch, '\\+content_c')
 
432
        self.assertNotContainsRe(md1.patch, '\\+content_a')
 
433
        self.assertContainsRe(md1.patch, '\\+content_c')
 
434
        self.assertNotContainsRe(md1.patch, '\\+content_a')
 
435
 
 
436
    def test_broken_bundle(self):
 
437
        tree_a, tree_b, branch_c = self.make_trees()
 
438
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
 
439
            tree_b.branch.base, public_branch=branch_c.base)
 
440
        lines = md1.to_lines()
 
441
        lines = [l.replace('\n', '\r\n') for l in lines]
 
442
        md2 = merge_directive.MergeDirective.from_lines(lines)
 
443
        self.assertEqual('rev2a', md2.revision_id)
 
444
 
 
445
    def test_signing(self):
 
446
        time = 453
 
447
        timezone = 7200
 
448
        class FakeBranch(object):
 
449
            def get_config(self):
 
450
                return self
 
451
            def gpg_signing_command(self):
 
452
                return 'loopback'
 
453
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
454
            'http://example.com', source_branch="http://example.org",
 
455
            patch='booga', patch_type='diff')
 
456
        old_strategy = gpg.GPGStrategy
 
457
        gpg.GPGStrategy = gpg.LoopbackGPGStrategy
 
458
        try:
 
459
            signed = md.to_signed(FakeBranch())
 
460
        finally:
 
461
            gpg.GPGStrategy = old_strategy
 
462
        self.assertContainsRe(signed, '^-----BEGIN PSEUDO-SIGNED CONTENT')
 
463
        self.assertContainsRe(signed, 'example.org')
 
464
        self.assertContainsRe(signed, 'booga')
 
465
 
 
466
    def test_email(self):
 
467
        tree_a, tree_b, branch_c = self.make_trees()
 
468
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 476, 60,
 
469
            tree_b.branch.base, patch_type=None,
 
470
            public_branch=tree_a.branch.base)
 
471
        message = md.to_email('pqm@example.com', tree_a.branch)
 
472
        self.assertContainsRe(message.as_string(), self.EMAIL1)
 
473
        md.message = 'Commit of rev2a with special message'
 
474
        message = md.to_email('pqm@example.com', tree_a.branch)
 
475
        self.assertContainsRe(message.as_string(), self.EMAIL2)
 
476
 
 
477
    def test_install_revisions_branch(self):
 
478
        tree_a, tree_b, branch_c = self.make_trees()
 
479
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
 
480
            tree_b.branch.base, patch_type=None,
 
481
            public_branch=tree_a.branch.base)
 
482
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
 
483
        revision = md.install_revisions(tree_b.branch.repository)
 
484
        self.assertEqual('rev2a', revision)
 
485
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
 
486
 
 
487
    def test_get_merge_request(self):
 
488
        tree_a, tree_b, branch_c = self.make_trees()
 
489
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
 
490
            tree_b.branch.base, patch_type='bundle',
 
491
            public_branch=tree_a.branch.base)
 
492
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
 
493
        md.install_revisions(tree_b.branch.repository)
 
494
        base, revision, verified = md.get_merge_request(
 
495
            tree_b.branch.repository)
 
496
        if isinstance(md, merge_directive.MergeDirective):
 
497
            self.assertIs(None, base)
 
498
            self.assertEqual('inapplicable', verified)
 
499
        else:
 
500
            self.assertEqual('rev1', base)
 
501
            self.assertEqual('verified', verified)
 
502
        self.assertEqual('rev2a', revision)
 
503
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
 
504
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
 
505
            tree_b.branch.base, patch_type=None,
 
506
            public_branch=tree_a.branch.base)
 
507
        base, revision, verified = md.get_merge_request(
 
508
            tree_b.branch.repository)
 
509
        if isinstance(md, merge_directive.MergeDirective):
 
510
            self.assertIs(None, base)
 
511
            self.assertEqual('inapplicable', verified)
 
512
        else:
 
513
            self.assertEqual('rev1', base)
 
514
            self.assertEqual('inapplicable', verified)
 
515
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
 
516
            tree_b.branch.base, patch_type='diff',
 
517
            public_branch=tree_a.branch.base)
 
518
        base, revision, verified = md.get_merge_request(
 
519
            tree_b.branch.repository)
 
520
        if isinstance(md, merge_directive.MergeDirective):
 
521
            self.assertIs(None, base)
 
522
            self.assertEqual('inapplicable', verified)
 
523
        else:
 
524
            self.assertEqual('rev1', base)
 
525
            self.assertEqual('verified', verified)
 
526
        md.patch='asdf'
 
527
        base, revision, verified = md.get_merge_request(
 
528
            tree_b.branch.repository)
 
529
        if isinstance(md, merge_directive.MergeDirective):
 
530
            self.assertIs(None, base)
 
531
            self.assertEqual('inapplicable', verified)
 
532
        else:
 
533
            self.assertEqual('rev1', base)
 
534
            self.assertEqual('failed', verified)
 
535
 
 
536
    def test_install_revisions_bundle(self):
 
537
        tree_a, tree_b, branch_c = self.make_trees()
 
538
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
 
539
            tree_b.branch.base, patch_type='bundle',
 
540
            public_branch=tree_a.branch.base)
 
541
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
 
542
        revision = md.install_revisions(tree_b.branch.repository)
 
543
        self.assertEqual('rev2a', revision)
 
544
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
 
545
 
 
546
    def test_get_target_revision_nofetch(self):
 
547
        tree_a, tree_b, branch_c = self.make_trees()
 
548
        tree_b.branch.fetch(tree_a.branch)
 
549
        md = self.from_objects( tree_a.branch.repository, 'rev2a', 500, 36,
 
550
            tree_b.branch.base, patch_type=None,
 
551
            public_branch=tree_a.branch.base)
 
552
        md.source_branch = '/dev/null'
 
553
        revision = md.install_revisions(tree_b.branch.repository)
 
554
        self.assertEqual('rev2a', revision)
 
555
 
 
556
 
 
557
class TestMergeDirective1Branch(tests.TestCaseWithTransport,
 
558
    TestMergeDirectiveBranch):
 
559
    """Test merge directive format 1 with a branch"""
 
560
 
 
561
    EMAIL1 = EMAIL1
 
562
 
 
563
    EMAIL2 = EMAIL2
 
564
 
 
565
    def from_objects(self, repository, revision_id, time, timezone,
 
566
        target_branch, patch_type='bundle', local_target_branch=None,
 
567
        public_branch=None, message=None):
 
568
        return merge_directive.MergeDirective.from_objects(
 
569
            repository, revision_id, time, timezone, target_branch,
 
570
            patch_type, local_target_branch, public_branch, message)
 
571
 
 
572
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
 
573
                 target_branch, patch=None, patch_type=None,
 
574
                 source_branch=None, message=None):
 
575
        return merge_directive.MergeDirective(revision_id, testament_sha1,
 
576
                 time, timezone, target_branch, patch, patch_type,
 
577
                 source_branch, message)
 
578
 
 
579
 
 
580
class TestMergeDirective2Branch(tests.TestCaseWithTransport,
 
581
    TestMergeDirectiveBranch):
 
582
    """Test merge directive format 2 with a branch"""
 
583
 
 
584
    EMAIL1 = EMAIL1_2
 
585
 
 
586
    EMAIL2 = EMAIL2_2
 
587
 
 
588
    def from_objects(self, repository, revision_id, time, timezone,
 
589
        target_branch, patch_type='bundle', local_target_branch=None,
 
590
        public_branch=None, message=None, base_revision_id=None):
 
591
        include_patch = (patch_type in ('bundle', 'diff'))
 
592
        include_bundle = (patch_type == 'bundle')
 
593
        assert patch_type in ('bundle', 'diff', None)
 
594
        return merge_directive.MergeDirective2.from_objects(
 
595
            repository, revision_id, time, timezone, target_branch,
 
596
            include_patch, include_bundle, local_target_branch, public_branch,
 
597
            message, base_revision_id)
 
598
 
 
599
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
 
600
                 target_branch, patch=None, patch_type=None,
 
601
                 source_branch=None, message=None, base_revision_id='null:'):
 
602
        if patch_type == 'bundle':
 
603
            bundle = patch
 
604
            patch = None
 
605
        else:
 
606
            bundle = None
 
607
        return merge_directive.MergeDirective2(revision_id, testament_sha1,
 
608
            time, timezone, target_branch, patch, source_branch, message,
 
609
            bundle, base_revision_id)
 
610
 
 
611
    def test_base_revision(self):
 
612
        tree_a, tree_b, branch_c = self.make_trees()
 
613
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
 
614
            tree_b.branch.base, patch_type='bundle',
 
615
            public_branch=tree_a.branch.base, base_revision_id=None)
 
616
        self.assertEqual('rev1', md.base_revision_id)
 
617
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
 
618
            tree_b.branch.base, patch_type='bundle',
 
619
            public_branch=tree_a.branch.base, base_revision_id='null:')
 
620
        self.assertEqual('null:', md.base_revision_id)
 
621
        lines = md.to_lines()
 
622
        md2 = merge_directive.MergeDirective.from_lines(lines)
 
623
        self.assertEqual(md2.base_revision_id, md.base_revision_id)
 
624
 
 
625
    def test_patch_verification(self):
 
626
        tree_a, tree_b, branch_c = self.make_trees()
 
627
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
 
628
            tree_b.branch.base, patch_type='bundle',
 
629
            public_branch=tree_a.branch.base)
 
630
        lines = md.to_lines()
 
631
        md2 = merge_directive.MergeDirective.from_lines(lines)
 
632
        md2._verify_patch(tree_a.branch.repository)
 
633
        # Strip trailing whitespace
 
634
        md2.patch = md2.patch.replace(' \n', '\n')
 
635
        md2._verify_patch(tree_a.branch.repository)
 
636
        # Convert to Mac line-endings
 
637
        md2.patch = re.sub('(\r\n|\r|\n)', '\r', md2.patch)
 
638
        self.assertTrue(md2._verify_patch(tree_a.branch.repository))
 
639
        # Convert to DOS line-endings
 
640
        md2.patch = re.sub('(\r\n|\r|\n)', '\r\n', md2.patch)
 
641
        self.assertTrue(md2._verify_patch(tree_a.branch.repository))
 
642
        md2.patch = md2.patch.replace('content_c', 'content_d')
 
643
        self.assertFalse(md2._verify_patch(tree_a.branch.repository))
 
644
 
 
645
 
 
646
class TestParseOldMergeDirective2(tests.TestCase):
 
647
 
 
648
    def test_parse_old_merge_directive(self):
 
649
        md = merge_directive.MergeDirective.from_lines(INPUT1_2_OLD)
 
650
        self.assertEqual('example:', md.revision_id)
 
651
        self.assertEqual('sha', md.testament_sha1)
 
652
        self.assertEqual('http://example.com', md.target_branch)
 
653
        self.assertEqual('http://example.org', md.source_branch)
 
654
        self.assertEqual(453, md.time)
 
655
        self.assertEqual(120, md.timezone)
 
656
        self.assertEqual('booga', md.patch)
 
657
        self.assertEqual('diff', md.patch_type)
 
658
        self.assertEqual('Hi mom!', md.message)