~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

  • Committer: Aaron Bentley
  • Date: 2006-02-21 01:27:09 UTC
  • mto: (2027.1.2 revert-subpath-56549)
  • mto: This revision was merged to the branch mainline in revision 1558.
  • Revision ID: aaron.bentley@utoronto.ca-20060221012709-c46aaa71a00010e8
Renamed a bunch of functions

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
import os
18
18
from cStringIO import StringIO
19
19
 
20
 
from bzrlib import log
21
20
from bzrlib.tests import BzrTestBase, TestCaseWithTransport
22
 
from bzrlib.log import (show_log,
23
 
                        get_view_revisions,
24
 
                        LogRevision,
25
 
                        LogFormatter,
26
 
                        LongLogFormatter,
27
 
                        ShortLogFormatter,
28
 
                        LineLogFormatter)
 
21
from bzrlib.log import LogFormatter, show_log, LongLogFormatter, ShortLogFormatter
29
22
from bzrlib.branch import Branch
30
23
from bzrlib.errors import InvalidRevisionNumber
31
24
 
 
25
class _LogEntry(object):
 
26
    # should probably move into bzrlib.log?
 
27
    pass
 
28
 
32
29
 
33
30
class LogCatcher(LogFormatter):
34
31
    """Pull log messages into list rather than displaying them.
39
36
 
40
37
    We should also test the LogFormatter.
41
38
    """
42
 
 
43
 
    supports_delta = True
44
 
 
45
39
    def __init__(self):
46
40
        super(LogCatcher, self).__init__(to_file=None)
47
41
        self.logs = []
48
 
 
49
 
    def log_revision(self, revision):
50
 
        self.logs.append(revision)
 
42
        
 
43
        
 
44
    def show(self, revno, rev, delta):
 
45
        le = _LogEntry()
 
46
        le.revno = revno
 
47
        le.rev = rev
 
48
        le.delta = delta
 
49
        self.logs.append(le)
51
50
 
52
51
 
53
52
class SimpleLogTest(TestCaseWithTransport):
85
84
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
86
85
                          start_revision=1, end_revision=-1) 
87
86
 
 
87
    def test_cur_revno(self):
 
88
        wt = self.make_branch_and_tree('.')
 
89
        b = wt.branch
 
90
 
 
91
        lf = LogCatcher()
 
92
        wt.commit('empty commit')
 
93
        show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
 
94
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
95
                          start_revision=2, end_revision=1) 
 
96
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
97
                          start_revision=1, end_revision=2) 
 
98
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
99
                          start_revision=0, end_revision=2) 
 
100
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
101
                          start_revision=1, end_revision=0) 
 
102
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
103
                          start_revision=-1, end_revision=1) 
 
104
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
105
                          start_revision=1, end_revision=-1) 
 
106
 
88
107
    def test_simple_log(self):
89
108
        eq = self.assertEquals
90
109
        
100
119
        lf = LogCatcher()
101
120
        show_log(b, lf, verbose=True)
102
121
        eq(len(lf.logs), 1)
103
 
        eq(lf.logs[0].revno, '1')
 
122
        eq(lf.logs[0].revno, 1)
104
123
        eq(lf.logs[0].rev.message, 'empty commit')
105
124
        d = lf.logs[0].delta
106
125
        self.log('log delta: %r' % d)
123
142
        eq(len(lf.logs), 2)
124
143
        self.log('log entries:')
125
144
        for logentry in lf.logs:
126
 
            self.log('%4s %s' % (logentry.revno, logentry.rev.message))
 
145
            self.log('%4d %s' % (logentry.revno, logentry.rev.message))
127
146
        
128
147
        # first one is most recent
129
148
        logentry = lf.logs[0]
130
 
        eq(logentry.revno, '2')
 
149
        eq(logentry.revno, 2)
131
150
        eq(logentry.rev.message, 'add one file')
132
151
        d = logentry.delta
133
152
        self.log('log 2 delta: %r' % d)
257
276
added:
258
277
  a
259
278
''')
260
 
 
261
 
    def test_line_log(self):
262
 
        """Line log should show revno
263
 
        
264
 
        bug #5162
265
 
        """
266
 
        wt = self.make_branch_and_tree('.')
267
 
        b = wt.branch
268
 
        self.build_tree(['a'])
269
 
        wt.add('a')
270
 
        b.nick = 'test-line-log'
271
 
        wt.commit(message='add a', 
272
 
                  timestamp=1132711707, 
273
 
                  timezone=36000,
274
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
275
 
        logfile = file('out.tmp', 'w+')
276
 
        formatter = LineLogFormatter(to_file=logfile)
277
 
        show_log(b, formatter)
278
 
        logfile.flush()
279
 
        logfile.seek(0)
280
 
        log_contents = logfile.read()
281
 
        self.assertEqualDiff(log_contents, '1: Line-Log-Formatte... 2005-11-23 add a\n')
282
 
 
283
 
    def test_short_log_with_merges(self):
284
 
        wt = self.make_branch_and_memory_tree('.')
285
 
        wt.lock_write()
286
 
        try:
287
 
            wt.add('')
288
 
            wt.commit('rev-1', rev_id='rev-1',
289
 
                      timestamp=1132586655, timezone=36000,
290
 
                      committer='Joe Foo <joe@foo.com>')
291
 
            wt.commit('rev-merged', rev_id='rev-2a',
292
 
                      timestamp=1132586700, timezone=36000,
293
 
                      committer='Joe Foo <joe@foo.com>')
294
 
            wt.set_parent_ids(['rev-1', 'rev-2a'])
295
 
            wt.branch.set_last_revision_info(1, 'rev-1')
296
 
            wt.commit('rev-2', rev_id='rev-2b',
297
 
                      timestamp=1132586800, timezone=36000,
298
 
                      committer='Joe Foo <joe@foo.com>')
299
 
            logfile = StringIO()
300
 
            formatter = ShortLogFormatter(to_file=logfile)
301
 
            show_log(wt.branch, formatter)
302
 
            logfile.flush()
303
 
            self.assertEqualDiff("""\
304
 
    2 Joe Foo\t2005-11-22 [merge]
305
 
      rev-2
306
 
 
307
 
    1 Joe Foo\t2005-11-22
308
 
      rev-1
309
 
 
310
 
""", logfile.getvalue())
311
 
        finally:
312
 
            wt.unlock()
313
 
 
314
 
    def make_tree_with_commits(self):
315
 
        """Create a tree with well-known revision ids"""
316
 
        wt = self.make_branch_and_tree('tree1')
317
 
        wt.commit('commit one', rev_id='1')
318
 
        wt.commit('commit two', rev_id='2')
319
 
        wt.commit('commit three', rev_id='3')
320
 
        mainline_revs = [None, '1', '2', '3']
321
 
        rev_nos = {'1': 1, '2': 2, '3': 3}
322
 
        return mainline_revs, rev_nos, wt
323
 
 
324
 
    def make_tree_with_merges(self):
325
 
        """Create a tree with well-known revision ids and a merge"""
326
 
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
327
 
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
328
 
        tree2.commit('four-a', rev_id='4a')
329
 
        wt.merge_from_branch(tree2.branch)
330
 
        wt.commit('four-b', rev_id='4b')
331
 
        mainline_revs.append('4b')
332
 
        rev_nos['4b'] = 4
333
 
        # 4a: 3.1.1
334
 
        return mainline_revs, rev_nos, wt
335
 
 
336
 
    def make_tree_with_many_merges(self):
337
 
        """Create a tree with well-known revision ids"""
338
 
        wt = self.make_branch_and_tree('tree1')
339
 
        wt.commit('commit one', rev_id='1')
340
 
        wt.commit('commit two', rev_id='2')
341
 
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
342
 
        tree3.commit('commit three a', rev_id='3a')
343
 
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
344
 
        tree2.merge_from_branch(tree3.branch)
345
 
        tree2.commit('commit three b', rev_id='3b')
346
 
        wt.merge_from_branch(tree2.branch)
347
 
        wt.commit('commit three c', rev_id='3c')
348
 
        tree2.commit('four-a', rev_id='4a')
349
 
        wt.merge_from_branch(tree2.branch)
350
 
        wt.commit('four-b', rev_id='4b')
351
 
        mainline_revs = [None, '1', '2', '3c', '4b']
352
 
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
353
 
        full_rev_nos_for_reference = {
354
 
            '1': '1',
355
 
            '2': '2',
356
 
            '3a': '2.2.1', #first commit tree 3
357
 
            '3b': '2.1.1', # first commit tree 2
358
 
            '3c': '3', #merges 3b to main
359
 
            '4a': '2.1.2', # second commit tree 2
360
 
            '4b': '4', # merges 4a to main
361
 
            }
362
 
        return mainline_revs, rev_nos, wt
363
 
 
364
 
    def test_get_view_revisions_forward(self):
365
 
        """Test the get_view_revisions method"""
366
 
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
367
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
368
 
                                            'forward'))
369
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
370
 
            revisions)
371
 
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
372
 
                                             'forward', include_merges=False))
373
 
        self.assertEqual(revisions, revisions2)
374
 
 
375
 
    def test_get_view_revisions_reverse(self):
376
 
        """Test the get_view_revisions with reverse"""
377
 
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
378
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
379
 
                                            'reverse'))
380
 
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
381
 
            revisions)
382
 
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
383
 
                                             'reverse', include_merges=False))
384
 
        self.assertEqual(revisions, revisions2)
385
 
 
386
 
    def test_get_view_revisions_merge(self):
387
 
        """Test get_view_revisions when there are merges"""
388
 
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
389
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
390
 
                                            'forward'))
391
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
392
 
            ('4b', '4', 0), ('4a', '3.1.1', 1)],
393
 
            revisions)
394
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
395
 
                                             'forward', include_merges=False))
396
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
397
 
            ('4b', '4', 0)],
398
 
            revisions)
399
 
 
400
 
    def test_get_view_revisions_merge_reverse(self):
401
 
        """Test get_view_revisions in reverse when there are merges"""
402
 
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
403
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
404
 
                                            'reverse'))
405
 
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
406
 
            ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
407
 
            revisions)
408
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
409
 
                                             'reverse', include_merges=False))
410
 
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
411
 
            ('1', '1', 0)],
412
 
            revisions)
413
 
 
414
 
    def test_get_view_revisions_merge2(self):
415
 
        """Test get_view_revisions when there are merges"""
416
 
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
417
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
418
 
                                            'forward'))
419
 
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
420
 
            ('3a', '2.2.1', 1), ('3b', '2.1.1', 1), ('4b', '4', 0),
421
 
            ('4a', '2.1.2', 1)]
422
 
        self.assertEqual(expected, revisions)
423
 
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
424
 
                                             'forward', include_merges=False))
425
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
426
 
            ('4b', '4', 0)],
427
 
            revisions)
428
 
 
429
 
 
430
 
class TestGetRevisionsTouchingFileID(TestCaseWithTransport):
431
 
 
432
 
    def create_tree_with_single_merge(self):
433
 
        """Create a branch with a moderate layout.
434
 
 
435
 
        The revision graph looks like:
436
 
 
437
 
           A
438
 
           |\
439
 
           B C
440
 
           |/
441
 
           D
442
 
 
443
 
        In this graph, A introduced files f1 and f2 and f3.
444
 
        B modifies f1 and f3, and C modifies f2 and f3.
445
 
        D merges the changes from B and C and resolves the conflict for f3.
446
 
        """
447
 
        # TODO: jam 20070218 This seems like it could really be done
448
 
        #       with make_branch_and_memory_tree() if we could just
449
 
        #       create the content of those files.
450
 
        # TODO: jam 20070218 Another alternative is that we would really
451
 
        #       like to only create this tree 1 time for all tests that
452
 
        #       use it. Since 'log' only uses the tree in a readonly
453
 
        #       fashion, it seems a shame to regenerate an identical
454
 
        #       tree for each test.
455
 
        tree = self.make_branch_and_tree('tree')
456
 
        tree.lock_write()
457
 
        self.addCleanup(tree.unlock)
458
 
 
459
 
        self.build_tree_contents([('tree/f1', 'A\n'),
460
 
                                  ('tree/f2', 'A\n'),
461
 
                                  ('tree/f3', 'A\n'),
462
 
                                 ])
463
 
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
464
 
        tree.commit('A', rev_id='A')
465
 
 
466
 
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
467
 
                                  ('tree/f3', 'A\nC\n'),
468
 
                                 ])
469
 
        tree.commit('C', rev_id='C')
470
 
        # Revert back to A to build the other history.
471
 
        tree.set_last_revision('A')
472
 
        tree.branch.set_last_revision_info(1, 'A')
473
 
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
474
 
                                  ('tree/f2', 'A\n'),
475
 
                                  ('tree/f3', 'A\nB\n'),
476
 
                                 ])
477
 
        tree.commit('B', rev_id='B')
478
 
        tree.set_parent_ids(['B', 'C'])
479
 
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
480
 
                                  ('tree/f2', 'A\nC\n'),
481
 
                                  ('tree/f3', 'A\nB\nC\n'),
482
 
                                 ])
483
 
        tree.commit('D', rev_id='D')
484
 
 
485
 
        # Switch to a read lock for this tree.
486
 
        # We still have addCleanup(unlock)
487
 
        tree.unlock()
488
 
        tree.lock_read()
489
 
        return tree
490
 
 
491
 
    def test_tree_with_single_merge(self):
492
 
        """Make sure the tree layout is correct."""
493
 
        tree = self.create_tree_with_single_merge()
494
 
        rev_A_tree = tree.branch.repository.revision_tree('A')
495
 
        rev_B_tree = tree.branch.repository.revision_tree('B')
496
 
 
497
 
        f1_changed = (u'f1', 'f1-id', 'file', True, False)
498
 
        f2_changed = (u'f2', 'f2-id', 'file', True, False)
499
 
        f3_changed = (u'f3', 'f3-id', 'file', True, False)
500
 
 
501
 
        delta = rev_B_tree.changes_from(rev_A_tree)
502
 
        self.assertEqual([f1_changed, f3_changed], delta.modified)
503
 
        self.assertEqual([], delta.renamed)
504
 
        self.assertEqual([], delta.added)
505
 
        self.assertEqual([], delta.removed)
506
 
 
507
 
        rev_C_tree = tree.branch.repository.revision_tree('C')
508
 
        delta = rev_C_tree.changes_from(rev_A_tree)
509
 
        self.assertEqual([f2_changed, f3_changed], delta.modified)
510
 
        self.assertEqual([], delta.renamed)
511
 
        self.assertEqual([], delta.added)
512
 
        self.assertEqual([], delta.removed)
513
 
 
514
 
        rev_D_tree = tree.branch.repository.revision_tree('D')
515
 
        delta = rev_D_tree.changes_from(rev_B_tree)
516
 
        self.assertEqual([f2_changed, f3_changed], delta.modified)
517
 
        self.assertEqual([], delta.renamed)
518
 
        self.assertEqual([], delta.added)
519
 
        self.assertEqual([], delta.removed)
520
 
 
521
 
        delta = rev_D_tree.changes_from(rev_C_tree)
522
 
        self.assertEqual([f1_changed, f3_changed], delta.modified)
523
 
        self.assertEqual([], delta.renamed)
524
 
        self.assertEqual([], delta.added)
525
 
        self.assertEqual([], delta.removed)
526
 
 
527
 
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
528
 
        """Make sure _get_revisions_touching_file_id returns the right values.
529
 
 
530
 
        Get the return value from _get_revisions_touching_file_id and make
531
 
        sure they are correct.
532
 
        """
533
 
        # The api for _get_revisions_touching_file_id is a little crazy,
534
 
        # So we do the setup here.
535
 
        mainline = tree.branch.revision_history()
536
 
        mainline.insert(0, None)
537
 
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
538
 
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
539
 
                                                'reverse', True)
540
 
        actual_revs = log._get_revisions_touching_file_id(tree.branch, file_id,
541
 
                                                          mainline,
542
 
                                                          view_revs_iter)
543
 
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
544
 
 
545
 
    def test_file_id_f1(self):
546
 
        tree = self.create_tree_with_single_merge()
547
 
        # f1 should be marked as modified by revisions A and B
548
 
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
549
 
 
550
 
    def test_file_id_f2(self):
551
 
        tree = self.create_tree_with_single_merge()
552
 
        # f2 should be marked as modified by revisions A, C, and D
553
 
        # because D merged the changes from C.
554
 
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
555
 
 
556
 
    def test_file_id_f3(self):
557
 
        tree = self.create_tree_with_single_merge()
558
 
        # f3 should be marked as modified by revisions A, B, C, and D
559
 
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])