/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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
2483.2.1 by John Arbash Meinel
Add a test with a merged revision
288
    def test_short_log_with_merges(self):
289
        wt = self.make_branch_and_memory_tree('.')
290
        wt.lock_write()
291
        try:
292
            wt.add('')
293
            wt.commit('rev-1', rev_id='rev-1',
294
                      timestamp=1132586655, timezone=36000,
295
                      committer='Joe Foo <joe@foo.com>')
296
            wt.commit('rev-merged', rev_id='rev-2a',
297
                      timestamp=1132586700, timezone=36000,
298
                      committer='Joe Foo <joe@foo.com>')
299
            wt.set_parent_ids(['rev-1', 'rev-2a'])
300
            wt.branch.set_last_revision_info(1, 'rev-1')
301
            wt.commit('rev-2', rev_id='rev-2b',
302
                      timestamp=1132586800, timezone=36000,
303
                      committer='Joe Foo <joe@foo.com>')
304
            logfile = StringIO()
305
            formatter = ShortLogFormatter(to_file=logfile)
306
            show_log(wt.branch, formatter)
307
            logfile.flush()
308
            self.assertEqualDiff("""\
2483.2.2 by John Arbash Meinel
Add [merge] after the timestamp for revisions with merges.
309
    2 Joe Foo\t2005-11-22 [merge]
2483.2.1 by John Arbash Meinel
Add a test with a merged revision
310
      rev-2
311
312
    1 Joe Foo\t2005-11-22
313
      rev-1
314
315
""", logfile.getvalue())
316
        finally:
317
            wt.unlock()
318
1756.2.22 by Aaron Bentley
Apply review comments
319
    def make_tree_with_commits(self):
320
        """Create a tree with well-known revision ids"""
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
321
        wt = self.make_branch_and_tree('tree1')
322
        wt.commit('commit one', rev_id='1')
323
        wt.commit('commit two', rev_id='2')
324
        wt.commit('commit three', rev_id='3')
325
        mainline_revs = [None, '1', '2', '3']
1756.2.22 by Aaron Bentley
Apply review comments
326
        rev_nos = {'1': 1, '2': 2, '3': 3}
327
        return mainline_revs, rev_nos, wt
328
329
    def make_tree_with_merges(self):
330
        """Create a tree with well-known revision ids and a merge"""
331
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
332
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
333
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
334
        wt.merge_from_branch(tree2.branch)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
335
        wt.commit('four-b', rev_id='4b')
336
        mainline_revs.append('4b')
1756.2.22 by Aaron Bentley
Apply review comments
337
        rev_nos['4b'] = 4
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
338
        # 4a: 3.1.1
1756.2.22 by Aaron Bentley
Apply review comments
339
        return mainline_revs, rev_nos, wt
340
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
341
    def make_tree_with_many_merges(self):
342
        """Create a tree with well-known revision ids"""
343
        wt = self.make_branch_and_tree('tree1')
344
        wt.commit('commit one', rev_id='1')
345
        wt.commit('commit two', rev_id='2')
346
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
347
        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,
348
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
349
        tree2.merge_from_branch(tree3.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
350
        tree2.commit('commit three b', rev_id='3b')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
351
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
352
        wt.commit('commit three c', rev_id='3c')
353
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
354
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
355
        wt.commit('four-b', rev_id='4b')
356
        mainline_revs = [None, '1', '2', '3c', '4b']
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
357
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
358
        full_rev_nos_for_reference = {
359
            '1': '1',
360
            '2': '2',
361
            '3a': '2.2.1', #first commit tree 3
362
            '3b': '2.1.1', # first commit tree 2
363
            '3c': '3', #merges 3b to main
364
            '4a': '2.1.2', # second commit tree 2
365
            '4b': '4', # merges 4a to main
366
            }
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
367
        return mainline_revs, rev_nos, wt
368
1756.2.22 by Aaron Bentley
Apply review comments
369
    def test_get_view_revisions_forward(self):
370
        """Test the get_view_revisions method"""
371
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
372
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
373
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
374
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
375
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
376
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
377
                                             'forward', include_merges=False))
378
        self.assertEqual(revisions, revisions2)
379
380
    def test_get_view_revisions_reverse(self):
381
        """Test the get_view_revisions with reverse"""
382
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
383
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
384
                                            'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
385
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
386
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
387
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
388
                                             'reverse', include_merges=False))
389
        self.assertEqual(revisions, revisions2)
390
391
    def test_get_view_revisions_merge(self):
392
        """Test get_view_revisions when there are merges"""
393
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
394
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
395
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
396
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
397
            ('4b', '4', 0), ('4a', '3.1.1', 1)],
398
            revisions)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
399
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1756.2.22 by Aaron Bentley
Apply review comments
400
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
401
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
402
            ('4b', '4', 0)],
403
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
404
405
    def test_get_view_revisions_merge_reverse(self):
406
        """Test get_view_revisions in reverse when there are merges"""
407
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
408
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
409
                                            'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
410
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
411
            ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
412
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
413
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
414
                                             'reverse', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
415
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
416
            ('1', '1', 0)],
417
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
418
419
    def test_get_view_revisions_merge2(self):
420
        """Test get_view_revisions when there are merges"""
421
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
422
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
423
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
424
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
425
            ('3a', '2.2.1', 1), ('3b', '2.1.1', 1), ('4b', '4', 0),
426
            ('4a', '2.1.2', 1)]
427
        self.assertEqual(expected, revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
428
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
429
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
430
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
431
            ('4b', '4', 0)],
432
            revisions)
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
433
434
435
class TestGetRevisionsTouchingFileID(TestCaseWithTransport):
436
437
    def create_tree_with_single_merge(self):
438
        """Create a branch with a moderate layout.
439
440
        The revision graph looks like:
441
442
           A
443
           |\
444
           B C
445
           |/
446
           D
447
448
        In this graph, A introduced files f1 and f2 and f3.
449
        B modifies f1 and f3, and C modifies f2 and f3.
450
        D merges the changes from B and C and resolves the conflict for f3.
451
        """
452
        # TODO: jam 20070218 This seems like it could really be done
453
        #       with make_branch_and_memory_tree() if we could just
454
        #       create the content of those files.
455
        # TODO: jam 20070218 Another alternative is that we would really
456
        #       like to only create this tree 1 time for all tests that
457
        #       use it. Since 'log' only uses the tree in a readonly
458
        #       fashion, it seems a shame to regenerate an identical
459
        #       tree for each test.
460
        tree = self.make_branch_and_tree('tree')
461
        tree.lock_write()
462
        self.addCleanup(tree.unlock)
463
464
        self.build_tree_contents([('tree/f1', 'A\n'),
465
                                  ('tree/f2', 'A\n'),
466
                                  ('tree/f3', 'A\n'),
467
                                 ])
468
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
469
        tree.commit('A', rev_id='A')
470
471
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
472
                                  ('tree/f3', 'A\nC\n'),
473
                                 ])
474
        tree.commit('C', rev_id='C')
475
        # Revert back to A to build the other history.
476
        tree.set_last_revision('A')
477
        tree.branch.set_last_revision_info(1, 'A')
478
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
479
                                  ('tree/f2', 'A\n'),
480
                                  ('tree/f3', 'A\nB\n'),
481
                                 ])
482
        tree.commit('B', rev_id='B')
483
        tree.set_parent_ids(['B', 'C'])
484
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
485
                                  ('tree/f2', 'A\nC\n'),
486
                                  ('tree/f3', 'A\nB\nC\n'),
487
                                 ])
488
        tree.commit('D', rev_id='D')
489
490
        # Switch to a read lock for this tree.
491
        # We still have addCleanup(unlock)
492
        tree.unlock()
493
        tree.lock_read()
494
        return tree
495
496
    def test_tree_with_single_merge(self):
497
        """Make sure the tree layout is correct."""
498
        tree = self.create_tree_with_single_merge()
499
        rev_A_tree = tree.branch.repository.revision_tree('A')
500
        rev_B_tree = tree.branch.repository.revision_tree('B')
501
502
        f1_changed = (u'f1', 'f1-id', 'file', True, False)
503
        f2_changed = (u'f2', 'f2-id', 'file', True, False)
504
        f3_changed = (u'f3', 'f3-id', 'file', True, False)
505
506
        delta = rev_B_tree.changes_from(rev_A_tree)
507
        self.assertEqual([f1_changed, f3_changed], delta.modified)
508
        self.assertEqual([], delta.renamed)
509
        self.assertEqual([], delta.added)
510
        self.assertEqual([], delta.removed)
511
512
        rev_C_tree = tree.branch.repository.revision_tree('C')
513
        delta = rev_C_tree.changes_from(rev_A_tree)
514
        self.assertEqual([f2_changed, f3_changed], delta.modified)
515
        self.assertEqual([], delta.renamed)
516
        self.assertEqual([], delta.added)
517
        self.assertEqual([], delta.removed)
518
519
        rev_D_tree = tree.branch.repository.revision_tree('D')
520
        delta = rev_D_tree.changes_from(rev_B_tree)
521
        self.assertEqual([f2_changed, f3_changed], delta.modified)
522
        self.assertEqual([], delta.renamed)
523
        self.assertEqual([], delta.added)
524
        self.assertEqual([], delta.removed)
525
526
        delta = rev_D_tree.changes_from(rev_C_tree)
527
        self.assertEqual([f1_changed, f3_changed], delta.modified)
528
        self.assertEqual([], delta.renamed)
529
        self.assertEqual([], delta.added)
530
        self.assertEqual([], delta.removed)
531
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
532
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
533
        """Make sure _get_revisions_touching_file_id returns the right values.
534
535
        Get the return value from _get_revisions_touching_file_id and make
536
        sure they are correct.
537
        """
538
        # The api for _get_revisions_touching_file_id is a little crazy,
539
        # So we do the setup here.
540
        mainline = tree.branch.revision_history()
541
        mainline.insert(0, None)
542
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
543
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
544
                                                'reverse', True)
545
        actual_revs = log._get_revisions_touching_file_id(tree.branch, file_id,
546
                                                          mainline,
547
                                                          view_revs_iter)
548
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
549
550
    def test_file_id_f1(self):
551
        tree = self.create_tree_with_single_merge()
552
        # f1 should be marked as modified by revisions A and B
553
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
554
555
    def test_file_id_f2(self):
556
        tree = self.create_tree_with_single_merge()
557
        # f2 should be marked as modified by revisions A, C, and D
558
        # because D merged the changes from C.
559
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
560
561
    def test_file_id_f3(self):
562
        tree = self.create_tree_with_single_merge()
563
        # f3 should be marked as modified by revisions A, B, C, and D
564
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])