File indexing completed on 2025-02-16 05:12:10

0001 /*
0002  * _test_main.cpp
0003  * Copyright 2013 Google Inc. All Rights Reserved.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a copy
0006  * of this software and associated documentation files (the "Software"), to deal
0007  * in the Software without restriction, including without limitation the rights
0008  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0009  * copies of the Software, and to permit persons to whom the Software is
0010  * furnished to do so, subject to the following conditions:
0011  *
0012  * The above copyright notice and this permission notice shall be included in
0013  * all copies or substantial portions of the Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0018  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0021  * SOFTWARE.
0022  */
0023 
0024 #include "test.hpp"
0025 #include <cstdio>
0026 #include <cstdlib>
0027 
0028 #ifdef _WIN32
0029 #include <windows.h>
0030 #define strcasecmp _stricmp
0031 #else
0032 #include <sys/wait.h>
0033 #include <unistd.h>
0034 #endif
0035 
0036 #if defined(__has_include) && __has_include(<error.h>)
0037 #include <error.h>
0038 #else
0039 #include <stdarg.h>
0040 
0041 #ifdef _WIN32
0042 char argv0[MAX_PATH];
0043 inline const char *getprogname() {
0044   return GetModuleFileName(NULL, argv0, sizeof(argv0)) ? argv0 : NULL;
0045 }
0046 #elif !defined(__APPLE__)
0047 // N.B.  getprogname() is an Apple/BSD-ism.
0048 // program_invocation_name is a GLIBC-ism, but it's also
0049 //  supported by libmusl.
0050 #define getprogname() program_invocation_name
0051 #endif
0052 
0053 void error(int status, int errnum, const char *format, ...) {
0054   fflush(stdout);
0055   fprintf(stderr, "%s: ", getprogname());
0056 
0057   va_list args;
0058   va_start(args, format);
0059   vfprintf(stderr, format, args);
0060   va_end(args);
0061 
0062   if (errnum != 0) {
0063     fprintf(stderr, ": %s\n", strerror(errnum));
0064   } else {
0065     fprintf(stderr, "\n");
0066   }
0067   if (status != 0) {
0068     exit(status);
0069   }
0070 }
0071 #endif
0072 
0073 using namespace test;
0074 
0075 bool run_test(TestBase &test, bool use_child_process = true) {
0076   if (!use_child_process) {
0077     exit(static_cast<int>(test.run()));
0078   }
0079 
0080   printf("-- running test case: %s\n", test.name);
0081 
0082   fflush(stdout);
0083 
0084   test::TestStatus status = test::SUCCESS;
0085 
0086 #ifdef _WIN32
0087   char filename[256];
0088   GetModuleFileName(NULL, filename, 256); // TODO: check for error
0089   std::string cmd_line = filename;
0090   cmd_line += " --nofork ";
0091   cmd_line += test.name;
0092 
0093   STARTUPINFO si;
0094   PROCESS_INFORMATION pi;
0095   ZeroMemory(&si, sizeof(si));
0096   si.cb = sizeof(si);
0097   ZeroMemory(&pi, sizeof(pi));
0098 
0099   if (!CreateProcessA(nullptr, const_cast<char *>(cmd_line.c_str()), nullptr,
0100                       nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
0101     printf("unable to create process\n");
0102     exit(-1);
0103   }
0104 
0105   WaitForSingleObject(pi.hProcess, INFINITE);
0106 
0107   DWORD exit_code;
0108   GetExitCodeProcess(pi.hProcess, &exit_code);
0109   switch (exit_code) {
0110   case 3:
0111     status = test::SIGNAL_ABORT;
0112     break;
0113   case 5:
0114     status = test::EXCEPTION_UNCAUGHT;
0115     break;
0116   case EXCEPTION_ACCESS_VIOLATION:
0117     status = test::SIGNAL_SEGFAULT;
0118     break;
0119   case EXCEPTION_STACK_OVERFLOW:
0120     status = test::SIGNAL_SEGFAULT;
0121     break;
0122   case EXCEPTION_INT_DIVIDE_BY_ZERO:
0123     status = test::SIGNAL_DIVZERO;
0124     break;
0125   }
0126   printf("Exit code: %lu\n", exit_code);
0127 
0128   CloseHandle(pi.hProcess);
0129   CloseHandle(pi.hThread);
0130 
0131   if (test.expected_status == test::ASSERT_FAIL) {
0132     // assert calls abort on windows
0133     return (status & test::SIGNAL_ABORT);
0134   }
0135 
0136 #else
0137 
0138   pid_t child_pid = fork();
0139   if (child_pid == 0) {
0140     exit(static_cast<int>(test.run()));
0141   }
0142   if (child_pid == -1) {
0143     error(EXIT_FAILURE, 0, "unable to fork");
0144   }
0145 
0146   int child_status = 0;
0147   waitpid(child_pid, &child_status, 0);
0148 
0149   if (WIFEXITED(child_status)) {
0150     int exit_status = WEXITSTATUS(child_status);
0151     if (exit_status & ~test::STATUS_MASK) {
0152       status = test::FAILED;
0153     } else {
0154       status = static_cast<test::TestStatus>(exit_status);
0155     }
0156   } else if (WIFSIGNALED(child_status)) {
0157     const int signum = WTERMSIG(child_status);
0158     printf("!! signal (%d) %s\n", signum, strsignal(signum));
0159     switch (signum) {
0160     case SIGABRT:
0161       status = test::SIGNAL_ABORT;
0162       break;
0163     case SIGSEGV:
0164     case SIGBUS:
0165       status = test::SIGNAL_SEGFAULT;
0166       break;
0167     case SIGFPE:
0168       status = test::SIGNAL_DIVZERO;
0169       break;
0170     default:
0171       status = test::SIGNAL_UNCAUGHT;
0172     }
0173   }
0174 
0175 #endif
0176 
0177   if (test.expected_status == test::FAILED) {
0178     return (status & test::FAILED);
0179   }
0180 
0181   if (test.expected_status == test::SIGNAL_UNCAUGHT) {
0182     return (status & test::SIGNAL_UNCAUGHT);
0183   }
0184 
0185   return status == test.expected_status;
0186 }
0187 
0188 int main(int argc, const char *const argv[]) {
0189 
0190 #ifdef _WIN32
0191   _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
0192 #endif
0193 
0194   if (argc == 3 && strcmp("--nofork", argv[1]) == 0) {
0195     // Windows has no fork, so we simulate it
0196     // we only execute one test, without forking
0197     for (test_registry_t::iterator it = test_registry().begin();
0198          it != test_registry().end(); ++it) {
0199       TestBase &test = **it;
0200       if (strcasecmp(argv[2], test.name) == 0) {
0201         run_test(test, false);
0202 
0203         return 0;
0204       }
0205     }
0206     return -1;
0207   }
0208 
0209   size_t success_cnt = 0;
0210   size_t total_cnt = 0;
0211   for (test_registry_t::iterator it = test_registry().begin();
0212        it != test_registry().end(); ++it) {
0213     TestBase &test = **it;
0214 
0215     bool consider_test = (argc <= 1);
0216     for (int i = 1; i < argc; ++i) {
0217       if (strcasecmp(argv[i], test.name) == 0) {
0218         consider_test = true;
0219         break;
0220       }
0221     }
0222     if (!consider_test) {
0223       continue;
0224     }
0225 
0226     total_cnt += 1;
0227     if (run_test(test)) {
0228       printf("-- test case success: %s\n", test.name);
0229       success_cnt += 1;
0230     } else {
0231       printf("** test case FAILED : %s\n", test.name);
0232     }
0233   }
0234   printf("-- tests passing: %zu/%zu", success_cnt, total_cnt);
0235   if (total_cnt) {
0236     printf(" (%zu%%)\n", success_cnt * 100 / total_cnt);
0237   } else {
0238     printf("\n");
0239   }
0240   return (success_cnt == total_cnt) ? EXIT_SUCCESS : EXIT_FAILURE;
0241 }