]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * | |
3 | * Copyright (c) 2004 | |
4 | * John Maddock | |
5 | * | |
6 | * Use, modification and distribution are subject to the | |
7 | * Boost Software License, Version 1.0. (See accompanying file | |
8 | * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | * | |
10 | */ | |
11 | ||
12 | /* | |
13 | * LOCATION: see http://www.boost.org for most recent version. | |
14 | * FILE info.hpp | |
15 | * VERSION see <boost/version.hpp> | |
16 | * DESCRIPTION: Error handling for test cases. | |
17 | */ | |
18 | ||
19 | #ifndef BOOST_REGEX_REGRESS_INFO_HPP | |
20 | #define BOOST_REGEX_REGRESS_INFO_HPP | |
21 | #include <iostream> | |
22 | #include <string> | |
23 | #include <boost/regex.hpp> | |
24 | ||
25 | #ifdef TEST_THREADS | |
26 | #include <boost/thread/once.hpp> | |
27 | #include <boost/thread.hpp> | |
28 | #endif | |
b32b8144 FG |
29 | |
30 | #ifdef GENERATE_CORPUS | |
31 | #include <boost/lexical_cast.hpp> | |
32 | #include <fstream> | |
33 | // | |
34 | // class de_fuzz_output | |
35 | // Generates de-fuzzing corpus files | |
36 | // | |
37 | template <class charT> | |
38 | class de_fuzz_output | |
39 | { | |
40 | public: | |
41 | de_fuzz_output() {} | |
42 | template <class U> | |
43 | void add(const U&, const U&) {} | |
44 | }; | |
45 | template<> | |
46 | class de_fuzz_output<char> | |
47 | { | |
48 | std::set<std::pair<std::string, std::string> > data; | |
49 | public: | |
50 | de_fuzz_output() {} | |
51 | void add(const std::string& re, const std::string& text) | |
52 | { | |
53 | data.insert(std::make_pair(re, text)); | |
54 | } | |
55 | ~de_fuzz_output() | |
56 | { | |
57 | unsigned j = 0; | |
58 | for(typename std::set<std::pair<std::string, std::string> >::const_iterator i = data.begin(); i != data.end(); ++i) | |
59 | { | |
60 | std::string filename = "corpus_" + boost::lexical_cast<std::string>(j); | |
61 | std::fstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::binary); | |
62 | ofs.put(static_cast<char>(i->first.size() >> 8)); | |
63 | ofs.put(static_cast<char>(i->first.size() & 0xff)); | |
64 | ofs.write(i->first.c_str(), i->first.size()); | |
65 | ofs.write(i->second.c_str(), i->second.size()); | |
66 | ++j; | |
67 | } | |
68 | } | |
69 | }; | |
70 | #endif | |
7c673cae FG |
71 | // |
72 | // class test info, | |
73 | // store information about the test we are about to conduct: | |
74 | // | |
75 | template <class charT> | |
76 | class test_info_base | |
77 | { | |
78 | public: | |
79 | typedef std::basic_string<charT> string_type; | |
80 | private: | |
81 | struct data_type | |
82 | { | |
83 | std::string file; | |
84 | int line; | |
85 | string_type expression; | |
86 | boost::regex_constants::syntax_option_type options; | |
87 | string_type search_text; | |
88 | boost::regex_constants::match_flag_type match_options; | |
89 | const int* answer_table; | |
90 | string_type format_string; | |
91 | string_type result_string; | |
92 | bool need_to_print; | |
93 | std::string expression_type_name; | |
94 | }; | |
95 | #ifdef TEST_THREADS | |
96 | static data_type& do_get_data() | |
97 | { | |
98 | static boost::thread_specific_ptr<data_type> pd; | |
99 | if(pd.get() == 0) | |
100 | pd.reset(new data_type()); | |
101 | return *(pd.get()); | |
102 | } | |
103 | static void init_data() | |
104 | { | |
105 | do_get_data(); | |
106 | } | |
107 | #endif | |
108 | static data_type& data() | |
109 | { | |
110 | #ifdef TEST_THREADS | |
111 | static boost::once_flag f = BOOST_ONCE_INIT; | |
112 | boost::call_once(f,&init_data); | |
113 | return do_get_data(); | |
114 | #else | |
115 | static data_type d; | |
116 | return d; | |
117 | #endif | |
118 | } | |
119 | public: | |
120 | test_info_base(){}; | |
121 | static void set_info( | |
122 | const char* file, | |
123 | int line, | |
124 | const string_type& ex, | |
125 | boost::regex_constants::syntax_option_type opt, | |
126 | const string_type& search_text = string_type(), | |
127 | boost::regex_constants::match_flag_type match_options = boost::match_default, | |
128 | const int* answer_table = 0, | |
129 | const string_type& format_string = string_type(), | |
130 | const string_type& result_string = string_type()) | |
131 | { | |
132 | data_type& dat = data(); | |
133 | dat.file = file; | |
134 | dat.line = line; | |
135 | dat.expression = ex; | |
136 | dat.options = opt; | |
137 | dat.search_text = search_text; | |
138 | dat.match_options = match_options; | |
139 | dat.answer_table = answer_table; | |
140 | dat.format_string = format_string; | |
141 | dat.result_string = result_string; | |
142 | dat.need_to_print = true; | |
b32b8144 FG |
143 | #ifdef GENERATE_CORPUS |
144 | static de_fuzz_output<charT> corpus; | |
145 | corpus.add(ex, search_text); | |
146 | #endif | |
7c673cae FG |
147 | } |
148 | static void set_typename(const std::string& n) | |
149 | { | |
150 | data().expression_type_name = n; | |
151 | } | |
152 | ||
153 | static const string_type& expression() | |
154 | { | |
155 | return data().expression; | |
156 | } | |
157 | static boost::regex_constants::syntax_option_type syntax_options() | |
158 | { | |
159 | return data().options; | |
160 | } | |
161 | static const string_type& search_text() | |
162 | { | |
163 | return data().search_text; | |
164 | } | |
165 | static boost::regex_constants::match_flag_type match_options() | |
166 | { | |
167 | return data().match_options; | |
168 | } | |
169 | static const int* answer_table() | |
170 | { | |
171 | return data().answer_table; | |
172 | } | |
173 | static const string_type& format_string() | |
174 | { | |
175 | return data().format_string; | |
176 | } | |
177 | static const string_type& result_string() | |
178 | { | |
179 | return data().result_string; | |
180 | } | |
181 | static bool need_to_print() | |
182 | { | |
183 | return data().need_to_print; | |
184 | } | |
185 | static const std::string& file() | |
186 | { | |
187 | return data().file; | |
188 | } | |
189 | static int line() | |
190 | { | |
191 | return data().line; | |
192 | } | |
193 | static void clear() | |
194 | { | |
195 | data().need_to_print = false; | |
196 | } | |
197 | static std::string& expression_typename() | |
198 | { | |
199 | return data().expression_type_name; | |
200 | } | |
201 | }; | |
202 | ||
203 | template <class T> | |
204 | struct test_info | |
205 | : public test_info_base<wchar_t> | |
206 | {}; | |
207 | ||
208 | template<> | |
209 | struct test_info<char> | |
210 | : public test_info_base<char> | |
211 | {}; | |
212 | ||
213 | #if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) | |
214 | ||
215 | // Some template instantiation modes (namely local, implicit local, and weak) of | |
216 | // this compiler need an explicit instantiation because otherwise we end up with | |
217 | // multiple copies of the static variable defined in this method. This explicit | |
218 | // instantiation generates the static variable with common linkage, which makes | |
219 | // the linker choose only one of the available definitions. For more details, | |
220 | // see "man ld". | |
221 | ||
222 | template test_info_base<wchar_t>::data_type & test_info_base<wchar_t>::data(); | |
223 | template test_info_base<char>::data_type & test_info_base<char>::data(); | |
224 | ||
225 | #endif | |
226 | ||
227 | template <class charT> | |
228 | std::ostream& operator<<(std::ostream& os, const test_info<charT>&) | |
229 | { | |
230 | if(test_info<charT>::need_to_print()) | |
231 | { | |
232 | os << test_info<charT>::file() << ":" << test_info<charT>::line() << ": Error in test here:" << std::endl; | |
233 | test_info<charT>::clear(); | |
234 | } | |
235 | return os; | |
236 | } | |
237 | // | |
238 | // define some test macros: | |
239 | // | |
240 | extern int error_count; | |
241 | ||
242 | #define BOOST_REGEX_TEST_ERROR(msg, charT)\ | |
243 | ++error_count;\ | |
244 | std::cerr << test_info<charT>();\ | |
245 | std::cerr << " " << __FILE__ << ":" << __LINE__ << ":" << msg \ | |
246 | << " (While testing " << test_info<charT>::expression_typename() << ")" << std::endl | |
247 | ||
248 | class errors_as_warnings | |
249 | { | |
250 | public: | |
251 | errors_as_warnings() | |
252 | { | |
253 | m_saved_error_count = error_count; | |
254 | } | |
255 | ~errors_as_warnings() | |
256 | { | |
257 | if(m_saved_error_count != error_count) | |
258 | { | |
259 | std::cerr << "<note>The above " << (error_count - m_saved_error_count) << " errors are treated as warnings only.</note>" << std::endl; | |
260 | error_count = m_saved_error_count; | |
261 | } | |
262 | } | |
263 | private: | |
264 | int m_saved_error_count; | |
265 | }; | |
266 | ||
267 | #endif | |
268 |