10 #ifndef __PION_TEST_UNIT_TEST_HEADER__ 11 #define __PION_TEST_UNIT_TEST_HEADER__ 15 #include <boost/version.hpp> 16 #include <boost/algorithm/string.hpp> 17 #include <boost/thread/mutex.hpp> 18 #include <boost/thread/condition.hpp> 19 #include <boost/test/execution_monitor.hpp> 20 #include <boost/test/unit_test.hpp> 21 #include <boost/test/unit_test_log.hpp> 22 #include <boost/test/unit_test_log_formatter.hpp> 23 #include <boost/test/test_case_template.hpp> 24 #include <boost/test/utils/xml_printer.hpp> 25 #include <pion/logger.hpp> 29 #define CHANGE_DIRECTORY _chdir 30 #define GET_DIRECTORY(a,b) _getcwd(a,b) 33 #define CHANGE_DIRECTORY chdir 34 #define GET_DIRECTORY(a,b) getcwd(a,b) 37 #define DIRECTORY_MAX_SIZE 1000 45 :
public boost::unit_test::unit_test_log_formatter
51 : m_entry_in_progress(false)
59 boost::unit_test::counter_t test_cases_amount )
61 ostr <<
"<TestLog>" << std::endl;
67 ostr <<
"</TestLog>" << std::endl;
74 <<
" platform" << attr_value() << BOOST_PLATFORM
75 <<
" compiler" << attr_value() << BOOST_COMPILER
76 <<
" stl" << attr_value() << BOOST_STDLIB
77 <<
" boost=\"" << BOOST_VERSION/100000 <<
"." 78 << BOOST_VERSION/100 % 1000 <<
"." 79 << BOOST_VERSION % 100 <<
'\"' 85 boost::unit_test::test_unit
const& tu )
87 ostr <<
"<" << tu_type_name( tu ) <<
" name" << attr_value() << tu.p_name.get() <<
">" << std::endl;
92 boost::unit_test::test_unit
const& tu,
93 unsigned long elapsed )
95 if ( tu.p_type == boost::unit_test::TUT_CASE )
96 ostr <<
"<TestingTime>" << elapsed <<
"</TestingTime>";
97 ostr <<
"</" << tu_type_name( tu ) <<
">" << std::endl;
102 boost::unit_test::test_unit
const& tu )
104 ostr <<
"<" << tu_type_name( tu )
105 <<
" name" << attr_value() << tu.p_name.get()
106 <<
" skipped" << attr_value() <<
"yes" 107 <<
"/>" << std::endl;
112 boost::unit_test::log_checkpoint_data
const& checkpoint_data,
113 boost::execution_exception
const& ex )
115 boost::execution_exception::location
const& loc = ex.where();
117 ostr <<
"<Exception file" << attr_value() << loc.m_file_name
118 <<
" line" << attr_value() << loc.m_line_num;
120 if( !loc.m_function.is_empty() )
121 ostr <<
" function" << attr_value() << loc.m_function;
123 ostr <<
">" << boost::unit_test::utils::cdata() << ex.what();
125 if( !checkpoint_data.m_file_name.is_empty() ) {
126 ostr <<
"<LastCheckpoint file" << attr_value() << checkpoint_data.m_file_name
127 <<
" line" << attr_value() << checkpoint_data.m_line_num
129 << boost::unit_test::utils::cdata() << checkpoint_data.m_message
130 <<
"</LastCheckpoint>";
133 ostr <<
"</Exception>" << std::endl;
138 boost::unit_test::log_entry_data
const& entry_data,
139 log_entry_types let )
141 boost::mutex::scoped_lock entry_lock(m_mutex);
142 while (m_entry_in_progress) {
143 m_entry_complete.wait(entry_lock);
145 m_entry_in_progress =
true;
147 static boost::unit_test::literal_string xml_tags[] = {
"Info",
"Message",
"Warning",
"Error",
"FatalError" };
148 m_curr_tag = xml_tags[let];
149 ostr <<
'<' << m_curr_tag
150 << BOOST_TEST_L(
" file" ) << attr_value() << entry_data.m_file_name
151 << BOOST_TEST_L(
" line" ) << attr_value() << entry_data.m_line_num
152 << BOOST_TEST_L(
"><![CDATA[" );
159 virtual void log_entry_value( std::ostream& ostr, boost::unit_test::const_string value )
161 boost::mutex::scoped_lock entry_lock(m_mutex);
162 if (m_entry_in_progress) {
172 boost::mutex::scoped_lock entry_lock(m_mutex);
173 if (m_entry_in_progress) {
174 ostr << BOOST_TEST_L(
"]]></" ) << m_curr_tag << BOOST_TEST_L(
">" ) << std::endl;
176 m_entry_in_progress =
false;
177 m_entry_complete.notify_all();
181 virtual void log_exception_start( std::ostream& os, boost::unit_test::log_checkpoint_data
const& lcd, boost::execution_exception
const& ex )
183 os <<
"<TestExceptionLog>" << std::endl;
186 virtual void log_exception_finish( std::ostream& os )
188 os <<
"</TestExceptionLog>" << std::endl;
191 virtual void entry_context_start( std::ostream& os, boost::unit_test::log_level l )
193 os <<
"<EntryContext>" << std::endl;
196 virtual void entry_context_finish( std::ostream& os, boost::unit_test::log_level )
198 os <<
"</EntryContext>" << std::endl;
201 virtual void log_entry_context( std::ostream& os, boost::unit_test::log_level, boost::unit_test::const_string value )
209 static boost::unit_test::const_string tu_type_name( boost::unit_test::test_unit
const& tu )
211 return tu.p_type == boost::unit_test::TUT_CASE ?
"TestCase" :
"TestSuite";
215 typedef boost::unit_test::utils::attr_value attr_value;
218 volatile bool m_entry_in_progress;
221 boost::condition m_entry_complete;
224 boost::mutex m_mutex;
227 boost::unit_test::const_string m_curr_tag;
238 std::cout <<
"global setup for all pion unit tests\n";
241 int argc = boost::unit_test::framework::master_test_suite().argc;
242 char** argv = boost::unit_test::framework::master_test_suite().argv;
243 bool verbose =
false;
246 if (argv[1][0] ==
'-' && argv[1][1] ==
'v') {
248 }
else if (strlen(argv[1]) > 13 && strncmp(argv[1],
"--log_output=", 13) == 0) {
249 const char *
const test_log_filename = argv[1] + 13;
250 m_test_log_file.open(test_log_filename);
251 if (m_test_log_file.is_open()) {
252 boost::unit_test::unit_test_log.set_stream(m_test_log_file);
255 std::cerr <<
"unable to open " << test_log_filename << std::endl;
261 PION_LOG_CONFIG_BASIC;
263 std::cout <<
"Use '-v' to enable logging of errors and warnings from pion.\n";
267 PION_LOG_SETLEVEL_WARN(log_ptr);
270 std::cout <<
"global teardown for all pion unit tests\n";
279 static inline char* trim(
char* str) {
280 for (
long len = strlen(str) - 1; len >= 0; len--) {
281 if (str[len] ==
'\n' || str[len] ==
'\r')
291 static inline bool read_lines_from_file(
const std::string& filename, std::list<std::string>& lines) {
293 std::ifstream a_file(filename.c_str(), std::ios::in | std::ios::binary);
294 if (! a_file.is_open())
299 std::string one_line;
300 while (std::getline(a_file, one_line)) {
301 boost::trim(one_line);
302 if (!one_line.empty() && one_line[0] !=
'#')
303 lines.push_back(one_line);
314 static inline bool check_files_match(
const std::string& fileA,
const std::string& fileB) {
316 std::list<std::string> a_lines, b_lines;
317 BOOST_REQUIRE(read_lines_from_file(fileA, a_lines));
318 BOOST_REQUIRE(read_lines_from_file(fileB, b_lines));
325 return (a_lines == b_lines);
328 static inline bool check_files_exact_match(
const std::string& fileA,
const std::string& fileB,
bool ignore_line_endings =
false) {
330 std::ifstream a_file(fileA.c_str(), std::ios::in | std::ios::binary);
331 BOOST_REQUIRE(a_file.is_open());
333 std::ifstream b_file(fileB.c_str(), std::ios::in | std::ios::binary);
334 BOOST_REQUIRE(b_file.is_open());
337 static const unsigned int BUF_SIZE = 4096;
338 char a_buf[BUF_SIZE];
339 char b_buf[BUF_SIZE];
341 if (ignore_line_endings) {
342 while (a_file.getline(a_buf, BUF_SIZE)) {
343 if (! b_file.getline(b_buf, BUF_SIZE))
347 if (strlen(a_buf) != strlen(b_buf))
349 if (memcmp(a_buf, b_buf, strlen(a_buf)) != 0)
352 if (b_file.getline(b_buf, BUF_SIZE))
355 while (a_file.read(a_buf, BUF_SIZE)) {
356 if (! b_file.read(b_buf, BUF_SIZE))
358 if (memcmp(a_buf, b_buf, BUF_SIZE) != 0)
361 if (b_file.read(b_buf, BUF_SIZE))
364 if (a_file.gcount() != b_file.gcount())
366 if (memcmp(a_buf, b_buf, a_file.gcount()) != 0)
444 #define BOOST_AUTO_TEST_SUITE_FIXTURE_TEMPLATE(suite_name, fixture_types) \ 445 BOOST_AUTO_TEST_SUITE(suite_name) \ 446 typedef fixture_types BOOST_AUTO_TEST_CASE_FIXTURE_TYPES; \ 449 #define BOOST_AUTO_TEST_CASE_FIXTURE_TEMPLATE(test_name) \ 450 template<typename F> \ 451 struct test_name : public F \ 452 { void test_method(); }; \ 454 struct BOOST_AUTO_TC_INVOKER( test_name ) { \ 455 template<typename TestType> \ 456 static void run( boost::type<TestType>* = 0 ) \ 458 test_name<TestType> t; \ 463 BOOST_AUTO_TU_REGISTRAR( test_name )( \ 464 boost::unit_test::ut_detail::template_test_case_gen< \ 465 BOOST_AUTO_TC_INVOKER( test_name ), \ 466 BOOST_AUTO_TEST_CASE_FIXTURE_TYPES >( \ 467 BOOST_STRINGIZE( test_name ), __FILE__, __LINE__ ), \ 468 boost::unit_test::decorator::collector::instance() ); \ 470 template<typename F> \ 471 void test_name<F>::test_method() \
static std::ofstream m_test_log_file
xml log results output stream (needs to be global)