/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 bzrlib/tests/test_dirstate.py

  • Committer: Jonathan Riddell
  • Date: 2011-05-25 13:07:26 UTC
  • mto: This revision was merged to the branch mainline in revision 5914.
  • Revision ID: jriddell@canonical.com-20110525130726-rgvup0ktqxn4ct9r
fix unescapted \n needed by sphinx

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-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 of the dirstate functionality being built for WorkingTreeFormat4."""
18
18
 
19
 
import bisect
20
19
import os
 
20
import tempfile
21
21
 
22
22
from bzrlib import (
 
23
    bzrdir,
23
24
    dirstate,
24
25
    errors,
25
26
    inventory,
26
27
    memorytree,
27
28
    osutils,
28
29
    revision as _mod_revision,
 
30
    revisiontree,
29
31
    tests,
 
32
    workingtree_4,
30
33
    )
 
34
from bzrlib.transport import memory
31
35
from bzrlib.tests import test_osutils
 
36
from bzrlib.tests.scenarios import load_tests_apply_scenarios
32
37
 
33
38
 
34
39
# TODO:
44
49
# set_path_id  setting id when state is in memory modified
45
50
 
46
51
 
47
 
def load_tests(basic_tests, module, loader):
48
 
    suite = loader.suiteClass()
49
 
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
50
 
        basic_tests, tests.condition_isinstance(TestCaseWithDirState))
51
 
    tests.multiply_tests(dir_reader_tests,
52
 
                         test_osutils.dir_reader_scenarios(), suite)
53
 
    suite.addTest(remaining_tests)
54
 
    return suite
 
52
load_tests = load_tests_apply_scenarios
55
53
 
56
54
 
57
55
class TestCaseWithDirState(tests.TestCaseWithTransport):
58
56
    """Helper functions for creating DirState objects with various content."""
59
57
 
 
58
    scenarios = test_osutils.dir_reader_scenarios()
 
59
 
60
60
    # Set by load_tests
61
61
    _dir_reader_class = None
62
62
    _native_to_unicode = None # Not used yet
532
532
 
533
533
class TestDirStateOnFile(TestCaseWithDirState):
534
534
 
 
535
    def create_updated_dirstate(self):
 
536
        self.build_tree(['a-file'])
 
537
        tree = self.make_branch_and_tree('.')
 
538
        tree.add(['a-file'], ['a-id'])
 
539
        tree.commit('add a-file')
 
540
        # Save and unlock the state, re-open it in readonly mode
 
541
        state = dirstate.DirState.from_tree(tree, 'dirstate')
 
542
        state.save()
 
543
        state.unlock()
 
544
        state = dirstate.DirState.on_file('dirstate')
 
545
        state.lock_read()
 
546
        return state
 
547
 
535
548
    def test_construct_with_path(self):
536
549
        tree = self.make_branch_and_tree('tree')
537
550
        state = dirstate.DirState.from_tree(tree, 'dirstate.from_tree')
566
579
            state.unlock()
567
580
 
568
581
    def test_can_save_in_read_lock(self):
569
 
        self.build_tree(['a-file'])
570
 
        state = dirstate.DirState.initialize('dirstate')
571
 
        try:
572
 
            # No stat and no sha1 sum.
573
 
            state.add('a-file', 'a-file-id', 'file', None, '')
574
 
            state.save()
575
 
        finally:
576
 
            state.unlock()
577
 
 
578
 
        # Now open in readonly mode
579
 
        state = dirstate.DirState.on_file('dirstate')
580
 
        state.lock_read()
 
582
        state = self.create_updated_dirstate()
581
583
        try:
582
584
            entry = state._get_entry(0, path_utf8='a-file')
583
585
            # The current size should be 0 (default)
584
586
            self.assertEqual(0, entry[1][0][2])
585
587
            # We should have a real entry.
586
588
            self.assertNotEqual((None, None), entry)
587
 
            # Make sure everything is old enough
 
589
            # Set the cutoff-time into the future, so things look cacheable
588
590
            state._sha_cutoff_time()
589
 
            state._cutoff_time += 10
590
 
            # Change the file length
591
 
            self.build_tree_contents([('a-file', 'shorter')])
592
 
            sha1sum = dirstate.update_entry(state, entry, 'a-file',
593
 
                os.lstat('a-file'))
594
 
            # new file, no cached sha:
595
 
            self.assertEqual(None, sha1sum)
 
591
            state._cutoff_time += 10.0
 
592
            st = os.lstat('a-file')
 
593
            sha1sum = dirstate.update_entry(state, entry, 'a-file', st)
 
594
            # We updated the current sha1sum because the file is cacheable
 
595
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
 
596
                             sha1sum)
596
597
 
597
598
            # The dirblock has been updated
598
 
            self.assertEqual(7, entry[1][0][2])
599
 
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
599
            self.assertEqual(st.st_size, entry[1][0][2])
 
600
            self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
600
601
                             state._dirblock_state)
601
602
 
602
603
            del entry
611
612
        state.lock_read()
612
613
        try:
613
614
            entry = state._get_entry(0, path_utf8='a-file')
614
 
            self.assertEqual(7, entry[1][0][2])
 
615
            self.assertEqual(st.st_size, entry[1][0][2])
615
616
        finally:
616
617
            state.unlock()
617
618
 
618
619
    def test_save_fails_quietly_if_locked(self):
619
620
        """If dirstate is locked, save will fail without complaining."""
620
 
        self.build_tree(['a-file'])
621
 
        state = dirstate.DirState.initialize('dirstate')
622
 
        try:
623
 
            # No stat and no sha1 sum.
624
 
            state.add('a-file', 'a-file-id', 'file', None, '')
625
 
            state.save()
626
 
        finally:
627
 
            state.unlock()
628
 
 
629
 
        state = dirstate.DirState.on_file('dirstate')
630
 
        state.lock_read()
 
621
        state = self.create_updated_dirstate()
631
622
        try:
632
623
            entry = state._get_entry(0, path_utf8='a-file')
633
 
            sha1sum = dirstate.update_entry(state, entry, 'a-file',
634
 
                os.lstat('a-file'))
635
 
            # No sha - too new
636
 
            self.assertEqual(None, sha1sum)
637
 
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
624
            # No cached sha1 yet.
 
625
            self.assertEqual('', entry[1][0][1])
 
626
            # Set the cutoff-time into the future, so things look cacheable
 
627
            state._sha_cutoff_time()
 
628
            state._cutoff_time += 10.0
 
629
            st = os.lstat('a-file')
 
630
            sha1sum = dirstate.update_entry(state, entry, 'a-file', st)
 
631
            self.assertEqual('ecc5374e9ed82ad3ea3b4d452ea995a5fd3e70e3',
 
632
                             sha1sum)
 
633
            self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
638
634
                             state._dirblock_state)
639
635
 
640
636
            # Now, before we try to save, grab another dirstate, and take out a
730
726
 
731
727
class TestDirStateManipulations(TestCaseWithDirState):
732
728
 
 
729
    def make_minimal_tree(self):
 
730
        tree1 = self.make_branch_and_memory_tree('tree1')
 
731
        tree1.lock_write()
 
732
        self.addCleanup(tree1.unlock)
 
733
        tree1.add('')
 
734
        revid1 = tree1.commit('foo')
 
735
        return tree1, revid1
 
736
 
 
737
    def test_update_minimal_updates_id_index(self):
 
738
        state = self.create_dirstate_with_root_and_subdir()
 
739
        self.addCleanup(state.unlock)
 
740
        id_index = state._get_id_index()
 
741
        self.assertEqual(['a-root-value', 'subdir-id'], sorted(id_index))
 
742
        state.add('file-name', 'file-id', 'file', None, '')
 
743
        self.assertEqual(['a-root-value', 'file-id', 'subdir-id'],
 
744
                         sorted(id_index))
 
745
        state.update_minimal(('', 'new-name', 'file-id'), 'f',
 
746
                             path_utf8='new-name')
 
747
        self.assertEqual(['a-root-value', 'file-id', 'subdir-id'],
 
748
                         sorted(id_index))
 
749
        self.assertEqual([('', 'new-name', 'file-id')],
 
750
                         sorted(id_index['file-id']))
 
751
        state._validate()
 
752
 
733
753
    def test_set_state_from_inventory_no_content_no_parents(self):
734
754
        # setting the current inventory is a slow but important api to support.
735
 
        tree1 = self.make_branch_and_memory_tree('tree1')
736
 
        tree1.lock_write()
737
 
        try:
738
 
            tree1.add('')
739
 
            revid1 = tree1.commit('foo').encode('utf8')
740
 
            root_id = tree1.get_root_id()
741
 
            inv = tree1.inventory
742
 
        finally:
743
 
            tree1.unlock()
 
755
        tree1, revid1 = self.make_minimal_tree()
 
756
        inv = tree1.inventory
 
757
        root_id = inv.path2id('')
744
758
        expected_result = [], [
745
759
            (('', '', root_id), [
746
760
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
758
772
            # This will unlock it
759
773
            self.check_state_with_reopen(expected_result, state)
760
774
 
 
775
    def test_set_state_from_scratch_no_parents(self):
 
776
        tree1, revid1 = self.make_minimal_tree()
 
777
        inv = tree1.inventory
 
778
        root_id = inv.path2id('')
 
779
        expected_result = [], [
 
780
            (('', '', root_id), [
 
781
             ('d', '', 0, False, dirstate.DirState.NULLSTAT)])]
 
782
        state = dirstate.DirState.initialize('dirstate')
 
783
        try:
 
784
            state.set_state_from_scratch(inv, [], [])
 
785
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
786
                             state._header_state)
 
787
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
788
                             state._dirblock_state)
 
789
        except:
 
790
            state.unlock()
 
791
            raise
 
792
        else:
 
793
            # This will unlock it
 
794
            self.check_state_with_reopen(expected_result, state)
 
795
 
 
796
    def test_set_state_from_scratch_identical_parent(self):
 
797
        tree1, revid1 = self.make_minimal_tree()
 
798
        inv = tree1.inventory
 
799
        root_id = inv.path2id('')
 
800
        rev_tree1 = tree1.branch.repository.revision_tree(revid1)
 
801
        d_entry = ('d', '', 0, False, dirstate.DirState.NULLSTAT)
 
802
        parent_entry = ('d', '', 0, False, revid1)
 
803
        expected_result = [revid1], [
 
804
            (('', '', root_id), [d_entry, parent_entry])]
 
805
        state = dirstate.DirState.initialize('dirstate')
 
806
        try:
 
807
            state.set_state_from_scratch(inv, [(revid1, rev_tree1)], [])
 
808
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
809
                             state._header_state)
 
810
            self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
811
                             state._dirblock_state)
 
812
        except:
 
813
            state.unlock()
 
814
            raise
 
815
        else:
 
816
            # This will unlock it
 
817
            self.check_state_with_reopen(expected_result, state)
 
818
 
761
819
    def test_set_state_from_inventory_preserves_hashcache(self):
762
820
        # https://bugs.launchpad.net/bzr/+bug/146176
763
821
        # set_state_from_inventory should preserve the stat and hash value for
1286
1344
            tree1.unlock()
1287
1345
 
1288
1346
 
 
1347
class TestDirStateHashUpdates(TestCaseWithDirState):
 
1348
 
 
1349
    def do_update_entry(self, state, path):
 
1350
        entry = state._get_entry(0, path_utf8=path)
 
1351
        stat = os.lstat(path)
 
1352
        return dirstate.update_entry(state, entry, os.path.abspath(path), stat)
 
1353
 
 
1354
    def test_worth_saving_limit_avoids_writing(self):
 
1355
        tree = self.make_branch_and_tree('.')
 
1356
        self.build_tree(['c', 'd'])
 
1357
        tree.lock_write()
 
1358
        tree.add(['c', 'd'], ['c-id', 'd-id'])
 
1359
        tree.commit('add c and d')
 
1360
        state = InstrumentedDirState.on_file(tree.current_dirstate()._filename,
 
1361
                                             worth_saving_limit=2)
 
1362
        tree.unlock()
 
1363
        state.lock_write()
 
1364
        self.addCleanup(state.unlock)
 
1365
        state._read_dirblocks_if_needed()
 
1366
        state.adjust_time(+20) # Allow things to be cached
 
1367
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1368
                         state._dirblock_state)
 
1369
        f = open(state._filename, 'rb')
 
1370
        try:
 
1371
            content = f.read()
 
1372
        finally:
 
1373
            f.close()
 
1374
        self.do_update_entry(state, 'c')
 
1375
        self.assertEqual(1, len(state._known_hash_changes))
 
1376
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
1377
                         state._dirblock_state)
 
1378
        state.save()
 
1379
        # It should not have set the state to IN_MEMORY_UNMODIFIED because the
 
1380
        # hash values haven't been written out.
 
1381
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
1382
                         state._dirblock_state)
 
1383
        self.assertFileEqual(content, state._filename)
 
1384
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
1385
                         state._dirblock_state)
 
1386
        self.do_update_entry(state, 'd')
 
1387
        self.assertEqual(2, len(state._known_hash_changes))
 
1388
        state.save()
 
1389
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1390
                         state._dirblock_state)
 
1391
        self.assertEqual(0, len(state._known_hash_changes))
 
1392
 
 
1393
 
1289
1394
class TestGetLines(TestCaseWithDirState):
1290
1395
 
1291
1396
    def test_get_line_with_2_rows(self):
1684
1789
class InstrumentedDirState(dirstate.DirState):
1685
1790
    """An DirState with instrumented sha1 functionality."""
1686
1791
 
1687
 
    def __init__(self, path, sha1_provider):
1688
 
        super(InstrumentedDirState, self).__init__(path, sha1_provider)
 
1792
    def __init__(self, path, sha1_provider, worth_saving_limit=0):
 
1793
        super(InstrumentedDirState, self).__init__(path, sha1_provider,
 
1794
            worth_saving_limit=worth_saving_limit)
1689
1795
        self._time_offset = 0
1690
1796
        self._log = []
1691
1797
        # member is dynamically set in DirState.__init__ to turn on trace
2320
2426
        self.assertTrue(len(statvalue) >= 10)
2321
2427
        self.assertEqual(len(text), statvalue.st_size)
2322
2428
        self.assertEqual(expected_sha, sha1)
 
2429
 
 
2430
 
 
2431
class _Repo(object):
 
2432
    """A minimal api to get InventoryRevisionTree to work."""
 
2433
 
 
2434
    def __init__(self):
 
2435
        default_format = bzrdir.format_registry.make_bzrdir('default')
 
2436
        self._format = default_format.repository_format
 
2437
 
 
2438
    def lock_read(self):
 
2439
        pass
 
2440
 
 
2441
    def unlock(self):
 
2442
        pass
 
2443
 
 
2444
 
 
2445
class TestUpdateBasisByDelta(tests.TestCase):
 
2446
 
 
2447
    def path_to_ie(self, path, file_id, rev_id, dir_ids):
 
2448
        if path.endswith('/'):
 
2449
            is_dir = True
 
2450
            path = path[:-1]
 
2451
        else:
 
2452
            is_dir = False
 
2453
        dirname, basename = osutils.split(path)
 
2454
        try:
 
2455
            dir_id = dir_ids[dirname]
 
2456
        except KeyError:
 
2457
            dir_id = osutils.basename(dirname) + '-id'
 
2458
        if is_dir:
 
2459
            ie = inventory.InventoryDirectory(file_id, basename, dir_id)
 
2460
            dir_ids[path] = file_id
 
2461
        else:
 
2462
            ie = inventory.InventoryFile(file_id, basename, dir_id)
 
2463
            ie.text_size = 0
 
2464
            ie.text_sha1 = ''
 
2465
        ie.revision = rev_id
 
2466
        return ie
 
2467
 
 
2468
    def create_tree_from_shape(self, rev_id, shape):
 
2469
        dir_ids = {'': 'root-id'}
 
2470
        inv = inventory.Inventory('root-id', rev_id)
 
2471
        for path, file_id in shape:
 
2472
            if path == '':
 
2473
                # Replace the root entry
 
2474
                del inv._byid[inv.root.file_id]
 
2475
                inv.root.file_id = file_id
 
2476
                inv._byid[file_id] = inv.root
 
2477
                dir_ids[''] = file_id
 
2478
                continue
 
2479
            inv.add(self.path_to_ie(path, file_id, rev_id, dir_ids))
 
2480
        return revisiontree.InventoryRevisionTree(_Repo(), inv, rev_id)
 
2481
 
 
2482
    def create_empty_dirstate(self):
 
2483
        fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
 
2484
        self.addCleanup(os.remove, path)
 
2485
        os.close(fd)
 
2486
        state = dirstate.DirState.initialize(path)
 
2487
        self.addCleanup(state.unlock)
 
2488
        return state
 
2489
 
 
2490
    def create_inv_delta(self, delta, rev_id):
 
2491
        """Translate a 'delta shape' into an actual InventoryDelta"""
 
2492
        dir_ids = {'': 'root-id'}
 
2493
        inv_delta = []
 
2494
        for old_path, new_path, file_id in delta:
 
2495
            if old_path is not None and old_path.endswith('/'):
 
2496
                # Don't have to actually do anything for this, because only
 
2497
                # new_path creates InventoryEntries
 
2498
                old_path = old_path[:-1]
 
2499
            if new_path is None: # Delete
 
2500
                inv_delta.append((old_path, None, file_id, None))
 
2501
                continue
 
2502
            ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
 
2503
            inv_delta.append((old_path, new_path, file_id, ie))
 
2504
        return inv_delta
 
2505
 
 
2506
    def assertUpdate(self, active, basis, target):
 
2507
        """Assert that update_basis_by_delta works how we want.
 
2508
 
 
2509
        Set up a DirState object with active_shape for tree 0, basis_shape for
 
2510
        tree 1. Then apply the delta from basis_shape to target_shape,
 
2511
        and assert that the DirState is still valid, and that its stored
 
2512
        content matches the target_shape.
 
2513
        """
 
2514
        active_tree = self.create_tree_from_shape('active', active)
 
2515
        basis_tree = self.create_tree_from_shape('basis', basis)
 
2516
        target_tree = self.create_tree_from_shape('target', target)
 
2517
        state = self.create_empty_dirstate()
 
2518
        state.set_state_from_scratch(active_tree.inventory,
 
2519
            [('basis', basis_tree)], [])
 
2520
        delta = target_tree.inventory._make_delta(basis_tree.inventory)
 
2521
        state.update_basis_by_delta(delta, 'target')
 
2522
        state._validate()
 
2523
        dirstate_tree = workingtree_4.DirStateRevisionTree(state,
 
2524
            'target', _Repo())
 
2525
        # The target now that delta has been applied should match the
 
2526
        # RevisionTree
 
2527
        self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
 
2528
        # And the dirblock state should be identical to the state if we created
 
2529
        # it from scratch.
 
2530
        state2 = self.create_empty_dirstate()
 
2531
        state2.set_state_from_scratch(active_tree.inventory,
 
2532
            [('target', target_tree)], [])
 
2533
        self.assertEqual(state2._dirblocks, state._dirblocks)
 
2534
        return state
 
2535
 
 
2536
    def assertBadDelta(self, active, basis, delta):
 
2537
        """Test that we raise InconsistentDelta when appropriate.
 
2538
 
 
2539
        :param active: The active tree shape
 
2540
        :param basis: The basis tree shape
 
2541
        :param delta: A description of the delta to apply. Similar to the form
 
2542
            for regular inventory deltas, but omitting the InventoryEntry.
 
2543
            So adding a file is: (None, 'path', 'file-id')
 
2544
            Adding a directory is: (None, 'path/', 'dir-id')
 
2545
            Renaming a dir is: ('old/', 'new/', 'dir-id')
 
2546
            etc.
 
2547
        """
 
2548
        active_tree = self.create_tree_from_shape('active', active)
 
2549
        basis_tree = self.create_tree_from_shape('basis', basis)
 
2550
        inv_delta = self.create_inv_delta(delta, 'target')
 
2551
        state = self.create_empty_dirstate()
 
2552
        state.set_state_from_scratch(active_tree.inventory,
 
2553
            [('basis', basis_tree)], [])
 
2554
        self.assertRaises(errors.InconsistentDelta,
 
2555
            state.update_basis_by_delta, inv_delta, 'target')
 
2556
        ## try:
 
2557
        ##     state.update_basis_by_delta(inv_delta, 'target')
 
2558
        ## except errors.InconsistentDelta, e:
 
2559
        ##     import pdb; pdb.set_trace()
 
2560
        ## else:
 
2561
        ##     import pdb; pdb.set_trace()
 
2562
        self.assertTrue(state._changes_aborted)
 
2563
 
 
2564
    def test_remove_file_matching_active_state(self):
 
2565
        state = self.assertUpdate(
 
2566
            active=[],
 
2567
            basis =[('file', 'file-id')],
 
2568
            target=[],
 
2569
            )
 
2570
 
 
2571
    def test_remove_file_present_in_active_state(self):
 
2572
        state = self.assertUpdate(
 
2573
            active=[('file', 'file-id')],
 
2574
            basis =[('file', 'file-id')],
 
2575
            target=[],
 
2576
            )
 
2577
 
 
2578
    def test_remove_file_present_elsewhere_in_active_state(self):
 
2579
        state = self.assertUpdate(
 
2580
            active=[('other-file', 'file-id')],
 
2581
            basis =[('file', 'file-id')],
 
2582
            target=[],
 
2583
            )
 
2584
 
 
2585
    def test_remove_file_active_state_has_diff_file(self):
 
2586
        state = self.assertUpdate(
 
2587
            active=[('file', 'file-id-2')],
 
2588
            basis =[('file', 'file-id')],
 
2589
            target=[],
 
2590
            )
 
2591
 
 
2592
    def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
 
2593
        state = self.assertUpdate(
 
2594
            active=[('file', 'file-id-2'),
 
2595
                    ('other-file', 'file-id')],
 
2596
            basis =[('file', 'file-id')],
 
2597
            target=[],
 
2598
            )
 
2599
 
 
2600
    def test_add_file_matching_active_state(self):
 
2601
        state = self.assertUpdate(
 
2602
            active=[('file', 'file-id')],
 
2603
            basis =[],
 
2604
            target=[('file', 'file-id')],
 
2605
            )
 
2606
 
 
2607
    def test_add_file_missing_in_active_state(self):
 
2608
        state = self.assertUpdate(
 
2609
            active=[],
 
2610
            basis =[],
 
2611
            target=[('file', 'file-id')],
 
2612
            )
 
2613
 
 
2614
    def test_add_file_elsewhere_in_active_state(self):
 
2615
        state = self.assertUpdate(
 
2616
            active=[('other-file', 'file-id')],
 
2617
            basis =[],
 
2618
            target=[('file', 'file-id')],
 
2619
            )
 
2620
 
 
2621
    def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
 
2622
        state = self.assertUpdate(
 
2623
            active=[('other-file', 'file-id'),
 
2624
                    ('file', 'file-id-2')],
 
2625
            basis =[],
 
2626
            target=[('file', 'file-id')],
 
2627
            )
 
2628
 
 
2629
    def test_rename_file_matching_active_state(self):
 
2630
        state = self.assertUpdate(
 
2631
            active=[('other-file', 'file-id')],
 
2632
            basis =[('file', 'file-id')],
 
2633
            target=[('other-file', 'file-id')],
 
2634
            )
 
2635
 
 
2636
    def test_rename_file_missing_in_active_state(self):
 
2637
        state = self.assertUpdate(
 
2638
            active=[],
 
2639
            basis =[('file', 'file-id')],
 
2640
            target=[('other-file', 'file-id')],
 
2641
            )
 
2642
 
 
2643
    def test_rename_file_present_elsewhere_in_active_state(self):
 
2644
        state = self.assertUpdate(
 
2645
            active=[('third', 'file-id')],
 
2646
            basis =[('file', 'file-id')],
 
2647
            target=[('other-file', 'file-id')],
 
2648
            )
 
2649
 
 
2650
    def test_rename_file_active_state_has_diff_source_file(self):
 
2651
        state = self.assertUpdate(
 
2652
            active=[('file', 'file-id-2')],
 
2653
            basis =[('file', 'file-id')],
 
2654
            target=[('other-file', 'file-id')],
 
2655
            )
 
2656
 
 
2657
    def test_rename_file_active_state_has_diff_target_file(self):
 
2658
        state = self.assertUpdate(
 
2659
            active=[('other-file', 'file-id-2')],
 
2660
            basis =[('file', 'file-id')],
 
2661
            target=[('other-file', 'file-id')],
 
2662
            )
 
2663
 
 
2664
    def test_rename_file_active_has_swapped_files(self):
 
2665
        state = self.assertUpdate(
 
2666
            active=[('file', 'file-id'),
 
2667
                    ('other-file', 'file-id-2')],
 
2668
            basis= [('file', 'file-id'),
 
2669
                    ('other-file', 'file-id-2')],
 
2670
            target=[('file', 'file-id-2'),
 
2671
                    ('other-file', 'file-id')])
 
2672
 
 
2673
    def test_rename_file_basis_has_swapped_files(self):
 
2674
        state = self.assertUpdate(
 
2675
            active=[('file', 'file-id'),
 
2676
                    ('other-file', 'file-id-2')],
 
2677
            basis= [('file', 'file-id-2'),
 
2678
                    ('other-file', 'file-id')],
 
2679
            target=[('file', 'file-id'),
 
2680
                    ('other-file', 'file-id-2')])
 
2681
 
 
2682
    def test_rename_directory_with_contents(self):
 
2683
        state = self.assertUpdate( # active matches basis
 
2684
            active=[('dir1/', 'dir-id'),
 
2685
                    ('dir1/file', 'file-id')],
 
2686
            basis= [('dir1/', 'dir-id'),
 
2687
                    ('dir1/file', 'file-id')],
 
2688
            target=[('dir2/', 'dir-id'),
 
2689
                    ('dir2/file', 'file-id')])
 
2690
        state = self.assertUpdate( # active matches target
 
2691
            active=[('dir2/', 'dir-id'),
 
2692
                    ('dir2/file', 'file-id')],
 
2693
            basis= [('dir1/', 'dir-id'),
 
2694
                    ('dir1/file', 'file-id')],
 
2695
            target=[('dir2/', 'dir-id'),
 
2696
                    ('dir2/file', 'file-id')])
 
2697
        state = self.assertUpdate( # active empty
 
2698
            active=[],
 
2699
            basis= [('dir1/', 'dir-id'),
 
2700
                    ('dir1/file', 'file-id')],
 
2701
            target=[('dir2/', 'dir-id'),
 
2702
                    ('dir2/file', 'file-id')])
 
2703
        state = self.assertUpdate( # active present at other location
 
2704
            active=[('dir3/', 'dir-id'),
 
2705
                    ('dir3/file', 'file-id')],
 
2706
            basis= [('dir1/', 'dir-id'),
 
2707
                    ('dir1/file', 'file-id')],
 
2708
            target=[('dir2/', 'dir-id'),
 
2709
                    ('dir2/file', 'file-id')])
 
2710
        state = self.assertUpdate( # active has different ids
 
2711
            active=[('dir1/', 'dir1-id'),
 
2712
                    ('dir1/file', 'file1-id'),
 
2713
                    ('dir2/', 'dir2-id'),
 
2714
                    ('dir2/file', 'file2-id')],
 
2715
            basis= [('dir1/', 'dir-id'),
 
2716
                    ('dir1/file', 'file-id')],
 
2717
            target=[('dir2/', 'dir-id'),
 
2718
                    ('dir2/file', 'file-id')])
 
2719
 
 
2720
    def test_invalid_file_not_present(self):
 
2721
        state = self.assertBadDelta(
 
2722
            active=[('file', 'file-id')],
 
2723
            basis= [('file', 'file-id')],
 
2724
            delta=[('other-file', 'file', 'file-id')])
 
2725
 
 
2726
    def test_invalid_new_id_same_path(self):
 
2727
        # The bad entry comes after
 
2728
        state = self.assertBadDelta(
 
2729
            active=[('file', 'file-id')],
 
2730
            basis= [('file', 'file-id')],
 
2731
            delta=[(None, 'file', 'file-id-2')])
 
2732
        # The bad entry comes first
 
2733
        state = self.assertBadDelta(
 
2734
            active=[('file', 'file-id-2')],
 
2735
            basis=[('file', 'file-id-2')],
 
2736
            delta=[(None, 'file', 'file-id')])
 
2737
 
 
2738
    def test_invalid_existing_id(self):
 
2739
        state = self.assertBadDelta(
 
2740
            active=[('file', 'file-id')],
 
2741
            basis= [('file', 'file-id')],
 
2742
            delta=[(None, 'file', 'file-id')])
 
2743
 
 
2744
    def test_invalid_parent_missing(self):
 
2745
        state = self.assertBadDelta(
 
2746
            active=[],
 
2747
            basis= [],
 
2748
            delta=[(None, 'path/path2', 'file-id')])
 
2749
        # Note: we force the active tree to have the directory, by knowing how
 
2750
        #       path_to_ie handles entries with missing parents
 
2751
        state = self.assertBadDelta(
 
2752
            active=[('path/', 'path-id')],
 
2753
            basis= [],
 
2754
            delta=[(None, 'path/path2', 'file-id')])
 
2755
        state = self.assertBadDelta(
 
2756
            active=[('path/', 'path-id'),
 
2757
                    ('path/path2', 'file-id')],
 
2758
            basis= [],
 
2759
            delta=[(None, 'path/path2', 'file-id')])
 
2760
 
 
2761
    def test_renamed_dir_same_path(self):
 
2762
        # We replace the parent directory, with another parent dir. But the C
 
2763
        # file doesn't look like it has been moved.
 
2764
        state = self.assertUpdate(# Same as basis
 
2765
            active=[('dir/', 'A-id'),
 
2766
                    ('dir/B', 'B-id')],
 
2767
            basis= [('dir/', 'A-id'),
 
2768
                    ('dir/B', 'B-id')],
 
2769
            target=[('dir/', 'C-id'),
 
2770
                    ('dir/B', 'B-id')])
 
2771
        state = self.assertUpdate(# Same as target
 
2772
            active=[('dir/', 'C-id'),
 
2773
                    ('dir/B', 'B-id')],
 
2774
            basis= [('dir/', 'A-id'),
 
2775
                    ('dir/B', 'B-id')],
 
2776
            target=[('dir/', 'C-id'),
 
2777
                    ('dir/B', 'B-id')])
 
2778
        state = self.assertUpdate(# empty active
 
2779
            active=[],
 
2780
            basis= [('dir/', 'A-id'),
 
2781
                    ('dir/B', 'B-id')],
 
2782
            target=[('dir/', 'C-id'),
 
2783
                    ('dir/B', 'B-id')])
 
2784
        state = self.assertUpdate(# different active
 
2785
            active=[('dir/', 'D-id'),
 
2786
                    ('dir/B', 'B-id')],
 
2787
            basis= [('dir/', 'A-id'),
 
2788
                    ('dir/B', 'B-id')],
 
2789
            target=[('dir/', 'C-id'),
 
2790
                    ('dir/B', 'B-id')])
 
2791
 
 
2792
    def test_parent_child_swap(self):
 
2793
        state = self.assertUpdate(# Same as basis
 
2794
            active=[('A/', 'A-id'),
 
2795
                    ('A/B/', 'B-id'),
 
2796
                    ('A/B/C', 'C-id')],
 
2797
            basis= [('A/', 'A-id'),
 
2798
                    ('A/B/', 'B-id'),
 
2799
                    ('A/B/C', 'C-id')],
 
2800
            target=[('A/', 'B-id'),
 
2801
                    ('A/B/', 'A-id'),
 
2802
                    ('A/B/C', 'C-id')])
 
2803
        state = self.assertUpdate(# Same as target
 
2804
            active=[('A/', 'B-id'),
 
2805
                    ('A/B/', 'A-id'),
 
2806
                    ('A/B/C', 'C-id')],
 
2807
            basis= [('A/', 'A-id'),
 
2808
                    ('A/B/', 'B-id'),
 
2809
                    ('A/B/C', 'C-id')],
 
2810
            target=[('A/', 'B-id'),
 
2811
                    ('A/B/', 'A-id'),
 
2812
                    ('A/B/C', 'C-id')])
 
2813
        state = self.assertUpdate(# empty active
 
2814
            active=[],
 
2815
            basis= [('A/', 'A-id'),
 
2816
                    ('A/B/', 'B-id'),
 
2817
                    ('A/B/C', 'C-id')],
 
2818
            target=[('A/', 'B-id'),
 
2819
                    ('A/B/', 'A-id'),
 
2820
                    ('A/B/C', 'C-id')])
 
2821
        state = self.assertUpdate(# different active
 
2822
            active=[('D/', 'A-id'),
 
2823
                    ('D/E/', 'B-id'),
 
2824
                    ('F', 'C-id')],
 
2825
            basis= [('A/', 'A-id'),
 
2826
                    ('A/B/', 'B-id'),
 
2827
                    ('A/B/C', 'C-id')],
 
2828
            target=[('A/', 'B-id'),
 
2829
                    ('A/B/', 'A-id'),
 
2830
                    ('A/B/C', 'C-id')])
 
2831
 
 
2832
    def test_change_root_id(self):
 
2833
        state = self.assertUpdate( # same as basis
 
2834
            active=[('', 'root-id'),
 
2835
                    ('file', 'file-id')],
 
2836
            basis= [('', 'root-id'),
 
2837
                    ('file', 'file-id')],
 
2838
            target=[('', 'target-root-id'),
 
2839
                    ('file', 'file-id')])
 
2840
        state = self.assertUpdate( # same as target
 
2841
            active=[('', 'target-root-id'),
 
2842
                    ('file', 'file-id')],
 
2843
            basis= [('', 'root-id'),
 
2844
                    ('file', 'file-id')],
 
2845
            target=[('', 'target-root-id'),
 
2846
                    ('file', 'root-id')])
 
2847
        state = self.assertUpdate( # all different
 
2848
            active=[('', 'active-root-id'),
 
2849
                    ('file', 'file-id')],
 
2850
            basis= [('', 'root-id'),
 
2851
                    ('file', 'file-id')],
 
2852
            target=[('', 'target-root-id'),
 
2853
                    ('file', 'root-id')])
 
2854
 
 
2855
    def test_change_file_absent_in_active(self):
 
2856
        state = self.assertUpdate(
 
2857
            active=[],
 
2858
            basis= [('file', 'file-id')],
 
2859
            target=[('file', 'file-id')])
 
2860
 
 
2861
    def test_invalid_changed_file(self):
 
2862
        state = self.assertBadDelta( # Not present in basis
 
2863
            active=[('file', 'file-id')],
 
2864
            basis= [],
 
2865
            delta=[('file', 'file', 'file-id')])
 
2866
        state = self.assertBadDelta( # present at another location in basis
 
2867
            active=[('file', 'file-id')],
 
2868
            basis= [('other-file', 'file-id')],
 
2869
            delta=[('file', 'file', 'file-id')])