mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 12:48:14 +00:00
Add testing.expect_value; Improve testing.set_fail_timeout
This commit is contained in:
@@ -6,6 +6,9 @@ import win32 "core:sys/windows"
|
|||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
_ :: fmt
|
||||||
|
|
||||||
Sema :: struct {
|
Sema :: struct {
|
||||||
count: i32,
|
count: i32,
|
||||||
@@ -18,12 +21,7 @@ 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, &original_count, size_of(original_count), win32.INFINITE)
|
||||||
&s.count,
|
|
||||||
&original_count,
|
|
||||||
size_of(original_count),
|
|
||||||
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) {
|
||||||
@@ -31,6 +29,31 @@ sema_wait :: proc "contextless" (s: ^Sema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
|
||||||
|
if duration <= 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
|
||||||
|
original_count := intrinsics.atomic_load(&s.count)
|
||||||
|
for start := time.tick_now(); original_count == 0; /**/ {
|
||||||
|
if intrinsics.atomic_load(&s.count) != original_count {
|
||||||
|
remaining := duration - time.tick_since(start)
|
||||||
|
if remaining < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ms := u32(remaining/time.Millisecond)
|
||||||
|
if !win32.WaitOnAddress(&s.count, &original_count, size_of(original_count), ms) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
original_count = s.count
|
||||||
|
}
|
||||||
|
if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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))
|
||||||
@@ -42,6 +65,7 @@ sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Thread_Proc :: #type proc(^Thread)
|
Thread_Proc :: #type proc(^Thread)
|
||||||
|
|
||||||
MAX_USER_ARGUMENTS :: 8
|
MAX_USER_ARGUMENTS :: 8
|
||||||
@@ -127,19 +151,21 @@ thread_terminate :: proc "contextless" (thread: ^Thread, exit_code: int) {
|
|||||||
_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {
|
_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {
|
||||||
thread := thread_create(proc(thread: ^Thread) {
|
thread := thread_create(proc(thread: ^Thread) {
|
||||||
t := thread.t
|
t := thread.t
|
||||||
time.sleep(thread.internal_fail_timeout)
|
timeout := thread.internal_fail_timeout
|
||||||
if !intrinsics.atomic_load(&t._is_done) {
|
if !sema_wait_with_timeout(&global_fail_timeout_semaphore, timeout) {
|
||||||
fail_now(t, "TIMEOUT", thread.internal_fail_timeout_loc)
|
fail_now(t, "TIMEOUT", thread.internal_fail_timeout_loc)
|
||||||
}
|
}
|
||||||
// NOTE(bill): Complete hack and probably not a good idea
|
|
||||||
thread_join_and_destroy(thread)
|
|
||||||
})
|
})
|
||||||
thread.internal_fail_timeout = duration
|
thread.internal_fail_timeout = duration
|
||||||
thread.internal_fail_timeout_loc = loc
|
thread.internal_fail_timeout_loc = loc
|
||||||
thread.t = t
|
thread.t = t
|
||||||
|
global_fail_timeout_thread = thread
|
||||||
thread_start(thread)
|
thread_start(thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global_fail_timeout_thread: ^Thread
|
||||||
|
global_fail_timeout_semaphore: Sema
|
||||||
|
|
||||||
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
|
||||||
@@ -164,7 +190,7 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) {
|
|||||||
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()
|
||||||
@@ -172,11 +198,14 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) {
|
|||||||
|
|
||||||
t := thread.t
|
t := thread.t
|
||||||
|
|
||||||
t._fail_timeout_set = false
|
global_fail_timeout_thread = nil
|
||||||
intrinsics.atomic_store(&t._is_done, false)
|
sema_reset(&global_fail_timeout_semaphore)
|
||||||
|
|
||||||
thread.it.p(t)
|
thread.it.p(t)
|
||||||
intrinsics.atomic_store(&t._is_done, true)
|
|
||||||
|
sema_post(&global_fail_timeout_semaphore)
|
||||||
|
thread_join_and_destroy(global_fail_timeout_thread)
|
||||||
|
|
||||||
thread.success = true
|
thread.success = true
|
||||||
sema_post(&global_threaded_runner_semaphore)
|
sema_post(&global_threaded_runner_semaphore)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package testing
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
// IMPORTANT NOTE: Compiler requires this layout
|
// IMPORTANT NOTE: Compiler requires this layout
|
||||||
Test_Signature :: proc(^T)
|
Test_Signature :: proc(^T)
|
||||||
@@ -28,8 +29,6 @@ T :: struct {
|
|||||||
cleanups: [dynamic]Internal_Cleanup,
|
cleanups: [dynamic]Internal_Cleanup,
|
||||||
|
|
||||||
_fail_now: proc() -> !,
|
_fail_now: proc() -> !,
|
||||||
_is_done: bool,
|
|
||||||
_fail_timeout_set: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -89,10 +88,17 @@ expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bo
|
|||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) {
|
||||||
|
ok := value == expected
|
||||||
|
if !ok {
|
||||||
|
errorf(t=t, format="expected %v, got %v", args={expected, value}, loc=loc)
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {
|
set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {
|
||||||
assert(t._fail_timeout_set == false, "set_fail_timeout previously called", loc)
|
assert(global_fail_timeout_thread == nil, "set_fail_timeout previously called", loc)
|
||||||
t._fail_timeout_set = true
|
|
||||||
_fail_timeout(t, duration, loc)
|
_fail_timeout(t, duration, loc)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user