|
6 | 6 | #include <Misra/Std/Io.h> |
7 | 7 | #include <Misra/Std/Log.h> |
8 | 8 |
|
9 | | -#include <unistd.h> |
10 | | - |
11 | 9 | #include "../Util/TestRunner.h" |
12 | 10 |
|
13 | 11 | // ---------------------------------------------------------------------------- |
@@ -603,47 +601,33 @@ static bool test_help_returns_help_code(void) { |
603 | 601 | // =========================================================================== |
604 | 602 |
|
605 | 603 | // --------------------------------------------------------------------------- |
606 | | -// print_help writes its usage table straight to fd 2 (FileStderr). To |
607 | | -// assert the EXACT layout -- column alignment, padding width, section |
608 | | -// order, separators -- we redirect fd 2 to a pipe, run |
609 | | -// ArgParseRun(--help), then drain the pipe back into a Str. pipe / dup / |
610 | | -// dup2 / read are OS interfaces (POSIX), not libc, so they are allowed |
611 | | -// in MisraStdC tests. |
| 604 | +// To assert the EXACT --help layout -- column alignment, padding width, |
| 605 | +// section order, separators -- we point the parser's output sink (`p->out`) |
| 606 | +// at a temp file, run ArgParseRun(--help), then read the file back. Fully |
| 607 | +// portable: the `File` abstraction handles the platform difference, so the |
| 608 | +// test needs no fd/handle redirection. |
612 | 609 | // |
613 | 610 | // ArgParseRun appends a synthetic "-h, --help print this help" FLAG |
614 | 611 | // spec before printing, so every captured help text ends with that row. |
615 | 612 | // --------------------------------------------------------------------------- |
616 | 613 | static void capture_help(ArgParse *p, Str *out) { |
617 | | - int pipefd[2]; |
618 | | - if (pipe(pipefd) != 0) |
619 | | - LOG_FATAL("capture_help: pipe failed"); |
620 | | - |
621 | | - int saved = dup(2); |
622 | | - if (saved < 0) |
623 | | - LOG_FATAL("capture_help: dup failed"); |
624 | | - if (dup2(pipefd[1], 2) < 0) |
625 | | - LOG_FATAL("capture_help: dup2 failed"); |
626 | | - close(pipefd[1]); |
| 614 | + Str tmp_path = StrInit(p->alloc); |
| 615 | + File tmp = FileOpenTemp(&tmp_path, p->alloc); |
| 616 | + StrDeinit(&tmp_path); |
| 617 | + if (!FileIsOpen(&tmp)) |
| 618 | + LOG_FATAL("capture_help: FileOpenTemp failed"); |
627 | 619 |
|
| 620 | + p->out = &tmp; |
628 | 621 | char *argv[] = {(char *)"prog", (char *)"--help"}; |
629 | 622 | ArgRun rc = ArgParseRun(p, 2, argv); |
630 | | - |
631 | | - // Restore the real stderr before draining so later logging is sane. |
632 | | - dup2(saved, 2); |
633 | | - close(saved); |
| 623 | + p->out = NULL; |
634 | 624 |
|
635 | 625 | if (rc != ARG_RUN_HELP) |
636 | 626 | LOG_FATAL("capture_help: expected ARG_RUN_HELP, got {}", (int)rc); |
637 | 627 |
|
638 | | - char buf[4096]; |
639 | | - for (;;) { |
640 | | - long n = read(pipefd[0], buf, sizeof(buf)); |
641 | | - if (n <= 0) |
642 | | - break; |
643 | | - for (long i = 0; i < n; ++i) |
644 | | - StrPushBackR(out, buf[i]); |
645 | | - } |
646 | | - close(pipefd[0]); |
| 628 | + FileSeek(&tmp, 0, FILE_SEEK_SET); |
| 629 | + FileRead(&tmp, out); |
| 630 | + FileClose(&tmp); |
647 | 631 | } |
648 | 632 |
|
649 | 633 | static bool help_equals(ArgParse *p, Zstr expected) { |
@@ -895,34 +879,19 @@ static bool test_a1_render_cap_is_64(void) { |
895 | 879 | // width) are then asserted. |
896 | 880 | // ---------------------------------------------------------------------------- |
897 | 881 |
|
898 | | -// Run --help with stderr redirected into `out`. Returns true on a clean |
899 | | -// capture. The captured help text (whole stderr stream) lands in `out`. |
900 | | -// (Tempfile-based variant; the pipe-based capture_help above is kept |
901 | | -// under its own name.) |
| 882 | +// Run --help with the parser's output sink pointed at a temp file, then |
| 883 | +// read it back into `out`. Returns true on a clean ARG_RUN_HELP capture. |
902 | 884 | static bool capture_help_file(ArgParse *p, Str *out) { |
903 | 885 | Str tmp_path = StrInit(p->alloc); |
904 | 886 | File tmp = FileOpenTemp(&tmp_path, p->alloc); |
905 | 887 | StrDeinit(&tmp_path); |
906 | 888 | if (!FileIsOpen(&tmp)) |
907 | 889 | return false; |
908 | 890 |
|
909 | | - int saved = dup(2); |
910 | | - if (saved < 0) { |
911 | | - FileClose(&tmp); |
912 | | - return false; |
913 | | - } |
914 | | - if (dup2(tmp.fd, 2) < 0) { |
915 | | - close(saved); |
916 | | - FileClose(&tmp); |
917 | | - return false; |
918 | | - } |
919 | | - |
| 891 | + p->out = &tmp; |
920 | 892 | char *argv[] = {(char *)"prog", (char *)"--help"}; |
921 | 893 | ArgRun rc = ArgParseRun(p, 2, argv); |
922 | | - |
923 | | - // Restore stderr before doing anything that might write to it. |
924 | | - dup2(saved, 2); |
925 | | - close(saved); |
| 894 | + p->out = NULL; |
926 | 895 |
|
927 | 896 | bool ok = (rc == ARG_RUN_HELP); |
928 | 897 | FileSeek(&tmp, 0, FILE_SEEK_SET); |
|
0 commit comments