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 }