info.hpp 6.7 KB

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