124
138
:return: The dirstate, still write-locked.
126
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
127
null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
128
root_entry = ('', '', 'a-root-value'), [
129
('d', '', 0, False, packed_stat),
131
a_entry = ('', 'a', 'a-dir'), [
132
('d', '', 0, False, packed_stat),
134
b_entry = ('', 'b', 'b-dir'), [
135
('d', '', 0, False, packed_stat),
137
c_entry = ('', 'c', 'c-file'), [
138
('f', null_sha, 10, False, packed_stat),
140
d_entry = ('', 'd', 'd-file'), [
141
('f', null_sha, 20, False, packed_stat),
143
e_entry = ('a', 'e', 'e-dir'), [
144
('d', '', 0, False, packed_stat),
146
f_entry = ('a', 'f', 'f-file'), [
147
('f', null_sha, 30, False, packed_stat),
149
g_entry = ('b', 'g', 'g-file'), [
150
('f', null_sha, 30, False, packed_stat),
152
h_entry = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file'), [
153
('f', null_sha, 40, False, packed_stat),
140
packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
141
null_sha = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
142
root_entry = (b'', b'', b'a-root-value'), [
143
(b'd', b'', 0, False, packed_stat),
145
a_entry = (b'', b'a', b'a-dir'), [
146
(b'd', b'', 0, False, packed_stat),
148
b_entry = (b'', b'b', b'b-dir'), [
149
(b'd', b'', 0, False, packed_stat),
151
c_entry = (b'', b'c', b'c-file'), [
152
(b'f', null_sha, 10, False, packed_stat),
154
d_entry = (b'', b'd', b'd-file'), [
155
(b'f', null_sha, 20, False, packed_stat),
157
e_entry = (b'a', b'e', b'e-dir'), [
158
(b'd', b'', 0, False, packed_stat),
160
f_entry = (b'a', b'f', b'f-file'), [
161
(b'f', null_sha, 30, False, packed_stat),
163
g_entry = (b'b', b'g', b'g-file'), [
164
(b'f', null_sha, 30, False, packed_stat),
166
h_entry = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file'), [
167
(b'f', null_sha, 40, False, packed_stat),
156
dirblocks.append(('', [root_entry]))
157
dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
158
dirblocks.append(('a', [e_entry, f_entry]))
159
dirblocks.append(('b', [g_entry, h_entry]))
170
dirblocks.append((b'', [root_entry]))
171
dirblocks.append((b'', [a_entry, b_entry, c_entry, d_entry]))
172
dirblocks.append((b'a', [e_entry, f_entry]))
173
dirblocks.append((b'b', [g_entry, h_entry]))
160
174
state = dirstate.DirState.initialize('dirstate')
161
175
state._validate()
241
256
f_len = len(f_text)
242
257
null_stat = dirstate.DirState.NULLSTAT
244
'':(('', '', 'TREE_ROOT'), [
245
('d', '', 0, False, null_stat),
246
('d', '', 0, False, revision_id),
248
'a':(('', 'a', 'a-id'), [
249
('f', '', 0, False, null_stat),
250
('f', a_sha, a_len, False, revision_id),
252
'b':(('', 'b', 'b-id'), [
253
('d', '', 0, False, null_stat),
254
('d', '', 0, False, revision_id),
256
'b/c':(('b', 'c', 'c-id'), [
257
('f', '', 0, False, null_stat),
258
('f', c_sha, c_len, False, revision_id),
260
'b/d':(('b', 'd', 'd-id'), [
261
('d', '', 0, False, null_stat),
262
('d', '', 0, False, revision_id),
264
'b/d/e':(('b/d', 'e', 'e-id'), [
265
('f', '', 0, False, null_stat),
266
('f', e_sha, e_len, False, revision_id),
268
'b-c':(('', 'b-c', 'b-c-id'), [
269
('f', '', 0, False, null_stat),
270
('f', b_c_sha, b_c_len, False, revision_id),
272
'f':(('', 'f', 'f-id'), [
273
('f', '', 0, False, null_stat),
274
('f', f_sha, f_len, False, revision_id),
259
b'': ((b'', b'', b'TREE_ROOT'), [
260
(b'd', b'', 0, False, null_stat),
261
(b'd', b'', 0, False, revision_id),
263
b'a': ((b'', b'a', b'a-id'), [
264
(b'f', b'', 0, False, null_stat),
265
(b'f', a_sha, a_len, False, revision_id),
267
b'b': ((b'', b'b', b'b-id'), [
268
(b'd', b'', 0, False, null_stat),
269
(b'd', b'', 0, False, revision_id),
271
b'b/c': ((b'b', b'c', b'c-id'), [
272
(b'f', b'', 0, False, null_stat),
273
(b'f', c_sha, c_len, False, revision_id),
275
b'b/d': ((b'b', b'd', b'd-id'), [
276
(b'd', b'', 0, False, null_stat),
277
(b'd', b'', 0, False, revision_id),
279
b'b/d/e': ((b'b/d', b'e', b'e-id'), [
280
(b'f', b'', 0, False, null_stat),
281
(b'f', e_sha, e_len, False, revision_id),
283
b'b-c': ((b'', b'b-c', b'b-c-id'), [
284
(b'f', b'', 0, False, null_stat),
285
(b'f', b_c_sha, b_c_len, False, revision_id),
287
b'f': ((b'', b'f', b'f-id'), [
288
(b'f', b'', 0, False, null_stat),
289
(b'f', f_sha, f_len, False, revision_id),
277
292
state = dirstate.DirState.from_tree(tree, 'dirstate')
900
971
"""Set the root file id in a dirstate with parents"""
901
972
mt = self.make_branch_and_tree('mt')
902
973
# in case the default tree format uses a different root id
903
mt.set_root_id('TREE_ROOT')
904
mt.commit('foo', rev_id='parent-revid')
905
rt = mt.branch.repository.revision_tree('parent-revid')
974
mt.set_root_id(b'TREE_ROOT')
975
mt.commit('foo', rev_id=b'parent-revid')
976
rt = mt.branch.repository.revision_tree(b'parent-revid')
906
977
state = dirstate.DirState.initialize('dirstate')
907
978
state._validate()
909
state.set_parent_trees([('parent-revid', rt)], ghosts=[])
910
root_entry = (('', '', 'TREE_ROOT'),
911
[('d', '', 0, False, 'x'*32),
912
('d', '', 0, False, 'parent-revid')])
913
self.assertEqual(root_entry, state._get_entry(0, path_utf8=''))
980
state.set_parent_trees([(b'parent-revid', rt)], ghosts=[])
981
root_entry = ((b'', b'', b'TREE_ROOT'),
982
[(b'd', b'', 0, False, b'x' * 32),
983
(b'd', b'', 0, False, b'parent-revid')])
984
self.assertEqual(root_entry, state._get_entry(0, path_utf8=b''))
914
985
self.assertEqual(root_entry,
915
state._get_entry(0, fileid_utf8='TREE_ROOT'))
986
state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
916
987
self.assertEqual((None, None),
917
state._get_entry(0, fileid_utf8='Asecond-root-id'))
918
state.set_path_id('', 'Asecond-root-id')
988
state._get_entry(0, fileid_utf8=b'Asecond-root-id'))
989
state.set_path_id(b'', b'Asecond-root-id')
919
990
state._validate()
920
991
# now see that it is what we expected
921
old_root_entry = (('', '', 'TREE_ROOT'),
922
[('a', '', 0, False, ''),
923
('d', '', 0, False, 'parent-revid')])
924
new_root_entry = (('', '', 'Asecond-root-id'),
925
[('d', '', 0, False, ''),
926
('a', '', 0, False, '')])
992
old_root_entry = ((b'', b'', b'TREE_ROOT'),
993
[(b'a', b'', 0, False, b''),
994
(b'd', b'', 0, False, b'parent-revid')])
995
new_root_entry = ((b'', b'', b'Asecond-root-id'),
996
[(b'd', b'', 0, False, b''),
997
(b'a', b'', 0, False, b'')])
927
998
expected_rows = [new_root_entry, old_root_entry]
928
999
state._validate()
929
1000
self.assertEqual(expected_rows, list(state._iter_entries()))
930
self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
931
self.assertEqual(old_root_entry, state._get_entry(1, path_utf8=''))
1002
new_root_entry, state._get_entry(0, path_utf8=b''))
1004
old_root_entry, state._get_entry(1, path_utf8=b''))
932
1005
self.assertEqual((None, None),
933
state._get_entry(0, fileid_utf8='TREE_ROOT'))
1006
state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
934
1007
self.assertEqual(old_root_entry,
935
state._get_entry(1, fileid_utf8='TREE_ROOT'))
1008
state._get_entry(1, fileid_utf8=b'TREE_ROOT'))
936
1009
self.assertEqual(new_root_entry,
937
state._get_entry(0, fileid_utf8='Asecond-root-id'))
1010
state._get_entry(0, fileid_utf8=b'Asecond-root-id'))
938
1011
self.assertEqual((None, None),
939
state._get_entry(1, fileid_utf8='Asecond-root-id'))
1012
state._get_entry(1, fileid_utf8=b'Asecond-root-id'))
940
1013
# should work across save too
1400
1529
def test_simple_structure(self):
1401
1530
state = self.create_dirstate_with_root_and_subdir()
1402
1531
self.addCleanup(state.unlock)
1403
self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'subdir', 0)
1404
self.assertBlockRowIndexEqual(1, 0, True, False, state, '', 'bdir', 0)
1405
self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'zdir', 0)
1406
self.assertBlockRowIndexEqual(2, 0, False, False, state, 'a', 'foo', 0)
1532
self.assertBlockRowIndexEqual(
1533
1, 0, True, True, state, b'', b'subdir', 0)
1534
self.assertBlockRowIndexEqual(
1535
1, 0, True, False, state, b'', b'bdir', 0)
1536
self.assertBlockRowIndexEqual(
1537
1, 1, True, False, state, b'', b'zdir', 0)
1538
self.assertBlockRowIndexEqual(
1539
2, 0, False, False, state, b'a', b'foo', 0)
1407
1540
self.assertBlockRowIndexEqual(2, 0, False, False, state,
1541
b'subdir', b'foo', 0)
1410
1543
def test_complex_structure_exists(self):
1411
1544
state = self.create_complex_dirstate()
1412
1545
self.addCleanup(state.unlock)
1413
1546
# Make sure we can find everything that exists
1414
self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1415
self.assertBlockRowIndexEqual(1, 0, True, True, state, '', 'a', 0)
1416
self.assertBlockRowIndexEqual(1, 1, True, True, state, '', 'b', 0)
1417
self.assertBlockRowIndexEqual(1, 2, True, True, state, '', 'c', 0)
1418
self.assertBlockRowIndexEqual(1, 3, True, True, state, '', 'd', 0)
1419
self.assertBlockRowIndexEqual(2, 0, True, True, state, 'a', 'e', 0)
1420
self.assertBlockRowIndexEqual(2, 1, True, True, state, 'a', 'f', 0)
1421
self.assertBlockRowIndexEqual(3, 0, True, True, state, 'b', 'g', 0)
1547
self.assertBlockRowIndexEqual(0, 0, True, True, state, b'', b'', 0)
1548
self.assertBlockRowIndexEqual(1, 0, True, True, state, b'', b'a', 0)
1549
self.assertBlockRowIndexEqual(1, 1, True, True, state, b'', b'b', 0)
1550
self.assertBlockRowIndexEqual(1, 2, True, True, state, b'', b'c', 0)
1551
self.assertBlockRowIndexEqual(1, 3, True, True, state, b'', b'd', 0)
1552
self.assertBlockRowIndexEqual(2, 0, True, True, state, b'a', b'e', 0)
1553
self.assertBlockRowIndexEqual(2, 1, True, True, state, b'a', b'f', 0)
1554
self.assertBlockRowIndexEqual(3, 0, True, True, state, b'b', b'g', 0)
1422
1555
self.assertBlockRowIndexEqual(3, 1, True, True, state,
1423
'b', 'h\xc3\xa5', 0)
1556
b'b', b'h\xc3\xa5', 0)
1425
1558
def test_complex_structure_missing(self):
1426
1559
state = self.create_complex_dirstate()
1427
1560
self.addCleanup(state.unlock)
1428
1561
# Make sure things would be inserted in the right locations
1429
1562
# '_' comes before 'a'
1430
self.assertBlockRowIndexEqual(0, 0, True, True, state, '', '', 0)
1431
self.assertBlockRowIndexEqual(1, 0, True, False, state, '', '_', 0)
1432
self.assertBlockRowIndexEqual(1, 1, True, False, state, '', 'aa', 0)
1563
self.assertBlockRowIndexEqual(0, 0, True, True, state, b'', b'', 0)
1564
self.assertBlockRowIndexEqual(1, 0, True, False, state, b'', b'_', 0)
1565
self.assertBlockRowIndexEqual(1, 1, True, False, state, b'', b'aa', 0)
1433
1566
self.assertBlockRowIndexEqual(1, 4, True, False, state,
1435
self.assertBlockRowIndexEqual(2, 0, False, False, state, '_', 'a', 0)
1436
self.assertBlockRowIndexEqual(3, 0, False, False, state, 'aa', 'a', 0)
1437
self.assertBlockRowIndexEqual(4, 0, False, False, state, 'bb', 'a', 0)
1567
b'', b'h\xc3\xa5', 0)
1568
self.assertBlockRowIndexEqual(2, 0, False, False, state, b'_', b'a', 0)
1569
self.assertBlockRowIndexEqual(
1570
3, 0, False, False, state, b'aa', b'a', 0)
1571
self.assertBlockRowIndexEqual(
1572
4, 0, False, False, state, b'bb', b'a', 0)
1438
1573
# This would be inserted between a/ and b/
1439
self.assertBlockRowIndexEqual(3, 0, False, False, state, 'a/e', 'a', 0)
1574
self.assertBlockRowIndexEqual(
1575
3, 0, False, False, state, b'a/e', b'a', 0)
1440
1576
# Put at the end
1441
self.assertBlockRowIndexEqual(4, 0, False, False, state, 'e', 'a', 0)
1577
self.assertBlockRowIndexEqual(4, 0, False, False, state, b'e', b'a', 0)
1444
1580
class TestGetEntry(TestCaseWithDirState):
1455
1591
def test_simple_structure(self):
1456
1592
state = self.create_dirstate_with_root_and_subdir()
1457
1593
self.addCleanup(state.unlock)
1458
self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1459
self.assertEntryEqual('', 'subdir', 'subdir-id', state, 'subdir', 0)
1460
self.assertEntryEqual(None, None, None, state, 'missing', 0)
1461
self.assertEntryEqual(None, None, None, state, 'missing/foo', 0)
1462
self.assertEntryEqual(None, None, None, state, 'subdir/foo', 0)
1594
self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
1595
self.assertEntryEqual(
1596
b'', b'subdir', b'subdir-id', state, b'subdir', 0)
1597
self.assertEntryEqual(None, None, None, state, b'missing', 0)
1598
self.assertEntryEqual(None, None, None, state, b'missing/foo', 0)
1599
self.assertEntryEqual(None, None, None, state, b'subdir/foo', 0)
1464
1601
def test_complex_structure_exists(self):
1465
1602
state = self.create_complex_dirstate()
1466
1603
self.addCleanup(state.unlock)
1467
self.assertEntryEqual('', '', 'a-root-value', state, '', 0)
1468
self.assertEntryEqual('', 'a', 'a-dir', state, 'a', 0)
1469
self.assertEntryEqual('', 'b', 'b-dir', state, 'b', 0)
1470
self.assertEntryEqual('', 'c', 'c-file', state, 'c', 0)
1471
self.assertEntryEqual('', 'd', 'd-file', state, 'd', 0)
1472
self.assertEntryEqual('a', 'e', 'e-dir', state, 'a/e', 0)
1473
self.assertEntryEqual('a', 'f', 'f-file', state, 'a/f', 0)
1474
self.assertEntryEqual('b', 'g', 'g-file', state, 'b/g', 0)
1475
self.assertEntryEqual('b', 'h\xc3\xa5', 'h-\xc3\xa5-file', state,
1604
self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
1605
self.assertEntryEqual(b'', b'a', b'a-dir', state, b'a', 0)
1606
self.assertEntryEqual(b'', b'b', b'b-dir', state, b'b', 0)
1607
self.assertEntryEqual(b'', b'c', b'c-file', state, b'c', 0)
1608
self.assertEntryEqual(b'', b'd', b'd-file', state, b'd', 0)
1609
self.assertEntryEqual(b'a', b'e', b'e-dir', state, b'a/e', 0)
1610
self.assertEntryEqual(b'a', b'f', b'f-file', state, b'a/f', 0)
1611
self.assertEntryEqual(b'b', b'g', b'g-file', state, b'b/g', 0)
1612
self.assertEntryEqual(b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file', state,
1478
1615
def test_complex_structure_missing(self):
1479
1616
state = self.create_complex_dirstate()
1480
1617
self.addCleanup(state.unlock)
1481
self.assertEntryEqual(None, None, None, state, '_', 0)
1482
self.assertEntryEqual(None, None, None, state, '_\xc3\xa5', 0)
1483
self.assertEntryEqual(None, None, None, state, 'a/b', 0)
1484
self.assertEntryEqual(None, None, None, state, 'c/d', 0)
1618
self.assertEntryEqual(None, None, None, state, b'_', 0)
1619
self.assertEntryEqual(None, None, None, state, b'_\xc3\xa5', 0)
1620
self.assertEntryEqual(None, None, None, state, b'a/b', 0)
1621
self.assertEntryEqual(None, None, None, state, b'c/d', 0)
1486
1623
def test_get_entry_uninitialized(self):
1487
1624
"""Calling get_entry will load data if it needs to"""
1529
1666
:return: The dirstate, still write-locked.
1531
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1532
null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1668
packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1669
null_sha = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1533
1670
NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1534
root_entry = ('', '', 'a-root-value'), [
1535
('d', '', 0, False, packed_stat),
1536
('d', '', 0, False, 'parent-revid'),
1538
a_entry = ('', 'a', 'a-dir'), [
1539
('d', '', 0, False, packed_stat),
1540
('d', '', 0, False, 'parent-revid'),
1542
b_entry = ('', 'b', 'b-dir'), [
1543
('d', '', 0, False, packed_stat),
1544
('d', '', 0, False, 'parent-revid'),
1546
c_entry = ('', 'c', 'c-file'), [
1547
('f', null_sha, 10, False, packed_stat),
1548
('r', 'b/j', 0, False, ''),
1550
d_entry = ('', 'd', 'd-file'), [
1551
('f', null_sha, 20, False, packed_stat),
1552
('f', 'd', 20, False, 'parent-revid'),
1554
e_entry = ('a', 'e', 'e-dir'), [
1555
('d', '', 0, False, packed_stat),
1556
('d', '', 0, False, 'parent-revid'),
1558
f_entry = ('a', 'f', 'f-file'), [
1559
('f', null_sha, 30, False, packed_stat),
1560
('f', 'f', 20, False, 'parent-revid'),
1562
g_entry = ('b', 'g', 'g-file'), [
1563
('f', null_sha, 30, False, packed_stat),
1564
NULL_PARENT_DETAILS,
1566
h_entry1 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file1'), [
1567
('f', null_sha, 40, False, packed_stat),
1568
NULL_PARENT_DETAILS,
1570
h_entry2 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file2'), [
1571
NULL_PARENT_DETAILS,
1572
('f', 'h', 20, False, 'parent-revid'),
1574
i_entry = ('b', 'i', 'i-file'), [
1575
NULL_PARENT_DETAILS,
1576
('f', 'h', 20, False, 'parent-revid'),
1578
j_entry = ('b', 'j', 'c-file'), [
1579
('r', 'c', 0, False, ''),
1580
('f', 'j', 20, False, 'parent-revid'),
1671
root_entry = (b'', b'', b'a-root-value'), [
1672
(b'd', b'', 0, False, packed_stat),
1673
(b'd', b'', 0, False, b'parent-revid'),
1675
a_entry = (b'', b'a', b'a-dir'), [
1676
(b'd', b'', 0, False, packed_stat),
1677
(b'd', b'', 0, False, b'parent-revid'),
1679
b_entry = (b'', b'b', b'b-dir'), [
1680
(b'd', b'', 0, False, packed_stat),
1681
(b'd', b'', 0, False, b'parent-revid'),
1683
c_entry = (b'', b'c', b'c-file'), [
1684
(b'f', null_sha, 10, False, packed_stat),
1685
(b'r', b'b/j', 0, False, b''),
1687
d_entry = (b'', b'd', b'd-file'), [
1688
(b'f', null_sha, 20, False, packed_stat),
1689
(b'f', b'd', 20, False, b'parent-revid'),
1691
e_entry = (b'a', b'e', b'e-dir'), [
1692
(b'd', b'', 0, False, packed_stat),
1693
(b'd', b'', 0, False, b'parent-revid'),
1695
f_entry = (b'a', b'f', b'f-file'), [
1696
(b'f', null_sha, 30, False, packed_stat),
1697
(b'f', b'f', 20, False, b'parent-revid'),
1699
g_entry = (b'b', b'g', b'g-file'), [
1700
(b'f', null_sha, 30, False, packed_stat),
1701
NULL_PARENT_DETAILS,
1703
h_entry1 = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file1'), [
1704
(b'f', null_sha, 40, False, packed_stat),
1705
NULL_PARENT_DETAILS,
1707
h_entry2 = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file2'), [
1708
NULL_PARENT_DETAILS,
1709
(b'f', b'h', 20, False, b'parent-revid'),
1711
i_entry = (b'b', b'i', b'i-file'), [
1712
NULL_PARENT_DETAILS,
1713
(b'f', b'h', 20, False, b'parent-revid'),
1715
j_entry = (b'b', b'j', b'c-file'), [
1716
(b'r', b'c', 0, False, b''),
1717
(b'f', b'j', 20, False, b'parent-revid'),
1583
dirblocks.append(('', [root_entry]))
1584
dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
1585
dirblocks.append(('a', [e_entry, f_entry]))
1586
dirblocks.append(('b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
1720
dirblocks.append((b'', [root_entry]))
1721
dirblocks.append((b'', [a_entry, b_entry, c_entry, d_entry]))
1722
dirblocks.append((b'a', [e_entry, f_entry]))
1724
(b'b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
1587
1725
state = dirstate.DirState.initialize('dirstate')
1588
1726
state._validate()
1590
state._set_data(['parent'], dirblocks)
1728
state._set_data([b'parent'], dirblocks)
1874
2016
tree, state, expected = self.create_basic_dirstate()
1876
2018
# Bisect should return the rows for the specified files.
1877
self.assertBisect(expected, [['']], state, [''])
1878
self.assertBisect(expected, [['a']], state, ['a'])
1879
self.assertBisect(expected, [['b']], state, ['b'])
1880
self.assertBisect(expected, [['b/c']], state, ['b/c'])
1881
self.assertBisect(expected, [['b/d']], state, ['b/d'])
1882
self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1883
self.assertBisect(expected, [['b-c']], state, ['b-c'])
1884
self.assertBisect(expected, [['f']], state, ['f'])
2019
self.assertBisect(expected, [[b'']], state, [b''])
2020
self.assertBisect(expected, [[b'a']], state, [b'a'])
2021
self.assertBisect(expected, [[b'b']], state, [b'b'])
2022
self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2023
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2024
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2025
self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2026
self.assertBisect(expected, [[b'f']], state, [b'f'])
1886
2028
def test_bisect_multi(self):
1887
2029
"""Bisect can be used to find multiple records at the same time."""
1888
2030
tree, state, expected = self.create_basic_dirstate()
1889
2031
# Bisect should be capable of finding multiple entries at the same time
1890
self.assertBisect(expected, [['a'], ['b'], ['f']],
1891
state, ['a', 'b', 'f'])
1892
self.assertBisect(expected, [['f'], ['b/d'], ['b/d/e']],
1893
state, ['f', 'b/d', 'b/d/e'])
1894
self.assertBisect(expected, [['b'], ['b-c'], ['b/c']],
1895
state, ['b', 'b-c', 'b/c'])
2032
self.assertBisect(expected, [[b'a'], [b'b'], [b'f']],
2033
state, [b'a', b'b', b'f'])
2034
self.assertBisect(expected, [[b'f'], [b'b/d'], [b'b/d/e']],
2035
state, [b'f', b'b/d', b'b/d/e'])
2036
self.assertBisect(expected, [[b'b'], [b'b-c'], [b'b/c']],
2037
state, [b'b', b'b-c', b'b/c'])
1897
2039
def test_bisect_one_page(self):
1898
2040
"""Test bisect when there is only 1 page to read"""
1899
2041
tree, state, expected = self.create_basic_dirstate()
1900
2042
state._bisect_page_size = 5000
1901
self.assertBisect(expected,[['']], state, [''])
1902
self.assertBisect(expected,[['a']], state, ['a'])
1903
self.assertBisect(expected,[['b']], state, ['b'])
1904
self.assertBisect(expected,[['b/c']], state, ['b/c'])
1905
self.assertBisect(expected,[['b/d']], state, ['b/d'])
1906
self.assertBisect(expected,[['b/d/e']], state, ['b/d/e'])
1907
self.assertBisect(expected,[['b-c']], state, ['b-c'])
1908
self.assertBisect(expected,[['f']], state, ['f'])
1909
self.assertBisect(expected,[['a'], ['b'], ['f']],
1910
state, ['a', 'b', 'f'])
1911
self.assertBisect(expected, [['b/d'], ['b/d/e'], ['f']],
1912
state, ['b/d', 'b/d/e', 'f'])
1913
self.assertBisect(expected, [['b'], ['b/c'], ['b-c']],
1914
state, ['b', 'b/c', 'b-c'])
2043
self.assertBisect(expected, [[b'']], state, [b''])
2044
self.assertBisect(expected, [[b'a']], state, [b'a'])
2045
self.assertBisect(expected, [[b'b']], state, [b'b'])
2046
self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2047
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2048
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2049
self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2050
self.assertBisect(expected, [[b'f']], state, [b'f'])
2051
self.assertBisect(expected, [[b'a'], [b'b'], [b'f']],
2052
state, [b'a', b'b', b'f'])
2053
self.assertBisect(expected, [[b'b/d'], [b'b/d/e'], [b'f']],
2054
state, [b'b/d', b'b/d/e', b'f'])
2055
self.assertBisect(expected, [[b'b'], [b'b/c'], [b'b-c']],
2056
state, [b'b', b'b/c', b'b-c'])
1916
2058
def test_bisect_duplicate_paths(self):
1917
2059
"""When bisecting for a path, handle multiple entries."""
1918
2060
tree, state, expected = self.create_duplicated_dirstate()
1920
2062
# Now make sure that both records are properly returned.
1921
self.assertBisect(expected, [['']], state, [''])
1922
self.assertBisect(expected, [['a', 'a2']], state, ['a'])
1923
self.assertBisect(expected, [['b', 'b2']], state, ['b'])
1924
self.assertBisect(expected, [['b/c', 'b/c2']], state, ['b/c'])
1925
self.assertBisect(expected, [['b/d', 'b/d2']], state, ['b/d'])
1926
self.assertBisect(expected, [['b/d/e', 'b/d/e2']],
1928
self.assertBisect(expected, [['b-c', 'b-c2']], state, ['b-c'])
1929
self.assertBisect(expected, [['f', 'f2']], state, ['f'])
2063
self.assertBisect(expected, [[b'']], state, [b''])
2064
self.assertBisect(expected, [[b'a', b'a2']], state, [b'a'])
2065
self.assertBisect(expected, [[b'b', b'b2']], state, [b'b'])
2066
self.assertBisect(expected, [[b'b/c', b'b/c2']], state, [b'b/c'])
2067
self.assertBisect(expected, [[b'b/d', b'b/d2']], state, [b'b/d'])
2068
self.assertBisect(expected, [[b'b/d/e', b'b/d/e2']],
2070
self.assertBisect(expected, [[b'b-c', b'b-c2']], state, [b'b-c'])
2071
self.assertBisect(expected, [[b'f', b'f2']], state, [b'f'])
1931
2073
def test_bisect_page_size_too_small(self):
1932
2074
"""If the page size is too small, we will auto increase it."""
1933
2075
tree, state, expected = self.create_basic_dirstate()
1934
2076
state._bisect_page_size = 50
1935
self.assertBisect(expected, [None], state, ['b/e'])
1936
self.assertBisect(expected, [['a']], state, ['a'])
1937
self.assertBisect(expected, [['b']], state, ['b'])
1938
self.assertBisect(expected, [['b/c']], state, ['b/c'])
1939
self.assertBisect(expected, [['b/d']], state, ['b/d'])
1940
self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1941
self.assertBisect(expected, [['b-c']], state, ['b-c'])
1942
self.assertBisect(expected, [['f']], state, ['f'])
2077
self.assertBisect(expected, [None], state, [b'b/e'])
2078
self.assertBisect(expected, [[b'a']], state, [b'a'])
2079
self.assertBisect(expected, [[b'b']], state, [b'b'])
2080
self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2081
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2082
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2083
self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2084
self.assertBisect(expected, [[b'f']], state, [b'f'])
1944
2086
def test_bisect_missing(self):
1945
2087
"""Test that bisect return None if it cannot find a path."""
1946
2088
tree, state, expected = self.create_basic_dirstate()
1947
self.assertBisect(expected, [None], state, ['foo'])
1948
self.assertBisect(expected, [None], state, ['b/foo'])
1949
self.assertBisect(expected, [None], state, ['bar/foo'])
1950
self.assertBisect(expected, [None], state, ['b-c/foo'])
2089
self.assertBisect(expected, [None], state, [b'foo'])
2090
self.assertBisect(expected, [None], state, [b'b/foo'])
2091
self.assertBisect(expected, [None], state, [b'bar/foo'])
2092
self.assertBisect(expected, [None], state, [b'b-c/foo'])
1952
self.assertBisect(expected, [['a'], None, ['b/d']],
1953
state, ['a', 'foo', 'b/d'])
2094
self.assertBisect(expected, [[b'a'], None, [b'b/d']],
2095
state, [b'a', b'foo', b'b/d'])
1955
2097
def test_bisect_rename(self):
1956
2098
"""Check that we find a renamed row."""
1957
2099
tree, state, expected = self.create_renamed_dirstate()
1959
2101
# Search for the pre and post renamed entries
1960
self.assertBisect(expected, [['a']], state, ['a'])
1961
self.assertBisect(expected, [['b/g']], state, ['b/g'])
1962
self.assertBisect(expected, [['b/d']], state, ['b/d'])
1963
self.assertBisect(expected, [['h']], state, ['h'])
2102
self.assertBisect(expected, [[b'a']], state, [b'a'])
2103
self.assertBisect(expected, [[b'b/g']], state, [b'b/g'])
2104
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2105
self.assertBisect(expected, [[b'h']], state, [b'h'])
1965
2107
# What about b/d/e? shouldn't that also get 2 directory entries?
1966
self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1967
self.assertBisect(expected, [['h/e']], state, ['h/e'])
2108
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2109
self.assertBisect(expected, [[b'h/e']], state, [b'h/e'])
1969
2111
def test_bisect_dirblocks(self):
1970
2112
tree, state, expected = self.create_duplicated_dirstate()
1971
2113
self.assertBisectDirBlocks(expected,
1972
[['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2']],
1974
self.assertBisectDirBlocks(expected,
1975
[['b/c', 'b/c2', 'b/d', 'b/d2']], state, ['b'])
1976
self.assertBisectDirBlocks(expected,
1977
[['b/d/e', 'b/d/e2']], state, ['b/d'])
1978
self.assertBisectDirBlocks(expected,
1979
[['', 'a', 'a2', 'b', 'b2', 'b-c', 'b-c2', 'f', 'f2'],
1980
['b/c', 'b/c2', 'b/d', 'b/d2'],
1981
['b/d/e', 'b/d/e2'],
1982
], state, ['', 'b', 'b/d'])
2114
[[b'', b'a', b'a2', b'b', b'b2',
2115
b'b-c', b'b-c2', b'f', b'f2']],
2117
self.assertBisectDirBlocks(expected,
2118
[[b'b/c', b'b/c2', b'b/d', b'b/d2']], state, [b'b'])
2119
self.assertBisectDirBlocks(expected,
2120
[[b'b/d/e', b'b/d/e2']], state, [b'b/d'])
2121
self.assertBisectDirBlocks(expected,
2122
[[b'', b'a', b'a2', b'b', b'b2', b'b-c', b'b-c2', b'f', b'f2'],
2123
[b'b/c', b'b/c2', b'b/d', b'b/d2'],
2124
[b'b/d/e', b'b/d/e2'],
2125
], state, [b'', b'b', b'b/d'])
1984
2127
def test_bisect_dirblocks_missing(self):
1985
2128
tree, state, expected = self.create_basic_dirstate()
1986
self.assertBisectDirBlocks(expected, [['b/d/e'], None],
1987
state, ['b/d', 'b/e'])
2129
self.assertBisectDirBlocks(expected, [[b'b/d/e'], None],
2130
state, [b'b/d', b'b/e'])
1988
2131
# Files don't show up in this search
1989
self.assertBisectDirBlocks(expected, [None], state, ['a'])
1990
self.assertBisectDirBlocks(expected, [None], state, ['b/c'])
1991
self.assertBisectDirBlocks(expected, [None], state, ['c'])
1992
self.assertBisectDirBlocks(expected, [None], state, ['b/d/e'])
1993
self.assertBisectDirBlocks(expected, [None], state, ['f'])
2132
self.assertBisectDirBlocks(expected, [None], state, [b'a'])
2133
self.assertBisectDirBlocks(expected, [None], state, [b'b/c'])
2134
self.assertBisectDirBlocks(expected, [None], state, [b'c'])
2135
self.assertBisectDirBlocks(expected, [None], state, [b'b/d/e'])
2136
self.assertBisectDirBlocks(expected, [None], state, [b'f'])
1995
2138
def test_bisect_recursive_each(self):
1996
2139
tree, state, expected = self.create_basic_dirstate()
1997
self.assertBisectRecursive(expected, ['a'], state, ['a'])
1998
self.assertBisectRecursive(expected, ['b/c'], state, ['b/c'])
1999
self.assertBisectRecursive(expected, ['b/d/e'], state, ['b/d/e'])
2000
self.assertBisectRecursive(expected, ['b-c'], state, ['b-c'])
2001
self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2003
self.assertBisectRecursive(expected, ['b', 'b/c', 'b/d', 'b/d/e'],
2005
self.assertBisectRecursive(expected, ['', 'a', 'b', 'b-c', 'f', 'b/c',
2140
self.assertBisectRecursive(expected, [b'a'], state, [b'a'])
2141
self.assertBisectRecursive(expected, [b'b/c'], state, [b'b/c'])
2142
self.assertBisectRecursive(expected, [b'b/d/e'], state, [b'b/d/e'])
2143
self.assertBisectRecursive(expected, [b'b-c'], state, [b'b-c'])
2144
self.assertBisectRecursive(expected, [b'b/d', b'b/d/e'],
2146
self.assertBisectRecursive(expected, [b'b', b'b/c', b'b/d', b'b/d/e'],
2148
self.assertBisectRecursive(expected, [b'', b'a', b'b', b'b-c', b'f', b'b/c',
2009
2152
def test_bisect_recursive_multiple(self):
2010
2153
tree, state, expected = self.create_basic_dirstate()
2011
self.assertBisectRecursive(expected, ['a', 'b/c'], state, ['a', 'b/c'])
2012
self.assertBisectRecursive(expected, ['b/d', 'b/d/e'],
2013
state, ['b/d', 'b/d/e'])
2154
self.assertBisectRecursive(
2155
expected, [b'a', b'b/c'], state, [b'a', b'b/c'])
2156
self.assertBisectRecursive(expected, [b'b/d', b'b/d/e'],
2157
state, [b'b/d', b'b/d/e'])
2015
2159
def test_bisect_recursive_missing(self):
2016
2160
tree, state, expected = self.create_basic_dirstate()
2017
self.assertBisectRecursive(expected, [], state, ['d'])
2018
self.assertBisectRecursive(expected, [], state, ['b/e'])
2019
self.assertBisectRecursive(expected, [], state, ['g'])
2020
self.assertBisectRecursive(expected, ['a'], state, ['a', 'g'])
2161
self.assertBisectRecursive(expected, [], state, [b'd'])
2162
self.assertBisectRecursive(expected, [], state, [b'b/e'])
2163
self.assertBisectRecursive(expected, [], state, [b'g'])
2164
self.assertBisectRecursive(expected, [b'a'], state, [b'a', b'g'])
2022
2166
def test_bisect_recursive_renamed(self):
2023
2167
tree, state, expected = self.create_renamed_dirstate()
2025
2169
# Looking for either renamed item should find the other
2026
self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['a'])
2027
self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['b/g'])
2170
self.assertBisectRecursive(expected, [b'a', b'b/g'], state, [b'a'])
2171
self.assertBisectRecursive(expected, [b'a', b'b/g'], state, [b'b/g'])
2028
2172
# Looking in the containing directory should find the rename target,
2029
2173
# and anything in a subdir of the renamed target.
2030
self.assertBisectRecursive(expected, ['a', 'b', 'b/c', 'b/d',
2031
'b/d/e', 'b/g', 'h', 'h/e'],
2174
self.assertBisectRecursive(expected, [b'a', b'b', b'b/c', b'b/d',
2175
b'b/d/e', b'b/g', b'h', b'h/e'],
2035
2179
class TestDirstateValidation(TestCaseWithDirState):
2141
2285
def test_discard_simple(self):
2143
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2144
root_entry_direntry = ('', '', 'a-root-value'), [
2145
('d', '', 0, False, packed_stat),
2146
('d', '', 0, False, packed_stat),
2147
('d', '', 0, False, packed_stat),
2287
packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2288
root_entry_direntry = (b'', b'', b'a-root-value'), [
2289
(b'd', b'', 0, False, packed_stat),
2290
(b'd', b'', 0, False, packed_stat),
2291
(b'd', b'', 0, False, packed_stat),
2149
expected_root_entry_direntry = ('', '', 'a-root-value'), [
2150
('d', '', 0, False, packed_stat),
2151
('d', '', 0, False, packed_stat),
2293
expected_root_entry_direntry = (b'', b'', b'a-root-value'), [
2294
(b'd', b'', 0, False, packed_stat),
2295
(b'd', b'', 0, False, packed_stat),
2154
dirblocks.append(('', [root_entry_direntry]))
2155
dirblocks.append(('', []))
2298
dirblocks.append((b'', [root_entry_direntry]))
2299
dirblocks.append((b'', []))
2157
2301
state = self.create_empty_dirstate()
2158
2302
self.addCleanup(state.unlock)
2159
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2303
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2160
2304
state._validate()
2162
2306
# This should strip of the extra column
2163
2307
state._discard_merge_parents()
2164
2308
state._validate()
2165
expected_dirblocks = [('', [expected_root_entry_direntry]), ('', [])]
2309
expected_dirblocks = [(b'', [expected_root_entry_direntry]), (b'', [])]
2166
2310
self.assertEqual(expected_dirblocks, state._dirblocks)
2168
2312
def test_discard_absent(self):
2169
2313
"""If entries are only in a merge, discard should remove the entries"""
2170
2314
null_stat = dirstate.DirState.NULLSTAT
2171
present_dir = ('d', '', 0, False, null_stat)
2172
present_file = ('f', '', 0, False, null_stat)
2315
present_dir = (b'd', b'', 0, False, null_stat)
2316
present_file = (b'f', b'', 0, False, null_stat)
2173
2317
absent = dirstate.DirState.NULL_PARENT_DETAILS
2174
root_key = ('', '', 'a-root-value')
2175
file_in_root_key = ('', 'file-in-root', 'a-file-id')
2176
file_in_merged_key = ('', 'file-in-merged', 'b-file-id')
2177
dirblocks = [('', [(root_key, [present_dir, present_dir, present_dir])]),
2178
('', [(file_in_merged_key,
2179
[absent, absent, present_file]),
2181
[present_file, present_file, present_file]),
2318
root_key = (b'', b'', b'a-root-value')
2319
file_in_root_key = (b'', b'file-in-root', b'a-file-id')
2320
file_in_merged_key = (b'', b'file-in-merged', b'b-file-id')
2321
dirblocks = [(b'', [(root_key, [present_dir, present_dir, present_dir])]),
2322
(b'', [(file_in_merged_key,
2323
[absent, absent, present_file]),
2325
[present_file, present_file, present_file]),
2185
2329
state = self.create_empty_dirstate()
2186
2330
self.addCleanup(state.unlock)
2187
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2331
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2188
2332
state._validate()
2190
exp_dirblocks = [('', [(root_key, [present_dir, present_dir])]),
2191
('', [(file_in_root_key,
2192
[present_file, present_file]),
2334
exp_dirblocks = [(b'', [(root_key, [present_dir, present_dir])]),
2335
(b'', [(file_in_root_key,
2336
[present_file, present_file]),
2195
2339
state._discard_merge_parents()
2196
2340
state._validate()
2197
2341
self.assertEqual(exp_dirblocks, state._dirblocks)
2199
2343
def test_discard_renamed(self):
2200
2344
null_stat = dirstate.DirState.NULLSTAT
2201
present_dir = ('d', '', 0, False, null_stat)
2202
present_file = ('f', '', 0, False, null_stat)
2345
present_dir = (b'd', b'', 0, False, null_stat)
2346
present_file = (b'f', b'', 0, False, null_stat)
2203
2347
absent = dirstate.DirState.NULL_PARENT_DETAILS
2204
root_key = ('', '', 'a-root-value')
2205
file_in_root_key = ('', 'file-in-root', 'a-file-id')
2348
root_key = (b'', b'', b'a-root-value')
2349
file_in_root_key = (b'', b'file-in-root', b'a-file-id')
2206
2350
# Renamed relative to parent
2207
file_rename_s_key = ('', 'file-s', 'b-file-id')
2208
file_rename_t_key = ('', 'file-t', 'b-file-id')
2351
file_rename_s_key = (b'', b'file-s', b'b-file-id')
2352
file_rename_t_key = (b'', b'file-t', b'b-file-id')
2209
2353
# And one that is renamed between the parents, but absent in this
2210
key_in_1 = ('', 'file-in-1', 'c-file-id')
2211
key_in_2 = ('', 'file-in-2', 'c-file-id')
2354
key_in_1 = (b'', b'file-in-1', b'c-file-id')
2355
key_in_2 = (b'', b'file-in-2', b'c-file-id')
2214
('', [(root_key, [present_dir, present_dir, present_dir])]),
2216
[absent, present_file, ('r', 'file-in-2', 'c-file-id')]),
2218
[absent, ('r', 'file-in-1', 'c-file-id'), present_file]),
2220
[present_file, present_file, present_file]),
2222
[('r', 'file-t', 'b-file-id'), absent, present_file]),
2224
[present_file, absent, ('r', 'file-s', 'b-file-id')]),
2358
(b'', [(root_key, [present_dir, present_dir, present_dir])]),
2360
[absent, present_file, (b'r', b'file-in-2', b'c-file-id')]),
2362
[absent, (b'r', b'file-in-1', b'c-file-id'), present_file]),
2364
[present_file, present_file, present_file]),
2366
[(b'r', b'file-t', b'b-file-id'), absent, present_file]),
2368
[present_file, absent, (b'r', b'file-s', b'b-file-id')]),
2227
2371
exp_dirblocks = [
2228
('', [(root_key, [present_dir, present_dir])]),
2229
('', [(key_in_1, [absent, present_file]),
2230
(file_in_root_key, [present_file, present_file]),
2231
(file_rename_t_key, [present_file, absent]),
2372
(b'', [(root_key, [present_dir, present_dir])]),
2373
(b'', [(key_in_1, [absent, present_file]),
2374
(file_in_root_key, [present_file, present_file]),
2375
(file_rename_t_key, [present_file, absent]),
2234
2378
state = self.create_empty_dirstate()
2235
2379
self.addCleanup(state.unlock)
2236
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2380
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2237
2381
state._validate()
2239
2383
state._discard_merge_parents()
2320
2464
self.assertTrue(len(statvalue) >= 10)
2321
2465
self.assertEqual(len(text), statvalue.st_size)
2322
2466
self.assertEqual(expected_sha, sha1)
2469
class _Repo(object):
2470
"""A minimal api to get InventoryRevisionTree to work."""
2473
default_format = controldir.format_registry.make_controldir('default')
2474
self._format = default_format.repository_format
2476
def lock_read(self):
2483
class TestUpdateBasisByDelta(tests.TestCase):
2485
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2486
if path.endswith('/'):
2491
dirname, basename = osutils.split(path)
2493
dir_id = dir_ids[dirname]
2495
dir_id = osutils.basename(dirname).encode('utf-8') + b'-id'
2497
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2498
dir_ids[path] = file_id
2500
ie = inventory.InventoryFile(file_id, basename, dir_id)
2503
ie.revision = rev_id
2506
def create_tree_from_shape(self, rev_id, shape):
2507
dir_ids = {'': b'root-id'}
2508
inv = inventory.Inventory(b'root-id', rev_id)
2511
path, file_id = info
2514
path, file_id, ie_rev_id = info
2516
# Replace the root entry
2517
del inv._byid[inv.root.file_id]
2518
inv.root.file_id = file_id
2519
inv._byid[file_id] = inv.root
2520
dir_ids[''] = file_id
2522
inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2523
return inventorytree.InventoryRevisionTree(_Repo(), inv, rev_id)
2525
def create_empty_dirstate(self):
2526
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2527
self.addCleanup(os.remove, path)
2529
state = dirstate.DirState.initialize(path)
2530
self.addCleanup(state.unlock)
2533
def create_inv_delta(self, delta, rev_id):
2534
"""Translate a 'delta shape' into an actual InventoryDelta"""
2535
dir_ids = {'': b'root-id'}
2537
for old_path, new_path, file_id in delta:
2538
if old_path is not None and old_path.endswith('/'):
2539
# Don't have to actually do anything for this, because only
2540
# new_path creates InventoryEntries
2541
old_path = old_path[:-1]
2542
if new_path is None: # Delete
2543
inv_delta.append((old_path, None, file_id, None))
2545
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2546
inv_delta.append((old_path, new_path, file_id, ie))
2549
def assertUpdate(self, active, basis, target):
2550
"""Assert that update_basis_by_delta works how we want.
2552
Set up a DirState object with active_shape for tree 0, basis_shape for
2553
tree 1. Then apply the delta from basis_shape to target_shape,
2554
and assert that the DirState is still valid, and that its stored
2555
content matches the target_shape.
2557
active_tree = self.create_tree_from_shape(b'active', active)
2558
basis_tree = self.create_tree_from_shape(b'basis', basis)
2559
target_tree = self.create_tree_from_shape(b'target', target)
2560
state = self.create_empty_dirstate()
2561
state.set_state_from_scratch(active_tree.root_inventory,
2562
[(b'basis', basis_tree)], [])
2563
delta = target_tree.root_inventory._make_delta(
2564
basis_tree.root_inventory)
2565
state.update_basis_by_delta(delta, b'target')
2567
dirstate_tree = workingtree_4.DirStateRevisionTree(
2568
state, b'target', _Repo(), None)
2569
# The target now that delta has been applied should match the
2571
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2572
# And the dirblock state should be identical to the state if we created
2574
state2 = self.create_empty_dirstate()
2575
state2.set_state_from_scratch(active_tree.root_inventory,
2576
[(b'target', target_tree)], [])
2577
self.assertEqual(state2._dirblocks, state._dirblocks)
2580
def assertBadDelta(self, active, basis, delta):
2581
"""Test that we raise InconsistentDelta when appropriate.
2583
:param active: The active tree shape
2584
:param basis: The basis tree shape
2585
:param delta: A description of the delta to apply. Similar to the form
2586
for regular inventory deltas, but omitting the InventoryEntry.
2587
So adding a file is: (None, 'path', b'file-id')
2588
Adding a directory is: (None, 'path/', b'dir-id')
2589
Renaming a dir is: ('old/', 'new/', b'dir-id')
2592
active_tree = self.create_tree_from_shape(b'active', active)
2593
basis_tree = self.create_tree_from_shape(b'basis', basis)
2594
inv_delta = self.create_inv_delta(delta, b'target')
2595
state = self.create_empty_dirstate()
2596
state.set_state_from_scratch(active_tree.root_inventory,
2597
[(b'basis', basis_tree)], [])
2598
self.assertRaises(errors.InconsistentDelta,
2599
state.update_basis_by_delta, inv_delta, b'target')
2601
## state.update_basis_by_delta(inv_delta, b'target')
2602
# except errors.InconsistentDelta, e:
2603
## import pdb; pdb.set_trace()
2605
## import pdb; pdb.set_trace()
2606
self.assertTrue(state._changes_aborted)
2608
def test_remove_file_matching_active_state(self):
2609
state = self.assertUpdate(
2611
basis=[('file', b'file-id')],
2615
def test_remove_file_present_in_active_state(self):
2616
state = self.assertUpdate(
2617
active=[('file', b'file-id')],
2618
basis=[('file', b'file-id')],
2622
def test_remove_file_present_elsewhere_in_active_state(self):
2623
state = self.assertUpdate(
2624
active=[('other-file', b'file-id')],
2625
basis=[('file', b'file-id')],
2629
def test_remove_file_active_state_has_diff_file(self):
2630
state = self.assertUpdate(
2631
active=[('file', b'file-id-2')],
2632
basis=[('file', b'file-id')],
2636
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2637
state = self.assertUpdate(
2638
active=[('file', b'file-id-2'),
2639
('other-file', b'file-id')],
2640
basis=[('file', b'file-id')],
2644
def test_add_file_matching_active_state(self):
2645
state = self.assertUpdate(
2646
active=[('file', b'file-id')],
2648
target=[('file', b'file-id')],
2651
def test_add_file_in_empty_dir_not_matching_active_state(self):
2652
state = self.assertUpdate(
2654
basis=[('dir/', b'dir-id')],
2655
target=[('dir/', b'dir-id', b'basis'), ('dir/file', b'file-id')],
2658
def test_add_file_missing_in_active_state(self):
2659
state = self.assertUpdate(
2662
target=[('file', b'file-id')],
2665
def test_add_file_elsewhere_in_active_state(self):
2666
state = self.assertUpdate(
2667
active=[('other-file', b'file-id')],
2669
target=[('file', b'file-id')],
2672
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2673
state = self.assertUpdate(
2674
active=[('other-file', b'file-id'),
2675
('file', b'file-id-2')],
2677
target=[('file', b'file-id')],
2680
def test_rename_file_matching_active_state(self):
2681
state = self.assertUpdate(
2682
active=[('other-file', b'file-id')],
2683
basis=[('file', b'file-id')],
2684
target=[('other-file', b'file-id')],
2687
def test_rename_file_missing_in_active_state(self):
2688
state = self.assertUpdate(
2690
basis=[('file', b'file-id')],
2691
target=[('other-file', b'file-id')],
2694
def test_rename_file_present_elsewhere_in_active_state(self):
2695
state = self.assertUpdate(
2696
active=[('third', b'file-id')],
2697
basis=[('file', b'file-id')],
2698
target=[('other-file', b'file-id')],
2701
def test_rename_file_active_state_has_diff_source_file(self):
2702
state = self.assertUpdate(
2703
active=[('file', b'file-id-2')],
2704
basis=[('file', b'file-id')],
2705
target=[('other-file', b'file-id')],
2708
def test_rename_file_active_state_has_diff_target_file(self):
2709
state = self.assertUpdate(
2710
active=[('other-file', b'file-id-2')],
2711
basis=[('file', b'file-id')],
2712
target=[('other-file', b'file-id')],
2715
def test_rename_file_active_has_swapped_files(self):
2716
state = self.assertUpdate(
2717
active=[('file', b'file-id'),
2718
('other-file', b'file-id-2')],
2719
basis=[('file', b'file-id'),
2720
('other-file', b'file-id-2')],
2721
target=[('file', b'file-id-2'),
2722
('other-file', b'file-id')])
2724
def test_rename_file_basis_has_swapped_files(self):
2725
state = self.assertUpdate(
2726
active=[('file', b'file-id'),
2727
('other-file', b'file-id-2')],
2728
basis=[('file', b'file-id-2'),
2729
('other-file', b'file-id')],
2730
target=[('file', b'file-id'),
2731
('other-file', b'file-id-2')])
2733
def test_rename_directory_with_contents(self):
2734
state = self.assertUpdate( # active matches basis
2735
active=[('dir1/', b'dir-id'),
2736
('dir1/file', b'file-id')],
2737
basis=[('dir1/', b'dir-id'),
2738
('dir1/file', b'file-id')],
2739
target=[('dir2/', b'dir-id'),
2740
('dir2/file', b'file-id')])
2741
state = self.assertUpdate( # active matches target
2742
active=[('dir2/', b'dir-id'),
2743
('dir2/file', b'file-id')],
2744
basis=[('dir1/', b'dir-id'),
2745
('dir1/file', b'file-id')],
2746
target=[('dir2/', b'dir-id'),
2747
('dir2/file', b'file-id')])
2748
state = self.assertUpdate( # active empty
2750
basis=[('dir1/', b'dir-id'),
2751
('dir1/file', b'file-id')],
2752
target=[('dir2/', b'dir-id'),
2753
('dir2/file', b'file-id')])
2754
state = self.assertUpdate( # active present at other location
2755
active=[('dir3/', b'dir-id'),
2756
('dir3/file', b'file-id')],
2757
basis=[('dir1/', b'dir-id'),
2758
('dir1/file', b'file-id')],
2759
target=[('dir2/', b'dir-id'),
2760
('dir2/file', b'file-id')])
2761
state = self.assertUpdate( # active has different ids
2762
active=[('dir1/', b'dir1-id'),
2763
('dir1/file', b'file1-id'),
2764
('dir2/', b'dir2-id'),
2765
('dir2/file', b'file2-id')],
2766
basis=[('dir1/', b'dir-id'),
2767
('dir1/file', b'file-id')],
2768
target=[('dir2/', b'dir-id'),
2769
('dir2/file', b'file-id')])
2771
def test_invalid_file_not_present(self):
2772
state = self.assertBadDelta(
2773
active=[('file', b'file-id')],
2774
basis=[('file', b'file-id')],
2775
delta=[('other-file', 'file', b'file-id')])
2777
def test_invalid_new_id_same_path(self):
2778
# The bad entry comes after
2779
state = self.assertBadDelta(
2780
active=[('file', b'file-id')],
2781
basis=[('file', b'file-id')],
2782
delta=[(None, 'file', b'file-id-2')])
2783
# The bad entry comes first
2784
state = self.assertBadDelta(
2785
active=[('file', b'file-id-2')],
2786
basis=[('file', b'file-id-2')],
2787
delta=[(None, 'file', b'file-id')])
2789
def test_invalid_existing_id(self):
2790
state = self.assertBadDelta(
2791
active=[('file', b'file-id')],
2792
basis=[('file', b'file-id')],
2793
delta=[(None, 'file', b'file-id')])
2795
def test_invalid_parent_missing(self):
2796
state = self.assertBadDelta(
2799
delta=[(None, 'path/path2', b'file-id')])
2800
# Note: we force the active tree to have the directory, by knowing how
2801
# path_to_ie handles entries with missing parents
2802
state = self.assertBadDelta(
2803
active=[('path/', b'path-id')],
2805
delta=[(None, 'path/path2', b'file-id')])
2806
state = self.assertBadDelta(
2807
active=[('path/', b'path-id'),
2808
('path/path2', b'file-id')],
2810
delta=[(None, 'path/path2', b'file-id')])
2812
def test_renamed_dir_same_path(self):
2813
# We replace the parent directory, with another parent dir. But the C
2814
# file doesn't look like it has been moved.
2815
state = self.assertUpdate( # Same as basis
2816
active=[('dir/', b'A-id'),
2817
('dir/B', b'B-id')],
2818
basis=[('dir/', b'A-id'),
2819
('dir/B', b'B-id')],
2820
target=[('dir/', b'C-id'),
2821
('dir/B', b'B-id')])
2822
state = self.assertUpdate( # Same as target
2823
active=[('dir/', b'C-id'),
2824
('dir/B', b'B-id')],
2825
basis=[('dir/', b'A-id'),
2826
('dir/B', b'B-id')],
2827
target=[('dir/', b'C-id'),
2828
('dir/B', b'B-id')])
2829
state = self.assertUpdate( # empty active
2831
basis=[('dir/', b'A-id'),
2832
('dir/B', b'B-id')],
2833
target=[('dir/', b'C-id'),
2834
('dir/B', b'B-id')])
2835
state = self.assertUpdate( # different active
2836
active=[('dir/', b'D-id'),
2837
('dir/B', b'B-id')],
2838
basis=[('dir/', b'A-id'),
2839
('dir/B', b'B-id')],
2840
target=[('dir/', b'C-id'),
2841
('dir/B', b'B-id')])
2843
def test_parent_child_swap(self):
2844
state = self.assertUpdate( # Same as basis
2845
active=[('A/', b'A-id'),
2847
('A/B/C', b'C-id')],
2848
basis=[('A/', b'A-id'),
2850
('A/B/C', b'C-id')],
2851
target=[('A/', b'B-id'),
2853
('A/B/C', b'C-id')])
2854
state = self.assertUpdate( # Same as target
2855
active=[('A/', b'B-id'),
2857
('A/B/C', b'C-id')],
2858
basis=[('A/', b'A-id'),
2860
('A/B/C', b'C-id')],
2861
target=[('A/', b'B-id'),
2863
('A/B/C', b'C-id')])
2864
state = self.assertUpdate( # empty active
2866
basis=[('A/', b'A-id'),
2868
('A/B/C', b'C-id')],
2869
target=[('A/', b'B-id'),
2871
('A/B/C', b'C-id')])
2872
state = self.assertUpdate( # different active
2873
active=[('D/', b'A-id'),
2876
basis=[('A/', b'A-id'),
2878
('A/B/C', b'C-id')],
2879
target=[('A/', b'B-id'),
2881
('A/B/C', b'C-id')])
2883
def test_change_root_id(self):
2884
state = self.assertUpdate( # same as basis
2885
active=[('', b'root-id'),
2886
('file', b'file-id')],
2887
basis=[('', b'root-id'),
2888
('file', b'file-id')],
2889
target=[('', b'target-root-id'),
2890
('file', b'file-id')])
2891
state = self.assertUpdate( # same as target
2892
active=[('', b'target-root-id'),
2893
('file', b'file-id')],
2894
basis=[('', b'root-id'),
2895
('file', b'file-id')],
2896
target=[('', b'target-root-id'),
2897
('file', b'root-id')])
2898
state = self.assertUpdate( # all different
2899
active=[('', b'active-root-id'),
2900
('file', b'file-id')],
2901
basis=[('', b'root-id'),
2902
('file', b'file-id')],
2903
target=[('', b'target-root-id'),
2904
('file', b'root-id')])
2906
def test_change_file_absent_in_active(self):
2907
state = self.assertUpdate(
2909
basis=[('file', b'file-id')],
2910
target=[('file', b'file-id')])
2912
def test_invalid_changed_file(self):
2913
state = self.assertBadDelta( # Not present in basis
2914
active=[('file', b'file-id')],
2916
delta=[('file', 'file', b'file-id')])
2917
state = self.assertBadDelta( # present at another location in basis
2918
active=[('file', b'file-id')],
2919
basis=[('other-file', b'file-id')],
2920
delta=[('file', 'file', b'file-id')])