/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge_directive.py

  • Committer: Robert Collins
  • Date: 2007-07-15 15:40:37 UTC
  • mto: (2592.3.33 repository)
  • mto: This revision was merged to the branch mainline in revision 2624.
  • Revision ID: robertc@robertcollins.net-20070715154037-3ar8g89decddc9su
Make GraphIndex accept nodes as key, value, references, so that the method
signature is closer to what a simple key->value index delivers. Also
change the behaviour when the reference list count is zero to accept
key, value as nodes, and emit key, value to make it identical in that case
to a simple key->value index. This may not be a good idea, but for now it
seems ok.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
import re
18
17
 
19
18
from bzrlib import (
20
19
    errors,
21
20
    gpg,
22
 
    mail_client,
23
21
    merge_directive,
24
22
    tests,
25
 
    trace,
26
23
    )
27
24
 
28
25
 
34
31
#\x20
35
32
booga"""
36
33
 
37
 
OUTPUT1_2 = """# Bazaar merge directive format 2 (Bazaar 0.90)
38
 
# revision_id: example:
39
 
# target_branch: http://example.com
40
 
# testament_sha1: sha
41
 
# timestamp: 1970-01-01 00:09:33 +0002
42
 
# base_revision_id: null:
43
 
#\x20
44
 
# Begin bundle
45
 
booga"""
46
34
 
47
35
OUTPUT2 = """# Bazaar merge directive format 1
48
36
# revision_id: example:
54
42
#\x20
55
43
booga"""
56
44
 
57
 
OUTPUT2_2 = """# Bazaar merge directive format 2 (Bazaar 0.90)
58
 
# revision_id: example:
59
 
# target_branch: http://example.com
60
 
# testament_sha1: sha
61
 
# timestamp: 1970-01-01 00:09:33 +0002
62
 
# source_branch: http://example.org
63
 
# message: Hi mom!
64
 
# base_revision_id: null:
65
 
#\x20
66
 
# Begin patch
67
 
booga"""
68
45
 
69
46
INPUT1 = """
70
47
I was thinking today about creating a merge directive.
88
65
booga""".splitlines(True)
89
66
 
90
67
 
91
 
INPUT1_2 = """
92
 
I was thinking today about creating a merge directive.
93
 
 
94
 
So I did.
95
 
 
96
 
Here it is.
97
 
 
98
 
(I've pasted it in the body of this message)
99
 
 
100
 
Aaron
101
 
 
102
 
# Bazaar merge directive format 2 (Bazaar 0.90)\r
103
 
# revision_id: example:
104
 
# target_branch: http://example.com
105
 
# testament_sha1: sha
106
 
# timestamp: 1970-01-01 00:09:33 +0002
107
 
# source_branch: http://example.org
108
 
# base_revision_id: null:
109
 
# message: Hi mom!
110
 
#\x20
111
 
# Begin patch
112
 
booga""".splitlines(True)
113
 
 
114
 
 
115
 
INPUT1_2_OLD = """
116
 
I was thinking today about creating a merge directive.
117
 
 
118
 
So I did.
119
 
 
120
 
Here it is.
121
 
 
122
 
(I've pasted it in the body of this message)
123
 
 
124
 
Aaron
125
 
 
126
 
# Bazaar merge directive format 2 (Bazaar 0.19)\r
127
 
# revision_id: example:
128
 
# target_branch: http://example.com
129
 
# testament_sha1: sha
130
 
# timestamp: 1970-01-01 00:09:33 +0002
131
 
# source_branch: http://example.org
132
 
# base_revision_id: null:
133
 
# message: Hi mom!
134
 
#\x20
135
 
# Begin patch
136
 
booga""".splitlines(True)
137
 
 
138
 
 
139
 
OLD_DIRECTIVE_2 = """# Bazaar merge directive format 2 (Bazaar 0.19)
140
 
# revision_id: abentley@panoramicfeedback.com-20070807234458-\
141
 
#   nzhkoyza56lan7z5
142
 
# target_branch: http://panoramicfeedback.com/opensource/bzr/repo\
143
 
#   /bzr.ab
144
 
# testament_sha1: d825a5cdb267a90ec2ba86b00895f3d8a9bed6bf
145
 
# timestamp: 2007-08-10 16:15:02 -0400
146
 
# source_branch: http://panoramicfeedback.com/opensource/bzr/repo\
147
 
#   /bzr.ab
148
 
# base_revision_id: abentley@panoramicfeedback.com-20070731163346-\
149
 
#   623xwcycwij91xen
150
 
#
151
 
""".splitlines(True)
152
 
 
153
 
 
154
 
class TestMergeDirective(object):
 
68
class TestMergeDirective(tests.TestCase):
155
69
 
156
70
    def test_merge_source(self):
157
71
        time = 500000.0
158
72
        timezone = 5 * 3600
159
 
        self.assertRaises(errors.NoMergeSource, self.make_merge_directive,
 
73
        self.assertRaises(errors.NoMergeSource, merge_directive.MergeDirective,
160
74
            'example:', 'sha', time, timezone, 'http://example.com')
161
 
        self.assertRaises(errors.NoMergeSource, self.make_merge_directive,
 
75
        self.assertRaises(errors.NoMergeSource, merge_directive.MergeDirective,
162
76
            'example:', 'sha', time, timezone, 'http://example.com',
163
77
            patch_type='diff')
164
 
        self.make_merge_directive('example:', 'sha', time, timezone,
 
78
        merge_directive.MergeDirective('example:', 'sha', time, timezone,
165
79
            'http://example.com', source_branch='http://example.org')
166
 
        md = self.make_merge_directive('null:', 'sha', time, timezone,
 
80
        md = merge_directive.MergeDirective('null:', 'sha', time, timezone,
167
81
            'http://example.com', patch='blah', patch_type='bundle')
168
82
        self.assertIs(None, md.source_branch)
169
 
        md2 = self.make_merge_directive('null:', 'sha', time, timezone,
 
83
        md2 = merge_directive.MergeDirective('null:', 'sha', time, timezone,
170
84
            'http://example.com', patch='blah', patch_type='bundle',
171
85
            source_branch='bar')
172
86
        self.assertEqual('bar', md2.source_branch)
173
87
 
 
88
    def test_require_patch(self):
 
89
        time = 500.0
 
90
        timezone = 120
 
91
        self.assertRaises(errors.PatchMissing, merge_directive.MergeDirective,
 
92
            'example:', 'sha', time, timezone, 'http://example.com',
 
93
            patch_type='bundle')
 
94
        md = merge_directive.MergeDirective('example:', 'sha1', time, timezone,
 
95
            'http://example.com', source_branch="http://example.org",
 
96
            patch='', patch_type='diff')
 
97
        self.assertEqual(md.patch, '')
 
98
 
174
99
    def test_serialization(self):
175
100
        time = 453
176
101
        timezone = 120
177
 
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
102
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
178
103
            'http://example.com', patch='booga', patch_type='bundle')
179
 
        self.assertEqualDiff(self.OUTPUT1, ''.join(md.to_lines()))
180
 
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
104
        self.assertEqualDiff(OUTPUT1, ''.join(md.to_lines()))
 
105
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
181
106
            'http://example.com', source_branch="http://example.org",
182
107
            patch='booga', patch_type='diff', message="Hi mom!")
183
 
        self.assertEqualDiff(self.OUTPUT2, ''.join(md.to_lines()))
 
108
        self.assertEqualDiff(OUTPUT2, ''.join(md.to_lines()))
184
109
 
185
110
    def test_deserialize_junk(self):
186
111
        time = 501
192
117
                          merge_directive.MergeDirective.from_lines, [])
193
118
 
194
119
    def test_deserialize_leading_junk(self):
195
 
        md = merge_directive.MergeDirective.from_lines(self.INPUT1)
 
120
        md = merge_directive.MergeDirective.from_lines(INPUT1)
196
121
        self.assertEqual('example:', md.revision_id)
197
122
        self.assertEqual('sha', md.testament_sha1)
198
123
        self.assertEqual('http://example.com', md.target_branch)
206
131
    def test_roundtrip(self):
207
132
        time = 500000
208
133
        timezone = 7.5 * 3600
209
 
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
134
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
210
135
            'http://example.com', source_branch="http://example.org",
211
136
            patch='booga', patch_type='diff')
212
137
        md2 = merge_directive.MergeDirective.from_lines(md.to_lines())
220
145
        self.assertEqual('diff', md2.patch_type)
221
146
        self.assertEqual('booga', md2.patch)
222
147
        self.assertEqual(None, md2.message)
223
 
        self.set_bundle(md, "# Bazaar revision bundle v0.9\n#\n")
 
148
        md.patch = "# Bazaar revision bundle v0.9\n#\n"
224
149
        md.message = "Hi mom!"
225
 
        lines = md.to_lines()
226
 
        md3 = merge_directive.MergeDirective.from_lines(lines)
227
 
        self.assertEqual("# Bazaar revision bundle v0.9\n#\n", md3.bundle)
 
150
        md3 = merge_directive.MergeDirective.from_lines(md.to_lines())
 
151
        self.assertEqual("# Bazaar revision bundle v0.9\n#\n", md3.patch)
228
152
        self.assertEqual("bundle", md3.patch_type)
229
153
        self.assertContainsRe(md3.to_lines()[0],
230
154
            '^# Bazaar merge directive format ')
231
155
        self.assertEqual("Hi mom!", md3.message)
232
 
        md3.clear_payload()
233
 
        self.assertIs(None, md3.get_raw_bundle())
 
156
        md3.patch_type = None
 
157
        md3.patch = None
234
158
        md4 = merge_directive.MergeDirective.from_lines(md3.to_lines())
235
159
        self.assertIs(None, md4.patch_type)
236
160
 
237
161
 
238
 
class TestMergeDirective1(tests.TestCase, TestMergeDirective):
239
 
    """Test merge directive format 1"""
240
 
 
241
 
    INPUT1 = INPUT1
242
 
 
243
 
    OUTPUT1 = OUTPUT1
244
 
 
245
 
    OUTPUT2 = OUTPUT2
246
 
 
247
 
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
248
 
                 target_branch, patch=None, patch_type=None,
249
 
                 source_branch=None, message=None):
250
 
        return merge_directive.MergeDirective(revision_id, testament_sha1,
251
 
                 time, timezone, target_branch, patch, patch_type,
252
 
                 source_branch, message)
253
 
 
254
 
    @staticmethod
255
 
    def set_bundle(md, value):
256
 
        md.patch = value
257
 
 
258
 
    def test_require_patch(self):
259
 
        time = 500.0
260
 
        timezone = 120
261
 
        self.assertRaises(errors.PatchMissing, merge_directive.MergeDirective,
262
 
            'example:', 'sha', time, timezone, 'http://example.com',
263
 
            patch_type='bundle')
264
 
        md = merge_directive.MergeDirective('example:', 'sha1', time, timezone,
265
 
            'http://example.com', source_branch="http://example.org",
266
 
            patch='', patch_type='diff')
267
 
        self.assertEqual(md.patch, '')
268
 
 
269
 
 
270
 
class TestMergeDirective2(tests.TestCase, TestMergeDirective):
271
 
    """Test merge directive format 2"""
272
 
 
273
 
    INPUT1 = INPUT1_2
274
 
 
275
 
    OUTPUT1 = OUTPUT1_2
276
 
 
277
 
    OUTPUT2 = OUTPUT2_2
278
 
 
279
 
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
280
 
                 target_branch, patch=None, patch_type=None,
281
 
                 source_branch=None, message=None, base_revision_id='null:'):
282
 
        if patch_type == 'bundle':
283
 
            bundle = patch
284
 
            patch = None
285
 
        else:
286
 
            bundle = None
287
 
        return merge_directive.MergeDirective2(revision_id, testament_sha1,
288
 
            time, timezone, target_branch, patch, source_branch, message,
289
 
            bundle, base_revision_id)
290
 
 
291
 
    @staticmethod
292
 
    def set_bundle(md, value):
293
 
        md.bundle = value
294
 
 
295
 
 
296
 
EMAIL1 = """From: "J. Random Hacker" <jrandom@example.com>
297
 
Subject: Commit of rev2a
298
 
To: pqm@example.com
299
 
User-Agent: Bazaar \(.*\)
300
 
 
301
 
# Bazaar merge directive format 1
302
 
# revision_id: rev2a
303
 
# target_branch: (.|\n)*
304
 
# testament_sha1: .*
305
 
# timestamp: 1970-01-01 00:08:56 \\+0001
306
 
# source_branch: (.|\n)*
307
 
"""
308
 
 
309
 
 
310
 
EMAIL1_2 = """From: "J. Random Hacker" <jrandom@example.com>
311
 
Subject: Commit of rev2a
312
 
To: pqm@example.com
313
 
User-Agent: Bazaar \(.*\)
314
 
 
315
 
# Bazaar merge directive format 2 \\(Bazaar 0.90\\)
316
 
# revision_id: rev2a
317
 
# target_branch: (.|\n)*
318
 
# testament_sha1: .*
319
 
# timestamp: 1970-01-01 00:08:56 \\+0001
320
 
# source_branch: (.|\n)*
321
 
"""
322
 
 
323
 
 
324
 
EMAIL2 = """From: "J. Random Hacker" <jrandom@example.com>
325
 
Subject: Commit of rev2a with special message
326
 
To: pqm@example.com
327
 
User-Agent: Bazaar \(.*\)
328
 
 
329
 
# Bazaar merge directive format 1
330
 
# revision_id: rev2a
331
 
# target_branch: (.|\n)*
332
 
# testament_sha1: .*
333
 
# timestamp: 1970-01-01 00:08:56 \\+0001
334
 
# source_branch: (.|\n)*
335
 
# message: Commit of rev2a with special message
336
 
"""
337
 
 
338
 
EMAIL2_2 = """From: "J. Random Hacker" <jrandom@example.com>
339
 
Subject: Commit of rev2a with special message
340
 
To: pqm@example.com
341
 
User-Agent: Bazaar \(.*\)
342
 
 
343
 
# Bazaar merge directive format 2 \\(Bazaar 0.90\\)
344
 
# revision_id: rev2a
345
 
# target_branch: (.|\n)*
346
 
# testament_sha1: .*
347
 
# timestamp: 1970-01-01 00:08:56 \\+0001
348
 
# source_branch: (.|\n)*
349
 
# message: Commit of rev2a with special message
350
 
"""
351
 
 
352
 
class TestMergeDirectiveBranch(object):
 
162
EMAIL1 = """To: pqm@example.com
 
163
From: J. Random Hacker <jrandom@example.com>
 
164
Subject: Commit of rev2a
 
165
 
 
166
# Bazaar merge directive format 1
 
167
# revision_id: rev2a
 
168
# target_branch: (.|\n)*
 
169
# testament_sha1: .*
 
170
# timestamp: 1970-01-01 00:08:56 \\+0001
 
171
# source_branch: (.|\n)*
 
172
"""
 
173
 
 
174
 
 
175
EMAIL2 = """To: pqm@example.com
 
176
From: J. Random Hacker <jrandom@example.com>
 
177
Subject: Commit of rev2a with special message
 
178
 
 
179
# Bazaar merge directive format 1
 
180
# revision_id: rev2a
 
181
# target_branch: (.|\n)*
 
182
# testament_sha1: .*
 
183
# timestamp: 1970-01-01 00:08:56 \\+0001
 
184
# source_branch: (.|\n)*
 
185
# message: Commit of rev2a with special message
 
186
"""
 
187
 
 
188
 
 
189
class TestMergeDirectiveBranch(tests.TestCaseWithTransport):
353
190
 
354
191
    def make_trees(self):
355
192
        tree_a = self.make_branch_and_tree('tree_a')
356
193
        tree_a.branch.get_config().set_user_option('email',
357
194
            'J. Random Hacker <jrandom@example.com>')
358
 
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_b\n'),
359
 
                                  ('tree_a/file_2', 'content_x\rcontent_y\r')])
360
 
        tree_a.add(['file', 'file_2'])
 
195
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_b\n')])
 
196
        tree_a.add('file')
361
197
        tree_a.commit('message', rev_id='rev1')
362
198
        tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
363
199
        branch_c = tree_a.bzrdir.sprout('branch_c').open_branch()
364
200
        tree_b.commit('message', rev_id='rev2b')
365
 
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_c \n'),
366
 
                                  ('tree_a/file_2', 'content_x\rcontent_z\r')])
 
201
        self.build_tree_contents([('tree_a/file', 'content_a\ncontent_c\n')])
367
202
        tree_a.commit('Commit of rev2a', rev_id='rev2a')
368
203
        return tree_a, tree_b, branch_c
369
204
 
370
205
    def test_empty_target(self):
371
206
        tree_a, tree_b, branch_c = self.make_trees()
372
207
        tree_d = self.make_branch_and_tree('tree_d')
373
 
        md2 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
374
 
            tree_d.branch.base, patch_type='diff',
375
 
            public_branch=tree_a.branch.base)
376
 
 
377
 
    def test_disk_name(self):
378
 
        tree_a, tree_b, branch_c = self.make_trees()
379
 
        tree_a.branch.nick = 'fancy <name>'
380
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
381
 
            tree_b.branch.base)
382
 
        self.assertEqual('fancy-name-2', md.get_disk_name(tree_a.branch))
383
 
 
384
 
    def test_disk_name_old_revno(self):
385
 
        tree_a, tree_b, branch_c = self.make_trees()
386
 
        tree_a.branch.nick = 'fancy-name'
387
 
        md = self.from_objects(tree_a.branch.repository, 'rev1', 500, 120,
388
 
            tree_b.branch.base)
389
 
        self.assertEqual('fancy-name-1', md.get_disk_name(tree_a.branch))
 
208
        md2 = merge_directive.MergeDirective.from_objects(
 
209
            tree_a.branch.repository, 'rev2a', 500, 120, tree_d.branch.base,
 
210
            patch_type='diff', public_branch=tree_a.branch.base)
390
211
 
391
212
    def test_generate_patch(self):
392
213
        tree_a, tree_b, branch_c = self.make_trees()
393
 
        md2 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
394
 
            tree_b.branch.base, patch_type='diff',
395
 
            public_branch=tree_a.branch.base)
 
214
        md2 = merge_directive.MergeDirective.from_objects(
 
215
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
 
216
            patch_type='diff', public_branch=tree_a.branch.base)
396
217
        self.assertNotContainsRe(md2.patch, 'Bazaar revision bundle')
397
218
        self.assertContainsRe(md2.patch, '\\+content_c')
398
219
        self.assertNotContainsRe(md2.patch, '\\+\\+\\+ b/')
401
222
    def test_public_branch(self):
402
223
        tree_a, tree_b, branch_c = self.make_trees()
403
224
        self.assertRaises(errors.PublicBranchOutOfDate,
404
 
            self.from_objects, tree_a.branch.repository, 'rev2a', 500, 144,
405
 
            tree_b.branch.base, public_branch=branch_c.base, patch_type='diff')
406
 
        self.assertRaises(errors.PublicBranchOutOfDate,
407
 
            self.from_objects, tree_a.branch.repository, 'rev2a', 500, 144,
408
 
            tree_b.branch.base, public_branch=branch_c.base, patch_type=None)
 
225
            merge_directive.MergeDirective.from_objects,
 
226
            tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
 
227
            public_branch=branch_c.base, patch_type='diff')
409
228
        # public branch is not checked if patch format is bundle.
410
 
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
411
 
            tree_b.branch.base, public_branch=branch_c.base)
 
229
        md1 = merge_directive.MergeDirective.from_objects(
 
230
            tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
 
231
            public_branch=branch_c.base)
412
232
        # public branch is provided with a bundle, despite possibly being out
413
233
        # of date, because it's not required if a bundle is present.
414
234
        self.assertEqual(md1.source_branch, branch_c.base)
415
235
        # Once we update the public branch, we can generate a diff.
416
236
        branch_c.pull(tree_a.branch)
417
 
        md3 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
418
 
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base)
 
237
        md3 = merge_directive.MergeDirective.from_objects(
 
238
            tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
 
239
            patch_type=None, public_branch=branch_c.base)
419
240
 
420
241
    def test_use_public_submit_branch(self):
421
242
        tree_a, tree_b, branch_c = self.make_trees()
422
243
        branch_c.pull(tree_a.branch)
423
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 144,
424
 
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base)
 
244
        md = merge_directive.MergeDirective.from_objects(
 
245
             tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
 
246
             patch_type=None, public_branch=branch_c.base)
425
247
        self.assertEqual(md.target_branch, tree_b.branch.base)
426
248
        tree_b.branch.set_public_branch('http://example.com')
427
 
        md2 = self.from_objects(
 
249
        md2 = merge_directive.MergeDirective.from_objects(
428
250
              tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
429
251
              patch_type=None, public_branch=branch_c.base)
430
252
        self.assertEqual(md2.target_branch, 'http://example.com')
431
253
 
432
254
    def test_message(self):
433
255
        tree_a, tree_b, branch_c = self.make_trees()
434
 
        md3 = self.from_objects(tree_a.branch.repository, 'rev1', 500, 120,
435
 
            tree_b.branch.base, patch_type=None, public_branch=branch_c.base,
 
256
        md3 = merge_directive.MergeDirective.from_objects(
 
257
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
 
258
            patch_type=None, public_branch=branch_c.base,
436
259
            message='Merge message')
437
260
        md3.to_lines()
438
261
        self.assertIs(None, md3.patch)
440
263
 
441
264
    def test_generate_bundle(self):
442
265
        tree_a, tree_b, branch_c = self.make_trees()
443
 
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
444
 
            tree_b.branch.base, public_branch=branch_c.base)
445
 
 
446
 
        self.assertContainsRe(md1.get_raw_bundle(), 'Bazaar revision bundle')
 
266
        md1 = merge_directive.MergeDirective.from_objects(
 
267
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
 
268
            public_branch=branch_c.base)
 
269
        self.assertContainsRe(md1.patch, 'Bazaar revision bundle')
447
270
        self.assertContainsRe(md1.patch, '\\+content_c')
448
271
        self.assertNotContainsRe(md1.patch, '\\+content_a')
449
272
        self.assertContainsRe(md1.patch, '\\+content_c')
451
274
 
452
275
    def test_broken_bundle(self):
453
276
        tree_a, tree_b, branch_c = self.make_trees()
454
 
        md1 = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 120,
455
 
            tree_b.branch.base, public_branch=branch_c.base)
 
277
        md1 = merge_directive.MergeDirective.from_objects(
 
278
            tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
 
279
            public_branch=branch_c.base)
456
280
        lines = md1.to_lines()
457
281
        lines = [l.replace('\n', '\r\n') for l in lines]
458
282
        md2 = merge_directive.MergeDirective.from_lines(lines)
466
290
                return self
467
291
            def gpg_signing_command(self):
468
292
                return 'loopback'
469
 
        md = self.make_merge_directive('example:', 'sha', time, timezone,
 
293
        md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
470
294
            'http://example.com', source_branch="http://example.org",
471
295
            patch='booga', patch_type='diff')
472
296
        old_strategy = gpg.GPGStrategy
481
305
 
482
306
    def test_email(self):
483
307
        tree_a, tree_b, branch_c = self.make_trees()
484
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 476, 60,
485
 
            tree_b.branch.base, patch_type=None,
486
 
            public_branch=tree_a.branch.base)
 
308
        md = merge_directive.MergeDirective.from_objects(
 
309
            tree_a.branch.repository, 'rev2a', 476, 60, tree_b.branch.base,
 
310
            patch_type=None, public_branch=tree_a.branch.base)
487
311
        message = md.to_email('pqm@example.com', tree_a.branch)
488
 
        self.assertContainsRe(message.as_string(), self.EMAIL1)
 
312
        self.assertContainsRe(message.as_string(), EMAIL1)
489
313
        md.message = 'Commit of rev2a with special message'
490
314
        message = md.to_email('pqm@example.com', tree_a.branch)
491
 
        self.assertContainsRe(message.as_string(), self.EMAIL2)
 
315
        self.assertContainsRe(message.as_string(), EMAIL2)
492
316
 
493
317
    def test_install_revisions_branch(self):
494
318
        tree_a, tree_b, branch_c = self.make_trees()
495
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
496
 
            tree_b.branch.base, patch_type=None,
497
 
            public_branch=tree_a.branch.base)
 
319
        md = merge_directive.MergeDirective.from_objects(
 
320
            tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
 
321
            patch_type=None, public_branch=tree_a.branch.base)
498
322
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
499
323
        revision = md.install_revisions(tree_b.branch.repository)
500
324
        self.assertEqual('rev2a', revision)
501
325
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
502
326
 
503
 
    def test_get_merge_request(self):
504
 
        tree_a, tree_b, branch_c = self.make_trees()
505
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
506
 
            tree_b.branch.base, patch_type='bundle',
507
 
            public_branch=tree_a.branch.base)
508
 
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
509
 
        md.install_revisions(tree_b.branch.repository)
510
 
        base, revision, verified = md.get_merge_request(
511
 
            tree_b.branch.repository)
512
 
        if isinstance(md, merge_directive.MergeDirective):
513
 
            self.assertIs(None, base)
514
 
            self.assertEqual('inapplicable', verified)
515
 
        else:
516
 
            self.assertEqual('rev1', base)
517
 
            self.assertEqual('verified', verified)
518
 
        self.assertEqual('rev2a', revision)
519
 
        self.assertTrue(tree_b.branch.repository.has_revision('rev2a'))
520
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
521
 
            tree_b.branch.base, patch_type=None,
522
 
            public_branch=tree_a.branch.base)
523
 
        base, revision, verified = md.get_merge_request(
524
 
            tree_b.branch.repository)
525
 
        if isinstance(md, merge_directive.MergeDirective):
526
 
            self.assertIs(None, base)
527
 
            self.assertEqual('inapplicable', verified)
528
 
        else:
529
 
            self.assertEqual('rev1', base)
530
 
            self.assertEqual('inapplicable', verified)
531
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
532
 
            tree_b.branch.base, patch_type='diff',
533
 
            public_branch=tree_a.branch.base)
534
 
        base, revision, verified = md.get_merge_request(
535
 
            tree_b.branch.repository)
536
 
        if isinstance(md, merge_directive.MergeDirective):
537
 
            self.assertIs(None, base)
538
 
            self.assertEqual('inapplicable', verified)
539
 
        else:
540
 
            self.assertEqual('rev1', base)
541
 
            self.assertEqual('verified', verified)
542
 
        md.patch='asdf'
543
 
        base, revision, verified = md.get_merge_request(
544
 
            tree_b.branch.repository)
545
 
        if isinstance(md, merge_directive.MergeDirective):
546
 
            self.assertIs(None, base)
547
 
            self.assertEqual('inapplicable', verified)
548
 
        else:
549
 
            self.assertEqual('rev1', base)
550
 
            self.assertEqual('failed', verified)
551
 
 
552
327
    def test_install_revisions_bundle(self):
553
328
        tree_a, tree_b, branch_c = self.make_trees()
554
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 36,
555
 
            tree_b.branch.base, patch_type='bundle',
556
 
            public_branch=tree_a.branch.base)
 
329
        md = merge_directive.MergeDirective.from_objects(
 
330
            tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
 
331
            patch_type='bundle', public_branch=tree_a.branch.base)
557
332
        self.assertFalse(tree_b.branch.repository.has_revision('rev2a'))
558
333
        revision = md.install_revisions(tree_b.branch.repository)
559
334
        self.assertEqual('rev2a', revision)
562
337
    def test_get_target_revision_nofetch(self):
563
338
        tree_a, tree_b, branch_c = self.make_trees()
564
339
        tree_b.branch.fetch(tree_a.branch)
565
 
        md = self.from_objects( tree_a.branch.repository, 'rev2a', 500, 36,
566
 
            tree_b.branch.base, patch_type=None,
567
 
            public_branch=tree_a.branch.base)
 
340
        md = merge_directive.MergeDirective.from_objects(
 
341
            tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
 
342
            patch_type=None, public_branch=tree_a.branch.base)
568
343
        md.source_branch = '/dev/null'
569
344
        revision = md.install_revisions(tree_b.branch.repository)
570
345
        self.assertEqual('rev2a', revision)
571
 
 
572
 
    def test_use_submit_for_missing_dependency(self):
573
 
        tree_a, tree_b, branch_c = self.make_trees()
574
 
        branch_c.pull(tree_a.branch)
575
 
        self.build_tree_contents([('tree_a/file', 'content_q\ncontent_r\n')])
576
 
        tree_a.commit('rev3a', rev_id='rev3a')
577
 
        md = self.from_objects(tree_a.branch.repository, 'rev3a', 500, 36,
578
 
            branch_c.base, base_revision_id='rev2a')
579
 
        revision = md.install_revisions(tree_b.branch.repository)
580
 
 
581
 
    def test_handle_target_not_a_branch(self):
582
 
        tree_a, tree_b, branch_c = self.make_trees()
583
 
        branch_c.pull(tree_a.branch)
584
 
        self.build_tree_contents([('tree_a/file', 'content_q\ncontent_r\n')])
585
 
        tree_a.commit('rev3a', rev_id='rev3a')
586
 
        md = self.from_objects(tree_a.branch.repository, 'rev3a', 500, 36,
587
 
            branch_c.base, base_revision_id='rev2a')
588
 
        md.target_branch = self.get_url('not-a-branch')
589
 
        self.assertRaises(errors.TargetNotBranch, md.install_revisions,
590
 
                tree_b.branch.repository)
591
 
 
592
 
 
593
 
class TestMergeDirective1Branch(tests.TestCaseWithTransport,
594
 
    TestMergeDirectiveBranch):
595
 
    """Test merge directive format 1 with a branch"""
596
 
 
597
 
    EMAIL1 = EMAIL1
598
 
 
599
 
    EMAIL2 = EMAIL2
600
 
 
601
 
    def from_objects(self, repository, revision_id, time, timezone,
602
 
        target_branch, patch_type='bundle', local_target_branch=None,
603
 
        public_branch=None, message=None, base_revision_id=None):
604
 
        if base_revision_id is not None:
605
 
            raise tests.TestNotApplicable('This format does not support'
606
 
                                          ' explicit bases.')
607
 
        repository.lock_write()
608
 
        try:
609
 
            return merge_directive.MergeDirective.from_objects( repository,
610
 
                revision_id, time, timezone, target_branch, patch_type,
611
 
                local_target_branch, public_branch, message)
612
 
        finally:
613
 
            repository.unlock()
614
 
 
615
 
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
616
 
                 target_branch, patch=None, patch_type=None,
617
 
                 source_branch=None, message=None):
618
 
        return merge_directive.MergeDirective(revision_id, testament_sha1,
619
 
                 time, timezone, target_branch, patch, patch_type,
620
 
                 source_branch, message)
621
 
 
622
 
 
623
 
class TestMergeDirective2Branch(tests.TestCaseWithTransport,
624
 
    TestMergeDirectiveBranch):
625
 
    """Test merge directive format 2 with a branch"""
626
 
 
627
 
    EMAIL1 = EMAIL1_2
628
 
 
629
 
    EMAIL2 = EMAIL2_2
630
 
 
631
 
    def from_objects(self, repository, revision_id, time, timezone,
632
 
        target_branch, patch_type='bundle', local_target_branch=None,
633
 
        public_branch=None, message=None, base_revision_id=None):
634
 
        include_patch = (patch_type in ('bundle', 'diff'))
635
 
        include_bundle = (patch_type == 'bundle')
636
 
        self.assertTrue(patch_type in ('bundle', 'diff', None))
637
 
        return merge_directive.MergeDirective2.from_objects(
638
 
            repository, revision_id, time, timezone, target_branch,
639
 
            include_patch, include_bundle, local_target_branch, public_branch,
640
 
            message, base_revision_id)
641
 
 
642
 
    def make_merge_directive(self, revision_id, testament_sha1, time, timezone,
643
 
                 target_branch, patch=None, patch_type=None,
644
 
                 source_branch=None, message=None, base_revision_id='null:'):
645
 
        if patch_type == 'bundle':
646
 
            bundle = patch
647
 
            patch = None
648
 
        else:
649
 
            bundle = None
650
 
        return merge_directive.MergeDirective2(revision_id, testament_sha1,
651
 
            time, timezone, target_branch, patch, source_branch, message,
652
 
            bundle, base_revision_id)
653
 
 
654
 
    def test_base_revision(self):
655
 
        tree_a, tree_b, branch_c = self.make_trees()
656
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
657
 
            tree_b.branch.base, patch_type='bundle',
658
 
            public_branch=tree_a.branch.base, base_revision_id=None)
659
 
        self.assertEqual('rev1', md.base_revision_id)
660
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
661
 
            tree_b.branch.base, patch_type='bundle',
662
 
            public_branch=tree_a.branch.base, base_revision_id='null:')
663
 
        self.assertEqual('null:', md.base_revision_id)
664
 
        lines = md.to_lines()
665
 
        md2 = merge_directive.MergeDirective.from_lines(lines)
666
 
        self.assertEqual(md2.base_revision_id, md.base_revision_id)
667
 
 
668
 
    def test_patch_verification(self):
669
 
        tree_a, tree_b, branch_c = self.make_trees()
670
 
        md = self.from_objects(tree_a.branch.repository, 'rev2a', 500, 60,
671
 
            tree_b.branch.base, patch_type='bundle',
672
 
            public_branch=tree_a.branch.base)
673
 
        lines = md.to_lines()
674
 
        md2 = merge_directive.MergeDirective.from_lines(lines)
675
 
        md2._verify_patch(tree_a.branch.repository)
676
 
        # Strip trailing whitespace
677
 
        md2.patch = md2.patch.replace(' \n', '\n')
678
 
        md2._verify_patch(tree_a.branch.repository)
679
 
        # Convert to Mac line-endings
680
 
        md2.patch = re.sub('(\r\n|\r|\n)', '\r', md2.patch)
681
 
        self.assertTrue(md2._verify_patch(tree_a.branch.repository))
682
 
        # Convert to DOS line-endings
683
 
        md2.patch = re.sub('(\r\n|\r|\n)', '\r\n', md2.patch)
684
 
        self.assertTrue(md2._verify_patch(tree_a.branch.repository))
685
 
        md2.patch = md2.patch.replace('content_c', 'content_d')
686
 
        self.assertFalse(md2._verify_patch(tree_a.branch.repository))
687
 
 
688
 
 
689
 
class TestParseOldMergeDirective2(tests.TestCase):
690
 
 
691
 
    def test_parse_old_merge_directive(self):
692
 
        md = merge_directive.MergeDirective.from_lines(INPUT1_2_OLD)
693
 
        self.assertEqual('example:', md.revision_id)
694
 
        self.assertEqual('sha', md.testament_sha1)
695
 
        self.assertEqual('http://example.com', md.target_branch)
696
 
        self.assertEqual('http://example.org', md.source_branch)
697
 
        self.assertEqual(453, md.time)
698
 
        self.assertEqual(120, md.timezone)
699
 
        self.assertEqual('booga', md.patch)
700
 
        self.assertEqual('diff', md.patch_type)
701
 
        self.assertEqual('Hi mom!', md.message)
702
 
 
703
 
 
704
 
class TestHook(object):
705
 
    """Hook callback for test purposes."""
706
 
 
707
 
    def __init__(self, result=None):
708
 
        self.calls = []
709
 
        self.result = result
710
 
 
711
 
    def __call__(self, params):
712
 
        self.calls.append(params)
713
 
        return self.result
714
 
 
715
 
 
716
 
class HookMailClient(mail_client.MailClient):
717
 
    """Mail client for testing hooks."""
718
 
 
719
 
    def __init__(self, config):
720
 
        self.body = None
721
 
        self.config = config
722
 
 
723
 
    def compose(self, prompt, to, subject, attachment, mime_subtype,
724
 
                extension, basename=None, body=None):
725
 
        self.body = body
726
 
 
727
 
 
728
 
class TestBodyHook(tests.TestCaseWithTransport):
729
 
 
730
 
    def compose_with_hooks(self, test_hooks, supports_body=True):
731
 
        client = HookMailClient({})
732
 
        client.supports_body = supports_body
733
 
        for test_hook in test_hooks:
734
 
            merge_directive.MergeDirective.hooks.install_named_hook(
735
 
                'merge_request_body', test_hook, 'test')
736
 
        tree = self.make_branch_and_tree('foo')
737
 
        tree.commit('foo')
738
 
        directive = merge_directive.MergeDirective2(
739
 
            tree.branch.last_revision(), 'sha', 0, 0, 'sha',
740
 
            source_branch=tree.branch.base,
741
 
            base_revision_id=tree.branch.last_revision(),
742
 
            message='This code rox')
743
 
        directive.compose_merge_request(client, 'jrandom@example.com',
744
 
            None, tree.branch)
745
 
        return client, directive
746
 
 
747
 
    def test_no_supports_body(self):
748
 
        test_hook = TestHook('foo')
749
 
        old_warn = trace.warning
750
 
        warnings = []
751
 
        def warn(*args):
752
 
            warnings.append(args)
753
 
        trace.warning = warn
754
 
        try:
755
 
            client, directive = self.compose_with_hooks([test_hook],
756
 
                supports_body=False)
757
 
        finally:
758
 
            trace.warning = old_warn
759
 
        self.assertEqual(0, len(test_hook.calls))
760
 
        self.assertEqual(('Cannot run merge_request_body hooks because mail'
761
 
                          ' client %s does not support message bodies.',
762
 
                          'HookMailClient'), warnings[0])
763
 
 
764
 
    def test_body_hook(self):
765
 
        test_hook = TestHook('foo')
766
 
        client, directive = self.compose_with_hooks([test_hook])
767
 
        self.assertEqual(1, len(test_hook.calls))
768
 
        self.assertEqual('foo', client.body)
769
 
        params = test_hook.calls[0]
770
 
        self.assertIsInstance(params,
771
 
                              merge_directive.MergeRequestBodyParams)
772
 
        self.assertIs(None, params.body)
773
 
        self.assertIs(None, params.orig_body)
774
 
        self.assertEqual('jrandom@example.com', params.to)
775
 
        self.assertEqual('[MERGE] This code rox', params.subject)
776
 
        self.assertEqual(directive, params.directive)
777
 
        self.assertEqual('foo-1', params.basename)
778
 
 
779
 
    def test_body_hook_chaining(self):
780
 
        test_hook1 = TestHook('foo')
781
 
        test_hook2 = TestHook('bar')
782
 
        client = self.compose_with_hooks([test_hook1, test_hook2])[0]
783
 
        self.assertEqual(None, test_hook1.calls[0].body)
784
 
        self.assertEqual(None, test_hook1.calls[0].orig_body)
785
 
        self.assertEqual('foo', test_hook2.calls[0].body)
786
 
        self.assertEqual(None, test_hook2.calls[0].orig_body)
787
 
        self.assertEqual('bar', client.body)