@@ -651,4 +651,48 @@ mod tests {
651651 ) ;
652652 Ok ( ( ) )
653653 }
654+
655+ #[ test]
656+ #[ cfg( not( windows) ) ]
657+ fn test_normalize_directory_preserves_symlinks ( ) -> Result < ( ) > {
658+ use std:: os:: unix:: fs:: symlink;
659+
660+ let temp_dir = crate :: utils:: fs:: TempDir :: create ( ) ?;
661+ let test_dir = temp_dir. path ( ) . join ( "TestApp.xcarchive" ) ;
662+ fs:: create_dir_all ( test_dir. join ( "Products" ) ) ?;
663+
664+ // Create a regular file
665+ fs:: write ( test_dir. join ( "Products" ) . join ( "app.txt" ) , "test content" ) ?;
666+
667+ // Create a symlink pointing to the regular file
668+ let symlink_path = test_dir. join ( "Products" ) . join ( "app_link.txt" ) ;
669+ symlink ( "app.txt" , & symlink_path) ?;
670+
671+ let result_zip = normalize_directory ( & test_dir, temp_dir. path ( ) ) ?;
672+ let zip_file = fs:: File :: open ( result_zip. path ( ) ) ?;
673+ let mut archive = ZipArchive :: new ( zip_file) ?;
674+
675+ // Check that both the regular file and symlink are in the zip
676+ let mut has_regular_file = false ;
677+ let mut has_symlink = false ;
678+
679+ for i in 0 ..archive. len ( ) {
680+ let file = archive. by_index ( i) ?;
681+ let file_name = file. name ( ) ;
682+
683+ if file_name == "TestApp.xcarchive/Products/app.txt" {
684+ has_regular_file = true ;
685+ // Verify it's actually a regular file, not a symlink
686+ assert ! ( !file. is_symlink( ) , "app.txt should be a regular file, not a symlink" ) ;
687+ } else if file_name == "TestApp.xcarchive/Products/app_link.txt" {
688+ has_symlink = true ;
689+ // Verify it's actually a symlink
690+ assert ! ( file. is_symlink( ) , "app_link.txt should be a symlink in the zip" ) ;
691+ }
692+ }
693+
694+ assert ! ( has_regular_file, "Regular file should be in zip" ) ;
695+ assert ! ( has_symlink, "Symlink should be preserved in zip" ) ;
696+ Ok ( ( ) )
697+ }
654698}
0 commit comments