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 <boost/iostreams/device/file.hpp>
10 #include <boost/iostreams/filtering_stream.hpp>
11 #include <boost/iostreams/filter/regex.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 
17 using namespace std;
18 using namespace boost::iostreams;
19 using namespace boost::iostreams::test;
20 using boost::unit_test::test_suite;
21 
22 struct replace_lower {
operator ()replace_lower23     std::string operator() (const boost::match_results<const char*>&)
24     { return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
25 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS
operator ()replace_lower26     std::wstring operator() (const boost::match_results<const wchar_t*>&)
27     { return L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
28 #endif
29 };
30 
regex_filter_test()31 void regex_filter_test()
32 {
33     // Note: Given the basic stream and filter tests, two regex tests
34     // are probably sufficient: reading with a filter based on a function,
35     // and writing with a filter based on a format string.
36 
37     test_file       test;
38     uppercase_file  upper;
39 
40     boost::regex match_lower("[a-z]+");
41     std::string fmt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
42 
43     {
44         // Note: the ifstream second is placed in a nested scope because
45         // closing and reopening a single ifstream failed for CW 9.4 on Windows.
46 
47         // Test reading from a regex filter based on a function in chars.
48         filtering_istream
49             first(boost::iostreams::regex_filter(match_lower, replace_lower()));
50         first.push(file_source(test.name(), in_mode));
51         {
52             ifstream second(upper.name().c_str(), in_mode);
53             BOOST_CHECK_MESSAGE(
54                 compare_streams_in_chars(first, second),
55                 "failed reading from function-based regex_filter in chars"
56             );
57         }
58         first.pop();
59 
60         // Test reading from a regex filter based on a function in chunks.
61         // (Also tests reusing the regex filter.)
62         first.push(file_source(test.name(), in_mode));
63         {
64             ifstream second(upper.name().c_str(), in_mode);
65             BOOST_CHECK_MESSAGE(
66                 compare_streams_in_chunks(first, second),
67                 "failed reading from function-based regex_filter in chunks"
68             );
69         }
70     }
71 
72     {
73         // Note: the ifstream second is placed in a nested scope because
74         // closing and reopening a single ifstream failed for CW 9.4 on Windows.
75 
76         // Test reading from a regex filter based on a format string in chars.
77         filtering_istream
78             first(boost::iostreams::regex_filter(match_lower, fmt));
79         first.push(file_source(test.name(), in_mode));
80         {
81             ifstream second(upper.name().c_str(), in_mode);
82             BOOST_CHECK_MESSAGE(
83                 compare_streams_in_chars(first, second),
84                 "failed reading from format-string-based regex_filter in chars"
85             );
86         }
87         first.pop();
88 
89         // Test reading from a regex filter based on a format string in chunks.
90         // (Also tests reusing the regex filter.)
91         first.push(file_source(test.name(), in_mode));
92         {
93             ifstream second(upper.name().c_str(), in_mode);
94             BOOST_CHECK_MESSAGE(
95                 compare_streams_in_chars(first, second),
96                 "failed reading from format-string-based regex_filter in chunks"
97             );
98         }
99     }
100 
101     {
102         test_file dest1;
103         test_file dest2;
104 
105         // Test writing to a regex filter based on a function in chars.
106         filtering_ostream
107             out(boost::iostreams::regex_filter(match_lower, replace_lower()));
108         out.push(file_sink(dest1.name(), out_mode));
109         write_data_in_chars(out);
110         out.pop();
111         BOOST_CHECK_MESSAGE(
112             compare_files(dest1.name(), upper.name()),
113             "failed writing to function-based regex_filter in chars"
114         );
115 
116         // Test writing to a regex filter based on a function in chunks.
117         // (Also tests reusing the regex filter.)
118         out.push(file_sink(dest2.name(), out_mode));
119         write_data_in_chunks(out);
120         out.pop();
121         BOOST_CHECK_MESSAGE(
122             compare_files(dest2.name(), upper.name()),
123             "failed writing to function-based regex_filter in chunks"
124         );
125     }
126 
127     {
128         test_file dest1;
129         test_file dest2;
130 
131         // Test writing to a regex filter based on a format string in chars.
132         filtering_ostream
133             out(boost::iostreams::regex_filter(match_lower, fmt));
134         out.push(file_sink(dest1.name(), out_mode));
135         write_data_in_chars(out);
136         out.pop();
137         BOOST_CHECK_MESSAGE(
138             compare_files(dest1.name(), upper.name()),
139             "failed writing to format-string-based regex_filter in chars"
140         );
141 
142         // Test writing to a regex filter based on a format string in chunks.
143         // (Also tests reusing the regex filter.)
144         out.push(file_sink(dest2.name(), out_mode));
145         write_data_in_chunks(out);
146         out.pop();
147         BOOST_CHECK_MESSAGE(
148             compare_files(dest2.name(), upper.name()),
149             "failed writing to format-string-based regex_filter in chunks"
150         );
151     }
152 
153     {
154         // Note: the ifstream second is placed in a nested scope because
155         // closing and reopening a single ifstream failed for CW 9.4 on Windows.
156 
157         // Test reading from a regex filter with no matches; this checks that
158         // Ticket #1139 is fixed
159         boost::regex   match_xxx("xxx");
160         test_file      test2;
161         filtering_istream
162             first(boost::iostreams::regex_filter(match_xxx, replace_lower()));
163         first.push(file_source(test.name(), in_mode));
164         {
165             ifstream second(test2.name().c_str(), in_mode);
166             BOOST_CHECK_MESSAGE(
167                 compare_streams_in_chars(first, second),
168                 "failed reading from a regex filter with no matches"
169             );
170         }
171     }
172 }
173 
174 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS
175 
wregex_filter_test()176 void wregex_filter_test()
177 {
178     // Note: Given the basic stream and filter tests, two regex tests
179     // are probably sufficient: reading with a filter based on a function,
180     // and writing with a filter based on a format string.
181 
182     test_file       test;
183     uppercase_file  upper;
184 
185     boost::wregex match_lower(L"[a-z]+");
186     std::wstring fmt = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
187 
188     {
189         // Note: the ifstream second is placed in a nested scope because
190         // closing and reopening a single ifstream failed for CW 9.4 on Windows.
191 
192         // Test reading from a regex filter based on a function in chars.
193         filtering_wistream
194             first(boost::iostreams::wregex_filter(match_lower, replace_lower()));
195         first.push(wfile_source(test.name(), in_mode));
196         {
197             wifstream second(upper.name().c_str(), in_mode);
198             BOOST_CHECK_MESSAGE(
199                 compare_streams_in_chars(first, second),
200                 "failed reading from function-based regex_filter in chars"
201             );
202         }
203         first.pop();
204 
205         // Test reading from a regex filter based on a function in chunks.
206         // (Also tests reusing the regex filter.)
207         first.push(wfile_source(test.name(), in_mode));
208         {
209             wifstream second(upper.name().c_str(), in_mode);
210             BOOST_CHECK_MESSAGE(
211                 compare_streams_in_chunks(first, second),
212                 "failed reading from function-based regex_filter in chunks"
213             );
214         }
215     }
216 
217     {
218         // Note: the ifstream second is placed in a nested scope because
219         // closing and reopening a single ifstream failed for CW 9.4 on Windows.
220 
221         // Test reading from a regex filter based on a format string in chars.
222         filtering_wistream
223             first(boost::iostreams::wregex_filter(match_lower, fmt));
224         first.push(wfile_source(test.name(), in_mode));
225         {
226             wifstream second(upper.name().c_str(), in_mode);
227             BOOST_CHECK_MESSAGE(
228                 compare_streams_in_chars(first, second),
229                 "failed reading from format-string-based regex_filter in chars"
230             );
231         }
232         first.pop();
233 
234         // Test reading from a regex filter based on a format string in chunks.
235         // (Also tests reusing the regex filter.)
236         first.push(wfile_source(test.name(), in_mode));
237         {
238             wifstream second(upper.name().c_str(), in_mode);
239             BOOST_CHECK_MESSAGE(
240                 compare_streams_in_chars(first, second),
241                 "failed reading from format-string-based regex_filter in chunks"
242             );
243         }
244     }
245 
246     {
247         test_file dest1;
248         test_file dest2;
249 
250         // Test writing to a regex filter based on a function in chars.
251         filtering_wostream
252             out(boost::iostreams::wregex_filter(match_lower, replace_lower()));
253         out.push(wfile_sink(dest1.name(), out_mode));
254         write_data_in_chars(out);
255         out.pop();
256         BOOST_CHECK_MESSAGE(
257             compare_files(dest1.name(), upper.name()),
258             "failed writing to function-based regex_filter in chars"
259         );
260 
261         // Test writing to a regex filter based on a function in chunks.
262         // (Also tests reusing the regex filter.)
263         out.push(wfile_sink(dest2.name(), out_mode));
264         write_data_in_chunks(out);
265         out.pop();
266         BOOST_CHECK_MESSAGE(
267             compare_files(dest2.name(), upper.name()),
268             "failed writing to function-based regex_filter in chunks"
269         );
270     }
271 
272     {
273         test_file dest1;
274         test_file dest2;
275 
276         // Test writing to a regex filter based on a format string in chars.
277         filtering_wostream
278             out(boost::iostreams::wregex_filter(match_lower, fmt));
279         out.push(wfile_sink(dest1.name(), out_mode));
280         write_data_in_chars(out);
281         out.pop();
282         BOOST_CHECK_MESSAGE(
283             compare_files(dest1.name(), upper.name()),
284             "failed writing to format-string-based regex_filter in chars"
285         );
286 
287         // Test writing to a regex filter based on a format string in chunks.
288         // (Also tests reusing the regex filter.)
289         out.push(wfile_sink(dest2.name(), out_mode));
290         write_data_in_chunks(out);
291         out.pop();
292         BOOST_CHECK_MESSAGE(
293             compare_files(dest2.name(), upper.name()),
294             "failed writing to format-string-based regex_filter in chunks"
295         );
296     }
297 
298     {
299         // Note: the ifstream second is placed in a nested scope because
300         // closing and reopening a single ifstream failed for CW 9.4 on Windows.
301 
302         // Test reading from a regex filter with no matches; this checks that
303         // Ticket #1139 is fixed
304         boost::wregex   match_xxx(L"xxx");
305         test_file      test2;
306         filtering_wistream
307             first(boost::iostreams::wregex_filter(match_xxx, replace_lower()));
308         first.push(wfile_source(test.name(), in_mode));
309         {
310             wifstream second(test2.name().c_str(), in_mode);
311             BOOST_CHECK_MESSAGE(
312                 compare_streams_in_chars(first, second),
313                 "failed reading from a regex filter with no matches"
314             );
315         }
316     }
317 }
318 
319 #endif
320 
init_unit_test_suite(int,char * [])321 test_suite* init_unit_test_suite(int, char* [])
322 {
323     test_suite* test = BOOST_TEST_SUITE("regex_filter test");
324     test->add(BOOST_TEST_CASE(&regex_filter_test));
325 #ifndef BOOST_IOSTREAMS_NO_WIDE_STREAMS
326     test->add(BOOST_TEST_CASE(&wregex_filter_test));
327 #endif
328     return test;
329 }
330