Atlas - testprocess.c

Home / ext / SDL / test Lines: 14 | Size: 47392 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
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\v\r\n", 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 /* Wait for the child process to finish initializing */ 371 SDL_Delay(500); 372 373 SDLTest_AssertPass("About to call SDL_KillProcess(true)"); 374 result = SDL_KillProcess(process, true); 375 SDLTest_AssertCheck(result == true, "Process should have exited"); 376 377 exit_code = 0; 378 SDLTest_AssertPass("About to call SDL_WaitProcess(true)"); 379 result = SDL_WaitProcess(process, true, &exit_code); 380 SDLTest_AssertCheck(result == true, "Process should have exited"); 381 SDLTest_AssertCheck(exit_code != 0, "Exit code should be non-zero, is %d", exit_code); 382 383 SDLTest_AssertPass("About to destroy process"); 384 SDL_DestroyProcess(process); 385 return TEST_COMPLETED; 386 387failed: 388 SDL_DestroyProcess(process); 389 return TEST_ABORTED; 390} 391 392static int process_testStdinToStdout(void *arg) 393{ 394 TestProcessData *data = (TestProcessData *)arg; 395 const char *process_args[] = { 396 data->childprocess_path, 397 "--stdin-to-stdout", 398 NULL, 399 }; 400 SDL_PropertiesID props; 401 SDL_Process *process = NULL; 402 Sint64 pid; 403 SDL_IOStream *process_stdin = NULL; 404 SDL_IOStream *process_stdout = NULL; 405 SDL_IOStream *process_stderr = NULL; 406 size_t text_in_size = 1 * 1024 * 1024; 407 char *text_in = NULL; 408 size_t total_written; 409 size_t total_read; 410 bool wait_result; 411 int exit_code; 412 SDL_IOStream *stdout_stream = NULL; 413 char *stdout_stream_buf; 414 int iteration_count = 0; 415 416 text_in = SDLTest_RandomAsciiStringOfSize((int)text_in_size); 417 /* Make sure text_in does not contain EOF */ 418 for (;;) { 419 char *e = SDL_strstr(text_in, "EOF"); 420 if (!e) { 421 break; 422 } 423 e[0] = 'N'; 424 } 425 text_in[text_in_size - 3] = 'E'; 426 text_in[text_in_size - 2] = 'O'; 427 text_in[text_in_size - 1] = 'F'; 428 429 stdout_stream = SDL_IOFromDynamicMem(); 430 431 props = SDL_CreateProperties(); 432 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 433 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 434 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 435 process = SDL_CreateProcessWithProperties(props); 436 SDL_DestroyProperties(props); 437 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 438 if (!process) { 439 goto failed; 440 } 441 442 props = SDL_GetProcessProperties(process); 443 SDLTest_AssertCheck(props != 0, "SDL_GetProcessProperties()"); 444 445 pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0); 446 SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid); 447 448 process_stdin = SDL_GetProcessInput(process); 449 SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) returns a valid IO stream"); 450 process_stdout = SDL_GetProcessOutput(process); 451 SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream"); 452 process_stderr = (SDL_IOStream *)SDL_GetPointerProperty(props, SDL_PROP_PROCESS_STDERR_POINTER, NULL); 453 SDLTest_AssertCheck(process_stderr == NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDERR_POINTER) returns NULL"); 454 if (!process_stdin || !process_stdout) { 455 goto failed; 456 } 457 458 total_written = 0; 459 total_read = 0; 460 for (;;) { 461 int log_this_iteration = (iteration_count % 32) == 32; 462 char local_buffer[16 * 4094]; 463 size_t amount_read; 464 SDL_IOStatus io_status; 465 if (total_written != text_in_size) { 466 size_t amount_written; 467 if (log_this_iteration) { 468 SDLTest_AssertPass("About to SDL_WriteIO (%dth time)", iteration_count); 469 } 470 amount_written = SDL_WriteIO(process_stdin, text_in + total_written, text_in_size - total_written); 471 if (log_this_iteration) { 472 SDLTest_Log("SDL_WriteIO() -> %u (%dth time)", (unsigned)amount_written, iteration_count); 473 } 474 if (amount_written == 0) { 475 io_status = SDL_GetIOStatus(process_stdin); 476 if (io_status != SDL_IO_STATUS_NOT_READY) { 477 SDLTest_Log("SDL_GetIOStatus(process_stdin) returns %d, breaking.", io_status); 478 break; 479 } 480 } 481 total_written += amount_written; 482 SDL_FlushIO(process_stdin); 483 } 484 485 /* FIXME: this needs a rate limit */ 486 if (log_this_iteration) { 487 SDLTest_AssertPass("About to SDL_ReadIO (%dth time)", iteration_count); 488 } 489 amount_read = SDL_ReadIO(process_stdout, local_buffer, sizeof(local_buffer)); 490 if (log_this_iteration) { 491 SDLTest_Log("SDL_ReadIO() -> %u (%dth time)", (unsigned)amount_read, iteration_count); 492 } 493 if (amount_read == 0) { 494 io_status = SDL_GetIOStatus(process_stdout); 495 if (io_status != SDL_IO_STATUS_NOT_READY) { 496 SDLTest_Log("SDL_GetIOStatus(process_stdout) returned %d, breaking.", io_status); 497 break; 498 } 499 } else { 500 total_read += amount_read; 501 SDL_WriteIO(stdout_stream, local_buffer, amount_read); 502 stdout_stream_buf = SDL_GetPointerProperty(SDL_GetIOProperties(stdout_stream), SDL_PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER, NULL); 503 if (SDL_strstr(stdout_stream_buf, "EOF")) { 504 SDLTest_Log("Found EOF in stdout"); 505 break; 506 } 507 } 508 SDL_Delay(10); 509 } 510 SDLTest_Log("Wrote %" SDL_PRIu64 " bytes to process.stdin", (Uint64)total_written); 511 SDLTest_Log("Read %" SDL_PRIu64 " bytes from process.stdout",(Uint64)total_read); 512 513 stdout_stream_buf = SDL_GetPointerProperty(SDL_GetIOProperties(stdout_stream), SDL_PROP_IOSTREAM_DYNAMIC_MEMORY_POINTER, NULL); 514 SDLTest_CompareMemory(stdout_stream_buf, total_written, text_in, text_in_size); 515 516 exit_code = 0xdeadbeef; 517 wait_result = SDL_WaitProcess(process, false, &exit_code); 518 SDLTest_AssertCheck(wait_result == false, "Process should not have closed yet"); 519 520 SDLTest_AssertPass("About to close stdin"); 521 /* Closing stdin of `subprocessstdin --stdin-to-stdout` should close the process */ 522 SDL_CloseIO(process_stdin); 523 524 process_stdin = SDL_GetProcessInput(process); 525 SDLTest_AssertCheck(process_stdin == NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) is cleared after close"); 526 527 SDLTest_AssertPass("About to wait on process"); 528 exit_code = 0xdeadbeef; 529 wait_result = SDL_WaitProcess(process, true, &exit_code); 530 SDLTest_AssertCheck(wait_result == true, "Process should have closed when closing stdin"); 531 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 532 if (!wait_result) { 533 bool killed; 534 SDL_Log("About to kill process"); 535 killed = SDL_KillProcess(process, true); 536 SDLTest_AssertCheck(killed, "SDL_KillProcess succeeded"); 537 } 538 SDLTest_AssertPass("About to destroy process"); 539 SDL_DestroyProcess(process); 540 SDL_CloseIO(stdout_stream); 541 SDL_free(text_in); 542 return TEST_COMPLETED; 543failed: 544 545 SDL_DestroyProcess(process); 546 SDL_CloseIO(stdout_stream); 547 SDL_free(text_in); 548 return TEST_ABORTED; 549} 550 551static int process_testStdinToStderr(void *arg) 552{ 553 TestProcessData *data = (TestProcessData *)arg; 554 const char *process_args[] = { 555 data->childprocess_path, 556 "--stdin-to-stderr", 557 NULL, 558 }; 559 SDL_Process *process = NULL; 560 SDL_IOStream *process_stdin = NULL; 561 SDL_IOStream *process_stdout = NULL; 562 SDL_IOStream *process_stderr = NULL; 563 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"; 564 size_t result; 565 int exit_code; 566 SDL_PropertiesID props; 567 char buffer[256]; 568 size_t amount_read; 569 570 props = SDL_CreateProperties(); 571 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 572 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 573 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_NULL); 574 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_APP); 575 process = SDL_CreateProcessWithProperties(props); 576 SDL_DestroyProperties(props); 577 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 578 if (!process) { 579 goto failed; 580 } 581 582 SDLTest_AssertPass("About to write to process"); 583 process_stdin = SDL_GetProcessInput(process); 584 SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetProcessInput()"); 585 result = SDL_WriteIO(process_stdin, text_in, SDL_strlen(text_in)); 586 SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in)); 587 SDL_CloseIO(process_stdin); 588 589 process_stdout = SDL_GetProcessOutput(process); 590 SDLTest_AssertCheck(process_stdout == NULL, "Process has no stdout"); 591 592 process_stderr = SDL_GetPointerProperty(SDL_GetProcessProperties(process), SDL_PROP_PROCESS_STDERR_POINTER, NULL); 593 SDLTest_AssertCheck(process_stderr != NULL, "Process has stderr"); 594 595 exit_code = 0xdeadbeef; 596 result = SDL_WaitProcess(process, true, &exit_code); 597 SDLTest_AssertCheck(result == true, "Process should have finished"); 598 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 599 600 amount_read = SDL_ReadIO(process_stderr, buffer, sizeof(buffer)); 601 SDLTest_CompareMemory(buffer, amount_read, text_in, SDL_strlen(text_in)); 602 603 SDLTest_AssertPass("About to destroy process"); 604 SDL_DestroyProcess(process); 605 return TEST_COMPLETED; 606 607failed: 608 SDL_DestroyProcess(process); 609 return TEST_ABORTED; 610} 611 612static int process_testSimpleStdinToStdout(void *arg) 613{ 614 TestProcessData *data = (TestProcessData *)arg; 615 const char *process_args[] = { 616 data->childprocess_path, 617 "--stdin-to-stdout", 618 NULL, 619 }; 620 SDL_Process *process = NULL; 621 SDL_IOStream *input = NULL; 622 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"; 623 char *buffer; 624 size_t result; 625 int exit_code; 626 size_t total_read = 0; 627 628 process = SDL_CreateProcess(process_args, true); 629 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess()"); 630 if (!process) { 631 goto failed; 632 } 633 634 SDLTest_AssertPass("About to write to process"); 635 input = SDL_GetProcessInput(process); 636 SDLTest_AssertCheck(input != NULL, "SDL_GetProcessInput()"); 637 result = SDL_WriteIO(input, text_in, SDL_strlen(text_in)); 638 SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in)); 639 SDL_CloseIO(input); 640 641 input = SDL_GetProcessInput(process); 642 SDLTest_AssertCheck(input == NULL, "SDL_GetProcessInput() after close"); 643 644 exit_code = 0xdeadbeef; 645 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 646 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 647 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 648 if (!buffer) { 649 goto failed; 650 } 651 652 SDLTest_LogEscapedString("Expected text read from subprocess: %s", text_in, SDL_strlen(text_in)); 653 SDLTest_LogEscapedString("Actual text read from subprocess: %s", buffer, total_read); 654 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); 655 SDLTest_AssertCheck(SDL_strcmp(buffer, text_in) == 0, "Subprocess stdout should match text written to stdin"); 656 SDL_free(buffer); 657 658 SDLTest_AssertPass("About to destroy process"); 659 SDL_DestroyProcess(process); 660 return TEST_COMPLETED; 661 662failed: 663 SDL_DestroyProcess(process); 664 return TEST_ABORTED; 665} 666 667static int process_testMultiprocessStdinToStdout(void *arg) 668{ 669 TestProcessData *data = (TestProcessData *)arg; 670 const char *process_args[] = { 671 data->childprocess_path, 672 "--stdin-to-stdout", 673 "--log-stdin", 674 NULL, 675 NULL, 676 }; 677 SDL_Process *process1 = NULL; 678 SDL_Process *process2 = NULL; 679 SDL_PropertiesID props; 680 SDL_IOStream *input = NULL; 681 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"; 682 char *buffer; 683 size_t result; 684 int exit_code; 685 size_t total_read = 0; 686 bool finished; 687 688 process_args[3] = "child1-stdin.txt"; 689 process1 = SDL_CreateProcess(process_args, true); 690 SDLTest_AssertCheck(process1 != NULL, "SDL_CreateProcess()"); 691 if (!process1) { 692 goto failed; 693 } 694 695 props = SDL_CreateProperties(); 696 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 697 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 698 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, SDL_GetPointerProperty(SDL_GetProcessProperties(process1), SDL_PROP_PROCESS_STDOUT_POINTER, NULL)); 699 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 700 SDLTest_AssertPass("About to call SDL_CreateProcessWithProperties"); 701 process_args[3] = "child2-stdin.txt"; 702 process2 = SDL_CreateProcessWithProperties(props); 703 SDL_DestroyProperties(props); 704 SDLTest_AssertCheck(process2 != NULL, "SDL_CreateProcess()"); 705 if (!process2) { 706 goto failed; 707 } 708 709 SDLTest_AssertPass("About to write to process"); 710 input = SDL_GetProcessInput(process1); 711 SDLTest_AssertCheck(input != NULL, "SDL_GetProcessInput()"); 712 result = SDL_WriteIO(input, text_in, SDL_strlen(text_in)); 713 SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in)); 714 SDL_CloseIO(input); 715 716 exit_code = 0xdeadbeef; 717 finished = SDL_WaitProcess(process1, true, &exit_code); 718 SDLTest_AssertCheck(finished == true, "process 1 should have finished"); 719 SDLTest_AssertCheck(exit_code == 0, "Exit code of process 1 should be 0, is %d", exit_code); 720 721 exit_code = 0xdeadbeef; 722 buffer = (char *)SDL_ReadProcess(process2, &total_read, &exit_code); 723 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 724 SDLTest_AssertCheck(exit_code == 0, "Exit code of process 2 should be 0, is %d", exit_code); 725 if (!buffer) { 726 goto failed; 727 } 728 729 SDLTest_LogEscapedString("Expected text read from subprocess: ", text_in, SDL_strlen(text_in)); 730 SDLTest_LogEscapedString("Actual text read from subprocess: ", buffer, total_read); 731 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); 732 SDLTest_AssertCheck(SDL_strcmp(buffer, text_in) == 0, "Subprocess stdout should match text written to stdin"); 733 SDL_free(buffer); 734 SDLTest_AssertPass("About to destroy processes"); 735 SDL_DestroyProcess(process1); 736 SDL_DestroyProcess(process2); 737 return TEST_COMPLETED; 738 739failed: 740 SDL_DestroyProcess(process1); 741 SDL_DestroyProcess(process2); 742 return TEST_ABORTED; 743} 744 745static int process_testWriteToFinishedProcess(void *arg) 746{ 747 TestProcessData *data = (TestProcessData *)arg; 748 const char *process_args[] = { 749 data->childprocess_path, 750 NULL, 751 }; 752 SDL_Process *process = NULL; 753 bool result; 754 int exit_code; 755 SDL_IOStream *process_stdin; 756 const char *text_in = "text_in"; 757 758 SDLTest_AssertPass("About to call SDL_CreateProcess"); 759 process = SDL_CreateProcess(process_args, true); 760 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess()"); 761 if (!process) { 762 goto failed; 763 } 764 765 exit_code = 0xdeadbeef; 766 SDLTest_AssertPass("About to call SDL_WaitProcess"); 767 result = SDL_WaitProcess(process, true, &exit_code); 768 SDLTest_AssertCheck(result, "SDL_WaitProcess()"); 769 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 770 771 process_stdin = SDL_GetProcessInput(process); 772 SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetProcessInput returns non-Null SDL_IOStream"); 773 SDLTest_AssertPass("About to call SDL_WriteIO on dead child process"); 774 SDL_WriteIO(process_stdin, text_in, SDL_strlen(text_in)); 775 776 SDLTest_AssertPass("About to destroy process"); 777 SDL_DestroyProcess(process); 778 return TEST_COMPLETED; 779 780failed: 781 SDL_DestroyProcess(process); 782 return TEST_ABORTED; 783} 784 785static int process_testNonExistingExecutable(void *arg) 786{ 787 static const int STEM_LENGTH = 16; 788 char **process_args; 789 char *random_stem; 790 char *random_path; 791 SDL_Process *process = NULL; 792 793 random_stem = SDLTest_RandomAsciiStringOfSize(STEM_LENGTH); 794 random_path = SDL_malloc(STEM_LENGTH + SDL_strlen(EXE) + 1); 795 SDL_snprintf(random_path, STEM_LENGTH + SDL_strlen(EXE) + 1, "%s%s", random_stem, EXE); 796 SDL_free(random_stem); 797 SDLTest_AssertCheck(!SDL_GetPathInfo(random_path, NULL), "%s does not exist", random_path); 798 799 process_args = CreateArguments(0, random_path, NULL); 800 SDL_free(random_path); 801 802 SDLTest_AssertPass("About to call SDL_CreateProcess"); 803 process = SDL_CreateProcess((const char * const *)process_args, false); 804 SDLTest_AssertCheck(process == NULL, "SDL_CreateProcess() should have failed (%s)", SDL_GetError()); 805 806 DestroyStringArray(process_args); 807 return TEST_COMPLETED; 808} 809 810static int process_testBatBadButVulnerability(void *arg) 811{ 812#ifndef SDL_PLATFORM_WINDOWS 813 SDLTest_AssertPass("The BatBadBut vulnerability only applied to Windows"); 814 return TEST_SKIPPED; 815#else 816 817 TestProcessData *data = (TestProcessData *)arg; 818 char *inject_arg = NULL; 819 char **process_args = NULL; 820 char *text_out = NULL; 821 size_t len_text_out; 822 int exitcode; 823 SDL_Process *process = NULL; 824 SDL_IOStream *child_bat; 825 char buffer[256]; 826 827 /* FIXME: remove child.bat at end of loop and/or create in temporary directory */ 828 child_bat = SDL_IOFromFile("child_batbadbut.bat", "w"); 829 SDL_IOprintf(child_bat, "@echo off\necho Hello from child_batbadbut.bat\necho \"|bat1=%%1|\"\n"); 830 SDL_CloseIO(child_bat); 831 832 inject_arg = SDL_malloc(SDL_strlen(data->childprocess_path) + 100); 833 SDL_snprintf(inject_arg, SDL_strlen(data->childprocess_path) + 100, "\"&%s --version --print-arguments --stdout OWNEDSTDOUT\"", data->childprocess_path); 834 process_args = CreateArguments(0, "child_batbadbut.bat", inject_arg, NULL); 835 836 SDLTest_AssertPass("About to call SDL_CreateProcess"); 837 process = SDL_CreateProcess((const char * const*)process_args, true); 838 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess"); 839 if (!process) { 840 goto cleanup; 841 } 842 text_out = SDL_ReadProcess(process, &len_text_out, &exitcode); 843 SDLTest_AssertCheck(exitcode == 0, "process exited with exitcode 0, was %d", exitcode); 844 SDLTest_AssertCheck(text_out != NULL, "SDL_ReadProcess returned data"); 845 SDLTest_LogEscapedString("Output: ", text_out, len_text_out); 846 if (!text_out) { 847 goto cleanup; 848 } 849 850 SDLTest_AssertCheck(SDL_strstr(text_out, "Hello from child_batbadbut") != NULL, "stdout contains 'Hello from child'"); 851 SDLTest_AssertCheck(SDL_strstr(text_out, "SDL version") == NULL, "stdout should not contain SDL version"); 852 SDL_snprintf(buffer, sizeof(buffer), "|bat1=\"\"\"&%s\"\"|", process_args[1] + 2); 853 SDLTest_LogEscapedString("stdout should contain: ", buffer, SDL_strlen(buffer)); 854 SDLTest_AssertCheck(SDL_strstr(text_out, buffer) != NULL, "Verify first argument"); 855 856cleanup: 857 SDL_free(text_out); 858 SDL_DestroyProcess(process); 859 SDL_free(inject_arg); 860 DestroyStringArray(process_args); 861 return TEST_COMPLETED; 862#endif 863} 864 865static int process_testFileRedirection(void *arg) 866{ 867 TestProcessData *data = (TestProcessData *)arg; 868 SDL_PropertiesID props = 0; 869 const char * process_args[] = { 870 data->childprocess_path, 871 "--stdin-to-stdout", 872 "--stdin-to-stderr", 873 NULL, 874 }; 875 const char TEXT_REF[] = "This is input for the child process"; 876 static const char *PATH_STDIN = "test_redirection_stdin.txt"; 877 static const char *PATH_STDOUT = "test_redirection_stdout.txt"; 878 static const char *PATH_STDERR = "test_redirection_stderr.txt"; 879 char *text_out = NULL; 880 size_t len_text_out; 881 int exitcode; 882 bool result; 883 SDL_Process *process = NULL; 884 SDL_IOStream *stream; 885 SDL_IOStream *input_stream = NULL; 886 SDL_IOStream *output_stream = NULL; 887 SDL_IOStream *error_stream = NULL; 888 889 stream = SDL_IOFromFile(PATH_STDIN, "w"); 890 SDLTest_AssertCheck(stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDIN); 891 if (!stream) { 892 goto cleanup; 893 } 894 SDL_WriteIO(stream, TEXT_REF, sizeof(TEXT_REF)); 895 SDL_CloseIO(stream); 896 897 input_stream = SDL_IOFromFile(PATH_STDIN, "r"); 898 SDLTest_AssertCheck(input_stream != NULL, "SDL_IOFromFile(\"%s\", \"r\")", PATH_STDIN); 899 if (!input_stream) { 900 goto cleanup; 901 } 902 903 output_stream = SDL_IOFromFile(PATH_STDOUT, "w"); 904 SDLTest_AssertCheck(output_stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDOUT); 905 if (!output_stream) { 906 goto cleanup; 907 } 908 909 error_stream = SDL_IOFromFile(PATH_STDERR, "w"); 910 SDLTest_AssertCheck(error_stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDERR); 911 if (!error_stream) { 912 goto cleanup; 913 } 914 915 props = SDL_CreateProperties(); 916 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 917 if (!props) { 918 goto cleanup; 919 } 920 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 921 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 922 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, (void *)input_stream); 923 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 924 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_POINTER, (void *)output_stream); 925 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 926 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_POINTER, (void *)error_stream); 927 process = SDL_CreateProcessWithProperties(props); 928 SDL_DestroyProperties(props); 929 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties (%s)", SDL_GetError()); 930 if (!process) { 931 goto cleanup; 932 } 933 934 exitcode = 0xdeadbeef; 935 text_out = SDL_ReadProcess(process, &len_text_out, &exitcode); 936 SDLTest_AssertCheck(text_out == NULL, "SDL_ReadProcess should not be able to close a redirected process (%s)", SDL_GetError()); 937 SDLTest_AssertCheck(len_text_out == 0, "length written by SDL_ReadProcess should be 0"); 938 SDL_free(text_out); 939 text_out = NULL; 940 941 exitcode = 0xdeadbeef; 942 result = SDL_WaitProcess(process, true, &exitcode); 943 SDLTest_AssertCheck(result, "process must have exited"); 944 SDLTest_AssertCheck(exitcode == 0, "process exited with exitcode 0, was %d", exitcode); 945 946 SDL_CloseIO(input_stream); 947 input_stream = NULL; 948 SDL_CloseIO(output_stream); 949 output_stream = NULL; 950 SDL_CloseIO(error_stream); 951 error_stream = NULL; 952 953 text_out = SDL_LoadFile(PATH_STDOUT, &len_text_out); 954 SDLTest_AssertCheck(text_out != NULL, "SDL_LoadFile(\"%s\") succeeded (%s)", PATH_STDOUT, SDL_GetError()); 955 SDLTest_AssertPass("Comparing stdout with reference"); 956 SDLTest_CompareMemory(text_out, len_text_out, TEXT_REF, sizeof(TEXT_REF)); 957 SDL_free(text_out); 958 959 text_out = SDL_LoadFile(PATH_STDERR, &len_text_out); 960 SDLTest_AssertCheck(text_out != NULL, "SDL_LoadFile(\"%s\") succeeded (%s)", PATH_STDERR, SDL_GetError()); 961 SDLTest_AssertPass("Comparing stderr with reference"); 962 SDLTest_CompareMemory(text_out, len_text_out, TEXT_REF, sizeof(TEXT_REF)); 963 SDL_free(text_out); 964 965cleanup: 966 SDL_CloseIO(input_stream); 967 SDL_CloseIO(output_stream); 968 SDL_CloseIO(error_stream); 969 SDL_DestroyProcess(process); 970 return TEST_COMPLETED; 971} 972 973static int process_testWindowsCmdline(void *arg) 974{ 975#ifndef SDL_PLATFORM_WINDOWS 976 SDLTest_AssertPass("SDL_PROP_PROCESS_CREATE_CMDLINE_STRING only works on Windows"); 977 return TEST_SKIPPED; 978#else 979 980 TestProcessData *data = (TestProcessData *)arg; 981 const char *process_args[] = { 982 data->childprocess_path, 983 "--print-arguments", 984 "--", 985 "", 986 " ", 987 "a b c", 988 "a\tb\tc\t", 989 "\"a b\" c", 990 "'a' 'b' 'c'", 991 "%d%%%s", 992 "\\t\\c", 993 "evil\\", 994 "a\\b\"c\\", 995 "\"\\^&|<>%", /* characters with a special meaning */ 996 NULL 997 }; 998 /* this will have the same result as process_args, but escaped in a different way */ 999 const char *process_cmdline_template = 1000 "%s " 1001 "--print-arguments " 1002 "-- " 1003 "\"\" " 1004 "\" \" " 1005 "a\" \"b\" \"c\t" /* using tab as delimiter */ 1006 "\"a\tb\tc\t\" " 1007 "\"\"\"\"a b\"\"\" c\" " 1008 "\"'a' 'b' 'c'\" " 1009 "%%d%%%%%%s " /* will be passed to sprintf */ 1010 "\\t\\c " 1011 "evil\\ " 1012 "a\\b\"\\\"\"c\\ " 1013 "\\\"\\^&|<>%%"; 1014 char process_cmdline[65535]; 1015 SDL_PropertiesID props; 1016 SDL_Process *process = NULL; 1017 char *buffer; 1018 int exit_code; 1019 int i; 1020 size_t total_read = 0; 1021 1022 props = SDL_CreateProperties(); 1023 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 1024 if (!props) { 1025 goto failed; 1026 } 1027 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 1028 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 1029 SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN, true); 1030 1031 process = SDL_CreateProcessWithProperties(props); 1032 SDLTest_AssertCheck(process == NULL, "SDL_CreateProcessWithProperties() should fail"); 1033 1034 SDL_snprintf(process_cmdline, SDL_arraysize(process_cmdline), process_cmdline_template, data->childprocess_path); 1035 SDL_SetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, process_cmdline); 1036 1037 process = SDL_CreateProcessWithProperties(props); 1038 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 1039 if (!process) { 1040 goto failed; 1041 } 1042 1043 exit_code = 0xdeadbeef; 1044 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 1045 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 1046 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 1047 if (!buffer) { 1048 goto failed; 1049 } 1050 SDLTest_LogEscapedString("stdout of process: ", buffer, total_read); 1051 1052 for (i = 3; process_args[i]; i++) { 1053 char line[64]; 1054 SDL_snprintf(line, sizeof(line), "|%d=%s|", i - 3, process_args[i]); 1055 SDLTest_AssertCheck(!!SDL_strstr(buffer, line), "Check %s is in output", line); 1056 } 1057 SDL_free(buffer); 1058 1059 SDLTest_AssertPass("About to destroy process"); 1060 SDL_DestroyProcess(process); 1061 1062 return TEST_COMPLETED; 1063 1064failed: 1065 SDL_DestroyProcess(process); 1066 return TEST_ABORTED; 1067#endif 1068} 1069 1070static int process_testWindowsCmdlinePrecedence(void *arg) 1071{ 1072#ifndef SDL_PLATFORM_WINDOWS 1073 SDLTest_AssertPass("SDL_PROP_PROCESS_CREATE_CMDLINE_STRING only works on Windows"); 1074 return TEST_SKIPPED; 1075#else 1076 1077 TestProcessData *data = (TestProcessData *)arg; 1078 const char *process_args[] = { 1079 data->childprocess_path, 1080 "--print-arguments", 1081 "--", 1082 "argument 1", 1083 NULL 1084 }; 1085 const char *process_cmdline_template = "%s --print-arguments -- \"argument 2\""; 1086 char process_cmdline[65535]; 1087 SDL_PropertiesID props; 1088 SDL_Process *process = NULL; 1089 char *buffer; 1090 int exit_code; 1091 size_t total_read = 0; 1092 1093 props = SDL_CreateProperties(); 1094 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 1095 if (!props) { 1096 goto failed; 1097 } 1098 1099 SDL_snprintf(process_cmdline, SDL_arraysize(process_cmdline), process_cmdline_template, data->childprocess_path); 1100 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 1101 SDL_SetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, (const char *)process_cmdline); 1102 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 1103 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 1104 SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN, true); 1105 1106 process = SDL_CreateProcessWithProperties(props); 1107 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 1108 if (!process) { 1109 goto failed; 1110 } 1111 1112 exit_code = 0xdeadbeef; 1113 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 1114 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 1115 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 1116 if (!buffer) { 1117 goto failed; 1118 } 1119 SDLTest_LogEscapedString("stdout of process: ", buffer, total_read); 1120 SDLTest_AssertCheck(!!SDL_strstr(buffer, "|0=argument 2|"), "Check |0=argument 2| is printed"); 1121 SDL_free(buffer); 1122 1123 SDLTest_AssertPass("About to destroy process"); 1124 SDL_DestroyProcess(process); 1125 1126 return TEST_COMPLETED; 1127 1128failed: 1129 SDL_DestroyProcess(process); 1130 return TEST_ABORTED; 1131#endif 1132} 1133 1134static const SDLTest_TestCaseReference processTestArguments = { 1135 process_testArguments, "process_testArguments", "Test passing arguments to child process", TEST_ENABLED 1136}; 1137 1138static const SDLTest_TestCaseReference processTestExitCode = { 1139 process_testexitCode, "process_testExitCode", "Test exit codes", TEST_ENABLED 1140}; 1141 1142static const SDLTest_TestCaseReference processTestInheritedEnv = { 1143 process_testInheritedEnv, "process_testInheritedEnv", "Test inheriting environment from parent process", TEST_ENABLED 1144}; 1145 1146static const SDLTest_TestCaseReference processTestNewEnv = { 1147 process_testNewEnv, "process_testNewEnv", "Test creating new environment for child process", TEST_ENABLED 1148}; 1149 1150static const SDLTest_TestCaseReference processTestKill = { 1151 process_testKill, "process_testKill", "Test Killing a child process", TEST_ENABLED 1152}; 1153 1154static const SDLTest_TestCaseReference processTestStdinToStdout = { 1155 process_testStdinToStdout, "process_testStdinToStdout", "Test writing to stdin and reading from stdout", TEST_ENABLED 1156}; 1157 1158static const SDLTest_TestCaseReference processTestStdinToStderr = { 1159 process_testStdinToStderr, "process_testStdinToStderr", "Test writing to stdin and reading from stderr", TEST_ENABLED 1160}; 1161 1162static const SDLTest_TestCaseReference processTestSimpleStdinToStdout = { 1163 process_testSimpleStdinToStdout, "process_testSimpleStdinToStdout", "Test writing to stdin and reading from stdout using the simplified API", TEST_ENABLED 1164}; 1165 1166static const SDLTest_TestCaseReference processTestMultiprocessStdinToStdout = { 1167 process_testMultiprocessStdinToStdout, "process_testMultiprocessStdinToStdout", "Test writing to stdin and reading from stdout using the simplified API", TEST_ENABLED 1168}; 1169 1170static const SDLTest_TestCaseReference processTestWriteToFinishedProcess = { 1171 process_testWriteToFinishedProcess, "process_testWriteToFinishedProcess", "Test writing to stdin of terminated process", TEST_ENABLED 1172}; 1173 1174static const SDLTest_TestCaseReference processTestNonExistingExecutable = { 1175 process_testNonExistingExecutable, "process_testNonExistingExecutable", "Test running a non-existing executable", TEST_ENABLED 1176}; 1177 1178static const SDLTest_TestCaseReference processTestBatBadButVulnerability = { 1179 process_testBatBadButVulnerability, "process_testBatBadButVulnerability", "Test BatBadBut vulnerability: command injection through cmd.exe", TEST_ENABLED 1180}; 1181 1182static const SDLTest_TestCaseReference processTestFileRedirection = { 1183 process_testFileRedirection, "process_testFileRedirection", "Test redirection from/to files", TEST_ENABLED 1184}; 1185 1186static const SDLTest_TestCaseReference processTestWindowsCmdline = { 1187 process_testWindowsCmdline, "process_testWindowsCmdline", "Test passing cmdline directly to CreateProcess", TEST_ENABLED 1188}; 1189 1190static const SDLTest_TestCaseReference processTestWindowsCmdlinePrecedence = { 1191 process_testWindowsCmdlinePrecedence, "process_testWindowsCmdlinePrecedence", "Test SDL_PROP_PROCESS_CREATE_CMDLINE_STRING precedence over SDL_PROP_PROCESS_CREATE_ARGS_POINTER", TEST_ENABLED 1192}; 1193 1194static const SDLTest_TestCaseReference *processTests[] = { 1195 &processTestArguments, 1196 &processTestExitCode, 1197 &processTestInheritedEnv, 1198 &processTestNewEnv, 1199 &processTestKill, 1200 &processTestStdinToStdout, 1201 &processTestStdinToStderr, 1202 &processTestSimpleStdinToStdout, 1203 &processTestMultiprocessStdinToStdout, 1204 &processTestWriteToFinishedProcess, 1205 &processTestNonExistingExecutable, 1206 &processTestBatBadButVulnerability, 1207 &processTestFileRedirection, 1208 &processTestWindowsCmdline, 1209 &processTestWindowsCmdlinePrecedence, 1210 NULL 1211}; 1212 1213static SDLTest_TestSuiteReference processTestSuite = { 1214 "Process", 1215 setUpProcess, 1216 processTests, 1217 NULL 1218}; 1219 1220static SDLTest_TestSuiteReference *testSuites[] = { 1221 &processTestSuite, 1222 NULL 1223}; 1224 1225int main(int argc, char *argv[]) 1226{ 1227 int i; 1228 int result; 1229 SDLTest_CommonState *state; 1230 SDLTest_TestSuiteRunner *runner; 1231 1232 /* Initialize test framework */ 1233 state = SDLTest_CommonCreateState(argv, 0); 1234 if (!state) { 1235 return 1; 1236 } 1237 1238 runner = SDLTest_CreateTestSuiteRunner(state, testSuites); 1239 1240 /* Parse commandline */ 1241 for (i = 1; i < argc;) { 1242 int consumed; 1243 1244 consumed = SDLTest_CommonArg(state, i); 1245 if (!consumed) { 1246 if (!parsed_args.childprocess_path) { 1247 parsed_args.childprocess_path = argv[i]; 1248 consumed = 1; 1249 } 1250 } 1251 if (consumed <= 0) { 1252 SDLTest_CommonLogUsage(state, argv[0], options); 1253 return 1; 1254 } 1255 1256 i += consumed; 1257 } 1258 1259 if (!parsed_args.childprocess_path) { 1260 SDLTest_CommonLogUsage(state, argv[0], options); 1261 return 1; 1262 } 1263 1264 result = SDLTest_ExecuteTestSuiteRunner(runner); 1265 1266 SDL_Quit(); 1267 SDLTest_DestroyTestSuiteRunner(runner); 1268 SDLTest_CommonDestroyState(state); 1269 return result; 1270} 1271
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.