Merge pull request #1133 from Kelimion/strip-semicolons

testing: Strip ; from test runner.
This commit is contained in:
Jeroen van Rijn
2021-09-07 15:07:20 +02:00
committed by GitHub
3 changed files with 120 additions and 120 deletions
+32 -32
View File
@@ -6,68 +6,68 @@ import "core:os"
import "core:slice" import "core:slice"
reset_t :: proc(t: ^T) { reset_t :: proc(t: ^T) {
clear(&t.cleanups); clear(&t.cleanups)
t.error_count = 0; t.error_count = 0
} }
end_t :: proc(t: ^T) { end_t :: proc(t: ^T) {
for i := len(t.cleanups)-1; i >= 0; i -= 1 { for i := len(t.cleanups)-1; i >= 0; i -= 1 {
c := t.cleanups[i]; c := t.cleanups[i]
c.procedure(c.user_data); c.procedure(c.user_data)
} }
} }
runner :: proc(internal_tests: []Internal_Test) -> bool { runner :: proc(internal_tests: []Internal_Test) -> bool {
stream := os.stream_from_handle(os.stdout); stream := os.stream_from_handle(os.stdout)
w, _ := io.to_writer(stream); w, _ := io.to_writer(stream)
t := &T{}; t := &T{}
t.w = w; t.w = w
reserve(&t.cleanups, 1024); reserve(&t.cleanups, 1024)
defer delete(t.cleanups); defer delete(t.cleanups)
total_success_count := 0; total_success_count := 0
total_test_count := len(internal_tests); total_test_count := len(internal_tests)
slice.sort_by(internal_tests, proc(a, b: Internal_Test) -> bool { slice.sort_by(internal_tests, proc(a, b: Internal_Test) -> bool {
if a.pkg < b.pkg { if a.pkg < b.pkg {
return true; return true
} }
return a.name < b.name; return a.name < b.name
}); })
prev_pkg := ""; prev_pkg := ""
for it in internal_tests { for it in internal_tests {
if it.p == nil { if it.p == nil {
total_test_count -= 1; total_test_count -= 1
continue; continue
} }
free_all(context.temp_allocator); free_all(context.temp_allocator)
reset_t(t); reset_t(t)
defer end_t(t); defer end_t(t)
if prev_pkg != it.pkg { if prev_pkg != it.pkg {
prev_pkg = it.pkg; prev_pkg = it.pkg
logf(t, "[Package: %s]", it.pkg); logf(t, "[Package: %s]", it.pkg)
} }
logf(t, "[Test: %s]", it.name); logf(t, "[Test: %s]", it.name)
run_internal_test(t, it); run_internal_test(t, it)
if failed(t) { if failed(t) {
logf(t, "[%s : FAILURE]", it.name); logf(t, "[%s : FAILURE]", it.name)
} else { } else {
logf(t, "[%s : SUCCESS]", it.name); logf(t, "[%s : SUCCESS]", it.name)
total_success_count += 1; total_success_count += 1
} }
} }
logf(t, "----------------------------------------"); logf(t, "----------------------------------------")
if total_test_count == 0 { if total_test_count == 0 {
log(t, "NO TESTS RAN"); log(t, "NO TESTS RAN")
} else { } else {
logf(t, "%d/%d SUCCESSFUL", total_success_count, total_test_count); logf(t, "%d/%d SUCCESSFUL", total_success_count, total_test_count)
} }
return total_success_count == total_test_count; return total_success_count == total_test_count
} }
+74 -74
View File
@@ -12,39 +12,39 @@ Sema :: struct {
} }
sema_reset :: proc "contextless" (s: ^Sema) { sema_reset :: proc "contextless" (s: ^Sema) {
intrinsics.atomic_store(&s.count, 0); intrinsics.atomic_store(&s.count, 0)
} }
sema_wait :: proc "contextless" (s: ^Sema) { sema_wait :: proc "contextless" (s: ^Sema) {
for { for {
original_count := s.count; original_count := s.count
for original_count == 0 { for original_count == 0 {
win32.WaitOnAddress( win32.WaitOnAddress(
&s.count, &s.count,
&original_count, &original_count,
size_of(original_count), size_of(original_count),
win32.INFINITE, win32.INFINITE,
); )
original_count = s.count; original_count = s.count
} }
if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) { if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) {
return; return
} }
} }
} }
sema_post :: proc "contextless" (s: ^Sema, count := 1) { sema_post :: proc "contextless" (s: ^Sema, count := 1) {
intrinsics.atomic_add(&s.count, i32(count)); intrinsics.atomic_add(&s.count, i32(count))
if count == 1 { if count == 1 {
win32.WakeByAddressSingle(&s.count); win32.WakeByAddressSingle(&s.count)
} else { } else {
win32.WakeByAddressAll(&s.count); win32.WakeByAddressAll(&s.count)
} }
} }
Thread_Proc :: #type proc(^Thread); Thread_Proc :: #type proc(^Thread)
MAX_USER_ARGUMENTS :: 8; MAX_USER_ARGUMENTS :: 8
Thread :: struct { Thread :: struct {
using specific: Thread_Os_Specific, using specific: Thread_Os_Specific,
@@ -67,66 +67,66 @@ Thread_Os_Specific :: struct {
thread_create :: proc(procedure: Thread_Proc) -> ^Thread { thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD { __windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
t := (^Thread)(t_); t := (^Thread)(t_)
context = t.init_context.? or_else runtime.default_context(); context = t.init_context.? or_else runtime.default_context()
t.procedure(t); t.procedure(t)
if t.init_context == nil { if t.init_context == nil {
if context.temp_allocator.data == &runtime.global_default_temp_allocator_data { if context.temp_allocator.data == &runtime.global_default_temp_allocator_data {
runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data); runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data)
} }
} }
intrinsics.atomic_store(&t.done, true); intrinsics.atomic_store(&t.done, true)
return 0; return 0
} }
thread := new(Thread); thread := new(Thread)
if thread == nil { if thread == nil {
return nil; return nil
} }
thread.creation_allocator = context.allocator; thread.creation_allocator = context.allocator
win32_thread_id: win32.DWORD; win32_thread_id: win32.DWORD
win32_thread := win32.CreateThread(nil, 0, __windows_thread_entry_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id); win32_thread := win32.CreateThread(nil, 0, __windows_thread_entry_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id)
if win32_thread == nil { if win32_thread == nil {
free(thread, thread.creation_allocator); free(thread, thread.creation_allocator)
return nil; return nil
} }
thread.procedure = procedure; thread.procedure = procedure
thread.win32_thread = win32_thread; thread.win32_thread = win32_thread
thread.win32_thread_id = win32_thread_id; thread.win32_thread_id = win32_thread_id
thread.init_context = context; thread.init_context = context
return thread; return thread
} }
thread_start :: proc "contextless" (thread: ^Thread) { thread_start :: proc "contextless" (thread: ^Thread) {
win32.ResumeThread(thread.win32_thread); win32.ResumeThread(thread.win32_thread)
} }
thread_join_and_destroy :: proc(thread: ^Thread) { thread_join_and_destroy :: proc(thread: ^Thread) {
if thread.win32_thread != win32.INVALID_HANDLE { if thread.win32_thread != win32.INVALID_HANDLE {
win32.WaitForSingleObject(thread.win32_thread, win32.INFINITE); win32.WaitForSingleObject(thread.win32_thread, win32.INFINITE)
win32.CloseHandle(thread.win32_thread); win32.CloseHandle(thread.win32_thread)
thread.win32_thread = win32.INVALID_HANDLE; thread.win32_thread = win32.INVALID_HANDLE
} }
free(thread, thread.creation_allocator); free(thread, thread.creation_allocator)
} }
thread_terminate :: proc "contextless" (thread: ^Thread, exit_code: int) { thread_terminate :: proc "contextless" (thread: ^Thread, exit_code: int) {
win32.TerminateThread(thread.win32_thread, u32(exit_code)); win32.TerminateThread(thread.win32_thread, u32(exit_code))
} }
global_threaded_runner_semaphore: Sema; global_threaded_runner_semaphore: Sema
global_exception_handler: rawptr; global_exception_handler: rawptr
global_current_thread: ^Thread; global_current_thread: ^Thread
global_current_t: ^T; global_current_t: ^T
run_internal_test :: proc(t: ^T, it: Internal_Test) { run_internal_test :: proc(t: ^T, it: Internal_Test) {
thread := thread_create(proc(thread: ^Thread) { thread := thread_create(proc(thread: ^Thread) {
@@ -140,47 +140,47 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) {
win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED, win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
win32.EXCEPTION_STACK_OVERFLOW: win32.EXCEPTION_STACK_OVERFLOW:
sema_post(&global_threaded_runner_semaphore); sema_post(&global_threaded_runner_semaphore)
return win32.EXCEPTION_EXECUTE_HANDLER; return win32.EXCEPTION_EXECUTE_HANDLER
} }
return win32.EXCEPTION_CONTINUE_SEARCH; return win32.EXCEPTION_CONTINUE_SEARCH
} }
global_exception_handler = win32.AddVectoredExceptionHandler(0, exception_handler_proc); global_exception_handler = win32.AddVectoredExceptionHandler(0, exception_handler_proc)
context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! {
errorf(t=global_current_t, format="%s %s", args={prefix, message}, loc=loc); errorf(t=global_current_t, format="%s %s", args={prefix, message}, loc=loc)
intrinsics.trap(); intrinsics.trap()
};
thread.it.p(thread.t);
thread.success = true;
sema_post(&global_threaded_runner_semaphore);
});
sema_reset(&global_threaded_runner_semaphore);
global_current_t = t;
t._fail_now = proc() -> ! {
intrinsics.trap();
};
thread.t = t;
thread.it = it;
thread.success = false;
thread_start(thread);
sema_wait(&global_threaded_runner_semaphore);
thread_terminate(thread, int(!thread.success));
thread_join_and_destroy(thread);
win32.RemoveVectoredExceptionHandler(global_exception_handler);
if !thread.success && t.error_count == 0 {
t.error_count += 1;
} }
return; thread.it.p(thread.t)
thread.success = true
sema_post(&global_threaded_runner_semaphore)
})
sema_reset(&global_threaded_runner_semaphore)
global_current_t = t
t._fail_now = proc() -> ! {
intrinsics.trap()
}
thread.t = t
thread.it = it
thread.success = false
thread_start(thread)
sema_wait(&global_threaded_runner_semaphore)
thread_terminate(thread, int(!thread.success))
thread_join_and_destroy(thread)
win32.RemoveVectoredExceptionHandler(global_exception_handler)
if !thread.success && t.error_count == 0 {
t.error_count += 1
}
return
} }
+19 -19
View File
@@ -4,7 +4,7 @@ import "core:fmt"
import "core:io" import "core:io"
// IMPORTANT NOTE: Compiler requires this layout // IMPORTANT NOTE: Compiler requires this layout
Test_Signature :: proc(^T); Test_Signature :: proc(^T)
// IMPORTANT NOTE: Compiler requires this layout // IMPORTANT NOTE: Compiler requires this layout
Internal_Test :: struct { Internal_Test :: struct {
@@ -31,53 +31,53 @@ T :: struct {
error :: proc(t: ^T, args: ..any, loc := #caller_location) { error :: proc(t: ^T, args: ..any, loc := #caller_location) {
fmt.wprintf(t.w, "%v: ", loc); fmt.wprintf(t.w, "%v: ", loc)
fmt.wprintln(t.w, ..args); fmt.wprintln(t.w, ..args)
t.error_count += 1; t.error_count += 1
} }
errorf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { errorf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) {
fmt.wprintf(t.w, "%v: ", loc); fmt.wprintf(t.w, "%v: ", loc)
fmt.wprintf(t.w, format, ..args); fmt.wprintf(t.w, format, ..args)
fmt.wprintln(t.w); fmt.wprintln(t.w)
t.error_count += 1; t.error_count += 1
} }
fail :: proc(t: ^T) { fail :: proc(t: ^T) {
error(t, "FAIL"); error(t, "FAIL")
t.error_count += 1; t.error_count += 1
} }
fail_now :: proc(t: ^T) { fail_now :: proc(t: ^T) {
fail(t); fail(t)
if t._fail_now != nil { if t._fail_now != nil {
t._fail_now(); t._fail_now()
} }
} }
failed :: proc(t: ^T) -> bool { failed :: proc(t: ^T) -> bool {
return t.error_count != 0; return t.error_count != 0
} }
log :: proc(t: ^T, args: ..any, loc := #caller_location) { log :: proc(t: ^T, args: ..any, loc := #caller_location) {
fmt.wprintln(t.w, ..args); fmt.wprintln(t.w, ..args)
} }
logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) {
fmt.wprintf(t.w, format, ..args); fmt.wprintf(t.w, format, ..args)
fmt.wprintln(t.w); fmt.wprintln(t.w)
} }
// cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete // cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete
// cleanup proceduers will be called in LIFO (last added, first called) order. // cleanup proceduers will be called in LIFO (last added, first called) order.
cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) { cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) {
append(&t.cleanups, Internal_Cleanup{procedure, user_data}); append(&t.cleanups, Internal_Cleanup{procedure, user_data})
} }
expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool { expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool {
if !ok { if !ok {
error(t=t, args={msg}, loc=loc); error(t=t, args={msg}, loc=loc)
} }
return ok; return ok
} }