00001
00042 #include "linden_common.h"
00043 #include "llerrorcontrol.h"
00044 #include "lltut.h"
00045
00046 #include <apr-1/apr_pools.h>
00047 #include <apr-1/apr_getopt.h>
00048
00049
00050
00051
00052 #ifdef CTYPE_WORKAROUND
00053 # include "ctype_workaround.h"
00054 #endif
00055
00056
00057 namespace tut
00058 {
00059 test_runner_singleton runner;
00060 }
00061
00062 class LLTestCallback : public tut::callback
00063 {
00064 public:
00065 LLTestCallback(bool verbose_mode) :
00066 mVerboseMode(verbose_mode),
00067 mTotalTests(0),
00068 mPassedTests(0),
00069 mFailedTests(0),
00070 mSkippedTests(0),
00071 mSkipedFailTests(0)
00072 {
00073 }
00074
00075 void run_started()
00076 {
00077
00078 }
00079
00080 void test_completed(const tut::test_result& tr)
00081 {
00082 ++mTotalTests;
00083 std::ostringstream out;
00084 out << "[" << tr.group << ", " << tr.test << "] ";
00085 switch(tr.result)
00086 {
00087 case tut::test_result::ok:
00088 ++mPassedTests;
00089 out << "ok";
00090 break;
00091 case tut::test_result::fail:
00092 ++mFailedTests;
00093 out << "fail";
00094 break;
00095 case tut::test_result::ex:
00096 ++mFailedTests;
00097 out << "exception";
00098 break;
00099 case tut::test_result::warn:
00100 ++mFailedTests;
00101 out << "test destructor throw";
00102 break;
00103 case tut::test_result::term:
00104 ++mFailedTests;
00105 out << "abnormal termination";
00106 break;
00107 case tut::test_result::skip:
00108 ++mSkippedTests;
00109 out << "skipped";
00110 break;
00111 case tut::test_result::skip_fail:
00112 ++mSkipedFailTests;
00113 out << "skipped known failure";
00114 break;
00115 default:
00116 ++mFailedTests;
00117 out << "unknown";
00118 }
00119 if(mVerboseMode || (tr.result != tut::test_result::ok))
00120 {
00121 if(!tr.message.empty())
00122 {
00123 out << ": '" << tr.message << "'";
00124 }
00125 std::cout << out.str() << std::endl;
00126 }
00127 }
00128
00129 void run_completed()
00130 {
00131 std::cout << std::endl;
00132 std::cout << "Total Tests: " << mTotalTests << std::endl;
00133 std::cout << "Passed Tests: " << mPassedTests << std::endl;
00134
00135 if (mSkippedTests > 0)
00136 {
00137 std::cout << "Skipped Tests: " << mSkippedTests << std::endl;
00138 }
00139
00140 if (mSkipedFailTests > 0)
00141 {
00142 std::cout << "Skipped known failures: " << mSkipedFailTests
00143 << std::endl;
00144 }
00145
00146 if(mFailedTests > 0)
00147 {
00148 std::cout << "*********************************" << std::endl;
00149 std::cout << "Failed Tests: " << mFailedTests << std::endl;
00150 std::cout << "Please report or fix the problem." << std::endl;
00151 std::cout << "*********************************" << std::endl;
00152 exit(1);
00153 }
00154 }
00155
00156 protected:
00157 bool mVerboseMode;
00158 int mTotalTests;
00159 int mPassedTests;
00160 int mFailedTests;
00161 int mSkippedTests;
00162 int mSkipedFailTests;
00163 };
00164
00165 static const apr_getopt_option_t TEST_CL_OPTIONS[] =
00166 {
00167 {"help", 'h', 0, "Print the help message."},
00168 {"list", 'l', 0, "List available test groups."},
00169 {"verbose", 'v', 0, "Verbose output."},
00170 {"group", 'g', 1, "Run test group specified by option argument."},
00171 {"skip", 's', 1, "Skip test number specified by option argument. Only works when a specific group is being tested"},
00172 {"wait", 'w', 0, "Wait for input before exit."},
00173 {"debug", 'd', 0, "Emit full debug logs."},
00174 {0, 0, 0, 0}
00175 };
00176
00177 void stream_usage(std::ostream& s, const char* app)
00178 {
00179 s << "Usage: " << app << " [OPTIONS]" << std::endl
00180 << std::endl;
00181
00182 s << "This application runs the unit tests." << std::endl << std::endl;
00183
00184 s << "Options: " << std::endl;
00185 const apr_getopt_option_t* option = &TEST_CL_OPTIONS[0];
00186 while(option->name)
00187 {
00188 s << " ";
00189 s << " -" << (char)option->optch << ", --" << option->name
00190 << std::endl;
00191 s << "\t" << option->description << std::endl << std::endl;
00192 ++option;
00193 }
00194
00195 s << "Examples:" << std::endl;
00196 s << " " << app << " --verbose" << std::endl;
00197 s << "\tRun all the tests and report all results." << std::endl;
00198 s << " " << app << " --list" << std::endl;
00199 s << "\tList all available test groups." << std::endl;
00200 s << " " << app << " --group=uuid" << std::endl;
00201 s << "\tRun the test group 'uuid'." << std::endl;
00202 s << " " << app << " --skip=2" << std::endl;
00203 s << "\tSkip test case 2." << std::endl;
00204 }
00205
00206 void stream_groups(std::ostream& s, const char* app)
00207 {
00208 s << "Registered test groups:" << std::endl;
00209 tut::groupnames gl = tut::runner.get().list_groups();
00210 tut::groupnames::const_iterator it = gl.begin();
00211 tut::groupnames::const_iterator end = gl.end();
00212 for(; it != end; ++it)
00213 {
00214 s << " " << *(it) << std::endl;
00215 }
00216 }
00217
00218 void wouldHaveCrashed(const std::string& message)
00219 {
00220 tut::fail("llerrs message: " + message);
00221 }
00222
00223 int main(int argc, char **argv)
00224 {
00225 LLError::initForApplication(".");
00226 LLError::setFatalFunction(wouldHaveCrashed);
00227 LLError::setDefaultLevel(LLError::LEVEL_ERROR);
00228
00229
00230
00231 #ifdef CTYPE_WORKAROUND
00232 ctype_workaround();
00233 #endif
00234
00235 apr_initialize();
00236 apr_pool_t* pool = NULL;
00237 if(APR_SUCCESS != apr_pool_create(&pool, NULL))
00238 {
00239 std::cerr << "Unable to initialize pool" << std::endl;
00240 return 1;
00241 }
00242 apr_getopt_t* os = NULL;
00243 if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv))
00244 {
00245 std::cerr << "Unable to pool" << std::endl;
00246 return 1;
00247 }
00248
00249
00250 bool verbose_mode = false;
00251 bool wait_at_exit = false;
00252 int skip_test_id = 0;
00253 std::string test_group;
00254
00255
00256 apr_status_t apr_err;
00257 const char* opt_arg = NULL;
00258 int opt_id = 0;
00259 while(true)
00260 {
00261 apr_err = apr_getopt_long(os, TEST_CL_OPTIONS, &opt_id, &opt_arg);
00262 if(APR_STATUS_IS_EOF(apr_err)) break;
00263 if(apr_err)
00264 {
00265 char buf[255];
00266 std::cerr << "Error parsing options: "
00267 << apr_strerror(apr_err, buf, 255) << std::endl;
00268 return 1;
00269 }
00270 switch (opt_id)
00271 {
00272 case 'g':
00273 test_group.assign(opt_arg);
00274 break;
00275 case 's':
00276 skip_test_id = atoi(opt_arg);
00277 break;
00278 case 'h':
00279 stream_usage(std::cout, argv[0]);
00280 return 0;
00281 break;
00282 case 'l':
00283 stream_groups(std::cout, argv[0]);
00284 return 0;
00285 case 'v':
00286 verbose_mode = true;
00287 break;
00288 case 'w':
00289 wait_at_exit = true;
00290 break;
00291 case 'd':
00292
00293
00294 LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
00295 break;
00296 default:
00297 stream_usage(std::cerr, argv[0]);
00298 return 1;
00299 break;
00300 }
00301 }
00302
00303
00304 LLTestCallback callback(verbose_mode);
00305 tut::runner.get().set_callback(&callback);
00306
00307 if(test_group.empty())
00308 {
00309 tut::runner.get().run_tests();
00310 }
00311 else
00312 {
00313 tut::runner.get().run_tests(test_group, skip_test_id);
00314 }
00315
00316 if (wait_at_exit)
00317 {
00318 std::cerr << "Waiting for input before exiting..." << std::endl;
00319 std::cin.get();
00320 }
00321
00322 apr_terminate();
00323 return 0;
00324 }