Line data Source code
1 : /*
2 : Zipios -- a small C++ library that provides easy access to .zip files.
3 :
4 : Copyright (C) 2000-2007 Thomas Sondergaard
5 : Copyright (C) 2015-2019 Made to Order Software Corporation
6 :
7 : This library is free software; you can redistribute it and/or
8 : modify it under the terms of the GNU Lesser General Public
9 : License as published by the Free Software Foundation; either
10 : version 2.1 of the License, or (at your option) any later version.
11 :
12 : This library is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this library; if not, write to the Free Software
19 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : */
21 :
22 : /** \file
23 : *
24 : * Zipios unit tests used to verify the VirtualSeeker class.
25 : */
26 :
27 : #include "tests.hpp"
28 :
29 : #include "zipios/virtualseeker.hpp"
30 : #include "zipios/zipiosexceptions.hpp"
31 :
32 : #include <fstream>
33 :
34 : #include <unistd.h>
35 :
36 :
37 : namespace
38 : {
39 :
40 :
41 : size_t const FOUR(4);
42 :
43 :
44 : } // no name namespace
45 :
46 :
47 2 : TEST_CASE("VirtualSeeker tests", "[zipios_common]")
48 : {
49 : // create a file of 256 bytes
50 2 : zipios_test::auto_unlink_t auto_unlink("file256.bin");
51 : {
52 2 : std::ofstream os("file256.bin", std::ios::out | std::ios::binary);
53 257 : for(int i(0); i < 256; ++i)
54 : {
55 256 : os << static_cast<char>(i);
56 : }
57 : }
58 :
59 : // reopen as read-only
60 2 : std::ifstream is("file256.bin", std::ios::out | std::ios::binary);
61 : char buf[256];
62 :
63 257 : for(int count(0); count < 256; ++count)
64 : {
65 : // make the start betwee 0 and 200 so that we have some wiggle room
66 : // for the end offset
67 : //
68 256 : zipios::offset_t const start_offset(rand() % 200);
69 256 : zipios::offset_t const end_offset(start_offset + rand() % (256 - start_offset));
70 256 : REQUIRE(start_offset <= end_offset); // this should always be true
71 256 : zipios::offset_t const end(256 - end_offset);
72 256 : size_t const max_read(end_offset - start_offset);
73 : // note that the "gap" may be zero
74 :
75 : // attempt to create the seeker with invalid offsets
76 512 : REQUIRE_THROWS_AS([&](){
77 : zipios::VirtualSeeker vs(start_offset, -end);
78 : }(), zipios::InvalidException);
79 512 : REQUIRE_THROWS_AS([&](){
80 : zipios::VirtualSeeker vs(-start_offset, -end);
81 : }(), zipios::InvalidException);
82 256 : if(start_offset != 0)
83 : {
84 506 : REQUIRE_THROWS_AS([&](){
85 : zipios::VirtualSeeker vs(-start_offset, end);
86 : }(), zipios::InvalidException);
87 : }
88 :
89 : // the end parameter to the VirtualSeeker is a "weird" position
90 256 : zipios::VirtualSeeker vs(start_offset, end);
91 :
92 : {
93 256 : REQUIRE(vs.startOffset() == start_offset);
94 256 : REQUIRE(vs.endOffset() == end);
95 :
96 : zipios::offset_t start_test;
97 : zipios::offset_t end_test;
98 256 : vs.getOffsets(start_test, end_test);
99 256 : REQUIRE(start_test == start_offset);
100 256 : REQUIRE(end_test == end);
101 : }
102 :
103 : {
104 256 : vs.vseekg(is, 0, std::ios::beg);
105 256 : REQUIRE(is.tellg() == start_offset);
106 256 : REQUIRE(vs.vtellg(is) == 0);
107 :
108 256 : size_t const sz(std::min(max_read, FOUR));
109 256 : is.read(buf, sz);
110 256 : REQUIRE(is.tellg() == static_cast<zipios::offset_t>(start_offset + sz));
111 256 : REQUIRE(is);
112 256 : if(sz > 0)
113 : {
114 255 : REQUIRE(buf[0] == static_cast<char>(start_offset));
115 : }
116 256 : if(sz > 1)
117 : {
118 252 : REQUIRE(buf[1] == static_cast<char>(start_offset + 1));
119 : }
120 256 : if(sz > 2)
121 : {
122 252 : REQUIRE(buf[2] == static_cast<char>(start_offset + 2));
123 : }
124 256 : if(sz > 3)
125 : {
126 249 : REQUIRE(buf[3] == static_cast<char>(start_offset + 3));
127 : }
128 :
129 : // try moving a little more (if max_read allows it)
130 256 : if(max_read > 9UL)
131 : {
132 239 : vs.vseekg(is, 4, std::ios::cur);
133 239 : REQUIRE(is.tellg() == start_offset + 8);
134 239 : REQUIRE(vs.vtellg(is) == 8);
135 :
136 239 : size_t const sz2(std::min(max_read - 8UL, 4UL));
137 239 : is.read(buf, sz2);
138 239 : REQUIRE(is);
139 239 : if(sz2 > 0)
140 : {
141 239 : REQUIRE(buf[0] == static_cast<char>(start_offset + 8));
142 : }
143 239 : if(sz2 > 1)
144 : {
145 239 : REQUIRE(buf[1] == static_cast<char>(start_offset + 8 + 1));
146 : }
147 239 : if(sz2 > 2)
148 : {
149 235 : REQUIRE(buf[2] == static_cast<char>(start_offset + 8 + 2));
150 : }
151 239 : if(sz2 > 3)
152 : {
153 234 : REQUIRE(buf[3] == static_cast<char>(start_offset + 8 + 3));
154 : }
155 : }
156 : }
157 :
158 : {
159 256 : ssize_t const sz(std::min(max_read, FOUR));
160 :
161 256 : vs.vseekg(is, -sz, std::ios::end);
162 256 : std::streampos const expected_absolute_pos(end_offset - sz);
163 256 : REQUIRE(is.tellg() == expected_absolute_pos);
164 256 : std::streampos const expected_virtual_pos(end_offset - sz - start_offset);
165 256 : REQUIRE(vs.vtellg(is) == expected_virtual_pos);
166 :
167 256 : is.read(buf, sz);
168 256 : REQUIRE(is.tellg() == end_offset);
169 256 : REQUIRE(is);
170 256 : if(sz > 0)
171 : {
172 255 : REQUIRE(buf[0] == static_cast<char>(end_offset - sz));
173 : }
174 256 : if(sz > 1)
175 : {
176 252 : REQUIRE(buf[1] == static_cast<char>(end_offset - sz + 1));
177 : }
178 256 : if(sz > 2)
179 : {
180 252 : REQUIRE(buf[2] == static_cast<char>(end_offset - sz + 2));
181 : }
182 256 : if(sz > 3)
183 : {
184 249 : REQUIRE(buf[3] == static_cast<char>(end_offset - sz + 3));
185 : }
186 :
187 : // try moving a little more (if max_read allows it)
188 256 : if(max_read >= 9UL && max_read - 8UL >= static_cast<size_t>(start_offset))
189 : {
190 103 : ssize_t const sz2(std::min(max_read - 8UL, 4UL));
191 :
192 103 : vs.vseekg(is, -sz2 - sz, std::ios::cur);
193 103 : std::streampos const expected_absolute_pos2(end_offset - sz2 - sz);
194 103 : REQUIRE(is.tellg() == expected_absolute_pos2);
195 103 : std::streampos const expected_virtual_pos2(end_offset - sz2 - sz - start_offset);
196 103 : REQUIRE(vs.vtellg(is) == expected_virtual_pos2);
197 :
198 103 : is.read(buf, sz2);
199 103 : REQUIRE(is);
200 103 : if(sz2 > 0)
201 : {
202 103 : REQUIRE(buf[0] == static_cast<char>(end_offset - sz2 - sz));
203 : }
204 103 : if(sz2 > 1)
205 : {
206 103 : REQUIRE(buf[1] == static_cast<char>(end_offset - sz2 - sz + 1));
207 : }
208 103 : if(sz2 > 2)
209 : {
210 103 : REQUIRE(buf[2] == static_cast<char>(end_offset - sz2 - sz + 2));
211 : }
212 103 : if(sz2 > 3)
213 : {
214 103 : REQUIRE(buf[3] == static_cast<char>(end_offset - sz2 - sz + 3));
215 : }
216 : }
217 : }
218 :
219 : // change the offset and try again
220 256 : zipios::offset_t const start_offset2(rand() % 200);
221 256 : zipios::offset_t const end_offset2(start_offset2 + rand() % (256 - start_offset2));
222 256 : REQUIRE(start_offset2 <= end_offset2); // this should not happen, period!
223 256 : zipios::offset_t const end2(256 - end_offset2);
224 256 : size_t max_read2(end_offset2 - start_offset2);
225 : // note that the "gap" may be zero
226 :
227 : // try setting the offsets with invalid values
228 256 : REQUIRE_THROWS_AS(vs.setOffsets(-start_offset2, -end2), zipios::InvalidException);
229 256 : REQUIRE_THROWS_AS(vs.setOffsets(start_offset2, -end2), zipios::InvalidException);
230 256 : if(start_offset2 != 0)
231 : {
232 256 : REQUIRE_THROWS_AS(vs.setOffsets(-start_offset2, -end2), zipios::InvalidException);
233 : }
234 :
235 : // then change it to a valid value
236 256 : vs.setOffsets(start_offset2, end2);
237 :
238 : {
239 256 : REQUIRE(vs.startOffset() == start_offset2);
240 256 : REQUIRE(vs.endOffset() == end2);
241 :
242 : zipios::offset_t start_test2;
243 : zipios::offset_t end_test2;
244 256 : vs.getOffsets(start_test2, end_test2);
245 256 : REQUIRE(start_test2 == start_offset2);
246 256 : REQUIRE(end_test2 == end2);
247 : }
248 :
249 51712 : for(int invalid_seek_direction(-100); invalid_seek_direction <= 100; ++invalid_seek_direction)
250 : {
251 51456 : switch(invalid_seek_direction)
252 : {
253 : case std::ios::cur:
254 : case std::ios::beg:
255 : case std::ios::end:
256 768 : break;
257 :
258 : default:
259 50688 : REQUIRE_THROWS_AS(vs.vseekg(is, 0, static_cast<std::ios::seekdir>(invalid_seek_direction)), std::logic_error);
260 50688 : break;
261 :
262 : }
263 : }
264 :
265 : {
266 256 : vs.vseekg(is, 0, std::ios::beg);
267 256 : REQUIRE(vs.vtellg(is) == 0);
268 :
269 256 : size_t const sz(std::min(max_read2, FOUR));
270 256 : is.read(buf, sz);
271 256 : REQUIRE(is);
272 256 : if(sz > 0)
273 : {
274 256 : REQUIRE(buf[0] == static_cast<char>(start_offset2));
275 : }
276 256 : if(sz > 1)
277 : {
278 250 : REQUIRE(buf[1] == static_cast<char>(start_offset2 + 1));
279 : }
280 256 : if(sz > 2)
281 : {
282 246 : REQUIRE(buf[2] == static_cast<char>(start_offset2 + 2));
283 : }
284 256 : if(sz > 3)
285 : {
286 242 : REQUIRE(buf[3] == static_cast<char>(start_offset2 + 3));
287 : }
288 : }
289 :
290 : {
291 256 : ssize_t const sz(std::min(max_read2, FOUR));
292 :
293 256 : vs.vseekg(is, -sz, std::ios::end);
294 256 : std::streampos const expected_absolute_pos(end_offset2 - sz);
295 256 : REQUIRE(is.tellg() == expected_absolute_pos);
296 256 : std::streampos const expected_virtual_pos(end_offset2 - sz - start_offset2);
297 256 : REQUIRE(vs.vtellg(is) == expected_virtual_pos);
298 :
299 256 : is.read(buf, sz);
300 256 : REQUIRE(is);
301 256 : if(sz > 0)
302 : {
303 256 : REQUIRE(buf[0] == static_cast<char>(end_offset2 - sz));
304 : }
305 256 : if(sz > 1)
306 : {
307 250 : REQUIRE(buf[1] == static_cast<char>(end_offset2 - sz + 1));
308 : }
309 256 : if(sz > 2)
310 : {
311 246 : REQUIRE(buf[2] == static_cast<char>(end_offset2 - sz + 2));
312 : }
313 256 : if(sz > 3)
314 : {
315 242 : REQUIRE(buf[3] == static_cast<char>(end_offset2 - sz + 3));
316 : }
317 : }
318 : }
319 4 : }
320 :
321 :
322 : // Local Variables:
323 : // mode: cpp
324 : // indent-tabs-mode: nil
325 : // c-basic-offset: 4
326 : // tab-width: 4
327 : // End:
328 :
329 : // vim: ts=4 sw=4 et
|