1/*
2 * Distributed under the Boost Software License, Version 1.0.(See accompanying
3 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
4 *
5 * See http://www.boost.org/libs/iostreams for documentation.
6 *
7 * Verifies that the close() member functions of filters and devices
8 * are called with the correct arguments in the correct order when
9 * used with chains and streams.
10 *
11 * File: libs/iostreams/test/close_test.cpp
12 * Date: Sun Dec 09 16:12:23 MST 2007
13 * Copyright: 2007 CodeRage
14 * Author: Jonathan Turkanis
15 */
16
17#include <boost/iostreams/chain.hpp>
18#include <boost/iostreams/filtering_streambuf.hpp>
19#include <boost/iostreams/stream.hpp>
20#include <boost/test/test_tools.hpp>
21#include <boost/test/unit_test.hpp>
22#include "detail/closable.hpp"
23#include "detail/operation_sequence.hpp"
24
25using namespace std;
26using namespace boost;
27using namespace boost::iostreams;
28using namespace boost::iostreams::test;
29using boost::unit_test::test_suite;
30namespace io = boost::iostreams;
31
32void input_chain_test()
33{
34 // Test input filter and device
35 {
36 operation_sequence seq;
37 filtering_streambuf<input> ch;
38
39 // Test chain::pop()
40 ch.push(t: closable_filter<input>(seq.new_operation(id: 2)));
41 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
42 BOOST_CHECK_NO_THROW(ch.pop());
43 BOOST_CHECK_OPERATION_SEQUENCE(seq);
44
45 // Test filter reuse and io::close()
46 seq.reset();
47 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
48 BOOST_CHECK_NO_THROW(io::close(ch));
49 BOOST_CHECK_OPERATION_SEQUENCE(seq);
50
51 // Test filter reuse and chain::reset()
52 seq.reset();
53 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
54 BOOST_CHECK_NO_THROW(ch.reset());
55 BOOST_CHECK_OPERATION_SEQUENCE(seq);
56 }
57
58 // Test bidirectional filter and device
59 {
60 operation_sequence seq;
61 filtering_streambuf<input> ch;
62
63 // Test chain::pop()
64 ch.push(
65 t: closable_filter<bidirectional>(
66 seq.new_operation(id: 2),
67 seq.new_operation(id: 3)
68 )
69 );
70 ch.push(
71 t: closable_device<bidirectional>(
72 seq.new_operation(id: 1),
73 seq.new_operation(id: 4)
74 )
75 );
76 BOOST_CHECK_NO_THROW(ch.pop());
77 BOOST_CHECK_OPERATION_SEQUENCE(seq);
78
79 // Test filter reuse and io::close()
80 seq.reset();
81 ch.push(
82 t: closable_device<bidirectional>(
83 seq.new_operation(id: 1),
84 seq.new_operation(id: 4)
85 )
86 );
87 BOOST_CHECK_NO_THROW(io::close(ch));
88 BOOST_CHECK_OPERATION_SEQUENCE(seq);
89
90 // Test filter reuse and chain::reset()
91 seq.reset();
92 ch.push(
93 t: closable_device<bidirectional>(
94 seq.new_operation(id: 1),
95 seq.new_operation(id: 4)
96 )
97 );
98 BOOST_CHECK_NO_THROW(ch.reset());
99 BOOST_CHECK_OPERATION_SEQUENCE(seq);
100 }
101
102 // Test seekable filter and device
103 {
104 operation_sequence seq;
105 filtering_streambuf<input> ch;
106
107 // Test chain::pop()
108 ch.push(t: closable_filter<seekable>(seq.new_operation(id: 1)));
109 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
110 BOOST_CHECK_NO_THROW(ch.pop());
111 BOOST_CHECK_OPERATION_SEQUENCE(seq);
112
113 // Test filter reuse and io::close()
114 seq.reset();
115 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
116 BOOST_CHECK_NO_THROW(io::close(ch));
117 BOOST_CHECK_OPERATION_SEQUENCE(seq);
118
119 // Test filter reuse and chain::reset()
120 seq.reset();
121 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
122 BOOST_CHECK_NO_THROW(ch.reset());
123 BOOST_CHECK_OPERATION_SEQUENCE(seq);
124 }
125
126 // Test dual-user filter
127 {
128 operation_sequence seq;
129 filtering_streambuf<input> ch;
130 operation dummy;
131
132 // Test chain::pop()
133 ch.push(
134 t: closable_filter<dual_use>(
135 seq.new_operation(id: 2),
136 dummy
137 )
138 );
139 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
140 BOOST_CHECK_NO_THROW(ch.pop());
141 BOOST_CHECK_OPERATION_SEQUENCE(seq);
142
143 // Test filter reuse and io::close()
144 seq.reset();
145 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
146 BOOST_CHECK_NO_THROW(io::close(ch));
147 BOOST_CHECK_OPERATION_SEQUENCE(seq);
148
149 // Test filter reuse and chain::reset()
150 seq.reset();
151 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
152 BOOST_CHECK_NO_THROW(ch.reset());
153 BOOST_CHECK_OPERATION_SEQUENCE(seq);
154 }
155
156 // Test direct source
157 {
158 operation_sequence seq;
159 filtering_streambuf<input> ch;
160
161 // Test chain::pop()
162 ch.push(t: closable_filter<input>(seq.new_operation(id: 2)));
163 ch.push(t: closable_device<direct_input>(seq.new_operation(id: 1)));
164 BOOST_CHECK_NO_THROW(ch.pop());
165 BOOST_CHECK_OPERATION_SEQUENCE(seq);
166
167 // Test filter reuse and io::close()
168 seq.reset();
169 ch.push(t: closable_device<direct_input>(seq.new_operation(id: 1)));
170 BOOST_CHECK_NO_THROW(io::close(ch));
171 BOOST_CHECK_OPERATION_SEQUENCE(seq);
172
173 // Test filter reuse and chain::reset()
174 seq.reset();
175 ch.push(t: closable_device<direct_input>(seq.new_operation(id: 1)));
176 BOOST_CHECK_NO_THROW(ch.reset());
177 BOOST_CHECK_OPERATION_SEQUENCE(seq);
178 }
179
180 // Test direct bidirectional device
181 {
182 operation_sequence seq;
183 filtering_streambuf<input> ch;
184
185 // Test chain::pop()
186 ch.push(t: closable_filter<input>(seq.new_operation(id: 2)));
187 ch.push(
188 t: closable_device<direct_bidirectional>(
189 seq.new_operation(id: 1),
190 seq.new_operation(id: 3)
191 )
192 );
193 BOOST_CHECK_NO_THROW(ch.pop());
194 BOOST_CHECK_OPERATION_SEQUENCE(seq);
195
196 // Test filter reuse and io::close()
197 seq.reset();
198 ch.push(
199 t: closable_device<direct_bidirectional>(
200 seq.new_operation(id: 1),
201 seq.new_operation(id: 3)
202 )
203 );
204 BOOST_CHECK_NO_THROW(io::close(ch));
205 BOOST_CHECK_OPERATION_SEQUENCE(seq);
206
207 // Test filter reuse and chain::reset()
208 seq.reset();
209 ch.push(
210 t: closable_device<direct_bidirectional>(
211 seq.new_operation(id: 1),
212 seq.new_operation(id: 3)
213 )
214 );
215 BOOST_CHECK_NO_THROW(ch.reset());
216 BOOST_CHECK_OPERATION_SEQUENCE(seq);
217 }
218
219 // Test direct seekable device
220 {
221 operation_sequence seq;
222 filtering_streambuf<input> ch;
223
224 // Test chain::pop()
225 ch.push(t: closable_filter<input>(seq.new_operation(id: 1)));
226 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
227 BOOST_CHECK_NO_THROW(ch.pop());
228 BOOST_CHECK_OPERATION_SEQUENCE(seq);
229
230 // Test filter reuse and io::close()
231 seq.reset();
232 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
233 BOOST_CHECK_NO_THROW(io::close(ch));
234 BOOST_CHECK_OPERATION_SEQUENCE(seq);
235
236 // Test filter reuse and chain::reset()
237 seq.reset();
238 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
239 BOOST_CHECK_NO_THROW(ch.reset());
240 BOOST_CHECK_OPERATION_SEQUENCE(seq);
241 }
242}
243
244void output_chain_test()
245{
246 // Test output filter and device
247 {
248 operation_sequence seq;
249 filtering_streambuf<output> ch;
250
251 // Test chain::pop()
252 ch.push(t: closable_filter<output>(seq.new_operation(id: 1)));
253 ch.push(t: closable_device<output>(seq.new_operation(id: 2)));
254 BOOST_CHECK_NO_THROW(ch.pop());
255 BOOST_CHECK_OPERATION_SEQUENCE(seq);
256
257 // Test filter reuse and io::close()
258 seq.reset();
259 ch.push(t: closable_device<output>(seq.new_operation(id: 2)));
260 BOOST_CHECK_NO_THROW(io::close(ch));
261 BOOST_CHECK_OPERATION_SEQUENCE(seq);
262
263 // Test filter reuse and chain::reset()
264 seq.reset();
265 ch.push(t: closable_device<output>(seq.new_operation(id: 2)));
266 BOOST_CHECK_NO_THROW(ch.reset());
267 BOOST_CHECK_OPERATION_SEQUENCE(seq);
268 }
269
270 // Test bidirectional filter and device
271 {
272 operation_sequence seq;
273 filtering_streambuf<output> ch;
274
275 // Test chain::pop()
276 ch.push(
277 t: closable_filter<bidirectional>(
278 seq.new_operation(id: 2),
279 seq.new_operation(id: 3)
280 )
281 );
282 ch.push(
283 t: closable_device<bidirectional>(
284 seq.new_operation(id: 1),
285 seq.new_operation(id: 4)
286 )
287 );
288 BOOST_CHECK_NO_THROW(ch.pop());
289 BOOST_CHECK_OPERATION_SEQUENCE(seq);
290
291 // Test filter reuse and io::close()
292 seq.reset();
293 ch.push(
294 t: closable_device<bidirectional>(
295 seq.new_operation(id: 1),
296 seq.new_operation(id: 4)
297 )
298 );
299 BOOST_CHECK_NO_THROW(io::close(ch));
300 BOOST_CHECK_OPERATION_SEQUENCE(seq);
301
302 // Test filter reuse and chain::reset()
303 seq.reset();
304 ch.push(
305 t: closable_device<bidirectional>(
306 seq.new_operation(id: 1),
307 seq.new_operation(id: 4)
308 )
309 );
310 BOOST_CHECK_NO_THROW(ch.reset());
311 BOOST_CHECK_OPERATION_SEQUENCE(seq);
312 }
313
314 // Test seekable filter and device
315 {
316 operation_sequence seq;
317 filtering_streambuf<output> ch;
318
319 // Test chain::pop()
320 ch.push(t: closable_filter<seekable>(seq.new_operation(id: 1)));
321 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
322 BOOST_CHECK_NO_THROW(ch.pop());
323 BOOST_CHECK_OPERATION_SEQUENCE(seq);
324
325 // Test filter reuse and io::close()
326 seq.reset();
327 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
328 BOOST_CHECK_NO_THROW(io::close(ch));
329 BOOST_CHECK_OPERATION_SEQUENCE(seq);
330
331 // Test filter reuse and chain::reset()
332 seq.reset();
333 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
334 BOOST_CHECK_NO_THROW(ch.reset());
335 BOOST_CHECK_OPERATION_SEQUENCE(seq);
336 }
337
338 // Test dual-user filter
339 {
340 operation_sequence seq;
341 filtering_streambuf<output> ch;
342 operation dummy;
343
344 // Test chain::pop()
345 ch.push(
346 t: closable_filter<dual_use>(
347 dummy,
348 seq.new_operation(id: 1)
349 )
350 );
351 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
352 BOOST_CHECK_NO_THROW(ch.pop());
353 BOOST_CHECK_OPERATION_SEQUENCE(seq);
354
355 // Test filter reuse and io::close()
356 seq.reset();
357 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
358 BOOST_CHECK_NO_THROW(io::close(ch));
359 BOOST_CHECK_OPERATION_SEQUENCE(seq);
360
361 // Test filter reuse and chain::reset()
362 seq.reset();
363 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
364 BOOST_CHECK_NO_THROW(ch.reset());
365 BOOST_CHECK_OPERATION_SEQUENCE(seq);
366 }
367
368 // Test direct sink
369 {
370 operation_sequence seq;
371 filtering_streambuf<output> ch;
372
373 // Test chain::pop()
374 ch.push(t: closable_filter<output>(seq.new_operation(id: 1)));
375 ch.push(t: closable_device<direct_output>(seq.new_operation(id: 2)));
376 BOOST_CHECK_NO_THROW(ch.pop());
377 BOOST_CHECK_OPERATION_SEQUENCE(seq);
378
379 // Test filter reuse and io::close()
380 seq.reset();
381 ch.push(t: closable_device<direct_output>(seq.new_operation(id: 2)));
382 BOOST_CHECK_NO_THROW(io::close(ch));
383 BOOST_CHECK_OPERATION_SEQUENCE(seq);
384
385 // Test filter reuse and chain::reset()
386 seq.reset();
387 ch.push(t: closable_device<direct_output>(seq.new_operation(id: 2)));
388 BOOST_CHECK_NO_THROW(ch.reset());
389 BOOST_CHECK_OPERATION_SEQUENCE(seq);
390 }
391
392 // Test direct bidirectional device
393 {
394 operation_sequence seq;
395 filtering_streambuf<output> ch;
396
397 // Test chain::pop()
398 ch.push(t: closable_filter<output>(seq.new_operation(id: 2)));
399 ch.push(
400 t: closable_device<direct_bidirectional>(
401 seq.new_operation(id: 1),
402 seq.new_operation(id: 3)
403 )
404 );
405 BOOST_CHECK_NO_THROW(ch.pop());
406 BOOST_CHECK_OPERATION_SEQUENCE(seq);
407
408 // Test filter reuse and io::close()
409 seq.reset();
410 ch.push(
411 t: closable_device<direct_bidirectional>(
412 seq.new_operation(id: 1),
413 seq.new_operation(id: 3)
414 )
415 );
416 BOOST_CHECK_NO_THROW(io::close(ch));
417 BOOST_CHECK_OPERATION_SEQUENCE(seq);
418
419 // Test filter reuse and chain::reset()
420 seq.reset();
421 ch.push(
422 t: closable_device<direct_bidirectional>(
423 seq.new_operation(id: 1),
424 seq.new_operation(id: 3)
425 )
426 );
427 BOOST_CHECK_NO_THROW(ch.reset());
428 BOOST_CHECK_OPERATION_SEQUENCE(seq);
429 }
430
431 // Test direct seekable device
432 {
433 operation_sequence seq;
434 filtering_streambuf<output> ch;
435
436 // Test chain::pop()
437 ch.push(t: closable_filter<output>(seq.new_operation(id: 1)));
438 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
439 BOOST_CHECK_NO_THROW(ch.pop());
440 BOOST_CHECK_OPERATION_SEQUENCE(seq);
441
442 // Test filter reuse and io::close()
443 seq.reset();
444 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
445 BOOST_CHECK_NO_THROW(io::close(ch));
446 BOOST_CHECK_OPERATION_SEQUENCE(seq);
447
448 // Test filter reuse and chain::reset()
449 seq.reset();
450 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
451 BOOST_CHECK_NO_THROW(ch.reset());
452 BOOST_CHECK_OPERATION_SEQUENCE(seq);
453 }
454}
455
456void bidirectional_chain_test()
457{
458 // Test bidirectional filter and device
459 {
460 operation_sequence seq;
461 filtering_streambuf<bidirectional> ch;
462
463 // Test chain::pop()
464 ch.push(
465 t: closable_filter<bidirectional>(
466 seq.new_operation(id: 2),
467 seq.new_operation(id: 3)
468 )
469 );
470 ch.push(
471 t: closable_device<bidirectional>(
472 seq.new_operation(id: 1),
473 seq.new_operation(id: 4)
474 )
475 );
476 BOOST_CHECK_NO_THROW(ch.pop());
477 BOOST_CHECK_OPERATION_SEQUENCE(seq);
478
479 // Test filter reuse and io::close()
480 seq.reset();
481 ch.push(
482 t: closable_device<bidirectional>(
483 seq.new_operation(id: 1),
484 seq.new_operation(id: 4)
485 )
486 );
487 BOOST_CHECK_NO_THROW(io::close(ch));
488 BOOST_CHECK_OPERATION_SEQUENCE(seq);
489
490 // Test filter reuse and chain::reset()
491 seq.reset();
492 ch.push(
493 t: closable_device<bidirectional>(
494 seq.new_operation(id: 1),
495 seq.new_operation(id: 4)
496 )
497 );
498 BOOST_CHECK_NO_THROW(ch.reset());
499 BOOST_CHECK_OPERATION_SEQUENCE(seq);
500 }
501
502 // Test direct bidirectional device
503 {
504 operation_sequence seq;
505 filtering_streambuf<bidirectional> ch;
506
507 // Test chain::pop()
508 ch.push(
509 t: closable_filter<bidirectional>(
510 seq.new_operation(id: 2),
511 seq.new_operation(id: 3)
512 )
513 );
514 ch.push(
515 t: closable_device<direct_bidirectional>(
516 seq.new_operation(id: 1),
517 seq.new_operation(id: 4)
518 )
519 );
520 BOOST_CHECK_NO_THROW(ch.pop());
521 BOOST_CHECK_OPERATION_SEQUENCE(seq);
522
523 // Test filter reuse and io::close()
524 seq.reset();
525 ch.push(
526 t: closable_device<direct_bidirectional>(
527 seq.new_operation(id: 1),
528 seq.new_operation(id: 4)
529 )
530 );
531 BOOST_CHECK_NO_THROW(io::close(ch));
532 BOOST_CHECK_OPERATION_SEQUENCE(seq);
533
534 // Test filter reuse and chain::reset()
535 seq.reset();
536 ch.push(
537 t: closable_device<direct_bidirectional>(
538 seq.new_operation(id: 1),
539 seq.new_operation(id: 4)
540 )
541 );
542 BOOST_CHECK_NO_THROW(ch.reset());
543 BOOST_CHECK_OPERATION_SEQUENCE(seq);
544 }
545}
546
547void seekable_chain_test()
548{
549 // Test seekable filter and device
550 {
551 operation_sequence seq;
552 filtering_streambuf<seekable> ch;
553
554 // Test chain::pop()
555 ch.push(t: closable_filter<seekable>(seq.new_operation(id: 1)));
556 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
557 BOOST_CHECK_NO_THROW(ch.pop());
558 BOOST_CHECK_OPERATION_SEQUENCE(seq);
559
560 // Test filter reuse and io::close()
561 seq.reset();
562 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
563 BOOST_CHECK_NO_THROW(io::close(ch));
564 BOOST_CHECK_OPERATION_SEQUENCE(seq);
565
566 // Test filter reuse and chain::reset()
567 seq.reset();
568 ch.push(t: closable_device<seekable>(seq.new_operation(id: 2)));
569 BOOST_CHECK_NO_THROW(ch.reset());
570 BOOST_CHECK_OPERATION_SEQUENCE(seq);
571 }
572
573 // Test direct seekable device
574 {
575 operation_sequence seq;
576 filtering_streambuf<seekable> ch;
577
578 // Test chain::pop()
579 ch.push(t: closable_filter<seekable>(seq.new_operation(id: 1)));
580 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
581 BOOST_CHECK_NO_THROW(ch.pop());
582 BOOST_CHECK_OPERATION_SEQUENCE(seq);
583
584 // Test filter reuse and io::close()
585 seq.reset();
586 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
587 BOOST_CHECK_NO_THROW(io::close(ch));
588 BOOST_CHECK_OPERATION_SEQUENCE(seq);
589
590 // Test filter reuse and chain::reset()
591 seq.reset();
592 ch.push(t: closable_device<direct_seekable>(seq.new_operation(id: 2)));
593 BOOST_CHECK_NO_THROW(ch.reset());
594 BOOST_CHECK_OPERATION_SEQUENCE(seq);
595 }
596}
597
598void stream_test()
599{
600 // Test source
601 {
602 operation_sequence seq;
603 stream< closable_device<input> > str;
604 str.open(t: closable_device<input>(seq.new_operation(id: 1)));
605 BOOST_CHECK_NO_THROW(str.close());
606 BOOST_CHECK_OPERATION_SEQUENCE(seq);
607 }
608
609 // Test sink
610 {
611 operation_sequence seq;
612 stream< closable_device<output> > str;
613 str.open(t: closable_device<output>(seq.new_operation(id: 1)));
614 BOOST_CHECK_NO_THROW(str.close());
615 BOOST_CHECK_OPERATION_SEQUENCE(seq);
616 }
617
618 // Test bidirectional device
619 {
620 operation_sequence seq;
621 stream< closable_device<bidirectional> > str;
622 str.open(
623 t: closable_device<bidirectional>(
624 seq.new_operation(id: 1),
625 seq.new_operation(id: 2)
626 )
627 );
628 BOOST_CHECK_NO_THROW(str.close());
629 BOOST_CHECK_OPERATION_SEQUENCE(seq);
630 }
631
632 // Test seekable device
633 {
634 operation_sequence seq;
635 stream< closable_device<seekable> > str;
636 str.open(t: closable_device<seekable>(seq.new_operation(id: 1)));
637 BOOST_CHECK_NO_THROW(str.close());
638 BOOST_CHECK_OPERATION_SEQUENCE(seq);
639 }
640}
641
642test_suite* init_unit_test_suite(int, char* [])
643{
644 test_suite* test = BOOST_TEST_SUITE("execute test");
645 test->add(BOOST_TEST_CASE(&input_chain_test));
646 test->add(BOOST_TEST_CASE(&output_chain_test));
647 test->add(BOOST_TEST_CASE(&bidirectional_chain_test));
648 test->add(BOOST_TEST_CASE(&seekable_chain_test));
649 test->add(BOOST_TEST_CASE(&stream_test));
650 return test;
651}
652

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