run.ha (2492B)
1 // License: MPL-2.0 2 // (c) 2022 Bor Grošelj Simić <bor.groseljsimic@telemach.net> 3 // (c) 2021 Drew DeVault <sir@cmpwn.com> 4 // (c) 2021 Ember Sawady <ecs@d2evs.net> 5 6 type test = struct { 7 name: str, 8 func: *fn() void, 9 }; 10 11 type abort_reason = struct { 12 loc: str, 13 msg: str, 14 }; 15 16 const @symbol("__test_array_start") test_start: [*]test; 17 const @symbol("__test_array_end") test_end: [*]test; 18 19 let jmp: jmpbuf = jmpbuf { ... }; 20 let reason: abort_reason = abort_reason { ... }; 21 22 export fn tests_main() size = { 23 const ntest = (&test_end: uintptr - &test_start: uintptr): size / size(test); 24 let maxname = 0z; 25 for (let i = 0z; i < ntest; i += 1) { 26 if (len(test_start[i].name) > maxname) { 27 maxname = len(test_start[i].name); 28 }; 29 }; 30 31 let failures: [](str, abort_reason) = []; 32 let npass = 0z, nfail = 0z; 33 let default_round = fegetround(); 34 print("Running "); 35 print(ztos(ntest)); 36 print(" tests:\n\n"); 37 time_start(); 38 for (let i = 0z; i < ntest; i += 1) { 39 if (!should_test(test_start[i].name)) { 40 continue; 41 }; 42 print(test_start[i].name); 43 dots(maxname - len(test_start[i].name) + 3); 44 print(" "); 45 46 if (setjmp(&jmp) != 0) { 47 nfail += 1; 48 append(failures, (test_start[i].name, reason)); 49 print("FAIL\n"); 50 continue; 51 }; 52 53 fesetround(default_round); 54 feclearexcept(~0u); 55 56 test_start[i].func(); 57 58 npass += 1; 59 print("OK\n"); 60 }; 61 let end = time_stop(); 62 63 if (nfail != 0) { 64 print("\n"); 65 print(ztos(nfail)); 66 if (nfail == 1) { 67 print(" test failed:\n"); 68 } else { 69 print(" tests failed:\n"); 70 }; 71 for (let i = 0z; i < nfail; i += 1) { 72 print(failures[i].0); 73 print(": "); 74 if (len(failures[i].1.loc) != 0) { 75 print(failures[i].1.loc); 76 print(": "); 77 }; 78 print(failures[i].1.msg); 79 print("\n"); 80 }; 81 }; 82 83 print("\n"); 84 print(ztos(npass)); 85 print(" passed; "); 86 print(ztos(nfail)); 87 print(" failed; "); 88 print(ztos(ntest)); 89 print(" tests completed in "); 90 print(ztos(end.0)); 91 print("."); 92 if (end.1 < 10) { 93 print("00"); 94 } else if (end.1 < 100) { 95 print("0"); 96 }; 97 print(ztos(end.1)); 98 print("s\n"); 99 100 return nfail; 101 }; 102 103 fn print(msg: str) void = { 104 write(STDOUT_FILENO, *(&msg: **void): *const char, len(msg))!; 105 }; 106 107 fn dots(n: size) void = { 108 // XXX: this is slow, I guess 109 for (let i = 0z; i < n; i += 1) { 110 print("."); 111 }; 112 }; 113 114 fn should_test(name: str) bool = { 115 if (argc == 1) { 116 return true; 117 }; 118 for (let i = 1z; i < argc; i += 1) { 119 let s = from_c_unsafe(argv[i]); 120 if (name == s) { 121 return true; 122 }; 123 }; 124 return false; 125 };