// Usage: #if 0 { #run,stallable { Test("thing", t => { Expect(some_condition, "error message: %", value); }); Test("other thing", t => { Expect(other_condition, "error message: %", value); }); // ... } } /// Test defines a new suite to be executed by the test runner. /// /// See: Expect for more information. /// /// Test("my_proc does what it should", t => { /// value1 := my_proc(/* ... */); /// Expect(value1 != 0, "my_proc returned zero!"); /// /// value2 := my_proc(/* .... */); /// Expect(value2 > 0, "my_proc returned a negative number!"); /// }); /// Test :: (name: string, proc: (t: *void) -> (), 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; } WriteString(path, ","); WriteNumber(loc.line_number); WriteString(": ", name, "... "); t: TestRun; proc(*t); if t.failed { WriteString("failed"); } else { WriteString("ok"); } WriteString(" ("); WriteNumber(t.total_ok); WriteString("/"); WriteNumber(t.total_expects); WriteString(")\n"); } /// Expect checks the given condition, failing the current test if it is false. /// /// Note: Expect must be called within a test. Additionally, it expects the test /// parameter to be called 't'. Expect :: (cond: bool, message := "", args: ..Any, loc := #caller_location) #expand { run := `t.(*TestRun); run.total_expects += 1; if cond { run.total_ok += 1; return; } msg := "expectation failed"; if message.count != 0 { msg = basic.tprint(message, ..args); } run.failed = true; if #compile_time { CompileError(msg, loc = loc); } else { WriteStderrLocation(loc); WriteStderrString(": ", msg, "\n"); } } #scope_file TestRun :: struct { location: Source_Code_Location; total_expects: s64; total_ok: s64; failed: bool; } basic :: #import "Basic"; // @future strings :: #import "String"; // @future compiler :: #import "Compiler"; // @future