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