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
1532
def test_simple_structure(self):
1401
1533
state = self.create_dirstate_with_root_and_subdir()
1402
1534
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)
1535
self.assertBlockRowIndexEqual(
1536
1, 0, True, True, state, b'', b'subdir', 0)
1537
self.assertBlockRowIndexEqual(
1538
1, 0, True, False, state, b'', b'bdir', 0)
1539
self.assertBlockRowIndexEqual(
1540
1, 1, True, False, state, b'', b'zdir', 0)
1541
self.assertBlockRowIndexEqual(
1542
2, 0, False, False, state, b'a', b'foo', 0)
1407
1543
self.assertBlockRowIndexEqual(2, 0, False, False, state,
1544
b'subdir', b'foo', 0)
1410
1546
def test_complex_structure_exists(self):
1411
1547
state = self.create_complex_dirstate()
1412
1548
self.addCleanup(state.unlock)
1413
1549
# 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)
1550
self.assertBlockRowIndexEqual(0, 0, True, True, state, b'', b'', 0)
1551
self.assertBlockRowIndexEqual(1, 0, True, True, state, b'', b'a', 0)
1552
self.assertBlockRowIndexEqual(1, 1, True, True, state, b'', b'b', 0)
1553
self.assertBlockRowIndexEqual(1, 2, True, True, state, b'', b'c', 0)
1554
self.assertBlockRowIndexEqual(1, 3, True, True, state, b'', b'd', 0)
1555
self.assertBlockRowIndexEqual(2, 0, True, True, state, b'a', b'e', 0)
1556
self.assertBlockRowIndexEqual(2, 1, True, True, state, b'a', b'f', 0)
1557
self.assertBlockRowIndexEqual(3, 0, True, True, state, b'b', b'g', 0)
1422
1558
self.assertBlockRowIndexEqual(3, 1, True, True, state,
1423
'b', 'h\xc3\xa5', 0)
1559
b'b', b'h\xc3\xa5', 0)
1425
1561
def test_complex_structure_missing(self):
1426
1562
state = self.create_complex_dirstate()
1427
1563
self.addCleanup(state.unlock)
1428
1564
# Make sure things would be inserted in the right locations
1429
1565
# '_' 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)
1566
self.assertBlockRowIndexEqual(0, 0, True, True, state, b'', b'', 0)
1567
self.assertBlockRowIndexEqual(1, 0, True, False, state, b'', b'_', 0)
1568
self.assertBlockRowIndexEqual(1, 1, True, False, state, b'', b'aa', 0)
1433
1569
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)
1570
b'', b'h\xc3\xa5', 0)
1571
self.assertBlockRowIndexEqual(2, 0, False, False, state, b'_', b'a', 0)
1572
self.assertBlockRowIndexEqual(
1573
3, 0, False, False, state, b'aa', b'a', 0)
1574
self.assertBlockRowIndexEqual(
1575
4, 0, False, False, state, b'bb', b'a', 0)
1438
1576
# This would be inserted between a/ and b/
1439
self.assertBlockRowIndexEqual(3, 0, False, False, state, 'a/e', 'a', 0)
1577
self.assertBlockRowIndexEqual(
1578
3, 0, False, False, state, b'a/e', b'a', 0)
1440
1579
# Put at the end
1441
self.assertBlockRowIndexEqual(4, 0, False, False, state, 'e', 'a', 0)
1580
self.assertBlockRowIndexEqual(4, 0, False, False, state, b'e', b'a', 0)
1444
1583
class TestGetEntry(TestCaseWithDirState):
1455
1594
def test_simple_structure(self):
1456
1595
state = self.create_dirstate_with_root_and_subdir()
1457
1596
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)
1597
self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
1598
self.assertEntryEqual(
1599
b'', b'subdir', b'subdir-id', state, b'subdir', 0)
1600
self.assertEntryEqual(None, None, None, state, b'missing', 0)
1601
self.assertEntryEqual(None, None, None, state, b'missing/foo', 0)
1602
self.assertEntryEqual(None, None, None, state, b'subdir/foo', 0)
1464
1604
def test_complex_structure_exists(self):
1465
1605
state = self.create_complex_dirstate()
1466
1606
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,
1607
self.assertEntryEqual(b'', b'', b'a-root-value', state, b'', 0)
1608
self.assertEntryEqual(b'', b'a', b'a-dir', state, b'a', 0)
1609
self.assertEntryEqual(b'', b'b', b'b-dir', state, b'b', 0)
1610
self.assertEntryEqual(b'', b'c', b'c-file', state, b'c', 0)
1611
self.assertEntryEqual(b'', b'd', b'd-file', state, b'd', 0)
1612
self.assertEntryEqual(b'a', b'e', b'e-dir', state, b'a/e', 0)
1613
self.assertEntryEqual(b'a', b'f', b'f-file', state, b'a/f', 0)
1614
self.assertEntryEqual(b'b', b'g', b'g-file', state, b'b/g', 0)
1615
self.assertEntryEqual(b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file', state,
1478
1618
def test_complex_structure_missing(self):
1479
1619
state = self.create_complex_dirstate()
1480
1620
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)
1621
self.assertEntryEqual(None, None, None, state, b'_', 0)
1622
self.assertEntryEqual(None, None, None, state, b'_\xc3\xa5', 0)
1623
self.assertEntryEqual(None, None, None, state, b'a/b', 0)
1624
self.assertEntryEqual(None, None, None, state, b'c/d', 0)
1486
1626
def test_get_entry_uninitialized(self):
1487
1627
"""Calling get_entry will load data if it needs to"""
1529
1669
:return: The dirstate, still write-locked.
1531
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1532
null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1671
packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1672
null_sha = b'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1533
1673
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'),
1674
root_entry = (b'', b'', b'a-root-value'), [
1675
(b'd', b'', 0, False, packed_stat),
1676
(b'd', b'', 0, False, b'parent-revid'),
1678
a_entry = (b'', b'a', b'a-dir'), [
1679
(b'd', b'', 0, False, packed_stat),
1680
(b'd', b'', 0, False, b'parent-revid'),
1682
b_entry = (b'', b'b', b'b-dir'), [
1683
(b'd', b'', 0, False, packed_stat),
1684
(b'd', b'', 0, False, b'parent-revid'),
1686
c_entry = (b'', b'c', b'c-file'), [
1687
(b'f', null_sha, 10, False, packed_stat),
1688
(b'r', b'b/j', 0, False, b''),
1690
d_entry = (b'', b'd', b'd-file'), [
1691
(b'f', null_sha, 20, False, packed_stat),
1692
(b'f', b'd', 20, False, b'parent-revid'),
1694
e_entry = (b'a', b'e', b'e-dir'), [
1695
(b'd', b'', 0, False, packed_stat),
1696
(b'd', b'', 0, False, b'parent-revid'),
1698
f_entry = (b'a', b'f', b'f-file'), [
1699
(b'f', null_sha, 30, False, packed_stat),
1700
(b'f', b'f', 20, False, b'parent-revid'),
1702
g_entry = (b'b', b'g', b'g-file'), [
1703
(b'f', null_sha, 30, False, packed_stat),
1704
NULL_PARENT_DETAILS,
1706
h_entry1 = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file1'), [
1707
(b'f', null_sha, 40, False, packed_stat),
1708
NULL_PARENT_DETAILS,
1710
h_entry2 = (b'b', b'h\xc3\xa5', b'h-\xc3\xa5-file2'), [
1711
NULL_PARENT_DETAILS,
1712
(b'f', b'h', 20, False, b'parent-revid'),
1714
i_entry = (b'b', b'i', b'i-file'), [
1715
NULL_PARENT_DETAILS,
1716
(b'f', b'h', 20, False, b'parent-revid'),
1718
j_entry = (b'b', b'j', b'c-file'), [
1719
(b'r', b'c', 0, False, b''),
1720
(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]))
1723
dirblocks.append((b'', [root_entry]))
1724
dirblocks.append((b'', [a_entry, b_entry, c_entry, d_entry]))
1725
dirblocks.append((b'a', [e_entry, f_entry]))
1727
(b'b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
1587
1728
state = dirstate.DirState.initialize('dirstate')
1588
1729
state._validate()
1590
state._set_data(['parent'], dirblocks)
1731
state._set_data([b'parent'], dirblocks)
1874
2019
tree, state, expected = self.create_basic_dirstate()
1876
2021
# 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'])
2022
self.assertBisect(expected, [[b'']], state, [b''])
2023
self.assertBisect(expected, [[b'a']], state, [b'a'])
2024
self.assertBisect(expected, [[b'b']], state, [b'b'])
2025
self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2026
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2027
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2028
self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2029
self.assertBisect(expected, [[b'f']], state, [b'f'])
1886
2031
def test_bisect_multi(self):
1887
2032
"""Bisect can be used to find multiple records at the same time."""
1888
2033
tree, state, expected = self.create_basic_dirstate()
1889
2034
# 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'])
2035
self.assertBisect(expected, [[b'a'], [b'b'], [b'f']],
2036
state, [b'a', b'b', b'f'])
2037
self.assertBisect(expected, [[b'f'], [b'b/d'], [b'b/d/e']],
2038
state, [b'f', b'b/d', b'b/d/e'])
2039
self.assertBisect(expected, [[b'b'], [b'b-c'], [b'b/c']],
2040
state, [b'b', b'b-c', b'b/c'])
1897
2042
def test_bisect_one_page(self):
1898
2043
"""Test bisect when there is only 1 page to read"""
1899
2044
tree, state, expected = self.create_basic_dirstate()
1900
2045
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'])
2046
self.assertBisect(expected, [[b'']], state, [b''])
2047
self.assertBisect(expected, [[b'a']], state, [b'a'])
2048
self.assertBisect(expected, [[b'b']], state, [b'b'])
2049
self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2050
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2051
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2052
self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2053
self.assertBisect(expected, [[b'f']], state, [b'f'])
2054
self.assertBisect(expected, [[b'a'], [b'b'], [b'f']],
2055
state, [b'a', b'b', b'f'])
2056
self.assertBisect(expected, [[b'b/d'], [b'b/d/e'], [b'f']],
2057
state, [b'b/d', b'b/d/e', b'f'])
2058
self.assertBisect(expected, [[b'b'], [b'b/c'], [b'b-c']],
2059
state, [b'b', b'b/c', b'b-c'])
1916
2061
def test_bisect_duplicate_paths(self):
1917
2062
"""When bisecting for a path, handle multiple entries."""
1918
2063
tree, state, expected = self.create_duplicated_dirstate()
1920
2065
# 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'])
2066
self.assertBisect(expected, [[b'']], state, [b''])
2067
self.assertBisect(expected, [[b'a', b'a2']], state, [b'a'])
2068
self.assertBisect(expected, [[b'b', b'b2']], state, [b'b'])
2069
self.assertBisect(expected, [[b'b/c', b'b/c2']], state, [b'b/c'])
2070
self.assertBisect(expected, [[b'b/d', b'b/d2']], state, [b'b/d'])
2071
self.assertBisect(expected, [[b'b/d/e', b'b/d/e2']],
2073
self.assertBisect(expected, [[b'b-c', b'b-c2']], state, [b'b-c'])
2074
self.assertBisect(expected, [[b'f', b'f2']], state, [b'f'])
1931
2076
def test_bisect_page_size_too_small(self):
1932
2077
"""If the page size is too small, we will auto increase it."""
1933
2078
tree, state, expected = self.create_basic_dirstate()
1934
2079
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'])
2080
self.assertBisect(expected, [None], state, [b'b/e'])
2081
self.assertBisect(expected, [[b'a']], state, [b'a'])
2082
self.assertBisect(expected, [[b'b']], state, [b'b'])
2083
self.assertBisect(expected, [[b'b/c']], state, [b'b/c'])
2084
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2085
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2086
self.assertBisect(expected, [[b'b-c']], state, [b'b-c'])
2087
self.assertBisect(expected, [[b'f']], state, [b'f'])
1944
2089
def test_bisect_missing(self):
1945
2090
"""Test that bisect return None if it cannot find a path."""
1946
2091
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'])
2092
self.assertBisect(expected, [None], state, [b'foo'])
2093
self.assertBisect(expected, [None], state, [b'b/foo'])
2094
self.assertBisect(expected, [None], state, [b'bar/foo'])
2095
self.assertBisect(expected, [None], state, [b'b-c/foo'])
1952
self.assertBisect(expected, [['a'], None, ['b/d']],
1953
state, ['a', 'foo', 'b/d'])
2097
self.assertBisect(expected, [[b'a'], None, [b'b/d']],
2098
state, [b'a', b'foo', b'b/d'])
1955
2100
def test_bisect_rename(self):
1956
2101
"""Check that we find a renamed row."""
1957
2102
tree, state, expected = self.create_renamed_dirstate()
1959
2104
# 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'])
2105
self.assertBisect(expected, [[b'a']], state, [b'a'])
2106
self.assertBisect(expected, [[b'b/g']], state, [b'b/g'])
2107
self.assertBisect(expected, [[b'b/d']], state, [b'b/d'])
2108
self.assertBisect(expected, [[b'h']], state, [b'h'])
1965
2110
# 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'])
2111
self.assertBisect(expected, [[b'b/d/e']], state, [b'b/d/e'])
2112
self.assertBisect(expected, [[b'h/e']], state, [b'h/e'])
1969
2114
def test_bisect_dirblocks(self):
1970
2115
tree, state, expected = self.create_duplicated_dirstate()
1971
2116
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'])
2117
[[b'', b'a', b'a2', b'b', b'b2',
2118
b'b-c', b'b-c2', b'f', b'f2']],
2120
self.assertBisectDirBlocks(expected,
2121
[[b'b/c', b'b/c2', b'b/d', b'b/d2']], state, [b'b'])
2122
self.assertBisectDirBlocks(expected,
2123
[[b'b/d/e', b'b/d/e2']], state, [b'b/d'])
2124
self.assertBisectDirBlocks(expected,
2125
[[b'', b'a', b'a2', b'b', b'b2', b'b-c', b'b-c2', b'f', b'f2'],
2126
[b'b/c', b'b/c2', b'b/d', b'b/d2'],
2127
[b'b/d/e', b'b/d/e2'],
2128
], state, [b'', b'b', b'b/d'])
1984
2130
def test_bisect_dirblocks_missing(self):
1985
2131
tree, state, expected = self.create_basic_dirstate()
1986
self.assertBisectDirBlocks(expected, [['b/d/e'], None],
1987
state, ['b/d', 'b/e'])
2132
self.assertBisectDirBlocks(expected, [[b'b/d/e'], None],
2133
state, [b'b/d', b'b/e'])
1988
2134
# 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'])
2135
self.assertBisectDirBlocks(expected, [None], state, [b'a'])
2136
self.assertBisectDirBlocks(expected, [None], state, [b'b/c'])
2137
self.assertBisectDirBlocks(expected, [None], state, [b'c'])
2138
self.assertBisectDirBlocks(expected, [None], state, [b'b/d/e'])
2139
self.assertBisectDirBlocks(expected, [None], state, [b'f'])
1995
2141
def test_bisect_recursive_each(self):
1996
2142
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',
2143
self.assertBisectRecursive(expected, [b'a'], state, [b'a'])
2144
self.assertBisectRecursive(expected, [b'b/c'], state, [b'b/c'])
2145
self.assertBisectRecursive(expected, [b'b/d/e'], state, [b'b/d/e'])
2146
self.assertBisectRecursive(expected, [b'b-c'], state, [b'b-c'])
2147
self.assertBisectRecursive(expected, [b'b/d', b'b/d/e'],
2149
self.assertBisectRecursive(expected, [b'b', b'b/c', b'b/d', b'b/d/e'],
2151
self.assertBisectRecursive(expected, [b'', b'a', b'b', b'b-c', b'f', b'b/c',
2009
2155
def test_bisect_recursive_multiple(self):
2010
2156
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'])
2157
self.assertBisectRecursive(
2158
expected, [b'a', b'b/c'], state, [b'a', b'b/c'])
2159
self.assertBisectRecursive(expected, [b'b/d', b'b/d/e'],
2160
state, [b'b/d', b'b/d/e'])
2015
2162
def test_bisect_recursive_missing(self):
2016
2163
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'])
2164
self.assertBisectRecursive(expected, [], state, [b'd'])
2165
self.assertBisectRecursive(expected, [], state, [b'b/e'])
2166
self.assertBisectRecursive(expected, [], state, [b'g'])
2167
self.assertBisectRecursive(expected, [b'a'], state, [b'a', b'g'])
2022
2169
def test_bisect_recursive_renamed(self):
2023
2170
tree, state, expected = self.create_renamed_dirstate()
2025
2172
# 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'])
2173
self.assertBisectRecursive(expected, [b'a', b'b/g'], state, [b'a'])
2174
self.assertBisectRecursive(expected, [b'a', b'b/g'], state, [b'b/g'])
2028
2175
# Looking in the containing directory should find the rename target,
2029
2176
# 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'],
2177
self.assertBisectRecursive(expected, [b'a', b'b', b'b/c', b'b/d',
2178
b'b/d/e', b'b/g', b'h', b'h/e'],
2035
2182
class TestDirstateValidation(TestCaseWithDirState):
2141
2288
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),
2290
packed_stat = b'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2291
root_entry_direntry = (b'', b'', b'a-root-value'), [
2292
(b'd', b'', 0, False, packed_stat),
2293
(b'd', b'', 0, False, packed_stat),
2294
(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),
2296
expected_root_entry_direntry = (b'', b'', b'a-root-value'), [
2297
(b'd', b'', 0, False, packed_stat),
2298
(b'd', b'', 0, False, packed_stat),
2154
dirblocks.append(('', [root_entry_direntry]))
2155
dirblocks.append(('', []))
2301
dirblocks.append((b'', [root_entry_direntry]))
2302
dirblocks.append((b'', []))
2157
2304
state = self.create_empty_dirstate()
2158
2305
self.addCleanup(state.unlock)
2159
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2306
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2160
2307
state._validate()
2162
2309
# This should strip of the extra column
2163
2310
state._discard_merge_parents()
2164
2311
state._validate()
2165
expected_dirblocks = [('', [expected_root_entry_direntry]), ('', [])]
2312
expected_dirblocks = [(b'', [expected_root_entry_direntry]), (b'', [])]
2166
2313
self.assertEqual(expected_dirblocks, state._dirblocks)
2168
2315
def test_discard_absent(self):
2169
2316
"""If entries are only in a merge, discard should remove the entries"""
2170
2317
null_stat = dirstate.DirState.NULLSTAT
2171
present_dir = ('d', '', 0, False, null_stat)
2172
present_file = ('f', '', 0, False, null_stat)
2318
present_dir = (b'd', b'', 0, False, null_stat)
2319
present_file = (b'f', b'', 0, False, null_stat)
2173
2320
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]),
2321
root_key = (b'', b'', b'a-root-value')
2322
file_in_root_key = (b'', b'file-in-root', b'a-file-id')
2323
file_in_merged_key = (b'', b'file-in-merged', b'b-file-id')
2324
dirblocks = [(b'', [(root_key, [present_dir, present_dir, present_dir])]),
2325
(b'', [(file_in_merged_key,
2326
[absent, absent, present_file]),
2328
[present_file, present_file, present_file]),
2185
2332
state = self.create_empty_dirstate()
2186
2333
self.addCleanup(state.unlock)
2187
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2334
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2188
2335
state._validate()
2190
exp_dirblocks = [('', [(root_key, [present_dir, present_dir])]),
2191
('', [(file_in_root_key,
2192
[present_file, present_file]),
2337
exp_dirblocks = [(b'', [(root_key, [present_dir, present_dir])]),
2338
(b'', [(file_in_root_key,
2339
[present_file, present_file]),
2195
2342
state._discard_merge_parents()
2196
2343
state._validate()
2197
2344
self.assertEqual(exp_dirblocks, state._dirblocks)
2199
2346
def test_discard_renamed(self):
2200
2347
null_stat = dirstate.DirState.NULLSTAT
2201
present_dir = ('d', '', 0, False, null_stat)
2202
present_file = ('f', '', 0, False, null_stat)
2348
present_dir = (b'd', b'', 0, False, null_stat)
2349
present_file = (b'f', b'', 0, False, null_stat)
2203
2350
absent = dirstate.DirState.NULL_PARENT_DETAILS
2204
root_key = ('', '', 'a-root-value')
2205
file_in_root_key = ('', 'file-in-root', 'a-file-id')
2351
root_key = (b'', b'', b'a-root-value')
2352
file_in_root_key = (b'', b'file-in-root', b'a-file-id')
2206
2353
# Renamed relative to parent
2207
file_rename_s_key = ('', 'file-s', 'b-file-id')
2208
file_rename_t_key = ('', 'file-t', 'b-file-id')
2354
file_rename_s_key = (b'', b'file-s', b'b-file-id')
2355
file_rename_t_key = (b'', b'file-t', b'b-file-id')
2209
2356
# 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')
2357
key_in_1 = (b'', b'file-in-1', b'c-file-id')
2358
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')]),
2361
(b'', [(root_key, [present_dir, present_dir, present_dir])]),
2363
[absent, present_file, (b'r', b'file-in-2', b'c-file-id')]),
2365
[absent, (b'r', b'file-in-1', b'c-file-id'), present_file]),
2367
[present_file, present_file, present_file]),
2369
[(b'r', b'file-t', b'b-file-id'), absent, present_file]),
2371
[present_file, absent, (b'r', b'file-s', b'b-file-id')]),
2227
2374
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]),
2375
(b'', [(root_key, [present_dir, present_dir])]),
2376
(b'', [(key_in_1, [absent, present_file]),
2377
(file_in_root_key, [present_file, present_file]),
2378
(file_rename_t_key, [present_file, absent]),
2234
2381
state = self.create_empty_dirstate()
2235
2382
self.addCleanup(state.unlock)
2236
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2383
state._set_data([b'parent-id', b'merged-id'], dirblocks[:])
2237
2384
state._validate()
2239
2386
state._discard_merge_parents()
2320
2467
self.assertTrue(len(statvalue) >= 10)
2321
2468
self.assertEqual(len(text), statvalue.st_size)
2322
2469
self.assertEqual(expected_sha, sha1)
2472
class _Repo(object):
2473
"""A minimal api to get InventoryRevisionTree to work."""
2476
default_format = controldir.format_registry.make_controldir('default')
2477
self._format = default_format.repository_format
2479
def lock_read(self):
2486
class TestUpdateBasisByDelta(tests.TestCase):
2488
def path_to_ie(self, path, file_id, rev_id, dir_ids):
2489
if path.endswith('/'):
2494
dirname, basename = osutils.split(path)
2496
dir_id = dir_ids[dirname]
2498
dir_id = osutils.basename(dirname).encode('utf-8') + b'-id'
2500
ie = inventory.InventoryDirectory(file_id, basename, dir_id)
2501
dir_ids[path] = file_id
2503
ie = inventory.InventoryFile(file_id, basename, dir_id)
2506
ie.revision = rev_id
2509
def create_tree_from_shape(self, rev_id, shape):
2510
dir_ids = {'': b'root-id'}
2511
inv = inventory.Inventory(b'root-id', rev_id)
2514
path, file_id = info
2517
path, file_id, ie_rev_id = info
2519
# Replace the root entry
2520
del inv._byid[inv.root.file_id]
2521
inv.root.file_id = file_id
2522
inv._byid[file_id] = inv.root
2523
dir_ids[''] = file_id
2525
inv.add(self.path_to_ie(path, file_id, ie_rev_id, dir_ids))
2526
return inventorytree.InventoryRevisionTree(_Repo(), inv, rev_id)
2528
def create_empty_dirstate(self):
2529
fd, path = tempfile.mkstemp(prefix='bzr-dirstate')
2530
self.addCleanup(os.remove, path)
2532
state = dirstate.DirState.initialize(path)
2533
self.addCleanup(state.unlock)
2536
def create_inv_delta(self, delta, rev_id):
2537
"""Translate a 'delta shape' into an actual InventoryDelta"""
2538
dir_ids = {'': b'root-id'}
2540
for old_path, new_path, file_id in delta:
2541
if old_path is not None and old_path.endswith('/'):
2542
# Don't have to actually do anything for this, because only
2543
# new_path creates InventoryEntries
2544
old_path = old_path[:-1]
2545
if new_path is None: # Delete
2546
inv_delta.append((old_path, None, file_id, None))
2548
ie = self.path_to_ie(new_path, file_id, rev_id, dir_ids)
2549
inv_delta.append((old_path, new_path, file_id, ie))
2552
def assertUpdate(self, active, basis, target):
2553
"""Assert that update_basis_by_delta works how we want.
2555
Set up a DirState object with active_shape for tree 0, basis_shape for
2556
tree 1. Then apply the delta from basis_shape to target_shape,
2557
and assert that the DirState is still valid, and that its stored
2558
content matches the target_shape.
2560
active_tree = self.create_tree_from_shape(b'active', active)
2561
basis_tree = self.create_tree_from_shape(b'basis', basis)
2562
target_tree = self.create_tree_from_shape(b'target', target)
2563
state = self.create_empty_dirstate()
2564
state.set_state_from_scratch(active_tree.root_inventory,
2565
[(b'basis', basis_tree)], [])
2566
delta = target_tree.root_inventory._make_delta(
2567
basis_tree.root_inventory)
2568
state.update_basis_by_delta(delta, b'target')
2570
dirstate_tree = workingtree_4.DirStateRevisionTree(state,
2572
# The target now that delta has been applied should match the
2574
self.assertEqual([], list(dirstate_tree.iter_changes(target_tree)))
2575
# And the dirblock state should be identical to the state if we created
2577
state2 = self.create_empty_dirstate()
2578
state2.set_state_from_scratch(active_tree.root_inventory,
2579
[(b'target', target_tree)], [])
2580
self.assertEqual(state2._dirblocks, state._dirblocks)
2583
def assertBadDelta(self, active, basis, delta):
2584
"""Test that we raise InconsistentDelta when appropriate.
2586
:param active: The active tree shape
2587
:param basis: The basis tree shape
2588
:param delta: A description of the delta to apply. Similar to the form
2589
for regular inventory deltas, but omitting the InventoryEntry.
2590
So adding a file is: (None, 'path', b'file-id')
2591
Adding a directory is: (None, 'path/', b'dir-id')
2592
Renaming a dir is: ('old/', 'new/', b'dir-id')
2595
active_tree = self.create_tree_from_shape(b'active', active)
2596
basis_tree = self.create_tree_from_shape(b'basis', basis)
2597
inv_delta = self.create_inv_delta(delta, b'target')
2598
state = self.create_empty_dirstate()
2599
state.set_state_from_scratch(active_tree.root_inventory,
2600
[(b'basis', basis_tree)], [])
2601
self.assertRaises(errors.InconsistentDelta,
2602
state.update_basis_by_delta, inv_delta, b'target')
2604
## state.update_basis_by_delta(inv_delta, b'target')
2605
# except errors.InconsistentDelta, e:
2606
## import pdb; pdb.set_trace()
2608
## import pdb; pdb.set_trace()
2609
self.assertTrue(state._changes_aborted)
2611
def test_remove_file_matching_active_state(self):
2612
state = self.assertUpdate(
2614
basis=[('file', b'file-id')],
2618
def test_remove_file_present_in_active_state(self):
2619
state = self.assertUpdate(
2620
active=[('file', b'file-id')],
2621
basis=[('file', b'file-id')],
2625
def test_remove_file_present_elsewhere_in_active_state(self):
2626
state = self.assertUpdate(
2627
active=[('other-file', b'file-id')],
2628
basis=[('file', b'file-id')],
2632
def test_remove_file_active_state_has_diff_file(self):
2633
state = self.assertUpdate(
2634
active=[('file', b'file-id-2')],
2635
basis=[('file', b'file-id')],
2639
def test_remove_file_active_state_has_diff_file_and_file_elsewhere(self):
2640
state = self.assertUpdate(
2641
active=[('file', b'file-id-2'),
2642
('other-file', b'file-id')],
2643
basis=[('file', b'file-id')],
2647
def test_add_file_matching_active_state(self):
2648
state = self.assertUpdate(
2649
active=[('file', b'file-id')],
2651
target=[('file', b'file-id')],
2654
def test_add_file_in_empty_dir_not_matching_active_state(self):
2655
state = self.assertUpdate(
2657
basis=[('dir/', b'dir-id')],
2658
target=[('dir/', b'dir-id', b'basis'), ('dir/file', b'file-id')],
2661
def test_add_file_missing_in_active_state(self):
2662
state = self.assertUpdate(
2665
target=[('file', b'file-id')],
2668
def test_add_file_elsewhere_in_active_state(self):
2669
state = self.assertUpdate(
2670
active=[('other-file', b'file-id')],
2672
target=[('file', b'file-id')],
2675
def test_add_file_active_state_has_diff_file_and_file_elsewhere(self):
2676
state = self.assertUpdate(
2677
active=[('other-file', b'file-id'),
2678
('file', b'file-id-2')],
2680
target=[('file', b'file-id')],
2683
def test_rename_file_matching_active_state(self):
2684
state = self.assertUpdate(
2685
active=[('other-file', b'file-id')],
2686
basis=[('file', b'file-id')],
2687
target=[('other-file', b'file-id')],
2690
def test_rename_file_missing_in_active_state(self):
2691
state = self.assertUpdate(
2693
basis=[('file', b'file-id')],
2694
target=[('other-file', b'file-id')],
2697
def test_rename_file_present_elsewhere_in_active_state(self):
2698
state = self.assertUpdate(
2699
active=[('third', b'file-id')],
2700
basis=[('file', b'file-id')],
2701
target=[('other-file', b'file-id')],
2704
def test_rename_file_active_state_has_diff_source_file(self):
2705
state = self.assertUpdate(
2706
active=[('file', b'file-id-2')],
2707
basis=[('file', b'file-id')],
2708
target=[('other-file', b'file-id')],
2711
def test_rename_file_active_state_has_diff_target_file(self):
2712
state = self.assertUpdate(
2713
active=[('other-file', b'file-id-2')],
2714
basis=[('file', b'file-id')],
2715
target=[('other-file', b'file-id')],
2718
def test_rename_file_active_has_swapped_files(self):
2719
state = self.assertUpdate(
2720
active=[('file', b'file-id'),
2721
('other-file', b'file-id-2')],
2722
basis=[('file', b'file-id'),
2723
('other-file', b'file-id-2')],
2724
target=[('file', b'file-id-2'),
2725
('other-file', b'file-id')])
2727
def test_rename_file_basis_has_swapped_files(self):
2728
state = self.assertUpdate(
2729
active=[('file', b'file-id'),
2730
('other-file', b'file-id-2')],
2731
basis=[('file', b'file-id-2'),
2732
('other-file', b'file-id')],
2733
target=[('file', b'file-id'),
2734
('other-file', b'file-id-2')])
2736
def test_rename_directory_with_contents(self):
2737
state = self.assertUpdate( # active matches basis
2738
active=[('dir1/', b'dir-id'),
2739
('dir1/file', b'file-id')],
2740
basis=[('dir1/', b'dir-id'),
2741
('dir1/file', b'file-id')],
2742
target=[('dir2/', b'dir-id'),
2743
('dir2/file', b'file-id')])
2744
state = self.assertUpdate( # active matches target
2745
active=[('dir2/', b'dir-id'),
2746
('dir2/file', b'file-id')],
2747
basis=[('dir1/', b'dir-id'),
2748
('dir1/file', b'file-id')],
2749
target=[('dir2/', b'dir-id'),
2750
('dir2/file', b'file-id')])
2751
state = self.assertUpdate( # active empty
2753
basis=[('dir1/', b'dir-id'),
2754
('dir1/file', b'file-id')],
2755
target=[('dir2/', b'dir-id'),
2756
('dir2/file', b'file-id')])
2757
state = self.assertUpdate( # active present at other location
2758
active=[('dir3/', b'dir-id'),
2759
('dir3/file', b'file-id')],
2760
basis=[('dir1/', b'dir-id'),
2761
('dir1/file', b'file-id')],
2762
target=[('dir2/', b'dir-id'),
2763
('dir2/file', b'file-id')])
2764
state = self.assertUpdate( # active has different ids
2765
active=[('dir1/', b'dir1-id'),
2766
('dir1/file', b'file1-id'),
2767
('dir2/', b'dir2-id'),
2768
('dir2/file', b'file2-id')],
2769
basis=[('dir1/', b'dir-id'),
2770
('dir1/file', b'file-id')],
2771
target=[('dir2/', b'dir-id'),
2772
('dir2/file', b'file-id')])
2774
def test_invalid_file_not_present(self):
2775
state = self.assertBadDelta(
2776
active=[('file', b'file-id')],
2777
basis=[('file', b'file-id')],
2778
delta=[('other-file', 'file', b'file-id')])
2780
def test_invalid_new_id_same_path(self):
2781
# The bad entry comes after
2782
state = self.assertBadDelta(
2783
active=[('file', b'file-id')],
2784
basis=[('file', b'file-id')],
2785
delta=[(None, 'file', b'file-id-2')])
2786
# The bad entry comes first
2787
state = self.assertBadDelta(
2788
active=[('file', b'file-id-2')],
2789
basis=[('file', b'file-id-2')],
2790
delta=[(None, 'file', b'file-id')])
2792
def test_invalid_existing_id(self):
2793
state = self.assertBadDelta(
2794
active=[('file', b'file-id')],
2795
basis=[('file', b'file-id')],
2796
delta=[(None, 'file', b'file-id')])
2798
def test_invalid_parent_missing(self):
2799
state = self.assertBadDelta(
2802
delta=[(None, 'path/path2', b'file-id')])
2803
# Note: we force the active tree to have the directory, by knowing how
2804
# path_to_ie handles entries with missing parents
2805
state = self.assertBadDelta(
2806
active=[('path/', b'path-id')],
2808
delta=[(None, 'path/path2', b'file-id')])
2809
state = self.assertBadDelta(
2810
active=[('path/', b'path-id'),
2811
('path/path2', b'file-id')],
2813
delta=[(None, 'path/path2', b'file-id')])
2815
def test_renamed_dir_same_path(self):
2816
# We replace the parent directory, with another parent dir. But the C
2817
# file doesn't look like it has been moved.
2818
state = self.assertUpdate( # Same as basis
2819
active=[('dir/', b'A-id'),
2820
('dir/B', b'B-id')],
2821
basis=[('dir/', b'A-id'),
2822
('dir/B', b'B-id')],
2823
target=[('dir/', b'C-id'),
2824
('dir/B', b'B-id')])
2825
state = self.assertUpdate( # Same as target
2826
active=[('dir/', b'C-id'),
2827
('dir/B', b'B-id')],
2828
basis=[('dir/', b'A-id'),
2829
('dir/B', b'B-id')],
2830
target=[('dir/', b'C-id'),
2831
('dir/B', b'B-id')])
2832
state = self.assertUpdate( # empty active
2834
basis=[('dir/', b'A-id'),
2835
('dir/B', b'B-id')],
2836
target=[('dir/', b'C-id'),
2837
('dir/B', b'B-id')])
2838
state = self.assertUpdate( # different active
2839
active=[('dir/', b'D-id'),
2840
('dir/B', b'B-id')],
2841
basis=[('dir/', b'A-id'),
2842
('dir/B', b'B-id')],
2843
target=[('dir/', b'C-id'),
2844
('dir/B', b'B-id')])
2846
def test_parent_child_swap(self):
2847
state = self.assertUpdate( # Same as basis
2848
active=[('A/', b'A-id'),
2850
('A/B/C', b'C-id')],
2851
basis=[('A/', b'A-id'),
2853
('A/B/C', b'C-id')],
2854
target=[('A/', b'B-id'),
2856
('A/B/C', b'C-id')])
2857
state = self.assertUpdate( # Same as target
2858
active=[('A/', b'B-id'),
2860
('A/B/C', b'C-id')],
2861
basis=[('A/', b'A-id'),
2863
('A/B/C', b'C-id')],
2864
target=[('A/', b'B-id'),
2866
('A/B/C', b'C-id')])
2867
state = self.assertUpdate( # empty active
2869
basis=[('A/', b'A-id'),
2871
('A/B/C', b'C-id')],
2872
target=[('A/', b'B-id'),
2874
('A/B/C', b'C-id')])
2875
state = self.assertUpdate( # different active
2876
active=[('D/', b'A-id'),
2879
basis=[('A/', b'A-id'),
2881
('A/B/C', b'C-id')],
2882
target=[('A/', b'B-id'),
2884
('A/B/C', b'C-id')])
2886
def test_change_root_id(self):
2887
state = self.assertUpdate( # same as basis
2888
active=[('', b'root-id'),
2889
('file', b'file-id')],
2890
basis=[('', b'root-id'),
2891
('file', b'file-id')],
2892
target=[('', b'target-root-id'),
2893
('file', b'file-id')])
2894
state = self.assertUpdate( # same as target
2895
active=[('', b'target-root-id'),
2896
('file', b'file-id')],
2897
basis=[('', b'root-id'),
2898
('file', b'file-id')],
2899
target=[('', b'target-root-id'),
2900
('file', b'root-id')])
2901
state = self.assertUpdate( # all different
2902
active=[('', b'active-root-id'),
2903
('file', b'file-id')],
2904
basis=[('', b'root-id'),
2905
('file', b'file-id')],
2906
target=[('', b'target-root-id'),
2907
('file', b'root-id')])
2909
def test_change_file_absent_in_active(self):
2910
state = self.assertUpdate(
2912
basis=[('file', b'file-id')],
2913
target=[('file', b'file-id')])
2915
def test_invalid_changed_file(self):
2916
state = self.assertBadDelta( # Not present in basis
2917
active=[('file', b'file-id')],
2919
delta=[('file', 'file', b'file-id')])
2920
state = self.assertBadDelta( # present at another location in basis
2921
active=[('file', b'file-id')],
2922
basis=[('other-file', b'file-id')],
2923
delta=[('file', 'file', b'file-id')])