rust/hg-core/src/dirstate_tree/dirstate_map.rs
changeset 49126 e7b74bb602a4
parent 49125 28a6178a07a2
child 49127 f3e8b0b0a8c2
equal deleted inserted replaced
49125:28a6178a07a2 49126:e7b74bb602a4
  1431             };
  1431             };
  1432             Ok(Some((node.full_path(map.on_disk)?, debug_tuple)))
  1432             Ok(Some((node.full_path(map.on_disk)?, debug_tuple)))
  1433         }))
  1433         }))
  1434     }
  1434     }
  1435 }
  1435 }
       
  1436 #[cfg(test)]
       
  1437 mod tests {
       
  1438     use super::*;
       
  1439 
       
  1440     /// Shortcut to return tracked descendants of a path.
       
  1441     /// Panics if the path does not exist.
       
  1442     fn tracked_descendants(map: &OwningDirstateMap, path: &[u8]) -> u32 {
       
  1443         let path = dbg!(HgPath::new(path));
       
  1444         let node = map.get_map().get_node(path);
       
  1445         node.unwrap().unwrap().tracked_descendants_count()
       
  1446     }
       
  1447 
       
  1448     /// Shortcut to return descendants with an entry.
       
  1449     /// Panics if the path does not exist.
       
  1450     fn descendants_with_an_entry(map: &OwningDirstateMap, path: &[u8]) -> u32 {
       
  1451         let path = dbg!(HgPath::new(path));
       
  1452         let node = map.get_map().get_node(path);
       
  1453         node.unwrap().unwrap().descendants_with_entry_count()
       
  1454     }
       
  1455 
       
  1456     fn assert_does_not_exist(map: &OwningDirstateMap, path: &[u8]) {
       
  1457         let path = dbg!(HgPath::new(path));
       
  1458         let node = map.get_map().get_node(path);
       
  1459         assert!(node.unwrap().is_none());
       
  1460     }
       
  1461 
       
  1462     /// Shortcut for path creation in tests
       
  1463     fn p(b: &[u8]) -> &HgPath {
       
  1464         HgPath::new(b)
       
  1465     }
       
  1466 
       
  1467     /// Test the very simple case a single tracked file
       
  1468     #[test]
       
  1469     fn test_tracked_descendants_simple() -> Result<(), DirstateError> {
       
  1470         let mut map = OwningDirstateMap::new_empty(vec![]);
       
  1471         assert_eq!(map.len(), 0);
       
  1472 
       
  1473         map.set_tracked(p(b"some/nested/path"))?;
       
  1474 
       
  1475         assert_eq!(map.len(), 1);
       
  1476         assert_eq!(tracked_descendants(&map, b"some"), 1);
       
  1477         assert_eq!(tracked_descendants(&map, b"some/nested"), 1);
       
  1478         assert_eq!(tracked_descendants(&map, b"some/nested/path"), 0);
       
  1479 
       
  1480         map.set_untracked(p(b"some/nested/path"))?;
       
  1481         assert_eq!(map.len(), 0);
       
  1482         assert!(map.get_map().get_node(p(b"some"))?.is_none());
       
  1483 
       
  1484         Ok(())
       
  1485     }
       
  1486 
       
  1487     /// Test the simple case of all tracked, but multiple files
       
  1488     #[test]
       
  1489     fn test_tracked_descendants_multiple() -> Result<(), DirstateError> {
       
  1490         let mut map = OwningDirstateMap::new_empty(vec![]);
       
  1491 
       
  1492         map.set_tracked(p(b"some/nested/path"))?;
       
  1493         map.set_tracked(p(b"some/nested/file"))?;
       
  1494         // one layer without any files to test deletion cascade
       
  1495         map.set_tracked(p(b"some/other/nested/path"))?;
       
  1496         map.set_tracked(p(b"root_file"))?;
       
  1497         map.set_tracked(p(b"some/file"))?;
       
  1498         map.set_tracked(p(b"some/file2"))?;
       
  1499         map.set_tracked(p(b"some/file3"))?;
       
  1500 
       
  1501         assert_eq!(map.len(), 7);
       
  1502         assert_eq!(tracked_descendants(&map, b"some"), 6);
       
  1503         assert_eq!(tracked_descendants(&map, b"some/nested"), 2);
       
  1504         assert_eq!(tracked_descendants(&map, b"some/other"), 1);
       
  1505         assert_eq!(tracked_descendants(&map, b"some/other/nested"), 1);
       
  1506         assert_eq!(tracked_descendants(&map, b"some/nested/path"), 0);
       
  1507 
       
  1508         map.set_untracked(p(b"some/nested/path"))?;
       
  1509         assert_eq!(map.len(), 6);
       
  1510         assert_eq!(tracked_descendants(&map, b"some"), 5);
       
  1511         assert_eq!(tracked_descendants(&map, b"some/nested"), 1);
       
  1512         assert_eq!(tracked_descendants(&map, b"some/other"), 1);
       
  1513         assert_eq!(tracked_descendants(&map, b"some/other/nested"), 1);
       
  1514 
       
  1515         map.set_untracked(p(b"some/nested/file"))?;
       
  1516         assert_eq!(map.len(), 5);
       
  1517         assert_eq!(tracked_descendants(&map, b"some"), 4);
       
  1518         assert_eq!(tracked_descendants(&map, b"some/other"), 1);
       
  1519         assert_eq!(tracked_descendants(&map, b"some/other/nested"), 1);
       
  1520         assert_does_not_exist(&map, b"some_nested");
       
  1521 
       
  1522         map.set_untracked(p(b"some/other/nested/path"))?;
       
  1523         assert_eq!(map.len(), 4);
       
  1524         assert_eq!(tracked_descendants(&map, b"some"), 3);
       
  1525         assert_does_not_exist(&map, b"some/other");
       
  1526 
       
  1527         map.set_untracked(p(b"root_file"))?;
       
  1528         assert_eq!(map.len(), 3);
       
  1529         assert_eq!(tracked_descendants(&map, b"some"), 3);
       
  1530         assert_does_not_exist(&map, b"root_file");
       
  1531 
       
  1532         map.set_untracked(p(b"some/file"))?;
       
  1533         assert_eq!(map.len(), 2);
       
  1534         assert_eq!(tracked_descendants(&map, b"some"), 2);
       
  1535         assert_does_not_exist(&map, b"some/file");
       
  1536 
       
  1537         map.set_untracked(p(b"some/file2"))?;
       
  1538         assert_eq!(map.len(), 1);
       
  1539         assert_eq!(tracked_descendants(&map, b"some"), 1);
       
  1540         assert_does_not_exist(&map, b"some/file2");
       
  1541 
       
  1542         map.set_untracked(p(b"some/file3"))?;
       
  1543         assert_eq!(map.len(), 0);
       
  1544         assert_does_not_exist(&map, b"some/file3");
       
  1545 
       
  1546         Ok(())
       
  1547     }
       
  1548 
       
  1549     /// Check with a mix of tracked and non-tracked items
       
  1550     #[test]
       
  1551     fn test_tracked_descendants_different() -> Result<(), DirstateError> {
       
  1552         let mut map = OwningDirstateMap::new_empty(vec![]);
       
  1553 
       
  1554         // A file that was just added
       
  1555         map.set_tracked(p(b"some/nested/path"))?;
       
  1556         // This has no information, the dirstate should ignore it
       
  1557         map.reset_state(p(b"some/file"), false, false, false, false, None)?;
       
  1558         assert_does_not_exist(&map, b"some/file");
       
  1559 
       
  1560         // A file that was removed
       
  1561         map.reset_state(
       
  1562             p(b"some/nested/file"),
       
  1563             false,
       
  1564             true,
       
  1565             false,
       
  1566             false,
       
  1567             None,
       
  1568         )?;
       
  1569         assert!(!map.get(p(b"some/nested/file"))?.unwrap().tracked());
       
  1570         // Only present in p2
       
  1571         map.reset_state(p(b"some/file3"), false, false, true, false, None)?;
       
  1572         assert!(!map.get(p(b"some/file3"))?.unwrap().tracked());
       
  1573         // A file that was merged
       
  1574         map.reset_state(p(b"root_file"), true, true, true, false, None)?;
       
  1575         assert!(map.get(p(b"root_file"))?.unwrap().tracked());
       
  1576         // A file that is added, with info from p2
       
  1577         // XXX is that actually possible?
       
  1578         map.reset_state(p(b"some/file2"), true, false, true, false, None)?;
       
  1579         assert!(map.get(p(b"some/file2"))?.unwrap().tracked());
       
  1580         // A clean file
       
  1581         // One layer without any files to test deletion cascade
       
  1582         map.reset_state(
       
  1583             p(b"some/other/nested/path"),
       
  1584             true,
       
  1585             true,
       
  1586             false,
       
  1587             false,
       
  1588             None,
       
  1589         )?;
       
  1590         assert!(map.get(p(b"some/other/nested/path"))?.unwrap().tracked());
       
  1591 
       
  1592         assert_eq!(map.len(), 6);
       
  1593         assert_eq!(tracked_descendants(&map, b"some"), 3);
       
  1594         assert_eq!(descendants_with_an_entry(&map, b"some"), 5);
       
  1595         assert_eq!(tracked_descendants(&map, b"some/other/nested"), 1);
       
  1596         assert_eq!(descendants_with_an_entry(&map, b"some/other/nested"), 1);
       
  1597         assert_eq!(tracked_descendants(&map, b"some/other/nested/path"), 0);
       
  1598         assert_eq!(
       
  1599             descendants_with_an_entry(&map, b"some/other/nested/path"),
       
  1600             0
       
  1601         );
       
  1602         assert_eq!(tracked_descendants(&map, b"some/nested"), 1);
       
  1603         assert_eq!(descendants_with_an_entry(&map, b"some/nested"), 2);
       
  1604 
       
  1605         // might as well check this
       
  1606         map.set_untracked(p(b"path/does/not/exist"))?;
       
  1607         assert_eq!(map.len(), 6);
       
  1608 
       
  1609         map.set_untracked(p(b"some/other/nested/path"))?;
       
  1610         // It is set untracked but not deleted since it held other information
       
  1611         assert_eq!(map.len(), 6);
       
  1612         assert_eq!(tracked_descendants(&map, b"some"), 2);
       
  1613         assert_eq!(descendants_with_an_entry(&map, b"some"), 5);
       
  1614         assert_eq!(descendants_with_an_entry(&map, b"some/other"), 1);
       
  1615         assert_eq!(descendants_with_an_entry(&map, b"some/other/nested"), 1);
       
  1616         assert_eq!(tracked_descendants(&map, b"some/nested"), 1);
       
  1617         assert_eq!(descendants_with_an_entry(&map, b"some/nested"), 2);
       
  1618 
       
  1619         map.set_untracked(p(b"some/nested/path"))?;
       
  1620         // It is set untracked *and* deleted since it was only added
       
  1621         assert_eq!(map.len(), 5);
       
  1622         assert_eq!(tracked_descendants(&map, b"some"), 1);
       
  1623         assert_eq!(descendants_with_an_entry(&map, b"some"), 4);
       
  1624         assert_eq!(tracked_descendants(&map, b"some/nested"), 0);
       
  1625         assert_eq!(descendants_with_an_entry(&map, b"some/nested"), 1);
       
  1626         assert_does_not_exist(&map, b"some/nested/path");
       
  1627 
       
  1628         map.set_untracked(p(b"root_file"))?;
       
  1629         // Untracked but not deleted
       
  1630         assert_eq!(map.len(), 5);
       
  1631         assert!(map.get(p(b"root_file"))?.is_some());
       
  1632 
       
  1633         map.set_untracked(p(b"some/file2"))?;
       
  1634         assert_eq!(map.len(), 5);
       
  1635         assert_eq!(tracked_descendants(&map, b"some"), 0);
       
  1636         assert!(map.get(p(b"some/file2"))?.is_some());
       
  1637 
       
  1638         map.set_untracked(p(b"some/file3"))?;
       
  1639         assert_eq!(map.len(), 5);
       
  1640         assert_eq!(tracked_descendants(&map, b"some"), 0);
       
  1641         assert!(map.get(p(b"some/file3"))?.is_some());
       
  1642 
       
  1643         Ok(())
       
  1644     }
       
  1645 
       
  1646     /// Check that copies counter is correctly updated
       
  1647     #[test]
       
  1648     fn test_copy_source() -> Result<(), DirstateError> {
       
  1649         let mut map = OwningDirstateMap::new_empty(vec![]);
       
  1650 
       
  1651         // Clean file
       
  1652         map.reset_state(p(b"files/clean"), true, true, false, false, None)?;
       
  1653         // Merged file
       
  1654         map.reset_state(p(b"files/from_p2"), true, true, true, false, None)?;
       
  1655         // Removed file
       
  1656         map.reset_state(p(b"removed"), false, true, false, false, None)?;
       
  1657         // Added file
       
  1658         map.reset_state(p(b"files/added"), true, false, false, false, None)?;
       
  1659         // Add copy
       
  1660         map.copy_map_insert(p(b"files/clean"), p(b"clean_copy_source"))?;
       
  1661         assert_eq!(map.copy_map_len(), 1);
       
  1662 
       
  1663         // Copy override
       
  1664         map.copy_map_insert(p(b"files/clean"), p(b"other_clean_copy_source"))?;
       
  1665         assert_eq!(map.copy_map_len(), 1);
       
  1666 
       
  1667         // Multiple copies
       
  1668         map.copy_map_insert(p(b"removed"), p(b"removed_copy_source"))?;
       
  1669         assert_eq!(map.copy_map_len(), 2);
       
  1670 
       
  1671         map.copy_map_insert(p(b"files/added"), p(b"added_copy_source"))?;
       
  1672         assert_eq!(map.copy_map_len(), 3);
       
  1673 
       
  1674         // Added, so the entry is completely removed
       
  1675         map.set_untracked(p(b"files/added"))?;
       
  1676         assert_does_not_exist(&map, b"files/added");
       
  1677         assert_eq!(map.copy_map_len(), 2);
       
  1678 
       
  1679         // Removed, so the entry is kept around, so is its copy
       
  1680         map.set_untracked(p(b"removed"))?;
       
  1681         assert!(map.get(p(b"removed"))?.is_some());
       
  1682         assert_eq!(map.copy_map_len(), 2);
       
  1683 
       
  1684         // Clean, so the entry is kept around, but not its copy
       
  1685         map.set_untracked(p(b"files/clean"))?;
       
  1686         assert!(map.get(p(b"files/clean"))?.is_some());
       
  1687         assert_eq!(map.copy_map_len(), 1);
       
  1688 
       
  1689         map.copy_map_insert(p(b"files/from_p2"), p(b"from_p2_copy_source"))?;
       
  1690         assert_eq!(map.copy_map_len(), 2);
       
  1691 
       
  1692         // Info from p2, so its copy source info is kept around
       
  1693         map.set_untracked(p(b"files/from_p2"))?;
       
  1694         assert!(map.get(p(b"files/from_p2"))?.is_some());
       
  1695         assert_eq!(map.copy_map_len(), 2);
       
  1696 
       
  1697         Ok(())
       
  1698     }
       
  1699 
       
  1700     /// Test with "on disk" data. For the sake of this test, the "on disk" data
       
  1701     /// does not actually come from the disk, but it's opaque to the code being
       
  1702     /// tested.
       
  1703     #[test]
       
  1704     fn test_on_disk() -> Result<(), DirstateError> {
       
  1705         // First let's create some data to put "on disk"
       
  1706         let mut map = OwningDirstateMap::new_empty(vec![]);
       
  1707 
       
  1708         // A file that was just added
       
  1709         map.set_tracked(p(b"some/nested/added"))?;
       
  1710         map.copy_map_insert(p(b"some/nested/added"), p(b"added_copy_source"))?;
       
  1711 
       
  1712         // A file that was removed
       
  1713         map.reset_state(
       
  1714             p(b"some/nested/removed"),
       
  1715             false,
       
  1716             true,
       
  1717             false,
       
  1718             false,
       
  1719             None,
       
  1720         )?;
       
  1721         // Only present in p2
       
  1722         map.reset_state(
       
  1723             p(b"other/p2_info_only"),
       
  1724             false,
       
  1725             false,
       
  1726             true,
       
  1727             false,
       
  1728             None,
       
  1729         )?;
       
  1730         map.copy_map_insert(
       
  1731             p(b"other/p2_info_only"),
       
  1732             p(b"other/p2_info_copy_source"),
       
  1733         )?;
       
  1734         // A file that was merged
       
  1735         map.reset_state(p(b"merged"), true, true, true, false, None)?;
       
  1736         // A file that is added, with info from p2
       
  1737         // XXX is that actually possible?
       
  1738         map.reset_state(
       
  1739             p(b"other/added_with_p2"),
       
  1740             true,
       
  1741             false,
       
  1742             true,
       
  1743             false,
       
  1744             None,
       
  1745         )?;
       
  1746         // One layer without any files to test deletion cascade
       
  1747         // A clean file
       
  1748         map.reset_state(
       
  1749             p(b"some/other/nested/clean"),
       
  1750             true,
       
  1751             true,
       
  1752             false,
       
  1753             false,
       
  1754             None,
       
  1755         )?;
       
  1756 
       
  1757         let (packed, metadata, _should_append) = map.pack_v2(false)?;
       
  1758         let packed_len = packed.len();
       
  1759         assert!(packed_len > 0);
       
  1760 
       
  1761         // Recreate "from disk"
       
  1762         let mut map = OwningDirstateMap::new_v2(
       
  1763             packed,
       
  1764             packed_len,
       
  1765             metadata.as_bytes(),
       
  1766         )?;
       
  1767 
       
  1768         // Check that everything is accounted for
       
  1769         assert!(map.contains_key(p(b"some/nested/added"))?);
       
  1770         assert!(map.contains_key(p(b"some/nested/removed"))?);
       
  1771         assert!(map.contains_key(p(b"merged"))?);
       
  1772         assert!(map.contains_key(p(b"other/p2_info_only"))?);
       
  1773         assert!(map.contains_key(p(b"other/added_with_p2"))?);
       
  1774         assert!(map.contains_key(p(b"some/other/nested/clean"))?);
       
  1775         assert_eq!(
       
  1776             map.copy_map_get(p(b"some/nested/added"))?,
       
  1777             Some(p(b"added_copy_source"))
       
  1778         );
       
  1779         assert_eq!(
       
  1780             map.copy_map_get(p(b"other/p2_info_only"))?,
       
  1781             Some(p(b"other/p2_info_copy_source"))
       
  1782         );
       
  1783         assert_eq!(tracked_descendants(&map, b"some"), 2);
       
  1784         assert_eq!(descendants_with_an_entry(&map, b"some"), 3);
       
  1785         assert_eq!(tracked_descendants(&map, b"other"), 1);
       
  1786         assert_eq!(descendants_with_an_entry(&map, b"other"), 2);
       
  1787         assert_eq!(tracked_descendants(&map, b"some/other"), 1);
       
  1788         assert_eq!(descendants_with_an_entry(&map, b"some/other"), 1);
       
  1789         assert_eq!(tracked_descendants(&map, b"some/other/nested"), 1);
       
  1790         assert_eq!(descendants_with_an_entry(&map, b"some/other/nested"), 1);
       
  1791         assert_eq!(tracked_descendants(&map, b"some/nested"), 1);
       
  1792         assert_eq!(descendants_with_an_entry(&map, b"some/nested"), 2);
       
  1793         assert_eq!(map.len(), 6);
       
  1794         assert_eq!(map.get_map().unreachable_bytes, 0);
       
  1795         assert_eq!(map.copy_map_len(), 2);
       
  1796 
       
  1797         // Shouldn't change anything since it's already not tracked
       
  1798         map.set_untracked(p(b"some/nested/removed"))?;
       
  1799         assert_eq!(map.get_map().unreachable_bytes, 0);
       
  1800 
       
  1801         match map.get_map().root {
       
  1802             ChildNodes::InMemory(_) => {
       
  1803                 panic!("root should not have been mutated")
       
  1804             }
       
  1805             _ => (),
       
  1806         }
       
  1807         // We haven't mutated enough (nothing, actually), we should still be in
       
  1808         // the append strategy
       
  1809         assert!(map.get_map().write_should_append());
       
  1810 
       
  1811         // But this mutates the structure, so there should be unreachable_bytes
       
  1812         assert!(map.set_untracked(p(b"some/nested/added"))?);
       
  1813         let unreachable_bytes = map.get_map().unreachable_bytes;
       
  1814         assert!(unreachable_bytes > 0);
       
  1815 
       
  1816         match map.get_map().root {
       
  1817             ChildNodes::OnDisk(_) => panic!("root should have been mutated"),
       
  1818             _ => (),
       
  1819         }
       
  1820 
       
  1821         // This should not mutate the structure either, since `root` has
       
  1822         // already been mutated along with its direct children.
       
  1823         map.set_untracked(p(b"merged"))?;
       
  1824         assert_eq!(map.get_map().unreachable_bytes, unreachable_bytes);
       
  1825 
       
  1826         match map.get_map().get_node(p(b"other/added_with_p2"))?.unwrap() {
       
  1827             NodeRef::InMemory(_, _) => {
       
  1828                 panic!("'other/added_with_p2' should not have been mutated")
       
  1829             }
       
  1830             _ => (),
       
  1831         }
       
  1832         // But this should, since it's in a different path
       
  1833         // than `<root>some/nested/add`
       
  1834         map.set_untracked(p(b"other/added_with_p2"))?;
       
  1835         assert!(map.get_map().unreachable_bytes > unreachable_bytes);
       
  1836 
       
  1837         match map.get_map().get_node(p(b"other/added_with_p2"))?.unwrap() {
       
  1838             NodeRef::OnDisk(_) => {
       
  1839                 panic!("'other/added_with_p2' should have been mutated")
       
  1840             }
       
  1841             _ => (),
       
  1842         }
       
  1843 
       
  1844         // We have rewritten most of the tree, we should create a new file
       
  1845         assert!(!map.get_map().write_should_append());
       
  1846 
       
  1847         Ok(())
       
  1848     }
       
  1849 }