HelenOS sources
This source file includes following definitions.
- before_test_start
- report_func_fail
- read_all
- read_test_output_on_background
- pcut_run_test_forking
- pcut_hook_before_test
#include "../internal.h"
#pragma warning(push, 0)
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma warning(pop)
#define OUTPUT_BUFFER_SIZE 8192
#define PCUT_COMMAND_LINE_BUFFER_SIZE 256
static char error_message_buffer[OUTPUT_BUFFER_SIZE];
static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
static void before_test_start(pcut_item_t *test) {
pcut_report_test_start(test);
memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
}
static void report_func_fail(pcut_item_t *test, const char *failed_function_name) {
pcut_snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
"%s failed: %s.", failed_function_name, "unknown reason");
pcut_report_test_done(test, PCUT_OUTCOME_INTERNAL_ERROR, error_message_buffer, NULL, NULL);
}
static size_t read_all(HANDLE fd, char *buffer, size_t buffer_size) {
DWORD actually_read;
char *buffer_start = buffer;
BOOL okay = FALSE;
do {
okay = ReadFile(fd, buffer, buffer_size, &actually_read, NULL);
if (!okay) {
break;
}
if (actually_read > 0) {
buffer += actually_read;
buffer_size -= actually_read;
if (buffer_size == 0) {
break;
}
}
} while (actually_read > 0);
if (buffer_start != buffer) {
if (*(buffer - 1) == 10) {
*(buffer - 1) = 0;
buffer--;
}
}
return buffer - buffer_start;
}
struct test_output_data {
HANDLE pipe_stdout;
HANDLE pipe_stderr;
char *output_buffer;
size_t output_buffer_size;
};
static DWORD WINAPI read_test_output_on_background(LPVOID test_output_data_ptr) {
size_t stderr_size = 0;
struct test_output_data *test_output_data = (struct test_output_data *) test_output_data_ptr;
stderr_size = read_all(test_output_data->pipe_stderr,
test_output_data->output_buffer,
test_output_data->output_buffer_size - 1);
read_all(test_output_data->pipe_stdout,
test_output_data->output_buffer,
test_output_data->output_buffer_size - 1 - stderr_size);
return 0;
}
int pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
BOOL okay = FALSE;
DWORD rc;
int outcome;
int timed_out;
int time_out_millis;
SECURITY_ATTRIBUTES security_attributes;
HANDLE link_stdout[2] = { NULL, NULL };
HANDLE link_stderr[2] = { NULL, NULL };
HANDLE link_stdin[2] = { NULL, NULL };
PROCESS_INFORMATION process_info;
STARTUPINFO start_info;
char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
struct test_output_data test_output_data;
HANDLE test_output_thread_reader;
before_test_start(test);
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attributes.bInheritHandle = TRUE;
security_attributes.lpSecurityDescriptor = NULL;
okay = CreatePipe(&link_stdout[0], &link_stdout[1], &security_attributes, 0);
if (!okay) {
report_func_fail(test, "CreatePipe(/* stdout */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = SetHandleInformation(link_stdout[0], HANDLE_FLAG_INHERIT, 0);
if (!okay) {
report_func_fail(test, "SetHandleInformation(/* stdout */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = CreatePipe(&link_stderr[0], &link_stderr[1], &security_attributes, 0);
if (!okay) {
report_func_fail(test, "CreatePipe(/* stderr */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = SetHandleInformation(link_stderr[0], HANDLE_FLAG_INHERIT, 0);
if (!okay) {
report_func_fail(test, "SetHandleInformation(/* stderr */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = CreatePipe(&link_stdin[0], &link_stdin[1], &security_attributes, 0);
if (!okay) {
report_func_fail(test, "CreatePipe(/* stdin */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = SetHandleInformation(link_stdin[1], HANDLE_FLAG_INHERIT, 0);
if (!okay) {
report_func_fail(test, "SetHandleInformation(/* stdin */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
ZeroMemory(&start_info, sizeof(STARTUPINFO));
start_info.cb = sizeof(STARTUPINFO);
start_info.hStdError = link_stderr[1];
start_info.hStdOutput = link_stdout[1];
start_info.hStdInput = link_stdin[0];
start_info.dwFlags |= STARTF_USESTDHANDLES;
pcut_snprintf(command, PCUT_COMMAND_LINE_BUFFER_SIZE - 1,
"\"%s\" -t%d", self_path, test->id);
okay = CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL,
&start_info, &process_info);
if (!okay) {
report_func_fail(test, "CreateProcess()");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
CloseHandle(process_info.hThread);
okay = CloseHandle(link_stdout[1]);
if (!okay) {
report_func_fail(test, "CloseHandle(/* stdout */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = CloseHandle(link_stderr[1]);
if (!okay) {
report_func_fail(test, "CloseHandle(/* stderr */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = CloseHandle(link_stdin[0]);
if (!okay) {
report_func_fail(test, "CloseHandle(/* stdin */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
test_output_data.pipe_stderr = link_stderr[0];
test_output_data.pipe_stdout = link_stdout[0];
test_output_data.output_buffer = extra_output_buffer;
test_output_data.output_buffer_size = OUTPUT_BUFFER_SIZE;
test_output_thread_reader = CreateThread(NULL, 0,
read_test_output_on_background, &test_output_data,
0, NULL);
if (test_output_thread_reader == NULL) {
report_func_fail(test, "CreateThread(/* read test stdout */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
timed_out = 0;
time_out_millis = pcut_get_test_timeout(test) * 1000;
rc = WaitForSingleObject(process_info.hProcess, time_out_millis);
PCUT_DEBUG("Waiting for test %s (%dms) returned %d.", test->name, time_out_millis, rc);
if (rc == WAIT_TIMEOUT) {
timed_out = 1;
okay = TerminateProcess(process_info.hProcess, 5);
if (!okay) {
report_func_fail(test, "TerminateProcess(/* PROCESS_INFORMATION.hProcess */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
rc = WaitForSingleObject(process_info.hProcess, INFINITE);
}
if (rc != WAIT_OBJECT_0) {
report_func_fail(test, "WaitForSingleObject(/* PROCESS_INFORMATION.hProcess */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
okay = GetExitCodeProcess(process_info.hProcess, &rc);
if (!okay) {
report_func_fail(test, "GetExitCodeProcess()");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
if (rc == 0) {
outcome = PCUT_OUTCOME_PASS;
} else if ((rc > 0) && (rc < 10) && !timed_out) {
outcome = PCUT_OUTCOME_FAIL;
} else {
outcome = PCUT_OUTCOME_INTERNAL_ERROR;
}
rc = WaitForSingleObject(test_output_thread_reader, INFINITE);
if (rc != WAIT_OBJECT_0) {
report_func_fail(test, "WaitForSingleObject(/* stdout reader thread */)");
return PCUT_OUTCOME_INTERNAL_ERROR;
}
pcut_report_test_done_unparsed(test, outcome, extra_output_buffer, OUTPUT_BUFFER_SIZE);
return outcome;
}
void pcut_hook_before_test(pcut_item_t *test) {
PCUT_UNUSED(test);
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
}
HelenOS homepage, sources at GitHub