sourcelibs/Check/src/Check.xtl

1⍝# Check: assertions that report as text, for tests and teaching. 2⍝# Import it with an alias of your choice: "k:" u_se< "Check". 3⍝# Put libs/Check/src on XETAL_PATH ("just path"); the reference is libs/Check/docs. 4⍝# Names with l: are exported; those under h: are private to this file. 5⍝# 6⍝# A check is a line of text, "ok" or "FAIL: ..." (X_eTaL has no 7⍝# assert and no way to stop with an error of your own yet): it prints 8⍝# when it is a statement, and checks join into a report with a_nd. 9⍝# 6 k:i_s '+ r_/ 1 2 3 # ok 10⍝# "sum" k:t_est 5 k:i_s '+ r_/ 1 2 3 # FAIL: sum: expected 5, got 6 11⍝# k:r_eport (a k:a_nd b k:a_nd c) # the lines, then "3 checks, all passed" 12 13ʰn̲l ← { @ → f̲irst "\n" } ⍝ the newline character 14 15⍝# t, its newlines shown as ";", so a value takes one line. 16ʰo̲neLine ← { t → 17 m ← t = ʰn̲l @ 18 ((r̲ange t̲ally t) + m × (1 + t̲ally t) − r̲ange t̲ally t) s̲elect t c̲at ";" 19} 20 21⍝# t on one line; when longer than 60 characters, its start and its 22⍝# shape: "1 2 3 ... (shape 100)". 23ʰs̲hown ← { t → 24 s ← ʰo̲neLine f̲ormat t 25 60 ≥ t̲ally s ? s 26 (48 t̲ake s) c̲at " ... (shape " c̲at (f̲ormat s̲hape t) c̲at ")" 27} 28 29ʰf̲ail ← { w g → "FAIL: expected " c̲at (ʰs̲hown w) c̲at ", got " c̲at ʰs̲hown g } 30 31⍝## Checks 32 33⍝# want i_s got: ok when got has want's shape and items (m_atch). 34ˡi̲s ← { w g → w m̲atch g ? "ok"◆ w ʰf̲ail g } 35 36⍝# want n_ear got: ok when the shapes match and every item is equal 37⍝# within e_q~'s relative tolerance, or within 1e-12 of it (so a 38⍝# computed 1e-17 is near an exact 0, which e_q~ alone never allows). 39ˡn̲ear ← { w g → 40 n̲ot (s̲hape w) m̲atch s̲hape g ? w ʰf̲ail g 41 '∧ r̲/ r̲avel (w e̲q~ g) ∨ 0.000000000001 ≥ a̲bs (f̲loat w) − f̲loat g ? "ok" 42 w ʰf̲ail g 43} 44 45⍝# t_rue c: ok when every item of the condition c is true (1). 46ˡt̲rue ← { c → '∧ r̲/ r̲avel c ? "ok"◆ "FAIL: expected true, got " c̲at ʰs̲hown c } 47 48⍝## Naming a check 49 50⍝# name t_est line: the check's line, named: "ok: name" or "FAIL: name: ...". 51ˡt̲est ← { name line → 52 "ok" m̲atch 2 t̲ake line ? "ok: " c̲at name 53 "FAIL: " c̲at name c̲at ": " c̲at 6 d̲rop line 54} 55 56⍝## Reports 57 58⍝# a a_nd b: two checks (or reports) as one text, a line each. 59ˡa̲nd ← { a b → a c̲at "\n" c̲at b } 60 61⍝# c_ount t: how many checks a text holds (its lines). 62ˡc̲ount ← { t → 1 + t̲ally w̲here t = ʰn̲l @ } 63 64⍝# f_ailures t: how many of its checks failed (lines starting FAIL). 65ˡf̲ailures ← { t → 66 s ← (ʰn̲l @) c̲at t 67 t̲ally w̲here (-1 d̲rop s = ʰn̲l @) ∧ (1 d̲rop s) = f̲irst "F" 68} 69 70⍝# p_assed? t: whether every check passed. 71ˡp̲assed? ← { t → 0 = ˡf̲ailures t } 72 73⍝# r_eport t: the checks, then a summary line. 74ˡr̲eport ← { t → 75 n ← ˡc̲ount t 76 f ← ˡf̲ailures t 77 s ← (f̲ormat n) c̲at " check" c̲at (n ≠ 1) r̲eplicate "s" 78 f = 0 ? t ˡa̲nd s c̲at ", all passed" 79 t ˡa̲nd s c̲at ", " c̲at (f̲ormat f) c̲at " FAILED" 80}