~bzr-pqm/bzr/bzr.dev

5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
1
# Copyright (C) 2008, 2010 Canonical Ltd
3794.5.9 by Mark Hammond
Correct line-endings.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3794.5.9 by Mark Hammond
Correct line-endings.
16
#
17
18
"""Tests variations of case-insensitive and case-preserving file-systems."""
19
20
import os
21
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
22
from bzrlib import (osutils,
23
    )
3794.5.9 by Mark Hammond
Correct line-endings.
24
from bzrlib.tests.blackbox import ExternalBase
25
from bzrlib.tests import CaseInsCasePresFilenameFeature, KnownFailure
3794.5.36 by Mark Hammond
test for, and fix problem with canonical_relpath when the tail does not exist.
26
from bzrlib.osutils import canonical_relpath, pathjoin
3794.5.21 by Mark Hammond
More cicp-filesystem tests
27
3794.5.23 by Mark Hammond
reoganize tests into categories.
28
class TestCICPBase(ExternalBase):
29
    """Base class for tests on a case-insensitive, case-preserving filesystem.
3794.5.9 by Mark Hammond
Correct line-endings.
30
    """
31
32
    _test_needs_features = [CaseInsCasePresFilenameFeature]
33
34
    def _make_mixed_case_tree(self):
35
        """Make a working tree with mixed-case filenames."""
36
        wt = self.make_branch_and_tree('.')
37
        # create a file on disk with the mixed-case parent and base name
38
        self.build_tree(['CamelCaseParent/', 'lowercaseparent/'])
39
        self.build_tree_contents([('CamelCaseParent/CamelCase', 'camel case'),
40
                                  ('lowercaseparent/lowercase', 'lower case'),
41
                                  ('lowercaseparent/mixedCase', 'mixedCasecase'),
42
                                 ])
43
        return wt
44
3794.5.21 by Mark Hammond
More cicp-filesystem tests
45
    def check_error_output(self, retcode, output, *args):
46
        got = self.run_bzr(retcode=retcode, *args)[1]
47
        self.failUnlessEqual(got, output)
3794.5.23 by Mark Hammond
reoganize tests into categories.
48
3794.5.31 by Mark Hammond
bulk of the simple review comments from igc.
49
    def check_empty_output(self, *args):
50
        """Check a bzr command generates no output anywhere and exits with 0"""
51
        out, err = self.run_bzr(retcode=0, *args)
52
        self.failIf(out)
53
        self.failIf(err)
54
55
3794.5.23 by Mark Hammond
reoganize tests into categories.
56
class TestAdd(TestCICPBase):
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
57
3794.5.9 by Mark Hammond
Correct line-endings.
58
    def test_add_simple(self):
59
        """Test add always uses the case of the filename reported by the os."""
60
        wt = self.make_branch_and_tree('.')
61
        # create a file on disk with the mixed-case name
62
        self.build_tree(['CamelCase'])
63
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
64
        self.check_output('adding CamelCase\n', 'add camelcase')
3794.5.9 by Mark Hammond
Correct line-endings.
65
66
    def test_add_subdir(self):
67
        """test_add_simple but with subdirectories tested too."""
68
        wt = self.make_branch_and_tree('.')
69
        # create a file on disk with the mixed-case parent and base name
70
        self.build_tree(['CamelCaseParent/', 'CamelCaseParent/CamelCase'])
71
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
72
        self.check_output('adding CamelCaseParent\n'
73
                          'adding CamelCaseParent/CamelCase\n',
3794.5.9 by Mark Hammond
Correct line-endings.
74
                          'add camelcaseparent/camelcase')
75
76
    def test_add_implied(self):
77
        """test add with no args sees the correct names."""
78
        wt = self.make_branch_and_tree('.')
79
        # create a file on disk with the mixed-case parent and base name
80
        self.build_tree(['CamelCaseParent/', 'CamelCaseParent/CamelCase'])
81
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
82
        self.check_output('adding CamelCaseParent\n'
83
                          'adding CamelCaseParent/CamelCase\n',
3794.5.9 by Mark Hammond
Correct line-endings.
84
                          'add')
85
3794.5.23 by Mark Hammond
reoganize tests into categories.
86
    def test_re_add(self):
87
        """Test than when a file has 'unintentionally' changed case, we can't
88
        add a new entry using the new case."""
89
        wt = self.make_branch_and_tree('.')
90
        # create a file on disk with the mixed-case name
91
        self.build_tree(['MixedCase'])
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
92
        self.check_output('adding MixedCase\n', 'add MixedCase')
3794.5.23 by Mark Hammond
reoganize tests into categories.
93
        # 'accidently' rename the file on disk
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
94
        osutils.rename('MixedCase', 'mixedcase')
3794.5.31 by Mark Hammond
bulk of the simple review comments from igc.
95
        self.check_empty_output('add mixedcase')
3794.5.23 by Mark Hammond
reoganize tests into categories.
96
97
    def test_re_add_dir(self):
98
        # like re-add, but tests when the operation is on a directory.
99
        """Test than when a file has 'unintentionally' changed case, we can't
100
        add a new entry using the new case."""
101
        wt = self.make_branch_and_tree('.')
102
        # create a file on disk with the mixed-case name
103
        self.build_tree(['MixedCaseParent/', 'MixedCaseParent/MixedCase'])
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
104
        self.check_output('adding MixedCaseParent\n'
105
                          'adding MixedCaseParent/MixedCase\n',
3794.5.23 by Mark Hammond
reoganize tests into categories.
106
                          'add MixedCaseParent')
107
        # 'accidently' rename the directory on disk
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
108
        osutils.rename('MixedCaseParent', 'mixedcaseparent')
3794.5.31 by Mark Hammond
bulk of the simple review comments from igc.
109
        self.check_empty_output('add mixedcaseparent')
3794.5.23 by Mark Hammond
reoganize tests into categories.
110
3794.5.36 by Mark Hammond
test for, and fix problem with canonical_relpath when the tail does not exist.
111
    def test_add_not_found(self):
112
        """Test add when the input file doesn't exist."""
113
        wt = self.make_branch_and_tree('.')
114
        # create a file on disk with the mixed-case name
115
        self.build_tree(['MixedCaseParent/', 'MixedCaseParent/MixedCase'])
116
        expected_fname = pathjoin(wt.basedir, "MixedCaseParent", "notfound")
117
        expected_msg = "bzr: ERROR: No such file: %r\n" % expected_fname
118
        self.check_error_output(3, expected_msg, 'add mixedcaseparent/notfound')
119
3794.5.23 by Mark Hammond
reoganize tests into categories.
120
121
class TestMove(TestCICPBase):
3794.5.9 by Mark Hammond
Correct line-endings.
122
    def test_mv_newname(self):
123
        wt = self._make_mixed_case_tree()
124
        self.run_bzr('add')
125
        self.run_bzr('ci -m message')
126
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
127
        self.check_output(
128
            'CamelCaseParent/CamelCase => CamelCaseParent/NewCamelCase\n',
129
            'mv camelcaseparent/camelcase camelcaseparent/NewCamelCase')
3794.5.9 by Mark Hammond
Correct line-endings.
130
131
    def test_mv_newname_after(self):
132
        wt = self._make_mixed_case_tree()
133
        self.run_bzr('add')
134
        self.run_bzr('ci -m message')
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
135
        osutils.rename('CamelCaseParent/CamelCase', 'CamelCaseParent/NewCamelCase')
3794.5.9 by Mark Hammond
Correct line-endings.
136
137
        # In this case we can specify the incorrect case for the destination,
138
        # as we use --after, so the file-system is sniffed.
4241.9.2 by Vincent Ladeuil
Fix most of cicp related failures on OSX.
139
        self.check_output(
140
            'CamelCaseParent/CamelCase => CamelCaseParent/NewCamelCase\n',
141
            'mv --after camelcaseparent/camelcase camelcaseparent/newcamelcase')
3794.5.9 by Mark Hammond
Correct line-endings.
142
3794.5.21 by Mark Hammond
More cicp-filesystem tests
143
    def test_mv_newname_exists(self):
144
        # test a mv, but when the target already exists with a name that
145
        # differs only by case.
146
        wt = self._make_mixed_case_tree()
147
        self.run_bzr('add')
148
        self.run_bzr('ci -m message')
149
        ex = 'bzr: ERROR: Could not move CamelCase => lowercase: lowercaseparent/lowercase is already versioned.\n'
150
        self.check_error_output(3, ex, 'mv camelcaseparent/camelcase LOWERCASEPARENT/LOWERCASE')
151
152
    def test_mv_newname_exists_after(self):
153
        # test a 'mv --after', but when the target already exists with a name
154
        # that differs only by case.  Note that this is somewhat unlikely
155
        # but still reasonable.
156
        wt = self._make_mixed_case_tree()
157
        self.run_bzr('add')
158
        self.run_bzr('ci -m message')
159
        # Remove the source and create a destination file on disk with a different case.
160
        # bzr should report that the filename is already versioned.
161
        os.unlink('CamelCaseParent/CamelCase')
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
162
        osutils.rename('lowercaseparent/lowercase', 'lowercaseparent/LOWERCASE')
3794.5.21 by Mark Hammond
More cicp-filesystem tests
163
        ex = 'bzr: ERROR: Could not move CamelCase => lowercase: lowercaseparent/lowercase is already versioned.\n'
164
        self.check_error_output(3, ex, 'mv --after camelcaseparent/camelcase LOWERCASEPARENT/LOWERCASE')
165
3794.5.9 by Mark Hammond
Correct line-endings.
166
    def test_mv_newname_root(self):
167
        wt = self._make_mixed_case_tree()
168
        self.run_bzr('add')
169
        self.run_bzr('ci -m message')
170
171
        self.check_output('CamelCaseParent => NewCamelCaseParent\n',
172
                          'mv camelcaseparent NewCamelCaseParent')
173
174
    def test_mv_newname_root_after(self):
175
        wt = self._make_mixed_case_tree()
176
        self.run_bzr('add')
177
        self.run_bzr('ci -m message')
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
178
        osutils.rename('CamelCaseParent', 'NewCamelCaseParent')
3794.5.9 by Mark Hammond
Correct line-endings.
179
180
        # In this case we can specify the incorrect case for the destination,
181
        # as we use --after, so the file-system is sniffed.
182
        self.check_output('CamelCaseParent => NewCamelCaseParent\n',
183
                          'mv --after camelcaseparent newcamelcaseparent')
184
185
    def test_mv_newcase(self):
186
        wt = self._make_mixed_case_tree()
187
        self.run_bzr('add')
188
        self.run_bzr('ci -m message')
189
3794.5.21 by Mark Hammond
More cicp-filesystem tests
190
        # perform a mv to the new case - we expect bzr to accept the new
191
        # name, as specified, and rename the file on the file-system too.
192
        self.check_output('CamelCaseParent/CamelCase => CamelCaseParent/camelCase\n',
193
                          'mv camelcaseparent/camelcase camelcaseparent/camelCase')
194
        self.failUnlessEqual(canonical_relpath(wt.basedir, 'camelcaseparent/camelcase'),
195
                             'CamelCaseParent/camelCase')
196
197
    def test_mv_newcase_after(self):
198
        wt = self._make_mixed_case_tree()
199
        self.run_bzr('add')
200
        self.run_bzr('ci -m message')
201
3794.5.9 by Mark Hammond
Correct line-endings.
202
        # perform a mv to the new case - we must ensure the file-system has the
203
        # new case first.
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
204
        osutils.rename('CamelCaseParent/CamelCase', 'CamelCaseParent/camelCase')
3794.5.9 by Mark Hammond
Correct line-endings.
205
        self.check_output('CamelCaseParent/CamelCase => CamelCaseParent/camelCase\n',
3794.5.21 by Mark Hammond
More cicp-filesystem tests
206
                          'mv --after camelcaseparent/camelcase camelcaseparent/camelCase')
207
        # bzr should not have renamed the file to a different case
208
        self.failUnlessEqual(canonical_relpath(wt.basedir, 'camelcaseparent/camelcase'),
209
                             'CamelCaseParent/camelCase')
3794.5.9 by Mark Hammond
Correct line-endings.
210
211
    def test_mv_multiple(self):
212
        wt = self._make_mixed_case_tree()
213
        self.run_bzr('add')
214
        self.run_bzr('ci -m message')
215
        self.check_output('lowercaseparent/lowercase => CamelCaseParent/lowercase\n'
216
                          'lowercaseparent/mixedCase => CamelCaseParent/mixedCase\n',
217
                          'mv LOWercaseparent/LOWercase LOWercaseparent/MIXEDCase camelcaseparent')
218
3794.5.23 by Mark Hammond
reoganize tests into categories.
219
220
class TestMisc(TestCICPBase):
4651.2.1 by Vincent Ladeuil
Catch up fix for #347649.
221
3794.5.23 by Mark Hammond
reoganize tests into categories.
222
    def test_status(self):
223
        wt = self._make_mixed_case_tree()
224
        self.run_bzr('add')
225
4651.2.1 by Vincent Ladeuil
Catch up fix for #347649.
226
        self.check_output(
227
            """added:
228
  CamelCaseParent/
229
  CamelCaseParent/CamelCase
230
  lowercaseparent/
231
  lowercaseparent/lowercase
232
""",
233
            'status camelcaseparent/camelcase LOWERCASEPARENT/LOWERCASE')
3794.5.23 by Mark Hammond
reoganize tests into categories.
234
235
    def test_ci(self):
236
        wt = self._make_mixed_case_tree()
237
        self.run_bzr('add')
238
239
        got = self.run_bzr('ci -m message camelcaseparent LOWERCASEPARENT')[1]
240
        for expected in ['CamelCaseParent', 'lowercaseparent',
241
                         'CamelCaseParent/CamelCase', 'lowercaseparent/lowercase']:
242
            self.assertContainsRe(got, 'added ' + expected + '\n')
243
244
    def test_rm(self):
245
        wt = self._make_mixed_case_tree()
246
        self.run_bzr('add')
247
        self.run_bzr('ci -m message')
248
249
        got = self.run_bzr('rm camelcaseparent LOWERCASEPARENT')[1]
250
        for expected in ['lowercaseparent/lowercase', 'CamelCaseParent/CamelCase']:
251
            self.assertContainsRe(got, 'deleted ' + expected + '\n')
252
3794.5.10 by Mark Hammond
Add comments about commands that should still get love.
253
254
    # The following commands need tests and/or cicp lovin':
255
    # update, remove, file_id, file_path, diff, log, touching_revisions, ls,
3794.5.31 by Mark Hammond
bulk of the simple review comments from igc.
256
    # ignore, cat, revert, resolve.