~bzr-pqm/bzr/bzr.dev

2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1685.1.80 by Wouter van Heyst
more code cleanup
2
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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.
1685.1.80 by Wouter van Heyst
more code cleanup
7
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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.
1685.1.80 by Wouter van Heyst
more code cleanup
12
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
18
from cStringIO import StringIO
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
19
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
20
from bzrlib import log
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
21
from bzrlib.tests import BzrTestBase, TestCaseWithTransport
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
22
from bzrlib.log import (show_log, 
23
                        get_view_revisions, 
24
                        LogFormatter, 
25
                        LongLogFormatter, 
26
                        ShortLogFormatter, 
27
                        LineLogFormatter)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
28
from bzrlib.branch import Branch
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
29
from bzrlib.errors import InvalidRevisionNumber
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
30
1685.1.69 by Wouter van Heyst
merge bzr.dev 1740
31
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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 = []
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
49
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
58
class SimpleLogTest(TestCaseWithTransport):
1102 by Martin Pool
- merge test refactoring from robertc
59
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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
1185.31.34 by John Arbash Meinel
Removing instances of os.sep
66
            #if os.sep != '/':
67
            #    expected = [x.replace('/', os.sep) for x in expected]
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
68
69
            # strip out only the path components
70
            got = [x[0] for x in getattr(delta, n)]
71
            self.assertEquals(expected, got)
72
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
73
    def test_cur_revno(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
74
        wt = self.make_branch_and_tree('.')
75
        b = wt.branch
1092.3.4 by Robert Collins
update symlink branch to integration
76
77
        lf = LogCatcher()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
78
        wt.commit('empty commit')
1092.3.4 by Robert Collins
update symlink branch to integration
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
1102 by Martin Pool
- merge test refactoring from robertc
93
    def test_simple_log(self):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
94
        eq = self.assertEquals
95
        
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
96
        wt = self.make_branch_and_tree('.')
97
        b = wt.branch
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
98
99
        lf = LogCatcher()
100
        show_log(b, lf)
101
        # no entries yet
102
        eq(lf.logs, [])
103
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
104
        wt.commit('empty commit')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
105
        lf = LogCatcher()
106
        show_log(b, lf, verbose=True)
107
        eq(len(lf.logs), 1)
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
108
        eq(lf.logs[0].revno, '1')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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'])
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
115
        wt.add('hello')
116
        wt.commit('add one file')
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
117
118
        lf = StringIO()
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
119
        # log using regular thing
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
120
        show_log(b, LongLogFormatter(lf))
121
        lf.seek(0)
122
        for l in lf.readlines():
123
            self.log(l)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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:
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
131
            self.log('%4s %s' % (logentry.revno, logentry.rev.message))
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
132
        
133
        # first one is most recent
134
        logentry = lf.logs[0]
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
135
        eq(logentry.revno, '2')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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
        
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
141
        # commit a log message with control characters
142
        msg = "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
143
        self.log("original commit message: %r", msg)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
144
        wt.commit(msg)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
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))
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
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)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
159
        wt.commit(msg)
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
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)
1185.31.22 by John Arbash Meinel
[merge] bzr.dev
165
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
166
    def test_trailing_newlines(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
167
        wt = self.make_branch_and_tree('.')
168
        b = wt.branch
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
169
        b.nick='test'
170
        open('a', 'wb').write('hello moto\n')
1185.33.54 by Martin Pool
[merge] test renames and other fixes (John)
171
        wt.add('a')
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
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')
1185.33.54 by Martin Pool
[merge] test renames and other fixes (John)
176
        wt.add('b')
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
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')
1185.33.54 by Martin Pool
[merge] test renames and other fixes (John)
182
        wt.add('c')
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
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
        
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
233
    def test_verbose_log(self):
234
        """Verbose log includes changed files
235
        
236
        bug #4676
237
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
238
        wt = self.make_branch_and_tree('.')
239
        b = wt.branch
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
240
        self.build_tree(['a'])
1185.33.45 by Martin Pool
[merge] refactoring of branch vs working tree, etc (robertc)
241
        wt.add('a')
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
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
''')
1185.85.4 by John Arbash Meinel
currently broken, trying to fix things up.
265
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
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')
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
287
1756.2.22 by Aaron Bentley
Apply review comments
288
    def make_tree_with_commits(self):
289
        """Create a tree with well-known revision ids"""
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
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']
1756.2.22 by Aaron Bentley
Apply review comments
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()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
301
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
302
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
303
        wt.merge_from_branch(tree2.branch)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
304
        wt.commit('four-b', rev_id='4b')
305
        mainline_revs.append('4b')
1756.2.22 by Aaron Bentley
Apply review comments
306
        rev_nos['4b'] = 4
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
307
        # 4a: 3.1.1
1756.2.22 by Aaron Bentley
Apply review comments
308
        return mainline_revs, rev_nos, wt
309
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
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')
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
317
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
318
        tree2.merge_from_branch(tree3.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
319
        tree2.commit('commit three b', rev_id='3b')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
320
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
321
        wt.commit('commit three c', rev_id='3c')
322
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
323
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
324
        wt.commit('four-b', rev_id='4b')
325
        mainline_revs = [None, '1', '2', '3c', '4b']
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
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
            }
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
336
        return mainline_revs, rev_nos, wt
337
1756.2.22 by Aaron Bentley
Apply review comments
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'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
343
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
344
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
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'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
354
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
355
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
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()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
363
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
364
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
365
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
366
            ('4b', '4', 0), ('4a', '3.1.1', 1)],
367
            revisions)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
368
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1756.2.22 by Aaron Bentley
Apply review comments
369
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
370
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
371
            ('4b', '4', 0)],
372
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
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'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
379
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
380
            ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
381
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
382
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
383
                                             'reverse', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
384
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
385
            ('1', '1', 0)],
386
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
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'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
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)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
397
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
398
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
399
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
400
            ('4b', '4', 0)],
401
            revisions)
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
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
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
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'])