[go: nahoru, domu]

blob: 25d0c54d0b9cafb22f26f4bd09c621c0c2650cf2 [file] [log] [blame]
Joel Galenson45581102021-06-21 14:24:55 -07001use byteorder::{LittleEndian, WriteBytesExt};
Yi Kongf19c3f22021-02-13 04:04:00 +08002use std::collections::HashSet;
3use std::io::prelude::*;
4use std::io::{Cursor, Seek};
5use std::iter::FromIterator;
6use zip::write::FileOptions;
David LeGare132eccb2022-04-11 16:44:12 +00007use zip::{CompressionMethod, SUPPORTED_COMPRESSION_METHODS};
Yi Kongf19c3f22021-02-13 04:04:00 +08008
9// This test asserts that after creating a zip file, then reading its contents back out,
10// the extracted data will *always* be exactly the same as the original data.
11#[test]
12fn end_to_end() {
David LeGare132eccb2022-04-11 16:44:12 +000013 for &method in SUPPORTED_COMPRESSION_METHODS {
14 let file = &mut Cursor::new(Vec::new());
Yi Kongf19c3f22021-02-13 04:04:00 +080015
David LeGare132eccb2022-04-11 16:44:12 +000016 println!("Writing file with {} compression", method);
17 write_test_archive(file, method).expect("Couldn't write test zip archive");
Yi Kongf19c3f22021-02-13 04:04:00 +080018
David LeGare132eccb2022-04-11 16:44:12 +000019 println!("Checking file contents");
20 check_archive_file(file, ENTRY_NAME, Some(method), LOREM_IPSUM);
21 }
Yi Kongf19c3f22021-02-13 04:04:00 +080022}
23
24// This test asserts that after copying a `ZipFile` to a new `ZipWriter`, then reading its
25// contents back out, the extracted data will *always* be exactly the same as the original data.
26#[test]
27fn copy() {
David LeGare132eccb2022-04-11 16:44:12 +000028 for &method in SUPPORTED_COMPRESSION_METHODS {
29 let src_file = &mut Cursor::new(Vec::new());
30 write_test_archive(src_file, method).expect("Couldn't write to test file");
Yi Kongf19c3f22021-02-13 04:04:00 +080031
David LeGare132eccb2022-04-11 16:44:12 +000032 let mut tgt_file = &mut Cursor::new(Vec::new());
Yi Kongf19c3f22021-02-13 04:04:00 +080033
34 {
David LeGare132eccb2022-04-11 16:44:12 +000035 let mut src_archive = zip::ZipArchive::new(src_file).unwrap();
36 let mut zip = zip::ZipWriter::new(&mut tgt_file);
37
38 {
39 let file = src_archive
40 .by_name(ENTRY_NAME)
41 .expect("Missing expected file");
42
43 zip.raw_copy_file(file).expect("Couldn't copy file");
44 }
45
46 {
47 let file = src_archive
48 .by_name(ENTRY_NAME)
49 .expect("Missing expected file");
50
51 zip.raw_copy_file_rename(file, COPY_ENTRY_NAME)
52 .expect("Couldn't copy and rename file");
53 }
Yi Kongf19c3f22021-02-13 04:04:00 +080054 }
55
David LeGare132eccb2022-04-11 16:44:12 +000056 let mut tgt_archive = zip::ZipArchive::new(tgt_file).unwrap();
57
58 check_archive_file_contents(&mut tgt_archive, ENTRY_NAME, LOREM_IPSUM);
59 check_archive_file_contents(&mut tgt_archive, COPY_ENTRY_NAME, LOREM_IPSUM);
Yi Kongf19c3f22021-02-13 04:04:00 +080060 }
Yi Kongf19c3f22021-02-13 04:04:00 +080061}
62
Joel Galenson45581102021-06-21 14:24:55 -070063// This test asserts that after appending to a `ZipWriter`, then reading its contents back out,
64// both the prior data and the appended data will be exactly the same as their originals.
65#[test]
66fn append() {
David LeGare132eccb2022-04-11 16:44:12 +000067 for &method in SUPPORTED_COMPRESSION_METHODS {
68 let mut file = &mut Cursor::new(Vec::new());
69 write_test_archive(file, method).expect("Couldn't write to test file");
Joel Galenson45581102021-06-21 14:24:55 -070070
David LeGare132eccb2022-04-11 16:44:12 +000071 {
72 let mut zip = zip::ZipWriter::new_append(&mut file).unwrap();
73 zip.start_file(
74 COPY_ENTRY_NAME,
75 FileOptions::default().compression_method(method),
76 )
77 .unwrap();
78 zip.write_all(LOREM_IPSUM).unwrap();
79 zip.finish().unwrap();
80 }
81
82 let mut zip = zip::ZipArchive::new(&mut file).unwrap();
83 check_archive_file_contents(&mut zip, ENTRY_NAME, LOREM_IPSUM);
84 check_archive_file_contents(&mut zip, COPY_ENTRY_NAME, LOREM_IPSUM);
Joel Galenson45581102021-06-21 14:24:55 -070085 }
Joel Galenson45581102021-06-21 14:24:55 -070086}
87
David LeGare132eccb2022-04-11 16:44:12 +000088// Write a test zip archive to buffer.
89fn write_test_archive(
90 file: &mut Cursor<Vec<u8>>,
91 method: CompressionMethod,
92) -> zip::result::ZipResult<()> {
Yi Kongf19c3f22021-02-13 04:04:00 +080093 let mut zip = zip::ZipWriter::new(file);
94
95 zip.add_directory("test/", Default::default())?;
96
97 let options = FileOptions::default()
David LeGare132eccb2022-04-11 16:44:12 +000098 .compression_method(method)
Yi Kongf19c3f22021-02-13 04:04:00 +080099 .unix_permissions(0o755);
David LeGare132eccb2022-04-11 16:44:12 +0000100
Yi Kongf19c3f22021-02-13 04:04:00 +0800101 zip.start_file("test/☃.txt", options)?;
102 zip.write_all(b"Hello, World!\n")?;
103
David LeGare132eccb2022-04-11 16:44:12 +0000104 zip.start_file_with_extra_data("test_with_extra_data/🐢.txt", options)?;
Joel Galenson45581102021-06-21 14:24:55 -0700105 zip.write_u16::<LittleEndian>(0xbeef)?;
106 zip.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
107 zip.write_all(EXTRA_DATA)?;
108 zip.end_extra_data()?;
109 zip.write_all(b"Hello, World! Again.\n")?;
110
David LeGare132eccb2022-04-11 16:44:12 +0000111 zip.start_file(ENTRY_NAME, options)?;
Yi Kongf19c3f22021-02-13 04:04:00 +0800112 zip.write_all(LOREM_IPSUM)?;
113
114 zip.finish()?;
115 Ok(())
116}
117
David LeGare132eccb2022-04-11 16:44:12 +0000118// Load an archive from buffer and check for test data.
119fn check_test_archive<R: Read + Seek>(zip_file: R) -> zip::result::ZipResult<zip::ZipArchive<R>> {
Joel Galenson45581102021-06-21 14:24:55 -0700120 let mut archive = zip::ZipArchive::new(zip_file).unwrap();
Yi Kongf19c3f22021-02-13 04:04:00 +0800121
David LeGare132eccb2022-04-11 16:44:12 +0000122 // Check archive contains expected file names.
123 {
124 let expected_file_names = [
125 "test/",
126 "test/☃.txt",
127 "test_with_extra_data/🐢.txt",
128 ENTRY_NAME,
129 ];
130 let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied());
131 let file_names = archive.file_names().collect::<HashSet<_>>();
132 assert_eq!(file_names, expected_file_names);
133 }
Yi Kongf19c3f22021-02-13 04:04:00 +0800134
David LeGare132eccb2022-04-11 16:44:12 +0000135 // Check an archive file for extra data field contents.
Joel Galenson45581102021-06-21 14:24:55 -0700136 {
137 let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?;
138 let mut extra_data = Vec::new();
139 extra_data.write_u16::<LittleEndian>(0xbeef)?;
140 extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?;
141 extra_data.write_all(EXTRA_DATA)?;
142 assert_eq!(file_with_extra_data.extra_data(), extra_data.as_slice());
143 }
144
Yi Kongf19c3f22021-02-13 04:04:00 +0800145 Ok(archive)
146}
147
David LeGare132eccb2022-04-11 16:44:12 +0000148// Read a file in the archive as a string.
149fn read_archive_file<R: Read + Seek>(
Yi Kongf19c3f22021-02-13 04:04:00 +0800150 archive: &mut zip::ZipArchive<R>,
151 name: &str,
152) -> zip::result::ZipResult<String> {
153 let mut file = archive.by_name(name)?;
154
155 let mut contents = String::new();
156 file.read_to_string(&mut contents).unwrap();
David LeGare132eccb2022-04-11 16:44:12 +0000157
Yi Kongf19c3f22021-02-13 04:04:00 +0800158 Ok(contents)
159}
160
David LeGare132eccb2022-04-11 16:44:12 +0000161// Check a file in the archive contains expected data and properties.
162fn check_archive_file(
163 zip_file: &mut Cursor<Vec<u8>>,
164 name: &str,
165 expected_method: Option<CompressionMethod>,
166 expected_data: &[u8],
167) {
168 let mut archive = check_test_archive(zip_file).unwrap();
169
170 if let Some(expected_method) = expected_method {
171 // Check the file's compression method.
172 let file = archive.by_name(name).unwrap();
173 let real_method = file.compression();
174
175 assert_eq!(
176 expected_method, real_method,
177 "File does not have expected compression method"
178 );
179 }
180
181 check_archive_file_contents(&mut archive, name, expected_data);
Yi Kongf19c3f22021-02-13 04:04:00 +0800182}
183
David LeGare132eccb2022-04-11 16:44:12 +0000184// Check a file in the archive contains the given data.
185fn check_archive_file_contents<R: Read + Seek>(
186 archive: &mut zip::ZipArchive<R>,
187 name: &str,
188 expected: &[u8],
189) {
190 let file_contents: String = read_archive_file(archive, name).unwrap();
191 assert_eq!(file_contents.as_bytes(), expected);
Yi Kongf19c3f22021-02-13 04:04:00 +0800192}
193
David LeGare132eccb2022-04-11 16:44:12 +0000194const LOREM_IPSUM : &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tellus elit, tristique vitae mattis egestas, ultricies vitae risus. Quisque sit amet quam ut urna aliquet
Yi Kongf19c3f22021-02-13 04:04:00 +0800195molestie. Proin blandit ornare dui, a tempor nisl accumsan in. Praesent a consequat felis. Morbi metus diam, auctor in auctor vel, feugiat id odio. Curabitur ex ex,
196dictum quis auctor quis, suscipit id lorem. Aliquam vestibulum dolor nec enim vehicula, porta tristique augue tincidunt. Vivamus ut gravida est. Sed pellentesque, dolor
197vitae tristique consectetur, neque lectus pulvinar dui, sed feugiat purus diam id lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
198inceptos himenaeos. Maecenas feugiat velit in ex ultrices scelerisque id id neque.
199";
200
David LeGare132eccb2022-04-11 16:44:12 +0000201const EXTRA_DATA: &[u8] = b"Extra Data";
Joel Galenson45581102021-06-21 14:24:55 -0700202
Yi Kongf19c3f22021-02-13 04:04:00 +0800203const ENTRY_NAME: &str = "test/lorem_ipsum.txt";
204
205const COPY_ENTRY_NAME: &str = "test/lorem_ipsum_renamed.txt";