Skip to content

Commit d119f94

Browse files
committed
test(eval): add Node + wasmtime + CI coverage for object iteration
CI gap: zig build test-unit was not run by CI, so the unit tests in src/eval.zig (every over object keys / values / default) were never validated upstream. Fixes: - ci.yml gains a test-unit job that runs zig build test-unit on ubuntu-latest. Independent of the build matrix; needs only the Zig toolchain. - test/run.mjs gains 6 cases covering every / some over object refs with kind=keys, kind=values, and the default (kind omitted). - test/run_wasmtime.py gets the same 6 cases (parity with run.mjs).
1 parent 083b42a commit d119f94

2 files changed

Lines changed: 128 additions & 0 deletions

File tree

test/run.mjs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,70 @@ check(
423423
0,
424424
);
425425

426+
// ---------------------------------------------------------------------------
427+
// 9. some / every over object refs (kind: keys / values, default keys)
428+
// ---------------------------------------------------------------------------
429+
const everyKeyNotInternal = {
430+
type: 'every', var: 'k', kind: 'keys',
431+
source: { type: 'ref', path: ['input', 'attrs'] },
432+
body: {
433+
type: 'neq',
434+
left: { type: 'ref', path: ['k'] },
435+
right: { type: 'value', value: 'internal' },
436+
},
437+
};
438+
check(
439+
'every over object keys: no banned key -> allow',
440+
decide({ attrs: { team: 'sre', region: 'us-east' } }, everyKeyNotInternal),
441+
1,
442+
);
443+
check(
444+
'every over object keys: banned key present -> deny',
445+
decide({ attrs: { team: 'sre', internal: 'yes' } }, everyKeyNotInternal),
446+
0,
447+
);
448+
449+
const someValueTrue = {
450+
type: 'some', var: 'v', kind: 'values',
451+
source: { type: 'ref', path: ['input', 'flags'] },
452+
body: {
453+
type: 'eq',
454+
left: { type: 'ref', path: ['v'] },
455+
right: { type: 'value', value: true },
456+
},
457+
};
458+
check(
459+
'some over object values: at least one true -> allow',
460+
decide({ flags: { a: false, b: true, c: false } }, someValueTrue),
461+
1,
462+
);
463+
check(
464+
'some over object values: all false -> deny',
465+
decide({ flags: { a: false, b: false } }, someValueTrue),
466+
0,
467+
);
468+
469+
// `kind` defaults to "keys" when omitted on an object source.
470+
const everyDefaultKeysNotBanned = {
471+
type: 'every', var: 'k',
472+
source: { type: 'ref', path: ['input', 'm'] },
473+
body: {
474+
type: 'neq',
475+
left: { type: 'ref', path: ['k'] },
476+
right: { type: 'value', value: 'banned' },
477+
},
478+
};
479+
check(
480+
'every over object defaults to keys: clean -> allow',
481+
decide({ m: { x: 1, y: 2 } }, everyDefaultKeysNotBanned),
482+
1,
483+
);
484+
check(
485+
'every over object defaults to keys: banned -> deny',
486+
decide({ m: { x: 1, banned: 2 } }, everyDefaultKeysNotBanned),
487+
0,
488+
);
489+
426490
if (failed > 0) {
427491
console.error(`\n${failed} test(s) failed`);
428492
exit(1);

test/run_wasmtime.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,70 @@ def check(name: str, got, expected):
300300
0,
301301
)
302302

303+
# ---------------------------------------------------------------------------
304+
# 9. some / every over object refs (kind: keys / values, default keys)
305+
# ---------------------------------------------------------------------------
306+
every_key_not_internal = {
307+
"type": "every", "var": "k", "kind": "keys",
308+
"source": {"type": "ref", "path": ["input", "attrs"]},
309+
"body": {
310+
"type": "neq",
311+
"left": {"type": "ref", "path": ["k"]},
312+
"right": {"type": "value", "value": "internal"},
313+
},
314+
}
315+
check(
316+
"every over object keys: no banned key -> allow",
317+
decide({"attrs": {"team": "sre", "region": "us-east"}}, every_key_not_internal),
318+
1,
319+
)
320+
check(
321+
"every over object keys: banned key present -> deny",
322+
decide({"attrs": {"team": "sre", "internal": "yes"}}, every_key_not_internal),
323+
0,
324+
)
325+
326+
some_value_true = {
327+
"type": "some", "var": "v", "kind": "values",
328+
"source": {"type": "ref", "path": ["input", "flags"]},
329+
"body": {
330+
"type": "eq",
331+
"left": {"type": "ref", "path": ["v"]},
332+
"right": {"type": "value", "value": True},
333+
},
334+
}
335+
check(
336+
"some over object values: at least one true -> allow",
337+
decide({"flags": {"a": False, "b": True, "c": False}}, some_value_true),
338+
1,
339+
)
340+
check(
341+
"some over object values: all false -> deny",
342+
decide({"flags": {"a": False, "b": False}}, some_value_true),
343+
0,
344+
)
345+
346+
# `kind` defaults to "keys" when omitted on an object source.
347+
every_default_keys = {
348+
"type": "every", "var": "k",
349+
"source": {"type": "ref", "path": ["input", "m"]},
350+
"body": {
351+
"type": "neq",
352+
"left": {"type": "ref", "path": ["k"]},
353+
"right": {"type": "value", "value": "banned"},
354+
},
355+
}
356+
check(
357+
"every over object defaults to keys: clean -> allow",
358+
decide({"m": {"x": 1, "y": 2}}, every_default_keys),
359+
1,
360+
)
361+
check(
362+
"every over object defaults to keys: banned -> deny",
363+
decide({"m": {"x": 1, "banned": 2}}, every_default_keys),
364+
0,
365+
)
366+
303367
if failed:
304368
print(f"\n{failed} test(s) failed", file=sys.stderr)
305369
sys.exit(1)

0 commit comments

Comments
 (0)