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-2022 Made to Order Software Corp. All Rights Reserved
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 "catch_main.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 1 : CATCH_TEST_CASE("VirtualSeeker tests", "[zipios_common]")
48 : {
49 1 : zipios_test::safe_chdir cwd(SNAP_CATCH2_NAMESPACE::g_tmp_dir());
50 :
51 : // create a file of 256 bytes
52 2 : zipios_test::auto_unlink_t auto_unlink("file256.bin", true);
53 : {
54 1 : std::ofstream os("file256.bin", std::ios::out | std::ios::binary);
55 257 : for(int i(0); i < 256; ++i)
56 : {
57 256 : os << static_cast<char>(i);
58 : }
59 1 : }
60 :
61 : // reopen as read-only
62 1 : std::ifstream is("file256.bin", std::ios::in | std::ios::binary);
63 : char buf[256];
64 :
65 257 : for(int count(0); count < 256; ++count)
66 : {
67 : // make the start betwee 0 and 200 so that we have some wiggle room
68 : // for the end offset
69 : //
70 256 : zipios::offset_t const start_offset(rand() % 200);
71 256 : zipios::offset_t const end_offset(start_offset + rand() % (256 - start_offset));
72 256 : CATCH_REQUIRE(start_offset <= end_offset); // this should always be true
73 256 : zipios::offset_t const end(256 - end_offset);
74 256 : size_t const max_read(end_offset - start_offset);
75 : // note that the "gap" may be zero
76 :
77 : // attempt to create the seeker with invalid offsets
78 512 : CATCH_REQUIRE_THROWS_AS([&](){
79 : zipios::VirtualSeeker vs(start_offset, -end);
80 : }(), zipios::InvalidException);
81 512 : CATCH_REQUIRE_THROWS_AS([&](){
82 : zipios::VirtualSeeker vs(-start_offset, -end);
83 : }(), zipios::InvalidException);
84 256 : if(start_offset != 0)
85 : {
86 512 : CATCH_REQUIRE_THROWS_AS([&](){
87 : zipios::VirtualSeeker vs(-start_offset, end);
88 : }(), zipios::InvalidException);
89 : }
90 :
91 : // the end parameter to the VirtualSeeker is a "weird" position
92 256 : zipios::VirtualSeeker vs(start_offset, end);
93 :
94 : {
95 256 : CATCH_REQUIRE(vs.startOffset() == start_offset);
96 256 : CATCH_REQUIRE(vs.endOffset() == end);
97 :
98 : zipios::offset_t start_test;
99 : zipios::offset_t end_test;
100 256 : vs.getOffsets(start_test, end_test);
101 256 : CATCH_REQUIRE(start_test == start_offset);
102 256 : CATCH_REQUIRE(end_test == end);
103 : }
104 :
105 : {
106 256 : vs.vseekg(is, 0, std::ios::beg);
107 256 : CATCH_REQUIRE(is.tellg() == start_offset);
108 256 : CATCH_REQUIRE(vs.vtellg(is) == 0);
109 :
110 256 : size_t const sz(std::min(max_read, FOUR));
111 256 : is.read(buf, sz);
112 256 : CATCH_REQUIRE(is.tellg() == static_cast<zipios::offset_t>(start_offset + sz));
113 256 : CATCH_REQUIRE(is);
114 256 : if(sz > 0)
115 : {
116 253 : CATCH_REQUIRE(buf[0] == static_cast<char>(start_offset));
117 : }
118 256 : if(sz > 1)
119 : {
120 253 : CATCH_REQUIRE(buf[1] == static_cast<char>(start_offset + 1));
121 : }
122 256 : if(sz > 2)
123 : {
124 251 : CATCH_REQUIRE(buf[2] == static_cast<char>(start_offset + 2));
125 : }
126 256 : if(sz > 3)
127 : {
128 249 : CATCH_REQUIRE(buf[3] == static_cast<char>(start_offset + 3));
129 : }
130 :
131 : // try moving a little more (if max_read allows it)
132 256 : if(max_read > 9UL)
133 : {
134 235 : vs.vseekg(is, 4, std::ios::cur);
135 235 : CATCH_REQUIRE(is.tellg() == start_offset + 8);
136 235 : CATCH_REQUIRE(vs.vtellg(is) == 8);
137 :
138 235 : size_t const sz2(std::min(max_read - 8UL, 4UL));
139 235 : is.read(buf, sz2);
140 235 : CATCH_REQUIRE(is);
141 235 : if(sz2 > 0)
142 : {
143 235 : CATCH_REQUIRE(buf[0] == static_cast<char>(start_offset + 8));
144 : }
145 235 : if(sz2 > 1)
146 : {
147 235 : CATCH_REQUIRE(buf[1] == static_cast<char>(start_offset + 8 + 1));
148 : }
149 235 : if(sz2 > 2)
150 : {
151 233 : CATCH_REQUIRE(buf[2] == static_cast<char>(start_offset + 8 + 2));
152 : }
153 235 : if(sz2 > 3)
154 : {
155 231 : CATCH_REQUIRE(buf[3] == static_cast<char>(start_offset + 8 + 3));
156 : }
157 : }
158 : }
159 :
160 : {
161 256 : ssize_t const sz(std::min(max_read, FOUR));
162 :
163 256 : vs.vseekg(is, -sz, std::ios::end);
164 256 : std::streampos const expected_absolute_pos(end_offset - sz);
165 256 : CATCH_REQUIRE(is.tellg() == expected_absolute_pos);
166 256 : std::streampos const expected_virtual_pos(end_offset - sz - start_offset);
167 256 : CATCH_REQUIRE(vs.vtellg(is) == expected_virtual_pos);
168 :
169 256 : is.read(buf, sz);
170 256 : CATCH_REQUIRE(is.tellg() == end_offset);
171 256 : CATCH_REQUIRE(is);
172 256 : if(sz > 0)
173 : {
174 253 : CATCH_REQUIRE(buf[0] == static_cast<char>(end_offset - sz));
175 : }
176 256 : if(sz > 1)
177 : {
178 253 : CATCH_REQUIRE(buf[1] == static_cast<char>(end_offset - sz + 1));
179 : }
180 256 : if(sz > 2)
181 : {
182 251 : CATCH_REQUIRE(buf[2] == static_cast<char>(end_offset - sz + 2));
183 : }
184 256 : if(sz > 3)
185 : {
186 249 : CATCH_REQUIRE(buf[3] == static_cast<char>(end_offset - sz + 3));
187 : }
188 :
189 : // try moving a little more (if max_read allows it)
190 256 : if(max_read >= 9UL && max_read - 8UL >= static_cast<size_t>(start_offset))
191 : {
192 90 : ssize_t const sz2(std::min(max_read - 8UL, 4UL));
193 :
194 90 : vs.vseekg(is, -sz2 - sz, std::ios::cur);
195 90 : std::streampos const expected_absolute_pos2(end_offset - sz2 - sz);
196 90 : CATCH_REQUIRE(is.tellg() == expected_absolute_pos2);
197 90 : std::streampos const expected_virtual_pos2(end_offset - sz2 - sz - start_offset);
198 90 : CATCH_REQUIRE(vs.vtellg(is) == expected_virtual_pos2);
199 :
200 90 : is.read(buf, sz2);
201 90 : CATCH_REQUIRE(is);
202 90 : if(sz2 > 0)
203 : {
204 90 : CATCH_REQUIRE(buf[0] == static_cast<char>(end_offset - sz2 - sz));
205 : }
206 90 : if(sz2 > 1)
207 : {
208 90 : CATCH_REQUIRE(buf[1] == static_cast<char>(end_offset - sz2 - sz + 1));
209 : }
210 90 : if(sz2 > 2)
211 : {
212 90 : CATCH_REQUIRE(buf[2] == static_cast<char>(end_offset - sz2 - sz + 2));
213 : }
214 90 : if(sz2 > 3)
215 : {
216 90 : CATCH_REQUIRE(buf[3] == static_cast<char>(end_offset - sz2 - sz + 3));
217 : }
218 : }
219 : }
220 :
221 : // change the offset and try again
222 256 : zipios::offset_t const start_offset2(rand() % 200);
223 256 : zipios::offset_t const end_offset2(start_offset2 + rand() % (256 - start_offset2));
224 256 : CATCH_REQUIRE(start_offset2 <= end_offset2); // this should not happen, period!
225 256 : zipios::offset_t const end2(256 - end_offset2);
226 256 : size_t max_read2(end_offset2 - start_offset2);
227 : // note that the "gap" may be zero
228 :
229 : // try setting the offsets with invalid values
230 256 : CATCH_REQUIRE_THROWS_AS(vs.setOffsets(-start_offset2, -end2), zipios::InvalidException);
231 256 : CATCH_REQUIRE_THROWS_AS(vs.setOffsets(start_offset2, -end2), zipios::InvalidException);
232 256 : if(start_offset2 != 0)
233 : {
234 256 : CATCH_REQUIRE_THROWS_AS(vs.setOffsets(-start_offset2, -end2), zipios::InvalidException);
235 : }
236 :
237 : // then change it to a valid value
238 256 : vs.setOffsets(start_offset2, end2);
239 :
240 : {
241 256 : CATCH_REQUIRE(vs.startOffset() == start_offset2);
242 256 : CATCH_REQUIRE(vs.endOffset() == end2);
243 :
244 : zipios::offset_t start_test2;
245 : zipios::offset_t end_test2;
246 256 : vs.getOffsets(start_test2, end_test2);
247 256 : CATCH_REQUIRE(start_test2 == start_offset2);
248 256 : CATCH_REQUIRE(end_test2 == end2);
249 : }
250 :
251 51712 : for(int invalid_seek_direction(-100); invalid_seek_direction <= 100; ++invalid_seek_direction)
252 : {
253 51456 : switch(invalid_seek_direction)
254 : {
255 768 : case std::ios::cur:
256 : case std::ios::beg:
257 : case std::ios::end:
258 768 : break;
259 :
260 50688 : default:
261 50688 : CATCH_REQUIRE_THROWS_AS(vs.vseekg(is, 0, static_cast<std::ios::seekdir>(invalid_seek_direction)), std::logic_error);
262 50688 : break;
263 :
264 : }
265 : }
266 :
267 : {
268 256 : vs.vseekg(is, 0, std::ios::beg);
269 256 : CATCH_REQUIRE(vs.vtellg(is) == 0);
270 :
271 256 : size_t const sz(std::min(max_read2, FOUR));
272 256 : is.read(buf, sz);
273 256 : CATCH_REQUIRE(is);
274 256 : if(sz > 0)
275 : {
276 254 : CATCH_REQUIRE(buf[0] == static_cast<char>(start_offset2));
277 : }
278 256 : if(sz > 1)
279 : {
280 253 : CATCH_REQUIRE(buf[1] == static_cast<char>(start_offset2 + 1));
281 : }
282 256 : if(sz > 2)
283 : {
284 250 : CATCH_REQUIRE(buf[2] == static_cast<char>(start_offset2 + 2));
285 : }
286 256 : if(sz > 3)
287 : {
288 249 : CATCH_REQUIRE(buf[3] == static_cast<char>(start_offset2 + 3));
289 : }
290 : }
291 :
292 : {
293 256 : ssize_t const sz(std::min(max_read2, FOUR));
294 :
295 256 : vs.vseekg(is, -sz, std::ios::end);
296 256 : std::streampos const expected_absolute_pos(end_offset2 - sz);
297 256 : CATCH_REQUIRE(is.tellg() == expected_absolute_pos);
298 256 : std::streampos const expected_virtual_pos(end_offset2 - sz - start_offset2);
299 256 : CATCH_REQUIRE(vs.vtellg(is) == expected_virtual_pos);
300 :
301 256 : is.read(buf, sz);
302 256 : CATCH_REQUIRE(is);
303 256 : if(sz > 0)
304 : {
305 254 : CATCH_REQUIRE(buf[0] == static_cast<char>(end_offset2 - sz));
306 : }
307 256 : if(sz > 1)
308 : {
309 253 : CATCH_REQUIRE(buf[1] == static_cast<char>(end_offset2 - sz + 1));
310 : }
311 256 : if(sz > 2)
312 : {
313 250 : CATCH_REQUIRE(buf[2] == static_cast<char>(end_offset2 - sz + 2));
314 : }
315 256 : if(sz > 3)
316 : {
317 249 : CATCH_REQUIRE(buf[3] == static_cast<char>(end_offset2 - sz + 3));
318 : }
319 : }
320 : }
321 1 : }
322 :
323 :
324 : // Local Variables:
325 : // mode: cpp
326 : // indent-tabs-mode: nil
327 : // c-basic-offset: 4
328 : // tab-width: 4
329 : // End:
330 :
331 : // vim: ts=4 sw=4 et
|