/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
import os
 
18
from cStringIO import StringIO
 
19
 
 
20
from bzrlib import log
 
21
from bzrlib.tests import BzrTestBase, TestCaseWithTransport
 
22
from bzrlib.log import (show_log, 
 
23
                        get_view_revisions, 
 
24
                        LogFormatter, 
 
25
                        LongLogFormatter, 
 
26
                        ShortLogFormatter, 
 
27
                        LineLogFormatter)
 
28
from bzrlib.branch import Branch
 
29
from bzrlib.errors import InvalidRevisionNumber
 
30
 
 
31
 
 
32
class _LogEntry(object):
 
33
    # should probably move into bzrlib.log?
 
34
    pass
 
35
 
 
36
 
 
37
class LogCatcher(LogFormatter):
 
38
    """Pull log messages into list rather than displaying them.
 
39
 
 
40
    For ease of testing we save log messages here rather than actually
 
41
    formatting them, so that we can precisely check the result without
 
42
    being too dependent on the exact formatting.
 
43
 
 
44
    We should also test the LogFormatter.
 
45
    """
 
46
    def __init__(self):
 
47
        super(LogCatcher, self).__init__(to_file=None)
 
48
        self.logs = []
 
49
 
 
50
    def show(self, revno, rev, delta):
 
51
        le = _LogEntry()
 
52
        le.revno = revno
 
53
        le.rev = rev
 
54
        le.delta = delta
 
55
        self.logs.append(le)
 
56
 
 
57
 
 
58
class SimpleLogTest(TestCaseWithTransport):
 
59
 
 
60
    def checkDelta(self, delta, **kw):
 
61
        """Check the filenames touched by a delta are as expected."""
 
62
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
 
63
            expected = kw.get(n, [])
 
64
 
 
65
            # tests are written with unix paths; fix them up for windows
 
66
            #if os.sep != '/':
 
67
            #    expected = [x.replace('/', os.sep) for x in expected]
 
68
 
 
69
            # strip out only the path components
 
70
            got = [x[0] for x in getattr(delta, n)]
 
71
            self.assertEquals(expected, got)
 
72
 
 
73
    def test_cur_revno(self):
 
74
        wt = self.make_branch_and_tree('.')
 
75
        b = wt.branch
 
76
 
 
77
        lf = LogCatcher()
 
78
        wt.commit('empty commit')
 
79
        show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
 
80
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
81
                          start_revision=2, end_revision=1) 
 
82
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
83
                          start_revision=1, end_revision=2) 
 
84
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
85
                          start_revision=0, end_revision=2) 
 
86
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
87
                          start_revision=1, end_revision=0) 
 
88
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
89
                          start_revision=-1, end_revision=1) 
 
90
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
91
                          start_revision=1, end_revision=-1) 
 
92
 
 
93
    def test_simple_log(self):
 
94
        eq = self.assertEquals
 
95
        
 
96
        wt = self.make_branch_and_tree('.')
 
97
        b = wt.branch
 
98
 
 
99
        lf = LogCatcher()
 
100
        show_log(b, lf)
 
101
        # no entries yet
 
102
        eq(lf.logs, [])
 
103
 
 
104
        wt.commit('empty commit')
 
105
        lf = LogCatcher()
 
106
        show_log(b, lf, verbose=True)
 
107
        eq(len(lf.logs), 1)
 
108
        eq(lf.logs[0].revno, '1')
 
109
        eq(lf.logs[0].rev.message, 'empty commit')
 
110
        d = lf.logs[0].delta
 
111
        self.log('log delta: %r' % d)
 
112
        self.checkDelta(d)
 
113
 
 
114
        self.build_tree(['hello'])
 
115
        wt.add('hello')
 
116
        wt.commit('add one file')
 
117
 
 
118
        lf = StringIO()
 
119
        # log using regular thing
 
120
        show_log(b, LongLogFormatter(lf))
 
121
        lf.seek(0)
 
122
        for l in lf.readlines():
 
123
            self.log(l)
 
124
 
 
125
        # get log as data structure
 
126
        lf = LogCatcher()
 
127
        show_log(b, lf, verbose=True)
 
128
        eq(len(lf.logs), 2)
 
129
        self.log('log entries:')
 
130
        for logentry in lf.logs:
 
131
            self.log('%4s %s' % (logentry.revno, logentry.rev.message))
 
132
        
 
133
        # first one is most recent
 
134
        logentry = lf.logs[0]
 
135
        eq(logentry.revno, '2')
 
136
        eq(logentry.rev.message, 'add one file')
 
137
        d = logentry.delta
 
138
        self.log('log 2 delta: %r' % d)
 
139
        # self.checkDelta(d, added=['hello'])
 
140
        
 
141
        # commit a log message with control characters
 
142
        msg = "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
 
143
        self.log("original commit message: %r", msg)
 
144
        wt.commit(msg)
 
145
        lf = LogCatcher()
 
146
        show_log(b, lf, verbose=True)
 
147
        committed_msg = lf.logs[0].rev.message
 
148
        self.log("escaped commit message: %r", committed_msg)
 
149
        self.assert_(msg != committed_msg)
 
150
        self.assert_(len(committed_msg) > len(msg))
 
151
 
 
152
        # Check that log message with only XML-valid characters isn't
 
153
        # escaped.  As ElementTree apparently does some kind of
 
154
        # newline conversion, neither LF (\x0A) nor CR (\x0D) are
 
155
        # included in the test commit message, even though they are
 
156
        # valid XML 1.0 characters.
 
157
        msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
 
158
        self.log("original commit message: %r", msg)
 
159
        wt.commit(msg)
 
160
        lf = LogCatcher()
 
161
        show_log(b, lf, verbose=True)
 
162
        committed_msg = lf.logs[0].rev.message
 
163
        self.log("escaped commit message: %r", committed_msg)
 
164
        self.assert_(msg == committed_msg)
 
165
 
 
166
    def test_trailing_newlines(self):
 
167
        wt = self.make_branch_and_tree('.')
 
168
        b = wt.branch
 
169
        b.nick='test'
 
170
        open('a', 'wb').write('hello moto\n')
 
171
        wt.add('a')
 
172
        wt.commit('simple log message', rev_id='a1'
 
173
                , timestamp=1132586655.459960938, timezone=-6*3600
 
174
                , committer='Joe Foo <joe@foo.com>')
 
175
        open('b', 'wb').write('goodbye\n')
 
176
        wt.add('b')
 
177
        wt.commit('multiline\nlog\nmessage\n', rev_id='a2'
 
178
                , timestamp=1132586842.411175966, timezone=-6*3600
 
179
                , committer='Joe Foo <joe@foo.com>')
 
180
 
 
181
        open('c', 'wb').write('just another manic monday\n')
 
182
        wt.add('c')
 
183
        wt.commit('single line with trailing newline\n', rev_id='a3'
 
184
                , timestamp=1132587176.835228920, timezone=-6*3600
 
185
                , committer = 'Joe Foo <joe@foo.com>')
 
186
 
 
187
        sio = StringIO()
 
188
        lf = ShortLogFormatter(to_file=sio)
 
189
        show_log(b, lf)
 
190
        self.assertEquals(sio.getvalue(), """\
 
191
    3 Joe Foo\t2005-11-21
 
192
      single line with trailing newline
 
193
 
 
194
    2 Joe Foo\t2005-11-21
 
195
      multiline
 
196
      log
 
197
      message
 
198
 
 
199
    1 Joe Foo\t2005-11-21
 
200
      simple log message
 
201
 
 
202
""")
 
203
 
 
204
        sio = StringIO()
 
205
        lf = LongLogFormatter(to_file=sio)
 
206
        show_log(b, lf)
 
207
        self.assertEquals(sio.getvalue(), """\
 
208
------------------------------------------------------------
 
209
revno: 3
 
210
committer: Joe Foo <joe@foo.com>
 
211
branch nick: test
 
212
timestamp: Mon 2005-11-21 09:32:56 -0600
 
213
message:
 
214
  single line with trailing newline
 
215
------------------------------------------------------------
 
216
revno: 2
 
217
committer: Joe Foo <joe@foo.com>
 
218
branch nick: test
 
219
timestamp: Mon 2005-11-21 09:27:22 -0600
 
220
message:
 
221
  multiline
 
222
  log
 
223
  message
 
224
------------------------------------------------------------
 
225
revno: 1
 
226
committer: Joe Foo <joe@foo.com>
 
227
branch nick: test
 
228
timestamp: Mon 2005-11-21 09:24:15 -0600
 
229
message:
 
230
  simple log message
 
231
""")
 
232
        
 
233
    def test_verbose_log(self):
 
234
        """Verbose log includes changed files
 
235
        
 
236
        bug #4676
 
237
        """
 
238
        wt = self.make_branch_and_tree('.')
 
239
        b = wt.branch
 
240
        self.build_tree(['a'])
 
241
        wt.add('a')
 
242
        # XXX: why does a longer nick show up?
 
243
        b.nick = 'test_verbose_log'
 
244
        wt.commit(message='add a', 
 
245
                  timestamp=1132711707, 
 
246
                  timezone=36000,
 
247
                  committer='Lorem Ipsum <test@example.com>')
 
248
        logfile = file('out.tmp', 'w+')
 
249
        formatter = LongLogFormatter(to_file=logfile)
 
250
        show_log(b, formatter, verbose=True)
 
251
        logfile.flush()
 
252
        logfile.seek(0)
 
253
        log_contents = logfile.read()
 
254
        self.assertEqualDiff(log_contents, '''\
 
255
------------------------------------------------------------
 
256
revno: 1
 
257
committer: Lorem Ipsum <test@example.com>
 
258
branch nick: test_verbose_log
 
259
timestamp: Wed 2005-11-23 12:08:27 +1000
 
260
message:
 
261
  add a
 
262
added:
 
263
  a
 
264
''')
 
265
 
 
266
    def test_line_log(self):
 
267
        """Line log should show revno
 
268
        
 
269
        bug #5162
 
270
        """
 
271
        wt = self.make_branch_and_tree('.')
 
272
        b = wt.branch
 
273
        self.build_tree(['a'])
 
274
        wt.add('a')
 
275
        b.nick = 'test-line-log'
 
276
        wt.commit(message='add a', 
 
277
                  timestamp=1132711707, 
 
278
                  timezone=36000,
 
279
                  committer='Line-Log-Formatter Tester <test@line.log>')
 
280
        logfile = file('out.tmp', 'w+')
 
281
        formatter = LineLogFormatter(to_file=logfile)
 
282
        show_log(b, formatter)
 
283
        logfile.flush()
 
284
        logfile.seek(0)
 
285
        log_contents = logfile.read()
 
286
        self.assertEqualDiff(log_contents, '1: Line-Log-Formatte... 2005-11-23 add a\n')
 
287
 
 
288
    def make_tree_with_commits(self):
 
289
        """Create a tree with well-known revision ids"""
 
290
        wt = self.make_branch_and_tree('tree1')
 
291
        wt.commit('commit one', rev_id='1')
 
292
        wt.commit('commit two', rev_id='2')
 
293
        wt.commit('commit three', rev_id='3')
 
294
        mainline_revs = [None, '1', '2', '3']
 
295
        rev_nos = {'1': 1, '2': 2, '3': 3}
 
296
        return mainline_revs, rev_nos, wt
 
297
 
 
298
    def make_tree_with_merges(self):
 
299
        """Create a tree with well-known revision ids and a merge"""
 
300
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
 
301
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
 
302
        tree2.commit('four-a', rev_id='4a')
 
303
        wt.merge_from_branch(tree2.branch)
 
304
        wt.commit('four-b', rev_id='4b')
 
305
        mainline_revs.append('4b')
 
306
        rev_nos['4b'] = 4
 
307
        # 4a: 3.1.1
 
308
        return mainline_revs, rev_nos, wt
 
309
 
 
310
    def make_tree_with_many_merges(self):
 
311
        """Create a tree with well-known revision ids"""
 
312
        wt = self.make_branch_and_tree('tree1')
 
313
        wt.commit('commit one', rev_id='1')
 
314
        wt.commit('commit two', rev_id='2')
 
315
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
 
316
        tree3.commit('commit three a', rev_id='3a')
 
317
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
 
318
        tree2.merge_from_branch(tree3.branch)
 
319
        tree2.commit('commit three b', rev_id='3b')
 
320
        wt.merge_from_branch(tree2.branch)
 
321
        wt.commit('commit three c', rev_id='3c')
 
322
        tree2.commit('four-a', rev_id='4a')
 
323
        wt.merge_from_branch(tree2.branch)
 
324
        wt.commit('four-b', rev_id='4b')
 
325
        mainline_revs = [None, '1', '2', '3c', '4b']
 
326
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
 
327
        full_rev_nos_for_reference = {
 
328
            '1': '1',
 
329
            '2': '2',
 
330
            '3a': '2.2.1', #first commit tree 3
 
331
            '3b': '2.1.1', # first commit tree 2
 
332
            '3c': '3', #merges 3b to main
 
333
            '4a': '2.1.2', # second commit tree 2
 
334
            '4b': '4', # merges 4a to main
 
335
            }
 
336
        return mainline_revs, rev_nos, wt
 
337
 
 
338
    def test_get_view_revisions_forward(self):
 
339
        """Test the get_view_revisions method"""
 
340
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
 
341
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
342
                                            'forward'))
 
343
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
 
344
            revisions)
 
345
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
346
                                             'forward', include_merges=False))
 
347
        self.assertEqual(revisions, revisions2)
 
348
 
 
349
    def test_get_view_revisions_reverse(self):
 
350
        """Test the get_view_revisions with reverse"""
 
351
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
 
352
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
353
                                            'reverse'))
 
354
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
 
355
            revisions)
 
356
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
357
                                             'reverse', include_merges=False))
 
358
        self.assertEqual(revisions, revisions2)
 
359
 
 
360
    def test_get_view_revisions_merge(self):
 
361
        """Test get_view_revisions when there are merges"""
 
362
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
 
363
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
364
                                            'forward'))
 
365
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
 
366
            ('4b', '4', 0), ('4a', '3.1.1', 1)],
 
367
            revisions)
 
368
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
369
                                             'forward', include_merges=False))
 
370
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
 
371
            ('4b', '4', 0)],
 
372
            revisions)
 
373
 
 
374
    def test_get_view_revisions_merge_reverse(self):
 
375
        """Test get_view_revisions in reverse when there are merges"""
 
376
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
 
377
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
378
                                            'reverse'))
 
379
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
 
380
            ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
 
381
            revisions)
 
382
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
383
                                             'reverse', include_merges=False))
 
384
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
 
385
            ('1', '1', 0)],
 
386
            revisions)
 
387
 
 
388
    def test_get_view_revisions_merge2(self):
 
389
        """Test get_view_revisions when there are merges"""
 
390
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
 
391
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
392
                                            'forward'))
 
393
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
 
394
            ('3a', '2.2.1', 1), ('3b', '2.1.1', 1), ('4b', '4', 0),
 
395
            ('4a', '2.1.2', 1)]
 
396
        self.assertEqual(expected, revisions)
 
397
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
 
398
                                             'forward', include_merges=False))
 
399
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
 
400
            ('4b', '4', 0)],
 
401
            revisions)
 
402
 
 
403
 
 
404
class TestGetRevisionsTouchingFileID(TestCaseWithTransport):
 
405
 
 
406
    def create_tree_with_single_merge(self):
 
407
        """Create a branch with a moderate layout.
 
408
 
 
409
        The revision graph looks like:
 
410
 
 
411
           A
 
412
           |\
 
413
           B C
 
414
           |/
 
415
           D
 
416
 
 
417
        In this graph, A introduced files f1 and f2 and f3.
 
418
        B modifies f1 and f3, and C modifies f2 and f3.
 
419
        D merges the changes from B and C and resolves the conflict for f3.
 
420
        """
 
421
        # TODO: jam 20070218 This seems like it could really be done
 
422
        #       with make_branch_and_memory_tree() if we could just
 
423
        #       create the content of those files.
 
424
        # TODO: jam 20070218 Another alternative is that we would really
 
425
        #       like to only create this tree 1 time for all tests that
 
426
        #       use it. Since 'log' only uses the tree in a readonly
 
427
        #       fashion, it seems a shame to regenerate an identical
 
428
        #       tree for each test.
 
429
        tree = self.make_branch_and_tree('tree')
 
430
        tree.lock_write()
 
431
        self.addCleanup(tree.unlock)
 
432
 
 
433
        self.build_tree_contents([('tree/f1', 'A\n'),
 
434
                                  ('tree/f2', 'A\n'),
 
435
                                  ('tree/f3', 'A\n'),
 
436
                                 ])
 
437
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
 
438
        tree.commit('A', rev_id='A')
 
439
 
 
440
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
 
441
                                  ('tree/f3', 'A\nC\n'),
 
442
                                 ])
 
443
        tree.commit('C', rev_id='C')
 
444
        # Revert back to A to build the other history.
 
445
        tree.set_last_revision('A')
 
446
        tree.branch.set_last_revision_info(1, 'A')
 
447
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
 
448
                                  ('tree/f2', 'A\n'),
 
449
                                  ('tree/f3', 'A\nB\n'),
 
450
                                 ])
 
451
        tree.commit('B', rev_id='B')
 
452
        tree.set_parent_ids(['B', 'C'])
 
453
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
 
454
                                  ('tree/f2', 'A\nC\n'),
 
455
                                  ('tree/f3', 'A\nB\nC\n'),
 
456
                                 ])
 
457
        tree.commit('D', rev_id='D')
 
458
 
 
459
        # Switch to a read lock for this tree.
 
460
        # We still have addCleanup(unlock)
 
461
        tree.unlock()
 
462
        tree.lock_read()
 
463
        return tree
 
464
 
 
465
    def test_tree_with_single_merge(self):
 
466
        """Make sure the tree layout is correct."""
 
467
        tree = self.create_tree_with_single_merge()
 
468
        rev_A_tree = tree.branch.repository.revision_tree('A')
 
469
        rev_B_tree = tree.branch.repository.revision_tree('B')
 
470
 
 
471
        f1_changed = (u'f1', 'f1-id', 'file', True, False)
 
472
        f2_changed = (u'f2', 'f2-id', 'file', True, False)
 
473
        f3_changed = (u'f3', 'f3-id', 'file', True, False)
 
474
 
 
475
        delta = rev_B_tree.changes_from(rev_A_tree)
 
476
        self.assertEqual([f1_changed, f3_changed], delta.modified)
 
477
        self.assertEqual([], delta.renamed)
 
478
        self.assertEqual([], delta.added)
 
479
        self.assertEqual([], delta.removed)
 
480
 
 
481
        rev_C_tree = tree.branch.repository.revision_tree('C')
 
482
        delta = rev_C_tree.changes_from(rev_A_tree)
 
483
        self.assertEqual([f2_changed, f3_changed], delta.modified)
 
484
        self.assertEqual([], delta.renamed)
 
485
        self.assertEqual([], delta.added)
 
486
        self.assertEqual([], delta.removed)
 
487
 
 
488
        rev_D_tree = tree.branch.repository.revision_tree('D')
 
489
        delta = rev_D_tree.changes_from(rev_B_tree)
 
490
        self.assertEqual([f2_changed, f3_changed], delta.modified)
 
491
        self.assertEqual([], delta.renamed)
 
492
        self.assertEqual([], delta.added)
 
493
        self.assertEqual([], delta.removed)
 
494
 
 
495
        delta = rev_D_tree.changes_from(rev_C_tree)
 
496
        self.assertEqual([f1_changed, f3_changed], delta.modified)
 
497
        self.assertEqual([], delta.renamed)
 
498
        self.assertEqual([], delta.added)
 
499
        self.assertEqual([], delta.removed)
 
500
 
 
501
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
 
502
        """Make sure _get_revisions_touching_file_id returns the right values.
 
503
 
 
504
        Get the return value from _get_revisions_touching_file_id and make
 
505
        sure they are correct.
 
506
        """
 
507
        # The api for _get_revisions_touching_file_id is a little crazy,
 
508
        # So we do the setup here.
 
509
        mainline = tree.branch.revision_history()
 
510
        mainline.insert(0, None)
 
511
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
 
512
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
 
513
                                                'reverse', True)
 
514
        actual_revs = log._get_revisions_touching_file_id(tree.branch, file_id,
 
515
                                                          mainline,
 
516
                                                          view_revs_iter)
 
517
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
 
518
 
 
519
    def test_file_id_f1(self):
 
520
        tree = self.create_tree_with_single_merge()
 
521
        # f1 should be marked as modified by revisions A and B
 
522
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
 
523
 
 
524
    def test_file_id_f2(self):
 
525
        tree = self.create_tree_with_single_merge()
 
526
        # f2 should be marked as modified by revisions A, C, and D
 
527
        # because D merged the changes from C.
 
528
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
 
529
 
 
530
    def test_file_id_f3(self):
 
531
        tree = self.create_tree_with_single_merge()
 
532
        # f3 should be marked as modified by revisions A, B, C, and D
 
533
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])