1pub mod error;
74pub mod reader;
75pub mod writer;
76
77#[cfg(feature = "encryption")]
78pub mod encryption;
79
80#[cfg(feature = "async")]
81pub mod async_writer;
82
83#[cfg(feature = "async")]
84pub mod async_reader;
85
86#[cfg(feature = "async")]
87pub mod parallel;
88
89#[cfg(any(feature = "cloud-s3", feature = "cloud-gcs"))]
90pub mod cloud;
91
92pub use error::{Result, SZipError};
93pub use reader::{StreamingZipReader, ZipEntry};
94pub use writer::{CompressionMethod, StreamingZipWriter};
95
96#[cfg(feature = "encryption")]
97pub use encryption::AesStrength;
98
99#[cfg(feature = "async")]
100pub use async_writer::AsyncStreamingZipWriter;
101
102#[cfg(feature = "async")]
103pub use async_reader::{AsyncStreamingZipReader, GenericAsyncZipReader};
104
105#[cfg(feature = "async")]
106pub use parallel::{ParallelConfig, ParallelEntry};
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use std::io::Cursor;
112
113 #[test]
114 fn test_basic_write_read_roundtrip() {
115 let buffer = Vec::new();
117 let cursor = Cursor::new(buffer);
118 let mut writer = StreamingZipWriter::from_writer(cursor).unwrap();
119
120 writer.start_entry("test1.txt").unwrap();
122 writer.write_data(b"Hello, World!").unwrap();
123
124 writer.start_entry("test2.txt").unwrap();
126 writer.write_data(b"Testing s-zip library").unwrap();
127
128 let cursor = writer.finish().unwrap();
130 let zip_bytes = cursor.into_inner();
131
132 assert!(!zip_bytes.is_empty(), "ZIP should not be empty");
134
135 assert_eq!(
137 &zip_bytes[0..4],
138 b"PK\x03\x04",
139 "Should start with ZIP signature"
140 );
141 }
142
143 #[test]
144 fn test_compression_method_to_zip_method() {
145 assert_eq!(CompressionMethod::Stored.to_zip_method(), 0);
146 assert_eq!(CompressionMethod::Deflate.to_zip_method(), 8);
147
148 #[cfg(feature = "zstd-support")]
149 assert_eq!(CompressionMethod::Zstd.to_zip_method(), 93);
150 }
151
152 #[test]
153 fn test_empty_entry_name() {
154 let buffer = Vec::new();
155 let cursor = Cursor::new(buffer);
156 let mut writer = StreamingZipWriter::from_writer(cursor).unwrap();
157
158 assert!(writer.start_entry("").is_ok());
160 }
161
162 #[test]
163 fn test_multiple_small_entries() {
164 let buffer = Vec::new();
165 let cursor = Cursor::new(buffer);
166 let mut writer = StreamingZipWriter::from_writer(cursor).unwrap();
167
168 for i in 0..10 {
170 let entry_name = format!("file_{}.txt", i);
171 let entry_data = format!("Content of file {}", i);
172
173 writer.start_entry(&entry_name).unwrap();
174 writer.write_data(entry_data.as_bytes()).unwrap();
175 }
176
177 let cursor = writer.finish().unwrap();
178 let zip_bytes = cursor.into_inner();
179
180 assert!(zip_bytes.len() > 100, "ZIP with 10 files should be larger");
182 }
183
184 #[test]
185 fn test_error_display() {
186 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
187 let err = SZipError::from(io_err);
188 assert!(format!("{}", err).contains("I/O error"));
189
190 let invalid_err = SZipError::InvalidFormat("bad format".to_string());
191 assert!(format!("{}", invalid_err).contains("Invalid ZIP format"));
192
193 let not_found_err = SZipError::EntryNotFound("missing.txt".to_string());
194 assert!(format!("{}", not_found_err).contains("Entry not found"));
195 }
196
197 #[cfg(feature = "encryption")]
198 #[test]
199 fn test_aes_strength() {
200 assert_eq!(AesStrength::Aes256.salt_size(), 16);
201 assert_eq!(AesStrength::Aes256.key_size(), 32);
202 assert_eq!(AesStrength::Aes256.to_winzip_code(), 0x03);
203 }
204}