/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
1
# Copyright (C) 2006 by 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
"""Tests for join between versioned files."""
18
19
1563.2.13 by Robert Collins
InterVersionedFile implemented.
20
import bzrlib.errors as errors
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
21
from bzrlib.tests import TestCaseWithTransport
22
from bzrlib.transport import get_transport
1563.2.13 by Robert Collins
InterVersionedFile implemented.
23
import bzrlib.versionedfile as versionedfile
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
24
25
26
class TestJoin(TestCaseWithTransport):
27
    #Tests have self.versionedfile_factory and self.versionedfile_factory_to
28
    #available to create source and target versioned files respectively.
29
30
    def get_source(self, name='source'):
31
        """Get a versioned file we will be joining from."""
32
        return self.versionedfile_factory(name,
33
                                          get_transport(self.get_url()))
34
1563.2.13 by Robert Collins
InterVersionedFile implemented.
35
    def get_target(self, name='target'):
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
36
        """"Get an empty versioned file to join into."""
37
        return self.versionedfile_factory_to(name,
38
                                             get_transport(self.get_url()))
39
40
    def test_join(self):
41
        f1 = self.get_source()
42
        f1.add_lines('r0', [], ['a\n', 'b\n'])
43
        f1.add_lines('r1', ['r0'], ['c\n', 'b\n'])
44
        f2 = self.get_target()
45
        f2.join(f1, None)
46
        def verify_file(f):
47
            self.assertTrue(f.has_version('r0'))
48
            self.assertTrue(f.has_version('r1'))
49
        verify_file(f2)
50
        verify_file(self.get_target())
51
1563.2.13 by Robert Collins
InterVersionedFile implemented.
52
        self.assertRaises(errors.RevisionNotPresent,
1563.2.12 by Robert Collins
Checkpointing: created InterObject to factor out common inter object worker code, added InterVersionedFile and tests to allow making join work between any versionedfile.
53
            f2.join, f1, version_ids=['r3'])
54
55
        #f3 = self.get_file('1')
56
        #f3.add_lines('r0', ['a\n', 'b\n'], [])
57
        #f3.add_lines('r1', ['c\n', 'b\n'], ['r0'])
58
        #f4 = self.get_file('2')
59
        #f4.join(f3, ['r0'])
60
        #self.assertTrue(f4.has_version('r0'))
61
        #self.assertFalse(f4.has_version('r1'))
62
1563.2.13 by Robert Collins
InterVersionedFile implemented.
63
    def test_gets_expected_inter_worker(self):
64
        source = self.get_source()
65
        target = self.get_target()
66
        inter = versionedfile.InterVersionedFile.get(source, target)
67
        self.assertTrue(isinstance(inter, self.interversionedfile_class))
68
        
69
    def test_join_add_parents(self):
70
        """Join inserting new parents into existing versions
71
        
72
        The new version must have the right parent list and must identify
73
        lines originating in another parent.
74
        """
75
        w1 = self.get_target('w1')
76
        w2 = self.get_source('w2')
77
        w1.add_lines('v-1', [], ['line 1\n'])
78
        w2.add_lines('v-2', [], ['line 2\n'])
79
        w1.add_lines('v-3', ['v-1'], ['line 1\n'])
80
        w2.add_lines('v-3', ['v-2'], ['line 1\n'])
81
        w1.join(w2)
82
        self.assertEqual(sorted(w1.versions()),
83
                         'v-1 v-2 v-3'.split())
84
        self.assertEqualDiff(w1.get_text('v-3'),
85
                'line 1\n')
86
        self.assertEqual(sorted(w1.get_parents('v-3')),
87
                ['v-1', 'v-2'])
88
        ann = list(w1.annotate('v-3'))
89
        self.assertEqual(len(ann), 1)
90
        self.assertEqual(ann[0][0], 'v-1')
91
        self.assertEqual(ann[0][1], 'line 1\n')
92
        
93
    def build_weave1(self):
94
        weave1 = self.get_source()
95
        self.lines1 = ['hello\n']
96
        self.lines3 = ['hello\n', 'cruel\n', 'world\n']
97
        weave1.add_lines('v1', [], self.lines1)
98
        weave1.add_lines('v2', ['v1'], ['hello\n', 'world\n'])
99
        weave1.add_lines('v3', ['v2'], self.lines3)
100
        return weave1
101
        
102
    def test_join_with_empty(self):
103
        """Reweave adding empty weave"""
104
        wb = self.get_target()
105
        w1 = self.build_weave1()
106
        w1.join(wb)
107
        self.verify_weave1(w1)
108
109
    def verify_weave1(self, w1):
110
        self.assertEqual(sorted(w1.versions()), ['v1', 'v2', 'v3'])
111
        self.assertEqual(w1.get_lines('v1'), ['hello\n'])
112
        self.assertEqual([], w1.get_parents('v1'))
113
        self.assertEqual(w1.get_lines('v2'), ['hello\n', 'world\n'])
114
        self.assertEqual(['v1'], w1.get_parents('v2'))
115
        self.assertEqual(w1.get_lines('v3'), ['hello\n', 'cruel\n', 'world\n'])
116
        self.assertEqual(['v2'], w1.get_parents('v3'))
117
118
    def test_join_with_ghosts_merges_parents(self):
119
        """Join combined parent lists"""
120
        wa = self.build_weave1()
121
        wb = self.get_target()
122
        wb.add_lines('x1', [], ['line from x1\n'])
123
        wb.add_lines('v1', [], ['hello\n'])
124
        wb.add_lines('v2', ['v1', 'x1'], ['hello\n', 'world\n'])
125
        wa.join(wb)
126
        self.assertEqual(['v1','x1'], wa.get_parents('v2'))
127
128
    def test_join_with_ghosts(self):
129
        """Join that inserts parents of an existing revision.
130
131
        This can happen when merging from another branch who
132
        knows about revisions the destination does not.  In 
133
        this test the second weave knows of an additional parent of 
134
        v2.  Any revisions which are in common still have to have the 
135
        same text.
136
        """
137
        w1 = self.build_weave1()
138
        wb = self.get_target()
139
        wb.add_lines('x1', [], ['line from x1\n'])
140
        wb.add_lines('v1', [], ['hello\n'])
141
        wb.add_lines('v2', ['v1', 'x1'], ['hello\n', 'world\n'])
142
        w1.join(wb)
143
        eq = self.assertEquals
144
        eq(sorted(w1.versions()), ['v1', 'v2', 'v3', 'x1',])
145
        eq(w1.get_text('x1'), 'line from x1\n')
146
        eq(w1.get_lines('v2'), ['hello\n', 'world\n'])
147
        eq(w1.get_parents('v2'), ['v1', 'x1'])
148
149
    def build_source_weave(self, name, *pattern):
150
        w = self.get_source(name)
151
        for version, parents in pattern:
152
            w.add_lines(version, parents, [])
153
        return w
154
155
    def build_target_weave(self, name, *pattern):
156
        w = self.get_target(name)
157
        for version, parents in pattern:
158
            w.add_lines(version, parents, [])
159
        return w
160
161
    def test_join_reorder(self):
162
        """Reweave requiring reordering of versions.
163
164
        Weaves must be stored such that parents come before children.  When
165
        reweaving, we may add new parents to some children, but it is required
166
        that there must be *some* valid order that can be found, otherwise the
167
        ancestries are contradictory.  (For the specific case of inserting
168
        ghost revisions there will be no disagreement, only partial knowledge
169
        of the history.)
170
171
        Note that the weaves are only partially ordered: when there are two
172
        versions where neither is an ancestor of the other the order in which
173
        they occur is unconstrained.  When we join those versions into
174
        another weave, they may become more constrained and it may be
175
        necessary to change their order.
176
177
        One simple case of this is 
178
179
        w1: (c[], a[], b[a])
180
        w2: (b[], c[b], a[])
181
        
182
        We need to recognize that the final weave must show the ordering
183
        a[], b[a], c[b].  The version that must be first in the result is 
184
        not first in either of the input weaves.
185
        """
186
        w1 = self.build_target_weave('1', ('c', []), ('a', []), ('b', ['a']))
187
        w2 = self.build_source_weave('2', ('b', []), ('c', ['b']), ('a', []))
188
        w1.join(w2)
189
        self.assertEqual([], w1.get_parents('a'))
190
        self.assertEqual(['a'], w1.get_parents('b'))
191
        self.assertEqual(['b'], w1.get_parents('c'))