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 <cctype>
9#include <boost/iostreams/compose.hpp>
10#include <boost/iostreams/device/file.hpp>
11#include <boost/iostreams/filtering_stream.hpp>
12#include <boost/test/test_tools.hpp>
13#include <boost/test/unit_test.hpp>
14#include "detail/closable.hpp"
15#include "detail/operation_sequence.hpp"
16#include "detail/filters.hpp"
17#include "detail/temp_file.hpp"
18#include "detail/verification.hpp"
19
20// Must come last.
21#include <boost/iostreams/detail/config/disable_warnings.hpp> // BCC 5.x.
22
23using namespace std;
24using namespace boost::iostreams;
25using namespace boost::iostreams::test;
26using boost::unit_test::test_suite;
27namespace io = boost::iostreams;
28
29void read_composite()
30{
31 test_file src1, src2;
32 filtering_istream first, second;
33
34 // Test composite device
35 first.push(t: toupper_filter());
36 first.push(t: padding_filter('a'));
37 first.push(t: file_source(src1.name(), in_mode));
38 second.push( t: compose( filter: toupper_filter(),
39 fod: compose( filter: padding_filter('a'),
40 fod: file_source(src1.name(), in_mode) ) ) );
41 BOOST_CHECK_MESSAGE(
42 compare_streams_in_chunks(first, second),
43 "failed reading from a stdio_filter"
44 );
45
46 // Test composite filter
47 first.reset();
48 second.reset();
49 first.push(t: toupper_filter());
50 first.push(t: padding_filter('a'));
51 first.push(t: file_source(src1.name(), in_mode));
52 second.push( t: compose( filter: compose( filter: toupper_filter(),
53 fod: padding_filter('a') ),
54 fod: file_source(src1.name(), in_mode) ) );
55 BOOST_CHECK_MESSAGE(
56 compare_streams_in_chunks(first, second),
57 "failed reading from a stdio_filter"
58 );
59}
60
61void write_composite()
62{
63 temp_file dest1, dest2;
64 filtering_ostream out1, out2;
65
66 // Test composite device
67 out1.push(t: tolower_filter());
68 out1.push(t: padding_filter('a'));
69 out1.push(t: file_sink(dest1.name(), in_mode));
70 out2.push( t: compose( filter: tolower_filter(),
71 fod: compose( filter: padding_filter('a'),
72 fod: file_sink(dest2.name(), in_mode) ) ) );
73 write_data_in_chunks(os&: out1);
74 write_data_in_chunks(os&: out2);
75 out1.reset();
76 out2.reset();
77
78 {
79 ifstream first(dest1.name().c_str());
80 ifstream second(dest2.name().c_str());
81 BOOST_CHECK_MESSAGE(
82 compare_streams_in_chunks(first, second),
83 "failed writing to a stdio_filter"
84 );
85 }
86
87 // Test composite filter
88 out1.push(t: tolower_filter());
89 out1.push(t: padding_filter('a'));
90 out1.push(t: file_sink(dest1.name(), in_mode));
91 out2.push( t: compose( filter: compose( filter: tolower_filter(),
92 fod: padding_filter('a') ),
93 fod: file_sink(dest2.name(), in_mode) ) );
94 write_data_in_chunks(os&: out1);
95 write_data_in_chunks(os&: out2);
96 out1.reset();
97 out2.reset();
98
99 {
100 ifstream first(dest1.name().c_str());
101 ifstream second(dest2.name().c_str());
102 BOOST_CHECK_MESSAGE(
103 compare_streams_in_chunks(first, second),
104 "failed writing to a stdio_filter"
105 );
106 }
107}
108
109void close_composite_device()
110{
111 // Compose an input filter with a source
112 {
113 operation_sequence seq;
114 chain<input> ch;
115 ch.push(
116 t: io::compose(
117 filter: closable_filter<input>(seq.new_operation(id: 2)),
118 fod: closable_device<input>(seq.new_operation(id: 1))
119 )
120 );
121 BOOST_CHECK_NO_THROW(ch.reset());
122 BOOST_CHECK_OPERATION_SEQUENCE(seq);
123 }
124
125 // Compose a bidirectional filter with a source
126 {
127 operation_sequence seq;
128 chain<input> ch;
129 ch.push(
130 t: io::compose(
131 filter: closable_filter<bidirectional>(
132 seq.new_operation(id: 2),
133 seq.new_operation(id: 3)
134 ),
135 fod: closable_device<input>(seq.new_operation(id: 1))
136 )
137 );
138 BOOST_CHECK_NO_THROW(ch.reset());
139 BOOST_CHECK_OPERATION_SEQUENCE(seq);
140 }
141
142 // Compose a seekable filter with a source
143 {
144 operation_sequence seq;
145 chain<input> ch;
146 ch.push(
147 t: io::compose(
148 filter: closable_filter<seekable>(seq.new_operation(id: 2)),
149 fod: closable_device<input>(seq.new_operation(id: 1))
150 )
151 );
152 BOOST_CHECK_NO_THROW(ch.reset());
153 BOOST_CHECK_OPERATION_SEQUENCE(seq);
154 }
155
156 // Compose a dual-use filter with a source
157 {
158 operation_sequence seq;
159 chain<input> ch;
160 operation dummy;
161 ch.push(
162 t: io::compose(
163 filter: closable_filter<dual_use>(
164 seq.new_operation(id: 2),
165 dummy
166 ),
167 fod: closable_device<input>(seq.new_operation(id: 1))
168 )
169 );
170 BOOST_CHECK_NO_THROW(ch.reset());
171 BOOST_CHECK_OPERATION_SEQUENCE(seq);
172 }
173
174 // Compose an output filter with a sink
175 {
176 operation_sequence seq;
177 chain<output> ch;
178 ch.push(
179 t: io::compose(
180 filter: closable_filter<output>(seq.new_operation(id: 1)),
181 fod: closable_device<output>(seq.new_operation(id: 2))
182 )
183 );
184 BOOST_CHECK_NO_THROW(ch.reset());
185 BOOST_CHECK_OPERATION_SEQUENCE(seq);
186 }
187
188 // Compose a bidirectional filter with a sink
189 {
190 operation_sequence seq;
191 chain<output> ch;
192 ch.push(
193 t: io::compose(
194 filter: closable_filter<bidirectional>(
195 seq.new_operation(id: 1),
196 seq.new_operation(id: 2)
197 ),
198 fod: closable_device<output>(seq.new_operation(id: 3))
199 )
200 );
201 BOOST_CHECK_NO_THROW(ch.reset());
202 BOOST_CHECK_OPERATION_SEQUENCE(seq);
203 }
204
205 // Compose a seekable filter with a sink
206 {
207 operation_sequence seq;
208 chain<output> ch;
209 ch.push(
210 t: io::compose(
211 filter: closable_filter<seekable>(seq.new_operation(id: 1)),
212 fod: closable_device<output>(seq.new_operation(id: 2))
213 )
214 );
215 BOOST_CHECK_NO_THROW(ch.reset());
216 BOOST_CHECK_OPERATION_SEQUENCE(seq);
217 }
218
219 // Compose a dual-use filter with a sink
220 {
221 operation_sequence seq;
222 chain<output> ch;
223 operation dummy;
224 ch.push(
225 t: io::compose(
226 filter: closable_filter<dual_use>(
227 dummy,
228 seq.new_operation(id: 1)
229 ),
230 fod: closable_device<output>(seq.new_operation(id: 2))
231 )
232 );
233 BOOST_CHECK_NO_THROW(ch.reset());
234 BOOST_CHECK_OPERATION_SEQUENCE(seq);
235 }
236
237 // Compose a bidirectional filter with a bidirectional device
238 {
239 operation_sequence seq;
240 chain<bidirectional> ch;
241 ch.push(
242 t: io::compose(
243 filter: closable_filter<bidirectional>(
244 seq.new_operation(id: 2),
245 seq.new_operation(id: 3)
246 ),
247 fod: closable_device<bidirectional>(
248 seq.new_operation(id: 1),
249 seq.new_operation(id: 4)
250 )
251 )
252 );
253 BOOST_CHECK_NO_THROW(ch.reset());
254 BOOST_CHECK_OPERATION_SEQUENCE(seq);
255 }
256
257 // Compose a seekable filter with a seekable device
258 {
259 operation_sequence seq;
260 chain<seekable> ch;
261 ch.push(
262 t: io::compose(
263 filter: closable_filter<seekable>(seq.new_operation(id: 1)),
264 fod: closable_device<seekable>(seq.new_operation(id: 2))
265 )
266 );
267 BOOST_CHECK_NO_THROW(ch.reset());
268 BOOST_CHECK_OPERATION_SEQUENCE(seq);
269 }
270}
271
272void close_composite_filter()
273{
274 // Compose two input filters
275 {
276 operation_sequence seq;
277 chain<input> ch;
278 ch.push(
279 t: io::compose(
280 filter: closable_filter<input>(seq.new_operation(id: 3)),
281 fod: closable_filter<input>(seq.new_operation(id: 2))
282 )
283 );
284 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
285 BOOST_CHECK_NO_THROW(ch.reset());
286 BOOST_CHECK_OPERATION_SEQUENCE(seq);
287 }
288
289 // Compose a bidirectional filter with an input filter
290 {
291 operation_sequence seq;
292 chain<input> ch;
293 ch.push(
294 t: io::compose(
295 filter: closable_filter<bidirectional>(
296 seq.new_operation(id: 3),
297 seq.new_operation(id: 4)
298 ),
299 fod: closable_filter<input>(seq.new_operation(id: 2))
300 )
301 );
302 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
303 BOOST_CHECK_NO_THROW(ch.reset());
304 BOOST_CHECK_MESSAGE(seq.is_success(), seq.message());
305 }
306
307 // Compose a seekable filter with an input filter
308 {
309 operation_sequence seq;
310 chain<input> ch;
311 ch.push(
312 t: io::compose(
313 filter: closable_filter<seekable>(seq.new_operation(id: 3)),
314 fod: closable_filter<input>(seq.new_operation(id: 2))
315 )
316 );
317 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
318 BOOST_CHECK_NO_THROW(ch.reset());
319 BOOST_CHECK_OPERATION_SEQUENCE(seq);
320 }
321
322 // Compose a dual-use filter with an input filter
323 {
324 operation_sequence seq;
325 chain<input> ch;
326 operation dummy;
327 ch.push(
328 t: io::compose(
329 filter: closable_filter<dual_use>(
330 seq.new_operation(id: 3),
331 dummy
332 ),
333 fod: closable_filter<input>(seq.new_operation(id: 2))
334 )
335 );
336 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
337 BOOST_CHECK_NO_THROW(ch.reset());
338 BOOST_CHECK_OPERATION_SEQUENCE(seq);
339 }
340
341 // Compose two output filters
342 {
343 operation_sequence seq;
344 chain<output> ch;
345 ch.push(
346 t: io::compose(
347 filter: closable_filter<output>(seq.new_operation(id: 1)),
348 fod: closable_filter<output>(seq.new_operation(id: 2))
349 )
350 );
351 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
352 BOOST_CHECK_NO_THROW(ch.reset());
353 BOOST_CHECK_OPERATION_SEQUENCE(seq);
354 }
355
356 // Compose a bidirectional filter with an output filter
357 {
358 operation_sequence seq;
359 chain<output> ch;
360 ch.push(
361 t: io::compose(
362 filter: closable_filter<bidirectional>(
363 seq.new_operation(id: 1),
364 seq.new_operation(id: 2)
365 ),
366 fod: closable_filter<output>(seq.new_operation(id: 3))
367 )
368 );
369 ch.push(t: closable_device<output>(seq.new_operation(id: 4)));
370 BOOST_CHECK_NO_THROW(ch.reset());
371 BOOST_CHECK_OPERATION_SEQUENCE(seq);
372 }
373
374 // Compose a seekable filter with an output filter
375 {
376 operation_sequence seq;
377 chain<output> ch;
378 ch.push(
379 t: io::compose(
380 filter: closable_filter<seekable>(seq.new_operation(id: 1)),
381 fod: closable_filter<output>(seq.new_operation(id: 2))
382 )
383 );
384 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
385 BOOST_CHECK_NO_THROW(ch.reset());
386 BOOST_CHECK_OPERATION_SEQUENCE(seq);
387 }
388
389 // Compose a dual-use filter with an output filter
390 {
391 operation_sequence seq;
392 chain<output> ch;
393 operation dummy;
394 ch.push(
395 t: io::compose(
396 filter: closable_filter<dual_use>(
397 dummy,
398 seq.new_operation(id: 1)
399 ),
400 fod: closable_filter<output>(seq.new_operation(id: 2))
401 )
402 );
403 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
404 BOOST_CHECK_NO_THROW(ch.reset());
405 BOOST_CHECK_OPERATION_SEQUENCE(seq);
406 }
407
408 // Compose two bidirectional filters
409 {
410 operation_sequence seq;
411 chain<bidirectional> ch;
412 ch.push(
413 t: io::compose(
414 filter: closable_filter<bidirectional>(
415 seq.new_operation(id: 3),
416 seq.new_operation(id: 4)
417 ),
418 fod: closable_filter<bidirectional>(
419 seq.new_operation(id: 2),
420 seq.new_operation(id: 5)
421 )
422 )
423 );
424 ch.push(
425 t: closable_device<bidirectional>(
426 seq.new_operation(id: 1),
427 seq.new_operation(id: 6)
428 )
429 );
430 BOOST_CHECK_NO_THROW(ch.reset());
431 BOOST_CHECK_OPERATION_SEQUENCE(seq);
432 }
433
434 // Compose two seekable filters
435 {
436 operation_sequence seq;
437 chain<seekable> ch;
438 ch.push(
439 t: io::compose(
440 filter: closable_filter<seekable>(seq.new_operation(id: 1)),
441 fod: closable_filter<seekable>(seq.new_operation(id: 2))
442 )
443 );
444 ch.push(t: closable_device<seekable>(seq.new_operation(id: 3)));
445 BOOST_CHECK_NO_THROW(ch.reset());
446 BOOST_CHECK_OPERATION_SEQUENCE(seq);
447 }
448
449 // Compose two dual-use filters for input
450 {
451 operation_sequence seq;
452 chain<input> ch;
453 operation dummy;
454 ch.push(
455 t: io::compose(
456 filter: closable_filter<dual_use>(
457 seq.new_operation(id: 3),
458 dummy
459 ),
460 fod: closable_filter<dual_use>(
461 seq.new_operation(id: 2),
462 dummy
463 )
464 )
465 );
466 ch.push(t: closable_device<input>(seq.new_operation(id: 1)));
467 BOOST_CHECK_NO_THROW(ch.reset());
468 BOOST_CHECK_OPERATION_SEQUENCE(seq);
469 }
470
471 // Compose two dual-use filters for output
472 {
473 operation_sequence seq;
474 chain<output> ch;
475 operation dummy;
476 ch.push(
477 t: io::compose(
478 filter: closable_filter<dual_use>(
479 dummy,
480 seq.new_operation(id: 1)
481 ),
482 fod: closable_filter<dual_use>(
483 dummy,
484 seq.new_operation(id: 2)
485 )
486 )
487 );
488 ch.push(t: closable_device<output>(seq.new_operation(id: 3)));
489 BOOST_CHECK_NO_THROW(ch.reset());
490 BOOST_CHECK_OPERATION_SEQUENCE(seq);
491 }
492}
493
494test_suite* init_unit_test_suite(int, char* [])
495{
496 test_suite* test = BOOST_TEST_SUITE("line_filter test");
497 test->add(BOOST_TEST_CASE(&read_composite));
498 test->add(BOOST_TEST_CASE(&write_composite));
499 test->add(BOOST_TEST_CASE(&close_composite_device));
500 test->add(BOOST_TEST_CASE(&close_composite_filter));
501 return test;
502}
503
504#include <boost/iostreams/detail/config/enable_warnings.hpp> // BCC 5.x.
505

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