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 | |
23 | using namespace std; |
24 | using namespace boost::iostreams; |
25 | using namespace boost::iostreams::test; |
26 | using boost::unit_test::test_suite; |
27 | namespace io = boost::iostreams; |
28 | |
29 | void 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 | |
61 | void 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 | |
109 | void 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 | |
272 | void 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 | |
494 | test_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 | |