From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/msvcrt/tests/file.c | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index 1ac6cfe3182..e680f9ce2b8 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -3059,6 +3059,96 @@ static void test_ioinfo_flags(void) free(tempf); }
+static void test_std_buffer_state( const char *selfname ) +{ + char cmdline[MAX_PATH]; + STARTUPINFOA startup = {.cb = sizeof(startup), .dwFlags = 0}; + PROCESS_INFORMATION proc; + DWORD exit_code; + BOOL ret; + + /* use child process to temper with std streams and only use ok() in parent process */ + sprintf( cmdline, "%s file stdbuf", selfname); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &proc ); + ok(ret, "Couldn't start process '%s'\n", cmdline); + ret = WaitForSingleObject( proc.hProcess, 30000 ); + ok(ret == WAIT_OBJECT_0, "Unexpected process termination\n"); + ret = GetExitCodeProcess( proc.hProcess, &exit_code ); + ok( ret, "Unexpected result\n" ); + ok( exit_code == 7, "Unexpected exit code %lx\n", exit_code); + CloseHandle( proc.hProcess ); + CloseHandle( proc.hThread ); +} + +static BOOL create_file( const char *filename, const char *content ) +{ + FILE *file; + int len; + + if (!(file = fopen( filename, "wb" ))) return FALSE; + len = fputs( content, file ); + fclose( file ); + return len >= 0; +} + +static unsigned gather_buffer_state( FILE *f ) +{ + unsigned ret = 0; + int fd = _fileno( f ); + __int64 pos; + char ch; + + /* these operations shall force buffer creation (if required) */ + switch (fd) + { + case 0: + if (fscanf( f, "%c", &ch ) != 1 || (pos = _telli64( fd )) < 0) + ret |= 1u << 7; + else if (pos > 2) + ret |= 1u << fd; + break; + case 1: + case 2: + if (fprintf( f, "a" ) != 1 || (pos = _telli64( fd )) < 0) + ret |= 1u << 7; + else if (pos == 0) + ret |= 1u << fd; + break; + default: + ret |= 1u << 7; + break; + } + return ret; +} + +static void test_std_buffer_state_child( int argc, char **argv ) +{ + unsigned exit_code = 0; + + /* return: + * - bit7 set in case of error; + * - bit0,1,2 set if fd 0,1,2 is buffered + */ + if (!create_file( "file0.tmp", "content\n" ) || + !freopen( "file0.tmp", "r", stdin ) || + !freopen( "file1.tmp", "w", stdout ) || + !freopen( "file2.tmp", "w", stderr )) + exit_code |= 1u << 7; + + exit_code |= gather_buffer_state( stdin ); + exit_code |= gather_buffer_state( stdout ); + exit_code |= gather_buffer_state( stderr ); + + fclose( stdin ); + fclose( stdout ); + fclose( stderr ); + + if (!DeleteFileA( "file0.tmp" ) || !DeleteFileA( "file1.tmp" ) || !DeleteFileA( "file2.tmp" )) + exit_code |= 1u << 7; + + ExitProcess( exit_code ); +} + START_TEST(file) { int arg_c; @@ -3079,6 +3169,8 @@ START_TEST(file) test_pipes_child(arg_c, arg_v); else if (strcmp(arg_v[2], "stdin") == 0) test_invalid_stdin_child(); + else if (strcmp(arg_v[2], "stdbuf") == 0) + test_std_buffer_state_child(arg_c, arg_v); else ok(0, "invalid argument '%s'\n", arg_v[2]); return; @@ -3135,6 +3227,7 @@ START_TEST(file) test_fopen_hints(); test_open_hints(); test_ioinfo_flags(); + test_std_buffer_state(arg_v[0]);
/* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report * file contains lines in the correct order