~bzr-pqm/bzr/bzr.dev

963 by Martin Pool
- add the start of a test for inventory file-id matching
1
# Copyright (C) 2005 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
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
17
from cStringIO import StringIO
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
18
import os
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
19
20
from bzrlib.branch import Branch
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
21
import bzrlib.errors as errors
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
22
from bzrlib.diff import internal_diff
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
23
from bzrlib.inventory import Inventory, ROOT_ID
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
24
import bzrlib.inventory as inventory
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
25
from bzrlib.osutils import has_symlinks, rename
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
26
from bzrlib.selftest import TestCase, TestCaseInTempDir
963 by Martin Pool
- add the start of a test for inventory file-id matching
27
969 by Martin Pool
- Add less-sucky is_within_any
28
1102 by Martin Pool
- merge test refactoring from robertc
29
class TestInventory(TestCase):
30
31
    def test_is_within(self):
968 by Martin Pool
- add some passing tests for is_inside_any
32
        from bzrlib.osutils import is_inside_any
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
33
34
        SRC_FOO_C = os.path.join('src', 'foo.c')
35
        for dirs, fn in [(['src', 'doc'], SRC_FOO_C),
36
                         (['src'], SRC_FOO_C),
968 by Martin Pool
- add some passing tests for is_inside_any
37
                         (['src'], 'src'),
38
                         ]:
39
            self.assert_(is_inside_any(dirs, fn))
40
            
969 by Martin Pool
- Add less-sucky is_within_any
41
        for dirs, fn in [(['src'], 'srccontrol'),
42
                         (['src'], 'srccontrol/foo')]:
43
            self.assertFalse(is_inside_any(dirs, fn))
44
            
1102 by Martin Pool
- merge test refactoring from robertc
45
    def test_ids(self):
963 by Martin Pool
- add the start of a test for inventory file-id matching
46
        """Test detection of files within selected directories."""
47
        inv = Inventory()
48
        
49
        for args in [('src', 'directory', 'src-id'), 
50
                     ('doc', 'directory', 'doc-id'), 
51
                     ('src/hello.c', 'file'),
52
                     ('src/bye.c', 'file', 'bye-id'),
53
                     ('Makefile', 'file')]:
54
            inv.add_path(*args)
55
            
56
        self.assertEqual(inv.path2id('src'), 'src-id')
57
        self.assertEqual(inv.path2id('src/bye.c'), 'bye-id')
58
        
59
        self.assert_('src-id' in inv)
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
60
61
62
    def test_version(self):
63
        """Inventory remembers the text's version."""
64
        inv = Inventory()
65
        ie = inv.add_path('foo.txt', 'file')
66
        ## XXX
67
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
68
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
69
class TestInventoryEntry(TestCase):
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
70
71
    def test_file_kind_character(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
72
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
73
        self.assertEqual(file.kind_character(), '')
74
75
    def test_dir_kind_character(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
76
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
77
        self.assertEqual(dir.kind_character(), '/')
78
79
    def test_link_kind_character(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
80
        dir = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
81
        self.assertEqual(dir.kind_character(), '')
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
82
83
    def test_dir_detect_changes(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
84
        left = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
85
        left.text_sha1 = 123
86
        left.executable = True
87
        left.symlink_target='foo'
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
88
        right = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
89
        right.text_sha1 = 321
90
        right.symlink_target='bar'
91
        self.assertEqual((False, False), left.detect_changes(right))
92
        self.assertEqual((False, False), right.detect_changes(left))
93
94
    def test_file_detect_changes(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
95
        left = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
96
        left.text_sha1 = 123
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
97
        right = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
98
        right.text_sha1 = 123
99
        self.assertEqual((False, False), left.detect_changes(right))
100
        self.assertEqual((False, False), right.detect_changes(left))
101
        left.executable = True
102
        self.assertEqual((False, True), left.detect_changes(right))
103
        self.assertEqual((False, True), right.detect_changes(left))
104
        right.text_sha1 = 321
105
        self.assertEqual((True, True), left.detect_changes(right))
106
        self.assertEqual((True, True), right.detect_changes(left))
107
108
    def test_symlink_detect_changes(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
109
        left = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
110
        left.text_sha1 = 123
111
        left.executable = True
112
        left.symlink_target='foo'
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
113
        right = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.3 by Robert Collins
move change detection for text and metadata from delta to entry.detect_changes
114
        right.text_sha1 = 321
115
        right.symlink_target='foo'
116
        self.assertEqual((False, False), left.detect_changes(right))
117
        self.assertEqual((False, False), right.detect_changes(left))
118
        left.symlink_target = 'different'
119
        self.assertEqual((True, False), left.detect_changes(right))
120
        self.assertEqual((True, False), right.detect_changes(left))
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
121
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
122
    def test_file_has_text(self):
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
123
        file = inventory.InventoryFile('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
124
        self.failUnless(file.has_text())
125
126
    def test_directory_has_text(self):
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
127
        dir = inventory.InventoryDirectory('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
128
        self.failIf(dir.has_text())
129
130
    def test_link_has_text(self):
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
131
        link = inventory.InventoryLink('123', 'hello.c', ROOT_ID)
1399.1.5 by Robert Collins
move checking whether an entry stores text into inventory.py from fetch,py
132
        self.failIf(link.has_text())
133
1399.1.4 by Robert Collins
move diff and symlink conditionals into inventory.py from diff.py
134
135
class TestEntryDiffing(TestCaseInTempDir):
136
137
    def setUp(self):
138
        super(TestEntryDiffing, self).setUp()
139
        self.branch = Branch.initialize('.')
140
        print >> open('file', 'wb'), 'foo'
141
        self.branch.add(['file'], ['fileid'])
142
        if has_symlinks():
143
            os.symlink('target1', 'symlink')
144
            self.branch.add(['symlink'], ['linkid'])
145
        self.branch.commit('message_1', rev_id = '1')
146
        print >> open('file', 'wb'), 'bar'
147
        if has_symlinks():
148
            os.unlink('symlink')
149
            os.symlink('target2', 'symlink')
150
        self.tree_1 = self.branch.revision_tree('1')
151
        self.inv_1 = self.branch.get_inventory('1')
152
        self.file_1 = self.inv_1['fileid']
153
        self.tree_2 = self.branch.working_tree()
154
        self.inv_2 = self.branch.inventory
155
        self.file_2 = self.inv_2['fileid']
156
        if has_symlinks():
157
            self.link_1 = self.inv_1['linkid']
158
            self.link_2 = self.inv_2['linkid']
159
160
    def test_file_diff_deleted(self):
161
        output = StringIO()
162
        self.file_1.diff(internal_diff, 
163
                          "old_label", self.tree_1,
164
                          "/dev/null", None, None,
165
                          output)
166
        self.assertEqual(output.getvalue(), "--- old_label\n"
167
                                            "+++ /dev/null\n"
168
                                            "@@ -1,1 +0,0 @@\n"
169
                                            "-foo\n"
170
                                            "\n")
171
172
    def test_file_diff_added(self):
173
        output = StringIO()
174
        self.file_1.diff(internal_diff, 
175
                          "new_label", self.tree_1,
176
                          "/dev/null", None, None,
177
                          output, reverse=True)
178
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
179
                                            "+++ new_label\n"
180
                                            "@@ -0,0 +1,1 @@\n"
181
                                            "+foo\n"
182
                                            "\n")
183
184
    def test_file_diff_changed(self):
185
        output = StringIO()
186
        self.file_1.diff(internal_diff, 
187
                          "/dev/null", self.tree_1, 
188
                          "new_label", self.file_2, self.tree_2,
189
                          output)
190
        self.assertEqual(output.getvalue(), "--- /dev/null\n"
191
                                            "+++ new_label\n"
192
                                            "@@ -1,1 +1,1 @@\n"
193
                                            "-foo\n"
194
                                            "+bar\n"
195
                                            "\n")
196
        
197
    def test_link_diff_deleted(self):
198
        output = StringIO()
199
        self.link_1.diff(internal_diff, 
200
                          "old_label", self.tree_1,
201
                          "/dev/null", None, None,
202
                          output)
203
        self.assertEqual(output.getvalue(),
204
                         "=== target was 'target1'\n")
205
206
    def test_link_diff_added(self):
207
        output = StringIO()
208
        self.link_1.diff(internal_diff, 
209
                          "new_label", self.tree_1,
210
                          "/dev/null", None, None,
211
                          output, reverse=True)
212
        self.assertEqual(output.getvalue(),
213
                         "=== target is 'target1'\n")
214
215
    def test_link_diff_changed(self):
216
        output = StringIO()
217
        self.link_1.diff(internal_diff, 
218
                          "/dev/null", self.tree_1, 
219
                          "new_label", self.link_2, self.tree_2,
220
                          output)
221
        self.assertEqual(output.getvalue(),
222
                         "=== target changed 'target1' => 'target2'\n")
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
223
224
225
class TestSnapshot(TestCaseInTempDir):
226
227
    def setUp(self):
228
        # for full testing we'll need a branch
229
        # with a subdir to test parent changes.
230
        # and a file, link and dir under that.
231
        # but right now I only need one attribute
232
        # to change, and then test merge patterns
233
        # with fake parent entries.
234
        super(TestSnapshot, self).setUp()
235
        self.branch = Branch.initialize('.')
236
        self.build_tree(['subdir/', 'subdir/file'])
237
        self.branch.add(['subdir', 'subdir/file'], ['dirid', 'fileid'])
238
        if has_symlinks():
239
            pass
240
        self.branch.commit('message_1', rev_id = '1')
241
        self.tree_1 = self.branch.revision_tree('1')
242
        self.inv_1 = self.branch.get_inventory('1')
243
        self.file_1 = self.inv_1['fileid']
244
        self.work_tree = self.branch.working_tree()
245
        self.file_active = self.work_tree.inventory['fileid']
246
247
    def test_snapshot_new_revision(self):
248
        # This tests that a simple commit with no parents makes a new
249
        # revision value in the inventory entry
250
        self.file_active.snapshot('2', 'subdir/file', {}, self.work_tree, 
251
                                  self.branch.weave_store)
252
        # expected outcome - file_1 has a revision id of '2', and we can get
253
        # its text of 'file contents' out of the weave.
254
        self.assertEqual(self.file_1.revision, '1')
255
        self.assertEqual(self.file_active.revision, '2')
256
        # this should be a separate test probably, but lets check it once..
257
        lines = self.branch.weave_store.get_lines('fileid','2')
258
        self.assertEqual(lines, ['contents of subdir/file\n'])
259
260
    def test_snapshot_unchanged(self):
261
        #This tests that a simple commit does not make a new entry for
262
        # an unchanged inventory entry
263
        self.file_active.snapshot('2', 'subdir/file', {'1':self.file_1},
264
                                  self.work_tree, self.branch.weave_store)
265
        self.assertEqual(self.file_1.revision, '1')
266
        self.assertEqual(self.file_active.revision, '1')
267
        self.assertRaises(errors.WeaveError,
268
                          self.branch.weave_store.get_lines, 'fileid', '2')
269
270
    def test_snapshot_merge_identical_different_revid(self):
271
        # This tests that a commit with two identical parents, one of which has
272
        # a different revision id, results in a new revision id in the entry.
1408 by Robert Collins
we do not need revision_trees in commit, parent inventories are sufficient
273
        # 1->other, commit a merge of other against 1, results in 2.
1407 by Robert Collins
define some expected behaviour for inventory_entry.snapshot
274
        other_ie = inventory.InventoryFile('fileid', 'newname', self.file_1.parent_id)
275
        other_ie = inventory.InventoryFile('fileid', 'file', self.file_1.parent_id)
276
        other_ie.revision = '1'
277
        other_ie.text_sha1 = self.file_1.text_sha1
278
        other_ie.text_size = self.file_1.text_size
279
        self.assertEqual(self.file_1, other_ie)
280
        other_ie.revision = 'other'
281
        self.assertNotEqual(self.file_1, other_ie)
282
        self.branch.weave_store.add_identical_text('fileid', '1', 'other', ['1'])
283
        self.file_active.snapshot('2', 'subdir/file', 
284
                                  {'1':self.file_1, 'other':other_ie},
285
                                  self.work_tree, self.branch.weave_store)
286
        self.assertEqual(self.file_active.revision, '2')
287
288
    def test_snapshot_changed(self):
289
        # This tests that a commit with one different parent results in a new
290
        # revision id in the entry.
291
        self.file_active.name='newname'
292
        rename('subdir/file', 'subdir/newname')
293
        self.file_active.snapshot('2', 'subdir/newname', {'1':self.file_1}, 
294
                                  self.work_tree, 
295
                                  self.branch.weave_store)
296
        # expected outcome - file_1 has a revision id of '2'
297
        self.assertEqual(self.file_active.revision, '2')