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