zip_archive_test.cc revision 46cdef53794ae9c6e96f7821caf7995a3c335008
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "ziparchive/zip_archive.h" 18 19#include <errno.h> 20#include <getopt.h> 21#include <stdio.h> 22#include <unistd.h> 23#include <vector> 24 25#include <gtest/gtest.h> 26 27static std::string test_data_dir; 28 29static const std::string kValidZip = "valid.zip"; 30 31static const uint8_t kATxtContents[] = { 32 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 33 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 34 '\n' 35}; 36 37static const uint8_t kBTxtContents[] = { 38 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 39 '\n' 40}; 41 42static int32_t OpenArchiveWrapper(const std::string& name, 43 ZipArchiveHandle* handle) { 44 const std::string abs_path = test_data_dir + "/" + name; 45 return OpenArchive(abs_path.c_str(), handle); 46} 47 48static void AssertNameEquals(const std::string& name_str, 49 const ZipEntryName& name) { 50 ASSERT_EQ(name_str.size(), name.name_length); 51 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length)); 52} 53 54TEST(ziparchive, Open) { 55 ZipArchiveHandle handle; 56 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); 57 58 CloseArchive(handle); 59} 60 61TEST(ziparchive, Iteration) { 62 ZipArchiveHandle handle; 63 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); 64 65 void* iteration_cookie; 66 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL)); 67 68 ZipEntry data; 69 ZipEntryName name; 70 71 // b/c.txt 72 ASSERT_EQ(0, Next(iteration_cookie, &data, &name)); 73 AssertNameEquals("b/c.txt", name); 74 75 // b/d.txt 76 ASSERT_EQ(0, Next(iteration_cookie, &data, &name)); 77 AssertNameEquals("b/d.txt", name); 78 79 // a.txt 80 ASSERT_EQ(0, Next(iteration_cookie, &data, &name)); 81 AssertNameEquals("a.txt", name); 82 83 // b.txt 84 ASSERT_EQ(0, Next(iteration_cookie, &data, &name)); 85 AssertNameEquals("b.txt", name); 86 87 // b/ 88 ASSERT_EQ(0, Next(iteration_cookie, &data, &name)); 89 AssertNameEquals("b/", name); 90 91 // End of iteration. 92 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name)); 93 94 CloseArchive(handle); 95} 96 97TEST(ziparchive, FindEntry) { 98 ZipArchiveHandle handle; 99 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); 100 101 ZipEntry data; 102 ASSERT_EQ(0, FindEntry(handle, "a.txt", &data)); 103 104 // Known facts about a.txt, from zipinfo -v. 105 ASSERT_EQ(63, data.offset); 106 ASSERT_EQ(kCompressDeflated, data.method); 107 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length); 108 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length); 109 ASSERT_EQ(0x950821c5, data.crc32); 110 111 // An entry that doesn't exist. Should be a negative return code. 112 ASSERT_LT(FindEntry(handle, "nonexistent.txt", &data), 0); 113 114 CloseArchive(handle); 115} 116 117TEST(ziparchive, ExtractToMemory) { 118 ZipArchiveHandle handle; 119 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); 120 121 // An entry that's deflated. 122 ZipEntry data; 123 ASSERT_EQ(0, FindEntry(handle, "a.txt", &data)); 124 const uint32_t a_size = data.uncompressed_length; 125 ASSERT_EQ(a_size, sizeof(kATxtContents)); 126 uint8_t* buffer = new uint8_t[a_size]; 127 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size)); 128 ASSERT_EQ(0, memcmp(buffer, kATxtContents, a_size)); 129 delete[] buffer; 130 131 // An entry that's stored. 132 ASSERT_EQ(0, FindEntry(handle, "b.txt", &data)); 133 const uint32_t b_size = data.uncompressed_length; 134 ASSERT_EQ(b_size, sizeof(kBTxtContents)); 135 buffer = new uint8_t[b_size]; 136 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size)); 137 ASSERT_EQ(0, memcmp(buffer, kBTxtContents, b_size)); 138 delete[] buffer; 139 140 CloseArchive(handle); 141} 142 143TEST(ziparchive, EmptyEntries) { 144 char temp_file_pattern[] = "empty_entries_test_XXXXXX"; 145 int fd = mkstemp(temp_file_pattern); 146 ASSERT_NE(-1, fd); 147 const uint32_t data[] = { 148 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000, 149 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13, 150 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b, 151 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000, 152 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974, 153 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400, 154 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 }; 155 const ssize_t file_size = 168; 156 ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size))); 157 158 ZipArchiveHandle handle; 159 ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle)); 160 161 ZipEntry entry; 162 ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry)); 163 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length); 164 uint8_t buffer[1]; 165 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1)); 166 167 char output_file_pattern[] = "empty_entries_output_XXXXXX"; 168 int output_fd = mkstemp(output_file_pattern); 169 ASSERT_NE(-1, output_fd); 170 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd)); 171 172 struct stat stat_buf; 173 ASSERT_EQ(0, fstat(output_fd, &stat_buf)); 174 ASSERT_EQ(0, stat_buf.st_size); 175 176 close(fd); 177 close(output_fd); 178} 179 180TEST(ziparchive, ExtractToFile) { 181 char kTempFilePattern[] = "zip_archive_input_XXXXXX"; 182 int fd = mkstemp(kTempFilePattern); 183 ASSERT_NE(-1, fd); 184 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' }; 185 const ssize_t data_size = sizeof(data); 186 187 ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(write(fd, data, data_size))); 188 189 ZipArchiveHandle handle; 190 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle)); 191 192 ZipEntry entry; 193 ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry)); 194 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd)); 195 196 197 // Assert that the first 8 bytes of the file haven't been clobbered. 198 uint8_t read_buffer[data_size]; 199 ASSERT_EQ(0, lseek64(fd, 0, SEEK_SET)); 200 ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(read(fd, read_buffer, data_size))); 201 ASSERT_EQ(0, memcmp(read_buffer, data, data_size)); 202 203 // Assert that the remainder of the file contains the incompressed data. 204 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length); 205 ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length), 206 TEMP_FAILURE_RETRY( 207 read(fd, &uncompressed_data[0], entry.uncompressed_length))); 208 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents, 209 sizeof(kATxtContents))); 210 211 // Assert that the total length of the file is sane 212 ASSERT_EQ(data_size + sizeof(kATxtContents), lseek64(fd, 0, SEEK_END)); 213 214 close(fd); 215} 216 217int main(int argc, char** argv) { 218 ::testing::InitGoogleTest(&argc, argv); 219 220 static struct option options[] = { 221 { "test_data_dir", required_argument, NULL, 't' }, 222 { NULL, 0, NULL, 0 } 223 }; 224 225 while (true) { 226 int option_index; 227 const int c = getopt_long_only(argc, argv, "", options, &option_index); 228 if (c == -1) { 229 break; 230 } 231 232 if (c == 't') { 233 test_data_dir = optarg; 234 } 235 } 236 237 if (test_data_dir.size() == 0) { 238 printf("Test data flag (--test_data_dir) required\n\n"); 239 return -1; 240 } 241 242 if (test_data_dir[0] != '/') { 243 printf("Test data must be an absolute path, was %s\n\n", 244 test_data_dir.c_str()); 245 return -2; 246 } 247 248 return RUN_ALL_TESTS(); 249} 250 251