@@ -58,6 +58,28 @@ fn sync_unzip_falls_back_when_root_directory_missing() -> Result<()> {
5858 Ok ( ( ) )
5959}
6060
61+ #[ test]
62+ fn sync_unzip_overwrites_duplicate_files ( ) -> Result < ( ) > {
63+ let temp = tempdir ( ) ?;
64+ let zip_path = temp. path ( ) . join ( "duplicate_files.zip" ) ;
65+ create_zip_with_duplicate_file ( & zip_path) ?;
66+
67+ let output_dir = temp. path ( ) . join ( "output" ) ;
68+ std:: fs:: create_dir_all ( & output_dir) ?;
69+
70+ let unzip_file = sync_unzip (
71+ zip_path. clone ( ) ,
72+ output_dir. clone ( ) ,
73+ Some ( FALLBACK_DIR . to_string ( ) ) ,
74+ ) ?;
75+
76+ let duplicated_file = unzip_file. unzip_dir . join ( "duplicate.csv" ) ;
77+ let content = std:: fs:: read_to_string ( duplicated_file) ?;
78+ assert_eq ! ( content, "second" ) ;
79+
80+ Ok ( ( ) )
81+ }
82+
6183#[ tokio:: test]
6284async fn async_unzip_preserves_root_directory_with_nested_zip ( ) -> Result < ( ) > {
6385 let temp = tempdir ( ) ?;
@@ -121,6 +143,33 @@ async fn async_unzip_falls_back_when_root_directory_missing() -> Result<()> {
121143 Ok ( ( ) )
122144}
123145
146+ #[ tokio:: test]
147+ async fn async_unzip_overwrites_duplicate_files ( ) -> Result < ( ) > {
148+ let temp = tempdir ( ) ?;
149+ let zip_path = temp. path ( ) . join ( "async_duplicate_files.zip" ) ;
150+ create_zip_with_duplicate_file ( & zip_path) ?;
151+
152+ let file = tokio:: fs:: File :: open ( & zip_path) . await ?;
153+ let reader = tokio:: io:: BufReader :: new ( file) . compat ( ) ;
154+ let zip_reader = async_zip:: base:: read:: stream:: ZipFileReader :: new ( reader) ;
155+
156+ let output_dir = temp. path ( ) . join ( "async_output_duplicate" ) ;
157+ tokio:: fs:: create_dir_all ( & output_dir) . await ?;
158+
159+ let unzip_file = async_unzip (
160+ zip_reader,
161+ output_dir. clone ( ) ,
162+ Some ( FALLBACK_DIR . to_string ( ) ) ,
163+ )
164+ . await ?;
165+
166+ let duplicated_file = unzip_file. unzip_dir_path . join ( "duplicate.csv" ) ;
167+ let content = tokio:: fs:: read_to_string ( duplicated_file) . await ?;
168+ assert_eq ! ( content, "second" ) ;
169+
170+ Ok ( ( ) )
171+ }
172+
124173fn create_zip_with_root_dir ( zip_path : & Path ) -> Result < ( ) > {
125174 let file = std:: fs:: File :: create ( zip_path) ?;
126175 let mut writer = ZipWriter :: new ( file) ;
@@ -152,6 +201,23 @@ fn create_zip_without_root_dir(zip_path: &Path) -> Result<()> {
152201 Ok ( ( ) )
153202}
154203
204+ fn create_zip_with_duplicate_file ( zip_path : & Path ) -> Result < ( ) > {
205+ let file = std:: fs:: File :: create ( zip_path) ?;
206+ let mut writer = ZipWriter :: new ( file) ;
207+ let options = FileOptions :: default ( ) . compression_method ( CompressionMethod :: Stored ) ;
208+
209+ writer. add_directory ( format ! ( "{ROOT_DIR}/" ) , options) ?;
210+
211+ writer. start_file ( format ! ( "{ROOT_DIR}/duplicate.csv" ) , options) ?;
212+ writer. write_all ( b"first" ) ?;
213+
214+ writer. start_file ( format ! ( "{ROOT_DIR}/duplicate.csv" ) , options) ?;
215+ writer. write_all ( b"second" ) ?;
216+
217+ writer. finish ( ) ?;
218+ Ok ( ( ) )
219+ }
220+
155221fn create_nested_zip_bytes ( name : & str ) -> Vec < u8 > {
156222 let cursor = Cursor :: new ( Vec :: new ( ) ) ;
157223 let mut nested_writer = ZipWriter :: new ( cursor) ;
0 commit comments