138
124
:return: The dirstate, still write-locked.
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),
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),
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]))
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]))
174
160
state = dirstate.DirState.initialize('dirstate')
175
161
state._validate()
256
241
f_len = len(f_text)
257
242
null_stat = dirstate.DirState.NULLSTAT
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),
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),
292
277
state = dirstate.DirState.from_tree(tree, 'dirstate')
971
900
"""Set the root file id in a dirstate with parents"""
972
901
mt = self.make_branch_and_tree('mt')
973
902
# in case the default tree format uses a different root id
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')
903
mt.set_root_id('TREE_ROOT')
904
mt.commit('foo', rev_id='parent-revid')
905
rt = mt.branch.repository.revision_tree('parent-revid')
977
906
state = dirstate.DirState.initialize('dirstate')
978
907
state._validate()
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''))
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=''))
985
914
self.assertEqual(root_entry,
986
state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
915
state._get_entry(0, fileid_utf8='TREE_ROOT'))
987
916
self.assertEqual((None, None),
988
state._get_entry(0, fileid_utf8=b'Asecond-root-id'))
989
state.set_path_id(b'', b'Asecond-root-id')
917
state._get_entry(0, fileid_utf8='Asecond-root-id'))
918
state.set_path_id('', 'Asecond-root-id')
990
919
state._validate()
991
920
# now see that it is what we expected
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'')])
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, '')])
998
927
expected_rows = [new_root_entry, old_root_entry]
999
928
state._validate()
1000
929
self.assertEqual(expected_rows, list(state._iter_entries()))
1002
new_root_entry, state._get_entry(0, path_utf8=b''))
1004
old_root_entry, state._get_entry(1, path_utf8=b''))
930
self.assertEqual(new_root_entry, state._get_entry(0, path_utf8=''))
931
self.assertEqual(old_root_entry, state._get_entry(1, path_utf8=''))
1005
932
self.assertEqual((None, None),
1006
state._get_entry(0, fileid_utf8=b'TREE_ROOT'))
933
state._get_entry(0, fileid_utf8='TREE_ROOT'))
1007
934
self.assertEqual(old_root_entry,
1008
state._get_entry(1, fileid_utf8=b'TREE_ROOT'))
935
state._get_entry(1, fileid_utf8='TREE_ROOT'))
1009
936
self.assertEqual(new_root_entry,
1010
state._get_entry(0, fileid_utf8=b'Asecond-root-id'))
937
state._get_entry(0, fileid_utf8='Asecond-root-id'))
1011
938
self.assertEqual((None, None),
1012
state._get_entry(1, fileid_utf8=b'Asecond-root-id'))
939
state._get_entry(1, fileid_utf8='Asecond-root-id'))
1013
940
# should work across save too
1529
1400
def test_simple_structure(self):
1530
1401
state = self.create_dirstate_with_root_and_subdir()
1531
1402
self.addCleanup(state.unlock)
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)
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)
1540
1407
self.assertBlockRowIndexEqual(2, 0, False, False, state,
1541
b'subdir', b'foo', 0)
1543
1410
def test_complex_structure_exists(self):
1544
1411
state = self.create_complex_dirstate()
1545
1412
self.addCleanup(state.unlock)
1546
1413
# Make sure we can find everything that exists
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)
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)
1555
1422
self.assertBlockRowIndexEqual(3, 1, True, True, state,
1556
b'b', b'h\xc3\xa5', 0)
1423
'b', 'h\xc3\xa5', 0)
1558
1425
def test_complex_structure_missing(self):
1559
1426
state = self.create_complex_dirstate()
1560
1427
self.addCleanup(state.unlock)
1561
1428
# Make sure things would be inserted in the right locations
1562
1429
# '_' comes before 'a'
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)
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)
1566
1433
self.assertBlockRowIndexEqual(1, 4, True, False, state,
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)
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)
1573
1438
# This would be inserted between a/ and b/
1574
self.assertBlockRowIndexEqual(
1575
3, 0, False, False, state, b'a/e', b'a', 0)
1439
self.assertBlockRowIndexEqual(3, 0, False, False, state, 'a/e', 'a', 0)
1576
1440
# Put at the end
1577
self.assertBlockRowIndexEqual(4, 0, False, False, state, b'e', b'a', 0)
1441
self.assertBlockRowIndexEqual(4, 0, False, False, state, 'e', 'a', 0)
1580
1444
class TestGetEntry(TestCaseWithDirState):
1591
1455
def test_simple_structure(self):
1592
1456
state = self.create_dirstate_with_root_and_subdir()
1593
1457
self.addCleanup(state.unlock)
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)
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)
1601
1464
def test_complex_structure_exists(self):
1602
1465
state = self.create_complex_dirstate()
1603
1466
self.addCleanup(state.unlock)
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,
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,
1615
1478
def test_complex_structure_missing(self):
1616
1479
state = self.create_complex_dirstate()
1617
1480
self.addCleanup(state.unlock)
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)
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)
1623
1486
def test_get_entry_uninitialized(self):
1624
1487
"""Calling get_entry will load data if it needs to"""
1666
1529
:return: The dirstate, still write-locked.
1668
packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1669
null_sha = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1531
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1532
null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1670
1533
NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
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'),
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'),
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]))
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]))
1725
1587
state = dirstate.DirState.initialize('dirstate')
1726
1588
state._validate()
1728
state._set_data([b'parent'], dirblocks)
1590
state._set_data(['parent'], dirblocks)
2016
1874
tree, state, expected = self.create_basic_dirstate()
2018
1876
# Bisect should return the rows for the specified files.
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'])
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'])
2028
1886
def test_bisect_multi(self):
2029
1887
"""Bisect can be used to find multiple records at the same time."""
2030
1888
tree, state, expected = self.create_basic_dirstate()
2031
1889
# Bisect should be capable of finding multiple entries at the same time
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'])
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'])
2039
1897
def test_bisect_one_page(self):
2040
1898
"""Test bisect when there is only 1 page to read"""
2041
1899
tree, state, expected = self.create_basic_dirstate()
2042
1900
state._bisect_page_size = 5000
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'])
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'])
2058
1916
def test_bisect_duplicate_paths(self):
2059
1917
"""When bisecting for a path, handle multiple entries."""
2060
1918
tree, state, expected = self.create_duplicated_dirstate()
2062
1920
# Now make sure that both records are properly returned.
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'])
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'])
2073
1931
def test_bisect_page_size_too_small(self):
2074
1932
"""If the page size is too small, we will auto increase it."""
2075
1933
tree, state, expected = self.create_basic_dirstate()
2076
1934
state._bisect_page_size = 50
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'])
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'])
2086
1944
def test_bisect_missing(self):
2087
1945
"""Test that bisect return None if it cannot find a path."""
2088
1946
tree, state, expected = self.create_basic_dirstate()
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'])
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'])
2094
self.assertBisect(expected, [[b'a'], None, [b'b/d']],
2095
state, [b'a', b'foo', b'b/d'])
1952
self.assertBisect(expected, [['a'], None, ['b/d']],
1953
state, ['a', 'foo', 'b/d'])
2097
1955
def test_bisect_rename(self):
2098
1956
"""Check that we find a renamed row."""
2099
1957
tree, state, expected = self.create_renamed_dirstate()
2101
1959
# Search for the pre and post renamed entries
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'])
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'])
2107
1965
# What about b/d/e? shouldn't that also get 2 directory entries?
2108
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2109
self.assertBisect(expected, [[b'h/e']], state, [b'h/e'])
1966
self.assertBisect(expected, [['b/d/e']], state, ['b/d/e'])
1967
self.assertBisect(expected, [['h/e']], state, ['h/e'])
2111
1969
def test_bisect_dirblocks(self):
2112
1970
tree, state, expected = self.create_duplicated_dirstate()
2113
1971
self.assertBisectDirBlocks(expected,
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'])
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'])
2127
1984
def test_bisect_dirblocks_missing(self):
2128
1985
tree, state, expected = self.create_basic_dirstate()
2129
self.assertBisectDirBlocks(expected, [[b'b/d/e'], None],
2130
state, [b'b/d', b'b/e'])
1986
self.assertBisectDirBlocks(expected, [['b/d/e'], None],
1987
state, ['b/d', 'b/e'])
2131
1988
# Files don't show up in this search
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'])
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'])
2138
1995
def test_bisect_recursive_each(self):
2139
1996
tree, state, expected = self.create_basic_dirstate()
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',
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',
2152
2009
def test_bisect_recursive_multiple(self):
2153
2010
tree, state, expected = self.create_basic_dirstate()
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'])
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'])
2159
2015
def test_bisect_recursive_missing(self):
2160
2016
tree, state, expected = self.create_basic_dirstate()
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'])
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'])
2166
2022
def test_bisect_recursive_renamed(self):
2167
2023
tree, state, expected = self.create_renamed_dirstate()
2169
2025
# Looking for either renamed item should find the other
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'])
2026
self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['a'])
2027
self.assertBisectRecursive(expected, ['a', 'b/g'], state, ['b/g'])
2172
2028
# Looking in the containing directory should find the rename target,
2173
2029
# and anything in a subdir of the renamed target.
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'],
2030
self.assertBisectRecursive(expected, ['a', 'b', 'b/c', 'b/d',
2031
'b/d/e', 'b/g', 'h', 'h/e'],
2179
2035
class TestDirstateValidation(TestCaseWithDirState):
2285
2141
def test_discard_simple(self):
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),
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),
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),
2149
expected_root_entry_direntry = ('', '', 'a-root-value'), [
2150
('d', '', 0, False, packed_stat),
2151
('d', '', 0, False, packed_stat),
2298
dirblocks.append((b'', [root_entry_direntry]))
2299
dirblocks.append((b'', []))
2154
dirblocks.append(('', [root_entry_direntry]))
2155
dirblocks.append(('', []))
2301
2157
state = self.create_empty_dirstate()
2302
2158
self.addCleanup(state.unlock)
2303
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2159
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2304
2160
state._validate()
2306
2162
# This should strip of the extra column
2307
2163
state._discard_merge_parents()
2308
2164
state._validate()
2309
expected_dirblocks = [(b'', [expected_root_entry_direntry]), (b'', [])]
2165
expected_dirblocks = [('', [expected_root_entry_direntry]), ('', [])]
2310
2166
self.assertEqual(expected_dirblocks, state._dirblocks)
2312
2168
def test_discard_absent(self):
2313
2169
"""If entries are only in a merge, discard should remove the entries"""
2314
2170
null_stat = dirstate.DirState.NULLSTAT
2315
present_dir = (b'd', b'', 0, False, null_stat)
2316
present_file = (b'f', b'', 0, False, null_stat)
2171
present_dir = ('d', '', 0, False, null_stat)
2172
present_file = ('f', '', 0, False, null_stat)
2317
2173
absent = dirstate.DirState.NULL_PARENT_DETAILS
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]),
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]),
2329
2185
state = self.create_empty_dirstate()
2330
2186
self.addCleanup(state.unlock)
2331
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2187
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2332
2188
state._validate()
2334
exp_dirblocks = [(b'', [(root_key, [present_dir, present_dir])]),
2335
(b'', [(file_in_root_key,
2336
[present_file, present_file]),
2190
exp_dirblocks = [('', [(root_key, [present_dir, present_dir])]),
2191
('', [(file_in_root_key,
2192
[present_file, present_file]),
2339
2195
state._discard_merge_parents()
2340
2196
state._validate()
2341
2197
self.assertEqual(exp_dirblocks, state._dirblocks)
2343
2199
def test_discard_renamed(self):
2344
2200
null_stat = dirstate.DirState.NULLSTAT
2345
present_dir = (b'd', b'', 0, False, null_stat)
2346
present_file = (b'f', b'', 0, False, null_stat)
2201
present_dir = ('d', '', 0, False, null_stat)
2202
present_file = ('f', '', 0, False, null_stat)
2347
2203
absent = dirstate.DirState.NULL_PARENT_DETAILS
2348
root_key = (b'', b'', b'a-root-value')
2349
file_in_root_key = (b'', b'file-in-root', b'a-file-id')
2204
root_key = ('', '', 'a-root-value')
2205
file_in_root_key = ('', 'file-in-root', 'a-file-id')
2350
2206
# Renamed relative to parent
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')
2207
file_rename_s_key = ('', 'file-s', 'b-file-id')
2208
file_rename_t_key = ('', 'file-t', 'b-file-id')
2353
2209
# And one that is renamed between the parents, but absent in this
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')
2210
key_in_1 = ('', 'file-in-1', 'c-file-id')
2211
key_in_2 = ('', 'file-in-2', 'c-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')]),
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')]),
2371
2227
exp_dirblocks = [
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]),
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]),
2378
2234
state = self.create_empty_dirstate()
2379
2235
self.addCleanup(state.unlock)
2380
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2236
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2381
2237
state._validate()
2383
2239
state._discard_merge_parents()
2464
2320
self.assertTrue(len(statvalue) >= 10)
2465
2321
self.assertEqual(len(text), statvalue.st_size)
2466
2322
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')])