~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: Vincent Ladeuil
  • Date: 2010-07-07 15:03:14 UTC
  • mto: (5355.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5356.
  • Revision ID: v.ladeuil+lp@free.fr-20100707150314-7i5po3dwg8umiv8x
Fix remaining sphinx_conf references.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import stat
19
18
from StringIO import StringIO
20
19
import sys
 
20
import time
21
21
 
22
22
from bzrlib import (
23
23
    bencode,
24
24
    errors,
 
25
    filters,
25
26
    generate_ids,
26
27
    osutils,
27
 
    progress,
28
28
    revision as _mod_revision,
29
 
    symbol_versioning,
 
29
    rules,
30
30
    tests,
31
31
    urlutils,
32
32
    )
33
33
from bzrlib.bzrdir import BzrDir
34
 
from bzrlib.conflicts import (DuplicateEntry, DuplicateID, MissingParent,
35
 
                              UnversionedParent, ParentLoop, DeletingParent,
36
 
                              NonDirectoryParent)
 
34
from bzrlib.conflicts import (
 
35
    DeletingParent,
 
36
    DuplicateEntry,
 
37
    DuplicateID,
 
38
    MissingParent,
 
39
    NonDirectoryParent,
 
40
    ParentLoop,
 
41
    UnversionedParent,
 
42
)
37
43
from bzrlib.diff import show_diff_trees
38
 
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
39
 
                           ReusingTransform, CantMoveRoot,
40
 
                           PathsNotVersionedError, ExistingLimbo,
41
 
                           ExistingPendingDeletion, ImmortalLimbo,
42
 
                           ImmortalPendingDeletion, LockError)
43
 
from bzrlib.osutils import file_kind, pathjoin
 
44
from bzrlib.errors import (
 
45
    DuplicateKey,
 
46
    ExistingLimbo,
 
47
    ExistingPendingDeletion,
 
48
    ImmortalLimbo,
 
49
    ImmortalPendingDeletion,
 
50
    LockError,
 
51
    MalformedTransform,
 
52
    NoSuchFile,
 
53
    ReusingTransform,
 
54
)
 
55
from bzrlib.osutils import (
 
56
    file_kind,
 
57
    pathjoin,
 
58
)
44
59
from bzrlib.merge import Merge3Merger, Merger
45
60
from bzrlib.tests import (
46
61
    HardlinkFeature,
48
63
    TestCase,
49
64
    TestCaseInTempDir,
50
65
    TestSkipped,
51
 
    )
52
 
from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths,
53
 
                              resolve_conflicts, cook_conflicts,
54
 
                              build_tree, get_backup_name,
55
 
                              _FileMover, resolve_checkout,
56
 
                              TransformPreview, create_from_tree)
 
66
)
 
67
from bzrlib.transform import (
 
68
    build_tree,
 
69
    create_from_tree,
 
70
    cook_conflicts,
 
71
    _FileMover,
 
72
    FinalPaths,
 
73
    get_backup_name,
 
74
    resolve_conflicts,
 
75
    resolve_checkout,
 
76
    ROOT_PARENT,
 
77
    TransformPreview,
 
78
    TreeTransform,
 
79
)
57
80
 
58
81
 
59
82
class TestTreeTransform(tests.TestCaseWithTransport):
136
159
        transform.finalize()
137
160
        transform.finalize()
138
161
 
 
162
    def test_create_files_same_timestamp(self):
 
163
        transform, root = self.get_transform()
 
164
        self.wt.lock_tree_write()
 
165
        self.addCleanup(self.wt.unlock)
 
166
        # Roll back the clock, so that we know everything is being set to the
 
167
        # exact time
 
168
        transform._creation_mtime = creation_mtime = time.time() - 20.0
 
169
        transform.create_file('content-one',
 
170
                              transform.create_path('one', root))
 
171
        time.sleep(1) # *ugly*
 
172
        transform.create_file('content-two',
 
173
                              transform.create_path('two', root))
 
174
        transform.apply()
 
175
        fo, st1 = self.wt.get_file_with_stat(None, path='one', filtered=False)
 
176
        fo.close()
 
177
        fo, st2 = self.wt.get_file_with_stat(None, path='two', filtered=False)
 
178
        fo.close()
 
179
        # We only guarantee 2s resolution
 
180
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
 
181
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
 
182
        # But if we have more than that, all files should get the same result
 
183
        self.assertEqual(st1.st_mtime, st2.st_mtime)
 
184
 
 
185
    def test_change_root_id(self):
 
186
        transform, root = self.get_transform()
 
187
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
 
188
        transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
189
        transform.delete_contents(root)
 
190
        transform.unversion_file(root)
 
191
        transform.fixup_new_roots()
 
192
        transform.apply()
 
193
        self.assertEqual('new-root-id', self.wt.get_root_id())
 
194
 
 
195
    def test_change_root_id_add_files(self):
 
196
        transform, root = self.get_transform()
 
197
        self.assertNotEqual('new-root-id', self.wt.get_root_id())
 
198
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
199
        transform.new_file('file', new_trans_id, ['new-contents\n'],
 
200
                           'new-file-id')
 
201
        transform.delete_contents(root)
 
202
        transform.unversion_file(root)
 
203
        transform.fixup_new_roots()
 
204
        transform.apply()
 
205
        self.assertEqual('new-root-id', self.wt.get_root_id())
 
206
        self.assertEqual('new-file-id', self.wt.path2id('file'))
 
207
        self.assertFileEqual('new-contents\n', self.wt.abspath('file'))
 
208
 
 
209
    def test_add_two_roots(self):
 
210
        transform, root = self.get_transform()
 
211
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
212
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
 
213
        self.assertRaises(ValueError, transform.fixup_new_roots)
 
214
 
139
215
    def test_hardlink(self):
140
216
        self.requireFeature(HardlinkFeature)
141
217
        transform, root = self.get_transform()
369
445
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
370
446
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
371
447
 
 
448
    def test_adjust_path_updates_child_limbo_names(self):
 
449
        tree = self.make_branch_and_tree('tree')
 
450
        transform = TreeTransform(tree)
 
451
        self.addCleanup(transform.finalize)
 
452
        foo_id = transform.new_directory('foo', transform.root)
 
453
        bar_id = transform.new_directory('bar', foo_id)
 
454
        baz_id = transform.new_directory('baz', bar_id)
 
455
        qux_id = transform.new_directory('qux', baz_id)
 
456
        transform.adjust_path('quxx', foo_id, bar_id)
 
457
        self.assertStartsWith(transform._limbo_name(qux_id),
 
458
                              transform._limbo_name(bar_id))
 
459
 
372
460
    def test_add_del(self):
373
461
        start, root = self.get_transform()
374
462
        start.new_directory('a', root, 'a')
669
757
                                         ' versioned, but has versioned'
670
758
                                         ' children.  Versioned directory.')
671
759
        self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
672
 
                                         ' oz/emeraldcity.  Cancelled move.')
 
760
                                         ' oz/emeraldcity. Cancelled move.')
673
761
 
674
762
    def prepare_wrong_parent_kind(self):
675
763
        tt, root = self.get_transform()
746
834
        create.apply()
747
835
        transform, root = self.get_transform()
748
836
        transform.adjust_root_path('oldroot', fun)
749
 
        new_root=transform.trans_id_tree_path('')
 
837
        new_root = transform.trans_id_tree_path('')
750
838
        transform.version_file('new-root', new_root)
751
839
        transform.apply()
752
840
 
764
852
        rename.set_executability(True, myfile)
765
853
        rename.apply()
766
854
 
 
855
    def test_rename_fails(self):
 
856
        # see https://bugs.launchpad.net/bzr/+bug/491763
 
857
        create, root_id = self.get_transform()
 
858
        first_dir = create.new_directory('first-dir', root_id, 'first-id')
 
859
        myfile = create.new_file('myfile', root_id, 'myfile-text',
 
860
                                 'myfile-id')
 
861
        create.apply()
 
862
        # make the file and directory readonly in the hope this will prevent
 
863
        # renames
 
864
        osutils.make_readonly(self.wt.abspath('first-dir'))
 
865
        osutils.make_readonly(self.wt.abspath('myfile'))
 
866
        # now transform to rename
 
867
        rename_transform, root_id = self.get_transform()
 
868
        file_trans_id = rename_transform.trans_id_file_id('myfile-id')
 
869
        dir_id = rename_transform.trans_id_file_id('first-id')
 
870
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
 
871
        e = self.assertRaises(errors.TransformRenameFailed,
 
872
            rename_transform.apply)
 
873
        # Looks like: 
 
874
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
 
875
        # to .../first-dir/newname: [Errno 13] Permission denied"
 
876
        # so the first filename is not visible in it; we expect a strerror but
 
877
        # it may vary per OS and language so it's not checked here
 
878
        self.assertContainsRe(str(e),
 
879
            "Failed to rename .*first-dir.newname:")
 
880
 
767
881
    def test_set_executability_order(self):
768
882
        """Ensure that executability behaves the same, no matter what order.
769
883
 
1856
1970
        self.assertEqual([], list(target.iter_changes(revision_tree)))
1857
1971
        self.assertTrue(source.is_executable('file1-id'))
1858
1972
 
 
1973
    def install_rot13_content_filter(self, pattern):
 
1974
        # We could use
 
1975
        # self.addCleanup(filters._reset_registry, filters._reset_registry())
 
1976
        # below, but that looks a bit... hard to read even if it's exactly
 
1977
        # the same thing.
 
1978
        original_registry = filters._reset_registry()
 
1979
        def restore_registry():
 
1980
            filters._reset_registry(original_registry)
 
1981
        self.addCleanup(restore_registry)
 
1982
        def rot13(chunks, context=None):
 
1983
            return [''.join(chunks).encode('rot13')]
 
1984
        rot13filter = filters.ContentFilter(rot13, rot13)
 
1985
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
 
1986
        os.mkdir(self.test_home_dir + '/.bazaar')
 
1987
        rules_filename = self.test_home_dir + '/.bazaar/rules'
 
1988
        f = open(rules_filename, 'wb')
 
1989
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
 
1990
        f.close()
 
1991
        def uninstall_rules():
 
1992
            os.remove(rules_filename)
 
1993
            rules.reset_rules()
 
1994
        self.addCleanup(uninstall_rules)
 
1995
        rules.reset_rules()
 
1996
 
 
1997
    def test_build_tree_content_filtered_files_are_not_hardlinked(self):
 
1998
        """build_tree will not hardlink files that have content filtering rules
 
1999
        applied to them (but will still hardlink other files from the same tree
 
2000
        if it can).
 
2001
        """
 
2002
        self.requireFeature(HardlinkFeature)
 
2003
        self.install_rot13_content_filter('file1')
 
2004
        source = self.create_ab_tree()
 
2005
        target = self.make_branch_and_tree('target')
 
2006
        revision_tree = source.basis_tree()
 
2007
        revision_tree.lock_read()
 
2008
        self.addCleanup(revision_tree.unlock)
 
2009
        build_tree(revision_tree, target, source, hardlink=True)
 
2010
        target.lock_read()
 
2011
        self.addCleanup(target.unlock)
 
2012
        self.assertEqual([], list(target.iter_changes(revision_tree)))
 
2013
        source_stat = os.stat('source/file1')
 
2014
        target_stat = os.stat('target/file1')
 
2015
        self.assertNotEqual(source_stat, target_stat)
 
2016
        source_stat = os.stat('source/file2')
 
2017
        target_stat = os.stat('target/file2')
 
2018
        self.assertEqualStat(source_stat, target_stat)
 
2019
 
1859
2020
    def test_case_insensitive_build_tree_inventory(self):
1860
2021
        if (tests.CaseInsensitiveFilesystemFeature.available()
1861
2022
            or tests.CaseInsCasePresFilenameFeature.available()):
1916
2077
        branch.lock_write()
1917
2078
        self.addCleanup(branch.unlock)
1918
2079
        tt = TransformPreview(branch.basis_tree())
 
2080
        self.addCleanup(tt.finalize)
1919
2081
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
1920
2082
        rev = tt.commit(branch, 'my message')
1921
2083
        self.assertEqual([], branch.basis_tree().get_parent_ids())
1927
2089
        branch.lock_write()
1928
2090
        self.addCleanup(branch.unlock)
1929
2091
        tt = TransformPreview(branch.basis_tree())
 
2092
        self.addCleanup(tt.finalize)
1930
2093
        e = self.assertRaises(ValueError, tt.commit, branch,
1931
2094
                          'my message', ['rev1b-id'])
1932
2095
        self.assertEqual('Cannot supply merge parents for first commit.',
1937
2100
        branch, tt = self.get_branch_and_transform()
1938
2101
        tt.new_file('file', tt.root, 'contents', 'file-id')
1939
2102
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
1940
 
        tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
 
2103
        if SymlinkFeature.available():
 
2104
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
1941
2105
        rev = tt.commit(branch, 'message')
1942
2106
        tree = branch.basis_tree()
1943
2107
        self.assertEqual('file', tree.id2path('file-id'))
1944
2108
        self.assertEqual('contents', tree.get_file_text('file-id'))
1945
2109
        self.assertEqual('dir', tree.id2path('dir-id'))
1946
 
        self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
1947
 
        self.assertEqual('target', tree.get_symlink_target('symlink-id'))
 
2110
        if SymlinkFeature.available():
 
2111
            self.assertEqual('dir/symlink', tree.id2path('symlink-id'))
 
2112
            self.assertEqual('target', tree.get_symlink_target('symlink-id'))
1948
2113
 
1949
2114
    def test_add_unversioned(self):
1950
2115
        branch, tt = self.get_branch_and_transform()
1957
2122
        tt.new_file('file', tt.root, 'contents', 'file-id')
1958
2123
        tt.commit(branch, 'message', strict=True)
1959
2124
        tt = TransformPreview(branch.basis_tree())
 
2125
        self.addCleanup(tt.finalize)
1960
2126
        trans_id = tt.trans_id_file_id('file-id')
1961
2127
        tt.delete_contents(trans_id)
1962
2128
        tt.create_file('contents', trans_id)
1973
2139
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
1974
2140
                          'message')
1975
2141
 
 
2142
    def test_commit_rich_revision_data(self):
 
2143
        branch, tt = self.get_branch_and_transform()
 
2144
        rev_id = tt.commit(branch, 'message', timestamp=1, timezone=43201,
 
2145
                           committer='me <me@example.com>',
 
2146
                           revprops={'foo': 'bar'}, revision_id='revid-1',
 
2147
                           authors=['Author1 <author1@example.com>',
 
2148
                              'Author2 <author2@example.com>',
 
2149
                               ])
 
2150
        self.assertEqual('revid-1', rev_id)
 
2151
        revision = branch.repository.get_revision(rev_id)
 
2152
        self.assertEqual(1, revision.timestamp)
 
2153
        self.assertEqual(43201, revision.timezone)
 
2154
        self.assertEqual('me <me@example.com>', revision.committer)
 
2155
        self.assertEqual(['Author1 <author1@example.com>',
 
2156
                          'Author2 <author2@example.com>'],
 
2157
                         revision.get_apparent_authors())
 
2158
        del revision.properties['authors']
 
2159
        self.assertEqual({'foo': 'bar',
 
2160
                          'branch-nick': 'tree'},
 
2161
                         revision.properties)
 
2162
 
 
2163
    def test_no_explicit_revprops(self):
 
2164
        branch, tt = self.get_branch_and_transform()
 
2165
        rev_id = tt.commit(branch, 'message', authors=[
 
2166
            'Author1 <author1@example.com>',
 
2167
            'Author2 <author2@example.com>', ])
 
2168
        revision = branch.repository.get_revision(rev_id)
 
2169
        self.assertEqual(['Author1 <author1@example.com>',
 
2170
                          'Author2 <author2@example.com>'],
 
2171
                         revision.get_apparent_authors())
 
2172
        self.assertEqual('tree', revision.properties['branch-nick'])
 
2173
 
1976
2174
 
1977
2175
class MockTransform(object):
1978
2176
 
2146
2344
    def create_tree(self):
2147
2345
        tree = self.make_branch_and_tree('.')
2148
2346
        self.build_tree_contents([('a', 'content 1')])
 
2347
        tree.set_root_id('TREE_ROOT')
2149
2348
        tree.add('a', 'a-id')
2150
2349
        tree.commit('rev1', rev_id='rev1')
2151
2350
        return tree.branch.repository.revision_tree('rev1')
2252
2451
    def test_ignore_pb(self):
2253
2452
        # pb could be supported, but TT.iter_changes doesn't support it.
2254
2453
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2255
 
        preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
 
2454
        preview_tree.iter_changes(revision_tree)
2256
2455
 
2257
2456
    def test_kind(self):
2258
2457
        revision_tree = self.create_tree()
2273
2472
        self.assertEqual(os.stat(limbo_path).st_mtime,
2274
2473
                         preview_tree.get_file_mtime('file-id'))
2275
2474
 
 
2475
    def test_get_file_mtime_renamed(self):
 
2476
        work_tree = self.make_branch_and_tree('tree')
 
2477
        self.build_tree(['tree/file'])
 
2478
        work_tree.add('file', 'file-id')
 
2479
        preview = TransformPreview(work_tree)
 
2480
        self.addCleanup(preview.finalize)
 
2481
        file_trans_id = preview.trans_id_tree_file_id('file-id')
 
2482
        preview.adjust_path('renamed', preview.root, file_trans_id)
 
2483
        preview_tree = preview.get_preview_tree()
 
2484
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
 
2485
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
 
2486
 
2276
2487
    def test_get_file(self):
2277
2488
        preview = self.get_empty_preview()
2278
2489
        preview.new_file('file', preview.root, 'contents', 'file-id')
2426
2637
        self.assertEqual(('missing', None, None, None), summary)
2427
2638
 
2428
2639
    def test_file_content_summary_executable(self):
2429
 
        if not osutils.supports_executable():
2430
 
            raise TestNotApplicable()
2431
2640
        preview = self.get_empty_preview()
2432
2641
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2433
2642
        preview.set_executability(True, path_id)
2442
2651
        self.assertIs(None, summary[3])
2443
2652
 
2444
2653
    def test_change_executability(self):
2445
 
        if not osutils.supports_executable():
2446
 
            raise TestNotApplicable()
2447
2654
        tree = self.make_branch_and_tree('tree')
2448
2655
        self.build_tree(['tree/path'])
2449
2656
        tree.add('path')
2463
2670
        # size must be known
2464
2671
        self.assertEqual(len('contents'), summary[1])
2465
2672
        # not executable
2466
 
        if osutils.supports_executable():
2467
 
            self.assertEqual(False, summary[2])
2468
 
        else:
2469
 
            self.assertEqual(None, summary[2])
 
2673
        self.assertEqual(False, summary[2])
2470
2674
        # will not have hash (not cheap to determine)
2471
2675
        self.assertIs(None, summary[3])
2472
2676
 
2613
2817
 
2614
2818
    def test_walkdirs(self):
2615
2819
        preview = self.get_empty_preview()
2616
 
        preview.version_file('tree-root', preview.root)
 
2820
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
 
2821
        # FIXME: new_directory should mark root.
 
2822
        preview.fixup_new_roots()
2617
2823
        preview_tree = preview.get_preview_tree()
2618
2824
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2619
2825
                                         'a-id')
2650
2856
        self.addCleanup(work_tree.unlock)
2651
2857
        preview = TransformPreview(work_tree)
2652
2858
        self.addCleanup(preview.finalize)
2653
 
        preview_tree = preview.get_preview_tree()
2654
2859
        file_trans_id = preview.trans_id_file_id('file-id')
2655
2860
        preview.delete_contents(file_trans_id)
2656
2861
        preview.create_file('a\nb\n', file_trans_id)
2657
 
        pb = progress.DummyProgress()
2658
 
        merger = Merger.from_revision_ids(pb, preview_tree,
 
2862
        preview_tree = preview.get_preview_tree()
 
2863
        merger = Merger.from_revision_ids(None, preview_tree,
2659
2864
                                          child_tree.branch.last_revision(),
2660
2865
                                          other_branch=child_tree.branch,
2661
2866
                                          tree_branch=work_tree.branch)
2667
2872
 
2668
2873
    def test_merge_preview_into_workingtree(self):
2669
2874
        tree = self.make_branch_and_tree('tree')
 
2875
        tree.set_root_id('TREE_ROOT')
2670
2876
        tt = TransformPreview(tree)
2671
2877
        self.addCleanup(tt.finalize)
2672
2878
        tt.new_file('name', tt.root, 'content', 'file-id')
2673
2879
        tree2 = self.make_branch_and_tree('tree2')
2674
 
        pb = progress.DummyProgress()
 
2880
        tree2.set_root_id('TREE_ROOT')
2675
2881
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2676
 
                                         pb, tree.basis_tree())
 
2882
                                         None, tree.basis_tree())
2677
2883
        merger.merge_type = Merge3Merger
2678
2884
        merger.do_merge()
2679
2885
 
2689
2895
        tt.create_file('baz', trans_id)
2690
2896
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2691
2897
        self.build_tree_contents([('tree2/foo', 'qux')])
2692
 
        pb = progress.DummyProgress()
 
2898
        pb = None
2693
2899
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2694
2900
                                         pb, tree.basis_tree())
2695
2901
        merger.merge_type = Merge3Merger
2722
2928
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
2723
2929
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
2724
2930
 
 
2931
    def test_ascii_limbo_paths(self):
 
2932
        self.requireFeature(tests.UnicodeFilenameFeature)
 
2933
        branch = self.make_branch('any')
 
2934
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
 
2935
        tt = TransformPreview(tree)
 
2936
        self.addCleanup(tt.finalize)
 
2937
        foo_id = tt.new_directory('', ROOT_PARENT)
 
2938
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
 
2939
        limbo_path = tt._limbo_name(bar_id)
 
2940
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
 
2941
 
2725
2942
 
2726
2943
class FakeSerializer(object):
2727
2944
    """Serializer implementation that simply returns the input.