184
def create_basic_dirstate(self):
185
"""Create a dirstate with a few files and directories.
194
tree = self.make_branch_and_tree('tree')
195
paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'f']
196
file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id']
197
self.build_tree(['tree/' + p for p in paths])
198
tree.set_root_id('TREE_ROOT')
199
tree.add([p.rstrip('/') for p in paths], file_ids)
200
tree.commit('initial', rev_id='rev-1')
201
revision_id = 'rev-1'
202
# a_packed_stat = dirstate.pack_stat(os.stat('tree/a'))
203
t = self.get_transport().clone('tree')
204
a_text = t.get_bytes('a')
205
a_sha = osutils.sha_string(a_text)
207
# b_packed_stat = dirstate.pack_stat(os.stat('tree/b'))
208
# c_packed_stat = dirstate.pack_stat(os.stat('tree/b/c'))
209
c_text = t.get_bytes('b/c')
210
c_sha = osutils.sha_string(c_text)
212
# d_packed_stat = dirstate.pack_stat(os.stat('tree/b/d'))
213
# e_packed_stat = dirstate.pack_stat(os.stat('tree/b/d/e'))
214
e_text = t.get_bytes('b/d/e')
215
e_sha = osutils.sha_string(e_text)
217
# f_packed_stat = dirstate.pack_stat(os.stat('tree/f'))
218
f_text = t.get_bytes('f')
219
f_sha = osutils.sha_string(f_text)
221
null_stat = dirstate.DirState.NULLSTAT
223
'':(('', '', 'TREE_ROOT'), [
224
('d', '', 0, False, null_stat),
225
('d', '', 0, False, revision_id),
227
'a':(('', 'a', 'a-id'), [
228
('f', '', 0, False, null_stat),
229
('f', a_sha, a_len, False, revision_id),
231
'b':(('', 'b', 'b-id'), [
232
('d', '', 0, False, null_stat),
233
('d', '', 0, False, revision_id),
235
'b/c':(('b', 'c', 'c-id'), [
236
('f', '', 0, False, null_stat),
237
('f', c_sha, c_len, False, revision_id),
239
'b/d':(('b', 'd', 'd-id'), [
240
('d', '', 0, False, null_stat),
241
('d', '', 0, False, revision_id),
243
'b/d/e':(('b/d', 'e', 'e-id'), [
244
('f', '', 0, False, null_stat),
245
('f', e_sha, e_len, False, revision_id),
247
'f':(('', 'f', 'f-id'), [
248
('f', '', 0, False, null_stat),
249
('f', f_sha, f_len, False, revision_id),
252
state = dirstate.DirState.from_tree(tree, 'dirstate')
257
# Use a different object, to make sure nothing is pre-cached in memory.
258
state = dirstate.DirState.on_file('dirstate')
260
self.addCleanup(state.unlock)
261
self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
262
state._dirblock_state)
263
# This is code is only really tested if we actually have to make more
264
# than one read, so set the page size to something smaller.
265
# We want it to contain about 2.2 records, so that we have a couple
266
# records that we can read per attempt
267
state._bisect_page_size = 200
268
return tree, state, expected
270
def create_duplicated_dirstate(self):
271
"""Create a dirstate with a deleted and added entries.
273
This grabs a basic_dirstate, and then removes and re adds every entry
276
tree, state, expected = self.create_basic_dirstate()
277
# Now we will just remove and add every file so we get an extra entry
278
# per entry. Unversion in reverse order so we handle subdirs
279
tree.unversion(['f-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
280
tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f'],
281
['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'f-id2'])
283
# Update the expected dictionary.
284
for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f']:
285
orig = expected[path]
287
# This record was deleted in the current tree
288
expected[path] = (orig[0], [dirstate.DirState.NULL_PARENT_DETAILS,
290
new_key = (orig[0][0], orig[0][1], orig[0][2]+'2')
291
# And didn't exist in the basis tree
292
expected[path2] = (new_key, [orig[1][0],
293
dirstate.DirState.NULL_PARENT_DETAILS])
295
# We will replace the 'dirstate' file underneath 'state', but that is
296
# okay as lock as we unlock 'state' first.
299
new_state = dirstate.DirState.from_tree(tree, 'dirstate')
305
# But we need to leave state in a read-lock because we already have
306
# a cleanup scheduled
308
return tree, state, expected
310
def create_renamed_dirstate(self):
311
"""Create a dirstate with a few internal renames.
313
This takes the basic dirstate, and moves the paths around.
315
tree, state, expected = self.create_basic_dirstate()
317
tree.rename_one('a', 'b/g')
319
tree.rename_one('b/d', 'h')
321
old_a = expected['a']
322
expected['a'] = (old_a[0], [('r', 'b/g', 0, False, ''), old_a[1][1]])
323
expected['b/g'] = (('b', 'g', 'a-id'), [old_a[1][0],
324
('r', 'a', 0, False, '')])
325
old_d = expected['b/d']
326
expected['b/d'] = (old_d[0], [('r', 'h', 0, False, ''), old_d[1][1]])
327
expected['h'] = (('', 'h', 'd-id'), [old_d[1][0],
328
('r', 'b/d', 0, False, '')])
330
old_e = expected['b/d/e']
331
expected['b/d/e'] = (old_e[0], [('r', 'h/e', 0, False, ''),
333
expected['h/e'] = (('h', 'e', 'e-id'), [old_e[1][0],
334
('r', 'b/d/e', 0, False, '')])
338
new_state = dirstate.DirState.from_tree(tree, 'dirstate')
345
return tree, state, expected
189
347
class TestTreeToDirState(TestCaseWithDirState):
960
1337
self.assertEqual(expected, dirblock_names)
963
class TestBisect(TestCaseWithTransport):
1340
class InstrumentedDirState(dirstate.DirState):
1341
"""An DirState with instrumented sha1 functionality."""
1343
def __init__(self, path):
1344
super(InstrumentedDirState, self).__init__(path)
1345
self._time_offset = 0
1348
def _sha_cutoff_time(self):
1349
timestamp = super(InstrumentedDirState, self)._sha_cutoff_time()
1350
self._cutoff_time = timestamp + self._time_offset
1352
def _sha1_file(self, abspath, entry):
1353
self._log.append(('sha1', abspath))
1354
return super(InstrumentedDirState, self)._sha1_file(abspath, entry)
1356
def _read_link(self, abspath, old_link):
1357
self._log.append(('read_link', abspath, old_link))
1358
return super(InstrumentedDirState, self)._read_link(abspath, old_link)
1360
def _lstat(self, abspath, entry):
1361
self._log.append(('lstat', abspath))
1362
return super(InstrumentedDirState, self)._lstat(abspath, entry)
1364
def _is_executable(self, mode, old_executable):
1365
self._log.append(('is_exec', mode, old_executable))
1366
return super(InstrumentedDirState, self)._is_executable(mode,
1369
def adjust_time(self, secs):
1370
"""Move the clock forward or back.
1372
:param secs: The amount to adjust the clock by. Positive values make it
1373
seem as if we are in the future, negative values make it seem like we
1376
self._time_offset += secs
1377
self._cutoff_time = None
1380
class _FakeStat(object):
1381
"""A class with the same attributes as a real stat result."""
1383
def __init__(self, size, mtime, ctime, dev, ino, mode):
1385
self.st_mtime = mtime
1386
self.st_ctime = ctime
1392
class TestUpdateEntry(TestCaseWithDirState):
1393
"""Test the DirState.update_entry functions"""
1395
def get_state_with_a(self):
1396
"""Create a DirState tracking a single object named 'a'"""
1397
state = InstrumentedDirState.initialize('dirstate')
1398
self.addCleanup(state.unlock)
1399
state.add('a', 'a-id', 'file', None, '')
1400
entry = state._get_entry(0, path_utf8='a')
1403
def test_update_entry(self):
1404
state, entry = self.get_state_with_a()
1405
self.build_tree(['a'])
1406
# Add one where we don't provide the stat or sha already
1407
self.assertEqual(('', 'a', 'a-id'), entry[0])
1408
self.assertEqual([('f', '', 0, False, dirstate.DirState.NULLSTAT)],
1410
# Flush the buffers to disk
1412
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1413
state._dirblock_state)
1415
stat_value = os.lstat('a')
1416
packed_stat = dirstate.pack_stat(stat_value)
1417
link_or_sha1 = state.update_entry(entry, abspath='a',
1418
stat_value=stat_value)
1419
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1422
# The dirblock entry should be updated with the new info
1423
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1425
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1426
state._dirblock_state)
1427
mode = stat_value.st_mode
1428
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
1431
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1432
state._dirblock_state)
1434
# If we do it again right away, we don't know if the file has changed
1435
# so we will re-read the file. Roll the clock back so the file is
1436
# guaranteed to look too new.
1437
state.adjust_time(-10)
1439
link_or_sha1 = state.update_entry(entry, abspath='a',
1440
stat_value=stat_value)
1441
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1442
('sha1', 'a'), ('is_exec', mode, False),
1444
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1446
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1447
state._dirblock_state)
1450
# However, if we move the clock forward so the file is considered
1451
# "stable", it should just returned the cached value.
1452
state.adjust_time(20)
1453
link_or_sha1 = state.update_entry(entry, abspath='a',
1454
stat_value=stat_value)
1455
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1457
self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
1458
('sha1', 'a'), ('is_exec', mode, False),
1461
def test_update_entry_no_stat_value(self):
1462
"""Passing the stat_value is optional."""
1463
state, entry = self.get_state_with_a()
1464
state.adjust_time(-10) # Make sure the file looks new
1465
self.build_tree(['a'])
1466
# Add one where we don't provide the stat or sha already
1467
link_or_sha1 = state.update_entry(entry, abspath='a')
1468
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1470
stat_value = os.lstat('a')
1471
self.assertEqual([('lstat', 'a'), ('sha1', 'a'),
1472
('is_exec', stat_value.st_mode, False),
1475
def test_update_entry_symlink(self):
1476
"""Update entry should read symlinks."""
1477
if not osutils.has_symlinks():
1478
# PlatformDeficiency / TestSkipped
1479
raise TestSkipped("No symlink support")
1480
state, entry = self.get_state_with_a()
1482
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1483
state._dirblock_state)
1484
os.symlink('target', 'a')
1486
state.adjust_time(-10) # Make the symlink look new
1487
stat_value = os.lstat('a')
1488
packed_stat = dirstate.pack_stat(stat_value)
1489
link_or_sha1 = state.update_entry(entry, abspath='a',
1490
stat_value=stat_value)
1491
self.assertEqual('target', link_or_sha1)
1492
self.assertEqual([('read_link', 'a', '')], state._log)
1493
# Dirblock is updated
1494
self.assertEqual([('l', link_or_sha1, 6, False, packed_stat)],
1496
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1497
state._dirblock_state)
1499
# Because the stat_value looks new, we should re-read the target
1500
link_or_sha1 = state.update_entry(entry, abspath='a',
1501
stat_value=stat_value)
1502
self.assertEqual('target', link_or_sha1)
1503
self.assertEqual([('read_link', 'a', ''),
1504
('read_link', 'a', 'target'),
1506
state.adjust_time(+20) # Skip into the future, all files look old
1507
link_or_sha1 = state.update_entry(entry, abspath='a',
1508
stat_value=stat_value)
1509
self.assertEqual('target', link_or_sha1)
1510
# There should not be a new read_link call.
1511
# (this is a weak assertion, because read_link is fairly inexpensive,
1512
# versus the number of symlinks that we would have)
1513
self.assertEqual([('read_link', 'a', ''),
1514
('read_link', 'a', 'target'),
1517
def test_update_entry_dir(self):
1518
state, entry = self.get_state_with_a()
1519
self.build_tree(['a/'])
1520
self.assertIs(None, state.update_entry(entry, 'a'))
1522
def create_and_test_file(self, state, entry):
1523
"""Create a file at 'a' and verify the state finds it.
1525
The state should already be versioning *something* at 'a'. This makes
1526
sure that state.update_entry recognizes it as a file.
1528
self.build_tree(['a'])
1529
stat_value = os.lstat('a')
1530
packed_stat = dirstate.pack_stat(stat_value)
1532
link_or_sha1 = state.update_entry(entry, abspath='a')
1533
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
1535
self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
1539
def create_and_test_dir(self, state, entry):
1540
"""Create a directory at 'a' and verify the state finds it.
1542
The state should already be versioning *something* at 'a'. This makes
1543
sure that state.update_entry recognizes it as a directory.
1545
self.build_tree(['a/'])
1546
stat_value = os.lstat('a')
1547
packed_stat = dirstate.pack_stat(stat_value)
1549
link_or_sha1 = state.update_entry(entry, abspath='a')
1550
self.assertIs(None, link_or_sha1)
1551
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1555
def create_and_test_symlink(self, state, entry):
1556
"""Create a symlink at 'a' and verify the state finds it.
1558
The state should already be versioning *something* at 'a'. This makes
1559
sure that state.update_entry recognizes it as a symlink.
1561
This should not be called if this platform does not have symlink
1564
# caller should care about skipping test on platforms without symlinks
1565
os.symlink('path/to/foo', 'a')
1567
stat_value = os.lstat('a')
1568
packed_stat = dirstate.pack_stat(stat_value)
1570
link_or_sha1 = state.update_entry(entry, abspath='a')
1571
self.assertEqual('path/to/foo', link_or_sha1)
1572
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1576
def test_update_missing_file(self):
1577
state, entry = self.get_state_with_a()
1578
packed_stat = self.create_and_test_file(state, entry)
1579
# Now if we delete the file, update_entry should recover and
1582
self.assertIs(None, state.update_entry(entry, abspath='a'))
1583
# And the record shouldn't be changed.
1584
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1585
self.assertEqual([('f', digest, 14, False, packed_stat)],
1588
def test_update_missing_dir(self):
1589
state, entry = self.get_state_with_a()
1590
packed_stat = self.create_and_test_dir(state, entry)
1591
# Now if we delete the directory, update_entry should recover and
1594
self.assertIs(None, state.update_entry(entry, abspath='a'))
1595
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1597
def test_update_missing_symlink(self):
1598
if not osutils.has_symlinks():
1599
# PlatformDeficiency / TestSkipped
1600
raise TestSkipped("No symlink support")
1601
state, entry = self.get_state_with_a()
1602
packed_stat = self.create_and_test_symlink(state, entry)
1604
self.assertIs(None, state.update_entry(entry, abspath='a'))
1605
# And the record shouldn't be changed.
1606
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1609
def test_update_file_to_dir(self):
1610
"""If a file changes to a directory we return None for the sha.
1611
We also update the inventory record.
1613
state, entry = self.get_state_with_a()
1614
self.create_and_test_file(state, entry)
1616
self.create_and_test_dir(state, entry)
1618
def test_update_file_to_symlink(self):
1619
"""File becomes a symlink"""
1620
if not osutils.has_symlinks():
1621
# PlatformDeficiency / TestSkipped
1622
raise TestSkipped("No symlink support")
1623
state, entry = self.get_state_with_a()
1624
self.create_and_test_file(state, entry)
1626
self.create_and_test_symlink(state, entry)
1628
def test_update_dir_to_file(self):
1629
"""Directory becoming a file updates the entry."""
1630
state, entry = self.get_state_with_a()
1631
self.create_and_test_dir(state, entry)
1633
self.create_and_test_file(state, entry)
1635
def test_update_dir_to_symlink(self):
1636
"""Directory becomes a symlink"""
1637
if not osutils.has_symlinks():
1638
# PlatformDeficiency / TestSkipped
1639
raise TestSkipped("No symlink support")
1640
state, entry = self.get_state_with_a()
1641
self.create_and_test_dir(state, entry)
1643
self.create_and_test_symlink(state, entry)
1645
def test_update_symlink_to_file(self):
1646
"""Symlink becomes a file"""
1647
if not has_symlinks():
1648
raise TestSkipped("No symlink support")
1649
state, entry = self.get_state_with_a()
1650
self.create_and_test_symlink(state, entry)
1652
self.create_and_test_file(state, entry)
1654
def test_update_symlink_to_dir(self):
1655
"""Symlink becomes a directory"""
1656
if not has_symlinks():
1657
raise TestSkipped("No symlink support")
1658
state, entry = self.get_state_with_a()
1659
self.create_and_test_symlink(state, entry)
1661
self.create_and_test_dir(state, entry)
1663
def test__is_executable_win32(self):
1664
state, entry = self.get_state_with_a()
1665
self.build_tree(['a'])
1667
# Make sure we are using the win32 implementation of _is_executable
1668
state._is_executable = state._is_executable_win32
1670
# The file on disk is not executable, but we are marking it as though
1671
# it is. With _is_executable_win32 we ignore what is on disk.
1672
entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1674
stat_value = os.lstat('a')
1675
packed_stat = dirstate.pack_stat(stat_value)
1677
state.adjust_time(-10) # Make sure everything is new
1678
# Make sure it wants to kkkkkkkk
1679
state.update_entry(entry, abspath='a', stat_value=stat_value)
1681
# The row is updated, but the executable bit stays set.
1682
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1683
self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
1686
class TestPackStat(TestCaseWithTransport):
1688
def assertPackStat(self, expected, stat_value):
1689
"""Check the packed and serialized form of a stat value."""
1690
self.assertEqual(expected, dirstate.pack_stat(stat_value))
1692
def test_pack_stat_int(self):
1693
st = _FakeStat(6859L, 1172758614, 1172758617, 777L, 6499538L, 0100644)
1694
# Make sure that all parameters have an impact on the packed stat.
1695
self.assertPackStat('AAAay0Xm4FZF5uBZAAADCQBjLNIAAIGk', st)
1698
self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1699
st.st_mtime = 1172758620
1701
self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1702
st.st_ctime = 1172758630
1704
self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1707
self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNIAAIGk', st)
1708
st.st_ino = 6499540L
1710
self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIGk', st)
1711
st.st_mode = 0100744
1713
self.assertPackStat('AAAbWEXm4FxF5uBmAAADeABjLNQAAIHk', st)
1715
def test_pack_stat_float(self):
1716
"""On some platforms mtime and ctime are floats.
1718
Make sure we don't get warnings or errors, and that we ignore changes <
1721
st = _FakeStat(7000L, 1172758614.0, 1172758617.0,
1722
777L, 6499538L, 0100644)
1723
# These should all be the same as the integer counterparts
1724
self.assertPackStat('AAAbWEXm4FZF5uBZAAADCQBjLNIAAIGk', st)
1725
st.st_mtime = 1172758620.0
1727
self.assertPackStat('AAAbWEXm4FxF5uBZAAADCQBjLNIAAIGk', st)
1728
st.st_ctime = 1172758630.0
1730
self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1731
# fractional seconds are discarded, so no change from above
1732
st.st_mtime = 1172758620.453
1733
self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1734
st.st_ctime = 1172758630.228
1735
self.assertPackStat('AAAbWEXm4FxF5uBmAAADCQBjLNIAAIGk', st)
1738
class TestBisect(TestCaseWithDirState):
964
1739
"""Test the ability to bisect into the disk format."""
966
def create_basic_dirstate(self):
967
"""Create a dirstate with a few files and directories.
976
tree = self.make_branch_and_tree('tree')
977
paths = ['a', 'b/', 'b/c', 'b/d/', 'b/d/e', 'f']
978
file_ids = ['a-id', 'b-id', 'c-id', 'd-id', 'e-id', 'f-id']
979
self.build_tree(['tree/' + p for p in paths])
980
tree.set_root_id('TREE_ROOT')
981
tree.add([p.rstrip('/') for p in paths], file_ids)
982
tree.commit('initial', rev_id='rev-1')
983
revision_id = 'rev-1'
984
# a_packed_stat = dirstate.pack_stat(os.stat('tree/a'))
985
t = self.get_transport().clone('tree')
986
a_text = t.get_bytes('a')
987
a_sha = osutils.sha_string(a_text)
989
# b_packed_stat = dirstate.pack_stat(os.stat('tree/b'))
990
# c_packed_stat = dirstate.pack_stat(os.stat('tree/b/c'))
991
c_text = t.get_bytes('b/c')
992
c_sha = osutils.sha_string(c_text)
994
# d_packed_stat = dirstate.pack_stat(os.stat('tree/b/d'))
995
# e_packed_stat = dirstate.pack_stat(os.stat('tree/b/d/e'))
996
e_text = t.get_bytes('b/d/e')
997
e_sha = osutils.sha_string(e_text)
999
# f_packed_stat = dirstate.pack_stat(os.stat('tree/f'))
1000
f_text = t.get_bytes('f')
1001
f_sha = osutils.sha_string(f_text)
1003
null_stat = dirstate.DirState.NULLSTAT
1005
'':(('', '', 'TREE_ROOT'), [
1006
('d', '', 0, False, null_stat),
1007
('d', '', 0, False, revision_id),
1009
'a':(('', 'a', 'a-id'), [
1010
('f', '', 0, False, null_stat),
1011
('f', a_sha, a_len, False, revision_id),
1013
'b':(('', 'b', 'b-id'), [
1014
('d', '', 0, False, null_stat),
1015
('d', '', 0, False, revision_id),
1017
'b/c':(('b', 'c', 'c-id'), [
1018
('f', '', 0, False, null_stat),
1019
('f', c_sha, c_len, False, revision_id),
1021
'b/d':(('b', 'd', 'd-id'), [
1022
('d', '', 0, False, null_stat),
1023
('d', '', 0, False, revision_id),
1025
'b/d/e':(('b/d', 'e', 'e-id'), [
1026
('f', '', 0, False, null_stat),
1027
('f', e_sha, e_len, False, revision_id),
1029
'f':(('', 'f', 'f-id'), [
1030
('f', '', 0, False, null_stat),
1031
('f', f_sha, f_len, False, revision_id),
1034
state = dirstate.DirState.from_tree(tree, 'dirstate')
1039
# Use a different object, to make sure nothing is pre-cached in memory.
1040
state = dirstate.DirState.on_file('dirstate')
1042
self.addCleanup(state.unlock)
1043
self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
1044
state._dirblock_state)
1045
# This is code is only really tested if we actually have to make more
1046
# than one read, so set the page size to something smaller.
1047
# We want it to contain about 2.2 records, so that we have a couple
1048
# records that we can read per attempt
1049
state._bisect_page_size = 200
1050
return tree, state, expected
1052
def create_duplicated_dirstate(self):
1053
"""Create a dirstate with a deleted and added entries.
1055
This grabs a basic_dirstate, and then removes and re adds every entry
1058
tree, state, expected = self.create_basic_dirstate()
1059
# Now we will just remove and add every file so we get an extra entry
1060
# per entry. Unversion in reverse order so we handle subdirs
1061
tree.unversion(['f-id', 'e-id', 'd-id', 'c-id', 'b-id', 'a-id'])
1062
tree.add(['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f'],
1063
['a-id2', 'b-id2', 'c-id2', 'd-id2', 'e-id2', 'f-id2'])
1065
# Update the expected dictionary.
1066
for path in ['a', 'b', 'b/c', 'b/d', 'b/d/e', 'f']:
1067
orig = expected[path]
1069
# This record was deleted in the current tree
1070
expected[path] = (orig[0], [dirstate.DirState.NULL_PARENT_DETAILS,
1072
new_key = (orig[0][0], orig[0][1], orig[0][2]+'2')
1073
# And didn't exist in the basis tree
1074
expected[path2] = (new_key, [orig[1][0],
1075
dirstate.DirState.NULL_PARENT_DETAILS])
1077
# We will replace the 'dirstate' file underneath 'state', but that is
1078
# okay as lock as we unlock 'state' first.
1081
new_state = dirstate.DirState.from_tree(tree, 'dirstate')
1087
# But we need to leave state in a read-lock because we already have
1088
# a cleanup scheduled
1090
return tree, state, expected
1092
def create_renamed_dirstate(self):
1093
"""Create a dirstate with a few internal renames.
1095
This takes the basic dirstate, and moves the paths around.
1097
tree, state, expected = self.create_basic_dirstate()
1099
tree.rename_one('a', 'b/g')
1101
tree.rename_one('b/d', 'h')
1103
old_a = expected['a']
1104
expected['a'] = (old_a[0], [('r', 'b/g', 0, False, ''), old_a[1][1]])
1105
expected['b/g'] = (('b', 'g', 'a-id'), [old_a[1][0],
1106
('r', 'a', 0, False, '')])
1107
old_d = expected['b/d']
1108
expected['b/d'] = (old_d[0], [('r', 'h', 0, False, ''), old_d[1][1]])
1109
expected['h'] = (('', 'h', 'd-id'), [old_d[1][0],
1110
('r', 'b/d', 0, False, '')])
1112
old_e = expected['b/d/e']
1113
expected['b/d/e'] = (old_e[0], [('r', 'h/e', 0, False, ''),
1115
expected['h/e'] = (('h', 'e', 'e-id'), [old_e[1][0],
1116
('r', 'b/d/e', 0, False, '')])
1120
new_state = dirstate.DirState.from_tree(tree, 'dirstate')
1127
return tree, state, expected
1129
1742
def assertBisect(self, expected_map, map_keys, state, paths):
1130
1743
"""Assert that bisecting for paths returns the right result.