regex/test/regress/info.hpp
2017-02-21 18:00:08 +00:00

269 lines
6.7 KiB
C++

/*
*
* Copyright (c) 2004
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org for most recent version.
* FILE info.hpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: Error handling for test cases.
*/
#ifndef BOOST_REGEX_REGRESS_INFO_HPP
#define BOOST_REGEX_REGRESS_INFO_HPP
#include <iostream>
#include <string>
#include <boost/regex.hpp>
#ifdef TEST_THREADS
#include <boost/thread/once.hpp>
#include <boost/thread.hpp>
#endif
#ifdef GENERATE_CORPUS
#include <boost/lexical_cast.hpp>
#include <fstream>
//
// class de_fuzz_output
// Generates de-fuzzing corpus files
//
template <class charT>
class de_fuzz_output
{
public:
de_fuzz_output() {}
template <class U>
void add(const U&, const U&) {}
};
template<>
class de_fuzz_output<char>
{
std::set<std::pair<std::string, std::string> > data;
public:
de_fuzz_output() {}
void add(const std::string& re, const std::string& text)
{
data.insert(std::make_pair(re, text));
}
~de_fuzz_output()
{
unsigned j = 0;
for(typename std::set<std::pair<std::string, std::string> >::const_iterator i = data.begin(); i != data.end(); ++i)
{
std::string filename = "corpus_" + boost::lexical_cast<std::string>(j);
std::fstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::binary);
ofs.put(static_cast<char>(i->first.size() >> 8));
ofs.put(static_cast<char>(i->first.size() & 0xff));
ofs.write(i->first.c_str(), i->first.size());
ofs.write(i->second.c_str(), i->second.size());
++j;
}
}
};
#endif
//
// class test info,
// store information about the test we are about to conduct:
//
template <class charT>
class test_info_base
{
public:
typedef std::basic_string<charT> string_type;
private:
struct data_type
{
std::string file;
int line;
string_type expression;
boost::regex_constants::syntax_option_type options;
string_type search_text;
boost::regex_constants::match_flag_type match_options;
const int* answer_table;
string_type format_string;
string_type result_string;
bool need_to_print;
std::string expression_type_name;
};
#ifdef TEST_THREADS
static data_type& do_get_data()
{
static boost::thread_specific_ptr<data_type> pd;
if(pd.get() == 0)
pd.reset(new data_type());
return *(pd.get());
}
static void init_data()
{
do_get_data();
}
#endif
static data_type& data()
{
#ifdef TEST_THREADS
static boost::once_flag f = BOOST_ONCE_INIT;
boost::call_once(f,&init_data);
return do_get_data();
#else
static data_type d;
return d;
#endif
}
public:
test_info_base(){};
static void set_info(
const char* file,
int line,
const string_type& ex,
boost::regex_constants::syntax_option_type opt,
const string_type& search_text = string_type(),
boost::regex_constants::match_flag_type match_options = boost::match_default,
const int* answer_table = 0,
const string_type& format_string = string_type(),
const string_type& result_string = string_type())
{
data_type& dat = data();
dat.file = file;
dat.line = line;
dat.expression = ex;
dat.options = opt;
dat.search_text = search_text;
dat.match_options = match_options;
dat.answer_table = answer_table;
dat.format_string = format_string;
dat.result_string = result_string;
dat.need_to_print = true;
#ifdef GENERATE_CORPUS
static de_fuzz_output<charT> corpus;
corpus.add(ex, search_text);
#endif
}
static void set_typename(const std::string& n)
{
data().expression_type_name = n;
}
static const string_type& expression()
{
return data().expression;
}
static boost::regex_constants::syntax_option_type syntax_options()
{
return data().options;
}
static const string_type& search_text()
{
return data().search_text;
}
static boost::regex_constants::match_flag_type match_options()
{
return data().match_options;
}
static const int* answer_table()
{
return data().answer_table;
}
static const string_type& format_string()
{
return data().format_string;
}
static const string_type& result_string()
{
return data().result_string;
}
static bool need_to_print()
{
return data().need_to_print;
}
static const std::string& file()
{
return data().file;
}
static int line()
{
return data().line;
}
static void clear()
{
data().need_to_print = false;
}
static std::string& expression_typename()
{
return data().expression_type_name;
}
};
template <class T>
struct test_info
: public test_info_base<wchar_t>
{};
template<>
struct test_info<char>
: public test_info_base<char>
{};
#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
// Some template instantiation modes (namely local, implicit local, and weak) of
// this compiler need an explicit instantiation because otherwise we end up with
// multiple copies of the static variable defined in this method. This explicit
// instantiation generates the static variable with common linkage, which makes
// the linker choose only one of the available definitions. For more details,
// see "man ld".
template test_info_base<wchar_t>::data_type & test_info_base<wchar_t>::data();
template test_info_base<char>::data_type & test_info_base<char>::data();
#endif
template <class charT>
std::ostream& operator<<(std::ostream& os, const test_info<charT>&)
{
if(test_info<charT>::need_to_print())
{
os << test_info<charT>::file() << ":" << test_info<charT>::line() << ": Error in test here:" << std::endl;
test_info<charT>::clear();
}
return os;
}
//
// define some test macros:
//
extern int error_count;
#define BOOST_REGEX_TEST_ERROR(msg, charT)\
++error_count;\
std::cerr << test_info<charT>();\
std::cerr << " " << __FILE__ << ":" << __LINE__ << ":" << msg \
<< " (While testing " << test_info<charT>::expression_typename() << ")" << std::endl
class errors_as_warnings
{
public:
errors_as_warnings()
{
m_saved_error_count = error_count;
}
~errors_as_warnings()
{
if(m_saved_error_count != error_count)
{
std::cerr << "<note>The above " << (error_count - m_saved_error_count) << " errors are treated as warnings only.</note>" << std::endl;
error_count = m_saved_error_count;
}
}
private:
int m_saved_error_count;
};
#endif