~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: John Arbash Meinel
  • Date: 2008-07-11 21:41:24 UTC
  • mto: This revision was merged to the branch mainline in revision 3543.
  • Revision ID: john@arbash-meinel.com-20080711214124-qi09irlj7pd5cuzg
Shortcut the case when one revision is in the ancestry of the other.

At the cost of a heads() check, when one parent supersedes, we don't have to extract
the text for the other. Changes merge time from 3m37s => 3m21s. Using a
CachingParentsProvider would drop the time down to 3m11s.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2006 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
40
40
                           ExistingPendingDeletion, ImmortalLimbo,
41
41
                           ImmortalPendingDeletion, LockError)
42
42
from bzrlib.osutils import file_kind, pathjoin
43
 
from bzrlib.merge import Merge3Merger, Merger
 
43
from bzrlib.merge import Merge3Merger
44
44
from bzrlib.tests import (
 
45
    CaseInsensitiveFilesystemFeature,
45
46
    HardlinkFeature,
46
47
    SymlinkFeature,
47
48
    TestCase,
52
53
                              resolve_conflicts, cook_conflicts, 
53
54
                              build_tree, get_backup_name,
54
55
                              _FileMover, resolve_checkout,
55
 
                              TransformPreview, create_from_tree)
56
 
from bzrlib.util import bencode
57
 
 
 
56
                              TransformPreview)
58
57
 
59
58
class TestTreeTransform(tests.TestCaseWithTransport):
60
59
 
1163
1162
        transform.cancel_creation(parent)
1164
1163
        transform.finalize()
1165
1164
 
1166
 
    def test_rollback_on_directory_clash(self):
 
1165
    def test_case_insensitive_clash(self):
 
1166
        self.requireFeature(CaseInsensitiveFilesystemFeature)
1167
1167
        def tt_helper():
1168
1168
            wt = self.make_branch_and_tree('.')
1169
1169
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1170
1170
            try:
1171
 
                foo = tt.new_directory('foo', tt.root)
1172
 
                tt.new_file('bar', foo, 'foobar')
1173
 
                baz = tt.new_directory('baz', tt.root)
1174
 
                tt.new_file('qux', baz, 'quux')
1175
 
                # Ask for a rename 'foo' -> 'baz'
1176
 
                tt.adjust_path('baz', tt.root, foo)
 
1171
                tt.new_file('foo', tt.root, 'bar')
 
1172
                tt.new_file('Foo', tt.root, 'spam')
1177
1173
                # Lie to tt that we've already resolved all conflicts.
1178
1174
                tt.apply(no_conflicts=True)
1179
1175
            except:
1180
1176
                wt.unlock()
1181
1177
                raise
1182
 
        # The rename will fail because the target directory is not empty (but
1183
 
        # raises FileExists anyway).
1184
1178
        err = self.assertRaises(errors.FileExists, tt_helper)
1185
1179
        self.assertContainsRe(str(err),
1186
 
            "^File exists: .+/baz")
 
1180
            "^File exists: .+/foo")
1187
1181
 
1188
1182
    def test_two_directories_clash(self):
1189
1183
        def tt_helper():
1192
1186
            try:
1193
1187
                foo_1 = tt.new_directory('foo', tt.root)
1194
1188
                tt.new_directory('bar', foo_1)
1195
 
                # Adding the same directory with a different content
1196
1189
                foo_2 = tt.new_directory('foo', tt.root)
1197
1190
                tt.new_directory('baz', foo_2)
1198
1191
                # Lie to tt that we've already resolved all conflicts.
1211
1204
            try:
1212
1205
                foo_1 = tt.new_directory('foo', tt.root)
1213
1206
                tt.new_directory('bar', foo_1)
1214
 
                # Adding the same directory with a different content
1215
1207
                foo_2 = tt.new_directory('foo', tt.root)
1216
1208
                tt.new_directory('baz', foo_2)
1217
1209
                # Lie to tt that we've already resolved all conflicts.
1223
1215
        self.assertContainsRe(str(err),
1224
1216
            "^File exists: .+/foo")
1225
1217
 
1226
 
    def test_file_to_directory(self):
1227
 
        wt = self.make_branch_and_tree('.')
1228
 
        self.build_tree(['foo'])
1229
 
        wt.add(['foo'])
1230
 
        wt.commit("one")
1231
 
        tt = TreeTransform(wt)
1232
 
        self.addCleanup(tt.finalize)
1233
 
        foo_trans_id = tt.trans_id_tree_path("foo")
1234
 
        tt.delete_contents(foo_trans_id)
1235
 
        tt.create_directory(foo_trans_id)
1236
 
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1237
 
        tt.create_file(["aa\n"], bar_trans_id)
1238
 
        tt.version_file("bar-1", bar_trans_id)
1239
 
        tt.apply()
1240
 
        self.failUnlessExists("foo/bar")
1241
 
        wt.lock_read()
1242
 
        try:
1243
 
            self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1244
 
                    "directory")
1245
 
        finally:
1246
 
            wt.unlock()
1247
 
        wt.commit("two")
1248
 
        changes = wt.changes_from(wt.basis_tree())
1249
 
        self.assertFalse(changes.has_changed(), changes)
1250
 
 
1251
 
    def test_file_to_symlink(self):
1252
 
        self.requireFeature(SymlinkFeature)
1253
 
        wt = self.make_branch_and_tree('.')
1254
 
        self.build_tree(['foo'])
1255
 
        wt.add(['foo'])
1256
 
        wt.commit("one")
1257
 
        tt = TreeTransform(wt)
1258
 
        self.addCleanup(tt.finalize)
1259
 
        foo_trans_id = tt.trans_id_tree_path("foo")
1260
 
        tt.delete_contents(foo_trans_id)
1261
 
        tt.create_symlink("bar", foo_trans_id)
1262
 
        tt.apply()
1263
 
        self.failUnlessExists("foo")
1264
 
        wt.lock_read()
1265
 
        self.addCleanup(wt.unlock)
1266
 
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1267
 
                "symlink")
1268
 
 
1269
 
    def test_dir_to_file(self):
1270
 
        wt = self.make_branch_and_tree('.')
1271
 
        self.build_tree(['foo/', 'foo/bar'])
1272
 
        wt.add(['foo', 'foo/bar'])
1273
 
        wt.commit("one")
1274
 
        tt = TreeTransform(wt)
1275
 
        self.addCleanup(tt.finalize)
1276
 
        foo_trans_id = tt.trans_id_tree_path("foo")
1277
 
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1278
 
        tt.delete_contents(foo_trans_id)
1279
 
        tt.delete_versioned(bar_trans_id)
1280
 
        tt.create_file(["aa\n"], foo_trans_id)
1281
 
        tt.apply()
1282
 
        self.failUnlessExists("foo")
1283
 
        wt.lock_read()
1284
 
        self.addCleanup(wt.unlock)
1285
 
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1286
 
                "file")
1287
 
 
1288
 
    def test_dir_to_hardlink(self):
1289
 
        self.requireFeature(HardlinkFeature)
1290
 
        wt = self.make_branch_and_tree('.')
1291
 
        self.build_tree(['foo/', 'foo/bar'])
1292
 
        wt.add(['foo', 'foo/bar'])
1293
 
        wt.commit("one")
1294
 
        tt = TreeTransform(wt)
1295
 
        self.addCleanup(tt.finalize)
1296
 
        foo_trans_id = tt.trans_id_tree_path("foo")
1297
 
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1298
 
        tt.delete_contents(foo_trans_id)
1299
 
        tt.delete_versioned(bar_trans_id)
1300
 
        self.build_tree(['baz'])
1301
 
        tt.create_hardlink("baz", foo_trans_id)
1302
 
        tt.apply()
1303
 
        self.failUnlessExists("foo")
1304
 
        self.failUnlessExists("baz")
1305
 
        wt.lock_read()
1306
 
        self.addCleanup(wt.unlock)
1307
 
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1308
 
                "file")
1309
 
 
1310
 
    def test_no_final_path(self):
1311
 
        transform, root = self.get_transform()
1312
 
        trans_id = transform.trans_id_file_id('foo')
1313
 
        transform.create_file('bar', trans_id)
1314
 
        transform.cancel_creation(trans_id)
1315
 
        transform.apply()
1316
 
 
1317
 
    def test_create_from_tree(self):
1318
 
        tree1 = self.make_branch_and_tree('tree1')
1319
 
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', 'baz')])
1320
 
        tree1.add(['foo', 'bar'], ['foo-id', 'bar-id'])
1321
 
        tree2 = self.make_branch_and_tree('tree2')
1322
 
        tt = TreeTransform(tree2)
1323
 
        foo_trans_id = tt.create_path('foo', tt.root)
1324
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1325
 
        bar_trans_id = tt.create_path('bar', tt.root)
1326
 
        create_from_tree(tt, bar_trans_id, tree1, 'bar-id')
1327
 
        tt.apply()
1328
 
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1329
 
        self.assertFileEqual('baz', 'tree2/bar')
1330
 
 
1331
 
    def test_create_from_tree_bytes(self):
1332
 
        """Provided lines are used instead of tree content."""
1333
 
        tree1 = self.make_branch_and_tree('tree1')
1334
 
        self.build_tree_contents([('tree1/foo', 'bar'),])
1335
 
        tree1.add('foo', 'foo-id')
1336
 
        tree2 = self.make_branch_and_tree('tree2')
1337
 
        tt = TreeTransform(tree2)
1338
 
        foo_trans_id = tt.create_path('foo', tt.root)
1339
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id', bytes='qux')
1340
 
        tt.apply()
1341
 
        self.assertFileEqual('qux', 'tree2/foo')
1342
 
 
1343
 
    def test_create_from_tree_symlink(self):
1344
 
        self.requireFeature(SymlinkFeature)
1345
 
        tree1 = self.make_branch_and_tree('tree1')
1346
 
        os.symlink('bar', 'tree1/foo')
1347
 
        tree1.add('foo', 'foo-id')
1348
 
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1349
 
        foo_trans_id = tt.create_path('foo', tt.root)
1350
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo-id')
1351
 
        tt.apply()
1352
 
        self.assertEqual('bar', os.readlink('tree2/foo'))
1353
 
 
1354
1218
 
1355
1219
class TransformGroup(object):
1356
1220
 
2014
1878
        resolve_conflicts(tt)
2015
1879
 
2016
1880
 
2017
 
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
2018
 
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2019
 
                  (False, False))
2020
 
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
2021
 
              ('', ''), ('directory', 'directory'), (False, None))
2022
 
 
2023
 
 
2024
1881
class TestTransformPreview(tests.TestCaseWithTransport):
2025
1882
 
2026
1883
    def create_tree(self):
2098
1955
                          (False, False))],
2099
1956
                          list(preview_tree.iter_changes(revision_tree)))
2100
1957
 
2101
 
    def test_include_unchanged_succeeds(self):
 
1958
    def test_wrong_tree_value_error(self):
2102
1959
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2103
 
        changes = preview_tree.iter_changes(revision_tree,
2104
 
                                            include_unchanged=True)
2105
 
        root = revision_tree.inventory.root.file_id
 
1960
        e = self.assertRaises(ValueError, preview_tree.iter_changes,
 
1961
                              preview_tree)
 
1962
        self.assertEqual('from_tree must be transform source tree.', str(e))
2106
1963
 
2107
 
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
 
1964
    def test_include_unchanged_value_error(self):
 
1965
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
 
1966
        e = self.assertRaises(ValueError, preview_tree.iter_changes,
 
1967
                              revision_tree, include_unchanged=True)
 
1968
        self.assertEqual('include_unchanged is not supported', str(e))
2108
1969
 
2109
1970
    def test_specific_files(self):
2110
1971
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2111
 
        changes = preview_tree.iter_changes(revision_tree,
2112
 
                                            specific_files=[''])
2113
 
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
 
1972
        e = self.assertRaises(ValueError, preview_tree.iter_changes,
 
1973
                              revision_tree, specific_files=['pete'])
 
1974
        self.assertEqual('specific_files is not supported', str(e))
2114
1975
 
2115
 
    def test_want_unversioned(self):
 
1976
    def test_want_unversioned_value_error(self):
2116
1977
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2117
 
        changes = preview_tree.iter_changes(revision_tree,
2118
 
                                            want_unversioned=True)
2119
 
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
 
1978
        e = self.assertRaises(ValueError, preview_tree.iter_changes,
 
1979
                              revision_tree, want_unversioned=True)
 
1980
        self.assertEqual('want_unversioned is not supported', str(e))
2120
1981
 
2121
1982
    def test_ignore_extra_trees_no_specific_files(self):
2122
1983
        # extra_trees is harmless without specific_files, so we'll silently
2170
2031
        preview_tree = preview.get_preview_tree()
2171
2032
        self.assertEqual('target',
2172
2033
                         preview_tree.get_symlink_target('symlink-id'))
2173
 
 
2174
 
    def test_all_file_ids(self):
2175
 
        tree = self.make_branch_and_tree('tree')
2176
 
        self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2177
 
        tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2178
 
        preview = TransformPreview(tree)
2179
 
        self.addCleanup(preview.finalize)
2180
 
        preview.unversion_file(preview.trans_id_file_id('b-id'))
2181
 
        c_trans_id = preview.trans_id_file_id('c-id')
2182
 
        preview.unversion_file(c_trans_id)
2183
 
        preview.version_file('c-id', c_trans_id)
2184
 
        preview_tree = preview.get_preview_tree()
2185
 
        self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2186
 
                         preview_tree.all_file_ids())
2187
 
 
2188
 
    def test_path2id_deleted_unchanged(self):
2189
 
        tree = self.make_branch_and_tree('tree')
2190
 
        self.build_tree(['tree/unchanged', 'tree/deleted'])
2191
 
        tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2192
 
        preview = TransformPreview(tree)
2193
 
        self.addCleanup(preview.finalize)
2194
 
        preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2195
 
        preview_tree = preview.get_preview_tree()
2196
 
        self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2197
 
        self.assertIs(None, preview_tree.path2id('deleted'))
2198
 
 
2199
 
    def test_path2id_created(self):
2200
 
        tree = self.make_branch_and_tree('tree')
2201
 
        self.build_tree(['tree/unchanged'])
2202
 
        tree.add(['unchanged'], ['unchanged-id'])
2203
 
        preview = TransformPreview(tree)
2204
 
        self.addCleanup(preview.finalize)
2205
 
        preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2206
 
            'contents', 'new-id')
2207
 
        preview_tree = preview.get_preview_tree()
2208
 
        self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2209
 
 
2210
 
    def test_path2id_moved(self):
2211
 
        tree = self.make_branch_and_tree('tree')
2212
 
        self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2213
 
        tree.add(['old_parent', 'old_parent/child'],
2214
 
                 ['old_parent-id', 'child-id'])
2215
 
        preview = TransformPreview(tree)
2216
 
        self.addCleanup(preview.finalize)
2217
 
        new_parent = preview.new_directory('new_parent', preview.root,
2218
 
                                           'new_parent-id')
2219
 
        preview.adjust_path('child', new_parent,
2220
 
                            preview.trans_id_file_id('child-id'))
2221
 
        preview_tree = preview.get_preview_tree()
2222
 
        self.assertIs(None, preview_tree.path2id('old_parent/child'))
2223
 
        self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2224
 
 
2225
 
    def test_path2id_renamed_parent(self):
2226
 
        tree = self.make_branch_and_tree('tree')
2227
 
        self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2228
 
        tree.add(['old_name', 'old_name/child'],
2229
 
                 ['parent-id', 'child-id'])
2230
 
        preview = TransformPreview(tree)
2231
 
        self.addCleanup(preview.finalize)
2232
 
        preview.adjust_path('new_name', preview.root,
2233
 
                            preview.trans_id_file_id('parent-id'))
2234
 
        preview_tree = preview.get_preview_tree()
2235
 
        self.assertIs(None, preview_tree.path2id('old_name/child'))
2236
 
        self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
2237
 
 
2238
 
    def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2239
 
        preview_tree = tt.get_preview_tree()
2240
 
        preview_result = list(preview_tree.iter_entries_by_dir(
2241
 
                              specific_file_ids))
2242
 
        tree = tt._tree
2243
 
        tt.apply()
2244
 
        actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2245
 
        self.assertEqual(actual_result, preview_result)
2246
 
 
2247
 
    def test_iter_entries_by_dir_new(self):
2248
 
        tree = self.make_branch_and_tree('tree')
2249
 
        tt = TreeTransform(tree)
2250
 
        tt.new_file('new', tt.root, 'contents', 'new-id')
2251
 
        self.assertMatchingIterEntries(tt)
2252
 
 
2253
 
    def test_iter_entries_by_dir_deleted(self):
2254
 
        tree = self.make_branch_and_tree('tree')
2255
 
        self.build_tree(['tree/deleted'])
2256
 
        tree.add('deleted', 'deleted-id')
2257
 
        tt = TreeTransform(tree)
2258
 
        tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2259
 
        self.assertMatchingIterEntries(tt)
2260
 
 
2261
 
    def test_iter_entries_by_dir_unversioned(self):
2262
 
        tree = self.make_branch_and_tree('tree')
2263
 
        self.build_tree(['tree/removed'])
2264
 
        tree.add('removed', 'removed-id')
2265
 
        tt = TreeTransform(tree)
2266
 
        tt.unversion_file(tt.trans_id_file_id('removed-id'))
2267
 
        self.assertMatchingIterEntries(tt)
2268
 
 
2269
 
    def test_iter_entries_by_dir_moved(self):
2270
 
        tree = self.make_branch_and_tree('tree')
2271
 
        self.build_tree(['tree/moved', 'tree/new_parent/'])
2272
 
        tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2273
 
        tt = TreeTransform(tree)
2274
 
        tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2275
 
                       tt.trans_id_file_id('moved-id'))
2276
 
        self.assertMatchingIterEntries(tt)
2277
 
 
2278
 
    def test_iter_entries_by_dir_specific_file_ids(self):
2279
 
        tree = self.make_branch_and_tree('tree')
2280
 
        tree.set_root_id('tree-root-id')
2281
 
        self.build_tree(['tree/parent/', 'tree/parent/child'])
2282
 
        tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2283
 
        tt = TreeTransform(tree)
2284
 
        self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
2285
 
 
2286
 
    def test_symlink_content_summary(self):
2287
 
        self.requireFeature(SymlinkFeature)
2288
 
        preview = self.get_empty_preview()
2289
 
        preview.new_symlink('path', preview.root, 'target', 'path-id')
2290
 
        summary = preview.get_preview_tree().path_content_summary('path')
2291
 
        self.assertEqual(('symlink', None, None, 'target'), summary)
2292
 
 
2293
 
    def test_missing_content_summary(self):
2294
 
        preview = self.get_empty_preview()
2295
 
        summary = preview.get_preview_tree().path_content_summary('path')
2296
 
        self.assertEqual(('missing', None, None, None), summary)
2297
 
 
2298
 
    def test_deleted_content_summary(self):
2299
 
        tree = self.make_branch_and_tree('tree')
2300
 
        self.build_tree(['tree/path/'])
2301
 
        tree.add('path')
2302
 
        preview = TransformPreview(tree)
2303
 
        self.addCleanup(preview.finalize)
2304
 
        preview.delete_contents(preview.trans_id_tree_path('path'))
2305
 
        summary = preview.get_preview_tree().path_content_summary('path')
2306
 
        self.assertEqual(('missing', None, None, None), summary)
2307
 
 
2308
 
    def test_file_content_summary_executable(self):
2309
 
        if not osutils.supports_executable():
2310
 
            raise TestNotApplicable()
2311
 
        preview = self.get_empty_preview()
2312
 
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2313
 
        preview.set_executability(True, path_id)
2314
 
        summary = preview.get_preview_tree().path_content_summary('path')
2315
 
        self.assertEqual(4, len(summary))
2316
 
        self.assertEqual('file', summary[0])
2317
 
        # size must be known
2318
 
        self.assertEqual(len('contents'), summary[1])
2319
 
        # executable
2320
 
        self.assertEqual(True, summary[2])
2321
 
        # will not have hash (not cheap to determine)
2322
 
        self.assertIs(None, summary[3])
2323
 
 
2324
 
    def test_change_executability(self):
2325
 
        if not osutils.supports_executable():
2326
 
            raise TestNotApplicable()
2327
 
        tree = self.make_branch_and_tree('tree')
2328
 
        self.build_tree(['tree/path'])
2329
 
        tree.add('path')
2330
 
        preview = TransformPreview(tree)
2331
 
        self.addCleanup(preview.finalize)
2332
 
        path_id = preview.trans_id_tree_path('path')
2333
 
        preview.set_executability(True, path_id)
2334
 
        summary = preview.get_preview_tree().path_content_summary('path')
2335
 
        self.assertEqual(True, summary[2])
2336
 
 
2337
 
    def test_file_content_summary_non_exec(self):
2338
 
        preview = self.get_empty_preview()
2339
 
        preview.new_file('path', preview.root, 'contents', 'path-id')
2340
 
        summary = preview.get_preview_tree().path_content_summary('path')
2341
 
        self.assertEqual(4, len(summary))
2342
 
        self.assertEqual('file', summary[0])
2343
 
        # size must be known
2344
 
        self.assertEqual(len('contents'), summary[1])
2345
 
        # not executable
2346
 
        if osutils.supports_executable():
2347
 
            self.assertEqual(False, summary[2])
2348
 
        else:
2349
 
            self.assertEqual(None, summary[2])
2350
 
        # will not have hash (not cheap to determine)
2351
 
        self.assertIs(None, summary[3])
2352
 
 
2353
 
    def test_dir_content_summary(self):
2354
 
        preview = self.get_empty_preview()
2355
 
        preview.new_directory('path', preview.root, 'path-id')
2356
 
        summary = preview.get_preview_tree().path_content_summary('path')
2357
 
        self.assertEqual(('directory', None, None, None), summary)
2358
 
 
2359
 
    def test_tree_content_summary(self):
2360
 
        preview = self.get_empty_preview()
2361
 
        path = preview.new_directory('path', preview.root, 'path-id')
2362
 
        preview.set_tree_reference('rev-1', path)
2363
 
        summary = preview.get_preview_tree().path_content_summary('path')
2364
 
        self.assertEqual(4, len(summary))
2365
 
        self.assertEqual('tree-reference', summary[0])
2366
 
 
2367
 
    def test_annotate(self):
2368
 
        tree = self.make_branch_and_tree('tree')
2369
 
        self.build_tree_contents([('tree/file', 'a\n')])
2370
 
        tree.add('file', 'file-id')
2371
 
        tree.commit('a', rev_id='one')
2372
 
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2373
 
        preview = TransformPreview(tree)
2374
 
        self.addCleanup(preview.finalize)
2375
 
        file_trans_id = preview.trans_id_file_id('file-id')
2376
 
        preview.delete_contents(file_trans_id)
2377
 
        preview.create_file('a\nb\nc\n', file_trans_id)
2378
 
        preview_tree = preview.get_preview_tree()
2379
 
        expected = [
2380
 
            ('one', 'a\n'),
2381
 
            ('me:', 'b\n'),
2382
 
            ('me:', 'c\n'),
2383
 
        ]
2384
 
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2385
 
        self.assertEqual(expected, annotation)
2386
 
 
2387
 
    def test_annotate_missing(self):
2388
 
        preview = self.get_empty_preview()
2389
 
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2390
 
        preview_tree = preview.get_preview_tree()
2391
 
        expected = [
2392
 
            ('me:', 'a\n'),
2393
 
            ('me:', 'b\n'),
2394
 
            ('me:', 'c\n'),
2395
 
         ]
2396
 
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2397
 
        self.assertEqual(expected, annotation)
2398
 
 
2399
 
    def test_annotate_rename(self):
2400
 
        tree = self.make_branch_and_tree('tree')
2401
 
        self.build_tree_contents([('tree/file', 'a\n')])
2402
 
        tree.add('file', 'file-id')
2403
 
        tree.commit('a', rev_id='one')
2404
 
        preview = TransformPreview(tree)
2405
 
        self.addCleanup(preview.finalize)
2406
 
        file_trans_id = preview.trans_id_file_id('file-id')
2407
 
        preview.adjust_path('newname', preview.root, file_trans_id)
2408
 
        preview_tree = preview.get_preview_tree()
2409
 
        expected = [
2410
 
            ('one', 'a\n'),
2411
 
        ]
2412
 
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2413
 
        self.assertEqual(expected, annotation)
2414
 
 
2415
 
    def test_annotate_deleted(self):
2416
 
        tree = self.make_branch_and_tree('tree')
2417
 
        self.build_tree_contents([('tree/file', 'a\n')])
2418
 
        tree.add('file', 'file-id')
2419
 
        tree.commit('a', rev_id='one')
2420
 
        self.build_tree_contents([('tree/file', 'a\nb\n')])
2421
 
        preview = TransformPreview(tree)
2422
 
        self.addCleanup(preview.finalize)
2423
 
        file_trans_id = preview.trans_id_file_id('file-id')
2424
 
        preview.delete_contents(file_trans_id)
2425
 
        preview_tree = preview.get_preview_tree()
2426
 
        annotation = preview_tree.annotate_iter('file-id', 'me:')
2427
 
        self.assertIs(None, annotation)
2428
 
 
2429
 
    def test_stored_kind(self):
2430
 
        preview = self.get_empty_preview()
2431
 
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2432
 
        preview_tree = preview.get_preview_tree()
2433
 
        self.assertEqual('file', preview_tree.stored_kind('file-id'))
2434
 
 
2435
 
    def test_is_executable(self):
2436
 
        preview = self.get_empty_preview()
2437
 
        preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2438
 
        preview.set_executability(True, preview.trans_id_file_id('file-id'))
2439
 
        preview_tree = preview.get_preview_tree()
2440
 
        self.assertEqual(True, preview_tree.is_executable('file-id'))
2441
 
 
2442
 
    def test_get_set_parent_ids(self):
2443
 
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2444
 
        self.assertEqual([], preview_tree.get_parent_ids())
2445
 
        preview_tree.set_parent_ids(['rev-1'])
2446
 
        self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2447
 
 
2448
 
    def test_plan_file_merge(self):
2449
 
        work_a = self.make_branch_and_tree('wta')
2450
 
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2451
 
        work_a.add('file', 'file-id')
2452
 
        base_id = work_a.commit('base version')
2453
 
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2454
 
        preview = TransformPreview(work_a)
2455
 
        self.addCleanup(preview.finalize)
2456
 
        trans_id = preview.trans_id_file_id('file-id')
2457
 
        preview.delete_contents(trans_id)
2458
 
        preview.create_file('b\nc\nd\ne\n', trans_id)
2459
 
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2460
 
        tree_a = preview.get_preview_tree()
2461
 
        tree_a.set_parent_ids([base_id])
2462
 
        self.assertEqual([
2463
 
            ('killed-a', 'a\n'),
2464
 
            ('killed-b', 'b\n'),
2465
 
            ('unchanged', 'c\n'),
2466
 
            ('unchanged', 'd\n'),
2467
 
            ('new-a', 'e\n'),
2468
 
            ('new-b', 'f\n'),
2469
 
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
2470
 
 
2471
 
    def test_plan_file_merge_revision_tree(self):
2472
 
        work_a = self.make_branch_and_tree('wta')
2473
 
        self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2474
 
        work_a.add('file', 'file-id')
2475
 
        base_id = work_a.commit('base version')
2476
 
        tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2477
 
        preview = TransformPreview(work_a.basis_tree())
2478
 
        self.addCleanup(preview.finalize)
2479
 
        trans_id = preview.trans_id_file_id('file-id')
2480
 
        preview.delete_contents(trans_id)
2481
 
        preview.create_file('b\nc\nd\ne\n', trans_id)
2482
 
        self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2483
 
        tree_a = preview.get_preview_tree()
2484
 
        tree_a.set_parent_ids([base_id])
2485
 
        self.assertEqual([
2486
 
            ('killed-a', 'a\n'),
2487
 
            ('killed-b', 'b\n'),
2488
 
            ('unchanged', 'c\n'),
2489
 
            ('unchanged', 'd\n'),
2490
 
            ('new-a', 'e\n'),
2491
 
            ('new-b', 'f\n'),
2492
 
        ], list(tree_a.plan_file_merge('file-id', tree_b)))
2493
 
 
2494
 
    def test_walkdirs(self):
2495
 
        preview = self.get_empty_preview()
2496
 
        preview.version_file('tree-root', preview.root)
2497
 
        preview_tree = preview.get_preview_tree()
2498
 
        file_trans_id = preview.new_file('a', preview.root, 'contents',
2499
 
                                         'a-id')
2500
 
        expected = [(('', 'tree-root'),
2501
 
                    [('a', 'a', 'file', None, 'a-id', 'file')])]
2502
 
        self.assertEqual(expected, list(preview_tree.walkdirs()))
2503
 
 
2504
 
    def test_extras(self):
2505
 
        work_tree = self.make_branch_and_tree('tree')
2506
 
        self.build_tree(['tree/removed-file', 'tree/existing-file',
2507
 
                         'tree/not-removed-file'])
2508
 
        work_tree.add(['removed-file', 'not-removed-file'])
2509
 
        preview = TransformPreview(work_tree)
2510
 
        self.addCleanup(preview.finalize)
2511
 
        preview.new_file('new-file', preview.root, 'contents')
2512
 
        preview.new_file('new-versioned-file', preview.root, 'contents',
2513
 
                         'new-versioned-id')
2514
 
        tree = preview.get_preview_tree()
2515
 
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
2516
 
        self.assertEqual(set(['new-file', 'removed-file', 'existing-file']),
2517
 
                         set(tree.extras()))
2518
 
 
2519
 
    def test_merge_into_preview(self):
2520
 
        work_tree = self.make_branch_and_tree('tree')
2521
 
        self.build_tree_contents([('tree/file','b\n')])
2522
 
        work_tree.add('file', 'file-id')
2523
 
        work_tree.commit('first commit')
2524
 
        child_tree = work_tree.bzrdir.sprout('child').open_workingtree()
2525
 
        self.build_tree_contents([('child/file','b\nc\n')])
2526
 
        child_tree.commit('child commit')
2527
 
        child_tree.lock_write()
2528
 
        self.addCleanup(child_tree.unlock)
2529
 
        work_tree.lock_write()
2530
 
        self.addCleanup(work_tree.unlock)
2531
 
        preview = TransformPreview(work_tree)
2532
 
        self.addCleanup(preview.finalize)
2533
 
        preview_tree = preview.get_preview_tree()
2534
 
        file_trans_id = preview.trans_id_file_id('file-id')
2535
 
        preview.delete_contents(file_trans_id)
2536
 
        preview.create_file('a\nb\n', file_trans_id)
2537
 
        pb = progress.DummyProgress()
2538
 
        merger = Merger.from_revision_ids(pb, preview_tree,
2539
 
                                          child_tree.branch.last_revision(),
2540
 
                                          other_branch=child_tree.branch,
2541
 
                                          tree_branch=work_tree.branch)
2542
 
        merger.merge_type = Merge3Merger
2543
 
        tt = merger.make_merger().make_preview_transform()
2544
 
        self.addCleanup(tt.finalize)
2545
 
        final_tree = tt.get_preview_tree()
2546
 
        self.assertEqual('a\nb\nc\n', final_tree.get_file_text('file-id'))
2547
 
 
2548
 
    def test_merge_preview_into_workingtree(self):
2549
 
        tree = self.make_branch_and_tree('tree')
2550
 
        tt = TransformPreview(tree)
2551
 
        self.addCleanup(tt.finalize)
2552
 
        tt.new_file('name', tt.root, 'content', 'file-id')
2553
 
        tree2 = self.make_branch_and_tree('tree2')
2554
 
        pb = progress.DummyProgress()
2555
 
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2556
 
                                         pb, tree.basis_tree())
2557
 
        merger.merge_type = Merge3Merger
2558
 
        merger.do_merge()
2559
 
 
2560
 
    def test_merge_preview_into_workingtree_handles_conflicts(self):
2561
 
        tree = self.make_branch_and_tree('tree')
2562
 
        self.build_tree_contents([('tree/foo', 'bar')])
2563
 
        tree.add('foo', 'foo-id')
2564
 
        tree.commit('foo')
2565
 
        tt = TransformPreview(tree)
2566
 
        self.addCleanup(tt.finalize)
2567
 
        trans_id = tt.trans_id_file_id('foo-id')
2568
 
        tt.delete_contents(trans_id)
2569
 
        tt.create_file('baz', trans_id)
2570
 
        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
2571
 
        self.build_tree_contents([('tree2/foo', 'qux')])
2572
 
        pb = progress.DummyProgress()
2573
 
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
2574
 
                                         pb, tree.basis_tree())
2575
 
        merger.merge_type = Merge3Merger
2576
 
        merger.do_merge()
2577
 
 
2578
 
    def test_is_executable(self):
2579
 
        tree = self.make_branch_and_tree('tree')
2580
 
        preview = TransformPreview(tree)
2581
 
        self.addCleanup(preview.finalize)
2582
 
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
2583
 
        preview_tree = preview.get_preview_tree()
2584
 
        self.assertEqual(False, preview_tree.is_executable('baz-id',
2585
 
                                                           'tree/foo'))
2586
 
        self.assertEqual(False, preview_tree.is_executable('baz-id'))
2587
 
 
2588
 
 
2589
 
class FakeSerializer(object):
2590
 
    """Serializer implementation that simply returns the input.
2591
 
 
2592
 
    The input is returned in the order used by pack.ContainerPushParser.
2593
 
    """
2594
 
    @staticmethod
2595
 
    def bytes_record(bytes, names):
2596
 
        return names, bytes
2597
 
 
2598
 
 
2599
 
class TestSerializeTransform(tests.TestCaseWithTransport):
2600
 
 
2601
 
    _test_needs_features = [tests.UnicodeFilenameFeature]
2602
 
 
2603
 
    def get_preview(self, tree=None):
2604
 
        if tree is None:
2605
 
            tree = self.make_branch_and_tree('tree')
2606
 
        tt = TransformPreview(tree)
2607
 
        self.addCleanup(tt.finalize)
2608
 
        return tt
2609
 
 
2610
 
    def assertSerializesTo(self, expected, tt):
2611
 
        records = list(tt.serialize(FakeSerializer()))
2612
 
        self.assertEqual(expected, records)
2613
 
 
2614
 
    @staticmethod
2615
 
    def default_attribs():
2616
 
        return {
2617
 
            '_id_number': 1,
2618
 
            '_new_name': {},
2619
 
            '_new_parent': {},
2620
 
            '_new_executability': {},
2621
 
            '_new_id': {},
2622
 
            '_tree_path_ids': {'': 'new-0'},
2623
 
            '_removed_id': [],
2624
 
            '_removed_contents': [],
2625
 
            '_non_present_ids': {},
2626
 
            }
2627
 
 
2628
 
    def make_records(self, attribs, contents):
2629
 
        records = [
2630
 
            (((('attribs'),),), bencode.bencode(attribs))]
2631
 
        records.extend([(((n, k),), c) for n, k, c in contents])
2632
 
        return records
2633
 
 
2634
 
    def creation_records(self):
2635
 
        attribs = self.default_attribs()
2636
 
        attribs['_id_number'] = 3
2637
 
        attribs['_new_name'] = {
2638
 
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
2639
 
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
2640
 
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
2641
 
        attribs['_new_executability'] = {'new-1': 1}
2642
 
        contents = [
2643
 
            ('new-1', 'file', 'i 1\nbar\n'),
2644
 
            ('new-2', 'directory', ''),
2645
 
            ]
2646
 
        return self.make_records(attribs, contents)
2647
 
 
2648
 
    def test_serialize_creation(self):
2649
 
        tt = self.get_preview()
2650
 
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
2651
 
        tt.new_directory('qux', tt.root, 'quxx')
2652
 
        self.assertSerializesTo(self.creation_records(), tt)
2653
 
 
2654
 
    def test_deserialize_creation(self):
2655
 
        tt = self.get_preview()
2656
 
        tt.deserialize(iter(self.creation_records()))
2657
 
        self.assertEqual(3, tt._id_number)
2658
 
        self.assertEqual({'new-1': u'foo\u1234',
2659
 
                          'new-2': 'qux'}, tt._new_name)
2660
 
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
2661
 
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
2662
 
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
2663
 
        self.assertEqual({'new-1': True}, tt._new_executability)
2664
 
        self.assertEqual({'new-1': 'file',
2665
 
                          'new-2': 'directory'}, tt._new_contents)
2666
 
        foo_limbo = open(tt._limbo_name('new-1'), 'rb')
2667
 
        try:
2668
 
            foo_content = foo_limbo.read()
2669
 
        finally:
2670
 
            foo_limbo.close()
2671
 
        self.assertEqual('bar', foo_content)
2672
 
 
2673
 
    def symlink_creation_records(self):
2674
 
        attribs = self.default_attribs()
2675
 
        attribs['_id_number'] = 2
2676
 
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
2677
 
        attribs['_new_parent'] = {'new-1': 'new-0'}
2678
 
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
2679
 
        return self.make_records(attribs, contents)
2680
 
 
2681
 
    def test_serialize_symlink_creation(self):
2682
 
        self.requireFeature(tests.SymlinkFeature)
2683
 
        tt = self.get_preview()
2684
 
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
2685
 
        self.assertSerializesTo(self.symlink_creation_records(), tt)
2686
 
 
2687
 
    def test_deserialize_symlink_creation(self):
2688
 
        tt = self.get_preview()
2689
 
        tt.deserialize(iter(self.symlink_creation_records()))
2690
 
        # XXX readlink should be returning unicode, not utf-8
2691
 
        foo_content = os.readlink(tt._limbo_name('new-1')).decode('utf-8')
2692
 
        self.assertEqual(u'bar\u1234', foo_content)
2693
 
 
2694
 
    def make_destruction_preview(self):
2695
 
        tree = self.make_branch_and_tree('.')
2696
 
        self.build_tree([u'foo\u1234', 'bar'])
2697
 
        tree.add([u'foo\u1234', 'bar'], ['foo-id', 'bar-id'])
2698
 
        return self.get_preview(tree)
2699
 
 
2700
 
    def destruction_records(self):
2701
 
        attribs = self.default_attribs()
2702
 
        attribs['_id_number'] = 3
2703
 
        attribs['_removed_id'] = ['new-1']
2704
 
        attribs['_removed_contents'] = ['new-2']
2705
 
        attribs['_tree_path_ids'] = {
2706
 
            '': 'new-0',
2707
 
            u'foo\u1234'.encode('utf-8'): 'new-1',
2708
 
            'bar': 'new-2',
2709
 
            }
2710
 
        return self.make_records(attribs, [])
2711
 
 
2712
 
    def test_serialize_destruction(self):
2713
 
        tt = self.make_destruction_preview()
2714
 
        foo_trans_id = tt.trans_id_tree_file_id('foo-id')
2715
 
        tt.unversion_file(foo_trans_id)
2716
 
        bar_trans_id = tt.trans_id_tree_file_id('bar-id')
2717
 
        tt.delete_contents(bar_trans_id)
2718
 
        self.assertSerializesTo(self.destruction_records(), tt)
2719
 
 
2720
 
    def test_deserialize_destruction(self):
2721
 
        tt = self.make_destruction_preview()
2722
 
        tt.deserialize(iter(self.destruction_records()))
2723
 
        self.assertEqual({u'foo\u1234': 'new-1',
2724
 
                          'bar': 'new-2',
2725
 
                          '': tt.root}, tt._tree_path_ids)
2726
 
        self.assertEqual({'new-1': u'foo\u1234',
2727
 
                          'new-2': 'bar',
2728
 
                          tt.root: ''}, tt._tree_id_paths)
2729
 
        self.assertEqual(set(['new-1']), tt._removed_id)
2730
 
        self.assertEqual(set(['new-2']), tt._removed_contents)
2731
 
 
2732
 
    def missing_records(self):
2733
 
        attribs = self.default_attribs()
2734
 
        attribs['_id_number'] = 2
2735
 
        attribs['_non_present_ids'] = {
2736
 
            'boo': 'new-1',}
2737
 
        return self.make_records(attribs, [])
2738
 
 
2739
 
    def test_serialize_missing(self):
2740
 
        tt = self.get_preview()
2741
 
        boo_trans_id = tt.trans_id_file_id('boo')
2742
 
        self.assertSerializesTo(self.missing_records(), tt)
2743
 
 
2744
 
    def test_deserialize_missing(self):
2745
 
        tt = self.get_preview()
2746
 
        tt.deserialize(iter(self.missing_records()))
2747
 
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
2748
 
 
2749
 
    def make_modification_preview(self):
2750
 
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
2751
 
        LINES_TWO = 'z\nbb\nx\ndd\n'
2752
 
        tree = self.make_branch_and_tree('tree')
2753
 
        self.build_tree_contents([('tree/file', LINES_ONE)])
2754
 
        tree.add('file', 'file-id')
2755
 
        return self.get_preview(tree), LINES_TWO
2756
 
 
2757
 
    def modification_records(self):
2758
 
        attribs = self.default_attribs()
2759
 
        attribs['_id_number'] = 2
2760
 
        attribs['_tree_path_ids'] = {
2761
 
            'file': 'new-1',
2762
 
            '': 'new-0',}
2763
 
        attribs['_removed_contents'] = ['new-1']
2764
 
        contents = [('new-1', 'file',
2765
 
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
2766
 
        return self.make_records(attribs, contents)
2767
 
 
2768
 
    def test_serialize_modification(self):
2769
 
        tt, LINES = self.make_modification_preview()
2770
 
        trans_id = tt.trans_id_file_id('file-id')
2771
 
        tt.delete_contents(trans_id)
2772
 
        tt.create_file(LINES, trans_id)
2773
 
        self.assertSerializesTo(self.modification_records(), tt)
2774
 
 
2775
 
    def test_deserialize_modification(self):
2776
 
        tt, LINES = self.make_modification_preview()
2777
 
        tt.deserialize(iter(self.modification_records()))
2778
 
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2779
 
 
2780
 
    def make_kind_change_preview(self):
2781
 
        LINES = 'a\nb\nc\nd\n'
2782
 
        tree = self.make_branch_and_tree('tree')
2783
 
        self.build_tree(['tree/foo/'])
2784
 
        tree.add('foo', 'foo-id')
2785
 
        return self.get_preview(tree), LINES
2786
 
 
2787
 
    def kind_change_records(self):
2788
 
        attribs = self.default_attribs()
2789
 
        attribs['_id_number'] = 2
2790
 
        attribs['_tree_path_ids'] = {
2791
 
            'foo': 'new-1',
2792
 
            '': 'new-0',}
2793
 
        attribs['_removed_contents'] = ['new-1']
2794
 
        contents = [('new-1', 'file',
2795
 
                     'i 4\na\nb\nc\nd\n\n')]
2796
 
        return self.make_records(attribs, contents)
2797
 
 
2798
 
    def test_serialize_kind_change(self):
2799
 
        tt, LINES = self.make_kind_change_preview()
2800
 
        trans_id = tt.trans_id_file_id('foo-id')
2801
 
        tt.delete_contents(trans_id)
2802
 
        tt.create_file(LINES, trans_id)
2803
 
        self.assertSerializesTo(self.kind_change_records(), tt)
2804
 
 
2805
 
    def test_deserialize_kind_change(self):
2806
 
        tt, LINES = self.make_kind_change_preview()
2807
 
        tt.deserialize(iter(self.kind_change_records()))
2808
 
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2809
 
 
2810
 
    def make_add_contents_preview(self):
2811
 
        LINES = 'a\nb\nc\nd\n'
2812
 
        tree = self.make_branch_and_tree('tree')
2813
 
        self.build_tree(['tree/foo'])
2814
 
        tree.add('foo')
2815
 
        os.unlink('tree/foo')
2816
 
        return self.get_preview(tree), LINES
2817
 
 
2818
 
    def add_contents_records(self):
2819
 
        attribs = self.default_attribs()
2820
 
        attribs['_id_number'] = 2
2821
 
        attribs['_tree_path_ids'] = {
2822
 
            'foo': 'new-1',
2823
 
            '': 'new-0',}
2824
 
        contents = [('new-1', 'file',
2825
 
                     'i 4\na\nb\nc\nd\n\n')]
2826
 
        return self.make_records(attribs, contents)
2827
 
 
2828
 
    def test_serialize_add_contents(self):
2829
 
        tt, LINES = self.make_add_contents_preview()
2830
 
        trans_id = tt.trans_id_tree_path('foo')
2831
 
        tt.create_file(LINES, trans_id)
2832
 
        self.assertSerializesTo(self.add_contents_records(), tt)
2833
 
 
2834
 
    def test_deserialize_add_contents(self):
2835
 
        tt, LINES = self.make_add_contents_preview()
2836
 
        tt.deserialize(iter(self.add_contents_records()))
2837
 
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
2838
 
 
2839
 
    def test_get_parents_lines(self):
2840
 
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
2841
 
        LINES_TWO = 'z\nbb\nx\ndd\n'
2842
 
        tree = self.make_branch_and_tree('tree')
2843
 
        self.build_tree_contents([('tree/file', LINES_ONE)])
2844
 
        tree.add('file', 'file-id')
2845
 
        tt = self.get_preview(tree)
2846
 
        trans_id = tt.trans_id_tree_path('file')
2847
 
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
2848
 
            tt._get_parents_lines(trans_id))
2849
 
 
2850
 
    def test_get_parents_texts(self):
2851
 
        LINES_ONE = 'aa\nbb\ncc\ndd\n'
2852
 
        LINES_TWO = 'z\nbb\nx\ndd\n'
2853
 
        tree = self.make_branch_and_tree('tree')
2854
 
        self.build_tree_contents([('tree/file', LINES_ONE)])
2855
 
        tree.add('file', 'file-id')
2856
 
        tt = self.get_preview(tree)
2857
 
        trans_id = tt.trans_id_tree_path('file')
2858
 
        self.assertEqual((LINES_ONE,),
2859
 
            tt._get_parents_texts(trans_id))