summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordzaima <dzaimagit@gmail.com>2023-04-24 15:25:44 +0300
committerdzaima <dzaimagit@gmail.com>2023-04-24 19:43:04 +0300
commit77154be2a883b0c33f141d6b4b29330db900d8a4 (patch)
treeac4efd7673a4c964b7f4454f9ee3c45cf9669427
parent6d33018788661f628979a4ab057f6e1fac90fa49 (diff)
testing setup for ˘ & ⎉
incl. toggleable fill testing for !CATCH_ERRORS
-rw-r--r--src/builtins/cells.c32
-rw-r--r--src/builtins/internal.c15
-rw-r--r--test/cells.bqn200
-rw-r--r--test/generated/.gitignore2
4 files changed, 238 insertions, 11 deletions
diff --git a/src/builtins/cells.c b/src/builtins/cells.c
index 257226c3..fa086e79 100644
--- a/src/builtins/cells.c
+++ b/src/builtins/cells.c
@@ -57,6 +57,19 @@ B insert_base(B f, B x, usz xia, bool has_w, B w) {
return r;
}
+
+#if TEST_CELL_FILLS
+ i32 fullCellFills = 2*CATCH_ERRORS;
+ i32 cellFillErrored = 0;
+ #define DO_CELL_CATCH (fullCellFills==2)
+ #define getFillQ2 (fullCellFills? getFillR : getFillQ)
+ #define SET_FILL_ERRORED cellFillErrored = 1
+#else
+ #define DO_CELL_CATCH CATCH_ERRORS
+ #define getFillQ2 getFillQ
+ #define SET_FILL_ERRORED
+#endif
+
static NOINLINE B empty_frame(usz* xsh, ur k) {
if (k==1) return emptyHVec();
assert(k>1);
@@ -219,7 +232,7 @@ static NOINLINE B transp_cells(ur ax, ur k, B x) {
// helpers
static NOINLINE B to_fill_cell(B x, ur k, u32 chr) { // consumes x
- B xf = getFillQ(x);
+ B xf = getFillQ2(x);
if (noFill(xf)) xf = m_f64(0);
ur cr = RNK(x)-k;
usz* sh = SH(x)+k;
@@ -237,7 +250,7 @@ static NOINLINE B to_fill_cell(B x, ur k, u32 chr) { // consumes x
static NOINLINE B merge_fill_result(B rc, ur k, usz* sh, u32 chr) {
u64 rr = k; if (isArr(rc)) rr+= RNK(rc);
if (rr>UR_MAX) thrF("%c: Result rank too large", chr);
- Arr* r = m_fillarrpEmpty(getFillQ(rc));
+ Arr* r = m_fillarrpEmpty(getFillQ2(rc));
usz* rsh = arr_shAlloc(r, rr);
if (rr>1) {
shcpy(rsh, sh, k);
@@ -265,7 +278,6 @@ static ur cell_rank(f64 r, f64 k) { // ⎉k over arg rank r
-
static NOINLINE B c1wrap(B f, B x) { B r = c1(f, x); return isAtm(r)? m_atomUnit(r) : r; }
static NOINLINE B c2wrap(B f, B w, B x) { B r = c2(f, w, x); return isAtm(r)? m_atomUnit(r) : r; }
// monadic ˘ & ⎉
@@ -355,11 +367,13 @@ B for_cells_c1(B f, u32 xr, u32 cr, u32 k, B x, u32 chr) { // F⎉cr x, with arr
noCells:;
usz s0=0; ShArr* s=NULL;
if (xr<=1) { s0=xsh[0]; xsh=&s0; } else { s=ptr_inc(shObj(x)); }
- if (!isPureFn(f) || !CATCH_ERRORS) { decG(x); goto empty; }
+ if (!DO_CELL_CATCH || !isPureFn(f)) { decG(x); goto empty; }
B cf = to_fill_cell(x, k, chr);
B r;
- if (CATCH) { empty:
+ if (CATCH) {
+ SET_FILL_ERRORED;
freeThrown();
+ empty:
r = empty_frame(xsh, k);
} else {
B rc = c1(f, cf);
@@ -406,18 +420,20 @@ B rank_c1(Md2D* d, B x) { B f = d->f; B g = d->g;
}
-static NOINLINE B rank2_empty(B f, B w, ur wk, B x, ur xk) {
+static NOINLINE B rank2_empty(B f, B w, ur wk, B x, ur xk) { // TODO pass chr around everywhere
B fa = wk>xk?w:x;
ur k = wk>xk?wk:xk;
usz* sh = SH(fa);
usz s0=0; ShArr* s=NULL; ur sho=RNK(fa)>1;
if (!sho) { s0=sh[0]; sh=&s0; } else { s=ptr_inc(shObj(fa)); }
- if (!isPureFn(f) || !CATCH_ERRORS) { dec(w); dec(x); goto empty; }
+ if (!DO_CELL_CATCH || !isPureFn(f)) { dec(w); dec(x); goto empty; }
B r;
if (wk) w = to_fill_cell(w, wk, U'⎉');
if (xk) x = to_fill_cell(x, xk, U'⎉');
- if (CATCH) { empty:
+ if (CATCH) {
+ SET_FILL_ERRORED;
freeThrown();
+ empty:
r = empty_frame(sh, k);
} else {
B rc = c2(f, w, x);
diff --git a/src/builtins/internal.c b/src/builtins/internal.c
index f6828fcd..26a05cd0 100644
--- a/src/builtins/internal.c
+++ b/src/builtins/internal.c
@@ -276,8 +276,17 @@ B eequal_c2(B t, B w, B x) {
extern B native_comp;
void switchComp(void);
#endif
+#if TEST_CELL_FILLS
+ extern i32 fullCellFills;
+ extern i32 cellFillErrored;
+#endif
B internalTemp_c1(B t, B x) {
-
+ #if TEST_CELL_FILLS
+ if (isNum(x)) fullCellFills = o2iG(x);
+ B r = m_i32(cellFillErrored);
+ cellFillErrored = 0;
+ return r;
+ #endif
#if NATIVE_COMPILER
switchComp();
B r = bqn_exec(x, bi_N, bi_N);
@@ -285,8 +294,8 @@ B internalTemp_c1(B t, B x) {
return r;
#endif
#ifdef TEST_BITCPY
- SGetU(x)
- bit_cpyN(bitarr_ptr(GetU(x,0)), o2s(GetU(x,1)), bitarr_ptr(GetU(x,2)), o2s(GetU(x,3)), o2s(GetU(x,4)));
+ SGetU(x)
+ bit_cpyN(bitarr_ptr(GetU(x,0)), o2s(GetU(x,1)), bitarr_ptr(GetU(x,2)), o2s(GetU(x,3)), o2s(GetU(x,4)));
#endif
return x;
}
diff --git a/test/cells.bqn b/test/cells.bqn
new file mode 100644
index 00000000..23ae1e8f
--- /dev/null
+++ b/test/cells.bqn
@@ -0,0 +1,200 @@
+# build/build replxx singeli native g debug f=-DEACH_FILLS f=-DTEST_CELL_FILLS && build/build replxx singeli native g debug heapverify f=-DTEST_CELL_FILLS OUTPUT=BQNh && ./BQN test/cells.bqn path/to/mlochbaum/BQN/bqn.js ./BQNh
+# (replace bqn.js path with "reuse" to use the previous result (requires the test set to not have changed))
+{𝕊: •Out "Usage: ./nonHeapverifyCBQN test/cells.bqn path/to/bqn.js heapverifyCBQN" ⋄ •Exit 0}⍟⊢ 2>≠•args
+a0 ← ⊑•args
+bqnjs‿hCBQN ← •wdpath⊸•file.At¨ •args
+bqnjsFile ← •file.At "generated/cells_bqnjsOut.bqn"
+hCBQNFile ← •file.At "generated/cells_hCBQNOut.bqn"
+validFile ← •file.At "generated/cells_valid.bqn"
+
+cbqni ← {⊑"internal"<⊸∊•listsys? •BQN"•internal"; @}
+bqntype ← {cbqni≡@? 2; "harr"≡cbqni.Type ⊢⎉0 ""} # 0: full CBQN; 1: heapverify CBQN; 2: bqn.js
+
+SHRun ← {
+ f←•BQN"•SH"
+ c‿o‿e ← F 𝕩
+ g←•BQN"•term.OutRaw‿•term.ErrRaw {𝕎•ToUTF8𝕩}¨ ⊢" ⋄ G o‿e
+ c≢0? •Exit c; @
+}
+
+GetTests ← { 𝕊:
+
+ tests ← ⟨⟩
+ AddTests ← {tests∾↩ 𝕩 ⋄ @}
+
+ Prod ← {⥊ (<⟨⟩) <⊸∾⌜´ 𝕩}
+
+ # generating random numerical arrays:
+ # )r N←{⟨⟩:"1";•Repr⊑⍟(1=≠)𝕩} ⋄ J←{(⊣∾𝕨∾⊢)´𝕩} ⋄ •Out '⟨'∾'⟩'∾˜','J ("⥊"J≢⋈○N⥊)¨ 15↑ ⍷ {𝕊: ((1+•rand.Range 4)•rand.Range 4)•rand.Range 10}¨ ↕100
+ # xs ↩ ⟨0,↕0⟩ ∾
+
+ { 𝕊: # F⎉k x
+ fs ← ⟨<,⊏,⊑,≍,⥊,«,»,⍉,×˝,¨,1˙,∞,'a'˙,'𝕨',"ab"‿2˙,⟨⟩,<"ab"‿1,2‿3,↕2‿3‿1⟩
+ xs ← ⟨
+ 1, <2,
+ 2‿3, 2‿3‿4⥊↕24, 1‿1‿1‿1⥊4,
+ ↕0, 0‿2⥊"", 4‿0⥊0, 0‿2‿3‿4‿5⥊0,
+ 1‿1‿2‿1⥊2‿'a', 2‿2⥊"abcd", ↕2‿3,
+ ⟩
+ ks ← ⟨@, ¯∞, ¯1, 0‿∞‿∞, 10‿1, ⟨2⟩, 3, 4, 5, ∞⟩
+ AddTests Prod ⟨fs, ks, xs⟩
+ }⍟⊢ 1
+
+ { 𝕊: # w ⋈⎉k x
+ xs ← ⟨0, 2‿2⥊"a"‿1⟩∾ {𝕩⥊↕×´⥊𝕩}¨ ⟨1, 2‿3, 2‿0, 2‿3‿4, 2‿2‿3‿4, 3‿4⟩
+ ks ← ⟨¯∞, ¯1, 0, 1, 2, 3, 4, ∞‿0‿1, ¯∞‿2‿1, ∞, 0‿∞, ∞‿0, 1‿∞, ∞‿1, 2‿∞, ∞‿2⟩
+ AddTests Prod ⟨xs, ⋈, ks, xs⟩
+ }⍟⊢ 1
+
+ { 𝕊: # w ⊏⎉k x / w ⊑⎉k x
+ ws ← ⟨0, 1, 2, 3, ¯1, ¯2, <1⟩
+ xs ← ⟨2‿2⥊"a"‿1‿"b"‿"cd", 3‿3‿3⥊'a'+↕27, 3‿6⟩∾ {𝕩⥊↕×´⥊𝕩}¨ ⟨2‿3, 2‿0, 2‿3‿4, 2‿2‿3‿4, 3‿4⟩
+ ks ← ⟨0, 1, 2, 3, 4, 0‿1, 0‿2⟩
+ AddTests Prod ⟨ws, ⊏‿⊑, ks, xs⟩
+ AddTests Prod ⟨0‿100‿¯100‿∞, ⊏‿⊑, 0‿1‿2, xs∾⟨0,<4⟩⟩
+ }⍟⊢ 1
+
+ { 𝕊: # w ≡⎉k x
+ xs ← ⟨0, 2‿3⥊@+↕6⟩∾ {𝕩⥊↕×´⥊𝕩}¨ ⟨1, 2‿3, 0‿3, 2‿0‿3, 4‿2‿3, 2‿4‿2‿3, 3‿1⟩
+ ks ← ⟨¯∞, ¯1, 0, 1, 2, 3, 4, 0‿1, 2‿1⟩
+ AddTests Prod ⟨xs, ≡, ks, xs⟩
+ xs2 ← ⟨2‿3⥊175, [¯81‿¯81‿¯81, 0‿0‿0]⟩∾{𝕩-˜𝕩+2‿3⥊'¯'}¨ 0‿100‿100000
+ AddTests Prod ⟨xs2, ≡, ks, xs2⟩
+ }⍟⊢ 1
+
+ { 𝕊: # w ⍉⎉k x
+ ws ← ⟨0, 1, 2, 3, 4, ¯1, 1‿0⟩
+ xs ← ⟨2‿2‿2⥊"a"‿1‿"b", 3‿3‿3⥊'a'+↕27, 3‿6⟩∾ {𝕩⥊↕×´⥊𝕩}¨ ⟨2‿3, 2‿0, 2‿3‿4, 2‿2‿3‿4, 3‿4, 3‿2‿1‿2‿2⟩
+ ks ← ⟨0, 1, 2, 3, 4, 5, 0‿1, 0‿2⟩
+ AddTests Prod ⟨ws, ⍉, ks, xs⟩
+ }⍟⊢ 1
+
+ { 𝕊: # w »⎉k x / w «⎉k x
+ ws ← ⟨0, 1, 'a', "ab", <"h"‿2⟩
+ xs ← ⟨2‿2‿2⥊"a"‿1‿"b", 3‿3‿3⥊'a'+↕27, 3‿6⟩∾ {𝕩⥊↕×´⥊𝕩}¨ ⟨2‿3, 2‿0, 2‿3‿4, 2‿2‿3‿4, 3‿4, 3‿2‿1‿2‿2⟩
+ ks ← ⟨0, 1, 2, 3, 4, @, 0‿1, 0‿2⟩
+ AddTests Prod ⟨ws, «‿», ks, xs⟩
+ }⍟⊢ 1
+
+ { 𝕊: # w ↑⎉k x / w ↓⎉k x
+ ws ← ⟨0,1,2,¯1,¯2,10,1‿1⟩
+ xs ← ⟨2‿2‿2⥊"a"‿1‿"b", 3‿3‿3⥊'a'+↕27, 3‿6⟩∾ {𝕩⥊↕×´⥊𝕩}¨ ⟨2‿3, 0‿2, 2‿0, 2‿3‿4, 2‿2‿3‿4, 3‿4, 3‿2‿1‿2‿2⟩
+ ks ← ⟨0, 1, 2, 3, 4, @, 0‿1, 0‿2, 1‿¯1⟩
+ AddTests Prod ⟨ws, ↑‿↓, ks, xs⟩
+ }⍟⊢ 1
+
+ tests
+}
+
+getFill ← {bqntype≢2? cbqni•ns.Has"hasfill"? {cbqni.HasFill 𝕩? ⊑1↑0⥊𝕩; '!'}; {1 ⊑∘↑⎊'!' 0⥊𝕩}}
+Info ← {⟨𝕩, GetFill 𝕩⟩}
+RunTests ← {
+ f‿k‿x: (Info F{k≡@? 𝔽˘; 𝔽⎉k})⎊"err" x;
+ w‿f‿k‿x: w (Info F{k≡@? 𝔽˘; 𝔽⎉k})⎊"err" x
+}¨
+
+
+{
+ "0"≡a0? # bqn.js
+ •Out⍟(bqntype≠2) "Warning: doesn't seem like the first argument is bqn.js!"
+ res ← RunTests GetTests@
+ bqnjsFile •FChars •Repr res
+ ;
+ "1"≡a0? # heapverify
+ •Out⍟(bqntype≠1) "Warning: doesn't seem like the second argument is CBQN with heapverify!"
+ tests ← GetTests@
+ valid ← '0'-˜•FChars validFile
+ ok ← valid≠2
+ HTests ← { 𝕊:
+ okTests ← ok/tests
+ hasFill ← 0=ok/valid
+ cbqni.Temp 2 ⋄ f1 ← RunTests okTests /˜ hasFill
+ cbqni.Temp 1 ⋄ f0 ← RunTests okTests /˜ ¬hasFill
+ cbqni.Temp 0
+ (⍋⍋hasFill) ⊏ f0∾f1
+ }
+ hCBQNFile •FChars •Repr HTests⌾(ok⊸/) "err"¨ tests
+ ;
+ # base
+ •Out⍟(bqntype≠0) "Warning: doesn't seem like the running binary is CBQN without heapverify!"
+
+ tests ← GetTests@
+ •Out ∾⟨"Running ", •Repr ≠tests, " tests on base CBQN.."⟩
+ cfe‿fo ← <˘⍉>{cbqni.Temp@ ⋄ (cbqni.Temp@) ⋈ ⊑RunTests ⋈𝕩}¨ tests
+ validFile •FChars '0'+ 2⌊ cfe + 2×"err"⊸≡¨ fo # 2: errored; 1: invalid fill; 0: valid fill
+
+ { 𝕊:
+ •Out "Calling bqn.js.."
+ •file.Remove⍟•file.Exists bqnjsFile
+ SHRun ⟨bqnjs, •file.At "cells.bqn", "0", ""⟩
+ {•file.Exists bqnjsFile?@; •Out "bqn.js didn't produce the result file!" ⋄ •Exit 1}
+ }⍟⊢ "reuse"≢a0
+
+ •file.Remove⍟•file.Exists hCBQNFile
+ •Out "Calling heapverify build.."
+ SHRun ⟨hCBQN, •file.At "cells.bqn", "1", ""⟩
+
+ •Out "Comparing.."
+ bo ← •Import bqnjsFile
+ ho ← •Import hCBQNFile
+
+ hCount ← +´ "err"⊸≢¨ bo
+ badH←0 ⋄ hBadFill←0 ⋄ hSuperset←0
+ badB←0 ⋄ bBadFill←0 ⋄ bSuperset←0
+
+ hBadEmpty←0
+ hBadButBase←0
+
+ FRepr ← {0≢≠⥊𝕩? •Repr 𝕩; '!'≢f←GetFill 𝕩? ∾⟨•Repr≢𝕩, "⥊", "<"⊸∾⍟(0≠≡f) •Repr f⟩; •Repr 𝕩}
+ FTest ← { test‿exp‿got:
+ ! exp≢got
+ ∾⟨
+ {F‿k‿x←¯3↑𝕩 ⋄ ∾⟨{3≡≠𝕩?""; "("∾") "∾˜FRepr⊑𝕩}𝕩 , •Repr f, {k≡@?"˘";"⎉"∾•Repr k}, " ", FRepr x⟩} test
+ ": "
+ {
+ exp≡"err"? "expected error, but got "∾•Repr ⊑got;
+ got≡"err"? "expected result, but got error";
+ {𝕨∾"; "∾𝕩}´ @⊸≢¨⊸/ "result"‿"result fill" {m𝕊e‿g: {e≡g? @; ∾⟨"expected ",m," to be ",FRepr e,", got ",FRepr g⟩}}¨ <˘⍉>⟨exp,got⟩
+ }
+ ⟩
+ }
+
+ { 𝕊 t‿f‿b‿h:
+ {
+ b≡f?@;
+ b≢○⊑f? badB+↩1 ⋄ •Out ∾⟨"base: incrorrect result: ",FTest t‿b‿f⟩;
+ '!'≡1⊑b? bSuperset+↩1;
+ bBadFill+↩1 ⋄ •Out ∾⟨"base: bad fill: ",FTest t‿b‿f⟩
+ }
+ {
+ b≡h?@; {∨´0=≠∘⥊¨ (¯3↓t)∾¯1↑t? hBadEmpty+↩1;@}
+ f≡h? hBadButBase+↩1;
+ b≢○⊑h? badH+↩1 ⋄ •Out ∾⟨"heapverify: incrorrect result: ",FTest t‿b‿h⟩;
+ '!'≡1⊑b? hSuperset+↩1;
+ hBadFill+↩ 1 ⋄ •Out ∾⟨"heapverify: bad fill: ",FTest t‿b‿h⟩
+
+ # ∨´0=≠∘⥊¨ (¯3↓t)∾¯1↑t? hBadEmpty+↩1;
+ # badH+↩1 ⋄ •Out ∾⟨"heapverify: incrorrect result: ",FTest t‿b‿h⟩
+ }
+ }¨ <˘⍉>⟨tests, fo, bo, ho⟩
+
+ •Out ∾⟨
+ "Base: ",
+ •Repr ≠tests, " tests: "
+ •Repr badB, " wrong results, "
+ •Repr bBadFill, " wrong fills, "
+ •Repr bSuperset, " superset fills"
+ ⟩
+ hBadTot ← hBadFill
+ •Out ∾⟨
+ "Heapverify: "
+ •Repr hCount, " tests: "
+ •Repr hBadButBase, " wrong results equal to base, "
+ •Repr badH, " wrong results, "
+ •Repr hBadFill, " wrong fills, "
+ •Repr hSuperset, " superset fills; "
+ •Repr hBadEmpty, " wrong results had empty input(s)"
+ ⟩
+ •Exit⍟(∨´0≠badH‿badB) 1
+ •Out "Passed!"
+}
diff --git a/test/generated/.gitignore b/test/generated/.gitignore
new file mode 100644
index 00000000..c96a04f0
--- /dev/null
+++ b/test/generated/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore \ No newline at end of file