code wiki / (root) / nx_test_harness.nx

nx_test_harness.nx source

↩ module page · 214 lines · 5998 B

1// nx_test_harness.nx -- assertion DSL for the bits-up test driver. 2// Replaces the JS `expect()` / `fail++` / `pass++` accounting in the 3// .mjs Playwright harnesses with NishiLang. 4// 5// Test files call: 6// nx_test_init() // once at start 7// nx_test_expect_eq(label, got, want) 8// nx_test_expect_contains(label, html, n, needle) 9// nx_test_expect_class_count(label, html, n, class_name, want_count) 10// nx_test_expect_click(label, intent, want_action, want_arg0) 11// return nx_test_summary() // returns 0 if all pass, 1 if any fail 12// 13// Output is human-readable: one [PASS]/[FAIL] line per assertion + a 14// summary at the end matching the .mjs format ("X pass, Y fail"). 15 16import "nx_dom_query.nx" 17import "nx_dom_click.nx" 18 19const _TH_STDOUT: i64 = 1 20const _TH_SYS_WRITE: i64 = 1 // syscall number for x86_64 write 21 22static NX_TEST_PASSES: i64 23static NX_TEST_FAILS: i64 24 25func nx_test_init() -> i64 { 26 NX_TEST_PASSES = 0 27 NX_TEST_FAILS = 0 28 return 0 29} 30 31func _th_strlen(s: *u8) -> i64 { 32 var n: i64 = 0 33 while s[n] != 0 { n = n + 1 } 34 return n 35} 36 37func _th_w(s: *u8) -> i64 { 38 return sys_write(_TH_STDOUT, s, _th_strlen(s)) 39} 40 41func _th_wn(s: *u8, n: i64) -> i64 { 42 return sys_write(_TH_STDOUT, s, n) 43} 44 45func _th_wln(s: *u8) -> i64 { 46 _th_w(s) 47 let nl: *u8 = sys_mmap(2) as *u8 48 nl[0] = 10 as u8 49 return sys_write(_TH_STDOUT, nl, 1 as i64) 50} 51 52// Write a signed decimal int. Handles negatives + up to 20 digits. 53func _th_wi(n: i64) -> i64 { 54 let buf: *u8 = sys_mmap(24) as *u8 55 var x: i64 = n 56 var neg: i64 = 0 57 if x < 0 { neg = 1; x = 0 - x } 58 var digits: *u8 = sys_mmap(24) as *u8 59 var nd: i64 = 0 60 if x == 0 { 61 digits[0] = 48 as u8 62 nd = 1 63 } 64 while x > 0 { 65 digits[nd] = ((x - (x / 10) * 10) + 48) as u8 66 nd = nd + 1 67 x = x / 10 68 } 69 var off: i64 = 0 70 if neg == 1 { buf[off] = 45 as u8; off = off + 1 } 71 var i: i64 = nd 72 while i > 0 { 73 i = i - 1 74 buf[off] = digits[i] 75 off = off + 1 76 } 77 return sys_write(_TH_STDOUT, buf, off) 78} 79 80// ===== Assertions =================================================== 81 82func nx_test_expect_eq(label: *u8, got: i64, want: i64) -> i64 { 83 if got == want { 84 _th_w(" [PASS] " as *u8) 85 _th_wln(label) 86 NX_TEST_PASSES = NX_TEST_PASSES + 1 87 return 1 88 } 89 _th_w(" [FAIL] " as *u8) 90 _th_w(label) 91 _th_w(" (got " as *u8) 92 _th_wi(got) 93 _th_w(" want " as *u8) 94 _th_wi(want) 95 _th_wln(")" as *u8) 96 NX_TEST_FAILS = NX_TEST_FAILS + 1 97 return 0 98} 99 100// Substring search. Returns 1 if needle in haystack. 101func _th_contains(hay: *u8, hay_len: i64, ndl: *u8, ndl_len: i64) -> i64 { 102 if ndl_len == 0 { return 1 } 103 if hay_len < ndl_len { return 0 } 104 var i: i64 = 0 105 let end: i64 = hay_len - ndl_len 106 while i <= end { 107 var j: i64 = 0 108 var hit: i64 = 1 109 while j < ndl_len { 110 if hay[i + j] != ndl[j] { hit = 0; j = ndl_len } 111 j = j + 1 112 } 113 if hit == 1 { return 1 } 114 i = i + 1 115 } 116 return 0 117} 118 119func nx_test_expect_contains(label: *u8, html: *u8, n: i64, needle: *u8) -> i64 { 120 let nl: i64 = _th_strlen(needle) 121 if _th_contains(html, n, needle, nl) == 1 { 122 _th_w(" [PASS] " as *u8) 123 _th_wln(label) 124 NX_TEST_PASSES = NX_TEST_PASSES + 1 125 return 1 126 } 127 _th_w(" [FAIL] " as *u8) 128 _th_w(label) 129 _th_w(" (needle '" as *u8) 130 _th_w(needle) 131 _th_wln("' not in HTML)" as *u8) 132 NX_TEST_FAILS = NX_TEST_FAILS + 1 133 return 0 134} 135 136func nx_test_expect_not_contains(label: *u8, html: *u8, n: i64, 137 needle: *u8) -> i64 { 138 let nl: i64 = _th_strlen(needle) 139 if _th_contains(html, n, needle, nl) == 0 { 140 _th_w(" [PASS] " as *u8) 141 _th_wln(label) 142 NX_TEST_PASSES = NX_TEST_PASSES + 1 143 return 1 144 } 145 _th_w(" [FAIL] " as *u8) 146 _th_w(label) 147 _th_w(" (needle '" as *u8) 148 _th_w(needle) 149 _th_wln("' UNEXPECTEDLY in HTML)" as *u8) 150 NX_TEST_FAILS = NX_TEST_FAILS + 1 151 return 0 152} 153 154func nx_test_expect_class_count(label: *u8, html: *u8, n: i64, 155 class_name: *u8, want: i64) -> i64 { 156 let got: i64 = nx_dom_count_class(html, n, class_name) 157 return nx_test_expect_eq(label, got, want) 158} 159 160func nx_test_expect_tag_count(label: *u8, html: *u8, n: i64, 161 tag_name: *u8, want: i64) -> i64 { 162 let got: i64 = nx_dom_count_tag(html, n, tag_name) 163 return nx_test_expect_eq(label, got, want) 164} 165 166func nx_test_expect_click(label: *u8, intent: *NxClickIntent, 167 want_action: i64, want_arg0: i64) -> i64 { 168 if intent.found != 1 { 169 _th_w(" [FAIL] " as *u8) 170 _th_w(label) 171 _th_wln(" (intent.found = 0)" as *u8) 172 NX_TEST_FAILS = NX_TEST_FAILS + 1 173 return 0 174 } 175 if intent.action != want_action { 176 _th_w(" [FAIL] " as *u8) 177 _th_w(label) 178 _th_w(" (action: got " as *u8) 179 _th_wi(intent.action) 180 _th_w(" want " as *u8) 181 _th_wi(want_action) 182 _th_wln(")" as *u8) 183 NX_TEST_FAILS = NX_TEST_FAILS + 1 184 return 0 185 } 186 if intent.arg0 != want_arg0 { 187 _th_w(" [FAIL] " as *u8) 188 _th_w(label) 189 _th_w(" (arg0: got " as *u8) 190 _th_wi(intent.arg0) 191 _th_w(" want " as *u8) 192 _th_wi(want_arg0) 193 _th_wln(")" as *u8) 194 NX_TEST_FAILS = NX_TEST_FAILS + 1 195 return 0 196 } 197 _th_w(" [PASS] " as *u8) 198 _th_wln(label) 199 NX_TEST_PASSES = NX_TEST_PASSES + 1 200 return 1 201} 202 203// ===== Summary ====================================================== 204 205func nx_test_summary() -> i64 { 206 _th_w("========== SUMMARY ==========" as *u8) 207 _th_wln("" as *u8) 208 _th_wi(NX_TEST_PASSES) 209 _th_w(" pass, " as *u8) 210 _th_wi(NX_TEST_FAILS) 211 _th_wln(" fail" as *u8) 212 if NX_TEST_FAILS > 0 { return 1 } 213 return 0 214}