Skip to content

Commit 6e78b6d

Browse files
committed
tests: port the test harness to Windows
This provides a functional Windows port of bsdtestharness and its dependencies so that we can start running the test suite on Windows. Some tests already build and run correctly, while others either fail at runtime or don't compile. I'll be following up with fixes for individual tests later.
1 parent afa6cc3 commit 6e78b6d

File tree

8 files changed

+412
-39
lines changed

8 files changed

+412
-39
lines changed

tests/CMakeLists.txt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
33
execute_process(COMMAND
4-
"${CMAKE_COMMAND}" -E copy "${PROJECT_SOURCE_DIR}/private"
4+
"${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/private"
55
"${CMAKE_CURRENT_BINARY_DIR}/dispatch")
66
execute_process(COMMAND
77
"${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/leaks-wrapper.sh"
@@ -36,6 +36,15 @@ if(BSD_OVERLAY_FOUND)
3636
PRIVATE
3737
${BSD_OVERLAY_CFLAGS})
3838
endif()
39+
if (WIN32)
40+
target_sources(bsdtests
41+
PRIVATE
42+
generic_win_port.c)
43+
target_compile_definitions(bsdtests
44+
PUBLIC
45+
_CRT_NONSTDC_NO_WARNINGS
46+
_CRT_SECURE_NO_WARNINGS)
47+
endif ()
3948

4049
add_executable(bsdtestharness
4150
bsdtestharness.c)
@@ -91,11 +100,11 @@ function(add_unit_test name)
91100
endif()
92101
if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")
93102
target_compile_options(${name} PRIVATE -Xclang -fblocks)
103+
target_compile_options(${name} PRIVATE /W3 -Wno-deprecated-declarations)
94104
else()
95105
target_compile_options(${name} PRIVATE -fblocks)
106+
target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
96107
endif()
97-
# TODO(compnerd) make this portable
98-
target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
99108
dispatch_set_linker(${name})
100109
target_link_libraries(${name}
101110
PRIVATE
@@ -187,4 +196,4 @@ target_link_libraries(dispatch_group PRIVATE m)
187196
target_link_libraries(dispatch_timer_short PRIVATE m)
188197

189198
# test-specific compile options
190-
target_compile_options(dispatch_c99 PRIVATE -std=c99)
199+
set_target_properties(dispatch_c99 PROPERTIES C_STANDARD 99)

tests/bsdtestharness.c

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,29 @@
2020

2121
#include <dispatch/dispatch.h>
2222
#include <assert.h>
23-
#include <spawn.h>
2423
#include <stdio.h>
2524
#include <stdlib.h>
2625
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
26+
#include <spawn.h>
27+
#include <sys/resource.h>
28+
#include <sys/time.h>
29+
#include <sys/wait.h>
2730
#include <unistd.h>
31+
#elif defined(_WIN32)
32+
#include <generic_win_port.h>
33+
#include <Psapi.h>
34+
#include <Windows.h>
2835
#endif
2936
#include <signal.h>
3037
#ifdef __APPLE__
3138
#include <mach/clock_types.h>
3239
#include <mach-o/arch.h>
3340
#endif
34-
#include <sys/resource.h>
35-
#include <sys/time.h>
36-
#if defined(__linux__) || defined(__FreeBSD__)
37-
#include <sys/wait.h>
38-
#endif
3941

4042
#include <bsdtests.h>
4143

44+
#if !defined(_WIN32)
4245
extern char **environ;
43-
44-
#ifdef __linux__
45-
// Linux lacks the DISPATCH_SOURCE_TYPE_PROC functionality
46-
// the real test harness needs.
47-
#define SIMPLE_TEST_HARNESS 1
48-
#else
49-
#define SIMPLE_TEST_HARNESS 0
5046
#endif
5147

5248
int
@@ -131,25 +127,43 @@ main(int argc, char *argv[])
131127
_Exit(EXIT_FAILURE);
132128
}
133129
}
130+
#elif defined(_WIN32)
131+
(void)res;
132+
WCHAR *cmdline = argv_to_command_line(newargv);
133+
if (!cmdline) {
134+
fprintf(stderr, "argv_to_command_line() failed\n");
135+
exit(EXIT_FAILURE);
136+
}
137+
STARTUPINFOW si = {.cb = sizeof(si)};
138+
PROCESS_INFORMATION pi;
139+
BOOL created = CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
140+
DWORD error = GetLastError();
141+
free(cmdline);
142+
if (!created) {
143+
print_winapi_error("CreateProcessW", error);
144+
exit(EXIT_FAILURE);
145+
}
146+
pid = (pid_t)pi.dwProcessId;
134147
#else
135148
#error "bsdtestharness not implemented on this platform"
136149
#endif
137150

138151
//fprintf(stderr, "pid = %d\n", pid);
139152
assert(pid > 0);
140153

141-
#if SIMPLE_TEST_HARNESS
154+
#if defined(__linux__)
142155
int status;
143156
struct rusage usage;
144157
struct timeval tv_stop, tv_wall;
145158

159+
int res2 = wait4(pid, &status, 0, &usage);
160+
(void)res2;
161+
146162
gettimeofday(&tv_stop, NULL);
147163
tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
148164
tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
149165
tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);
150166

151-
int res2 = wait4(pid, &status, 0, &usage);
152-
(void)res2;
153167
assert(res2 != -1);
154168
test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0);
155169
printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
@@ -161,6 +175,46 @@ main(int argc, char *argv[])
161175
printf("[PERF]\tvoluntary context switches: %ld\n", usage.ru_nvcsw);
162176
printf("[PERF]\tinvoluntary context switches: %ld\n", usage.ru_nivcsw);
163177
exit((WIFEXITED(status) && WEXITSTATUS(status)) || WIFSIGNALED(status));
178+
#elif defined(_WIN32)
179+
if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) {
180+
print_winapi_error("WaitForSingleObject", GetLastError());
181+
exit(EXIT_FAILURE);
182+
}
183+
184+
struct timeval tv_stop, tv_wall;
185+
gettimeofday(&tv_stop, NULL);
186+
tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
187+
tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
188+
tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);
189+
190+
DWORD status;
191+
if (!GetExitCodeProcess(pi.hProcess, &status)) {
192+
print_winapi_error("GetExitCodeProcess", GetLastError());
193+
exit(EXIT_FAILURE);
194+
}
195+
196+
FILETIME create_time, exit_time, kernel_time, user_time;
197+
if (!GetProcessTimes(pi.hProcess, &create_time, &exit_time, &kernel_time, &user_time)) {
198+
print_winapi_error("GetProcessTimes", GetLastError());
199+
exit(EXIT_FAILURE);
200+
}
201+
struct timeval utime, stime;
202+
filetime_to_timeval(&utime, &user_time);
203+
filetime_to_timeval(&stime, &kernel_time);
204+
205+
PROCESS_MEMORY_COUNTERS counters;
206+
if (!GetProcessMemoryInfo(pi.hProcess, &counters, sizeof(counters))) {
207+
print_winapi_error("GetProcessMemoryInfo", GetLastError());
208+
exit(EXIT_FAILURE);
209+
}
210+
211+
test_long("Process exited", status == 0 || status == 0xff, 1);
212+
printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
213+
printf("[PERF]\tuser time: %ld.%06ld\n", utime.tv_sec, utime.tv_usec);
214+
printf("[PERF]\tsystem time: %ld.%06ld\n", stime.tv_sec, stime.tv_usec);
215+
printf("[PERF]\tmax working set size: %zu\n", counters.PeakWorkingSetSize);
216+
printf("[PERF]\tpage faults: %lu\n", counters.PageFaultCount);
217+
exit(status ? EXIT_FAILURE : EXIT_SUCCESS);
164218
#else
165219
dispatch_queue_t main_q = dispatch_get_main_queue();
166220

@@ -219,7 +273,7 @@ main(int argc, char *argv[])
219273
kill(pid, SIGCONT);
220274

221275
dispatch_main();
222-
#endif // SIMPLE_TEST_HARNESS
276+
#endif
223277

224278
return 0;
225279
}

tests/bsdtests.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@
2929
#include <unistd.h>
3030
#endif
3131
#include <errno.h>
32-
#include <sys/errno.h>
33-
#include <sys/wait.h>
3432
#include <string.h>
3533
#ifdef __APPLE__
3634
#include <crt_externs.h>
3735
#include <mach/mach_error.h>
38-
#endif
3936
#include <spawn.h>
37+
#include <sys/wait.h>
38+
#endif
39+
#if defined(_WIN32)
40+
#include <generic_win_port.h>
41+
#endif
4042
#include <inttypes.h>
4143
#include "bsdtests.h"
4244

@@ -454,18 +456,11 @@ test_start(const char* desc)
454456
usleep(100000); // give 'gdb --waitfor=' a chance to find this proc
455457
}
456458

457-
#if defined(__linux__) || defined(__FreeBSD__)
458-
static char** get_environment(void)
459-
{
460-
extern char **environ;
461-
return environ;
462-
}
463-
#else
459+
#if defined(__APPLE__) && defined(__MACH__)
464460
static char** get_environment(void)
465461
{
466462
return (* _NSGetEnviron());
467463
}
468-
#endif
469464

470465
void
471466
test_leaks_pid(const char *name, pid_t pid)
@@ -517,15 +512,18 @@ test_leaks(const char *name)
517512
{
518513
test_leaks_pid(name, getpid());
519514
}
515+
#endif
520516

521517
void
522518
test_stop_after_delay(void *delay)
523519
{
524520
if (delay != NULL) {
525-
sleep((uint)(intptr_t)delay);
521+
sleep((unsigned int)(intptr_t)delay);
526522
}
527523

524+
#if defined(__APPLE__) && defined(__MACH__)
528525
test_leaks(NULL);
526+
#endif
529527

530528
fflush(stdout);
531529
_exit(_test_exit_code);

tests/bsdtests.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,22 @@ __BASENAME__(const char *_str_)
6363
}
6464
#define __SOURCE_FILE__ __BASENAME__(__FILE__)
6565

66-
__BEGIN_DECLS
66+
#if defined(__cplusplus)
67+
extern "C" {
68+
#endif
6769

6870
/**
6971
* test_start() provides the TEST token. Use this once per test "tool"
7072
*/
7173
void test_start(const char* desc);
7274

75+
#if defined(__APPLE__) && defined(__MACH__)
7376
/**
7477
* Explicitly runs the 'leaks' test without stopping the process.
7578
*/
7679
void test_leaks_pid(const char *name, pid_t pid);
7780
void test_leaks(const char *name);
81+
#endif
7882

7983
/**
8084
* test_stop() checks for leaks during the tests using leaks-wrapper. Use this at the end of each "tool"
@@ -179,6 +183,8 @@ void _test_skip(const char* file, long line, const char* desc);
179183
#define test_skip2(m) _test_skip("", 0, m)
180184
void test_skip_format(const char *format, ...) __printflike(1,2);
181185

182-
__END_DECLS
186+
#if defined(__cplusplus)
187+
} /* extern "C" */
188+
#endif
183189

184190
#endif /* __BSD_TEST_H__ */

tests/dispatch_test.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@
2929
#include <stdio.h>
3030
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
3131
#include <unistd.h>
32-
#endif
3332
#if __has_include(<sys/event.h>)
3433
#define HAS_SYS_EVENT_H 1
3534
#include <sys/event.h>
3635
#else
3736
#include <sys/poll.h>
3837
#endif
38+
#elif defined(_WIN32)
39+
#include <io.h>
40+
#include <Windows.h>
41+
#endif
3942
#include <assert.h>
4043

4144
#include <dispatch/dispatch.h>
@@ -68,6 +71,20 @@ dispatch_test_check_evfilt_read_for_fd(int fd)
6871
int r = kevent(kq, &ke, 1, &ke, 1, &t);
6972
close(kq);
7073
return r > 0;
74+
#elif defined(_WIN32)
75+
HANDLE handle = (HANDLE)_get_osfhandle(fd);
76+
// A zero-distance move retrieves the file pointer
77+
LARGE_INTEGER currentPosition;
78+
LARGE_INTEGER distance = {.QuadPart = 0};
79+
if (!SetFilePointerEx(handle, distance, &currentPosition, FILE_CURRENT)) {
80+
return false;
81+
}
82+
// If we are not at the end, assume the file is readable
83+
LARGE_INTEGER fileSize;
84+
if (GetFileSizeEx(handle, &fileSize) == 0) {
85+
return false;
86+
}
87+
return currentPosition.QuadPart < fileSize.QuadPart;
7188
#else
7289
struct pollfd pfd = {
7390
.fd = fd,
@@ -141,6 +158,10 @@ dispatch_test_get_large_file(void)
141158
close(temp_fd);
142159
free(file_buf);
143160
return path;
161+
#elif defined(_WIN32)
162+
// TODO
163+
fprintf(stderr, "dispatch_test_get_large_file() not implemented on Windows\n");
164+
abort();
144165
#else
145166
#error "dispatch_test_get_large_file not implemented on this platform"
146167
#endif
@@ -154,6 +175,8 @@ dispatch_test_release_large_file(const char *path)
154175
(void)path;
155176
#elif defined(__unix__)
156177
unlink(path);
178+
#elif defined(_WIN32)
179+
// TODO
157180
#else
158181
#error "dispatch_test_release_large_file not implemented on this platform"
159182
#endif

tests/dispatch_test.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
* @APPLE_APACHE_LICENSE_HEADER_END@
1919
*/
2020

21-
#include <sys/cdefs.h>
2221
#include <stdbool.h>
2322
#include <dispatch/dispatch.h>
2423

2524
#if defined(__linux__) || defined(__FreeBSD__)
2625
#include <generic_unix_port.h>
26+
#elif defined(_WIN32)
27+
#include <generic_win_port.h>
2728
#endif
2829

2930
#define test_group_wait(g) do { \
@@ -33,7 +34,9 @@
3334
test_stop(); \
3435
} } while (0)
3536

36-
__BEGIN_DECLS
37+
#if defined(__cplusplus)
38+
extern "C" {
39+
#endif
3740

3841
void dispatch_test_start(const char* desc);
3942

@@ -50,4 +53,6 @@ int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
5053
size_t *newpl);
5154
#endif
5255

53-
__END_DECLS
56+
#if defined(__cplusplus)
57+
} /* extern "C" */
58+
#endif

0 commit comments

Comments
 (0)