package core:testing

⌘K
Ctrl+K
or
/

    Overview

    The implementation of the odin test runner and procedures user tests can use for this purpose.

    Defineables through #config:

    `odin // 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, 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) // Treat memory leaks and bad frees as errors. FAIL_ON_BAD_MEMORY : bool : #config(ODIN_TEST_FAIL_ON_BAD_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. // This requires terminal color support, as well as STDOUT to not be redirected to a file. FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) // Copy failed tests to the clipboard when done. 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) // Set the lowest log level for this test run. LOG_LEVEL_DEFAULT : string : "debug" when ODIN_DEBUG else "info" LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, LOG_LEVEL_DEFAULT) // Report a message at the info level when a test has changed its state. LOG_STATE_CHANGES : bool : #config(ODIN_TEST_LOG_STATE_CHANGES, false) // Show only the most necessary logging information. USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) // Output a report of the tests to the given path. JSON_REPORT : string : #config(ODIN_TEST_JSON_REPORT, "") // Print the full file path for failed test cases on a new line // in a way that's friendly to regex capture for an editor's "go to error". GO_TO_ERROR : bool : #config(ODIN_TEST_GO_TO_ERROR, false) `

    Types

    Internal_Cleanup ¶

    Internal_Cleanup :: struct {
    	procedure: proc(rawptr),
    	user_data: rawptr,
    	ctx:       runtime.Context,
    }

    Internal_Test ¶

    Internal_Test :: struct {
    	pkg:  string,
    	name: string,
    	p:    Test_Signature,
    }
     

    IMPORTANT NOTE: Compiler requires this layout

    Memory_Verifier_Proc ¶

    Memory_Verifier_Proc :: proc(t: ^T, ta: ^mem.Tracking_Allocator)
    Related Procedures With Parameters

    T ¶

    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:          sync_chan.Chan($T=Channel_Event, $D=-1),
    	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_called: bool,
    }
    Related Procedures With Parameters

    Test_Signature ¶

    Test_Signature :: proc(^T)
     

    IMPORTANT NOTE: Compiler requires this layout

    Constants

    MAX_EXPECTED_ASSERTIONS_PER_TEST ¶

    MAX_EXPECTED_ASSERTIONS_PER_TEST: int : 5

    Variables

    This section is empty.

    Procedures

    cleanup ¶

    cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) {…}
     

    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, and if the test failed due to a timeout, failed assertion, panic, bounds-checking error, memory access violation, or any other signal-based fault, this procedure will run with greater privilege in the test runner's main thread.

    That means that any cleanup procedure absolutely must not fail in the same way, or it will take down the entire test runner with it. This is for when you need something to run no matter what, if a test failed.

    For almost every usual case, defer should be preferable and sufficient.

    expect ¶

    expect :: proc(t: ^T, ok: bool, msg: string = "", expr: string = #caller_expression(ok), loc := #caller_location) -> bool {…}

    expect_assert_from ¶

    expect_assert_from :: proc(t: ^T, expected_place: runtime.Source_Code_Location, caller_loc := #caller_location) {…}
     

    Let the test runner know that it should expect an assertion failure from a specific location in the source code for this test.

    In the event that an assertion fails, a debug message will be logged with its exact message and location in a copyable format to make it convenient to write tests which use this API.

    This procedure may be called up to 5 times with different locations.

    This is a limitation for the sake of simplicity in the implementation, and you should consider breaking up your tests into smaller procedures if you need to check for asserts in more than 2 places.

    Related Procedure Groups

    expect_assert_message ¶

    expect_assert_message :: proc(t: ^T, expected_message: string, caller_loc := #caller_location) {…}
     

    Let the test runner know that it should expect an assertion failure with a specific message for this test.

    In the event that an assertion fails, a debug message will be logged with its exact message and location in a copyable format to make it convenient to write tests which use this API.

    This procedure may be called up to 5 times with different messages.

    This is a limitation for the sake of simplicity in the implementation, and you should consider breaking up your tests into smaller procedures if you need to check for more than a couple different assertion messages.

    Related Procedure Groups

    expect_leaks ¶

    expect_leaks :: proc(t: ^T, client_test: proc(t: ^T), verifier: Memory_Verifier_Proc) {…}

    expect_signal ¶

    expect_signal :: proc(t: ^T, #any_int sig: i32) {…}
     

    Let the test runner know that it should expect a signal to be raised within this test.

    This API is for advanced users, as arbitrary signals will not be caught; only the ones already handled by the test runner, such as

    SIGINT, (interrupt) SIGTERM, (polite termination) SIGILL, (illegal instruction) SIGFPE, (arithmetic error) SIGSEGV, and (segmentation fault) SIGTRAP (only on POSIX systems). (trap / debug trap)

    Note that only one signal can be expected per test.

    expect_value ¶

    expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location, value_expr: string = #caller_expression(value)) -> bool {…}

    expectf ¶

    expectf :: proc(t: ^T, ok: bool, format: string, .. args: ..any, loc := #caller_location) -> bool {…}

    fail ¶

    fail :: proc(t: ^T, loc := #caller_location) {…}

    fail_now ¶

    fail_now :: proc(t: ^T, msg: string = "", loc := #caller_location) -> ! {…}
     

    fail_now will cause a test to immediately fail and abort, much in the same way a failed assertion or panic call will stop a thread.

    It is for when you absolutely need a test to fail without calling any of its deferred statements. It will be cleaner than a regular assert or panic, as the test runner will know to expect the signal this procedure will raise.

    failed ¶

    failed :: proc(t: ^T) -> bool {…}

    set_fail_timeout ¶

    set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {…}

    Procedure Groups

    Source Files

    Generation Information

    Generated with odin version dev-2026-02 (vendor "odin") Windows_amd64 @ 2026-02-08 21:17:57.470831500 +0000 UTC