@@ -1513,4 +1513,155 @@ pub(crate) mod tests {
15131513 "Compiler must catch infinite alias cycles"
15141514 ) ;
15151515 }
1516+
1517+ // --- C3 Error Display Tests ---
1518+
1519+ #[ test]
1520+ fn display_c3_cycle_detected ( ) {
1521+ let cycle = vec ! [
1522+ "main.simf" . to_string( ) ,
1523+ "libs/lib/A.simf" . to_string( ) ,
1524+ "libs/lib/B.simf" . to_string( ) ,
1525+ "main.simf" . to_string( ) ,
1526+ ] ;
1527+
1528+ let error = C3Error :: CycleDetected ( cycle) ;
1529+
1530+ let expected = r#"Circular dependency detected: "main.simf -> libs/lib/A.simf -> libs/lib/B.simf -> main.simf""# ;
1531+
1532+ assert_eq ! ( error. to_string( ) , expected) ;
1533+ }
1534+
1535+ #[ test]
1536+ fn display_c3_inconsistent_linearization ( ) {
1537+ let conflicts = vec ! [
1538+ vec![ "lib/x" . to_string( ) , "lib/y" . to_string( ) ] ,
1539+ vec![ "lib/y" . to_string( ) , "lib/x" . to_string( ) ] ,
1540+ ] ;
1541+
1542+ let error = C3Error :: InconsistentLinearization {
1543+ module : "main" . to_string ( ) ,
1544+ conflicts,
1545+ } ;
1546+
1547+ let expected = r#"Inconsistent resolution order for module 'main'
1548+ The compiler could not resolve the following conflicting import constraints:
1549+ [lib/x, lib/y]
1550+ [lib/y, lib/x]
1551+ Try reordering your `use` statements to avoid cross-wiring."#
1552+ . to_string ( ) ;
1553+
1554+ assert_eq ! ( error. to_string( ) , expected) ;
1555+ }
1556+
1557+ // --- Dependent File Error Display Tests ---
1558+
1559+ #[ test]
1560+ fn test_display_error_in_imported_dependency ( ) {
1561+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
1562+ let root_path = create_simf_file ( temp_dir. path ( ) , "main.simf" , "use lib::math::add;" ) ;
1563+
1564+ create_simf_file (
1565+ temp_dir. path ( ) ,
1566+ "libs/lib/math.simf" ,
1567+ "pub fn add(a: u32 b: u32) {}" ,
1568+ ) ;
1569+
1570+ let mut lib_map = HashMap :: new ( ) ;
1571+ lib_map. insert ( "lib" . to_string ( ) , temp_dir. path ( ) . join ( "libs/lib" ) ) ;
1572+
1573+ let ( root_program, root_source) = parse_root ( & root_path) ;
1574+ let mut handler = ErrorCollector :: new ( ) ;
1575+
1576+ let result =
1577+ ProjectGraph :: new ( root_source, Arc :: from ( lib_map) , & root_program, & mut handler) ;
1578+
1579+ assert ! (
1580+ result. is_none( ) ,
1581+ "Graph construction should fail due to syntax error in dependency"
1582+ ) ;
1583+ assert ! (
1584+ handler. has_errors( ) ,
1585+ "Handler should contain the imported module's error"
1586+ ) ;
1587+
1588+ let err_msg = ErrorCollector :: to_string ( & handler) ;
1589+
1590+ assert ! (
1591+ err_msg. contains( "math:1" ) ,
1592+ "Error should correctly display the file name (without .simf) and line number. Got:\n {}" ,
1593+ err_msg
1594+ ) ;
1595+ assert ! (
1596+ err_msg. contains( "pub fn add(a: u32 b: u32) {}" ) ,
1597+ "Error should print the snippet from the imported file. Got:\n {}" ,
1598+ err_msg
1599+ ) ;
1600+ }
1601+
1602+ #[ test]
1603+ fn test_display_unresolved_item_in_dependency ( ) {
1604+ let ( graph, ids, _dir) = setup_graph ( vec ! [
1605+ ( "libs/lib/B.simf" , "pub fn real() {}" ) ,
1606+ ( "libs/lib/A.simf" , "use lib::B::ghost;\n pub fn foo() {}" ) ,
1607+ ( "main.simf" , "use lib::A::foo;" ) ,
1608+ ] ) ;
1609+
1610+ let id_a = * ids. get ( "A" ) . unwrap ( ) ;
1611+ let id_b = * ids. get ( "B" ) . unwrap ( ) ;
1612+ let id_root = * ids. get ( "main" ) . unwrap ( ) ;
1613+ let order = vec ! [ id_b, id_a, id_root] ;
1614+
1615+ let mut handler = ErrorCollector :: new ( ) ;
1616+ let _ = graph. build_program ( & order, & mut handler) ;
1617+
1618+ let err_msg = ErrorCollector :: to_string ( & handler) ;
1619+
1620+ assert ! (
1621+ err_msg. contains( "A:1" ) ,
1622+ "Error should point to A (without .simf) where the bad import happened. Got:\n {}" ,
1623+ err_msg
1624+ ) ;
1625+ assert ! (
1626+ err_msg. contains( "use lib::B::ghost;" ) ,
1627+ "Error should print the snippet from A.simf"
1628+ ) ;
1629+ assert ! (
1630+ err_msg. contains( "Unknown item `ghost`" ) ,
1631+ "Error should correctly identify the missing item"
1632+ ) ;
1633+ }
1634+
1635+ #[ test]
1636+ fn test_display_private_item_access_in_dependency ( ) {
1637+ let ( graph, ids, _dir) = setup_graph ( vec ! [
1638+ ( "libs/lib/B.simf" , "fn secret() {}" ) ,
1639+ ( "libs/lib/A.simf" , "use lib::B::secret;\n pub fn foo() {}" ) ,
1640+ ( "main.simf" , "use lib::A::foo;" ) ,
1641+ ] ) ;
1642+
1643+ let id_a = * ids. get ( "A" ) . unwrap ( ) ;
1644+ let id_b = * ids. get ( "B" ) . unwrap ( ) ;
1645+ let id_root = * ids. get ( "main" ) . unwrap ( ) ;
1646+ let order = vec ! [ id_b, id_a, id_root] ;
1647+
1648+ let mut handler = ErrorCollector :: new ( ) ;
1649+ let _ = graph. build_program ( & order, & mut handler) ;
1650+
1651+ let err_msg = ErrorCollector :: to_string ( & handler) ;
1652+
1653+ assert ! (
1654+ err_msg. contains( "A:1" ) ,
1655+ "Error should point to A (without .simf) where the privacy violation happened. Got:\n {}" ,
1656+ err_msg
1657+ ) ;
1658+ assert ! (
1659+ err_msg. contains( "use lib::B::secret;" ) ,
1660+ "Error should print the snippet from A.simf"
1661+ ) ;
1662+ assert ! (
1663+ err_msg. contains( "Item `secret` is private" ) ,
1664+ "Error should correctly identify the privacy violation"
1665+ ) ;
1666+ }
15161667}
0 commit comments