testing.odin 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package testing
  2. import "core:fmt"
  3. import "core:io"
  4. // IMPORTANT NOTE: Compiler requires this layout
  5. Test_Signature :: proc(^T);
  6. // IMPORTANT NOTE: Compiler requires this layout
  7. Internal_Test :: struct {
  8. pkg: string,
  9. name: string,
  10. p: Test_Signature,
  11. }
  12. Internal_Cleanup :: struct {
  13. procedure: proc(rawptr),
  14. user_data: rawptr,
  15. }
  16. T :: struct {
  17. error_count: int,
  18. w: io.Writer,
  19. cleanups: [dynamic]Internal_Cleanup,
  20. _fail_now: proc() -> !,
  21. }
  22. error :: proc(t: ^T, args: ..any, loc := #caller_location) {
  23. fmt.wprintf(t.w, "%v: ", loc);
  24. fmt.wprintln(t.w, ..args);
  25. t.error_count += 1;
  26. }
  27. errorf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) {
  28. fmt.wprintf(t.w, "%v: ", loc);
  29. fmt.wprintf(t.w, format, ..args);
  30. fmt.wprintln(t.w);
  31. t.error_count += 1;
  32. }
  33. fail :: proc(t: ^T) {
  34. error(t, "FAIL");
  35. t.error_count += 1;
  36. }
  37. fail_now :: proc(t: ^T) {
  38. fail(t);
  39. if t._fail_now != nil {
  40. t._fail_now();
  41. }
  42. }
  43. failed :: proc(t: ^T) -> bool {
  44. return t.error_count != 0;
  45. }
  46. log :: proc(t: ^T, args: ..any, loc := #caller_location) {
  47. fmt.wprintln(t.w, ..args);
  48. }
  49. logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) {
  50. fmt.wprintf(t.w, format, ..args);
  51. fmt.wprintln(t.w);
  52. }
  53. // cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete
  54. // cleanup proceduers will be called in LIFO (last added, first called) order.
  55. cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) {
  56. append(&t.cleanups, Internal_Cleanup{procedure, user_data});
  57. }
  58. expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool {
  59. if !ok {
  60. error(t=t, args={msg}, loc=loc);
  61. }
  62. return ok;
  63. }