~bzr-pqm/bzr/bzr.dev

2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005 Canonical Ltd
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
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
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
17
1570.1.6 by Robert Collins
Update fast topological_sort to be a function and to have the topo_sort tests run against it.
18
"""Tests for topological sort."""
19
20
1185.31.25 by John Arbash Meinel
Renamed all of the tests from selftest/foo.py to tests/test_foo.py
21
from bzrlib.tests import TestCase
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
22
from bzrlib.tsort import topo_sort, TopoSorter, MergeSorter, merge_sort
1185.16.114 by mbp at sourcefrog
Improved topological sort
23
from bzrlib.errors import GraphCycleError
3236.2.1 by Michael Hudson
test and fix
24
from bzrlib.revision import NULL_REVISION
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
25
1570.1.6 by Robert Collins
Update fast topological_sort to be a function and to have the topo_sort tests run against it.
26
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
27
class TopoSortTests(TestCase):
28
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
29
    def assertSortAndIterate(self, graph, result_list):
30
        """Check that sorting and iter_topo_order on graph works."""
31
        self.assertEquals(result_list, topo_sort(graph))
32
        self.assertEqual(result_list,
33
                         list(TopoSorter(graph).iter_topo_order()))
34
35
    def assertSortAndIterateRaise(self, exception_type, graph):
36
        """Try both iterating and topo_sorting graph and expect an exception."""
37
        self.assertRaises(exception_type, topo_sort, graph)
38
        self.assertRaises(exception_type,
39
                          list,
40
                          TopoSorter(graph).iter_topo_order())
41
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
42
    def test_tsort_empty(self):
43
        """TopoSort empty list"""
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
44
        self.assertSortAndIterate([], [])
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
45
46
    def test_tsort_easy(self):
1185.16.114 by mbp at sourcefrog
Improved topological sort
47
        """TopoSort list with one node"""
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
48
        self.assertSortAndIterate({0: []}.items(), [0])
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
49
50
    def test_tsort_cycle(self):
1185.16.114 by mbp at sourcefrog
Improved topological sort
51
        """TopoSort traps graph with cycles"""
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
52
        self.assertSortAndIterateRaise(GraphCycleError,
53
                                       {0: [1], 
54
                                        1: [0]}.items())
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
55
1185.16.114 by mbp at sourcefrog
Improved topological sort
56
    def test_tsort_cycle_2(self):
57
        """TopoSort traps graph with longer cycle"""
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
58
        self.assertSortAndIterateRaise(GraphCycleError,
59
                                       {0: [1], 
60
                                        1: [2], 
61
                                        2: [0]}.items())
1185.16.114 by mbp at sourcefrog
Improved topological sort
62
                 
1185.16.113 by mbp at sourcefrog
Add topo_sort utility function
63
    def test_tsort_1(self):
64
        """TopoSort simple nontrivial graph"""
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
65
        self.assertSortAndIterate({0: [3], 
66
                                   1: [4],
67
                                   2: [1, 4],
68
                                   3: [], 
69
                                   4: [0, 3]}.items(),
70
                                  [3, 0, 4, 1, 2])
1185.16.115 by mbp at sourcefrog
Another topo_sort test
71
72
    def test_tsort_partial(self):
73
        """Topological sort with partial ordering.
74
75
        If the graph does not give an order between two nodes, they are 
76
        returned in lexicographical order.
77
        """
1570.1.7 by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets.
78
        self.assertSortAndIterate(([(0, []),
79
                                   (1, [0]),
80
                                   (2, [0]),
81
                                   (3, [0]),
82
                                   (4, [1, 2, 3]),
83
                                   (5, [1, 2]),
84
                                   (6, [1, 2]),
85
                                   (7, [2, 3]),
86
                                   (8, [0, 1, 4, 5, 6])]),
87
                                  [0, 1, 2, 3, 4, 5, 6, 7, 8])
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
88
2490.2.31 by Aaron Bentley
Fix iter_topo_order to permit un-included parents
89
    def test_tsort_unincluded_parent(self):
90
        """Sort nodes, but don't include some parents in the output"""
91
        self.assertSortAndIterate([(0, [1]),
92
                                   (1, [2])],
93
                                   [1, 0])
94
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
95
96
class MergeSortTests(TestCase):
97
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
98
    def assertSortAndIterate(self, graph, branch_tip, result_list,
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
99
            generate_revno, mainline_revisions=None):
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
100
        """Check that merge based sorting and iter_topo_order on graph works."""
3613.1.1 by John Arbash Meinel
Fix the merge_sort code so that it properly increments.
101
        value = merge_sort(graph, branch_tip,
102
                           mainline_revisions=mainline_revisions,
103
                           generate_revno=generate_revno)
104
        if result_list != value:
105
            import pprint
106
            self.assertEqualDiff(pprint.pformat(result_list),
107
                                 pprint.pformat(value))
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
108
        self.assertEquals(result_list,
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
109
            merge_sort(graph, branch_tip, mainline_revisions=mainline_revisions,
110
                generate_revno=generate_revno))
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
111
        self.assertEqual(result_list,
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
112
            list(MergeSorter(
113
                graph,
114
                branch_tip,
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
115
                mainline_revisions=mainline_revisions,
116
                generate_revno=generate_revno,
117
                ).iter_topo_order()))
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
118
119
    def test_merge_sort_empty(self):
120
        # sorting of an emptygraph does not error
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
121
        self.assertSortAndIterate({}, None, [], False)
122
        self.assertSortAndIterate({}, None, [], True)
3236.2.1 by Michael Hudson
test and fix
123
        self.assertSortAndIterate({}, NULL_REVISION, [], False)
124
        self.assertSortAndIterate({}, NULL_REVISION, [], True)
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
125
126
    def test_merge_sort_not_empty_no_tip(self):
127
        # merge sorting of a branch starting with None should result
128
        # in an empty list: no revisions are dragged in.
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
129
        self.assertSortAndIterate({0: []}.items(), None, [], False)
130
        self.assertSortAndIterate({0: []}.items(), None, [], True)
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
131
132
    def test_merge_sort_one_revision(self):
133
        # sorting with one revision as the tip returns the correct fields:
134
        # sequence - 0, revision id, merge depth - 0, end_of_merge
135
        self.assertSortAndIterate({'id': []}.items(),
136
                                  'id',
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
137
                                  [(0, 'id', 0, True)],
138
                                  False)
139
        self.assertSortAndIterate({'id': []}.items(),
140
                                  'id',
141
                                  [(0, 'id', 0, (1,), True)],
142
                                  True)
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
143
    
144
    def test_sequence_numbers_increase_no_merges(self):
145
        # emit a few revisions with no merges to check the sequence
146
        # numbering works in trivial cases
147
        self.assertSortAndIterate(
148
            {'A': [],
149
             'B': ['A'],
150
             'C': ['B']}.items(),
151
            'C',
152
            [(0, 'C', 0, False),
153
             (1, 'B', 0, False),
154
             (2, 'A', 0, True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
155
             ],
156
            False
157
            )
158
        self.assertSortAndIterate(
159
            {'A': [],
160
             'B': ['A'],
161
             'C': ['B']}.items(),
162
            'C',
163
            [(0, 'C', 0, (3,), False),
164
             (1, 'B', 0, (2,), False),
165
             (2, 'A', 0, (1,), True),
166
             ],
167
            True
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
168
            )
169
170
    def test_sequence_numbers_increase_with_merges(self):
171
        # test that sequence numbers increase across merges
172
        self.assertSortAndIterate(
173
            {'A': [],
174
             'B': ['A'],
175
             'C': ['A', 'B']}.items(),
176
            'C',
177
            [(0, 'C', 0, False),
178
             (1, 'B', 1, True),
179
             (2, 'A', 0, True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
180
             ],
181
            False
182
            )
183
        self.assertSortAndIterate(
184
            {'A': [],
185
             'B': ['A'],
186
             'C': ['A', 'B']}.items(),
187
            'C',
188
            [(0, 'C', 0, (2,), False),
189
             (1, 'B', 1, (1,1,1), True),
190
             (2, 'A', 0, (1,), True),
191
             ],
192
            True
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
193
            )
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
194
195
    def test_merge_sort_race(self):
196
        # A
197
        # |
198
        # B-.
199
        # |\ \
200
        # | | C
201
        # | |/
202
        # | D
203
        # |/
204
        # F
205
        graph = {'A': [],
206
                 'B': ['A'],
207
                 'C': ['B'],
208
                 'D': ['B', 'C'],
209
                 'F': ['B', 'D'],
210
                 }
211
        self.assertSortAndIterate(graph, 'F',
212
            [(0, 'F', 0, (3,), False),
213
             (1, 'D', 1, (2,2,1), False),
3170.3.8 by John Arbash Meinel
Finish the rest of the review feedback.
214
             (2, 'C', 1, (2,1,1), True), # XXX: Shouldn't it be merge_depth=2?
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
215
             (3, 'B', 0, (2,), False),
216
             (4, 'A', 0, (1,), True),
217
             ], True)
218
        # A
219
        # |
220
        # B-.
221
        # |\ \
222
        # | X C
223
        # | |/
224
        # | D
225
        # |/
226
        # F
227
        graph = {'A': [],
228
                 'B': ['A'],
229
                 'C': ['B'],
230
                 'X': ['B'],
231
                 'D': ['X', 'C'],
232
                 'F': ['B', 'D'],
233
                 }
234
        self.assertSortAndIterate(graph, 'F',
235
            [(0, 'F', 0, (3,), False),
236
             (1, 'D', 1, (2,1,2), False),
237
             (2, 'C', 2, (2,2,1), True),
238
             (3, 'X', 1, (2,1,1), True),
239
             (4, 'B', 0, (2,), False),
240
             (5, 'A', 0, (1,), True),
241
             ], True)
242
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
243
    def test_merge_depth_with_nested_merges(self):
244
        # the merge depth marker should reflect the depth of the revision
245
        # in terms of merges out from the mainline
246
        # revid, depth, parents:
247
        #  A 0   [D, B]   
248
        #  B  1  [C, F]   
249
        #  C  1  [H] 
250
        #  D 0   [H, E]
251
        #  E  1  [G, F]
252
        #  F   2 [G]
253
        #  G  1  [H]
254
        #  H 0
255
        self.assertSortAndIterate(
256
            {'A': ['D', 'B'],
257
             'B': ['C', 'F'],
258
             'C': ['H'],
259
             'D': ['H', 'E'],
260
             'E': ['G', 'F'],
261
             'F': ['G'],
262
             'G': ['H'],
263
             'H': []
264
             }.items(),
265
            'A',
266
            [(0, 'A', 0, False),
267
             (1, 'B', 1, False),
268
             (2, 'C', 1, True),
269
             (3, 'D', 0, False),
270
             (4, 'E', 1, False),
271
             (5, 'F', 2, True),
272
             (6, 'G', 1, True),
273
             (7, 'H', 0, True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
274
             ],
275
            False
276
            )
277
        self.assertSortAndIterate(
278
            {'A': ['D', 'B'],
279
             'B': ['C', 'F'],
280
             'C': ['H'],
281
             'D': ['H', 'E'],
282
             'E': ['G', 'F'],
283
             'F': ['G'],
284
             'G': ['H'],
285
             'H': []
286
             }.items(),
287
            'A',
288
            [(0, 'A', 0, (3,),  False),
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
289
             (1, 'B', 1, (1,3,2), False),
290
             (2, 'C', 1, (1,3,1), True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
291
             (3, 'D', 0, (2,), False),
292
             (4, 'E', 1, (1,1,2), False),
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
293
             (5, 'F', 2, (1,2,1), True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
294
             (6, 'G', 1, (1,1,1), True),
295
             (7, 'H', 0, (1,), True),
296
             ],
297
            True
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
298
            )
3170.3.1 by John Arbash Meinel
Write up a simple test that is getting ready to fix up deeply nested dotted revnos.
299
300
    def test_dotted_revnos_with_simple_merges(self):
301
        # A         1
302
        # |\
303
        # B C       2, 1.1.1
304
        # | |\
305
        # D E F     3, 1.1.2, 1.2.1
306
        # |/ /|
307
        # G H I     4, 1.2.2, 1.3.1
308
        # |/ /
309
        # J K       5, 1.3.2
310
        # |/
311
        # L         6
312
        self.assertSortAndIterate(
313
            {'A': [],
314
             'B': ['A'],
315
             'C': ['A'],
316
             'D': ['B'],
317
             'E': ['C'],
318
             'F': ['C'],
319
             'G': ['D', 'E'],
320
             'H': ['F'],
321
             'I': ['F'],
322
             'J': ['G', 'H'],
323
             'K': ['I'],
324
             'L': ['J', 'K'],
325
            }.items(),
326
            'L',
327
            [(0, 'L', 0, (6,), False),
3170.3.2 by John Arbash Meinel
Implement the new dotted revision numbering.
328
             (1, 'K', 1, (1,3,2), False),
329
             (2, 'I', 1, (1,3,1), True),
3170.3.1 by John Arbash Meinel
Write up a simple test that is getting ready to fix up deeply nested dotted revnos.
330
             (3, 'J', 0, (5,), False),
3170.3.2 by John Arbash Meinel
Implement the new dotted revision numbering.
331
             (4, 'H', 1, (1,2,2), False),
332
             (5, 'F', 1, (1,2,1), True),
3170.3.1 by John Arbash Meinel
Write up a simple test that is getting ready to fix up deeply nested dotted revnos.
333
             (6, 'G', 0, (4,), False),
334
             (7, 'E', 1, (1,1,2), False),
335
             (8, 'C', 1, (1,1,1), True),
336
             (9, 'D', 0, (3,), False),
337
             (10, 'B', 0, (2,), False),
338
             (11, 'A', 0, (1,),  True),
339
             ],
340
            True
341
            )
342
        # Adding a shortcut from the first revision should not change any of
343
        # the existing numbers
344
        self.assertSortAndIterate(
345
            {'A': [],
346
             'B': ['A'],
347
             'C': ['A'],
348
             'D': ['B'],
349
             'E': ['C'],
350
             'F': ['C'],
351
             'G': ['D', 'E'],
352
             'H': ['F'],
353
             'I': ['F'],
354
             'J': ['G', 'H'],
355
             'K': ['I'],
356
             'L': ['J', 'K'],
357
             'M': ['A'],
358
             'N': ['L', 'M'],
359
            }.items(),
360
            'N',
361
            [(0, 'N', 0, (7,), False),
3170.3.2 by John Arbash Meinel
Implement the new dotted revision numbering.
362
             (1, 'M', 1, (1,4,1), True),
3170.3.1 by John Arbash Meinel
Write up a simple test that is getting ready to fix up deeply nested dotted revnos.
363
             (2, 'L', 0, (6,), False),
3170.3.2 by John Arbash Meinel
Implement the new dotted revision numbering.
364
             (3, 'K', 1, (1,3,2), False),
365
             (4, 'I', 1, (1,3,1), True),
3170.3.1 by John Arbash Meinel
Write up a simple test that is getting ready to fix up deeply nested dotted revnos.
366
             (5, 'J', 0, (5,), False),
3170.3.2 by John Arbash Meinel
Implement the new dotted revision numbering.
367
             (6, 'H', 1, (1,2,2), False),
368
             (7, 'F', 1, (1,2,1), True),
3170.3.1 by John Arbash Meinel
Write up a simple test that is getting ready to fix up deeply nested dotted revnos.
369
             (8, 'G', 0, (4,), False),
370
             (9, 'E', 1, (1,1,2), False),
371
             (10, 'C', 1, (1,1,1), True),
372
             (11, 'D', 0, (3,), False),
373
             (12, 'B', 0, (2,), False),
374
             (13, 'A', 0, (1,),  True),
375
             ],
376
            True
377
            )
378
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
379
    def test_end_of_merge_not_last_revision_in_branch(self):
380
        # within a branch only the last revision gets an
381
        # end of merge marker.
382
        self.assertSortAndIterate(
383
            {'A': ['B'],
384
             'B': [],
385
             },
386
            'A',
387
            [(0, 'A', 0, False),
388
             (1, 'B', 0, True)
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
389
             ],
390
            False
391
            )
392
        self.assertSortAndIterate(
393
            {'A': ['B'],
394
             'B': [],
395
             },
396
            'A',
397
            [(0, 'A', 0, (2,), False),
398
             (1, 'B', 0, (1,), True)
399
             ],
400
            True
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
401
            )
402
403
    def test_end_of_merge_multiple_revisions_merged_at_once(self):
404
        # when multiple branches are merged at once, both of their
405
        # branch-endpoints should be listed as end-of-merge.
406
        # Also, the order of the multiple merges should be 
407
        # left-right shown top to bottom.
408
        # * means end of merge
409
        # A 0    [H, B, E] 
410
        # B  1   [D, C]
411
        # C   2  [D]       *
412
        # D  1   [H]       *
413
        # E  1   [G, F]
414
        # F   2  [G]       *
415
        # G  1   [H]       *
416
        # H 0    []        *
417
        self.assertSortAndIterate(
418
            {'A': ['H', 'B', 'E'],
419
             'B': ['D', 'C'],
420
             'C': ['D'],
421
             'D': ['H'],
422
             'E': ['G', 'F'],
423
             'F': ['G'],
424
             'G': ['H'],
425
             'H': [],
426
             },
427
            'A',
428
            [(0, 'A', 0, False),
429
             (1, 'B', 1, False),
430
             (2, 'C', 2, True),
431
             (3, 'D', 1, True),
432
             (4, 'E', 1, False),
433
             (5, 'F', 2, True),
434
             (6, 'G', 1, True),
435
             (7, 'H', 0, True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
436
             ],
437
            False
438
            )
439
        self.assertSortAndIterate(
440
            {'A': ['H', 'B', 'E'],
441
             'B': ['D', 'C'],
442
             'C': ['D'],
443
             'D': ['H'],
444
             'E': ['G', 'F'],
445
             'F': ['G'],
446
             'G': ['H'],
447
             'H': [],
448
             },
449
            'A',
450
            [(0, 'A', 0, (2,), False),
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
451
             (1, 'B', 1, (1,3,2), False),
452
             (2, 'C', 2, (1,4,1), True),
453
             (3, 'D', 1, (1,3,1), True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
454
             (4, 'E', 1, (1,1,2), False),
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
455
             (5, 'F', 2, (1,2,1), True),
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
456
             (6, 'G', 1, (1,1,1), True),
457
             (7, 'H', 0, (1,), True),
458
             ],
459
            True
1624.1.2 by Robert Collins
Add MergeSort facility to bzrlib.tsort.
460
            )
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
461
462
    def test_mainline_revs_partial(self):
463
        # when a mainline_revisions list is passed this must
464
        # override the graphs idea of mainline, and must also
465
        # truncate the output to the specified range, if needed.
466
        # so we test both at once: a mainline_revisions list that
467
        # disagrees with the graph about which revs are 'mainline'
468
        # and also truncates the output.
469
        # graph:
470
        # A 0 [E, B]
471
        # B 1 [D, C]
472
        # C 2 [D]
473
        # D 1 [E]
474
        # E 0
475
        # with a mainline of NONE,E,A (the inferred one) this will show the merge
476
        # depths above.
477
        # with a overriden mainline of NONE,E,D,B,A it should show:
478
        # A 0
479
        # B 0
480
        # C 1
481
        # D 0
482
        # E 0
483
        # and thus when truncated to D,B,A it should show
484
        # A 0
485
        # B 0
486
        # C 1 
487
        # because C is brought in by B in this view and D
488
        # is the terminating revision id
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
489
        # this should also preserve revision numbers: C should still be 2.1.1
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
490
        self.assertSortAndIterate(
491
            {'A': ['E', 'B'],
492
             'B': ['D', 'C'],
493
             'C': ['D'],
494
             'D': ['E'],
495
             'E': []
496
             },
497
            'A',
498
            [(0, 'A', 0, False),
499
             (1, 'B', 0, False),
500
             (2, 'C', 1, True),
501
             ],
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
502
            False,
503
            mainline_revisions=['D', 'B', 'A']
504
            )
505
        self.assertSortAndIterate(
506
            {'A': ['E', 'B'],
507
             'B': ['D', 'C'],
508
             'C': ['D'],
509
             'D': ['E'],
510
             'E': []
511
             },
512
            'A',
513
            [(0, 'A', 0, (4,), False),
514
             (1, 'B', 0, (3,), False),
515
             (2, 'C', 1, (2,1,1), True),
516
             ],
517
            True,
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
518
            mainline_revisions=['D', 'B', 'A']
519
            )
520
521
    def test_mainline_revs_with_none(self):
522
        # a simple test to ensure that a mainline_revs
523
        # list which goes all the way to None works
524
        self.assertSortAndIterate(
525
            {'A': [],
526
             },
527
            'A',
528
            [(0, 'A', 0, True),
529
             ],
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
530
            False,
531
            mainline_revisions=[None, 'A']
532
            )
533
        self.assertSortAndIterate(
534
            {'A': [],
535
             },
536
            'A',
537
            [(0, 'A', 0, (1,), True),
538
             ],
539
            True,
1624.1.3 by Robert Collins
Convert log to use the new tsort.merge_sort routine.
540
            mainline_revisions=[None, 'A']
541
            )
542
3533.2.1 by John Arbash Meinel
(bug #243536) tsort.merge_sorted() should work even with a ghost in mainline.
543
    def test_mainline_revs_with_ghost(self):
544
        # We have a mainline, but the end of it is actually a ghost
545
        # The graph that is passed to tsort has had ghosts filtered out, but
546
        # the mainline history has not.
547
        self.assertSortAndIterate(
548
            {'B':[],
549
             'C':['B']}.items(),
550
            'C',
551
            [(0, 'C', 0, (2,), False),
552
             (1, 'B', 0, (1,), True),
553
             ],
554
             True, mainline_revisions=['A', 'B', 'C'])
555
1988.4.1 by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter
556
    def test_parallel_root_sequence_numbers_increase_with_merges(self):
557
        """When there are parallel roots, check their revnos."""
558
        self.assertSortAndIterate(
559
            {'A': [],
560
             'B': [],
561
             'C': ['A', 'B']}.items(),
562
            'C',
563
            [(0, 'C', 0, (2,), False),
564
             (1, 'B', 1, (0,1,1), True),
565
             (2, 'A', 0, (1,), True),
566
             ],
567
            True
568
            )
569
        
570
    def test_revnos_are_globally_assigned(self):
571
        """revnos are assigned according to the revision they derive from."""
572
        # in this test we setup a number of branches that all derive from 
573
        # the first revision, and then merge them one at a time, which 
574
        # should give the revisions as they merge numbers still deriving from
575
        # the revision were based on.
576
        # merge 3: J: ['G', 'I']
577
        # branch 3:
578
        #  I: ['H']
579
        #  H: ['A']
580
        # merge 2: G: ['D', 'F']
581
        # branch 2:
582
        #  F: ['E']
583
        #  E: ['A']
584
        # merge 1: D: ['A', 'C']
585
        # branch 1:
586
        #  C: ['B']
587
        #  B: ['A']
588
        # root: A: []
589
        self.assertSortAndIterate(
590
            {'J': ['G', 'I'],
591
             'I': ['H',],
592
             'H': ['A'],
593
             'G': ['D', 'F'],
594
             'F': ['E'],
595
             'E': ['A'],
596
             'D': ['A', 'C'],
597
             'C': ['B'],
598
             'B': ['A'],
599
             'A': [],
600
             }.items(),
601
            'J',
602
            [(0, 'J', 0, (4,), False),
603
             (1, 'I', 1, (1,3,2), False),
604
             (2, 'H', 1, (1,3,1), True),
605
             (3, 'G', 0, (3,), False),
606
             (4, 'F', 1, (1,2,2), False),
607
             (5, 'E', 1, (1,2,1), True),
608
             (6, 'D', 0, (2,), False),
609
             (7, 'C', 1, (1,1,2), False),
610
             (8, 'B', 1, (1,1,1), True),
611
             (9, 'A', 0, (1,), True),
612
             ],
613
            True
614
            )
3613.1.1 by John Arbash Meinel
Fix the merge_sort code so that it properly increments.
615
616
    def test_roots_and_sub_branches_versus_ghosts(self):
617
        """Extra roots and their mini branches use the same numbering.
618
619
        All of them use the 0-node numbering.
620
        """
621
        #       A D   K
622
        #       | |\  |\
623
        #       B E F L M
624
        #       | |/  |/
625
        #       C G   N
626
        #       |/    |\
627
        #       H I   O P
628
        #       |/    |/
629
        #       J     Q
630
        #       |.---'
631
        #       R
632
        self.assertSortAndIterate(
633
            {'A': [],
634
             'B': ['A'],
635
             'C': ['B'],
636
             'D': [],
637
             'E': ['D'],
638
             'F': ['D'],
639
             'G': ['E', 'F'],
640
             'H': ['C', 'G'],
641
             'I': [],
642
             'J': ['H', 'I'],
643
             'K': [],
644
             'L': ['K'],
645
             'M': ['K'],
646
             'N': ['L', 'M'],
647
             'O': ['N'],
648
             'P': ['N'],
649
             'Q': ['O', 'P'],
650
             'R': ['J', 'Q'],
651
            }.items(),
652
            'R',
653
            [( 0, 'R', 0, (6,), False),
654
             ( 1, 'Q', 1, (0,4,5), False),
655
             ( 2, 'P', 2, (0,6,1), True),
656
             ( 3, 'O', 1, (0,4,4), False),
657
             ( 4, 'N', 1, (0,4,3), False),
658
             ( 5, 'M', 2, (0,5,1), True),
659
             ( 6, 'L', 1, (0,4,2), False),
660
             ( 7, 'K', 1, (0,4,1), True),
661
             ( 8, 'J', 0, (5,), False),
662
             ( 9, 'I', 1, (0,3,1), True),
663
             (10, 'H', 0, (4,), False),
664
             (11, 'G', 1, (0,1,3), False),
665
             (12, 'F', 2, (0,2,1), True),
666
             (13, 'E', 1, (0,1,2), False),
667
             (14, 'D', 1, (0,1,1), True),
668
             (15, 'C', 0, (3,), False),
669
             (16, 'B', 0, (2,), False),
670
             (17, 'A', 0, (1,), True),
671
             ],
672
            True
673
            )