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