/* boost regression test program * * Copyright Jens Maurer 2000 * Permission to use, copy, modify, sell, and distribute this software * is hereby granted without free provided that the above copyright notice * appears in all copies and that both that copyright notice and this * permission notice appear in supporting documentation, * * Jens Maurer makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * See http://www.boost.org for most recent version including documentation. */ #include #include #include #include #include #include #include #include // It is OK to use boost headers which contain entirely inline code. #include # ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::exit; using ::system; using ::strftime; using ::gmtime; using ::time; using ::time_t; } # endif std::string get_host() { #if defined __linux__ return "linux"; #elif defined __osf__ return "tru64"; #elif defined __sgi return "irix"; #elif defined _WIN32 return "win32"; #elif defined __BEOS__ return "beos"; #else # error Please adapt for your platform #endif } // retrieve precise system configuration as descriptive string #ifdef __unix #include std::string get_system_configuration() { struct utsname ut; // "struct" is required for the DEC Tru64 compiler if(uname(&ut) < 0) return ""; std::string config = std::string(ut.sysname) + " " + ut.release; return config; } #elif defined _WIN32 std::string get_system_configuration() { return "Microsoft Windows 32bit"; } #elif defined __BEOS__ std::string get_system_configuration() { return "BeOS"; } #else # error Please adapt for your platform #endif struct entry { std::string os, identifier, name, compile_only_command, compile_link_command, html; }; // replace the first %name in s with value void replace(std::string & s, const std::string & name, const std::string & value) { std::string::size_type p = s.find(name); if(p != std::string::npos) s.replace(p, name.length(), value); } // replace all $XXX in s with the value of getenv("XXX") void replace_environment(std::string & s) { std::string::size_type end = 0; for(;;) { std::string::size_type pos = s.find('$', end); if(pos == std::string::npos) break; end = s.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", pos+1); const char * env = getenv(s.substr(pos+1, end-pos-1).c_str()); if(env) replace(s, s.substr(pos, end-pos), env); else break; } } // get a string line, ignoring empty lines and comment lines void getstringline( std::ifstream & is, std::string & s ) { do { std::getline( static_cast(is), s ); // cast required by IRIX } while ( is.good() && (!s.size() || (s.size() >= 2 && s[0] == '/' && s[1] == '/')) ); } // read the compiler configuration from file and push entry's to out template void read_compiler_configuration(const std::string & file, OutputIterator out) { std::ifstream f(file.c_str()); int lineno = 0; while(f.good()) { entry e; getstringline(f, e.os); getstringline(f, e.identifier); getstringline(f, e.name); getstringline(f, e.compile_only_command); getstringline(f, e.compile_link_command); getstringline(f, e.html); *out = e; ++out; std::string l; std::getline(f, l); lineno += 6; if(l != "") { std::cerr << file << ", line " << lineno << ": Empty line expected, got " << l << "\n"; std::exit(1); } } } // run command (possibly needs portability adjustment) bool execute(const std::string & command) { std::cout << command << std::endl; // fix: endl ensures cout ordering return std::system(command.c_str()) == 0; } enum test_result { ok = 0, unknown_type, compile_failed, compile_ok, link_failed, link_ok, run_failed, run_ok }; test_result compile(std::string command, const std::string & boostpath, const std::string & file) { replace(command, "%source", boostpath + "/" + file); return execute(command) ? compile_ok : compile_failed; } test_result link(std::string command, const std::string & boostpath, const std::string & file) { replace(command, "%source", boostpath + "/" + file); return execute(command) ? link_ok : link_failed; } test_result run(std::string command, const std::string & boostpath, const std::string & file) { std::string exename = "boosttmp.exe"; replace(command, "%source", boostpath + "/" + file); if(execute(command)) { return execute( (get_host() == "win32" ? "" : "./") + exename ) ? run_ok : run_failed; } else { return link_failed; } } std::pair run_test(const std::string & type, std::string compile_only_command, std::string compile_link_command, const std::string & boostpath, const std::string & source) { replace(compile_only_command, "%include", boostpath); replace(compile_link_command, "%include", boostpath); if(type == "compile") return std::make_pair(compile(compile_only_command, boostpath, source), compile_ok); else if(type == "compile-fail") return std::make_pair(compile(compile_only_command, boostpath, source), compile_failed); else if(type == "link") return std::make_pair(link(compile_link_command, boostpath, source), link_ok); else if(type == "link-fail") return std::make_pair(link(compile_link_command, boostpath, source), link_failed); else if(type == "run") return std::make_pair(run(compile_link_command, boostpath, source), run_ok); else if(type == "run-fail") return std::make_pair(run(compile_link_command, boostpath, source), run_failed); else return std::make_pair(unknown_type, ok); } template void do_tests(std::ostream & out, ForwardIterator firstcompiler, ForwardIterator lastcompiler, const std::string & testconfig, const std::string & boostpath) { out << "\n" << "Program\n" << "Test
Type\n"; for(ForwardIterator it = firstcompiler; it != lastcompiler; ++it) { out << "" << it->html << "\n"; } out << "\n"; std::ifstream f(testconfig.c_str()); while(f.good()) { std::string l; getstringline(f, l); if (!f.good()) break; typedef std::string::size_type sz_type; sz_type p = l.find(' '); if(p == std::string::npos) { std::cerr << "Test " << l << " is wrong\n"; continue; } std::string type(l, 0, p); std::string file(l, p+1, std::string::npos); // 3rd arg to fix VC++ bug std::cout << "*** " << file << " ***\n\n"; out << "\n" << "" << file << "\n" << "" << type << "\n"; for(ForwardIterator it = firstcompiler; it != lastcompiler; ++it) { std::cout << "** " << it->name << "\n"; std::pair result = run_test(type, it->compile_only_command, it->compile_link_command, boostpath, file); if(result.first == unknown_type) { std::cerr << "Unknown test type " << type << ", skipped\n"; continue; } out << "" << (result.first == result.second ? "Pass" : "Fail") << "" << std::endl; std::cout << (result.first == result.second ? "Pass" : "Fail") << "\n\n"; } out << "\n"; } } int main(int argc, char * argv[]) { // std::vector args(argv+1, argv+argc); // hack around VC++ lack of ctor taking iterator args std::vector args; for ( const char ** ait = (const char **)(argv+1); ait != (const char **)(argv+argc); ++ait) args.push_back(std::string( *ait )); if(args.size() < 3) { std::cerr << argv[0] << " usage: compiler-config test-config boost-path [compiler|* [[command] file]]\n"; std::exit(1); } std::string compiler = (args.size() >= 4 ? args[3] : "*"); std::list l; read_compiler_configuration(args[0], std::back_inserter(l)); std::string host = get_host(); for(std::list::iterator it = l.begin(); it != l.end(); ) { if(it->os == host && (compiler == "*" || it->identifier == compiler)) { replace_environment(it->compile_only_command); replace_environment(it->compile_link_command); ++it; } else { it = l.erase(it); } } std::string boostpath = args[2]; // if file argument present, write temporary test configuration file for do_tests if(args.size() >= 5) { // file argument present std::ofstream tmp((args[1]="boosttmp.tmp").c_str()); if (args.size() >= 6) tmp << args[4] << " " << args[5] << std::endl; // command present else tmp << "compile " << args[4] << std::endl; // command not present } std::ofstream out( ("cs-" + host + ".html").c_str() ); char run_date[100]; std::time_t ct; std::time(&ct); std::strftime(run_date, sizeof(run_date), "%d %b %Y %H:%M GMT", std::gmtime(&ct)); out << "\n\n\nCompiler Status: " + host + "\n\n\n" << "\n" << "

\n" << "

Compiler Status: " + host + "

\n" << "\n" << "

Run Date: " << run_date << "

\n" << "

System Configuration: " << get_system_configuration() << "

\n" << "

\n" << "\n"; do_tests(out, l.begin(), l.end(), args[1], boostpath); out << "

\n

\n"; if(host == "linux") out << "Notes: A hand-crafted <limits> Standard header has been\n" << "applied to all configurations.\n" << "The tests were run on a GNU libc 2.2 system which has improved\n" << "wide character support compared to previous versions."; else if(host == "irix" || host == "tru64") out << "Note: For the 'clib' configuration, the missing new-style C\n" << "library headers <cXXX> have been supplied.\n"; out << "

\n\n" << std::endl; return 0; }