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 <string>
9#include <boost/iostreams/compose.hpp>
10#include <boost/iostreams/copy.hpp>
11#include <boost/iostreams/device/back_inserter.hpp>
12#include <boost/iostreams/device/null.hpp>
13#include <boost/iostreams/filter/newline.hpp>
14#include <boost/iostreams/filter/test.hpp>
15#include <boost/iostreams/filtering_stream.hpp>
16#include <boost/test/test_tools.hpp>
17#include <boost/test/unit_test.hpp>
18#include <boost/utility/base_from_member.hpp>
19
20namespace io = boost::iostreams;
21using boost::unit_test::test_suite;
22
23const std::string posix =
24 "When I was one-and-twenty\n"
25 "I heard a wise man say,\n"
26 "'Give crowns and pounds and guineas\n"
27 "But not your heart away;\n"
28 "\n"
29 "Give pearls away and rubies\n"
30 "But keep your fancy free.'\n"
31 "But I was one-and-twenty,\n"
32 "No use to talk to me.\n"
33 "\n"
34 "When I was one-and-twenty\n"
35 "I heard him say again,\n"
36 "'The heart out of the bosom\n"
37 "Was never given in vain;\n"
38 "\n"
39 "'Tis paid with sighs a plenty\n"
40 "And sold for endless rue.'\n"
41 "And I am two-and-twenty,\n"
42 "And oh, 'tis true, 'tis true.\n";
43
44const std::string dos =
45 "When I was one-and-twenty\r\n"
46 "I heard a wise man say,\r\n"
47 "'Give crowns and pounds and guineas\r\n"
48 "But not your heart away;\r\n"
49 "\r\n"
50 "Give pearls away and rubies\r\n"
51 "But keep your fancy free.'\r\n"
52 "But I was one-and-twenty,\r\n"
53 "No use to talk to me.\r\n"
54 "\r\n"
55 "When I was one-and-twenty\r\n"
56 "I heard him say again,\r\n"
57 "'The heart out of the bosom\r\n"
58 "Was never given in vain;\r\n"
59 "\r\n"
60 "'Tis paid with sighs a plenty\r\n"
61 "And sold for endless rue.'\r\n"
62 "And I am two-and-twenty,\r\n"
63 "And oh, 'tis true, 'tis true.\r\n";
64
65const std::string mac =
66 "When I was one-and-twenty\r"
67 "I heard a wise man say,\r"
68 "'Give crowns and pounds and guineas\r"
69 "But not your heart away;\r"
70 "\r"
71 "Give pearls away and rubies\r"
72 "But keep your fancy free.'\r"
73 "But I was one-and-twenty,\r"
74 "No use to talk to me.\r"
75 "\r"
76 "When I was one-and-twenty\r"
77 "I heard him say again,\r"
78 "'The heart out of the bosom\r"
79 "Was never given in vain;\r"
80 "\r"
81 "'Tis paid with sighs a plenty\r"
82 "And sold for endless rue.'\r"
83 "And I am two-and-twenty,\r"
84 "And oh, 'tis true, 'tis true.\r";
85
86const std::string no_final_newline =
87 "When I was one-and-twenty\n"
88 "I heard a wise man say,\n"
89 "'Give crowns and pounds and guineas\n"
90 "But not your heart away;\n"
91 "\n"
92 "Give pearls away and rubies\n"
93 "But keep your fancy free.'\n"
94 "But I was one-and-twenty,\n"
95 "No use to talk to me.\n"
96 "\n"
97 "When I was one-and-twenty\n"
98 "I heard him say again,\n"
99 "'The heart out of the bosom\n"
100 "Was never given in vain;\n"
101 "\n"
102 "'Tis paid with sighs a plenty\n"
103 "And sold for endless rue.'\n"
104 "And I am two-and-twenty,\n"
105 "And oh, 'tis true, 'tis true.";
106
107const std::string mixed =
108 "When I was one-and-twenty\n"
109 "I heard a wise man say,\r\n"
110 "'Give crowns and pounds and guineas\r"
111 "But not your heart away;\n"
112 "\r\n"
113 "Give pearls away and rubies\r"
114 "But keep your fancy free.'\n"
115 "But I was one-and-twenty,\r\n"
116 "No use to talk to me.\r"
117 "\r"
118 "When I was one-and-twenty\r\n"
119 "I heard him say again,\r"
120 "'The heart out of the bosom\n"
121 "Was never given in vain;\r\n"
122 "\r"
123 "'Tis paid with sighs a plenty\n"
124 "And sold for endless rue.'\r\n"
125 "And I am two-and-twenty,\r"
126 "And oh, 'tis true, 'tis true.\n";
127
128struct string_source : boost::base_from_member<std::string>, io::array_source {
129 typedef io::array_source base_type;
130 typedef boost::base_from_member<std::string> pbase_type;
131 string_source(const std::string& src)
132 : pbase_type(src), base_type(member.data(), member.size())
133 { }
134
135 string_source(const string_source& src)
136 : pbase_type(src.member), base_type(member.data(), member.size())
137 { }
138};
139
140void read_newline_filter()
141{
142 using namespace io;
143
144 // Test converting to posix format.
145
146 BOOST_CHECK(test_input_filter(newline_filter(newline::posix), posix, posix));
147 BOOST_CHECK(test_input_filter(newline_filter(newline::posix), dos, posix));
148 BOOST_CHECK(test_input_filter(newline_filter(newline::posix), mac, posix));
149 BOOST_CHECK(test_input_filter(newline_filter(newline::posix), mixed, posix));
150
151 // Test converting to dos format.
152
153 BOOST_CHECK(test_input_filter(newline_filter(newline::dos), posix, dos));
154 BOOST_CHECK(test_input_filter(newline_filter(newline::dos), dos, dos));
155 BOOST_CHECK(test_input_filter(newline_filter(newline::dos), mac, dos));
156 BOOST_CHECK(test_input_filter(newline_filter(newline::dos), mixed, dos));
157
158 // Test converting to mac format.
159
160 BOOST_CHECK(test_input_filter(newline_filter(newline::mac), posix, mac));
161 BOOST_CHECK(test_input_filter(newline_filter(newline::mac), dos, mac));
162 BOOST_CHECK(test_input_filter(newline_filter(newline::mac), mac, mac));
163 BOOST_CHECK(test_input_filter(newline_filter(newline::mac), mixed, mac));
164}
165
166// Verify that a filter works as expected with both a non-blocking sink
167// and a normal output stream.
168//
169// test_output_filter only tests for a non-blocking sink.
170// TODO: Other tests should probably test with an output stream.
171
172template<typename Filter>
173bool my_test_output_filter(Filter filter,
174 const std::string& input,
175 const std::string& output)
176{
177 const std::streamsize default_increment = 5;
178
179 for ( int inc = default_increment;
180 inc < default_increment * 40;
181 inc += default_increment )
182 {
183 io::array_source src(input.data(), input.data() + input.size());
184
185 std::ostringstream stream;
186 io::copy(src, compose(filter, stream));
187 if (stream.str() != output )
188 return false;
189
190 }
191 return test_output_filter(filter, input, output);
192}
193
194void write_newline_filter()
195{
196 using namespace io;
197
198 // Test converting to posix format.
199
200 BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), posix, posix));
201 BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), dos, posix));
202 BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), mac, posix));
203 BOOST_CHECK(my_test_output_filter(newline_filter(newline::posix), mixed, posix));
204
205 // Test converting to dos format.
206
207 BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), posix, dos));
208 BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), dos, dos));
209 BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), mac, dos));
210 BOOST_CHECK(my_test_output_filter(newline_filter(newline::dos), mixed, dos));
211
212 // Test converting to mac format.
213
214 BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), posix, mac));
215 BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), dos, mac));
216 BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), mac, mac));
217 BOOST_CHECK(my_test_output_filter(newline_filter(newline::mac), mixed, mac));
218}
219
220void test_input_against_flags(int flags, const std::string& input, bool read)
221{
222 if (read) {
223 io::copy(
224 src: io::compose(
225 filter: io::newline_checker(flags),
226 fod: string_source(input)
227 ),
228 snk: io::null_sink()
229 );
230 } else {
231 io::copy(
232 src: string_source(input),
233 snk: io::compose(filter: io::newline_checker(flags), fod: io::null_sink())
234 );
235 }
236}
237
238void read_newline_checker()
239{
240 io::filtering_istream in;
241 io::newline_checker* checker = 0;
242
243 // Verify properties of ::posix.
244
245 in.push(t: io::newline_checker(io::newline::posix));
246 in.push(t: string_source(::posix));
247 BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink()));
248 checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker);
249 BOOST_CHECK(checker->is_posix());
250 BOOST_CHECK(!checker->is_dos());
251 BOOST_CHECK(!checker->is_mac());
252 BOOST_CHECK(!checker->is_mixed());
253 BOOST_CHECK(checker->has_final_newline());
254 in.pop(); // pop checker.
255
256 // Verify properties of ::dos.
257
258 in.push(t: io::newline_checker(io::newline::dos));
259 in.push(t: string_source(::dos));
260 try {
261 io::copy(src&: in, snk: io::null_sink());
262 } catch (io::newline_error&) {
263 BOOST_CHECK_MESSAGE(
264 false, "failed checking for dos line endings"
265 );
266 }
267 checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker);
268 BOOST_CHECK(!checker->is_posix());
269 BOOST_CHECK(checker->is_dos());
270 BOOST_CHECK(!checker->is_mac());
271 BOOST_CHECK(!checker->is_mixed());
272 BOOST_CHECK(checker->has_final_newline());
273 in.pop(); // pop checker.
274
275 // Verify properties of ::mac.
276
277 in.push(t: io::newline_checker(io::newline::mac));
278 in.push(t: string_source(::mac));
279 BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink()));
280 checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker);
281 BOOST_CHECK(!checker->is_posix());
282 BOOST_CHECK(!checker->is_dos());
283 BOOST_CHECK(checker->is_mac());
284 BOOST_CHECK(!checker->is_mixed());
285 BOOST_CHECK(checker->has_final_newline());
286 in.pop(); // pop checker.
287
288 // Verify properties of no_final_newline.
289
290 in.push(t: io::newline_checker(io::newline::posix));
291 in.push(t: string_source(::no_final_newline));
292 BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink()));
293 checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker);
294 BOOST_CHECK(checker->is_posix());
295 BOOST_CHECK(!checker->is_dos());
296 BOOST_CHECK(!checker->is_mac());
297 BOOST_CHECK(!checker->is_mixed());
298 BOOST_CHECK(!checker->has_final_newline());
299 in.pop(); // pop checker.
300
301 // Verify properties of mixed.
302
303 in.push(t: io::newline_checker());
304 in.push(t: string_source(::mixed));
305 BOOST_CHECK_NO_THROW(io::copy(in, io::null_sink()));
306 checker = BOOST_IOSTREAMS_COMPONENT(in, 0, io::newline_checker);
307 BOOST_CHECK(!checker->is_posix());
308 BOOST_CHECK(!checker->is_dos());
309 BOOST_CHECK(!checker->is_mac());
310 BOOST_CHECK(checker->is_mixed_posix());
311 BOOST_CHECK(checker->is_mixed_dos());
312 BOOST_CHECK(checker->is_mixed_mac());
313 BOOST_CHECK(checker->is_mixed());
314 BOOST_CHECK(checker->has_final_newline());
315 in.pop(); // pop checker.
316
317 // Verify exceptions when input does not satisfy target conditions.
318
319 BOOST_CHECK_THROW(
320 test_input_against_flags(io::newline::dos, ::posix, true),
321 io::newline_error
322 );
323 BOOST_CHECK_THROW(
324 test_input_against_flags(io::newline::mac, ::posix, true),
325 io::newline_error
326 );
327 BOOST_CHECK_THROW(
328 test_input_against_flags(io::newline::posix, ::dos, true),
329 io::newline_error
330 );
331 BOOST_CHECK_THROW(
332 test_input_against_flags(io::newline::mac, ::dos, true),
333 io::newline_error
334 );
335 BOOST_CHECK_THROW(
336 test_input_against_flags(io::newline::posix, ::mac, true),
337 io::newline_error
338 );
339 BOOST_CHECK_THROW(
340 test_input_against_flags(io::newline::dos, ::mac, true),
341 io::newline_error
342 );
343 BOOST_CHECK_THROW(
344 test_input_against_flags(io::newline::final_newline, ::no_final_newline, true),
345 io::newline_error
346 );
347 BOOST_CHECK_THROW(
348 test_input_against_flags(io::newline::posix, ::mixed, true),
349 io::newline_error
350 );
351 BOOST_CHECK_THROW(
352 test_input_against_flags(io::newline::dos, ::mixed, true),
353 io::newline_error
354 );
355 BOOST_CHECK_THROW(
356 test_input_against_flags(io::newline::mac, ::mixed, true),
357 io::newline_error
358 );
359}
360
361void write_newline_checker()
362{
363 io::filtering_ostream out;
364 io::newline_checker* checker = 0;
365
366 // Verify properties of ::posix.
367
368 out.push(t: io::newline_checker(io::newline::posix));
369 out.push(t: io::null_sink());
370 BOOST_CHECK_NO_THROW(io::copy(string_source(::posix), out));
371 checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker);
372 BOOST_CHECK(checker->is_posix());
373 BOOST_CHECK(!checker->is_dos());
374 BOOST_CHECK(!checker->is_mac());
375 BOOST_CHECK(!checker->is_mixed());
376 BOOST_CHECK(checker->has_final_newline());
377 out.pop(); // pop checker.
378
379 // Verify properties of ::dos.
380
381 out.push(t: io::newline_checker(io::newline::dos));
382 out.push(t: io::null_sink());
383 BOOST_CHECK_NO_THROW(io::copy(string_source(::dos), out));
384 checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker);
385 BOOST_CHECK(!checker->is_posix());
386 BOOST_CHECK(checker->is_dos());
387 BOOST_CHECK(!checker->is_mac());
388 BOOST_CHECK(!checker->is_mixed());
389 BOOST_CHECK(checker->has_final_newline());
390 out.pop(); // pop checker.
391
392 // Verify properties of ::mac.
393
394 out.push(t: io::newline_checker(io::newline::mac));
395 out.push(t: io::null_sink());
396 BOOST_CHECK_NO_THROW(io::copy(string_source(::mac), out));
397 checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker);
398 BOOST_CHECK(!checker->is_posix());
399 BOOST_CHECK(!checker->is_dos());
400 BOOST_CHECK(checker->is_mac());
401 BOOST_CHECK(!checker->is_mixed());
402 BOOST_CHECK(checker->has_final_newline());
403 out.pop(); // pop checker.
404
405 // Verify properties of no_final_newline.
406
407 out.push(t: io::newline_checker(io::newline::posix));
408 out.push(t: io::null_sink());
409 BOOST_CHECK_NO_THROW(io::copy(string_source(::no_final_newline), out));
410 checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker);
411 BOOST_CHECK(checker->is_posix());
412 BOOST_CHECK(!checker->is_dos());
413 BOOST_CHECK(!checker->is_mac());
414 BOOST_CHECK(!checker->is_mixed());
415 BOOST_CHECK(!checker->has_final_newline());
416 out.pop(); // pop checker.
417
418 // Verify properties of mixed.
419
420 out.push(t: io::newline_checker());
421 out.push(t: io::null_sink());
422 BOOST_CHECK_NO_THROW(io::copy(string_source(::mixed), out));
423 checker = BOOST_IOSTREAMS_COMPONENT(out, 0, io::newline_checker);
424 BOOST_CHECK(!checker->is_posix());
425 BOOST_CHECK(!checker->is_dos());
426 BOOST_CHECK(!checker->is_mac());
427 BOOST_CHECK(checker->is_mixed_posix());
428 BOOST_CHECK(checker->is_mixed_dos());
429 BOOST_CHECK(checker->is_mixed_mac());
430 BOOST_CHECK(checker->is_mixed());
431 BOOST_CHECK(checker->has_final_newline());
432 out.pop(); // pop checker.
433
434 // Verify exceptions when input does not satisfy target conditions.
435
436 BOOST_CHECK_THROW(
437 test_input_against_flags(io::newline::dos, ::posix, false),
438 io::newline_error
439 );
440 BOOST_CHECK_THROW(
441 test_input_against_flags(io::newline::mac, ::posix, false),
442 io::newline_error
443 );
444 BOOST_CHECK_THROW(
445 test_input_against_flags(io::newline::posix, ::dos, false),
446 io::newline_error
447 );
448 BOOST_CHECK_THROW(
449 test_input_against_flags(io::newline::mac, ::dos, false),
450 io::newline_error
451 );
452 BOOST_CHECK_THROW(
453 test_input_against_flags(io::newline::posix, ::mac, false),
454 io::newline_error
455 );
456 BOOST_CHECK_THROW(
457 test_input_against_flags(io::newline::dos, ::mac, false),
458 io::newline_error
459 );
460 BOOST_CHECK_THROW(
461 test_input_against_flags(io::newline::final_newline, ::no_final_newline, false),
462 io::newline_error
463 );
464 BOOST_CHECK_THROW(
465 test_input_against_flags(io::newline::posix, ::mixed, false),
466 io::newline_error
467 );
468 BOOST_CHECK_THROW(
469 test_input_against_flags(io::newline::dos, ::mixed, false),
470 io::newline_error
471 );
472 BOOST_CHECK_THROW(
473 test_input_against_flags(io::newline::mac, ::mixed, false),
474 io::newline_error
475 );
476}
477
478test_suite* init_unit_test_suite(int, char* [])
479{
480 test_suite* test = BOOST_TEST_SUITE("newline_filter test");
481 test->add(BOOST_TEST_CASE(&read_newline_filter));
482 test->add(BOOST_TEST_CASE(&write_newline_filter));
483 test->add(BOOST_TEST_CASE(&read_newline_checker));
484 test->add(BOOST_TEST_CASE(&write_newline_checker));
485 return test;
486}
487

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