Simple Directmedia Layer
at main 41 kB view raw
1#include <SDL3/SDL.h> 2#include <SDL3/SDL_main.h> 3#include <SDL3/SDL_test.h> 4 5#ifdef SDL_PLATFORM_WINDOWS 6#define EXE ".exe" 7#else 8#define EXE "" 9#endif 10 11/* 12 * FIXME: Additional tests: 13 * - stdin to stderr 14 */ 15 16typedef struct { 17 const char *childprocess_path; 18} TestProcessData; 19 20static TestProcessData parsed_args; 21 22static void SDLCALL setUpProcess(void **arg) { 23 *arg = &parsed_args; 24} 25 26static const char *options[] = { 27 "/path/to/childprocess" EXE, 28 NULL 29}; 30 31static char **CreateArguments(int ignore, ...) { 32 va_list ap; 33 size_t count = 1; 34 size_t i; 35 char **result; 36 37 va_start(ap, ignore); 38 for (;;) { 39 const char *keyN = va_arg(ap, const char *); 40 if (!keyN) { 41 break; 42 } 43 count += 1; 44 } 45 va_end(ap); 46 47 result = SDL_calloc(count, sizeof(char *)); 48 49 i = 0; 50 va_start(ap, ignore); 51 for (;;) { 52 const char *keyN = va_arg(ap, const char *); 53 if (!keyN) { 54 break; 55 } 56 result[i++] = SDL_strdup(keyN); 57 } 58 va_end(ap); 59 60 return result; 61} 62 63static void DestroyStringArray(char **list) { 64 char **current; 65 66 if (!list) { 67 return; 68 } 69 for (current = list; *current; current++) { 70 SDL_free(*current); 71 } 72 SDL_free(list); 73} 74 75static int SDLCALL process_testArguments(void *arg) 76{ 77 TestProcessData *data = (TestProcessData *)arg; 78 const char *process_args[] = { 79 data->childprocess_path, 80 "--print-arguments", 81 "--", 82 "", 83 " ", 84 "a b c", 85 "a\tb\tc\t", 86 "\"a b\" c", 87 "'a' 'b' 'c'", 88 "%d%%%s", 89 "\\t\\c", 90 "evil\\", 91 "a\\b\"c\\", 92 "\"\\^&|<>%", /* characters with a special meaning */ 93 NULL 94 }; 95 SDL_Process *process = NULL; 96 char *buffer; 97 int exit_code; 98 int i; 99 size_t total_read = 0; 100 101 process = SDL_CreateProcess(process_args, true); 102 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess()"); 103 if (!process) { 104 goto failed; 105 } 106 107 exit_code = 0xdeadbeef; 108 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 109 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 110 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 111 if (!buffer) { 112 goto failed; 113 } 114 SDLTest_LogEscapedString("stdout of process: ", buffer, total_read); 115 116 for (i = 3; process_args[i]; i++) { 117 char line[64]; 118 SDL_snprintf(line, sizeof(line), "|%d=%s|", i - 3, process_args[i]); 119 SDLTest_AssertCheck(!!SDL_strstr(buffer, line), "Check %s is in output", line); 120 } 121 SDL_free(buffer); 122 123 SDLTest_AssertPass("About to destroy process"); 124 SDL_DestroyProcess(process); 125 return TEST_COMPLETED; 126failed: 127 SDL_DestroyProcess(process); 128 return TEST_ABORTED; 129} 130 131static int SDLCALL process_testexitCode(void *arg) 132{ 133 TestProcessData *data = (TestProcessData *)arg; 134 int i; 135 int exit_codes[] = { 136 0, 13, 31, 127, 255 137 }; 138 139 for (i = 0; i < SDL_arraysize(exit_codes); i++) { 140 bool wait_result; 141 SDL_Process *process = NULL; 142 char **process_args = NULL; 143 char number_buffer[8]; 144 int exit_code; 145 146 SDL_snprintf(number_buffer, sizeof(number_buffer), "%d", exit_codes[i]); 147 148 process_args = CreateArguments(0, data->childprocess_path, "--exit-code", number_buffer, NULL); 149 150 process = SDL_CreateProcess((const char * const *)process_args, false); 151 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess()"); 152 if (!process) { 153 goto failed; 154 } 155 156 exit_code = 0xdeadbeef; 157 SDLTest_AssertPass("About to wait on process (first time)"); 158 wait_result = SDL_WaitProcess(process, true, &exit_code); 159 SDLTest_AssertCheck(wait_result == true, "SDL_WaitProcess(): Process should have closed immediately"); 160 SDLTest_AssertCheck(exit_code == exit_codes[i], "SDL_WaitProcess(): Exit code should be %d, is %d", exit_codes[i], exit_code); 161 162 exit_code = 0xdeadbeef; 163 SDLTest_AssertPass("About to wait on process (second time)"); 164 wait_result = SDL_WaitProcess(process, true, &exit_code); 165 SDLTest_AssertCheck(wait_result == true, "SDL_WaitProcess(): Process should have closed immediately"); 166 SDLTest_AssertCheck(exit_code == exit_codes[i], "SDL_WaitProcess(): Exit code should be %d, is %d", exit_codes[i], exit_code); 167 168 SDLTest_AssertPass("About to destroy process"); 169 SDL_DestroyProcess(process); 170 DestroyStringArray(process_args); 171 continue; 172failed: 173 SDL_DestroyProcess(process); 174 DestroyStringArray(process_args); 175 return TEST_ABORTED; 176 } 177 return TEST_COMPLETED; 178#if 0 179failed: 180 SDL_DestroyProcess(process); 181 DestroyStringArray(process_args); 182 return TEST_ABORTED; 183#endif 184} 185 186static int SDLCALL process_testInheritedEnv(void *arg) 187{ 188 TestProcessData *data = (TestProcessData *)arg; 189 const char *process_args[] = { 190 data->childprocess_path, 191 "--print-environment", 192 NULL, 193 }; 194 SDL_PropertiesID props; 195 SDL_Process *process = NULL; 196 Sint64 pid; 197 int exit_code; 198 char random_env1[64]; 199 char random_env2[64]; 200 static const char *const TEST_ENV_KEY1 = "testprocess_inherited_var"; 201 static const char *const TEST_ENV_KEY2 = "testprocess_other_var"; 202 char *test_env_val1 = NULL; 203 char *test_env_val2 = NULL; 204 char *buffer = NULL; 205 206 test_env_val1 = SDLTest_RandomAsciiStringOfSize(32); 207 SDL_snprintf(random_env1, sizeof(random_env1), "%s=%s", TEST_ENV_KEY1, test_env_val1); 208 SDLTest_AssertPass("Setting parent environment variable %s=%s", TEST_ENV_KEY1, test_env_val1); 209 SDL_SetEnvironmentVariable(SDL_GetEnvironment(), TEST_ENV_KEY1, test_env_val1, true); 210 211 SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), TEST_ENV_KEY2); 212 213 props = SDL_CreateProperties(); 214 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 215 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 216 process = SDL_CreateProcessWithProperties(props); 217 SDL_DestroyProperties(props); 218 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 219 if (!process) { 220 goto failed; 221 } 222 223 test_env_val2 = SDLTest_RandomAsciiStringOfSize(32); 224 SDL_snprintf(random_env2, sizeof(random_env2), "%s=%s", TEST_ENV_KEY2, test_env_val2); 225 SDLTest_AssertPass("Setting parent environment variable %s=%s", TEST_ENV_KEY2, test_env_val2); 226 SDL_SetEnvironmentVariable(SDL_GetEnvironment(),TEST_ENV_KEY2, test_env_val2, true); 227 SDLTest_AssertCheck(SDL_strcmp(test_env_val1, test_env_val2) != 0, "Sanity checking the 2 random environment variables are not identical"); 228 229 props = SDL_GetProcessProperties(process); 230 SDLTest_AssertCheck(props != 0, "SDL_GetProcessProperties()"); 231 232 pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); 233 SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); 234 235 exit_code = 0xdeadbeef; 236 buffer = (char *)SDL_ReadProcess(process, NULL, &exit_code); 237 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 238 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 239 240 SDLTest_AssertCheck(SDL_strstr(buffer, random_env1) != NULL, "Environment of child should contain \"%s\"", test_env_val1); 241 SDLTest_AssertCheck(SDL_strstr(buffer, random_env2) == NULL, "Environment of child should not contain \"%s\"", test_env_val2); 242 243 SDLTest_AssertPass("About to destroy process"); 244 SDL_DestroyProcess(process); 245 SDL_free(test_env_val1); 246 SDL_free(test_env_val2); 247 SDL_free(buffer); 248 return TEST_COMPLETED; 249failed: 250 SDL_free(test_env_val1); 251 SDL_free(test_env_val2); 252 SDL_DestroyProcess(process); 253 SDL_free(buffer); 254 return TEST_ABORTED; 255} 256 257static int SDLCALL process_testNewEnv(void *arg) 258{ 259 TestProcessData *data = (TestProcessData *)arg; 260 const char *process_args[] = { 261 data->childprocess_path, 262 "--print-environment", 263 NULL, 264 }; 265 SDL_Environment *process_env; 266 SDL_PropertiesID props; 267 SDL_Process *process = NULL; 268 Sint64 pid; 269 int exit_code; 270 char random_env1[64]; 271 char random_env2[64]; 272 static const char *const TEST_ENV_KEY1 = "testprocess_inherited_var"; 273 static const char *const TEST_ENV_KEY2 = "testprocess_other_var"; 274 char *test_env_val1 = NULL; 275 char *test_env_val2 = NULL; 276 char *buffer = NULL; 277 size_t total_read = 0; 278 279 test_env_val1 = SDLTest_RandomAsciiStringOfSize(32); 280 SDL_snprintf(random_env1, sizeof(random_env1), "%s=%s", TEST_ENV_KEY1, test_env_val1); 281 SDLTest_AssertPass("Unsetting parent environment variable %s", TEST_ENV_KEY1); 282 SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), TEST_ENV_KEY1); 283 284 process_env = SDL_CreateEnvironment(true); 285 SDL_SetEnvironmentVariable(process_env, "PATH", SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "PATH"), true); 286 SDL_SetEnvironmentVariable(process_env, "LD_LIBRARY_PATH", SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LD_LIBRARY_PATH"), true); 287 SDL_SetEnvironmentVariable(process_env, "DYLD_LIBRARY_PATH", SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "DYLD_LIBRARY_PATH"), true); 288 SDL_SetEnvironmentVariable(process_env, TEST_ENV_KEY1, test_env_val1, true); 289 290 test_env_val2 = SDLTest_RandomAsciiStringOfSize(32); 291 SDL_snprintf(random_env2, sizeof(random_env2), "%s=%s", TEST_ENV_KEY2, test_env_val1); 292 SDLTest_AssertPass("Setting parent environment variable %s=%s", TEST_ENV_KEY2, test_env_val2); 293 SDL_SetEnvironmentVariable(SDL_GetEnvironment(), TEST_ENV_KEY2, test_env_val2, true); 294 SDLTest_AssertCheck(SDL_strcmp(test_env_val1, test_env_val2) != 0, "Sanity checking the 2 random environment variables are not identical"); 295 296 props = SDL_CreateProperties(); 297 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 298 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER, process_env); 299 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 300 process = SDL_CreateProcessWithProperties(props); 301 SDL_DestroyProperties(props); 302 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 303 if (!process) { 304 goto failed; 305 } 306 307 props = SDL_GetProcessProperties(process); 308 SDLTest_AssertCheck(props != 0, "SDL_GetProcessProperties()"); 309 310 pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); 311 SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); 312 313 exit_code = 0xdeadbeef; 314 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 315 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 316 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 317 SDLTest_LogEscapedString("Text read from subprocess: ", buffer, total_read); 318 319 SDLTest_AssertCheck(SDL_strstr(buffer, random_env1) != NULL, "Environment of child should contain \"%s\"", random_env1); 320 SDLTest_AssertCheck(SDL_strstr(buffer, random_env2) == NULL, "Environment of child should not contain \"%s\"", random_env1); 321 322 SDLTest_AssertPass("About to destroy process"); 323 SDL_DestroyProcess(process); 324 SDL_DestroyEnvironment(process_env); 325 SDL_free(test_env_val1); 326 SDL_free(test_env_val2); 327 SDL_free(buffer); 328 return TEST_COMPLETED; 329 330failed: 331 SDL_DestroyProcess(process); 332 SDL_DestroyEnvironment(process_env); 333 SDL_free(test_env_val1); 334 SDL_free(test_env_val2); 335 SDL_free(buffer); 336 return TEST_ABORTED; 337} 338 339static int SDLCALL process_testKill(void *arg) 340{ 341 TestProcessData *data = (TestProcessData *)arg; 342 const char *process_args[] = { 343 data->childprocess_path, 344 "--stdin", 345 NULL, 346 }; 347 SDL_Process *process = NULL; 348 SDL_PropertiesID props; 349 Sint64 pid; 350 int result; 351 int exit_code; 352 353 SDLTest_AssertPass("About to call SDL_CreateProcess(true)"); 354 process = SDL_CreateProcess(process_args, true); 355 if (!process) { 356 goto failed; 357 } 358 359 props = SDL_GetProcessProperties(process); 360 SDLTest_AssertCheck(props != 0, "SDL_GetProcessProperties()"); 361 362 pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); 363 SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); 364 365 exit_code = 0xdeadbeef; 366 SDLTest_AssertPass("About to call SDL_WaitProcess(false)"); 367 result = SDL_WaitProcess(process, false, &exit_code); 368 SDLTest_AssertCheck(result == false, "Process should not have exited yet"); 369 370 SDLTest_AssertPass("About to call SDL_KillProcess(false)"); 371 result = SDL_KillProcess(process, false); 372 SDLTest_AssertCheck(result == true, "Process should have exited"); 373 374 exit_code = 0; 375 SDLTest_AssertPass("About to call SDL_WaitProcess(true)"); 376 result = SDL_WaitProcess(process, true, &exit_code); 377 SDLTest_AssertCheck(result == true, "Process should have exited"); 378 SDLTest_AssertCheck(exit_code != 0, "Exit code should be non-zero, is %d", exit_code); 379 380 SDLTest_AssertPass("About to destroy process"); 381 SDL_DestroyProcess(process); 382 return TEST_COMPLETED; 383 384failed: 385 SDL_DestroyProcess(process); 386 return TEST_ABORTED; 387} 388 389static int process_testStdinToStdout(void *arg) 390{ 391 TestProcessData *data = (TestProcessData *)arg; 392 const char *process_args[] = { 393 data->childprocess_path, 394 "--stdin-to-stdout", 395 NULL, 396 }; 397 SDL_PropertiesID props; 398 SDL_Process *process = NULL; 399 Sint64 pid; 400 SDL_IOStream *process_stdin = NULL; 401 SDL_IOStream *process_stdout = NULL; 402 SDL_IOStream *process_stderr = NULL; 403 size_t text_in_size = 1 * 1024 * 1024; 404 char *text_in = NULL; 405 size_t total_written; 406 size_t total_read; 407 bool wait_result; 408 int exit_code; 409 SDL_IOStream *stdout_stream = NULL; 410 char *stdout_stream_buf; 411 int iteration_count = 0; 412 413 text_in = SDLTest_RandomAsciiStringOfSize((int)text_in_size); 414 /* Make sure text_in does not contain EOF */ 415 for (;;) { 416 char *e = SDL_strstr(text_in, "EOF"); 417 if (!e) { 418 break; 419 } 420 e[0] = 'N'; 421 } 422 text_in[text_in_size - 3] = 'E'; 423 text_in[text_in_size - 2] = 'O'; 424 text_in[text_in_size - 1] = 'F'; 425 426 stdout_stream = SDL_IOFromDynamicMem(); 427 428 props = SDL_CreateProperties(); 429 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 430 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 431 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 432 process = SDL_CreateProcessWithProperties(props); 433 SDL_DestroyProperties(props); 434 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 435 if (!process) { 436 goto failed; 437 } 438 439 props = SDL_GetProcessProperties(process); 440 SDLTest_AssertCheck(props != 0, "SDL_GetProcessProperties()"); 441 442 pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); 443 SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); 444 445 process_stdin = SDL_GetProcessInput(process); 446 SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) returns a valid IO stream"); 447 process_stdout = SDL_GetProcessOutput(process); 448 SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream"); 449 process_stderr = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDERR_POINTER, NULL); 450 SDLTest_AssertCheck(process_stderr == NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDERR_POINTER) returns NULL"); 451 if (!process_stdin || !process_stdout) { 452 goto failed; 453 } 454 455 total_written = 0; 456 total_read = 0; 457 for (;;) { 458 int log_this_iteration = (iteration_count % 32) == 32; 459 char local_buffer[16 * 4094]; 460 size_t amount_read; 461 SDL_IOStatus io_status; 462 if (total_written != text_in_size) { 463 size_t amount_written; 464 if (log_this_iteration) { 465 SDLTest_AssertPass("About to SDL_WriteIO (%dth time)", iteration_count); 466 } 467 amount_written = SDL_WriteIO(process_stdin, text_in + total_written, text_in_size - total_written); 468 if (log_this_iteration) { 469 SDLTest_Log("SDL_WriteIO() -> %u (%dth time)", (unsigned)amount_written, iteration_count); 470 } 471 if (amount_written == 0) { 472 io_status = SDL_GetIOStatus(process_stdin); 473 if (io_status != SDL_IO_STATUS_NOT_READY) { 474 SDLTest_Log("SDL_GetIOStatus(process_stdin) returns %d, breaking.", io_status); 475 break; 476 } 477 } 478 total_written += amount_written; 479 SDL_FlushIO(process_stdin); 480 } 481 482 /* FIXME: this needs a rate limit */ 483 if (log_this_iteration) { 484 SDLTest_AssertPass("About to SDL_ReadIO (%dth time)", iteration_count); 485 } 486 amount_read = SDL_ReadIO(process_stdout, local_buffer, sizeof(local_buffer)); 487 if (log_this_iteration) { 488 SDLTest_Log("SDL_ReadIO() -> %u (%dth time)", (unsigned)amount_read, iteration_count); 489 } 490 if (amount_read == 0) { 491 io_status = SDL_GetIOStatus(process_stdout); 492 if (io_status != SDL_IO_STATUS_NOT_READY) { 493 SDLTest_Log("SDL_GetIOStatus(process_stdout) returned %d, breaking.", io_status); 494 break; 495 } 496 } else { 497 total_read += amount_read; 498 SDL_WriteIO(stdout_stream, local_buffer, amount_read); 499 stdout_stream_buf = SDL_GetPointerProperty(SDL_GetIOProperties(stdout_stream), SDL_PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER, NULL); 500 if (SDL_strstr(stdout_stream_buf, "EOF")) { 501 SDLTest_Log("Found EOF in stdout"); 502 break; 503 } 504 } 505 SDL_Delay(10); 506 } 507 SDLTest_Log("Wrote %" SDL_PRIu64 " bytes to process.stdin", (Uint64)total_written); 508 SDLTest_Log("Read %" SDL_PRIu64 " bytes from process.stdout",(Uint64)total_read); 509 510 stdout_stream_buf = SDL_GetPointerProperty(SDL_GetIOProperties(stdout_stream), SDL_PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER, NULL); 511 SDLTest_CompareMemory(stdout_stream_buf, total_written, text_in, text_in_size); 512 513 exit_code = 0xdeadbeef; 514 wait_result = SDL_WaitProcess(process, false, &exit_code); 515 SDLTest_AssertCheck(wait_result == false, "Process should not have closed yet"); 516 517 SDLTest_AssertPass("About to close stdin"); 518 /* Closing stdin of `subprocessstdin --stdin-to-stdout` should close the process */ 519 SDL_CloseIO(process_stdin); 520 521 process_stdin = SDL_GetProcessInput(process); 522 SDLTest_AssertCheck(process_stdin == NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) is cleared after close"); 523 524 SDLTest_AssertPass("About to wait on process"); 525 exit_code = 0xdeadbeef; 526 wait_result = SDL_WaitProcess(process, true, &exit_code); 527 SDLTest_AssertCheck(wait_result == true, "Process should have closed when closing stdin"); 528 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 529 if (!wait_result) { 530 bool killed; 531 SDL_Log("About to kill process"); 532 killed = SDL_KillProcess(process, true); 533 SDLTest_AssertCheck(killed, "SDL_KillProcess succeeded"); 534 } 535 SDLTest_AssertPass("About to destroy process"); 536 SDL_DestroyProcess(process); 537 SDL_CloseIO(stdout_stream); 538 SDL_free(text_in); 539 return TEST_COMPLETED; 540failed: 541 542 SDL_DestroyProcess(process); 543 SDL_CloseIO(stdout_stream); 544 SDL_free(text_in); 545 return TEST_ABORTED; 546} 547 548static int process_testStdinToStderr(void *arg) 549{ 550 TestProcessData *data = (TestProcessData *)arg; 551 const char *process_args[] = { 552 data->childprocess_path, 553 "--stdin-to-stderr", 554 NULL, 555 }; 556 SDL_Process *process = NULL; 557 SDL_IOStream *process_stdin = NULL; 558 SDL_IOStream *process_stdout = NULL; 559 SDL_IOStream *process_stderr = NULL; 560 const char *text_in = "Tests whether we can write to stdin and read from stderr\r\n{'succes': true, 'message': 'Success!'}\r\nYippie ka yee\r\nEOF"; 561 size_t result; 562 int exit_code; 563 SDL_PropertiesID props; 564 char buffer[256]; 565 size_t amount_read; 566 567 props = SDL_CreateProperties(); 568 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 569 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 570 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_NULL); 571 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_APP); 572 process = SDL_CreateProcessWithProperties(props); 573 SDL_DestroyProperties(props); 574 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 575 if (!process) { 576 goto failed; 577 } 578 579 SDLTest_AssertPass("About to write to process"); 580 process_stdin = SDL_GetProcessInput(process); 581 SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetProcessInput()"); 582 result = SDL_WriteIO(process_stdin, text_in, SDL_strlen(text_in)); 583 SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in)); 584 SDL_CloseIO(process_stdin); 585 586 process_stdout = SDL_GetProcessOutput(process); 587 SDLTest_AssertCheck(process_stdout == NULL, "Process has no stdout"); 588 589 process_stderr = SDL_GetPointerProperty(SDL_GetProcessProperties(process), SDL_PROP_PROCESS_STDERR_POINTER, NULL); 590 SDLTest_AssertCheck(process_stderr != NULL, "Process has stderr"); 591 592 exit_code = 0xdeadbeef; 593 result = SDL_WaitProcess(process, true, &exit_code); 594 SDLTest_AssertCheck(result == true, "Process should have finished"); 595 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 596 597 amount_read = SDL_ReadIO(process_stderr, buffer, sizeof(buffer)); 598 SDLTest_CompareMemory(buffer, amount_read, text_in, SDL_strlen(text_in)); 599 600 SDLTest_AssertPass("About to destroy process"); 601 SDL_DestroyProcess(process); 602 return TEST_COMPLETED; 603 604failed: 605 SDL_DestroyProcess(process); 606 return TEST_ABORTED; 607} 608 609static int process_testSimpleStdinToStdout(void *arg) 610{ 611 TestProcessData *data = (TestProcessData *)arg; 612 const char *process_args[] = { 613 data->childprocess_path, 614 "--stdin-to-stdout", 615 NULL, 616 }; 617 SDL_Process *process = NULL; 618 SDL_IOStream *input = NULL; 619 const char *text_in = "Tests whether we can write to stdin and read from stdout\r\n{'succes': true, 'message': 'Success!'}\r\nYippie ka yee\r\nEOF"; 620 char *buffer; 621 size_t result; 622 int exit_code; 623 size_t total_read = 0; 624 625 process = SDL_CreateProcess(process_args, true); 626 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess()"); 627 if (!process) { 628 goto failed; 629 } 630 631 SDLTest_AssertPass("About to write to process"); 632 input = SDL_GetProcessInput(process); 633 SDLTest_AssertCheck(input != NULL, "SDL_GetProcessInput()"); 634 result = SDL_WriteIO(input, text_in, SDL_strlen(text_in)); 635 SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in)); 636 SDL_CloseIO(input); 637 638 input = SDL_GetProcessInput(process); 639 SDLTest_AssertCheck(input == NULL, "SDL_GetProcessInput() after close"); 640 641 exit_code = 0xdeadbeef; 642 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 643 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 644 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 645 if (!buffer) { 646 goto failed; 647 } 648 649 SDLTest_LogEscapedString("Expected text read from subprocess: %s", text_in, SDL_strlen(text_in)); 650 SDLTest_LogEscapedString("Actual text read from subprocess: %s", buffer, total_read); 651 SDLTest_AssertCheck(total_read == SDL_strlen(text_in), "Expected to read %u bytes, actually read %u bytes", (unsigned)SDL_strlen(text_in), (unsigned)total_read); 652 SDLTest_AssertCheck(SDL_strcmp(buffer, text_in) == 0, "Subprocess stdout should match text written to stdin"); 653 SDL_free(buffer); 654 655 SDLTest_AssertPass("About to destroy process"); 656 SDL_DestroyProcess(process); 657 return TEST_COMPLETED; 658 659failed: 660 SDL_DestroyProcess(process); 661 return TEST_ABORTED; 662} 663 664static int process_testMultiprocessStdinToStdout(void *arg) 665{ 666 TestProcessData *data = (TestProcessData *)arg; 667 const char *process_args[] = { 668 data->childprocess_path, 669 "--stdin-to-stdout", 670 "--log-stdin", 671 NULL, 672 NULL, 673 }; 674 SDL_Process *process1 = NULL; 675 SDL_Process *process2 = NULL; 676 SDL_PropertiesID props; 677 SDL_IOStream *input = NULL; 678 const char *text_in = "Tests whether we can write to stdin and read from stdout\r\n{'succes': true, 'message': 'Success!'}\r\nYippie ka yee\r\nEOF"; 679 char *buffer; 680 size_t result; 681 int exit_code; 682 size_t total_read = 0; 683 bool finished; 684 685 process_args[3] = "child1-stdin.txt"; 686 process1 = SDL_CreateProcess(process_args, true); 687 SDLTest_AssertCheck(process1 != NULL, "SDL_CreateProcess()"); 688 if (!process1) { 689 goto failed; 690 } 691 692 props = SDL_CreateProperties(); 693 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 694 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 695 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, SDL_GetPointerProperty(SDL_GetProcessProperties(process1), SDL_PROP_PROCESS_STDOUT_POINTER, NULL)); 696 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 697 SDLTest_AssertPass("About to call SDL_CreateProcessWithProperties"); 698 process_args[3] = "child2-stdin.txt"; 699 process2 = SDL_CreateProcessWithProperties(props); 700 SDL_DestroyProperties(props); 701 SDLTest_AssertCheck(process2 != NULL, "SDL_CreateProcess()"); 702 if (!process2) { 703 goto failed; 704 } 705 706 SDLTest_AssertPass("About to write to process"); 707 input = SDL_GetProcessInput(process1); 708 SDLTest_AssertCheck(input != NULL, "SDL_GetProcessInput()"); 709 result = SDL_WriteIO(input, text_in, SDL_strlen(text_in)); 710 SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in)); 711 SDL_CloseIO(input); 712 713 exit_code = 0xdeadbeef; 714 finished = SDL_WaitProcess(process1, true, &exit_code); 715 SDLTest_AssertCheck(finished == true, "process 1 should have finished"); 716 SDLTest_AssertCheck(exit_code == 0, "Exit code of process 1 should be 0, is %d", exit_code); 717 718 exit_code = 0xdeadbeef; 719 buffer = (char *)SDL_ReadProcess(process2, &total_read, &exit_code); 720 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 721 SDLTest_AssertCheck(exit_code == 0, "Exit code of process 2 should be 0, is %d", exit_code); 722 if (!buffer) { 723 goto failed; 724 } 725 726 SDLTest_LogEscapedString("Expected text read from subprocess: ", text_in, SDL_strlen(text_in)); 727 SDLTest_LogEscapedString("Actual text read from subprocess: ", buffer, total_read); 728 SDLTest_AssertCheck(total_read == SDL_strlen(text_in), "Expected to read %u bytes, actually read %u bytes", (unsigned)SDL_strlen(text_in), (unsigned)total_read); 729 SDLTest_AssertCheck(SDL_strcmp(buffer, text_in) == 0, "Subprocess stdout should match text written to stdin"); 730 SDL_free(buffer); 731 SDLTest_AssertPass("About to destroy processes"); 732 SDL_DestroyProcess(process1); 733 SDL_DestroyProcess(process2); 734 return TEST_COMPLETED; 735 736failed: 737 SDL_DestroyProcess(process1); 738 SDL_DestroyProcess(process2); 739 return TEST_ABORTED; 740} 741 742static int process_testWriteToFinishedProcess(void *arg) 743{ 744 TestProcessData *data = (TestProcessData *)arg; 745 const char *process_args[] = { 746 data->childprocess_path, 747 NULL, 748 }; 749 SDL_Process *process = NULL; 750 bool result; 751 int exit_code; 752 SDL_IOStream *process_stdin; 753 const char *text_in = "text_in"; 754 755 SDLTest_AssertPass("About to call SDL_CreateProcess"); 756 process = SDL_CreateProcess(process_args, true); 757 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess()"); 758 if (!process) { 759 goto failed; 760 } 761 762 exit_code = 0xdeadbeef; 763 SDLTest_AssertPass("About to call SDL_WaitProcess"); 764 result = SDL_WaitProcess(process, true, &exit_code); 765 SDLTest_AssertCheck(result, "SDL_WaitProcess()"); 766 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 767 768 process_stdin = SDL_GetProcessInput(process); 769 SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetProcessInput returns non-Null SDL_IOStream"); 770 SDLTest_AssertPass("About to call SDL_WriteIO on dead child process"); 771 SDL_WriteIO(process_stdin, text_in, SDL_strlen(text_in)); 772 773 SDLTest_AssertPass("About to destroy process"); 774 SDL_DestroyProcess(process); 775 return TEST_COMPLETED; 776 777failed: 778 SDL_DestroyProcess(process); 779 return TEST_ABORTED; 780} 781 782static int process_testNonExistingExecutable(void *arg) 783{ 784 static const int STEM_LENGTH = 16; 785 char **process_args; 786 char *random_stem; 787 char *random_path; 788 SDL_Process *process = NULL; 789 790 random_stem = SDLTest_RandomAsciiStringOfSize(STEM_LENGTH); 791 random_path = SDL_malloc(STEM_LENGTH + SDL_strlen(EXE) + 1); 792 SDL_snprintf(random_path, STEM_LENGTH + SDL_strlen(EXE) + 1, "%s%s", random_stem, EXE); 793 SDL_free(random_stem); 794 SDLTest_AssertCheck(!SDL_GetPathInfo(random_path, NULL), "%s does not exist", random_path); 795 796 process_args = CreateArguments(0, random_path, NULL); 797 SDL_free(random_path); 798 799 SDLTest_AssertPass("About to call SDL_CreateProcess"); 800 process = SDL_CreateProcess((const char * const *)process_args, false); 801 SDLTest_AssertCheck(process == NULL, "SDL_CreateProcess() should have failed (%s)", SDL_GetError()); 802 803 DestroyStringArray(process_args); 804 return TEST_COMPLETED; 805} 806 807static int process_testBatBadButVulnerability(void *arg) 808{ 809 TestProcessData *data = (TestProcessData *)arg; 810 char *inject_arg = NULL; 811 char **process_args = NULL; 812 char *text_out = NULL; 813 size_t len_text_out; 814 int exitcode; 815 SDL_Process *process = NULL; 816 SDL_IOStream *child_bat; 817 char buffer[256]; 818 819#ifndef SDL_PLATFORM_WINDOWS 820 SDLTest_AssertPass("The BatBadBut vulnerability only applied to Windows"); 821 return TEST_SKIPPED; 822#endif 823 /* FIXME: remove child.bat at end of loop and/or create in temporary directory */ 824 child_bat = SDL_IOFromFile("child_batbadbut.bat", "w"); 825 SDL_IOprintf(child_bat, "@echo off\necho Hello from child_batbadbut.bat\necho \"|bat1=%%1|\"\n"); 826 SDL_CloseIO(child_bat); 827 828 inject_arg = SDL_malloc(SDL_strlen(data->childprocess_path) + 100); 829 SDL_snprintf(inject_arg, SDL_strlen(data->childprocess_path) + 100, "\"&%s --version --print-arguments --stdout OWNEDSTDOUT\"", data->childprocess_path); 830 process_args = CreateArguments(0, "child_batbadbut.bat", inject_arg, NULL); 831 832 SDLTest_AssertPass("About to call SDL_CreateProcess"); 833 process = SDL_CreateProcess((const char * const*)process_args, true); 834 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess"); 835 if (!process) { 836 goto cleanup; 837 } 838 text_out = SDL_ReadProcess(process, &len_text_out, &exitcode); 839 SDLTest_AssertCheck(exitcode == 0, "process exited with exitcode 0, was %d", exitcode); 840 SDLTest_AssertCheck(text_out != NULL, "SDL_ReadProcess returned data"); 841 SDLTest_LogEscapedString("Output: ", text_out, len_text_out); 842 if (!text_out) { 843 goto cleanup; 844 } 845 846 SDLTest_AssertCheck(SDL_strstr(text_out, "Hello from child_batbadbut") != NULL, "stdout contains 'Hello from child'"); 847 SDLTest_AssertCheck(SDL_strstr(text_out, "SDL version") == NULL, "stdout should not contain SDL version"); 848 SDL_snprintf(buffer, sizeof(buffer), "|bat1=\"\"\"&%s\"\"|", process_args[1] + 2); 849 SDLTest_LogEscapedString("stdout should contain: ", buffer, SDL_strlen(buffer)); 850 SDLTest_AssertCheck(SDL_strstr(text_out, buffer) != NULL, "Verify first argument"); 851 852cleanup: 853 SDL_free(text_out); 854 SDL_DestroyProcess(process); 855 SDL_free(inject_arg); 856 DestroyStringArray(process_args); 857 return TEST_COMPLETED; 858} 859 860static int process_testFileRedirection(void *arg) 861{ 862 TestProcessData *data = (TestProcessData *)arg; 863 SDL_PropertiesID props = 0; 864 const char * process_args[] = { 865 data->childprocess_path, 866 "--stdin-to-stdout", 867 "--stdin-to-stderr", 868 NULL, 869 }; 870 const char TEXT_REF[] = "This is input for the child process"; 871 static const char *PATH_STDIN = "test_redirection_stdin.txt"; 872 static const char *PATH_STDOUT = "test_redirection_stdout.txt"; 873 static const char *PATH_STDERR = "test_redirection_stderr.txt"; 874 char *text_out = NULL; 875 size_t len_text_out; 876 int exitcode; 877 bool result; 878 SDL_Process *process = NULL; 879 SDL_IOStream *stream; 880 SDL_IOStream *input_stream = NULL; 881 SDL_IOStream *output_stream = NULL; 882 SDL_IOStream *error_stream = NULL; 883 884 stream = SDL_IOFromFile(PATH_STDIN, "w"); 885 SDLTest_AssertCheck(stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDIN); 886 if (!stream) { 887 goto cleanup; 888 } 889 SDL_WriteIO(stream, TEXT_REF, sizeof(TEXT_REF)); 890 SDL_CloseIO(stream); 891 892 input_stream = SDL_IOFromFile(PATH_STDIN, "r"); 893 SDLTest_AssertCheck(input_stream != NULL, "SDL_IOFromFile(\"%s\", \"r\")", PATH_STDIN); 894 if (!input_stream) { 895 goto cleanup; 896 } 897 898 output_stream = SDL_IOFromFile(PATH_STDOUT, "w"); 899 SDLTest_AssertCheck(output_stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDOUT); 900 if (!output_stream) { 901 goto cleanup; 902 } 903 904 error_stream = SDL_IOFromFile(PATH_STDERR, "w"); 905 SDLTest_AssertCheck(error_stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDERR); 906 if (!error_stream) { 907 goto cleanup; 908 } 909 910 props = SDL_CreateProperties(); 911 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 912 if (!props) { 913 goto cleanup; 914 } 915 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 916 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 917 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, (void *)input_stream); 918 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 919 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_POINTER, (void *)output_stream); 920 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 921 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_POINTER, (void *)error_stream); 922 process = SDL_CreateProcessWithProperties(props); 923 SDL_DestroyProperties(props); 924 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties (%s)", SDL_GetError()); 925 if (!process) { 926 goto cleanup; 927 } 928 929 exitcode = 0xdeadbeef; 930 text_out = SDL_ReadProcess(process, &len_text_out, &exitcode); 931 SDLTest_AssertCheck(text_out == NULL, "SDL_ReadProcess should not be able to close a redirected process (%s)", SDL_GetError()); 932 SDLTest_AssertCheck(len_text_out == 0, "length written by SDL_ReadProcess should be 0"); 933 SDL_free(text_out); 934 text_out = NULL; 935 936 exitcode = 0xdeadbeef; 937 result = SDL_WaitProcess(process, true, &exitcode); 938 SDLTest_AssertCheck(result, "process must have exited"); 939 SDLTest_AssertCheck(exitcode == 0, "process exited with exitcode 0, was %d", exitcode); 940 941 SDL_CloseIO(input_stream); 942 input_stream = NULL; 943 SDL_CloseIO(output_stream); 944 output_stream = NULL; 945 SDL_CloseIO(error_stream); 946 error_stream = NULL; 947 948 text_out = SDL_LoadFile(PATH_STDOUT, &len_text_out); 949 SDLTest_AssertCheck(text_out != NULL, "SDL_LoadFile(\"%s\") succeeded (%s)", PATH_STDOUT, SDL_GetError()); 950 SDLTest_AssertPass("Comparing stdout with reference"); 951 SDLTest_CompareMemory(text_out, len_text_out, TEXT_REF, sizeof(TEXT_REF)); 952 SDL_free(text_out); 953 954 text_out = SDL_LoadFile(PATH_STDERR, &len_text_out); 955 SDLTest_AssertCheck(text_out != NULL, "SDL_LoadFile(\"%s\") succeeded (%s)", PATH_STDERR, SDL_GetError()); 956 SDLTest_AssertPass("Comparing stderr with reference"); 957 SDLTest_CompareMemory(text_out, len_text_out, TEXT_REF, sizeof(TEXT_REF)); 958 SDL_free(text_out); 959 960cleanup: 961 SDL_CloseIO(input_stream); 962 SDL_CloseIO(output_stream); 963 SDL_CloseIO(error_stream); 964 SDL_DestroyProcess(process); 965 return TEST_COMPLETED; 966} 967 968static const SDLTest_TestCaseReference processTestArguments = { 969 process_testArguments, "process_testArguments", "Test passing arguments to child process", TEST_ENABLED 970}; 971 972static const SDLTest_TestCaseReference processTestExitCode = { 973 process_testexitCode, "process_testExitCode", "Test exit codes", TEST_ENABLED 974}; 975 976static const SDLTest_TestCaseReference processTestInheritedEnv = { 977 process_testInheritedEnv, "process_testInheritedEnv", "Test inheriting environment from parent process", TEST_ENABLED 978}; 979 980static const SDLTest_TestCaseReference processTestNewEnv = { 981 process_testNewEnv, "process_testNewEnv", "Test creating new environment for child process", TEST_ENABLED 982}; 983 984static const SDLTest_TestCaseReference processTestKill = { 985 process_testKill, "process_testKill", "Test Killing a child process", TEST_ENABLED 986}; 987 988static const SDLTest_TestCaseReference processTestStdinToStdout = { 989 process_testStdinToStdout, "process_testStdinToStdout", "Test writing to stdin and reading from stdout", TEST_ENABLED 990}; 991 992static const SDLTest_TestCaseReference processTestStdinToStderr = { 993 process_testStdinToStderr, "process_testStdinToStderr", "Test writing to stdin and reading from stderr", TEST_ENABLED 994}; 995 996static const SDLTest_TestCaseReference processTestSimpleStdinToStdout = { 997 process_testSimpleStdinToStdout, "process_testSimpleStdinToStdout", "Test writing to stdin and reading from stdout using the simplified API", TEST_ENABLED 998}; 999 1000static const SDLTest_TestCaseReference processTestMultiprocessStdinToStdout = { 1001 process_testMultiprocessStdinToStdout, "process_testMultiprocessStdinToStdout", "Test writing to stdin and reading from stdout using the simplified API", TEST_ENABLED 1002}; 1003 1004static const SDLTest_TestCaseReference processTestWriteToFinishedProcess = { 1005 process_testWriteToFinishedProcess, "process_testWriteToFinishedProcess", "Test writing to stdin of terminated process", TEST_ENABLED 1006}; 1007 1008static const SDLTest_TestCaseReference processTestNonExistingExecutable = { 1009 process_testNonExistingExecutable, "process_testNonExistingExecutable", "Test running a non-existing executable", TEST_ENABLED 1010}; 1011 1012static const SDLTest_TestCaseReference processTestBatBadButVulnerability = { 1013 process_testBatBadButVulnerability, "process_testBatBadButVulnerability", "Test BatBadBut vulnerability: command injection through cmd.exe", TEST_ENABLED 1014}; 1015 1016static const SDLTest_TestCaseReference processTestFileRedirection = { 1017 process_testFileRedirection, "process_testFileRedirection", "Test redirection from/to files", TEST_ENABLED 1018}; 1019 1020static const SDLTest_TestCaseReference *processTests[] = { 1021 &processTestArguments, 1022 &processTestExitCode, 1023 &processTestInheritedEnv, 1024 &processTestNewEnv, 1025 &processTestKill, 1026 &processTestStdinToStdout, 1027 &processTestStdinToStderr, 1028 &processTestSimpleStdinToStdout, 1029 &processTestMultiprocessStdinToStdout, 1030 &processTestWriteToFinishedProcess, 1031 &processTestNonExistingExecutable, 1032 &processTestBatBadButVulnerability, 1033 &processTestFileRedirection, 1034 NULL 1035}; 1036 1037static SDLTest_TestSuiteReference processTestSuite = { 1038 "Process", 1039 setUpProcess, 1040 processTests, 1041 NULL 1042}; 1043 1044static SDLTest_TestSuiteReference *testSuites[] = { 1045 &processTestSuite, 1046 NULL 1047}; 1048 1049int main(int argc, char *argv[]) 1050{ 1051 int i; 1052 int result; 1053 SDLTest_CommonState *state; 1054 SDLTest_TestSuiteRunner *runner; 1055 1056 /* Initialize test framework */ 1057 state = SDLTest_CommonCreateState(argv, 0); 1058 if (!state) { 1059 return 1; 1060 } 1061 1062 runner = SDLTest_CreateTestSuiteRunner(state, testSuites); 1063 1064 /* Parse commandline */ 1065 for (i = 1; i < argc;) { 1066 int consumed; 1067 1068 consumed = SDLTest_CommonArg(state, i); 1069 if (!consumed) { 1070 if (!parsed_args.childprocess_path) { 1071 parsed_args.childprocess_path = argv[i]; 1072 consumed = 1; 1073 } 1074 } 1075 if (consumed <= 0) { 1076 SDLTest_CommonLogUsage(state, argv[0], options); 1077 return 1; 1078 } 1079 1080 i += consumed; 1081 } 1082 1083 if (!parsed_args.childprocess_path) { 1084 SDLTest_CommonLogUsage(state, argv[0], options); 1085 return 1; 1086 } 1087 1088 result = SDLTest_ExecuteTestSuiteRunner(runner); 1089 1090 SDL_Quit(); 1091 SDLTest_DestroyTestSuiteRunner(runner); 1092 SDLTest_CommonDestroyState(state); 1093 return result; 1094}