From 2ecf909be02f719596f566853d13666d0db4da8d Mon Sep 17 00:00:00 2001 From: Harold Brenes Date: Mon, 27 May 2024 11:54:28 -0400 Subject: [PATCH 01/93] Fix open() foreign libc signature on Darwin --- core/os/os_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index a688e1ac3..877a90bf1 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -442,7 +442,7 @@ F_GETPATH :: 50 // return the full path of the fd foreign libc { @(link_name="__error") __error :: proc() -> ^c.int --- - @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle --- + @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, #c_vararg args: ..any) -> Handle --- @(link_name="close") _unix_close :: proc(handle: Handle) -> c.int --- @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- From 8ae375dbffa344dc6f99fe0dc82f9070559ab137 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 23 May 2024 16:23:54 -0400 Subject: [PATCH 02/93] Move log timestamping out to `do_time_header` proc --- core/log/file_console_logger.odin | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index bcce67578..99ca1f51a 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -73,15 +73,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string do_level_header(options, level, &buf) when time.IS_SUPPORTED { - if Full_Timestamp_Opts & options != nil { - fmt.sbprint(&buf, "[") - t := time.now() - y, m, d := time.date(t) - h, min, s := time.clock(t) - if .Date in options { fmt.sbprintf(&buf, "%d-%02d-%02d ", y, m, d) } - if .Time in options { fmt.sbprintf(&buf, "%02d:%02d:%02d", h, min, s) } - fmt.sbprint(&buf, "] ") - } + do_time_header(options, &buf, time.now()) } do_location_header(options, &buf, location) @@ -125,6 +117,19 @@ do_level_header :: proc(opts: Options, level: Level, str: ^strings.Builder) { } } +do_time_header :: proc(opts: Options, buf: ^strings.Builder, t: time.Time) { + when time.IS_SUPPORTED { + if Full_Timestamp_Opts & opts != nil { + fmt.sbprint(buf, "[") + y, m, d := time.date(t) + h, min, s := time.clock(t) + if .Date in opts { fmt.sbprintf(buf, "%d-%02d-%02d ", y, m, d) } + if .Time in opts { fmt.sbprintf(buf, "%02d:%02d:%02d", h, min, s) } + fmt.sbprint(buf, "] ") + } + } +} + do_location_header :: proc(opts: Options, buf: ^strings.Builder, location := #caller_location) { if Location_Header_Opts & opts == nil { return From 7d4da6eaa7cf420b1808652cb44763e259634001 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 23 May 2024 16:29:18 -0400 Subject: [PATCH 03/93] Fix trailing space with only `.Date` log option --- core/log/file_console_logger.odin | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 99ca1f51a..6843d3a63 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -123,7 +123,12 @@ do_time_header :: proc(opts: Options, buf: ^strings.Builder, t: time.Time) { fmt.sbprint(buf, "[") y, m, d := time.date(t) h, min, s := time.clock(t) - if .Date in opts { fmt.sbprintf(buf, "%d-%02d-%02d ", y, m, d) } + if .Date in opts { + fmt.sbprintf(buf, "%d-%02d-%02d", y, m, d) + if .Time in opts { + fmt.sbprint(buf, " ") + } + } if .Time in opts { fmt.sbprintf(buf, "%02d:%02d:%02d", h, min, s) } fmt.sbprint(buf, "] ") } From 1875e7c36a4aaee71aa39defe0d169104a8030b0 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 15:56:58 -0400 Subject: [PATCH 04/93] Make `log.do_*_header` argument orders consistent --- core/log/file_console_logger.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 6843d3a63..661f5d408 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -70,7 +70,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string backing: [1024]byte //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths. buf := strings.builder_from_bytes(backing[:]) - do_level_header(options, level, &buf) + do_level_header(options, &buf, level) when time.IS_SUPPORTED { do_time_header(options, &buf, time.now()) @@ -91,7 +91,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text) } -do_level_header :: proc(opts: Options, level: Level, str: ^strings.Builder) { +do_level_header :: proc(opts: Options, str: ^strings.Builder, level: Level) { RESET :: "\x1b[0m" RED :: "\x1b[31m" From 558c330028e90db9934d82414e7b21374ed58e1c Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 23 May 2024 16:43:26 -0400 Subject: [PATCH 05/93] Add task-stopping functionality to `thread.Pool` --- core/thread/thread_pool.odin | 130 +++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 15 deletions(-) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index fddcac89e..53f89ea0c 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -44,6 +44,29 @@ Pool :: struct { tasks_done: [dynamic]Task, } +Pool_Thread_Data :: struct { + pool: ^Pool, + task: Task, +} + +@(private="file") +pool_thread_runner :: proc(t: ^Thread) { + data := cast(^Pool_Thread_Data)t.data + pool := data.pool + + for intrinsics.atomic_load(&pool.is_running) { + sync.wait(&pool.sem_available) + + if task, ok := pool_pop_waiting(pool); ok { + data.task = task + pool_do_work(pool, task) + data.task = {} + } + } + + sync.post(&pool.sem_available, 1) +} + // Once initialized, the pool's memory address is not allowed to change until // it is destroyed. // @@ -58,21 +81,11 @@ pool_init :: proc(pool: ^Pool, allocator: mem.Allocator, thread_count: int) { pool.is_running = true for _, i in pool.threads { - t := create(proc(t: ^Thread) { - pool := (^Pool)(t.data) - - for intrinsics.atomic_load(&pool.is_running) { - sync.wait(&pool.sem_available) - - if task, ok := pool_pop_waiting(pool); ok { - pool_do_work(pool, task) - } - } - - sync.post(&pool.sem_available, 1) - }) + t := create(pool_thread_runner) + data := new(Pool_Thread_Data) + data.pool = pool t.user_index = i - t.data = pool + t.data = data pool.threads[i] = t } } @@ -82,6 +95,8 @@ pool_destroy :: proc(pool: ^Pool) { delete(pool.tasks_done) for &t in pool.threads { + data := cast(^Pool_Thread_Data)t.data + free(data, pool.allocator) destroy(t) } @@ -103,7 +118,7 @@ pool_join :: proc(pool: ^Pool) { yield() -started_count: int + started_count: int for started_count < len(pool.threads) { started_count = 0 for t in pool.threads { @@ -138,6 +153,91 @@ pool_add_task :: proc(pool: ^Pool, allocator: mem.Allocator, procedure: Task_Pro sync.post(&pool.sem_available, 1) } +// Forcibly stop a running task by its user index. +// +// This will terminate the underlying thread. Ideally, you should use some +// means of communication to stop a task, as thread termination may leave +// resources unclaimed. +// +// The thread will be restarted to accept new tasks. +// +// Returns true if the task was found and terminated. +pool_stop_task :: proc(pool: ^Pool, user_index: int, exit_code: int = 1) -> bool { + sync.guard(&pool.mutex) + + for t, i in pool.threads { + data := cast(^Pool_Thread_Data)t.data + if data.task.user_index == user_index && data.task.procedure != nil { + terminate(t, exit_code) + + append(&pool.tasks_done, data.task) + intrinsics.atomic_add(&pool.num_done, 1) + intrinsics.atomic_sub(&pool.num_outstanding, 1) + intrinsics.atomic_sub(&pool.num_in_processing, 1) + + destroy(t) + + replacement := create(pool_thread_runner) + replacement.user_index = t.user_index + replacement.data = data + pool.threads[i] = replacement + + start(replacement) + return true + } + } + + return false +} + +// Forcibly stop all running tasks. +// +// The same notes from `pool_stop_task` apply here. +pool_stop_all_tasks :: proc(pool: ^Pool, exit_code: int = 1) { + sync.guard(&pool.mutex) + + for t, i in pool.threads { + data := cast(^Pool_Thread_Data)t.data + if data.task.procedure != nil { + terminate(t, exit_code) + + append(&pool.tasks_done, data.task) + intrinsics.atomic_add(&pool.num_done, 1) + intrinsics.atomic_sub(&pool.num_outstanding, 1) + intrinsics.atomic_sub(&pool.num_in_processing, 1) + + destroy(t) + + replacement := create(pool_thread_runner) + replacement.user_index = t.user_index + replacement.data = data + pool.threads[i] = replacement + + start(replacement) + } + } +} + +// Force the pool to stop all of its threads and put it into a state where +// it will no longer run any more tasks. +// +// The pool must still be destroyed after this. +pool_shutdown :: proc(pool: ^Pool, exit_code: int = 1) { + sync.guard(&pool.mutex) + + for t in pool.threads { + terminate(t, exit_code) + + data := cast(^Pool_Thread_Data)t.data + if data.task.procedure != nil { + append(&pool.tasks_done, data.task) + intrinsics.atomic_add(&pool.num_done, 1) + intrinsics.atomic_sub(&pool.num_outstanding, 1) + intrinsics.atomic_sub(&pool.num_in_processing, 1) + } + } +} + // Number of tasks waiting to be processed. Only informational, mostly for // debugging. Don't rely on this value being consistent with other num_* // values. From 8137b9dd753672d5359828a3170545d856936f10 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 23 May 2024 16:50:21 -0400 Subject: [PATCH 06/93] Add `mem.tracking_allocator_reset` --- core/mem/tracking_allocator.odin | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/mem/tracking_allocator.odin b/core/mem/tracking_allocator.odin index bc624617d..1b57e5fb4 100644 --- a/core/mem/tracking_allocator.odin +++ b/core/mem/tracking_allocator.odin @@ -47,6 +47,7 @@ tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) { } +// Clear only the current allocation data while keeping the totals intact. tracking_allocator_clear :: proc(t: ^Tracking_Allocator) { sync.mutex_lock(&t.mutex) clear(&t.allocation_map) @@ -55,6 +56,19 @@ tracking_allocator_clear :: proc(t: ^Tracking_Allocator) { sync.mutex_unlock(&t.mutex) } +// Reset all of a Tracking Allocator's allocation data back to zero. +tracking_allocator_reset :: proc(t: ^Tracking_Allocator) { + sync.mutex_lock(&t.mutex) + clear(&t.allocation_map) + clear(&t.bad_free_array) + t.total_memory_allocated = 0 + t.total_allocation_count = 0 + t.total_memory_freed = 0 + t.total_free_count = 0 + t.peak_memory_allocated = 0 + t.current_memory_allocated = 0 + sync.mutex_unlock(&t.mutex) +} @(require_results) tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator { From fc4f6b87bb777d73b506a16749e934e076a5b8bc Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 15:51:28 -0400 Subject: [PATCH 07/93] Add `core:encoding/ansi` package --- core/encoding/ansi/ansi.odin | 137 ++++++++++++++++++++++++++++++ core/encoding/ansi/doc.odin | 20 +++++ core/log/file_console_logger.odin | 9 +- 3 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 core/encoding/ansi/ansi.odin create mode 100644 core/encoding/ansi/doc.odin diff --git a/core/encoding/ansi/ansi.odin b/core/encoding/ansi/ansi.odin new file mode 100644 index 000000000..5550a1671 --- /dev/null +++ b/core/encoding/ansi/ansi.odin @@ -0,0 +1,137 @@ +package ansi + +BEL :: "\a" // Bell +BS :: "\b" // Backspace +ESC :: "\e" // Escape + +// Fe Escape sequences + +CSI :: ESC + "[" // Control Sequence Introducer +OSC :: ESC + "]" // Operating System Command +ST :: ESC + "\\" // String Terminator + +// CSI sequences + +CUU :: "A" // Cursor Up +CUD :: "B" // Cursor Down +CUF :: "C" // Cursor Forward +CUB :: "D" // Cursor Back +CNL :: "E" // Cursor Next Line +CPL :: "F" // Cursor Previous Line +CHA :: "G" // Cursor Horizontal Absolute +CUP :: "H" // Cursor Position +ED :: "J" // Erase in Display +EL :: "K" // Erase in Line +SU :: "S" // Scroll Up +SD :: "T" // Scroll Down +HVP :: "f" // Horizontal Vertical Position +SGR :: "m" // Select Graphic Rendition +AUX_ON :: "5i" // AUX Port On +AUX_OFF :: "4i" // AUX Port Off +DSR :: "6n" // Device Status Report + +// CSI: private sequences + +SCP :: "s" // Save Current Cursor Position +RCP :: "u" // Restore Saved Cursor Position +DECAWM_ON :: "?7h" // Auto Wrap Mode (Enabled) +DECAWM_OFF :: "?7l" // Auto Wrap Mode (Disabled) +DECTCEM_SHOW :: "?25h" // Text Cursor Enable Mode (Visible) +DECTCEM_HIDE :: "?25l" // Text Cursor Enable Mode (Invisible) + +// SGR sequences + +RESET :: "0" +BOLD :: "1" +FAINT :: "2" +ITALIC :: "3" // Not widely supported. +UNDERLINE :: "4" +BLINK_SLOW :: "5" +BLINK_RAPID :: "6" // Not widely supported. +INVERT :: "7" // Also known as reverse video. +HIDE :: "8" // Not widely supported. +STRIKE :: "9" +FONT_PRIMARY :: "10" +FONT_ALT1 :: "11" +FONT_ALT2 :: "12" +FONT_ALT3 :: "13" +FONT_ALT4 :: "14" +FONT_ALT5 :: "15" +FONT_ALT6 :: "16" +FONT_ALT7 :: "17" +FONT_ALT8 :: "18" +FONT_ALT9 :: "19" +FONT_FRAKTUR :: "20" // Rarely supported. +UNDERLINE_DOUBLE :: "21" // May be interpreted as "disable bold." +NO_BOLD_FAINT :: "22" +NO_ITALIC_BLACKLETTER :: "23" +NO_UNDERLINE :: "24" +NO_BLINK :: "25" +PROPORTIONAL_SPACING :: "26" +NO_REVERSE :: "27" +NO_HIDE :: "28" +NO_STRIKE :: "29" + +FG_BLACK :: "30" +FG_RED :: "31" +FG_GREEN :: "32" +FG_YELLOW :: "33" +FG_BLUE :: "34" +FG_MAGENTA :: "35" +FG_CYAN :: "36" +FG_WHITE :: "37" +FG_COLOR :: "38" +FG_COLOR_8_BIT :: "38;5" // Followed by ";n" where n is in 0..=255 +FG_COLOR_24_BIT :: "38;2" // Followed by ";r;g;b" where r,g,b are in 0..=255 +FG_DEFAULT :: "39" + +BG_BLACK :: "40" +BG_RED :: "41" +BG_GREEN :: "42" +BG_YELLOW :: "43" +BG_BLUE :: "44" +BG_MAGENTA :: "45" +BG_CYAN :: "46" +BG_WHITE :: "47" +BG_COLOR :: "48" +BG_COLOR_8_BIT :: "48;5" // Followed by ";n" where n is in 0..=255 +BG_COLOR_24_BIT :: "48;2" // Followed by ";r;g;b" where r,g,b are in 0..=255 +BG_DEFAULT :: "49" + +NO_PROPORTIONAL_SPACING :: "50" +FRAMED :: "51" +ENCIRCLED :: "52" +OVERLINED :: "53" +NO_FRAME_ENCIRCLE :: "54" +NO_OVERLINE :: "55" + +// SGR: non-standard bright colors + +FG_BRIGHT_BLACK :: "90" // Also known as grey. +FG_BRIGHT_RED :: "91" +FG_BRIGHT_GREEN :: "92" +FG_BRIGHT_YELLOW :: "93" +FG_BRIGHT_BLUE :: "94" +FG_BRIGHT_MAGENTA :: "95" +FG_BRIGHT_CYAN :: "96" +FG_BRIGHT_WHITE :: "97" + +BG_BRIGHT_BLACK :: "100" // Also known as grey. +BG_BRIGHT_RED :: "101" +BG_BRIGHT_GREEN :: "102" +BG_BRIGHT_YELLOW :: "103" +BG_BRIGHT_BLUE :: "104" +BG_BRIGHT_MAGENTA :: "105" +BG_BRIGHT_CYAN :: "106" +BG_BRIGHT_WHITE :: "107" + +// Fp Escape sequences + +DECSC :: ESC + "7" // DEC Save Cursor +DECRC :: ESC + "8" // DEC Restore Cursor + +// OSC sequences + +WINDOW_TITLE :: "2" // Followed by ";" ST. +HYPERLINK :: "8" // Followed by ";[params];" ST. Closed by OSC HYPERLINK ";;" ST. +CLIPBOARD :: "52" // Followed by ";c;" ST. diff --git a/core/encoding/ansi/doc.odin b/core/encoding/ansi/doc.odin new file mode 100644 index 000000000..a0945c581 --- /dev/null +++ b/core/encoding/ansi/doc.odin @@ -0,0 +1,20 @@ +/* +package ansi implements constant references to many widely-supported ANSI +escape codes, primarily used in terminal emulators for enhanced graphics, such +as colors, text styling, and animated displays. + +For example, you can print out a line of cyan text like this: + fmt.println(ansi.CSI + ansi.FG_CYAN + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) + +Multiple SGR (Select Graphic Rendition) codes can be joined by semicolons: + fmt.println(ansi.CSI + ansi.BOLD + ";" + ansi.FG_BLUE + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) + +If your terminal supports 24-bit true color mode, you can also do this: + fmt.println(ansi.CSI + ansi.FG_COLOR_24_BIT + ";0;255;255" + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR) + +For more information, see: + 1. https://en.wikipedia.org/wiki/ANSI_escape_code + 2. https://www.vt100.net/docs/vt102-ug/chapter5.html + 3. https://invisible-island.net/xterm/ctlseqs/ctlseqs.html +*/ +package ansi diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 661f5d408..fb968ccb6 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -1,6 +1,7 @@ //+build !freestanding package log +import "core:encoding/ansi" import "core:fmt" import "core:strings" import "core:os" @@ -93,10 +94,10 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string do_level_header :: proc(opts: Options, str: ^strings.Builder, level: Level) { - RESET :: "\x1b[0m" - RED :: "\x1b[31m" - YELLOW :: "\x1b[33m" - DARK_GREY :: "\x1b[90m" + RESET :: ansi.CSI + ansi.RESET + ansi.SGR + RED :: ansi.CSI + ansi.FG_RED + ansi.SGR + YELLOW :: ansi.CSI + ansi.FG_YELLOW + ansi.SGR + DARK_GREY :: ansi.CSI + ansi.FG_BRIGHT_BLACK + ansi.SGR col := RESET switch level { From 50dffaf131452f64a2b28477718850ad2a8b78f2 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 16:29:34 -0400 Subject: [PATCH 08/93] Add `mem.Rollback_Stack` --- core/mem/rollback_stack_allocator.odin | 319 +++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 core/mem/rollback_stack_allocator.odin diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin new file mode 100644 index 000000000..bf397d2c8 --- /dev/null +++ b/core/mem/rollback_stack_allocator.odin @@ -0,0 +1,319 @@ +package mem + +// The Rollback Stack Allocator was designed for the test runner to be fast, +// able to grow, and respect the Tracking Allocator's requirement for +// individual frees. It is not overly concerned with fragmentation, however. +// +// It has support for expansion when configured with a block allocator and +// limited support for out-of-order frees. +// +// Allocation has constant-time best and usual case performance. +// At worst, it is linear according to the number of memory blocks. +// +// Allocation follows a first-fit strategy when there are multiple memory +// blocks. +// +// Freeing has constant-time best and usual case performance. +// At worst, it is linear according to the number of memory blocks and number +// of freed items preceding the last item in a block. +// +// Resizing has constant-time performance, if it's the last item in a block, or +// the new size is smaller. Naturally, this becomes linear-time if there are +// multiple blocks to search for the pointer's owning block. Otherwise, the +// allocator defaults to a combined alloc & free operation internally. +// +// Out-of-order freeing is accomplished by collapsing a run of freed items +// from the last allocation backwards. +// +// Each allocation has an overhead of 8 bytes and any extra bytes to satisfy +// the requested alignment. + +import "base:runtime" + +ROLLBACK_STACK_DEFAULT_BLOCK_SIZE :: 4 * Megabyte + +// This limitation is due to the size of `prev_ptr`, but it is only for the +// head block; any allocation in excess of the allocator's `block_size` is +// valid, so long as the block allocator can handle it. +// +// This is because allocations over the block size are not split up if the item +// within is freed; they are immediately returned to the block allocator. +ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE :: 1 * Gigabyte + + +Rollback_Stack_Header :: bit_field u64 { + prev_offset: int | 32, + is_free: bool | 1, + prev_ptr: int | 31, +} + +Rollback_Stack_Block :: struct { + next_block: ^Rollback_Stack_Block, + last_alloc: rawptr, + offset: int, + buffer: []byte, +} + +Rollback_Stack :: struct { + head: ^Rollback_Stack_Block, + block_size: int, + block_allocator: Allocator, +} + + +@(private="file") +@(require_results) +rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool { + start := cast(uintptr)raw_data(block.buffer) + end := cast(uintptr)raw_data(block.buffer) + cast(uintptr)block.offset + return start < cast(uintptr)ptr && cast(uintptr)ptr <= end +} + +@(private="file") +@(require_results) +rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( + parent: ^Rollback_Stack_Block, + block: ^Rollback_Stack_Block, + header: ^Rollback_Stack_Header, + err: Allocator_Error, +) { + for block = stack.head; block != nil; block = block.next_block { + if rb_ptr_in_bounds(block, ptr) { + header = cast(^Rollback_Stack_Header)(cast(uintptr)ptr - size_of(Rollback_Stack_Header)) + return + } + parent = block + } + return nil, nil, nil, .Invalid_Pointer +} + +@(private="file") +@(require_results) +rb_find_last_alloc :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( + block: ^Rollback_Stack_Block, + header: ^Rollback_Stack_Header, + ok: bool, +) { + for block = stack.head; block != nil; block = block.next_block { + if block.last_alloc == ptr { + header = cast(^Rollback_Stack_Header)(cast(uintptr)ptr - size_of(Rollback_Stack_Header)) + return block, header, true + } + } + return nil, nil, false +} + +@(private="file") +rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_Header) { + header := header + for block.offset > 0 && header.is_free { + block.offset = header.prev_offset + block.last_alloc = cast(rawptr)(cast(uintptr)raw_data(block.buffer) + cast(uintptr)header.prev_ptr) + header = cast(^Rollback_Stack_Header)(cast(uintptr)raw_data(block.buffer) + cast(uintptr)header.prev_ptr - size_of(Rollback_Stack_Header)) + } +} + +@(private="file") +@(require_results) +rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error { + parent, block, header := rb_find_ptr(stack, ptr) or_return + if header.is_free { + return .Invalid_Pointer + } + header.is_free = true + if block.last_alloc == ptr { + block.offset = header.prev_offset + rb_rollback_block(block, header) + } + if parent != nil && block.offset == 0 { + parent.next_block = block.next_block + runtime.mem_free_with_size(block, size_of(Rollback_Stack_Block) + len(block.buffer), stack.block_allocator) + } + return nil +} + +@(private="file") +rb_free_all :: proc(stack: ^Rollback_Stack) { + for block := stack.head.next_block; block != nil; /**/ { + next_block := block.next_block + runtime.mem_free_with_size(block, size_of(Rollback_Stack_Block) + len(block.buffer), stack.block_allocator) + block = next_block + } + + stack.head.next_block = nil + stack.head.last_alloc = nil + stack.head.offset = 0 +} + +@(private="file") +@(require_results) +rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment: int) -> (result: []byte, err: Allocator_Error) { + if ptr != nil { + if block, _, ok := rb_find_last_alloc(stack, ptr); ok { + if block.offset + (size - old_size) < len(block.buffer) { + block.offset += (size - old_size) + #no_bounds_check return (cast([^]byte)ptr)[:size], nil + } + } + } + + result = rb_alloc(stack, size, alignment) or_return + runtime.mem_copy_non_overlapping(raw_data(result), ptr, old_size) + err = rb_free(stack, ptr) + + return +} + +@(private="file") +@(require_results) +rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byte, err: Allocator_Error) { + parent: ^Rollback_Stack_Block + for block := stack.head; /**/; block = block.next_block { + if block == nil { + if stack.block_allocator.procedure == nil { + return nil, .Out_Of_Memory + } + + minimum_size_required := size_of(Rollback_Stack_Header) + size + alignment - 1 + new_block_size := max(minimum_size_required, stack.block_size) + block = rb_make_block(new_block_size, stack.block_allocator) or_return + parent.next_block = block + } + + start := cast(uintptr)raw_data(block.buffer) + cast(uintptr)block.offset + padding := calc_padding_with_header(start, cast(uintptr)alignment, size_of(Rollback_Stack_Header)) + + if block.offset + padding + size > len(block.buffer) { + parent = block + continue + } + + header := cast(^Rollback_Stack_Header)(start + cast(uintptr)padding - size_of(Rollback_Stack_Header)) + ptr := (cast([^]byte)(start + cast(uintptr)padding)) + + header^ = { + prev_offset = block.offset, + prev_ptr = max(0, cast(int)(cast(uintptr)block.last_alloc - cast(uintptr)raw_data(block.buffer))), + is_free = false, + } + + block.last_alloc = ptr + block.offset += padding + size + + if len(block.buffer) > stack.block_size { + // This block exceeds the allocator's standard block size and is considered a singleton. + // Prevent any further allocations on it. + block.offset = len(block.buffer) + } + + #no_bounds_check return ptr[:size], nil + } + + return nil, .Out_Of_Memory +} + +@(private="file") +@(require_results) +rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stack_Block, err: Allocator_Error) { + buffer := runtime.mem_alloc(size_of(Rollback_Stack_Block) + size, align_of(Rollback_Stack_Block), allocator) or_return + + block = cast(^Rollback_Stack_Block)raw_data(buffer) + #no_bounds_check block.buffer = buffer[size_of(Rollback_Stack_Block):] + return +} + + +rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte) { + MIN_SIZE :: size_of(Rollback_Stack_Block) + size_of(Rollback_Stack_Header) + size_of(rawptr) + assert(len(buffer) >= MIN_SIZE, "User-provided buffer to Rollback Stack Allocator is too small.") + + block := cast(^Rollback_Stack_Block)raw_data(buffer) + block^ = {} + #no_bounds_check block.buffer = buffer[size_of(Rollback_Stack_Block):] + + stack^ = {} + stack.head = block + stack.block_size = len(block.buffer) +} + +rollback_stack_init_dynamic :: proc( + stack: ^Rollback_Stack, + block_size := ROLLBACK_STACK_DEFAULT_BLOCK_SIZE, + block_allocator := context.allocator, +) -> Allocator_Error { + assert(block_size >= size_of(Rollback_Stack_Header) + size_of(rawptr), "Rollback Stack Allocator block size is too small.") + assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 1 gigabyte.") + + block := rb_make_block(block_size, block_allocator) or_return + + stack^ = {} + stack.head = block + stack.block_size = block_size + stack.block_allocator = block_allocator + + return nil +} + +rollback_stack_init :: proc { + rollback_stack_init_buffered, + rollback_stack_init_dynamic, +} + +rollback_stack_destroy :: proc(stack: ^Rollback_Stack) { + if stack.block_allocator.procedure != nil { + rb_free_all(stack) + free(stack.head, stack.block_allocator) + } + stack^ = {} +} + +@(require_results) +rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator { + return Allocator { + data = stack, + procedure = rollback_stack_allocator_proc, + } +} + +@(require_results) +rollback_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, location := #caller_location, +) -> (result: []byte, err: Allocator_Error) { + stack := cast(^Rollback_Stack)allocator_data + + switch mode { + case .Alloc, .Alloc_Non_Zeroed: + assert(is_power_of_two(cast(uintptr)alignment), "alignment must be a power of two", location) + result = rb_alloc(stack, size, alignment) or_return + + if mode == .Alloc { + zero_slice(result) + } + + case .Free: + err = rb_free(stack, old_memory) + + case .Free_All: + rb_free_all(stack) + + case .Resize, .Resize_Non_Zeroed: + result = rb_resize(stack, old_memory, old_size, size, alignment) or_return + + #no_bounds_check if mode == .Resize && size > old_size { + zero_slice(result[old_size:]) + } + + case .Query_Features: + set := (^Allocator_Mode_Set)(old_memory) + if set != nil { + set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed} + } + return nil, nil + + case .Query_Info: + return nil, .Mode_Not_Implemented + } + + return +} From 95c2e020fff74f8e2e193db595c25726a8b9a99e Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 19:59:49 -0400 Subject: [PATCH 09/93] Share `libc` signal definitions with more platforms I confirmed that these 3 platforms share the same signal definitions from these sources. Haiku: https://github.com/haiku/haiku/blob/master/headers/posix/signal.h OpenBSD: https://github.com/openbsd/src/blob/master/sys/sys/signal.h NetBSD: http://fxr.watson.org/fxr/source/sys/signal.h?v=NETBSD --- core/c/libc/signal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/c/libc/signal.odin b/core/c/libc/signal.odin index 186b74d8c..1489779fe 100644 --- a/core/c/libc/signal.odin +++ b/core/c/libc/signal.odin @@ -34,7 +34,7 @@ when ODIN_OS == .Windows { SIGTERM :: 15 } -when ODIN_OS == .Linux || ODIN_OS == .FreeBSD { +when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { SIG_ERR :: rawptr(~uintptr(0)) SIG_DFL :: rawptr(uintptr(0)) SIG_IGN :: rawptr(uintptr(1)) From b6c4dfb68d5d7d2ac883eaa18409eb8e7d6f2e9c Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 19:44:19 -0400 Subject: [PATCH 10/93] Refactor the test runner Changes - Support multi-threaded testing. - Support `set_fail_timeout` on all platforms. - Display an animated progress report. - Setup all tests with a context logger. - Give all tests their own separate custom allocators. - Support tracking test memory usage. - Display a summary of the failed tests at the end. - Let users select only specific tests to run. - Support copying failed tests to the clipboard to run again. - Support catching SIGINT (CTRL-C) to cancel early. - Record context in cleanup procs. - Write all log messages to STDERR for easy redirection. - Possibly more I've forgotten. New Options - `-define:test_threads=N`: Specify thread count. - `-define:test_thread_memory=B`: Specify initial memory block size in bytes to each thread. - `-define:test_track_memory=true`: Track the memory usage of individual tests. - `-define:test_fancy=false`: Disable animated progress report. - `-define:test_select=package.test_name,...`: Run only select tests. - `-define:test_clipboard=true`: Copy names of failed tests to the clipboard. - `-define:test_progress_width=24`: Change the width of the animated progress bars. --- core/testing/events.odin | 48 ++ core/testing/logging.odin | 71 +++ core/testing/reporting.odin | 312 +++++++++++ core/testing/runner.odin | 692 +++++++++++++++++++++++-- core/testing/signal_handler.odin | 19 + core/testing/signal_handler_other.odin | 11 + core/testing/testing.odin | 59 ++- 7 files changed, 1141 insertions(+), 71 deletions(-) create mode 100644 core/testing/events.odin create mode 100644 core/testing/logging.odin create mode 100644 core/testing/reporting.odin create mode 100644 core/testing/signal_handler.odin create mode 100644 core/testing/signal_handler_other.odin diff --git a/core/testing/events.odin b/core/testing/events.odin new file mode 100644 index 000000000..bab35aaad --- /dev/null +++ b/core/testing/events.odin @@ -0,0 +1,48 @@ +//+private +package testing + +import "base:runtime" +import "core:sync/chan" +import "core:time" + +Test_State :: enum { + Ready, + Running, + Successful, + Failed, +} + +Update_Channel :: chan.Chan(Channel_Event) +Update_Channel_Sender :: chan.Chan(Channel_Event, .Send) + +Task_Channel :: struct { + channel: Update_Channel, + test_index: int, +} + +Event_New_Test :: struct { + test_index: int, +} + +Event_State_Change :: struct { + new_state: Test_State, +} + +Event_Set_Fail_Timeout :: struct { + at_time: time.Time, + location: runtime.Source_Code_Location, +} + +Event_Log_Message :: struct { + level: runtime.Logger_Level, + text: string, + time: time.Time, + formatted_text: string, +} + +Channel_Event :: union { + Event_New_Test, + Event_State_Change, + Event_Set_Fail_Timeout, + Event_Log_Message, +} diff --git a/core/testing/logging.odin b/core/testing/logging.odin new file mode 100644 index 000000000..5bbbffeae --- /dev/null +++ b/core/testing/logging.odin @@ -0,0 +1,71 @@ +//+private +package testing + +import "base:runtime" +import "core:fmt" +import pkg_log "core:log" +import "core:strings" +import "core:sync/chan" +import "core:time" + +Default_Test_Logger_Opts :: runtime.Logger_Options { + .Level, + .Terminal_Color, + .Short_File_Path, + .Line, + .Procedure, + .Date, .Time, +} + +Log_Message :: struct { + level: runtime.Logger_Level, + text: string, + time: time.Time, + // `text` may be allocated differently, depending on where a log message + // originates from. + allocator: runtime.Allocator, +} + +test_logger_proc :: proc(logger_data: rawptr, level: runtime.Logger_Level, text: string, options: runtime.Logger_Options, location := #caller_location) { + t := cast(^T)logger_data + + if level >= .Error { + t.error_count += 1 + } + + cloned_text, clone_error := strings.clone(text, t._log_allocator) + assert(clone_error == nil, "Error while cloning string in test thread logger proc.") + + now := time.now() + + chan.send(t.channel, Event_Log_Message { + level = level, + text = cloned_text, + time = now, + formatted_text = format_log_text(level, text, options, location, now, t._log_allocator), + }) +} + +runner_logger_proc :: proc(logger_data: rawptr, level: runtime.Logger_Level, text: string, options: runtime.Logger_Options, location := #caller_location) { + log_messages := cast(^[dynamic]Log_Message)logger_data + + now := time.now() + + append(log_messages, Log_Message { + level = level, + text = format_log_text(level, text, options, location, now), + time = now, + allocator = context.allocator, + }) +} + +format_log_text :: proc(level: runtime.Logger_Level, text: string, options: runtime.Logger_Options, location: runtime.Source_Code_Location, at_time: time.Time, allocator := context.allocator) -> string{ + backing: [1024]byte + buf := strings.builder_from_bytes(backing[:]) + + pkg_log.do_level_header(options, &buf, level) + pkg_log.do_time_header(options, &buf, at_time) + pkg_log.do_location_header(options, &buf, location) + + return fmt.aprintf("%s%s", strings.to_string(buf), text, allocator = allocator) +} diff --git a/core/testing/reporting.odin b/core/testing/reporting.odin new file mode 100644 index 000000000..d06681c2d --- /dev/null +++ b/core/testing/reporting.odin @@ -0,0 +1,312 @@ +//+private +package testing + +import "base:runtime" +import "core:encoding/ansi" +import "core:fmt" +import "core:io" +import "core:mem" +import "core:path/filepath" +import "core:strings" + +// Definitions of colors for use in the test runner. +SGR_RESET :: ansi.CSI + ansi.RESET + ansi.SGR +SGR_READY :: ansi.CSI + ansi.FG_BRIGHT_BLACK + ansi.SGR +SGR_RUNNING :: ansi.CSI + ansi.FG_YELLOW + ansi.SGR +SGR_SUCCESS :: ansi.CSI + ansi.FG_GREEN + ansi.SGR +SGR_FAILED :: ansi.CSI + ansi.FG_RED + ansi.SGR + +// More than enough bytes to cover long package names, long test names, dozens +// of ANSI codes, et cetera. +LINE_BUFFER_SIZE :: (PROGRESS_WIDTH * 8 + 256) * runtime.Byte + +PROGRESS_COLUMN_SPACING :: 2 + +Package_Run :: struct { + name: string, + header: string, + + frame_ready: bool, + + redraw_buffer: [LINE_BUFFER_SIZE]byte, + redraw_string: string, + + last_change_state: Test_State, + last_change_name: string, + + tests: []Internal_Test, + test_states: []Test_State, +} + +Report :: struct { + packages: []Package_Run, + packages_by_name: map[string]^Package_Run, + + pkg_column_len: int, + test_column_len: int, + + all_tests: []Internal_Test, + all_test_states: []Test_State, +} + +// Organize all tests by package and sort out test state data. +make_report :: proc(internal_tests: []Internal_Test) -> (report: Report, error: runtime.Allocator_Error) { + assert(len(internal_tests) > 0, "make_report called with no tests") + + packages: [dynamic]Package_Run + + report.all_tests = internal_tests + report.all_test_states = make([]Test_State, len(internal_tests)) or_return + + // First, figure out what belongs where. + #no_bounds_check cur_pkg := internal_tests[0].pkg + pkg_start: int + + // This loop assumes the tests are sorted by package already. + for it, index in internal_tests { + if cur_pkg != it.pkg { + #no_bounds_check { + append(&packages, Package_Run { + name = cur_pkg, + tests = report.all_tests[pkg_start:index], + test_states = report.all_test_states[pkg_start:index], + }) or_return + } + + pkg_start = index + report.pkg_column_len = max(report.pkg_column_len, len(cur_pkg)) + cur_pkg = it.pkg + } + report.test_column_len = max(report.test_column_len, len(it.name)) + } + + // Handle the last package. + #no_bounds_check { + append(&packages, Package_Run { + name = cur_pkg, + header = cur_pkg, + tests = report.all_tests[pkg_start:], + test_states = report.all_test_states[pkg_start:], + }) or_return + } + + report.pkg_column_len = PROGRESS_COLUMN_SPACING + max(report.pkg_column_len, len(cur_pkg)) + + shrink(&packages) or_return + + for &pkg in packages { + pkg.header = fmt.aprintf("%- *[1]s[", pkg.name, report.pkg_column_len) + assert(len(pkg.header) > 0, "Error allocating package header string.") + + // This is safe because the array is done resizing, and it has the same + // lifetime as the map. + report.packages_by_name[pkg.name] = &pkg + } + + // It's okay to discard the dynamic array's allocator information here, + // because its capacity has been shrunk to its length, it was allocated by + // the caller's context allocator, and it will be deallocated by the same. + // + // `delete_slice` is equivalent to `delete_dynamic_array` in this case. + report.packages = packages[:] + + return +} + +destroy_report :: proc(report: ^Report) { + for pkg in report.packages { + delete(pkg.header) + } + + delete(report.packages) + delete(report.packages_by_name) + delete(report.all_test_states) +} + +redraw_package :: proc(w: io.Writer, pkg: ^Package_Run) { + if pkg.frame_ready { + io.write_string(w, pkg.redraw_string) + return + } + + // Write the output line here so we can cache it. + line_builder := strings.builder_from_bytes(pkg.redraw_buffer[:]) + line_writer := strings.to_writer(&line_builder) + + highest_run_index: int + failed_count: int + done_count: int + #no_bounds_check for i := 0; i < len(pkg.test_states); i += 1 { + switch pkg.test_states[i] { + case .Ready: + continue + case .Running: + highest_run_index = max(highest_run_index, i) + case .Successful: + done_count += 1 + case .Failed: + failed_count += 1 + done_count += 1 + } + } + + start := max(0, highest_run_index - (PROGRESS_WIDTH - 1)) + end := min(start + PROGRESS_WIDTH, len(pkg.test_states)) + + // This variable is to keep track of the last ANSI code emitted, in + // order to avoid repeating the same code over in a sequence. + // + // This should help reduce screen flicker. + last_state := Test_State(-1) + + io.write_string(line_writer, pkg.header) + + #no_bounds_check for state in pkg.test_states[start:end] { + switch state { + case .Ready: + if last_state != state { + io.write_string(line_writer, SGR_READY) + last_state = state + } + case .Running: + if last_state != state { + io.write_string(line_writer, SGR_RUNNING) + last_state = state + } + case .Successful: + if last_state != state { + io.write_string(line_writer, SGR_SUCCESS) + last_state = state + } + case .Failed: + if last_state != state { + io.write_string(line_writer, SGR_FAILED) + last_state = state + } + } + io.write_byte(line_writer, '|') + } + + for _ in 0 ..< PROGRESS_WIDTH - (end - start) { + io.write_byte(line_writer, ' ') + } + + io.write_string(line_writer, SGR_RESET + "] ") + + ticker: string + if done_count == len(pkg.test_states) { + ticker = "[package done]" + if failed_count > 0 { + ticker = fmt.tprintf("%s (" + SGR_FAILED + "%i" + SGR_RESET + " failed)", ticker, failed_count) + } + } else { + if len(pkg.last_change_name) == 0 { + #no_bounds_check pkg.last_change_name = pkg.tests[0].name + } + + switch pkg.last_change_state { + case .Ready: + ticker = fmt.tprintf(SGR_READY + "%s" + SGR_RESET, pkg.last_change_name) + case .Running: + ticker = fmt.tprintf(SGR_RUNNING + "%s" + SGR_RESET, pkg.last_change_name) + case .Failed: + ticker = fmt.tprintf(SGR_FAILED + "%s" + SGR_RESET, pkg.last_change_name) + case .Successful: + ticker = fmt.tprintf(SGR_SUCCESS + "%s" + SGR_RESET, pkg.last_change_name) + } + } + + if done_count == len(pkg.test_states) { + fmt.wprintfln(line_writer, " % 4i :: %s", + len(pkg.test_states), + ticker, + ) + } else { + fmt.wprintfln(line_writer, "% 4i/% 4i :: %s", + done_count, + len(pkg.test_states), + ticker, + ) + } + + pkg.redraw_string = strings.to_string(line_builder) + pkg.frame_ready = true + io.write_string(w, pkg.redraw_string) +} + +redraw_report :: proc(w: io.Writer, report: Report) { + // If we print a line longer than the user's terminal can handle, it may + // wrap around, shifting the progress report out of alignment. + // + // There are ways to get the current terminal width, and that would be the + // ideal way to handle this, but it would require system-specific code such + // as setting STDIN to be non-blocking in order to read the response from + // the ANSI DSR escape code, or reading environment variables. + // + // The DECAWM escape codes control whether or not the terminal will wrap + // long lines or overwrite the last visible character. + // This should be fine for now. + // + // Note that we only do this for the animated summary; log messages are + // still perfectly fine to wrap, as they're printed in their own batch, + // whereas the animation depends on each package being only on one line. + // + // Of course, if you resize your terminal while it's printing, things can + // still break... + fmt.wprint(w, ansi.CSI + ansi.DECAWM_OFF) + for &pkg in report.packages { + redraw_package(w, &pkg) + } + fmt.wprint(w, ansi.CSI + ansi.DECAWM_ON) +} + +needs_to_redraw :: proc(report: Report) -> bool { + for pkg in report.packages { + if !pkg.frame_ready { + return true + } + } + + return false +} + +draw_status_bar :: proc(w: io.Writer, threads_string: string, total_done_count, total_test_count: int) { + if total_done_count != total_test_count { + fmt.wprintfln(w, + "%s % 4i/% 4i :: total", + threads_string, + total_done_count, + total_test_count) + } +} + +write_memory_report :: proc(w: io.Writer, tracker: ^mem.Tracking_Allocator, pkg, name: string) { + fmt.wprintf(w, + "<% 10M/% 10M> <% 10M> (% 5i/% 5i) :: %s.%s", + tracker.current_memory_allocated, + tracker.total_memory_allocated, + tracker.peak_memory_allocated, + tracker.total_free_count, + tracker.total_allocation_count, + pkg, + name) + + for ptr, entry in tracker.allocation_map { + fmt.wprintf(w, + "\n +++ leak % 10M @ %p [%s:%i:%s()]", + entry.size, + ptr, + filepath.base(entry.location.file_path), + entry.location.line, + entry.location.procedure) + } + + for entry in tracker.bad_free_array { + fmt.wprintf(w, + "\n +++ bad free @ %p [%s:%i:%s()]", + entry.memory, + filepath.base(entry.location.file_path), + entry.location.line, + entry.location.procedure) + } +} diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 0039f1939..ce5aa112a 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -1,73 +1,675 @@ //+private package testing +import "base:intrinsics" +import "base:runtime" +import "core:bytes" +import "core:encoding/ansi" +import "core:encoding/base64" +import "core:fmt" import "core:io" +import pkg_log "core:log" +import "core:mem" import "core:os" import "core:slice" +import "core:strings" +import "core:sync/chan" +import "core:thread" +import "core:time" + +// Keep `-vet` happy. +base64_encode :: base64.encode +_ :: pkg_log +_ :: strings + +// Specify how many threads to use when running tests. +TEST_THREADS : int : #config(test_threads, 0) +// Track the memory used by each test. +TRACKING_MEMORY : bool : #config(test_track_memory, false) +// Specify how much memory each thread allocator starts with. +PER_THREAD_MEMORY : int : #config(test_thread_memory, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) +// Select a specific set of tests to run by name. +TEST_SELECT : string : #config(test_select, "") +// Show the fancy animated progress report. +FANCY_OUTPUT : bool : #config(test_fancy, true) +// Copy failed tests to the clipboard when done. +USE_CLIPBOARD : bool : #config(test_clipboard, false) +// How many test results to show at a time per package. +PROGRESS_WIDTH : int : #config(test_progress_width, 24) + -reset_t :: proc(t: ^T) { - clear(&t.cleanups) - t.error_count = 0 -} end_t :: proc(t: ^T) { for i := len(t.cleanups)-1; i >= 0; i -= 1 { - c := t.cleanups[i] + #no_bounds_check c := t.cleanups[i] + context = c.ctx c.procedure(c.user_data) } + + delete(t.cleanups) + t.cleanups = {} +} + +Task_Data :: struct { + it: Internal_Test, + t: T, + allocator_index: int, +} + +Task_Timeout :: struct { + test_index: int, + at_time: time.Time, + location: runtime.Source_Code_Location, +} + +run_test_task :: proc(task: thread.Task) { + data := cast(^Task_Data)(task.data) + + chan.send(data.t.channel, Event_New_Test { + test_index = task.user_index, + }) + + chan.send(data.t.channel, Event_State_Change { + new_state = .Running, + }) + + context.logger = { + procedure = test_logger_proc, + data = &data.t, + lowest_level = .Debug if ODIN_DEBUG else .Info, + options = Default_Test_Logger_Opts, + } + + free_all(context.temp_allocator) + + run_internal_test(&data.t, data.it) + + end_t(&data.t) + + new_state : Test_State = .Failed if failed(&data.t) else .Successful + + chan.send(data.t.channel, Event_State_Change { + new_state = new_state, + }) } runner :: proc(internal_tests: []Internal_Test) -> bool { - stream := os.stream_from_handle(os.stdout) - w := io.to_writer(stream) + BATCH_BUFFER_SIZE :: 32 * mem.Kilobyte + POOL_BLOCK_SIZE :: 16 * mem.Kilobyte + CLIPBOARD_BUFFER_SIZE :: 16 * mem.Kilobyte - t := &T{} - t.w = w - reserve(&t.cleanups, 1024) - defer delete(t.cleanups) + BUFFERED_EVENTS_PER_CHANNEL :: 16 + RESERVED_LOG_MESSAGES :: 64 + RESERVED_TEST_FAILURES :: 64 - total_success_count := 0 - total_test_count := len(internal_tests) + ERROR_STRING_TIMEOUT : string : "Test timed out." + ERROR_STRING_UNKNOWN : string : "Test failed for unknown reasons." + OSC_WINDOW_TITLE : string : ansi.OSC + ansi.WINDOW_TITLE + ";Odin test runner (%i/%i)" + ansi.ST - slice.sort_by(internal_tests, proc(a, b: Internal_Test) -> bool { - if a.pkg < b.pkg { - return true + safe_delete_string :: proc(s: string, allocator := context.allocator) { + // Guard against bad frees on static strings. + switch raw_data(s) { + case raw_data(ERROR_STRING_TIMEOUT), raw_data(ERROR_STRING_UNKNOWN): + return + case: + delete(s, allocator) } - return a.name < b.name - }) + } - prev_pkg := "" + stdout := io.to_writer(os.stream_from_handle(os.stdout)) + stderr := io.to_writer(os.stream_from_handle(os.stderr)) + + // -- Prepare test data. + + alloc_error: mem.Allocator_Error + + when TEST_SELECT != "" { + select_internal_tests: [dynamic]Internal_Test + defer delete(select_internal_tests) + + { + index_list := TEST_SELECT + for selector in strings.split_iterator(&index_list, ",") { + // Temp allocator is fine since we just need to identify which test it's referring to. + split_selector := strings.split(selector, ".", context.temp_allocator) + + found := false + switch len(split_selector) { + case 1: + // Only the test name? + #no_bounds_check name := split_selector[0] + find_test_by_name: for it in internal_tests { + if it.name == name { + found = true + _, alloc_error = append(&select_internal_tests, it) + fmt.assertf(alloc_error == nil, "Error appending to select internal tests: %v", alloc_error) + break find_test_by_name + } + } + case 2: + #no_bounds_check pkg := split_selector[0] + #no_bounds_check name := split_selector[1] + find_test_by_pkg_and_name: for it in internal_tests { + if it.pkg == pkg && it.name == name { + found = true + _, alloc_error = append(&select_internal_tests, it) + fmt.assertf(alloc_error == nil, "Error appending to select internal tests: %v", alloc_error) + break find_test_by_pkg_and_name + } + } + } + if !found { + fmt.wprintfln(stderr, "No test found for the name: %q", selector) + } + } + } + + // Intentional shadow with user-specified tests. + internal_tests := select_internal_tests[:] + } + + total_failure_count := 0 + total_success_count := 0 + total_done_count := 0 + total_test_count := len(internal_tests) + + when !FANCY_OUTPUT { + // This is strictly for updating the window title when the progress + // report is disabled. We're otherwise able to depend on the call to + // `needs_to_redraw`. + last_done_count := -1 + } + + if total_test_count == 0 { + // Exit early. + fmt.wprintln(stdout, "No tests to run.") + return true + } for it in internal_tests { - if it.p == nil { - total_test_count -= 1 - continue - } + // NOTE(Feoramund): The old test runner skipped over tests with nil + // procedures, but I couldn't find any case where they occurred. + // This assert stands to prevent any oversight on my part. + fmt.assertf(it.p != nil, "Test %s.%s has procedure.", it.pkg, it.name) + } - free_all(context.temp_allocator) - reset_t(t) - defer end_t(t) - - if prev_pkg != it.pkg { - prev_pkg = it.pkg - logf(t, "[Package: %s]", it.pkg) - } - - logf(t, "[Test: %s]", it.name) - - run_internal_test(t, it) - - if failed(t) { - logf(t, "[%s : FAILURE]", it.name) + slice.stable_sort_by(internal_tests, proc(a, b: Internal_Test) -> bool { + if a.pkg == b.pkg { + return a.name < b.name } else { - logf(t, "[%s : SUCCESS]", it.name) - total_success_count += 1 + return a.pkg < b.pkg + } + }) + + // -- Set thread count. + + when TEST_THREADS == 0 { + thread_count := os.processor_core_count() + } else { + thread_count := max(1, TEST_THREADS) + } + + thread_count = min(thread_count, total_test_count) + + // -- Allocate. + + pool_stack: mem.Rollback_Stack + alloc_error = mem.rollback_stack_init(&pool_stack, POOL_BLOCK_SIZE) + fmt.assertf(alloc_error == nil, "Error allocating memory for thread pool: %v", alloc_error) + defer mem.rollback_stack_destroy(&pool_stack) + + pool: thread.Pool + thread.pool_init(&pool, mem.rollback_stack_allocator(&pool_stack), thread_count) + defer thread.pool_destroy(&pool) + + task_channels: []Task_Channel = --- + task_channels, alloc_error = make([]Task_Channel, thread_count) + fmt.assertf(alloc_error == nil, "Error allocating memory for update channels: %v", alloc_error) + defer delete(task_channels) + + for &task_channel, index in task_channels { + task_channel.channel, alloc_error = chan.create_buffered(Update_Channel, BUFFERED_EVENTS_PER_CHANNEL, context.allocator) + fmt.assertf(alloc_error == nil, "Error allocating memory for update channel #%i: %v", index, alloc_error) + } + defer for &task_channel in task_channels { + chan.destroy(&task_channel.channel) + } + + // This buffer is used to batch writes to STDOUT or STDERR, to help reduce + // screen flickering. + batch_buffer: bytes.Buffer + bytes.buffer_init_allocator(&batch_buffer, 0, BATCH_BUFFER_SIZE) + batch_writer := io.to_writer(bytes.buffer_to_stream(&batch_buffer)) + defer bytes.buffer_destroy(&batch_buffer) + + report: Report = --- + report, alloc_error = make_report(internal_tests) + fmt.assertf(alloc_error == nil, "Error allocating memory for test report: %v", alloc_error) + defer destroy_report(&report) + + when FANCY_OUTPUT { + // We cannot make use of the ANSI save/restore cursor codes, because they + // work by absolute screen coordinates. This will cause unnecessary + // scrollback if we print at the bottom of someone's terminal. + ansi_redraw_string := fmt.aprintf( + // ANSI for "go up N lines then erase the screen from the cursor forward." + ansi.CSI + "%i" + ansi.CPL + ansi.CSI + ansi.ED + + // We'll combine this with the window title format string, since it + // can be printed at the same time. + "%s", + // 1 extra line for the status bar. + 1 + len(report.packages), OSC_WINDOW_TITLE) + assert(len(ansi_redraw_string) > 0, "Error allocating ANSI redraw string.") + defer delete(ansi_redraw_string) + + thread_count_status_string: string = --- + { + PADDING :: PROGRESS_COLUMN_SPACING + PROGRESS_WIDTH + + unpadded := fmt.tprintf("%i thread%s", thread_count, "" if thread_count == 1 else "s") + thread_count_status_string = fmt.aprintf("%- *[1]s", unpadded, report.pkg_column_len + PADDING) + assert(len(thread_count_status_string) > 0, "Error allocating thread count status string.") + } + defer delete(thread_count_status_string) + } + + task_data_slots: []Task_Data = --- + task_data_slots, alloc_error = make([]Task_Data, thread_count) + fmt.assertf(alloc_error == nil, "Error allocating memory for task data slots: %v", alloc_error) + defer delete(task_data_slots) + + safe_heap: mem.Mutex_Allocator + mem.mutex_allocator_init(&safe_heap, context.allocator) + safe_heap_allocator := mem.mutex_allocator(&safe_heap) + + // Tests rotate through these allocators as they finish. + task_allocators: []mem.Rollback_Stack = --- + task_allocators, alloc_error = make([]mem.Rollback_Stack, thread_count) + fmt.assertf(alloc_error == nil, "Error allocating memory for task allocators: %v", alloc_error) + defer delete(task_allocators) + + when TRACKING_MEMORY { + task_memory_trackers: []mem.Tracking_Allocator = --- + task_memory_trackers, alloc_error = make([]mem.Tracking_Allocator, thread_count) + fmt.assertf(alloc_error == nil, "Error allocating memory for memory trackers: %v", alloc_error) + defer delete(task_memory_trackers) + } + + #no_bounds_check for i in 0 ..< thread_count { + alloc_error = mem.rollback_stack_init(&task_allocators[i], PER_THREAD_MEMORY, block_allocator = safe_heap_allocator) + fmt.assertf(alloc_error == nil, "Error allocating memory for task allocator #%i: %v", i, alloc_error) + when TRACKING_MEMORY { + mem.tracking_allocator_init(&task_memory_trackers[i], mem.rollback_stack_allocator(&task_allocators[i])) } } - logf(t, "----------------------------------------") - if total_test_count == 0 { - log(t, "NO TESTS RAN") - } else { - logf(t, "%d/%d SUCCESSFUL", total_success_count, total_test_count) + + defer #no_bounds_check for i in 0 ..< thread_count { + when TRACKING_MEMORY { + mem.tracking_allocator_destroy(&task_memory_trackers[i]) + } + mem.rollback_stack_destroy(&task_allocators[i]) } + + task_timeouts: [dynamic]Task_Timeout = --- + task_timeouts, alloc_error = make([dynamic]Task_Timeout, 0, thread_count) + fmt.assertf(alloc_error == nil, "Error allocating memory for task timeouts: %v", alloc_error) + defer delete(task_timeouts) + + failed_test_reason_map: map[int]string = --- + failed_test_reason_map, alloc_error = make(map[int]string, RESERVED_TEST_FAILURES) + fmt.assertf(alloc_error == nil, "Error allocating memory for failed test reasons: %v", alloc_error) + defer delete(failed_test_reason_map) + + log_messages: [dynamic]Log_Message = --- + log_messages, alloc_error = make([dynamic]Log_Message, 0, RESERVED_LOG_MESSAGES) + fmt.assertf(alloc_error == nil, "Error allocating memory for log message queue: %v", alloc_error) + defer delete(log_messages) + + sorted_failed_test_reasons: [dynamic]int = --- + sorted_failed_test_reasons, alloc_error = make([dynamic]int, 0, RESERVED_TEST_FAILURES) + fmt.assertf(alloc_error == nil, "Error allocating memory for sorted failed test reasons: %v", alloc_error) + defer delete(sorted_failed_test_reasons) + + when USE_CLIPBOARD { + clipboard_buffer: bytes.Buffer + bytes.buffer_init_allocator(&clipboard_buffer, 0, CLIPBOARD_BUFFER_SIZE) + defer bytes.buffer_destroy(&clipboard_buffer) + } + + // -- Setup initial tasks. + + // NOTE(Feoramund): This is the allocator that will be used by threads to + // persist log messages past their lifetimes. It has its own variable name + // in the event it needs to be changed from `safe_heap_allocator` without + // digging through the source to divine everywhere it is used for that. + shared_log_allocator := safe_heap_allocator + + context.allocator = safe_heap_allocator + + context.logger = { + procedure = runner_logger_proc, + data = &log_messages, + lowest_level = .Debug if ODIN_DEBUG else .Info, + options = Default_Test_Logger_Opts - {.Short_File_Path, .Line, .Procedure}, + } + + run_index: int + + setup_tasks: for &data, task_index in task_data_slots { + setup_next_test: for run_index < total_test_count { + #no_bounds_check it := internal_tests[run_index] + defer run_index += 1 + + data.it = it + #no_bounds_check data.t.channel = chan.as_send(task_channels[task_index].channel) + data.t._log_allocator = shared_log_allocator + data.allocator_index = task_index + + #no_bounds_check when TRACKING_MEMORY { + task_allocator := mem.tracking_allocator(&task_memory_trackers[task_index]) + } else { + task_allocator := mem.rollback_stack_allocator(&task_allocators[task_index]) + } + + thread.pool_add_task(&pool, task_allocator, run_test_task, &data, run_index) + + continue setup_tasks + } + } + + // -- Run tests. + + setup_signal_handler() + + fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_HIDE) + + when FANCY_OUTPUT { + redraw_report(stdout, report) + draw_status_bar(stdout, thread_count_status_string, total_done_count, total_test_count) + } + + when TRACKING_MEMORY { + pkg_log.info("Memory tracking is enabled. Tests will log their memory usage when complete.") + pkg_log.info("< Final Mem/ Total Mem> < Peak Mem> (#Free/Alloc) :: [package.test_name]") + } + + start_time := time.now() + + thread.pool_start(&pool) + main_loop: for !thread.pool_is_empty(&pool) { + + cycle_pool: for task in thread.pool_pop_done(&pool) { + data := cast(^Task_Data)(task.data) + + when TRACKING_MEMORY { + #no_bounds_check tracker := &task_memory_trackers[data.allocator_index] + + write_memory_report(batch_writer, tracker, data.it.pkg, data.it.name) + + pkg_log.info(bytes.buffer_to_string(&batch_buffer)) + bytes.buffer_reset(&batch_buffer) + + mem.tracking_allocator_reset(tracker) + } + + free_all(task.allocator) + + if run_index < total_test_count { + #no_bounds_check it := internal_tests[run_index] + defer run_index += 1 + + data.it = it + data.t.error_count = 0 + + thread.pool_add_task(&pool, task.allocator, run_test_task, data, run_index) + } + } + + handle_events: for &task_channel in task_channels { + for ev in chan.try_recv(task_channel.channel) { + switch event in ev { + case Event_New_Test: + task_channel.test_index = event.test_index + + case Event_State_Change: + #no_bounds_check report.all_test_states[task_channel.test_index] = event.new_state + + #no_bounds_check it := internal_tests[task_channel.test_index] + #no_bounds_check pkg := report.packages_by_name[it.pkg] + + #partial switch event.new_state { + case .Failed: + if task_channel.test_index not_in failed_test_reason_map { + failed_test_reason_map[task_channel.test_index] = ERROR_STRING_UNKNOWN + } + total_failure_count += 1 + total_done_count += 1 + case .Successful: + total_success_count += 1 + total_done_count += 1 + } + + when ODIN_DEBUG { + pkg_log.debugf("Test #%i %s.%s changed state to %v.", task_channel.test_index, it.pkg, it.name, event.new_state) + } + + pkg.last_change_state = event.new_state + pkg.last_change_name = it.name + pkg.frame_ready = false + + case Event_Set_Fail_Timeout: + _, alloc_error = append(&task_timeouts, Task_Timeout { + test_index = task_channel.test_index, + at_time = event.at_time, + location = event.location, + }) + fmt.assertf(alloc_error == nil, "Error appending to task timeouts: %v", alloc_error) + + case Event_Log_Message: + _, alloc_error = append(&log_messages, Log_Message { + level = event.level, + text = event.formatted_text, + time = event.time, + allocator = shared_log_allocator, + }) + fmt.assertf(alloc_error == nil, "Error appending to log messages: %v", alloc_error) + + if event.level >= .Error { + // Save the message for the final summary. + if old_error, ok := failed_test_reason_map[task_channel.test_index]; ok { + safe_delete_string(old_error, shared_log_allocator) + } + failed_test_reason_map[task_channel.test_index] = event.text + } else { + delete(event.text, shared_log_allocator) + } + } + } + } + + check_timeouts: for i := len(task_timeouts) - 1; i >= 0; i -= 1 { + #no_bounds_check timeout := &task_timeouts[i] + + if time.since(timeout.at_time) < 0 { + continue check_timeouts + } + + defer unordered_remove(&task_timeouts, i) + + #no_bounds_check if report.all_test_states[timeout.test_index] > .Running { + continue check_timeouts + } + + if !thread.pool_stop_task(&pool, timeout.test_index) { + // The task may have stopped a split second after we started + // checking, but we haven't handled the new state yet. + continue check_timeouts + } + + #no_bounds_check report.all_test_states[timeout.test_index] = .Failed + #no_bounds_check it := internal_tests[timeout.test_index] + #no_bounds_check pkg := report.packages_by_name[it.pkg] + pkg.frame_ready = false + + if old_error, ok := failed_test_reason_map[timeout.test_index]; ok { + safe_delete_string(old_error, shared_log_allocator) + } + failed_test_reason_map[timeout.test_index] = ERROR_STRING_TIMEOUT + total_failure_count += 1 + total_done_count += 1 + + now := time.now() + _, alloc_error = append(&log_messages, Log_Message { + level = .Error, + text = format_log_text(.Error, ERROR_STRING_TIMEOUT, Default_Test_Logger_Opts, timeout.location, now), + time = now, + allocator = context.allocator, + }) + fmt.assertf(alloc_error == nil, "Error appending to log messages: %v", alloc_error) + + find_task_data: for &data in task_data_slots { + if data.it.pkg == it.pkg && data.it.name == it.name { + end_t(&data.t) + break find_task_data + } + } + } + + if should_abort() { + fmt.wprintln(stderr, "\nCaught interrupt signal. Stopping all tests.") + thread.pool_shutdown(&pool) + break main_loop + } + + // -- Redraw. + + when FANCY_OUTPUT { + if len(log_messages) == 0 && !needs_to_redraw(report) { + continue main_loop + } + + fmt.wprintf(stdout, ansi_redraw_string, total_done_count, total_test_count) + } else { + if total_done_count != last_done_count { + fmt.wprintf(stdout, OSC_WINDOW_TITLE, total_done_count, total_test_count) + last_done_count = total_done_count + } + + if len(log_messages) == 0 { + continue main_loop + } + } + + // Because each thread has its own messenger channel, log messages + // arrive in chunks that are in-order, but when they're merged with the + // logs from other threads, they become out-of-order. + slice.stable_sort_by(log_messages[:], proc(a, b: Log_Message) -> bool { + return time.diff(a.time, b.time) > 0 + }) + + for message in log_messages { + fmt.wprintln(batch_writer, message.text) + delete(message.text, message.allocator) + } + + fmt.wprint(stderr, bytes.buffer_to_string(&batch_buffer)) + clear(&log_messages) + bytes.buffer_reset(&batch_buffer) + + when FANCY_OUTPUT { + redraw_report(batch_writer, report) + draw_status_bar(batch_writer, thread_count_status_string, total_done_count, total_test_count) + fmt.wprint(stdout, bytes.buffer_to_string(&batch_buffer)) + bytes.buffer_reset(&batch_buffer) + } + } + + // -- All tests are complete, or the runner has been interrupted. + + thread.pool_join(&pool) + + finished_in := time.since(start_time) + + fmt.wprintf(batch_writer, + "\nFinished %i test%s in %v.", + total_done_count, + "" if total_done_count == 1 else "s", + finished_in) + + if total_done_count != total_test_count { + not_run_count := total_test_count - total_done_count + fmt.wprintf(batch_writer, + " " + SGR_READY + "%i" + SGR_RESET + " %s left undone.", + not_run_count, + "test was" if not_run_count == 1 else "tests were") + } + + if total_success_count == total_test_count { + fmt.wprintfln(batch_writer, + " %s " + SGR_SUCCESS + "successful." + SGR_RESET, + "The test was" if total_test_count == 1 else "All tests were") + } else if total_failure_count > 0 { + if total_failure_count == total_test_count { + fmt.wprintfln(batch_writer, + " %s " + SGR_FAILED + "failed." + SGR_RESET, + "The test" if total_test_count == 1 else "All tests") + } else { + fmt.wprintfln(batch_writer, + " " + SGR_FAILED + "%i" + SGR_RESET + " test%s failed.", + total_failure_count, + "" if total_failure_count == 1 else "s") + } + + for test_index in failed_test_reason_map { + _, alloc_error = append(&sorted_failed_test_reasons, test_index) + fmt.assertf(alloc_error == nil, "Error appending to sorted failed test reasons: %v", alloc_error) + } + + slice.sort(sorted_failed_test_reasons[:]) + + for test_index in sorted_failed_test_reasons { + #no_bounds_check last_error := failed_test_reason_map[test_index] + #no_bounds_check it := internal_tests[test_index] + pkg_and_name := fmt.tprintf("%s.%s", it.pkg, it.name) + fmt.wprintfln(batch_writer, " - %- *[1]s\t%s", + pkg_and_name, + report.pkg_column_len + report.test_column_len, + last_error) + safe_delete_string(last_error, shared_log_allocator) + } + + if total_success_count > 0 { + when USE_CLIPBOARD { + clipboard_writer := io.to_writer(bytes.buffer_to_stream(&clipboard_buffer)) + fmt.wprint(clipboard_writer, "-define:test_select=") + for test_index in sorted_failed_test_reasons { + #no_bounds_check it := internal_tests[test_index] + fmt.wprintf(clipboard_writer, "%s.%s,", it.pkg, it.name) + } + + encoded_names := base64_encode(bytes.buffer_to_bytes(&clipboard_buffer), allocator = context.temp_allocator) + + fmt.wprintf(batch_writer, + ansi.OSC + ansi.CLIPBOARD + ";c;%s" + ansi.ST + + "\nThe name%s of the failed test%s been copied to your clipboard.", + encoded_names, + "" if total_failure_count == 1 else "s", + " has" if total_failure_count == 1 else "s have") + } else { + fmt.wprintf(batch_writer, "\nTo run only the failed test%s, use:\n\t-define:test_select=", + "" if total_failure_count == 1 else "s") + for test_index in sorted_failed_test_reasons { + #no_bounds_check it := internal_tests[test_index] + fmt.wprintf(batch_writer, "%s.%s,", it.pkg, it.name) + } + } + + fmt.wprintln(batch_writer) + } + } + + fmt.wprint(batch_writer, ansi.CSI + ansi.DECTCEM_SHOW) + + fmt.wprintln(stderr, bytes.buffer_to_string(&batch_buffer)) + return total_success_count == total_test_count } diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler.odin new file mode 100644 index 000000000..2dd0ff192 --- /dev/null +++ b/core/testing/signal_handler.odin @@ -0,0 +1,19 @@ +//+private +//+build windows, linux, darwin, freebsd, openbsd, netbsd, haiku +package testing + +import "base:intrinsics" +import "core:c/libc" + +@(private="file") +abort_flag: libc.sig_atomic_t + +setup_signal_handler :: proc() { + libc.signal(libc.SIGINT, proc "c" (sig: libc.int) { + intrinsics.atomic_add(&abort_flag, 1) + }) +} + +should_abort :: proc() -> bool { + return intrinsics.atomic_load(&abort_flag) > 0 +} diff --git a/core/testing/signal_handler_other.odin b/core/testing/signal_handler_other.odin new file mode 100644 index 000000000..b2e2ea906 --- /dev/null +++ b/core/testing/signal_handler_other.odin @@ -0,0 +1,11 @@ +//+private +//+build js, wasi, freestanding +package testing + +setup_signal_handler :: proc() { + // Do nothing. +} + +should_abort :: proc() -> bool { + return false +} diff --git a/core/testing/testing.odin b/core/testing/testing.odin index a8c5ffa48..30109304d 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -1,10 +1,11 @@ package testing -import "core:fmt" -import "core:io" -import "core:time" import "base:intrinsics" +import "base:runtime" +import pkg_log "core:log" import "core:reflect" +import "core:sync/chan" +import "core:time" _ :: reflect // alias reflect to nothing to force visibility for -vet @@ -22,44 +23,45 @@ Internal_Test :: struct { Internal_Cleanup :: struct { procedure: proc(rawptr), user_data: rawptr, + ctx: runtime.Context, } T :: struct { error_count: int, - w: io.Writer, + channel: Update_Channel_Sender, cleanups: [dynamic]Internal_Cleanup, + // This allocator is shared between the test runner and its threads for + // cloning log strings, so they can outlive the lifetime of individual + // tests during channel transmission. + _log_allocator: runtime.Allocator, + _fail_now: proc() -> !, } +@(deprecated="prefer `log.error`") error :: proc(t: ^T, args: ..any, loc := #caller_location) { - fmt.wprintf(t.w, "%v: ", loc) - fmt.wprintln(t.w, ..args) - t.error_count += 1 + pkg_log.error(..args, location = loc) } +@(deprecated="prefer `log.errorf`") errorf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { - fmt.wprintf(t.w, "%v: ", loc) - fmt.wprintf(t.w, format, ..args) - fmt.wprintln(t.w) - t.error_count += 1 + pkg_log.errorf(format, ..args, location = loc) } fail :: proc(t: ^T, loc := #caller_location) { - error(t, "FAIL", loc=loc) - t.error_count += 1 + pkg_log.error("FAIL", location=loc) } fail_now :: proc(t: ^T, msg := "", loc := #caller_location) { if msg != "" { - error(t, "FAIL:", msg, loc=loc) + pkg_log.error("FAIL:", msg, location=loc) } else { - error(t, "FAIL", loc=loc) + pkg_log.error("FAIL", location=loc) } - t.error_count += 1 if t._fail_now != nil { t._fail_now() } @@ -69,32 +71,34 @@ failed :: proc(t: ^T) -> bool { return t.error_count != 0 } +@(deprecated="prefer `log.info`") log :: proc(t: ^T, args: ..any, loc := #caller_location) { - fmt.wprintln(t.w, ..args) + pkg_log.info(..args, location = loc) } +@(deprecated="prefer `log.infof`") logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { - fmt.wprintf(t.w, format, ..args) - fmt.wprintln(t.w) + pkg_log.infof(format, ..args, location = loc) } -// cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete -// cleanup procedures will be called in LIFO (last added, first called) order. +// cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete. +// Cleanup procedures will be called in LIFO (last added, first called) order. +// Each procedure will use a copy of the context at the time of registering. 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, context}) } expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool { if !ok { - error(t, msg, loc=loc) + pkg_log.error(msg, location=loc) } return ok } expectf :: proc(t: ^T, ok: bool, format: string, args: ..any, loc := #caller_location) -> bool { if !ok { - errorf(t, format, ..args, loc=loc) + pkg_log.errorf(format, ..args, location=loc) } return ok } @@ -102,12 +106,15 @@ expectf :: proc(t: ^T, ok: bool, format: string, args: ..any, loc := #caller_loc expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) if !ok { - errorf(t, "expected %v, got %v", expected, value, loc=loc) + pkg_log.errorf("expected %v, got %v", expected, value, location=loc) } return ok } set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) { - _fail_timeout(t, duration, loc) + chan.send(t.channel, Event_Set_Fail_Timeout { + at_time = time.time_add(time.now(), duration), + location = loc, + }) } From d03024088aec0238ed236dd02987f8f8e8734958 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 20:04:49 -0400 Subject: [PATCH 11/93] Remove unneeded code --- core/testing/runner_other.odin | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/testing/runner_other.odin b/core/testing/runner_other.odin index f3271d209..29f338828 100644 --- a/core/testing/runner_other.odin +++ b/core/testing/runner_other.odin @@ -2,13 +2,7 @@ //+build !windows package testing -import "core:time" - run_internal_test :: proc(t: ^T, it: Internal_Test) { // TODO(bill): Catch panics on other platforms it.p(t) } - -_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) { - -} \ No newline at end of file From 87ea4a2652e99f44a286fe6328659fe7e6e5f7b9 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 20:05:43 -0400 Subject: [PATCH 12/93] Temporarily disable Windows-specific test runner I do not have a Windows machine to test the refactored test runner, and I am unsure if it would even run correctly on Windows without this disabled. --- core/testing/runner_windows.odin | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin index 15264355b..23dab4f31 100644 --- a/core/testing/runner_windows.odin +++ b/core/testing/runner_windows.odin @@ -2,6 +2,12 @@ //+build windows package testing +run_internal_test :: proc(t: ^T, it: Internal_Test) { + it.p(t) +} + +// Temporarily disabled during multi-threaded test runner refactor. +/* import win32 "core:sys/windows" import "base:runtime" import "base:intrinsics" @@ -233,3 +239,4 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) { return } +*/ From 852f694bee4469c009cb02a850e02fe1c7165477 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 27 May 2024 20:42:35 -0400 Subject: [PATCH 13/93] Get tests passing again `T` no longer has a writer assigned to it. `test_core_cbor.odin` has global state and is run with `odin test`, so I've set it to use only one thread. --- tests/core/build.bat | 2 +- tests/core/compress/test_core_compress.odin | 8 ++++---- tests/core/text/match/test_core_text_match.odin | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/core/build.bat b/tests/core/build.bat index 7871e52e2..4755e0a44 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -25,7 +25,7 @@ rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe | %PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b -%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe || exit /b +%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe -define:test_threads=1 -define:test_fancy=false || exit /b %PATH_TO_ODIN% run encoding/hex %COMMON% -out:test_hex.exe || exit /b %PATH_TO_ODIN% run encoding/base64 %COMMON% -out:test_base64.exe || exit /b diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index ac7555e9a..db6f3d06b 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -21,7 +21,7 @@ import "core:fmt" import "core:mem" import "core:os" -import "core:io" +// import "core:io" TEST_count := 0 TEST_fail := 0 @@ -45,8 +45,8 @@ when ODIN_TEST { } main :: proc() { - w := io.to_writer(os.stream_from_handle(os.stdout)) - t := testing.T{w=w} + // w := io.to_writer(os.stream_from_handle(os.stdout)) + t := testing.T{}//{w=w} zlib_test(&t) gzip_test(&t) shoco_test(&t) @@ -195,4 +195,4 @@ shoco_test :: proc(t: ^testing.T) { size, err = shoco.decompress(v.compressed[:v.short_sentinel], buffer[:]) expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after non-ASCII sentinel.") } -} \ No newline at end of file +} diff --git a/tests/core/text/match/test_core_text_match.odin b/tests/core/text/match/test_core_text_match.odin index b72190f78..eadd17433 100644 --- a/tests/core/text/match/test_core_text_match.odin +++ b/tests/core/text/match/test_core_text_match.odin @@ -14,7 +14,7 @@ failed :: proc(t: ^testing.T, ok: bool, loc := #caller_location) -> bool { TEST_count += 1 if !ok { - fmt.wprintf(t.w, "%v: ", loc) + fmt.printf(/*t.w,*/ "%v: ", loc) t.error_count += 1 TEST_fail += 1 } @@ -25,7 +25,7 @@ failed :: proc(t: ^testing.T, ok: bool, loc := #caller_location) -> bool { expect :: testing.expect logf :: proc(t: ^testing.T, format: string, args: ..any) { - fmt.wprintf(t.w, format, ..args) + fmt.printf(/*t.w,*/ format, ..args) } // find correct byte offsets @@ -380,7 +380,7 @@ main :: proc() { t: testing.T stream := os.stream_from_handle(os.stdout) w := io.to_writer(stream) - t.w = w + // t.w = w test_find(&t) test_match(&t) @@ -396,4 +396,4 @@ main :: proc() { if TEST_fail > 0 { os.exit(1) } -} \ No newline at end of file +} From eb3d6d7d75cf8b2de1bfddf03820ee60ce595b05 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 17:16:24 +0200 Subject: [PATCH 14/93] Update `core:image` tests to use new runner. --- tests/core/Makefile | 4 +- tests/core/build.bat | 4 +- tests/core/image/build.bat | 6 +- tests/core/image/test_core_image.odin | 301 ++++++++++---------------- 4 files changed, 120 insertions(+), 195 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 9026ed3d9..a740b3d7c 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,6 +1,6 @@ ODIN=../../odin PYTHON=$(shell which python3) -COMMON=-vet -strict-style +COMMON=-no-bounds-check -vet -strict-style -define:test_track_memory=true COLLECTION=-collection:tests=.. all: all_bsd \ @@ -34,7 +34,7 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image $(COMMON) -out:test_core_image + $(ODIN) test image $(COMMON) -define:test_progress_width=12 -out:test_core_image compress_test: $(ODIN) run compress $(COMMON) -out:test_core_compress diff --git a/tests/core/build.bat b/tests/core/build.bat index 4755e0a44..4d981be11 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,5 +1,5 @@ @echo off -set COMMON=-no-bounds-check -vet -strict-style +set COMMON=-no-bounds-check -vet -strict-style -define:test_track_memory=true set COLLECTION=-collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py @@ -42,7 +42,7 @@ echo --- echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% -out:test_core_image.exe || exit /b +%PATH_TO_ODIN% test image %COMMON% -define:test_progress_width=12 -out:test_core_image.exe || exit /b echo --- echo Running core:math tests diff --git a/tests/core/image/build.bat b/tests/core/image/build.bat index 03ee6b9a5..35d1c64e9 100644 --- a/tests/core/image/build.bat +++ b/tests/core/image/build.bat @@ -1,4 +1,2 @@ -@echo off -pushd .. -odin run image -popd \ No newline at end of file +@echo off +odin test . -define:test_track_memory=true -define:test_progress_width=12 -vet -strict-style \ No newline at end of file diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index ae92ca617..e3bef6c9d 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -20,49 +20,15 @@ import "core:image/tga" import "core:bytes" import "core:hash" -import "core:fmt" import "core:strings" - import "core:mem" -import "core:os" import "core:time" - import "base:runtime" -TEST_SUITE_PATH :: "assets/PNG" +TEST_SUITE_PATH :: "assets/PNG" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} I_Error :: image.Error -main :: proc() { - t := testing.T{} - png_test(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - PNG_Test :: struct { file: string, tests: []struct { @@ -72,7 +38,6 @@ PNG_Test :: struct { hash: u32, }, } - Default :: image.Options{} Alpha_Add :: image.Options{.alpha_add_if_missing} Premul_Drop :: image.Options{.alpha_premultiply, .alpha_drop_if_present} @@ -82,7 +47,7 @@ Blend_BG_Keep :: image.Options{.blend_background, .alpha_add_if_missing} Return_Metadata :: image.Options{.return_metadata} No_Channel_Expansion :: image.Options{.do_not_expand_channels, .return_metadata} -PNG_Dims :: struct { +PNG_Dims :: struct { width: int, height: int, channels: int, @@ -1430,38 +1395,66 @@ Expected_Text := map[string]map[string]png.Text { } @test -png_test :: proc(t: ^testing.T) { - - total_tests := 0 - total_expected := 235 - - PNG_Suites := [][]PNG_Test{ - Basic_PNG_Tests, - Interlaced_PNG_Tests, - Odd_Sized_PNG_Tests, - PNG_bKGD_Tests, - PNG_tRNS_Tests, - PNG_Filter_Tests, - PNG_Varied_IDAT_Tests, - PNG_ZLIB_Levels_Tests, - PNG_sPAL_Tests, - PNG_Ancillary_Tests, - Corrupt_PNG_Tests, - - No_Postprocesing_Tests, - - } - - for suite in PNG_Suites { - total_tests += run_png_suite(t, suite) - } - - error := fmt.tprintf("Expected %v PNG tests, %v ran.", total_expected, total_tests) - expect(t, total_tests == total_expected, error) +png_test_basic :: proc(t: ^testing.T) { + run_png_suite(t, Basic_PNG_Tests) } -run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { +@test +png_test_interlaced :: proc(t: ^testing.T) { + run_png_suite(t, Interlaced_PNG_Tests) +} +@test +png_test_odd_sized :: proc(t: ^testing.T) { + run_png_suite(t, Odd_Sized_PNG_Tests) +} + +@test +png_test_bKGD :: proc(t: ^testing.T) { + run_png_suite(t, PNG_bKGD_Tests) +} + +@test +png_test_tRNS :: proc(t: ^testing.T) { + run_png_suite(t, PNG_tRNS_Tests) +} + +@test +png_test_sPAL :: proc(t: ^testing.T) { + run_png_suite(t, PNG_sPAL_Tests) +} + +@test +png_test_filter :: proc(t: ^testing.T) { + run_png_suite(t, PNG_Filter_Tests) +} + +@test +png_test_varied_idat :: proc(t: ^testing.T) { + run_png_suite(t, PNG_Varied_IDAT_Tests) +} + +@test +png_test_zlib_levels :: proc(t: ^testing.T) { + run_png_suite(t, PNG_ZLIB_Levels_Tests) +} + +@test +png_test_ancillary :: proc(t: ^testing.T) { + run_png_suite(t, PNG_Ancillary_Tests) +} + +@test +png_test_corrupt :: proc(t: ^testing.T) { + run_png_suite(t, Corrupt_PNG_Tests) +} + +@test +png_test_no_postproc :: proc(t: ^testing.T) { + run_png_suite(t, No_Postprocesing_Tests) +} + +run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) { context = runtime.default_context() for file in suite { @@ -1472,9 +1465,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { count := 0 for test in file.tests { - count += 1 - subtotal += 1 - passed := false + count += 1 track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) @@ -1482,29 +1473,21 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { img, err = png.load(test_file, test.options) - error := fmt.tprintf("%v failed with %v.", test_file, err) - - passed = (test.expected_error == nil && err == nil) || (test.expected_error == err) - - expect(t, passed, error) + passed := (test.expected_error == nil && err == nil) || (test.expected_error == err) + testing.expectf(t, passed, "%v failed with %v.", test_file, err) if err == nil { // No point in running the other tests if it didn't load. pixels := bytes.buffer_to_bytes(&img.pixels) // This struct compare fails at -opt:2 if PNG_Dims is not #packed. - - dims := PNG_Dims{img.width, img.height, img.channels, img.depth} - error = fmt.tprintf("%v has %v, expected: %v.", file.file, dims, test.dims) - + dims := PNG_Dims{img.width, img.height, img.channels, img.depth} dims_pass := test.dims == dims - expect(t, dims_pass, error) - + testing.expectf(t, dims_pass, "%v has %v, expected: %v.", file.file, dims, test.dims) passed &= dims_pass - png_hash := hash.crc32(pixels) - error = fmt.tprintf("%v test %v hash is %08x, expected %08x with %v.", file.file, count, png_hash, test.hash, test.options) - expect(t, test.hash == png_hash, error) + png_hash := hash.crc32(pixels) + testing.expectf(t, test.hash == png_hash, "%v test %v hash is %08x, expected %08x with %v.", file.file, count, png_hash, test.hash, test.options) passed &= test.hash == png_hash @@ -1515,19 +1498,16 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { defer bytes.buffer_destroy(&qoi_buffer) qoi_save_err := qoi.save(&qoi_buffer, img) - error = fmt.tprintf("%v test %v QOI save failed with %v.", file.file, count, qoi_save_err) - expect(t, qoi_save_err == nil, error) + testing.expectf(t, qoi_save_err == nil, "%v test %v QOI save failed with %v.", file.file, count, qoi_save_err) if qoi_save_err == nil { qoi_img, qoi_load_err := qoi.load(qoi_buffer.buf[:]) defer qoi.destroy(qoi_img) - error = fmt.tprintf("%v test %v QOI load failed with %v.", file.file, count, qoi_load_err) - expect(t, qoi_load_err == nil, error) + testing.expectf(t, qoi_load_err == nil, "%v test %v QOI load failed with %v.", file.file, count, qoi_load_err) qoi_hash := hash.crc32(qoi_img.pixels.buf[:]) - error = fmt.tprintf("%v test %v QOI load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, qoi_hash, png_hash, test.options) - expect(t, qoi_hash == png_hash, error) + testing.expectf(t, qoi_hash == png_hash, "%v test %v QOI load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, qoi_hash, png_hash, test.options) } } @@ -1537,19 +1517,15 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { defer bytes.buffer_destroy(&tga_buffer) tga_save_err := tga.save(&tga_buffer, img) - error = fmt.tprintf("%v test %v TGA save failed with %v.", file.file, count, tga_save_err) - expect(t, tga_save_err == nil, error) - + testing.expectf(t, tga_save_err == nil, "%v test %v TGA save failed with %v.", file.file, count, tga_save_err) if tga_save_err == nil { tga_img, tga_load_err := tga.load(tga_buffer.buf[:]) defer tga.destroy(tga_img) - error = fmt.tprintf("%v test %v TGA load failed with %v.", file.file, count, tga_load_err) - expect(t, tga_load_err == nil, error) + testing.expectf(t, tga_load_err == nil, "%v test %v TGA load failed with %v.", file.file, count, tga_load_err) tga_hash := hash.crc32(tga_img.pixels.buf[:]) - error = fmt.tprintf("%v test %v TGA load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, tga_hash, png_hash, test.options) - expect(t, tga_hash == png_hash, error) + testing.expectf(t, tga_hash == png_hash, "%v test %v TGA load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, tga_hash, png_hash, test.options) } } @@ -1558,22 +1534,18 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { pbm_buf, pbm_save_err := pbm.save_to_buffer(img) defer delete(pbm_buf) - error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) - expect(t, pbm_save_err == nil, error) + testing.expectf(t, pbm_save_err == nil, "%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) if pbm_save_err == nil { // Try to load it again. pbm_img, pbm_load_err := pbm.load(pbm_buf) defer pbm.destroy(pbm_img) - error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) - expect(t, pbm_load_err == nil, error) + testing.expectf(t, pbm_load_err == nil, "%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) if pbm_load_err == nil { pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) - - error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) - expect(t, pbm_hash == png_hash, error) + testing.expectf(t, pbm_hash == png_hash, "%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) } } } @@ -1587,22 +1559,18 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { pbm_buf, pbm_save_err := pbm.save_to_buffer(img, pbm_info) defer delete(pbm_buf) - error = fmt.tprintf("%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) - expect(t, pbm_save_err == nil, error) + testing.expectf(t, pbm_save_err == nil, "%v test %v PBM save failed with %v.", file.file, count, pbm_save_err) if pbm_save_err == nil { // Try to load it again. pbm_img, pbm_load_err := pbm.load(pbm_buf) defer pbm.destroy(pbm_img) - error = fmt.tprintf("%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) - expect(t, pbm_load_err == nil, error) + testing.expectf(t, pbm_load_err == nil, "%v test %v PBM load failed with %v.", file.file, count, pbm_load_err) if pbm_load_err == nil { pbm_hash := hash.crc32(pbm_img.pixels.buf[:]) - - error = fmt.tprintf("%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) - expect(t, pbm_hash == png_hash, error) + testing.expectf(t, pbm_hash == png_hash, "%v test %v PBM load hash is %08x, expected it match PNG's %08x with %v.", file.file, count, pbm_hash, png_hash, test.options) } } } @@ -1655,21 +1623,18 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { float_pbm_buf, float_pbm_save_err := pbm.save_to_buffer(float_img, pbm_info) defer delete(float_pbm_buf) - error = fmt.tprintf("%v test %v save as PFM failed with %v", file.file, count, float_pbm_save_err) - expect(t, float_pbm_save_err == nil, error) + testing.expectf(t, float_pbm_save_err == nil, "%v test %v save as PFM failed with %v", file.file, count, float_pbm_save_err) if float_pbm_save_err == nil { // Load float image and compare. float_pbm_img, float_pbm_load_err := pbm.load(float_pbm_buf) defer pbm.destroy(float_pbm_img) - error = fmt.tprintf("%v test %v PFM load failed with %v", file.file, count, float_pbm_load_err) - expect(t, float_pbm_load_err == nil, error) + testing.expectf(t, float_pbm_load_err == nil, "%v test %v PFM load failed with %v", file.file, count, float_pbm_load_err) load_float := mem.slice_data_cast([]f32, float_pbm_img.pixels.buf[:]) - error = fmt.tprintf("%v test %v PFM load returned %v floats, expected %v", file.file, count, len(load_float), len(orig_float)) - expect(t, len(load_float) == len(orig_float), error) + testing.expectf(t, len(load_float) == len(orig_float), "%v test %v PFM load returned %v floats, expected %v", file.file, count, len(load_float), len(orig_float)) // Compare floats equal := true @@ -1679,15 +1644,13 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { break } } - error = fmt.tprintf("%v test %v PFM loaded floats to match", file.file, count) - expect(t, equal, error) + testing.expectf(t, equal, "%v test %v PFM loaded floats to match", file.file, count) } } } } if .return_metadata in test.options { - if v, ok := img.metadata.(^image.PNG_Info); ok { for c in v.chunks { #partial switch(c.header.type) { @@ -1696,8 +1659,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { case "pp0n2c16", "pp0n6a08": gamma, gamma_ok := png.gamma(c) expected_gamma := f32(1.0) - error = fmt.tprintf("%v test %v gAMA is %v, expected %v.", file.file, count, gamma, expected_gamma) - expect(t, gamma == expected_gamma && gamma_ok, error) + testing.expectf(t, gamma == expected_gamma && gamma_ok, "%v test %v gAMA is %v, expected %v.", file.file, count, gamma, expected_gamma) } case .PLTE: switch(file.file) { @@ -1705,8 +1667,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { plte, plte_ok := png.plte(c) expected_plte_len := u16(216) - error = fmt.tprintf("%v test %v PLTE length is %v, expected %v.", file.file, count, plte.used, expected_plte_len) - expect(t, expected_plte_len == plte.used && plte_ok, error) + testing.expectf(t, expected_plte_len == plte.used && plte_ok, "%v test %v PLTE length is %v, expected %v.", file.file, count, plte.used, expected_plte_len) } case .sPLT: switch(file.file) { @@ -1714,12 +1675,10 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { splt, splt_ok := png.splt(c) expected_splt_len := u16(216) - error = fmt.tprintf("%v test %v sPLT length is %v, expected %v.", file.file, count, splt.used, expected_splt_len) - expect(t, expected_splt_len == splt.used && splt_ok, error) + testing.expectf(t, expected_splt_len == splt.used && splt_ok, "%v test %v sPLT length is %v, expected %v.", file.file, count, splt.used, expected_splt_len) expected_splt_name := "six-cube" - error = fmt.tprintf("%v test %v sPLT name is %v, expected %v.", file.file, count, splt.name, expected_splt_name) - expect(t, expected_splt_name == splt.name && splt_ok, error) + testing.expectf(t, expected_splt_name == splt.name && splt_ok, "%v test %v sPLT name is %v, expected %v.", file.file, count, splt.name, expected_splt_name) png.splt_destroy(splt) } @@ -1733,48 +1692,37 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { g = png.CIE_1931{x = 0.3000, y = 0.6000}, b = png.CIE_1931{x = 0.1500, y = 0.0600}, } - error = fmt.tprintf("%v test %v cHRM is %v, expected %v.", file.file, count, chrm, expected_chrm) - expect(t, expected_chrm == chrm && chrm_ok, error) + testing.expectf(t, expected_chrm == chrm && chrm_ok, "%v test %v cHRM is %v, expected %v.", file.file, count, chrm, expected_chrm) } case .pHYs: phys, phys_ok := png.phys(c) - phys_err := "%v test %v cHRM is %v, expected %v." switch (file.file) { case "cdfn2c08": expected_phys := png.pHYs{ppu_x = 1, ppu_y = 4, unit = .Unknown} - error = fmt.tprintf(phys_err, file.file, count, phys, expected_phys) - expect(t, expected_phys == phys && phys_ok, error) + testing.expectf(t, expected_phys == phys && phys_ok, "%v test %v cHRM is %v, expected %v.", file.file, count, phys, expected_phys) case "cdhn2c08": expected_phys := png.pHYs{ppu_x = 4, ppu_y = 1, unit = .Unknown} - error = fmt.tprintf(phys_err, file.file, count, phys, expected_phys) - expect(t, expected_phys == phys && phys_ok, error) + testing.expectf(t, expected_phys == phys && phys_ok, "%v test %v cHRM is %v, expected %v.", file.file, count, phys, expected_phys) case "cdsn2c08": expected_phys := png.pHYs{ppu_x = 1, ppu_y = 1, unit = .Unknown} - error = fmt.tprintf(phys_err, file.file, count, phys, expected_phys) - expect(t, expected_phys == phys && phys_ok, error) + testing.expectf(t, expected_phys == phys && phys_ok, "%v test %v cHRM is %v, expected %v.", file.file, count, phys, expected_phys) case "cdun2c08": expected_phys := png.pHYs{ppu_x = 1000, ppu_y = 1000, unit = .Meter} - error = fmt.tprintf(phys_err, file.file, count, phys, expected_phys) - expect(t, expected_phys == phys && phys_ok, error) + testing.expectf(t, expected_phys == phys && phys_ok, "%v test %v cHRM is %v, expected %v.", file.file, count, phys, expected_phys) } case .hIST: hist, hist_ok := png.hist(c) - hist_err := "%v test %v hIST has %v entries, expected %v." switch (file.file) { case "ch1n3p04": - error = fmt.tprintf(hist_err, file.file, count, hist.used, 15) - expect(t, hist.used == 15 && hist_ok, error) + testing.expectf(t, hist.used == 15 && hist_ok, "%v test %v hIST has %v entries, expected %v.", file.file, count, hist.used, 15) case "ch2n3p08": - error = fmt.tprintf(hist_err, file.file, count, hist.used, 256) - expect(t, hist.used == 256 && hist_ok, error) + testing.expectf(t, hist.used == 256 && hist_ok, "%v test %v hIST has %v entries, expected %v.", file.file, count, hist.used, 256) } case .tIME: png_time, png_time_ok := png.time(c) - time_err := "%v test %v tIME was %v, expected %v." expected_time: png.tIME core_time, core_time_ok := png.core_time(c) - time_core_err := "%v test %v tIME->core:time is %v, expected %v." expected_core: time.Time switch(file.file) { @@ -1789,14 +1737,10 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { expected_core = time.Time{_nsec = 946684799000000000} } - error = fmt.tprintf(time_err, file.file, count, png_time, expected_time) - expect(t, png_time == expected_time && png_time_ok, error) - - error = fmt.tprintf(time_core_err, file.file, count, core_time, expected_core) - expect(t, core_time == expected_core && core_time_ok, error) + testing.expectf(t, png_time == expected_time && png_time_ok, "%v test %v tIME was %v, expected %v.", file.file, count, png_time, expected_time) + testing.expectf(t, core_time == expected_core && core_time_ok, "%v test %v tIME->core:time is %v, expected %v.", file.file, count, core_time, expected_core) case .sBIT: sbit, sbit_ok := png.sbit(c) - sbit_err := "%v test %v sBIT was %v, expected %v." expected_sbit: [4]u8 switch (file.file) { @@ -1815,8 +1759,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { case "cdfn2c08", "cdhn2c08", "cdsn2c08", "cdun2c08", "ch1n3p04", "basn3p04": expected_sbit = [4]u8{ 4, 4, 4, 0} } - error = fmt.tprintf(sbit_err, file.file, count, sbit, expected_sbit) - expect(t, sbit == expected_sbit && sbit_ok, error) + testing.expectf(t, sbit == expected_sbit && sbit_ok, "%v test %v sBIT was %v, expected %v.", file.file, count, sbit, expected_sbit) case .tEXt, .zTXt: text, text_ok := png.text(c) defer png.text_destroy(text) @@ -1828,8 +1771,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { if file.file in Expected_Text { if text.keyword in Expected_Text[file.file] { test_text := Expected_Text[file.file][text.keyword].text - error = fmt.tprintf("%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text.text, test_text) - expect(t, text.text == test_text && text_ok, error) + testing.expectf(t, text.text == test_text && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text.text, test_text) } } } @@ -1842,74 +1784,59 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { if file.file in Expected_Text { if text.keyword in Expected_Text[file.file] { test := Expected_Text[file.file][text.keyword] - error = fmt.tprintf("%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) - expect(t, text.language == test.language && text_ok, error) - expect(t, text.keyword_localized == test.keyword_localized && text_ok, error) + testing.expectf(t, text.language == test.language && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.keyword_localized == test.keyword_localized && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) } } case "ctfn0g04": // international UTF-8, finnish if file.file in Expected_Text { if text.keyword in Expected_Text[file.file] { test := Expected_Text[file.file][text.keyword] - error = fmt.tprintf("%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) - expect(t, text.text == test.text && text_ok, error) - expect(t, text.language == test.language && text_ok, error) - expect(t, text.keyword_localized == test.keyword_localized && text_ok, error) + testing.expectf(t, text.text == test.text && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.language == test.language && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.keyword_localized == test.keyword_localized && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) } } case "ctgn0g04": // international UTF-8, greek if file.file in Expected_Text { if text.keyword in Expected_Text[file.file] { test := Expected_Text[file.file][text.keyword] - error = fmt.tprintf("%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) - expect(t, text.text == test.text && text_ok, error) - expect(t, text.language == test.language && text_ok, error) - expect(t, text.keyword_localized == test.keyword_localized && text_ok, error) + testing.expectf(t, text.text == test.text && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.language == test.language && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.keyword_localized == test.keyword_localized && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) } } case "cthn0g04": // international UTF-8, hindi if file.file in Expected_Text { if text.keyword in Expected_Text[file.file] { test := Expected_Text[file.file][text.keyword] - error = fmt.tprintf("%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) - expect(t, text.text == test.text && text_ok, error) - expect(t, text.language == test.language && text_ok, error) - expect(t, text.keyword_localized == test.keyword_localized && text_ok, error) + testing.expectf(t, text.text == test.text && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.language == test.language && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.keyword_localized == test.keyword_localized && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) } } case "ctjn0g04": // international UTF-8, japanese if file.file in Expected_Text { if text.keyword in Expected_Text[file.file] { test := Expected_Text[file.file][text.keyword] - error = fmt.tprintf("%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) - expect(t, text.text == test.text && text_ok, error) - expect(t, text.language == test.language && text_ok, error) - expect(t, text.keyword_localized == test.keyword_localized && text_ok, error) + testing.expectf(t, text.text == test.text && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.language == test.language && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) + testing.expectf(t, text.keyword_localized == test.keyword_localized && text_ok, "%v test %v text keyword {{%v}}:'%v', expected '%v'.", file.file, count, text.keyword, text, test) } } } case .eXIf: if file.file == "exif2c08" { // chunk with jpeg exif data exif, exif_ok := png.exif(c) - error = fmt.tprintf("%v test %v eXIf byte order '%v', expected 'big_endian'.", file.file, count, exif.byte_order) - error_len := fmt.tprintf("%v test %v eXIf data length '%v', expected '%v'.", file.file, len(exif.data), 978) - expect(t, exif.byte_order == .big_endian && exif_ok, error) - expect(t, len(exif.data) == 978 && exif_ok, error_len) + testing.expectf(t, exif.byte_order == .big_endian && exif_ok, "%v test %v eXIf byte order '%v', expected 'big_endian'.", file.file, count, exif.byte_order) + testing.expectf(t, len(exif.data) == 978 && exif_ok, "%v test %v eXIf data length '%v', expected '%v'.", file.file, len(exif.data), 978) } } } } } } - png.destroy(img) - - for _, v in track.allocation_map { - error = fmt.tprintf("%v test %v leaked %v bytes @ loc %v.", file.file, count, v.size, v.location) - expect(t, false, error) - } } } - - return -} +} \ No newline at end of file From 22c092f846b0a7654b71d55c4e37980cd155f781 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 17:22:02 +0200 Subject: [PATCH 15/93] Delete duplicated flag. --- tests/core/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index a740b3d7c..4fb046449 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -46,10 +46,10 @@ strings_test: $(ODIN) run strings $(COMMON) -out:test_core_strings hash_test: - $(ODIN) run hash $(COMMON) -o:speed -no-bounds-check -out:test_hash + $(ODIN) run hash $(COMMON) -o:speed -out:test_hash crypto_test: - $(ODIN) run crypto $(COMMON) $(COLLECTION) -o:speed -no-bounds-check -out:test_crypto + $(ODIN) run crypto $(COMMON) $(COLLECTION) -o:speed -out:test_crypto noise_test: $(ODIN) run math/noise $(COMMON) -out:test_noise From e3181c13c66b68ae2c0788d43417316a45b58b1d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 17:53:27 +0200 Subject: [PATCH 16/93] Update `core:compress` tests --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/compress/test_core_compress.odin | 101 ++++---------------- 3 files changed, 18 insertions(+), 87 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 4fb046449..ef76bbbb8 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -37,7 +37,7 @@ image_test: $(ODIN) test image $(COMMON) -define:test_progress_width=12 -out:test_core_image compress_test: - $(ODIN) run compress $(COMMON) -out:test_core_compress + $(ODIN) test compress $(COMMON) -define:test_progress_width=3 -out:test_core_compress container_test: $(ODIN) run container $(COMMON) $(COLLECTION) -out:test_core_container diff --git a/tests/core/build.bat b/tests/core/build.bat index 4d981be11..e33b49531 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -6,7 +6,7 @@ python3 download_assets.py echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% -out:test_core_compress.exe || exit /b +%PATH_TO_ODIN% test compress %COMMON% -define:test_progress_width=3 -out:test_core_compress.exe || exit /b echo --- echo Running core:container tests diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index db6f3d06b..4ab63ae67 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -15,47 +15,7 @@ import "core:testing" import "core:compress/zlib" import "core:compress/gzip" import "core:compress/shoco" - import "core:bytes" -import "core:fmt" - -import "core:mem" -import "core:os" -// import "core:io" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - // w := io.to_writer(os.stream_from_handle(os.stdout)) - t := testing.T{}//{w=w} - zlib_test(&t) - gzip_test(&t) - shoco_test(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} @test zlib_test :: proc(t: ^testing.T) { @@ -80,26 +40,14 @@ zlib_test :: proc(t: ^testing.T) { } buf: bytes.Buffer + err := zlib.inflate(ODIN_DEMO, &buf) - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - err := zlib.inflate(ODIN_DEMO, &buf) - - expect(t, err == nil, "ZLIB failed to decompress ODIN_DEMO") + testing.expect(t, err == nil, "ZLIB failed to decompress ODIN_DEMO") s := bytes.buffer_to_string(&buf) - expect(t, s[68] == 240 && s[69] == 159 && s[70] == 152, "ZLIB result should've contained 😃 at position 68.") - - expect(t, len(s) == 438, "ZLIB result has an unexpected length.") - + testing.expect(t, s[68] == 240 && s[69] == 159 && s[70] == 152, "ZLIB result should've contained 😃 at position 68.") + testing.expect(t, len(s) == 438, "ZLIB result has an unexpected length.") bytes.buffer_destroy(&buf) - - for _, v in track.allocation_map { - error := fmt.tprintf("ZLIB test leaked %v bytes", v.size) - expect(t, false, error) - } } @test @@ -117,24 +65,12 @@ gzip_test :: proc(t: ^testing.T) { } buf: bytes.Buffer + err := gzip.load(TEST, &buf) - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - err := gzip.load(TEST, &buf) // , 438); - - expect(t, err == nil, "GZIP failed to decompress TEST") - s := bytes.buffer_to_string(&buf) - - expect(t, s == "payload", "GZIP result wasn't 'payload'") + testing.expect(t, err == nil, "GZIP failed to decompress TEST") + testing.expect(t, bytes.buffer_to_string(&buf) == "payload", "GZIP result wasn't 'payload'") bytes.buffer_destroy(&buf) - - for _, v in track.allocation_map { - error := fmt.tprintf("GZIP test leaked %v bytes", v.size) - expect(t, false, error) - } } @test @@ -168,31 +104,26 @@ shoco_test :: proc(t: ^testing.T) { defer delete(buffer) size, err := shoco.decompress(v.compressed, buffer[:]) - msg := fmt.tprintf("Expected `decompress` to return `nil`, got %v", err) - expect(t, err == nil, msg) + testing.expectf(t, err == nil, "Expected `decompress` to return `nil`, got %v", err) - msg = fmt.tprintf("Decompressed %v bytes into %v. Expected to decompress into %v bytes.", len(v.compressed), size, expected_raw) - expect(t, size == expected_raw, msg) - expect(t, string(buffer[:size]) == string(v.raw), "Decompressed contents don't match.") + testing.expectf(t, size == expected_raw, "Decompressed %v bytes into %v. Expected to decompress into %v bytes", len(v.compressed), size, expected_raw) + testing.expect(t, string(buffer[:size]) == string(v.raw), "Decompressed contents don't match") size, err = shoco.compress(string(v.raw), buffer[:]) - expect(t, err == nil, "Expected `compress` to return `nil`.") + testing.expect(t, err == nil, "Expected `compress` to return `nil`.") - msg = fmt.tprintf("Compressed %v bytes into %v. Expected to compress into %v bytes.", expected_raw, size, expected_compressed) - expect(t, size == expected_compressed, msg) + testing.expectf(t, size == expected_compressed, "Compressed %v bytes into %v. Expected to compress into %v bytes", expected_raw, size, expected_compressed) size, err = shoco.decompress(v.compressed, buffer[:expected_raw - 10]) - msg = fmt.tprintf("Decompressing into too small a buffer returned %v, expected `.Output_Too_Short`", err) - expect(t, err == .Output_Too_Short, msg) + testing.expectf(t, err == .Output_Too_Short, "Decompressing into too small a buffer returned %v, expected `.Output_Too_Short`", err) size, err = shoco.compress(string(v.raw), buffer[:expected_compressed - 10]) - msg = fmt.tprintf("Compressing into too small a buffer returned %v, expected `.Output_Too_Short`", err) - expect(t, err == .Output_Too_Short, msg) + testing.expectf(t, err == .Output_Too_Short, "Compressing into too small a buffer returned %v, expected `.Output_Too_Short`", err) size, err = shoco.decompress(v.compressed[:v.short_pack], buffer[:]) - expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after selecting a pack.") + testing.expectf(t, err == .Stream_Too_Short, "Insufficient data after pack returned %v, expected `.Stream_Too_Short`", err) size, err = shoco.decompress(v.compressed[:v.short_sentinel], buffer[:]) - expect(t, err == .Stream_Too_Short, "Expected `decompress` to return `Stream_Too_Short` because there was no more data after non-ASCII sentinel.") + testing.expectf(t, err == .Stream_Too_Short, "No more data after non-ASCII sentinel returned %v, expected `.Stream_Too_Short`", err) } } From a463e282db7931226c85b7562a4b4a716399b21b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 19:35:03 +0200 Subject: [PATCH 17/93] Update `core:container` tests --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/container/test_core_avl.odin | 71 +++++++-------- tests/core/container/test_core_container.odin | 26 ------ tests/core/container/test_core_rbtree.odin | 90 ++++++++++--------- .../core/container/test_core_small_array.odin | 67 +++++++------- 6 files changed, 119 insertions(+), 139 deletions(-) delete mode 100644 tests/core/container/test_core_container.odin diff --git a/tests/core/Makefile b/tests/core/Makefile index ef76bbbb8..fff46fb69 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -40,7 +40,7 @@ compress_test: $(ODIN) test compress $(COMMON) -define:test_progress_width=3 -out:test_core_compress container_test: - $(ODIN) run container $(COMMON) $(COLLECTION) -out:test_core_container + $(ODIN) test container $(COMMON) -define:test_progress_width=4 -out:test_core_container strings_test: $(ODIN) run strings $(COMMON) -out:test_core_strings diff --git a/tests/core/build.bat b/tests/core/build.bat index e33b49531..07432a657 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -11,7 +11,7 @@ echo --- echo --- echo Running core:container tests echo --- -%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b +%PATH_TO_ODIN% test container %COMMON% define:test_progress_width=4 -out:test_core_container.exe || exit /b echo --- echo Running core:crypto tests diff --git a/tests/core/container/test_core_avl.odin b/tests/core/container/test_core_avl.odin index 2244ab7f6..37b21a6be 100644 --- a/tests/core/container/test_core_avl.odin +++ b/tests/core/container/test_core_avl.odin @@ -4,22 +4,21 @@ import "core:container/avl" import "core:math/rand" import "core:slice" import "core:testing" -import "core:fmt" -import tc "tests:common" +import "core:log" @(test) test_avl :: proc(t: ^testing.T) { - tc.log(t, fmt.tprintf("Testing avl, using random seed %v, add -define:RANDOM_SEED=%v to reuse it.", random_seed, random_seed)) + log.infof("Testing avl, using random seed %v, add -define:RANDOM_SEED=%v to reuse it.", random_seed, random_seed) // Initialization. tree: avl.Tree(int) avl.init(&tree, slice.cmp_proc(int)) - tc.expect(t, avl.len(&tree) == 0, "empty: len should be 0") - tc.expect(t, avl.first(&tree) == nil, "empty: first should be nil") - tc.expect(t, avl.last(&tree) == nil, "empty: last should be nil") + testing.expect(t, avl.len(&tree) == 0, "empty: len should be 0") + testing.expect(t, avl.first(&tree) == nil, "empty: first should be nil") + testing.expect(t, avl.last(&tree) == nil, "empty: last should be nil") iter := avl.iterator(&tree, avl.Direction.Forward) - tc.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") + testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") r: rand.Rand rand.init(&r, random_seed) @@ -27,30 +26,32 @@ test_avl :: proc(t: ^testing.T) { // Test insertion. NR_INSERTS :: 32 + 1 // Ensure at least 1 collision. inserted_map := make(map[int]^avl.Node(int)) + defer delete(inserted_map) for i := 0; i < NR_INSERTS; i += 1 { v := int(rand.uint32(&r) & 0x1f) existing_node, in_map := inserted_map[v] n, ok, _ := avl.find_or_insert(&tree, v) - tc.expect(t, in_map != ok, "insert: ok should match inverse of map lookup") + testing.expect(t, in_map != ok, "insert: ok should match inverse of map lookup") if ok { inserted_map[v] = n } else { - tc.expect(t, existing_node == n, "insert: expecting existing node") + testing.expect(t, existing_node == n, "insert: expecting existing node") } } nrEntries := len(inserted_map) - tc.expect(t, avl.len(&tree) == nrEntries, "insert: len after") + testing.expect(t, avl.len(&tree) == nrEntries, "insert: len after") validate_avl(t, &tree) // Ensure that all entries can be found. for k, v in inserted_map { - tc.expect(t, v == avl.find(&tree, k), "Find(): Node") - tc.expect(t, k == v.value, "Find(): Node value") + testing.expect(t, v == avl.find(&tree, k), "Find(): Node") + testing.expect(t, k == v.value, "Find(): Node value") } // Test the forward/backward iterators. inserted_values: [dynamic]int + defer delete(inserted_values) for k in inserted_map { append(&inserted_values, k) } @@ -60,38 +61,38 @@ test_avl :: proc(t: ^testing.T) { visited: int for node in avl.iterator_next(&iter) { v, idx := node.value, visited - tc.expect(t, inserted_values[idx] == v, "iterator/forward: value") - tc.expect(t, node == avl.iterator_get(&iter), "iterator/forward: get") + testing.expect(t, inserted_values[idx] == v, "iterator/forward: value") + testing.expect(t, node == avl.iterator_get(&iter), "iterator/forward: get") visited += 1 } - tc.expect(t, visited == nrEntries, "iterator/forward: visited") + testing.expect(t, visited == nrEntries, "iterator/forward: visited") slice.reverse(inserted_values[:]) iter = avl.iterator(&tree, avl.Direction.Backward) visited = 0 for node in avl.iterator_next(&iter) { v, idx := node.value, visited - tc.expect(t, inserted_values[idx] == v, "iterator/backward: value") + testing.expect(t, inserted_values[idx] == v, "iterator/backward: value") visited += 1 } - tc.expect(t, visited == nrEntries, "iterator/backward: visited") + testing.expect(t, visited == nrEntries, "iterator/backward: visited") // Test removal. rand.shuffle(inserted_values[:], &r) for v, i in inserted_values { node := avl.find(&tree, v) - tc.expect(t, node != nil, "remove: find (pre)") + testing.expect(t, node != nil, "remove: find (pre)") ok := avl.remove(&tree, v) - tc.expect(t, ok, "remove: succeeds") - tc.expect(t, nrEntries - (i + 1) == avl.len(&tree), "remove: len (post)") + testing.expect(t, ok, "remove: succeeds") + testing.expect(t, nrEntries - (i + 1) == avl.len(&tree), "remove: len (post)") validate_avl(t, &tree) - tc.expect(t, nil == avl.find(&tree, v), "remove: find (post") + testing.expect(t, nil == avl.find(&tree, v), "remove: find (post") } - tc.expect(t, avl.len(&tree) == 0, "remove: len should be 0") - tc.expect(t, avl.first(&tree) == nil, "remove: first should be nil") - tc.expect(t, avl.last(&tree) == nil, "remove: last should be nil") + testing.expect(t, avl.len(&tree) == 0, "remove: len should be 0") + testing.expect(t, avl.first(&tree) == nil, "remove: first should be nil") + testing.expect(t, avl.last(&tree) == nil, "remove: last should be nil") // Refill the tree. for v in inserted_values { @@ -104,25 +105,25 @@ test_avl :: proc(t: ^testing.T) { v := node.value ok := avl.iterator_remove(&iter) - tc.expect(t, ok, "iterator/remove: success") + testing.expect(t, ok, "iterator/remove: success") ok = avl.iterator_remove(&iter) - tc.expect(t, !ok, "iterator/remove: redundant removes should fail") + testing.expect(t, !ok, "iterator/remove: redundant removes should fail") - tc.expect(t, avl.find(&tree, v) == nil, "iterator/remove: node should be gone") - tc.expect(t, avl.iterator_get(&iter) == nil, "iterator/remove: get should return nil") + testing.expect(t, avl.find(&tree, v) == nil, "iterator/remove: node should be gone") + testing.expect(t, avl.iterator_get(&iter) == nil, "iterator/remove: get should return nil") // Ensure that iterator_next still works. node, ok = avl.iterator_next(&iter) - tc.expect(t, ok == (avl.len(&tree) > 0), "iterator/remove: next should return false") - tc.expect(t, node == avl.first(&tree), "iterator/remove: next should return first") + testing.expect(t, ok == (avl.len(&tree) > 0), "iterator/remove: next should return false") + testing.expect(t, node == avl.first(&tree), "iterator/remove: next should return first") validate_avl(t, &tree) } - tc.expect(t, avl.len(&tree) == nrEntries - 1, "iterator/remove: len should drop by 1") + testing.expect(t, avl.len(&tree) == nrEntries - 1, "iterator/remove: len should drop by 1") avl.destroy(&tree) - tc.expect(t, avl.len(&tree) == 0, "destroy: len should be 0") + testing.expect(t, avl.len(&tree) == 0, "destroy: len should be 0") } @(private) @@ -141,10 +142,10 @@ tree_check_invariants :: proc( } // Validate the parent pointer. - tc.expect(t, parent == node._parent, "invalid parent pointer") + testing.expect(t, parent == node._parent, "invalid parent pointer") // Validate that the balance factor is -1, 0, 1. - tc.expect( + testing.expect( t, node._balance == -1 || node._balance == 0 || node._balance == 1, "invalid balance factor", @@ -155,7 +156,7 @@ tree_check_invariants :: proc( r_height := tree_check_invariants(t, tree, node._right, node) // Validate the AVL invariant and the balance factor. - tc.expect(t, int(node._balance) == r_height - l_height, "AVL balance factor invariant violated") + testing.expect(t, int(node._balance) == r_height - l_height, "AVL balance factor invariant violated") if l_height > r_height { return l_height + 1 } diff --git a/tests/core/container/test_core_container.odin b/tests/core/container/test_core_container.odin deleted file mode 100644 index 7dd4a3628..000000000 --- a/tests/core/container/test_core_container.odin +++ /dev/null @@ -1,26 +0,0 @@ -package test_core_container - -import "core:fmt" -import "core:testing" - -import tc "tests:common" - -expect_equal :: proc(t: ^testing.T, the_slice, expected: []int, loc := #caller_location) { - _eq :: proc(a, b: []int) -> bool { - if len(a) != len(b) do return false - for a, i in a { - if b[i] != a do return false - } - return true - } - tc.expect(t, _eq(the_slice, expected), fmt.tprintf("Expected %v, got %v\n", the_slice, expected), loc) -} - -main :: proc() { - t := testing.T{} - - test_avl(&t) - test_rbtree(&t) - test_small_array(&t) - tc.report(&t) -} diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index 89742b1d0..a4151d120 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -3,14 +3,16 @@ package test_core_container import rb "core:container/rbtree" import "core:math/rand" import "core:testing" -import "core:fmt" import "base:intrinsics" import "core:mem" import "core:slice" -import tc "tests:common" +import "core:log" -RANDOM_SEED :: #config(RANDOM_SEED, 0) -random_seed := u64(intrinsics.read_cycle_counter()) when RANDOM_SEED == 0 else u64(RANDOM_SEED) +@(private) +_RANDOM_SEED :: #config(RANDOM_SEED, u64(0)) + +// Exported +random_seed := u64(intrinsics.read_cycle_counter()) when _RANDOM_SEED == 0 else u64(_RANDOM_SEED) test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { track: mem.Tracking_Allocator @@ -21,15 +23,15 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { r: rand.Rand rand.init(&r, random_seed) - tc.log(t, fmt.tprintf("Testing Red-Black Tree($Key=%v,$Value=%v), using random seed %v, add -define:RANDOM_SEED=%v to reuse it.", type_info_of(Key), type_info_of(Value), random_seed, random_seed)) + log.infof("Testing Red-Black Tree($Key=%v,$Value=%v), using random seed %v, add -define:RANDOM_SEED=%v to reuse it.", type_info_of(Key), type_info_of(Value), random_seed, random_seed) tree: rb.Tree(Key, Value) rb.init(&tree) - tc.expect(t, rb.len(&tree) == 0, "empty: len should be 0") - tc.expect(t, rb.first(&tree) == nil, "empty: first should be nil") - tc.expect(t, rb.last(&tree) == nil, "empty: last should be nil") + testing.expect(t, rb.len(&tree) == 0, "empty: len should be 0") + testing.expect(t, rb.first(&tree) == nil, "empty: first should be nil") + testing.expect(t, rb.last(&tree) == nil, "empty: last should be nil") iter := rb.iterator(&tree, .Forward) - tc.expect(t, rb.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") + testing.expect(t, rb.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") // Test insertion. NR_INSERTS :: 32 + 1 // Ensure at least 1 collision. @@ -45,27 +47,27 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { existing_node, in_map := inserted_map[k] n, inserted, _ := rb.find_or_insert(&tree, k, v) - tc.expect(t, in_map != inserted, "insert: inserted should match inverse of map lookup") + testing.expect(t, in_map != inserted, "insert: inserted should match inverse of map lookup") if inserted { inserted_map[k] = n } else { - tc.expect(t, existing_node == n, "insert: expecting existing node") + testing.expect(t, existing_node == n, "insert: expecting existing node") } } entry_count := len(inserted_map) - tc.expect(t, rb.len(&tree) == entry_count, "insert: len after") + testing.expect(t, rb.len(&tree) == entry_count, "insert: len after") validate_rbtree(t, &tree) first := rb.first(&tree) last := rb.last(&tree) - tc.expect(t, first != nil && first.key == min_key, fmt.tprintf("insert: first should be present with key %v", min_key)) - tc.expect(t, last != nil && last.key == max_key, fmt.tprintf("insert: last should be present with key %v", max_key)) + testing.expectf(t, first != nil && first.key == min_key, "insert: first should be present with key %v", min_key) + testing.expectf(t, last != nil && last.key == max_key, "insert: last should be present with key %v", max_key) // Ensure that all entries can be found. for k, v in inserted_map { - tc.expect(t, v == rb.find(&tree, k), "Find(): Node") - tc.expect(t, k == v.key, "Find(): Node key") + testing.expect(t, v == rb.find(&tree, k), "Find(): Node") + testing.expect(t, k == v.key, "Find(): Node key") } // Test the forward/backward iterators. @@ -79,21 +81,21 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { visited: int for node in rb.iterator_next(&iter) { k, idx := node.key, visited - tc.expect(t, inserted_keys[idx] == k, "iterator/forward: key") - tc.expect(t, node == rb.iterator_get(&iter), "iterator/forward: get") + testing.expect(t, inserted_keys[idx] == k, "iterator/forward: key") + testing.expect(t, node == rb.iterator_get(&iter), "iterator/forward: get") visited += 1 } - tc.expect(t, visited == entry_count, "iterator/forward: visited") + testing.expect(t, visited == entry_count, "iterator/forward: visited") slice.reverse(inserted_keys[:]) iter = rb.iterator(&tree, rb.Direction.Backward) visited = 0 for node in rb.iterator_next(&iter) { k, idx := node.key, visited - tc.expect(t, inserted_keys[idx] == k, "iterator/backward: key") + testing.expect(t, inserted_keys[idx] == k, "iterator/backward: key") visited += 1 } - tc.expect(t, visited == entry_count, "iterator/backward: visited") + testing.expect(t, visited == entry_count, "iterator/backward: visited") // Test removal (and on_remove callback) rand.shuffle(inserted_keys[:], &r) @@ -104,19 +106,19 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { } for k, i in inserted_keys { node := rb.find(&tree, k) - tc.expect(t, node != nil, "remove: find (pre)") + testing.expect(t, node != nil, "remove: find (pre)") ok := rb.remove(&tree, k) - tc.expect(t, ok, "remove: succeeds") - tc.expect(t, entry_count - (i + 1) == rb.len(&tree), "remove: len (post)") + testing.expect(t, ok, "remove: succeeds") + testing.expect(t, entry_count - (i + 1) == rb.len(&tree), "remove: len (post)") validate_rbtree(t, &tree) - tc.expect(t, nil == rb.find(&tree, k), "remove: find (post") + testing.expect(t, nil == rb.find(&tree, k), "remove: find (post") } - tc.expect(t, rb.len(&tree) == 0, "remove: len should be 0") - tc.expect(t, callback_count == 0, fmt.tprintf("remove: on_remove should've been called %v times, it was %v", entry_count, callback_count)) - tc.expect(t, rb.first(&tree) == nil, "remove: first should be nil") - tc.expect(t, rb.last(&tree) == nil, "remove: last should be nil") + testing.expect(t, rb.len(&tree) == 0, "remove: len should be 0") + testing.expectf(t, callback_count == 0, "remove: on_remove should've been called %v times, it was %v", entry_count, callback_count) + testing.expect(t, rb.first(&tree) == nil, "remove: first should be nil") + testing.expect(t, rb.last(&tree) == nil, "remove: last should be nil") // Refill the tree. for k in inserted_keys { @@ -130,32 +132,32 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { k := node.key ok := rb.iterator_remove(&iter) - tc.expect(t, ok, "iterator/remove: success") + testing.expect(t, ok, "iterator/remove: success") ok = rb.iterator_remove(&iter) - tc.expect(t, !ok, "iterator/remove: redundant removes should fail") + testing.expect(t, !ok, "iterator/remove: redundant removes should fail") - tc.expect(t, rb.find(&tree, k) == nil, "iterator/remove: node should be gone") - tc.expect(t, rb.iterator_get(&iter) == nil, "iterator/remove: get should return nil") + testing.expect(t, rb.find(&tree, k) == nil, "iterator/remove: node should be gone") + testing.expect(t, rb.iterator_get(&iter) == nil, "iterator/remove: get should return nil") // Ensure that iterator_next still works. node, ok = rb.iterator_next(&iter) - tc.expect(t, ok == (rb.len(&tree) > 0), "iterator/remove: next should return false") - tc.expect(t, node == rb.first(&tree), "iterator/remove: next should return first") + testing.expect(t, ok == (rb.len(&tree) > 0), "iterator/remove: next should return false") + testing.expect(t, node == rb.first(&tree), "iterator/remove: next should return first") validate_rbtree(t, &tree) } - tc.expect(t, rb.len(&tree) == entry_count - 1, "iterator/remove: len should drop by 1") + testing.expect(t, rb.len(&tree) == entry_count - 1, "iterator/remove: len should drop by 1") rb.destroy(&tree) - tc.expect(t, rb.len(&tree) == 0, "destroy: len should be 0") - tc.expect(t, callback_count == 0, fmt.tprintf("remove: on_remove should've been called %v times, it was %v", entry_count, callback_count)) + testing.expect(t, rb.len(&tree) == 0, "destroy: len should be 0") + testing.expectf(t, callback_count == 0, "remove: on_remove should've been called %v times, it was %v", entry_count, callback_count) // print_tree_node(tree._root) delete(inserted_map) delete(inserted_keys) - tc.expect(t, len(track.allocation_map) == 0, fmt.tprintf("Expected 0 leaks, have %v", len(track.allocation_map))) - tc.expect(t, len(track.bad_free_array) == 0, fmt.tprintf("Expected 0 bad frees, have %v", len(track.bad_free_array))) + testing.expectf(t, len(track.allocation_map) == 0, "Expected 0 leaks, have %v", len(track.allocation_map)) + testing.expectf(t, len(track.bad_free_array) == 0, "Expected 0 bad frees, have %v", len(track.bad_free_array)) return } @@ -194,7 +196,7 @@ validate_rbtree :: proc(t: ^testing.T, tree: ^$T/rb.Tree($Key, $Value)) { } verify_rbtree_propery_1 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) { - tc.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.") + testing.expect(t, rb.node_color(n) == .Black || rb.node_color(n) == .Red, "Property #1: Each node is either red or black.") if n == nil { return } @@ -203,14 +205,14 @@ verify_rbtree_propery_1 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) { } verify_rbtree_propery_2 :: proc(t: ^testing.T, root: ^$N/rb.Node($Key, $Value)) { - tc.expect(t, rb.node_color(root) == .Black, "Property #2: Root node should be black.") + testing.expect(t, rb.node_color(root) == .Black, "Property #2: Root node should be black.") } verify_rbtree_propery_4 :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Value)) { if rb.node_color(n) == .Red { // A red node's left, right and parent should be black all_black := rb.node_color(n._left) == .Black && rb.node_color(n._right) == .Black && rb.node_color(n._parent) == .Black - tc.expect(t, all_black, "Property #3: Red node's children + parent must be black.") + testing.expect(t, all_black, "Property #3: Red node's children + parent must be black.") } if n == nil { return @@ -233,7 +235,7 @@ verify_rbtree_propery_5_helper :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Valu if path_black_count^ == -1 { path_black_count^ = black_count } else { - tc.expect(t, black_count == path_black_count^, "Property #5: Paths from a node to its leaves contain same black count.") + testing.expect(t, black_count == path_black_count^, "Property #5: Paths from a node to its leaves contain same black count.") } return } diff --git a/tests/core/container/test_core_small_array.odin b/tests/core/container/test_core_small_array.odin index 78998de16..580df793e 100644 --- a/tests/core/container/test_core_small_array.odin +++ b/tests/core/container/test_core_small_array.odin @@ -3,44 +3,47 @@ package test_core_container import "core:testing" import "core:container/small_array" -import tc "tests:common" - -@(test) -test_small_array :: proc(t: ^testing.T) { - tc.log(t, "Testing small_array") - - test_small_array_removes(t) - test_small_array_inject_at(t) -} - @(test) test_small_array_removes :: proc(t: ^testing.T) { - array: small_array.Small_Array(10, int) - small_array.append(&array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + array: small_array.Small_Array(10, int) + small_array.append(&array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) - small_array.ordered_remove(&array, 0) - expect_equal(t, small_array.slice(&array), []int { 1, 2, 3, 4, 5, 6, 7, 8, 9 }) - small_array.ordered_remove(&array, 5) - expect_equal(t, small_array.slice(&array), []int { 1, 2, 3, 4, 5, 7, 8, 9 }) - small_array.ordered_remove(&array, 6) - expect_equal(t, small_array.slice(&array), []int { 1, 2, 3, 4, 5, 7, 9 }) - small_array.unordered_remove(&array, 0) - expect_equal(t, small_array.slice(&array), []int { 9, 2, 3, 4, 5, 7 }) - small_array.unordered_remove(&array, 2) - expect_equal(t, small_array.slice(&array), []int { 9, 2, 7, 4, 5 }) - small_array.unordered_remove(&array, 4) - expect_equal(t, small_array.slice(&array), []int { 9, 2, 7, 4 }) + small_array.ordered_remove(&array, 0) + testing.expect(t, slice_equal(small_array.slice(&array), []int { 1, 2, 3, 4, 5, 6, 7, 8, 9 })) + small_array.ordered_remove(&array, 5) + testing.expect(t, slice_equal(small_array.slice(&array), []int { 1, 2, 3, 4, 5, 7, 8, 9 })) + small_array.ordered_remove(&array, 6) + testing.expect(t, slice_equal(small_array.slice(&array), []int { 1, 2, 3, 4, 5, 7, 9 })) + small_array.unordered_remove(&array, 0) + testing.expect(t, slice_equal(small_array.slice(&array), []int { 9, 2, 3, 4, 5, 7 })) + small_array.unordered_remove(&array, 2) + testing.expect(t, slice_equal(small_array.slice(&array), []int { 9, 2, 7, 4, 5 })) + small_array.unordered_remove(&array, 4) + testing.expect(t, slice_equal(small_array.slice(&array), []int { 9, 2, 7, 4 })) } @(test) test_small_array_inject_at :: proc(t: ^testing.T) { - array: small_array.Small_Array(13, int) - small_array.append(&array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + array: small_array.Small_Array(13, int) + small_array.append(&array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) - tc.expect(t, small_array.inject_at(&array, 0, 0), "Expected to be able to inject into small array") - expect_equal(t, small_array.slice(&array), []int { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }) - tc.expect(t, small_array.inject_at(&array, 0, 5), "Expected to be able to inject into small array") - expect_equal(t, small_array.slice(&array), []int { 0, 0, 1, 2, 3, 0, 4, 5, 6, 7, 8, 9 }) - tc.expect(t, small_array.inject_at(&array, 0, small_array.len(array)), "Expected to be able to inject into small array") - expect_equal(t, small_array.slice(&array), []int { 0, 0, 1, 2, 3, 0, 4, 5, 6, 7, 8, 9, 0 }) + testing.expect(t, small_array.inject_at(&array, 0, 0), "Expected to be able to inject into small array") + testing.expect(t, slice_equal(small_array.slice(&array), []int { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })) + testing.expect(t, small_array.inject_at(&array, 0, 5), "Expected to be able to inject into small array") + testing.expect(t, slice_equal(small_array.slice(&array), []int { 0, 0, 1, 2, 3, 0, 4, 5, 6, 7, 8, 9 })) + testing.expect(t, small_array.inject_at(&array, 0, small_array.len(array)), "Expected to be able to inject into small array") + testing.expect(t, slice_equal(small_array.slice(&array), []int { 0, 0, 1, 2, 3, 0, 4, 5, 6, 7, 8, 9, 0 })) +} + +slice_equal :: proc(a, b: []int) -> bool { + if len(a) != len(b) { + return false + } + + for a, i in a { + if b[i] != a { + return false + } + } + return true } From a0b2ea6d6e327dfc345b0f07c6188ae64abc2d95 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 22:12:33 +0200 Subject: [PATCH 18/93] Update `tests\core\crypto` --- tests/core/Makefile | 6 +- tests/core/build.bat | 2 +- tests/core/crypto/test_core_crypto.odin | 96 ++---- tests/core/crypto/test_core_crypto_aes.odin | 125 ++++---- .../crypto/test_core_crypto_ecc25519.odin | 293 +++++++----------- tests/core/crypto/test_core_crypto_hash.odin | 98 +++--- tests/core/crypto/test_core_crypto_kdf.odin | 54 ++-- tests/core/crypto/test_core_crypto_mac.odin | 82 ++--- .../test_core_crypto_sha3_variants.odin | 96 +++--- tests/core/crypto/test_crypto_benchmark.odin | 68 ++-- tests/core/image/test_core_image.odin | 12 +- 11 files changed, 355 insertions(+), 577 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index fff46fb69..4dede0370 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -42,15 +42,15 @@ compress_test: container_test: $(ODIN) test container $(COMMON) -define:test_progress_width=4 -out:test_core_container +crypto_test: + $(ODIN) test crypto $(COMMON) -define:test_progress_width=18 -o:speed -out:test_crypto + strings_test: $(ODIN) run strings $(COMMON) -out:test_core_strings hash_test: $(ODIN) run hash $(COMMON) -o:speed -out:test_hash -crypto_test: - $(ODIN) run crypto $(COMMON) $(COLLECTION) -o:speed -out:test_crypto - noise_test: $(ODIN) run math/noise $(COMMON) -out:test_noise diff --git a/tests/core/build.bat b/tests/core/build.bat index 07432a657..fc5e2dc3f 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -16,7 +16,7 @@ echo --- echo --- echo Running core:crypto tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% %COLLECTION% -out:test_crypto.exe || exit /b +%PATH_TO_ODIN% test crypto %COMMON% define:test_progress_width=18 -o:speed -out:test_crypto.exe || exit /b echo --- echo Running core:encoding tests diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 1f7bcece3..f3f76646b 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -13,41 +13,20 @@ package test_core_crypto */ import "core:encoding/hex" -import "core:fmt" import "core:mem" import "core:testing" +import "base:runtime" +import "core:log" import "core:crypto" import "core:crypto/chacha20" import "core:crypto/chacha20poly1305" -import tc "tests:common" - -main :: proc() { - t := testing.T{} - - test_rand_bytes(&t) - - test_hash(&t) - test_mac(&t) - test_kdf(&t) // After hash/mac tests because those should pass first. - test_ecc25519(&t) - - test_aes(&t) - test_chacha20(&t) - test_chacha20poly1305(&t) - test_sha3_variants(&t) - - bench_crypto(&t) - - tc.report(&t) -} - _PLAINTEXT_SUNSCREEN_STR := "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." @(test) test_chacha20 :: proc(t: ^testing.T) { - tc.log(t, "Testing (X)ChaCha20") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() // Test cases taken from RFC 8439, and draft-irtf-cfrg-xchacha-03 plaintext := transmute([]byte)(_PLAINTEXT_SUNSCREEN_STR) @@ -90,14 +69,12 @@ test_chacha20 :: proc(t: ^testing.T) { chacha20.xor_bytes(&ctx, derived_ciphertext[:], plaintext[:]) derived_ciphertext_str := string(hex.encode(derived_ciphertext[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_ciphertext_str == ciphertext_str, - fmt.tprintf( - "Expected %s for xor_bytes(plaintext_str), but got %s instead", - ciphertext_str, - derived_ciphertext_str, - ), + "Expected %s for xor_bytes(plaintext_str), but got %s instead", + ciphertext_str, + derived_ciphertext_str, ) xkey := [chacha20.KEY_SIZE]byte { @@ -137,21 +114,17 @@ test_chacha20 :: proc(t: ^testing.T) { chacha20.xor_bytes(&ctx, derived_ciphertext[:], plaintext[:]) derived_ciphertext_str = string(hex.encode(derived_ciphertext[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_ciphertext_str == xciphertext_str, - fmt.tprintf( - "Expected %s for xor_bytes(plaintext_str), but got %s instead", - xciphertext_str, - derived_ciphertext_str, - ), + "Expected %s for xor_bytes(plaintext_str), but got %s instead", + xciphertext_str, + derived_ciphertext_str, ) } @(test) test_chacha20poly1305 :: proc(t: ^testing.T) { - tc.log(t, "Testing chacha20poly1205") - plaintext := transmute([]byte)(_PLAINTEXT_SUNSCREEN_STR) aad := [12]byte { @@ -209,25 +182,21 @@ test_chacha20poly1305 :: proc(t: ^testing.T) { ) derived_ciphertext_str := string(hex.encode(derived_ciphertext[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_ciphertext_str == ciphertext_str, - fmt.tprintf( - "Expected ciphertext %s for encrypt(aad, plaintext), but got %s instead", - ciphertext_str, - derived_ciphertext_str, - ), + "Expected ciphertext %s for encrypt(aad, plaintext), but got %s instead", + ciphertext_str, + derived_ciphertext_str, ) derived_tag_str := string(hex.encode(derived_tag[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_tag_str == tag_str, - fmt.tprintf( - "Expected tag %s for encrypt(aad, plaintext), but got %s instead", - tag_str, - derived_tag_str, - ), + "Expected tag %s for encrypt(aad, plaintext), but got %s instead", + tag_str, + derived_tag_str, ) derived_plaintext: [114]byte @@ -240,15 +209,13 @@ test_chacha20poly1305 :: proc(t: ^testing.T) { ciphertext[:], ) derived_plaintext_str := string(derived_plaintext[:]) - tc.expect(t, ok, "Expected true for decrypt(tag, aad, ciphertext)") - tc.expect( + testing.expect(t, ok, "Expected true for decrypt(tag, aad, ciphertext)") + testing.expectf( t, derived_plaintext_str == _PLAINTEXT_SUNSCREEN_STR, - fmt.tprintf( - "Expected plaintext %s for decrypt(tag, aad, ciphertext), but got %s instead", - _PLAINTEXT_SUNSCREEN_STR, - derived_plaintext_str, - ), + "Expected plaintext %s for decrypt(tag, aad, ciphertext), but got %s instead", + _PLAINTEXT_SUNSCREEN_STR, + derived_plaintext_str, ) derived_ciphertext[0] ~= 0xa5 @@ -260,7 +227,7 @@ test_chacha20poly1305 :: proc(t: ^testing.T) { aad[:], derived_ciphertext[:], ) - tc.expect(t, !ok, "Expected false for decrypt(tag, aad, corrupted_ciphertext)") + testing.expect(t, !ok, "Expected false for decrypt(tag, aad, corrupted_ciphertext)") aad[0] ~= 0xa5 ok = chacha20poly1305.decrypt( @@ -271,15 +238,13 @@ test_chacha20poly1305 :: proc(t: ^testing.T) { aad[:], ciphertext[:], ) - tc.expect(t, !ok, "Expected false for decrypt(tag, corrupted_aad, ciphertext)") + testing.expect(t, !ok, "Expected false for decrypt(tag, corrupted_aad, ciphertext)") } @(test) test_rand_bytes :: proc(t: ^testing.T) { - tc.log(t, "Testing rand_bytes") - if !crypto.HAS_RAND_BYTES { - tc.log(t, "rand_bytes not supported - skipping") + log.info("rand_bytes not supported - skipping") return } @@ -307,10 +272,5 @@ test_rand_bytes :: proc(t: ^testing.T) { break } } - - tc.expect( - t, - seems_ok, - "Expected to randomize the head and tail of the buffer within a handful of attempts", - ) + testing.expect(t, seems_ok, "Expected to randomize the head and tail of the buffer within a handful of attempts") } diff --git a/tests/core/crypto/test_core_crypto_aes.odin b/tests/core/crypto/test_core_crypto_aes.odin index f33292a53..8b96b0ae9 100644 --- a/tests/core/crypto/test_core_crypto_aes.odin +++ b/tests/core/crypto/test_core_crypto_aes.odin @@ -2,19 +2,17 @@ package test_core_crypto import "base:runtime" import "core:encoding/hex" -import "core:fmt" +import "core:log" import "core:testing" import "core:crypto/aes" import "core:crypto/sha2" -import tc "tests:common" - @(test) test_aes :: proc(t: ^testing.T) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - tc.log(t, "Testing AES") + log.info("Testing AES") impls := make([dynamic]aes.Implementation, 0, 2) append(&impls, aes.Implementation.Portable) @@ -29,9 +27,8 @@ test_aes :: proc(t: ^testing.T) { } } -@(test) test_aes_ecb :: proc(t: ^testing.T, impl: aes.Implementation) { - tc.log(t, fmt.tprintf("Testing AES-ECB/%v", impl)) + log.infof("Testing AES-ECB/%v", impl) test_vectors := []struct { key: string, @@ -111,39 +108,34 @@ test_aes_ecb :: proc(t: ^testing.T, impl: aes.Implementation) { aes.encrypt_ecb(&ctx, dst[:], plaintext) dst_str := string(hex.encode(dst[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.ciphertext, - fmt.tprintf( - "AES-ECB/%v: Expected: %s for encrypt(%s, %s), but got %s instead", - impl, - v.ciphertext, - v.key, - v.plaintext, - dst_str, - ), + "AES-ECB/%v: Expected: %s for encrypt(%s, %s), but got %s instead", + impl, + v.ciphertext, + v.key, + v.plaintext, + dst_str, ) aes.decrypt_ecb(&ctx, dst[:], ciphertext) dst_str = string(hex.encode(dst[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.plaintext, - fmt.tprintf( - "AES-ECB/%v: Expected: %s for decrypt(%s, %s), but got %s instead", - impl, - v.plaintext, - v.key, - v.ciphertext, - dst_str, - ), + "AES-ECB/%v: Expected: %s for decrypt(%s, %s), but got %s instead", + impl, + v.plaintext, + v.key, + v.ciphertext, + dst_str, ) } } -@(test) test_aes_ctr :: proc(t: ^testing.T, impl: aes.Implementation) { - tc.log(t, fmt.tprintf("Testing AES-CTR/%v", impl)) + log.infof("Testing AES-CTR/%v", impl) test_vectors := []struct { key: string, @@ -185,18 +177,16 @@ test_aes_ctr :: proc(t: ^testing.T, impl: aes.Implementation) { aes.xor_bytes_ctr(&ctx, dst, plaintext) dst_str := string(hex.encode(dst[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.ciphertext, - fmt.tprintf( - "AES-CTR/%v: Expected: %s for encrypt(%s, %s, %s), but got %s instead", - impl, - v.ciphertext, - v.key, - v.iv, - v.plaintext, - dst_str, - ), + "AES-CTR/%v: Expected: %s for encrypt(%s, %s, %s), but got %s instead", + impl, + v.ciphertext, + v.key, + v.iv, + v.plaintext, + dst_str, ) } @@ -224,21 +214,18 @@ test_aes_ctr :: proc(t: ^testing.T, impl: aes.Implementation) { digest_str := string(hex.encode(digest[:], context.temp_allocator)) expected_digest_str := "d4445343afeb9d1237f95b10d00358aed4c1d7d57c9fe480cd0afb5e2ffd448c" - tc.expect( + testing.expectf( t, expected_digest_str == digest_str, - fmt.tprintf( - "AES-CTR/%v: Expected %s for keystream digest, but got %s instead", - impl, - expected_digest_str, - digest_str, - ), + "AES-CTR/%v: Expected %s for keystream digest, but got %s instead", + impl, + expected_digest_str, + digest_str, ) } -@(test) test_aes_gcm :: proc(t: ^testing.T, impl: aes.Implementation) { - tc.log(t, fmt.tprintf("Testing AES-GCM/%v", impl)) + log.infof("Testing AES-GCM/%v", impl) // NIST did a reorg of their site, so the source of the test vectors // is only available from an archive. The commented out tests are @@ -422,41 +409,37 @@ test_aes_gcm :: proc(t: ^testing.T, impl: aes.Implementation) { dst_str := string(hex.encode(dst[:], context.temp_allocator)) tag_str := string(hex.encode(tag_[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.ciphertext && tag_str == v.tag, - fmt.tprintf( - "AES-GCM/%v: Expected: (%s, %s) for seal(%s, %s, %s, %s), but got (%s, %s) instead", - impl, - v.ciphertext, - v.tag, - v.key, - v.iv, - v.aad, - v.plaintext, - dst_str, - tag_str, - ), + "AES-GCM/%v: Expected: (%s, %s) for seal(%s, %s, %s, %s), but got (%s, %s) instead", + impl, + v.ciphertext, + v.tag, + v.key, + v.iv, + v.aad, + v.plaintext, + dst_str, + tag_str, ) ok := aes.open_gcm(&ctx, dst, iv, aad, ciphertext, tag) dst_str = string(hex.encode(dst[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, ok && dst_str == v.plaintext, - fmt.tprintf( - "AES-GCM/%v: Expected: (%s, true) for open(%s, %s, %s, %s, %s), but got (%s, %s) instead", - impl, - v.plaintext, - v.key, - v.iv, - v.aad, - v.ciphertext, - v.tag, - dst_str, - ok, - ), + "AES-GCM/%v: Expected: (%s, true) for open(%s, %s, %s, %s, %s), but got (%s, %s) instead", + impl, + v.plaintext, + v.key, + v.iv, + v.aad, + v.ciphertext, + v.tag, + dst_str, + ok, ) } } diff --git a/tests/core/crypto/test_core_crypto_ecc25519.odin b/tests/core/crypto/test_core_crypto_ecc25519.odin index 5ea008f90..baf4a1a38 100644 --- a/tests/core/crypto/test_core_crypto_ecc25519.odin +++ b/tests/core/crypto/test_core_crypto_ecc25519.odin @@ -1,8 +1,6 @@ package test_core_crypto -import "base:runtime" import "core:encoding/hex" -import "core:fmt" import "core:testing" import field "core:crypto/_fiat/field_curve25519" @@ -10,25 +8,8 @@ import "core:crypto/ed25519" import "core:crypto/ristretto255" import "core:crypto/x25519" -import tc "tests:common" - -@(test) -test_ecc25519 :: proc(t: ^testing.T) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - tc.log(t, "Testing curve25519 ECC") - - test_sqrt_ratio_m1(t) - test_ristretto255(t) - - test_ed25519(t) - test_x25519(t) -} - @(test) test_sqrt_ratio_m1 :: proc(t: ^testing.T) { - tc.log(t, "Testing sqrt_ratio_m1") - test_vectors := []struct { u: string, v: string, @@ -90,25 +71,21 @@ test_sqrt_ratio_m1 :: proc(t: ^testing.T) { field.fe_relax_cast(&vee), ) - tc.expect( + testing.expectf( t, (was_square == 1) == v.was_square && field.fe_equal_bytes(&r, r_) == 1, - fmt.tprintf( - "Expected (%v, %s) for SQRT_RATIO_M1(%s, %s), got %s", - v.was_square, - v.r, - v.u, - v.v, - fe_str(&r), - ), + "Expected (%v, %s) for SQRT_RATIO_M1(%s, %s), got %s", + v.was_square, + v.r, + v.u, + v.v, + fe_str(&r), ) } } @(test) test_ristretto255 :: proc(t: ^testing.T) { - tc.log(t, "Testing ristretto255") - ge_gen: ristretto255.Group_Element ristretto255.ge_generator(&ge_gen) @@ -158,7 +135,7 @@ test_ristretto255 :: proc(t: ^testing.T) { ge: ristretto255.Group_Element ok := ristretto255.ge_set_bytes(&ge, b) - tc.expect(t, !ok, fmt.tprintf("Expected false for %s", x)) + testing.expectf(t, !ok, "Expected false for %s", x) } generator_multiples := []string { @@ -185,22 +162,20 @@ test_ristretto255 :: proc(t: ^testing.T) { ge := &ges[i] ok := ristretto255.ge_set_bytes(ge, b) - tc.expect(t, ok, fmt.tprintf("Expected true for %s", x)) + testing.expectf(t, ok, "Expected true for %s", x) x_check := ge_str(ge) - tc.expect( + testing.expectf( t, x == x_check, - fmt.tprintf( - "Expected %s (round-trip) but got %s instead", - x, - x_check, - ), + "Expected %s (round-trip) but got %s instead", + x, + x_check, ) if i == 1 { - tc.expect( + testing.expect( t, ristretto255.ge_equal(ge, &ge_gen) == 1, "Expected element 1 to be the generator", @@ -217,41 +192,35 @@ test_ristretto255 :: proc(t: ^testing.T) { ristretto255.ge_scalarmult_generator(&ge_check, &sc) x_check := ge_str(&ge_check) - tc.expect( + testing.expectf( t, x_check == generator_multiples[i], - fmt.tprintf( - "Expected %s for G * %d (specialized), got %s", - generator_multiples[i], - i, - x_check, - ), + "Expected %s for G * %d (specialized), got %s", + generator_multiples[i], + i, + x_check, ) ristretto255.ge_scalarmult(&ge_check, &ges[1], &sc) x_check = ge_str(&ge_check) - tc.expect( + testing.expectf( t, x_check == generator_multiples[i], - fmt.tprintf( - "Expected %s for G * %d (generic), got %s (slow compare)", - generator_multiples[i], - i, - x_check, - ), + "Expected %s for G * %d (generic), got %s (slow compare)", + generator_multiples[i], + i, + x_check, ) ristretto255.ge_scalarmult_vartime(&ge_check, &ges[1], &sc) x_check = ge_str(&ge_check) - tc.expect( + testing.expectf( t, x_check == generator_multiples[i], - fmt.tprintf( - "Expected %s for G * %d (generic vartime), got %s (slow compare)", - generator_multiples[i], - i, - x_check, - ), + "Expected %s for G * %d (generic vartime), got %s (slow compare)", + generator_multiples[i], + i, + x_check, ) switch i { @@ -261,28 +230,24 @@ test_ristretto255 :: proc(t: ^testing.T) { ristretto255.ge_add(&ge_check, ge_prev, &ge_gen) x_check = ge_str(&ge_check) - tc.expect( + testing.expectf( t, x_check == generator_multiples[i], - fmt.tprintf( - "Expected %s for ges[%d] + ges[%d], got %s (slow compare)", - generator_multiples[i], - i-1, - 1, - x_check, - ), + "Expected %s for ges[%d] + ges[%d], got %s (slow compare)", + generator_multiples[i], + i-1, + 1, + x_check, ) - tc.expect( + testing.expectf( t, ristretto255.ge_equal(&ges[i], &ge_check) == 1, - fmt.tprintf( - "Expected %s for ges[%d] + ges[%d], got %s (fast compare)", - generator_multiples[i], - i-1, - 1, - x_check, - ), + "Expected %s for ges[%d] + ges[%d], got %s (fast compare)", + generator_multiples[i], + i-1, + 1, + x_check, ) } } @@ -344,22 +309,18 @@ test_ristretto255 :: proc(t: ^testing.T) { ristretto255.ge_set_wide_bytes(&ge, in_bytes) ge_check := ge_str(&ge) - tc.expect( + testing.expectf( t, ge_check == v.output, - fmt.tprintf( - "Expected %s for %s, got %s", - v.output, - ge_check, - ), + "Expected %s for %s, got %s", + v.output, + ge_check, ) } } @(test) test_ed25519 :: proc(t: ^testing.T) { - tc.log(t, "Testing ed25519") - test_vectors_rfc := []struct { priv_key: string, pub_key: string, @@ -401,87 +362,73 @@ test_ed25519 :: proc(t: ^testing.T) { priv_key: ed25519.Private_Key ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) - tc.expect( + testing.expectf( t, ok, - fmt.tprintf( - "Expected %s to be a valid private key", - v.priv_key, - ), + "Expected %s to be a valid private key", + v.priv_key, ) key_bytes: [32]byte ed25519.private_key_bytes(&priv_key, key_bytes[:]) - tc.expect( + testing.expectf( t, ok, - fmt.tprintf( - "Expected private key %s round-trip, got %s", - v.priv_key, - string(hex.encode(key_bytes[:], context.temp_allocator)), - ), + "Expected private key %s round-trip, got %s", + v.priv_key, + string(hex.encode(key_bytes[:], context.temp_allocator)), ) pub_key: ed25519.Public_Key ok = ed25519.public_key_set_bytes(&pub_key, pub_bytes) - tc.expect( + testing.expectf( t, ok, - fmt.tprintf( - "Expected %s to be a valid public key (priv->pub: %s)", - v.pub_key, - string(hex.encode(priv_key._pub_key._b[:], context.temp_allocator)), - ), + "Expected %s to be a valid public key (priv->pub: %s)", + v.pub_key, + string(hex.encode(priv_key._pub_key._b[:], context.temp_allocator)), ) ed25519.public_key_bytes(&pub_key, key_bytes[:]) - tc.expect( + testing.expectf( t, ok, - fmt.tprintf( - "Expected public key %s round-trip, got %s", - v.pub_key, - string(hex.encode(key_bytes[:], context.temp_allocator)), - ), + "Expected public key %s round-trip, got %s", + v.pub_key, + string(hex.encode(key_bytes[:], context.temp_allocator)), ) sig: [ed25519.SIGNATURE_SIZE]byte ed25519.sign(&priv_key, msg_bytes, sig[:]) x := string(hex.encode(sig[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, x == v.sig, - fmt.tprintf( - "Expected %s for sign(%s, %s), got %s", - v.sig, - v.priv_key, - v.msg, - x, - ), + "Expected %s for sign(%s, %s), got %s", + v.sig, + v.priv_key, + v.msg, + x, ) ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) - tc.expect( + testing.expectf( t, ok, - fmt.tprintf( - "Expected true for verify(%s, %s, %s)", - v.pub_key, - v.msg, - v.sig, - ), + "Expected true for verify(%s, %s, %s)", + v.pub_key, + v.msg, + v.sig, ) ok = ed25519.verify(&priv_key._pub_key, msg_bytes, sig_bytes) - tc.expect( + testing.expectf( t, ok, - fmt.tprintf( - "Expected true for verify(pub(%s), %s %s)", - v.priv_key, - v.msg, - v.sig, - ), + "Expected true for verify(pub(%s), %s %s)", + v.priv_key, + v.msg, + v.sig, ) // Corrupt the message and make sure verification fails. @@ -493,15 +440,13 @@ test_ed25519 :: proc(t: ^testing.T) { msg_bytes[0] = msg_bytes[0] ~ 69 } ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) - tc.expect( + testing.expectf( t, ok == false, - fmt.tprintf( - "Expected false for verify(%s, %s (corrupted), %s)", - v.pub_key, - v.msg, - v.sig, - ), + "Expected false for verify(%s, %s (corrupted), %s)", + v.pub_key, + v.msg, + v.sig, ) } @@ -634,15 +579,13 @@ test_ed25519 :: proc(t: ^testing.T) { pub_key: ed25519.Public_Key ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes) - tc.expect( + testing.expectf( t, ok == v.pub_key_ok, - fmt.tprintf( - "speccheck/%d: Expected %s to be a (in)valid public key, got %v", - i, - v.pub_key, - ok, - ), + "speccheck/%d: Expected %s to be a (in)valid public key, got %v", + i, + v.pub_key, + ok, ) // If A is rejected for being non-canonical, skip signature check. @@ -651,17 +594,15 @@ test_ed25519 :: proc(t: ^testing.T) { } ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes) - tc.expect( + testing.expectf( t, ok == v.sig_ok, - fmt.tprintf( - "speccheck/%d Expected %v for verify(%s, %s, %s)", - i, - v.sig_ok, - v.pub_key, - v.msg, - v.sig, - ), + "speccheck/%d Expected %v for verify(%s, %s, %s)", + i, + v.sig_ok, + v.pub_key, + v.msg, + v.sig, ) // If the signature is accepted, skip the relaxed signature check. @@ -670,25 +611,21 @@ test_ed25519 :: proc(t: ^testing.T) { } ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes, true) - tc.expect( + testing.expectf( t, ok == v.sig_ok_relaxed, - fmt.tprintf( - "speccheck/%d Expected %v for verify(%s, %s, %s, true)", - i, - v.sig_ok_relaxed, - v.pub_key, - v.msg, - v.sig, - ), + "speccheck/%d Expected %v for verify(%s, %s, %s, true)", + i, + v.sig_ok_relaxed, + v.pub_key, + v.msg, + v.sig, ) } } @(test) test_x25519 :: proc(t: ^testing.T) { - tc.log(t, "Testing X25519") - // Local copy of this so that the base point doesn't need to be exported. _BASE_POINT: [32]byte = { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -720,17 +657,15 @@ test_x25519 :: proc(t: ^testing.T) { x25519.scalarmult(derived_point[:], scalar[:], point[:]) derived_point_str := string(hex.encode(derived_point[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_point_str == v.product, - fmt.tprintf( - "Expected %s for %s * %s, but got %s instead", - v.product, - v.scalar, - v.point, - derived_point_str, - ), - ) + "Expected %s for %s * %s, but got %s instead", + v.product, + v.scalar, + v.point, + derived_point_str, + ) // Abuse the test vectors to sanity-check the scalar-basepoint multiply. p1, p2: [x25519.POINT_SIZE]byte @@ -738,15 +673,13 @@ test_x25519 :: proc(t: ^testing.T) { x25519.scalarmult(p2[:], scalar[:], _BASE_POINT[:]) p1_str := string(hex.encode(p1[:], context.temp_allocator)) p2_str := string(hex.encode(p2[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, p1_str == p2_str, - fmt.tprintf( - "Expected %s for %s * basepoint, but got %s instead", - p2_str, - v.scalar, - p1_str, - ), + "Expected %s for %s * basepoint, but got %s instead", + p2_str, + v.scalar, + p1_str, ) } } @@ -763,4 +696,4 @@ fe_str :: proc(fe: ^field.Tight_Field_Element) -> string { b: [32]byte field.fe_to_bytes(&b, fe) return string(hex.encode(b[:], context.temp_allocator)) -} +} \ No newline at end of file diff --git a/tests/core/crypto/test_core_crypto_hash.odin b/tests/core/crypto/test_core_crypto_hash.odin index c4e8e8dd7..9a9d0cc76 100644 --- a/tests/core/crypto/test_core_crypto_hash.odin +++ b/tests/core/crypto/test_core_crypto_hash.odin @@ -3,23 +3,17 @@ package test_core_crypto import "base:runtime" import "core:bytes" import "core:encoding/hex" -import "core:fmt" import "core:strings" import "core:testing" - import "core:crypto/hash" -import tc "tests:common" - @(test) test_hash :: proc(t: ^testing.T) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - tc.log(t, "Testing Hashes") - // TODO: // - Stick the test vectors in a JSON file or something. - data_1_000_000_a := strings.repeat("a", 1_000_000) + data_1_000_000_a := strings.repeat("a", 1_000_000, context.temp_allocator) digest: [hash.MAX_DIGEST_SIZE]byte test_vectors := []struct{ @@ -496,16 +490,14 @@ test_hash :: proc(t: ^testing.T) { dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.hash, - fmt.tprintf( - "%s/incremental: Expected: %s for input of %s, but got %s instead", - algo_name, - v.hash, - v.str, - dst_str, - ), + "%s/incremental: Expected: %s for input of %s, but got %s instead", + algo_name, + v.hash, + v.str, + dst_str, ) } @@ -521,25 +513,21 @@ test_hash :: proc(t: ^testing.T) { // still correct. digest_sz := hash.DIGEST_SIZES[algo] block_sz := hash.BLOCK_SIZES[algo] - tc.expect( + testing.expectf( t, digest_sz <= hash.MAX_DIGEST_SIZE, - fmt.tprintf( - "%s: Digest size %d exceeds max %d", - algo_name, - digest_sz, - hash.MAX_DIGEST_SIZE, - ), + "%s: Digest size %d exceeds max %d", + algo_name, + digest_sz, + hash.MAX_DIGEST_SIZE, ) - tc.expect( + testing.expectf( t, block_sz <= hash.MAX_BLOCK_SIZE, - fmt.tprintf( - "%s: Block size %d exceeds max %d", - algo_name, - block_sz, - hash.MAX_BLOCK_SIZE, - ), + "%s: Block size %d exceeds max %d", + algo_name, + block_sz, + hash.MAX_BLOCK_SIZE, ) // Exercise most of the happy-path for the high level interface. @@ -553,15 +541,13 @@ test_hash :: proc(t: ^testing.T) { a_str := string(hex.encode(digest_a, context.temp_allocator)) b_str := string(hex.encode(digest_b, context.temp_allocator)) - tc.expect( + testing.expectf( t, a_str == b_str, - fmt.tprintf( - "%s/cmp: Expected: %s (hash_stream) == %s (hash_bytes)", - algo_name, - a_str, - b_str, - ), + "%s/cmp: Expected: %s (hash_stream) == %s (hash_bytes)", + algo_name, + a_str, + b_str, ) // Exercise the rolling digest functionality, which also covers @@ -571,25 +557,21 @@ test_hash :: proc(t: ^testing.T) { api_algo := hash.algorithm(&ctx) api_digest_size := hash.digest_size(&ctx) - tc.expect( + testing.expectf( t, algo == api_algo, - fmt.tprintf( - "%s/algorithm: Expected: %v but got %v instead", - algo_name, - algo, - api_algo, - ), + "%s/algorithm: Expected: %v but got %v instead", + algo_name, + algo, + api_algo, ) - tc.expect( + testing.expectf( t, hash.DIGEST_SIZES[algo] == api_digest_size, - fmt.tprintf( - "%s/digest_size: Expected: %d but got %d instead", - algo_name, - hash.DIGEST_SIZES[algo], - api_digest_size, - ), + "%s/digest_size: Expected: %d but got %d instead", + algo_name, + hash.DIGEST_SIZES[algo], + api_digest_size, ) hash.update(&ctx, digest_a) @@ -604,16 +586,14 @@ test_hash :: proc(t: ^testing.T) { b_str = string(hex.encode(digest_b, context.temp_allocator)) c_str := string(hex.encode(digest_c, context.temp_allocator)) - tc.expect( + testing.expectf( t, a_str == b_str && b_str == c_str, - fmt.tprintf( - "%s/rolling: Expected: %s (first) == %s (second) == %s (third)", - algo_name, - a_str, - b_str, - c_str, - ), + "%s/rolling: Expected: %s (first) == %s (second) == %s (third)", + algo_name, + a_str, + b_str, + c_str, ) } -} +} \ No newline at end of file diff --git a/tests/core/crypto/test_core_crypto_kdf.odin b/tests/core/crypto/test_core_crypto_kdf.odin index 73177d8be..247529e65 100644 --- a/tests/core/crypto/test_core_crypto_kdf.odin +++ b/tests/core/crypto/test_core_crypto_kdf.odin @@ -2,28 +2,14 @@ package test_core_crypto import "base:runtime" import "core:encoding/hex" -import "core:fmt" import "core:testing" - import "core:crypto/hash" import "core:crypto/hkdf" import "core:crypto/pbkdf2" -import tc "tests:common" - -@(test) -test_kdf :: proc(t: ^testing.T) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - tc.log(t, "Testing KDFs") - - test_hkdf(t) - test_pbkdf2(t) -} - @(test) test_hkdf :: proc(t: ^testing.T) { - tc.log(t, "Testing HKDF") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() tmp: [128]byte // Good enough. @@ -70,25 +56,23 @@ test_hkdf :: proc(t: ^testing.T) { dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.okm, - fmt.tprintf( - "HKDF-%s: Expected: %s for input of (%s, %s, %s), but got %s instead", - algo_name, - v.okm, - v.ikm, - v.salt, - v.info, - dst_str, - ), + "HKDF-%s: Expected: %s for input of (%s, %s, %s), but got %s instead", + algo_name, + v.okm, + v.ikm, + v.salt, + v.info, + dst_str, ) } } @(test) test_pbkdf2 :: proc(t: ^testing.T) { - tc.log(t, "Testing PBKDF2") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() tmp: [64]byte // 512-bits is enough for every output for now. @@ -174,18 +158,16 @@ test_pbkdf2 :: proc(t: ^testing.T) { dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.dk, - fmt.tprintf( - "HMAC-%s: Expected: %s for input of (%s, %s, %d), but got %s instead", - algo_name, - v.dk, - v.password, - v.salt, - v.iterations, - dst_str, - ), + "HMAC-%s: Expected: %s for input of (%s, %s, %d), but got %s instead", + algo_name, + v.dk, + v.password, + v.salt, + v.iterations, + dst_str, ) } } diff --git a/tests/core/crypto/test_core_crypto_mac.odin b/tests/core/crypto/test_core_crypto_mac.odin index f2eeacb19..ed95ba0ad 100644 --- a/tests/core/crypto/test_core_crypto_mac.odin +++ b/tests/core/crypto/test_core_crypto_mac.odin @@ -2,30 +2,17 @@ package test_core_crypto import "base:runtime" import "core:encoding/hex" -import "core:fmt" import "core:mem" import "core:testing" - import "core:crypto/hash" import "core:crypto/hmac" import "core:crypto/poly1305" import "core:crypto/siphash" -import tc "tests:common" - -@(test) -test_mac :: proc(t: ^testing.T) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - tc.log(t, "Testing MACs") - - test_hmac(t) - test_poly1305(t) - test_siphash_2_4(t) -} - @(test) test_hmac :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + // Test cases pulled out of RFC 6234, note that HMAC is a generic // construct so as long as the underlying hash is correct and all // the code paths are covered the implementation is "fine", so @@ -86,40 +73,36 @@ test_hmac :: proc(t: ^testing.T) { msg_str := string(hex.encode(msg, context.temp_allocator)) dst_str := string(hex.encode(dst[:tag_len], context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == expected_str, - fmt.tprintf( - "%s/incremental: Expected: %s for input of %s - %s, but got %s instead", - algo_name, - tags_sha256[i], - key_str, - msg_str, - dst_str, - ), + "%s/incremental: Expected: %s for input of %s - %s, but got %s instead", + algo_name, + tags_sha256[i], + key_str, + msg_str, + dst_str, ) hmac.sum(algo, dst, msg, key) oneshot_str := string(hex.encode(dst[:tag_len], context.temp_allocator)) - tc.expect( + testing.expectf( t, oneshot_str == expected_str, - fmt.tprintf( - "%s/oneshot: Expected: %s for input of %s - %s, but got %s instead", - algo_name, - tags_sha256[i], - key_str, - msg_str, - oneshot_str, - ), + "%s/oneshot: Expected: %s for input of %s - %s, but got %s instead", + algo_name, + tags_sha256[i], + key_str, + msg_str, + oneshot_str, ) } } @(test) test_poly1305 :: proc(t: ^testing.T) { - tc.log(t, "Testing poly1305") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() // Test cases taken from poly1305-donna. key := [poly1305.KEY_SIZE]byte { @@ -157,16 +140,17 @@ test_poly1305 :: proc(t: ^testing.T) { // Verify - oneshot + compare ok := poly1305.verify(tag[:], msg[:], key[:]) - tc.expect(t, ok, "oneshot verify call failed") + testing.expect(t, ok, "oneshot verify call failed") // Sum - oneshot derived_tag: [poly1305.TAG_SIZE]byte poly1305.sum(derived_tag[:], msg[:], key[:]) derived_tag_str := string(hex.encode(derived_tag[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_tag_str == tag_str, - fmt.tprintf("Expected %s for sum(msg, key), but got %s instead", tag_str, derived_tag_str), + "Expected %s for sum(msg, key), but got %s instead", + tag_str, derived_tag_str, ) // Incremental @@ -182,21 +166,16 @@ test_poly1305 :: proc(t: ^testing.T) { } poly1305.final(&ctx, derived_tag[:]) derived_tag_str = string(hex.encode(derived_tag[:], context.temp_allocator)) - tc.expect( + testing.expectf( t, derived_tag_str == tag_str, - fmt.tprintf( - "Expected %s for init/update/final - incremental, but got %s instead", - tag_str, - derived_tag_str, - ), + "Expected %s for init/update/final - incremental, but got %s instead", + tag_str, derived_tag_str, ) } @(test) test_siphash_2_4 :: proc(t: ^testing.T) { - tc.log(t, "Testing SipHash-2-4") - // Test vectors from // https://github.com/veorq/SipHash/blob/master/vectors.h test_vectors := [?]u64 { @@ -225,6 +204,7 @@ test_siphash_2_4 :: proc(t: ^testing.T) { for i in 0 ..< len(test_vectors) { data := make([]byte, i) + defer delete(data) for j in 0 ..< i { data[j] = byte(j) } @@ -232,15 +212,13 @@ test_siphash_2_4 :: proc(t: ^testing.T) { vector := test_vectors[i] computed := siphash.sum_2_4(data[:], key[:]) - tc.expect( + testing.expectf( t, computed == vector, - fmt.tprintf( - "Expected: 0x%x for input of %v, but got 0x%x instead", - vector, - data, - computed, - ), + "Expected: 0x%x for input of %v, but got 0x%x instead", + vector, + data, + computed, ) } } diff --git a/tests/core/crypto/test_core_crypto_sha3_variants.odin b/tests/core/crypto/test_core_crypto_sha3_variants.odin index 8e44996bc..c11868e72 100644 --- a/tests/core/crypto/test_core_crypto_sha3_variants.odin +++ b/tests/core/crypto/test_core_crypto_sha3_variants.odin @@ -2,30 +2,14 @@ package test_core_crypto import "base:runtime" import "core:encoding/hex" -import "core:fmt" import "core:testing" - import "core:crypto/kmac" import "core:crypto/shake" import "core:crypto/tuplehash" -import tc "tests:common" - -@(test) -test_sha3_variants :: proc(t: ^testing.T) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - tc.log(t, "Testing SHA3 derived functions") - - test_shake(t) - test_cshake(t) - test_tuplehash(t) - test_kmac(t) -} - @(test) test_shake :: proc(t: ^testing.T) { - tc.log(t, "Testing SHAKE") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() test_vectors := []struct { sec_strength: int, @@ -67,23 +51,21 @@ test_shake :: proc(t: ^testing.T) { dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.output, - fmt.tprintf( - "SHAKE%d: Expected: %s for input of %s, but got %s instead", - v.sec_strength, - v.output, - v.str, - dst_str, - ), + "SHAKE%d: Expected: %s for input of %s, but got %s instead", + v.sec_strength, + v.output, + v.str, + dst_str, ) } } @(test) test_cshake :: proc(t: ^testing.T) { - tc.log(t, "Testing cSHAKE") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() test_vectors := []struct { sec_strength: int, @@ -135,29 +117,27 @@ test_cshake :: proc(t: ^testing.T) { shake.init_cshake_256(&ctx, domainsep) } - data, _ := hex.decode(transmute([]byte)(v.str)) + data, _ := hex.decode(transmute([]byte)(v.str), context.temp_allocator) shake.write(&ctx, data) shake.read(&ctx, dst) dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.output, - fmt.tprintf( - "cSHAKE%d: Expected: %s for input of %s, but got %s instead", - v.sec_strength, - v.output, - v.str, - dst_str, - ), + "cSHAKE%d: Expected: %s for input of %s, but got %s instead", + v.sec_strength, + v.output, + v.str, + dst_str, ) } } @(test) test_tuplehash :: proc(t: ^testing.T) { - tc.log(t, "Testing TupleHash(XOF)") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() test_vectors := []struct { sec_strength: int, @@ -317,7 +297,7 @@ test_tuplehash :: proc(t: ^testing.T) { } for e in v.tuple { - data, _ := hex.decode(transmute([]byte)(e)) + data, _ := hex.decode(transmute([]byte)(e), context.temp_allocator) tuplehash.write_element(&ctx, data) } @@ -332,24 +312,22 @@ test_tuplehash :: proc(t: ^testing.T) { dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.output, - fmt.tprintf( - "TupleHash%s%d: Expected: %s for input of %v, but got %s instead", - suffix, - v.sec_strength, - v.output, - v.tuple, - dst_str, - ), + "TupleHash%s%d: Expected: %s for input of %v, but got %s instead", + suffix, + v.sec_strength, + v.output, + v.tuple, + dst_str, ) } } @(test) test_kmac :: proc(t:^testing.T) { - tc.log(t, "Testing KMAC") + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() test_vectors := []struct { sec_strength: int, @@ -410,7 +388,7 @@ test_kmac :: proc(t:^testing.T) { for v in test_vectors { dst := make([]byte, len(v.output) / 2, context.temp_allocator) - key, _ := hex.decode(transmute([]byte)(v.key)) + key, _ := hex.decode(transmute([]byte)(v.key), context.temp_allocator) domainsep := transmute([]byte)(v.domainsep) ctx: kmac.Context @@ -421,24 +399,22 @@ test_kmac :: proc(t:^testing.T) { kmac.init_256(&ctx, key, domainsep) } - data, _ := hex.decode(transmute([]byte)(v.msg)) + data, _ := hex.decode(transmute([]byte)(v.msg), context.temp_allocator) kmac.update(&ctx, data) kmac.final(&ctx, dst) dst_str := string(hex.encode(dst, context.temp_allocator)) - tc.expect( + testing.expectf( t, dst_str == v.output, - fmt.tprintf( - "KMAC%d: Expected: %s for input of (%s, %s, %s), but got %s instead", - v.sec_strength, - v.output, - v.key, - v.domainsep, - v.msg, - dst_str, - ), + "KMAC%d: Expected: %s for input of (%s, %s, %s), but got %s instead", + v.sec_strength, + v.output, + v.key, + v.domainsep, + v.msg, + dst_str, ) } -} +} \ No newline at end of file diff --git a/tests/core/crypto/test_crypto_benchmark.odin b/tests/core/crypto/test_crypto_benchmark.odin index 600dc9ade..5bfc579bd 100644 --- a/tests/core/crypto/test_crypto_benchmark.odin +++ b/tests/core/crypto/test_crypto_benchmark.odin @@ -2,7 +2,7 @@ package test_core_crypto import "base:runtime" import "core:encoding/hex" -import "core:fmt" +import "core:log" import "core:testing" import "core:time" @@ -13,16 +13,11 @@ import "core:crypto/ed25519" import "core:crypto/poly1305" import "core:crypto/x25519" -import tc "tests:common" - // Cryptographic primitive benchmarks. @(test) bench_crypto :: proc(t: ^testing.T) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - fmt.println("Starting benchmarks:") - bench_chacha20(t) bench_poly1305(t) bench_chacha20poly1305(t) @@ -157,8 +152,8 @@ _benchmark_aes256_gcm :: proc( } benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { - fmt.printf( - "\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", + log.infof( + "\n\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s", name, options.rounds, options.processed, @@ -179,19 +174,19 @@ bench_chacha20 :: proc(t: ^testing.T) { } err := time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "ChaCha20 1024 bytes" options.bytes = 1024 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "ChaCha20 65536 bytes" options.bytes = 65536 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) } @@ -206,13 +201,13 @@ bench_poly1305 :: proc(t: ^testing.T) { } err := time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "Poly1305 1024 zero bytes" options.bytes = 1024 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) } @@ -227,19 +222,19 @@ bench_chacha20poly1305 :: proc(t: ^testing.T) { } err := time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "chacha20poly1305 1024 bytes" options.bytes = 1024 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "chacha20poly1305 65536 bytes" options.bytes = 65536 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) } @@ -265,19 +260,19 @@ bench_aes256_gcm :: proc(t: ^testing.T) { context.user_ptr = &ctx err := time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "AES256-GCM 1024 bytes" options.bytes = 1024 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) name = "AES256-GCM 65536 bytes" options.bytes = 65536 err = time.benchmark(options, context.allocator) - tc.expect(t, err == nil, name) + testing.expect(t, err == nil, name) benchmark_print(name, options) } @@ -293,12 +288,9 @@ bench_ed25519 :: proc(t: ^testing.T) { assert(ok, "private key should deserialize") } elapsed := time.since(start) - tc.log( - t, - fmt.tprintf( - "ed25519.private_key_set_bytes: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ), + log.infof( + "ed25519.private_key_set_bytes: ~%f us/op", + time.duration_microseconds(elapsed) / iters, ) pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing" @@ -309,12 +301,9 @@ bench_ed25519 :: proc(t: ^testing.T) { assert(ok, "public key should deserialize") } elapsed = time.since(start) - tc.log( - t, - fmt.tprintf( - "ed25519.public_key_set_bytes: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ), + log.infof( + "ed25519.public_key_set_bytes: ~%f us/op", + time.duration_microseconds(elapsed) / iters, ) msg := "Got a job for you, 621." @@ -325,7 +314,10 @@ bench_ed25519 :: proc(t: ^testing.T) { ed25519.sign(&priv_key, msg_bytes, sig_bytes[:]) } elapsed = time.since(start) - tc.log(t, fmt.tprintf("ed25519.sign: ~%f us/op", time.duration_microseconds(elapsed) / iters)) + log.infof( + "ed25519.sign: ~%f us/op", + time.duration_microseconds(elapsed) / iters, + ) start = time.now() for i := 0; i < iters; i = i + 1 { @@ -333,9 +325,9 @@ bench_ed25519 :: proc(t: ^testing.T) { assert(ok, "signature should validate") } elapsed = time.since(start) - tc.log( - t, - fmt.tprintf("ed25519.verify: ~%f us/op", time.duration_microseconds(elapsed) / iters), + log.infof( + "ed25519.verify: ~%f us/op", + time.duration_microseconds(elapsed) / iters, ) } @@ -354,8 +346,8 @@ bench_x25519 :: proc(t: ^testing.T) { } elapsed := time.since(start) - tc.log( - t, - fmt.tprintf("x25519.scalarmult: ~%f us/op", time.duration_microseconds(elapsed) / iters), + log.infof( + "x25519.scalarmult: ~%f us/op", + time.duration_microseconds(elapsed) / iters, ) } diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index e3bef6c9d..7fc04ce6b 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -23,9 +23,8 @@ import "core:hash" import "core:strings" import "core:mem" import "core:time" -import "base:runtime" -TEST_SUITE_PATH :: "assets/PNG" +TEST_SUITE_PATH :: ODIN_ROOT + "tests/core/assets/PNG/" I_Error :: image.Error @@ -1455,10 +1454,9 @@ png_test_no_postproc :: proc(t: ^testing.T) { } run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) { - context = runtime.default_context() - for file in suite { - test_file := strings.concatenate({TEST_SUITE_PATH, "/", file.file, ".png"}, context.temp_allocator) + test_file := strings.concatenate({TEST_SUITE_PATH, file.file, ".png"}) + defer delete(test_file) img: ^png.Image err: png.Error @@ -1467,10 +1465,6 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) { for test in file.tests { count += 1 - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - img, err = png.load(test_file, test.options) passed := (test.expected_error == nil && err == nil) || (test.expected_error == err) From 568b746c9897ea4b343d454309d6d1275a4a5320 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 16:39:20 -0400 Subject: [PATCH 19/93] Fix indentation --- core/mem/rollback_stack_allocator.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index bf397d2c8..6fa86ab0b 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -292,7 +292,7 @@ rollback_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mo } case .Free: - err = rb_free(stack, old_memory) + err = rb_free(stack, old_memory) case .Free_All: rb_free_all(stack) From 0f675fa4368253e8ebdf9dad325bbba2101ecd22 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 19:36:20 -0400 Subject: [PATCH 20/93] Use `uintptr` where applicable in `mem.Rollback_Stack` --- core/mem/rollback_stack_allocator.odin | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index 6fa86ab0b..104ad0e95 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -38,19 +38,19 @@ ROLLBACK_STACK_DEFAULT_BLOCK_SIZE :: 4 * Megabyte // // This is because allocations over the block size are not split up if the item // within is freed; they are immediately returned to the block allocator. -ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE :: 1 * Gigabyte +ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE :: 2 * Gigabyte Rollback_Stack_Header :: bit_field u64 { - prev_offset: int | 32, - is_free: bool | 1, - prev_ptr: int | 31, + prev_offset: uintptr | 32, + is_free: bool | 1, + prev_ptr: uintptr | 31, } Rollback_Stack_Block :: struct { next_block: ^Rollback_Stack_Block, last_alloc: rawptr, - offset: int, + offset: uintptr, buffer: []byte, } @@ -65,7 +65,7 @@ Rollback_Stack :: struct { @(require_results) rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool { start := cast(uintptr)raw_data(block.buffer) - end := cast(uintptr)raw_data(block.buffer) + cast(uintptr)block.offset + end := cast(uintptr)raw_data(block.buffer) + block.offset return start < cast(uintptr)ptr && cast(uintptr)ptr <= end } @@ -150,8 +150,8 @@ rb_free_all :: proc(stack: ^Rollback_Stack) { rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment: int) -> (result: []byte, err: Allocator_Error) { if ptr != nil { if block, _, ok := rb_find_last_alloc(stack, ptr); ok { - if block.offset + (size - old_size) < len(block.buffer) { - block.offset += (size - old_size) + if block.offset + cast(uintptr)size - cast(uintptr)old_size < cast(uintptr)len(block.buffer) { + block.offset += cast(uintptr)size - cast(uintptr)old_size #no_bounds_check return (cast([^]byte)ptr)[:size], nil } } @@ -180,10 +180,10 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt parent.next_block = block } - start := cast(uintptr)raw_data(block.buffer) + cast(uintptr)block.offset - padding := calc_padding_with_header(start, cast(uintptr)alignment, size_of(Rollback_Stack_Header)) + start := cast(uintptr)raw_data(block.buffer) + block.offset + padding := cast(uintptr)calc_padding_with_header(start, cast(uintptr)alignment, size_of(Rollback_Stack_Header)) - if block.offset + padding + size > len(block.buffer) { + if block.offset + padding + cast(uintptr)size > cast(uintptr)len(block.buffer) { parent = block continue } @@ -193,17 +193,17 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt header^ = { prev_offset = block.offset, - prev_ptr = max(0, cast(int)(cast(uintptr)block.last_alloc - cast(uintptr)raw_data(block.buffer))), + prev_ptr = uintptr(0) if block.last_alloc == nil else cast(uintptr)block.last_alloc - cast(uintptr)raw_data(block.buffer), is_free = false, } block.last_alloc = ptr - block.offset += padding + size + block.offset += padding + cast(uintptr)size if len(block.buffer) > stack.block_size { // This block exceeds the allocator's standard block size and is considered a singleton. // Prevent any further allocations on it. - block.offset = len(block.buffer) + block.offset = cast(uintptr)len(block.buffer) } #no_bounds_check return ptr[:size], nil @@ -242,7 +242,7 @@ rollback_stack_init_dynamic :: proc( block_allocator := context.allocator, ) -> Allocator_Error { assert(block_size >= size_of(Rollback_Stack_Header) + size_of(rawptr), "Rollback Stack Allocator block size is too small.") - assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 1 gigabyte.") + assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 2 gigabytes.") block := rb_make_block(block_size, block_allocator) or_return From 09ef08f0354cd68ca589e3c6d094f08d08a48d78 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 18:23:05 -0400 Subject: [PATCH 21/93] Add more sanity checking to `mem.Rollback_Stack` --- core/mem/rollback_stack_allocator.odin | 31 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index 104ad0e95..a3f6647cf 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -150,6 +150,10 @@ rb_free_all :: proc(stack: ^Rollback_Stack) { rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment: int) -> (result: []byte, err: Allocator_Error) { if ptr != nil { if block, _, ok := rb_find_last_alloc(stack, ptr); ok { + // `block.offset` should never underflow because it is contingent + // on `old_size` in the first place, assuming sane arguments. + assert(block.offset >= cast(uintptr)old_size, "Rollback Stack Allocator received invalid `old_size`.") + if block.offset + cast(uintptr)size - cast(uintptr)old_size < cast(uintptr)len(block.buffer) { block.offset += cast(uintptr)size - cast(uintptr)old_size #no_bounds_check return (cast([^]byte)ptr)[:size], nil @@ -169,6 +173,10 @@ rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byte, err: Allocator_Error) { parent: ^Rollback_Stack_Block for block := stack.head; /**/; block = block.next_block { + when !ODIN_DISABLE_ASSERT { + allocated_new_block: bool + } + if block == nil { if stack.block_allocator.procedure == nil { return nil, .Out_Of_Memory @@ -178,12 +186,20 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt new_block_size := max(minimum_size_required, stack.block_size) block = rb_make_block(new_block_size, stack.block_allocator) or_return parent.next_block = block + when !ODIN_DISABLE_ASSERT { + allocated_new_block = true + } } start := cast(uintptr)raw_data(block.buffer) + block.offset padding := cast(uintptr)calc_padding_with_header(start, cast(uintptr)alignment, size_of(Rollback_Stack_Header)) if block.offset + padding + cast(uintptr)size > cast(uintptr)len(block.buffer) { + when !ODIN_DISABLE_ASSERT { + if allocated_new_block { + panic("Rollback Stack Allocator allocated a new block but did not use it.") + } + } parent = block continue } @@ -223,9 +239,9 @@ rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stac } -rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte) { +rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, location := #caller_location) { MIN_SIZE :: size_of(Rollback_Stack_Block) + size_of(Rollback_Stack_Header) + size_of(rawptr) - assert(len(buffer) >= MIN_SIZE, "User-provided buffer to Rollback Stack Allocator is too small.") + assert(len(buffer) >= MIN_SIZE, "User-provided buffer to Rollback Stack Allocator is too small.", location) block := cast(^Rollback_Stack_Block)raw_data(buffer) block^ = {} @@ -240,9 +256,10 @@ rollback_stack_init_dynamic :: proc( stack: ^Rollback_Stack, block_size := ROLLBACK_STACK_DEFAULT_BLOCK_SIZE, block_allocator := context.allocator, + location := #caller_location, ) -> Allocator_Error { - assert(block_size >= size_of(Rollback_Stack_Header) + size_of(rawptr), "Rollback Stack Allocator block size is too small.") - assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 2 gigabytes.") + assert(block_size >= size_of(Rollback_Stack_Header) + size_of(rawptr), "Rollback Stack Allocator block size is too small.", location) + assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 2 gigabytes.", location) block := rb_make_block(block_size, block_allocator) or_return @@ -284,7 +301,8 @@ rollback_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mo switch mode { case .Alloc, .Alloc_Non_Zeroed: - assert(is_power_of_two(cast(uintptr)alignment), "alignment must be a power of two", location) + assert(size >= 0, "Size must be positive or zero.", location) + assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", location) result = rb_alloc(stack, size, alignment) or_return if mode == .Alloc { @@ -298,6 +316,9 @@ rollback_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mo rb_free_all(stack) case .Resize, .Resize_Non_Zeroed: + assert(size >= 0, "Size must be positive or zero.", location) + assert(old_size >= 0, "Old size must be positive or zero.", location) + assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", location) result = rb_resize(stack, old_memory, old_size, size, alignment) or_return #no_bounds_check if mode == .Resize && size > old_size { From 1afc235359334aa2b7df0e4b4c79386763076e75 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 19:14:28 -0400 Subject: [PATCH 22/93] Use plain sort for `internal_tests` --- core/testing/runner.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index ce5aa112a..1a9fc3ddc 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -192,7 +192,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.assertf(it.p != nil, "Test %s.%s has procedure.", it.pkg, it.name) } - slice.stable_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 { return a.name < b.name } else { From eadfbb13185a94a30d87c52eb50e83fcec8e0d52 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 19:49:56 -0400 Subject: [PATCH 23/93] Forbid singleton allocations from shrinking their block offset --- core/mem/rollback_stack_allocator.odin | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index a3f6647cf..b86f514ec 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -155,7 +155,11 @@ rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment assert(block.offset >= cast(uintptr)old_size, "Rollback Stack Allocator received invalid `old_size`.") if block.offset + cast(uintptr)size - cast(uintptr)old_size < cast(uintptr)len(block.buffer) { - block.offset += cast(uintptr)size - cast(uintptr)old_size + // Prevent singleton allocations from fragmenting by forbidding + // them to shrink, removing the possibility of overflow bugs. + if len(block.buffer) <= stack.block_size { + block.offset += cast(uintptr)size - cast(uintptr)old_size + } #no_bounds_check return (cast([^]byte)ptr)[:size], nil } } From dffc3af86c1c101e1a7c465478ae5454f811fb89 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 19:55:45 -0400 Subject: [PATCH 24/93] Remove `safe_heap_allocator` from test runner I was under the impression that the default `context.allocator` was not thread-safe, but I've been told that this is not the case. --- core/testing/runner.odin | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 1a9fc3ddc..3a024d090 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -277,10 +277,6 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.assertf(alloc_error == nil, "Error allocating memory for task data slots: %v", alloc_error) defer delete(task_data_slots) - safe_heap: mem.Mutex_Allocator - mem.mutex_allocator_init(&safe_heap, context.allocator) - safe_heap_allocator := mem.mutex_allocator(&safe_heap) - // Tests rotate through these allocators as they finish. task_allocators: []mem.Rollback_Stack = --- task_allocators, alloc_error = make([]mem.Rollback_Stack, thread_count) @@ -295,7 +291,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } #no_bounds_check for i in 0 ..< thread_count { - alloc_error = mem.rollback_stack_init(&task_allocators[i], PER_THREAD_MEMORY, block_allocator = safe_heap_allocator) + alloc_error = mem.rollback_stack_init(&task_allocators[i], PER_THREAD_MEMORY) fmt.assertf(alloc_error == nil, "Error allocating memory for task allocator #%i: %v", i, alloc_error) when TRACKING_MEMORY { mem.tracking_allocator_init(&task_memory_trackers[i], mem.rollback_stack_allocator(&task_allocators[i])) @@ -339,11 +335,9 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { // NOTE(Feoramund): This is the allocator that will be used by threads to // persist log messages past their lifetimes. It has its own variable name - // in the event it needs to be changed from `safe_heap_allocator` without + // in the event it needs to be changed from `context.allocator` without // digging through the source to divine everywhere it is used for that. - shared_log_allocator := safe_heap_allocator - - context.allocator = safe_heap_allocator + shared_log_allocator := context.allocator context.logger = { procedure = runner_logger_proc, From 89d8df28bec7b5aebaac1e38ef642754ef57e1f1 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 28 May 2024 19:58:35 -0400 Subject: [PATCH 25/93] Combine multi-line attributes onto one line --- core/mem/rollback_stack_allocator.odin | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index b86f514ec..75b3cd745 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -61,16 +61,14 @@ Rollback_Stack :: struct { } -@(private="file") -@(require_results) +@(private="file", require_results) rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool { start := cast(uintptr)raw_data(block.buffer) end := cast(uintptr)raw_data(block.buffer) + block.offset return start < cast(uintptr)ptr && cast(uintptr)ptr <= end } -@(private="file") -@(require_results) +@(private="file", require_results) rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( parent: ^Rollback_Stack_Block, block: ^Rollback_Stack_Block, @@ -87,8 +85,7 @@ rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( return nil, nil, nil, .Invalid_Pointer } -@(private="file") -@(require_results) +@(private="file", require_results) rb_find_last_alloc :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( block: ^Rollback_Stack_Block, header: ^Rollback_Stack_Header, @@ -113,8 +110,7 @@ rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_ } } -@(private="file") -@(require_results) +@(private="file", require_results) rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error { parent, block, header := rb_find_ptr(stack, ptr) or_return if header.is_free { @@ -145,8 +141,7 @@ rb_free_all :: proc(stack: ^Rollback_Stack) { stack.head.offset = 0 } -@(private="file") -@(require_results) +@(private="file", require_results) rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment: int) -> (result: []byte, err: Allocator_Error) { if ptr != nil { if block, _, ok := rb_find_last_alloc(stack, ptr); ok { @@ -172,8 +167,7 @@ rb_resize :: proc(stack: ^Rollback_Stack, ptr: rawptr, old_size, size, alignment return } -@(private="file") -@(require_results) +@(private="file", require_results) rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byte, err: Allocator_Error) { parent: ^Rollback_Stack_Block for block := stack.head; /**/; block = block.next_block { @@ -232,8 +226,7 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt return nil, .Out_Of_Memory } -@(private="file") -@(require_results) +@(private="file", require_results) rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stack_Block, err: Allocator_Error) { buffer := runtime.mem_alloc(size_of(Rollback_Stack_Block) + size, align_of(Rollback_Stack_Block), allocator) or_return From a1c5bebac72d14711c317e393d337143df17ca87 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 15:36:22 -0400 Subject: [PATCH 26/93] Fix ANSI redraw eating last log line --- core/testing/reporting.odin | 6 +++++- core/testing/runner.odin | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/testing/reporting.odin b/core/testing/reporting.odin index d06681c2d..fba67d67f 100644 --- a/core/testing/reporting.odin +++ b/core/testing/reporting.odin @@ -271,7 +271,11 @@ needs_to_redraw :: proc(report: Report) -> bool { } draw_status_bar :: proc(w: io.Writer, threads_string: string, total_done_count, total_test_count: int) { - if total_done_count != total_test_count { + if total_done_count == total_test_count { + // All tests are done; print a blank line to maintain the same height + // of the progress report. + fmt.wprintln(w) + } else { fmt.wprintfln(w, "%s % 4i/% 4i :: total", threads_string, diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 3a024d090..734b143a6 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -583,8 +583,14 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { finished_in := time.since(start_time) + when !FANCY_OUTPUT { + // One line to space out the results, since we don't have the status + // bar in plain mode. + fmt.wprintln(batch_writer) + } + fmt.wprintf(batch_writer, - "\nFinished %i test%s in %v.", + "Finished %i test%s in %v.", total_done_count, "" if total_done_count == 1 else "s", finished_in) From dcfda195d2c1e215dd506253703fc04e660c9fc6 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 15:36:50 -0400 Subject: [PATCH 27/93] Send terminal control code to `STDOUT` instead `STDERR` might be redirected, and this code signals to the terminal to show the cursor again. Otherwise, the cursor will be invisible. --- core/testing/runner.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 734b143a6..3b4e59e48 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -667,7 +667,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } - fmt.wprint(batch_writer, ansi.CSI + ansi.DECTCEM_SHOW) + fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_SHOW) fmt.wprintln(stderr, bytes.buffer_to_string(&batch_buffer)) From e11f3d252037500197672db990e8884faee230e4 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 15:47:01 -0400 Subject: [PATCH 28/93] Fix missing `-` for define in `tests/core/build.bat` --- tests/core/build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/build.bat b/tests/core/build.bat index fc5e2dc3f..29603dc68 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -11,7 +11,7 @@ echo --- echo --- echo Running core:container tests echo --- -%PATH_TO_ODIN% test container %COMMON% define:test_progress_width=4 -out:test_core_container.exe || exit /b +%PATH_TO_ODIN% test container %COMMON% -define:test_progress_width=4 -out:test_core_container.exe || exit /b echo --- echo Running core:crypto tests From b7e1ae7073a96099c9a5b18fa6fd44a561823691 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 15:50:16 -0400 Subject: [PATCH 29/93] Change test runner options to `SCREAMING_SNAKE_CASE` This commit also changes the name of `test_select` to `ODIN_TEST_NAMES`, to better conform with the already-existing `-test-name:` option. --- core/testing/runner.odin | 22 +++++++++++----------- tests/core/Makefile | 8 ++++---- tests/core/build.bat | 12 ++++++------ tests/core/image/build.bat | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 3b4e59e48..c79d5537b 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -23,19 +23,19 @@ _ :: pkg_log _ :: strings // Specify how many threads to use when running tests. -TEST_THREADS : int : #config(test_threads, 0) +TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) // Track the memory used by each test. -TRACKING_MEMORY : bool : #config(test_track_memory, false) +TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, false) // Specify how much memory each thread allocator starts with. -PER_THREAD_MEMORY : int : #config(test_thread_memory, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) +PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) // Select a specific set of tests to run by name. -TEST_SELECT : string : #config(test_select, "") +TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") // Show the fancy animated progress report. -FANCY_OUTPUT : bool : #config(test_fancy, true) +FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) // Copy failed tests to the clipboard when done. -USE_CLIPBOARD : bool : #config(test_clipboard, false) +USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) // How many test results to show at a time per package. -PROGRESS_WIDTH : int : #config(test_progress_width, 24) +PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) end_t :: proc(t: ^T) { @@ -122,12 +122,12 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { alloc_error: mem.Allocator_Error - when TEST_SELECT != "" { + when TEST_NAMES != "" { select_internal_tests: [dynamic]Internal_Test defer delete(select_internal_tests) { - index_list := TEST_SELECT + index_list := TEST_NAMES for selector in strings.split_iterator(&index_list, ",") { // Temp allocator is fine since we just need to identify which test it's referring to. split_selector := strings.split(selector, ".", context.temp_allocator) @@ -640,7 +640,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { if total_success_count > 0 { when USE_CLIPBOARD { clipboard_writer := io.to_writer(bytes.buffer_to_stream(&clipboard_buffer)) - fmt.wprint(clipboard_writer, "-define:test_select=") + fmt.wprint(clipboard_writer, "-define:ODIN_TEST_NAMES=") for test_index in sorted_failed_test_reasons { #no_bounds_check it := internal_tests[test_index] fmt.wprintf(clipboard_writer, "%s.%s,", it.pkg, it.name) @@ -655,7 +655,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { "" if total_failure_count == 1 else "s", " has" if total_failure_count == 1 else "s have") } else { - fmt.wprintf(batch_writer, "\nTo run only the failed test%s, use:\n\t-define:test_select=", + fmt.wprintf(batch_writer, "\nTo run only the failed test%s, use:\n\t-define:ODIN_TEST_NAMES=", "" if total_failure_count == 1 else "s") for test_index in sorted_failed_test_reasons { #no_bounds_check it := internal_tests[test_index] diff --git a/tests/core/Makefile b/tests/core/Makefile index 4dede0370..13f8ef41b 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,6 +1,6 @@ ODIN=../../odin PYTHON=$(shell which python3) -COMMON=-no-bounds-check -vet -strict-style -define:test_track_memory=true +COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_TRACK_MEMORY=true COLLECTION=-collection:tests=.. all: all_bsd \ @@ -34,13 +34,13 @@ download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) test image $(COMMON) -define:test_progress_width=12 -out:test_core_image + $(ODIN) test image $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=12 -out:test_core_image compress_test: - $(ODIN) test compress $(COMMON) -define:test_progress_width=3 -out:test_core_compress + $(ODIN) test compress $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=3 -out:test_core_compress container_test: - $(ODIN) test container $(COMMON) -define:test_progress_width=4 -out:test_core_container + $(ODIN) test container $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=4 -out:test_core_container crypto_test: $(ODIN) test crypto $(COMMON) -define:test_progress_width=18 -o:speed -out:test_crypto diff --git a/tests/core/build.bat b/tests/core/build.bat index 29603dc68..b63c0f311 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,17 +1,17 @@ @echo off -set COMMON=-no-bounds-check -vet -strict-style -define:test_track_memory=true +set COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_TRACK_MEMORY=true set COLLECTION=-collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% test compress %COMMON% -define:test_progress_width=3 -out:test_core_compress.exe || exit /b +%PATH_TO_ODIN% test compress %COMMON% -define:ODIN_TEST_PROGRESS_WIDTH=3 -out:test_core_compress.exe || exit /b echo --- echo Running core:container tests echo --- -%PATH_TO_ODIN% test container %COMMON% -define:test_progress_width=4 -out:test_core_container.exe || exit /b +%PATH_TO_ODIN% test container %COMMON% -define:ODIN_TEST_PROGRESS_WIDTH=4 -out:test_core_container.exe || exit /b echo --- echo Running core:crypto tests @@ -25,7 +25,7 @@ rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe | %PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b -%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe -define:test_threads=1 -define:test_fancy=false || exit /b +%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe -define:ODIN_TEST_THREADS=1 -define:ODIN_TEST_FANCY=false || exit /b %PATH_TO_ODIN% run encoding/hex %COMMON% -out:test_hex.exe || exit /b %PATH_TO_ODIN% run encoding/base64 %COMMON% -out:test_base64.exe || exit /b @@ -42,7 +42,7 @@ echo --- echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% test image %COMMON% -define:test_progress_width=12 -out:test_core_image.exe || exit /b +%PATH_TO_ODIN% test image %COMMON% -define:ODIN_TEST_PROGRESS_WIDTH=12 -out:test_core_image.exe || exit /b echo --- echo Running core:math tests @@ -107,4 +107,4 @@ echo --- echo --- echo Running core:time tests echo --- -%PATH_TO_ODIN% run time %COMMON% %COLLECTION% -out:test_core_time.exe || exit /b \ No newline at end of file +%PATH_TO_ODIN% run time %COMMON% %COLLECTION% -out:test_core_time.exe || exit /b diff --git a/tests/core/image/build.bat b/tests/core/image/build.bat index 35d1c64e9..5a07971b8 100644 --- a/tests/core/image/build.bat +++ b/tests/core/image/build.bat @@ -1,2 +1,2 @@ @echo off -odin test . -define:test_track_memory=true -define:test_progress_width=12 -vet -strict-style \ No newline at end of file +odin test . -define:ODIN_TEST_TRACK_MEMORY=true -define:ODIN_TEST_PROGRESS_WIDTH=12 -vet -strict-style From c531427ee5d95187d4da1edb1679b67af58b4cbb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 22:18:05 +0200 Subject: [PATCH 30/93] Update -define for `crypto` --- tests/core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 13f8ef41b..23d0dcf99 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -43,7 +43,7 @@ container_test: $(ODIN) test container $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=4 -out:test_core_container crypto_test: - $(ODIN) test crypto $(COMMON) -define:test_progress_width=18 -o:speed -out:test_crypto + $(ODIN) test crypto $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=18 -o:speed -out:test_crypto strings_test: $(ODIN) run strings $(COMMON) -out:test_core_strings From bf42e39b1ce77da0bc45f64ff35322e618a59b9c Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 16:19:06 -0400 Subject: [PATCH 31/93] Be specific about `int` size for `Rollback_Stack` asserts This should fix tests failing on 32-bit platforms. --- core/mem/rollback_stack_allocator.odin | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index 75b3cd745..d159897cd 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -251,12 +251,16 @@ rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, loc rollback_stack_init_dynamic :: proc( stack: ^Rollback_Stack, - block_size := ROLLBACK_STACK_DEFAULT_BLOCK_SIZE, + block_size : int = ROLLBACK_STACK_DEFAULT_BLOCK_SIZE, block_allocator := context.allocator, location := #caller_location, ) -> Allocator_Error { assert(block_size >= size_of(Rollback_Stack_Header) + size_of(rawptr), "Rollback Stack Allocator block size is too small.", location) - assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 2 gigabytes.", location) + when size_of(int) > 4 { + // It's impossible to specify an argument in excess when your integer + // size is insufficient; check only on platforms with big enough ints. + assert(block_size <= ROLLBACK_STACK_MAX_HEAD_BLOCK_SIZE, "Rollback Stack Allocators cannot support head blocks larger than 2 gigabytes.", location) + } block := rb_make_block(block_size, block_allocator) or_return From e1a3c0e21d2683804cdfc7644e55ee6ba7a9f0ea Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 16:39:44 -0400 Subject: [PATCH 32/93] Track memory in the test runner by default --- core/testing/runner.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index c79d5537b..6a9bd6d8f 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -25,7 +25,7 @@ _ :: strings // Specify how many threads to use when running tests. TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) // Track the memory used by each test. -TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, false) +TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true) // Specify how much memory each thread allocator starts with. PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) // Select a specific set of tests to run by name. From 49fa66370f2c96e9fc738ccda67bd3b6d12bad71 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 16:55:04 -0400 Subject: [PATCH 33/93] Report test memory usage only if there's an issue Adds new option `ODIN_TEST_ALWAYS_REPORT_MEMORY`, for when you always want to see the memory usage report. --- core/testing/runner.odin | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 6a9bd6d8f..759b23b0f 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -23,19 +23,21 @@ _ :: pkg_log _ :: strings // Specify how many threads to use when running tests. -TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) +TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) // Track the memory used by each test. -TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true) +TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true) +// Always report how much memory is used, even when there are no leaks or bad frees. +ALWAYS_REPORT_MEMORY : bool : #config(ODIN_TEST_ALWAYS_REPORT_MEMORY, false) // Specify how much memory each thread allocator starts with. -PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) +PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) // Select a specific set of tests to run by name. -TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") +TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") // Show the fancy animated progress report. -FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) +FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) // Copy failed tests to the clipboard when done. -USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) +USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) // How many test results to show at a time per package. -PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) +PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) end_t :: proc(t: ^T) { @@ -382,8 +384,14 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } when TRACKING_MEMORY { - pkg_log.info("Memory tracking is enabled. Tests will log their memory usage when complete.") + when ALWAYS_REPORT_MEMORY { + pkg_log.info("Memory tracking is enabled. Tests will log their memory usage when complete.") + } else { + pkg_log.info("Memory tracking is enabled. Tests will log their memory usage if there's an issue.") + } pkg_log.info("< Final Mem/ Total Mem> < Peak Mem> (#Free/Alloc) :: [package.test_name]") + } else when ALWAYS_REPORT_MEMORY { + pkg_log.warn("ODIN_TEST_ALWAYS_REPORT_MEMORY is true, but ODIN_TRACK_MEMORY is false.") } start_time := time.now() @@ -397,10 +405,18 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { when TRACKING_MEMORY { #no_bounds_check tracker := &task_memory_trackers[data.allocator_index] - write_memory_report(batch_writer, tracker, data.it.pkg, data.it.name) + when ALWAYS_REPORT_MEMORY { + should_report := true + } else { + should_report := len(tracker.allocation_map) + len(tracker.bad_free_array) > 0 + } - pkg_log.info(bytes.buffer_to_string(&batch_buffer)) - bytes.buffer_reset(&batch_buffer) + if should_report { + write_memory_report(batch_writer, tracker, data.it.pkg, data.it.name) + + pkg_log.info(bytes.buffer_to_string(&batch_buffer)) + bytes.buffer_reset(&batch_buffer) + } mem.tracking_allocator_reset(tracker) } From 84ad71fdb3e7714d22cf724c8a593f98100962b1 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 17:27:08 -0400 Subject: [PATCH 34/93] Support `ODIN_TEST_PROGRESS_WIDTH=0` This will automatically calculate how wide the progress bars should be based on the package with the greatest number of tests. The progress width is now capped to 100. --- core/testing/reporting.odin | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/core/testing/reporting.odin b/core/testing/reporting.odin index fba67d67f..92e144ccc 100644 --- a/core/testing/reporting.odin +++ b/core/testing/reporting.odin @@ -16,9 +16,11 @@ SGR_RUNNING :: ansi.CSI + ansi.FG_YELLOW + ansi.SGR SGR_SUCCESS :: ansi.CSI + ansi.FG_GREEN + ansi.SGR SGR_FAILED :: ansi.CSI + ansi.FG_RED + ansi.SGR +MAX_PROGRESS_WIDTH :: 100 + // More than enough bytes to cover long package names, long test names, dozens // of ANSI codes, et cetera. -LINE_BUFFER_SIZE :: (PROGRESS_WIDTH * 8 + 256) * runtime.Byte +LINE_BUFFER_SIZE :: (MAX_PROGRESS_WIDTH * 8 + 224) * runtime.Byte PROGRESS_COLUMN_SPACING :: 2 @@ -44,6 +46,7 @@ Report :: struct { pkg_column_len: int, test_column_len: int, + progress_width: int, all_tests: []Internal_Test, all_test_states: []Test_State, @@ -73,6 +76,10 @@ make_report :: proc(internal_tests: []Internal_Test) -> (report: Report, error: }) or_return } + when PROGRESS_WIDTH == 0 { + report.progress_width = max(report.progress_width, index - pkg_start) + } + pkg_start = index report.pkg_column_len = max(report.pkg_column_len, len(cur_pkg)) cur_pkg = it.pkg @@ -80,7 +87,7 @@ make_report :: proc(internal_tests: []Internal_Test) -> (report: Report, error: report.test_column_len = max(report.test_column_len, len(it.name)) } - // Handle the last package. + // Handle the last (or only) package. #no_bounds_check { append(&packages, Package_Run { name = cur_pkg, @@ -89,6 +96,12 @@ make_report :: proc(internal_tests: []Internal_Test) -> (report: Report, error: test_states = report.all_test_states[pkg_start:], }) or_return } + when PROGRESS_WIDTH == 0 { + report.progress_width = max(report.progress_width, len(internal_tests) - pkg_start) + } else { + report.progress_width = PROGRESS_WIDTH + } + report.progress_width = min(report.progress_width, MAX_PROGRESS_WIDTH) report.pkg_column_len = PROGRESS_COLUMN_SPACING + max(report.pkg_column_len, len(cur_pkg)) @@ -123,7 +136,7 @@ destroy_report :: proc(report: ^Report) { delete(report.all_test_states) } -redraw_package :: proc(w: io.Writer, pkg: ^Package_Run) { +redraw_package :: proc(w: io.Writer, report: Report, pkg: ^Package_Run) { if pkg.frame_ready { io.write_string(w, pkg.redraw_string) return @@ -150,8 +163,8 @@ redraw_package :: proc(w: io.Writer, pkg: ^Package_Run) { } } - start := max(0, highest_run_index - (PROGRESS_WIDTH - 1)) - end := min(start + PROGRESS_WIDTH, len(pkg.test_states)) + start := max(0, highest_run_index - (report.progress_width - 1)) + end := min(start + report.progress_width, len(pkg.test_states)) // This variable is to keep track of the last ANSI code emitted, in // order to avoid repeating the same code over in a sequence. @@ -187,7 +200,7 @@ redraw_package :: proc(w: io.Writer, pkg: ^Package_Run) { io.write_byte(line_writer, '|') } - for _ in 0 ..< PROGRESS_WIDTH - (end - start) { + for _ in 0 ..< report.progress_width - (end - start) { io.write_byte(line_writer, ' ') } @@ -255,7 +268,7 @@ redraw_report :: proc(w: io.Writer, report: Report) { // still break... fmt.wprint(w, ansi.CSI + ansi.DECAWM_OFF) for &pkg in report.packages { - redraw_package(w, &pkg) + redraw_package(w, report, &pkg) } fmt.wprint(w, ansi.CSI + ansi.DECAWM_ON) } From 6a1649d8aa000e903353303d54d4514159f7a9b2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 29 May 2024 23:40:15 +0200 Subject: [PATCH 35/93] Update using new defaults for memory + reporting width --- tests/core/Makefile | 99 ++++++++++++++++++++++---------------------- tests/core/build.bat | 12 +++--- 2 files changed, 55 insertions(+), 56 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 23d0dcf99..6556f2916 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,16 +1,16 @@ ODIN=../../odin PYTHON=$(shell which python3) -COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_TRACK_MEMORY=true +COMMON=-no-bounds-check -vet -strict-style COLLECTION=-collection:tests=.. all: all_bsd \ net_test -all_bsd: c_libc_test \ +all_bsd: download_test_assets \ + c_libc_test \ compress_test \ container_test \ crypto_test \ - download_test_assets \ encoding_test \ filepath_test \ fmt_test \ @@ -23,36 +23,26 @@ all_bsd: c_libc_test \ noise_test \ os_exit_test \ reflect_test \ + runtime_test \ slice_test \ strings_test \ thread_test \ - runtime_test \ - time_test \ - fmt_test + time_test download_test_assets: $(PYTHON) download_assets.py -image_test: - $(ODIN) test image $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=12 -out:test_core_image +c_libc_test: + $(ODIN) run c/libc $(COMMON) -out:test_core_libc compress_test: - $(ODIN) test compress $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=3 -out:test_core_compress + $(ODIN) test compress $(COMMON) -out:test_core_compress container_test: - $(ODIN) test container $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=4 -out:test_core_container + $(ODIN) test container $(COMMON) -out:test_core_container crypto_test: - $(ODIN) test crypto $(COMMON) -define:ODIN_TEST_PROGRESS_WIDTH=18 -o:speed -out:test_crypto - -strings_test: - $(ODIN) run strings $(COMMON) -out:test_core_strings - -hash_test: - $(ODIN) run hash $(COMMON) -o:speed -out:test_hash - -noise_test: - $(ODIN) run math/noise $(COMMON) -out:test_noise + $(ODIN) test crypto $(COMMON) -o:speed -out:test_crypto encoding_test: $(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa @@ -63,44 +53,53 @@ encoding_test: $(ODIN) run encoding/hex $(COMMON) -out:test_hex $(ODIN) run encoding/base64 $(COMMON) -out:test_base64 -math_test: - $(ODIN) run math $(COMMON) $(COLLECTION) -out:test_core_math - -linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl $(COMMON) $(COLLECTION) -out:test_linalg_glsl_math - filepath_test: $(ODIN) run path/filepath $(COMMON) $(COLLECTION) -out:test_core_filepath -reflect_test: - $(ODIN) run reflect $(COMMON) $(COLLECTION) -out:test_core_reflect - -slice_test: - $(ODIN) run slice $(COMMON) -out:test_core_slice - -os_exit_test: - $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 - -i18n_test: - $(ODIN) run text/i18n $(COMMON) -out:test_core_i18n - -match_test: - $(ODIN) run text/match $(COMMON) -out:test_core_match - -c_libc_test: - $(ODIN) run c/libc $(COMMON) -out:test_core_libc - -net_test: - $(ODIN) run net $(COMMON) -out:test_core_net - fmt_test: $(ODIN) run fmt $(COMMON) -out:test_core_fmt -thread_test: - $(ODIN) run thread $(COMMON) -out:test_core_thread +hash_test: + $(ODIN) run hash $(COMMON) -o:speed -out:test_hash + +i18n_test: + $(ODIN) run text/i18n $(COMMON) -out:test_core_i18n + +image_test: + $(ODIN) test image $(COMMON) -out:test_core_image + +linalg_glsl_math_test: + $(ODIN) run math/linalg/glsl $(COMMON) $(COLLECTION) -out:test_linalg_glsl_math + +match_test: + $(ODIN) run text/match $(COMMON) -out:test_core_match + +math_test: + $(ODIN) run math $(COMMON) $(COLLECTION) -out:test_core_math + +net_test: + $(ODIN) run net $(COMMON) -out:test_core_net + +noise_test: + $(ODIN) run math/noise $(COMMON) -out:test_noise + +os_exit_test: + $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 + +reflect_test: + $(ODIN) run reflect $(COMMON) $(COLLECTION) -out:test_core_reflect runtime_test: $(ODIN) run runtime $(COMMON) -out:test_core_runtime +slice_test: + $(ODIN) run slice $(COMMON) -out:test_core_slice + +strings_test: + $(ODIN) run strings $(COMMON) -out:test_core_strings + +thread_test: + $(ODIN) run thread $(COMMON) -out:test_core_thread + time_test: - $(ODIN) run time $(COMMON) -out:test_core_time + $(ODIN) run time $(COMMON) -out:test_core_time \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index b63c0f311..60296090e 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,22 +1,22 @@ @echo off -set COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_TRACK_MEMORY=true +set COMMON=-no-bounds-check -vet -strict-style set COLLECTION=-collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% test compress %COMMON% -define:ODIN_TEST_PROGRESS_WIDTH=3 -out:test_core_compress.exe || exit /b +%PATH_TO_ODIN% test compress %COMMON% -out:test_core_compress.exe || exit /b echo --- echo Running core:container tests echo --- -%PATH_TO_ODIN% test container %COMMON% -define:ODIN_TEST_PROGRESS_WIDTH=4 -out:test_core_container.exe || exit /b +%PATH_TO_ODIN% test container %COMMON% -out:test_core_container.exe || exit /b echo --- echo Running core:crypto tests echo --- -%PATH_TO_ODIN% test crypto %COMMON% define:test_progress_width=18 -o:speed -out:test_crypto.exe || exit /b +%PATH_TO_ODIN% test crypto %COMMON% -o:speed -out:test_crypto.exe || exit /b echo --- echo Running core:encoding tests @@ -42,7 +42,7 @@ echo --- echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% test image %COMMON% -define:ODIN_TEST_PROGRESS_WIDTH=12 -out:test_core_image.exe || exit /b +%PATH_TO_ODIN% test image %COMMON% -out:test_core_image.exe || exit /b echo --- echo Running core:math tests @@ -107,4 +107,4 @@ echo --- echo --- echo Running core:time tests echo --- -%PATH_TO_ODIN% run time %COMMON% %COLLECTION% -out:test_core_time.exe || exit /b +%PATH_TO_ODIN% run time %COMMON% %COLLECTION% -out:test_core_time.exe || exit /b \ No newline at end of file From a27b16721893f78f1788c4f8a7a952d65f7799c3 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 10:42:27 +0200 Subject: [PATCH 36/93] Update `tests\core\encoding\cbor` to use new test runner. It was leaky and required a substantial number of `loc := #caller_location` additions to parts of the core library to make it easier to track down how and where it leaked. The tests now run fine multi-threaded. --- core/bufio/reader.odin | 4 +- core/bytes/buffer.odin | 70 ++-- core/encoding/cbor/cbor.odin | 4 +- core/encoding/cbor/coding.odin | 107 +++--- core/encoding/cbor/marshal.odin | 16 +- core/encoding/cbor/unmarshal.odin | 102 +++--- core/strings/builder.odin | 8 +- tests/core/Makefile | 14 +- tests/core/build.bat | 12 +- tests/core/encoding/base64/base64.odin | 65 ++-- tests/core/encoding/cbor/test_core_cbor.odin | 341 +++++++------------ 11 files changed, 323 insertions(+), 420 deletions(-) diff --git a/core/bufio/reader.odin b/core/bufio/reader.odin index 8ec736a66..a875c732d 100644 --- a/core/bufio/reader.odin +++ b/core/bufio/reader.odin @@ -29,12 +29,12 @@ MIN_READ_BUFFER_SIZE :: 16 @(private) DEFAULT_MAX_CONSECUTIVE_EMPTY_READS :: 128 -reader_init :: proc(b: ^Reader, rd: io.Reader, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator) { +reader_init :: proc(b: ^Reader, rd: io.Reader, size: int = DEFAULT_BUF_SIZE, allocator := context.allocator, loc := #caller_location) { size := size size = max(size, MIN_READ_BUFFER_SIZE) reader_reset(b, rd) b.buf_allocator = allocator - b.buf = make([]byte, size, allocator) + b.buf = make([]byte, size, allocator, loc) } reader_init_with_buf :: proc(b: ^Reader, rd: io.Reader, buf: []byte) { diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin index cb2ef9c62..a7e9b1c64 100644 --- a/core/bytes/buffer.odin +++ b/core/bytes/buffer.odin @@ -27,19 +27,19 @@ Read_Op :: enum i8 { } -buffer_init :: proc(b: ^Buffer, buf: []byte) { - resize(&b.buf, len(buf)) +buffer_init :: proc(b: ^Buffer, buf: []byte, loc := #caller_location) { + resize(&b.buf, len(buf), loc=loc) copy(b.buf[:], buf) } -buffer_init_string :: proc(b: ^Buffer, s: string) { - resize(&b.buf, len(s)) +buffer_init_string :: proc(b: ^Buffer, s: string, loc := #caller_location) { + resize(&b.buf, len(s), loc=loc) copy(b.buf[:], s) } -buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) { +buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator, loc := #caller_location) { if b.buf == nil { - b.buf = make([dynamic]byte, len, cap, allocator) + b.buf = make([dynamic]byte, len, cap, allocator, loc) return } @@ -96,28 +96,28 @@ buffer_truncate :: proc(b: ^Buffer, n: int) { } @(private) -_buffer_try_grow :: proc(b: ^Buffer, n: int) -> (int, bool) { +_buffer_try_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) -> (int, bool) { if l := len(b.buf); n <= cap(b.buf)-l { - resize(&b.buf, l+n) + resize(&b.buf, l+n, loc=loc) return l, true } return 0, false } @(private) -_buffer_grow :: proc(b: ^Buffer, n: int) -> int { +_buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) -> int { m := buffer_length(b) if m == 0 && b.off != 0 { buffer_reset(b) } - if i, ok := _buffer_try_grow(b, n); ok { + if i, ok := _buffer_try_grow(b, n, loc=loc); ok { return i } if b.buf == nil && n <= SMALL_BUFFER_SIZE { // Fixes #2756 by preserving allocator if already set on Buffer via init_buffer_allocator - reserve(&b.buf, SMALL_BUFFER_SIZE) - resize(&b.buf, n) + reserve(&b.buf, SMALL_BUFFER_SIZE, loc=loc) + resize(&b.buf, n, loc=loc) return 0 } @@ -127,31 +127,31 @@ _buffer_grow :: proc(b: ^Buffer, n: int) -> int { } else if c > max(int) - c - n { panic("bytes.Buffer: too large") } else { - resize(&b.buf, 2*c + n) + resize(&b.buf, 2*c + n, loc=loc) copy(b.buf[:], b.buf[b.off:]) } b.off = 0 - resize(&b.buf, m+n) + resize(&b.buf, m+n, loc=loc) return m } -buffer_grow :: proc(b: ^Buffer, n: int) { +buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) { if n < 0 { panic("bytes.buffer_grow: negative count") } - m := _buffer_grow(b, n) - resize(&b.buf, m) + m := _buffer_grow(b, n, loc=loc) + resize(&b.buf, m, loc=loc) } -buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) { +buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int, loc := #caller_location) -> (n: int, err: io.Error) { b.last_read = .Invalid if offset < 0 { err = .Invalid_Offset return } - _, ok := _buffer_try_grow(b, offset+len(p)) + _, ok := _buffer_try_grow(b, offset+len(p), loc=loc) if !ok { - _ = _buffer_grow(b, offset+len(p)) + _ = _buffer_grow(b, offset+len(p), loc=loc) } if len(b.buf) <= offset { return 0, .Short_Write @@ -160,47 +160,47 @@ buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io. } -buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) { +buffer_write :: proc(b: ^Buffer, p: []byte, loc := #caller_location) -> (n: int, err: io.Error) { b.last_read = .Invalid - m, ok := _buffer_try_grow(b, len(p)) + m, ok := _buffer_try_grow(b, len(p), loc=loc) if !ok { - m = _buffer_grow(b, len(p)) + m = _buffer_grow(b, len(p), loc=loc) } return copy(b.buf[m:], p), nil } -buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) { - return buffer_write(b, ([^]byte)(ptr)[:size]) +buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int, loc := #caller_location) -> (n: int, err: io.Error) { + return buffer_write(b, ([^]byte)(ptr)[:size], loc=loc) } -buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) { +buffer_write_string :: proc(b: ^Buffer, s: string, loc := #caller_location) -> (n: int, err: io.Error) { b.last_read = .Invalid - m, ok := _buffer_try_grow(b, len(s)) + m, ok := _buffer_try_grow(b, len(s), loc=loc) if !ok { - m = _buffer_grow(b, len(s)) + m = _buffer_grow(b, len(s), loc=loc) } return copy(b.buf[m:], s), nil } -buffer_write_byte :: proc(b: ^Buffer, c: byte) -> io.Error { +buffer_write_byte :: proc(b: ^Buffer, c: byte, loc := #caller_location) -> io.Error { b.last_read = .Invalid - m, ok := _buffer_try_grow(b, 1) + m, ok := _buffer_try_grow(b, 1, loc=loc) if !ok { - m = _buffer_grow(b, 1) + m = _buffer_grow(b, 1, loc=loc) } b.buf[m] = c return nil } -buffer_write_rune :: proc(b: ^Buffer, r: rune) -> (n: int, err: io.Error) { +buffer_write_rune :: proc(b: ^Buffer, r: rune, loc := #caller_location) -> (n: int, err: io.Error) { if r < utf8.RUNE_SELF { - buffer_write_byte(b, byte(r)) + buffer_write_byte(b, byte(r), loc=loc) return 1, nil } b.last_read = .Invalid - m, ok := _buffer_try_grow(b, utf8.UTF_MAX) + m, ok := _buffer_try_grow(b, utf8.UTF_MAX, loc=loc) if !ok { - m = _buffer_grow(b, utf8.UTF_MAX) + m = _buffer_grow(b, utf8.UTF_MAX, loc=loc) } res: [4]byte res, n = utf8.encode_rune(r) diff --git a/core/encoding/cbor/cbor.odin b/core/encoding/cbor/cbor.odin index d0e406ab1..7897b2a37 100644 --- a/core/encoding/cbor/cbor.odin +++ b/core/encoding/cbor/cbor.odin @@ -320,8 +320,8 @@ to_diagnostic_format :: proc { // Turns the given CBOR value into a human-readable string. // See docs on the proc group `diagnose` for more info. -to_diagnostic_format_string :: proc(val: Value, padding := 0, allocator := context.allocator) -> (string, mem.Allocator_Error) #optional_allocator_error { - b := strings.builder_make(allocator) +to_diagnostic_format_string :: proc(val: Value, padding := 0, allocator := context.allocator, loc := #caller_location) -> (string, mem.Allocator_Error) #optional_allocator_error { + b := strings.builder_make(allocator, loc) w := strings.to_stream(&b) err := to_diagnostic_format_writer(w, val, padding) if err == .EOF { diff --git a/core/encoding/cbor/coding.odin b/core/encoding/cbor/coding.odin index 0d276a7a1..07f0637a6 100644 --- a/core/encoding/cbor/coding.odin +++ b/core/encoding/cbor/coding.odin @@ -95,24 +95,25 @@ decode :: decode_from // Decodes the given string as CBOR. // See docs on the proc group `decode` for more information. -decode_from_string :: proc(s: string, flags: Decoder_Flags = {}, allocator := context.allocator) -> (v: Value, err: Decode_Error) { +decode_from_string :: proc(s: string, flags: Decoder_Flags = {}, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) { r: strings.Reader strings.reader_init(&r, s) - return decode_from_reader(strings.reader_to_stream(&r), flags, allocator) + return decode_from_reader(strings.reader_to_stream(&r), flags, allocator, loc) } // Reads a CBOR value from the given reader. // See docs on the proc group `decode` for more information. -decode_from_reader :: proc(r: io.Reader, flags: Decoder_Flags = {}, allocator := context.allocator) -> (v: Value, err: Decode_Error) { +decode_from_reader :: proc(r: io.Reader, flags: Decoder_Flags = {}, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) { return decode_from_decoder( Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, allocator=allocator, + loc = loc, ) } // Reads a CBOR value from the given decoder. // See docs on the proc group `decode` for more information. -decode_from_decoder :: proc(d: Decoder, allocator := context.allocator) -> (v: Value, err: Decode_Error) { +decode_from_decoder :: proc(d: Decoder, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) { context.allocator = allocator d := d @@ -121,13 +122,13 @@ decode_from_decoder :: proc(d: Decoder, allocator := context.allocator) -> (v: V d.max_pre_alloc = DEFAULT_MAX_PRE_ALLOC } - v, err = _decode_from_decoder(d) + v, err = _decode_from_decoder(d, {}, allocator, loc) // Normal EOF does not exist here, we try to read the exact amount that is said to be provided. if err == .EOF { err = .Unexpected_EOF } return } -_decode_from_decoder :: proc(d: Decoder, hdr: Header = Header(0)) -> (v: Value, err: Decode_Error) { +_decode_from_decoder :: proc(d: Decoder, hdr: Header = Header(0), allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) { hdr := hdr r := d.reader if hdr == Header(0) { hdr = _decode_header(r) or_return } @@ -161,11 +162,11 @@ _decode_from_decoder :: proc(d: Decoder, hdr: Header = Header(0)) -> (v: Value, switch maj { case .Unsigned: return _decode_tiny_u8(add) case .Negative: return Negative_U8(_decode_tiny_u8(add) or_return), nil - case .Bytes: return _decode_bytes_ptr(d, add) - case .Text: return _decode_text_ptr(d, add) - case .Array: return _decode_array_ptr(d, add) - case .Map: return _decode_map_ptr(d, add) - case .Tag: return _decode_tag_ptr(d, add) + case .Bytes: return _decode_bytes_ptr(d, add, .Bytes, allocator, loc) + case .Text: return _decode_text_ptr(d, add, allocator, loc) + case .Array: return _decode_array_ptr(d, add, allocator, loc) + case .Map: return _decode_map_ptr(d, add, allocator, loc) + case .Tag: return _decode_tag_ptr(d, add, allocator, loc) case .Other: return _decode_tiny_simple(add) case: return nil, .Bad_Major } @@ -203,27 +204,27 @@ encode :: encode_into // Encodes the CBOR value into binary CBOR allocated on the given allocator. // See the docs on the proc group `encode_into` for more info. -encode_into_bytes :: proc(v: Value, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (data: []byte, err: Encode_Error) { - b := strings.builder_make(allocator) or_return +encode_into_bytes :: proc(v: Value, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (data: []byte, err: Encode_Error) { + b := strings.builder_make(allocator, loc) or_return encode_into_builder(&b, v, flags, temp_allocator) or_return return b.buf[:], nil } // Encodes the CBOR value into binary CBOR written to the given builder. // See the docs on the proc group `encode_into` for more info. -encode_into_builder :: proc(b: ^strings.Builder, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Encode_Error { - return encode_into_writer(strings.to_stream(b), v, flags, temp_allocator) +encode_into_builder :: proc(b: ^strings.Builder, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Encode_Error { + return encode_into_writer(strings.to_stream(b), v, flags, temp_allocator, loc=loc) } // Encodes the CBOR value into binary CBOR written to the given writer. // See the docs on the proc group `encode_into` for more info. -encode_into_writer :: proc(w: io.Writer, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Encode_Error { - return encode_into_encoder(Encoder{flags, w, temp_allocator}, v) +encode_into_writer :: proc(w: io.Writer, v: Value, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Encode_Error { + return encode_into_encoder(Encoder{flags, w, temp_allocator}, v, loc=loc) } // Encodes the CBOR value into binary CBOR written to the given encoder. // See the docs on the proc group `encode_into` for more info. -encode_into_encoder :: proc(e: Encoder, v: Value) -> Encode_Error { +encode_into_encoder :: proc(e: Encoder, v: Value, loc := #caller_location) -> Encode_Error { e := e if e.temp_allocator.procedure == nil { @@ -366,21 +367,21 @@ _encode_u64_exact :: proc(w: io.Writer, v: u64, major: Major = .Unsigned) -> (er return } -_decode_bytes_ptr :: proc(d: Decoder, add: Add, type: Major = .Bytes) -> (v: ^Bytes, err: Decode_Error) { - v = new(Bytes) or_return - defer if err != nil { free(v) } +_decode_bytes_ptr :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := context.allocator, loc := #caller_location) -> (v: ^Bytes, err: Decode_Error) { + v = new(Bytes, allocator, loc) or_return + defer if err != nil { free(v, allocator, loc) } - v^ = _decode_bytes(d, add, type) or_return + v^ = _decode_bytes(d, add, type, allocator, loc) or_return return } -_decode_bytes :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := context.allocator) -> (v: Bytes, err: Decode_Error) { +_decode_bytes :: proc(d: Decoder, add: Add, type: Major = .Bytes, allocator := context.allocator, loc := #caller_location) -> (v: Bytes, err: Decode_Error) { context.allocator = allocator add := add n, scap := _decode_len_str(d, add) or_return - buf := strings.builder_make(0, scap) or_return + buf := strings.builder_make(0, scap, allocator, loc) or_return defer if err != nil { strings.builder_destroy(&buf) } buf_stream := strings.to_stream(&buf) @@ -426,40 +427,40 @@ _encode_bytes :: proc(e: Encoder, val: Bytes, major: Major = .Bytes) -> (err: En return } -_decode_text_ptr :: proc(d: Decoder, add: Add) -> (v: ^Text, err: Decode_Error) { - v = new(Text) or_return +_decode_text_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Text, err: Decode_Error) { + v = new(Text, allocator, loc) or_return defer if err != nil { free(v) } - v^ = _decode_text(d, add) or_return + v^ = _decode_text(d, add, allocator, loc) or_return return } -_decode_text :: proc(d: Decoder, add: Add, allocator := context.allocator) -> (v: Text, err: Decode_Error) { - return (Text)(_decode_bytes(d, add, .Text, allocator) or_return), nil +_decode_text :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Text, err: Decode_Error) { + return (Text)(_decode_bytes(d, add, .Text, allocator, loc) or_return), nil } _encode_text :: proc(e: Encoder, val: Text) -> Encode_Error { return _encode_bytes(e, transmute([]byte)val, .Text) } -_decode_array_ptr :: proc(d: Decoder, add: Add) -> (v: ^Array, err: Decode_Error) { - v = new(Array) or_return +_decode_array_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Array, err: Decode_Error) { + v = new(Array, allocator, loc) or_return defer if err != nil { free(v) } - v^ = _decode_array(d, add) or_return + v^ = _decode_array(d, add, allocator, loc) or_return return } -_decode_array :: proc(d: Decoder, add: Add) -> (v: Array, err: Decode_Error) { +_decode_array :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Array, err: Decode_Error) { n, scap := _decode_len_container(d, add) or_return - array := make([dynamic]Value, 0, scap) or_return + array := make([dynamic]Value, 0, scap, allocator, loc) or_return defer if err != nil { - for entry in array { destroy(entry) } - delete(array) + for entry in array { destroy(entry, allocator) } + delete(array, loc) } for i := 0; n == -1 || i < n; i += 1 { - val, verr := _decode_from_decoder(d) + val, verr := _decode_from_decoder(d, {}, allocator, loc) if n == -1 && verr == .Break { break } else if verr != nil { @@ -485,39 +486,39 @@ _encode_array :: proc(e: Encoder, arr: Array) -> Encode_Error { return nil } -_decode_map_ptr :: proc(d: Decoder, add: Add) -> (v: ^Map, err: Decode_Error) { - v = new(Map) or_return +_decode_map_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: ^Map, err: Decode_Error) { + v = new(Map, allocator, loc) or_return defer if err != nil { free(v) } - v^ = _decode_map(d, add) or_return + v^ = _decode_map(d, add, allocator, loc) or_return return } -_decode_map :: proc(d: Decoder, add: Add) -> (v: Map, err: Decode_Error) { +_decode_map :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Map, err: Decode_Error) { n, scap := _decode_len_container(d, add) or_return - items := make([dynamic]Map_Entry, 0, scap) or_return + items := make([dynamic]Map_Entry, 0, scap, allocator, loc) or_return defer if err != nil { for entry in items { destroy(entry.key) destroy(entry.value) } - delete(items) + delete(items, loc) } for i := 0; n == -1 || i < n; i += 1 { - key, kerr := _decode_from_decoder(d) + key, kerr := _decode_from_decoder(d, {}, allocator, loc) if n == -1 && kerr == .Break { break } else if kerr != nil { return nil, kerr } - value := _decode_from_decoder(d) or_return + value := _decode_from_decoder(d, {}, allocator, loc) or_return append(&items, Map_Entry{ key = key, value = value, - }) or_return + }, loc) or_return } if .Shrink_Excess in d.flags { shrink(&items) } @@ -578,20 +579,20 @@ _encode_map :: proc(e: Encoder, m: Map) -> (err: Encode_Error) { return nil } -_decode_tag_ptr :: proc(d: Decoder, add: Add) -> (v: Value, err: Decode_Error) { - tag := _decode_tag(d, add) or_return +_decode_tag_ptr :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Value, err: Decode_Error) { + tag := _decode_tag(d, add, allocator, loc) or_return if t, ok := tag.?; ok { defer if err != nil { destroy(t.value) } - tp := new(Tag) or_return + tp := new(Tag, allocator, loc) or_return tp^ = t return tp, nil } // no error, no tag, this was the self described CBOR tag, skip it. - return _decode_from_decoder(d) + return _decode_from_decoder(d, {}, allocator, loc) } -_decode_tag :: proc(d: Decoder, add: Add) -> (v: Maybe(Tag), err: Decode_Error) { +_decode_tag :: proc(d: Decoder, add: Add, allocator := context.allocator, loc := #caller_location) -> (v: Maybe(Tag), err: Decode_Error) { num := _decode_uint_as_u64(d.reader, add) or_return // CBOR can be wrapped in a tag that decoders can use to see/check if the binary data is CBOR. @@ -602,7 +603,7 @@ _decode_tag :: proc(d: Decoder, add: Add) -> (v: Maybe(Tag), err: Decode_Error) t := Tag{ number = num, - value = _decode_from_decoder(d) or_return, + value = _decode_from_decoder(d, {}, allocator, loc) or_return, } if nested, ok := t.value.(^Tag); ok { @@ -883,4 +884,4 @@ _encode_deterministic_f64 :: proc(w: io.Writer, v: f64) -> io.Error { } return _encode_f64_exact(w, v) -} +} \ No newline at end of file diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index 37c9dd180..775eafd9c 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -45,8 +45,8 @@ marshal :: marshal_into // Marshals the given value into a CBOR byte stream (allocated using the given allocator). // See docs on the `marshal_into` proc group for more info. -marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (bytes: []byte, err: Marshal_Error) { - b, alloc_err := strings.builder_make(allocator) +marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (bytes: []byte, err: Marshal_Error) { + b, alloc_err := strings.builder_make(allocator, loc=loc) // The builder as a stream also returns .EOF if it ran out of memory so this is consistent. if alloc_err != nil { return nil, .EOF @@ -54,7 +54,7 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a defer if err != nil { strings.builder_destroy(&b) } - if err = marshal_into_builder(&b, v, flags, temp_allocator); err != nil { + if err = marshal_into_builder(&b, v, flags, temp_allocator, loc=loc); err != nil { return } @@ -63,20 +63,20 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a // Marshals the given value into a CBOR byte stream written to the given builder. // See docs on the `marshal_into` proc group for more info. -marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error { - return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator) +marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error { + return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator, loc=loc) } // Marshals the given value into a CBOR byte stream written to the given writer. // See docs on the `marshal_into` proc group for more info. -marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error { +marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error { encoder := Encoder{flags, w, temp_allocator} - return marshal_into_encoder(encoder, v) + return marshal_into_encoder(encoder, v, loc=loc) } // Marshals the given value into a CBOR byte stream written to the given encoder. // See docs on the `marshal_into` proc group for more info. -marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) { +marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (err: Marshal_Error) { e := e if e.temp_allocator.procedure == nil { diff --git a/core/encoding/cbor/unmarshal.odin b/core/encoding/cbor/unmarshal.odin index a1524d9f4..c31ba1d92 100644 --- a/core/encoding/cbor/unmarshal.odin +++ b/core/encoding/cbor/unmarshal.odin @@ -31,8 +31,8 @@ unmarshal :: proc { unmarshal_from_string, } -unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) { - err = unmarshal_from_decoder(Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, ptr, allocator, temp_allocator) +unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { + err = unmarshal_from_decoder(Decoder{ DEFAULT_MAX_PRE_ALLOC, flags, r }, ptr, allocator, temp_allocator, loc) // Normal EOF does not exist here, we try to read the exact amount that is said to be provided. if err == .EOF { err = .Unexpected_EOF } @@ -40,21 +40,21 @@ unmarshal_from_reader :: proc(r: io.Reader, ptr: ^$T, flags := Decoder_Flags{}, } // Unmarshals from a string, see docs on the proc group `Unmarshal` for more info. -unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) { +unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { sr: strings.Reader r := strings.to_reader(&sr, s) - err = unmarshal_from_reader(r, ptr, flags, allocator, temp_allocator) + err = unmarshal_from_reader(r, ptr, flags, allocator, temp_allocator, loc) // Normal EOF does not exist here, we try to read the exact amount that is said to be provided. if err == .EOF { err = .Unexpected_EOF } return } -unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator) -> (err: Unmarshal_Error) { +unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { d := d - err = _unmarshal_any_ptr(d, ptr, nil, allocator, temp_allocator) + err = _unmarshal_any_ptr(d, ptr, nil, allocator, temp_allocator, loc) // Normal EOF does not exist here, we try to read the exact amount that is said to be provided. if err == .EOF { err = .Unexpected_EOF } @@ -62,7 +62,7 @@ unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.alloca } -_unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocator := context.allocator, temp_allocator := context.temp_allocator) -> Unmarshal_Error { +_unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> Unmarshal_Error { context.allocator = allocator context.temp_allocator = temp_allocator v := v @@ -78,10 +78,10 @@ _unmarshal_any_ptr :: proc(d: Decoder, v: any, hdr: Maybe(Header) = nil, allocat } data := any{(^rawptr)(v.data)^, ti.variant.(reflect.Type_Info_Pointer).elem.id} - return _unmarshal_value(d, data, hdr.? or_else (_decode_header(d.reader) or_return)) + return _unmarshal_value(d, data, hdr.? or_else (_decode_header(d.reader) or_return), allocator, temp_allocator, loc) } -_unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Error) { +_unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { v := v ti := reflect.type_info_base(type_info_of(v.id)) r := d.reader @@ -104,7 +104,7 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Err // Allow generic unmarshal by doing it into a `Value`. switch &dst in v { case Value: - dst = err_conv(_decode_from_decoder(d, hdr)) or_return + dst = err_conv(_decode_from_decoder(d, hdr, allocator, loc)) or_return return } @@ -308,7 +308,7 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Err if impl, ok := _tag_implementations_nr[nr]; ok { return impl->unmarshal(d, nr, v) } else if nr == TAG_OBJECT_TYPE { - return _unmarshal_union(d, v, ti, hdr) + return _unmarshal_union(d, v, ti, hdr, loc=loc) } else { // Discard the tag info and unmarshal as its value. return _unmarshal_value(d, v, _decode_header(r) or_return) @@ -316,19 +316,19 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header) -> (err: Unmarshal_Err return _unsupported(v, hdr, add) - case .Bytes: return _unmarshal_bytes(d, v, ti, hdr, add) - case .Text: return _unmarshal_string(d, v, ti, hdr, add) - case .Array: return _unmarshal_array(d, v, ti, hdr, add) - case .Map: return _unmarshal_map(d, v, ti, hdr, add) + case .Bytes: return _unmarshal_bytes(d, v, ti, hdr, add, allocator=allocator, loc=loc) + case .Text: return _unmarshal_string(d, v, ti, hdr, add, allocator=allocator, loc=loc) + case .Array: return _unmarshal_array(d, v, ti, hdr, add, allocator=allocator, loc=loc) + case .Map: return _unmarshal_map(d, v, ti, hdr, add, allocator=allocator, loc=loc) case: return .Bad_Major } } -_unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { +_unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { #partial switch t in ti.variant { case reflect.Type_Info_String: - bytes := err_conv(_decode_bytes(d, add)) or_return + bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return if t.is_cstring { raw := (^cstring)(v.data) @@ -347,7 +347,7 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if elem_base.id != byte { return _unsupported(v, hdr) } - bytes := err_conv(_decode_bytes(d, add)) or_return + bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return raw := (^mem.Raw_Slice)(v.data) raw^ = transmute(mem.Raw_Slice)bytes return @@ -357,12 +357,12 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if elem_base.id != byte { return _unsupported(v, hdr) } - bytes := err_conv(_decode_bytes(d, add)) or_return + bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return raw := (^mem.Raw_Dynamic_Array)(v.data) raw.data = raw_data(bytes) raw.len = len(bytes) raw.cap = len(bytes) - raw.allocator = context.allocator + raw.allocator = allocator return case reflect.Type_Info_Array: @@ -385,10 +385,10 @@ _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return _unsupported(v, hdr) } -_unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { +_unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { #partial switch t in ti.variant { case reflect.Type_Info_String: - text := err_conv(_decode_text(d, add)) or_return + text := err_conv(_decode_text(d, add, allocator, loc)) or_return if t.is_cstring { raw := (^cstring)(v.data) @@ -403,8 +403,8 @@ _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Heade // Enum by its variant name. case reflect.Type_Info_Enum: - text := err_conv(_decode_text(d, add, allocator=context.temp_allocator)) or_return - defer delete(text, context.temp_allocator) + text := err_conv(_decode_text(d, add, allocator=temp_allocator, loc=loc)) or_return + defer delete(text, temp_allocator, loc) for name, i in t.names { if name == text { @@ -414,8 +414,8 @@ _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Heade } case reflect.Type_Info_Rune: - text := err_conv(_decode_text(d, add, allocator=context.temp_allocator)) or_return - defer delete(text, context.temp_allocator) + text := err_conv(_decode_text(d, add, allocator=temp_allocator, loc=loc)) or_return + defer delete(text, temp_allocator, loc) r := (^rune)(v.data) dr, n := utf8.decode_rune(text) @@ -430,13 +430,15 @@ _unmarshal_string :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Heade return _unsupported(v, hdr) } -_unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { +_unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { assign_array :: proc( d: Decoder, da: ^mem.Raw_Dynamic_Array, elemt: ^reflect.Type_Info, length: int, growable := true, + allocator := context.allocator, + loc := #caller_location, ) -> (out_of_space: bool, err: Unmarshal_Error) { for idx: uintptr = 0; length == -1 || idx < uintptr(length); idx += 1 { elem_ptr := rawptr(uintptr(da.data) + idx*uintptr(elemt.size)) @@ -450,13 +452,13 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if !growable { return true, .Out_Of_Memory } cap := 2 * da.cap - ok := runtime.__dynamic_array_reserve(da, elemt.size, elemt.align, cap) + ok := runtime.__dynamic_array_reserve(da, elemt.size, elemt.align, cap, loc) // NOTE: Might be lying here, but it is at least an allocator error. if !ok { return false, .Out_Of_Memory } } - err = _unmarshal_value(d, elem, hdr) + err = _unmarshal_value(d, elem, hdr, allocator=allocator, loc=loc) if length == -1 && err == .Break { break } if err != nil { return } @@ -469,10 +471,10 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header // Allow generically storing the values array. switch &dst in v { case ^Array: - dst = err_conv(_decode_array_ptr(d, add)) or_return + dst = err_conv(_decode_array_ptr(d, add, allocator=allocator, loc=loc)) or_return return case Array: - dst = err_conv(_decode_array(d, add)) or_return + dst = err_conv(_decode_array(d, add, allocator=allocator, loc=loc)) or_return return } @@ -480,8 +482,8 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header case reflect.Type_Info_Slice: length, scap := err_conv(_decode_len_container(d, add)) or_return - data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align) or_return - defer if err != nil { mem.free_bytes(data) } + data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return + defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) } da := mem.Raw_Dynamic_Array{raw_data(data), 0, length, context.allocator } @@ -489,7 +491,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if .Shrink_Excess in d.flags { // Ignoring an error here, but this is not critical to succeed. - _ = runtime.__dynamic_array_shrink(&da, t.elem.size, t.elem.align, da.len) + _ = runtime.__dynamic_array_shrink(&da, t.elem.size, t.elem.align, da.len, loc=loc) } raw := (^mem.Raw_Slice)(v.data) @@ -500,8 +502,8 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header case reflect.Type_Info_Dynamic_Array: length, scap := err_conv(_decode_len_container(d, add)) or_return - data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align) or_return - defer if err != nil { mem.free_bytes(data) } + data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, loc=loc) or_return + defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) } raw := (^mem.Raw_Dynamic_Array)(v.data) raw.data = raw_data(data) @@ -513,7 +515,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if .Shrink_Excess in d.flags { // Ignoring an error here, but this is not critical to succeed. - _ = runtime.__dynamic_array_shrink(raw, t.elem.size, t.elem.align, raw.len) + _ = runtime.__dynamic_array_shrink(raw, t.elem.size, t.elem.align, raw.len, loc=loc) } return @@ -525,7 +527,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return _unsupported(v, hdr) } - da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, context.allocator } + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return if out_of_space { return _unsupported(v, hdr) } @@ -539,7 +541,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return _unsupported(v, hdr) } - da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, context.allocator } + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return if out_of_space { return _unsupported(v, hdr) } @@ -553,7 +555,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return _unsupported(v, hdr) } - da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 2, context.allocator } + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 2, allocator } info: ^runtime.Type_Info switch ti.id { @@ -575,7 +577,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header return _unsupported(v, hdr) } - da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 4, context.allocator } + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, 4, allocator } info: ^runtime.Type_Info switch ti.id { @@ -593,17 +595,17 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header } } -_unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add) -> (err: Unmarshal_Error) { +_unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { r := d.reader - decode_key :: proc(d: Decoder, v: any, allocator := context.allocator) -> (k: string, err: Unmarshal_Error) { + decode_key :: proc(d: Decoder, v: any, allocator := context.allocator, loc := #caller_location) -> (k: string, err: Unmarshal_Error) { entry_hdr := _decode_header(d.reader) or_return entry_maj, entry_add := _header_split(entry_hdr) #partial switch entry_maj { case .Text: - k = err_conv(_decode_text(d, entry_add, allocator)) or_return + k = err_conv(_decode_text(d, entry_add, allocator=allocator, loc=loc)) or_return return case .Bytes: - bytes := err_conv(_decode_bytes(d, entry_add, allocator=allocator)) or_return + bytes := err_conv(_decode_bytes(d, entry_add, allocator=allocator, loc=loc)) or_return k = string(bytes) return case: @@ -615,10 +617,10 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, // Allow generically storing the map array. switch &dst in v { case ^Map: - dst = err_conv(_decode_map_ptr(d, add)) or_return + dst = err_conv(_decode_map_ptr(d, add, allocator=allocator, loc=loc)) or_return return case Map: - dst = err_conv(_decode_map(d, add)) or_return + dst = err_conv(_decode_map(d, add, allocator=allocator, loc=loc)) or_return return } @@ -754,7 +756,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, // Unmarshal into a union, based on the `TAG_OBJECT_TYPE` tag of the spec, it denotes a tag which // contains an array of exactly two elements, the first is a textual representation of the following // CBOR value's type. -_unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header) -> (err: Unmarshal_Error) { +_unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, loc := #caller_location) -> (err: Unmarshal_Error) { r := d.reader #partial switch t in ti.variant { case reflect.Type_Info_Union: @@ -792,7 +794,7 @@ _unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header case reflect.Type_Info_Named: if vti.name == target_name { reflect.set_union_variant_raw_tag(v, tag) - return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return) + return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return, loc=loc) } case: @@ -804,7 +806,7 @@ _unmarshal_union :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if variant_name == target_name { reflect.set_union_variant_raw_tag(v, tag) - return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return) + return _unmarshal_value(d, any{v.data, variant.id}, _decode_header(r) or_return, loc=loc) } } } diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 72eb815f9..11885b689 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -350,9 +350,9 @@ Output: ab */ -write_byte :: proc(b: ^Builder, x: byte) -> (n: int) { +write_byte :: proc(b: ^Builder, x: byte, loc := #caller_location) -> (n: int) { n0 := len(b.buf) - append(&b.buf, x) + append(&b.buf, x, loc) n1 := len(b.buf) return n1-n0 } @@ -380,9 +380,9 @@ NOTE: The backing dynamic array may be fixed in capacity or fail to resize, `n` Returns: - n: The number of bytes appended */ -write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) { +write_bytes :: proc(b: ^Builder, x: []byte, loc := #caller_location) -> (n: int) { n0 := len(b.buf) - append(&b.buf, ..x) + append(&b.buf, ..x, loc=loc) n1 := len(b.buf) return n1-n0 } diff --git a/tests/core/Makefile b/tests/core/Makefile index 6556f2916..0a1055120 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -45,13 +45,13 @@ crypto_test: $(ODIN) test crypto $(COMMON) -o:speed -out:test_crypto encoding_test: - $(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa - $(ODIN) run encoding/json $(COMMON) -out:test_json - $(ODIN) run encoding/varint $(COMMON) -out:test_varint - $(ODIN) run encoding/xml $(COMMON) -out:test_xml - $(ODIN) run encoding/cbor $(COMMON) -out:test_cbor - $(ODIN) run encoding/hex $(COMMON) -out:test_hex - $(ODIN) run encoding/base64 $(COMMON) -out:test_base64 + $(ODIN) test encoding/base64 $(COMMON) -out:test_base64 + $(ODIN) test encoding/cbor $(COMMON) -out:test_cbor + $(ODIN) run encoding/hex $(COMMON) -out:test_hex + $(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa + $(ODIN) run encoding/json $(COMMON) -out:test_json + $(ODIN) run encoding/varint $(COMMON) -out:test_varint + $(ODIN) run encoding/xml $(COMMON) -out:test_xml filepath_test: $(ODIN) run path/filepath $(COMMON) $(COLLECTION) -out:test_core_filepath diff --git a/tests/core/build.bat b/tests/core/build.bat index 60296090e..a26ccf176 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -21,13 +21,13 @@ echo --- echo --- echo Running core:encoding tests echo --- +%PATH_TO_ODIN% test encoding/base64 %COMMON% -out:test_base64.exe || exit /b +%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe || exit /b +%PATH_TO_ODIN% test encoding/hex %COMMON% -out:test_hex.exe || exit /b rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b -%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b -%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b -%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b -%PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe -define:ODIN_TEST_THREADS=1 -define:ODIN_TEST_FANCY=false || exit /b -%PATH_TO_ODIN% run encoding/hex %COMMON% -out:test_hex.exe || exit /b -%PATH_TO_ODIN% run encoding/base64 %COMMON% -out:test_base64.exe || exit /b +%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b +%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b +%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b echo --- echo Running core:fmt tests diff --git a/tests/core/encoding/base64/base64.odin b/tests/core/encoding/base64/base64.odin index e48eea020..6679c8ce2 100644 --- a/tests/core/encoding/base64/base64.odin +++ b/tests/core/encoding/base64/base64.odin @@ -1,61 +1,38 @@ package test_encoding_base64 import "base:intrinsics" - import "core:encoding/base64" -import "core:fmt" -import "core:os" -import "core:reflect" import "core:testing" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect_value :: testing.expect_value - -} else { - expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { - TEST_count += 1 - ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) - if !ok { - TEST_fail += 1 - fmt.printf("[%v] expected %v, got %v\n", loc, expected, value) - } - return ok - } +Test :: struct { + vector: string, + base64: string, } -main :: proc() { - t := testing.T{} - - test_encoding(&t) - test_decoding(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } +tests :: []Test{ + {"", ""}, + {"f", "Zg=="}, + {"fo", "Zm8="}, + {"foo", "Zm9v"}, + {"foob", "Zm9vYg=="}, + {"fooba", "Zm9vYmE="}, + {"foobar", "Zm9vYmFy"}, } @(test) test_encoding :: proc(t: ^testing.T) { - expect_value(t, base64.encode(transmute([]byte)string("")), "") - expect_value(t, base64.encode(transmute([]byte)string("f")), "Zg==") - expect_value(t, base64.encode(transmute([]byte)string("fo")), "Zm8=") - expect_value(t, base64.encode(transmute([]byte)string("foo")), "Zm9v") - expect_value(t, base64.encode(transmute([]byte)string("foob")), "Zm9vYg==") - expect_value(t, base64.encode(transmute([]byte)string("fooba")), "Zm9vYmE=") - expect_value(t, base64.encode(transmute([]byte)string("foobar")), "Zm9vYmFy") + for test in tests { + v := base64.encode(transmute([]byte)test.vector) + defer delete(v) + testing.expect_value(t, v, test.base64) + } } @(test) test_decoding :: proc(t: ^testing.T) { - expect_value(t, string(base64.decode("")), "") - expect_value(t, string(base64.decode("Zg==")), "f") - expect_value(t, string(base64.decode("Zm8=")), "fo") - expect_value(t, string(base64.decode("Zm9v")), "foo") - expect_value(t, string(base64.decode("Zm9vYg==")), "foob") - expect_value(t, string(base64.decode("Zm9vYmE=")), "fooba") - expect_value(t, string(base64.decode("Zm9vYmFy")), "foobar") + for test in tests { + v := string(base64.decode(test.base64)) + defer delete(v) + testing.expect_value(t, v, test.vector) + } } diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index 72244e1d3..d069ef05b 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -1,105 +1,15 @@ package test_encoding_cbor import "base:intrinsics" - import "core:bytes" import "core:encoding/cbor" import "core:fmt" import "core:io" import "core:math/big" -import "core:mem" -import "core:os" import "core:reflect" import "core:testing" import "core:time" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - expect_value :: testing.expect_value - errorf :: testing.errorf - log :: testing.log - -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - - expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { - TEST_count += 1 - ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) - if !ok { - TEST_fail += 1 - fmt.printf("[%v] expected %v, got %v\n", loc, expected, value) - } - return ok - } - - errorf :: proc(t: ^testing.T, fmts: string, args: ..any, loc := #caller_location) { - TEST_fail += 1 - fmt.printf("[%v] ERROR: ", loc) - fmt.printf(fmts, ..args) - fmt.println() - } - - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - test_marshalling(&t) - - test_marshalling_maybe(&t) - test_marshalling_nil_maybe(&t) - - test_marshalling_union(&t) - - test_lying_length_array(&t) - - test_decode_unsigned(&t) - test_encode_unsigned(&t) - - test_decode_negative(&t) - test_encode_negative(&t) - - test_decode_simples(&t) - test_encode_simples(&t) - - test_decode_floats(&t) - test_encode_floats(&t) - - test_decode_bytes(&t) - test_encode_bytes(&t) - - test_decode_strings(&t) - test_encode_strings(&t) - - test_decode_lists(&t) - test_encode_lists(&t) - - test_decode_maps(&t) - test_encode_maps(&t) - - test_decode_tags(&t) - test_encode_tags(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - Foo :: struct { str: string, cstr: cstring, @@ -143,14 +53,6 @@ FooBars :: bit_set[FooBar; u16] @(test) test_marshalling :: proc(t: ^testing.T) { - tracker: mem.Tracking_Allocator - mem.tracking_allocator_init(&tracker, context.allocator) - context.allocator = mem.tracking_allocator(&tracker) - context.temp_allocator = context.allocator - defer mem.tracking_allocator_destroy(&tracker) - - ev :: expect_value - { nice := "16 is a nice number" now := time.Time{_nsec = 1701117968 * 1e9} @@ -205,18 +107,18 @@ test_marshalling :: proc(t: ^testing.T) { } data, err := cbor.marshal(f, cbor.ENCODE_FULLY_DETERMINISTIC) - ev(t, err, nil) + testing.expect_value(t, err, nil) defer delete(data) decoded, derr := cbor.decode(string(data)) - ev(t, derr, nil) + testing.expect_value(t, derr, nil) defer cbor.destroy(decoded) diagnosis, eerr := cbor.to_diagnostic_format(decoded) - ev(t, eerr, nil) + testing.expect_value(t, eerr, nil) defer delete(diagnosis) - ev(t, diagnosis, `{ + testing.expect_value(t, diagnosis, `{ "base64": 34("MTYgaXMgYSBuaWNlIG51bWJlcg=="), "biggest": 2(h'f951a9fd3c158afdff08ab8e0'), "biggie": 18446744073709551615, @@ -285,7 +187,7 @@ test_marshalling :: proc(t: ^testing.T) { backf: Foo uerr := cbor.unmarshal(string(data), &backf) - ev(t, uerr, nil) + testing.expect_value(t, uerr, nil) defer { delete(backf.str) delete(backf.cstr) @@ -304,104 +206,102 @@ test_marshalling :: proc(t: ^testing.T) { big.destroy(&backf.smallest) } - ev(t, backf.str, f.str) - ev(t, backf.cstr, f.cstr) + testing.expect_value(t, backf.str, f.str) + testing.expect_value(t, backf.cstr, f.cstr) #partial switch v in backf.value { case ^cbor.Map: for entry, i in v { fm := f.value.(^cbor.Map) - ev(t, entry.key, fm[i].key) + testing.expect_value(t, entry.key, fm[i].key) if str, is_str := entry.value.(^cbor.Text); is_str { - ev(t, str^, fm[i].value.(^cbor.Text)^) + testing.expect_value(t, str^, fm[i].value.(^cbor.Text)^) } else { - ev(t, entry.value, fm[i].value) + testing.expect_value(t, entry.value, fm[i].value) } } - case: errorf(t, "wrong type %v", v) + case: testing.expectf(t, false, "wrong type %v", v) } - ev(t, backf.neg, f.neg) - ev(t, backf.iamint, f.iamint) - ev(t, backf.base64, f.base64) - ev(t, backf.renamed, f.renamed) - ev(t, backf.now, f.now) - ev(t, backf.nowie, f.nowie) - for e, i in f.child.dyn { ev(t, backf.child.dyn[i], e) } - for key, value in f.child.mappy { ev(t, backf.child.mappy[key], value) } - ev(t, backf.child.my_integers, f.child.my_integers) - ev(t, len(backf.my_bytes), 0) - ev(t, len(backf.my_bytes), len(f.my_bytes)) - ev(t, backf.ennie, f.ennie) - ev(t, backf.ennieb, f.ennieb) - ev(t, backf.quat, f.quat) - ev(t, backf.comp, f.comp) - ev(t, backf.important, f.important) - ev(t, backf.no, nil) - ev(t, backf.nos, nil) - ev(t, backf.yes, f.yes) - ev(t, backf.biggie, f.biggie) - ev(t, backf.smallie, f.smallie) - ev(t, backf.onetwenty, f.onetwenty) - ev(t, backf.small_onetwenty, f.small_onetwenty) - ev(t, backf.ignore_this, nil) + testing.expect_value(t, backf.neg, f.neg) + testing.expect_value(t, backf.iamint, f.iamint) + testing.expect_value(t, backf.base64, f.base64) + testing.expect_value(t, backf.renamed, f.renamed) + testing.expect_value(t, backf.now, f.now) + testing.expect_value(t, backf.nowie, f.nowie) + for e, i in f.child.dyn { testing.expect_value(t, backf.child.dyn[i], e) } + for key, value in f.child.mappy { testing.expect_value(t, backf.child.mappy[key], value) } + testing.expect_value(t, backf.child.my_integers, f.child.my_integers) + testing.expect_value(t, len(backf.my_bytes), 0) + testing.expect_value(t, len(backf.my_bytes), len(f.my_bytes)) + testing.expect_value(t, backf.ennie, f.ennie) + testing.expect_value(t, backf.ennieb, f.ennieb) + testing.expect_value(t, backf.quat, f.quat) + testing.expect_value(t, backf.comp, f.comp) + testing.expect_value(t, backf.important, f.important) + testing.expect_value(t, backf.no, nil) + testing.expect_value(t, backf.nos, nil) + testing.expect_value(t, backf.yes, f.yes) + testing.expect_value(t, backf.biggie, f.biggie) + testing.expect_value(t, backf.smallie, f.smallie) + testing.expect_value(t, backf.onetwenty, f.onetwenty) + testing.expect_value(t, backf.small_onetwenty, f.small_onetwenty) + testing.expect_value(t, backf.ignore_this, nil) s_equals, s_err := big.equals(&backf.smallest, &f.smallest) - ev(t, s_err, nil) + testing.expect_value(t, s_err, nil) if !s_equals { - errorf(t, "smallest: %v does not equal %v", big.itoa(&backf.smallest), big.itoa(&f.smallest)) + testing.expectf(t, false, "smallest: %v does not equal %v", big.itoa(&backf.smallest), big.itoa(&f.smallest)) } b_equals, b_err := big.equals(&backf.biggest, &f.biggest) - ev(t, b_err, nil) + testing.expect_value(t, b_err, nil) if !b_equals { - errorf(t, "biggest: %v does not equal %v", big.itoa(&backf.biggest), big.itoa(&f.biggest)) + testing.expectf(t, false, "biggest: %v does not equal %v", big.itoa(&backf.biggest), big.itoa(&f.biggest)) } } - - for _, leak in tracker.allocation_map { - errorf(t, "%v leaked %m\n", leak.location, leak.size) - } - - for bad_free in tracker.bad_free_array { - errorf(t, "%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) - } } @(test) test_marshalling_maybe :: proc(t: ^testing.T) { maybe_test: Maybe(int) = 1 data, err := cbor.marshal(maybe_test) - expect_value(t, err, nil) + defer delete(data) + testing.expect_value(t, err, nil) val, derr := cbor.decode(string(data)) - expect_value(t, derr, nil) + testing.expect_value(t, derr, nil) - expect_value(t, cbor.to_diagnostic_format(val), "1") + diag := cbor.to_diagnostic_format(val) + testing.expect_value(t, diag, "1") + delete(diag) maybe_dest: Maybe(int) uerr := cbor.unmarshal(string(data), &maybe_dest) - expect_value(t, uerr, nil) - expect_value(t, maybe_dest, 1) + testing.expect_value(t, uerr, nil) + testing.expect_value(t, maybe_dest, 1) } @(test) test_marshalling_nil_maybe :: proc(t: ^testing.T) { maybe_test: Maybe(int) data, err := cbor.marshal(maybe_test) - expect_value(t, err, nil) + defer delete(data) + testing.expect_value(t, err, nil) val, derr := cbor.decode(string(data)) - expect_value(t, derr, nil) + testing.expect_value(t, derr, nil) - expect_value(t, cbor.to_diagnostic_format(val), "nil") + diag := cbor.to_diagnostic_format(val) + testing.expect_value(t, diag, "nil") + delete(diag) maybe_dest: Maybe(int) uerr := cbor.unmarshal(string(data), &maybe_dest) - expect_value(t, uerr, nil) - expect_value(t, maybe_dest, nil) + testing.expect_value(t, uerr, nil) + testing.expect_value(t, maybe_dest, nil) } @(test) @@ -427,17 +327,24 @@ test_marshalling_union :: proc(t: ^testing.T) { { test: My_Union = My_Distinct("Hello, World!") data, err := cbor.marshal(test) - expect_value(t, err, nil) + defer delete(data) + testing.expect_value(t, err, nil) val, derr := cbor.decode(string(data)) - expect_value(t, derr, nil) + defer cbor.destroy(val) + testing.expect_value(t, derr, nil) - expect_value(t, cbor.to_diagnostic_format(val, -1), `1010(["My_Distinct", "Hello, World!"])`) + diag := cbor.to_diagnostic_format(val, -1) + defer delete(diag) + testing.expect_value(t, diag, `1010(["My_Distinct", "Hello, World!"])`) dest: My_Union uerr := cbor.unmarshal(string(data), &dest) - expect_value(t, uerr, nil) - expect_value(t, dest, My_Distinct("Hello, World!")) + testing.expect_value(t, uerr, nil) + testing.expect_value(t, dest, My_Distinct("Hello, World!")) + if str, ok := dest.(My_Distinct); ok { + delete(string(str)) + } } My_Union_No_Nil :: union #no_nil { @@ -450,17 +357,21 @@ test_marshalling_union :: proc(t: ^testing.T) { { test: My_Union_No_Nil = My_Struct{.Two} data, err := cbor.marshal(test) - expect_value(t, err, nil) + defer delete(data) + testing.expect_value(t, err, nil) val, derr := cbor.decode(string(data)) - expect_value(t, derr, nil) + defer cbor.destroy(val) + testing.expect_value(t, derr, nil) - expect_value(t, cbor.to_diagnostic_format(val, -1), `1010(["My_Struct", {"my_enum": 1}])`) + diag := cbor.to_diagnostic_format(val, -1) + defer delete(diag) + testing.expect_value(t, diag, `1010(["My_Struct", {"my_enum": 1}])`) dest: My_Union_No_Nil uerr := cbor.unmarshal(string(data), &dest) - expect_value(t, uerr, nil) - expect_value(t, dest, My_Struct{.Two}) + testing.expect_value(t, uerr, nil) + testing.expect_value(t, dest, My_Struct{.Two}) } } @@ -469,7 +380,7 @@ test_lying_length_array :: proc(t: ^testing.T) { // Input says this is an array of length max(u64), this should not allocate that amount. input := []byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42} _, err := cbor.decode(string(input)) - expect_value(t, err, io.Error.Unexpected_EOF) // .Out_Of_Memory would be bad. + testing.expect_value(t, err, io.Error.Unexpected_EOF) // .Out_Of_Memory would be bad. } @(test) @@ -691,65 +602,73 @@ test_encode_lists :: proc(t: ^testing.T) { expect_streamed_encoding(t, "\x9f\xff", &cbor.Array{}) { - bytes.buffer_reset(&buf) + buf: bytes.Buffer + bytes.buffer_init_allocator(&buf, 0, 0) + defer bytes.buffer_destroy(&buf) + stream := bytes.buffer_to_stream(&buf) + encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}} err: cbor.Encode_Error err = cbor.encode_stream_begin(stream, .Array) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) { err = cbor.encode_stream_array_item(encoder, u8(1)) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) err = cbor.encode_stream_array_item(encoder, &cbor.Array{u8(2), u8(3)}) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) err = cbor.encode_stream_begin(stream, .Array) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) { err = cbor.encode_stream_array_item(encoder, u8(4)) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) err = cbor.encode_stream_array_item(encoder, u8(5)) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) } err = cbor.encode_stream_end(stream) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) } err = cbor.encode_stream_end(stream) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) - expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x9f\x01\x82\x02\x03\x9f\x04\x05\xff\xff"))) + testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x9f\x01\x82\x02\x03\x9f\x04\x05\xff\xff"))) } { - bytes.buffer_reset(&buf) + buf: bytes.Buffer + bytes.buffer_init_allocator(&buf, 0, 0) + defer bytes.buffer_destroy(&buf) + stream := bytes.buffer_to_stream(&buf) + encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}} err: cbor.Encode_Error err = cbor._encode_u8(stream, 2, .Array) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) a := "a" err = cbor.encode(encoder, &a) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) { err = cbor.encode_stream_begin(stream, .Map) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) b := "b" c := "c" err = cbor.encode_stream_map_entry(encoder, &b, &c) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) err = cbor.encode_stream_end(stream) - expect_value(t, err, nil) + testing.expect_value(t, err, nil) } - expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x82\x61\x61\xbf\x61\x62\x61\x63\xff"))) + testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)string("\x82\x61\x61\xbf\x61\x62\x61\x63\xff"))) } } @@ -807,30 +726,30 @@ expect_decoding :: proc(t: ^testing.T, encoded: string, decoded: string, type: t res, err := cbor.decode(encoded) defer cbor.destroy(res) - expect_value(t, reflect.union_variant_typeid(res), type, loc) - expect_value(t, err, nil, loc) + testing.expect_value(t, reflect.union_variant_typeid(res), type, loc) + testing.expect_value(t, err, nil, loc) str := cbor.to_diagnostic_format(res, padding=-1) defer delete(str) - expect_value(t, str, decoded, loc) + testing.expect_value(t, str, decoded, loc) } expect_tag :: proc(t: ^testing.T, encoded: string, nr: cbor.Tag_Number, value_decoded: string, loc := #caller_location) { res, err := cbor.decode(encoded) defer cbor.destroy(res) - expect_value(t, err, nil, loc) + testing.expect_value(t, err, nil, loc) if tag, is_tag := res.(^cbor.Tag); is_tag { - expect_value(t, tag.number, nr, loc) + testing.expect_value(t, tag.number, nr, loc) str := cbor.to_diagnostic_format(tag, padding=-1) defer delete(str) - expect_value(t, str, value_decoded, loc) + testing.expect_value(t, str, value_decoded, loc) } else { - errorf(t, "Value %#v is not a tag", res, loc) + testing.expectf(t, false, "Value %#v is not a tag", res, loc) } } @@ -838,35 +757,39 @@ expect_float :: proc(t: ^testing.T, encoded: string, expected: $T, loc := #calle res, err := cbor.decode(encoded) defer cbor.destroy(res) - expect_value(t, reflect.union_variant_typeid(res), typeid_of(T), loc) - expect_value(t, err, nil, loc) + testing.expect_value(t, reflect.union_variant_typeid(res), typeid_of(T), loc) + testing.expect_value(t, err, nil, loc) #partial switch r in res { case f16: - when T == f16 { expect_value(t, res, expected, loc) } else { unreachable() } + when T == f16 { testing.expect_value(t, res, expected, loc) } else { unreachable() } case f32: - when T == f32 { expect_value(t, res, expected, loc) } else { unreachable() } + when T == f32 { testing.expect_value(t, res, expected, loc) } else { unreachable() } case f64: - when T == f64 { expect_value(t, res, expected, loc) } else { unreachable() } + when T == f64 { testing.expect_value(t, res, expected, loc) } else { unreachable() } case: unreachable() } } -buf: bytes.Buffer -stream := bytes.buffer_to_stream(&buf) -encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}} - expect_encoding :: proc(t: ^testing.T, val: cbor.Value, encoded: string, loc := #caller_location) { - bytes.buffer_reset(&buf) + buf: bytes.Buffer + bytes.buffer_init_allocator(&buf, 0, 0) + defer bytes.buffer_destroy(&buf) + stream := bytes.buffer_to_stream(&buf) + encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}} - err := cbor.encode(encoder, val) - expect_value(t, err, nil, loc) - expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc) + err := cbor.encode(encoder, val, loc) + testing.expect_value(t, err, nil, loc) + testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc) } expect_streamed_encoding :: proc(t: ^testing.T, encoded: string, values: ..cbor.Value, loc := #caller_location) { - bytes.buffer_reset(&buf) + buf: bytes.Buffer + bytes.buffer_init_allocator(&buf, 0, 0) + defer bytes.buffer_destroy(&buf) + stream := bytes.buffer_to_stream(&buf) + encoder := cbor.Encoder{cbor.ENCODE_FULLY_DETERMINISTIC, stream, {}} for value, i in values { err: cbor.Encode_Error @@ -891,15 +814,15 @@ expect_streamed_encoding :: proc(t: ^testing.T, encoded: string, values: ..cbor. if err2 != nil { break } } case: - errorf(t, "%v does not support streamed encoding", reflect.union_variant_typeid(value)) + testing.expectf(t, false, "%v does not support streamed encoding", reflect.union_variant_typeid(value)) } - expect_value(t, err, nil, loc) - expect_value(t, err2, nil, loc) + testing.expect_value(t, err, nil, loc) + testing.expect_value(t, err2, nil, loc) } err := cbor.encode_stream_end(stream) - expect_value(t, err, nil, loc) + testing.expect_value(t, err, nil, loc) - expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc) + testing.expect_value(t, fmt.tprint(bytes.buffer_to_bytes(&buf)), fmt.tprint(transmute([]byte)encoded), loc) } From 1f6a6f2cd367aec2e506ae8d5fafcb34d4b2a0e3 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 18:04:59 -0400 Subject: [PATCH 37/93] Support deterministic random seeding of tests Add a new option `ODIN_TEST_RANDOM_SEED` which is picked from the cycle counter at startup, if it's not specified by the user. This number is sent to every test in the `T` struct and reset every test (just in case). --- core/testing/runner.odin | 14 ++++++++++++++ core/testing/testing.odin | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 759b23b0f..faba54286 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -9,6 +9,7 @@ import "core:encoding/base64" import "core:fmt" import "core:io" import pkg_log "core:log" +import "core:math/rand" import "core:mem" import "core:os" import "core:slice" @@ -38,6 +39,9 @@ FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) // How many test results to show at a time per package. PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) +// This is the random seed that will be sent to each test. +// If it is unspecified, it will be set to the system cycle counter at startup. +SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) end_t :: proc(t: ^T) { @@ -333,6 +337,12 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { defer bytes.buffer_destroy(&clipboard_buffer) } + when SHARED_RANDOM_SEED == 0 { + shared_random_seed := cast(u64)intrinsics.read_cycle_counter() + } else { + shared_random_seed := SHARED_RANDOM_SEED + } + // -- Setup initial tasks. // NOTE(Feoramund): This is the allocator that will be used by threads to @@ -356,6 +366,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { defer run_index += 1 data.it = it + data.t.seed = shared_random_seed #no_bounds_check data.t.channel = chan.as_send(task_channels[task_index].channel) data.t._log_allocator = shared_log_allocator data.allocator_index = task_index @@ -383,6 +394,8 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { draw_status_bar(stdout, thread_count_status_string, total_done_count, total_test_count) } + pkg_log.infof("The random seed sent to every test is: %v", shared_random_seed) + when TRACKING_MEMORY { when ALWAYS_REPORT_MEMORY { pkg_log.info("Memory tracking is enabled. Tests will log their memory usage when complete.") @@ -428,6 +441,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { defer run_index += 1 data.it = it + data.t.seed = shared_random_seed data.t.error_count = 0 thread.pool_add_task(&pool, task.allocator, run_test_task, data, run_index) diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 30109304d..92b4d391d 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -29,6 +29,16 @@ Internal_Cleanup :: struct { T :: struct { error_count: int, + // If your test needs to perform random operations, it's advised to use + // this value to seed a local random number generator rather than relying + // on the non-thread-safe global one. + // + // This way, your results will be deterministic. + // + // This value is chosen at startup of the test runner, logged, and may be + // specified by the user. It is the same for all tests of a single run. + seed: u64, + channel: Update_Channel_Sender, cleanups: [dynamic]Internal_Cleanup, From b74b956fdaccbd930851e705ecc3e7d0f5d8a957 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 29 May 2024 18:09:41 -0400 Subject: [PATCH 38/93] Remove unneeded import --- core/testing/runner.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index faba54286..47ae5d528 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -9,7 +9,6 @@ import "core:encoding/base64" import "core:fmt" import "core:io" import pkg_log "core:log" -import "core:math/rand" import "core:mem" import "core:os" import "core:slice" From 40b20fb47353e61681ef815c43423d76b99e61d9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 11:32:41 +0200 Subject: [PATCH 39/93] Port `tests\core\c\libc` --- tests/core/Makefile | 2 +- tests/core/build.bat | 5 +++ tests/core/c/libc/test_core_libc.odin | 36 ------------------- .../c/libc/test_core_libc_complex_pow.odin | 15 ++++---- 4 files changed, 13 insertions(+), 45 deletions(-) delete mode 100644 tests/core/c/libc/test_core_libc.odin diff --git a/tests/core/Makefile b/tests/core/Makefile index 0a1055120..4073da3f1 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -33,7 +33,7 @@ download_test_assets: $(PYTHON) download_assets.py c_libc_test: - $(ODIN) run c/libc $(COMMON) -out:test_core_libc + $(ODIN) test c/libc $(COMMON) -out:test_core_libc compress_test: $(ODIN) test compress $(COMMON) -out:test_core_compress diff --git a/tests/core/build.bat b/tests/core/build.bat index a26ccf176..69a7d432a 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -3,6 +3,11 @@ set COMMON=-no-bounds-check -vet -strict-style set COLLECTION=-collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py +echo --- +echo Running core:c/libc tests +echo --- +%PATH_TO_ODIN% test c\libc %COMMON% -out:test_libc.exe || exit /b + echo --- echo Running core:compress tests echo --- diff --git a/tests/core/c/libc/test_core_libc.odin b/tests/core/c/libc/test_core_libc.odin deleted file mode 100644 index 9b5014dee..000000000 --- a/tests/core/c/libc/test_core_libc.odin +++ /dev/null @@ -1,36 +0,0 @@ -package test_core_libc - -import "core:fmt" -import "core:os" -import "core:testing" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - test_libc_complex(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} diff --git a/tests/core/c/libc/test_core_libc_complex_pow.odin b/tests/core/c/libc/test_core_libc_complex_pow.odin index 90928794c..cd50c8f6a 100644 --- a/tests/core/c/libc/test_core_libc_complex_pow.odin +++ b/tests/core/c/libc/test_core_libc_complex_pow.odin @@ -1,8 +1,8 @@ package test_core_libc import "core:testing" -import "core:fmt" import "core:c/libc" +import "core:log" reldiff :: proc(lhs, rhs: $T) -> f64 { if lhs == rhs { @@ -14,7 +14,7 @@ reldiff :: proc(lhs, rhs: $T) -> f64 { return out } -isclose :: proc(lhs, rhs: $T, rtol:f64 = 1e-12, atol:f64 = 1e-12) -> bool { +isclose :: proc(t: ^testing.T, lhs, rhs: $T, rtol:f64 = 1e-12, atol:f64 = 1e-12) -> bool { adiff := f64(abs(lhs - rhs)) if adiff < atol { return true @@ -23,7 +23,7 @@ isclose :: proc(lhs, rhs: $T, rtol:f64 = 1e-12, atol:f64 = 1e-12) -> bool { if rdiff < rtol { return true } - fmt.printf("not close -- lhs:%v rhs:%v -- adiff:%e rdiff:%e\n",lhs, rhs, adiff, rdiff) + log.infof("not close -- lhs:%v rhs:%v -- adiff:%e rdiff:%e\n",lhs, rhs, adiff, rdiff) return false } @@ -44,7 +44,6 @@ test_libc_complex :: proc(t: ^testing.T) { test_libc_pow_binding(t, libc.complex_float, f32, libc_powf, 1e-12, 1e-5) } -@test test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, pow: proc(LIBC_COMPLEX, LIBC_COMPLEX) -> LIBC_COMPLEX, rtol: f64, atol: f64) { // Tests that c/libc/pow(f) functions have two arguments and that the function works as expected for simple inputs @@ -56,8 +55,8 @@ test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, po for n in -4..=4 { complex_power := LIBC_COMPLEX(complex(F(n), F(0.))) result := pow(complex_base, complex_power) - expect(t, isclose(expected_real, F(real(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol)) - expect(t, isclose(expected_imag, F(imag(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol)) + testing.expectf(t, isclose(t, expected_real, F(real(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol) + testing.expectf(t, isclose(t, expected_imag, F(imag(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol) expected_real *= 2 } } @@ -83,8 +82,8 @@ test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, po expected_real = 0. expected_imag = -value } - expect(t, isclose(expected_real, F(real(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol)) - expect(t, isclose(expected_imag, F(imag(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol)) + testing.expectf(t, isclose(t, expected_real, F(real(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol) + testing.expectf(t, isclose(t, expected_imag, F(imag(result)), rtol, atol), "ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol) value *= 2 } } From 3404dea8ac741f98e3de4a341f64ef37d06550d9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 11:42:34 +0200 Subject: [PATCH 40/93] Port `tests\encoding\hex` --- core/encoding/hex/hex.odin | 11 ++- tests/core/Makefile | 2 +- tests/core/encoding/hex/test_core_hex.odin | 94 ++++++++++------------ 3 files changed, 50 insertions(+), 57 deletions(-) diff --git a/core/encoding/hex/hex.odin b/core/encoding/hex/hex.odin index dbffe216b..c2cd89c5b 100644 --- a/core/encoding/hex/hex.odin +++ b/core/encoding/hex/hex.odin @@ -2,8 +2,8 @@ package encoding_hex import "core:strings" -encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check { - dst := make([]byte, len(src) * 2, allocator) +encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> []byte #no_bounds_check { + dst := make([]byte, len(src) * 2, allocator, loc) for i, j := 0, 0; i < len(src); i += 1 { v := src[i] dst[j] = HEXTABLE[v>>4] @@ -15,12 +15,12 @@ encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds } -decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check { +decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) #no_bounds_check { if len(src) % 2 == 1 { return } - dst = make([]byte, len(src) / 2, allocator) + dst = make([]byte, len(src) / 2, allocator, loc) for i, j := 0, 1; j < len(src); j += 2 { p := src[j-1] q := src[j] @@ -69,5 +69,4 @@ hex_digit :: proc(char: byte) -> (u8, bool) { case 'A' ..= 'F': return char - 'A' + 10, true case: return 0, false } -} - +} \ No newline at end of file diff --git a/tests/core/Makefile b/tests/core/Makefile index 4073da3f1..93d141e60 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -47,7 +47,7 @@ crypto_test: encoding_test: $(ODIN) test encoding/base64 $(COMMON) -out:test_base64 $(ODIN) test encoding/cbor $(COMMON) -out:test_cbor - $(ODIN) run encoding/hex $(COMMON) -out:test_hex + $(ODIN) test encoding/hex $(COMMON) -out:test_hex $(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa $(ODIN) run encoding/json $(COMMON) -out:test_json $(ODIN) run encoding/varint $(COMMON) -out:test_varint diff --git a/tests/core/encoding/hex/test_core_hex.odin b/tests/core/encoding/hex/test_core_hex.odin index d928cd28e..6a00c9705 100644 --- a/tests/core/encoding/hex/test_core_hex.odin +++ b/tests/core/encoding/hex/test_core_hex.odin @@ -2,42 +2,6 @@ package test_core_hex import "core:encoding/hex" import "core:testing" -import "core:fmt" -import "core:os" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - hex_encode(&t) - hex_decode(&t) - hex_decode_sequence(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} CASES :: [][2]string{ {"11", "3131"}, @@ -49,10 +13,14 @@ CASES :: [][2]string{ hex_encode :: proc(t: ^testing.T) { for test in CASES { encoded := string(hex.encode(transmute([]byte)test[0])) - expect( + defer delete(encoded) + testing.expectf( t, encoded == test[1], - fmt.tprintf("encode: %q -> %q (should be: %q)", test[0], encoded, test[1]), + "encode: %q -> %q (should be: %q)", + test[0], + encoded, + test[1], ) } } @@ -61,11 +29,20 @@ hex_encode :: proc(t: ^testing.T) { hex_decode :: proc(t: ^testing.T) { for test in CASES { decoded, ok := hex.decode(transmute([]byte)test[1]) - expect(t, ok, fmt.tprintf("decode: %q not ok", test[1])) - expect( + defer delete(decoded) + testing.expectf( + t, + ok, + "decode: %q not ok", + test[1], + ) + testing.expectf( t, string(decoded) == test[0], - fmt.tprintf("decode: %q -> %q (should be: %q)", test[1], string(decoded), test[0]), + "decode: %q -> %q (should be: %q)", + test[1], + string(decoded), + test[0], ) } } @@ -73,20 +50,37 @@ hex_decode :: proc(t: ^testing.T) { @(test) hex_decode_sequence :: proc(t: ^testing.T) { b, ok := hex.decode_sequence("0x23") - expect(t, ok, "decode_sequence: 0x23 not ok") - expect(t, b == '#', fmt.tprintf("decode_sequence: 0x23 -> %c (should be: %c)", b, '#')) + testing.expect(t, ok, "decode_sequence: 0x23 not ok") + testing.expectf( + t, + b == '#', + "decode_sequence: 0x23 -> %c (should be: %c)", + b, + '#', + ) b, ok = hex.decode_sequence("0X3F") - expect(t, ok, "decode_sequence: 0X3F not ok") - expect(t, b == '?', fmt.tprintf("decode_sequence: 0X3F -> %c (should be: %c)", b, '?')) + testing.expect(t, ok, "decode_sequence: 0X3F not ok") + testing.expectf( + t, + b == '?', + "decode_sequence: 0X3F -> %c (should be: %c)", + b, + '?', + ) b, ok = hex.decode_sequence("2a") - expect(t, ok, "decode_sequence: 2a not ok") - expect(t, b == '*', fmt.tprintf("decode_sequence: 2a -> %c (should be: %c)", b, '*')) + testing.expect(t, ok, "decode_sequence: 2a not ok") + testing.expectf(t, + b == '*', + "decode_sequence: 2a -> %c (should be: %c)", + b, + '*', + ) _, ok = hex.decode_sequence("1") - expect(t, !ok, "decode_sequence: 1 should be too short") + testing.expect(t, !ok, "decode_sequence: 1 should be too short") _, ok = hex.decode_sequence("123") - expect(t, !ok, "decode_sequence: 123 should be too long") -} + testing.expect(t, !ok, "decode_sequence: 123 should be too long") +} \ No newline at end of file From 1b32e27aa47c59a71b1cf4fefd40ce6e5ffc5bfb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 13:10:38 +0200 Subject: [PATCH 41/93] Port `tests\core\encoding\hxa` And fix a few leaks in `core:encoding/hxa` while at it. --- core/encoding/hxa/hxa.odin | 31 ++-- core/encoding/hxa/read.odin | 42 ++--- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/encoding/hxa/test_core_hxa.odin | 202 +++++++++------------ 5 files changed, 125 insertions(+), 154 deletions(-) diff --git a/core/encoding/hxa/hxa.odin b/core/encoding/hxa/hxa.odin index 9b24ede9c..9d0c58196 100644 --- a/core/encoding/hxa/hxa.odin +++ b/core/encoding/hxa/hxa.odin @@ -160,34 +160,35 @@ CONVENTION_SOFT_TRANSFORM :: "transform" /* destroy procedures */ -meta_destroy :: proc(meta: Meta, allocator := context.allocator) { +meta_destroy :: proc(meta: Meta, allocator := context.allocator, loc := #caller_location) { if nested, ok := meta.value.([]Meta); ok { for m in nested { - meta_destroy(m) + meta_destroy(m, loc=loc) } - delete(nested, allocator) + delete(nested, allocator, loc=loc) } } -nodes_destroy :: proc(nodes: []Node, allocator := context.allocator) { +nodes_destroy :: proc(nodes: []Node, allocator := context.allocator, loc := #caller_location) { for node in nodes { for meta in node.meta_data { - meta_destroy(meta) + meta_destroy(meta, loc=loc) } - delete(node.meta_data, allocator) + delete(node.meta_data, allocator, loc=loc) switch n in node.content { case Node_Geometry: - delete(n.corner_stack, allocator) - delete(n.edge_stack, allocator) - delete(n.face_stack, allocator) + delete(n.corner_stack, allocator, loc=loc) + delete(n.vertex_stack, allocator, loc=loc) + delete(n.edge_stack, allocator, loc=loc) + delete(n.face_stack, allocator, loc=loc) case Node_Image: - delete(n.image_stack, allocator) + delete(n.image_stack, allocator, loc=loc) } } - delete(nodes, allocator) + delete(nodes, allocator, loc=loc) } -file_destroy :: proc(file: File) { - nodes_destroy(file.nodes, file.allocator) - delete(file.backing, file.allocator) -} +file_destroy :: proc(file: File, loc := #caller_location) { + nodes_destroy(file.nodes, file.allocator, loc=loc) + delete(file.backing, file.allocator, loc=loc) +} \ No newline at end of file diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index f37dc3193..5c8503229 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -11,24 +11,21 @@ Read_Error :: enum { Unable_To_Read_File, } -read_from_file :: proc(filename: string, print_error := false, allocator := context.allocator) -> (file: File, err: Read_Error) { +read_from_file :: proc(filename: string, print_error := false, allocator := context.allocator, loc := #caller_location) -> (file: File, err: Read_Error) { context.allocator = allocator - data, ok := os.read_entire_file(filename) + data, ok := os.read_entire_file(filename, allocator, loc) if !ok { err = .Unable_To_Read_File + delete(data, allocator, loc) return } - defer if !ok { - delete(data) - } else { - file.backing = data - } - file, err = read(data, filename, print_error, allocator) + file, err = read(data, filename, print_error, allocator, loc) + file.backing = data return } -read :: proc(data: []byte, filename := "", print_error := false, allocator := context.allocator) -> (file: File, err: Read_Error) { +read :: proc(data: []byte, filename := "", print_error := false, allocator := context.allocator, loc := #caller_location) -> (file: File, err: Read_Error) { Reader :: struct { filename: string, data: []byte, @@ -79,8 +76,8 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato return string(data[:len]), nil } - read_meta :: proc(r: ^Reader, capacity: u32le) -> (meta_data: []Meta, err: Read_Error) { - meta_data = make([]Meta, int(capacity)) + read_meta :: proc(r: ^Reader, capacity: u32le, allocator := context.allocator, loc := #caller_location) -> (meta_data: []Meta, err: Read_Error) { + meta_data = make([]Meta, int(capacity), allocator=allocator) count := 0 defer meta_data = meta_data[:count] for &m in meta_data { @@ -111,10 +108,10 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato return } - read_layer_stack :: proc(r: ^Reader, capacity: u32le) -> (layers: Layer_Stack, err: Read_Error) { + read_layer_stack :: proc(r: ^Reader, capacity: u32le, allocator := context.allocator, loc := #caller_location) -> (layers: Layer_Stack, err: Read_Error) { stack_count := read_value(r, u32le) or_return layer_count := 0 - layers = make(Layer_Stack, stack_count) + layers = make(Layer_Stack, stack_count, allocator=allocator, loc=loc) defer layers = layers[:layer_count] for &layer in layers { layer.name = read_name(r) or_return @@ -170,7 +167,8 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato node_count := 0 file.header = header^ - file.nodes = make([]Node, header.internal_node_count) + file.nodes = make([]Node, header.internal_node_count, allocator=allocator, loc=loc) + file.allocator = allocator defer if err != nil { nodes_destroy(file.nodes) file.nodes = nil @@ -198,15 +196,15 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato case .Geometry: g: Node_Geometry - g.vertex_count = read_value(r, u32le) or_return - g.vertex_stack = read_layer_stack(r, g.vertex_count) or_return - g.edge_corner_count = read_value(r, u32le) or_return - g.corner_stack = read_layer_stack(r, g.edge_corner_count) or_return + g.vertex_count = read_value(r, u32le) or_return + g.vertex_stack = read_layer_stack(r, g.vertex_count, loc=loc) or_return + g.edge_corner_count = read_value(r, u32le) or_return + g.corner_stack = read_layer_stack(r, g.edge_corner_count, loc=loc) or_return if header.version > 2 { - g.edge_stack = read_layer_stack(r, g.edge_corner_count) or_return + g.edge_stack = read_layer_stack(r, g.edge_corner_count, loc=loc) or_return } - g.face_count = read_value(r, u32le) or_return - g.face_stack = read_layer_stack(r, g.face_count) or_return + g.face_count = read_value(r, u32le) or_return + g.face_stack = read_layer_stack(r, g.face_count, loc=loc) or_return node.content = g @@ -233,4 +231,4 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato } return -} +} \ No newline at end of file diff --git a/tests/core/Makefile b/tests/core/Makefile index 93d141e60..46b9e352e 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -48,7 +48,7 @@ encoding_test: $(ODIN) test encoding/base64 $(COMMON) -out:test_base64 $(ODIN) test encoding/cbor $(COMMON) -out:test_cbor $(ODIN) test encoding/hex $(COMMON) -out:test_hex - $(ODIN) run encoding/hxa $(COMMON) $(COLLECTION) -out:test_hxa + $(ODIN) test encoding/hxa $(COMMON) -out:test_hxa $(ODIN) run encoding/json $(COMMON) -out:test_json $(ODIN) run encoding/varint $(COMMON) -out:test_varint $(ODIN) run encoding/xml $(COMMON) -out:test_xml diff --git a/tests/core/build.bat b/tests/core/build.bat index 69a7d432a..094a12f14 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -29,7 +29,7 @@ echo --- %PATH_TO_ODIN% test encoding/base64 %COMMON% -out:test_base64.exe || exit /b %PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe || exit /b %PATH_TO_ODIN% test encoding/hex %COMMON% -out:test_hex.exe || exit /b -rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b +%PATH_TO_ODIN% test encoding/hxa %COMMON% -out:test_hxa.exe || exit /b %PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b diff --git a/tests/core/encoding/hxa/test_core_hxa.odin b/tests/core/encoding/hxa/test_core_hxa.odin index 40c3c2e23..31d40c8b3 100644 --- a/tests/core/encoding/hxa/test_core_hxa.odin +++ b/tests/core/encoding/hxa/test_core_hxa.odin @@ -6,127 +6,99 @@ package test_core_hxa import "core:encoding/hxa" import "core:fmt" import "core:testing" -import tc "tests:common" -TEAPOT_PATH :: "core/assets/HXA/teapot.hxa" +TEAPOT_PATH :: ODIN_ROOT + "tests/core/assets/HXA/teapot.hxa" -main :: proc() { - t := testing.T{} - - test_read(&t) - test_write(&t) - - tc.report(&t) -} +import "core:os" @test test_read :: proc(t: ^testing.T) { - filename := tc.get_data_path(t, TEAPOT_PATH) - defer delete(filename) + data, _ := os.read_entire_file(TEAPOT_PATH) + // file, err := hxa.read_from_file(TEAPOT_PATH) + file, err := hxa.read(data) + file.backing = data + file.allocator = context.allocator + hxa.file_destroy(file) + // fmt.printfln("%#v", file) - file, err := hxa.read_from_file(filename) e :: hxa.Read_Error.None - tc.expect(t, err == e, fmt.tprintf("%v: read_from_file(%v) -> %v != %v", #procedure, filename, err, e)) - defer hxa.file_destroy(file) + testing.expectf(t, err == e, "read_from_file(%v) -> %v != %v", TEAPOT_PATH, err, e) /* Header */ - tc.expect(t, file.magic_number == 0x417848, fmt.tprintf("%v: file.magic_number %v != %v", - #procedure, file.magic_number, 0x417848)) - tc.expect(t, file.version == 1, fmt.tprintf("%v: file.version %v != %v", - #procedure, file.version, 1)) - tc.expect(t, file.internal_node_count == 1, fmt.tprintf("%v: file.internal_node_count %v != %v", - #procedure, file.internal_node_count, 1)) + testing.expectf(t, file.magic_number == 0x417848, "file.magic_number %v != %v", file.magic_number, 0x417848) + testing.expectf(t, file.version == 1, "file.version %v != %v", file.version, 1) + testing.expectf(t, file.internal_node_count == 1, "file.internal_node_count %v != %v", file.internal_node_count, 1) /* Nodes (only one) */ - tc.expect(t, len(file.nodes) == 1, fmt.tprintf("%v: len(file.nodes) %v != %v", #procedure, len(file.nodes), 1)) + testing.expectf(t, len(file.nodes) == 1, "len(file.nodes) %v != %v", len(file.nodes), 1) m := &file.nodes[0].meta_data - tc.expect(t, len(m^) == 38, fmt.tprintf("%v: len(m^) %v != %v", #procedure, len(m^), 38)) + testing.expectf(t, len(m^) == 38, "len(m^) %v != %v", len(m^), 38) { e :: "Texture resolution" - tc.expect(t, m[0].name == e, fmt.tprintf("%v: m[0].name %v != %v", #procedure, m[0].name, e)) + testing.expectf(t, m[0].name == e, "m[0].name %v != %v", m[0].name, e) m_v, m_v_ok := m[0].value.([]i64le) - tc.expect(t, m_v_ok, fmt.tprintf("%v: m_v_ok %v != %v", #procedure, m_v_ok, true)) - tc.expect(t, len(m_v) == 1, fmt.tprintf("%v: len(m_v) %v != %v", #procedure, len(m_v), 1)) - tc.expect(t, m_v[0] == 1024, fmt.tprintf("%v: m_v[0] %v != %v", #procedure, len(m_v), 1024)) + testing.expectf(t, m_v_ok, "m_v_ok %v != %v", m_v_ok, true) + testing.expectf(t, len(m_v) == 1, "len(m_v) %v != %v", len(m_v), 1) + testing.expectf(t, m_v[0] == 1024, "m_v[0] %v != %v", len(m_v), 1024) } { e :: "Validate" - tc.expect(t, m[37].name == e, fmt.tprintf("%v: m[37].name %v != %v", #procedure, m[37].name, e)) + testing.expectf(t, m[37].name == e, "m[37].name %v != %v", m[37].name, e) m_v, m_v_ok := m[37].value.([]i64le) - tc.expect(t, m_v_ok, fmt.tprintf("%v: m_v_ok %v != %v", #procedure, m_v_ok, true)) - tc.expect(t, len(m_v) == 1, fmt.tprintf("%v: len(m_v) %v != %v", #procedure, len(m_v), 1)) - tc.expect(t, m_v[0] == -2054847231, fmt.tprintf("%v: m_v[0] %v != %v", #procedure, len(m_v), -2054847231)) + testing.expectf(t, m_v_ok, "m_v_ok %v != %v", m_v_ok, true) + testing.expectf(t, len(m_v) == 1, "len(m_v) %v != %v", len(m_v), 1) + testing.expectf(t, m_v[0] == -2054847231, "m_v[0] %v != %v", len(m_v), -2054847231) } /* Node content */ v, v_ok := file.nodes[0].content.(hxa.Node_Geometry) - tc.expect(t, v_ok, fmt.tprintf("%v: v_ok %v != %v", #procedure, v_ok, true)) + testing.expectf(t, v_ok, "v_ok %v != %v", v_ok, true) - tc.expect(t, v.vertex_count == 530, fmt.tprintf("%v: v.vertex_count %v != %v", #procedure, v.vertex_count, 530)) - tc.expect(t, v.edge_corner_count == 2026, fmt.tprintf("%v: v.edge_corner_count %v != %v", - #procedure, v.edge_corner_count, 2026)) - tc.expect(t, v.face_count == 517, fmt.tprintf("%v: v.face_count %v != %v", #procedure, v.face_count, 517)) + testing.expectf(t, v.vertex_count == 530, "v.vertex_count %v != %v", v.vertex_count, 530) + testing.expectf(t, v.edge_corner_count == 2026, "v.edge_corner_count %v != %v", v.edge_corner_count, 2026) + testing.expectf(t, v.face_count == 517, "v.face_count %v != %v", v.face_count, 517) /* Vertex stack */ - tc.expect(t, len(v.vertex_stack) == 1, fmt.tprintf("%v: len(v.vertex_stack) %v != %v", - #procedure, len(v.vertex_stack), 1)) + testing.expectf(t, len(v.vertex_stack) == 1, "len(v.vertex_stack) %v != %v", len(v.vertex_stack), 1) { e := "vertex" - tc.expect(t, v.vertex_stack[0].name == e, fmt.tprintf("%v: v.vertex_stack[0].name %v != %v", - #procedure, v.vertex_stack[0].name, e)) + testing.expectf(t, v.vertex_stack[0].name == e, "v.vertex_stack[0].name %v != %v", v.vertex_stack[0].name, e) } - tc.expect(t, v.vertex_stack[0].components == 3, fmt.tprintf("%v: v.vertex_stack[0].components %v != %v", - #procedure, v.vertex_stack[0].components, 3)) + testing.expectf(t, v.vertex_stack[0].components == 3, "v.vertex_stack[0].components %v != %v", v.vertex_stack[0].components, 3) /* Vertex stack data */ vs_d, vs_d_ok := v.vertex_stack[0].data.([]f64le) - tc.expect(t, vs_d_ok, fmt.tprintf("%v: vs_d_ok %v != %v", #procedure, vs_d_ok, true)) - tc.expect(t, len(vs_d) == 1590, fmt.tprintf("%v: len(vs_d) %v != %v", #procedure, len(vs_d), 1590)) - - tc.expect(t, vs_d[0] == 4.06266, fmt.tprintf("%v: vs_d[0] %v (%h) != %v (%h)", - #procedure, vs_d[0], vs_d[0], 4.06266, 4.06266)) - tc.expect(t, vs_d[1] == 2.83457, fmt.tprintf("%v: vs_d[1] %v (%h) != %v (%h)", - #procedure, vs_d[1], vs_d[1], 2.83457, 2.83457)) - tc.expect(t, vs_d[2] == 0hbfbc5da6a4441787, fmt.tprintf("%v: vs_d[2] %v (%h) != %v (%h)", - #procedure, vs_d[2], vs_d[2], - 0hbfbc5da6a4441787, 0hbfbc5da6a4441787)) - tc.expect(t, vs_d[3] == 0h4010074fb549f948, fmt.tprintf("%v: vs_d[3] %v (%h) != %v (%h)", - #procedure, vs_d[3], vs_d[3], - 0h4010074fb549f948, 0h4010074fb549f948)) - tc.expect(t, vs_d[1587] == 0h400befa82e87d2c7, fmt.tprintf("%v: vs_d[1587] %v (%h) != %v (%h)", - #procedure, vs_d[1587], vs_d[1587], - 0h400befa82e87d2c7, 0h400befa82e87d2c7)) - tc.expect(t, vs_d[1588] == 2.83457, fmt.tprintf("%v: vs_d[1588] %v (%h) != %v (%h)", - #procedure, vs_d[1588], vs_d[1588], 2.83457, 2.83457)) - tc.expect(t, vs_d[1589] == -1.56121, fmt.tprintf("%v: vs_d[1589] %v (%h) != %v (%h)", - #procedure, vs_d[1589], vs_d[1589], -1.56121, -1.56121)) + testing.expectf(t, vs_d_ok, "vs_d_ok %v != %v", vs_d_ok, true) + testing.expectf(t, len(vs_d) == 1590, "len(vs_d) %v != %v", len(vs_d), 1590) + testing.expectf(t, vs_d[0] == 4.06266, "vs_d[0] %v (%h) != %v (%h)", vs_d[0], vs_d[0], 4.06266, 4.06266) + testing.expectf(t, vs_d[1] == 2.83457, "vs_d[1] %v (%h) != %v (%h)", vs_d[1], vs_d[1], 2.83457, 2.83457) + testing.expectf(t, vs_d[2] == 0hbfbc5da6a4441787, "vs_d[2] %v (%h) != %v (%h)", vs_d[2], vs_d[2], 0hbfbc5da6a4441787, 0hbfbc5da6a4441787) + testing.expectf(t, vs_d[3] == 0h4010074fb549f948, "vs_d[3] %v (%h) != %v (%h)", vs_d[3], vs_d[3], 0h4010074fb549f948, 0h4010074fb549f948) + testing.expectf(t, vs_d[1587] == 0h400befa82e87d2c7, "vs_d[1587] %v (%h) != %v (%h)", vs_d[1587], vs_d[1587], 0h400befa82e87d2c7, 0h400befa82e87d2c7) + testing.expectf(t, vs_d[1588] == 2.83457, "vs_d[1588] %v (%h) != %v (%h)", vs_d[1588], vs_d[1588], 2.83457, 2.83457) + testing.expectf(t, vs_d[1589] == -1.56121, "vs_d[1589] %v (%h) != %v (%h)", vs_d[1589], vs_d[1589], -1.56121, -1.56121) /* Corner stack */ - tc.expect(t, len(v.corner_stack) == 1, - fmt.tprintf("%v: len(v.corner_stack) %v != %v", #procedure, len(v.corner_stack), 1)) + testing.expectf(t, len(v.corner_stack) == 1, "len(v.corner_stack) %v != %v", len(v.corner_stack), 1) { e := "reference" - tc.expect(t, v.corner_stack[0].name == e, fmt.tprintf("%v: v.corner_stack[0].name %v != %v", - #procedure, v.corner_stack[0].name, e)) + testing.expectf(t, v.corner_stack[0].name == e, "v.corner_stack[0].name %v != %v", v.corner_stack[0].name, e) } - tc.expect(t, v.corner_stack[0].components == 1, fmt.tprintf("%v: v.corner_stack[0].components %v != %v", - #procedure, v.corner_stack[0].components, 1)) + testing.expectf(t, v.corner_stack[0].components == 1, "v.corner_stack[0].components %v != %v", v.corner_stack[0].components, 1) /* Corner stack data */ cs_d, cs_d_ok := v.corner_stack[0].data.([]i32le) - tc.expect(t, cs_d_ok, fmt.tprintf("%v: cs_d_ok %v != %v", #procedure, cs_d_ok, true)) - tc.expect(t, len(cs_d) == 2026, fmt.tprintf("%v: len(cs_d) %v != %v", #procedure, len(cs_d), 2026)) - tc.expect(t, cs_d[0] == 6, fmt.tprintf("%v: cs_d[0] %v != %v", #procedure, cs_d[0], 6)) - tc.expect(t, cs_d[2025] == -32, fmt.tprintf("%v: cs_d[2025] %v != %v", #procedure, cs_d[2025], -32)) + testing.expectf(t, cs_d_ok, "cs_d_ok %v != %v", cs_d_ok, true) + testing.expectf(t, len(cs_d) == 2026, "len(cs_d) %v != %v", len(cs_d), 2026) + testing.expectf(t, cs_d[0] == 6, "cs_d[0] %v != %v", cs_d[0], 6) + testing.expectf(t, cs_d[2025] == -32, "cs_d[2025] %v != %v", cs_d[2025], -32) /* Edge and face stacks (empty) */ - tc.expect(t, len(v.edge_stack) == 0, fmt.tprintf("%v: len(v.edge_stack) %v != %v", - #procedure, len(v.edge_stack), 0)) - tc.expect(t, len(v.face_stack) == 0, fmt.tprintf("%v: len(v.face_stack) %v != %v", - #procedure, len(v.face_stack), 0)) + testing.expectf(t, len(v.edge_stack) == 0, "len(v.edge_stack) %v != %v", len(v.edge_stack), 0) + testing.expectf(t, len(v.face_stack) == 0, "len(v.face_stack) %v != %v", len(v.face_stack), 0) } @test @@ -154,72 +126,72 @@ test_write :: proc(t: ^testing.T) { n, write_err := hxa.write(buf, w_file) write_e :: hxa.Write_Error.None - tc.expect(t, write_err == write_e, fmt.tprintf("%v: write_err %v != %v", #procedure, write_err, write_e)) - tc.expect(t, n == required_size, fmt.tprintf("%v: n %v != %v", #procedure, n, required_size)) + testing.expectf(t, write_err == write_e, fmt.tprintf("write_err %v != %v", write_err, write_e)) + testing.expectf(t, n == required_size, fmt.tprintf("n %v != %v", n, required_size)) file, read_err := hxa.read(buf) read_e :: hxa.Read_Error.None - tc.expect(t, read_err == read_e, fmt.tprintf("%v: read_err %v != %v", #procedure, read_err, read_e)) + testing.expectf(t, read_err == read_e, fmt.tprintf("read_err %v != %v", read_err, read_e)) defer hxa.file_destroy(file) - tc.expect(t, file.magic_number == 0x417848, fmt.tprintf("%v: file.magic_number %v != %v", - #procedure, file.magic_number, 0x417848)) - tc.expect(t, file.version == 3, fmt.tprintf("%v: file.version %v != %v", #procedure, file.version, 3)) - tc.expect(t, file.internal_node_count == 1, fmt.tprintf("%v: file.internal_node_count %v != %v", - #procedure, file.internal_node_count, 1)) + testing.expectf(t, file.magic_number == 0x417848, fmt.tprintf("file.magic_number %v != %v", + file.magic_number, 0x417848)) + testing.expectf(t, file.version == 3, fmt.tprintf("file.version %v != %v", file.version, 3)) + testing.expectf(t, file.internal_node_count == 1, fmt.tprintf("file.internal_node_count %v != %v", + file.internal_node_count, 1)) - tc.expect(t, len(file.nodes) == len(w_file.nodes), fmt.tprintf("%v: len(file.nodes) %v != %v", - #procedure, len(file.nodes), len(w_file.nodes))) + testing.expectf(t, len(file.nodes) == len(w_file.nodes), fmt.tprintf("len(file.nodes) %v != %v", + len(file.nodes), len(w_file.nodes))) m := &file.nodes[0].meta_data w_m := &w_file.nodes[0].meta_data - tc.expect(t, len(m^) == len(w_m^), fmt.tprintf("%v: len(m^) %v != %v", #procedure, len(m^), len(w_m^))) - tc.expect(t, m[0].name == w_m[0].name, fmt.tprintf("%v: m[0].name %v != %v", #procedure, m[0].name, w_m[0].name)) + testing.expectf(t, len(m^) == len(w_m^), fmt.tprintf("len(m^) %v != %v", len(m^), len(w_m^))) + testing.expectf(t, m[0].name == w_m[0].name, fmt.tprintf("m[0].name %v != %v", m[0].name, w_m[0].name)) m_v, m_v_ok := m[0].value.([]f64le) - tc.expect(t, m_v_ok, fmt.tprintf("%v: m_v_ok %v != %v", #procedure, m_v_ok, true)) - tc.expect(t, len(m_v) == len(n1_m1_value), fmt.tprintf("%v: %v != len(m_v) %v", - #procedure, len(m_v), len(n1_m1_value))) + testing.expectf(t, m_v_ok, fmt.tprintf("m_v_ok %v != %v", m_v_ok, true)) + testing.expectf(t, len(m_v) == len(n1_m1_value), fmt.tprintf("%v != len(m_v) %v", + len(m_v), len(n1_m1_value))) for i := 0; i < len(m_v); i += 1 { - tc.expect(t, m_v[i] == n1_m1_value[i], fmt.tprintf("%v: m_v[%d] %v != %v", - #procedure, i, m_v[i], n1_m1_value[i])) + testing.expectf(t, m_v[i] == n1_m1_value[i], fmt.tprintf("m_v[%d] %v != %v", + i, m_v[i], n1_m1_value[i])) } v, v_ok := file.nodes[0].content.(hxa.Node_Image) - tc.expect(t, v_ok, fmt.tprintf("%v: v_ok %v != %v", #procedure, v_ok, true)) - tc.expect(t, v.type == n1_content.type, fmt.tprintf("%v: v.type %v != %v", #procedure, v.type, n1_content.type)) - tc.expect(t, len(v.resolution) == 3, fmt.tprintf("%v: len(v.resolution) %v != %v", - #procedure, len(v.resolution), 3)) - tc.expect(t, len(v.image_stack) == len(n1_content.image_stack), fmt.tprintf("%v: len(v.image_stack) %v != %v", - #procedure, len(v.image_stack), len(n1_content.image_stack))) + testing.expectf(t, v_ok, fmt.tprintf("v_ok %v != %v", v_ok, true)) + testing.expectf(t, v.type == n1_content.type, fmt.tprintf("v.type %v != %v", v.type, n1_content.type)) + testing.expectf(t, len(v.resolution) == 3, fmt.tprintf("len(v.resolution) %v != %v", + len(v.resolution), 3)) + testing.expectf(t, len(v.image_stack) == len(n1_content.image_stack), fmt.tprintf("len(v.image_stack) %v != %v", + len(v.image_stack), len(n1_content.image_stack))) for i := 0; i < len(v.image_stack); i += 1 { - tc.expect(t, v.image_stack[i].name == n1_content.image_stack[i].name, - fmt.tprintf("%v: v.image_stack[%d].name %v != %v", - #procedure, i, v.image_stack[i].name, n1_content.image_stack[i].name)) - tc.expect(t, v.image_stack[i].components == n1_content.image_stack[i].components, - fmt.tprintf("%v: v.image_stack[%d].components %v != %v", - #procedure, i, v.image_stack[i].components, n1_content.image_stack[i].components)) + testing.expectf(t, v.image_stack[i].name == n1_content.image_stack[i].name, + fmt.tprintf("v.image_stack[%d].name %v != %v", + i, v.image_stack[i].name, n1_content.image_stack[i].name)) + testing.expectf(t, v.image_stack[i].components == n1_content.image_stack[i].components, + fmt.tprintf("v.image_stack[%d].components %v != %v", + i, v.image_stack[i].components, n1_content.image_stack[i].components)) switch n1_t in n1_content.image_stack[i].data { case []u8: - tc.expect(t, false, fmt.tprintf("%v: n1_content.image_stack[i].data []u8", #procedure)) + testing.expectf(t, false, fmt.tprintf("n1_content.image_stack[i].data []u8", #procedure)) case []i32le: - tc.expect(t, false, fmt.tprintf("%v: n1_content.image_stack[i].data []i32le", #procedure)) + testing.expectf(t, false, fmt.tprintf("n1_content.image_stack[i].data []i32le", #procedure)) case []f32le: l, l_ok := v.image_stack[i].data.([]f32le) - tc.expect(t, l_ok, fmt.tprintf("%v: l_ok %v != %v", #procedure, l_ok, true)) - tc.expect(t, len(l) == len(n1_t), fmt.tprintf("%v: len(l) %v != %v", #procedure, len(l), len(n1_t))) + testing.expectf(t, l_ok, fmt.tprintf("l_ok %v != %v", l_ok, true)) + testing.expectf(t, len(l) == len(n1_t), fmt.tprintf("len(l) %v != %v", len(l), len(n1_t))) for j := 0; j < len(l); j += 1 { - tc.expect(t, l[j] == n1_t[j], fmt.tprintf("%v: l[%d] %v (%h) != %v (%h)", - #procedure, j, l[j], l[j], n1_t[j], n1_t[j])) + testing.expectf(t, l[j] == n1_t[j], fmt.tprintf("l[%d] %v (%h) != %v (%h)", + j, l[j], l[j], n1_t[j], n1_t[j])) } case []f64le: l, l_ok := v.image_stack[i].data.([]f64le) - tc.expect(t, l_ok, fmt.tprintf("%v: l_ok %v != %v", #procedure, l_ok, true)) - tc.expect(t, len(l) == len(n1_t), fmt.tprintf("%v: len(l) %v != %v", #procedure, len(l), len(n1_t))) + testing.expectf(t, l_ok, fmt.tprintf("l_ok %v != %v", l_ok, true)) + testing.expectf(t, len(l) == len(n1_t), fmt.tprintf("len(l) %v != %v", len(l), len(n1_t))) for j := 0; j < len(l); j += 1 { - tc.expect(t, l[j] == n1_t[j], fmt.tprintf("%v: l[%d] %v != %v", #procedure, j, l[j], n1_t[j])) + testing.expectf(t, l[j] == n1_t[j], fmt.tprintf("l[%d] %v != %v", j, l[j], n1_t[j])) } } } -} +} \ No newline at end of file From 601df0e8f77bb9da13557e9f54abbd99b973c4f2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 14:36:36 +0200 Subject: [PATCH 42/93] Port `tests\core\encoding\json` --- core/encoding/json/marshal.odin | 4 +- core/encoding/json/parser.odin | 65 ++++++++------- core/encoding/json/types.odin | 14 ++-- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/encoding/json/test_core_json.odin | 88 +++++--------------- 6 files changed, 67 insertions(+), 108 deletions(-) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 4f5b50ec5..2933adf9a 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -62,8 +62,8 @@ Marshal_Options :: struct { mjson_skipped_first_braces_end: bool, } -marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { - b := strings.builder_make(allocator) +marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Marshal_Error) { + b := strings.builder_make(allocator, loc) defer if err != nil { strings.builder_destroy(&b) } diff --git a/core/encoding/json/parser.odin b/core/encoding/json/parser.odin index 3973725dc..38f71edf6 100644 --- a/core/encoding/json/parser.odin +++ b/core/encoding/json/parser.odin @@ -28,27 +28,27 @@ make_parser_from_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, par } -parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> (Value, Error) { - return parse_string(string(data), spec, parse_integers, allocator) +parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) { + return parse_string(string(data), spec, parse_integers, allocator, loc) } -parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> (Value, Error) { +parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) { context.allocator = allocator p := make_parser_from_string(data, spec, parse_integers, allocator) switch p.spec { case .JSON: - return parse_object(&p) + return parse_object(&p, loc) case .JSON5: - return parse_value(&p) + return parse_value(&p, loc) case .SJSON: #partial switch p.curr_token.kind { case .Ident, .String: - return parse_object_body(&p, .EOF) + return parse_object_body(&p, .EOF, loc) } - return parse_value(&p) + return parse_value(&p, loc) } - return parse_object(&p) + return parse_object(&p, loc) } token_end_pos :: proc(tok: Token) -> Pos { @@ -106,7 +106,7 @@ parse_comma :: proc(p: ^Parser) -> (do_break: bool) { return false } -parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) { +parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) { err = .None token := p.curr_token #partial switch token.kind { @@ -142,13 +142,13 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) { case .String: advance_token(p) - return unquote_string(token, p.spec, p.allocator) + return unquote_string(token, p.spec, p.allocator, loc) case .Open_Brace: - return parse_object(p) + return parse_object(p, loc) case .Open_Bracket: - return parse_array(p) + return parse_array(p, loc) case: if p.spec != .JSON { @@ -176,7 +176,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) { return } -parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) { +parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) { err = .None expect_token(p, .Open_Bracket) or_return @@ -184,14 +184,14 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) { array.allocator = p.allocator defer if err != nil { for elem in array { - destroy_value(elem) + destroy_value(elem, loc=loc) } - delete(array) + delete(array, loc) } for p.curr_token.kind != .Close_Bracket { - elem := parse_value(p) or_return - append(&array, elem) + elem := parse_value(p, loc) or_return + append(&array, elem, loc) if parse_comma(p) { break @@ -228,38 +228,39 @@ clone_string :: proc(s: string, allocator: mem.Allocator, loc := #caller_locatio return } -parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator) -> (key: string, err: Error) { +parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator, loc := #caller_location) -> (key: string, err: Error) { tok := p.curr_token if p.spec != .JSON { if allow_token(p, .Ident) { - return clone_string(tok.text, key_allocator) + return clone_string(tok.text, key_allocator, loc) } } if tok_err := expect_token(p, .String); tok_err != nil { err = .Expected_String_For_Object_Key return } - return unquote_string(tok, p.spec, key_allocator) + return unquote_string(tok, p.spec, key_allocator, loc) } -parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, err: Error) { - obj.allocator = p.allocator +parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_location) -> (obj: Object, err: Error) { + obj = make(Object, allocator=p.allocator, loc=loc) + defer if err != nil { for key, elem in obj { - delete(key, p.allocator) - destroy_value(elem) + delete(key, p.allocator, loc) + destroy_value(elem, loc=loc) } - delete(obj) + delete(obj, loc) } for p.curr_token.kind != end_token { - key := parse_object_key(p, p.allocator) or_return + key := parse_object_key(p, p.allocator, loc) or_return parse_colon(p) or_return - elem := parse_value(p) or_return + elem := parse_value(p, loc) or_return if key in obj { err = .Duplicate_Object_Key - delete(key, p.allocator) + delete(key, p.allocator, loc) return } @@ -267,7 +268,7 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, er // inserting empty key/values into the object and for those we do not // want to allocate anything if key != "" { - reserve_error := reserve(&obj, len(obj) + 1) + reserve_error := reserve(&obj, len(obj) + 1, loc) if reserve_error == mem.Allocator_Error.Out_Of_Memory { return nil, .Out_Of_Memory } @@ -281,9 +282,9 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, er return obj, .None } -parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) { +parse_object :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) { expect_token(p, .Open_Brace) or_return - obj := parse_object_body(p, .Close_Brace) or_return + obj := parse_object_body(p, .Close_Brace, loc) or_return expect_token(p, .Close_Brace) or_return return obj, .None } @@ -480,4 +481,4 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a } return string(b[:w]), nil -} +} \ No newline at end of file diff --git a/core/encoding/json/types.odin b/core/encoding/json/types.odin index 73e183615..41eb21377 100644 --- a/core/encoding/json/types.odin +++ b/core/encoding/json/types.odin @@ -89,22 +89,22 @@ Error :: enum { -destroy_value :: proc(value: Value, allocator := context.allocator) { +destroy_value :: proc(value: Value, allocator := context.allocator, loc := #caller_location) { context.allocator = allocator #partial switch v in value { case Object: for key, elem in v { - delete(key) - destroy_value(elem) + delete(key, loc=loc) + destroy_value(elem, loc=loc) } - delete(v) + delete(v, loc=loc) case Array: for elem in v { - destroy_value(elem) + destroy_value(elem, loc=loc) } - delete(v) + delete(v, loc=loc) case String: - delete(v) + delete(v, loc=loc) } } diff --git a/tests/core/Makefile b/tests/core/Makefile index 46b9e352e..98027ab39 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -49,7 +49,7 @@ encoding_test: $(ODIN) test encoding/cbor $(COMMON) -out:test_cbor $(ODIN) test encoding/hex $(COMMON) -out:test_hex $(ODIN) test encoding/hxa $(COMMON) -out:test_hxa - $(ODIN) run encoding/json $(COMMON) -out:test_json + $(ODIN) test encoding/json $(COMMON) -out:test_json $(ODIN) run encoding/varint $(COMMON) -out:test_varint $(ODIN) run encoding/xml $(COMMON) -out:test_xml diff --git a/tests/core/build.bat b/tests/core/build.bat index 094a12f14..4bc5bb938 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -30,7 +30,7 @@ echo --- %PATH_TO_ODIN% test encoding/cbor %COMMON% -out:test_cbor.exe || exit /b %PATH_TO_ODIN% test encoding/hex %COMMON% -out:test_hex.exe || exit /b %PATH_TO_ODIN% test encoding/hxa %COMMON% -out:test_hxa.exe || exit /b -%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b +%PATH_TO_ODIN% test encoding/json %COMMON% -out:test_json.exe || exit /b %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index 813d11b2c..92c050952 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -2,46 +2,8 @@ package test_core_json import "core:encoding/json" import "core:testing" -import "core:fmt" -import "core:os" import "core:mem/virtual" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - parse_json(&t) - marshal_json(&t) - unmarshal_json(&t) - surrogate(&t) - utf8_string_of_multibyte_characters(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - @test parse_json :: proc(t: ^testing.T) { @@ -72,10 +34,9 @@ parse_json :: proc(t: ^testing.T) { } ` - _, err := json.parse(transmute([]u8)json_data) - - msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err) - expect(t, err == nil, msg) + val, err := json.parse(transmute([]u8)json_data) + json.destroy_value(val) + testing.expectf(t, err == nil, "Expected `json.parse` to return nil, got %v", err) } @test @@ -83,7 +44,7 @@ out_of_memory_in_parse_json :: proc(t: ^testing.T) { arena: virtual.Arena arena_buffer: [256]byte arena_init_error := virtual.arena_init_buffer(&arena, arena_buffer[:]) - testing.expect(t, arena_init_error == nil, fmt.tprintf("Expected arena initialization to not return error, got: %v\n", arena_init_error)) + testing.expectf(t, arena_init_error == nil, "Expected arena initialization to not return error, got: %v\n", arena_init_error) context.allocator = virtual.arena_allocator(&arena) @@ -114,11 +75,11 @@ out_of_memory_in_parse_json :: proc(t: ^testing.T) { } ` - _, err := json.parse(transmute([]u8)json_data) + val, err := json.parse(transmute([]u8)json_data) + json.destroy_value(val) expected_error := json.Error.Out_Of_Memory - msg := fmt.tprintf("Expected `json.parse` to fail with %v, got %v", expected_error, err) - expect(t, err == json.Error.Out_Of_Memory, msg) + testing.expectf(t, err == json.Error.Out_Of_Memory, "Expected `json.parse` to fail with %v, got %v", expected_error, err) } @test @@ -134,9 +95,9 @@ marshal_json :: proc(t: ^testing.T) { b = 5, } - _, err := json.marshal(my_struct) - msg := fmt.tprintf("Expected `json.marshal` to return nil, got %v", err) - expect(t, err == nil, msg) + data, err := json.marshal(my_struct) + defer delete(data) + testing.expectf(t, err == nil, "Expected `json.marshal` to return nil, got %v", err) } PRODUCTS := ` @@ -378,17 +339,12 @@ unmarshal_json :: proc(t: ^testing.T) { err := json.unmarshal(transmute([]u8)PRODUCTS, &g, json.DEFAULT_SPECIFICATION) defer cleanup(g) - msg := fmt.tprintf("Expected `json.unmarshal` to return nil, got %v", err) - expect(t, err == nil, msg) - - msg = fmt.tprintf("Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products)) - expect(t, len(g.products) == len(original_data.products), msg) - - msg = fmt.tprintf("Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash) - expect(t, original_data.cash == g.cash, msg) + testing.expectf(t, err == nil, "Expected `json.unmarshal` to return nil, got %v", err) + testing.expectf(t, len(g.products) == len(original_data.products), "Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products)) + testing.expectf(t, original_data.cash == g.cash, "Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash) for p, i in g.products { - expect(t, p == original_data.products[i], "Producted unmarshaled improperly") + testing.expect(t, p == original_data.products[i], "Producted unmarshaled improperly") } } @@ -397,17 +353,19 @@ surrogate :: proc(t: ^testing.T) { input := `+ + * 😃 - /` out, err := json.marshal(input) - expect(t, err == nil, fmt.tprintf("Expected `json.marshal(%q)` to return a nil error, got %v", input, err)) + defer delete(out) + testing.expectf(t, err == nil, "Expected `json.marshal(%q)` to return a nil error, got %v", input, err) back: string uerr := json.unmarshal(out, &back) - expect(t, uerr == nil, fmt.tprintf("Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr)) - expect(t, back == input, fmt.tprintf("Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr)) + defer delete(back) + testing.expectf(t, uerr == nil, "Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr) + testing.expectf(t, back == input, "Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr) } @test utf8_string_of_multibyte_characters :: proc(t: ^testing.T) { - _, err := json.parse_string(`"🐛✅"`) - msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err) - expect(t, err == nil, msg) -} + val, err := json.parse_string(`"🐛✅"`) + defer json.destroy_value(val) + testing.expectf(t, err == nil, "Expected `json.parse` to return nil, got %v", err) +} \ No newline at end of file From 6641a6f6c9357c8cb977622ff2da2937af69cfed Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 14:57:43 +0200 Subject: [PATCH 43/93] Port `tests\core\encoding\varint` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- .../encoding/varint/test_core_varint.odin | 84 ++++++------------- 3 files changed, 26 insertions(+), 62 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 98027ab39..4dc12969d 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -50,7 +50,7 @@ encoding_test: $(ODIN) test encoding/hex $(COMMON) -out:test_hex $(ODIN) test encoding/hxa $(COMMON) -out:test_hxa $(ODIN) test encoding/json $(COMMON) -out:test_json - $(ODIN) run encoding/varint $(COMMON) -out:test_varint + $(ODIN) test encoding/varint $(COMMON) -out:test_varint $(ODIN) run encoding/xml $(COMMON) -out:test_xml filepath_test: diff --git a/tests/core/build.bat b/tests/core/build.bat index 4bc5bb938..983546ddb 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -31,7 +31,7 @@ echo --- %PATH_TO_ODIN% test encoding/hex %COMMON% -out:test_hex.exe || exit /b %PATH_TO_ODIN% test encoding/hxa %COMMON% -out:test_hxa.exe || exit /b %PATH_TO_ODIN% test encoding/json %COMMON% -out:test_json.exe || exit /b -%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b +%PATH_TO_ODIN% test encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b echo --- diff --git a/tests/core/encoding/varint/test_core_varint.odin b/tests/core/encoding/varint/test_core_varint.odin index ee1798aa7..5058f3022 100644 --- a/tests/core/encoding/varint/test_core_varint.odin +++ b/tests/core/encoding/varint/test_core_varint.odin @@ -2,110 +2,74 @@ package test_core_varint import "core:encoding/varint" import "core:testing" -import "core:fmt" -import "core:os" import "core:slice" import "core:math/rand" -TEST_count := 0 -TEST_fail := 0 - -RANDOM_TESTS :: 100 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - test_leb128(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} +NUM_RANDOM_TESTS_PER_BYTE_SIZE :: 10_000 @(test) -test_leb128 :: proc(t: ^testing.T) { +test_uleb :: proc(t: ^testing.T) { buf: [varint.LEB128_MAX_BYTES]u8 for vector in ULEB_Vectors { val, size, err := varint.decode_uleb128(vector.encoded) - msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) - expect(t, size == vector.size && val == vector.value, msg) - - msg = fmt.tprintf("Expected decoder to return error %v, got %v for vector %v", vector.error, err, vector) - expect(t, err == vector.error, msg) + testing.expectf(t, size == vector.size && val == vector.value, "Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) + testing.expectf(t, err == vector.error, "Expected decoder to return error %v, got %v for vector %v", vector.error, err, vector) if err == .None { // Try to roundtrip size, err = varint.encode_uleb128(buf[:], vector.value) - msg = fmt.tprintf("Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size]) - expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg) + testing.expectf(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), "Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size]) } } +} + +@(test) +test_ileb :: proc(t: ^testing.T) { + buf: [varint.LEB128_MAX_BYTES]u8 for vector in ILEB_Vectors { val, size, err := varint.decode_ileb128(vector.encoded) - msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) - expect(t, size == vector.size && val == vector.value, msg) - - msg = fmt.tprintf("Expected decoder to return error %v, got %v", vector.error, err) - expect(t, err == vector.error, msg) + testing.expectf(t, size == vector.size && val == vector.value, "Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size) + testing.expectf(t, err == vector.error, "Expected decoder to return error %v, got %v", vector.error, err) if err == .None { // Try to roundtrip size, err = varint.encode_ileb128(buf[:], vector.value) - msg = fmt.tprintf("Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size]) - expect(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), msg) + testing.expectf(t, size == vector.size && slice.simple_equal(vector.encoded, buf[:size]), "Expected %v to encode to %02x, got %02x", vector.value, vector.encoded, buf[:size]) } } +} + +@(test) +test_random :: proc(t: ^testing.T) { + buf: [varint.LEB128_MAX_BYTES]u8 for num_bytes in 1..=uint(16) { - for _ in 0..=RANDOM_TESTS { + for _ in 0..=NUM_RANDOM_TESTS_PER_BYTE_SIZE { unsigned, signed := get_random(num_bytes) - { encode_size, encode_err := varint.encode_uleb128(buf[:], unsigned) - msg := fmt.tprintf("%v failed to encode as an unsigned LEB128 value, got %v", unsigned, encode_err) - expect(t, encode_err == .None, msg) + testing.expectf(t, encode_err == .None, "%v failed to encode as an unsigned LEB128 value, got %v", unsigned, encode_err) decoded, decode_size, decode_err := varint.decode_uleb128(buf[:]) - msg = fmt.tprintf("Expected %02x to decode as %v, got %v", buf[:encode_size], unsigned, decoded) - expect(t, decode_err == .None && decode_size == encode_size && decoded == unsigned, msg) + testing.expectf(t, decode_err == .None && decode_size == encode_size && decoded == unsigned, "Expected %02x to decode as %v, got %v", buf[:encode_size], unsigned, decoded) } { encode_size, encode_err := varint.encode_ileb128(buf[:], signed) - msg := fmt.tprintf("%v failed to encode as a signed LEB128 value, got %v", signed, encode_err) - expect(t, encode_err == .None, msg) + testing.expectf(t, encode_err == .None, "%v failed to encode as a signed LEB128 value, got %v", signed, encode_err) decoded, decode_size, decode_err := varint.decode_ileb128(buf[:]) - msg = fmt.tprintf("Expected %02x to decode as %v, got %v, err: %v", buf[:encode_size], signed, decoded, decode_err) - expect(t, decode_err == .None && decode_size == encode_size && decoded == signed, msg) + testing.expectf(t, decode_err == .None && decode_size == encode_size && decoded == signed, "Expected %02x to decode as %v, got %v, err: %v", buf[:encode_size], signed, decoded, decode_err) } } } } +@(private) get_random :: proc(byte_count: uint) -> (u: u128, i: i128) { assert(byte_count >= 0 && byte_count <= size_of(u128)) From 9d0f4833bfde5c1ae443c4826f268b565022a817 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 15:45:15 +0200 Subject: [PATCH 44/93] Port `tests\core\encoding\xml` Made them run in parallel as well. --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/encoding/xml/test_core_xml.odin | 226 ++++++++------------- 3 files changed, 89 insertions(+), 141 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 4dc12969d..357a22edb 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -51,7 +51,7 @@ encoding_test: $(ODIN) test encoding/hxa $(COMMON) -out:test_hxa $(ODIN) test encoding/json $(COMMON) -out:test_json $(ODIN) test encoding/varint $(COMMON) -out:test_varint - $(ODIN) run encoding/xml $(COMMON) -out:test_xml + $(ODIN) test encoding/xml $(COMMON) -out:test_xml filepath_test: $(ODIN) run path/filepath $(COMMON) $(COLLECTION) -out:test_core_filepath diff --git a/tests/core/build.bat b/tests/core/build.bat index 983546ddb..d35fee5b3 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -32,7 +32,7 @@ echo --- %PATH_TO_ODIN% test encoding/hxa %COMMON% -out:test_hxa.exe || exit /b %PATH_TO_ODIN% test encoding/json %COMMON% -out:test_json.exe || exit /b %PATH_TO_ODIN% test encoding/varint %COMMON% -out:test_varint.exe || exit /b -%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b +%PATH_TO_ODIN% test encoding/xml %COMMON% -out:test_xml.exe || exit /b echo --- echo Running core:fmt tests diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index c62033491..22852d1f3 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -2,10 +2,10 @@ package test_core_xml import "core:encoding/xml" import "core:testing" -import "core:mem" import "core:strings" import "core:io" import "core:fmt" +import "core:log" import "core:hash" Silent :: proc(pos: xml.Pos, format: string, args: ..any) {} @@ -14,9 +14,6 @@ OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "", } -TEST_count := 0 -TEST_fail := 0 - TEST :: struct { filename: string, options: xml.Options, @@ -24,22 +21,14 @@ TEST :: struct { crc32: u32, } -/* - Relative to ODIN_ROOT -*/ -TEST_FILE_PATH_PREFIX :: "tests/core/assets" +TEST_SUITE_PATH :: ODIN_ROOT + "tests/core/assets/" -TESTS :: []TEST{ - /* - First we test that certain files parse without error. - */ - - { - /* - Tests UTF-8 idents and values. - Test namespaced ident. - Tests that nested partial CDATA start doesn't trip up parser. - */ +@(test) +xml_test_utf8_normal :: proc(t: ^testing.T) { + run_test(t, { + // Tests UTF-8 idents and values. + // Test namespaced ident. + // Tests that nested partial CDATA start doesn't trip up parser. filename = "XML/utf8.xml", options = { flags = { @@ -48,13 +37,14 @@ TESTS :: []TEST{ expected_doctype = "恥ずべきフクロウ", }, crc32 = 0xe9b62f03, - }, + }) +} - { - /* - Same as above. - Unbox CDATA in data tag. - */ +@(test) +xml_test_utf8_unbox_cdata :: proc(t: ^testing.T) { + run_test(t, { + // Same as above. + // Unbox CDATA in data tag. filename = "XML/utf8.xml", options = { flags = { @@ -63,13 +53,14 @@ TESTS :: []TEST{ expected_doctype = "恥ずべきフクロウ", }, crc32 = 0x9c2643ed, - }, + }) +} - { - /* - Simple Qt TS translation file. - `core:i18n` requires it to be parsed properly. - */ +@(test) +xml_test_nl_qt_ts :: proc(t: ^testing.T) { + run_test(t, { + // Simple Qt TS translation file. + // `core:i18n` requires it to be parsed properly. filename = "I18N/nl_NL-qt-ts.ts", options = { flags = { @@ -78,13 +69,14 @@ TESTS :: []TEST{ expected_doctype = "TS", }, crc32 = 0x859b7443, - }, + }) +} - { - /* - Simple XLiff 1.2 file. - `core:i18n` requires it to be parsed properly. - */ +@(test) +xml_test_xliff_1_2 :: proc(t: ^testing.T) { + run_test(t, { + // Simple XLiff 1.2 file. + // `core:i18n` requires it to be parsed properly. filename = "I18N/nl_NL-xliff-1.2.xliff", options = { flags = { @@ -93,13 +85,14 @@ TESTS :: []TEST{ expected_doctype = "xliff", }, crc32 = 0x3deaf329, - }, + }) +} - { - /* - Simple XLiff 2.0 file. - `core:i18n` requires it to be parsed properly. - */ +@(test) +xml_test_xliff_2_0 :: proc(t: ^testing.T) { + run_test(t, { + // Simple XLiff 2.0 file. + // `core:i18n` requires it to be parsed properly. filename = "I18N/nl_NL-xliff-2.0.xliff", options = { flags = { @@ -108,9 +101,12 @@ TESTS :: []TEST{ expected_doctype = "xliff", }, crc32 = 0x0c55e287, - }, + }) +} - { +@(test) +xml_test_entities :: proc(t: ^testing.T) { + run_test(t, { filename = "XML/entities.html", options = { flags = { @@ -119,9 +115,12 @@ TESTS :: []TEST{ expected_doctype = "html", }, crc32 = 0x05373317, - }, + }) +} - { +@(test) +xml_test_entities_unbox :: proc(t: ^testing.T) { + run_test(t, { filename = "XML/entities.html", options = { flags = { @@ -130,9 +129,12 @@ TESTS :: []TEST{ expected_doctype = "html", }, crc32 = 0x3b6d4a90, - }, + }) +} - { +@(test) +xml_test_entities_unbox_decode :: proc(t: ^testing.T) { + run_test(t, { filename = "XML/entities.html", options = { flags = { @@ -141,12 +143,12 @@ TESTS :: []TEST{ expected_doctype = "html", }, crc32 = 0x5be2ffdc, - }, + }) +} - /* - Then we test that certain errors are returned as expected. - */ - { +@(test) +xml_test_invalid_doctype :: proc(t: ^testing.T) { + run_test(t, { filename = "XML/utf8.xml", options = { flags = { @@ -156,12 +158,12 @@ TESTS :: []TEST{ }, err = .Invalid_DocType, crc32 = 0x49b83d0a, - }, + }) +} - /* - Parse the 9.08 MiB unicode.xml for good measure. - */ - { +@(test) +xml_test_unicode :: proc(t: ^testing.T) { + run_test(t, { filename = "XML/unicode.xml", options = { flags = { @@ -171,39 +173,37 @@ TESTS :: []TEST{ }, err = .None, crc32 = 0x0b6100ab, - }, + }) } -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] LOG:\n\t%v\n", loc, v) +@(private) +run_test :: proc(t: ^testing.T, test: TEST) { + path := strings.concatenate({TEST_SUITE_PATH, test.filename}) + defer delete(path) + + doc, err := xml.load_from_file(path, test.options, Silent) + defer xml.destroy(doc) + + tree_string := doc_to_string(doc) + tree_bytes := transmute([]u8)tree_string + defer delete(tree_bytes) + + crc32 := hash.crc32(tree_bytes) + + failed := err != test.err + testing.expectf(t, err == test.err, "%v: Expected return value %v, got %v", test.filename, test.err, err) + + failed |= crc32 != test.crc32 + testing.expectf(t, crc32 == test.crc32, "%v: Expected CRC 0x%08x, got 0x%08x, with options %v", test.filename, test.crc32, crc32, test.options) + + if failed { + // Don't fully print big trees. + tree_string = tree_string[:min(2_048, len(tree_string))] + log.error(tree_string) } } -test_file_path :: proc(filename: string) -> (path: string) { - - path = fmt.tprintf("%v%v/%v", ODIN_ROOT, TEST_FILE_PATH_PREFIX, filename) - temp := transmute([]u8)path - - for r, i in path { - if r == '\\' { - temp[i] = '/' - } - } - return path -} - +@(private) doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { /* Effectively a clone of the debug printer in the xml package. @@ -284,56 +284,4 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { print(strings.to_writer(&buf), doc) return strings.clone(strings.to_string(buf)) -} - -@test -run_tests :: proc(t: ^testing.T) { - for test in TESTS { - path := test_file_path(test.filename) - log(t, fmt.tprintf("Trying to parse %v", path)) - - doc, err := xml.load_from_file(path, test.options, Silent) - defer xml.destroy(doc) - - tree_string := doc_to_string(doc) - tree_bytes := transmute([]u8)tree_string - defer delete(tree_bytes) - - crc32 := hash.crc32(tree_bytes) - - failed := err != test.err - err_msg := fmt.tprintf("Expected return value %v, got %v", test.err, err) - expect(t, err == test.err, err_msg) - - failed |= crc32 != test.crc32 - err_msg = fmt.tprintf("Expected CRC 0x%08x, got 0x%08x, with options %v", test.crc32, crc32, test.options) - expect(t, crc32 == test.crc32, err_msg) - - if failed { - /* - Don't fully print big trees. - */ - tree_string = tree_string[:min(2_048, len(tree_string))] - fmt.println(tree_string) - } - } -} - -main :: proc() { - t := testing.T{} - - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - run_tests(&t) - - if len(track.allocation_map) > 0 { - for _, v in track.allocation_map { - err_msg := fmt.tprintf("%v Leaked %v bytes.", v.location, v.size) - expect(&t, false, err_msg) - } - } - - fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } \ No newline at end of file From d334b8c72a6c95e22af2113a4dc71c04224af4ee Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 16:04:24 +0200 Subject: [PATCH 45/93] Port `tests\core\path\filepath` --- tests/core/Makefile | 2 +- tests/core/build.bat | 10 +-- .../path/filepath/test_core_filepath.odin | 73 +++++++++---------- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 357a22edb..df3924e4d 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -54,7 +54,7 @@ encoding_test: $(ODIN) test encoding/xml $(COMMON) -out:test_xml filepath_test: - $(ODIN) run path/filepath $(COMMON) $(COLLECTION) -out:test_core_filepath + $(ODIN) test path/filepath $(COMMON) -out:test_core_filepath fmt_test: $(ODIN) run fmt $(COMMON) -out:test_core_fmt diff --git a/tests/core/build.bat b/tests/core/build.bat index d35fee5b3..214f15b45 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -34,6 +34,11 @@ echo --- %PATH_TO_ODIN% test encoding/varint %COMMON% -out:test_varint.exe || exit /b %PATH_TO_ODIN% test encoding/xml %COMMON% -out:test_xml.exe || exit /b +echo --- +echo Running core:path/filepath tests +echo --- +%PATH_TO_ODIN% test path/filepath %COMMON% -out:test_core_filepath.exe || exit /b + echo --- echo Running core:fmt tests echo --- @@ -74,11 +79,6 @@ echo Running core:odin tests echo --- %PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe || exit /b -echo --- -echo Running core:path/filepath tests -echo --- -%PATH_TO_ODIN% run path/filepath %COMMON% %COLLECTION% -out:test_core_filepath.exe || exit /b - echo --- echo Running core:reflect tests echo --- diff --git a/tests/core/path/filepath/test_core_filepath.odin b/tests/core/path/filepath/test_core_filepath.odin index 4c70e5f28..94b9329bb 100644 --- a/tests/core/path/filepath/test_core_filepath.odin +++ b/tests/core/path/filepath/test_core_filepath.odin @@ -1,26 +1,19 @@ // Tests "path.odin" in "core:path/filepath". -// Must be run with `-collection:tests=` flag, e.g. -// ./odin run tests/core/path/filepath/test_core_filepath.odin -collection:tests=tests package test_core_filepath import "core:fmt" import "core:path/filepath" import "core:testing" -import tc "tests:common" - -main :: proc() { - t := testing.T{} +@(test) +test_split_list :: proc(t: ^testing.T) { when ODIN_OS == .Windows { - test_split_list_windows(&t) + test_split_list_windows(t) } else { - test_split_list_unix(&t) + test_split_list_unix(t) } - - tc.report(&t) } -@test test_split_list_windows :: proc(t: ^testing.T) { Datum :: struct { i: int, @@ -41,12 +34,12 @@ test_split_list_windows :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) r := filepath.split_list(d.v) - defer delete(r) - tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", + defer delete_split(r) + testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", i, #procedure, d.v, len(r), len(d.e))) if len(r) == len(d.e) { for _, j in r { - tc.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", + testing.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", i, #procedure, d.v, r[j], j, d.e[j])) } } @@ -55,47 +48,43 @@ test_split_list_windows :: proc(t: ^testing.T) { { v := "" r := filepath.split_list(v) - tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) + defer delete_split(r) + testing.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) } { v := "a" r := filepath.split_list(v) - defer delete(r) - tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) + defer delete_split(r) + testing.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) if len(r) == 1 { - tc.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) + testing.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) } } } -@test test_split_list_unix :: proc(t: ^testing.T) { Datum :: struct { - i: int, v: string, e: [3]string, } @static data := []Datum{ - { 0, "/opt/butler:/home/fancykillerpanda/Projects/Odin/Odin:/usr/local/sbin", + { "/opt/butler:/home/fancykillerpanda/Projects/Odin/Odin:/usr/local/sbin", [3]string{"/opt/butler", "/home/fancykillerpanda/Projects/Odin/Odin", "/usr/local/sbin"} }, // Issue #1537 - { 1, "a::b", [3]string{"a", "", "b"} }, - { 2, "a:b:", [3]string{"a", "b", ""} }, - { 3, ":a:b", [3]string{"", "a", "b"} }, - { 4, "::", [3]string{"", "", ""} }, - { 5, "\"a:b\"c:d:\"f\"", [3]string{"a:bc", "d", "f"} }, - { 6, "\"a:b:c\":d\":e\":f", [3]string{"a:b:c", "d:e", "f"} }, + { "a::b", [3]string{"a", "", "b"} }, + { "a:b:", [3]string{"a", "b", ""} }, + { ":a:b", [3]string{"", "a", "b"} }, + { "::", [3]string{"", "", ""} }, + { "\"a:b\"c:d:\"f\"", [3]string{"a:bc", "d", "f"} }, + { "\"a:b:c\":d\":e\":f", [3]string{"a:b:c", "d:e", "f"} }, } - for d, i in data { - assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) + for d in data { r := filepath.split_list(d.v) - defer delete(r) - tc.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", - i, #procedure, d.v, len(r), len(d.e))) + defer delete_split(r) + testing.expectf(t, len(r) == len(d.e), "%s len(r) %d != len(d.e) %d", d.v, len(r), len(d.e)) if len(r) == len(d.e) { for _, j in r { - tc.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", - i, #procedure, d.v, r[j], j, d.e[j])) + testing.expectf(t, r[j] == d.e[j], "%v -> %v[%d] != %v", d.v, r[j], j, d.e[j]) } } } @@ -103,15 +92,23 @@ test_split_list_unix :: proc(t: ^testing.T) { { v := "" r := filepath.split_list(v) - tc.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) + testing.expectf(t, r == nil, "'%s' -> '%v' != nil", v, r) } { v := "a" r := filepath.split_list(v) - defer delete(r) - tc.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) + defer delete_split(r) + testing.expectf(t, len(r) == 1, "'%s' len(r) %d != 1", v, len(r)) if len(r) == 1 { - tc.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) + testing.expectf(t, r[0] == "a", "'%v' -> %v[0] != a", v, r[0]) } } } + +@(private) +delete_split :: proc(s: []string) { + for part in s { + delete(part) + } + delete(s) +} \ No newline at end of file From 6f7c5a7577c6c03a6894728009daa7681e60a0a1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 16:52:29 +0200 Subject: [PATCH 46/93] Port `tests\core\fmt` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/fmt/test_core_fmt.odin | 61 ++++++++++--------------------- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index df3924e4d..bc574b004 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -57,7 +57,7 @@ filepath_test: $(ODIN) test path/filepath $(COMMON) -out:test_core_filepath fmt_test: - $(ODIN) run fmt $(COMMON) -out:test_core_fmt + $(ODIN) test fmt $(COMMON) -out:test_core_fmt hash_test: $(ODIN) run hash $(COMMON) -o:speed -out:test_hash diff --git a/tests/core/build.bat b/tests/core/build.bat index 214f15b45..aa307672b 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -42,7 +42,7 @@ echo --- echo --- echo Running core:fmt tests echo --- -%PATH_TO_ODIN% run fmt %COMMON% %COLLECTION% -out:test_core_fmt.exe || exit /b +%PATH_TO_ODIN% test fmt %COMMON% -out:test_core_fmt.exe || exit /b echo --- echo Running core:hash tests diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 82d009ac6..3e5839ae7 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -1,47 +1,8 @@ package test_core_fmt import "core:fmt" -import "core:os" -import "core:testing" import "core:mem" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - test_fmt_memory(&t) - test_fmt_doc_examples(&t) - test_fmt_options(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - -check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) { - got := fmt.tprintf(format, ..args) - expect(t, got == exp, fmt.tprintf("(%q, %v): %q != %q", format, args, got, exp), loc) -} +import "core:testing" @(test) test_fmt_memory :: proc(t: ^testing.T) { @@ -75,7 +36,7 @@ test_fmt_doc_examples :: proc(t: ^testing.T) { } @(test) -test_fmt_options :: proc(t: ^testing.T) { +test_fmt_escaping_prefixes :: proc(t: ^testing.T) { // Escaping check(t, "% { } 0 { } } {", "%% {{ }} {} {{ }} }} {{", 0 ) @@ -86,7 +47,10 @@ test_fmt_options :: proc(t: ^testing.T) { check(t, "+3", "%+i", 3 ) check(t, "0b11", "%#b", 3 ) check(t, "0xA", "%#X", 10 ) +} +@(test) +test_fmt_indexing :: proc(t: ^testing.T) { // Specific index formatting check(t, "1 2 3", "%i %i %i", 1, 2, 3) check(t, "1 2 3", "%[0]i %[1]i %[2]i", 1, 2, 3) @@ -95,7 +59,10 @@ test_fmt_options :: proc(t: ^testing.T) { check(t, "1 2 3", "%i %[1]i %i", 1, 2, 3) check(t, "1 3 2", "%i %[2]i %i", 1, 2, 3) check(t, "1 1 1", "%[0]i %[0]i %[0]i", 1) +} +@(test) +test_fmt_width_precision :: proc(t: ^testing.T) { // Width check(t, "3.140", "%f", 3.14) check(t, "3.140", "%4f", 3.14) @@ -133,7 +100,10 @@ test_fmt_options :: proc(t: ^testing.T) { check(t, "3.140", "%*[1].*[2][0]f", 3.14, 5, 3) check(t, "3.140", "%*[2].*[1]f", 3.14, 3, 5) check(t, "3.140", "%5.*[1]f", 3.14, 3) +} +@(test) +test_fmt_arg_errors :: proc(t: ^testing.T) { // Error checking check(t, "%!(MISSING ARGUMENT)%!(NO VERB)", "%" ) @@ -156,7 +126,10 @@ test_fmt_options :: proc(t: ^testing.T) { check(t, "%!(BAD ARGUMENT NUMBER)%!(NO VERB)%!(EXTRA 0)", "%[1]", 0) check(t, "3.1%!(EXTRA 3.14)", "%.1f", 3.14, 3.14) +} +@(test) +test_fmt_python_syntax :: proc(t: ^testing.T) { // Python-like syntax check(t, "1 2 3", "{} {} {}", 1, 2, 3) check(t, "3 2 1", "{2} {1} {0}", 1, 2, 3) @@ -181,3 +154,9 @@ test_fmt_options :: proc(t: ^testing.T) { check(t, "%!(MISSING CLOSE BRACE)%!(EXTRA 1)", "{", 1) check(t, "%!(MISSING CLOSE BRACE)%!(EXTRA 1)", "{0", 1 ) } + +@(private) +check :: proc(t: ^testing.T, exp: string, format: string, args: ..any) { + got := fmt.tprintf(format, ..args) + testing.expectf(t, got == exp, "(%q, %v): %q != %q", format, args, got, exp) +} \ No newline at end of file From 39fd73fe171c06f9eb58e107d5d5242114b43539 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 18:05:09 +0200 Subject: [PATCH 47/93] Port `testing\core\hash` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/hash/test_core_hash.odin | 604 +++++++++++------------ tests/core/hash/test_vectors_xxhash.odin | 6 +- 4 files changed, 302 insertions(+), 312 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index bc574b004..873bd24af 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -60,7 +60,7 @@ fmt_test: $(ODIN) test fmt $(COMMON) -out:test_core_fmt hash_test: - $(ODIN) run hash $(COMMON) -o:speed -out:test_hash + $(ODIN) test hash $(COMMON) -o:speed -out:test_hash i18n_test: $(ODIN) run text/i18n $(COMMON) -out:test_core_i18n diff --git a/tests/core/build.bat b/tests/core/build.bat index aa307672b..4748c3071 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -47,7 +47,7 @@ echo --- echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_core_hash.exe || exit /b +%PATH_TO_ODIN% test hash %COMMON% -o:speed -out:test_core_hash.exe || exit /b echo --- echo Running core:image tests diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index 932d2f34c..a6294de55 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -5,47 +5,314 @@ import "core:hash" import "core:time" import "core:testing" import "core:fmt" -import "core:os" +import "core:log" import "core:math/rand" import "base:intrinsics" -TEST_count := 0 -TEST_fail := 0 +@test +test_xxhash_zero_fixed :: proc(t: ^testing.T) { + many_zeroes := make([]u8, 16 * 1024 * 1024) + defer delete(many_zeroes) -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return + // All at once. + for i, v in ZERO_VECTORS { + b := many_zeroes[:i] + + xxh32 := xxhash.XXH32(b) + xxh64 := xxhash.XXH64(b) + xxh3_64 := xxhash.XXH3_64(b) + xxh3_128 := xxhash.XXH3_128(b) + + testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + } +} + +@(test) +test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) { + many_zeroes := make([]u8, 16 * 1024 * 1024) + defer delete(many_zeroes) + + // Streamed + for i, v in ZERO_VECTORS { + b := many_zeroes[:i] + + xxh_32_state, xxh_32_err := xxhash.XXH32_create_state() + defer xxhash.XXH32_destroy_state(xxh_32_state) + testing.expect(t, xxh_32_err == nil, "Problem initializing XXH_32 state") + + xxh_64_state, xxh_64_err := xxhash.XXH64_create_state() + defer xxhash.XXH64_destroy_state(xxh_64_state) + testing.expect(t, xxh_64_err == nil, "Problem initializing XXH_64 state") + + xxh3_64_state, xxh3_64_err := xxhash.XXH3_create_state() + defer xxhash.XXH3_destroy_state(xxh3_64_state) + testing.expect(t, xxh3_64_err == nil, "Problem initializing XXH3_64 state") + + xxh3_128_state, xxh3_128_err := xxhash.XXH3_create_state() + defer xxhash.XXH3_destroy_state(xxh3_128_state) + testing.expect(t, xxh3_128_err == nil, "Problem initializing XXH3_128 state") + + // XXH3_128_update + random_seed := rand.create(t.seed) + for len(b) > 0 { + update_size := min(len(b), rand.int_max(8192, &random_seed)) + if update_size > 4096 { + update_size %= 73 + } + xxhash.XXH32_update (xxh_32_state, b[:update_size]) + xxhash.XXH64_update (xxh_64_state, b[:update_size]) + + xxhash.XXH3_64_update (xxh3_64_state, b[:update_size]) + xxhash.XXH3_128_update(xxh3_128_state, b[:update_size]) + + b = b[update_size:] + } + + // Now finalize + xxh32 := xxhash.XXH32_digest(xxh_32_state) + xxh64 := xxhash.XXH64_digest(xxh_64_state) + + xxh3_64 := xxhash.XXH3_64_digest(xxh3_64_state) + xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state) + + xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + + testing.expect(t, xxh32 == v.xxh_32, xxh32_error) + testing.expect(t, xxh64 == v.xxh_64, xxh64_error) + testing.expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) + testing.expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) + } +} + +@test +test_xxhash_seeded :: proc(t: ^testing.T) { + buf := make([]u8, 256) + defer delete(buf) + + for seed, table in XXHASH_TEST_VECTOR_SEEDED { + for v, i in table { + b := buf[:i] + + xxh32 := xxhash.XXH32(b, u32(seed)) + xxh64 := xxhash.XXH64(b, seed) + xxh3_64 := xxhash.XXH3_64(b, seed) + xxh3_128 := xxhash.XXH3_128(b, seed) + + testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + + if len(b) > xxhash.XXH3_MIDSIZE_MAX { + xxh3_state, _ := xxhash.XXH3_create_state() + xxhash.XXH3_64_reset_with_seed(xxh3_state, seed) + xxhash.XXH3_64_update(xxh3_state, b) + xxh3_64_streamed := xxhash.XXH3_64_digest(xxh3_state) + xxhash.XXH3_destroy_state(xxh3_state) + testing.expectf(t, xxh3_64_streamed == v.xxh3_64, "[XXH3_64s(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64_streamed) + + xxh3_state2, _ := xxhash.XXH3_create_state() + xxhash.XXH3_128_reset_with_seed(xxh3_state2, seed) + xxhash.XXH3_128_update(xxh3_state2, b) + xxh3_128_streamed := xxhash.XXH3_128_digest(xxh3_state2) + xxhash.XXH3_destroy_state(xxh3_state2) + testing.expectf(t, xxh3_128_streamed == v.xxh3_128, "[XXH3_128s(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128_streamed) + } } } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) +} + +@test +test_xxhash_secret :: proc(t: ^testing.T) { + buf := make([]u8, 256) + defer delete(buf) + + for secret, table in XXHASH_TEST_VECTOR_SECRET { + secret_bytes := transmute([]u8)secret + for v, i in table { + b := buf[:i] + + xxh3_128 := xxhash.XXH3_128(b, secret_bytes) + testing.expectf(t, xxh3_128 == v.xxh3_128_secret, "[XXH3_128(%03d)] Expected: %32x, got: %32x", i, v.xxh3_128_secret, xxh3_128) + } } } -main :: proc() { - t := testing.T{} - test_benchmark_runner(&t) - test_crc64_vectors(&t) - test_xxhash_vectors(&t) - test_xxhash_large(&t) +@test +test_crc64_vectors :: proc(t: ^testing.T) { + vectors := map[string][4]u64 { + "123456789" = { + 0x6c40df5f0b497347, // ECMA-182, + 0x995dc9bbdf1939fa, // XZ + 0x46a5a9388a5beffe, // ISO 3306 + 0xb90956c775a41001, // ISO 3306, input and output inverted + }, + "This is a test of the emergency broadcast system." = { + 0x344fe1d09c983d13, // ECMA-182 + 0x27db187fc15bbc72, // XZ + 0x187184d744afc49e, // ISO 3306 + 0xe7fcf1006b503b61, // ISO 3306, input and output inverted + }, + } + defer delete(vectors) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) + for vector, expected in vectors { + b := transmute([]u8)vector + ecma := hash.crc64_ecma_182(b) + xz := hash.crc64_xz(b) + iso := hash.crc64_iso_3306(b) + iso2 := hash.crc64_iso_3306_inverse(b) + + testing.expectf(t, ecma == expected[0], "[ CRC-64 ECMA ] Expected: %016x, got: %016x", expected[0], ecma) + testing.expectf(t, xz == expected[1], "[ CRC-64 XZ ] Expected: %016x, got: %016x", expected[1], xz) + testing.expectf(t, iso == expected[2], "[ CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[2], iso) + testing.expectf(t, iso2 == expected[3], "[~CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[3], iso2) } } -/* - Benchmarks -*/ +@(test) +test_benchmark_xxh32 :: proc(t: ^testing.T) { + name := "XXH32 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh32, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x85f6413c) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh32_1MB :: proc(t: ^testing.T) { + name := "XXH32 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh32, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x9430f97f) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh64 :: proc(t: ^testing.T) { + name := "XXH64 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x17bb1103c92c502f) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh64_1MB :: proc(t: ^testing.T) { + name := "XXH64 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x87d2a1b6e1163ef1) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh3_64 :: proc(t: ^testing.T) { + name := "XXH3_64 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh3_64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x801fedc74ccd608c) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh3_64_1MB :: proc(t: ^testing.T) { + name := "XXH3_64 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh3_64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x918780b90550bf34) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh3_128 :: proc(t: ^testing.T) { + name := "XXH3_128 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh3_128, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x6ba30a4e9dffe1ff801fedc74ccd608c) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +@(test) +test_benchmark_xxh3_128_1MB :: proc(t: ^testing.T) { + name := "XXH3_128 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh3_128, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0xb6ef17a3448492b6918780b90550bf34) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(name, options) +} + +// Benchmarks setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { assert(options != nil) @@ -113,289 +380,14 @@ benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := contex return nil } -benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { - fmt.printf("\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", +benchmark_print :: proc(name: string, options: ^time.Benchmark_Options, loc := #caller_location) { + log.infof("\n\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s", name, options.rounds, options.processed, time.duration_nanoseconds(options.duration), options.rounds_per_second, options.megabytes_per_second, + location=loc, ) -} - -@test -test_benchmark_runner :: proc(t: ^testing.T) { - fmt.println("Starting benchmarks:") - - name := "XXH32 100 zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 100, - setup = setup_xxhash, - bench = benchmark_xxh32, - teardown = teardown_xxhash, - } - - err := time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x85f6413c, name) - benchmark_print(name, options) - - name = "XXH32 1 MiB zero bytes" - options.bytes = 1_048_576 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x9430f97f, name) - benchmark_print(name, options) - - name = "XXH64 100 zero bytes" - options.bytes = 100 - options.bench = benchmark_xxh64 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x17bb1103c92c502f, name) - benchmark_print(name, options) - - name = "XXH64 1 MiB zero bytes" - options.bytes = 1_048_576 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x87d2a1b6e1163ef1, name) - benchmark_print(name, options) - - name = "XXH3_64 100 zero bytes" - options.bytes = 100 - options.bench = benchmark_xxh3_64 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x801fedc74ccd608c, name) - benchmark_print(name, options) - - name = "XXH3_64 1 MiB zero bytes" - options.bytes = 1_048_576 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x918780b90550bf34, name) - benchmark_print(name, options) - - name = "XXH3_128 100 zero bytes" - options.bytes = 100 - options.bench = benchmark_xxh3_128 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0x6ba30a4e9dffe1ff801fedc74ccd608c, name) - benchmark_print(name, options) - - name = "XXH3_128 1 MiB zero bytes" - options.bytes = 1_048_576 - err = time.benchmark(options, context.allocator) - expect(t, err == nil, name) - expect(t, options.hash == 0xb6ef17a3448492b6918780b90550bf34, name) - benchmark_print(name, options) -} - -@test -test_xxhash_large :: proc(t: ^testing.T) { - many_zeroes := make([]u8, 16 * 1024 * 1024) - defer delete(many_zeroes) - - // All at once. - for i, v in ZERO_VECTORS { - b := many_zeroes[:i] - - fmt.printf("[test_xxhash_large] All at once. Size: %v\n", i) - - xxh32 := xxhash.XXH32(b) - xxh64 := xxhash.XXH64(b) - xxh3_64 := xxhash.XXH3_64(b) - xxh3_128 := xxhash.XXH3_128(b) - - xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32) - xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64) - xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh3_64, xxh3_64) - xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128) - - expect(t, xxh32 == v.xxh_32, xxh32_error) - expect(t, xxh64 == v.xxh_64, xxh64_error) - expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) - expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) - } - - when #config(RAND_STATE, -1) >= 0 && #config(RAND_INC, -1) >= 0 { - random_seed := rand.Rand{ - state = u64(#config(RAND_STATE, -1)), - inc = u64(#config(RAND_INC, -1)), - } - fmt.printf("Using user-selected seed {{%v,%v}} for update size randomness.\n", random_seed.state, random_seed.inc) - } else { - random_seed := rand.create(u64(intrinsics.read_cycle_counter())) - fmt.printf("Randonly selected seed {{%v,%v}} for update size randomness.\n", random_seed.state, random_seed.inc) - } - - // Streamed - for i, v in ZERO_VECTORS { - b := many_zeroes[:i] - - fmt.printf("[test_xxhash_large] Streamed. Size: %v\n", i) - - // bytes_per_update := []int{1, 42, 13, 7, 16, 5, 23, 74, 1024, 511, 1023, 47} - // update_size_idx: int - - xxh_32_state, xxh_32_err := xxhash.XXH32_create_state() - defer xxhash.XXH32_destroy_state(xxh_32_state) - expect(t, xxh_32_err == nil, "Problem initializing XXH_32 state.") - - xxh_64_state, xxh_64_err := xxhash.XXH64_create_state() - defer xxhash.XXH64_destroy_state(xxh_64_state) - expect(t, xxh_64_err == nil, "Problem initializing XXH_64 state.") - - xxh3_64_state, xxh3_64_err := xxhash.XXH3_create_state() - defer xxhash.XXH3_destroy_state(xxh3_64_state) - expect(t, xxh3_64_err == nil, "Problem initializing XXH3_64 state.") - - xxh3_128_state, xxh3_128_err := xxhash.XXH3_create_state() - defer xxhash.XXH3_destroy_state(xxh3_128_state) - expect(t, xxh3_128_err == nil, "Problem initializing XXH3_128 state.") - - // XXH3_128_update - - for len(b) > 0 { - update_size := min(len(b), rand.int_max(8192, &random_seed)) - if update_size > 4096 { - update_size %= 73 - } - xxhash.XXH32_update (xxh_32_state, b[:update_size]) - xxhash.XXH64_update (xxh_64_state, b[:update_size]) - - xxhash.XXH3_64_update (xxh3_64_state, b[:update_size]) - xxhash.XXH3_128_update(xxh3_128_state, b[:update_size]) - - b = b[update_size:] - } - - // Now finalize - xxh32 := xxhash.XXH32_digest(xxh_32_state) - xxh64 := xxhash.XXH64_digest(xxh_64_state) - - xxh3_64 := xxhash.XXH3_64_digest(xxh3_64_state) - xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state) - - xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32) - xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64) - xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh3_64, xxh3_64) - xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128) - - expect(t, xxh32 == v.xxh_32, xxh32_error) - expect(t, xxh64 == v.xxh_64, xxh64_error) - expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) - expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) - } -} - -@test -test_xxhash_vectors :: proc(t: ^testing.T) { - fmt.println("Verifying against XXHASH_TEST_VECTOR_SEEDED:") - - buf := make([]u8, 256) - defer delete(buf) - - for seed, table in XXHASH_TEST_VECTOR_SEEDED { - fmt.printf("\tSeed: %v\n", seed) - - for v, i in table { - b := buf[:i] - - xxh32 := xxhash.XXH32(b, u32(seed)) - xxh64 := xxhash.XXH64(b, seed) - xxh3_64 := xxhash.XXH3_64(b, seed) - xxh3_128 := xxhash.XXH3_128(b, seed) - - xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x. Got: %08x.", i, v.xxh_32, xxh32) - xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh_64, xxh64) - - xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh3_64, xxh3_64) - xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128) - - expect(t, xxh32 == v.xxh_32, xxh32_error) - expect(t, xxh64 == v.xxh_64, xxh64_error) - expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) - expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) - - if len(b) > xxhash.XXH3_MIDSIZE_MAX { - fmt.printf("XXH3 - size: %v\n", len(b)) - - xxh3_state, _ := xxhash.XXH3_create_state() - xxhash.XXH3_64_reset_with_seed(xxh3_state, seed) - xxhash.XXH3_64_update(xxh3_state, b) - xxh3_64_streamed := xxhash.XXH3_64_digest(xxh3_state) - xxhash.XXH3_destroy_state(xxh3_state) - xxh3_64s_error := fmt.tprintf("[XXH3_64s(%03d) ] Expected: %16x. Got: %16x.", i, v.xxh3_64, xxh3_64_streamed) - expect(t, xxh3_64_streamed == v.xxh3_64, xxh3_64s_error) - - xxh3_state2, _ := xxhash.XXH3_create_state() - xxhash.XXH3_128_reset_with_seed(xxh3_state2, seed) - xxhash.XXH3_128_update(xxh3_state2, b) - xxh3_128_streamed := xxhash.XXH3_128_digest(xxh3_state2) - xxhash.XXH3_destroy_state(xxh3_state2) - xxh3_128s_error := fmt.tprintf("[XXH3_128s(%03d) ] Expected: %32x. Got: %32x.", i, v.xxh3_128, xxh3_128_streamed) - expect(t, xxh3_128_streamed == v.xxh3_128, xxh3_128s_error) - } - } - } - - fmt.println("Verifying against XXHASH_TEST_VECTOR_SECRET:") - for secret, table in XXHASH_TEST_VECTOR_SECRET { - fmt.printf("\tSecret:\n\t\t\"%v\"\n", secret) - - secret_bytes := transmute([]u8)secret - - for v, i in table { - b := buf[:i] - - xxh3_128 := xxhash.XXH3_128(b, secret_bytes) - xxh3_128_error := fmt.tprintf("[XXH3_128(%03d)] Expected: %32x. Got: %32x.", i, v.xxh3_128_secret, xxh3_128) - - expect(t, xxh3_128 == v.xxh3_128_secret, xxh3_128_error) - } - } -} - -@test -test_crc64_vectors :: proc(t: ^testing.T) { - fmt.println("Verifying CRC-64:") - - vectors := map[string][4]u64 { - "123456789" = { - 0x6c40df5f0b497347, // ECMA-182, - 0x995dc9bbdf1939fa, // XZ - 0x46a5a9388a5beffe, // ISO 3306 - 0xb90956c775a41001, // ISO 3306, input and output inverted - }, - "This is a test of the emergency broadcast system." = { - 0x344fe1d09c983d13, // ECMA-182 - 0x27db187fc15bbc72, // XZ - 0x187184d744afc49e, // ISO 3306 - 0xe7fcf1006b503b61, // ISO 3306, input and output inverted - }, - } - - for vector, expected in vectors { - fmt.println("\tVector:", vector) - b := transmute([]u8)vector - ecma := hash.crc64_ecma_182(b) - xz := hash.crc64_xz(b) - iso := hash.crc64_iso_3306(b) - iso2 := hash.crc64_iso_3306_inverse(b) - - ecma_error := fmt.tprintf("[ CRC-64 ECMA ] Expected: %016x. Got: %016x.", expected[0], ecma) - xz_error := fmt.tprintf("[ CRC-64 XZ ] Expected: %016x. Got: %016x.", expected[1], xz) - iso_error := fmt.tprintf("[ CRC-64 ISO 3306] Expected: %016x. Got: %016x.", expected[2], iso) - iso2_error := fmt.tprintf("[~CRC-64 ISO 3306] Expected: %016x. Got: %016x.", expected[3], iso2) - - expect(t, ecma == expected[0], ecma_error) - expect(t, xz == expected[1], xz_error) - expect(t, iso == expected[2], iso_error) - expect(t, iso2 == expected[3], iso2_error) - } } \ No newline at end of file diff --git a/tests/core/hash/test_vectors_xxhash.odin b/tests/core/hash/test_vectors_xxhash.odin index 6a37aef30..f72e2699a 100644 --- a/tests/core/hash/test_vectors_xxhash.odin +++ b/tests/core/hash/test_vectors_xxhash.odin @@ -1,6 +1,4 @@ -/* - Hash Test Vectors -*/ +// Hash Test Vectors package test_core_hash XXHASH_Test_Vectors :: struct #packed { @@ -6789,4 +6787,4 @@ XXHASH_TEST_VECTOR_SECRET := map[string][257]XXHASH_Test_Vectors_With_Secret{ /* XXH3_128_with_secret */ 0x0f9b41191242ade48bbde48dff0d38ec, }, }, -} +} \ No newline at end of file From d7bfbe05523ec4a786e57a916d32b6e849de1681 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 18:38:35 +0200 Subject: [PATCH 48/93] Port `testing\core\text\i18n` --- core/text/i18n/qt_linguist.odin | 2 - tests/core/Makefile | 6 +- tests/core/build.bat | 10 +- tests/core/text/i18n/test_core_text_i18n.odin | 169 +++++++----------- 4 files changed, 75 insertions(+), 112 deletions(-) diff --git a/core/text/i18n/qt_linguist.odin b/core/text/i18n/qt_linguist.odin index 0e75df873..bdd3f5fd7 100644 --- a/core/text/i18n/qt_linguist.odin +++ b/core/text/i18n/qt_linguist.odin @@ -162,8 +162,6 @@ parse_qt_linguist_file :: proc(filename: string, options := DEFAULT_PARSE_OPTION context.allocator = allocator data, data_ok := os.read_entire_file(filename) - defer delete(data) - if !data_ok { return {}, .File_Error } return parse_qt_linguist_from_bytes(data, options, pluralizer, allocator) diff --git a/tests/core/Makefile b/tests/core/Makefile index 873bd24af..6a01653f0 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -62,12 +62,12 @@ fmt_test: hash_test: $(ODIN) test hash $(COMMON) -o:speed -out:test_hash -i18n_test: - $(ODIN) run text/i18n $(COMMON) -out:test_core_i18n - image_test: $(ODIN) test image $(COMMON) -out:test_core_image +i18n_test: + $(ODIN) test text/i18n $(COMMON) -out:test_core_i18n + linalg_glsl_math_test: $(ODIN) run math/linalg/glsl $(COMMON) $(COLLECTION) -out:test_linalg_glsl_math diff --git a/tests/core/build.bat b/tests/core/build.bat index 4748c3071..c06a9269f 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -54,6 +54,11 @@ echo Running core:image tests echo --- %PATH_TO_ODIN% test image %COMMON% -out:test_core_image.exe || exit /b +echo --- +echo Running core:text/i18n tests +echo --- +%PATH_TO_ODIN% test text\i18n %COMMON% -out:test_core_i18n.exe || exit /b + echo --- echo Running core:math tests echo --- @@ -99,11 +104,6 @@ echo Running core:strings tests echo --- %PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe || exit /b -echo --- -echo Running core:text/i18n tests -echo --- -%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe || exit /b - echo --- echo Running core:thread tests echo --- diff --git a/tests/core/text/i18n/test_core_text_i18n.odin b/tests/core/text/i18n/test_core_text_i18n.odin index dcbdeb0c4..f6cffc318 100644 --- a/tests/core/text/i18n/test_core_text_i18n.odin +++ b/tests/core/text/i18n/test_core_text_i18n.odin @@ -1,31 +1,9 @@ package test_core_text_i18n -import "core:mem" -import "core:fmt" -import "core:os" +import "base:runtime" import "core:testing" import "core:text/i18n" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} T :: i18n.get Test :: struct { @@ -37,25 +15,28 @@ Test :: struct { Test_Suite :: struct { file: string, - loader: proc(string, i18n.Parse_Options, proc(int) -> int, mem.Allocator) -> (^i18n.Translation, i18n.Error), + loader: proc(string, i18n.Parse_Options, proc(int) -> int, runtime.Allocator) -> (^i18n.Translation, i18n.Error), plural: proc(int) -> int, err: i18n.Error, options: i18n.Parse_Options, tests: []Test, } -// Custom pluralizer for plur.mo -plur_mo_pluralizer :: proc(n: int) -> (slot: int) { - switch { - case n == 1: return 0 - case n != 0 && n % 1_000_000 == 0: return 1 - case: return 2 - } -} +TEST_SUITE_PATH :: ODIN_ROOT + "tests/core/assets/I18N/" -TESTS := []Test_Suite{ - { - file = "assets/I18N/plur.mo", +@(test) +test_custom_pluralizer :: proc(t: ^testing.T) { + // Custom pluralizer for plur.mo + plur_mo_pluralizer :: proc(n: int) -> (slot: int) { + switch { + case n == 1: return 0 + case n != 0 && n % 1_000_000 == 0: return 1 + case: return 2 + } + } + + test(t, { + file = TEST_SUITE_PATH + "plur.mo", loader = i18n.parse_mo_file, plural = plur_mo_pluralizer, tests = { @@ -66,14 +47,16 @@ TESTS := []Test_Suite{ {"", "Message1/plural", "This is message 1", 1}, {"", "Message1/plural", "This is message 1 - plural A", 1_000_000}, {"", "Message1/plural", "This is message 1 - plural B", 42}, - // This isn't in the catalog, so should ruturn the key. {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, }, - }, + }) +} - { - file = "assets/I18N/mixed_context.mo", +@(test) +test_mixed_context :: proc(t: ^testing.T) { + test(t, { + file = TEST_SUITE_PATH + "mixed_context.mo", loader = i18n.parse_mo_file, plural = nil, tests = { @@ -84,19 +67,25 @@ TESTS := []Test_Suite{ // This isn't in the catalog, so should ruturn the key. {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, }, - }, + }) +} - { - file = "assets/I18N/mixed_context.mo", +@(test) +test_mixed_context_dupe :: proc(t: ^testing.T) { + test(t, { + file = TEST_SUITE_PATH + "mixed_context.mo", loader = i18n.parse_mo_file, plural = nil, // Message1 exists twice, once within Context, which has been merged into "" err = .Duplicate_Key, options = {merge_sections = true}, - }, + }) +} - { - file = "assets/I18N/nl_NL.mo", +@(test) +test_nl_mo :: proc(t: ^testing.T) { + test(t, { + file = TEST_SUITE_PATH + "nl_NL.mo", loader = i18n.parse_mo_file, plural = nil, // Default pluralizer tests = { @@ -111,12 +100,13 @@ TESTS := []Test_Suite{ // This isn't in the catalog, so should ruturn the key. {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, }, - }, + }) +} - - // QT Linguist with default loader options. - { - file = "assets/I18N/nl_NL-qt-ts.ts", +@(test) +test_qt_linguist :: proc(t: ^testing.T) { + test(t, { + file = TEST_SUITE_PATH + "nl_NL-qt-ts.ts", loader = i18n.parse_qt_linguist_file, plural = nil, // Default pluralizer tests = { @@ -131,11 +121,13 @@ TESTS := []Test_Suite{ {"", "Come visit us on Discord!", "Come visit us on Discord!", 1}, {"Fake_Section", "Come visit us on Discord!", "Come visit us on Discord!", 1}, }, - }, + }) +} - // QT Linguist, merging sections. - { - file = "assets/I18N/nl_NL-qt-ts.ts", +@(test) +test_qt_linguist_merge_sections :: proc(t: ^testing.T) { + test(t, { + file = TEST_SUITE_PATH + "nl_NL-qt-ts.ts", loader = i18n.parse_qt_linguist_file, plural = nil, // Default pluralizer options = {merge_sections = true}, @@ -154,65 +146,38 @@ TESTS := []Test_Suite{ {"apple_count", "%d apple(s)", "%d apple(s)", 1}, {"apple_count", "%d apple(s)", "%d apple(s)", 42}, }, - }, + }) +} - // QT Linguist, merging sections. Expecting .Duplicate_Key error because same key exists in more than 1 section. - { - file = "assets/I18N/duplicate-key.ts", +@(test) +test_qt_linguist_duplicate_key_err :: proc(t: ^testing.T) { + test(t, { // QT Linguist, merging sections. Expecting .Duplicate_Key error because same key exists in more than 1 section. + file = TEST_SUITE_PATH + "duplicate-key.ts", loader = i18n.parse_qt_linguist_file, plural = nil, // Default pluralizer options = {merge_sections = true}, err = .Duplicate_Key, - }, + }) +} - // QT Linguist, not merging sections. Shouldn't return error despite same key existing in more than 1 section. - { - file = "assets/I18N/duplicate-key.ts", +@(test) +test_qt_linguist_duplicate_key :: proc(t: ^testing.T) { + test(t, { // QT Linguist, not merging sections. Shouldn't return error despite same key existing in more than 1 section. + file = TEST_SUITE_PATH + "duplicate-key.ts", loader = i18n.parse_qt_linguist_file, plural = nil, // Default pluralizer - }, + }) } -@test -tests :: proc(t: ^testing.T) { - cat: ^i18n.Translation - err: i18n.Error +test :: proc(t: ^testing.T, suite: Test_Suite, loc := #caller_location) { + cat, err := suite.loader(suite.file, suite.options, suite.plural, context.allocator) + testing.expectf(t, err == suite.err, "Expected loading %v to return %v, got %v", suite.file, suite.err, err, loc=loc) - for suite in TESTS { - cat, err = suite.loader(suite.file, suite.options, suite.plural, context.allocator) - - msg := fmt.tprintf("Expected loading %v to return %v, got %v", suite.file, suite.err, err) - expect(t, err == suite.err, msg) - - if err == .None { - for test in suite.tests { - val := T(test.section, test.key, test.n, cat) - - msg = fmt.tprintf("Expected key `%v` from section `%v`'s form for value `%v` to equal `%v`, got `%v`", test.key, test.section, test.n, test.val, val) - expect(t, val == test.val, msg) - } - } - i18n.destroy(cat) - } -} - -main :: proc() { - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - t := testing.T{} - tests(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } - - if len(track.allocation_map) > 0 { - fmt.println() - for _, v in track.allocation_map { - fmt.printf("%v Leaked %v bytes.\n", v.location, v.size) + if err == .None { + for test in suite.tests { + val := T(test.section, test.key, test.n, cat) + testing.expectf(t, val == test.val, "Expected key `%v` from section `%v`'s form for value `%v` to equal `%v`, got `%v`", test.key, test.section, test.n, test.val, val, loc=loc) } } + i18n.destroy(cat) } \ No newline at end of file From b0faab29e0c4cfcde54b5ffa66f5b43c77283d3d Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 19:42:44 +0200 Subject: [PATCH 49/93] Port `tests\core\math`, `math\linalg\glsl` and `math\noise` --- tests/core/Makefile | 14 +- tests/core/build.bat | 6 +- .../linalg/glsl/test_linalg_glsl_math.odin | 20 +- .../core/math/noise/test_core_math_noise.odin | 195 +++++-------- tests/core/math/test_core_math.odin | 258 +++++++----------- 5 files changed, 180 insertions(+), 313 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 6a01653f0..eb16f6645 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -68,21 +68,21 @@ image_test: i18n_test: $(ODIN) test text/i18n $(COMMON) -out:test_core_i18n +math_test: + $(ODIN) test math $(COMMON) -out:test_core_math + linalg_glsl_math_test: - $(ODIN) run math/linalg/glsl $(COMMON) $(COLLECTION) -out:test_linalg_glsl_math + $(ODIN) test math/linalg/glsl $(COMMON) -out:test_linalg_glsl_math + +noise_test: + $(ODIN) test math/noise $(COMMON) -out:test_noise match_test: $(ODIN) run text/match $(COMMON) -out:test_core_match -math_test: - $(ODIN) run math $(COMMON) $(COLLECTION) -out:test_core_math - net_test: $(ODIN) run net $(COMMON) -out:test_core_net -noise_test: - $(ODIN) run math/noise $(COMMON) -out:test_noise - os_exit_test: $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 diff --git a/tests/core/build.bat b/tests/core/build.bat index c06a9269f..f14579056 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -62,17 +62,17 @@ echo --- echo --- echo Running core:math tests echo --- -%PATH_TO_ODIN% run math %COMMON% %COLLECTION% -out:test_core_math.exe || exit /b +%PATH_TO_ODIN% test math %COMMON% -out:test_core_math.exe || exit /b echo --- echo Running core:math/linalg/glsl tests echo --- -%PATH_TO_ODIN% run math/linalg/glsl %COMMON% %COLLECTION% -out:test_linalg_glsl.exe || exit /b +%PATH_TO_ODIN% test math/linalg/glsl %COMMON% -out:test_linalg_glsl.exe || exit /b echo --- echo Running core:math/noise tests echo --- -%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise.exe || exit /b +%PATH_TO_ODIN% test math/noise %COMMON% -out:test_noise.exe || exit /b echo --- echo Running core:net diff --git a/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin b/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin index cf91b8a97..6d4571b24 100644 --- a/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin +++ b/tests/core/math/linalg/glsl/test_linalg_glsl_math.odin @@ -1,24 +1,10 @@ // Tests "linalg_glsl_math.odin" in "core:math/linalg/glsl". -// Must be run with `-collection:tests=` flag, e.g. -// ./odin run tests/core/math/linalg/glsl/test_linalg_glsl_math.odin -collection:tests=./tests package test_core_math_linalg_glsl_math import glsl "core:math/linalg/glsl" -import "core:fmt" import "core:math" import "core:testing" -import tc "tests:common" - -main :: proc() { - - t := testing.T{} - - test_fract_f32(&t) - test_fract_f64(&t) - - tc.report(&t) -} @test test_fract_f32 :: proc(t: ^testing.T) { @@ -45,7 +31,7 @@ test_fract_f32 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = glsl.fract(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%v (%h)) -> %v (%h) != %v", i, #procedure, d.v, d.v, r, r, d.e)) + testing.expectf(t, r == d.e, "%v (%h) -> %v (%h) != %v", d.v, d.v, r, r, d.e) } } @@ -74,6 +60,6 @@ test_fract_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = glsl.fract(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%v (%h)) -> %v (%h) != %v", i, #procedure, d.v, d.v, r, r, d.e)) + testing.expectf(t, r == d.e, "%v (%h) -> %v (%h) != %v", d.v, d.v, r, r, d.e) } -} +} \ No newline at end of file diff --git a/tests/core/math/noise/test_core_math_noise.odin b/tests/core/math/noise/test_core_math_noise.odin index a0360e695..f835cf58c 100644 --- a/tests/core/math/noise/test_core_math_noise.odin +++ b/tests/core/math/noise/test_core_math_noise.odin @@ -2,42 +2,6 @@ package test_core_math_noise import "core:testing" import "core:math/noise" -import "core:fmt" -import "core:os" - -TEST_count := 0 -TEST_fail := 0 - -V2 :: noise.Vec2 -V3 :: noise.Vec3 -V4 :: noise.Vec4 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - noise_test(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} Test_Vector :: struct { seed: i64, @@ -51,6 +15,10 @@ Test_Vector :: struct { }, } +V2 :: noise.Vec2 +V3 :: noise.Vec3 +V4 :: noise.Vec4 + SEED_1 :: 2324223232 SEED_2 :: 932466901 SEED_3 :: 9321 @@ -59,93 +27,78 @@ COORD_1 :: V4{ 242.0, 3433.0, 920.0, 222312.0} COORD_2 :: V4{ 590.0, 9411.0, 5201.0, 942124256.0} COORD_3 :: V4{12090.0, 19411.0, 81950901.0, 4224219.0} -Noise_Tests := []Test_Vector{ - /* - `noise_2d` tests. - */ - {SEED_1, COORD_1.xy, 0.25010583, noise.noise_2d}, - {SEED_2, COORD_2.xy, -0.92513955, noise.noise_2d}, - {SEED_3, COORD_3.xy, 0.67327416, noise.noise_2d}, - - /* - `noise_2d_improve_x` tests. - */ - {SEED_1, COORD_1.xy, 0.17074019, noise.noise_2d_improve_x}, - {SEED_2, COORD_2.xy, 0.72330487, noise.noise_2d_improve_x}, - {SEED_3, COORD_3.xy, -0.032076947, noise.noise_2d_improve_x}, - - /* - `noise_3d_improve_xy` tests. - */ - {SEED_1, COORD_1.xyz, 0.14819577, noise.noise_3d_improve_xy}, - {SEED_2, COORD_2.xyz, -0.065345764, noise.noise_3d_improve_xy}, - {SEED_3, COORD_3.xyz, -0.37761918, noise.noise_3d_improve_xy}, - - /* - `noise_3d_improve_xz` tests. - */ - {SEED_1, COORD_1.xyz, -0.50075006, noise.noise_3d_improve_xz}, - {SEED_2, COORD_2.xyz, -0.36039603, noise.noise_3d_improve_xz}, - {SEED_3, COORD_3.xyz, -0.3479203, noise.noise_3d_improve_xz}, - - /* - `noise_3d_fallback` tests. - */ - {SEED_1, COORD_1.xyz, 0.6557345, noise.noise_3d_fallback}, - {SEED_2, COORD_2.xyz, 0.55452216, noise.noise_3d_fallback}, - {SEED_3, COORD_3.xyz, -0.26408964, noise.noise_3d_fallback}, - - /* - `noise_3d_fallback` tests. - */ - {SEED_1, COORD_1.xyz, 0.6557345, noise.noise_3d_fallback}, - {SEED_2, COORD_2.xyz, 0.55452216, noise.noise_3d_fallback}, - {SEED_3, COORD_3.xyz, -0.26408964, noise.noise_3d_fallback}, - - /* - `noise_4d_improve_xyz_improve_xy` tests. - */ - {SEED_1, COORD_1, 0.44929826, noise.noise_4d_improve_xyz_improve_xy}, - {SEED_2, COORD_2, -0.13270882, noise.noise_4d_improve_xyz_improve_xy}, - {SEED_3, COORD_3, 0.10298563, noise.noise_4d_improve_xyz_improve_xy}, - - /* - `noise_4d_improve_xyz_improve_xz` tests. - */ - {SEED_1, COORD_1, -0.078514606, noise.noise_4d_improve_xyz_improve_xz}, - {SEED_2, COORD_2, -0.032157656, noise.noise_4d_improve_xyz_improve_xz}, - {SEED_3, COORD_3, -0.38607058, noise.noise_4d_improve_xyz_improve_xz}, - - /* - `noise_4d_improve_xyz` tests. - */ - {SEED_1, COORD_1, -0.4442258, noise.noise_4d_improve_xyz}, - {SEED_2, COORD_2, 0.36822623, noise.noise_4d_improve_xyz}, - {SEED_3, COORD_3, 0.22628775, noise.noise_4d_improve_xyz}, - - /* - `noise_4d_fallback` tests. - */ - {SEED_1, COORD_1, -0.14233987, noise.noise_4d_fallback}, - {SEED_2, COORD_2, 0.1354035, noise.noise_4d_fallback}, - {SEED_3, COORD_3, 0.14565045, noise.noise_4d_fallback}, - +@(test) +test_noise_2d :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1.xy, 0.25010583, noise.noise_2d}) + test(t, {SEED_2, COORD_2.xy, -0.92513955, noise.noise_2d}) + test(t, {SEED_3, COORD_3.xy, 0.67327416, noise.noise_2d}) } -noise_test :: proc(t: ^testing.T) { - for test in Noise_Tests { - output: f32 +@(test) +test_noise_2d_improve_x :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1.xy, 0.17074019, noise.noise_2d_improve_x}) + test(t, {SEED_2, COORD_2.xy, 0.72330487, noise.noise_2d_improve_x}) + test(t, {SEED_3, COORD_3.xy, -0.032076947, noise.noise_2d_improve_x}) +} - switch coord in test.coord { - case V2: - output = test.test_proc.(proc(_: i64, _: V2) -> f32)(test.seed, test.coord.(V2)) - case V3: - output = test.test_proc.(proc(_: i64, _: V3) -> f32)(test.seed, test.coord.(V3)) - case V4: - output = test.test_proc.(proc(_: i64, _: V4) -> f32)(test.seed, test.coord.(V4)) - } - - error := fmt.tprintf("Seed %v, Coord: %v, Expected: %3.8f. Got %3.8f", test.seed, test.coord, test.expected, output) - expect(t, test.expected == output, error) +@(test) +test_noise_3d_improve_xy :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1.xyz, 0.14819577, noise.noise_3d_improve_xy}) + test(t, {SEED_2, COORD_2.xyz, -0.065345764, noise.noise_3d_improve_xy}) + test(t, {SEED_3, COORD_3.xyz, -0.37761918, noise.noise_3d_improve_xy}) +} + +@(test) +test_noise_3d_improve_xz :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1.xyz, -0.50075006, noise.noise_3d_improve_xz}) + test(t, {SEED_2, COORD_2.xyz, -0.36039603, noise.noise_3d_improve_xz}) + test(t, {SEED_3, COORD_3.xyz, -0.3479203, noise.noise_3d_improve_xz}) +} + +@(test) +test_noise_3d_fallback :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1.xyz, 0.6557345, noise.noise_3d_fallback}) + test(t, {SEED_2, COORD_2.xyz, 0.55452216, noise.noise_3d_fallback}) + test(t, {SEED_3, COORD_3.xyz, -0.26408964, noise.noise_3d_fallback}) +} + +@(test) +test_noise_4d_improve_xyz_improve_xy :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1, 0.44929826, noise.noise_4d_improve_xyz_improve_xy}) + test(t, {SEED_2, COORD_2, -0.13270882, noise.noise_4d_improve_xyz_improve_xy}) + test(t, {SEED_3, COORD_3, 0.10298563, noise.noise_4d_improve_xyz_improve_xy}) +} + +@(test) +test_noise_4d_improve_xyz_improve_xz :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1, -0.078514606, noise.noise_4d_improve_xyz_improve_xz}) + test(t, {SEED_2, COORD_2, -0.032157656, noise.noise_4d_improve_xyz_improve_xz}) + test(t, {SEED_3, COORD_3, -0.38607058, noise.noise_4d_improve_xyz_improve_xz}) +} + +@(test) +test_noise_4d_improve_xyz :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1, -0.4442258, noise.noise_4d_improve_xyz}) + test(t, {SEED_2, COORD_2, 0.36822623, noise.noise_4d_improve_xyz}) + test(t, {SEED_3, COORD_3, 0.22628775, noise.noise_4d_improve_xyz}) +} + +@(test) +test_noise_4d_fallback :: proc(t: ^testing.T) { + test(t, {SEED_1, COORD_1, -0.14233987, noise.noise_4d_fallback}) + test(t, {SEED_2, COORD_2, 0.1354035, noise.noise_4d_fallback}) + test(t, {SEED_3, COORD_3, 0.14565045, noise.noise_4d_fallback}) +} + +test :: proc(t: ^testing.T, test: Test_Vector) { + output: f32 + switch coord in test.coord { + case V2: + output = test.test_proc.(proc(_: i64, _: V2) -> f32)(test.seed, test.coord.(V2)) + case V3: + output = test.test_proc.(proc(_: i64, _: V3) -> f32)(test.seed, test.coord.(V3)) + case V4: + output = test.test_proc.(proc(_: i64, _: V4) -> f32)(test.seed, test.coord.(V4)) } + testing.expectf(t, test.expected == output, "Seed %v, Coord: %v, Expected: %3.8f. Got %3.8f", test.seed, test.coord, test.expected, output) } \ No newline at end of file diff --git a/tests/core/math/test_core_math.odin b/tests/core/math/test_core_math.odin index df989bff6..2a752e366 100644 --- a/tests/core/math/test_core_math.odin +++ b/tests/core/math/test_core_math.odin @@ -1,49 +1,8 @@ // Tests "math.odin" in "core:math". -// Must be run with `-collection:tests=` flag, e.g. -// ./odin run tests/core/math/test_core_math.odin -collection:tests=./tests package test_core_math -import "core:fmt" import "core:math" import "core:testing" -import tc "tests:common" - -main :: proc() { - t := testing.T{} - - test_classify_f16(&t) - test_classify_f32(&t) - test_classify_f64(&t) - - test_trunc_f16(&t) - test_trunc_f32(&t) - test_trunc_f64(&t) - - test_round_f16(&t) - test_round_f32(&t) - test_round_f64(&t) - - test_nan(&t) - test_acos(&t) - test_acosh(&t) - test_asin(&t) - test_asinh(&t) - test_atan(&t) - test_atanh(&t) - test_atan2(&t) - test_cos(&t) - test_cosh(&t) - test_sin(&t) - test_sinh(&t) - test_sqrt(&t) - test_tan(&t) - test_tanh(&t) - test_large_cos(&t) - test_large_sin(&t) - test_large_tan(&t) - - tc.report(&t) -} @test test_classify_f16 :: proc(t: ^testing.T) { @@ -68,7 +27,7 @@ test_classify_f16 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.classify_f16(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %v != %v", d.v, r, d.e) } /* Check all subnormals (exponent 0, 10-bit significand non-zero) */ @@ -76,7 +35,7 @@ test_classify_f16 :: proc(t: ^testing.T) { v := transmute(f16)i r = math.classify_f16(v) e :: math.Float_Class.Subnormal - tc.expect(t, r == e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, v, r, e)) + testing.expectf(t, r == e, "%h -> %v != %v", v, r, e) } } @@ -103,7 +62,7 @@ test_classify_f32 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.classify_f32(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %v != %v", d.v, r, d.e) } } @@ -130,7 +89,7 @@ test_classify_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.classify_f64(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %v != %v", d.v, r, d.e) } } @@ -175,16 +134,16 @@ test_trunc_f16 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.trunc_f16(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %h != %h", d.v, r, d.e) } v = math.SNAN_F16 r = math.trunc_f16(v) - tc.expect(t, math.is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f16(r), "%f != NaN", v, r) v = math.QNAN_F16 r = math.trunc_f16(v) - tc.expect(t, math.is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f16(r), "%f != NaN", v, r) } @test @@ -237,16 +196,16 @@ test_trunc_f32 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.trunc_f32(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %h != %h", d.v, r, d.e) } v = math.SNAN_F32 r = math.trunc_f32(v) - tc.expect(t, math.is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f32(r), "%f -> %f != NaN", v, r) v = math.QNAN_F32 r = math.trunc_f32(v) - tc.expect(t, math.is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f32(r), "%f -> %f != NaN", v, r) } @test @@ -299,16 +258,16 @@ test_trunc_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.trunc_f64(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %h != %h", d.v, r, d.e) } v = math.SNAN_F64 r = math.trunc_f64(v) - tc.expect(t, math.is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f64(r), "%f -> %f != NaN", v, r) v = math.QNAN_F64 r = math.trunc_f64(v) - tc.expect(t, math.is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f64(r), "%f -> %f != NaN", v, r) } @test @@ -352,16 +311,16 @@ test_round_f16 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.round_f16(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %h != %h", d.v, r, d.e) } v = math.SNAN_F16 r = math.round_f16(v) - tc.expect(t, math.is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f16(r), "%f -> %f != NaN", v, r) v = math.QNAN_F16 r = math.round_f16(v) - tc.expect(t, math.is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f16(r), "%f -> %f != NaN", v, r) } @test @@ -414,16 +373,16 @@ test_round_f32 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.round_f32(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %h != %h", i, d.v, r, d.e) } v = math.SNAN_F32 r = math.round_f32(v) - tc.expect(t, math.is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f32(r), "%f -> %f != NaN", v, r) v = math.QNAN_F32 r = math.round_f32(v) - tc.expect(t, math.is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f32(r), "%f -> %f != NaN", v, r) } @test @@ -476,16 +435,16 @@ test_round_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r = math.round_f64(d.v) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e)) + testing.expectf(t, r == d.e, "%h -> %h != %h", d.v, r, d.e) } v = math.SNAN_F64 r = math.round_f64(v) - tc.expect(t, math.is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f64(r), "%f -> %f != NaN", v, r) v = math.QNAN_F64 r = math.round_f64(v) - tc.expect(t, math.is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r)) + testing.expectf(t, math.is_nan_f64(r), "%f -> %f != NaN", v, r) } @@ -1033,17 +992,17 @@ tolerance :: proc(a, b, e: f64) -> bool { } close :: proc(t: ^testing.T, a, b: f64, loc := #caller_location) -> bool { ok := tolerance(a, b, 1e-9) - // tc.expect(t, ok, fmt.tprintf("%.15g is not close to %.15g", a, b), loc) + testing.expectf(t, ok, "%.15g is not close to %.15g", a, b, loc=loc) return ok } veryclose :: proc(t: ^testing.T, a, b: f64, loc := #caller_location) -> bool { ok := tolerance(a, b, 4e-14) - // tc.expect(t, ok, fmt.tprintf("%.15g is not veryclose to %.15g", a, b), loc) + testing.expectf(t, ok, "%.15g is not veryclose to %.15g", a, b, loc=loc) return ok } soclose :: proc(t: ^testing.T, a, b, e: f64, loc := #caller_location) -> bool { ok := tolerance(a, b, e) - // tc.expect(t, ok, fmt.tprintf("%.15g is not soclose to %.15g", a, b), loc) + testing.expectf(t, ok, "%.15g is not soclose to %.15g", a, b, loc=loc) return ok } alike :: proc(t: ^testing.T, a, b: f64, loc := #caller_location) -> bool { @@ -1054,34 +1013,34 @@ alike :: proc(t: ^testing.T, a, b: f64, loc := #caller_location) -> bool { case a == b: ok = math.signbit(a) == math.signbit(b) } - // tc.expect(t, ok, fmt.tprintf("%.15g is not alike to %.15g", a, b), loc) + testing.expectf(t, ok, "%.15g is not alike to %.15g", a, b, loc=loc) return ok } @test -test_nan :: proc(t: ^testing.T) { +test_nan32 :: proc(t: ^testing.T) { + float32 := f32(NaN) + equal := float32 == float32 + testing.expectf(t, !equal, "float32(NaN) is %.15g, expected NaN", float32) +} + +@test +test_nan64 :: proc(t: ^testing.T) { float64 := NaN - if float64 == float64 { - tc.errorf(t, "NaN returns %.15g, expected NaN", float64) - } - float32 := f32(float64) - if float32 == float32 { - tc.errorf(t, "float32(NaN) is %.15g, expected NaN", float32) - } + equal := float64 == float64 + testing.expectf(t, !equal, "NaN returns %.15g, expected NaN", float64) } @test test_acos :: proc(t: ^testing.T) { for _, i in vf { a := vf[i] / 10 - if f := math.acos(a); !close(t, acos[i], f) { - tc.errorf(t, "math.acos(%.15g) = %.15g, want %.15g", a, f, acos[i]) - } + f := math.acos(a) + testing.expectf(t, close(t, acos[i], f), "math.acos(%.15g) = %.15g, want %.15g", a, f, acos[i]) } for _, i in vfacos_sc { - if f := math.acos(vfacos_sc[i]); !alike(t, acos_sc[i], f) { - tc.errorf(t, "math.acos(%.15g) = %.15g, want %.15g", vfacos_sc[i], f, acos_sc[i]) - } + f := math.acos(vfacos_sc[i]) + testing.expectf(t, alike(t, acos_sc[i], f), "math.acos(%.15g) = %.15g, want %.15g", vfacos_sc[i], f, acos_sc[i]) } } @@ -1089,14 +1048,12 @@ test_acos :: proc(t: ^testing.T) { test_acosh :: proc(t: ^testing.T) { for _, i in vf { a := 1 + abs(vf[i]) - if f := math.acosh(a); !veryclose(t, acosh[i], f) { - tc.errorf(t, "math.acosh(%.15g) = %.15g, want %.15g", a, f, acosh[i]) - } + f := math.acosh(a) + testing.expectf(t, veryclose(t, acosh[i], f), "math.acosh(%.15g) = %.15g, want %.15g", a, f, acosh[i]) } for _, i in vfacosh_sc { - if f := math.acosh(vfacosh_sc[i]); !alike(t, acosh_sc[i], f) { - tc.errorf(t, "math.acosh(%.15g) = %.15g, want %.15g", vfacosh_sc[i], f, acosh_sc[i]) - } + f := math.acosh(vfacosh_sc[i]) + testing.expectf(t, alike(t, acosh_sc[i], f), "math.acosh(%.15g) = %.15g, want %.15g", vfacosh_sc[i], f, acosh_sc[i]) } } @@ -1104,42 +1061,36 @@ test_acosh :: proc(t: ^testing.T) { test_asin :: proc(t: ^testing.T) { for _, i in vf { a := vf[i] / 10 - if f := math.asin(a); !veryclose(t, asin[i], f) { - tc.errorf(t, "math.asin(%.15g) = %.15g, want %.15g", a, f, asin[i]) - } + f := math.asin(a) + testing.expectf(t, veryclose(t, asin[i], f), "math.asin(%.15g) = %.15g, want %.15g", a, f, asin[i]) } for _, i in vfasin_sc { - if f := math.asin(vfasin_sc[i]); !alike(t, asin_sc[i], f) { - tc.errorf(t, "math.asin(%.15g) = %.15g, want %.15g", vfasin_sc[i], f, asin_sc[i]) - } + f := math.asin(vfasin_sc[i]) + testing.expectf(t, alike(t, asin_sc[i], f), "math.asin(%.15g) = %.15g, want %.15g", vfasin_sc[i], f, asin_sc[i]) } } @test test_asinh :: proc(t: ^testing.T) { for _, i in vf { - if f := math.asinh(vf[i]); !veryclose(t, asinh[i], f) { - tc.errorf(t, "math.asinh(%.15g) = %.15g, want %.15g", vf[i], f, asinh[i]) - } + f := math.asinh(vf[i]) + testing.expectf(t, veryclose(t, asinh[i], f), "math.asinh(%.15g) = %.15g, want %.15g", vf[i], f, asinh[i]) } for _, i in vfasinh_sc { - if f := math.asinh(vfasinh_sc[i]); !alike(t, asinh_sc[i], f) { - tc.errorf(t, "math.asinh(%.15g) = %.15g, want %.15g", vfasinh_sc[i], f, asinh_sc[i]) - } + f := math.asinh(vfasinh_sc[i]) + testing.expectf(t, alike(t, asinh_sc[i], f), "math.asinh(%.15g) = %.15g, want %.15g", vfasinh_sc[i], f, asinh_sc[i]) } } @test test_atan :: proc(t: ^testing.T) { for _, i in vf { - if f := math.atan(vf[i]); !veryclose(t, atan[i], f) { - tc.errorf(t, "math.atan(%.15g) = %.15g, want %.15g", vf[i], f, atan[i]) - } + f := math.atan(vf[i]) + testing.expectf(t, veryclose(t, atan[i], f), "math.atan(%.15g) = %.15g, want %.15g", vf[i], f, atan[i]) } for _, i in vfatan_sc { - if f := math.atan(vfatan_sc[i]); !alike(t, atan_sc[i], f) { - tc.errorf(t, "math.atan(%.15g) = %.15g, want %.15g", vfatan_sc[i], f, atan_sc[i]) - } + f := math.atan(vfatan_sc[i]) + testing.expectf(t, alike(t, atan_sc[i], f), "math.atan(%.15g) = %.15g, want %.15g", vfatan_sc[i], f, atan_sc[i]) } } @@ -1147,84 +1098,72 @@ test_atan :: proc(t: ^testing.T) { test_atanh :: proc(t: ^testing.T) { for _, i in vf { a := vf[i] / 10 - if f := math.atanh(a); !veryclose(t, atanh[i], f) { - tc.errorf(t, "math.atanh(%.15g) = %.15g, want %.15g", a, f, atanh[i]) - } + f := math.atanh(a) + testing.expectf(t, veryclose(t, atanh[i], f), "math.atanh(%.15g) = %.15g, want %.15g", a, f, atanh[i]) } for _, i in vfatanh_sc { - if f := math.atanh(vfatanh_sc[i]); !alike(t, atanh_sc[i], f) { - tc.errorf(t, "math.atanh(%.15g) = %.15g, want %.15g", vfatanh_sc[i], f, atanh_sc[i]) - } + f := math.atanh(vfatanh_sc[i]) + testing.expectf(t, alike(t, atanh_sc[i], f), "math.atanh(%.15g) = %.15g, want %.15g", vfatanh_sc[i], f, atanh_sc[i]) } } @test test_atan2 :: proc(t: ^testing.T) { for _, i in vf { - if f := math.atan2(10, vf[i]); !veryclose(t, atan2[i], f) { - tc.errorf(t, "math.atan2(10, %.15g) = %.15g, want %.15g", vf[i], f, atan2[i]) - } + f := math.atan2(10, vf[i]) + testing.expectf(t, veryclose(t, atan2[i], f), "math.atan2(10, %.15g) = %.15g, want %.15g", vf[i], f, atan2[i]) } for _, i in vfatan2_sc { - if f := math.atan2(vfatan2_sc[i][0], vfatan2_sc[i][1]); !alike(t, atan2_sc[i], f) { - tc.errorf(t, "math.atan2(%.15g, %.15g) = %.15g, want %.15g", vfatan2_sc[i][0], vfatan2_sc[i][1], f, atan2_sc[i]) - } + f := math.atan2(vfatan2_sc[i][0], vfatan2_sc[i][1]) + testing.expectf(t, alike(t, atan2_sc[i], f), "math.atan2(%.15g, %.15g) = %.15g, want %.15g", vfatan2_sc[i][0], vfatan2_sc[i][1], f, atan2_sc[i]) } } @test test_cos :: proc(t: ^testing.T) { for _, i in vf { - if f := math.cos(vf[i]); !veryclose(t, cos[i], f) { - tc.errorf(t, "math.cos(%.15g) = %.15g, want %.15g", vf[i], f, cos[i]) - } + f := math.cos(vf[i]) + testing.expectf(t, veryclose(t, cos[i], f), "math.cos(%.15g) = %.15g, want %.15g", vf[i], f, cos[i]) } for _, i in vfcos_sc { - if f := math.cos(vfcos_sc[i]); !alike(t, cos_sc[i], f) { - tc.errorf(t, "math.cos(%.15g) = %.15g, want %.15g", vfcos_sc[i], f, cos_sc[i]) - } + f := math.cos(vfcos_sc[i]) + testing.expectf(t, alike(t, cos_sc[i], f), "math.cos(%.15g) = %.15g, want %.15g", vfcos_sc[i], f, cos_sc[i]) } } @test test_cosh :: proc(t: ^testing.T) { for _, i in vf { - if f := math.cosh(vf[i]); !close(t, cosh[i], f) { - tc.errorf(t, "math.cosh(%.15g) = %.15g, want %.15g", vf[i], f, cosh[i]) - } + f := math.cosh(vf[i]) + testing.expectf(t, close(t, cosh[i], f), "math.cosh(%.15g) = %.15g, want %.15g", vf[i], f, cosh[i]) } for _, i in vfcosh_sc { - if f := math.cosh(vfcosh_sc[i]); !alike(t, cosh_sc[i], f) { - tc.errorf(t, "math.cosh(%.15g) = %.15g, want %.15g", vfcosh_sc[i], f, cosh_sc[i]) - } + f := math.cosh(vfcosh_sc[i]) + testing.expectf(t, alike(t, cosh_sc[i], f), "math.cosh(%.15g) = %.15g, want %.15g", vfcosh_sc[i], f, cosh_sc[i]) } } @test test_sin :: proc(t: ^testing.T) { for _, i in vf { - if f := math.sin(vf[i]); !veryclose(t, sin[i], f) { - tc.errorf(t, "math.sin(%.15g) = %.15g, want %.15g", vf[i], f, sin[i]) - } + f := math.sin(vf[i]) + testing.expectf(t, veryclose(t, sin[i], f), "math.sin(%.15g) = %.15g, want %.15g", vf[i], f, sin[i]) } for _, i in vfsin_sc { - if f := math.sin(vfsin_sc[i]); !alike(t, sin_sc[i], f) { - tc.errorf(t, "math.sin(%.15g) = %.15g, want %.15g", vfsin_sc[i], f, sin_sc[i]) - } + f := math.sin(vfsin_sc[i]) + testing.expectf(t, alike(t, sin_sc[i], f), "math.sin(%.15g) = %.15g, want %.15g", vfsin_sc[i], f, sin_sc[i]) } } @test test_sinh :: proc(t: ^testing.T) { for _, i in vf { - if f := math.sinh(vf[i]); !close(t, sinh[i], f) { - tc.errorf(t, "math.sinh(%.15g) = %.15g, want %.15g", vf[i], f, sinh[i]) - } + f := math.sinh(vf[i]) + testing.expectf(t, close(t, sinh[i], f), "math.sinh(%.15g) = %.15g, want %.15g", vf[i], f, sinh[i]) } for _, i in vfsinh_sc { - if f := math.sinh(vfsinh_sc[i]); !alike(t, sinh_sc[i], f) { - tc.errorf(t, "math.sinh(%.15g) = %.15g, want %.15g", vfsinh_sc[i], f, sinh_sc[i]) - } + f := math.sinh(vfsinh_sc[i]) + testing.expectf(t, alike(t, sinh_sc[i], f), "math.sinh(%.15g) = %.15g, want %.15g", vfsinh_sc[i], f, sinh_sc[i]) } } @@ -1232,38 +1171,33 @@ test_sinh :: proc(t: ^testing.T) { test_sqrt :: proc(t: ^testing.T) { for _, i in vf { a := abs(vf[i]) - if f := math.sqrt(a); !veryclose(t, sqrt[i], f) { - tc.errorf(t, "math.sqrt(%.15g) = %.15g, want %.15g", a, f, sqrt[i]) - } + f := math.sqrt(a) + testing.expectf(t, veryclose(t, sqrt[i], f), "math.sqrt(%.15g) = %.15g, want %.15g", a, f, sqrt[i]) } } @test test_tan :: proc(t: ^testing.T) { for _, i in vf { - if f := math.tan(vf[i]); !veryclose(t, tan[i], f) { - tc.errorf(t, "math.tan(%.15g) = %.15g, want %.15g", vf[i], f, tan[i]) - } + f := math.tan(vf[i]) + testing.expectf(t, veryclose(t, tan[i], f), "math.tan(%.15g) = %.15g, want %.15g", vf[i], f, tan[i]) } // same special cases as Sin for _, i in vfsin_sc { - if f := math.tan(vfsin_sc[i]); !alike(t, sin_sc[i], f) { - tc.errorf(t, "math.tan(%.15g) = %.15g, want %.15g", vfsin_sc[i], f, sin_sc[i]) - } + f := math.tan(vfsin_sc[i]) + testing.expectf(t, alike(t, sin_sc[i], f), "math.tan(%.15g) = %.15g, want %.15g", vfsin_sc[i], f, sin_sc[i]) } } @test test_tanh :: proc(t: ^testing.T) { for _, i in vf { - if f := math.tanh(vf[i]); !veryclose(t, tanh[i], f) { - tc.errorf(t, "math.tanh(%.15g) = %.15g, want %.15g", vf[i], f, tanh[i]) - } + f := math.tanh(vf[i]) + testing.expectf(t, veryclose(t, tanh[i], f), "math.tanh(%.15g) = %.15g, want %.15g", vf[i], f, tanh[i]) } for _, i in vftanh_sc { - if f := math.tanh(vftanh_sc[i]); !alike(t, tanh_sc[i], f) { - tc.errorf(t, "math.tanh(%.15g) = %.15g, want %.15g", vftanh_sc[i], f, tanh_sc[i]) - } + f := math.tanh(vftanh_sc[i]) + testing.expectf(t, alike(t, tanh_sc[i], f), "math.tanh(%.15g) = %.15g, want %.15g", vftanh_sc[i], f, tanh_sc[i]) } } @@ -1273,9 +1207,7 @@ test_large_cos :: proc(t: ^testing.T) { for _, i in vf { f1 := cosLarge[i] f2 := math.cos(vf[i] + large) - if !close(t, f1, f2) { - tc.errorf(t, "math.cos(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) - } + testing.expectf(t, close(t, f1, f2), "math.cos(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) } } @@ -1285,9 +1217,7 @@ test_large_sin :: proc(t: ^testing.T) { for _, i in vf { f1 := sinLarge[i] f2 := math.sin(vf[i] + large) - if !close(t, f1, f2) { - tc.errorf(t, "math.sin(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) - } + testing.expectf(t, close(t, f1, f2), "math.sin(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) } } @@ -1297,8 +1227,6 @@ test_large_tan :: proc(t: ^testing.T) { for _, i in vf { f1 := tanLarge[i] f2 := math.tan(vf[i] + large) - if !close(t, f1, f2) { - tc.errorf(t, "math.tan(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) - } + testing.expectf(t, close(t, f1, f2), "math.tan(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) } } \ No newline at end of file From 8383a45b62df9a3f28df0e0967bdd2b864c90cb9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 30 May 2024 23:25:34 +0200 Subject: [PATCH 50/93] Port `tests\core\text\match` --- tests/core/Makefile | 6 +- tests/core/build.bat | 5 + .../core/text/match/test_core_text_match.odin | 161 +++++++----------- 3 files changed, 71 insertions(+), 101 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index eb16f6645..ad8209b86 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -68,6 +68,9 @@ image_test: i18n_test: $(ODIN) test text/i18n $(COMMON) -out:test_core_i18n +match_test: + $(ODIN) test text/match $(COMMON) -out:test_core_match + math_test: $(ODIN) test math $(COMMON) -out:test_core_math @@ -77,9 +80,6 @@ linalg_glsl_math_test: noise_test: $(ODIN) test math/noise $(COMMON) -out:test_noise -match_test: - $(ODIN) run text/match $(COMMON) -out:test_core_match - net_test: $(ODIN) run net $(COMMON) -out:test_core_net diff --git a/tests/core/build.bat b/tests/core/build.bat index f14579056..f77c4adfc 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -59,6 +59,11 @@ echo Running core:text/i18n tests echo --- %PATH_TO_ODIN% test text\i18n %COMMON% -out:test_core_i18n.exe || exit /b +echo --- +echo Running text:match tests +echo --- +%PATH_TO_ODIN% test text/match %COMMON% -out:test_core_match.exe || exit /b + echo --- echo Running core:math tests echo --- diff --git a/tests/core/text/match/test_core_text_match.odin b/tests/core/text/match/test_core_text_match.odin index eadd17433..5716b06fb 100644 --- a/tests/core/text/match/test_core_text_match.odin +++ b/tests/core/text/match/test_core_text_match.odin @@ -2,31 +2,6 @@ package test_strlib import "core:text/match" import "core:testing" -import "core:fmt" -import "core:os" -import "core:io" - -TEST_count: int -TEST_fail: int - -// inline expect with custom props -failed :: proc(t: ^testing.T, ok: bool, loc := #caller_location) -> bool { - TEST_count += 1 - - if !ok { - fmt.printf(/*t.w,*/ "%v: ", loc) - t.error_count += 1 - TEST_fail += 1 - } - - return !ok -} - -expect :: testing.expect - -logf :: proc(t: ^testing.T, format: string, args: ..any) { - fmt.printf(/*t.w,*/ format, ..args) -} // find correct byte offsets @test @@ -61,18 +36,17 @@ test_find :: proc(t: ^testing.T) { { "helelo", "h.-l", 0, { 0, 3, true } }, } - for entry, i in ENTRIES { + for entry in ENTRIES { matcher := match.matcher_init(entry.s, entry.p, entry.offset) start, end, ok := match.matcher_find(&matcher) success := entry.match.ok == ok && start == entry.match.start && end == entry.match.end - if failed(t, success) { - logf(t, "Find %d failed!\n", i) - logf(t, "\tHAYSTACK %s\tPATTERN %s\n", entry.s, entry.p) - logf(t, "\tSTART: %d == %d?\n", entry.match.start, start) - logf(t, "\tEND: %d == %d?\n", entry.match.end, end) - logf(t, "\tErr: %v\tLength %d\n", matcher.err, matcher.captures_length) - } + testing.expectf( + t, + success, + "HAYSTACK %q PATTERN %q, START: %d == %d? END: %d == %d? Err: %v Length %d", + entry.s, entry.p, entry.match.start, start, entry.match.end, end, matcher.err, matcher.captures_length, + ) } } @@ -178,17 +152,17 @@ test_match :: proc(t: ^testing.T) { { "testing _this_ out", "%b_", "", false }, } - for entry, i in ENTRIES { + for entry in ENTRIES { matcher := match.matcher_init(entry.s, entry.p) result, ok := match.matcher_match(&matcher) success := entry.ok == ok && result == entry.result - if failed(t, success) { - logf(t, "Match %d failed!\n", i) - logf(t, "\tHAYSTACK %s\tPATTERN %s\n", entry.s, entry.p) - logf(t, "\tResults: WANTED %s\tGOT %s\n", entry.result, result) - logf(t, "\tErr: %v\tLength %d\n", matcher.err, matcher.captures_length) - } + testing.expectf( + t, + success, + "HAYSTACK %q PATTERN %q WANTED %q GOT %q Err: %v Length %d", + entry.s, entry.p, entry.result, result, matcher.err, matcher.captures_length, + ) } } @@ -203,19 +177,23 @@ test_captures :: proc(t: ^testing.T) { compare_captures :: proc(t: ^testing.T, test: ^Temp, haystack: string, comp: []string, loc := #caller_location) { length, err := match.find_aux(haystack, test.pattern, 0, false, &test.captures) result := len(comp) == length && err == .OK - if failed(t, result == true) { - logf(t, "Captures Compare Failed!\n") - logf(t, "\tErr: %v\n", err) - logf(t, "\tLengths: %v != %v\n", len(comp), length) - } + testing.expectf( + t, + result, + "Captures Compare Failed! Lengths: %v != %v Err: %v", + len(comp), length, err, + ) for i in 0.. %s != %s\n", comp[i], text) - } + testing.expectf( + t, + comp[i] == text, + "Capture don't equal -> %q != %q\n", + comp[i], text, + ) } } @@ -224,11 +202,12 @@ test_captures :: proc(t: ^testing.T) { length, err := match.find_aux(haystack, test.pattern, 0, false, &test.captures) result := length > 0 && err == .OK - if failed(t, result == ok) { - logf(t, "Capture match failed!\n") - logf(t, "\tErr: %v\n", err) - logf(t, "\tLength: %v\n", length) - } + testing.expectf( + t, + result == ok, + "Capture match failed! Length: %v Pattern: %q Haystack: %q Err: %v", + length, test.pattern, haystack, err, + ) } temp := Temp { pattern = "(one).+" } @@ -253,15 +232,8 @@ test_captures :: proc(t: ^testing.T) { cap2 := captures[2] text1 := haystack[cap1.byte_start:cap1.byte_end] text2 := haystack[cap2.byte_start:cap2.byte_end] - expect(t, text1 == "233", "Multi-Capture failed at 1") - expect(t, text2 == "hello", "Multi-Capture failed at 2") - } -} - -gmatch_check :: proc(t: ^testing.T, index: int, a: []string, b: string) { - if failed(t, a[index] == b) { - logf(t, "GMATCH %d failed!\n", index) - logf(t, "\t%s != %s\n", a[index], b) + testing.expect(t, text1 == "233", "Multi-Capture failed at 1") + testing.expect(t, text2 == "hello", "Multi-Capture failed at 2") } } @@ -298,9 +270,9 @@ test_gmatch :: proc(t: ^testing.T) { @test test_gsub :: proc(t: ^testing.T) { result := match.gsub("testing123testing", "%d+", " sup ", context.temp_allocator) - expect(t, result == "testing sup testing", "GSUB 0: failed") + testing.expect(t, result == "testing sup testing", "GSUB 0: failed") result = match.gsub("testing123testing", "%a+", "345", context.temp_allocator) - expect(t, result == "345123345", "GSUB 1: failed") + testing.expect(t, result == "345123345", "GSUB 1: failed") } @test @@ -313,10 +285,12 @@ test_gfind :: proc(t: ^testing.T) { index: int for word in match.gfind(s, pattern, &captures) { - if failed(t, output[index] == word) { - logf(t, "GFIND %d failed!\n", index) - logf(t, "\t%s != %s\n", output[index], word) - } + testing.expectf( + t, + output[index] == word, + "GFIND %d failed! %q != %q", + index, output[index], word, + ) index += 1 } } @@ -332,11 +306,12 @@ test_frontier :: proc(t: ^testing.T) { call :: proc(data: rawptr, word: string, haystack: string, captures: []match.Match) { temp := cast(^Temp) data - if failed(temp.t, word == temp.output[temp.index]) { - logf(temp.t, "GSUB_WITH %d failed!\n", temp.index) - logf(temp.t, "\t%s != %s\n", temp.output[temp.index], word) - } - + testing.expectf( + temp.t, + word == temp.output[temp.index], + "GSUB_WITH %d failed! %q != %q", + temp.index, temp.output[temp.index], word, + ) temp.index += 1 } @@ -369,31 +344,21 @@ test_case_insensitive :: proc(t: ^testing.T) { pattern := match.pattern_case_insensitive("test", 256, context.temp_allocator) goal := "[tT][eE][sS][tT]" - if failed(t, pattern == goal) { - logf(t, "Case Insensitive Pattern doesn't match result\n") - logf(t, "\t%s != %s\n", pattern, goal) - } + testing.expectf( + t, + pattern == goal, + "Case Insensitive Pattern doesn't match result. %q != %q", + pattern, goal, + ) } } -main :: proc() { - t: testing.T - stream := os.stream_from_handle(os.stdout) - w := io.to_writer(stream) - // t.w = w - - test_find(&t) - test_match(&t) - test_captures(&t) - test_gmatch(&t) - test_gsub(&t) - test_gfind(&t) - test_frontier(&t) - test_utf8(&t) - test_case_insensitive(&t) - - fmt.wprintf(w, "%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} +@(private) +gmatch_check :: proc(t: ^testing.T, index: int, a: []string, b: string) { + testing.expectf( + t, + a[index] == b, + "GMATCH %d failed! %q != %q", + index, a[index], b, + ) +} \ No newline at end of file From 9829a02571250a27b81e5560e5c4add4df3b3f62 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 00:12:18 +0200 Subject: [PATCH 51/93] Port `tests\core\odin` --- tests/core/Makefile | 11 +++++-- tests/core/build.bat | 2 +- tests/core/odin/test_parser.odin | 53 +++++++------------------------ tests/core/test_core_odin | Bin 0 -> 1401192 bytes 4 files changed, 22 insertions(+), 44 deletions(-) create mode 100644 tests/core/test_core_odin diff --git a/tests/core/Makefile b/tests/core/Makefile index ad8209b86..2cd7304ac 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -21,6 +21,7 @@ all_bsd: download_test_assets \ match_test \ math_test \ noise_test \ + odin_test \ os_exit_test \ reflect_test \ runtime_test \ @@ -86,8 +87,11 @@ net_test: os_exit_test: $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 +odin_test: + $(ODIN) test odin $(COMMON) -out:test_core_odin + reflect_test: - $(ODIN) run reflect $(COMMON) $(COLLECTION) -out:test_core_reflect + $(ODIN) test reflect $(COMMON) -out:test_core_reflect runtime_test: $(ODIN) run runtime $(COMMON) -out:test_core_runtime @@ -102,4 +106,7 @@ thread_test: $(ODIN) run thread $(COMMON) -out:test_core_thread time_test: - $(ODIN) run time $(COMMON) -out:test_core_time \ No newline at end of file + $(ODIN) run time $(COMMON) -out:test_core_time + +clean: + rm test_* \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index f77c4adfc..418908884 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -87,7 +87,7 @@ echo --- echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe || exit /b +%PATH_TO_ODIN% test odin %COMMON% -o:size -out:test_core_odin.exe || exit /b echo --- echo Running core:reflect tests diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index 821b7a53c..772ae5982 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -1,58 +1,29 @@ package test_core_odin_parser -import "core:fmt" import "core:odin/ast" import "core:odin/parser" -import "core:os" +import "base:runtime" import "core:testing" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - test_parse_demo(&t) - test_parse_bitfield(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - - @test test_parse_demo :: proc(t: ^testing.T) { - pkg, ok := parser.parse_package_from_path("examples/demo") + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + pkg, ok := parser.parse_package_from_path(ODIN_ROOT + "examples/demo") - expect(t, ok == true, "parser.parse_package_from_path failed") + testing.expect(t, ok, "parser.parse_package_from_path failed") for key, value in pkg.files { - expect(t, value.syntax_error_count == 0, fmt.tprintf("%v should contain zero errors", key)) + testing.expectf(t, value.syntax_error_count == 0, "%v should contain zero errors", key) } } @test test_parse_bitfield :: proc(t: ^testing.T) { + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + file := ast.File{ fullpath = "test.odin", src = ` @@ -78,5 +49,5 @@ Foo :: bit_field uint { p := parser.default_parser() ok := parser.parse_file(&p, &file) - expect(t, ok == true, "bad parse") -} + testing.expect(t, ok, "bad parse") +} \ No newline at end of file diff --git a/tests/core/test_core_odin b/tests/core/test_core_odin new file mode 100644 index 0000000000000000000000000000000000000000..bdf316228a8bddc5f4a0998789b00dc1f182e9f4 GIT binary patch literal 1401192 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 z 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
m48_I)?Rx1i0? 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ñ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≶hAgq7v#(}_X|98HG!E7`)fd%3v{yIiwW(& z{vT^mS%(@2EDWG~ej(x0P{GVlsstKW0cSPn+Jh2-E{HB3(8g$xc32oRR4_6iWI>C_ zK(apFB`Ou5f(&}ae0PWncyD$AsP6>20LmWJ?*!T4)w_oUl+pKrvbm4uG0?6u(CSD~ zXA0DM19h>%eCUQf=vs_9U_W?vKJe`W1yoRhn$9qnL(&Oo;Rs9wl1`wz`MM#xUdV!1t3U#$s|UQ$1U0RMLMjB%APK0X z2VdU_x$_FLn;2XffKH?a6-F5#yTAi{psmWFRtKWn2pVl<0nP(1=V7#-XRbqAfh!vxxI z)B?TcXAh)2@9Y6rGB%*L6S#rj0xD0f* z7r1bR9P-`(uRuU<0aqZUAYX%cunGjsMyf!-0|bqGR6sN+A;2mSD^MdI6bK&OyeyxP zllilc@ML}(%tWq3R<^+E5Ku=KR)-YZLh2Au7YLRCKn`iB0M#KoA$5qm4FiAcTCjIO zM^HiQ5DSmy7kvEflcC}kpgQCMv<`v97Tkx}s*%nqpdu5$LU2uzFa=T`gPaJiNfg1m zxA5x(*HmgmSOKn2{!T`-Vjs9ZA;OBolL`9*Y{e`zD_+Neayuj%A!!7?p$qmxG7;v3 z>lQ0?^TBlss1!ksR#4qC8(I&5A{th=fK-A?I1ml5TZ%!s3S7^Fy3-za4ST?sKS8S*kSw?W25(pac?VX_fY`8VCIGpb0de5f42T1-W5n*QFZ@G#j;?Z2801F8Imfc_(7x1k-phNK( zJfNi!xJ6rT3Th~TTeA_%L9N+iEh->YNv~y~to+wPP*&Az4k)VvG#LxZC9r{~aH6v2 ziGJj)KLvcxNEgIDEZwMC{Y>EFjUYo(po%I27KxB-GY#xBNX~#{8|Xo4&>MeVtN`C| z0a4J^qXJTomUWQM_i20sN>0#GUC>cXoi!>J;QJ=s!4)#7n+9&df$|-w5(Xbf0UpT$ zZ|(>62Hio!i2Ai4|ElmHD8g8FhDEs*XTXvGJ(_r=CgDhldLfh573 z7bii^6%qyoA=pXa7P5zuT z1aU#;fh+;(0oA)8OF=Z)QpkMplS@n2FZd}Pk~(80mJlz)Xa2et@Pt+xf6~D;ehuEKLc9!V{4odlHBO}QiyrvIA93)L z2ftR23djqe_~QCk3?-VMKs!f4LTMiSbq73lf-(vN14Dy{;fXX4 z{=5TlEub_K0d6F*sDK(sq|DBN)PttDK(qsRMh$XY1Beg0cL79$=4e1PxGkg!IgAp- z2d&En(V)T$M1zWX#4TW;feUDN1Qg<+<~7IwP-zD0c7P@xKw@xTf|4XCwd_g*-vbJ| zrr+gT@CqyFrDc%ux*8RM z&JysLoeaoyg>DxW8N?g}==@dC9UqWUy5tf)@F<;3^NYfgKp3+KdJMiy^NTX*G59jg zFUm^{UMGOcF$KsidEn7u)M3@x-Jpp;&_$%6xzpDnAnzcn1`obL#%^EKUk0f?2nuHo z4`z=7k4}$**Giz|uiyf5GN^C|jSWk9B!4ixv=ek-`3unALh!+hX|VHRKrsv|iWOWs zT~u^H{xtwiTUmfcD;+vOHv{{3gCx3rR1Cl))7>SYKm^Upb?yP57Y$Ng0h#_0?+8&T z2bq!4>7tU-d|)%=0$z#c7rOlIDWH`K-Jp!n&2sbtxLyPW2KeYG$W$Gud7#kcq9X3m zEvgyK$Kcb=D;3Sh0Pgm9bUyR}T`$)u2fF z6}))Di4kJbr$}7B16}R$;_<8h|6hV`D8*ya_DFCzt-xs#=6q>i74W6l4xsdG(Ru7e!Jq&CUpj-OT~sVOT~rd9Yg7^#ptDM) zf{itx17`%_XUT|yhMN?+OQ6QQxbW=%|JOy}>;Nh;KqVOZsQ(K1?1ynXXmlBrs6oja z5=fmF!6t%|GkB6Mz@wXYaRfMwrbO_8PEiD%9TdO;x}6;qG=?W%)V%!v|7Aa@r~_pe zP`d>!Vf%FR8i0*pRg8c~*dw1#A^vR_njbN~IQ{Ma|JQ+_T#qeV_;m9!L3Do($ELd% zq#Hb_j}#6kK-U*R58Lu+d;=;MT{?YKOh8R9Xf6khi~EBHJOV&@8QdTQS4yBj?{-l! z0l5b>59bf^5#%U$P!KtQnpofxxf6PFQzvA$5>gnbcT7dIW|9F+zHMxf16e0{w zhZq_`z)*0R5ezcao(MyQAcis%Fcj?lf1twg6*#Nn_x|2cu=m%6;`ctdBv}bE6f}@e zD55eThDH)F6qIvbgn$eMHMj^Fsthqygcw8rgG$fW(9D?79RfdmFA5(0|NpuQS+6ii`b=H6;HNo?Zpq?0{ngboy+zp=X zL_gFEvd{)pbb`DF9yxRdxfy(*C}gz_OcKrCFP=7nS|(G#ccFq>k)X2I1AZj{xY_{Q z3$?O42t3Ej0cy5^+OQxkpvEwW4=IOWcM$Y|n{1%K0-yN}lLWVUL3_18v3VTQBnR~m zKn8&hNdmRFLCtfp7^sH?QU^L`1+;A!e04bMOYkT#WVW{ld>;X5VNHt)=!|F3zz(RZ z0b6;i1@bq@Ja}IRWFBZA6Nm;+PeR=AdJ8vl8fvo|r-GD}q3kPVN36y~w_Nag< zh=Gum(jWl{pXoIpvIVbWVWz_ueKWmw2Q@kbKphNFw0600fcBH0hQt(@f*1uc8YBSW zGri_PF`5B1tOx3BKqG+}x_7b@N@GbPFLOY1?%m*aeUA$0{96ymsl?#nPH@h%U?>SB zGUMgcL7FiN&~ilrlvN<*3aB=%c%l6O)LsS^3DEmI8Y-9=_*)M`Ll?AK6Ew#FT4cuG zvKlIC&|m?(ql~`=G~NTM{K1_+ko(Zbi$V8Jy)dqYIRw(xDN(6-vHt%5|4@HG76^el zmf$`r=;FI+7m6X7mEf1Zosy?aph^;iRB)^DyZAKTxII>7xQU-?1}9MF!MH zQuxF#2wL0H*MTLh6oR7Fcoo~>-Qz#9-9~HDaA3E{`nXUvG0vjp^tLUv!DFdwtGW@oyiIIWf zg_g>%|Dd%%5X(Ukr2z6dN0*BV_~_gO@X|7nQc(90ylyN5lftFclC42V2iYQQzJphzd zd_ZS@gMz3Ve3o&DO2iAdpWxM%pg}y)>JFs)tUVgvSb!35XN^h#I0hgWu5^Z|(OsefH@Ze8U}ri51B2)B1E6yeUtIY6|Nl!*a97kv1-o*{ zSPp2U?ZqOHYH7TxQ^6xYY@iXB5|HY*pp*e#iq!3+5&$0If*iID8f^lV93UE0et~FE z@d=_q^(lx3Rh1wbl#4)R7HAX;R2}jQFoI9!6$n(|7l<_A7f5vA7sw3Y7br~d==LlC zg%wCCzvdPdP%R5SZVgmxf{t4Q({sSfroqRpf%%Zdm~g8=I}{ih7>+rDhKwMWm3nkK zf{R*Eq#Sc(W&|Za2%C`sBvlt(u!n-{p9_}vq9-!|x|d(e;+ z=q5DQKOmuQ-nSqMbap!^w^_UfuLc8WdGN99;A^i6K&1nC1)_!F0q`;)ln(9cTc9%3 zMJ0e=15###_9%eUlExJ9G0XfK&;+2d1l(%k*H{Ct#rQQK2?i9opacXOoZ=TONZ=RD z2;dh?aNrk=FyI#qP=KDb3u(+2beDkgZ;eX83!&@aG60m@52MT{fOaB)yRMx+D&X5S zJU|r&q~qG{qT&L|{?LryU83RvDri9?x}Z|P16*`Kwi|S|sMvtH(A$+dA@{d*wy3Cp zghBg=K{R;A7+f1EKrsJX*hb z@OxeZ9aOD(%!A+O5Ga>|3II@Ig{;4av_C;w!Te5G&Vyd11NB}*1qVZ^5vc754x;9Y z0QhK%O!FRaNR+`69QScZ&=f*;e1k%%(?vz5`9%bOOCu8l18nHCkiSI|iCc^qA1y0U zhAArNZ~4NA&{M(RV#mb5@Nyz}IG{xZl4 z1m#hL;obQClmW5_dRGD{L4az2*Q6Pt3N-@K34@$DN}>^uiXkBj>WzY20jhUi9tV#_ zfUc2%hb6jS4tgT30S0ftaNq##Nnv1c+yOo@)^jbyU{J{pG8j~tzsv(=MyQ#P9i`xb zC#c9V2gtGtP&X7DlgC|DK#LW?li#3Z0g6VDB!BNuP@Mo;>;s~~%Yd3|R0`m^!k}Rf zcu0$(L=DumLc|HUoPe*6-UW_u{UT6=vu3z}OX*Ay)d^lv4;spZ?vn86X4MC& z=;k#5QE-KzRvLJP5!fzBIpCvGz`u=!qw^RjT|j0$u$0}7piRjPFJ4{&mEbMl5ja>9 z1Njxy#;Je^xTsXT{P+)i?g})-x_ZFg?C@ZEEe2{{h+}{xc+mO{{Mf;i&g(_i2gO``a$E0aQ%HC z{h(ex7XL%^=b-Bc4I#qy`+@ZLf^u3nhW{b@bntd3fr977@;p$v0qPPV%|O69@sKN8 zeY$xC9l*tk5Qsvbhv@WC5rL!;kjo`rJiP$vc`M+u{1(V^P}+E*1+yHUA;D8=AU}g= zStCHD0LV{1-MoGFASa0SgDCJgCFtHx$h=%JAsda2f*C-|`WRm9$c1Dj@DUUq9*svp zAr8CG1bqJ;sEgQHgJp9VNCGy#0KRYm(iQ}_)Ig(*$6ZuF84bJz%HV}RFC+NsR`8Y+ z@O?hu8(BaT8x9_wl^hOj4#5EX&$5)~Oxjt1}G;NTZv;1}=^;1>u`;1`H6;1@`6;1|dU;1?)J;1{SU z;Md#(-D|uBy4QFObg%Ie=w9PF(7nb}z2BU-9Bj z5NPzJMn$39M@0ryoe6-HKx%DR)7wD;BnIl(fU*)qJ7mxCi`?}L3@^QyK@DS2VIlyk zQXmNx>L^gZ!Q*%f_}&VzLwfh9fW%&0{sXGzd%zsfuo~#n5YV}Opu!z~XLk>{3lCb= z1R2@<4>F=e1ME(agQ1ZQ>$pt;U-kW>;}dA=7`zY_Pr7^zDnW!mV-+tlA?Xs_E!|L5UecL&6heBq%%~ zTBm@oRM?pba*xD11_n?=2|Qx}%9`j|szwf06zM{p4r(%kECRKEUxGHJgK`Gg^Pt(2 z?h+N)t?ZyyEyxp~9x>PxpaUX7mO6uXG4w$0NrA33>4G$*L6rh1?SV=LP({$u0&Z); zTb7v+e?s#=dRGE;zx|7=>7dypu!CB_Cj)?@9Ap-#p93-*&5JKWG9YmRZuo(AIlTmp z!{ZGVM1+ciHHWA`svvMwf`$g+TP2UXs6aNF!ebC54a*WI{ZXS2w3`BQ5CACRz_%E| z2L2%Nm9d8C_^M3@c?;GGgNz{{imw;vj)B{>&@vHxA7A5}3{W4W6SS?k6V!PJZ8-(i z<&c?hQ2h=bsRVEEgj5fpv0L!T4V^tIpe8RUVSq}o7w`Q*J_8$a2-I8z-_`>eV}PE2 z09rT*%7Kt8e?i3^DA_`kfY$wh%U}tlGMK-m8(c_%jPn2$0pRw81it_izkrtjzd(=z zzd)1$zd(`$zd%+1zd%s}zd#kZ42BHOK`v1T4bnlz0hfTY9KYrq$XJagV5_fQ2z`xRwn=&00#vW_|{Pgk6y@)Igrhq9(*8ggLY_lLxf+jDKdiA z=(K>dO)qpx=;I(7mObb@h z&FRt2a}dz0Cpg8n}!H?J@+7 zx#PSXDGL{00f1x_bq5g};Z2dJ0<6=9%+1S--X9ev1}Y>?+2Kw~+bkei~rTOis&hkJpH>4x4C z4_(3yD(XSnL9;xd^awH@bc`%0=V^eA*#bX-7IYvj$Xd_=wVf?0JRs@rJt`n&FZTID z8atq)UO`R((}>1S1uUb1PWu5lqxl76i6p3Kho-#d7vlUapsBEz54af^T)Ls2?uL50 zdkW;-fo^Cy4mv0pWK4I6N(H}wlLII_fzD4w&#jtsR6s|Zf`-UJr`LgUALxWqkn#9m4Io;L3yAM11&TL50nVJ@csAy|4S8a z(5bD^GZH|15n(Mj%^nqyxo~@rw}6kR1J_%i>vceVOR#@hRKOwE&EawIAv5SU^@Bg` zL1Eqivbhs-HWDb#KsLXyJkH6`aS$5A9X%@bObiUoKa%*TKn_D{_z5~Spq#&TF=X5j zl#H5x- zf{GUCx>!?iDav_*zvUfhsP!l)hU0|O&S1bnzv_ZEms(D8~)3=A&{moR{eA5d{~7_@2v zrX75`B9cR2x*|C)t(zgOvqdEi;yh5&V<-_x>xPJ=9X!B+Bnyd20*(hQwgfpIWFp9^ zVEzu!&MBDV!TTAyVFxflwp+Z|vKYzn+acD2v|~6PoDiTP+sy!)gg|z>KzECZ4HE+c z{|ST)QO*W6YeCKiX$IK~=I;PC$6?L}bqhi5W3UWp1Q`_Oe-|N~4YeAi8^hI?K#drv zt3A3IKx#m}%Z5GR+|Ez}-v0m+@!$ua0|sI?!14}(5C?B_05uvw$pkk4y#q9T26H-S zX9mdWV3pldz&jydI3YP5lm$Ung4~7Sb}_Kqdmt4^H={?lCwQF^xVH>C)){gLASCIi zf$}Q2iwrt_9;A`~ga`jgP}zs3o~T#>udnZgY}Ew04b0yG%H%Mwf%ZFqyatx(o&w(g z@FIO7B33|NgE**11>ywQxuPv9Ag{g#Zvoo@F1C63b|TMAe%Jw@nY;>SGVK2bnwb;@ z^-q+&L5;XQ;L}!LsJVdZ&4VDjV6{4Af5#8lT96Vq(Dp2dHPHD;=yo8GCQwm`-s5-_ z4QiTC0r%QLeh2N`cx?kKIbga#{T6Ut1Fogv8Op&IPb z7RZ@(sCsr)gZ#BS3N&^G*^>gA^z`s(KA-?%IDi_lpxGqDZ;;~y7@0vK0P2nO_CQWQ z>jWKm0^>9v)BqLO5gyGuKw%=yLwF68j+t`zX?c9ih#_Ehlc z1Yt)BkIqT~SR)fM-v_c7<0u|aK7FuQvT zq-p|f<^W~6?kSMt*Fc*gLFQ?G@{l~i-@F-Ge?Xd^pnL%`8Du$lG@}zT1_6pkP%;F` zgN_pg1(^jXsesm3fIJLR?Ame4@MPyXM^Gd(xO80f==|=(zx23E$3@S}4?s1Ph2ytF z4xaq3KYaLIk9jt}1lLr}w-`J+KY8*yUGU&{`tG6l(L?b9sAii2*>c7D@;1n|&3nL; zh42X)JCNm&bP7o&Xz6kn;uJWCNJt6=H`_r6pg~FkP@ppKw}6Mmdt1O`R*x@fgT5+fjT{g9^F2M9BAS2!YKmcdr&_Sl*1t7 zC(v0_=n_UyFZXr%OC|6ng~+x+Vi(e!^ni43A>%HPFb73Eh>vC`WKH(V7>LE-!5iq# zSx~rwEQ5s|m<>yi&5$I>=+S%uT=Rg_VK=l>33Vwbb-z^n3+nEJvJ-Lw@IWgjYC*-s zlrScEVmTKsOV4tb>AT8)*N?H0Zk$>fI3kM9^DQK;6rR` z9YI4j;4Yj3x^>`F6jedifp@-u-3#6V16s-mOfXWhZTy;Wv>Y%}C&~PEB zECDYq=!6UjcDAVe0Vg(SB7+uw2F*XpVY{z5Hbi&0sOZ1u*ia3o!D~q}Km(MZEt>kE zv9(Otv=T1}=C3M!64!$C-A1f{$NjrH0fX#p3t3MjV4cDSg>zvkFb3#Jja zfwl+9BWW%0=!V<2F9aN`pfcw$C`o}G)a?-fIcCxWyw4OQ2AcNcZ&?SfQ$SZ2gIYGA z!UQd)fabbhWP!|tDF8({sLcQlD_9BWp#U{s0aP4-MmxdfENEvZhyhj$3IR(je z@QT73REgvC9-@|zf_e`$E&(zO)OrKQ0w_A55eVAH*Bt^`(eD8YOOQ=Su>-2lz?~z| zfq(F|2ghAh3LvhBE%$;Bu~vX`aRDf6RlJCv4(iN9ybTLYu)mIF?&fz++#ah8f5(1_p+m(ni7HW3xaKjypi2FAly2#cU5mZTA!v4^Uqla(@;m zdxHAGAZLNv)*X;Lq+mBK@wcRcFXn+Y-1b14!`)lJw_3f}!32~;6~Dgwg;pyd*$Uikd}`F{mtsVYbwBn}$o0X1ZHnX1F)NHifz z#J~p_fJ4jhfJfsIP_!S0i!p8hjf{fD5J3g4vO!HPu#>hxoCG@57BTGx>J5O3G4Mc| zW(#=aY^SOgB=|tXXpm;)3n!2-L3^0NZP+a;pbLvY$q1w$lvpA6JZ(_{T`B|$PteF4 zC_KS;1c90zAbrPMR6t``kX#61gGQ7=dZ613`CGPt3-A^dumPZZmzfwCx>z_^9`J8F z0WuKOdeadoF9ul-VuO|qE36G*`2PST0ve_~=D^7KIuyLcni3L2o4|6%ob?OKyoE$rg00jRSIjh?tu0Cp|jr1VCXAa#M!~E661vCPom0+uERe7(j6Xbw+~?haPNXuH_AQ_7UM9 zuqlwcroc>4&k&>+w3rt}gC?RtNes54uM@iJ4!@Vdqj$&yp}l*+U8NUlDf~b% zY>clNj<3#i`JfBJx3#E%XvB`Jd7!)8_Nag;=!GV% z@Ecu0T0z&EfFxnpnt-lno{)vB0l20Skfd3kLZdG}cdo51==? zf@}w0Zqm*IKBODO$9cI)8{}@jR*-ewEs#slxAmxiv_j6Z1#dY61v%&ndsvWHARG)5 z28At12o$EEumv5Y05-4(d;uaT@qvUv(kMX=yU`UCZjf6}@*z$JQC2M~AXh>5PJuRq zft+g9q5_hG2tqIDWI0XYm7IzK=qBIv4W7Wic-V4?0F70@w0BsvIG)AxX9 z@j-bH+-U>d%LTFnbYv_u1o990uOe8h90IuMh&@Pg2xybUxIdDL7m;%q5>MB z1D)Zb@fvh9F@#rKB8A|APGM%^ZvyQad3g`)G^kTRWe~KH2yzOjp#|=u^+L`}H2k&; zwAlQ`gf~C`gRF;iX!bxlK%jYDuwKYvG@$SYb(laM8BqTMHg$_-@tsGvLjlMt&^<`VF^k)VYipji{p)H7%n0W|dtnrZ+wurGjzKYAb+iGUW6LT0sn zIz0+NCoO@E6Ld%bvB5?PIs|~&prwlZf({NKHpmEmfgbQVLi_@dGmiNM=75iSLfhZ- z;?PP?hL_8seKwHSKwbrn)F6U{!K0hyghzLU#0$~eprbYqf>I%wO~9K>K;q!U0-N{;t#Sv&AZRWd6#Bh;z@x~p zn0odKdrX1)@!<9zNDt_|BybQynx#a<6lgUYD5gM#FDRxU*TpP>E|;7GT`oBVJlYS6 zDbOfCD5gN8p`czANI!Uo7G!5WET+K5L1PMRBs8W#a}BVV0vQ2{DX@_OP%8wWRtlo* z#CjpIf)l!r`8DViQBW7J1JW;sb@LGWu|gfg9m5<$9YcaaCyRh?i0)BY0*d6$Ju09% z4NwOhBS1$+;BC*;a;(4v26 z!Qj~40(Lmkh=?92szFJ-dka_!WEsek7v&4U+aEv|%tt%MIL120ImX9=2OL4OW(^gA z4E*383&?XI&m*6S>a#_?{%x z8K8^FLFEnjR`SLpXud~ys|OlGQ&hka-VK?H>vBi{9n{#O;tq-j(BKst0|UB4*V#jc z5-mV#I$Kl>Kr~dXNAm&jr9YsVvxYrjV;D;0;IRhZy}`X9x}!y9Iw;?BZ>WYb89*rn z66{k{Kt_NLNCXF2j|wOjAcxJv2a-$eK*QFMknunpKn5xAa$o_C$sjuqIy4NrTD_}9 zMV}44p-&z~1!ABW=7CaU(3lQrX+()8!i7+Kv5iLGv1MX_Y36Tv30~;~Ro;y-9@>Qm z-PjIFW}sB*(e01{iaqd*B6v!)1zgU6W<^04a~giz6#<$UdHobp^num&_CPM}1fAal z3M?4E`CtI3Xa-MeLZ(LD+2?#uw(^?ygw`Wl1dQ8 zPy!xC0o_9c$}x~}M#OdZsG;N`0rHsx_@X1wiE5BLKN~6%K)nVPMjM6_TaY1;AO#(= z{{pljNB}jw!6sUxnFv0%AFLa+ zNtu9&pyU8bZ44#Wpq3QK76$(5kk$@yX{y5-vOCTIbQ2Y*W;@=Zq5)%r=Gj1jVcDVr zlIL%Z;sgy_LU^DAr2q+NuoFrHKu!ROz?}e|kA-ABNIFH!^GNft8$j*=?V14D2O1;< z(Z^dq&Ken7eyVE2RKb_-<1LN}!T0!0@n z!+U^p7kDIH;l=gGpy42hcOVi6K||~ch%yi+H$?@Kx*(|y&Fe4rTY<{u7KnwQDU!%ZIDpyh8wW z1V(7TioXTiqkvYTpppc1bv)P-mJ=S}w4nehut4k5p`|`(bOc-wf>iY)#wtKfKhTYE z0U+__gWz%wyjlQKg7cLcf)YDe1azA#xCGw=S@7O1?$KS&;n7_$fWES23Rpo`iwfxa zWl#lwz@zh_2k4ka@FE)q1_mP!(1DFV_RTg3X4oYQnhW{E4%*8LYT|hA6b7X=1_t35 zo8N-21%PF~7RU$-=%PuGYrChYfP4iCrv?xo)O-WeEh><)Dk$CAq5>JAfzjag0uCUh z-Fv`NFMfYyV6b5T?XiMJ9yG$yBTF9?S)fAjg`_zsvZkm&hFMxvK*KICw}P8t(5wqD zD|*0pwt#{WxgG$IfOhj-1TB;Rt>OR`JfKB4AZPKfKLrv7-9ZQ%nuN^Yf`==Px2Q-U z| z(4gt*1E@FN+oJ-eJA1$jj6mrK%m*KN&;#x~K^IE#lq!PU1nO{rN(o437dBG`KLG(E z0IKPk85mI0jW)=e*wPIv2bOeG{TemhfL+zuq5>KEfzqJ0G$3DqW~IS2I9-58u)FuD zfJU@mJbq7Vx?nVgq>CFM6G7bu zx2Qnq9u-hM3Tj7y-HAvjpwSy>)PP57Kyz52QUzLogTz1~2#N%dQjp0YF%Tc*Q`o9< z$Y9VG@E{P#77!nnP@YwQcA&uu;}U|kD`GLg8)HbIfX9+R<08<#Y>-L>R@8&54p15d zWdUgM52|=xw*3UH-~l-mTIs^4ui=id1*LA}@*7FD0(7!l;f2W^TvaqI&qB&*ND&HO zceo3@IH=qRsd^>B^Y4uyo}U4V$j%m(32@JYnocm!gW27XCKgN#)ZBVG0d#mL_(%e% z=i%OYnac%fbb*u6@fH=(-1UFZRgB;oKmb$&fTp`)aSNW(KHj1Nn$iX<>xQsl)`7%9 zlW-t){Jnf!Nd0WcMnq7O1uN<{^5{H|wy$K1N&(n|kQr}~-QXE;(5=GEke1r978TGu z00XEq4V~};t!xJM3>dn&4th5bWQH3q2Huwmn(YQ9DUiLO1zyms2AYNk)vDl0^W%^iesDGe ztyq9M8LYLl1w0E6G6HNos2dBJ*$24*)N6$BK;CibSfirH%)sE%u|!1|Oz%O8TMMV{?e2nBJnI4AM45 zMF~Xps3?M{7RZVKSSbWr833;2Tfi$CKw%AD-~pZIg^h*Xx(?|Of|DMo@d4JeMFliU z2`V>0dWabN0?l=T#=bz)^PsUW$n^da@bo^YI|rJ{1a;>i8&n|E$Dr^APeXU_0Z*4h z$G*UWhMg7QQA)6J(6KMDkQ#cBHpOB?3(MfK&AgiM#(n z21usv0hG8mI1oG~4O)N$3KGy%J~%1D zdL#@W%fTfPXcQSbZvh&!1I=H&V17Yr{jLbLH2`EAsAUP-H4_V}v5-n9&}cKbblMI& z@{;`03A9rklt@74fzKBLbz49+I_&CW@Vyd{6>muDU}sW+2kSLkAX|Y!r4wl64x}Aa zI)U5|ax#<;x-kP}1bB)9R62pyv$UvyTmUMaAUu$Fz@-xtv~&W~dsKA5^cEFuCTQsd zI=gU=iY8ci4*1#)aOni*_o#pxn=TzKDym@RdsI}w^cEFmkhUo*N+7C7MG-_n9S?FS zsG|wpIM_7>TxdCTZ2^~IE?qs~BF&|13b=%G>6!yB@w(|GDL}g*0k54ce7=ux=_iqswzeNgGyqXM}M zrU$av3N-fy3efHzNO9i@o123!=;{QmV1$ZwdPsoMCS=ae19Yw`$fynv{w|0W9UgpL z5U03wIPk)nj}9FbJfP$Y8glON;0BohDuZ1*GPqni5;$EtDmYv^3fLVwGT1sISY0|I zSX?>+m|Z$Nm>fC^7(2ilXOX)hkgNgehJea`&}tOT7VumRXo)CjlMT2+1I<{%k`L&b zb5QbuZOeg91H#%FAU&Yw7-)(KR2P8w-90J+%nS@K7Ue;jETF6nDpf#hXS#a8DYT3r+{M~6t|#+0Ez}sx^U@g0jCpCT!YdLD6YZjsB4ajIw*BQl9@x-8c4G1+M=Qb zN^V_yz^M`x*WgszwMIo3q`XH(50t)oRK9`i>`~E&@V-K050rI4Z5YTB)gBda_5iJK zfy#rX*F2!H310UDjZLunPH=33jDo}_$O=eof;{Nbk-_WIk-+29QNiufQNZQUk-^y! z!Qs*o!S2!#z~<87!RpfCz~azR!R*jcz|;}I*ueoS&`D`@muo=EN67vl$aW*hH;WRft`xFuC+uB;z+O*(%2u&XI(vz zA$|`Qm^p*;PR*4IM_9AFN*DaPwg}Y31Z5w{(O51j8r?oBJRtW7fZPK)q8GG=+5j{y2%c009Z3P&+fV=s zm<&(=By{?y#30X{*@6~qgAYLi=|FESAdbb!R0ZXR5Eb}wLLdhp25phBfZGl^k?}qK9R{DA^P?C#7Fj9+;TJ;r{4LSoj!%t>!iy)| zpdExQ(Bo%dG-yZ)w9REFXod^C)rz98fv}ZwG;&?=S^?a>5JS z34{$?0m@*YV-7%cC-k5Q&`=VHk92tzXvf2goJoWY1eNw6FN10L(YlaBMnGN$6(=Bh zP&x5pH$ekKR4PF6T>;AE8K45X0934icS;nzkeN)#J>V-KKm_dI@(7T2@KL-GFKUsr zgEvXZH2)}oX15Y)Xd;1KOtcHMd*sEfb^rgrHU?#W4^Xis15yMo-oQr@g3oPq0M*N& zV#62Qi(pZCG4&)O>7}8S?9mbAdLujfh|j(0(Jyig$UVe$qTLvr>H>YyjxU2bKuQ;R9Zk28?cRiS)kMbifp*^ z(X6%tl`Y9QtOgl{)#^#mdc_0mnHCk$WFjG(G(k4~lmTxk0wqK6ni@#pgGcN^fealw z0ga-9#)rUzs`&;ojwDQJ=k z)K_~^0tz%xg##L&0PRo&(TztSfe7`HgA+dklKHBy6+ta~&^$OO1Aqb!Q(KrUZQH9y9>Dr$7Rtw?_oz>mA@YfZRR^9_0s3y@1@(y$7Vjyr4^KnIt5e*f^|CMfWsfdC3w zP|WOvNPB$$2yy{P1T>rpqG1b3_**2w;e;ssz$pP|c;$kO1}o{E0+~qzt)v5mPiKn? zcw~6QwN18nBTnxJjV`7tDtas zF$olt&|m}|>(#IaT(mKisK9-WT<}0$0!>Z2ps`_?3&FJrXd@-4K%$pxz9qkcUmX_wE5tdcSzi0-9rn>@Wox3<+p2hW2q>^%1Gz>sEJrS`SJgYg3>(|~&d z5F^0M&TAeA-`RT{{3Qk2BA$5(qVEDo=>@QRwt&|L>;ifA#nMhr@Bj(KXD!fH8t8;V zL<!5faYUJ>l!-gEC3nk1Fu8^_y3@W3PT6+J(^z#m*_%tfV+j@bM`

#g64sYn}3wSjKsCx;T3Ixp-!sbHH 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 YU=Tz~J1{X2-5DVYq8Mb*G@x-A0P!{*ivR!s literal 0 HcmV?d00001 From 80b115748f319cc4d0d556cb89e30493afd92a30 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 00:27:30 +0200 Subject: [PATCH 52/93] Port `tests\core\reflect` --- tests/core/Makefile | 2 +- tests/core/build.bat | 4 +- tests/core/reflect/test_core_reflect.odin | 87 +++++++++-------------- 3 files changed, 36 insertions(+), 57 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 2cd7304ac..fa2c25810 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -94,7 +94,7 @@ reflect_test: $(ODIN) test reflect $(COMMON) -out:test_core_reflect runtime_test: - $(ODIN) run runtime $(COMMON) -out:test_core_runtime + $(ODIN) test runtime $(COMMON) -out:test_core_runtime slice_test: $(ODIN) run slice $(COMMON) -out:test_core_slice diff --git a/tests/core/build.bat b/tests/core/build.bat index 418908884..4eca48866 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -92,12 +92,12 @@ echo --- echo --- echo Running core:reflect tests echo --- -%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b +%PATH_TO_ODIN% test reflect %COMMON% -out:test_core_reflect.exe || exit /b echo --- echo Running core:runtime tests echo --- -%PATH_TO_ODIN% run runtime %COMMON% %COLLECTION% -out:test_core_runtime.exe || exit /b +%PATH_TO_ODIN% test runtime %COMMON% -out:test_core_runtime.exe || exit /b echo --- echo Running core:slice tests diff --git a/tests/core/reflect/test_core_reflect.odin b/tests/core/reflect/test_core_reflect.odin index a3a66f968..7d2394688 100644 --- a/tests/core/reflect/test_core_reflect.odin +++ b/tests/core/reflect/test_core_reflect.odin @@ -1,21 +1,8 @@ // Tests "core:reflect/reflect". -// Must be run with `-collection:tests=` flag, e.g. -// ./odin run tests/core/reflect/test_core_reflect.odin -out=tests/core/test_core_reflect -collection:tests=./tests package test_core_reflect -import "core:fmt" import "core:reflect" import "core:testing" -import tc "tests:common" - -main :: proc() { - t := testing.T{} - - test_as_u64(&t) - test_as_f64(&t) - - tc.report(&t) -} @test test_as_u64 :: proc(t: ^testing.T) { @@ -31,9 +18,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v (0x%X) != %v (0x%X)\n", - i, #procedure, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "i8 %v !valid", d.v) + testing.expectf(t, r == d.e, "i8 %v -> %v (0x%X) != %v (0x%X)", d.v, r, r, d.e, d.e) } } { @@ -48,9 +34,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v (0x%X) != %v (0x%X)\n", - i, #procedure, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "i16 %v !valid", d.v) + testing.expectf(t, r == d.e, "i16 %v -> %v (0x%X) != %v (0x%X)", d.v, r, r, d.e, d.e) } } { @@ -65,9 +50,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v (0x%X) != %v (0x%X)\n", - i, #procedure, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "i32 %v !valid", d.v) + testing.expectf(t, r == d.e, "i32 %v -> %v (0x%X) != %v (0x%X)", d.v, r, r, d.e, d.e) } } { @@ -82,9 +66,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v (0x%X) != %v (0x%X)\n", - i, #procedure, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "i64 %v !valid", d.v) + testing.expectf(t, r == d.e, "i64 %v -> %v (0x%X) != %v (0x%X)", d.v, r, r, d.e, d.e) } } { @@ -102,9 +85,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (0x%X) != %v (0x%X)\n", - i, #procedure, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "i128 %v !valid", d.v) + testing.expectf(t, r == d.e, "i128 %v -> %v (0x%X) != %v (0x%X)", d.v, r, r, d.e, d.e) } } { @@ -118,8 +100,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "f16 %v !valid", d.v) + testing.expectf(t, r == d.e, "f16 %v -> %v != %v", d.v, r, d.e) } } { @@ -132,8 +114,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "f32 %v !valid", d.v) + testing.expectf(t, r == d.e, "f32 %v -> %v != %v", d.v, r, d.e) } } { @@ -146,8 +128,8 @@ test_as_u64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_u64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "f64 %v !valid", d.v) + testing.expectf(t, r == d.e, "f64 %v -> %v != %v", d.v, r, d.e) } } } @@ -166,8 +148,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i8 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i8 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "i8 %v !valid", d.v) + testing.expectf(t, r == d.e, "i8 %v -> %v != %v", d.v, r, d.e) } } { @@ -182,8 +164,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i16 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i16 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "i16 %v !valid", d.v) + testing.expectf(t, r == d.e, "i16 %v -> %v != %v", d.v, r, d.e) } } { @@ -198,8 +180,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i32 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i32 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "i32 %v !valid", d.v) + testing.expectf(t, r == d.e, "i32 %v -> %v != %v", d.v, r, d.e) } } { @@ -214,8 +196,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i64 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "i64 %v !valid", d.v) + testing.expectf(t, r == d.e, "i64 %v -> %v != %v", d.v, r, d.e) } } { @@ -231,9 +213,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(i128 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(i128 %v) -> %v (%H) != %v (%H)\n", - i, #procedure, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "i128 %v !valid", d.v) + testing.expectf(t, r == d.e, "i128 %v -> %v (%H) != %v (%H)", d.v, r, r, d.e, d.e) } } { @@ -247,9 +228,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(f16 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f16 %v (%H)) -> %v (%H) != %v (%H)\n", - i, #procedure, d.v, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "f16 %v !valid", d.v) + testing.expectf(t, r == d.e, "f16 %v (%H) -> %v (%H) != %v (%H)", d.v, d.v, r, r, d.e, d.e) } } { @@ -262,9 +242,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(f32 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f32 %v (%H)) -> %v (%H) != %v (%H)\n", - i, #procedure, d.v, d.v, r, r, d.e, d.e)) + testing.expectf(t, valid, "f32 %v !valid", d.v) + testing.expectf(t, r == d.e, "f32 %v (%H) -> %v (%H) != %v (%H)", d.v, d.v, r, r, d.e, d.e) } } { @@ -277,8 +256,8 @@ test_as_f64 :: proc(t: ^testing.T) { for d, i in data { assert(i == d.i) r, valid := reflect.as_f64(d.v) - tc.expect(t, valid, fmt.tprintf("i:%d %s(f64 %v) !valid\n", i, #procedure, d.v)) - tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(f64 %v) -> %v != %v\n", i, #procedure, d.v, r, d.e)) + testing.expectf(t, valid, "f64 %v !valid", d.v) + testing.expectf(t, r == d.e, "f64 %v -> %v != %v", d.v, r, d.e) } } -} +} \ No newline at end of file From ed0384c102c97edc6c35f74c7c6c0a8fa15dad9f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 00:35:57 +0200 Subject: [PATCH 53/93] Port `tests\core\runtime` --- tests/core/runtime/test_core_runtime.odin | 43 +++-------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index 786cf003a..008146dcf 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -1,43 +1,10 @@ package test_core_runtime -import "core:fmt" import "base:intrinsics" import "core:mem" -import "core:os" -import "core:reflect" import "base:runtime" import "core:testing" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect_value :: testing.expect_value -} else { - expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { - TEST_count += 1 - ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) - if !ok { - TEST_fail += 1 - fmt.printf("[%v] expected %v, got %v\n", loc, expected, value) - } - return ok - } -} - -main :: proc() { - t := testing.T{} - - test_temp_allocator_big_alloc_and_alignment(&t) - test_temp_allocator_alignment_boundary(&t) - test_temp_allocator_returns_correct_size(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - // Tests that having space for the allocation, but not for the allocation and alignment // is handled correctly. @(test) @@ -47,7 +14,7 @@ test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) { _, _ = mem.alloc(int(runtime.DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE)-120) _, err := mem.alloc(112, 32) - expect_value(t, err, nil) + testing.expect(t, err == nil) } // Tests that big allocations with big alignments are handled correctly. @@ -58,7 +25,7 @@ test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) { mappy: map[[8]int]int err := reserve(&mappy, 50000) - expect_value(t, err, nil) + testing.expect(t, err == nil) } @(test) @@ -67,6 +34,6 @@ test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) { context.allocator = runtime.arena_allocator(&arena) bytes, err := mem.alloc_bytes(10, 16) - expect_value(t, err, nil) - expect_value(t, len(bytes), 10) -} + testing.expect(t, err == nil) + testing.expect(t, len(bytes) == 10) +} \ No newline at end of file From 9ba02e888ddf5e448eb5f2463070f39d183be052 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 00:50:58 +0200 Subject: [PATCH 54/93] Port `tests\core\slice` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/slice/test_core_slice.odin | 136 ++++++++------------------ 3 files changed, 41 insertions(+), 99 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index fa2c25810..453b84dbe 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -97,7 +97,7 @@ runtime_test: $(ODIN) test runtime $(COMMON) -out:test_core_runtime slice_test: - $(ODIN) run slice $(COMMON) -out:test_core_slice + $(ODIN) test slice $(COMMON) -out:test_core_slice strings_test: $(ODIN) run strings $(COMMON) -out:test_core_strings diff --git a/tests/core/build.bat b/tests/core/build.bat index 4eca48866..9a21d6b79 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -102,7 +102,7 @@ echo --- echo --- echo Running core:slice tests echo --- -%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe || exit /b +%PATH_TO_ODIN% test slice %COMMON% -out:test_core_slice.exe || exit /b echo --- echo Running core:strings tests diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 06329ddda..4a464503f 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -1,56 +1,16 @@ package test_core_slice import "core:slice" -import "core:strings" import "core:testing" -import "core:fmt" -import "core:os" import "core:math/rand" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - test_sort_with_indices(&t) - test_binary_search(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - @test test_sort_with_indices :: proc(t: ^testing.T) { - seed := rand.uint64() - fmt.printf("Random seed: %v\n", seed) - // Test sizes are all prime. test_sizes :: []int{7, 13, 347, 1031, 10111, 100003} for test_size in test_sizes { - fmt.printf("Sorting %v random u64 values along with index.\n", test_size) - - r := rand.create(seed) + r := rand.create(t.seed) vals := make([]u64, test_size) r_idx := make([]int, test_size) // Reverse index @@ -61,7 +21,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { // Set up test values for _, i in vals { - vals[i] = rand.uint64(&r) + vals[i] = rand.uint64(&r) } // Sort @@ -69,7 +29,7 @@ test_sort_with_indices :: proc(t: ^testing.T) { defer delete(f_idx) // Verify sorted test values - rand.init(&r, seed) + rand.init(&r, t.seed) for v, i in f_idx { r_idx[v] = i @@ -79,14 +39,14 @@ test_sort_with_indices :: proc(t: ^testing.T) { for v, i in vals { if i > 0 { val_pass := v >= last - expect(t, val_pass, "Expected values to have been sorted.") + testing.expect(t, val_pass, "Expected randomized test values to have been sorted") if !val_pass { break } } idx_pass := vals[r_idx[i]] == rand.uint64(&r) - expect(t, idx_pass, "Expected index to have been sorted.") + testing.expect(t, idx_pass, "Expected index to have been sorted") if !idx_pass { break } @@ -97,16 +57,11 @@ test_sort_with_indices :: proc(t: ^testing.T) { @test test_sort_by_indices :: proc(t: ^testing.T) { - seed := rand.uint64() - fmt.printf("Random seed: %v\n", seed) - // Test sizes are all prime. test_sizes :: []int{7, 13, 347, 1031, 10111, 100003} for test_size in test_sizes { - fmt.printf("Sorting %v random u64 values along with index.\n", test_size) - - r := rand.create(seed) + r := rand.create(t.seed) vals := make([]u64, test_size) r_idx := make([]int, test_size) // Reverse index @@ -117,7 +72,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { // Set up test values for _, i in vals { - vals[i] = rand.uint64(&r) + vals[i] = rand.uint64(&r) } // Sort @@ -125,7 +80,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { defer delete(f_idx) // Verify sorted test values - rand.init(&r, seed) + rand.init(&r, t.seed) { indices := make([]int, test_size) @@ -138,7 +93,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { defer delete(sorted_indices) for v, i in sorted_indices { idx_pass := v == f_idx[i] - expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") + testing.expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") if !idx_pass { break } @@ -154,7 +109,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { slice.sort_by_indices_overwrite(indices, f_idx) for v, i in indices { idx_pass := v == f_idx[i] - expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") + testing.expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") if !idx_pass { break } @@ -174,7 +129,7 @@ test_sort_by_indices :: proc(t: ^testing.T) { slice.sort_by_indices(indices, swap, f_idx) for v, i in swap { idx_pass := v == f_idx[i] - expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") + testing.expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices") if !idx_pass { break } @@ -185,61 +140,48 @@ test_sort_by_indices :: proc(t: ^testing.T) { @test test_binary_search :: proc(t: ^testing.T) { - builder := strings.Builder{} - defer strings.builder_destroy(&builder) - - test_search :: proc(t: ^testing.T, b: ^strings.Builder, s: []i32, v: i32) -> (int, bool) { - log(t, fmt.sbprintf(b, "Searching for %v in %v", v, s)) - strings.builder_reset(b) - index, found := slice.binary_search(s, v) - log(t, fmt.sbprintf(b, "index: %v, found: %v", index, found)) - strings.builder_reset(b ) - - return index, found - } - index: int found: bool s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55} - index, found = test_search(t, &builder, s, 13) - expect(t, index == 9, "Expected index to be 9.") - expect(t, found == true, "Expected found to be true.") + index, found = slice.binary_search(s, 13) + testing.expect(t, index == 9, "Expected index to be 9") + testing.expect(t, found == true, "Expected found to be true") - index, found = test_search(t, &builder, s, 4) - expect(t, index == 7, "Expected index to be 7.") - expect(t, found == false, "Expected found to be false.") + index, found = slice.binary_search(s, 4) + testing.expect(t, index == 7, "Expected index to be 7.") + testing.expect(t, found == false, "Expected found to be false.") - index, found = test_search(t, &builder, s, 100) - expect(t, index == 13, "Expected index to be 13.") - expect(t, found == false, "Expected found to be false.") + index, found = slice.binary_search(s, 100) + testing.expect(t, index == 13, "Expected index to be 13.") + testing.expect(t, found == false, "Expected found to be false.") - index, found = test_search(t, &builder, s, 1) - expect(t, index >= 1 && index <= 4, "Expected index to be 1, 2, 3, or 4.") - expect(t, found == true, "Expected found to be true.") + index, found = slice.binary_search(s, 1) + testing.expect(t, index >= 1 && index <= 4, "Expected index to be 1, 2, 3, or 4.") + testing.expect(t, found == true, "Expected found to be true.") - index, found = test_search(t, &builder, s, -1) - expect(t, index == 0, "Expected index to be 0.") - expect(t, found == false, "Expected found to be false.") + index, found = slice.binary_search(s, -1) + testing.expect(t, index == 0, "Expected index to be 0.") + testing.expect(t, found == false, "Expected found to be false.") a := []i32{} - index, found = test_search(t, &builder, a, 13) - expect(t, index == 0, "Expected index to be 0.") - expect(t, found == false, "Expected found to be false.") + index, found = slice.binary_search(a, 13) + testing.expect(t, index == 0, "Expected index to be 0.") + testing.expect(t, found == false, "Expected found to be false.") b := []i32{1} - index, found = test_search(t, &builder, b, 13) - expect(t, index == 1, "Expected index to be 1.") - expect(t, found == false, "Expected found to be false.") + index, found = slice.binary_search(b, 13) + testing.expect(t, index == 1, "Expected index to be 1.") + testing.expect(t, found == false, "Expected found to be false.") - index, found = test_search(t, &builder, b, 1) - expect(t, index == 0, "Expected index to be 0.") - expect(t, found == true, "Expected found to be true.") + index, found = slice.binary_search(b, 1) + testing.expect(t, index == 0, "Expected index to be 0.") + testing.expect(t, found == true, "Expected found to be true.") - index, found = test_search(t, &builder, b, 0) - expect(t, index == 0, "Expected index to be 0.") - expect(t, found == false, "Expected found to be false.") -} + index, found = slice.binary_search(b, 0) + testing.expect(t, index == 0, "Expected index to be 0.") + testing.expect(t, found == false, "Expected found to be false.") +} \ No newline at end of file From a406ff70636b03a91024791c22838c1a67ce4817 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 00:57:05 +0200 Subject: [PATCH 55/93] Port `tests\core\strings` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/strings/test_core_strings.odin | 86 +++++++---------------- 3 files changed, 26 insertions(+), 64 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 453b84dbe..34e490c69 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -100,7 +100,7 @@ slice_test: $(ODIN) test slice $(COMMON) -out:test_core_slice strings_test: - $(ODIN) run strings $(COMMON) -out:test_core_strings + $(ODIN) test strings $(COMMON) -out:test_core_strings thread_test: $(ODIN) run thread $(COMMON) -out:test_core_thread diff --git a/tests/core/build.bat b/tests/core/build.bat index 9a21d6b79..eee489dec 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -107,7 +107,7 @@ echo --- echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe || exit /b +%PATH_TO_ODIN% test strings %COMMON% -out:test_core_strings.exe || exit /b echo --- echo Running core:thread tests diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index f49476765..0ee2b3eb9 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -2,81 +2,42 @@ package test_core_strings import "core:strings" import "core:testing" -import "core:fmt" -import "core:os" import "base:runtime" -import "core:mem" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - test_index_any_small_string_not_found(&t) - test_index_any_larger_string_not_found(&t) - test_index_any_small_string_found(&t) - test_index_any_larger_string_found(&t) - test_cut(&t) - test_case_conversion(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} @test test_index_any_small_string_not_found :: proc(t: ^testing.T) { index := strings.index_any(".", "/:\"") - expect(t, index == -1, "index_any should be negative") + testing.expect(t, index == -1, "index_any should be negative") } @test test_index_any_larger_string_not_found :: proc(t: ^testing.T) { index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") - expect(t, index == -1, "index_any should be negative") + testing.expect(t, index == -1, "index_any should be negative") } @test test_index_any_small_string_found :: proc(t: ^testing.T) { index := strings.index_any(".", "/:.\"") - expect(t, index == 0, "index_any should be 0") + testing.expect(t, index == 0, "index_any should be 0") } @test test_index_any_larger_string_found :: proc(t: ^testing.T) { index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") - expect(t, index == 8, "index_any should be 8") + testing.expect(t, index == 8, "index_any should be 8") } @test test_last_index_any_small_string_found :: proc(t: ^testing.T) { index := strings.last_index_any(".", "/:.\"") - expect(t, index == 0, "last_index_any should be 0") + testing.expect(t, index == 0, "last_index_any should be 0") } @test test_last_index_any_small_string_not_found :: proc(t: ^testing.T) { index := strings.last_index_any(".", "/:\"") - expect(t, index == -1, "last_index_any should be -1") + testing.expect(t, index == -1, "last_index_any should be -1") } Cut_Test :: struct { @@ -100,9 +61,12 @@ test_cut :: proc(t: ^testing.T) { res := strings.cut(test.input, test.offset, test.length) defer delete(res) - msg := fmt.tprintf("cut(\"%v\", %v, %v) expected to return \"%v\", got \"%v\"", - test.input, test.offset, test.length, test.output, res) - expect(t, res == test.output, msg) + testing.expectf( + t, + res == test.output, + "cut(\"%v\", %v, %v) expected to return \"%v\", got \"%v\"", + test.input, test.offset, test.length, test.output, res, + ) } } @@ -118,7 +82,7 @@ Case_Kind :: enum { Ada_Case, } -Case_Proc :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) +Case_Proc :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) test_cases := [Case_Kind]struct{s: string, p: Case_Proc}{ .Lower_Space_Case = {"hellope world", to_lower_space_case}, @@ -132,33 +96,31 @@ test_cases := [Case_Kind]struct{s: string, p: Case_Proc}{ .Ada_Case = {"Hellope_World", to_ada_case}, } -to_lower_space_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { +to_lower_space_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_delimiter_case(r, ' ', false, allocator) } -to_upper_space_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { +to_upper_space_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_delimiter_case(r, ' ', true, allocator) } // NOTE: we have these wrappers as having #optional_allocator_error changes the type to not be equivalent -to_snake_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_snake_case(r, allocator) } -to_upper_snake_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_upper_snake_case(r, allocator) } -to_kebab_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_kebab_case(r, allocator) } -to_upper_kebab_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_upper_kebab_case(r, allocator) } -to_camel_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_camel_case(r, allocator) } -to_pascal_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_pascal_case(r, allocator) } -to_ada_case :: proc(r: string, allocator: runtime.Allocator) -> (string, mem.Allocator_Error) { return strings.to_ada_case(r, allocator) } +to_snake_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_snake_case(r, allocator) } +to_upper_snake_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_upper_snake_case(r, allocator) } +to_kebab_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_kebab_case(r, allocator) } +to_upper_kebab_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_upper_kebab_case(r, allocator) } +to_camel_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_camel_case(r, allocator) } +to_pascal_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_pascal_case(r, allocator) } +to_ada_case :: proc(r: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { return strings.to_ada_case(r, allocator) } @test test_case_conversion :: proc(t: ^testing.T) { for entry in test_cases { for test_case, case_kind in test_cases { result, err := entry.p(test_case.s, context.allocator) - msg := fmt.tprintf("ERROR: We got the allocation error '{}'\n", err) - expect(t, err == nil, msg) + testing.expectf(t, err == nil, "ERROR: We got the allocation error '{}'\n", err) defer delete(result) - msg = fmt.tprintf("ERROR: Input `{}` to converter {} does not match `{}`, got `{}`.\n", test_case.s, case_kind, entry.s, result) - expect(t, result == entry.s, msg) + testing.expectf(t, result == entry.s, "ERROR: Input `{}` to converter {} does not match `{}`, got `{}`.\n", test_case.s, case_kind, entry.s, result) } } } \ No newline at end of file From 5b1ffba915286209b83c444d40f9fcb4d44c9bc8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 01:12:35 +0200 Subject: [PATCH 56/93] Port `testing\core\time` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/time/test_core_time.odin | 170 +++++++++++++++------------- 3 files changed, 94 insertions(+), 80 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 34e490c69..ec4cdcafd 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -106,7 +106,7 @@ thread_test: $(ODIN) run thread $(COMMON) -out:test_core_thread time_test: - $(ODIN) run time $(COMMON) -out:test_core_time + $(ODIN) test time $(COMMON) -out:test_core_time clean: rm test_* \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index eee489dec..090369848 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -117,4 +117,4 @@ echo --- echo --- echo Running core:time tests echo --- -%PATH_TO_ODIN% run time %COMMON% %COLLECTION% -out:test_core_time.exe || exit /b \ No newline at end of file +%PATH_TO_ODIN% test time %COMMON% -out:test_core_time.exe || exit /b \ No newline at end of file diff --git a/tests/core/time/test_core_time.odin b/tests/core/time/test_core_time.odin index c6c6869a7..aeae44ca1 100644 --- a/tests/core/time/test_core_time.odin +++ b/tests/core/time/test_core_time.odin @@ -1,68 +1,17 @@ package test_core_time -import "core:fmt" -import "core:mem" -import "core:os" import "core:testing" import "core:time" import dt "core:time/datetime" is_leap_year :: time.is_leap_year -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - expect_value :: testing.expect_value - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - defer mem.tracking_allocator_destroy(&track) - context.allocator = mem.tracking_allocator(&track) - - test_ordinal_date_roundtrip(&t) - test_component_to_time_roundtrip(&t) - test_parse_rfc3339_string(&t) - test_parse_iso8601_string(&t) - - for _, leak in track.allocation_map { - expect(&t, false, fmt.tprintf("%v leaked %m\n", leak.location, leak.size)) - } - for bad_free in track.bad_free_array { - expect(&t, false, fmt.tprintf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory)) - } - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - @test test_ordinal_date_roundtrip :: proc(t: ^testing.T) { - expect(t, dt.unsafe_ordinal_to_date(dt.unsafe_date_to_ordinal(dt.MIN_DATE)) == dt.MIN_DATE, "Roundtripping MIN_DATE failed.") - expect(t, dt.unsafe_date_to_ordinal(dt.unsafe_ordinal_to_date(dt.MIN_ORD)) == dt.MIN_ORD, "Roundtripping MIN_ORD failed.") - expect(t, dt.unsafe_ordinal_to_date(dt.unsafe_date_to_ordinal(dt.MAX_DATE)) == dt.MAX_DATE, "Roundtripping MAX_DATE failed.") - expect(t, dt.unsafe_date_to_ordinal(dt.unsafe_ordinal_to_date(dt.MAX_ORD)) == dt.MAX_ORD, "Roundtripping MAX_ORD failed.") + testing.expect(t, dt.unsafe_ordinal_to_date(dt.unsafe_date_to_ordinal(dt.MIN_DATE)) == dt.MIN_DATE, "Roundtripping MIN_DATE failed.") + testing.expect(t, dt.unsafe_date_to_ordinal(dt.unsafe_ordinal_to_date(dt.MIN_ORD)) == dt.MIN_ORD, "Roundtripping MIN_ORD failed.") + testing.expect(t, dt.unsafe_ordinal_to_date(dt.unsafe_date_to_ordinal(dt.MAX_DATE)) == dt.MAX_DATE, "Roundtripping MAX_DATE failed.") + testing.expect(t, dt.unsafe_date_to_ordinal(dt.unsafe_ordinal_to_date(dt.MAX_ORD)) == dt.MAX_ORD, "Roundtripping MAX_ORD failed.") } /* @@ -160,22 +109,51 @@ test_parse_rfc3339_string :: proc(t: ^testing.T) { is_leap := false if test.apply_offset { res, consumed := time.rfc3339_to_time_utc(test.rfc_3339, &is_leap) - msg := fmt.tprintf("[apply offet] Parsing failed: %v -> %v (nsec: %v). Expected %v consumed, got %v", test.rfc_3339, res, res._nsec, test.consumed, consumed) - expect(t, test.consumed == consumed, msg) + testing.expectf( + t, + test.consumed == consumed, + "[apply offet] Parsing failed: %v -> %v (nsec: %v). Expected %v consumed, got %v", + test.rfc_3339, res, res._nsec, test.consumed, consumed, + ) if test.consumed == consumed { - expect(t, test.datetime == res, fmt.tprintf("Time didn't match. Expected %v (%v), got %v (%v)", test.datetime, test.datetime._nsec, res, res._nsec)) - expect(t, test.is_leap == is_leap, "Expected a leap second, got none.") + testing.expectf( + t, + test.datetime == res, + "Time didn't match. Expected %v (%v), got %v (%v)", + test.datetime, test.datetime._nsec, res, res._nsec, + ) + testing.expect( + t, + test.is_leap == is_leap, + "Expected a leap second, got none", + ) } } else { res, offset, consumed := time.rfc3339_to_time_and_offset(test.rfc_3339) - msg := fmt.tprintf("Parsing failed: %v -> %v (nsec: %v), offset: %v. Expected %v consumed, got %v", test.rfc_3339, res, res._nsec, offset, test.consumed, consumed) - expect(t, test.consumed == consumed, msg) + testing.expectf( + t, + test.consumed == consumed, + "Parsing failed: %v -> %v (nsec: %v), offset: %v. Expected %v consumed, got %v", + test.rfc_3339, res, res._nsec, offset, test.consumed, consumed, + ) if test.consumed == consumed { - expect(t, test.datetime == res, fmt.tprintf("Time didn't match. Expected %v (%v), got %v (%v)", test.datetime, test.datetime._nsec, res, res._nsec)) - expect(t, test.utc_offset == offset, fmt.tprintf("UTC offset didn't match. Expected %v, got %v", test.utc_offset, offset)) - expect(t, test.is_leap == is_leap, "Expected a leap second, got none.") + testing.expectf( + t, test.datetime == res, + "Time didn't match. Expected %v (%v), got %v (%v)", + test.datetime, test.datetime._nsec, res, res._nsec, + ) + testing.expectf( + t, + test.utc_offset == offset, + "UTC offset didn't match. Expected %v, got %v", + test.utc_offset, offset, + ) + testing.expect( + t, test.is_leap == is_leap, + "Expected a leap second, got none", + ) } } } @@ -187,22 +165,52 @@ test_parse_iso8601_string :: proc(t: ^testing.T) { is_leap := false if test.apply_offset { res, consumed := time.iso8601_to_time_utc(test.iso_8601, &is_leap) - msg := fmt.tprintf("[apply offet] Parsing failed: %v -> %v (nsec: %v). Expected %v consumed, got %v", test.iso_8601, res, res._nsec, test.consumed, consumed) - expect(t, test.consumed == consumed, msg) + testing.expectf( + t, + test.consumed == consumed, + "[apply offet] Parsing failed: %v -> %v (nsec: %v). Expected %v consumed, got %v", + test.iso_8601, res, res._nsec, test.consumed, consumed, + ) if test.consumed == consumed { - expect(t, test.datetime == res, fmt.tprintf("Time didn't match. Expected %v (%v), got %v (%v)", test.datetime, test.datetime._nsec, res, res._nsec)) - expect(t, test.is_leap == is_leap, "Expected a leap second, got none.") + testing.expectf( + t, + test.datetime == res, + "Time didn't match. Expected %v (%v), got %v (%v)", + test.datetime, test.datetime._nsec, res, res._nsec, + ) + testing.expect( + t, + test.is_leap == is_leap, + "Expected a leap second, got none", + ) } } else { res, offset, consumed := time.iso8601_to_time_and_offset(test.iso_8601) - msg := fmt.tprintf("Parsing failed: %v -> %v (nsec: %v), offset: %v. Expected %v consumed, got %v", test.iso_8601, res, res._nsec, offset, test.consumed, consumed) - expect(t, test.consumed == consumed, msg) + testing.expectf( + t, + test.consumed == consumed, + "Parsing failed: %v -> %v (nsec: %v), offset: %v. Expected %v consumed, got %v", + test.iso_8601, res, res._nsec, offset, test.consumed, consumed, + ) if test.consumed == consumed { - expect(t, test.datetime == res, fmt.tprintf("Time didn't match. Expected %v (%v), got %v (%v)", test.datetime, test.datetime._nsec, res, res._nsec)) - expect(t, test.utc_offset == offset, fmt.tprintf("UTC offset didn't match. Expected %v, got %v", test.utc_offset, offset)) - expect(t, test.is_leap == is_leap, "Expected a leap second, got none.") + testing.expectf( + t, test.datetime == res, + "Time didn't match. Expected %v (%v), got %v (%v)", + test.datetime, test.datetime._nsec, res, res._nsec, + ) + testing.expectf( + t, + test.utc_offset == offset, + "UTC offset didn't match. Expected %v, got %v", + test.utc_offset, offset, + ) + testing.expect( + t, + test.is_leap == is_leap, + "Expected a leap second, got none", + ) } } } @@ -231,15 +239,21 @@ test_component_to_time_roundtrip :: proc(t: ^testing.T) { date_component_roundtrip_test :: proc(t: ^testing.T, moment: dt.DateTime) { res, ok := time.datetime_to_time(moment.year, moment.month, moment.day, moment.hour, moment.minute, moment.second) - expect(t, ok, "Couldn't convert date components into date") + testing.expect( + t, + ok, + "Couldn't convert date components into date", + ) YYYY, MM, DD := time.date(res) hh, mm, ss := time.clock(res) - expected := fmt.tprintf("Expected %4d-%2d-%2d %2d:%2d:%2d, got %4d-%2d-%2d %2d:%2d:%2d", - moment.year, moment.month, moment.day, moment.hour, moment.minute, moment.second, YYYY, MM, DD, hh, mm, ss) - ok = moment.year == i64(YYYY) && moment.month == i8(MM) && moment.day == i8(DD) ok &= moment.hour == i8(hh) && moment.minute == i8(mm) && moment.second == i8(ss) - expect(t, ok, expected) + testing.expectf( + t, + ok, + "Expected %4d-%2d-%2d %2d:%2d:%2d, got %4d-%2d-%2d %2d:%2d:%2d", + moment.year, moment.month, moment.day, moment.hour, moment.minute, moment.second, YYYY, MM, DD, hh, mm, ss, + ) } \ No newline at end of file From dacb0f7786f5eb1e05b06179a5f68b587aa9db8a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 12:14:33 +0200 Subject: [PATCH 57/93] Port `tests\core\thread` --- tests/common/common.odin | 81 ------------------------ tests/core/Makefile | 3 +- tests/core/build.bat | 3 +- tests/core/test_core_odin | Bin 1401192 -> 0 bytes tests/core/thread/test_core_thread.odin | 56 ++++------------ 5 files changed, 14 insertions(+), 129 deletions(-) delete mode 100644 tests/common/common.odin delete mode 100644 tests/core/test_core_odin diff --git a/tests/common/common.odin b/tests/common/common.odin deleted file mode 100644 index 021fb21c5..000000000 --- a/tests/common/common.odin +++ /dev/null @@ -1,81 +0,0 @@ -// Boilerplate for tests -package common - -import "core:testing" -import "core:fmt" -import "core:os" -import "core:strings" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log - errorf :: testing.errorf -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v:%s] FAIL %v\n", loc, loc.procedure, message) - return - } - } - errorf :: proc(t: ^testing.T, message: string, args: ..any, loc := #caller_location) { - TEST_fail += 1 - fmt.printf("[%v:%s] Error %v\n", loc, loc.procedure, fmt.tprintf(message, ..args)) - return - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -report :: proc(t: ^testing.T) { - if TEST_fail > 0 { - if TEST_fail > 1 { - fmt.printf("%v/%v tests successful, %v tests failed.\n", TEST_count - TEST_fail, TEST_count, TEST_fail) - } else { - fmt.printf("%v/%v tests successful, 1 test failed.\n", TEST_count - TEST_fail, TEST_count) - } - os.exit(1) - } else { - fmt.printf("%v/%v tests successful.\n", TEST_count, TEST_count) - } -} - -// Returns absolute path to `sub_path` where `sub_path` is within the "tests/" sub-directory of the Odin project root -// and we're being run from the Odin project root or from a sub-directory of "tests/" -// e.g. get_data_path("assets/blah") will return "/Odin_root/tests/assets/blah" if run within "/Odin_root", -// "/Odin_root/tests" or "/Odin_root/tests/subdir" etc -get_data_path :: proc(t: ^testing.T, sub_path: string) -> (data_path: string) { - - cwd := os.get_current_directory() - defer delete(cwd) - - when ODIN_OS == .Windows { - norm, was_allocation := strings.replace_all(cwd, "\\", "/") - if !was_allocation { - norm = strings.clone(norm) - } - defer delete(norm) - } else { - norm := cwd - } - - last_index := strings.last_index(norm, "/tests/") - if last_index == -1 { - len := len(norm) - if len >= 6 && norm[len-6:] == "/tests" { - data_path = fmt.tprintf("%s/%s", norm, sub_path) - } else { - data_path = fmt.tprintf("%s/tests/%s", norm, sub_path) - } - } else { - data_path = fmt.tprintf("%s/tests/%s", norm[:last_index], sub_path) - } - - return data_path -} diff --git a/tests/core/Makefile b/tests/core/Makefile index ec4cdcafd..4e13733b0 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,7 +1,6 @@ ODIN=../../odin PYTHON=$(shell which python3) COMMON=-no-bounds-check -vet -strict-style -COLLECTION=-collection:tests=.. all: all_bsd \ net_test @@ -103,7 +102,7 @@ strings_test: $(ODIN) test strings $(COMMON) -out:test_core_strings thread_test: - $(ODIN) run thread $(COMMON) -out:test_core_thread + $(ODIN) test thread $(COMMON) -out:test_core_thread time_test: $(ODIN) test time $(COMMON) -out:test_core_time diff --git a/tests/core/build.bat b/tests/core/build.bat index 090369848..accf0808a 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,6 +1,5 @@ @echo off set COMMON=-no-bounds-check -vet -strict-style -set COLLECTION=-collection:tests=.. set PATH_TO_ODIN==..\..\odin python3 download_assets.py echo --- @@ -112,7 +111,7 @@ echo --- echo --- echo Running core:thread tests echo --- -%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b +%PATH_TO_ODIN% test thread %COMMON% -out:test_core_thread.exe || exit /b echo --- echo Running core:time tests diff --git a/tests/core/test_core_odin b/tests/core/test_core_odin deleted file mode 100644 index bdf316228a8bddc5f4a0998789b00dc1f182e9f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1401192 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 z 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
m48_I)?Rx1i0? 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ñ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≶hAgq7v#(}_X|98HG!E7`)fd%3v{yIiwW(& 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

#g64sYn}3wSjKsCx;T3Ixp-!sbHH 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 YU=Tz~J1{X2-5DVYq8Mb*G@x-A0P!{*ivR!s diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin index c0c7396a7..0b77ad511 100644 --- a/tests/core/thread/test_core_thread.odin +++ b/tests/core/thread/test_core_thread.odin @@ -2,39 +2,7 @@ package test_core_thread import "core:testing" import "core:thread" -import "core:fmt" -import "core:os" - -TEST_count := 0 -TEST_fail := 0 - -t := &testing.T{} - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - poly_data_test(t) - - if TEST_fail > 0 { - os.exit(1) - } -} +import "base:intrinsics" @(test) poly_data_test :: proc(_t: ^testing.T) { @@ -46,7 +14,7 @@ poly_data_test :: proc(_t: ^testing.T) { b: [MAX]byte = 8 t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) { b_expect: [MAX]byte = 8 - expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + testing.expect(poly_data_test_t, b == b_expect, "thread poly data not correct") }) defer free(t1) @@ -55,8 +23,8 @@ poly_data_test :: proc(_t: ^testing.T) { t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) { b_expect: [3]uintptr = 1 b2_expect: [MAX / 2]byte = 3 - expect(poly_data_test_t, b == b_expect, "thread poly data not correct") - expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") + testing.expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + testing.expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") }) defer free(t2) @@ -64,21 +32,21 @@ poly_data_test :: proc(_t: ^testing.T) { b_expect: [3]uintptr = 1 b2_expect: [MAX / 2]byte = 3 - expect(poly_data_test_t, b == b_expect, "thread poly data not correct") - expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") - expect(poly_data_test_t, b3 == 333, "thread poly data not correct") + testing.expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + testing.expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct") + testing.expect(poly_data_test_t, b3 == 333, "thread poly data not correct") }) defer free(t3) t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) { b_expect: [3]uintptr = 1 - expect(poly_data_test_t, n == 111, "thread poly data not correct") - expect(poly_data_test_t, b == b_expect, "thread poly data not correct") - expect(poly_data_test_t, n2 == 333, "thread poly data not correct") - expect(poly_data_test_t, n4 == 5, "thread poly data not correct") + testing.expect(poly_data_test_t, n == 111, "thread poly data not correct") + testing.expect(poly_data_test_t, b == b_expect, "thread poly data not correct") + testing.expect(poly_data_test_t, n2 == 333, "thread poly data not correct") + testing.expect(poly_data_test_t, n4 == 5, "thread poly data not correct") }) defer free(t4) thread.join_multiple(t1, t2, t3, t4) -} +} \ No newline at end of file From 62b7d8de9732eef542dcb878b089b30972cb8afc Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 16:32:12 +0200 Subject: [PATCH 58/93] Port `tests\core\net` --- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/net/test_core_net.odin | 276 +++++++++--------------------- 3 files changed, 85 insertions(+), 195 deletions(-) diff --git a/tests/core/Makefile b/tests/core/Makefile index 4e13733b0..9b12f5d76 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -81,7 +81,7 @@ noise_test: $(ODIN) test math/noise $(COMMON) -out:test_noise net_test: - $(ODIN) run net $(COMMON) -out:test_core_net + $(ODIN) test net $(COMMON) -out:test_core_net os_exit_test: $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 diff --git a/tests/core/build.bat b/tests/core/build.bat index accf0808a..3e67b6e13 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -81,7 +81,7 @@ echo --- echo --- echo Running core:net echo --- -%PATH_TO_ODIN% run net %COMMON% -out:test_core_net.exe || exit /b +%PATH_TO_ODIN% test net %COMMON% -out:test_core_net.exe || exit /b echo --- echo Running core:odin tests diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index 9df03414c..3cbb7fa34 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -11,71 +11,12 @@ package test_core_net import "core:testing" -import "core:mem" -import "core:fmt" import "core:net" import "core:strconv" import "core:sync" import "core:time" import "core:thread" -import "core:os" - -_, _ :: time, thread - -TEST_count := 0 -TEST_fail := 0 - -t := &testing.T{} - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -_tracking_allocator := mem.Tracking_Allocator{} - -print_tracking_allocator_report :: proc() { - for _, leak in _tracking_allocator.allocation_map { - fmt.printf("%v leaked %v bytes\n", leak.location, leak.size) - } - - for bf in _tracking_allocator.bad_free_array { - fmt.printf("%v allocation %p was freed badly\n", bf.location, bf.memory) - } -} - -main :: proc() { - mem.tracking_allocator_init(&_tracking_allocator, context.allocator) - context.allocator = mem.tracking_allocator(&_tracking_allocator) - - address_parsing_test(t) - - tcp_tests(t) - - split_url_test(t) - join_url_test(t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - - print_tracking_allocator_report() - - if TEST_fail > 0 { - os.exit(1) - } -} +import "core:fmt" @test address_parsing_test :: proc(t: ^testing.T) { @@ -89,127 +30,66 @@ address_parsing_test :: proc(t: ^testing.T) { } valid := len(vector.binstr) > 0 - - fmt.printf("%v %v\n", kind, vector.input) - - msg := "-set a proper message-" switch vector.family { case .IP4, .IP4_Alt: - /* - Does `net.parse_ip4_address` think we parsed the address properly? - */ + // Does `net.parse_ip4_address` think we parsed the address properly? non_decimal := vector.family == .IP4_Alt + any_addr := net.parse_address(vector.input, non_decimal) + parsed_ok := any_addr != nil + parsed: net.IP4_Address - any_addr := net.parse_address(vector.input, non_decimal) - parsed_ok := any_addr != nil - parsed: net.IP4_Address - - /* - Ensure that `parse_address` doesn't parse IPv4 addresses into IPv6 addreses by mistake. - */ + // Ensure that `parse_address` doesn't parse IPv4 addresses into IPv6 addreses by mistake. switch addr in any_addr { case net.IP4_Address: parsed = addr case net.IP6_Address: parsed_ok = false - msg = fmt.tprintf("parse_address mistook %v as IPv6 address %04x", vector.input, addr) - expect(t, false, msg) + testing.expectf(t, false, "parse_address mistook %v as IPv6 address %04x", vector.input, addr) } if !parsed_ok && valid { - msg = fmt.tprintf("parse_ip4_address failed to parse %v, expected %v", vector.input, binstr_to_address(vector.binstr)) + testing.expectf(t, parsed_ok == valid, "parse_ip4_address failed to parse %v, expected %v", vector.input, binstr_to_address(t, vector.binstr)) } else if parsed_ok && !valid { - msg = fmt.tprintf("parse_ip4_address parsed %v into %v, expected failure", vector.input, parsed) + testing.expectf(t, parsed_ok == valid, "parse_ip4_address parsed %v into %v, expected failure", vector.input, parsed) } - expect(t, parsed_ok == valid, msg) if valid && parsed_ok { actual_binary := address_to_binstr(parsed) - msg = fmt.tprintf("parse_ip4_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr) - expect(t, actual_binary == vector.binstr, msg) + testing.expectf(t, actual_binary == vector.binstr, "parse_ip4_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr) - /* - Do we turn an address back into the same string properly? - No point in testing the roundtrip if the first part failed. - */ + // Do we turn an address back into the same string properly? No point in testing the roundtrip if the first part failed. if len(vector.output) > 0 && actual_binary == vector.binstr { stringified := net.address_to_string(parsed) - msg = fmt.tprintf("address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output) - expect(t, stringified == vector.output, msg) + testing.expectf(t, stringified == vector.output, "address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output) } } case .IP6: - /* - Do we parse the address properly? - */ + // Do we parse the address properly? parsed, parsed_ok := net.parse_ip6_address(vector.input) if !parsed_ok && valid { - msg = fmt.tprintf("parse_ip6_address failed to parse %v, expected %04x", vector.input, binstr_to_address(vector.binstr)) + testing.expectf(t, parsed_ok == valid, "parse_ip6_address failed to parse %v, expected %04x", vector.input, binstr_to_address(t, vector.binstr)) } else if parsed_ok && !valid { - msg = fmt.tprintf("parse_ip6_address parsed %v into %04x, expected failure", vector.input, parsed) + testing.expectf(t, parsed_ok == valid, "parse_ip6_address parsed %v into %04x, expected failure", vector.input, parsed) } - expect(t, parsed_ok == valid, msg) if valid && parsed_ok { actual_binary := address_to_binstr(parsed) - msg = fmt.tprintf("parse_ip6_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr) - expect(t, actual_binary == vector.binstr, msg) + testing.expectf(t, actual_binary == vector.binstr, "parse_ip6_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr) - /* - Do we turn an address back into the same string properly? - No point in testing the roundtrip if the first part failed. - */ + // Do we turn an address back into the same string properly? No point in testing the roundtrip if the first part failed. if len(vector.output) > 0 && actual_binary == vector.binstr { stringified := net.address_to_string(parsed) - msg = fmt.tprintf("address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output) - expect(t, stringified == vector.output, msg) + testing.expectf(t, stringified == vector.output, "address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output) } } } } } -address_to_binstr :: proc(address: net.Address) -> (binstr: string) { - switch t in address { - case net.IP4_Address: - b := transmute(u32be)t - return fmt.tprintf("%08x", b) - case net.IP6_Address: - b := transmute(u128be)t - return fmt.tprintf("%32x", b) - case: - return "" - } - unreachable() -} - -binstr_to_address :: proc(binstr: string) -> (address: net.Address) { - switch len(binstr) { - case 8: // IPv4 - a, ok := strconv.parse_u64_of_base(binstr, 16) - expect(t, ok, "failed to parse test case bin string") - - ipv4 := u32be(a) - return net.IP4_Address(transmute([4]u8)ipv4) - - - case 32: // IPv6 - a, ok := strconv.parse_u128_of_base(binstr, 16) - expect(t, ok, "failed to parse test case bin string") - - ipv4 := u128be(a) - return net.IP6_Address(transmute([8]u16be)ipv4) - - case 0: - return nil - } - panic("Invalid test case") -} - Kind :: enum { IP4, // Decimal IPv4 IP4_Alt, // Non-decimal address @@ -223,10 +103,7 @@ IP_Address_Parsing_Test_Vector :: struct { // Input address to try and parse. input: string, - /* - Hexadecimal representation of the expected numeric value of the address. - Zero length means input is invalid and the parser should report failure. - */ + // Hexadecimal representation of the expected numeric value of the address. Zero length means input is invalid and the parser should report failure. binstr: string, // Expected `address_to_string` output, if a valid input and this string is non-empty. @@ -335,38 +212,30 @@ IP_Address_Parsing_Test_Vectors :: []IP_Address_Parsing_Test_Vector{ { .IP6, "c0a8", "", ""}, } -tcp_tests :: proc(t: ^testing.T) { - fmt.println("Testing two servers trying to bind to the same endpoint...") - two_servers_binding_same_endpoint(t) - fmt.println("Testing client connecting to a closed port...") - client_connects_to_closed_port(t) - fmt.println("Testing client sending server data...") - client_sends_server_data(t) -} - -ENDPOINT := net.Endpoint{ - net.IP4_Address{127, 0, 0, 1}, - 9999, -} +ENDPOINT_TWO_SERVERS := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9991} +ENDPOINT_CLOSED_PORT := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9992} +ENDPOINT_SERVER_SENDS := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9993} @(test) two_servers_binding_same_endpoint :: proc(t: ^testing.T) { - skt1, err1 := net.listen_tcp(ENDPOINT) + skt1, err1 := net.listen_tcp(ENDPOINT_TWO_SERVERS) defer net.close(skt1) - skt2, err2 := net.listen_tcp(ENDPOINT) + skt2, err2 := net.listen_tcp(ENDPOINT_TWO_SERVERS) defer net.close(skt2) - expect(t, err1 == nil, "expected first server binding to endpoint to do so without error") - expect(t, err2 == net.Bind_Error.Address_In_Use, "expected second server to bind to an endpoint to return .Address_In_Use") + testing.expect(t, err1 == nil, "expected first server binding to endpoint to do so without error") + testing.expect(t, err2 == net.Bind_Error.Address_In_Use, "expected second server to bind to an endpoint to return .Address_In_Use") } @(test) client_connects_to_closed_port :: proc(t: ^testing.T) { - skt, err := net.dial_tcp(ENDPOINT) + + skt, err := net.dial_tcp(ENDPOINT_CLOSED_PORT) defer net.close(skt) - expect(t, err == net.Dial_Error.Refused, "expected dial of a closed endpoint to return .Refused") + testing.expect(t, err == net.Dial_Error.Refused, "expected dial of a closed endpoint to return .Refused") } + @(test) client_sends_server_data :: proc(t: ^testing.T) { CONTENT: string: "Hellope!" @@ -390,8 +259,8 @@ client_sends_server_data :: proc(t: ^testing.T) { defer sync.wait_group_done(r.wg) - if r.skt, r.err = net.dial_tcp(ENDPOINT); r.err != nil { - log(r.t, r.err) + if r.skt, r.err = net.dial_tcp(ENDPOINT_SERVER_SENDS); r.err != nil { + testing.expectf(r.t, false, "[tcp_client:dial_tcp] %v", r.err) return } @@ -405,19 +274,17 @@ client_sends_server_data :: proc(t: ^testing.T) { defer sync.wait_group_done(r.wg) - log(r.t, "tcp_server listen") - if r.skt, r.err = net.listen_tcp(ENDPOINT); r.err != nil { + if r.skt, r.err = net.listen_tcp(ENDPOINT_SERVER_SENDS); r.err != nil { sync.wait_group_done(r.wg) - log(r.t, r.err) + testing.expectf(r.t, false, "[tcp_server:listen_tcp] %v", r.err) return } sync.wait_group_done(r.wg) - log(r.t, "tcp_server accept") client: net.TCP_Socket if client, _, r.err = net.accept_tcp(r.skt.(net.TCP_Socket)); r.err != nil { - log(r.t, r.err) + testing.expectf(r.t, false, "[tcp_server:accept_tcp] %v", r.err) return } defer net.close(client) @@ -437,10 +304,7 @@ client_sends_server_data :: proc(t: ^testing.T) { thread_data[0].wg = &wg thread_data[0].tid = thread.create_and_start_with_data(&thread_data[0], tcp_server, context) - log(t, "waiting for server to start listening") sync.wait_group_wait(&wg) - log(t, "starting up client") - sync.wait_group_add(&wg, 2) thread_data[1].t = t @@ -454,20 +318,15 @@ client_sends_server_data :: proc(t: ^testing.T) { net.close(thread_data[1].skt) thread.destroy(thread_data[1].tid) } - - log(t, "waiting for threads to finish") sync.wait_group_wait(&wg) - log(t, "threads finished") okay := thread_data[0].err == nil && thread_data[1].err == nil - msg := fmt.tprintf("Expected client and server to return `nil`, got %v and %v", thread_data[0].err, thread_data[1].err) - expect(t, okay, msg) + testing.expectf(t, okay, "Expected client and server to return `nil`, got %v and %v", thread_data[0].err, thread_data[1].err) received := string(thread_data[0].data[:thread_data[0].length]) okay = received == CONTENT - msg = fmt.tprintf("Expected client to send \"{}\", got \"{}\"", CONTENT, received) - expect(t, okay, msg) + testing.expectf(t, okay, "Expected client to send \"{}\", got \"{}\"", CONTENT, received) } URL_Test :: struct { @@ -559,22 +418,15 @@ split_url_test :: proc(t: ^testing.T) { delete(test.queries) } - msg := fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.scheme, scheme) - expect(t, scheme == test.scheme, msg) - msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.host, host) - expect(t, host == test.host, msg) - msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.path, path) - expect(t, path == test.path, msg) - msg = fmt.tprintf("Expected `net.split_url` to return %d queries, got %d queries", len(test.queries), len(queries)) - expect(t, len(queries) == len(test.queries), msg) + testing.expectf(t, scheme == test.scheme, "Expected `net.split_url` to return %s, got %s", test.scheme, scheme) + testing.expectf(t, host == test.host, "Expected `net.split_url` to return %s, got %s", test.host, host) + testing.expectf(t, path == test.path, "Expected `net.split_url` to return %s, got %s", test.path, path) + testing.expectf(t, len(queries) == len(test.queries), "Expected `net.split_url` to return %d queries, got %d queries", len(test.queries), len(queries)) for k, v in queries { expected := test.queries[k] - msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", expected, v) - expect(t, v == expected, msg) + testing.expectf(t, v == expected, "Expected `net.split_url` to return %s, got %s", expected, v) } - msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.fragment, fragment) - expect(t, fragment == test.fragment, msg) - + testing.expectf(t, fragment == test.fragment, "Expected `net.split_url` to return %s, got %s", test.fragment, fragment) } } @@ -659,7 +511,45 @@ join_url_test :: proc(t: ^testing.T) { for test_url in test.url { pass |= url == test_url } - msg := fmt.tprintf("Expected `net.join_url` to return one of %s, got %s", test.url, url) - expect(t, pass, msg) + testing.expectf(t, pass, "Expected `net.join_url` to return one of %s, got %s", test.url, url) } } + +@(private) +address_to_binstr :: proc(address: net.Address) -> (binstr: string) { + switch t in address { + case net.IP4_Address: + b := transmute(u32be)t + return fmt.tprintf("%08x", b) + case net.IP6_Address: + b := transmute(u128be)t + return fmt.tprintf("%32x", b) + case: + return "" + } + unreachable() +} + +@(private) +binstr_to_address :: proc(t: ^testing.T, binstr: string) -> (address: net.Address) { + switch len(binstr) { + case 8: // IPv4 + a, ok := strconv.parse_u64_of_base(binstr, 16) + testing.expect(t, ok, "failed to parse test case bin string") + + ipv4 := u32be(a) + return net.IP4_Address(transmute([4]u8)ipv4) + + + case 32: // IPv6 + a, ok := strconv.parse_u128_of_base(binstr, 16) + testing.expect(t, ok, "failed to parse test case bin string") + + ipv4 := u128be(a) + return net.IP6_Address(transmute([8]u16be)ipv4) + + case 0: + return nil + } + panic("Invalid test case") +} \ No newline at end of file From 8d93379e299b8115c2727ba1a442609ac4293416 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 20:10:55 +0200 Subject: [PATCH 59/93] Factor benchmarks out into tests\benchmark\ --- .github/workflows/ci.yml | 23 ++ tests/benchmark/Makefile | 14 + tests/benchmark/crypto/benchmark_crypto.odin | 356 +++++++++++++++++++ tests/benchmark/hash/benchmark_hash.odin | 218 ++++++++++++ tests/core/crypto/test_crypto_benchmark.odin | 353 ------------------ tests/core/hash/test_core_hash.odin | 232 +----------- 6 files changed, 615 insertions(+), 581 deletions(-) create mode 100644 tests/benchmark/Makefile create mode 100644 tests/benchmark/crypto/benchmark_crypto.odin create mode 100644 tests/benchmark/hash/benchmark_hash.odin delete mode 100644 tests/core/crypto/test_crypto_benchmark.odin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffb2077d1..67b2bfbda 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,7 @@ jobs: (cd tests/core; gmake all_bsd) (cd tests/internal; gmake all_bsd) (cd tests/issues; ./run.sh) + (cd tests/benchmark; gmake all) build_linux: name: Ubuntu Build, Check, and Test runs-on: ubuntu-latest @@ -80,6 +81,11 @@ jobs: cd tests/internal make timeout-minutes: 10 + - name: Odin core library benchmarks + run: | + cd tests/benchmark + make + timeout-minutes: 10 - name: Odin check examples/all for Linux i386 run: ./odin check examples/all -vet -strict-style -target:linux_i386 timeout-minutes: 10 @@ -131,6 +137,11 @@ jobs: cd tests/internal make timeout-minutes: 10 + - name: Odin core library benchmarks + run: | + cd tests/benchmark + make + timeout-minutes: 10 build_macOS_arm: name: MacOS ARM Build, Check, and Test runs-on: macos-14 # This is an arm/m1 runner. @@ -170,6 +181,11 @@ jobs: cd tests/internal make timeout-minutes: 10 + - name: Odin core library benchmarks + run: | + cd tests/benchmark + make + timeout-minutes: 10 build_windows: name: Windows Build, Check, and Test runs-on: windows-2022 @@ -245,6 +261,13 @@ jobs: cd tests\core\math\big call build.bat timeout-minutes: 10 + - name: core library benchmarks + shell: cmd + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + cd tests\benchmark + call build.bat + timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd run: | diff --git a/tests/benchmark/Makefile b/tests/benchmark/Makefile new file mode 100644 index 000000000..8a8e08b24 --- /dev/null +++ b/tests/benchmark/Makefile @@ -0,0 +1,14 @@ +ODIN=../../odin +COMMON=-no-bounds-check -vet -strict-style + +all: crypto_bench \ + hash_bench + +crypto_bench: + $(ODIN) test crypto $(COMMON) -o:speed -out:bench_crypto + +hash_bench: + $(ODIN) test hash $(COMMON) -o:speed -out:bench_hash + +clean: + rm bench_* \ No newline at end of file diff --git a/tests/benchmark/crypto/benchmark_crypto.odin b/tests/benchmark/crypto/benchmark_crypto.odin new file mode 100644 index 000000000..e90216ad6 --- /dev/null +++ b/tests/benchmark/crypto/benchmark_crypto.odin @@ -0,0 +1,356 @@ +package benchmark_core_crypto + +import "base:runtime" +import "core:encoding/hex" +import "core:fmt" +import "core:log" +import "core:strings" +import "core:testing" +import "core:time" + +import "core:crypto/aes" +import "core:crypto/chacha20" +import "core:crypto/chacha20poly1305" +import "core:crypto/ed25519" +import "core:crypto/poly1305" +import "core:crypto/x25519" + +// Cryptographic primitive benchmarks. + +@(test) +benchmark_crypto :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + str: strings.Builder + strings.builder_init(&str, context.allocator) + defer { + log.info(strings.to_string(str)) + strings.builder_destroy(&str) + } + + { + name := "ChaCha20 64 bytes" + options := &time.Benchmark_Options { + rounds = 1_000, + bytes = 64, + setup = _setup_sized_buf, + bench = _benchmark_chacha20, + teardown = _teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "ChaCha20 1024 bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "ChaCha20 65536 bytes" + options.bytes = 65536 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + } + { + name := "Poly1305 64 zero bytes" + options := &time.Benchmark_Options { + rounds = 1_000, + bytes = 64, + setup = _setup_sized_buf, + bench = _benchmark_poly1305, + teardown = _teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "Poly1305 1024 zero bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + } + { + name := "chacha20poly1305 64 bytes" + options := &time.Benchmark_Options { + rounds = 1_000, + bytes = 64, + setup = _setup_sized_buf, + bench = _benchmark_chacha20poly1305, + teardown = _teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "chacha20poly1305 1024 bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "chacha20poly1305 65536 bytes" + options.bytes = 65536 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + } + { + name := "AES256-GCM 64 bytes" + options := &time.Benchmark_Options { + rounds = 1_000, + bytes = 64, + setup = _setup_sized_buf, + bench = _benchmark_aes256_gcm, + teardown = _teardown_sized_buf, + } + + key := [aes.KEY_SIZE_256]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + ctx: aes.Context_GCM + aes.init_gcm(&ctx, key[:]) + + context.user_ptr = &ctx + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "AES256-GCM 1024 bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + + name = "AES256-GCM 65536 bytes" + options.bytes = 65536 + err = time.benchmark(options, context.allocator) + testing.expect(t, err == nil, name) + benchmark_print(&str, name, options) + } + { + iters :: 10000 + + priv_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" + priv_bytes, _ := hex.decode(transmute([]byte)(priv_str), context.temp_allocator) + priv_key: ed25519.Private_Key + start := time.now() + for i := 0; i < iters; i = i + 1 { + ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) + assert(ok, "private key should deserialize") + } + elapsed := time.since(start) + fmt.sbprintfln(&str, + "ed25519.private_key_set_bytes: ~%f us/op", + time.duration_microseconds(elapsed) / iters, + ) + + pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing" + pub_key: ed25519.Public_Key + start = time.now() + for i := 0; i < iters; i = i + 1 { + ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:]) + assert(ok, "public key should deserialize") + } + elapsed = time.since(start) + fmt.sbprintfln(&str, + "ed25519.public_key_set_bytes: ~%f us/op", + time.duration_microseconds(elapsed) / iters, + ) + + msg := "Got a job for you, 621." + sig_bytes: [ed25519.SIGNATURE_SIZE]byte + msg_bytes := transmute([]byte)(msg) + start = time.now() + for i := 0; i < iters; i = i + 1 { + ed25519.sign(&priv_key, msg_bytes, sig_bytes[:]) + } + elapsed = time.since(start) + fmt.sbprintfln(&str, + "ed25519.sign: ~%f us/op", + time.duration_microseconds(elapsed) / iters, + ) + + start = time.now() + for i := 0; i < iters; i = i + 1 { + ok := ed25519.verify(&pub_key, msg_bytes, sig_bytes[:]) + assert(ok, "signature should validate") + } + elapsed = time.since(start) + fmt.sbprintfln(&str, + "ed25519.verify: ~%f us/op", + time.duration_microseconds(elapsed) / iters, + ) + } + { + point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" + + point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) + scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) + out: [x25519.POINT_SIZE]byte = --- + + iters :: 10000 + start := time.now() + for i := 0; i < iters; i = i + 1 { + x25519.scalarmult(out[:], scalar[:], point[:]) + } + elapsed := time.since(start) + + fmt.sbprintfln(&str, + "x25519.scalarmult: ~%f us/op", + time.duration_microseconds(elapsed) / iters, + ) + } +} + +@(private) +_setup_sized_buf :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + assert(options != nil) + + options.input = make([]u8, options.bytes, allocator) + return nil if len(options.input) == options.bytes else .Allocation_Error +} + +@(private) +_teardown_sized_buf :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + assert(options != nil) + + delete(options.input) + return nil +} + +@(private) +_benchmark_chacha20 :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + key := [chacha20.KEY_SIZE]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + nonce := [chacha20.NONCE_SIZE]byte { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + } + + ctx: chacha20.Context = --- + chacha20.init(&ctx, key[:], nonce[:]) + + for _ in 0 ..= options.rounds { + chacha20.xor_bytes(&ctx, buf, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + return nil +} + +@(private) +_benchmark_poly1305 :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + key := [poly1305.KEY_SIZE]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + + tag: [poly1305.TAG_SIZE]byte = --- + for _ in 0 ..= options.rounds { + poly1305.sum(tag[:], buf, key[:]) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + //options.hash = u128(h) + return nil +} + +@(private) +_benchmark_chacha20poly1305 :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + key := [chacha20.KEY_SIZE]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + nonce := [chacha20.NONCE_SIZE]byte { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + } + + tag: [chacha20poly1305.TAG_SIZE]byte = --- + + for _ in 0 ..= options.rounds { + chacha20poly1305.encrypt(buf, tag[:], key[:], nonce[:], nil, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + return nil +} + +_benchmark_aes256_gcm :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + nonce: [aes.GCM_NONCE_SIZE]byte + tag: [aes.GCM_TAG_SIZE]byte = --- + + ctx := transmute(^aes.Context_GCM)context.user_ptr + + for _ in 0 ..= options.rounds { + aes.seal_gcm(ctx, buf, tag[:], nonce[:], nil, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + return nil +} + +@(private) +benchmark_print :: proc(str: ^strings.Builder, name: string, options: ^time.Benchmark_Options, loc := #caller_location) { + fmt.sbprintfln(str, "[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", + name, + options.rounds, + options.processed, + time.duration_nanoseconds(options.duration), + options.rounds_per_second, + options.megabytes_per_second, + ) +} diff --git a/tests/benchmark/hash/benchmark_hash.odin b/tests/benchmark/hash/benchmark_hash.odin new file mode 100644 index 000000000..84eb827e7 --- /dev/null +++ b/tests/benchmark/hash/benchmark_hash.odin @@ -0,0 +1,218 @@ +package benchmark_core_hash + +import "core:fmt" +import "core:hash/xxhash" +import "base:intrinsics" +import "core:strings" +import "core:testing" +import "core:time" + +@(test) +benchmark_hash :: proc(t: ^testing.T) { + str: strings.Builder + strings.builder_init(&str, context.allocator) + defer { + fmt.println(strings.to_string(str)) + strings.builder_destroy(&str) + } + + { + name := "XXH32 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh32, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x85f6413c) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH32 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh32, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x9430f97f) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH64 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x17bb1103c92c502f) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH64 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x87d2a1b6e1163ef1) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH3_64 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh3_64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x801fedc74ccd608c) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH3_64 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh3_64, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x918780b90550bf34) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH3_128 100 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 100, + setup = setup_xxhash, + bench = benchmark_xxh3_128, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0x6ba30a4e9dffe1ff801fedc74ccd608c) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } + { + name := "XXH3_128 1 MiB zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 1_048_576, + setup = setup_xxhash, + bench = benchmark_xxh3_128, + teardown = teardown_xxhash, + } + err := time.benchmark(options, context.allocator) + testing.expectf(t, err == nil, "%s failed with err %v", name, err) + hash := u128(0xb6ef17a3448492b6918780b90550bf34) + testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) + benchmark_print(&str, name, options) + } +} + +// Benchmarks + +setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + assert(options != nil) + + options.input = make([]u8, options.bytes, allocator) + return nil if len(options.input) == options.bytes else .Allocation_Error +} + +teardown_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + assert(options != nil) + + delete(options.input) + return nil +} + +benchmark_xxh32 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + + h: u32 + for _ in 0..=options.rounds { + h = xxhash.XXH32(buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + options.hash = u128(h) + return nil +} + +benchmark_xxh64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + + h: u64 + for _ in 0..=options.rounds { + h = xxhash.XXH64(buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + options.hash = u128(h) + return nil +} + +benchmark_xxh3_64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + + h: u64 + for _ in 0..=options.rounds { + h = xxhash.XXH3_64(buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + options.hash = u128(h) + return nil +} + +benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + + h: u128 + for _ in 0..=options.rounds { + h = xxhash.XXH3_128(buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + options.hash = h + return nil +} + +benchmark_print :: proc(str: ^strings.Builder, name: string, options: ^time.Benchmark_Options, loc := #caller_location) { + fmt.sbprintfln(str, "[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", + name, + options.rounds, + options.processed, + time.duration_nanoseconds(options.duration), + options.rounds_per_second, + options.megabytes_per_second, + ) +} \ No newline at end of file diff --git a/tests/core/crypto/test_crypto_benchmark.odin b/tests/core/crypto/test_crypto_benchmark.odin deleted file mode 100644 index 5bfc579bd..000000000 --- a/tests/core/crypto/test_crypto_benchmark.odin +++ /dev/null @@ -1,353 +0,0 @@ -package test_core_crypto - -import "base:runtime" -import "core:encoding/hex" -import "core:log" -import "core:testing" -import "core:time" - -import "core:crypto/aes" -import "core:crypto/chacha20" -import "core:crypto/chacha20poly1305" -import "core:crypto/ed25519" -import "core:crypto/poly1305" -import "core:crypto/x25519" - -// Cryptographic primitive benchmarks. - -@(test) -bench_crypto :: proc(t: ^testing.T) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - bench_chacha20(t) - bench_poly1305(t) - bench_chacha20poly1305(t) - bench_aes256_gcm(t) - bench_ed25519(t) - bench_x25519(t) -} - -_setup_sized_buf :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - assert(options != nil) - - options.input = make([]u8, options.bytes, allocator) - return nil if len(options.input) == options.bytes else .Allocation_Error -} - -_teardown_sized_buf :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - assert(options != nil) - - delete(options.input) - return nil -} - -_benchmark_chacha20 :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [chacha20.KEY_SIZE]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - nonce := [chacha20.NONCE_SIZE]byte { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - } - - ctx: chacha20.Context = --- - chacha20.init(&ctx, key[:], nonce[:]) - - for _ in 0 ..= options.rounds { - chacha20.xor_bytes(&ctx, buf, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -_benchmark_poly1305 :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [poly1305.KEY_SIZE]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - - tag: [poly1305.TAG_SIZE]byte = --- - for _ in 0 ..= options.rounds { - poly1305.sum(tag[:], buf, key[:]) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - //options.hash = u128(h) - return nil -} - -_benchmark_chacha20poly1305 :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [chacha20.KEY_SIZE]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - nonce := [chacha20.NONCE_SIZE]byte { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - } - - tag: [chacha20poly1305.TAG_SIZE]byte = --- - - for _ in 0 ..= options.rounds { - chacha20poly1305.encrypt(buf, tag[:], key[:], nonce[:], nil, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -_benchmark_aes256_gcm :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - nonce: [aes.GCM_NONCE_SIZE]byte - tag: [aes.GCM_TAG_SIZE]byte = --- - - ctx := transmute(^aes.Context_GCM)context.user_ptr - - for _ in 0 ..= options.rounds { - aes.seal_gcm(ctx, buf, tag[:], nonce[:], nil, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { - log.infof( - "\n\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s", - name, - options.rounds, - options.processed, - time.duration_nanoseconds(options.duration), - options.rounds_per_second, - options.megabytes_per_second, - ) -} - -bench_chacha20 :: proc(t: ^testing.T) { - name := "ChaCha20 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_chacha20, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "ChaCha20 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "ChaCha20 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) -} - -bench_poly1305 :: proc(t: ^testing.T) { - name := "Poly1305 64 zero bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_poly1305, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "Poly1305 1024 zero bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) -} - -bench_chacha20poly1305 :: proc(t: ^testing.T) { - name := "chacha20poly1305 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_chacha20poly1305, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "chacha20poly1305 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "chacha20poly1305 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) -} - -bench_aes256_gcm :: proc(t: ^testing.T) { - name := "AES256-GCM 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_aes256_gcm, - teardown = _teardown_sized_buf, - } - - key := [aes.KEY_SIZE_256]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - ctx: aes.Context_GCM - aes.init_gcm(&ctx, key[:]) - - context.user_ptr = &ctx - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "AES256-GCM 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) - - name = "AES256-GCM 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(name, options) -} - -bench_ed25519 :: proc(t: ^testing.T) { - iters :: 10000 - - priv_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" - priv_bytes, _ := hex.decode(transmute([]byte)(priv_str), context.temp_allocator) - priv_key: ed25519.Private_Key - start := time.now() - for i := 0; i < iters; i = i + 1 { - ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) - assert(ok, "private key should deserialize") - } - elapsed := time.since(start) - log.infof( - "ed25519.private_key_set_bytes: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - - pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing" - pub_key: ed25519.Public_Key - start = time.now() - for i := 0; i < iters; i = i + 1 { - ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:]) - assert(ok, "public key should deserialize") - } - elapsed = time.since(start) - log.infof( - "ed25519.public_key_set_bytes: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - - msg := "Got a job for you, 621." - sig_bytes: [ed25519.SIGNATURE_SIZE]byte - msg_bytes := transmute([]byte)(msg) - start = time.now() - for i := 0; i < iters; i = i + 1 { - ed25519.sign(&priv_key, msg_bytes, sig_bytes[:]) - } - elapsed = time.since(start) - log.infof( - "ed25519.sign: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - - start = time.now() - for i := 0; i < iters; i = i + 1 { - ok := ed25519.verify(&pub_key, msg_bytes, sig_bytes[:]) - assert(ok, "signature should validate") - } - elapsed = time.since(start) - log.infof( - "ed25519.verify: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) -} - -bench_x25519 :: proc(t: ^testing.T) { - point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" - - point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) - scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) - out: [x25519.POINT_SIZE]byte = --- - - iters :: 10000 - start := time.now() - for i := 0; i < iters; i = i + 1 { - x25519.scalarmult(out[:], scalar[:], point[:]) - } - elapsed := time.since(start) - - log.infof( - "x25519.scalarmult: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) -} diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index a6294de55..c332383e7 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -2,10 +2,7 @@ package test_core_hash import "core:hash/xxhash" import "core:hash" -import "core:time" import "core:testing" -import "core:fmt" -import "core:log" import "core:math/rand" import "base:intrinsics" @@ -78,15 +75,10 @@ test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) { xxh3_64 := xxhash.XXH3_64_digest(xxh3_64_state) xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state) - xxh32_error := fmt.tprintf("[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) - xxh64_error := fmt.tprintf("[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) - xxh3_64_error := fmt.tprintf("[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) - xxh3_128_error := fmt.tprintf("[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) - - testing.expect(t, xxh32 == v.xxh_32, xxh32_error) - testing.expect(t, xxh64 == v.xxh_64, xxh64_error) - testing.expect(t, xxh3_64 == v.xxh3_64, xxh3_64_error) - testing.expect(t, xxh3_128 == v.xxh3_128, xxh3_128_error) + testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) } } @@ -174,220 +166,4 @@ test_crc64_vectors :: proc(t: ^testing.T) { testing.expectf(t, iso == expected[2], "[ CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[2], iso) testing.expectf(t, iso2 == expected[3], "[~CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[3], iso2) } -} - -@(test) -test_benchmark_xxh32 :: proc(t: ^testing.T) { - name := "XXH32 100 zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 100, - setup = setup_xxhash, - bench = benchmark_xxh32, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x85f6413c) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh32_1MB :: proc(t: ^testing.T) { - name := "XXH32 1 MiB zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 1_048_576, - setup = setup_xxhash, - bench = benchmark_xxh32, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x9430f97f) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh64 :: proc(t: ^testing.T) { - name := "XXH64 100 zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 100, - setup = setup_xxhash, - bench = benchmark_xxh64, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x17bb1103c92c502f) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh64_1MB :: proc(t: ^testing.T) { - name := "XXH64 1 MiB zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 1_048_576, - setup = setup_xxhash, - bench = benchmark_xxh64, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x87d2a1b6e1163ef1) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh3_64 :: proc(t: ^testing.T) { - name := "XXH3_64 100 zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 100, - setup = setup_xxhash, - bench = benchmark_xxh3_64, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x801fedc74ccd608c) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh3_64_1MB :: proc(t: ^testing.T) { - name := "XXH3_64 1 MiB zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 1_048_576, - setup = setup_xxhash, - bench = benchmark_xxh3_64, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x918780b90550bf34) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh3_128 :: proc(t: ^testing.T) { - name := "XXH3_128 100 zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 100, - setup = setup_xxhash, - bench = benchmark_xxh3_128, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0x6ba30a4e9dffe1ff801fedc74ccd608c) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -@(test) -test_benchmark_xxh3_128_1MB :: proc(t: ^testing.T) { - name := "XXH3_128 1 MiB zero bytes" - options := &time.Benchmark_Options{ - rounds = 1_000, - bytes = 1_048_576, - setup = setup_xxhash, - bench = benchmark_xxh3_128, - teardown = teardown_xxhash, - } - err := time.benchmark(options, context.allocator) - testing.expectf(t, err == nil, "%s failed with err %v", name, err) - hash := u128(0xb6ef17a3448492b6918780b90550bf34) - testing.expectf(t, options.hash == hash, "%v hash expected to be %v, got %v", name, hash, options.hash) - benchmark_print(name, options) -} - -// Benchmarks - -setup_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - assert(options != nil) - - options.input = make([]u8, options.bytes, allocator) - return nil if len(options.input) == options.bytes else .Allocation_Error -} - -teardown_xxhash :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - assert(options != nil) - - delete(options.input) - return nil -} - -benchmark_xxh32 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - buf := options.input - - h: u32 - for _ in 0..=options.rounds { - h = xxhash.XXH32(buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - options.hash = u128(h) - return nil -} - -benchmark_xxh64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - buf := options.input - - h: u64 - for _ in 0..=options.rounds { - h = xxhash.XXH64(buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - options.hash = u128(h) - return nil -} - -benchmark_xxh3_64 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - buf := options.input - - h: u64 - for _ in 0..=options.rounds { - h = xxhash.XXH3_64(buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - options.hash = u128(h) - return nil -} - -benchmark_xxh3_128 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { - buf := options.input - - h: u128 - for _ in 0..=options.rounds { - h = xxhash.XXH3_128(buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - options.hash = h - return nil -} - -benchmark_print :: proc(name: string, options: ^time.Benchmark_Options, loc := #caller_location) { - log.infof("\n\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s", - name, - options.rounds, - options.processed, - time.duration_nanoseconds(options.duration), - options.rounds_per_second, - options.megabytes_per_second, - location=loc, - ) } \ No newline at end of file From 54dae06ad1d727a6607024cf7d118e53e9981289 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 20:19:17 +0200 Subject: [PATCH 60/93] Update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67b2bfbda..7180fbd15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -261,7 +261,7 @@ jobs: cd tests\core\math\big call build.bat timeout-minutes: 10 - - name: core library benchmarks + - name: Core library benchmarks shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat From 3354212f8eda24f1807bc04247911db000c0159f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 31 May 2024 20:32:25 +0200 Subject: [PATCH 61/93] Update ci.yml Disable benchmark on Windows for a moment. --- .github/workflows/ci.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7180fbd15..2ee557846 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -261,13 +261,6 @@ jobs: cd tests\core\math\big call build.bat timeout-minutes: 10 - - name: Core library benchmarks - shell: cmd - run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - cd tests\benchmark - call build.bat - timeout-minutes: 10 - name: Odin check examples/all for Windows 32bits shell: cmd run: | From 306169699c6f59d910fc38e357124de6f93c78dd Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 1 Jun 2024 13:07:40 +0200 Subject: [PATCH 62/93] Update ci.yml --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ee557846..c5493775f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,6 +233,13 @@ jobs: cd tests\core call build.bat timeout-minutes: 10 + - name: Core library benchmarks + shell: cmd + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat + cd tests\benchmark + call build.bat + timeout-minutes: 10 - name: Vendor library tests shell: cmd run: | From 6050bc3bf66f5b2159f339a1b62f855fd774b966 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 1 Jun 2024 13:17:59 +0200 Subject: [PATCH 63/93] Add missing benchmarks build.bat. --- tests/benchmark/build.bat | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/benchmark/build.bat diff --git a/tests/benchmark/build.bat b/tests/benchmark/build.bat new file mode 100644 index 000000000..e9051855b --- /dev/null +++ b/tests/benchmark/build.bat @@ -0,0 +1,13 @@ +@echo off +set COMMON=-no-bounds-check -vet -strict-style +set PATH_TO_ODIN==..\..\odin + +echo --- +echo Running core:crypto benchmarks +echo --- +%PATH_TO_ODIN% test crypto %COMMON% -o:speed -out:bench_crypto.exe || exit /b + +echo --- +echo Running core:hash benchmarks +echo --- +%PATH_TO_ODIN% test hash %COMMON% -o:speed -out:bench_hash.exe || exit /b \ No newline at end of file From fb37572c4ce9d8058cd73c0b7c21c1ecd2fdad65 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 30 May 2024 17:02:32 -0400 Subject: [PATCH 64/93] Rename `signal_handler.odin` to `signal_handler_libc.odin` --- core/testing/{signal_handler.odin => signal_handler_libc.odin} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/testing/{signal_handler.odin => signal_handler_libc.odin} (100%) diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler_libc.odin similarity index 100% rename from core/testing/signal_handler.odin rename to core/testing/signal_handler_libc.odin From d1723664a79a5818e8b43dc43210270dfdcb7b92 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 30 May 2024 17:46:28 -0400 Subject: [PATCH 65/93] Catch `SIGILL`, `SIGFPE`, `SIGSEGV` in the test runner --- core/testing/runner.odin | 65 ++++++++++++- core/testing/signal_handler.odin | 33 +++++++ core/testing/signal_handler_libc.odin | 126 +++++++++++++++++++++++-- core/testing/signal_handler_other.odin | 12 ++- 4 files changed, 224 insertions(+), 12 deletions(-) create mode 100644 core/testing/signal_handler.odin diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 47ae5d528..63b3864dd 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -69,6 +69,8 @@ Task_Timeout :: struct { run_test_task :: proc(task: thread.Task) { data := cast(^Task_Data)(task.data) + setup_task_signal_handler(task.user_index) + chan.send(data.t.channel, Event_New_Test { test_index = task.user_index, }) @@ -76,6 +78,8 @@ run_test_task :: proc(task: thread.Task) { chan.send(data.t.channel, Event_State_Change { new_state = .Running, }) + + context.assertion_failure_proc = test_assertion_failure_proc context.logger = { procedure = test_logger_proc, @@ -389,6 +393,8 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_HIDE) when FANCY_OUTPUT { + signals_were_raised := false + redraw_report(stdout, report) draw_status_bar(stdout, thread_count_status_string, total_done_count, total_test_count) } @@ -557,12 +563,57 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } - if should_abort() { + if should_stop_runner() { fmt.wprintln(stderr, "\nCaught interrupt signal. Stopping all tests.") thread.pool_shutdown(&pool) break main_loop } + when FANCY_OUTPUT { + // Because the bounds checking procs send directly to STDERR with + // no way to redirect or handle them, we need to at least try to + // let the user see those messages when using the animated progress + // report. This flag may be set by the block of code below if a + // signal is raised. + // + // It'll be purely by luck if the output is interleaved properly, + // given the nature of non-thread-safe printing. + // + // At worst, if Odin did not print any error for this signal, we'll + // just re-display the progress report. The fatal log error message + // should be enough to clue the user in that something dire has + // occurred. + bypass_progress_overwrite := false + } + + if test_index, reason, ok := should_stop_test(); ok { + #no_bounds_check report.all_test_states[test_index] = .Failed + #no_bounds_check it := internal_tests[test_index] + #no_bounds_check pkg := report.packages_by_name[it.pkg] + pkg.frame_ready = false + + fmt.assertf(thread.pool_stop_task(&pool, test_index), + "A signal (%v) was raised to stop test #%i %s.%s, but it was unable to be found.", + reason, test_index, it.pkg, it.name) + + if test_index not_in failed_test_reason_map { + // We only write a new error message here if there wasn't one + // already, because the message we can provide based only on + // the signal won't be very useful, whereas asserts and panics + // will provide a user-written error message. + failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator) + pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) + + when FANCY_OUTPUT { + signals_were_raised = true + bypass_progress_overwrite = true + } + } + + total_failure_count += 1 + total_done_count += 1 + } + // -- Redraw. when FANCY_OUTPUT { @@ -570,7 +621,9 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { continue main_loop } - fmt.wprintf(stdout, ansi_redraw_string, total_done_count, total_test_count) + if !bypass_progress_overwrite { + fmt.wprintf(stdout, ansi_redraw_string, total_done_count, total_test_count) + } } else { if total_done_count != last_done_count { fmt.wprintf(stdout, OSC_WINDOW_TITLE, total_done_count, total_test_count) @@ -698,6 +751,14 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_SHOW) + when FANCY_OUTPUT { + if signals_were_raised { + fmt.wprintln(batch_writer, ` +Signals were raised during this test run. Log messages are likely to have collided with each other. +To partly mitigate this, redirect STDERR to a file or use the -define:ODIN_TEST_FANCY=false option.`) + } + } + fmt.wprintln(stderr, bytes.buffer_to_string(&batch_buffer)) return total_success_count == total_test_count diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler.odin new file mode 100644 index 000000000..891f6bbb6 --- /dev/null +++ b/core/testing/signal_handler.odin @@ -0,0 +1,33 @@ +//+private +package testing + +import "base:runtime" +import pkg_log "core:log" + +Stop_Reason :: enum { + Unknown, + Illegal_Instruction, + Arithmetic_Error, + Segmentation_Fault, +} + +test_assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { + pkg_log.fatalf("%s: %s", prefix, message, location = loc) + runtime.trap() +} + +setup_signal_handler :: proc() { + _setup_signal_handler() +} + +setup_task_signal_handler :: proc(test_index: int) { + _setup_task_signal_handler(test_index) +} + +should_stop_runner :: proc() -> bool { + return _should_stop_runner() +} + +should_stop_test :: proc() -> (test_index: int, reason: Stop_Reason, ok: bool) { + return _should_stop_test() +} diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index 2dd0ff192..ff3dbe135 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -4,16 +4,126 @@ package testing import "base:intrinsics" import "core:c/libc" +import "core:encoding/ansi" +import "core:sync" + +@(private="file") stop_runner_flag: libc.sig_atomic_t + +@(private="file") stop_test_gate: sync.Mutex +@(private="file") stop_test_index: libc.sig_atomic_t +@(private="file") stop_test_reason: libc.sig_atomic_t +@(private="file") stop_test_alert: libc.sig_atomic_t + +@(private="file", thread_local) +local_test_index: libc.sig_atomic_t @(private="file") -abort_flag: libc.sig_atomic_t - -setup_signal_handler :: proc() { - libc.signal(libc.SIGINT, proc "c" (sig: libc.int) { - intrinsics.atomic_add(&abort_flag, 1) - }) +stop_runner_callback :: proc "c" (sig: libc.int) { + intrinsics.atomic_store(&stop_runner_flag, 1) } -should_abort :: proc() -> bool { - return intrinsics.atomic_load(&abort_flag) > 0 +@(private="file") +stop_test_callback :: proc "c" (sig: libc.int) { + if local_test_index == -1 { + // We're the test runner, and we ourselves have caught a signal from + // which there is no recovery. + // + // The most we can do now is make sure the user's cursor is visible, + // nuke the entire processs, and hope a useful core dump survives. + + // NOTE(Feoramund): Using these write calls in a signal handler is + // undefined behavior in C99 but possibly tolerated in POSIX 2008. + // Either way, we may as well try to salvage what we can. + show_cursor := ansi.CSI + ansi.DECTCEM_SHOW + libc.fwrite(raw_data(show_cursor), size_of(byte), len(show_cursor), libc.stdout) + libc.fflush(libc.stdout) + + // This is an attempt at being compliant by avoiding printf. + sigbuf: [8]byte + sigstr: string + { + signum := cast(int)sig + i := len(sigbuf) - 2 + for signum > 0 { + m := signum % 10 + signum /= 10 + sigbuf[i] = cast(u8)('0' + m) + i -= 1 + } + sigstr = cast(string)sigbuf[i:] + } + + advisory_a := ` +The test runner's main thread has caught an unrecoverable error (signal ` + advisory_b := `) and will now forcibly terminate. +This is a dire bug and should be reported to the Odin developers. +` + libc.fwrite(raw_data(advisory_a), size_of(byte), len(advisory_a), libc.stderr) + libc.fwrite(raw_data(sigstr), size_of(byte), len(sigstr), libc.stderr) + libc.fwrite(raw_data(advisory_b), size_of(byte), len(advisory_b), libc.stderr) + + // Try to get a core dump. + libc.abort() + } + + if sync.mutex_guard(&stop_test_gate) { + intrinsics.atomic_store(&stop_test_index, local_test_index) + intrinsics.atomic_store(&stop_test_reason, cast(libc.sig_atomic_t)sig) + intrinsics.atomic_store(&stop_test_alert, 1) + + for { + // Idle until this thread is terminated by the runner, + // otherwise we may continue to generate signals. + intrinsics.cpu_relax() + } + } +} + +_setup_signal_handler :: proc() { + local_test_index = -1 + + // Catch user interrupt / CTRL-C. + libc.signal(libc.SIGINT, stop_runner_callback) + // Catch polite termination request. + libc.signal(libc.SIGTERM, stop_runner_callback) + + // For tests: + // Catch asserts and panics. + libc.signal(libc.SIGILL, stop_test_callback) + // Catch arithmetic errors. + libc.signal(libc.SIGFPE, stop_test_callback) + // Catch segmentation faults (illegal memory access). + libc.signal(libc.SIGSEGV, stop_test_callback) +} + +_setup_task_signal_handler :: proc(test_index: int) { + local_test_index = cast(libc.sig_atomic_t)test_index +} + +_should_stop_runner :: proc() -> bool { + return intrinsics.atomic_load(&stop_runner_flag) == 1 +} + +@(private="file") +unlock_stop_test_gate :: proc(_: int, _: Stop_Reason, ok: bool) { + if ok { + sync.mutex_unlock(&stop_test_gate) + } +} + +@(deferred_out=unlock_stop_test_gate) +_should_stop_test :: proc() -> (test_index: int, reason: Stop_Reason, ok: bool) { + if intrinsics.atomic_load(&stop_test_alert) == 1 { + intrinsics.atomic_store(&stop_test_alert, 0) + + test_index = cast(int)intrinsics.atomic_load(&stop_test_index) + switch intrinsics.atomic_load(&stop_test_reason) { + case libc.SIGFPE: reason = .Arithmetic_Error + case libc.SIGILL: reason = .Illegal_Instruction + case libc.SIGSEGV: reason = .Segmentation_Fault + } + ok = true + } + + return } diff --git a/core/testing/signal_handler_other.odin b/core/testing/signal_handler_other.odin index b2e2ea906..8621349f0 100644 --- a/core/testing/signal_handler_other.odin +++ b/core/testing/signal_handler_other.odin @@ -2,10 +2,18 @@ //+build js, wasi, freestanding package testing -setup_signal_handler :: proc() { +_setup_signal_handler :: proc() { // Do nothing. } -should_abort :: proc() -> bool { +_setup_task_signal_handler :: proc(test_index: int) { + // Do nothing. +} + +_should_stop_runner :: proc() -> bool { return false } + +_should_stop_test :: proc() -> (test_index: int, reason: Stop_Reason, ok: bool) { + return 0, {}, false +} From 433ca538bfccdfca9704942c4575b582b36db9ad Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 30 May 2024 18:01:22 -0400 Subject: [PATCH 66/93] Be specific about platforms not implementing test runner signal handler --- core/testing/signal_handler_other.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/testing/signal_handler_other.odin b/core/testing/signal_handler_other.odin index 8621349f0..04981f5af 100644 --- a/core/testing/signal_handler_other.odin +++ b/core/testing/signal_handler_other.odin @@ -1,5 +1,5 @@ //+private -//+build js, wasi, freestanding +//+build !windows !linux !darwin !freebsd !openbsd !netbsd !haiku package testing _setup_signal_handler :: proc() { From 6a5d51f0d6c82d350e9082c1132fd1f48720d4c0 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Fri, 31 May 2024 15:45:06 -0400 Subject: [PATCH 67/93] Use more concise way of satisfying `-vet` --- core/testing/runner.odin | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 63b3864dd..64c1ad760 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -5,23 +5,18 @@ import "base:intrinsics" import "base:runtime" import "core:bytes" import "core:encoding/ansi" -import "core:encoding/base64" +@require import "core:encoding/base64" import "core:fmt" import "core:io" -import pkg_log "core:log" +@require import pkg_log "core:log" import "core:mem" import "core:os" import "core:slice" -import "core:strings" +@require import "core:strings" import "core:sync/chan" import "core:thread" import "core:time" -// Keep `-vet` happy. -base64_encode :: base64.encode -_ :: pkg_log -_ :: strings - // Specify how many threads to use when running tests. TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0) // Track the memory used by each test. @@ -728,7 +723,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.wprintf(clipboard_writer, "%s.%s,", it.pkg, it.name) } - encoded_names := base64_encode(bytes.buffer_to_bytes(&clipboard_buffer), allocator = context.temp_allocator) + encoded_names := base64.encode(bytes.buffer_to_bytes(&clipboard_buffer), allocator = context.temp_allocator) fmt.wprintf(batch_writer, ansi.OSC + ansi.CLIPBOARD + ";c;%s" + ansi.ST + From cb8faf5b74cd0863e226908d2bebd4829b71cbc8 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:04:20 -0400 Subject: [PATCH 68/93] Remove `-test-name` in favor of test runner option `-define:ODIN_TEST_NAMES=...` is capable of selecting test by package and name or name only, with the ability to access packages included by `-all-packages`. --- src/build_settings.cpp | 1 - src/checker.cpp | 29 ----------------------------- src/main.cpp | 24 ------------------------ 3 files changed, 54 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 376e56a8e..7bdec376b 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -893,7 +893,6 @@ struct BuildContext { u32 cmd_doc_flags; Array extra_packages; - StringSet test_names; bool test_all_packages; gbAffinity affinity; diff --git a/src/checker.cpp b/src/checker.cpp index 2fd274975..97e685d33 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5852,35 +5852,6 @@ gb_internal void remove_neighbouring_duplicate_entires_from_sorted_array(Arrayinfo.testing_procedures, init_procedures_cmp); remove_neighbouring_duplicate_entires_from_sorted_array(&c->info.testing_procedures); - - if (build_context.test_names.entries.count == 0) { - return; - } - - AstPackage *pkg = c->info.init_package; - Scope *s = pkg->scope; - - for (String const &name : build_context.test_names) { - Entity *e = scope_lookup(s, name); - if (e == nullptr) { - Token tok = {}; - if (pkg->files.count != 0) { - tok = pkg->files[0]->tokens[0]; - } - error(tok, "Unable to find the test '%.*s' in 'package %.*s' ", LIT(name), LIT(pkg->name)); - } - } - - for (isize i = 0; i < c->info.testing_procedures.count; /**/) { - Entity *e = c->info.testing_procedures[i]; - String name = e->token.string; - if (!string_set_exists(&build_context.test_names, name)) { - array_ordered_remove(&c->info.testing_procedures, i); - } else { - i += 1; - } - } - } diff --git a/src/main.cpp b/src/main.cpp index 4df6f97d5..e7f076c7c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -276,8 +276,6 @@ enum BuildFlagKind { BuildFlag_RelocMode, BuildFlag_DisableRedZone, - BuildFlag_TestName, - BuildFlag_DisallowDo, BuildFlag_DefaultToNilAllocator, BuildFlag_DefaultToPanicAllocator, @@ -471,8 +469,6 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); - add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_DefaultToPanicAllocator, str_lit("default-to-panic-allocator"),BuildFlagParam_None, Command__does_check); @@ -1119,21 +1115,6 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_DisableRedZone: build_context.disable_red_zone = true; break; - case BuildFlag_TestName: { - GB_ASSERT(value.kind == ExactValue_String); - { - String name = value.value_string; - if (!string_is_valid_identifier(name)) { - gb_printf_err("Test name '%.*s' must be a valid identifier\n", LIT(name)); - bad_flags = true; - break; - } - string_set_add(&build_context.test_names, name); - - // NOTE(bill): Allow for multiple -test-name - continue; - } - } case BuildFlag_DisallowDo: build_context.disallow_do = true; break; @@ -1962,10 +1943,6 @@ gb_internal void print_show_help(String const arg0, String const &command) { } if (test_only) { - print_usage_line(1, "-test-name:"); - print_usage_line(2, "Runs specific test only by name."); - print_usage_line(0, ""); - print_usage_line(1, "-all-packages"); print_usage_line(2, "Tests all packages imported into the given initial package."); print_usage_line(0, ""); @@ -2489,7 +2466,6 @@ int main(int arg_count, char const **arg_ptr) { TIME_SECTION("init args"); map_init(&build_context.defined_values); build_context.extra_packages.allocator = heap_allocator(); - string_set_init(&build_context.test_names); Array args = setup_args(arg_count, arg_ptr); From 45fa9d81487e89b88e4b5cd22803be45ea341f85 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:12:51 -0400 Subject: [PATCH 69/93] Expand documentation comment for `ODIN_TEST_NAMES` --- core/testing/runner.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 64c1ad760..9027750da 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -26,6 +26,9 @@ ALWAYS_REPORT_MEMORY : bool : #config(ODIN_TEST_ALWAYS_REPORT_MEMORY, false) // Specify how much memory each thread allocator starts with. PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE) // Select a specific set of tests to run by name. +// Each test is separated by a comma and may optionally include the package name. +// This may be useful when running tests on multiple packages with `-all-packages`. +// The format is: `package.test_name,test_name_only,...` TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") // Show the fancy animated progress report. FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) From 21064fbb60ac9b3a838b100e4718e1e66dfdf80f Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:15:27 -0400 Subject: [PATCH 70/93] Clear thread pool task data on restart --- core/thread/thread_pool.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 53f89ea0c..6d80cb619 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -180,6 +180,7 @@ pool_stop_task :: proc(pool: ^Pool, user_index: int, exit_code: int = 1) -> bool replacement := create(pool_thread_runner) replacement.user_index = t.user_index replacement.data = data + data.task = {} pool.threads[i] = replacement start(replacement) @@ -211,6 +212,7 @@ pool_stop_all_tasks :: proc(pool: ^Pool, exit_code: int = 1) { replacement := create(pool_thread_runner) replacement.user_index = t.user_index replacement.data = data + data.task = {} pool.threads[i] = replacement start(replacement) From 9dcf3457952c32e34baa9136c5c4163cb4a55ceb Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:16:14 -0400 Subject: [PATCH 71/93] Set thread pool `is_running` to false on shutdown --- core/thread/thread_pool.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 6d80cb619..da5e116ff 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -225,6 +225,7 @@ pool_stop_all_tasks :: proc(pool: ^Pool, exit_code: int = 1) { // // The pool must still be destroyed after this. pool_shutdown :: proc(pool: ^Pool, exit_code: int = 1) { + intrinsics.atomic_store(&pool.is_running, false) sync.guard(&pool.mutex) for t in pool.threads { From ccdbd4b6cecfb5712edac97d9b22cc37c141a542 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:30:02 -0400 Subject: [PATCH 72/93] Simplify casts in `mem.Rollback_Stack` procs --- core/mem/rollback_stack_allocator.odin | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index d159897cd..f5e428d87 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -63,9 +63,9 @@ Rollback_Stack :: struct { @(private="file", require_results) rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool { - start := cast(uintptr)raw_data(block.buffer) - end := cast(uintptr)raw_data(block.buffer) + block.offset - return start < cast(uintptr)ptr && cast(uintptr)ptr <= end + start := raw_data(block.buffer) + end := start[block.offset:] + return start < ptr && ptr <= end } @(private="file", require_results) @@ -105,8 +105,8 @@ rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_ header := header for block.offset > 0 && header.is_free { block.offset = header.prev_offset - block.last_alloc = cast(rawptr)(cast(uintptr)raw_data(block.buffer) + cast(uintptr)header.prev_ptr) - header = cast(^Rollback_Stack_Header)(cast(uintptr)raw_data(block.buffer) + cast(uintptr)header.prev_ptr - size_of(Rollback_Stack_Header)) + block.last_alloc = raw_data(block.buffer)[header.prev_ptr:] + header = cast(^Rollback_Stack_Header)(raw_data(block.buffer)[header.prev_ptr - size_of(Rollback_Stack_Header):]) } } @@ -189,8 +189,8 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt } } - start := cast(uintptr)raw_data(block.buffer) + block.offset - padding := cast(uintptr)calc_padding_with_header(start, cast(uintptr)alignment, size_of(Rollback_Stack_Header)) + start := raw_data(block.buffer)[block.offset:] + padding := cast(uintptr)calc_padding_with_header(cast(uintptr)start, cast(uintptr)alignment, size_of(Rollback_Stack_Header)) if block.offset + padding + cast(uintptr)size > cast(uintptr)len(block.buffer) { when !ODIN_DISABLE_ASSERT { @@ -202,8 +202,8 @@ rb_alloc :: proc(stack: ^Rollback_Stack, size, alignment: int) -> (result: []byt continue } - header := cast(^Rollback_Stack_Header)(start + cast(uintptr)padding - size_of(Rollback_Stack_Header)) - ptr := (cast([^]byte)(start + cast(uintptr)padding)) + header := cast(^Rollback_Stack_Header)(start[padding - size_of(Rollback_Stack_Header):]) + ptr := start[padding:] header^ = { prev_offset = block.offset, From 4875f745c832119e634197a7eb6403a30f82a95b Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:42:23 -0400 Subject: [PATCH 73/93] Remove Windows test runner in favor of `libc` implementation --- core/testing/runner.odin | 2 +- core/testing/runner_other.odin | 8 - core/testing/runner_windows.odin | 242 ------------------------------- 3 files changed, 1 insertion(+), 251 deletions(-) delete mode 100644 core/testing/runner_other.odin delete mode 100644 core/testing/runner_windows.odin diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 9027750da..8b156eb22 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -88,7 +88,7 @@ run_test_task :: proc(task: thread.Task) { free_all(context.temp_allocator) - run_internal_test(&data.t, data.it) + data.it.p(&data.t) end_t(&data.t) diff --git a/core/testing/runner_other.odin b/core/testing/runner_other.odin deleted file mode 100644 index 29f338828..000000000 --- a/core/testing/runner_other.odin +++ /dev/null @@ -1,8 +0,0 @@ -//+private -//+build !windows -package testing - -run_internal_test :: proc(t: ^T, it: Internal_Test) { - // TODO(bill): Catch panics on other platforms - it.p(t) -} diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin deleted file mode 100644 index 23dab4f31..000000000 --- a/core/testing/runner_windows.odin +++ /dev/null @@ -1,242 +0,0 @@ -//+private -//+build windows -package testing - -run_internal_test :: proc(t: ^T, it: Internal_Test) { - it.p(t) -} - -// Temporarily disabled during multi-threaded test runner refactor. -/* -import win32 "core:sys/windows" -import "base:runtime" -import "base:intrinsics" -import "core:time" - -Sema :: struct { - count: i32, -} - -sema_reset :: proc "contextless" (s: ^Sema) { - intrinsics.atomic_store(&s.count, 0) -} -sema_wait :: proc "contextless" (s: ^Sema) { - for { - original_count := s.count - for original_count == 0 { - win32.WaitOnAddress(&s.count, &original_count, size_of(original_count), win32.INFINITE) - original_count = s.count - } - if original_count == intrinsics.atomic_compare_exchange_strong(&s.count, original_count-1, original_count) { - return - } - } -} -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_compare_exchange_strong(&s.count, original_count-1, original_count) { - return true - } - } -} - -sema_post :: proc "contextless" (s: ^Sema, count := 1) { - intrinsics.atomic_add(&s.count, i32(count)) - if count == 1 { - win32.WakeByAddressSingle(&s.count) - } else { - win32.WakeByAddressAll(&s.count) - } -} - - - -Thread_Proc :: #type proc(^Thread) - -MAX_USER_ARGUMENTS :: 8 - -Thread :: struct { - using specific: Thread_Os_Specific, - procedure: Thread_Proc, - - t: ^T, - it: Internal_Test, - success: bool, - - init_context: Maybe(runtime.Context), - - creation_allocator: runtime.Allocator, - - internal_fail_timeout: time.Duration, - internal_fail_timeout_loc: runtime.Source_Code_Location, -} - -Thread_Os_Specific :: struct { - win32_thread: win32.HANDLE, - win32_thread_id: win32.DWORD, - done: bool, // see note in `is_done` -} - -thread_create :: proc(procedure: Thread_Proc) -> ^Thread { - __windows_thread_entry_proc :: proc "system" (t_: rawptr) -> win32.DWORD { - t := (^Thread)(t_) - context = t.init_context.? or_else runtime.default_context() - - t.procedure(t) - - if t.init_context == nil { - if context.temp_allocator.data == &runtime.global_default_temp_allocator_data { - runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data) - } - } - - intrinsics.atomic_store(&t.done, true) - return 0 - } - - - thread := new(Thread) - if thread == nil { - return nil - } - thread.creation_allocator = context.allocator - - win32_thread_id: win32.DWORD - win32_thread := win32.CreateThread(nil, 0, __windows_thread_entry_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id) - if win32_thread == nil { - free(thread, thread.creation_allocator) - return nil - } - thread.procedure = procedure - thread.win32_thread = win32_thread - thread.win32_thread_id = win32_thread_id - thread.init_context = context - - return thread -} - -thread_start :: proc "contextless" (thread: ^Thread) { - win32.ResumeThread(thread.win32_thread) -} - -thread_join_and_destroy :: proc(thread: ^Thread) { - if thread.win32_thread != win32.INVALID_HANDLE { - win32.WaitForSingleObject(thread.win32_thread, win32.INFINITE) - win32.CloseHandle(thread.win32_thread) - thread.win32_thread = win32.INVALID_HANDLE - } - free(thread, thread.creation_allocator) -} - -thread_terminate :: proc "contextless" (thread: ^Thread, exit_code: int) { - win32.TerminateThread(thread.win32_thread, u32(exit_code)) -} - - -_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) { - assert(global_fail_timeout_thread == nil, "set_fail_timeout previously called", loc) - - thread := thread_create(proc(thread: ^Thread) { - t := thread.t - timeout := thread.internal_fail_timeout - if !sema_wait_with_timeout(&global_fail_timeout_semaphore, timeout) { - fail_now(t, "TIMEOUT", thread.internal_fail_timeout_loc) - } - }) - thread.internal_fail_timeout = duration - thread.internal_fail_timeout_loc = loc - thread.t = t - global_fail_timeout_thread = thread - thread_start(thread) -} - -global_fail_timeout_thread: ^Thread -global_fail_timeout_semaphore: Sema - -global_threaded_runner_semaphore: Sema -global_exception_handler: rawptr -global_current_thread: ^Thread -global_current_t: ^T - -run_internal_test :: proc(t: ^T, it: Internal_Test) { - thread := thread_create(proc(thread: ^Thread) { - exception_handler_proc :: proc "system" (ExceptionInfo: ^win32.EXCEPTION_POINTERS) -> win32.LONG { - switch ExceptionInfo.ExceptionRecord.ExceptionCode { - case - win32.EXCEPTION_DATATYPE_MISALIGNMENT, - win32.EXCEPTION_BREAKPOINT, - win32.EXCEPTION_ACCESS_VIOLATION, - win32.EXCEPTION_ILLEGAL_INSTRUCTION, - win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED, - win32.EXCEPTION_STACK_OVERFLOW: - - sema_post(&global_threaded_runner_semaphore) - return win32.EXCEPTION_EXECUTE_HANDLER - } - - return win32.EXCEPTION_CONTINUE_SEARCH - } - global_exception_handler = win32.AddVectoredExceptionHandler(0, exception_handler_proc) - - context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { - errorf(global_current_t, "%s %s", prefix, message, loc=loc) - intrinsics.trap() - } - - t := thread.t - - global_fail_timeout_thread = nil - sema_reset(&global_fail_timeout_semaphore) - - thread.it.p(t) - - sema_post(&global_fail_timeout_semaphore) - if global_fail_timeout_thread != nil do thread_join_and_destroy(global_fail_timeout_thread) - - 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 -} -*/ From cb00b8022b5041b93a4b066e4b27c2a0368a377c Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 07:56:28 -0400 Subject: [PATCH 74/93] Add note about `SIGSEGV` edge case on UNIX-likes --- core/testing/runner.odin | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 8b156eb22..24b902005 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -659,6 +659,13 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { // -- All tests are complete, or the runner has been interrupted. + // NOTE(Feoramund): If you've arrived here after receiving signal 11 or + // SIGSEGV on the main runner thread, while using a UNIX-like platform, + // there is the possibility that you may have encountered a rare edge case + // involving the joining of threads. + // + // At the time of writing, the thread library is undergoing a rewrite that + // should solve this problem; it is not an issue with the test runner itself. thread.pool_join(&pool) finished_in := time.since(start_time) From 5db65aa796ef5dc2bfecf3a74d718e43ef5b40d0 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 08:16:40 -0400 Subject: [PATCH 75/93] Make it easier to learn about `ODIN_TEST_CLIPBOARD` --- core/testing/runner.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 24b902005..ddc01c919 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -748,6 +748,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { #no_bounds_check it := internal_tests[test_index] fmt.wprintf(batch_writer, "%s.%s,", it.pkg, it.name) } + fmt.wprint(batch_writer, "\n\nIf your terminal supports OSC 52, you may use -define:ODIN_TEST_CLIPBOARD to have this copied directly to your clipboard.") } fmt.wprintln(batch_writer) From 6a9203328bfd34c59abeb46d61f1cb5d238b24a7 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:03:36 -0400 Subject: [PATCH 76/93] Log thread count at test run start Provides a helpful info message about the option to change how many threads are used per run. --- core/testing/runner.odin | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index ddc01c919..4a45dabd1 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -397,6 +397,16 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { draw_status_bar(stdout, thread_count_status_string, total_done_count, total_test_count) } + when TEST_THREADS == 0 { + pkg_log.infof("Starting test runner with %i thread%s. Set with -define:ODIN_TEST_THREADS=n.", + thread_count, + "" if thread_count == 1 else "s") + } else { + pkg_log.infof("Starting test runner with %i thread%s.", + thread_count, + "" if thread_count == 1 else "s") + } + pkg_log.infof("The random seed sent to every test is: %v", shared_random_seed) when TRACKING_MEMORY { From 5e3e958574a7654a70382fb04cea2212f8652ff0 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:04:49 -0400 Subject: [PATCH 77/93] Add `-define:ODIN_TEST_LOG_LEVEL` to set lowest log level --- core/testing/runner.odin | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 4a45dabd1..dcc7c10ce 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -39,8 +39,23 @@ PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24) // This is the random seed that will be sent to each test. // If it is unspecified, it will be set to the system cycle counter at startup. SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) +// Set the lowest log level for this test run. +LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, "info") +get_log_level :: #force_inline proc() -> runtime.Logger_Level { + when ODIN_DEBUG { + // Always use .Debug in `-debug` mode. + return .Debug + } else { + when LOG_LEVEL == "debug" { return .Debug } + else when LOG_LEVEL == "info" { return .Info } + else when LOG_LEVEL == "warning" { return .Warning } + else when LOG_LEVEL == "error" { return .Error } + else when LOG_LEVEL == "fatal" { return .Fatal } + } +} + end_t :: proc(t: ^T) { for i := len(t.cleanups)-1; i >= 0; i -= 1 { #no_bounds_check c := t.cleanups[i] @@ -82,7 +97,7 @@ run_test_task :: proc(task: thread.Task) { context.logger = { procedure = test_logger_proc, data = &data.t, - lowest_level = .Debug if ODIN_DEBUG else .Info, + lowest_level = get_log_level(), options = Default_Test_Logger_Opts, } @@ -355,7 +370,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { context.logger = { procedure = runner_logger_proc, data = &log_messages, - lowest_level = .Debug if ODIN_DEBUG else .Info, + lowest_level = get_log_level(), options = Default_Test_Logger_Opts - {.Short_File_Path, .Line, .Procedure}, } From d581dbbec52a7ddcb8dbc986240a5d5092659450 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 14:28:02 -0400 Subject: [PATCH 78/93] Keep test runner main thread from using 100% of a CPU core --- core/testing/runner.odin | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index dcc7c10ce..fbe413bb2 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -439,6 +439,23 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { thread.pool_start(&pool) main_loop: for !thread.pool_is_empty(&pool) { + { + events_pending := thread.pool_num_done(&pool) > 0 + + if !events_pending { + poll_tasks: for &task_channel in task_channels { + if chan.len(task_channel.channel) > 0 { + events_pending = true + break poll_tasks + } + } + } + + if !events_pending { + // Keep the main thread from pegging a core at 100% usage. + time.sleep(1 * time.Microsecond) + } + } cycle_pool: for task in thread.pool_pop_done(&pool) { data := cast(^Task_Data)(task.data) From 890fe07c6e7e1e52407e458ea125d4d29b171c60 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 1 Jun 2024 19:59:20 -0400 Subject: [PATCH 79/93] Disable `FANCY_OUTPUT` in Odin test scripts This should tidy up the CI output logs a bit. --- tests/benchmark/Makefile | 2 +- tests/benchmark/build.bat | 4 ++-- tests/core/Makefile | 2 +- tests/core/build.bat | 2 +- tests/core/math/big/build.bat | 2 +- tests/issues/run.bat | 2 +- tests/issues/run.sh | 2 +- tests/vendor/build.bat | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/benchmark/Makefile b/tests/benchmark/Makefile index 8a8e08b24..840174dbb 100644 --- a/tests/benchmark/Makefile +++ b/tests/benchmark/Makefile @@ -1,5 +1,5 @@ ODIN=../../odin -COMMON=-no-bounds-check -vet -strict-style +COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_FANCY=false all: crypto_bench \ hash_bench diff --git a/tests/benchmark/build.bat b/tests/benchmark/build.bat index e9051855b..30b030066 100644 --- a/tests/benchmark/build.bat +++ b/tests/benchmark/build.bat @@ -1,5 +1,5 @@ @echo off -set COMMON=-no-bounds-check -vet -strict-style +set COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_FANCY=false set PATH_TO_ODIN==..\..\odin echo --- @@ -10,4 +10,4 @@ echo --- echo --- echo Running core:hash benchmarks echo --- -%PATH_TO_ODIN% test hash %COMMON% -o:speed -out:bench_hash.exe || exit /b \ No newline at end of file +%PATH_TO_ODIN% test hash %COMMON% -o:speed -out:bench_hash.exe || exit /b diff --git a/tests/core/Makefile b/tests/core/Makefile index 9b12f5d76..85f3783b4 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,6 +1,6 @@ ODIN=../../odin PYTHON=$(shell which python3) -COMMON=-no-bounds-check -vet -strict-style +COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_FANCY=false all: all_bsd \ net_test diff --git a/tests/core/build.bat b/tests/core/build.bat index 3e67b6e13..67ac10f86 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -1,5 +1,5 @@ @echo off -set COMMON=-no-bounds-check -vet -strict-style +set COMMON=-no-bounds-check -vet -strict-style -define:ODIN_TEST_FANCY=false set PATH_TO_ODIN==..\..\odin python3 download_assets.py echo --- diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat index ad199d775..54b715a4f 100644 --- a/tests/core/math/big/build.bat +++ b/tests/core/math/big/build.bat @@ -5,7 +5,7 @@ set TEST_ARGS=-fast-tests set TEST_ARGS=-no-random set TEST_ARGS= set OUT_NAME=math_big_test_library.dll -set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style +set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style -define:ODIN_TEST_FANCY=false echo --- echo Running core:math/big tests echo --- diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 41c52c02f..cd23faefb 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -3,7 +3,7 @@ if not exist "build\" mkdir build pushd build -set COMMON=-collection:tests=..\.. +set COMMON=-collection:tests=..\.. -define:ODIN_TEST_FANCY=false @echo on diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 6d53388a7..a7eee8514 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -4,7 +4,7 @@ set -eu mkdir -p build pushd build ODIN=../../../odin -COMMON="-collection:tests=../.." +COMMON="-collection:tests=../.. -define:ODIN_TEST_FANCY=false" NO_NIL_ERR="Error: " diff --git a/tests/vendor/build.bat b/tests/vendor/build.bat index 693d344f4..1ba53615a 100644 --- a/tests/vendor/build.bat +++ b/tests/vendor/build.bat @@ -1,5 +1,5 @@ @echo off -set COMMON=-show-timings -no-bounds-check -vet -strict-style +set COMMON=-show-timings -no-bounds-check -vet -strict-style -define:ODIN_TEST_FANCY=false set PATH_TO_ODIN==..\..\odin echo --- From 21a1ddfbae92fb78bf536f4047016d0001b76cc2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 2 Jun 2024 21:03:22 +0200 Subject: [PATCH 80/93] Disable NetBSD tests until 'undefined reference to stdout' is solved. --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5493775f..36914b41b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,10 +31,6 @@ jobs: ./odin version ./odin report ./odin check examples/all -vet -strict-style -target:netbsd_amd64 - (cd tests/core; gmake all_bsd) - (cd tests/internal; gmake all_bsd) - (cd tests/issues; ./run.sh) - (cd tests/benchmark; gmake all) build_linux: name: Ubuntu Build, Check, and Test runs-on: ubuntu-latest From 9d8d864400f49e84076fbea843ebf0435d61721a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 2 Jun 2024 21:12:24 +0200 Subject: [PATCH 81/93] Plug leak in AES tests. --- tests/core/crypto/test_core_crypto_aes.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/core/crypto/test_core_crypto_aes.odin b/tests/core/crypto/test_core_crypto_aes.odin index 8b96b0ae9..4d4c06bdc 100644 --- a/tests/core/crypto/test_core_crypto_aes.odin +++ b/tests/core/crypto/test_core_crypto_aes.odin @@ -15,6 +15,7 @@ test_aes :: proc(t: ^testing.T) { log.info("Testing AES") impls := make([dynamic]aes.Implementation, 0, 2) + defer delete(impls) append(&impls, aes.Implementation.Portable) if aes.is_hardware_accelerated() { append(&impls, aes.Implementation.Hardware) From 60d0c03134dbb65692a0e6208068cf1fb64960d8 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 2 Jun 2024 21:15:25 +0200 Subject: [PATCH 82/93] Strip old test runner back out of `internal`, `issues` and `vendor` --- tests/internal/Makefile | 17 +- tests/internal/build.bat | 15 +- tests/internal/test_128.odin | 50 +--- tests/internal/test_asan.odin | 45 +--- tests/internal/test_map.odin | 162 ++++--------- tests/internal/test_pow.odin | 48 +--- tests/internal/test_rtti.odin | 69 +----- tests/internal/test_string_compare.odin | 60 +---- tests/issues/run.bat | 20 +- tests/issues/run.sh | 22 +- tests/issues/test_issue_1592.odin | 293 ++++++++++++------------ tests/issues/test_issue_2056.odin | 5 +- tests/issues/test_issue_2466.odin | 5 +- tests/issues/test_issue_829.odin | 7 +- tests/vendor/build.bat | 2 +- tests/vendor/glfw/test_vendor_glfw.odin | 44 +--- 16 files changed, 282 insertions(+), 582 deletions(-) diff --git a/tests/internal/Makefile b/tests/internal/Makefile index 09182cd23..fb22767d2 100644 --- a/tests/internal/Makefile +++ b/tests/internal/Makefile @@ -1,23 +1,22 @@ ODIN=../../odin +COMMON=-file -vet -strict-style -o:minimal -all: all_bsd asan_test - -all_bsd: rtti_test map_test pow_test 128_test string_compare_test +all: asan_test rtti_test map_test pow_test 128_test string_compare_test rtti_test: - $(ODIN) run test_rtti.odin -file -vet -strict-style -o:minimal + $(ODIN) test test_rtti.odin $(COMMON) map_test: - $(ODIN) run test_map.odin -file -vet -strict-style -o:minimal + $(ODIN) test test_map.odin $(COMMON) pow_test: - $(ODIN) run test_pow.odin -file -vet -strict-style -o:minimal + $(ODIN) test test_pow.odin $(COMMON) 128_test: - $(ODIN) run test_128.odin -file -vet -strict-style -o:minimal + $(ODIN) test test_128.odin $(COMMON) asan_test: - $(ODIN) run test_asan.odin -file -sanitize:address -debug + $(ODIN) test test_asan.odin $(COMMON) -sanitize:address -debug string_compare_test: - $(ODIN) run test_string_compare.odin -file -vet -strict-style -o:minimal + $(ODIN) test test_string_compare.odin $(COMMON) \ No newline at end of file diff --git a/tests/internal/build.bat b/tests/internal/build.bat index 29b3e36c3..edaa2684b 100644 --- a/tests/internal/build.bat +++ b/tests/internal/build.bat @@ -1,10 +1,9 @@ @echo off set PATH_TO_ODIN==..\..\odin -rem %PATH_TO_ODIN% run test_rtti.odin -file -vet -strict-style -o:minimal || exit /b -%PATH_TO_ODIN% run test_map.odin -file -vet -strict-style -o:minimal || exit /b -rem -define:SEED=42 -%PATH_TO_ODIN% run test_pow.odin -file -vet -strict-style -o:minimal || exit /b - -%PATH_TO_ODIN% run test_128.odin -file -vet -strict-style -o:minimal || exit /b - -%PATH_TO_ODIN% run test_string_compare.odin -file -vet -strict-style -o:minimal || exit /b \ No newline at end of file +set COMMON=-file -vet -strict-style -o:minimal +%PATH_TO_ODIN% test test_rtti.odin %COMMON% || exit /b +%PATH_TO_ODIN% test test_map.odin %COMMON% || exit /b +%PATH_TO_ODIN% test test_pow.odin %COMMON% || exit /b +%PATH_TO_ODIN% test test_asan.odin %COMMON% || exit /b +%PATH_TO_ODIN% test test_128.odin %COMMON% || exit /b +%PATH_TO_ODIN% test test_string_compare.odin %COMMON% || exit /b \ No newline at end of file diff --git a/tests/internal/test_128.odin b/tests/internal/test_128.odin index 11ef068ed..1aa7487b6 100644 --- a/tests/internal/test_128.odin +++ b/tests/internal/test_128.odin @@ -1,41 +1,7 @@ package test_128 -import "core:fmt" -import "core:os" import "core:testing" -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - test_128_align(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - @test test_128_align :: proc(t: ^testing.T) { Danger_Struct :: struct { @@ -45,15 +11,15 @@ test_128_align :: proc(t: ^testing.T) { list := [?]Danger_Struct{{0, 0}, {1, 0}, {2, 0}, {3, 0}} - expect(t, list[0].x == 0, fmt.tprintf("[0].x (%v) != 0", list[0].x)) - expect(t, list[0].y == 0, fmt.tprintf("[0].y (%v) != 0", list[0].y)) + testing.expectf(t, list[0].x == 0, "[0].x (%v) != 0", list[0].x) + testing.expectf(t, list[0].y == 0, "[0].y (%v) != 0", list[0].y) - expect(t, list[1].x == 1, fmt.tprintf("[1].x (%v) != 1", list[1].x)) - expect(t, list[1].y == 0, fmt.tprintf("[1].y (%v) != 0", list[1].y)) + testing.expectf(t, list[1].x == 1, "[1].x (%v) != 1", list[1].x) + testing.expectf(t, list[1].y == 0, "[1].y (%v) != 0", list[1].y) - expect(t, list[2].x == 2, fmt.tprintf("[2].x (%v) != 2", list[2].x)) - expect(t, list[2].y == 0, fmt.tprintf("[2].y (%v) != 0", list[2].y)) + testing.expectf(t, list[2].x == 2, "[2].x (%v) != 2", list[2].x) + testing.expectf(t, list[2].y == 0, "[2].y (%v) != 0", list[2].y) - expect(t, list[3].x == 3, fmt.tprintf("[3].x (%v) != 3", list[3].x)) - expect(t, list[3].y == 0, fmt.tprintf("[3].y (%v) != 0", list[3].y)) + testing.expectf(t, list[3].x == 3, "[3].x (%v) != 3", list[3].x) + testing.expectf(t, list[3].y == 0, "[3].y (%v) != 0", list[3].y) } diff --git a/tests/internal/test_asan.odin b/tests/internal/test_asan.odin index 2384ada76..66f3c6547 100644 --- a/tests/internal/test_asan.odin +++ b/tests/internal/test_asan.odin @@ -1,42 +1,7 @@ // Intended to contain code that would trigger asan easily if the abi was set up badly. package test_asan -import "core:fmt" import "core:testing" -import "core:os" - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - - test_12_bytes(&t) - test_12_bytes_two(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} @(test) test_12_bytes :: proc(t: ^testing.T) { @@ -45,9 +10,9 @@ test_12_bytes :: proc(t: ^testing.T) { } a, b, ok := internal() - expect(t, a == max(f32), fmt.tprintf("a (%v) != max(f32)", a)) - expect(t, b == 0, fmt.tprintf("b (%v) != 0", b)) - expect(t, ok, fmt.tprintf("ok (%v) != true", ok)) + testing.expectf(t, a == max(f32), "a (%v) != max(f32)", a) + testing.expectf(t, b == 0, "b (%v) != 0", b) + testing.expectf(t, ok, "ok (%v) != true", ok) } @(test) @@ -57,6 +22,6 @@ test_12_bytes_two :: proc(t: ^testing.T) { } a, b := internal() - expect(t, a == 100., fmt.tprintf("a (%v) != 100.", a)) - expect(t, b == max(int), fmt.tprintf("b (%v) != max(int)", b)) + testing.expectf(t, a == 100., "a (%v) != 100.", a) + testing.expectf(t, b == max(int), "b (%v) != max(int)", b) } diff --git a/tests/internal/test_map.odin b/tests/internal/test_map.odin index 7d1dbf470..fa13244ac 100644 --- a/tests/internal/test_map.odin +++ b/tests/internal/test_map.odin @@ -1,26 +1,22 @@ package test_internal_map -import "core:fmt" +import "core:log" import "base:intrinsics" import "core:math/rand" -import "core:mem" -import "core:os" import "core:testing" -seed: u64 - ENTRY_COUNTS := []int{11, 101, 1_001, 10_001, 100_001, 1_000_001} @test map_insert_random_key_value :: proc(t: ^testing.T) { seed_incr := u64(0) for entries in ENTRY_COUNTS { - fmt.printf("[map_insert_random_key_value] Testing %v entries.\n", entries) + log.infof("Testing %v entries", entries) m: map[i64]i64 defer delete(m) unique_keys := 0 - r := rand.create(seed + seed_incr) + r := rand.create(t.seed + seed_incr) for _ in 0.. 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Unexpected value. Expected m[%v] = %v, got %v", k, v, m[k])) + testing.expectf(t, false, "Unexpected value. Expected m[%v] = %v, got %v", k, v, m[k]) } } seed_incr += 1 @@ -65,12 +61,12 @@ map_insert_random_key_value :: proc(t: ^testing.T) { map_update_random_key_value :: proc(t: ^testing.T) { seed_incr := u64(0) for entries in ENTRY_COUNTS { - fmt.printf("[map_update_random_key_value] Testing %v entries.\n", entries) + log.infof("Testing %v entries", entries) m: map[i64]i64 defer delete(m) unique_keys := 0 - r := rand.create(seed + seed_incr) + r := rand.create(t.seed + seed_incr) for _ in 0.. 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Unexpected value. Expected m[%v] = %v, got %v", k, v, m[k])) + testing.expectf(t, false, "Unexpected value. Expected m[%v] = %v, got %v", k, v, m[k]) } } seed_incr += 1 @@ -127,12 +123,12 @@ map_update_random_key_value :: proc(t: ^testing.T) { map_delete_random_key_value :: proc(t: ^testing.T) { seed_incr := u64(0) for entries in ENTRY_COUNTS { - fmt.printf("[map_delete_random_key_value] Testing %v entries.\n", entries) + log.infof("Testing %v entries", entries) m: map[i64]i64 defer delete(m) unique_keys := 0 - r := rand.create(seed + seed_incr) + r := rand.create(t.seed + seed_incr) for _ in 0.. 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Unexpected key present. Expected m[%v] to have been deleted, got %v", k, m[k])) + testing.expectf(t, false, "Unexpected key present. Expected m[%v] to have been deleted, got %v", k, m[k]) } } else { if k not_in m { num_fails += 1 if num_fails > 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Expected key not present. Expected m[%v] = %v", k, v)) + testing.expectf(t, false, "Expected key not present. Expected m[%v] = %v", k, v) } else if m[k] != v { num_fails += 1 if num_fails > 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Unexpected value. Expected m[%v] = %v, got %v", k, v, m[k])) + testing.expectf(t, false, "Unexpected value. Expected m[%v] = %v, got %v", k, v, m[k]) } } } @@ -205,12 +201,12 @@ map_delete_random_key_value :: proc(t: ^testing.T) { set_insert_random_key_value :: proc(t: ^testing.T) { seed_incr := u64(0) for entries in ENTRY_COUNTS { - fmt.printf("[set_insert_random_key_value] Testing %v entries.\n", entries) + log.infof("Testing %v entries", entries) m: map[i64]struct{} defer delete(m) unique_keys := 0 - r := rand.create(seed + seed_incr) + r := rand.create(t.seed + seed_incr) for _ in 0.. 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Unexpected value. Expected m[%v] to exist", k)) + testing.expectf(t, false, "Unexpected value. Expected m[%v] to exist", k) } } seed_incr += 1 @@ -252,12 +248,12 @@ set_insert_random_key_value :: proc(t: ^testing.T) { set_delete_random_key_value :: proc(t: ^testing.T) { seed_incr := u64(0) for entries in ENTRY_COUNTS { - fmt.printf("[set_delete_random_key_value] Testing %v entries.\n", entries) + log.infof("Testing %v entries", entries) m: map[i64]struct{} defer delete(m) unique_keys := 0 - r := rand.create(seed + seed_incr) + r := rand.create(t.seed + seed_incr) for _ in 0.. 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Unexpected key present. Expected m[%v] to have been deleted", k)) + testing.expectf(t, false, "Unexpected key present. Expected m[%v] to have been deleted", k) } } else { if k not_in m { num_fails += 1 if num_fails > 5 { - fmt.println("... and more") + log.info("... and more") break } - expect(t, false, fmt.tprintf("Expected key not present. Expected m[%v] to exist", k)) + testing.expectf(t, false, "Expected key not present. Expected m[%v] to exist", k) } } } seed_incr += 1 } -} - -// -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- - -main :: proc() { - t := testing.T{} - - // Allow tests to be repeatable - SEED :: #config(SEED, -1) - when SEED > 0 { - seed = u64(SEED) - } else { - seed = u64(intrinsics.read_cycle_counter()) - } - fmt.println("Initialized seed to", seed) - - mem_track_test(&t, map_insert_random_key_value) - mem_track_test(&t, map_update_random_key_value) - mem_track_test(&t, map_delete_random_key_value) - - mem_track_test(&t, set_insert_random_key_value) - mem_track_test(&t, set_delete_random_key_value) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - -mem_track_test :: proc(t: ^testing.T, test: proc(t: ^testing.T)) { - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - test(t) - - expect(t, len(track.allocation_map) == 0, "Expected no leaks.") - expect(t, len(track.bad_free_array) == 0, "Expected no leaks.") - - for _, leak in track.allocation_map { - fmt.printf("%v leaked %v bytes\n", leak.location, leak.size) - } - for bad_free in track.bad_free_array { - fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) - } -} - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} +} \ No newline at end of file diff --git a/tests/internal/test_pow.odin b/tests/internal/test_pow.odin index 70b81258d..609087fb2 100644 --- a/tests/internal/test_pow.odin +++ b/tests/internal/test_pow.odin @@ -1,8 +1,7 @@ package test_internal_math_pow -import "core:fmt" +@(require) import "core:log" import "core:math" -import "core:os" import "core:testing" @test @@ -19,14 +18,14 @@ pow_test :: proc(t: ^testing.T) { // pow2_f64 returns the same float on all platforms because it isn't this stupid _v1 = 0h00000000_00000000 } - expect(t, _v1 == _v2, fmt.tprintf("Expected math.pow2_f64(%d) == math.pow(2, %d) (= %16x), got %16x", exp, exp, _v1, _v2)) + testing.expectf(t, _v1 == _v2, "Expected math.pow2_f64(%d) == math.pow(2, %d) (= %16x), got %16x", exp, exp, _v1, _v2) } { v1 := math.pow(2, f32(exp)) v2 := math.pow2_f32(exp) _v1 := transmute(u32)v1 _v2 := transmute(u32)v2 - expect(t, _v1 == _v2, fmt.tprintf("Expected math.pow2_f32(%d) == math.pow(2, %d) (= %08x), got %08x", exp, exp, _v1, _v2)) + testing.expectf(t, _v1 == _v2, "Expected math.pow2_f32(%d) == math.pow(2, %d) (= %08x), got %08x", exp, exp, _v1, _v2) } { v1 := math.pow(2, f16(exp)) @@ -36,46 +35,11 @@ pow_test :: proc(t: ^testing.T) { when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 { if exp == -25 { - testing.logf(t, "skipping known test failure on darwin+arm64, Expected math.pow2_f16(-25) == math.pow(2, -25) (= 0000), got 0001") + log.info("skipping known test failure on darwin+arm64, Expected math.pow2_f16(-25) == math.pow(2, -25) (= 0000), got 0001") _v2 = 0 } } - - expect(t, _v1 == _v2, fmt.tprintf("Expected math.pow2_f16(%d) == math.pow(2, %d) (= %04x), got %04x", exp, exp, _v1, _v2)) + testing.expectf(t, _v1 == _v2, "Expected math.pow2_f16(%d) == math.pow(2, %d) (= %04x), got %04x", exp, exp, _v1, _v2) } } -} - -// -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- - -main :: proc() { - t := testing.T{} - - pow_test(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} +} \ No newline at end of file diff --git a/tests/internal/test_rtti.odin b/tests/internal/test_rtti.odin index 12f64462b..ec5508208 100644 --- a/tests/internal/test_rtti.odin +++ b/tests/internal/test_rtti.odin @@ -1,11 +1,8 @@ package test_internal_rtti import "core:fmt" -import "core:mem" -import "core:os" import "core:testing" - Buggy_Struct :: struct { a: int, b: bool, @@ -28,74 +25,22 @@ rtti_test :: proc(t: ^testing.T) { for v, i in g_b { checksum += (i+1) * int(v) } - expect(t, checksum == 0, fmt.tprintf("Expected g_b to be zero-initialized, got %v", g_b)) + testing.expectf(t, checksum == 0, "Expected g_b to be zero-initialized, got %v", g_b) } { checksum := 0 for v, i in l_b { checksum += (i+1) * int(v) } - expect(t, checksum == 0, fmt.tprintf("Expected l_b to be zero-initialized, got %v", l_b)) + testing.expectf(t, checksum == 0, "Expected l_b to be zero-initialized, got %v", l_b) } - expect(t, size_of(Buggy_Struct) == 40, fmt.tprintf("Expected size_of(Buggy_Struct) == 40, got %v", size_of(Buggy_Struct))) - expect(t, size_of(g_buggy) == 40, fmt.tprintf("Expected size_of(g_buggy) == 40, got %v", size_of(g_buggy))) - expect(t, size_of(l_buggy) == 40, fmt.tprintf("Expected size_of(l_buggy) == 40, got %v", size_of(l_buggy))) + testing.expectf(t, size_of(Buggy_Struct) == 40, "Expected size_of(Buggy_Struct) == 40, got %v", size_of(Buggy_Struct)) + testing.expectf(t, size_of(g_buggy) == 40, "Expected size_of(g_buggy) == 40, got %v", size_of(g_buggy)) + testing.expectf(t, size_of(l_buggy) == 40, "Expected size_of(l_buggy) == 40, got %v", size_of(l_buggy)) g_s := fmt.tprintf("%s", g_buggy) l_s := fmt.tprintf("%s", l_buggy) - expect(t, g_s == EXPECTED_REPR, fmt.tprintf("Expected fmt.tprintf(\"%%s\", g_s)) to return \"%v\", got \"%v\"", EXPECTED_REPR, g_s)) - expect(t, l_s == EXPECTED_REPR, fmt.tprintf("Expected fmt.tprintf(\"%%s\", l_s)) to return \"%v\", got \"%v\"", EXPECTED_REPR, l_s)) -} - -// -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- - -main :: proc() { - t := testing.T{} - - mem_track_test(&t, rtti_test) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - -mem_track_test :: proc(t: ^testing.T, test: proc(t: ^testing.T)) { - track: mem.Tracking_Allocator - mem.tracking_allocator_init(&track, context.allocator) - context.allocator = mem.tracking_allocator(&track) - - test(t) - - expect(t, len(track.allocation_map) == 0, "Expected no leaks.") - expect(t, len(track.bad_free_array) == 0, "Expected no leaks.") - - for _, leak in track.allocation_map { - fmt.printf("%v leaked %v bytes\n", leak.location, leak.size) - } - for bad_free in track.bad_free_array { - fmt.printf("%v allocation %p was freed badly\n", bad_free.location, bad_free.memory) - } -} - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + testing.expectf(t, g_s == EXPECTED_REPR, "Expected fmt.tprintf(\"%%s\", g_s)) to return \"%v\", got \"%v\"", EXPECTED_REPR, g_s) + testing.expectf(t, l_s == EXPECTED_REPR, "Expected fmt.tprintf(\"%%s\", l_s)) to return \"%v\", got \"%v\"", EXPECTED_REPR, l_s) } \ No newline at end of file diff --git a/tests/internal/test_string_compare.odin b/tests/internal/test_string_compare.odin index ff65b41c2..63b62cc96 100644 --- a/tests/internal/test_string_compare.odin +++ b/tests/internal/test_string_compare.odin @@ -1,7 +1,5 @@ package test_internal_string_compare -import "core:fmt" -import "core:os" import "core:testing" Op :: enum { Eq, Lt, Gt } @@ -29,65 +27,31 @@ string_compare :: proc(t: ^testing.T) { for res, op in v.res { switch op { case .Eq: - expect(t, (v.a == v.b) == res, fmt.tprintf("Expected cstring(\"%v\") == cstring(\"%v\") to be %v", v.a, v.b, res)) - expect(t, (s_a == s_b) == res, fmt.tprintf("Expected string(\"%v\") == string(\"%v\") to be %v", v.a, v.b, res)) + testing.expectf(t, (v.a == v.b) == res, "Expected cstring(\"%v\") == cstring(\"%v\") to be %v", v.a, v.b, res) + testing.expectf(t, (s_a == s_b) == res, "Expected string(\"%v\") == string(\"%v\") to be %v", v.a, v.b, res) // If a == b then a != b - expect(t, (v.a != v.b) == !res, fmt.tprintf("Expected cstring(\"%v\") != cstring(\"%v\") to be %v", v.a, v.b, !res)) - expect(t, (s_a != s_b) == !res, fmt.tprintf("Expected string(\"%v\") != string(\"%v\") to be %v", v.a, v.b, !res)) + testing.expectf(t, (v.a != v.b) == !res, "Expected cstring(\"%v\") != cstring(\"%v\") to be %v", v.a, v.b, !res) + testing.expectf(t, (s_a != s_b) == !res, "Expected string(\"%v\") != string(\"%v\") to be %v", v.a, v.b, !res) case .Lt: - expect(t, (v.a < v.b) == res, fmt.tprintf("Expected cstring(\"%v\") < cstring(\"%v\") to be %v", v.a, v.b, res)) - expect(t, (s_a < s_b) == res, fmt.tprintf("Expected string(\"%v\") < string(\"%v\") to be %v", v.a, v.b, res)) + testing.expectf(t, (v.a < v.b) == res, "Expected cstring(\"%v\") < cstring(\"%v\") to be %v", v.a, v.b, res) + testing.expectf(t, (s_a < s_b) == res, "Expected string(\"%v\") < string(\"%v\") to be %v", v.a, v.b, res) // .Lt | .Eq == .LtEq lteq := v.res[.Eq] | res - expect(t, (v.a <= v.b) == lteq, fmt.tprintf("Expected cstring(\"%v\") <= cstring(\"%v\") to be %v", v.a, v.b, lteq)) - expect(t, (s_a <= s_b) == lteq, fmt.tprintf("Expected string(\"%v\") <= string(\"%v\") to be %v", v.a, v.b, lteq)) + testing.expectf(t, (v.a <= v.b) == lteq, "Expected cstring(\"%v\") <= cstring(\"%v\") to be %v", v.a, v.b, lteq) + testing.expectf(t, (s_a <= s_b) == lteq, "Expected string(\"%v\") <= string(\"%v\") to be %v", v.a, v.b, lteq) case .Gt: - expect(t, (v.a > v.b) == res, fmt.tprintf("Expected cstring(\"%v\") > cstring(\"%v\") to be %v", v.a, v.b, res)) - expect(t, (s_a > s_b) == res, fmt.tprintf("Expected string(\"%v\") > string(\"%v\") to be %v", v.a, v.b, res)) + testing.expectf(t, (v.a > v.b) == res, "Expected cstring(\"%v\") > cstring(\"%v\") to be %v", v.a, v.b, res) + testing.expectf(t, (s_a > s_b) == res, "Expected string(\"%v\") > string(\"%v\") to be %v", v.a, v.b, res) // .Gt | .Eq == .GtEq gteq := v.res[.Eq] | res - expect(t, (v.a >= v.b) == gteq, fmt.tprintf("Expected cstring(\"%v\") >= cstring(\"%v\") to be %v", v.a, v.b, gteq)) - expect(t, (s_a >= s_b) == gteq, fmt.tprintf("Expected string(\"%v\") >= string(\"%v\") to be %v", v.a, v.b, gteq)) + testing.expectf(t, (v.a >= v.b) == gteq, "Expected cstring(\"%v\") >= cstring(\"%v\") to be %v", v.a, v.b, gteq) + testing.expectf(t, (s_a >= s_b) == gteq, "Expected string(\"%v\") >= string(\"%v\") to be %v", v.a, v.b, gteq) } } } -} - -// -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- - -main :: proc() { - t := testing.T{} - - string_compare(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.printf("[%v] %v\n", loc, message) - return - } - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } } \ No newline at end of file diff --git a/tests/issues/run.bat b/tests/issues/run.bat index cd23faefb..f3e3daba9 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -3,19 +3,19 @@ if not exist "build\" mkdir build pushd build -set COMMON=-collection:tests=..\.. -define:ODIN_TEST_FANCY=false +set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style @echo on -..\..\..\odin test ..\test_issue_829.odin %COMMON% -file || exit /b -..\..\..\odin test ..\test_issue_1592.odin %COMMON% -file || exit /b -..\..\..\odin test ..\test_issue_2056.odin %COMMON% -file || exit /b -..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file || exit /b -..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug || exit /b -..\..\..\odin test ..\test_issue_2466.odin %COMMON% -file || exit /b -..\..\..\odin test ..\test_issue_2615.odin %COMMON% -file || exit /b -..\..\..\odin test ..\test_issue_2637.odin %COMMON% -file || exit /b -..\..\..\odin test ..\test_issue_2666.odin %COMMON% -file || exit /b +..\..\..\odin test ..\test_issue_829.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_1592.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_2056.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_2087.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_2113.odin %COMMON% -debug || exit /b +..\..\..\odin test ..\test_issue_2466.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_2615.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index a7eee8514..24b388b07 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -4,22 +4,22 @@ set -eu mkdir -p build pushd build ODIN=../../../odin -COMMON="-collection:tests=../.. -define:ODIN_TEST_FANCY=false" +COMMON="-define:ODIN_TEST_FANCY=false -file -vet -strict-style" NO_NIL_ERR="Error: " set -x -$ODIN test ../test_issue_829.odin $COMMON -file -$ODIN test ../test_issue_1592.odin $COMMON -file -$ODIN test ../test_issue_2056.odin $COMMON -file -$ODIN test ../test_issue_2087.odin $COMMON -file -$ODIN build ../test_issue_2113.odin $COMMON -file -debug -$ODIN test ../test_issue_2466.odin $COMMON -file -$ODIN test ../test_issue_2615.odin $COMMON -file -$ODIN test ../test_issue_2637.odin $COMMON -file -$ODIN test ../test_issue_2666.odin $COMMON -file -if [[ $($ODIN build ../test_issue_2395.odin $COMMON -file 2>&1 >/dev/null | grep -c "$NO_NIL_ERR") -eq 2 ]] ; then +$ODIN test ../test_issue_829.odin $COMMON +$ODIN test ../test_issue_1592.odin $COMMON +$ODIN test ../test_issue_2056.odin $COMMON +$ODIN test ../test_issue_2087.odin $COMMON +$ODIN build ../test_issue_2113.odin $COMMON -debug +$ODIN test ../test_issue_2466.odin $COMMON +$ODIN test ../test_issue_2615.odin $COMMON +$ODIN test ../test_issue_2637.odin $COMMON +$ODIN test ../test_issue_2666.odin $COMMON +if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "$NO_NIL_ERR") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" else echo "SUCCESSFUL 0/1" diff --git a/tests/issues/test_issue_1592.odin b/tests/issues/test_issue_1592.odin index 800314a93..79eff33df 100644 --- a/tests/issues/test_issue_1592.odin +++ b/tests/issues/test_issue_1592.odin @@ -1,7 +1,6 @@ // Tests issue #1592 https://github.com/odin-lang/Odin/issues/1592 package test_issues -import "core:fmt" import "core:testing" /* Original issue #1592 example */ @@ -31,428 +30,428 @@ true_result :: proc() -> bool { @test test_simple_const_false :: proc(t: ^testing.T) { if CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if (CONSTANT_FALSE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if (!CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !!CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_FALSE == true { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_FALSE == false { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(CONSTANT_FALSE == true) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(CONSTANT_FALSE == false) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } } @test test_simple_const_true :: proc(t: ^testing.T) { if CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if (CONSTANT_TRUE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if (!CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if (!CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !!CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_TRUE == true { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_TRUE == false { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_TRUE == true) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_TRUE == false) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_simple_proc_false :: proc(t: ^testing.T) { if false_result() { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !false_result() { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_simple_proc_true :: proc(t: ^testing.T) { if true_result() { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !true_result() { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } } @test test_const_false_const_false :: proc(t: ^testing.T) { if CONSTANT_FALSE || CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_FALSE && CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !CONSTANT_FALSE || CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !CONSTANT_FALSE && CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_FALSE || !CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_FALSE && !CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_FALSE || CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(CONSTANT_FALSE && CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_const_false_const_true :: proc(t: ^testing.T) { if CONSTANT_FALSE || CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_FALSE && CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !CONSTANT_FALSE || CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !CONSTANT_FALSE && CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_FALSE || !CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_FALSE && !CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_FALSE || CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_FALSE && CONSTANT_TRUE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_const_true_const_false :: proc(t: ^testing.T) { if CONSTANT_TRUE || CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_TRUE && CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !CONSTANT_TRUE || CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !CONSTANT_TRUE && CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_TRUE || !CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_TRUE && !CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(CONSTANT_TRUE || CONSTANT_FALSE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_TRUE && CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_const_true_const_true :: proc(t: ^testing.T) { if CONSTANT_TRUE || CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_TRUE && CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !CONSTANT_TRUE || CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !CONSTANT_TRUE && CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if CONSTANT_TRUE || !CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if CONSTANT_TRUE && !CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_TRUE || CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(CONSTANT_TRUE && CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } } @test test_proc_false_const_false :: proc(t: ^testing.T) { if false_result() || CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if false_result() && CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(false_result() || CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(false_result() && CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_proc_false_const_true :: proc(t: ^testing.T) { if false_result() || CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if false_result() && CONSTANT_TRUE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(false_result() || CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(false_result() && CONSTANT_TRUE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_proc_true_const_false :: proc(t: ^testing.T) { if true_result() || CONSTANT_FALSE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if true_result() && CONSTANT_FALSE { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(true_result() || CONSTANT_FALSE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(true_result() && CONSTANT_FALSE) { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } } @test test_proc_true_const_true :: proc(t: ^testing.T) { if true_result() || CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if true_result() && CONSTANT_TRUE { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } else { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } if !(true_result() || CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } if !(true_result() && CONSTANT_TRUE) { - testing.expect(t, false, fmt.tprintf("%s: !false\n", #procedure)) + testing.expect(t, false, "!false") } else { - testing.expect(t, true, fmt.tprintf("%s: !true\n", #procedure)) + testing.expect(t, true, "!true") } } diff --git a/tests/issues/test_issue_2056.odin b/tests/issues/test_issue_2056.odin index 4869b557e..06bc11fba 100644 --- a/tests/issues/test_issue_2056.odin +++ b/tests/issues/test_issue_2056.odin @@ -1,7 +1,6 @@ // Tests issue #2056 https://github.com/odin-lang/Odin/issues/2056 package test_issues -import "core:fmt" import "core:testing" @test @@ -12,9 +11,9 @@ test_scalar_matrix_conversion :: proc(t: ^testing.T) { for i in 0..<4 { for j in 0..<4 { if i == j { - testing.expect(t, m[i,j] == 1, fmt.tprintf("expected 1 at m[%d,%d], found %f\n", i, j, m[i,j])) + testing.expectf(t, m[i,j] == 1, "expected 1 at m[%d,%d], found %f\n", i, j, m[i,j]) } else { - testing.expect(t, m[i,j] == 0, fmt.tprintf("expected 0 at m[%d,%d], found %f\n", i, j, m[i,j])) + testing.expectf(t, m[i,j] == 0, "expected 0 at m[%d,%d], found %f\n", i, j, m[i,j]) } } } diff --git a/tests/issues/test_issue_2466.odin b/tests/issues/test_issue_2466.odin index 4810cfea9..f5987903a 100644 --- a/tests/issues/test_issue_2466.odin +++ b/tests/issues/test_issue_2466.odin @@ -1,7 +1,6 @@ // Tests issue #2466 https://github.com/odin-lang/Odin/issues/2466 package test_issues -import "core:fmt" import "core:testing" Bug :: struct { @@ -16,7 +15,7 @@ test_compound_literal_local_reuse :: proc(t: ^testing.T) { val = v, arr = {42}, } - testing.expect(t, bug.val == 123, fmt.tprintf("expected 123, found %d", bug.val)) - testing.expect(t, bug.arr[0] == 42, fmt.tprintf("expected 42, found %d", bug.arr[0])) + testing.expectf(t, bug.val == 123, "expected 123, found %d", bug.val) + testing.expectf(t, bug.arr[0] == 42, "expected 42, found %d", bug.arr[0]) } diff --git a/tests/issues/test_issue_829.odin b/tests/issues/test_issue_829.odin index 273b3b3b5..229d8e9b4 100644 --- a/tests/issues/test_issue_829.odin +++ b/tests/issues/test_issue_829.odin @@ -1,7 +1,6 @@ // Tests issue #829 https://github.com/odin-lang/Odin/issues/829 package test_issues -import "core:fmt" import "core:testing" /* Original issue #829 example */ @@ -13,6 +12,6 @@ env : map[string]proc(a, b : int) -> int = { @(test) test_orig_ret :: proc(t: ^testing.T) { - r := fmt.tprint(env["+"](1, 2)) - testing.expect(t, r == "3", fmt.tprintf("%s: \"%s\" != \"3\"\n", #procedure, r)) -} + r := env["+"](1, 2) + testing.expectf(t, r == 3, "%q != 3", r) +} \ No newline at end of file diff --git a/tests/vendor/build.bat b/tests/vendor/build.bat index 1ba53615a..84ab2f1ef 100644 --- a/tests/vendor/build.bat +++ b/tests/vendor/build.bat @@ -5,4 +5,4 @@ set PATH_TO_ODIN==..\..\odin echo --- echo Running vendor:glfw tests echo --- -%PATH_TO_ODIN% run glfw %COMMON% -out:vendor_glfw.exe || exit /b \ No newline at end of file +%PATH_TO_ODIN% test glfw %COMMON% -out:vendor_glfw.exe || exit /b \ No newline at end of file diff --git a/tests/vendor/glfw/test_vendor_glfw.odin b/tests/vendor/glfw/test_vendor_glfw.odin index ce55ad7ef..4254ebb09 100644 --- a/tests/vendor/glfw/test_vendor_glfw.odin +++ b/tests/vendor/glfw/test_vendor_glfw.odin @@ -1,49 +1,21 @@ package test_vendor_glfw import "core:testing" -import "core:fmt" import "vendor:glfw" -import "core:os" GLFW_MAJOR :: 3 GLFW_MINOR :: 4 GLFW_PATCH :: 0 -TEST_count := 0 -TEST_fail := 0 - -when ODIN_TEST { - expect :: testing.expect - log :: testing.log -} else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } -} - -main :: proc() { - t := testing.T{} - test_glfw(&t) - - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) - if TEST_fail > 0 { - os.exit(1) - } -} - @(test) test_glfw :: proc(t: ^testing.T) { major, minor, patch := glfw.GetVersion() - expect(t, major == GLFW_MAJOR && minor == GLFW_MINOR, fmt.tprintf("Expected GLFW.GetVersion: %v.%v.%v, got %v.%v.%v instead", GLFW_MAJOR, GLFW_MINOR, GLFW_PATCH, major, minor, patch)) + testing.expectf( + t, + major == GLFW_MAJOR && \ + minor == GLFW_MINOR, + "Expected GLFW.GetVersion: %v.%v.%v, got %v.%v.%v instead", + GLFW_MAJOR, GLFW_MINOR, GLFW_PATCH, + major, minor, patch, + ) } From 8d8c42e9625b234e181dd8b7d16875ad5140d2ad Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:30:23 -0400 Subject: [PATCH 83/93] Use `T.seed` in tests where applicable --- tests/core/container/test_core_avl.odin | 4 ++-- tests/core/container/test_core_rbtree.odin | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/core/container/test_core_avl.odin b/tests/core/container/test_core_avl.odin index 37b21a6be..99dbba8b2 100644 --- a/tests/core/container/test_core_avl.odin +++ b/tests/core/container/test_core_avl.odin @@ -8,7 +8,7 @@ import "core:log" @(test) test_avl :: proc(t: ^testing.T) { - log.infof("Testing avl, using random seed %v, add -define:RANDOM_SEED=%v to reuse it.", random_seed, random_seed) + log.infof("Testing avl using random seed %v.", t.seed) // Initialization. tree: avl.Tree(int) @@ -21,7 +21,7 @@ test_avl :: proc(t: ^testing.T) { testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil") r: rand.Rand - rand.init(&r, random_seed) + rand.init(&r, t.seed) // Test insertion. NR_INSERTS :: 32 + 1 // Ensure at least 1 collision. diff --git a/tests/core/container/test_core_rbtree.odin b/tests/core/container/test_core_rbtree.odin index a4151d120..8def8edb6 100644 --- a/tests/core/container/test_core_rbtree.odin +++ b/tests/core/container/test_core_rbtree.odin @@ -8,12 +8,6 @@ import "core:mem" import "core:slice" import "core:log" -@(private) -_RANDOM_SEED :: #config(RANDOM_SEED, u64(0)) - -// Exported -random_seed := u64(intrinsics.read_cycle_counter()) when _RANDOM_SEED == 0 else u64(_RANDOM_SEED) - test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) @@ -21,9 +15,9 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) { context.allocator = mem.tracking_allocator(&track) r: rand.Rand - rand.init(&r, random_seed) + rand.init(&r, t.seed) - log.infof("Testing Red-Black Tree($Key=%v,$Value=%v), using random seed %v, add -define:RANDOM_SEED=%v to reuse it.", type_info_of(Key), type_info_of(Value), random_seed, random_seed) + log.infof("Testing Red-Black Tree($Key=%v,$Value=%v) using random seed %v.", type_info_of(Key), type_info_of(Value), t.seed) tree: rb.Tree(Key, Value) rb.init(&tree) @@ -243,4 +237,4 @@ verify_rbtree_propery_5_helper :: proc(t: ^testing.T, n: ^$N/rb.Node($Key, $Valu verify_rbtree_propery_5_helper(t, n._right, black_count, path_black_count) } // Properties 4 and 5 together guarantee that no path in the tree is more than about twice as long as any other path, -// which guarantees that it has O(log n) height. \ No newline at end of file +// which guarantees that it has O(log n) height. From 3f1249c27e6364896d801cbbfe7edaf12f69cf37 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:34:13 -0400 Subject: [PATCH 84/93] Tell user about `ODIN_TEST_RANDOM_SEED` option --- core/testing/runner.odin | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index fbe413bb2..5b80d0cf8 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -422,7 +422,11 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { "" if thread_count == 1 else "s") } - pkg_log.infof("The random seed sent to every test is: %v", shared_random_seed) + when SHARED_RANDOM_SEED == 0 { + pkg_log.infof("The random seed sent to every test is: %v. Set with -define:ODIN_TEST_RANDOM_SEED=n.", shared_random_seed) + } else { + pkg_log.infof("The random seed sent to every test is: %v.", shared_random_seed) + } when TRACKING_MEMORY { when ALWAYS_REPORT_MEMORY { From f77ce359cec2cc50c5a98e4b4257e63ed702995e Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:40:09 -0400 Subject: [PATCH 85/93] Be pedantic about not overwriting Odin errors I was encountering bounds-check error messages being overwritten during a test, if the test failed for another reason and sent a log message. The original intent of having this check inside of the above `if` block was that if a test sent an error message, then it was assumed an overwrite would be safe, but it's completely possible for a test to fail for a legitimate reason, then do an unrelated bounds check somewhere else that would be buried under the animation. This change will make sure that, no matter what, the progress display will not trigger a clear if a signal was raised. There's still no guarantee that bounds-check messages will be printed properly, and it's best to redirect STDERR. The only way that can be fixed is if they get a similar hook to `context.assertion_failure_proc`. --- core/testing/runner.odin | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 5b80d0cf8..190e10744 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -648,10 +648,11 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator) pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) - when FANCY_OUTPUT { - signals_were_raised = true - bypass_progress_overwrite = true - } + } + + when FANCY_OUTPUT { + bypass_progress_overwrite = true + signals_were_raised = true } total_failure_count += 1 From ac9484206b8fb79bd289049ab8c2f4b6488e9cfa Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:15:28 -0400 Subject: [PATCH 86/93] Fix `STDIN`, `STDOUT`, `STDERR` handles for BSDs Tested on FreeBSD 14.0 and NetBSD 10.0 OpenBSD is untested, but link names were sourced from: https://github.com/openbsd/src/blob/master/include/stdio.h According to this, OpenBSD shares the same layout as NetBSD. FreeBSD has the same as Darwin in this regard. --- core/c/libc/stdio.odin | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index f17d3bd06..3e1d0f5a2 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -102,10 +102,12 @@ when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { SEEK_END :: 2 foreign libc { - stderr: ^FILE - stdin: ^FILE - stdout: ^FILE + __sF: [3]FILE } + + stdin: ^FILE = &__sF[0] + stdout: ^FILE = &__sF[1] + stderr: ^FILE = &__sF[2] } when ODIN_OS == .FreeBSD { @@ -127,9 +129,9 @@ when ODIN_OS == .FreeBSD { SEEK_END :: 2 foreign libc { - stderr: ^FILE - stdin: ^FILE - stdout: ^FILE + @(link_name="__stderrp") stderr: ^FILE + @(link_name="__stdinp") stdin: ^FILE + @(link_name="__stdoutp") stdout: ^FILE } } From c8539fe4115b733583849705bac14e396a3a7dd7 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:28:07 -0400 Subject: [PATCH 87/93] Revert "Disable NetBSD tests until 'undefined reference to stdout' is solved." This reverts commit 21a1ddfbae92fb78bf536f4047016d0001b76cc2. --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36914b41b..c5493775f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,10 @@ jobs: ./odin version ./odin report ./odin check examples/all -vet -strict-style -target:netbsd_amd64 + (cd tests/core; gmake all_bsd) + (cd tests/internal; gmake all_bsd) + (cd tests/issues; ./run.sh) + (cd tests/benchmark; gmake all) build_linux: name: Ubuntu Build, Check, and Test runs-on: ubuntu-latest From 6a5633df2d3c7a398d6aa20e1024f6f380c9d987 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 20:16:23 -0400 Subject: [PATCH 88/93] Fix wrong `PTHREAD_CANCEL_ASYNCHRONOUS` on FreeBSD and OpenBSD The test runner was deadlocking when a test raised a signal on FreeBSD. This is untested on OpenBSD, but I have referenced this file: https://github.com/openbsd/src/blob/master/include/pthread.h --- core/sys/unix/pthread_freebsd.odin | 4 ++-- core/sys/unix/pthread_openbsd.odin | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/sys/unix/pthread_freebsd.odin b/core/sys/unix/pthread_freebsd.odin index 3417d3943..5f4dac289 100644 --- a/core/sys/unix/pthread_freebsd.odin +++ b/core/sys/unix/pthread_freebsd.odin @@ -95,7 +95,7 @@ sem_t :: struct { PTHREAD_CANCEL_ENABLE :: 0 PTHREAD_CANCEL_DISABLE :: 1 PTHREAD_CANCEL_DEFERRED :: 0 -PTHREAD_CANCEL_ASYNCHRONOUS :: 1 +PTHREAD_CANCEL_ASYNCHRONOUS :: 2 foreign import "system:pthread" @@ -119,4 +119,4 @@ foreign pthread { pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int --- pthread_setcanceltype :: proc (type: c.int, old_type: ^c.int) -> c.int --- pthread_cancel :: proc (thread: pthread_t) -> c.int --- -} \ No newline at end of file +} diff --git a/core/sys/unix/pthread_openbsd.odin b/core/sys/unix/pthread_openbsd.odin index 7ae82e662..855e7d99c 100644 --- a/core/sys/unix/pthread_openbsd.odin +++ b/core/sys/unix/pthread_openbsd.odin @@ -49,7 +49,7 @@ sem_t :: distinct rawptr PTHREAD_CANCEL_ENABLE :: 0 PTHREAD_CANCEL_DISABLE :: 1 PTHREAD_CANCEL_DEFERRED :: 0 -PTHREAD_CANCEL_ASYNCHRONOUS :: 1 +PTHREAD_CANCEL_ASYNCHRONOUS :: 2 foreign import libc "system:c" @@ -71,4 +71,4 @@ foreign libc { pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int --- pthread_setcanceltype :: proc (type: c.int, old_type: ^c.int) -> c.int --- pthread_cancel :: proc (thread: pthread_t) -> c.int --- -} \ No newline at end of file +} From 7764ab2ab0a45786d3c27c2a5bfad264e181b7b7 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:25:04 -0400 Subject: [PATCH 89/93] Prevent test runner deadlock on NetBSD Add `pthread_testcancel` to `core:sys/unix` --- core/sys/unix/pthread_unix.odin | 1 + core/testing/signal_handler_libc.odin | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin index 5760560ee..c876a214a 100644 --- a/core/sys/unix/pthread_unix.odin +++ b/core/sys/unix/pthread_unix.odin @@ -116,4 +116,5 @@ foreign pthread { pthread_mutexattr_setpshared :: proc(attrs: ^pthread_mutexattr_t, value: c.int) -> c.int --- pthread_mutexattr_getpshared :: proc(attrs: ^pthread_mutexattr_t, result: ^c.int) -> c.int --- + pthread_testcancel :: proc () --- } diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index ff3dbe135..f60cf2540 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -6,6 +6,7 @@ import "base:intrinsics" import "core:c/libc" import "core:encoding/ansi" import "core:sync" +@require import "core:sys/unix" @(private="file") stop_runner_flag: libc.sig_atomic_t @@ -75,6 +76,18 @@ This is a dire bug and should be reported to the Odin developers. // Idle until this thread is terminated by the runner, // otherwise we may continue to generate signals. intrinsics.cpu_relax() + + when ODIN_OS != .Windows { + // NOTE(Feoramund): Some UNIX-like platforms may require this. + // + // During testing, I found that NetBSD 10.0 refused to + // terminate a task thread, even when its thread had been + // properly set to PTHREAD_CANCEL_ASYNCHRONOUS. + // + // The runner would stall after returning from `pthread_cancel`. + + unix.pthread_testcancel() + } } } } From fa29974dabc03479848935168eb4e26becbe304d Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:21:44 -0400 Subject: [PATCH 90/93] Use `Warning` log level for reporting memory leaks Works well with `-define:ODIN_TEST_LOG_LEVEL=warning`. --- core/testing/runner.odin | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 190e10744..c82aa1fda 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -467,16 +467,18 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { when TRACKING_MEMORY { #no_bounds_check tracker := &task_memory_trackers[data.allocator_index] + memory_is_in_bad_state := len(tracker.allocation_map) + len(tracker.bad_free_array) > 0 + when ALWAYS_REPORT_MEMORY { should_report := true } else { - should_report := len(tracker.allocation_map) + len(tracker.bad_free_array) > 0 + should_report := memory_is_in_bad_state } if should_report { write_memory_report(batch_writer, tracker, data.it.pkg, data.it.name) - pkg_log.info(bytes.buffer_to_string(&batch_buffer)) + pkg_log.log(.Warning if memory_is_in_bad_state else .Info, bytes.buffer_to_string(&batch_buffer)) bytes.buffer_reset(&batch_buffer) } From 0ff130d82bf058a41f77c08c8c0c63fb9e205a13 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:36:04 -0400 Subject: [PATCH 91/93] Fix ad hoc `printf` in test runner signal handler --- core/testing/signal_handler_libc.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index f60cf2540..d76fdd66b 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -51,7 +51,7 @@ stop_test_callback :: proc "c" (sig: libc.int) { sigbuf[i] = cast(u8)('0' + m) i -= 1 } - sigstr = cast(string)sigbuf[i:] + sigstr = cast(string)sigbuf[1 + i:len(sigbuf) - 1] } advisory_a := ` From e46e22e21ba61e0bceb2e96084c1e1772bb7ed11 Mon Sep 17 00:00:00 2001 From: Colin Davidson Date: Tue, 4 Jun 2024 01:12:10 -0700 Subject: [PATCH 92/93] add a few more x11 funcs, fix egl bug --- vendor/egl/egl.odin | 2 +- vendor/x11/xlib/xlib_procs.odin | 2566 ++++++++++++++++--------------- 2 files changed, 1288 insertions(+), 1280 deletions(-) diff --git a/vendor/egl/egl.odin b/vendor/egl/egl.odin index 3174fa60b..82181b1c5 100644 --- a/vendor/egl/egl.odin +++ b/vendor/egl/egl.odin @@ -47,7 +47,7 @@ foreign egl { GetDisplay :: proc(display: NativeDisplayType) -> Display --- Initialize :: proc(display: Display, major: ^i32, minor: ^i32) -> i32 --- BindAPI :: proc(api: u32) -> i32 --- - ChooseConfig :: proc(display: Display, attrib_list: ^i32, configs: ^Context, config_size: i32, num_config: ^i32) -> i32 --- + ChooseConfig :: proc(display: Display, attrib_list: ^i32, configs: ^Config, config_size: i32, num_config: ^i32) -> i32 --- CreateWindowSurface :: proc(display: Display, config: Config, native_window: NativeWindowType, attrib_list: ^i32) -> Surface --- CreateContext :: proc(display: Display, config: Config, share_context: Context, attrib_list: ^i32) -> Context --- MakeCurrent :: proc(display: Display, draw: Surface, read: Surface, ctx: Context) -> i32 --- diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 5e999519b..5465cd71b 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -8,108 +8,108 @@ foreign xlib { /* ---- X11/Xlib.h ---------------------------------------------------------*/ -@(default_calling_convention="c") +@(default_calling_convention="c", link_prefix="X") foreign xlib { // Free data allocated by Xlib - XFree :: proc(ptr: rawptr) --- + Free :: proc(ptr: rawptr) --- // Opening/closing a display - XOpenDisplay :: proc(name: cstring) -> ^Display --- - XCloseDisplay :: proc(display: ^Display) --- - XSetCloseDownMode :: proc(display: ^Display, mode: CloseMode) --- + OpenDisplay :: proc(name: cstring) -> ^Display --- + CloseDisplay :: proc(display: ^Display) --- + SetCloseDownMode :: proc(display: ^Display, mode: CloseMode) --- // Generate a no-op request - XNoOp :: proc(display: ^Display) --- + NoOp :: proc(display: ^Display) --- // Display macros (connection) - XConnectionNumber :: proc(display: ^Display) -> i32 --- - XExtendedMaxRequestSize :: + ConnectionNumber :: proc(display: ^Display) -> i32 --- + ExtendedMaxRequestSize :: proc(display: ^Display) -> int --- - XMaxRequestSize :: proc(display: ^Display) -> int --- - XLastKnownRequestProcessed :: + MaxRequestSize :: proc(display: ^Display) -> int --- + LastKnownRequestProcessed :: proc(display: ^Display) -> uint --- - XNextRequest :: proc(display: ^Display) -> uint --- - XProtocolVersion :: proc(display: ^Display) -> i32 --- - XProtocolRevision :: proc(display: ^Display) -> i32 --- - XQLength :: proc(display: ^Display) -> i32 --- - XServerVendor :: proc(display: ^Display) -> cstring --- - XVendorRelease :: proc(display: ^Display) -> i32 --- + NextRequest :: proc(display: ^Display) -> uint --- + ProtocolVersion :: proc(display: ^Display) -> i32 --- + ProtocolRevision :: proc(display: ^Display) -> i32 --- + QLength :: proc(display: ^Display) -> i32 --- + ServerVendor :: proc(display: ^Display) -> cstring --- + VendorRelease :: proc(display: ^Display) -> i32 --- // Display macros (display properties) - XBlackPixel :: proc(display: ^Display, screen_no: i32) -> uint --- - XWhitePixel :: proc(display: ^Display, screen_no: i32) -> uint --- - XListDepths :: proc(display: ^Display, screen_no: i32, count: ^i32) -> [^]i32 --- - XDisplayCells :: proc(display: ^Display, screen_no: i32) -> i32 --- - XDisplayPlanes :: proc(display: ^Display, screen_no: i32) -> i32 --- - XScreenOfDisplay :: proc(display: ^Display, screen_no: i32) -> ^Screen --- - XDisplayString :: proc(display: ^Display) -> cstring --- + BlackPixel :: proc(display: ^Display, screen_no: i32) -> uint --- + WhitePixel :: proc(display: ^Display, screen_no: i32) -> uint --- + ListDepths :: proc(display: ^Display, screen_no: i32, count: ^i32) -> [^]i32 --- + DisplayCells :: proc(display: ^Display, screen_no: i32) -> i32 --- + DisplayPlanes :: proc(display: ^Display, screen_no: i32) -> i32 --- + ScreenOfDisplay :: proc(display: ^Display, screen_no: i32) -> ^Screen --- + DisplayString :: proc(display: ^Display) -> cstring --- // Display macros (defaults) - XDefaultColormap :: proc(display: ^Display, screen_no: i32) -> Colormap --- - XDefaultDepth :: proc(display: ^Display) -> i32 --- - XDefaultGC :: proc(display: ^Display, screen_no: i32) -> GC --- - XDefaultRootWindow :: proc(display: ^Display) -> Window --- - XDefaultScreen :: proc(display: ^Display) -> i32 --- - XDefaultVisual :: proc(display: ^Display, screen_no: i32) -> ^Visual --- - XDefaultScreenOfDisplay :: + DefaultColormap :: proc(display: ^Display, screen_no: i32) -> Colormap --- + DefaultDepth :: proc(display: ^Display) -> i32 --- + DefaultGC :: proc(display: ^Display, screen_no: i32) -> GC --- + DefaultRootWindow :: proc(display: ^Display) -> Window --- + DefaultScreen :: proc(display: ^Display) -> i32 --- + DefaultVisual :: proc(display: ^Display, screen_no: i32) -> ^Visual --- + DefaultScreenOfDisplay :: proc(display: ^Display) -> ^Screen --- // Display macros (other) - XRootWindow :: proc(display: ^Display, screen_no: i32) -> Window --- - XScreenCount :: proc(display: ^Display) -> i32 --- + RootWindow :: proc(display: ^Display, screen_no: i32) -> Window --- + ScreenCount :: proc(display: ^Display) -> i32 --- // Display image format macros - XListPixmapFormats :: proc(display: ^Display, count: ^i32) -> [^]XPixmapFormatValues --- - XImageByteOrder :: proc(display: ^Display) -> ByteOrder --- - XBitmapUnit :: proc(display: ^Display) -> i32 --- - XBitmapBitOrder :: proc(display: ^Display) -> ByteOrder --- - XBitmapPad :: proc(display: ^Display) -> i32 --- - XDisplayHeight :: proc(display: ^Display, screen_no: i32) -> i32 --- - XDisplayHeightMM :: proc(display: ^Display, screen_no: i32) -> i32 --- - XDisplayWidth :: proc(display: ^Display, screen_no: i32) -> i32 --- - XDisplayWidthMM :: proc(display: ^Display, screen_no: i32) -> i32 --- + ListPixmapFormats :: proc(display: ^Display, count: ^i32) -> [^]XPixmapFormatValues --- + ImageByteOrder :: proc(display: ^Display) -> ByteOrder --- + BitmapUnit :: proc(display: ^Display) -> i32 --- + BitmapBitOrder :: proc(display: ^Display) -> ByteOrder --- + BitmapPad :: proc(display: ^Display) -> i32 --- + DisplayHeight :: proc(display: ^Display, screen_no: i32) -> i32 --- + DisplayHeightMM :: proc(display: ^Display, screen_no: i32) -> i32 --- + DisplayWidth :: proc(display: ^Display, screen_no: i32) -> i32 --- + DisplayWidthMM :: proc(display: ^Display, screen_no: i32) -> i32 --- // Screen macros - XBlackPixelsOfScreen :: proc(screen: ^Screen) -> uint --- - XWhitePixelsOfScreen :: proc(screen: ^Screen) -> uint --- - XCellsOfScreen :: proc(screen: ^Screen) -> i32 --- - XDefaultColormapOfScreen :: proc(screen: ^Screen) -> Colormap --- - XDefaultDepthOfScreen :: proc(screen: ^Screen) -> i32 --- - XDefaultGCOfScreen :: proc(screen: ^Screen) -> GC --- - XDefaultVisualOfScreen :: proc(screen: ^Screen) -> ^Visual --- - XDoesBackingStore :: proc(screen: ^Screen) -> BackingStore --- - XDoesSaveUnders :: proc(screen: ^Screen) -> b32 --- - XDisplayOfScreen :: proc(screen: ^Screen) -> ^Display --- - XScreenNumberOfScreens :: proc(screen: ^Screen) -> i32 --- - XEventMaskOfScreen :: proc(screen: ^Screen) -> EventMask --- - XWidthOfScreen :: proc(screen: ^Screen) -> i32 --- - XHeightOfScreen :: proc(screen: ^Screen) -> i32 --- - XWidthMMOfScreen :: proc(screen: ^Screen) -> i32 --- - XHeightMMOfScreen :: proc(screen: ^Screen) -> i32 --- - XMaxCmapsOfScreen :: proc(screen: ^Screen) -> i32 --- - XMinCmapsOfScreen :: proc(screen: ^Screen) -> i32 --- - XPlanesOfScreen :: proc(screen: ^Screen) -> i32 --- - XRootWindowOfScreen :: proc(screen: ^Screen) -> Window --- + BlackPixelsOfScreen :: proc(screen: ^Screen) -> uint --- + WhitePixelsOfScreen :: proc(screen: ^Screen) -> uint --- + CellsOfScreen :: proc(screen: ^Screen) -> i32 --- + DefaultColormapOfScreen :: proc(screen: ^Screen) -> Colormap --- + DefaultDepthOfScreen :: proc(screen: ^Screen) -> i32 --- + DefaultGCOfScreen :: proc(screen: ^Screen) -> GC --- + DefaultVisualOfScreen :: proc(screen: ^Screen) -> ^Visual --- + DoesBackingStore :: proc(screen: ^Screen) -> BackingStore --- + DoesSaveUnders :: proc(screen: ^Screen) -> b32 --- + DisplayOfScreen :: proc(screen: ^Screen) -> ^Display --- + ScreenNumberOfScreens :: proc(screen: ^Screen) -> i32 --- + EventMaskOfScreen :: proc(screen: ^Screen) -> EventMask --- + WidthOfScreen :: proc(screen: ^Screen) -> i32 --- + HeightOfScreen :: proc(screen: ^Screen) -> i32 --- + WidthMMOfScreen :: proc(screen: ^Screen) -> i32 --- + HeightMMOfScreen :: proc(screen: ^Screen) -> i32 --- + MaxCmapsOfScreen :: proc(screen: ^Screen) -> i32 --- + MinCmapsOfScreen :: proc(screen: ^Screen) -> i32 --- + PlanesOfScreen :: proc(screen: ^Screen) -> i32 --- + RootWindowOfScreen :: proc(screen: ^Screen) -> Window --- // Threading functions - XInitThreads :: proc() -> Status --- - XLockDisplay :: proc(display: ^Display) --- - XUnlockDisplay :: proc(display: ^Display) --- + InitThreads :: proc() -> Status --- + LockDisplay :: proc(display: ^Display) --- + UnlockDisplay :: proc(display: ^Display) --- // Internal connections - XAddConnectionWatch :: proc( + AddConnectionWatch :: proc( display: ^Display, procedure: XConnectionWatchProc, data: rawptr, ) -> Status --- - XRemoveConnectionWatch :: proc( + RemoveConnectionWatch :: proc( display: ^Display, procedure: XConnectionWatchProc, data: rawptr, ) -> Status --- - XProcessInternalConnections :: proc( + ProcessInternalConnections :: proc( display: ^Display, fd: i32, ) --- - XInternalConnectionNumbers :: proc( + InternalConnectionNumbers :: proc( display: ^Display, fds: ^[^]i32, count: ^i32, ) -> Status --- // Windows functions - XVisualIDFromVisual :: proc(visual: ^Visual) -> VisualID --- + VisualIDFromVisual :: proc(visual: ^Visual) -> VisualID --- // Windows: creation/destruction - XCreateWindow :: proc( + CreateWindow :: proc( display: ^Display, parent: Window, x: i32, @@ -123,7 +123,7 @@ foreign xlib { attr_mask: WindowAttributeMask, attr: ^XSetWindowAttributes, ) -> Window --- - XCreateSimpleWindow :: proc( + CreateSimpleWindow :: proc( display: ^Display, parent: Window, x: i32, @@ -134,34 +134,34 @@ foreign xlib { border: int, bg: int, ) -> Window --- - XDestroyWindow :: proc(display: ^Display, window: Window) --- - XDestroySubwindows :: proc(display: ^Display, window: Window) --- + DestroyWindow :: proc(display: ^Display, window: Window) --- + DestroySubwindows :: proc(display: ^Display, window: Window) --- // Windows: mapping/unmapping - XMapWindow :: proc(display: ^Display, window: Window) --- - XMapRaised :: proc(display: ^Display, window: Window) --- - XMapSubwindows :: proc(display: ^Display, window: Window) --- - XUnmapWindow :: proc(display: ^Display, window: Window) --- - XUnmapSubwindows :: proc(display: ^Display, window: Window) --- + MapWindow :: proc(display: ^Display, window: Window) --- + MapRaised :: proc(display: ^Display, window: Window) --- + MapSubwindows :: proc(display: ^Display, window: Window) --- + UnmapWindow :: proc(display: ^Display, window: Window) --- + UnmapSubwindows :: proc(display: ^Display, window: Window) --- // Windows: configuring - XConfigureWindow :: proc( + ConfigureWindow :: proc( display: ^Display, window: Window, mask: WindowChangesMask, values: XWindowChanges, ) --- - XMoveWindow :: proc( + MoveWindow :: proc( display: ^Display, window: Window, x: i32, y: i32, ) --- - XResizeWindow :: proc( + ResizeWindow :: proc( display: ^Display, window: Window, width: u32, height: u32, ) --- - XMoveResizeWindow :: proc( + MoveResizeWindow :: proc( display: ^Display, window: Window, x: i32, @@ -169,51 +169,51 @@ foreign xlib { width: u32, height: u32, ) --- - XSetWindowBorderWidth :: proc( + SetWindowBorderWidth :: proc( display: ^Display, window: Window, width: u32, ) --- // Window: changing stacking order - XRaiseWindow :: proc(display: ^Display, window: Window) --- - XLowerWindow :: proc(display: ^Display, window: Window) --- - XCirculateSubwindows :: proc(display: ^Display, window: Window, direction: CirculationDirection) --- - XCirculateSubwindowsUp :: proc(display: ^Display, window: Window) --- - XCirculateSubwindowsDown :: proc(display: ^Display, window: Window) --- - XRestackWindows :: proc(display: ^Display, windows: [^]Window, nwindows: i32) --- + RaiseWindow :: proc(display: ^Display, window: Window) --- + LowerWindow :: proc(display: ^Display, window: Window) --- + CirculateSubwindows :: proc(display: ^Display, window: Window, direction: CirculationDirection) --- + CirculateSubwindowsUp :: proc(display: ^Display, window: Window) --- + CirculateSubwindowsDown :: proc(display: ^Display, window: Window) --- + RestackWindows :: proc(display: ^Display, windows: [^]Window, nwindows: i32) --- // Window: changing attributes - XChangeWindowAttributes :: proc( + ChangeWindowAttributes :: proc( display: ^Display, window: Window, attr_mask: WindowAttributeMask, attr: XWindowAttributes, ) --- - XSetWindowBackground :: proc( + SetWindowBackground :: proc( display: ^Display, window: Window, pixel: uint, ) --- - XSetWindowBackgroundMap :: proc( + SetWindowBackgroundMap :: proc( display: ^Display, window: Window, pixmap: Pixmap, ) --- - XSetWindowColormap :: proc( + SetWindowColormap :: proc( display: ^Display, window: Window, colormap: Colormap, ) --- - XDefineCursor :: proc( + DefineCursor :: proc( display: ^Display, window: Window, cursor: Cursor, ) --- - XUndefineCursor :: proc( + UndefineCursor :: proc( display: ^Display, window: Window, ) --- // Windows: querying information - XQueryTree :: proc( + QueryTree :: proc( display: ^Display, window: Window, root: ^Window, @@ -221,12 +221,12 @@ foreign xlib { children: ^[^]Window, nchildren: ^u32, ) -> Status --- - XGetWindowAttributes :: proc( + GetWindowAttributes :: proc( display: ^Display, window: Window, attr: ^XWindowAttributes, ) --- - XGetGeometry :: proc( + GetGeometry :: proc( display: ^Display, drawable: Drawable, root: ^Window, @@ -238,7 +238,7 @@ foreign xlib { depth: ^u32, ) -> Status --- // Windows: translating screen coordinates - XTranslateCoordinates :: proc( + TranslateCoordinates :: proc( display: ^Display, src_window: Window, dst_window: Window, @@ -247,7 +247,7 @@ foreign xlib { dst_x: ^i32, dst_y: ^i32, ) -> b32 --- - XQueryPointer :: proc( + QueryPointer :: proc( display: ^Display, window: Window, root: ^Window, @@ -259,29 +259,29 @@ foreign xlib { mask: ^KeyMask, ) -> b32 --- // Atoms - XInternAtom :: proc( + InternAtom :: proc( display: ^Display, name: cstring, existing: b32, ) -> Atom --- - XInternAtoms :: proc( + InternAtoms :: proc( display: ^Display, names: [^]cstring, count: i32, atoms: [^]Atom, ) -> Status --- - XGetAtomName :: proc( + GetAtomName :: proc( display: ^Display, atom: Atom, ) -> cstring --- - XGetAtomNames :: proc( + GetAtomNames :: proc( display: ^Display, atoms: [^]Atom, count: i32, names: [^]cstring, ) -> Status --- // Windows: Obtaining and changing properties - XGetWindowProperty :: proc( + GetWindowProperty :: proc( display: ^Display, window: Window, property: Atom, @@ -295,12 +295,12 @@ foreign xlib { bytes_after: [^]uint, props: ^rawptr, ) -> i32 --- - XListProperties :: proc( + ListProperties :: proc( display: ^Display, window: Window, num: ^i32, ) -> [^]Atom --- - XChangeProperty :: proc( + ChangeProperty :: proc( display: ^Display, window: Window, property: Atom, @@ -310,30 +310,30 @@ foreign xlib { data: rawptr, count: i32, ) --- - XRotateWindowProperties :: proc( + RotateWindowProperties :: proc( display: ^Display, window: Window, props: [^]Atom, nprops: i32, npos: i32, ) --- - XDeleteProperty :: proc( + DeleteProperty :: proc( display: ^Display, window: Window, prop: Atom, ) --- // Selections - XSetSelectionOwner :: proc( + SetSelectionOwner :: proc( display: ^Display, selection: Atom, owber: Window, time: Time, ) --- - XGetSelectionOwner :: proc( + GetSelectionOwner :: proc( display: ^Display, selection: Atom, ) -> Window --- - XConvertSelection :: proc( + ConvertSelection :: proc( display: ^Display, selection: Atom, target: Atom, @@ -342,23 +342,23 @@ foreign xlib { time: Time, ) --- // Creating and freeing pixmaps - XCreatePixmap :: proc( + CreatePixmap :: proc( display: ^Display, drawable: Drawable, width: u32, height: u32, depth: u32, ) -> Pixmap --- - XFreePixmap :: proc( + FreePixmap :: proc( display: ^Display, pixmap: Pixmap, ) --- // Creating recoloring and freeing cursors - XCreateFontCursor :: proc( + CreateFontCursor :: proc( display: ^Display, shape: CursorShape, ) -> Cursor --- - XCreateGlyphCursor :: proc( + CreateGlyphCursor :: proc( display: ^Display, src_font: Font, mask_font: Font, @@ -367,7 +367,7 @@ foreign xlib { fg: ^XColor, bg: ^XColor, ) -> Cursor --- - XCreatePixmapCursor :: proc( + CreatePixmapCursor :: proc( display: ^Display, source: Pixmap, mask: Pixmap, @@ -376,7 +376,7 @@ foreign xlib { x: u32, y: u32, ) -> Cursor --- - XQueryBestCursor :: proc( + QueryBestCursor :: proc( display: ^Display, drawable: Drawable, width: u32, @@ -384,72 +384,50 @@ foreign xlib { out_width: ^u32, out_height: ^u32, ) -> Status --- - XRecolorCursor :: proc( + RecolorCursor :: proc( display: ^Display, cursor: Cursor, fg: ^XColor, bg: ^XColor, ) --- - XFreeCursor :: proc(display: ^Display, cursor: Cursor) --- + FreeCursor :: proc(display: ^Display, cursor: Cursor) --- // Creation/destruction of colormaps - XCreateColormap :: proc( + CreateColormap :: proc( display: ^Display, window: Window, visual: ^Visual, alloc: ColormapAlloc, ) -> Colormap --- - XCopyColormapAndFree :: proc( + CopyColormapAndFree :: proc( display: ^Display, colormap: Colormap, ) -> Colormap --- - XFreeColormap :: proc( + FreeColormap :: proc( display: ^Display, colormap: Colormap, ) --- // Mapping color names to values - XLookupColor :: proc( + LookupColor :: proc( display: ^Display, colomap: Colormap, name: cstring, exact: ^XColor, screen: ^XColor, ) -> Status --- - XcmsLookupColor :: proc( - display: ^Display, - colormap: Colormap, - name: cstring, - exact: XcmsColor, - screen: XcmsColor, - format: XcmsColorFormat, - ) -> Status --- // Allocating and freeing color cells - XAllocColor :: proc( + AllocColor :: proc( display: ^Display, colormap: Colormap, screen: ^XColor, ) -> Status --- - XcmsAllocColor :: proc( - display: ^Display, - colormap: Colormap, - color: ^XcmsColor, - format: XcmsColorFormat, - ) -> Status --- - XAllocNamedColor :: proc( + AllocNamedColor :: proc( display: ^Display, colormap: Colormap, name: cstring, screen: ^XColor, exact: ^XColor, ) -> Status --- - XcmsAllocNamedColor :: proc( - display: ^Display, - colormap: Colormap, - name: cstring, - screen: ^XcmsColor, - exact: ^XcmsColor, - format: XcmsColorFormat, - ) -> Status --- - XAllocColorCells :: proc( + AllocColorCells :: proc( display: ^Display, colormap: Colormap, contig: b32, @@ -458,7 +436,7 @@ foreign xlib { pixels: [^]uint, npixels: u32, ) -> Status --- - XAllocColorPlanes :: proc( + AllocColorPlanes :: proc( display: ^Display, colormap: Colormap, contig: b32, @@ -471,7 +449,7 @@ foreign xlib { gmask: [^]uint, bmask: [^]uint, ) -> Status --- - XFreeColors :: proc( + FreeColors :: proc( display: ^Display, colormap: Colormap, pixels: [^]uint, @@ -479,17 +457,1155 @@ foreign xlib { planes: uint, ) --- // Modifying and querying colormap cells - XStoreColor :: proc( + StoreColor :: proc( display: ^Display, colormap: Colormap, color: ^XColor, ) --- - XStoreColors :: proc( + StoreColors :: proc( display: ^Display, colormap: Colormap, color: [^]XColor, ncolors: i32, ) --- + // Graphics context functions + CreateGC :: proc( + display: ^Display, + drawable: Drawable, + mask: GCAttributeMask, + attr: ^XGCValues, + ) -> GC --- + CopyGC :: proc( + display: ^Display, + src: GC, + dst: GC, + mask: GCAttributeMask, + ) --- + ChangeGC :: proc( + display: ^Display, + gc: GC, + mask: GCAttributeMask, + values: ^XGCValues, + ) --- + GetGCValues :: proc( + display: ^Display, + gc: GC, + mask: GCAttributeMask, + values: ^XGCValues, + ) -> Status --- + FreeGC :: proc(display: ^Display, gc: GC) --- + GCContextFromGC :: proc(gc: GC) -> GContext --- + FlushGC :: proc(display: ^Display, gc: GC) --- + // Convenience routines for GC + SetState :: proc( + display: ^Display, + gc: GC, + fg: uint, + bg: uint, + fn: GCFunction, + pmask: uint, + ) --- + SetForeground :: proc( + display: ^Display, + gc: GC, + fg: uint, + ) --- + SetBackground :: proc( + display: ^Display, + gc: GC, + bg: uint, + ) --- + SetFunction :: proc( + display: ^Display, + gc: GC, + fn: GCFunction, + ) --- + SetPlaneMask :: proc( + display: ^Display, + gc: GC, + pmask: uint, + ) --- + SetLineAttributes :: proc( + display: ^Display, + gc: GC, + width: u32, + line_style: LineStyle, + cap_style: CapStyle, + join_style: JoinStyle, + ) --- + SetDashes :: proc( + display: ^Display, + gc: GC, + dash_offs: i32, + dash_list: [^]i8, + n: i32, + ) --- + SetFillStyle :: proc( + display: ^Display, + gc: GC, + style: FillStyle, + ) --- + SetFillRule :: proc( + display: ^Display, + gc: GC, + rule: FillRule, + ) --- + QueryBestSize :: proc( + display: ^Display, + class: i32, + which: Drawable, + width: u32, + height: u32, + out_width: ^u32, + out_height: ^u32, + ) -> Status --- + QueryBestTile :: proc( + display: ^Display, + which: Drawable, + width: u32, + height: u32, + out_width: ^u32, + out_height: ^u32, + ) -> Status --- + QueryBestStripple :: proc( + display: ^Display, + which: Drawable, + width: u32, + height: u32, + out_width: u32, + out_height: u32, + ) -> Status --- + SetTile :: proc(display: ^Display, gc: GC, tile: Pixmap) --- + SetStripple :: proc(display: ^Display, gc: GC, stripple: Pixmap) --- + SetTSOrigin :: proc(display: ^Display, gc: GC, x: i32, y: i32) --- + SetFont :: proc(display: ^Display, gc: GC, font: Font) --- + SetClipOrigin :: proc(display: ^Display, gc: GC, x: i32, y: i32) --- + SetClipMask :: proc(display: ^Display, gc: GC, pixmap: Pixmap) --- + SetClipRectangles :: proc( + display: ^Display, + gc: GC, + x: i32, + y: i32, + rects: [^]XRectangle, + n: i32, + ordering: i32, + ) --- + SetArcMode :: proc(display: ^Display, gc: GC, mode: ArcMode) --- + SetSubwindowMode :: proc(display: ^Display, gc: GC, mode: SubwindowMode) --- + SetGraphicsExposures :: proc(display: ^Display, gc: GC, exp: b32) --- + // Graphics functions + ClearArea :: proc( + display: ^Display, + window: Window, + x: i32, + y: i32, + width: u32, + height: u32, + exp: b32, + ) --- + ClearWindow :: proc( + display: ^Display, + window: Window, + ) --- + CopyArea :: proc( + display: ^Display, + src: Drawable, + dst: Drawable, + gc: GC, + src_x: i32, + src_y: i32, + width: u32, + height: u32, + dst_x: i32, + dst_y: i32, + ) --- + CopyPlane :: proc( + display: ^Display, + src: Drawable, + dst: Drawable, + gc: GC, + src_x: i32, + src_y: i32, + width: u32, + height: u32, + dst_x: i32, + dst_y: i32, + plane: uint, + ) --- + // Drawing lines, points, rectangles and arc + DrawPoint :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + ) --- + DrawPoints :: proc( + display: Display, + drawable: Drawable, + gc: GC, + point: [^]XPoint, + npoints: i32, + mode: CoordMode, + ) --- + DrawLine :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x1: i32, + y1: i32, + x2: i32, + y2: i32, + ) --- + DrawLines :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + points: [^]XPoint, + npoints: i32, + ) --- + DrawSegments :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + segs: [^]XSegment, + nsegs: i32, + ) --- + DrawRectangle :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32, + ) --- + DrawRectangles :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + rects: [^]XRectangle, + nrects: i32, + ) --- + DrawArc :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32, + angle1: i32, + angle2: i32, + ) --- + DrawArcs :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + arcs: [^]XArc, + narcs: i32, + ) --- + // Filling areas + FillRectangle :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32, + ) --- + FillRectangles :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + rects: [^]XRectangle, + nrects: i32, + ) --- + FillPolygon :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + points: [^]XPoint, + npoints: i32, + shape: Shape, + mode: CoordMode, + ) --- + FillArc :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + width: u32, + height: u32, + angle1: i32, + angle2: i32, + ) --- + FillArcs :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + arcs: [^]XArc, + narcs: i32, + ) --- + // Font metrics + LoadFont :: proc(display: ^Display, name: cstring) -> Font --- + QueryFont :: proc(display: ^Display, id: XID) -> ^XFontStruct --- + LoadQueryFont :: proc(display: ^Display, name: cstring) -> ^XFontStruct --- + FreeFont :: proc(display: ^Display, font_struct: ^XFontStruct) --- + GetFontProperty :: proc(font_struct: ^XFontStruct, atom: Atom, ret: ^uint) -> b32 --- + UnloadFont :: proc(display: ^Display, font: Font) --- + ListFonts :: proc(display: ^Display, pat: cstring, max: i32, count: ^i32) -> [^]cstring --- + FreeFontNames :: proc(display: ^Display, list: [^]cstring) --- + ListFontsWithInfo :: proc( + display: ^Display, + pat: cstring, + max: i32, + count: ^i32, + info: ^[^]XFontStruct, + ) -> [^]cstring --- + FreeFontInfo :: proc(names: [^]cstring, info: [^]XFontStruct, count: i32) --- + // Computing character string sizes + TextWidth :: proc(font_struct: ^XFontStruct, string: [^]u8, count: i32) -> i32 --- + TextWidth16 :: proc(font_struct: ^XFontStruct, string: [^]XChar2b, count: i32) -> i32 --- + TextExtents :: proc( + font_struct: ^XFontStruct, + string: [^]u8, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct, + ) --- + TextExtents16 :: proc( + font_struct: ^XFontStruct, + string: [^]XChar2b, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct, + ) --- + QueryTextExtents :: proc( + display: ^Display, + font_id: XID, + string: [^]u8, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct, + ) --- + QueryTextExtents16 :: proc( + display: ^Display, + font_id: XID, + string: [^]XChar2b, + nchars: i32, + direction: ^FontDirection, + ascent: ^i32, + descent: ^i32, + ret: ^XCharStruct, + ) --- + // Drawing complex text + DrawText :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + items: XTextItem, + nitems: i32, + ) --- + DrawText16 :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + items: XTextItem16, + nitems: i32, + ) --- + // Drawing text characters + DrawString :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]u8, + length: i32, + ) --- + DrawString16 :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]XChar2b, + length: i32, + ) --- + DrawImageString :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]u8, + length: i32, + ) --- + DrawImageString16 :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + x: i32, + y: i32, + string: [^]XChar2b, + length: i32, + ) --- + // Transferring images between client and server + InitImage :: proc(image: ^XImage) -> Status --- + PutImage :: proc( + display: ^Display, + drawable: Drawable, + gc: GC, + image: ^XImage, + src_x: i32, + src_y: i32, + dst_x: i32, + dst_y: i32, + width: u32, + height: u32, + ) --- + GetImage :: proc( + display: ^Display, + drawable: Drawable, + x: i32, + y: i32, + width: u32, + height: u32, + mask: uint, + format: ImageFormat, + ) -> ^XImage --- + GetSubImage :: proc( + display: ^Display, + drawable: Drawable, + src_x: i32, + src_y: i32, + width: u32, + height: u32, + mask: uint, + format: ImageFormat, + dst: ^XImage, + dst_x: i32, + dst_y: i32, + ) -> ^XImage --- + // Window and session manager functions + ReparentWindow :: proc( + display: ^Display, + window: Window, + parent: Window, + x: i32, + y: i32, + ) --- + ChangeSaveSet :: proc( + display: ^Display, + window: Window, + mode: SaveSetChangeMode, + ) --- + AddToSaveSet :: proc( + display: ^Display, + window: Window, + ) --- + RemoveFromSaveSet :: proc( + display: ^Display, + window: Window, + ) --- + // Managing installed colormaps + InstallColormap :: proc(display: ^Display, colormap: Colormap) --- + UninstallColormap :: proc(display: ^Display, colormap: Colormap) --- + ListInstalledColormaps :: proc(display: ^Display, window: Window, n: ^i32) -> [^]Colormap --- + // Setting and retrieving font search paths + SetFontPath :: proc(display: ^Display, dirs: [^]cstring, ndirs: i32) --- + GetFontPath :: proc(display: ^Display, npaths: ^i32) -> [^]cstring --- + FreeFontPath :: proc(list: [^]cstring) --- + // Grabbing the server + GrabServer :: proc(display: ^Display) --- + UngrabServer :: proc(display: ^Display) --- + // Killing clients + KillClient :: proc(display: ^Display, resource: XID) --- + // Controlling the screen saver + SetScreenSaver :: proc( + display: ^Display, + timeout: i32, + interval: i32, + blanking: ScreenSaverBlanking, + exposures: ScreenSavingExposures, + ) --- + ForceScreenSaver :: proc(display: ^Display, mode: ScreenSaverForceMode) --- + ActivateScreenSaver :: proc(display: ^Display) --- + ResetScreenSaver :: proc(display: ^Display) --- + GetScreenSaver :: proc( + display: ^Display, + timeout: ^i32, + interval: ^i32, + blanking: ^ScreenSaverBlanking, + exposures: ^ScreenSavingExposures, + ) --- + // Controlling host address + AddHost :: proc(display: ^Display, addr: ^XHostAddress) --- + AddHosts :: proc(display: ^Display, hosts: [^]XHostAddress, nhosts: i32) --- + ListHosts :: proc(display: ^Display, nhosts: ^i32, state: [^]b32) -> [^]XHostAddress --- + RemoveHost :: proc(display: ^Display, host: XHostAddress) --- + RemoveHosts :: proc(display: ^Display, hosts: [^]XHostAddress, nhosts: i32) --- + // Access control list + SetAccessControl :: proc(display: ^Display, mode: AccessControlMode) --- + EnableAccessControl :: proc(display: ^Display) --- + DisableAccessControl :: proc(display: ^Display) --- + // Events + SelectInput :: proc(display: ^Display, window: Window, mask: EventMask) --- + Flush :: proc(display: ^Display) --- + Sync :: proc(display: ^Display) --- + EventsQueued :: proc(display: ^Display, mode: EventQueueMode) -> i32 --- + Pending :: proc(display: ^Display) -> i32 --- + NextEvent :: proc(display: ^Display, event: ^XEvent) --- + PeekEvent :: proc(display: ^Display, event: ^XEvent) --- + GetEventData :: proc(display: ^Display, cookie: ^XGenericEventCookie) -> b32 --- + FreeEventData :: proc(display: ^Display, cookie: ^XGenericEventCookie) --- + // Selecting events using a predicate procedure + IfEvent :: proc( + display: ^Display, + event: ^XEvent, + predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, + ctx: rawptr, + ) --- + CheckIfEvent :: proc( + display: ^Display, + event: ^XEvent, + predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, + arg: rawptr, + ) -> b32 --- + PeekIfEvent :: proc( + display: ^Display, + event: ^XEvent, + predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, + ctx: rawptr, + ) --- + // Selecting events using a window or event mask + WindowEvent :: proc( + display: ^Display, + window: Window, + mask: EventMask, + event: ^XEvent, + ) --- + CheckWindowEvent :: proc( + display: ^Display, + window: Window, + mask: EventMask, + event: ^XEvent, + ) -> b32 --- + MaskEvent :: proc( + display: ^Display, + mask: EventMask, + event: ^XEvent, + ) --- + CheckMaskEvent :: proc( + display: ^Display, + mask: EventMask, + event: ^XEvent, + ) -> b32 --- + CheckTypedEvent :: proc( + display: ^Display, + type: EventType, + event: ^XEvent, + ) -> b32 --- + CheckTypedWindowEvent :: proc( + display: ^Display, + window: Window, + type: EventType, + event: ^XEvent, + ) -> b32 --- + // Putting events back + PutBackEvent :: proc( + display: ^Display, + event: ^XEvent, + ) --- + // Sending events to other applications + SendEvent :: proc( + display: ^Display, + window: Window, + propagate: b32, + mask: EventMask, + event: ^XEvent, + ) -> Status --- + // Getting the history of pointer motion + DisplayMotionBufferSize :: proc(display: ^Display) -> uint --- + GetMotionEvents :: proc( + display: ^Display, + window: Window, + start: Time, + stop: Time, + nevents: ^i32, + ) -> [^]XTimeCoord --- + // Enabling or disabling synchronization + SetAfterFunction :: proc( + display: ^Display, + procedure: #type proc "c" (display: ^Display) -> i32, + ) -> i32 --- + Synchronize :: proc( + display: ^Display, + onoff: b32, + ) -> i32 --- + // Error handling + SetErrorHandler :: proc( + handler: #type proc "c" (display: ^Display, event: ^XErrorEvent) -> i32, + ) -> i32 --- + GetErrorText :: proc( + display: ^Display, + code: i32, + buffer: [^]u8, + size: i32, + ) --- + GetErrorDatabaseText :: proc( + display: ^Display, + name: cstring, + message: cstring, + default_string: cstring, + buffer: [^]u8, + size: i32, + ) --- + DisplayName :: proc(string: cstring) -> cstring --- + SetIOErrorHandler :: proc( + handler: #type proc "c" (display: ^Display) -> i32, + ) -> i32 --- + // Pointer grabbing + GrabPointer :: proc( + display: ^Display, + grab_window: Window, + owner_events: b32, + mask: EventMask, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + confine_to: Window, + cursor: Cursor, + time: Time, + ) -> i32 --- + UngrabPointer :: proc( + display: ^Display, + time: Time, + ) -> i32 --- + ChangeActivePointerGrab :: proc( + display: ^Display, + event_mask: EventMask, + cursor: Cursor, + time: Time, + ) --- + GrabButton :: proc( + display: ^Display, + button: u32, + modifiers: InputMask, + grab_window: Window, + owner_events: b32, + event_mask: EventMask, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + confine_to: Window, + cursor: Cursor, + ) --- + UngrabButton :: proc( + display: ^Display, + button: u32, + modifiers: InputMask, + grab_window: Window, + ) --- + GrabKeyboard :: proc( + display: ^Display, + grab_window: Window, + owner_events: b32, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + time: Time, + ) -> i32 --- + UngrabKeyboard :: proc( + display: ^Display, + time: Time, + ) --- + GrabKey :: proc( + display: ^Display, + keycode: i32, + modifiers: InputMask, + grab_window: Window, + owner_events: b32, + pointer_mode: GrabMode, + keyboard_mode: GrabMode, + ) --- + UngrabKey :: proc( + display: ^Display, + keycode: i32, + modifiers: InputMask, + grab_window: Window, + ) --- + // Resuming event processing + AllowEvents :: proc(display: ^Display, evend_mode: AllowEventsMode, time: Time) --- + // Moving the pointer + WarpPointer :: proc( + display: ^Display, + src_window: Window, + dst_window: Window, + src_x: i32, + src_y: i32, + src_width: u32, + src_height: u32, + dst_x: i32, + dst_y: i32, + ) --- + // Controlling input focus + SetInputFocus :: proc( + display: ^Display, + focus: Window, + revert_to: FocusRevert, + time: Time, + ) --- + GetInputFocus :: proc( + display: ^Display, + focus: ^Window, + revert_to: ^FocusRevert, + ) --- + // Manipulating the keyboard and pointer settings + ChangeKeyboardControl :: proc( + display: ^Display, + mask: KeyboardControlMask, + values: ^XKeyboardControl, + ) --- + GetKeyboardControl :: proc( + display: ^Display, + values: ^XKeyboardState, + ) --- + AutoRepeatOn :: proc(display: ^Display) --- + AutoRepeatOff :: proc(display: ^Display) --- + Bell :: proc(display: ^Display, percent: i32) --- + QueryKeymap :: proc(display: ^Display, keys: [^]u32) --- + SetPointerMapping :: proc(display: ^Display, map_should_not_be_a_keyword: [^]u8, nmap: i32) -> i32 --- + GetPointerMapping :: proc(display: ^Display, map_should_not_be_a_keyword: [^]u8, nmap: i32) -> i32 --- + ChangePointerControl :: proc( + display: ^Display, + do_accel: b32, + do_threshold: b32, + accel_numerator: i32, + accel_denominator: i32, + threshold: i32, + ) --- + GetPointerControl :: proc( + display: ^Display, + accel_numerator: ^i32, + accel_denominator: ^i32, + threshold: ^i32, + ) --- + // Manipulating the keyboard encoding + DisplayKeycodes :: proc( + display: ^Display, + min_keycodes: ^i32, + max_keycodes: ^i32, + ) --- + GetKeyboardMapping :: proc( + display: ^Display, + first: KeyCode, + count: i32, + keysyms_per: ^i32, + ) -> ^KeySym --- + ChangeKeyboardMapping :: proc( + display: ^Display, + first: KeyCode, + keysyms_per: i32, + keysyms: [^]KeySym, + num_codes: i32, + ) --- + NewModifiermap :: proc(max_keys_per_mode: i32) -> ^XModifierKeymap --- + InsertModifiermapEntry :: proc( + modmap: ^XModifierKeymap, + keycode_entry: KeyCode, + modifier: i32, + ) -> ^XModifierKeymap --- + DeleteModifiermapEntry :: proc( + modmap: ^XModifierKeymap, + keycode_entry: KeyCode, + modifier: i32, + ) -> ^XModifierKeymap --- + FreeModifiermap :: proc(modmap: ^XModifierKeymap) --- + SetModifierMapping :: proc(display: ^Display, modmap: ^XModifierKeymap) -> i32 --- + GetModifierMapping :: proc(display: ^Display) -> ^XModifierKeymap --- + // Manipulating top-level windows + IconifyWindow :: proc( + dipslay: ^Display, + window: Window, + screen_no: i32, + ) -> Status --- + WithdrawWindow :: proc( + dipslay: ^Display, + window: Window, + screen_no: i32, + ) -> Status --- + ReconfigureWMWindow :: proc( + dipslay: ^Display, + window: Window, + screen_no: i32, + mask: WindowChangesMask, + changes: ^XWindowChanges, + ) -> Status --- + // Getting and setting the WM_NAME property + SetWMName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) --- + GetWMName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) -> Status --- + StoreName :: proc( + display: ^Display, + window: Window, + name: cstring, + ) --- + FetchName :: proc( + display: ^Display, + window: Window, + name: ^cstring, + ) -> Status --- + SetWMIconName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) --- + GetWMIconName :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) -> Status --- + SetIconName :: proc( + display: ^Display, + window: Window, + name: cstring, + ) --- + GetIconName :: proc( + display: ^Display, + window: Window, + prop: ^cstring, + ) -> Status --- + // Setting and reading WM_HINTS property + AllocWMHints :: proc() -> ^XWMHints --- + SetWMHints :: proc( + display: ^Display, + window: Window, + hints: ^XWMHints, + ) --- + GetWMHints :: proc( + display: ^Display, + window: Window, + ) -> ^XWMHints --- + // Setting and reading MW_NORMAL_HINTS property + AllocSizeHints :: proc() -> ^XSizeHints --- + SetWMNormalHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + ) --- + GetWMNormalHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + flags: ^SizeHints, + ) -> Status --- + SetWMSizeHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + prop: Atom, + ) --- + GetWMSizeHints :: proc( + display: ^Display, + window: Window, + hints: ^XSizeHints, + masks: ^SizeHints, + prop: Atom, + ) -> Status --- + // Setting and reading the WM_CLASS property + AllocClassHint :: proc() -> ^XClassHint --- + SetClassHint :: proc( + display: ^Display, + window: Window, + hint: ^XClassHint, + ) --- + GetClassHint :: proc( + display: ^Display, + window: Window, + hint: ^XClassHint, + ) -> Status --- + // Setting and reading WM_TRANSIENT_FOR property + SetTransientForHint :: proc( + display: ^Display, + window: Window, + prop_window: Window, + ) --- + GetTransientForHint :: proc( + display: ^Display, + window: Window, + prop_window: ^Window, + ) -> Status --- + // Setting and reading the WM_PROTOCOLS property + SetWMProtocols :: proc( + display: ^Display, + window: Window, + protocols: [^]Atom, + count: i32, + ) -> Status --- + GetWMProtocols :: proc( + display: ^Display, + window: Window, + protocols: ^[^]Atom, + count: ^i32, + ) -> Status --- + // Setting and reading the WM_COLORMAP_WINDOWS property + SetWMColormapWindows :: proc( + display: ^Display, + window: Window, + colormap_windows: [^]Window, + count: i32, + ) -> Status --- + GetWMColormapWindows :: proc( + display: ^Display, + window: Window, + colormap_windows: ^[^]Window, + count: ^i32, + ) -> Status --- + // Setting and reading the WM_ICON_SIZE_PROPERTY + AllocIconSize :: proc() -> ^XIconSize --- + SetIconSizes :: proc( + display: ^Display, + window: Window, + size_list: [^]XIconSize, + count: i32, + ) --- + GetIconSizes :: proc( + display: ^Display, + window: Window, + size_list: ^[^]XIconSize, + count: ^i32, + ) -> Status --- + // Using window manager convenience functions + mbSetWMProperties :: proc( + display: ^Display, + window: Window, + window_name: cstring, + icon_name: cstring, + argv: [^]cstring, + argc: i32, + normal_hints: ^XSizeHints, + wm_hints: ^XWMHints, + class_hints: ^XClassHint, + ) --- + SetWMProperties :: proc( + display: ^Display, + window: Window, + window_name: ^XTextProperty, + argv: [^]cstring, + argc: i32, + normal_hints: ^XSizeHints, + wm_hints: ^XWMHints, + class_hints: ^XWMHints, + ) --- + // Client to session manager communication + SetCommand :: proc( + display: ^Display, + window: Window, + argv: [^]cstring, + argc: i32, + ) --- + GetCommand :: proc( + display: ^Display, + window: Window, + argv: ^[^]cstring, + argc: ^i32, + ) -> Status --- + SetWMClientMachine :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) --- + GetWMClientMachine :: proc( + display: ^Display, + window: Window, + prop: ^XTextProperty, + ) -> Status --- + SetRGBColormaps :: proc( + display: ^Display, + window: Window, + colormap: ^XStandardColormap, + prop: Atom, + ) --- + GetRGBColormaps :: proc( + display: ^Display, + window: Window, + colormap: ^[^]XStandardColormap, + count: ^i32, + prop: Atom, + ) -> Status --- + // Keyboard utility functions + LookupKeysym :: proc( + event: ^XKeyEvent, + index: i32, + ) -> KeySym --- + KeycodeToKeysym :: proc( + display: ^Display, + keycode: KeyCode, + index: i32, + ) -> KeySym --- + KeysymToKeycode :: proc( + display: ^Display, + keysym: KeySym, + ) -> KeyCode --- + RefreshKeyboardMapping :: proc(event_map: ^XMappingEvent) --- + ConvertCase :: proc( + keysym: KeySym, + lower: ^KeySym, + upper: ^KeySym, + ) --- + StringToKeysym :: proc(str: cstring) -> KeySym --- + KeysymToString :: proc(keysym: KeySym) -> cstring --- + LookupString :: proc( + event: ^XKeyEvent, + buffer: [^]u8, + count: i32, + keysym: ^KeySym, + status: ^XComposeStatus, + ) -> i32 --- + RebindKeysym :: proc( + display: ^Display, + keysym: KeySym, + list: [^]KeySym, + mod_count: i32, + string: [^]u8, + num_bytes: i32, + ) --- + // Allocating permanent storage + Permalloc :: proc(size: u32) -> rawptr --- + // Parsing the window geometry + ParseGeometry :: proc( + parsestring: cstring, + x_ret: ^i32, + y_ret: ^i32, + width: ^u32, + height: ^u32, + ) -> i32 --- + WMGeometry :: proc( + display: ^Display, + screen_no: i32, + user_geom: cstring, + def_geom: cstring, + bwidth: u32, + hints: ^XSizeHints, + x_ret: ^i32, + y_ret: ^i32, + w_ret: ^u32, + h_ret: ^u32, + grav: ^Gravity, + ) -> i32 --- + // Creating, copying and destroying regions + CreateRegion :: proc() -> Region --- + PolygonRegion :: proc( + points: [^]XPoint, + n: i32, + fill: FillRule, + ) -> Region --- + SetRegion :: proc( + display: ^Display, + gc: GC, + region: Region, + ) --- + DestroyRegion :: proc(r: Region) --- + // Moving or shrinking regions + OffsetRegion :: proc(region: Region, dx, dy: i32) --- + ShrinkRegion :: proc(region: Region, dx, dy: i32) --- + // Computing with regions + ClipBox :: proc(region: Region, rect: ^XRectangle) --- + IntersectRegion :: proc(sra, srb, ret: Region) --- + UnionRegion :: proc(sra, srb, ret: Region) --- + UnionRectWithRegion :: proc(rect: ^XRectangle, src, dst: Region) --- + SubtractRegion :: proc(sra, srb, ret: Region) --- + XorRegion :: proc(sra, srb, ret: Region) --- + EmptyRegion :: proc(reg: Region) -> b32 --- + EqualRegion :: proc(a,b: Region) -> b32 --- + PointInRegion :: proc(reg: Region, x,y: i32) -> b32 --- + RectInRegion :: proc(reg: Region, x,y: i32, w,h: u32) -> b32 --- + // Using cut buffers + StoreBytes :: proc(display: ^Display, bytes: [^]u8, nbytes: i32) --- + StoreBuffer :: proc(display: ^Display, bytes: [^]u8, nbytes: i32, buffer: i32) --- + FetchBytes :: proc(display: ^Display, nbytes: ^i32) -> [^]u8 --- + FetchBuffer :: proc(display: ^Display, nbytes: ^i32, buffer: i32) -> [^]u8 --- + // Determining the appropriate visual types + GetVisualInfo :: proc( + display: ^Display, + mask: VisualInfoMask, + info: ^XVisualInfo, + nret: ^i32, + ) -> [^]XVisualInfo --- + MatchVisualInfo :: proc( + display: ^Display, + screen_no: i32, + depth: i32, + class: i32, + ret: ^XVisualInfo, + ) -> Status --- + // Manipulating images + CreateImage :: proc( + display: ^Display, + visual: ^Visual, + depth: u32, + format: ImageFormat, + offset: i32, + data: rawptr, + width: u32, + height: u32, + pad: i32, + stride: i32, + ) -> ^XImage --- + GetPixel :: proc( + image: ^XImage, + x: i32, + y: i32, + ) -> uint --- + PutPixel :: proc( + image: ^XImage, + x: i32, + y: i32, + pixel: uint, + ) --- + SubImage :: proc( + image: ^XImage, + x: i32, + y: i32, + w: u32, + h: u32, + ) -> ^XImage --- + AddPixel :: proc( + image: ^XImage, + value: int, + ) --- + DestroyImage :: proc(image: ^XImage) --- + ResourceManagerString :: proc(display: ^Display) -> cstring --- +} + +@(default_calling_convention="c") +foreign xlib { + XcmsLookupColor :: proc( + display: ^Display, + colormap: Colormap, + name: cstring, + exact: XcmsColor, + screen: XcmsColor, + format: XcmsColorFormat, + ) -> Status --- XcmsStoreColor :: proc( display: ^Display, colormap: Colormap, @@ -502,25 +1618,25 @@ foreign xlib { ncolors: XcmsColor, cflags: [^]b32, ) -> Status --- - XStoreNamedColor :: proc( + StoreNamedColor :: proc( display: ^Display, colormap: Colormap, name: cstring, pixel: uint, flags: ColorFlags, ) --- - XQueryColor :: proc( + QueryColor :: proc( display: ^Display, colormap: Colormap, color: ^XColor, ) --- - XQueryColors :: proc( + QueryColors :: proc( display: ^Display, colormap: Colormap, colors: [^]XColor, ncolors: i32, ) --- - XQueryExtension :: proc( + QueryExtension :: proc( display: ^Display, name: cstring, major_opcode_return: ^i32, @@ -790,1129 +1906,21 @@ foreign xlib { chroma: XcmsFloat, color: ^XcmsColor, ) -> Status --- - // Graphics context functions - XCreateGC :: proc( + XcmsAllocNamedColor :: proc( display: ^Display, - drawable: Drawable, - mask: GCAttributeMask, - attr: ^XGCValues, - ) -> GC --- - XCopyGC :: proc( - display: ^Display, - src: GC, - dst: GC, - mask: GCAttributeMask, - ) --- - XChangeGC :: proc( - display: ^Display, - gc: GC, - mask: GCAttributeMask, - values: ^XGCValues, - ) --- - XGetGCValues :: proc( - display: ^Display, - gc: GC, - mask: GCAttributeMask, - values: ^XGCValues, + colormap: Colormap, + name: cstring, + screen: ^XcmsColor, + exact: ^XcmsColor, + format: XcmsColorFormat, ) -> Status --- - XFreeGC :: proc(display: ^Display, gc: GC) --- - XGCContextFromGC :: proc(gc: GC) -> GContext --- - XFlushGC :: proc(display: ^Display, gc: GC) --- - // Convenience routines for GC - XSetState :: proc( - display: ^Display, - gc: GC, - fg: uint, - bg: uint, - fn: GCFunction, - pmask: uint, - ) --- - XSetForeground :: proc( - display: ^Display, - gc: GC, - fg: uint, - ) --- - XSetBackground :: proc( - display: ^Display, - gc: GC, - bg: uint, - ) --- - XSetFunction :: proc( - display: ^Display, - gc: GC, - fn: GCFunction, - ) --- - XSetPlaneMask :: proc( - display: ^Display, - gc: GC, - pmask: uint, - ) --- - XSetLineAttributes :: proc( - display: ^Display, - gc: GC, - width: u32, - line_style: LineStyle, - cap_style: CapStyle, - join_style: JoinStyle, - ) --- - XSetDashes :: proc( - display: ^Display, - gc: GC, - dash_offs: i32, - dash_list: [^]i8, - n: i32, - ) --- - XSetFillStyle :: proc( - display: ^Display, - gc: GC, - style: FillStyle, - ) --- - XSetFillRule :: proc( - display: ^Display, - gc: GC, - rule: FillRule, - ) --- - XQueryBestSize :: proc( - display: ^Display, - class: i32, - which: Drawable, - width: u32, - height: u32, - out_width: ^u32, - out_height: ^u32, + XcmsAllocColor :: proc( + display: ^Display, + colormap: Colormap, + color: ^XcmsColor, + format: XcmsColorFormat, ) -> Status --- - XQueryBestTile :: proc( - display: ^Display, - which: Drawable, - width: u32, - height: u32, - out_width: ^u32, - out_height: ^u32, - ) -> Status --- - XQueryBestStripple :: proc( - display: ^Display, - which: Drawable, - width: u32, - height: u32, - out_width: u32, - out_height: u32, - ) -> Status --- - XSetTile :: proc(display: ^Display, gc: GC, tile: Pixmap) --- - XSetStripple :: proc(display: ^Display, gc: GC, stripple: Pixmap) --- - XSetTSOrigin :: proc(display: ^Display, gc: GC, x: i32, y: i32) --- - XSetFont :: proc(display: ^Display, gc: GC, font: Font) --- - XSetClipOrigin :: proc(display: ^Display, gc: GC, x: i32, y: i32) --- - XSetClipMask :: proc(display: ^Display, gc: GC, pixmap: Pixmap) --- - XSetClipRectangles :: proc( - display: ^Display, - gc: GC, - x: i32, - y: i32, - rects: [^]XRectangle, - n: i32, - ordering: i32, - ) --- - XSetArcMode :: proc(display: ^Display, gc: GC, mode: ArcMode) --- - XSetSubwindowMode :: proc(display: ^Display, gc: GC, mode: SubwindowMode) --- - XSetGraphicsExposures :: proc(display: ^Display, gc: GC, exp: b32) --- - // Graphics functions - XClearArea :: proc( - display: ^Display, - window: Window, - x: i32, - y: i32, - width: u32, - height: u32, - exp: b32, - ) --- - XClearWindow :: proc( - display: ^Display, - window: Window, - ) --- - XCopyArea :: proc( - display: ^Display, - src: Drawable, - dst: Drawable, - gc: GC, - src_x: i32, - src_y: i32, - width: u32, - height: u32, - dst_x: i32, - dst_y: i32, - ) --- - XCopyPlane :: proc( - display: ^Display, - src: Drawable, - dst: Drawable, - gc: GC, - src_x: i32, - src_y: i32, - width: u32, - height: u32, - dst_x: i32, - dst_y: i32, - plane: uint, - ) --- - // Drawing lines, points, rectangles and arc - XDrawPoint :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - ) --- - XDrawPoints :: proc( - display: Display, - drawable: Drawable, - gc: GC, - point: [^]XPoint, - npoints: i32, - mode: CoordMode, - ) --- - XDrawLine :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x1: i32, - y1: i32, - x2: i32, - y2: i32, - ) --- - XDrawLines :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - points: [^]XPoint, - npoints: i32, - ) --- - XDrawSegments :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - segs: [^]XSegment, - nsegs: i32, - ) --- - XDrawRectangle :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - width: u32, - height: u32, - ) --- - XDrawRectangles :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - rects: [^]XRectangle, - nrects: i32, - ) --- - XDrawArc :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - width: u32, - height: u32, - angle1: i32, - angle2: i32, - ) --- - XDrawArcs :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - arcs: [^]XArc, - narcs: i32, - ) --- - // Filling areas - XFillRectangle :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - width: u32, - height: u32, - ) --- - XFillRectangles :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - rects: [^]XRectangle, - nrects: i32, - ) --- - XFillPolygon :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - points: [^]XPoint, - npoints: i32, - shape: Shape, - mode: CoordMode, - ) --- - XFillArc :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - width: u32, - height: u32, - angle1: i32, - angle2: i32, - ) --- - XFillArcs :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - arcs: [^]XArc, - narcs: i32, - ) --- - // Font metrics - XLoadFont :: proc(display: ^Display, name: cstring) -> Font --- - XQueryFont :: proc(display: ^Display, id: XID) -> ^XFontStruct --- - XLoadQueryFont :: proc(display: ^Display, name: cstring) -> ^XFontStruct --- - XFreeFont :: proc(display: ^Display, font_struct: ^XFontStruct) --- - XGetFontProperty :: proc(font_struct: ^XFontStruct, atom: Atom, ret: ^uint) -> b32 --- - XUnloadFont :: proc(display: ^Display, font: Font) --- - XListFonts :: proc(display: ^Display, pat: cstring, max: i32, count: ^i32) -> [^]cstring --- - XFreeFontNames :: proc(display: ^Display, list: [^]cstring) --- - XListFontsWithInfo :: proc( - display: ^Display, - pat: cstring, - max: i32, - count: ^i32, - info: ^[^]XFontStruct, - ) -> [^]cstring --- - XFreeFontInfo :: proc(names: [^]cstring, info: [^]XFontStruct, count: i32) --- - // Computing character string sizes - XTextWidth :: proc(font_struct: ^XFontStruct, string: [^]u8, count: i32) -> i32 --- - XTextWidth16 :: proc(font_struct: ^XFontStruct, string: [^]XChar2b, count: i32) -> i32 --- - XTextExtents :: proc( - font_struct: ^XFontStruct, - string: [^]u8, - nchars: i32, - direction: ^FontDirection, - ascent: ^i32, - descent: ^i32, - ret: ^XCharStruct, - ) --- - XTextExtents16 :: proc( - font_struct: ^XFontStruct, - string: [^]XChar2b, - nchars: i32, - direction: ^FontDirection, - ascent: ^i32, - descent: ^i32, - ret: ^XCharStruct, - ) --- - XQueryTextExtents :: proc( - display: ^Display, - font_id: XID, - string: [^]u8, - nchars: i32, - direction: ^FontDirection, - ascent: ^i32, - descent: ^i32, - ret: ^XCharStruct, - ) --- - XQueryTextExtents16 :: proc( - display: ^Display, - font_id: XID, - string: [^]XChar2b, - nchars: i32, - direction: ^FontDirection, - ascent: ^i32, - descent: ^i32, - ret: ^XCharStruct, - ) --- - // Drawing complex text - XDrawText :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - items: XTextItem, - nitems: i32, - ) --- - XDrawText16 :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - items: XTextItem16, - nitems: i32, - ) --- - // Drawing text characters - XDrawString :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - string: [^]u8, - length: i32, - ) --- - XDrawString16 :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - string: [^]XChar2b, - length: i32, - ) --- - XDrawImageString :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - string: [^]u8, - length: i32, - ) --- - XDrawImageString16 :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - x: i32, - y: i32, - string: [^]XChar2b, - length: i32, - ) --- - // Transferring images between client and server - XInitImage :: proc(image: ^XImage) -> Status --- - XPutImage :: proc( - display: ^Display, - drawable: Drawable, - gc: GC, - image: ^XImage, - src_x: i32, - src_y: i32, - dst_x: i32, - dst_y: i32, - width: u32, - height: u32, - ) --- - XGetImage :: proc( - display: ^Display, - drawable: Drawable, - x: i32, - y: i32, - width: u32, - height: u32, - mask: uint, - format: ImageFormat, - ) -> ^XImage --- - XGetSubImage :: proc( - display: ^Display, - drawable: Drawable, - src_x: i32, - src_y: i32, - width: u32, - height: u32, - mask: uint, - format: ImageFormat, - dst: ^XImage, - dst_x: i32, - dst_y: i32, - ) -> ^XImage --- - // Window and session manager functions - XReparentWindow :: proc( - display: ^Display, - window: Window, - parent: Window, - x: i32, - y: i32, - ) --- - XChangeSaveSet :: proc( - display: ^Display, - window: Window, - mode: SaveSetChangeMode, - ) --- - XAddToSaveSet :: proc( - display: ^Display, - window: Window, - ) --- - XRemoveFromSaveSet :: proc( - display: ^Display, - window: Window, - ) --- - // Managing installed colormaps - XInstallColormap :: proc(display: ^Display, colormap: Colormap) --- - XUninstallColormap :: proc(display: ^Display, colormap: Colormap) --- - XListInstalledColormaps :: proc(display: ^Display, window: Window, n: ^i32) -> [^]Colormap --- - // Setting and retrieving font search paths - XSetFontPath :: proc(display: ^Display, dirs: [^]cstring, ndirs: i32) --- - XGetFontPath :: proc(display: ^Display, npaths: ^i32) -> [^]cstring --- - XFreeFontPath :: proc(list: [^]cstring) --- - // Grabbing the server - XGrabServer :: proc(display: ^Display) --- - XUngrabServer :: proc(display: ^Display) --- - // Killing clients - XKillClient :: proc(display: ^Display, resource: XID) --- - // Controlling the screen saver - XSetScreenSaver :: proc( - display: ^Display, - timeout: i32, - interval: i32, - blanking: ScreenSaverBlanking, - exposures: ScreenSavingExposures, - ) --- - XForceScreenSaver :: proc(display: ^Display, mode: ScreenSaverForceMode) --- - XActivateScreenSaver :: proc(display: ^Display) --- - XResetScreenSaver :: proc(display: ^Display) --- - XGetScreenSaver :: proc( - display: ^Display, - timeout: ^i32, - interval: ^i32, - blanking: ^ScreenSaverBlanking, - exposures: ^ScreenSavingExposures, - ) --- - // Controlling host address - XAddHost :: proc(display: ^Display, addr: ^XHostAddress) --- - XAddHosts :: proc(display: ^Display, hosts: [^]XHostAddress, nhosts: i32) --- - XListHosts :: proc(display: ^Display, nhosts: ^i32, state: [^]b32) -> [^]XHostAddress --- - XRemoveHost :: proc(display: ^Display, host: XHostAddress) --- - XRemoveHosts :: proc(display: ^Display, hosts: [^]XHostAddress, nhosts: i32) --- - // Access control list - XSetAccessControl :: proc(display: ^Display, mode: AccessControlMode) --- - XEnableAccessControl :: proc(display: ^Display) --- - XDisableAccessControl :: proc(display: ^Display) --- - // Events - XSelectInput :: proc(display: ^Display, window: Window, mask: EventMask) --- - XFlush :: proc(display: ^Display) --- - XSync :: proc(display: ^Display) --- - XEventsQueued :: proc(display: ^Display, mode: EventQueueMode) -> i32 --- - XPending :: proc(display: ^Display) -> i32 --- - XNextEvent :: proc(display: ^Display, event: ^XEvent) --- - XPeekEvent :: proc(display: ^Display, event: ^XEvent) --- - XGetEventData :: proc(display: ^Display, cookie: ^XGenericEventCookie) -> b32 --- - XFreeEventData :: proc(display: ^Display, cookie: ^XGenericEventCookie) --- - // Selecting events using a predicate procedure - XIfEvent :: proc( - display: ^Display, - event: ^XEvent, - predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, - ctx: rawptr, - ) --- - XCheckIfEvent :: proc( - display: ^Display, - event: ^XEvent, - predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, - arg: rawptr, - ) -> b32 --- - XPeekIfEvent :: proc( - display: ^Display, - event: ^XEvent, - predicate: #type proc "c" (display: ^Display, event: ^XEvent, ctx: rawptr) -> b32, - ctx: rawptr, - ) --- - // Selecting events using a window or event mask - XWindowEvent :: proc( - display: ^Display, - window: Window, - mask: EventMask, - event: ^XEvent, - ) --- - XCheckWindowEvent :: proc( - display: ^Display, - window: Window, - mask: EventMask, - event: ^XEvent, - ) -> b32 --- - XMaskEvent :: proc( - display: ^Display, - mask: EventMask, - event: ^XEvent, - ) --- - XCheckMaskEvent :: proc( - display: ^Display, - mask: EventMask, - event: ^XEvent, - ) -> b32 --- - XCheckTypedEvent :: proc( - display: ^Display, - type: EventType, - event: ^XEvent, - ) -> b32 --- - XCheckTypedWindowEvent :: proc( - display: ^Display, - window: Window, - type: EventType, - event: ^XEvent, - ) -> b32 --- - // Putting events back - XPutBackEvent :: proc( - display: ^Display, - event: ^XEvent, - ) --- - // Sending events to other applications - XSendEvent :: proc( - display: ^Display, - window: Window, - propagate: b32, - mask: EventMask, - event: ^XEvent, - ) -> Status --- - // Getting the history of pointer motion - XDisplayMotionBufferSize :: proc(display: ^Display) -> uint --- - XGetMotionEvents :: proc( - display: ^Display, - window: Window, - start: Time, - stop: Time, - nevents: ^i32, - ) -> [^]XTimeCoord --- - // Enabling or disabling synchronization - XSetAfterFunction :: proc( - display: ^Display, - procedure: #type proc "c" (display: ^Display) -> i32, - ) -> i32 --- - XSynchronize :: proc( - display: ^Display, - onoff: b32, - ) -> i32 --- - // Error handling - XSetErrorHandler :: proc( - handler: #type proc "c" (display: ^Display, event: ^XErrorEvent) -> i32, - ) -> i32 --- - XGetErrorText :: proc( - display: ^Display, - code: i32, - buffer: [^]u8, - size: i32, - ) --- - XGetErrorDatabaseText :: proc( - display: ^Display, - name: cstring, - message: cstring, - default_string: cstring, - buffer: [^]u8, - size: i32, - ) --- - XDisplayName :: proc(string: cstring) -> cstring --- - XSetIOErrorHandler :: proc( - handler: #type proc "c" (display: ^Display) -> i32, - ) -> i32 --- - // Pointer grabbing - XGrabPointer :: proc( - display: ^Display, - grab_window: Window, - owner_events: b32, - mask: EventMask, - pointer_mode: GrabMode, - keyboard_mode: GrabMode, - confine_to: Window, - cursor: Cursor, - time: Time, - ) -> i32 --- - XUngrabPointer :: proc( - display: ^Display, - time: Time, - ) -> i32 --- - XChangeActivePointerGrab :: proc( - display: ^Display, - event_mask: EventMask, - cursor: Cursor, - time: Time, - ) --- - XGrabButton :: proc( - display: ^Display, - button: u32, - modifiers: InputMask, - grab_window: Window, - owner_events: b32, - event_mask: EventMask, - pointer_mode: GrabMode, - keyboard_mode: GrabMode, - confine_to: Window, - cursor: Cursor, - ) --- - XUngrabButton :: proc( - display: ^Display, - button: u32, - modifiers: InputMask, - grab_window: Window, - ) --- - XGrabKeyboard :: proc( - display: ^Display, - grab_window: Window, - owner_events: b32, - pointer_mode: GrabMode, - keyboard_mode: GrabMode, - time: Time, - ) -> i32 --- - XUngrabKeyboard :: proc( - display: ^Display, - time: Time, - ) --- - XGrabKey :: proc( - display: ^Display, - keycode: i32, - modifiers: InputMask, - grab_window: Window, - owner_events: b32, - pointer_mode: GrabMode, - keyboard_mode: GrabMode, - ) --- - XUngrabKey :: proc( - display: ^Display, - keycode: i32, - modifiers: InputMask, - grab_window: Window, - ) --- - // Resuming event processing - XAllowEvents :: proc(display: ^Display, evend_mode: AllowEventsMode, time: Time) --- - // Moving the pointer - XWarpPointer :: proc( - display: ^Display, - src_window: Window, - dst_window: Window, - src_x: i32, - src_y: i32, - src_width: u32, - src_height: u32, - dst_x: i32, - dst_y: i32, - ) --- - // Controlling input focus - XSetInputFocus :: proc( - display: ^Display, - focus: Window, - revert_to: FocusRevert, - time: Time, - ) --- - XGetInputFocus :: proc( - display: ^Display, - focus: ^Window, - revert_to: ^FocusRevert, - ) --- - // Manipulating the keyboard and pointer settings - XChangeKeyboardControl :: proc( - display: ^Display, - mask: KeyboardControlMask, - values: ^XKeyboardControl, - ) --- - XGetKeyboardControl :: proc( - display: ^Display, - values: ^XKeyboardState, - ) --- - XAutoRepeatOn :: proc(display: ^Display) --- - XAutoRepeatOff :: proc(display: ^Display) --- - XBell :: proc(display: ^Display, percent: i32) --- - XQueryKeymap :: proc(display: ^Display, keys: [^]u32) --- - XSetPointerMapping :: proc(display: ^Display, map_should_not_be_a_keyword: [^]u8, nmap: i32) -> i32 --- - XGetPointerMapping :: proc(display: ^Display, map_should_not_be_a_keyword: [^]u8, nmap: i32) -> i32 --- - XChangePointerControl :: proc( - display: ^Display, - do_accel: b32, - do_threshold: b32, - accel_numerator: i32, - accel_denominator: i32, - threshold: i32, - ) --- - XGetPointerControl :: proc( - display: ^Display, - accel_numerator: ^i32, - accel_denominator: ^i32, - threshold: ^i32, - ) --- - // Manipulating the keyboard encoding - XDisplayKeycodes :: proc( - display: ^Display, - min_keycodes: ^i32, - max_keycodes: ^i32, - ) --- - XGetKeyboardMapping :: proc( - display: ^Display, - first: KeyCode, - count: i32, - keysyms_per: ^i32, - ) -> ^KeySym --- - XChangeKeyboardMapping :: proc( - display: ^Display, - first: KeyCode, - keysyms_per: i32, - keysyms: [^]KeySym, - num_codes: i32, - ) --- - XNewModifiermap :: proc(max_keys_per_mode: i32) -> ^XModifierKeymap --- - XInsertModifiermapEntry :: proc( - modmap: ^XModifierKeymap, - keycode_entry: KeyCode, - modifier: i32, - ) -> ^XModifierKeymap --- - XDeleteModifiermapEntry :: proc( - modmap: ^XModifierKeymap, - keycode_entry: KeyCode, - modifier: i32, - ) -> ^XModifierKeymap --- - XFreeModifiermap :: proc(modmap: ^XModifierKeymap) --- - XSetModifierMapping :: proc(display: ^Display, modmap: ^XModifierKeymap) -> i32 --- - XGetModifierMapping :: proc(display: ^Display) -> ^XModifierKeymap --- - // Manipulating top-level windows - XIconifyWindow :: proc( - dipslay: ^Display, - window: Window, - screen_no: i32, - ) -> Status --- - XWithdrawWindow :: proc( - dipslay: ^Display, - window: Window, - screen_no: i32, - ) -> Status --- - XReconfigureWMWindow :: proc( - dipslay: ^Display, - window: Window, - screen_no: i32, - mask: WindowChangesMask, - changes: ^XWindowChanges, - ) -> Status --- - // Getting and setting the WM_NAME property - XSetWMName :: proc( - display: ^Display, - window: Window, - prop: ^XTextProperty, - ) --- - XGetWMName :: proc( - display: ^Display, - window: Window, - prop: ^XTextProperty, - ) -> Status --- - XStoreName :: proc( - display: ^Display, - window: Window, - name: cstring, - ) --- - XFetchName :: proc( - display: ^Display, - window: Window, - name: ^cstring, - ) -> Status --- - XSetWMIconName :: proc( - display: ^Display, - window: Window, - prop: ^XTextProperty, - ) --- - XGetWMIconName :: proc( - display: ^Display, - window: Window, - prop: ^XTextProperty, - ) -> Status --- - XSetIconName :: proc( - display: ^Display, - window: Window, - name: cstring, - ) --- - XGetIconName :: proc( - display: ^Display, - window: Window, - prop: ^cstring, - ) -> Status --- - // Setting and reading WM_HINTS property - XAllocWMHints :: proc() -> ^XWMHints --- - XSetWMHints :: proc( - display: ^Display, - window: Window, - hints: ^XWMHints, - ) --- - XGetWMHints :: proc( - display: ^Display, - window: Window, - ) -> ^XWMHints --- - // Setting and reading MW_NORMAL_HINTS property - XAllocSizeHints :: proc() -> ^XSizeHints --- - XSetWMNormalHints :: proc( - display: ^Display, - window: Window, - hints: ^XSizeHints, - ) --- - XGetWMNormalHints :: proc( - display: ^Display, - window: Window, - hints: ^XSizeHints, - flags: ^SizeHints, - ) -> Status --- - XSetWMSizeHints :: proc( - display: ^Display, - window: Window, - hints: ^XSizeHints, - prop: Atom, - ) --- - XGetWMSizeHints :: proc( - display: ^Display, - window: Window, - hints: ^XSizeHints, - masks: ^SizeHints, - prop: Atom, - ) -> Status --- - // Setting and reading the WM_CLASS property - XAllocClassHint :: proc() -> ^XClassHint --- - XSetClassHint :: proc( - display: ^Display, - window: Window, - hint: ^XClassHint, - ) --- - XGetClassHint :: proc( - display: ^Display, - window: Window, - hint: ^XClassHint, - ) -> Status --- - // Setting and reading WM_TRANSIENT_FOR property - XSetTransientForHint :: proc( - display: ^Display, - window: Window, - prop_window: Window, - ) --- - XGetTransientForHint :: proc( - display: ^Display, - window: Window, - prop_window: ^Window, - ) -> Status --- - // Setting and reading the WM_PROTOCOLS property - XSetWMProtocols :: proc( - display: ^Display, - window: Window, - protocols: [^]Atom, - count: i32, - ) -> Status --- - XGetWMProtocols :: proc( - display: ^Display, - window: Window, - protocols: ^[^]Atom, - count: ^i32, - ) -> Status --- - // Setting and reading the WM_COLORMAP_WINDOWS property - XSetWMColormapWindows :: proc( - display: ^Display, - window: Window, - colormap_windows: [^]Window, - count: i32, - ) -> Status --- - XGetWMColormapWindows :: proc( - display: ^Display, - window: Window, - colormap_windows: ^[^]Window, - count: ^i32, - ) -> Status --- - // Setting and reading the WM_ICON_SIZE_PROPERTY - XAllocIconSize :: proc() -> ^XIconSize --- - XSetIconSizes :: proc( - display: ^Display, - window: Window, - size_list: [^]XIconSize, - count: i32, - ) --- - XGetIconSizes :: proc( - display: ^Display, - window: Window, - size_list: ^[^]XIconSize, - count: ^i32, - ) -> Status --- - // Using window manager convenience functions - XmbSetWMProperties :: proc( - display: ^Display, - window: Window, - window_name: cstring, - icon_name: cstring, - argv: [^]cstring, - argc: i32, - normal_hints: ^XSizeHints, - wm_hints: ^XWMHints, - class_hints: ^XClassHint, - ) --- - XSetWMProperties :: proc( - display: ^Display, - window: Window, - window_name: ^XTextProperty, - argv: [^]cstring, - argc: i32, - normal_hints: ^XSizeHints, - wm_hints: ^XWMHints, - class_hints: ^XWMHints, - ) --- - // Client to session manager communication - XSetCommand :: proc( - display: ^Display, - window: Window, - argv: [^]cstring, - argc: i32, - ) --- - XGetCommand :: proc( - display: ^Display, - window: Window, - argv: ^[^]cstring, - argc: ^i32, - ) -> Status --- - XSetWMClientMachine :: proc( - display: ^Display, - window: Window, - prop: ^XTextProperty, - ) --- - XGetWMClientMachine :: proc( - display: ^Display, - window: Window, - prop: ^XTextProperty, - ) -> Status --- - XSetRGBColormaps :: proc( - display: ^Display, - window: Window, - colormap: ^XStandardColormap, - prop: Atom, - ) --- - XGetRGBColormaps :: proc( - display: ^Display, - window: Window, - colormap: ^[^]XStandardColormap, - count: ^i32, - prop: Atom, - ) -> Status --- - // Keyboard utility functions - XLookupKeysym :: proc( - event: ^XKeyEvent, - index: i32, - ) -> KeySym --- - XKeycodeToKeysym :: proc( - display: ^Display, - keycode: KeyCode, - index: i32, - ) -> KeySym --- - XKeysymToKeycode :: proc( - display: ^Display, - keysym: KeySym, - ) -> KeyCode --- - XRefreshKeyboardMapping :: proc(event_map: ^XMappingEvent) --- - XConvertCase :: proc( - keysym: KeySym, - lower: ^KeySym, - upper: ^KeySym, - ) --- - XStringToKeysym :: proc(str: cstring) -> KeySym --- - XKeysymToString :: proc(keysym: KeySym) -> cstring --- - XLookupString :: proc( - event: ^XKeyEvent, - buffer: [^]u8, - count: i32, - keysym: ^KeySym, - status: ^XComposeStatus, - ) -> i32 --- - XRebindKeysym :: proc( - display: ^Display, - keysym: KeySym, - list: [^]KeySym, - mod_count: i32, - string: [^]u8, - num_bytes: i32, - ) --- - // Allocating permanent storage - XPermalloc :: proc(size: u32) -> rawptr --- - // Parsing the window geometry - XParseGeometry :: proc( - parsestring: cstring, - x_ret: ^i32, - y_ret: ^i32, - width: ^u32, - height: ^u32, - ) -> i32 --- - XWMGeometry :: proc( - display: ^Display, - screen_no: i32, - user_geom: cstring, - def_geom: cstring, - bwidth: u32, - hints: ^XSizeHints, - x_ret: ^i32, - y_ret: ^i32, - w_ret: ^u32, - h_ret: ^u32, - grav: ^Gravity, - ) -> i32 --- - // Creating, copying and destroying regions - XCreateRegion :: proc() -> Region --- - XPolygonRegion :: proc( - points: [^]XPoint, - n: i32, - fill: FillRule, - ) -> Region --- - XSetRegion :: proc( - display: ^Display, - gc: GC, - region: Region, - ) --- - XDestroyRegion :: proc(r: Region) --- - // Moving or shrinking regions - XOffsetRegion :: proc(region: Region, dx, dy: i32) --- - XShrinkRegion :: proc(region: Region, dx, dy: i32) --- - // Computing with regions - XClipBox :: proc(region: Region, rect: ^XRectangle) --- - XIntersectRegion :: proc(sra, srb, ret: Region) --- - XUnionRegion :: proc(sra, srb, ret: Region) --- - XUnionRectWithRegion :: proc(rect: ^XRectangle, src, dst: Region) --- - XSubtractRegion :: proc(sra, srb, ret: Region) --- - XXorRegion :: proc(sra, srb, ret: Region) --- - XEmptyRegion :: proc(reg: Region) -> b32 --- - XEqualRegion :: proc(a,b: Region) -> b32 --- - XPointInRegion :: proc(reg: Region, x,y: i32) -> b32 --- - XRectInRegion :: proc(reg: Region, x,y: i32, w,h: u32) -> b32 --- - // Using cut buffers - XStoreBytes :: proc(display: ^Display, bytes: [^]u8, nbytes: i32) --- - XStoreBuffer :: proc(display: ^Display, bytes: [^]u8, nbytes: i32, buffer: i32) --- - XFetchBytes :: proc(display: ^Display, nbytes: ^i32) -> [^]u8 --- - XFetchBuffer :: proc(display: ^Display, nbytes: ^i32, buffer: i32) -> [^]u8 --- - // Determining the appropriate visual types - XGetVisualInfo :: proc( - display: ^Display, - mask: VisualInfoMask, - info: ^XVisualInfo, - nret: ^i32, - ) -> [^]XVisualInfo --- - XMatchVisualInfo :: proc( - display: ^Display, - screen_no: i32, - depth: i32, - class: i32, - ret: ^XVisualInfo, - ) -> Status --- - // Manipulating images - XCreateImage :: proc( - display: ^Display, - visual: ^Visual, - depth: u32, - format: ImageFormat, - offset: i32, - data: rawptr, - width: u32, - height: u32, - pad: i32, - stride: i32, - ) -> ^XImage --- - XGetPixel :: proc( - image: ^XImage, - x: i32, - y: i32, - ) -> uint --- - XPutPixel :: proc( - image: ^XImage, - x: i32, - y: i32, - pixel: uint, - ) --- - XSubImage :: proc( - image: ^XImage, - x: i32, - y: i32, - w: u32, - h: u32, - ) -> ^XImage --- - XAddPixel :: proc( - image: ^XImage, - value: int, - ) --- - XDestroyImage :: proc(image: ^XImage) --- + XrmInitialize :: proc() --- + XrmGetStringDatabase :: proc(data: cstring) -> XrmDatabase --- + XrmGetResource :: proc(db: XrmDatabase, name: cstring, class: cstring, type_return: ^cstring, val_return: ^XrmValue) -> b32 --- } From 303d86ab7e54abb084bb96a556b6ff6d4a2d0f63 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 4 Jun 2024 11:26:57 +0200 Subject: [PATCH 93/93] Complete nightly scripts update to new b2 cli version --- ci/create_nightly_json.py | 5 ++--- ci/delete_old_binaries.py | 6 ++---- ci/upload_create_nightly.sh | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/ci/create_nightly_json.py b/ci/create_nightly_json.py index d7029399a..03c653040 100644 --- a/ci/create_nightly_json.py +++ b/ci/create_nightly_json.py @@ -13,7 +13,7 @@ def main(): for x in files_lines: parts = x.split(" ", 1) if parts[0]: - json_str = execute_cli(f"b2 get-file-info {parts[0]}") + json_str = execute_cli(f"b2 file info {parts[0]}") data = json.loads(json_str) name = remove_prefix(data['fileName'], "nightly/") url = f"https://f001.backblazeb2.com/file/{bucket}/nightly/{urllib.parse.quote_plus(name)}" @@ -47,5 +47,4 @@ def execute_cli(command): return sb.stdout.read().decode("utf-8"); if __name__ == '__main__': - sys.exit(main()) - + sys.exit(main()) \ No newline at end of file diff --git a/ci/delete_old_binaries.py b/ci/delete_old_binaries.py index 39e8ff2ac..6ea3cb78d 100644 --- a/ci/delete_old_binaries.py +++ b/ci/delete_old_binaries.py @@ -12,7 +12,6 @@ def main(): print(f"Looking for binaries to delete older than {days_to_keep} days") files_lines = execute_cli(f"b2 ls --long --versions b2://{bucket}/nightly/").split("\n") - print(files_lines) for x in files_lines: parts = [y for y in x.split(' ') if y] @@ -23,7 +22,7 @@ def main(): if delta.days > days_to_keep: print(f'Deleting {parts[5]}') - execute_cli(f'b2 delete-file-version {parts[0]}') + execute_cli(f'b2 rm {parts[0]}') def execute_cli(command): @@ -31,5 +30,4 @@ def execute_cli(command): return sb.stdout.read().decode("utf-8"); if __name__ == '__main__': - sys.exit(main()) - + sys.exit(main()) \ No newline at end of file diff --git a/ci/upload_create_nightly.sh b/ci/upload_create_nightly.sh index a4122f1da..8404b33ff 100755 --- a/ci/upload_create_nightly.sh +++ b/ci/upload_create_nightly.sh @@ -22,4 +22,4 @@ else 7z a -bd "output/$filename" -r "$artifact" fi -b2 upload-file "$bucket" "output/$filename" "nightly/$filename" +b2 file upload "$bucket" "output/$filename" "nightly/$filename"