/* A very simple test runner that can be used at compile-time. Usage: test :: #import "jx/test"; #if RUN_TESTS #run { test.run("collection of tests", t => { test.expect(t, some_condition, "error message: %", value); }); } */ T :: struct { location: Source_Code_Location; expects_run: s64; expects_ok: s64; failed: bool; } Proc :: #type (t: *T); expect :: (t: *T, cond: bool, message := "", args: ..Any, loc := #caller_location) { t.expects_run += 1; if cond { t.expects_ok += 1; return; } msg := "expectation failed"; if message.count != 0 { msg = basic.tprint(message, ..args); } t.failed = true; if #compile_time { compiler.compiler_report(msg, loc = loc, mode = .ERROR_CONTINUABLE); } else { basic.assert(false, msg, loc = loc); } } run :: (name: string, proc: Proc, loc := #caller_location) { // @note(judah): incredibly dumb way to get nicer test runs path := loc.fully_pathed_filename; i := path.count - 1; found_first_slash := false; while i >= 0 { if path[i] == "/" { if found_first_slash { i += 1; break; } found_first_slash = true; } i -= 1; } if !found_first_slash { path = strings.path_filename(loc.fully_pathed_filename); } else { path.count -= i; path.data += i; } basic.print("%,%: %...", path, loc.line_number, name); t: T; proc(*t); if t.failed { basic.print(" failed!\n"); } else { basic.print(" ok!\n"); } } #scope_file; basic :: #import "Basic"; // @future strings :: #import "String"; // @future compiler :: #import "Compiler"; // @future