1435
class TestIterChildEntries(TestCaseWithDirState):
1437
def create_dirstate_with_two_trees(self):
1438
"""This dirstate contains multiple files and directories.
1448
b/h\xc3\xa5 h-\xc3\xa5-file #This is u'\xe5' encoded into utf-8
1450
Notice that a/e is an empty directory.
1452
There is one parent tree, which has the same shape with the following variations:
1453
b/g in the parent is gone.
1454
b/h in the parent has a different id
1455
b/i is new in the parent
1456
c is renamed to b/j in the parent
1458
:return: The dirstate, still write-locked.
1460
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
1461
null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
1462
NULL_PARENT_DETAILS = dirstate.DirState.NULL_PARENT_DETAILS
1463
root_entry = ('', '', 'a-root-value'), [
1464
('d', '', 0, False, packed_stat),
1465
('d', '', 0, False, 'parent-revid'),
1467
a_entry = ('', 'a', 'a-dir'), [
1468
('d', '', 0, False, packed_stat),
1469
('d', '', 0, False, 'parent-revid'),
1471
b_entry = ('', 'b', 'b-dir'), [
1472
('d', '', 0, False, packed_stat),
1473
('d', '', 0, False, 'parent-revid'),
1475
c_entry = ('', 'c', 'c-file'), [
1476
('f', null_sha, 10, False, packed_stat),
1477
('r', 'b/j', 0, False, ''),
1479
d_entry = ('', 'd', 'd-file'), [
1480
('f', null_sha, 20, False, packed_stat),
1481
('f', 'd', 20, False, 'parent-revid'),
1483
e_entry = ('a', 'e', 'e-dir'), [
1484
('d', '', 0, False, packed_stat),
1485
('d', '', 0, False, 'parent-revid'),
1487
f_entry = ('a', 'f', 'f-file'), [
1488
('f', null_sha, 30, False, packed_stat),
1489
('f', 'f', 20, False, 'parent-revid'),
1491
g_entry = ('b', 'g', 'g-file'), [
1492
('f', null_sha, 30, False, packed_stat),
1493
NULL_PARENT_DETAILS,
1495
h_entry1 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file1'), [
1496
('f', null_sha, 40, False, packed_stat),
1497
NULL_PARENT_DETAILS,
1499
h_entry2 = ('b', 'h\xc3\xa5', 'h-\xc3\xa5-file2'), [
1500
NULL_PARENT_DETAILS,
1501
('f', 'h', 20, False, 'parent-revid'),
1503
i_entry = ('b', 'i', 'i-file'), [
1504
NULL_PARENT_DETAILS,
1505
('f', 'h', 20, False, 'parent-revid'),
1507
j_entry = ('b', 'j', 'c-file'), [
1508
('r', 'c', 0, False, ''),
1509
('f', 'j', 20, False, 'parent-revid'),
1512
dirblocks.append(('', [root_entry]))
1513
dirblocks.append(('', [a_entry, b_entry, c_entry, d_entry]))
1514
dirblocks.append(('a', [e_entry, f_entry]))
1515
dirblocks.append(('b', [g_entry, h_entry1, h_entry2, i_entry, j_entry]))
1516
state = dirstate.DirState.initialize('dirstate')
1519
state._set_data(['parent'], dirblocks)
1523
return state, dirblocks
1525
def test_iter_children_b(self):
1526
state, dirblocks = self.create_dirstate_with_two_trees()
1527
self.addCleanup(state.unlock)
1528
expected_result = []
1529
expected_result.append(dirblocks[3][1][2]) # h2
1530
expected_result.append(dirblocks[3][1][3]) # i
1531
expected_result.append(dirblocks[3][1][4]) # j
1532
self.assertEqual(expected_result,
1533
list(state._iter_child_entries(1, 'b')))
1535
def test_iter_child_root(self):
1536
state, dirblocks = self.create_dirstate_with_two_trees()
1537
self.addCleanup(state.unlock)
1538
expected_result = []
1539
expected_result.append(dirblocks[1][1][0]) # a
1540
expected_result.append(dirblocks[1][1][1]) # b
1541
expected_result.append(dirblocks[1][1][3]) # d
1542
expected_result.append(dirblocks[2][1][0]) # e
1543
expected_result.append(dirblocks[2][1][1]) # f
1544
expected_result.append(dirblocks[3][1][2]) # h2
1545
expected_result.append(dirblocks[3][1][3]) # i
1546
expected_result.append(dirblocks[3][1][4]) # j
1547
self.assertEqual(expected_result,
1548
list(state._iter_child_entries(1, '')))
1551
1395
class TestDirstateSortOrder(TestCaseWithTransport):
1552
1396
"""Test that DirState adds entries in the right order."""
2350
2195
self.assertEqual(expected, state._find_block(key))
2355
class TestDiscardMergeParents(TestCaseWithDirState):
2357
def test_discard_no_parents(self):
2358
# This should be a no-op
2359
state = self.create_empty_dirstate()
2360
self.addCleanup(state.unlock)
2361
state._discard_merge_parents()
2364
def test_discard_one_parent(self):
2366
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2367
root_entry_direntry = ('', '', 'a-root-value'), [
2368
('d', '', 0, False, packed_stat),
2369
('d', '', 0, False, packed_stat),
2372
dirblocks.append(('', [root_entry_direntry]))
2373
dirblocks.append(('', []))
2375
state = self.create_empty_dirstate()
2376
self.addCleanup(state.unlock)
2377
state._set_data(['parent-id'], dirblocks[:])
2380
state._discard_merge_parents()
2382
self.assertEqual(dirblocks, state._dirblocks)
2384
def test_discard_simple(self):
2386
packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
2387
root_entry_direntry = ('', '', 'a-root-value'), [
2388
('d', '', 0, False, packed_stat),
2389
('d', '', 0, False, packed_stat),
2390
('d', '', 0, False, packed_stat),
2392
expected_root_entry_direntry = ('', '', 'a-root-value'), [
2393
('d', '', 0, False, packed_stat),
2394
('d', '', 0, False, packed_stat),
2397
dirblocks.append(('', [root_entry_direntry]))
2398
dirblocks.append(('', []))
2400
state = self.create_empty_dirstate()
2401
self.addCleanup(state.unlock)
2402
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2405
# This should strip of the extra column
2406
state._discard_merge_parents()
2408
expected_dirblocks = [('', [expected_root_entry_direntry]), ('', [])]
2409
self.assertEqual(expected_dirblocks, state._dirblocks)
2411
def test_discard_absent(self):
2412
"""If entries are only in a merge, discard should remove the entries"""
2413
null_stat = dirstate.DirState.NULLSTAT
2414
present_dir = ('d', '', 0, False, null_stat)
2415
present_file = ('f', '', 0, False, null_stat)
2416
absent = dirstate.DirState.NULL_PARENT_DETAILS
2417
root_key = ('', '', 'a-root-value')
2418
file_in_root_key = ('', 'file-in-root', 'a-file-id')
2419
file_in_merged_key = ('', 'file-in-merged', 'b-file-id')
2420
dirblocks = [('', [(root_key, [present_dir, present_dir, present_dir])]),
2421
('', [(file_in_merged_key,
2422
[absent, absent, present_file]),
2424
[present_file, present_file, present_file]),
2428
state = self.create_empty_dirstate()
2429
self.addCleanup(state.unlock)
2430
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2433
exp_dirblocks = [('', [(root_key, [present_dir, present_dir])]),
2434
('', [(file_in_root_key,
2435
[present_file, present_file]),
2438
state._discard_merge_parents()
2440
self.assertEqual(exp_dirblocks, state._dirblocks)
2442
def test_discard_renamed(self):
2443
null_stat = dirstate.DirState.NULLSTAT
2444
present_dir = ('d', '', 0, False, null_stat)
2445
present_file = ('f', '', 0, False, null_stat)
2446
absent = dirstate.DirState.NULL_PARENT_DETAILS
2447
root_key = ('', '', 'a-root-value')
2448
file_in_root_key = ('', 'file-in-root', 'a-file-id')
2449
# Renamed relative to parent
2450
file_rename_s_key = ('', 'file-s', 'b-file-id')
2451
file_rename_t_key = ('', 'file-t', 'b-file-id')
2452
# And one that is renamed between the parents, but absent in this
2453
key_in_1 = ('', 'file-in-1', 'c-file-id')
2454
key_in_2 = ('', 'file-in-2', 'c-file-id')
2457
('', [(root_key, [present_dir, present_dir, present_dir])]),
2459
[absent, present_file, ('r', 'file-in-2', 'c-file-id')]),
2461
[absent, ('r', 'file-in-1', 'c-file-id'), present_file]),
2463
[present_file, present_file, present_file]),
2465
[('r', 'file-t', 'b-file-id'), absent, present_file]),
2467
[present_file, absent, ('r', 'file-s', 'b-file-id')]),
2471
('', [(root_key, [present_dir, present_dir])]),
2472
('', [(key_in_1, [absent, present_file]),
2473
(file_in_root_key, [present_file, present_file]),
2474
(file_rename_t_key, [present_file, absent]),
2477
state = self.create_empty_dirstate()
2478
self.addCleanup(state.unlock)
2479
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2482
state._discard_merge_parents()
2484
self.assertEqual(exp_dirblocks, state._dirblocks)
2486
def test_discard_all_subdir(self):
2487
null_stat = dirstate.DirState.NULLSTAT
2488
present_dir = ('d', '', 0, False, null_stat)
2489
present_file = ('f', '', 0, False, null_stat)
2490
absent = dirstate.DirState.NULL_PARENT_DETAILS
2491
root_key = ('', '', 'a-root-value')
2492
subdir_key = ('', 'sub', 'dir-id')
2493
child1_key = ('sub', 'child1', 'child1-id')
2494
child2_key = ('sub', 'child2', 'child2-id')
2495
child3_key = ('sub', 'child3', 'child3-id')
2498
('', [(root_key, [present_dir, present_dir, present_dir])]),
2499
('', [(subdir_key, [present_dir, present_dir, present_dir])]),
2500
('sub', [(child1_key, [absent, absent, present_file]),
2501
(child2_key, [absent, absent, present_file]),
2502
(child3_key, [absent, absent, present_file]),
2506
('', [(root_key, [present_dir, present_dir])]),
2507
('', [(subdir_key, [present_dir, present_dir])]),
2510
state = self.create_empty_dirstate()
2511
self.addCleanup(state.unlock)
2512
state._set_data(['parent-id', 'merged-id'], dirblocks[:])
2515
state._discard_merge_parents()
2517
self.assertEqual(exp_dirblocks, state._dirblocks)
2520
class Test_InvEntryToDetails(TestCaseWithDirState):
2522
def assertDetails(self, expected, inv_entry):
2523
details = dirstate.DirState._inv_entry_to_details(inv_entry)
2524
self.assertEqual(expected, details)
2525
# details should always allow join() and always be a plain str when
2527
(minikind, fingerprint, size, executable, tree_data) = details
2528
self.assertIsInstance(minikind, str)
2529
self.assertIsInstance(fingerprint, str)
2530
self.assertIsInstance(tree_data, str)
2532
def test_unicode_symlink(self):
2533
# In general, the code base doesn't support a target that contains
2534
# non-ascii characters. So we just assert tha
2535
inv_entry = inventory.InventoryLink('link-file-id', 'name',
2537
inv_entry.revision = 'link-revision-id'
2538
inv_entry.symlink_target = u'link-target'
2539
details = self.assertDetails(('l', 'link-target', 0, False,
2540
'link-revision-id'), inv_entry)