1// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2// (C) Copyright 2004-2007 Jonathan Turkanis
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5
6// See http://www.boost.org/libs/iostreams for documentation.
7
8#include <fstream>
9#include <fcntl.h>
10#include <boost/iostreams/device/file_descriptor.hpp>
11#include <boost/iostreams/stream.hpp>
12#include <boost/test/test_tools.hpp>
13#include <boost/test/unit_test.hpp>
14#include "detail/temp_file.hpp"
15#include "detail/verification.hpp"
16#include "detail/file_handle.hpp"
17
18using namespace boost;
19using namespace boost::iostreams;
20using namespace boost::iostreams::test;
21namespace boost_ios = boost::iostreams;
22using std::ifstream;
23using boost::unit_test::test_suite;
24
25void file_descriptor_test()
26{
27
28 typedef stream<file_descriptor_source> fdistream;
29 typedef stream<file_descriptor_sink> fdostream;
30 typedef stream<file_descriptor> fdstream;
31
32 test_file test1;
33 test_file test2;
34
35 //--------------Test file_descriptor_source-------------------------------//
36
37 {
38 fdistream first(file_descriptor_source(test1.name()), 0);
39 ifstream second(test2.name().c_str());
40 BOOST_CHECK(first->is_open());
41 BOOST_CHECK_MESSAGE(
42 compare_streams_in_chars(first, second),
43 "failed reading from file_descriptor_source in chars with no buffer"
44 );
45 first->close();
46 BOOST_CHECK(!first->is_open());
47 }
48
49 {
50 fdistream first(file_descriptor_source(test1.name()), 0);
51 ifstream second(test2.name().c_str());
52 BOOST_CHECK(first->is_open());
53 BOOST_CHECK_MESSAGE(
54 compare_streams_in_chunks(first, second),
55 "failed reading from file_descriptor_source in chunks with no buffer"
56 );
57 first->close();
58 BOOST_CHECK(!first->is_open());
59 }
60
61 {
62 file_descriptor_source file(test1.name());
63 fdistream first(file);
64 ifstream second(test2.name().c_str());
65 BOOST_CHECK(first->is_open());
66 BOOST_CHECK_MESSAGE(
67 compare_streams_in_chars(first, second),
68 "failed reading from file_descriptor_source in chars with buffer"
69 );
70 first->close();
71 BOOST_CHECK(!first->is_open());
72 }
73
74 {
75 file_descriptor_source file(test1.name());
76 fdistream first(file);
77 ifstream second(test2.name().c_str());
78 BOOST_CHECK(first->is_open());
79 BOOST_CHECK_MESSAGE(
80 compare_streams_in_chunks(first, second),
81 "failed reading from file_descriptor_source in chunks with buffer"
82 );
83 first->close();
84 BOOST_CHECK(!first->is_open());
85 }
86
87 // test illegal flag combinations
88 {
89 BOOST_CHECK_THROW(
90 file_descriptor_source(test1.name(),
91 BOOST_IOS::trunc),
92 BOOST_IOSTREAMS_FAILURE);
93 BOOST_CHECK_THROW(
94 file_descriptor_source(test1.name(),
95 BOOST_IOS::app | BOOST_IOS::trunc),
96 BOOST_IOSTREAMS_FAILURE);
97 BOOST_CHECK_THROW(
98 file_descriptor_source(test1.name(),
99 BOOST_IOS::out),
100 BOOST_IOSTREAMS_FAILURE);
101 BOOST_CHECK_THROW(
102 file_descriptor_source(test1.name(),
103 BOOST_IOS::out | BOOST_IOS::app),
104 BOOST_IOSTREAMS_FAILURE);
105 BOOST_CHECK_THROW(
106 file_descriptor_source(test1.name(),
107 BOOST_IOS::out | BOOST_IOS::trunc),
108 BOOST_IOSTREAMS_FAILURE);
109 BOOST_CHECK_THROW(
110 file_descriptor_source(test1.name(),
111 BOOST_IOS::out | BOOST_IOS::app | BOOST_IOS::trunc),
112 BOOST_IOSTREAMS_FAILURE);
113 }
114
115 //--------------Test file_descriptor_sink---------------------------------//
116
117 {
118 temp_file temp;
119 file_descriptor_sink file(temp.name(), BOOST_IOS::trunc);
120 fdostream out(file, 0);
121 BOOST_CHECK(out->is_open());
122 write_data_in_chars(os&: out);
123 out.close();
124 BOOST_CHECK_MESSAGE(
125 compare_files(test1.name(), temp.name()),
126 "failed writing to file_descriptor_sink in chars with no buffer"
127 );
128 file.close();
129 BOOST_CHECK(!file.is_open());
130 }
131
132 {
133 temp_file temp;
134 file_descriptor_sink file(temp.name(), BOOST_IOS::trunc);
135 fdostream out(file, 0);
136 BOOST_CHECK(out->is_open());
137 write_data_in_chunks(os&: out);
138 out.close();
139 BOOST_CHECK_MESSAGE(
140 compare_files(test1.name(), temp.name()),
141 "failed writing to file_descriptor_sink in chunks with no buffer"
142 );
143 file.close();
144 BOOST_CHECK(!file.is_open());
145 }
146
147 {
148 temp_file temp;
149 file_descriptor_sink file(temp.name(), BOOST_IOS::trunc);
150 fdostream out(file);
151 BOOST_CHECK(out->is_open());
152 write_data_in_chars(os&: out);
153 out.close();
154 BOOST_CHECK_MESSAGE(
155 compare_files(test1.name(), temp.name()),
156 "failed writing to file_descriptor_sink in chars with buffer"
157 );
158 file.close();
159 BOOST_CHECK(!file.is_open());
160 }
161
162 {
163 temp_file temp;
164 file_descriptor_sink file(temp.name(), BOOST_IOS::trunc);
165 fdostream out(file);
166 BOOST_CHECK(out->is_open());
167 write_data_in_chunks(os&: out);
168 out.close();
169 BOOST_CHECK_MESSAGE(
170 compare_files(test1.name(), temp.name()),
171 "failed writing to file_descriptor_sink in chunks with buffer"
172 );
173 file.close();
174 BOOST_CHECK(!file.is_open());
175 }
176
177 {
178 temp_file temp;
179 // set up the tests
180 {
181 file_descriptor_sink file(temp.name(), BOOST_IOS::trunc);
182 fdostream out(file);
183 write_data_in_chunks(os&: out);
184 out.close();
185 file.close();
186 }
187 // test std::ios_base::app
188 {
189 file_descriptor_sink file(temp.name(), BOOST_IOS::app);
190 fdostream out(file);
191 BOOST_CHECK(out->is_open());
192 write_data_in_chars(os&: out);
193 out.close();
194 std::string expected(narrow_data());
195 expected += narrow_data();
196 BOOST_CHECK_MESSAGE(
197 compare_container_and_file(expected, temp.name()),
198 "failed writing to file_descriptor_sink in append mode"
199 );
200 file.close();
201 BOOST_CHECK(!file.is_open());
202 }
203 // test std::ios_base::trunc
204 {
205 file_descriptor_sink file(temp.name(), BOOST_IOS::trunc);
206 fdostream out(file);
207 BOOST_CHECK(out->is_open());
208 write_data_in_chars(os&: out);
209 out.close();
210 BOOST_CHECK_MESSAGE(
211 compare_files(test1.name(), temp.name()),
212 "failed writing to file_descriptor_sink in trunc mode"
213 );
214 file.close();
215 BOOST_CHECK(!file.is_open());
216 }
217
218 // test illegal flag combinations
219 {
220 BOOST_CHECK_THROW(
221 file_descriptor_sink(temp.name(),
222 BOOST_IOS::trunc | BOOST_IOS::app),
223 BOOST_IOSTREAMS_FAILURE);
224 BOOST_CHECK_THROW(
225 file_descriptor_sink(temp.name(),
226 BOOST_IOS::in),
227 BOOST_IOSTREAMS_FAILURE);
228 BOOST_CHECK_THROW(
229 file_descriptor_sink(temp.name(),
230 BOOST_IOS::in | BOOST_IOS::app),
231 BOOST_IOSTREAMS_FAILURE);
232 BOOST_CHECK_THROW(
233 file_descriptor_sink(temp.name(),
234 BOOST_IOS::in | BOOST_IOS::trunc),
235 BOOST_IOSTREAMS_FAILURE);
236 BOOST_CHECK_THROW(
237 file_descriptor_sink(temp.name(),
238 BOOST_IOS::in | BOOST_IOS::trunc | BOOST_IOS::app),
239 BOOST_IOSTREAMS_FAILURE);
240 }
241 }
242
243 //--Test seeking with file_descriptor_source and file_descriptor_sink-----//
244
245 test_file test3;
246 {
247 file_descriptor_sink sink(test3.name());
248 fdostream out(sink);
249 BOOST_CHECK(out->is_open());
250 BOOST_CHECK_MESSAGE(
251 test_output_seekable(out),
252 "failed seeking within a file_descriptor_sink"
253 );
254 out->close();
255 BOOST_CHECK(!out->is_open());
256
257 file_descriptor_source source(test3.name());
258 fdistream in(source);
259 BOOST_CHECK(in->is_open());
260 BOOST_CHECK_MESSAGE(
261 test_input_seekable(in),
262 "failed seeking within a file_descriptor_source"
263 );
264 in->close();
265 BOOST_CHECK(!in->is_open());
266 }
267
268 //--------------Test file_descriptor--------------------------------------//
269
270 {
271 temp_file temp;
272 file_descriptor file( temp.name(),
273 BOOST_IOS::in |
274 BOOST_IOS::out |
275 BOOST_IOS::trunc |
276 BOOST_IOS::binary );
277 fdstream io(file, BUFSIZ);
278 BOOST_CHECK_MESSAGE(
279 test_seekable_in_chars(io),
280 "failed seeking within a file_descriptor, in chars"
281 );
282 }
283
284 {
285 temp_file temp;
286 file_descriptor file( temp.name(),
287 BOOST_IOS::in |
288 BOOST_IOS::out |
289 BOOST_IOS::trunc |
290 BOOST_IOS::binary );
291 fdstream io(file, BUFSIZ);
292 BOOST_CHECK_MESSAGE(
293 test_seekable_in_chunks(io),
294 "failed seeking within a file_descriptor, in chunks"
295 );
296 }
297
298 //--------------Test read-only file_descriptor----------------------------//
299
300 {
301 fdstream first(file_descriptor(test1.name(), BOOST_IOS::in), 0);
302 ifstream second(test2.name().c_str());
303 BOOST_CHECK(first->is_open());
304 write_data_in_chars(os&: first);
305 BOOST_CHECK(first.fail());
306 first.clear();
307 BOOST_CHECK_MESSAGE(
308 compare_streams_in_chars(first, second),
309 "failed reading from file_descriptor in chars with no buffer"
310 );
311 first->close();
312 BOOST_CHECK(!first->is_open());
313 }
314
315 {
316 fdstream first(file_descriptor(test1.name(), BOOST_IOS::in), 0);
317 ifstream second(test2.name().c_str());
318 BOOST_CHECK(first->is_open());
319 write_data_in_chunks(os&: first);
320 BOOST_CHECK(first.fail());
321 first.clear();
322 BOOST_CHECK_MESSAGE(
323 compare_streams_in_chunks(first, second),
324 "failed reading from file_descriptor in chunks with no buffer"
325 );
326 first->close();
327 BOOST_CHECK(!first->is_open());
328 }
329
330 {
331 file_descriptor file(test1.name(), BOOST_IOS::in);
332 fdstream first(file);
333 ifstream second(test2.name().c_str());
334 BOOST_CHECK(first->is_open());
335 write_data_in_chars(os&: first);
336 BOOST_CHECK(first.fail());
337 first.clear();
338 first.seekg(0, BOOST_IOS::beg);
339 BOOST_CHECK_MESSAGE(
340 compare_streams_in_chars(first, second),
341 "failed reading from file_descriptor in chars with buffer"
342 );
343 first->close();
344 BOOST_CHECK(!first->is_open());
345 }
346
347 {
348 file_descriptor file(test1.name(), BOOST_IOS::in);
349 fdstream first(file);
350 ifstream second(test2.name().c_str());
351 BOOST_CHECK(first->is_open());
352 write_data_in_chunks(os&: first);
353 BOOST_CHECK(first.fail());
354 first.clear();
355 first.seekg(0, BOOST_IOS::beg);
356 BOOST_CHECK_MESSAGE(
357 compare_streams_in_chunks(first, second),
358 "failed reading from file_descriptor in chunks with buffer"
359 );
360 first->close();
361 BOOST_CHECK(!first->is_open());
362 }
363
364 //--------------Test write-only file_descriptor---------------------------//
365 {
366 temp_file temp;
367 file_descriptor file( temp.name(),
368 BOOST_IOS::out |
369 BOOST_IOS::trunc );
370 fdstream out(file, 0);
371 BOOST_CHECK(out->is_open());
372 out.get();
373 BOOST_CHECK(out.fail());
374 out.clear();
375 write_data_in_chars(os&: out);
376 out.seekg(0, BOOST_IOS::beg);
377 out.get();
378 BOOST_CHECK(out.fail());
379 out.clear();
380 out.close();
381 BOOST_CHECK_MESSAGE(
382 compare_files(test1.name(), temp.name()),
383 "failed writing to file_descriptor in chars with no buffer"
384 );
385 file.close();
386 BOOST_CHECK(!file.is_open());
387 }
388
389 {
390 temp_file temp;
391 file_descriptor file( temp.name(),
392 BOOST_IOS::out |
393 BOOST_IOS::trunc );
394 fdstream out(file, 0);
395 BOOST_CHECK(out->is_open());
396 out.get();
397 BOOST_CHECK(out.fail());
398 out.clear();
399 write_data_in_chunks(os&: out);
400 out.seekg(0, BOOST_IOS::beg);
401 out.get();
402 BOOST_CHECK(out.fail());
403 out.clear();
404 out.close();
405 BOOST_CHECK_MESSAGE(
406 compare_files(test1.name(), temp.name()),
407 "failed writing to file_descriptor_sink in chunks with no buffer"
408 );
409 file.close();
410 BOOST_CHECK(!file.is_open());
411 }
412
413 {
414 temp_file temp;
415 file_descriptor file( temp.name(),
416 BOOST_IOS::out |
417 BOOST_IOS::trunc );
418 fdstream out(file);
419 BOOST_CHECK(out->is_open());
420 out.get();
421 BOOST_CHECK(out.fail());
422 out.clear();
423 write_data_in_chars(os&: out);
424 out.seekg(0, BOOST_IOS::beg);
425 out.get();
426 BOOST_CHECK(out.fail());
427 out.clear();
428 out.close();
429 BOOST_CHECK_MESSAGE(
430 compare_files(test1.name(), temp.name()),
431 "failed writing to file_descriptor_sink in chars with buffer"
432 );
433 file.close();
434 BOOST_CHECK(!file.is_open());
435 }
436
437 {
438 temp_file temp;
439 file_descriptor file( temp.name(),
440 BOOST_IOS::out |
441 BOOST_IOS::trunc );
442 fdstream out(file);
443 BOOST_CHECK(out->is_open());
444 out.get();
445 BOOST_CHECK(out.fail());
446 out.clear();
447 write_data_in_chunks(os&: out);
448 out.seekg(0, BOOST_IOS::beg);
449 out.get();
450 BOOST_CHECK(out.fail());
451 out.clear();
452 out.close();
453 BOOST_CHECK_MESSAGE(
454 compare_files(test1.name(), temp.name()),
455 "failed writing to file_descriptor_sink in chunks with buffer"
456 );
457 file.close();
458 BOOST_CHECK(!file.is_open());
459 }
460
461 // test illegal flag combinations
462 {
463 BOOST_CHECK_THROW(
464 file_descriptor(test1.name(),
465 BOOST_IOS::openmode(0)),
466 BOOST_IOSTREAMS_FAILURE);
467 BOOST_CHECK_THROW(
468 file_descriptor(test1.name(),
469 BOOST_IOS::trunc),
470 BOOST_IOSTREAMS_FAILURE);
471 BOOST_CHECK_THROW(
472 file_descriptor(test1.name(),
473 BOOST_IOS::app | BOOST_IOS::trunc),
474 BOOST_IOSTREAMS_FAILURE);
475 BOOST_CHECK_THROW(
476 file_descriptor(test1.name(),
477 BOOST_IOS::in | BOOST_IOS::trunc),
478 BOOST_IOSTREAMS_FAILURE);
479 BOOST_CHECK_THROW(
480 file_descriptor(test1.name(),
481 BOOST_IOS::in | BOOST_IOS::app | BOOST_IOS::trunc),
482 BOOST_IOSTREAMS_FAILURE);
483 BOOST_CHECK_THROW(
484 file_descriptor(test1.name(),
485 BOOST_IOS::out | BOOST_IOS::app | BOOST_IOS::trunc),
486 BOOST_IOSTREAMS_FAILURE);
487 BOOST_CHECK_THROW(
488 file_descriptor(test1.name(),
489 BOOST_IOS::in |
490 BOOST_IOS::out |
491 BOOST_IOS::app |
492 BOOST_IOS::trunc),
493 BOOST_IOSTREAMS_FAILURE);
494 }
495}
496
497template <class FileDescriptor>
498void file_handle_test_impl(FileDescriptor*)
499{
500 test_file test1;
501 test_file test2;
502
503 {
504 boost_ios::detail::file_handle handle = open_file_handle(name: test1.name());
505 {
506 FileDescriptor device1(handle, boost_ios::never_close_handle);
507 BOOST_CHECK(device1.handle() == handle);
508 }
509 BOOST_CHECK_HANDLE_OPEN(handle);
510 close_file_handle(handle);
511 }
512
513 {
514 boost_ios::detail::file_handle handle = open_file_handle(name: test1.name());
515 {
516 FileDescriptor device1(handle, boost_ios::close_handle);
517 BOOST_CHECK(device1.handle() == handle);
518 }
519 BOOST_CHECK_HANDLE_CLOSED(handle);
520 }
521
522 {
523 boost_ios::detail::file_handle handle = open_file_handle(name: test1.name());
524 FileDescriptor device1(handle, boost_ios::never_close_handle);
525 BOOST_CHECK(device1.handle() == handle);
526 device1.close();
527 BOOST_CHECK(!device1.is_open());
528 BOOST_CHECK_HANDLE_OPEN(handle);
529 close_file_handle(handle);
530 }
531
532 {
533 boost_ios::detail::file_handle handle = open_file_handle(name: test1.name());
534 FileDescriptor device1(handle, boost_ios::close_handle);
535 BOOST_CHECK(device1.handle() == handle);
536 device1.close();
537 BOOST_CHECK(!device1.is_open());
538 BOOST_CHECK_HANDLE_CLOSED(handle);
539 }
540
541 {
542 boost_ios::detail::file_handle handle1 = open_file_handle(name: test1.name());
543 boost_ios::detail::file_handle handle2 = open_file_handle(name: test2.name());
544 {
545 FileDescriptor device1(handle1, boost_ios::never_close_handle);
546 BOOST_CHECK(device1.handle() == handle1);
547 device1.open(handle2, boost_ios::never_close_handle);
548 BOOST_CHECK(device1.handle() == handle2);
549 }
550 BOOST_CHECK_HANDLE_OPEN(handle1);
551 BOOST_CHECK_HANDLE_OPEN(handle2);
552 close_file_handle(handle: handle1);
553 close_file_handle(handle: handle2);
554 }
555
556 {
557 boost_ios::detail::file_handle handle1 = open_file_handle(name: test1.name());
558 boost_ios::detail::file_handle handle2 = open_file_handle(name: test2.name());
559 {
560 FileDescriptor device1(handle1, boost_ios::close_handle);
561 BOOST_CHECK(device1.handle() == handle1);
562 device1.open(handle2, boost_ios::close_handle);
563 BOOST_CHECK(device1.handle() == handle2);
564 BOOST_CHECK_HANDLE_CLOSED(handle1);
565 BOOST_CHECK_HANDLE_OPEN(handle2);
566 }
567 BOOST_CHECK_HANDLE_CLOSED(handle1);
568 BOOST_CHECK_HANDLE_CLOSED(handle2);
569 }
570
571 {
572 boost_ios::detail::file_handle handle1 = open_file_handle(name: test1.name());
573 boost_ios::detail::file_handle handle2 = open_file_handle(name: test2.name());
574 {
575 FileDescriptor device1(handle1, boost_ios::close_handle);
576 BOOST_CHECK(device1.handle() == handle1);
577 device1.open(handle2, boost_ios::never_close_handle);
578 BOOST_CHECK(device1.handle() == handle2);
579 BOOST_CHECK_HANDLE_CLOSED(handle1);
580 BOOST_CHECK_HANDLE_OPEN(handle2);
581 }
582 BOOST_CHECK_HANDLE_CLOSED(handle1);
583 BOOST_CHECK_HANDLE_OPEN(handle2);
584 close_file_handle(handle: handle2);
585 }
586
587 {
588 boost_ios::detail::file_handle handle = open_file_handle(name: test1.name());
589 {
590 FileDescriptor device1;
591 BOOST_CHECK(!device1.is_open());
592 device1.open(handle, boost_ios::never_close_handle);
593 BOOST_CHECK(device1.handle() == handle);
594 BOOST_CHECK_HANDLE_OPEN(handle);
595 }
596 BOOST_CHECK_HANDLE_OPEN(handle);
597 close_file_handle(handle);
598 }
599
600 {
601 boost_ios::detail::file_handle handle = open_file_handle(name: test1.name());
602 {
603 FileDescriptor device1;
604 BOOST_CHECK(!device1.is_open());
605 device1.open(handle, boost_ios::close_handle);
606 BOOST_CHECK(device1.handle() == handle);
607 BOOST_CHECK_HANDLE_OPEN(handle);
608 }
609 BOOST_CHECK_HANDLE_CLOSED(handle);
610 }
611}
612
613void file_handle_test()
614{
615 file_handle_test_impl((boost_ios::file_descriptor*) 0);
616 file_handle_test_impl((boost_ios::file_descriptor_source*) 0);
617 file_handle_test_impl((boost_ios::file_descriptor_sink*) 0);
618}
619
620test_suite* init_unit_test_suite(int, char* [])
621{
622 test_suite* test = BOOST_TEST_SUITE("file_descriptor test");
623 test->add(BOOST_TEST_CASE(&file_descriptor_test));
624 test->add(BOOST_TEST_CASE(&file_handle_test));
625 return test;
626}
627

source code of boost/libs/iostreams/test/file_descriptor_test.cpp