Atlas - testprocess.c

Home / ext / SDL / test Lines: 14 | Size: 47373 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 TestProcessData *data = (TestProcessData *)arg; 813 char *inject_arg = NULL; 814 char **process_args = NULL; 815 char *text_out = NULL; 816 size_t len_text_out; 817 int exitcode; 818 SDL_Process *process = NULL; 819 SDL_IOStream *child_bat; 820 char buffer[256]; 821 822#ifndef SDL_PLATFORM_WINDOWS 823 SDLTest_AssertPass("The BatBadBut vulnerability only applied to Windows"); 824 return TEST_SKIPPED; 825#endif 826 /* FIXME: remove child.bat at end of loop and/or create in temporary directory */ 827 child_bat = SDL_IOFromFile("child_batbadbut.bat", "w"); 828 SDL_IOprintf(child_bat, "@echo off\necho Hello from child_batbadbut.bat\necho \"|bat1=%%1|\"\n"); 829 SDL_CloseIO(child_bat); 830 831 inject_arg = SDL_malloc(SDL_strlen(data->childprocess_path) + 100); 832 SDL_snprintf(inject_arg, SDL_strlen(data->childprocess_path) + 100, "\"&%s --version --print-arguments --stdout OWNEDSTDOUT\"", data->childprocess_path); 833 process_args = CreateArguments(0, "child_batbadbut.bat", inject_arg, NULL); 834 835 SDLTest_AssertPass("About to call SDL_CreateProcess"); 836 process = SDL_CreateProcess((const char * const*)process_args, true); 837 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcess"); 838 if (!process) { 839 goto cleanup; 840 } 841 text_out = SDL_ReadProcess(process, &len_text_out, &exitcode); 842 SDLTest_AssertCheck(exitcode == 0, "process exited with exitcode 0, was %d", exitcode); 843 SDLTest_AssertCheck(text_out != NULL, "SDL_ReadProcess returned data"); 844 SDLTest_LogEscapedString("Output: ", text_out, len_text_out); 845 if (!text_out) { 846 goto cleanup; 847 } 848 849 SDLTest_AssertCheck(SDL_strstr(text_out, "Hello from child_batbadbut") != NULL, "stdout contains 'Hello from child'"); 850 SDLTest_AssertCheck(SDL_strstr(text_out, "SDL version") == NULL, "stdout should not contain SDL version"); 851 SDL_snprintf(buffer, sizeof(buffer), "|bat1=\"\"\"&%s\"\"|", process_args[1] + 2); 852 SDLTest_LogEscapedString("stdout should contain: ", buffer, SDL_strlen(buffer)); 853 SDLTest_AssertCheck(SDL_strstr(text_out, buffer) != NULL, "Verify first argument"); 854 855cleanup: 856 SDL_free(text_out); 857 SDL_DestroyProcess(process); 858 SDL_free(inject_arg); 859 DestroyStringArray(process_args); 860 return TEST_COMPLETED; 861} 862 863static int process_testFileRedirection(void *arg) 864{ 865 TestProcessData *data = (TestProcessData *)arg; 866 SDL_PropertiesID props = 0; 867 const char * process_args[] = { 868 data->childprocess_path, 869 "--stdin-to-stdout", 870 "--stdin-to-stderr", 871 NULL, 872 }; 873 const char TEXT_REF[] = "This is input for the child process"; 874 static const char *PATH_STDIN = "test_redirection_stdin.txt"; 875 static const char *PATH_STDOUT = "test_redirection_stdout.txt"; 876 static const char *PATH_STDERR = "test_redirection_stderr.txt"; 877 char *text_out = NULL; 878 size_t len_text_out; 879 int exitcode; 880 bool result; 881 SDL_Process *process = NULL; 882 SDL_IOStream *stream; 883 SDL_IOStream *input_stream = NULL; 884 SDL_IOStream *output_stream = NULL; 885 SDL_IOStream *error_stream = NULL; 886 887 stream = SDL_IOFromFile(PATH_STDIN, "w"); 888 SDLTest_AssertCheck(stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDIN); 889 if (!stream) { 890 goto cleanup; 891 } 892 SDL_WriteIO(stream, TEXT_REF, sizeof(TEXT_REF)); 893 SDL_CloseIO(stream); 894 895 input_stream = SDL_IOFromFile(PATH_STDIN, "r"); 896 SDLTest_AssertCheck(input_stream != NULL, "SDL_IOFromFile(\"%s\", \"r\")", PATH_STDIN); 897 if (!input_stream) { 898 goto cleanup; 899 } 900 901 output_stream = SDL_IOFromFile(PATH_STDOUT, "w"); 902 SDLTest_AssertCheck(output_stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDOUT); 903 if (!output_stream) { 904 goto cleanup; 905 } 906 907 error_stream = SDL_IOFromFile(PATH_STDERR, "w"); 908 SDLTest_AssertCheck(error_stream != NULL, "SDL_IOFromFile(\"%s\", \"w\")", PATH_STDERR); 909 if (!error_stream) { 910 goto cleanup; 911 } 912 913 props = SDL_CreateProperties(); 914 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 915 if (!props) { 916 goto cleanup; 917 } 918 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 919 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 920 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_POINTER, (void *)input_stream); 921 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 922 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_POINTER, (void *)output_stream); 923 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_NUMBER, SDL_PROCESS_STDIO_REDIRECT); 924 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_POINTER, (void *)error_stream); 925 process = SDL_CreateProcessWithProperties(props); 926 SDL_DestroyProperties(props); 927 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties (%s)", SDL_GetError()); 928 if (!process) { 929 goto cleanup; 930 } 931 932 exitcode = 0xdeadbeef; 933 text_out = SDL_ReadProcess(process, &len_text_out, &exitcode); 934 SDLTest_AssertCheck(text_out == NULL, "SDL_ReadProcess should not be able to close a redirected process (%s)", SDL_GetError()); 935 SDLTest_AssertCheck(len_text_out == 0, "length written by SDL_ReadProcess should be 0"); 936 SDL_free(text_out); 937 text_out = NULL; 938 939 exitcode = 0xdeadbeef; 940 result = SDL_WaitProcess(process, true, &exitcode); 941 SDLTest_AssertCheck(result, "process must have exited"); 942 SDLTest_AssertCheck(exitcode == 0, "process exited with exitcode 0, was %d", exitcode); 943 944 SDL_CloseIO(input_stream); 945 input_stream = NULL; 946 SDL_CloseIO(output_stream); 947 output_stream = NULL; 948 SDL_CloseIO(error_stream); 949 error_stream = NULL; 950 951 text_out = SDL_LoadFile(PATH_STDOUT, &len_text_out); 952 SDLTest_AssertCheck(text_out != NULL, "SDL_LoadFile(\"%s\") succeeded (%s)", PATH_STDOUT, SDL_GetError()); 953 SDLTest_AssertPass("Comparing stdout with reference"); 954 SDLTest_CompareMemory(text_out, len_text_out, TEXT_REF, sizeof(TEXT_REF)); 955 SDL_free(text_out); 956 957 text_out = SDL_LoadFile(PATH_STDERR, &len_text_out); 958 SDLTest_AssertCheck(text_out != NULL, "SDL_LoadFile(\"%s\") succeeded (%s)", PATH_STDERR, SDL_GetError()); 959 SDLTest_AssertPass("Comparing stderr with reference"); 960 SDLTest_CompareMemory(text_out, len_text_out, TEXT_REF, sizeof(TEXT_REF)); 961 SDL_free(text_out); 962 963cleanup: 964 SDL_CloseIO(input_stream); 965 SDL_CloseIO(output_stream); 966 SDL_CloseIO(error_stream); 967 SDL_DestroyProcess(process); 968 return TEST_COMPLETED; 969} 970 971static int process_testWindowsCmdline(void *arg) 972{ 973 TestProcessData *data = (TestProcessData *)arg; 974 const char *process_args[] = { 975 data->childprocess_path, 976 "--print-arguments", 977 "--", 978 "", 979 " ", 980 "a b c", 981 "a\tb\tc\t", 982 "\"a b\" c", 983 "'a' 'b' 'c'", 984 "%d%%%s", 985 "\\t\\c", 986 "evil\\", 987 "a\\b\"c\\", 988 "\"\\^&|<>%", /* characters with a special meaning */ 989 NULL 990 }; 991 /* this will have the same result as process_args, but escaped in a different way */ 992 const char *process_cmdline_template = 993 "%s " 994 "--print-arguments " 995 "-- " 996 "\"\" " 997 "\" \" " 998 "a\" \"b\" \"c\t" /* using tab as delimiter */ 999 "\"a\tb\tc\t\" " 1000 "\"\"\"\"a b\"\"\" c\" " 1001 "\"'a' 'b' 'c'\" " 1002 "%%d%%%%%%s " /* will be passed to sprintf */ 1003 "\\t\\c " 1004 "evil\\ " 1005 "a\\b\"\\\"\"c\\ " 1006 "\\\"\\^&|<>%%"; 1007 char process_cmdline[65535]; 1008 SDL_PropertiesID props; 1009 SDL_Process *process = NULL; 1010 char *buffer; 1011 int exit_code; 1012 int i; 1013 size_t total_read = 0; 1014 1015#ifndef SDL_PLATFORM_WINDOWS 1016 SDLTest_AssertPass("SDL_PROP_PROCESS_CREATE_CMDLINE_STRING only works on Windows"); 1017 return TEST_SKIPPED; 1018#endif 1019 1020 props = SDL_CreateProperties(); 1021 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 1022 if (!props) { 1023 goto failed; 1024 } 1025 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 1026 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 1027 SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN, true); 1028 1029 process = SDL_CreateProcessWithProperties(props); 1030 SDLTest_AssertCheck(process == NULL, "SDL_CreateProcessWithProperties() should fail"); 1031 1032 SDL_snprintf(process_cmdline, SDL_arraysize(process_cmdline), process_cmdline_template, data->childprocess_path); 1033 SDL_SetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, process_cmdline); 1034 1035 process = SDL_CreateProcessWithProperties(props); 1036 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 1037 if (!process) { 1038 goto failed; 1039 } 1040 1041 exit_code = 0xdeadbeef; 1042 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 1043 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 1044 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 1045 if (!buffer) { 1046 goto failed; 1047 } 1048 SDLTest_LogEscapedString("stdout of process: ", buffer, total_read); 1049 1050 for (i = 3; process_args[i]; i++) { 1051 char line[64]; 1052 SDL_snprintf(line, sizeof(line), "|%d=%s|", i - 3, process_args[i]); 1053 SDLTest_AssertCheck(!!SDL_strstr(buffer, line), "Check %s is in output", line); 1054 } 1055 SDL_free(buffer); 1056 1057 SDLTest_AssertPass("About to destroy process"); 1058 SDL_DestroyProcess(process); 1059 1060 return TEST_COMPLETED; 1061 1062failed: 1063 SDL_DestroyProcess(process); 1064 return TEST_ABORTED; 1065} 1066 1067static int process_testWindowsCmdlinePrecedence(void *arg) 1068{ 1069 TestProcessData *data = (TestProcessData *)arg; 1070 const char *process_args[] = { 1071 data->childprocess_path, 1072 "--print-arguments", 1073 "--", 1074 "argument 1", 1075 NULL 1076 }; 1077 const char *process_cmdline_template = "%s --print-arguments -- \"argument 2\""; 1078 char process_cmdline[65535]; 1079 SDL_PropertiesID props; 1080 SDL_Process *process = NULL; 1081 char *buffer; 1082 int exit_code; 1083 size_t total_read = 0; 1084 1085#ifndef SDL_PLATFORM_WINDOWS 1086 SDLTest_AssertPass("SDL_PROP_PROCESS_CREATE_CMDLINE_STRING only works on Windows"); 1087 return TEST_SKIPPED; 1088#endif 1089 1090 props = SDL_CreateProperties(); 1091 SDLTest_AssertCheck(props != 0, "SDL_CreateProperties()"); 1092 if (!props) { 1093 goto failed; 1094 } 1095 1096 SDL_snprintf(process_cmdline, SDL_arraysize(process_cmdline), process_cmdline_template, data->childprocess_path); 1097 SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)process_args); 1098 SDL_SetStringProperty(props, SDL_PROP_PROCESS_CREATE_CMDLINE_STRING, (const char *)process_cmdline); 1099 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); 1100 SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); 1101 SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN, true); 1102 1103 process = SDL_CreateProcessWithProperties(props); 1104 SDLTest_AssertCheck(process != NULL, "SDL_CreateProcessWithProperties()"); 1105 if (!process) { 1106 goto failed; 1107 } 1108 1109 exit_code = 0xdeadbeef; 1110 buffer = (char *)SDL_ReadProcess(process, &total_read, &exit_code); 1111 SDLTest_AssertCheck(buffer != NULL, "SDL_ReadProcess()"); 1112 SDLTest_AssertCheck(exit_code == 0, "Exit code should be 0, is %d", exit_code); 1113 if (!buffer) { 1114 goto failed; 1115 } 1116 SDLTest_LogEscapedString("stdout of process: ", buffer, total_read); 1117 SDLTest_AssertCheck(!!SDL_strstr(buffer, "|0=argument 2|"), "Check |0=argument 2| is printed"); 1118 SDL_free(buffer); 1119 1120 SDLTest_AssertPass("About to destroy process"); 1121 SDL_DestroyProcess(process); 1122 1123 return TEST_COMPLETED; 1124 1125failed: 1126 SDL_DestroyProcess(process); 1127 return TEST_ABORTED; 1128} 1129 1130static const SDLTest_TestCaseReference processTestArguments = { 1131 process_testArguments, "process_testArguments", "Test passing arguments to child process", TEST_ENABLED 1132}; 1133 1134static const SDLTest_TestCaseReference processTestExitCode = { 1135 process_testexitCode, "process_testExitCode", "Test exit codes", TEST_ENABLED 1136}; 1137 1138static const SDLTest_TestCaseReference processTestInheritedEnv = { 1139 process_testInheritedEnv, "process_testInheritedEnv", "Test inheriting environment from parent process", TEST_ENABLED 1140}; 1141 1142static const SDLTest_TestCaseReference processTestNewEnv = { 1143 process_testNewEnv, "process_testNewEnv", "Test creating new environment for child process", TEST_ENABLED 1144}; 1145 1146static const SDLTest_TestCaseReference processTestKill = { 1147 process_testKill, "process_testKill", "Test Killing a child process", TEST_ENABLED 1148}; 1149 1150static const SDLTest_TestCaseReference processTestStdinToStdout = { 1151 process_testStdinToStdout, "process_testStdinToStdout", "Test writing to stdin and reading from stdout", TEST_ENABLED 1152}; 1153 1154static const SDLTest_TestCaseReference processTestStdinToStderr = { 1155 process_testStdinToStderr, "process_testStdinToStderr", "Test writing to stdin and reading from stderr", TEST_ENABLED 1156}; 1157 1158static const SDLTest_TestCaseReference processTestSimpleStdinToStdout = { 1159 process_testSimpleStdinToStdout, "process_testSimpleStdinToStdout", "Test writing to stdin and reading from stdout using the simplified API", TEST_ENABLED 1160}; 1161 1162static const SDLTest_TestCaseReference processTestMultiprocessStdinToStdout = { 1163 process_testMultiprocessStdinToStdout, "process_testMultiprocessStdinToStdout", "Test writing to stdin and reading from stdout using the simplified API", TEST_ENABLED 1164}; 1165 1166static const SDLTest_TestCaseReference processTestWriteToFinishedProcess = { 1167 process_testWriteToFinishedProcess, "process_testWriteToFinishedProcess", "Test writing to stdin of terminated process", TEST_ENABLED 1168}; 1169 1170static const SDLTest_TestCaseReference processTestNonExistingExecutable = { 1171 process_testNonExistingExecutable, "process_testNonExistingExecutable", "Test running a non-existing executable", TEST_ENABLED 1172}; 1173 1174static const SDLTest_TestCaseReference processTestBatBadButVulnerability = { 1175 process_testBatBadButVulnerability, "process_testBatBadButVulnerability", "Test BatBadBut vulnerability: command injection through cmd.exe", TEST_ENABLED 1176}; 1177 1178static const SDLTest_TestCaseReference processTestFileRedirection = { 1179 process_testFileRedirection, "process_testFileRedirection", "Test redirection from/to files", TEST_ENABLED 1180}; 1181 1182static const SDLTest_TestCaseReference processTestWindowsCmdline = { 1183 process_testWindowsCmdline, "process_testWindowsCmdline", "Test passing cmdline directly to CreateProcess", TEST_ENABLED 1184}; 1185 1186static const SDLTest_TestCaseReference processTestWindowsCmdlinePrecedence = { 1187 process_testWindowsCmdlinePrecedence, "process_testWindowsCmdlinePrecedence", "Test SDL_PROP_PROCESS_CREATE_CMDLINE_STRING precedence over SDL_PROP_PROCESS_CREATE_ARGS_POINTER", TEST_ENABLED 1188}; 1189 1190static const SDLTest_TestCaseReference *processTests[] = { 1191 &processTestArguments, 1192 &processTestExitCode, 1193 &processTestInheritedEnv, 1194 &processTestNewEnv, 1195 &processTestKill, 1196 &processTestStdinToStdout, 1197 &processTestStdinToStderr, 1198 &processTestSimpleStdinToStdout, 1199 &processTestMultiprocessStdinToStdout, 1200 &processTestWriteToFinishedProcess, 1201 &processTestNonExistingExecutable, 1202 &processTestBatBadButVulnerability, 1203 &processTestFileRedirection, 1204 &processTestWindowsCmdline, 1205 &processTestWindowsCmdlinePrecedence, 1206 NULL 1207}; 1208 1209static SDLTest_TestSuiteReference processTestSuite = { 1210 "Process", 1211 setUpProcess, 1212 processTests, 1213 NULL 1214}; 1215 1216static SDLTest_TestSuiteReference *testSuites[] = { 1217 &processTestSuite, 1218 NULL 1219}; 1220 1221int main(int argc, char *argv[]) 1222{ 1223 int i; 1224 int result; 1225 SDLTest_CommonState *state; 1226 SDLTest_TestSuiteRunner *runner; 1227 1228 /* Initialize test framework */ 1229 state = SDLTest_CommonCreateState(argv, 0); 1230 if (!state) { 1231 return 1; 1232 } 1233 1234 runner = SDLTest_CreateTestSuiteRunner(state, testSuites); 1235 1236 /* Parse commandline */ 1237 for (i = 1; i < argc;) { 1238 int consumed; 1239 1240 consumed = SDLTest_CommonArg(state, i); 1241 if (!consumed) { 1242 if (!parsed_args.childprocess_path) { 1243 parsed_args.childprocess_path = argv[i]; 1244 consumed = 1; 1245 } 1246 } 1247 if (consumed <= 0) { 1248 SDLTest_CommonLogUsage(state, argv[0], options); 1249 return 1; 1250 } 1251 1252 i += consumed; 1253 } 1254 1255 if (!parsed_args.childprocess_path) { 1256 SDLTest_CommonLogUsage(state, argv[0], options); 1257 return 1; 1258 } 1259 1260 result = SDLTest_ExecuteTestSuiteRunner(runner); 1261 1262 SDL_Quit(); 1263 SDLTest_DestroyTestSuiteRunner(runner); 1264 SDLTest_CommonDestroyState(state); 1265 return result; 1266} 1267
[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.