@@ -16,7 +16,7 @@ use walkdir::WalkDir;
1616use crate :: zccache:: FingerprintWatch ;
1717
1818pub const BUILD_FINGERPRINT_VERSION : u32 = 2 ;
19- const WATCH_STAMP_CACHE_VERSION : u32 = 1 ;
19+ const WATCH_STAMP_CACHE_VERSION : u32 = 2 ;
2020
2121#[ derive( Debug , Clone , Serialize , Deserialize ) ]
2222pub struct PersistedBuildFingerprint {
@@ -456,6 +456,10 @@ mod tests {
456456 . unwrap ( )
457457 }
458458
459+ fn set_file_mtime ( path : & Path , secs : i64 ) {
460+ filetime:: set_file_mtime ( path, filetime:: FileTime :: from_unix_time ( secs, 0 ) ) . unwrap ( ) ;
461+ }
462+
459463 #[ test]
460464 fn test_hash_files_changes_when_contents_change ( ) {
461465 let tmp = tempfile:: TempDir :: new ( ) . unwrap ( ) ;
@@ -568,6 +572,60 @@ mod tests {
568572 assert_eq ! ( first, second) ;
569573 }
570574
575+ #[ test]
576+ fn test_hash_watch_set_stamps_survives_mtime_reset_without_rewrite ( ) {
577+ let tmp = tempfile:: TempDir :: new ( ) . unwrap ( ) ;
578+ let src = tmp. path ( ) . join ( "src" ) ;
579+ fs:: create_dir_all ( & src) . unwrap ( ) ;
580+ let main = src. join ( "main.cpp" ) ;
581+ fs:: write ( & main, "int main() { return 1; }\n " ) . unwrap ( ) ;
582+ set_file_mtime ( & main, 1_700_000_000 ) ;
583+
584+ let watch = make_watch ( & src, & tmp. path ( ) . join ( ".project.zccache_fp.json" ) ) ;
585+ let hash_count = Cell :: new ( 0usize ) ;
586+
587+ let first = hash_watch_with_counter ( & watch, & hash_count) ;
588+ set_file_mtime ( & main, 1_700_000_123 ) ;
589+ let second = hash_watch_with_counter ( & watch, & hash_count) ;
590+ let after_second = hash_count. get ( ) ;
591+ let third = hash_watch_with_counter ( & watch, & hash_count) ;
592+
593+ assert_eq ! ( first, second) ;
594+ assert_eq ! ( second, third) ;
595+ assert_eq ! (
596+ after_second, 2 ,
597+ "mtime reset should rehash once to prove byte identity"
598+ ) ;
599+ assert_eq ! (
600+ hash_count. get( ) ,
601+ after_second,
602+ "updated stamp cache should restore the stat-only fast path"
603+ ) ;
604+ }
605+
606+ #[ test]
607+ fn test_hash_watch_set_stamps_detects_same_length_content_change_after_mtime_reset ( ) {
608+ let tmp = tempfile:: TempDir :: new ( ) . unwrap ( ) ;
609+ let src = tmp. path ( ) . join ( "src" ) ;
610+ fs:: create_dir_all ( & src) . unwrap ( ) ;
611+ let main = src. join ( "main.cpp" ) ;
612+ fs:: write ( & main, "int main() { return 1; }\n " ) . unwrap ( ) ;
613+ set_file_mtime ( & main, 1_700_000_000 ) ;
614+
615+ let watch = make_watch ( & src, & tmp. path ( ) . join ( ".project.zccache_fp.json" ) ) ;
616+
617+ let first = hash_watch_set_stamps ( std:: slice:: from_ref ( & watch) ) . unwrap ( ) ;
618+ fs:: write ( & main, "int main() { return 2; }\n " ) . unwrap ( ) ;
619+ set_file_mtime ( & main, 1_700_000_123 ) ;
620+ let second = hash_watch_set_stamps ( std:: slice:: from_ref ( & watch) ) . unwrap ( ) ;
621+
622+ assert_eq ! (
623+ fs:: metadata( & main) . unwrap( ) . len( ) ,
624+ "int main() { return 1; }\n " . len( ) as u64
625+ ) ;
626+ assert_ne ! ( first, second) ;
627+ }
628+
571629 #[ test]
572630 fn test_hash_watch_set_stamps_skips_rehash_when_stamp_unchanged ( ) {
573631 let tmp = tempfile:: TempDir :: new ( ) . unwrap ( ) ;
0 commit comments