/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_tree.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2008 Canonical Ltd
 
1
# Copyright (C) 2006-2009, 2011 Canonical Ltd
2
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
16
16
 
17
17
"""Tests for Tree and InterTree."""
18
18
 
19
 
from bzrlib import (
 
19
from breezy import (
20
20
    errors,
21
21
    revision,
22
 
    tests,
23
22
    tree as _mod_tree,
24
23
    )
25
 
from bzrlib.tests import TestCaseWithTransport
26
 
from bzrlib.tree import InterTree
 
24
from breezy.tests import (
 
25
    TestCase,
 
26
    TestCaseWithTransport,
 
27
    )
 
28
from breezy.tree import (
 
29
    FileTimestampUnavailable,
 
30
    InterTree,
 
31
    find_previous_paths,
 
32
    get_canonical_path,
 
33
    )
 
34
 
 
35
 
 
36
class TestErrors(TestCase):
 
37
 
 
38
    def test_file_timestamp_unavailable(self):
 
39
        e = FileTimestampUnavailable("/path/foo")
 
40
        self.assertEqual("The filestamp for /path/foo is not available.",
 
41
                         str(e))
27
42
 
28
43
 
29
44
class TestInterTree(TestCaseWithTransport):
68
83
    calls = []
69
84
 
70
85
    def compare(self, want_unchanged=False, specific_files=None,
71
 
        extra_trees=None, require_versioned=False, include_root=False,
72
 
        want_unversioned=False):
 
86
                extra_trees=None, require_versioned=False, include_root=False,
 
87
                want_unversioned=False):
73
88
        self.calls.append(
74
89
            ('compare', self.source, self.target, want_unchanged,
75
90
             specific_files, extra_trees, require_versioned,
100
115
                              'require', True)
101
116
            # pass in all optional arguments by keyword
102
117
            tree.changes_from(tree2,
103
 
                specific_files='specific',
104
 
                want_unchanged='unchanged',
105
 
                extra_trees='extra',
106
 
                require_versioned='require',
107
 
                include_root=True,
108
 
                want_unversioned=True,
109
 
                )
 
118
                              specific_files='specific',
 
119
                              want_unchanged='unchanged',
 
120
                              extra_trees='extra',
 
121
                              require_versioned='require',
 
122
                              include_root=True,
 
123
                              want_unversioned=True,
 
124
                              )
110
125
        finally:
111
126
            InterTree._optimisers = old_optimisers
112
127
        self.assertEqual(
113
128
            [
114
 
             ('compare', tree2, tree, False, None, None, False, False, False),
115
 
             ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
116
 
              'require', True, False),
117
 
             ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
118
 
              'require', True, True),
 
129
                ('compare', tree2, tree, False, None, None, False, False,
 
130
                    False),
 
131
                ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
 
132
                    'require', True, False),
 
133
                ('compare', tree2, tree, 'unchanged', 'specific', 'extra',
 
134
                    'require', True, True),
119
135
            ], RecordingOptimiser.calls)
120
136
 
121
137
    def test_changes_from_with_root(self):
125
141
        self.assertEqual(len(delta.added), 0)
126
142
        delta = wt.changes_from(wt.basis_tree(), include_root=True)
127
143
        self.assertEqual(len(delta.added), 1)
128
 
        self.assertEqual(delta.added[0][0], '')
 
144
        self.assertEqual(delta.added[0].path[1], '')
129
145
 
130
146
    def test_changes_from_with_require_versioned(self):
131
147
        """Ensure the require_versioned option does what's expected."""
133
149
        self.build_tree(['known_file', 'unknown_file'])
134
150
        wt.add('known_file')
135
151
 
136
 
        self.assertRaises(errors.PathsNotVersionedError,
137
 
            wt.changes_from, wt.basis_tree(), wt, specific_files=['known_file',
138
 
            'unknown_file'], require_versioned=True)
 
152
        self.assertRaises(
 
153
            errors.PathsNotVersionedError,
 
154
            wt.changes_from, wt.basis_tree(), wt,
 
155
            specific_files=['known_file', 'unknown_file'],
 
156
            require_versioned=True)
139
157
 
140
158
        # we need to pass a known file with an unknown file to get this to
141
159
        # fail when expected.
142
160
        delta = wt.changes_from(wt.basis_tree(),
143
 
            specific_files=['known_file', 'unknown_file'] ,
144
 
            require_versioned=False)
 
161
                                specific_files=['known_file', 'unknown_file'],
 
162
                                require_versioned=False)
145
163
        self.assertEqual(len(delta.added), 1)
146
164
 
147
165
 
148
 
class TestMultiWalker(TestCaseWithTransport):
149
 
 
150
 
    def assertStepOne(self, has_more, path, file_id, iterator):
151
 
        retval = _mod_tree.MultiWalker._step_one(iterator)
152
 
        if not has_more:
153
 
            self.assertIs(None, path)
154
 
            self.assertIs(None, file_id)
155
 
            self.assertEqual((False, None, None), retval)
156
 
        else:
157
 
            self.assertEqual((has_more, path, file_id),
158
 
                             (retval[0], retval[1], retval[2].file_id))
159
 
 
160
 
    def test__step_one_empty(self):
161
 
        tree = self.make_branch_and_tree('empty')
162
 
        repo = tree.branch.repository
163
 
        empty_tree = repo.revision_tree(revision.NULL_REVISION)
164
 
 
165
 
        iterator = empty_tree.iter_entries_by_dir()
166
 
        self.assertStepOne(False, None, None, iterator)
167
 
        self.assertStepOne(False, None, None, iterator)
168
 
 
169
 
    def test__step_one(self):
170
 
        tree = self.make_branch_and_tree('tree')
171
 
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
172
 
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
173
 
 
174
 
        iterator = tree.iter_entries_by_dir()
175
 
        tree.lock_read()
176
 
        self.addCleanup(tree.unlock)
177
 
 
178
 
        root_id = tree.path2id('')
179
 
        self.assertStepOne(True, '', root_id, iterator)
180
 
        self.assertStepOne(True, 'a', 'a-id', iterator)
181
 
        self.assertStepOne(True, 'b', 'b-id', iterator)
182
 
        self.assertStepOne(True, 'b/c', 'c-id', iterator)
183
 
        self.assertStepOne(False, None, None, iterator)
184
 
        self.assertStepOne(False, None, None, iterator)
185
 
 
186
 
    def assertWalkerNext(self, exp_path, exp_file_id, master_has_node,
187
 
                         exp_other_paths, iterator):
188
 
        """Check what happens when we step the iterator.
189
 
 
190
 
        :param path: The path for this entry
191
 
        :param file_id: The file_id for this entry
192
 
        :param master_has_node: Does the master tree have this entry?
193
 
        :param exp_other_paths: A list of other_path values.
194
 
        :param iterator: The iterator to step
195
 
        """
196
 
        path, file_id, master_ie, other_values = iterator.next()
197
 
        self.assertEqual((exp_path, exp_file_id), (path, file_id),
198
 
                         'Master entry did not match')
199
 
        if master_has_node:
200
 
            self.assertIsNot(None, master_ie, 'master should have an entry')
201
 
        else:
202
 
            self.assertIs(None, master_ie, 'master should not have an entry')
203
 
        self.assertEqual(len(exp_other_paths), len(other_values),
204
 
                            'Wrong number of other entries')
205
 
        other_paths = []
206
 
        other_file_ids = []
207
 
        for path, ie in other_values:
208
 
            other_paths.append(path)
209
 
            if ie is None:
210
 
                other_file_ids.append(None)
211
 
            else:
212
 
                other_file_ids.append(ie.file_id)
213
 
 
214
 
        exp_file_ids = []
215
 
        for path in exp_other_paths:
216
 
            if path is None:
217
 
                exp_file_ids.append(None)
218
 
            else:
219
 
                exp_file_ids.append(file_id)
220
 
        self.assertEqual(exp_other_paths, other_paths, "Other paths incorrect")
221
 
        self.assertEqual(exp_file_ids, other_file_ids,
222
 
                         "Other file_ids incorrect")
223
 
 
224
 
    def lock_and_get_basis_and_root_id(self, tree):
225
 
        tree.lock_read()
226
 
        self.addCleanup(tree.unlock)
227
 
        basis_tree = tree.basis_tree()
228
 
        basis_tree.lock_read()
229
 
        self.addCleanup(basis_tree.unlock)
230
 
        root_id = tree.path2id('')
231
 
        return basis_tree, root_id
232
 
 
233
 
    def test_simple_stepping(self):
234
 
        tree = self.make_branch_and_tree('tree')
235
 
        self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
236
 
        tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
237
 
 
238
 
        tree.commit('first', rev_id='first-rev-id')
239
 
 
240
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
241
 
 
242
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
243
 
        iterator = walker.iter_all()
244
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
245
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
246
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
247
 
        self.assertWalkerNext(u'b/c', 'c-id', True, [u'b/c'], iterator)
248
 
        self.assertRaises(StopIteration, iterator.next)
249
 
 
250
 
    def test_master_has_extra(self):
251
 
        tree = self.make_branch_and_tree('tree')
252
 
        self.build_tree(['tree/a', 'tree/b/', 'tree/c', 'tree/d'])
253
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
254
 
 
255
 
        tree.commit('first', rev_id='first-rev-id')
256
 
 
257
 
        tree.add(['c'], ['c-id'])
258
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
259
 
 
260
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
261
 
        iterator = walker.iter_all()
262
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
263
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
264
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
265
 
        self.assertWalkerNext(u'c', 'c-id', True, [None], iterator)
266
 
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
267
 
        self.assertRaises(StopIteration, iterator.next)
268
 
 
269
 
    def test_master_renamed_to_earlier(self):
270
 
        """The record is still present, it just shows up early."""
271
 
        tree = self.make_branch_and_tree('tree')
272
 
        self.build_tree(['tree/a', 'tree/c', 'tree/d'])
273
 
        tree.add(['a', 'c', 'd'], ['a-id', 'c-id', 'd-id'])
274
 
        tree.commit('first', rev_id='first-rev-id')
275
 
        tree.rename_one('d', 'b')
276
 
 
277
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
278
 
 
279
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
280
 
        iterator = walker.iter_all()
281
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
282
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
283
 
        self.assertWalkerNext(u'b', 'd-id', True, [u'd'], iterator)
284
 
        self.assertWalkerNext(u'c', 'c-id', True, [u'c'], iterator)
285
 
        self.assertRaises(StopIteration, iterator.next)
286
 
 
287
 
    def test_master_renamed_to_later(self):
288
 
        tree = self.make_branch_and_tree('tree')
289
 
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
290
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
291
 
        tree.commit('first', rev_id='first-rev-id')
292
 
        tree.rename_one('b', 'e')
293
 
 
294
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
295
 
 
296
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
297
 
        iterator = walker.iter_all()
298
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
299
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
300
 
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
301
 
        self.assertWalkerNext(u'e', 'b-id', True, [u'b'], iterator)
302
 
        self.assertRaises(StopIteration, iterator.next)
303
 
 
304
 
    def test_other_extra_in_middle(self):
305
 
        tree = self.make_branch_and_tree('tree')
306
 
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
307
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
308
 
        tree.commit('first', rev_id='first-rev-id')
309
 
        tree.remove(['b'])
310
 
 
311
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
312
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
313
 
        iterator = walker.iter_all()
314
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
315
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
316
 
        self.assertWalkerNext(u'd', 'd-id', True, [u'd'], iterator)
317
 
        self.assertWalkerNext(u'b', 'b-id', False, [u'b'], iterator)
318
 
        self.assertRaises(StopIteration, iterator.next)
319
 
 
320
 
    def test_other_extra_at_end(self):
321
 
        tree = self.make_branch_and_tree('tree')
322
 
        self.build_tree(['tree/a', 'tree/b', 'tree/d'])
323
 
        tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
324
 
        tree.commit('first', rev_id='first-rev-id')
325
 
        tree.remove(['d'])
326
 
 
327
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
328
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree])
329
 
        iterator = walker.iter_all()
330
 
        self.assertWalkerNext(u'', root_id, True, [u''], iterator)
331
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a'], iterator)
332
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b'], iterator)
333
 
        self.assertWalkerNext(u'd', 'd-id', False, [u'd'], iterator)
334
 
        self.assertRaises(StopIteration, iterator.next)
335
 
 
336
 
    def test_others_extra_at_end(self):
337
 
        tree = self.make_branch_and_tree('tree')
338
 
        self.build_tree(['tree/a', 'tree/b', 'tree/c', 'tree/d', 'tree/e'])
339
 
        tree.add(['a', 'b', 'c', 'd', 'e'],
340
 
                 ['a-id', 'b-id', 'c-id', 'd-id', 'e-id'])
341
 
        tree.commit('first', rev_id='first-rev-id')
342
 
        tree.remove(['e'])
343
 
        tree.commit('second', rev_id='second-rev-id')
344
 
        tree.remove(['d'])
345
 
        tree.commit('third', rev_id='third-rev-id')
346
 
        tree.remove(['c'])
347
 
 
348
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
349
 
        first_tree = tree.branch.repository.revision_tree('first-rev-id')
350
 
        second_tree = tree.branch.repository.revision_tree('second-rev-id')
351
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree, first_tree,
352
 
                                              second_tree])
353
 
        iterator = walker.iter_all()
354
 
        self.assertWalkerNext(u'', root_id, True, [u'', u'', u''], iterator)
355
 
        self.assertWalkerNext(u'a', 'a-id', True, [u'a', u'a', u'a'], iterator)
356
 
        self.assertWalkerNext(u'b', 'b-id', True, [u'b', u'b', u'b'], iterator)
357
 
        self.assertWalkerNext(u'c', 'c-id', False, [u'c', u'c', u'c'], iterator)
358
 
        self.assertWalkerNext(u'd', 'd-id', False, [None, u'd', u'd'], iterator)
359
 
        self.assertWalkerNext(u'e', 'e-id', False, [None, u'e', None], iterator)
360
 
        self.assertRaises(StopIteration, iterator.next)
361
 
 
362
 
    def test_different_file_id_in_others(self):
363
 
        tree = self.make_branch_and_tree('tree')
364
 
        self.build_tree(['tree/a', 'tree/b', 'tree/c/'])
365
 
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
366
 
        tree.commit('first', rev_id='first-rev-id')
367
 
 
368
 
        tree.rename_one('b', 'c/d')
369
 
        self.build_tree(['tree/b'])
370
 
        tree.add(['b'], ['b2-id'])
371
 
        tree.commit('second', rev_id='second-rev-id')
372
 
 
373
 
        tree.rename_one('a', 'c/e')
374
 
        self.build_tree(['tree/a'])
375
 
        tree.add(['a'], ['a2-id'])
376
 
 
377
 
        basis_tree, root_id = self.lock_and_get_basis_and_root_id(tree)
378
 
        first_tree = tree.branch.repository.revision_tree('first-rev-id')
379
 
        walker = _mod_tree.MultiWalker(tree, [basis_tree, first_tree])
380
 
 
381
 
        iterator = walker.iter_all()
382
 
        self.assertWalkerNext(u'', root_id, True, [u'', u''], iterator)
383
 
        self.assertWalkerNext(u'a', 'a2-id', True, [None, None], iterator)
384
 
        self.assertWalkerNext(u'b', 'b2-id', True, [u'b', None], iterator)
385
 
        self.assertWalkerNext(u'c', 'c-id', True, [u'c', u'c'], iterator)
386
 
        self.assertWalkerNext(u'c/d', 'b-id', True, [u'c/d', u'b'], iterator)
387
 
        self.assertWalkerNext(u'c/e', 'a-id', True, [u'a', u'a'], iterator)
388
 
        self.assertRaises(StopIteration, iterator.next)
389
 
 
390
 
    def assertCmpByDirblock(self, cmp_val, path1, path2):
391
 
        self.assertEqual(cmp_val,
392
 
            _mod_tree.MultiWalker._cmp_path_by_dirblock(path1, path2))
393
 
 
394
 
    def test__cmp_path_by_dirblock(self):
395
 
        # We only support Unicode strings at this point
396
 
        self.assertRaises(TypeError,
397
 
            _mod_tree.MultiWalker._cmp_path_by_dirblock, '', 'b')
398
 
        self.assertCmpByDirblock(0, u'', u'')
399
 
        self.assertCmpByDirblock(0, u'a', u'a')
400
 
        self.assertCmpByDirblock(0, u'a/b', u'a/b')
401
 
        self.assertCmpByDirblock(0, u'a/b/c', u'a/b/c')
402
 
        self.assertCmpByDirblock(1, u'a-a', u'a')
403
 
        self.assertCmpByDirblock(-1, u'a-a', u'a/a')
404
 
        self.assertCmpByDirblock(-1, u'a=a', u'a/a')
405
 
        self.assertCmpByDirblock(1, u'a-a/a', u'a/a')
406
 
        self.assertCmpByDirblock(1, u'a=a/a', u'a/a')
407
 
        self.assertCmpByDirblock(1, u'a-a/a', u'a/a/a')
408
 
        self.assertCmpByDirblock(1, u'a=a/a', u'a/a/a')
409
 
        self.assertCmpByDirblock(1, u'a-a/a/a', u'a/a/a')
410
 
        self.assertCmpByDirblock(1, u'a=a/a/a', u'a/a/a')
411
 
 
412
 
    def assertPathToKey(self, expected, path):
413
 
        self.assertEqual(expected, _mod_tree.MultiWalker._path_to_key(path))
414
 
 
415
 
    def test__path_to_key(self):
416
 
        self.assertPathToKey(([u''], u''), u'')
417
 
        self.assertPathToKey(([u''], u'a'), u'a')
418
 
        self.assertPathToKey(([u'a'], u'b'), u'a/b')
419
 
        self.assertPathToKey(([u'a', u'b'], u'c'), u'a/b/c')
 
166
class FindPreviousPathsTests(TestCaseWithTransport):
 
167
 
 
168
    def test_new(self):
 
169
        tree = self.make_branch_and_tree('tree')
 
170
        self.build_tree(['tree/b'])
 
171
        tree.add(['b'])
 
172
        revid1 = tree.commit('first')
 
173
        tree1 = tree.branch.repository.revision_tree(revid1)
 
174
 
 
175
        tree0 = tree.branch.repository.revision_tree(revision.NULL_REVISION)
 
176
 
 
177
        self.assertEqual({'b': None}, find_previous_paths(tree1, tree0, ['b']))
 
178
 
 
179
    def test_find_previous_paths(self):
 
180
        tree = self.make_branch_and_tree('tree')
 
181
        self.build_tree(['tree/b'])
 
182
        tree.add(['b'])
 
183
        revid1 = tree.commit('first')
 
184
        tree1 = tree.branch.repository.revision_tree(revid1)
 
185
 
 
186
        tree.rename_one('b', 'c')
 
187
        self.build_tree(['tree/b'])
 
188
        tree.add(['b'])
 
189
        revid2 = tree.commit('second')
 
190
        tree2 = tree.branch.repository.revision_tree(revid2)
 
191
 
 
192
        self.assertEqual({'c': 'b', 'b': None},
 
193
                         find_previous_paths(tree2, tree1, ['b', 'c']))
 
194
 
 
195
 
 
196
class GetCanonicalPath(TestCaseWithTransport):
 
197
 
 
198
    def test_existing_case(self):
 
199
        # Test that we can find a file from a path with different case
 
200
        tree = self.make_branch_and_tree('tree')
 
201
        self.build_tree(['tree/b'])
 
202
        tree.add(['b'])
 
203
        self.assertEqual(
 
204
            'b',
 
205
            get_canonical_path(tree, 'b', lambda x: x.lower()))
 
206
        self.assertEqual(
 
207
            'b',
 
208
            get_canonical_path(tree, 'B', lambda x: x.lower()))
 
209
 
 
210
    def test_nonexistant_preserves_case(self):
 
211
        tree = self.make_branch_and_tree('tree')
 
212
        self.assertEqual(
 
213
            'b',
 
214
            get_canonical_path(tree, 'b', lambda x: x.lower()))
 
215
        self.assertEqual(
 
216
            'B',
 
217
            get_canonical_path(tree, 'B', lambda x: x.lower()))
 
218
 
 
219
    def test_in_directory_with_case(self):
 
220
        tree = self.make_branch_and_tree('tree')
 
221
        self.build_tree(['tree/a/', 'tree/a/b'])
 
222
        tree.add(['a', 'a/b'])
 
223
        self.assertEqual(
 
224
            'a/b',
 
225
            get_canonical_path(tree, 'a/b', lambda x: x.lower()))
 
226
        self.assertEqual(
 
227
            'a/b',
 
228
            get_canonical_path(tree, 'A/B', lambda x: x.lower()))
 
229
        self.assertEqual(
 
230
            'a/b',
 
231
            get_canonical_path(tree, 'A/b', lambda x: x.lower()))
 
232
        self.assertEqual(
 
233
            'a/C',
 
234
            get_canonical_path(tree, 'A/C', lambda x: x.lower()))