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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 : */
21 :
22 : /** \file
23 : *
24 : * Zipios++ unit tests used to verify the VirtualSeeker class.
25 : */
26 :
27 : #include "catch_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 1 : zipios_test::auto_unlink_t auto_unlink("file256.bin");
51 : {
52 1 : 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 1 : }
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 256 : REQUIRE_THROWS_AS(zipios::VirtualSeeker vs(start_offset, -end), zipios::InvalidException);
77 256 : REQUIRE_THROWS_AS(zipios::VirtualSeeker vs(-start_offset, -end), zipios::InvalidException);
78 256 : if(start_offset != 0)
79 : {
80 255 : REQUIRE_THROWS_AS(zipios::VirtualSeeker vs(-start_offset, end), zipios::InvalidException);
81 : }
82 :
83 : // the end parameter to the VirtualSeeker is a "weird" position
84 256 : zipios::VirtualSeeker vs(start_offset, end);
85 :
86 : {
87 256 : REQUIRE(vs.startOffset() == start_offset);
88 256 : REQUIRE(vs.endOffset() == end);
89 :
90 : zipios::offset_t start_test;
91 : zipios::offset_t end_test;
92 256 : vs.getOffsets(start_test, end_test);
93 256 : REQUIRE(start_test == start_offset);
94 256 : REQUIRE(end_test == end);
95 : }
96 :
97 : {
98 256 : vs.vseekg(is, 0, std::ios::beg);
99 256 : REQUIRE(is.tellg() == start_offset);
100 256 : REQUIRE(vs.vtellg(is) == 0);
101 :
102 256 : size_t const sz(std::min(max_read, FOUR));
103 256 : is.read(buf, sz);
104 256 : REQUIRE(is.tellg() == static_cast<zipios::offset_t>(start_offset + sz));
105 256 : REQUIRE(is);
106 256 : if(sz > 0)
107 : {
108 254 : REQUIRE(buf[0] == static_cast<char>(start_offset));
109 : }
110 256 : if(sz > 1)
111 : {
112 253 : REQUIRE(buf[1] == static_cast<char>(start_offset + 1));
113 : }
114 256 : if(sz > 2)
115 : {
116 253 : REQUIRE(buf[2] == static_cast<char>(start_offset + 2));
117 : }
118 256 : if(sz > 3)
119 : {
120 251 : REQUIRE(buf[3] == static_cast<char>(start_offset + 3));
121 : }
122 :
123 : // try moving a little more (if max_read allows it)
124 256 : if(max_read > 9UL)
125 : {
126 240 : vs.vseekg(is, 4, std::ios::cur);
127 240 : REQUIRE(is.tellg() == start_offset + 8);
128 240 : REQUIRE(vs.vtellg(is) == 8);
129 :
130 240 : size_t const sz2(std::min(max_read - 8UL, 4UL));
131 240 : is.read(buf, sz2);
132 240 : REQUIRE(is);
133 240 : if(sz2 > 0)
134 : {
135 240 : REQUIRE(buf[0] == static_cast<char>(start_offset + 8));
136 : }
137 240 : if(sz2 > 1)
138 : {
139 240 : REQUIRE(buf[1] == static_cast<char>(start_offset + 8 + 1));
140 : }
141 240 : if(sz2 > 2)
142 : {
143 238 : REQUIRE(buf[2] == static_cast<char>(start_offset + 8 + 2));
144 : }
145 240 : if(sz2 > 3)
146 : {
147 236 : REQUIRE(buf[3] == static_cast<char>(start_offset + 8 + 3));
148 : }
149 : }
150 : }
151 :
152 : {
153 256 : ssize_t const sz(std::min(max_read, FOUR));
154 :
155 256 : vs.vseekg(is, -sz, std::ios::end);
156 256 : std::streampos const expected_absolute_pos(end_offset - sz);
157 256 : REQUIRE(is.tellg() == expected_absolute_pos);
158 256 : std::streampos const expected_virtual_pos(end_offset - sz - start_offset);
159 256 : REQUIRE(vs.vtellg(is) == expected_virtual_pos);
160 :
161 256 : is.read(buf, sz);
162 256 : REQUIRE(is.tellg() == end_offset);
163 256 : REQUIRE(is);
164 256 : if(sz > 0)
165 : {
166 254 : REQUIRE(buf[0] == static_cast<char>(end_offset - sz));
167 : }
168 256 : if(sz > 1)
169 : {
170 253 : REQUIRE(buf[1] == static_cast<char>(end_offset - sz + 1));
171 : }
172 256 : if(sz > 2)
173 : {
174 253 : REQUIRE(buf[2] == static_cast<char>(end_offset - sz + 2));
175 : }
176 256 : if(sz > 3)
177 : {
178 251 : REQUIRE(buf[3] == static_cast<char>(end_offset - sz + 3));
179 : }
180 :
181 : // try moving a little more (if max_read allows it)
182 256 : if(max_read >= 9UL && max_read - 8UL >= static_cast<size_t>(start_offset))
183 : {
184 99 : ssize_t const sz2(std::min(max_read - 8UL, 4UL));
185 :
186 99 : vs.vseekg(is, -sz2 - sz, std::ios::cur);
187 99 : std::streampos const expected_absolute_pos2(end_offset - sz2 - sz);
188 99 : REQUIRE(is.tellg() == expected_absolute_pos2);
189 99 : std::streampos const expected_virtual_pos2(end_offset - sz2 - sz - start_offset);
190 99 : REQUIRE(vs.vtellg(is) == expected_virtual_pos2);
191 :
192 99 : is.read(buf, sz2);
193 99 : REQUIRE(is);
194 99 : if(sz2 > 0)
195 : {
196 99 : REQUIRE(buf[0] == static_cast<char>(end_offset - sz2 - sz));
197 : }
198 99 : if(sz2 > 1)
199 : {
200 99 : REQUIRE(buf[1] == static_cast<char>(end_offset - sz2 - sz + 1));
201 : }
202 99 : if(sz2 > 2)
203 : {
204 99 : REQUIRE(buf[2] == static_cast<char>(end_offset - sz2 - sz + 2));
205 : }
206 99 : if(sz2 > 3)
207 : {
208 99 : REQUIRE(buf[3] == static_cast<char>(end_offset - sz2 - sz + 3));
209 : }
210 : }
211 : }
212 :
213 : // change the offset and try again
214 256 : zipios::offset_t const start_offset2(rand() % 200);
215 256 : zipios::offset_t const end_offset2(start_offset2 + rand() % (256 - start_offset2));
216 256 : REQUIRE(start_offset2 <= end_offset2); // this should not happen, period!
217 256 : zipios::offset_t const end2(256 - end_offset2);
218 256 : size_t max_read2(end_offset2 - start_offset2);
219 : // note that the "gap" may be zero
220 :
221 : // try setting the offsets with invalid values
222 256 : REQUIRE_THROWS_AS(vs.setOffsets(-start_offset2, -end2), zipios::InvalidException);
223 256 : REQUIRE_THROWS_AS(vs.setOffsets(start_offset2, -end2), zipios::InvalidException);
224 256 : if(start_offset2 != 0)
225 : {
226 255 : REQUIRE_THROWS_AS(vs.setOffsets(-start_offset2, -end2), zipios::InvalidException);
227 : }
228 :
229 : // then change it to a valid value
230 256 : vs.setOffsets(start_offset2, end2);
231 :
232 : {
233 256 : REQUIRE(vs.startOffset() == start_offset2);
234 256 : REQUIRE(vs.endOffset() == end2);
235 :
236 : zipios::offset_t start_test2;
237 : zipios::offset_t end_test2;
238 256 : vs.getOffsets(start_test2, end_test2);
239 256 : REQUIRE(start_test2 == start_offset2);
240 256 : REQUIRE(end_test2 == end2);
241 : }
242 :
243 51712 : for(int invalid_seek_direction(-100); invalid_seek_direction <= 100; ++invalid_seek_direction)
244 : {
245 51456 : switch(invalid_seek_direction)
246 : {
247 : case std::ios::cur:
248 : case std::ios::beg:
249 : case std::ios::end:
250 768 : break;
251 :
252 : default:
253 50688 : REQUIRE_THROWS_AS(vs.vseekg(is, 0, static_cast<std::ios::seekdir>(invalid_seek_direction)), std::logic_error);
254 50688 : break;
255 :
256 : }
257 : }
258 :
259 : {
260 256 : vs.vseekg(is, 0, std::ios::beg);
261 256 : REQUIRE(vs.vtellg(is) == 0);
262 :
263 256 : size_t const sz(std::min(max_read2, FOUR));
264 256 : is.read(buf, sz);
265 256 : REQUIRE(is);
266 256 : if(sz > 0)
267 : {
268 254 : REQUIRE(buf[0] == static_cast<char>(start_offset2));
269 : }
270 256 : if(sz > 1)
271 : {
272 253 : REQUIRE(buf[1] == static_cast<char>(start_offset2 + 1));
273 : }
274 256 : if(sz > 2)
275 : {
276 251 : REQUIRE(buf[2] == static_cast<char>(start_offset2 + 2));
277 : }
278 256 : if(sz > 3)
279 : {
280 249 : REQUIRE(buf[3] == static_cast<char>(start_offset2 + 3));
281 : }
282 : }
283 :
284 : {
285 256 : ssize_t const sz(std::min(max_read2, FOUR));
286 :
287 256 : vs.vseekg(is, -sz, std::ios::end);
288 256 : std::streampos const expected_absolute_pos(end_offset2 - sz);
289 256 : REQUIRE(is.tellg() == expected_absolute_pos);
290 256 : std::streampos const expected_virtual_pos(end_offset2 - sz - start_offset2);
291 256 : REQUIRE(vs.vtellg(is) == expected_virtual_pos);
292 :
293 256 : is.read(buf, sz);
294 256 : REQUIRE(is);
295 256 : if(sz > 0)
296 : {
297 254 : REQUIRE(buf[0] == static_cast<char>(end_offset2 - sz));
298 : }
299 256 : if(sz > 1)
300 : {
301 253 : REQUIRE(buf[1] == static_cast<char>(end_offset2 - sz + 1));
302 : }
303 256 : if(sz > 2)
304 : {
305 251 : REQUIRE(buf[2] == static_cast<char>(end_offset2 - sz + 2));
306 : }
307 256 : if(sz > 3)
308 : {
309 249 : REQUIRE(buf[3] == static_cast<char>(end_offset2 - sz + 3));
310 : }
311 : }
312 1 : }
313 4 : }
314 :
315 :
316 : // vim: ts=4 sw=4 et
317 :
318 : // Local Variables:
319 : // mode: cpp
320 : // indent-tabs-mode: nil
321 : // c-basic-offset: 4
322 : // tab-width: 4
323 : // End:
|