• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 using namespace boost;
19 using namespace boost::iostreams;
20 using namespace boost::iostreams::test;
21 namespace boost_ios = boost::iostreams;
22 using std::ifstream;
23 using boost::unit_test::test_suite;
24 
file_descriptor_test()25 void 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 
497 template <class FileDescriptor>
file_handle_test_impl(FileDescriptor *)498 void 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(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(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(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(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(test1.name());
543         boost_ios::detail::file_handle handle2 = open_file_handle(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(handle1);
553         close_file_handle(handle2);
554     }
555 
556     {
557         boost_ios::detail::file_handle handle1 = open_file_handle(test1.name());
558         boost_ios::detail::file_handle handle2 = open_file_handle(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(test1.name());
573         boost_ios::detail::file_handle handle2 = open_file_handle(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(handle2);
585     }
586 
587     {
588         boost_ios::detail::file_handle handle = open_file_handle(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(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 
file_handle_test()613 void 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 
init_unit_test_suite(int,char * [])620 test_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