@@ -210,26 +210,6 @@ pub fn find_struct_by_name_in_all_files(
210210 return Some ( ( metadata. clone ( ) , module_path) ) ;
211211 }
212212
213- // Fallback: contains-match disambiguation
214- if found_in_candidates. len ( ) > 1 {
215- let matching: Vec < _ > = found_in_candidates
216- . into_iter ( )
217- . filter ( |( path, _) | {
218- path. file_stem ( )
219- . and_then ( |s| s. to_str ( ) )
220- . is_some_and ( |name| {
221- normalize_name ( name) . contains ( prefix_normalized. as_str ( ) )
222- } )
223- } )
224- . collect ( ) ;
225-
226- if matching. len ( ) == 1 {
227- let ( path, metadata) = matching. into_iter ( ) . next ( ) . unwrap ( ) ;
228- let module_path = file_path_to_module_path ( & path, src_dir) ;
229- return Some ( ( metadata, module_path) ) ;
230- }
231- }
232-
233213 // Still ambiguous among candidates
234214 return None ;
235215 }
@@ -262,52 +242,12 @@ pub fn find_struct_by_name_in_all_files(
262242 }
263243
264244 match found_structs. len ( ) {
265- 0 => None ,
266245 1 => {
267246 let ( path, metadata) = found_structs. remove ( 0 ) ;
268247 let module_path = file_path_to_module_path ( & path, src_dir) ;
269248 Some ( ( metadata, module_path) )
270249 }
271- _ => {
272- // Multiple matches without hint (or hint didn't match candidates above).
273- // Re-use hint disambiguation logic for full-scan results.
274- if let Some ( prefix_normalized) = & prefix_normalized {
275- let exact_match: Vec < _ > = found_structs
276- . iter ( )
277- . filter ( |( path, _) | {
278- path. file_stem ( )
279- . and_then ( |s| s. to_str ( ) )
280- . is_some_and ( |name| normalize_name ( name) == * prefix_normalized)
281- } )
282- . collect ( ) ;
283-
284- if exact_match. len ( ) == 1 {
285- let ( path, metadata) = exact_match[ 0 ] ;
286- let module_path = file_path_to_module_path ( path, src_dir) ;
287- return Some ( ( metadata. clone ( ) , module_path) ) ;
288- }
289-
290- let matching: Vec < _ > = found_structs
291- . into_iter ( )
292- . filter ( |( path, _) | {
293- path. file_stem ( )
294- . and_then ( |s| s. to_str ( ) )
295- . is_some_and ( |name| {
296- normalize_name ( name) . contains ( prefix_normalized. as_str ( ) )
297- } )
298- } )
299- . collect ( ) ;
300-
301- if matching. len ( ) == 1 {
302- let ( path, metadata) = matching. into_iter ( ) . next ( ) . unwrap ( ) ;
303- let module_path = file_path_to_module_path ( & path, src_dir) ;
304- return Some ( ( metadata, module_path) ) ;
305- }
306- }
307-
308- // Still ambiguous
309- None
310- }
250+ _ => None ,
311251 }
312252}
313253
@@ -1516,4 +1456,114 @@ pub struct Model {
15161456 "Field without 'from' attribute should return None"
15171457 ) ;
15181458 }
1459+
1460+ // ============================================================
1461+ // Coverage tests for find_struct_by_name_in_all_files (candidate/rest paths)
1462+ // ============================================================
1463+
1464+ #[ test]
1465+ #[ serial]
1466+ fn test_find_struct_candidate_unparseable_file ( ) {
1467+ // Tests line 145: candidate file fails to parse -> continue to next candidate
1468+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
1469+ let src_dir = temp_dir. path ( ) ;
1470+
1471+ // user.rs matches hint prefix "user" (candidate), contains "Model" text, but won't parse
1472+ std:: fs:: write (
1473+ src_dir. join ( "user.rs" ) ,
1474+ "pub struct Model {{{{ broken syntax" ,
1475+ )
1476+ . unwrap ( ) ;
1477+
1478+ // valid.rs contains Model and parses fine (goes to rest since filename doesn't match prefix)
1479+ std:: fs:: write ( src_dir. join ( "valid.rs" ) , "pub struct Model { pub id: i32 }" ) . unwrap ( ) ;
1480+
1481+ let result = find_struct_by_name_in_all_files ( src_dir, "Model" , Some ( "UserSchema" ) ) ;
1482+
1483+ assert ! (
1484+ result. is_some( ) ,
1485+ "Should find Model in valid.rs after skipping unparseable candidate user.rs"
1486+ ) ;
1487+ }
1488+
1489+ #[ test]
1490+ #[ serial]
1491+ fn test_find_struct_exact_filename_disambiguation ( ) {
1492+ // Tests lines 168-170: multiple candidates found, exact filename match disambiguates
1493+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
1494+ let src_dir = temp_dir. path ( ) ;
1495+
1496+ // user.rs: exact match (normalize_name("user") == prefix "user")
1497+ std:: fs:: write ( src_dir. join ( "user.rs" ) , "pub struct Model { pub id: i32 }" ) . unwrap ( ) ;
1498+
1499+ // user_extended.rs: contains-match only (normalize_name("user_extended") = "userextended" != "user")
1500+ std:: fs:: write (
1501+ src_dir. join ( "user_extended.rs" ) ,
1502+ "pub struct Model { pub name: String }" ,
1503+ )
1504+ . unwrap ( ) ;
1505+
1506+ let result = find_struct_by_name_in_all_files ( src_dir, "Model" , Some ( "UserSchema" ) ) ;
1507+
1508+ assert ! ( result. is_some( ) , "Should resolve via exact filename match" ) ;
1509+ let ( metadata, _) = result. unwrap ( ) ;
1510+ assert ! (
1511+ metadata. definition. contains( "id" ) ,
1512+ "Should return user.rs Model (with id field)"
1513+ ) ;
1514+ }
1515+
1516+ #[ test]
1517+ #[ serial]
1518+ fn test_find_struct_no_match_in_candidates_falls_to_rest ( ) {
1519+ // Tests line 189: candidates have no struct match -> rs_files = rest -> full scan finds it
1520+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
1521+ let src_dir = temp_dir. path ( ) ;
1522+
1523+ // user.rs is a candidate (filename matches "user" prefix) but has no struct Model
1524+ // Must contain "Model" text for get_struct_candidates to include it
1525+ std:: fs:: write (
1526+ src_dir. join ( "user.rs" ) ,
1527+ "pub struct Other { pub x: i32 } // Model ref" ,
1528+ )
1529+ . unwrap ( ) ;
1530+
1531+ // data.rs is in rest (filename "data" doesn't contain "user"), has struct Model
1532+ std:: fs:: write ( src_dir. join ( "data.rs" ) , "pub struct Model { pub id: i32 }" ) . unwrap ( ) ;
1533+
1534+ let result = find_struct_by_name_in_all_files ( src_dir, "Model" , Some ( "UserSchema" ) ) ;
1535+
1536+ assert ! (
1537+ result. is_some( ) ,
1538+ "Should find Model in data.rs after candidates had no match"
1539+ ) ;
1540+ }
1541+
1542+ #[ test]
1543+ #[ serial]
1544+ fn test_find_struct_full_scan_unparseable_file ( ) {
1545+ // Tests line 197: full-scan file fails to parse -> continue to next file
1546+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
1547+ let src_dir = temp_dir. path ( ) ;
1548+
1549+ // user.rs is candidate but no struct Model
1550+ std:: fs:: write (
1551+ src_dir. join ( "user.rs" ) ,
1552+ "pub struct Other { pub x: i32 } // Model" ,
1553+ )
1554+ . unwrap ( ) ;
1555+
1556+ // broken.rs is rest, contains "Model" text but won't parse
1557+ std:: fs:: write ( src_dir. join ( "broken.rs" ) , "Model unparseable {{{{{" ) . unwrap ( ) ;
1558+
1559+ // valid.rs is rest, has struct Model
1560+ std:: fs:: write ( src_dir. join ( "valid.rs" ) , "pub struct Model { pub id: i32 }" ) . unwrap ( ) ;
1561+
1562+ let result = find_struct_by_name_in_all_files ( src_dir, "Model" , Some ( "UserSchema" ) ) ;
1563+
1564+ assert ! (
1565+ result. is_some( ) ,
1566+ "Should find Model in valid.rs after skipping unparseable broken.rs in rest"
1567+ ) ;
1568+ }
15191569}
0 commit comments