mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
199 lines
13 KiB
C
199 lines
13 KiB
C
/* scriptc runtime — node:assert (scr_assert.c). Included by scr_runtime.h,
|
|
* which says where new declarations go. */
|
|
#ifndef SCR_ASSERT_H
|
|
#define SCR_ASSERT_H
|
|
|
|
#include "scr_http2.h"
|
|
|
|
/* ── node:assert (scr_assert.c; scr_assert_match lives in scr_regex.c —
|
|
* it needs the matcher, and every assert.match site carries a regex, so
|
|
* the regex link switch is already on). Failures throw a catchable
|
|
* AssertionError (%Error with name "AssertionError", code
|
|
* "ERR_ASSERTION"); the exception is pending on return, the fs pattern.
|
|
* Generated messages are Node's assertion_error.js scalar forms exactly
|
|
* (the design note atop scr_assert.c lists the documented divergences).
|
|
* All ScrStr/ScrError/ScrRegex arguments are BORROWED. `has_msg`
|
|
* distinguishes an omitted user message from an empty one (Node treats
|
|
* them differently per operator). */
|
|
void scr_assert_fail_msg(ScrStr *message); /* takes ownership; always throws */
|
|
/* AssertionError properties: a failure path records actual, expected and
|
|
* operator before it throws (scr_assert.c). */
|
|
void scr_assert_fail(ScrStr *message, bool generated); /* takes ownership; always throws */
|
|
/* The options of the node:assert Assert instance whose call is running:
|
|
* bit 1 is `diff: "full"`, bit 2 is `skipPrototype`. The next AssertionError
|
|
* consumes them; a passing call clears them. */
|
|
void scr_assert_set_options(int options);
|
|
void scr_assert_clear_options(void);
|
|
/* A message argument that is not a string, for the next assertion that
|
|
* fails with SCR_ASSERT_VALUE_MESSAGE as its message (scr_assert.c): an
|
|
* Error (`error`) is thrown as it is, anything else reports String(value).
|
|
* Borrows value; clear drops a registration the call did not consume. */
|
|
#define SCR_ASSERT_VALUE_MESSAGE "\x01scriptc:assert-message-value"
|
|
void scr_assert_message_value(struct ScrDyn *value, bool error);
|
|
void scr_assert_message_clear(void);
|
|
/* An assert method as a function value, by canonical name (+1). */
|
|
struct ScrDyn *scr_assert_method_value(ScrStr *name);
|
|
/* assert.throws/rejects with a validation function: its result must be
|
|
* true (Node's expectedException), else the AssertionError. Borrows all. */
|
|
void scr_assert_throws_validate(struct ScrDyn *actual, struct ScrDyn *validate, ScrStr *op,
|
|
ScrStr *msg, bool has_msg);
|
|
bool scr_assert_diff_full(void);
|
|
bool scr_assert_skip_prototype(void);
|
|
void scr_assert_record(ScrDyn *actual, ScrDyn *expected, const char *op); /* values move in */
|
|
void scr_assert_record_dyn(ScrDyn *actual, ScrDyn *expected, ScrStr *op); /* borrows */
|
|
const char *scr_assert_eq_operator(bool negated, bool deep);
|
|
ScrError *scr_assert_error_new(ScrDyn *options);
|
|
/* deepEqual / notDeepEqual (Node's loose deep comparison). */
|
|
void scr_assert_loose_deep_dyn(ScrDyn *a, ScrDyn *b, bool negated, ScrStr *msg, bool has_msg);
|
|
void scr_assert_loose_deep_result(bool equal, bool negated, ScrStr *msg, bool has_msg);
|
|
bool scr_assert_loose_bytes_eq(const ScrBytes *a, const ScrBytes *b);
|
|
bool scr_assert_loose_f64_eq(double a, double b);
|
|
/* partialDeepStrictEqual (Node's partial deep comparison). */
|
|
void scr_assert_partial_deep_dyn(ScrDyn *a, ScrDyn *b, ScrStr *msg, bool has_msg);
|
|
void scr_assert_partial_deep_result(bool equal, bool negated, ScrStr *msg, bool has_msg);
|
|
bool scr_assert_partial_eq_dyn(const ScrDyn *a, const ScrDyn *b);
|
|
ScrStr *scr_assert_inspect_str(const ScrStr *s); /* util.inspect quoting; +1 */
|
|
void scr_assert_ok(bool pass, ScrStr *message, bool generated);
|
|
bool scr_assert_same_value_f64(double a, double b); /* Object.is */
|
|
/* deepStrictEqual over cyclic values: pair memo (enter answers true for
|
|
* a pair already being compared — Node's coinductive memo; leave pops).
|
|
* The compiler-emitted helpers over cycle-capable types wrap with these. */
|
|
bool scr_assert_deq_enter(const void *a, const void *b);
|
|
void scr_assert_deq_leave(void);
|
|
void scr_assert_eq_f64(double a, double b, bool negated, bool deep, ScrStr *msg, bool has_msg);
|
|
void scr_assert_eq_str(ScrStr *a, ScrStr *b, bool negated, bool deep, ScrStr *msg, bool has_msg);
|
|
void scr_assert_eq_bool(bool a, bool b, bool negated, bool deep, ScrStr *msg, bool has_msg);
|
|
/* BigInt scalar equality (scr_bigint_assert.c): included only when both
|
|
* optional runtime families are active, preserving their independent
|
|
* link gates. */
|
|
void scr_assert_eq_bigint(ScrBigInt *a, ScrBigInt *b, bool negated, bool deep,
|
|
ScrStr *msg, bool has_msg);
|
|
void scr_assert_deep_result(bool equal, bool negated, ScrStr *msg, bool has_msg);
|
|
/* deepStrictEqual's verdict over two typed-array/Buffer values of one
|
|
* static elem kind: brands_eq (Node compares prototypes — Buffer vs
|
|
* Uint8Array differ; a compile-time answer from the two arguments' checker
|
|
* types) AND same element count AND byte-identical storage. Both sides
|
|
* always evaluate (they are ordinary borrowed arguments), so a
|
|
* compile-time brand mismatch still runs their side effects. Never
|
|
* throws. */
|
|
bool scr_assert_bytes_deep_eq(const ScrBytes *a, const ScrBytes *b, bool brands_eq);
|
|
/* strictEqual/notStrictEqual over bytes values: reference identity
|
|
* (Object.is on objects), with Node's object-comparison headers —
|
|
* "Values have same structure but are not reference-equal:" when the
|
|
* contents (and static brands) match, the reference-equal expectation
|
|
* header otherwise. Header-only messages, the composite stance
|
|
* (SEMANTICS.md 102). Borrows a/b/msg; throws on the failing verdict. */
|
|
void scr_assert_ref_eq_bytes(const ScrBytes *a, const ScrBytes *b, bool negated,
|
|
bool brands_eq, ScrStr *msg, bool has_msg);
|
|
/* strictEqual/notStrictEqual over function values: reference identity
|
|
* with the same object-comparison headers (two distinct functions are
|
|
* never structure-equal, so the failing equal form always expects
|
|
* reference equality). Header-only messages (SEMANTICS.md 102). */
|
|
void scr_assert_ref_eq_fn(const ScrClosure *a, const ScrClosure *b, bool negated,
|
|
ScrStr *msg, bool has_msg);
|
|
/* The failing-EQUAL-operator message assembler (createErrDiff's scalar
|
|
* slice): exported for the spoke files that carry their own value
|
|
* inspection (scr_symbol.c's symbol comparison — the assert.match
|
|
* precedent). `ia`/`ib` are the inspected actual/expected bytes;
|
|
* `quotes` counts string-typed sides (2 quote chars each, excluded from
|
|
* the 12-char short-form budget); `strings` enables the stacked form's
|
|
* first-difference `^` indicator. Throws; borrows msg. */
|
|
void scr_assert_eq_fail(const char *ia, size_t la, const char *ib, size_t lb,
|
|
int quotes, bool both_zero, bool strings, bool deep,
|
|
ScrStr *msg, bool has_msg);
|
|
/* The failing NOT-equal-operator twin: `insp` is the inspected actual. */
|
|
void scr_assert_neq_fail(const char *insp, size_t ilen, bool deep,
|
|
ScrStr *msg, bool has_msg);
|
|
/* strictEqual/notStrictEqual/deepStrictEqual/notDeepStrictEqual where
|
|
* either operand is a checked-dynamic value (the frontend boxes a static
|
|
* side into the checked-dynamic tree first). Strict pair: SameValue over the dyn kinds —
|
|
* Object.is numbers, byte-equal strings, units by kind, node identity
|
|
* for arrays/objects/bytes, BOXED-CLOSURE identity for functions. Deep
|
|
* pair: the structural dyn walk (per-element arrays, key-set objects,
|
|
* brand-aware bytes via the buffer flavor bit, closure identity for
|
|
* functions). Generated messages reproduce assertion_error.js — the
|
|
* scalar simple/stacked forms byte-exactly, composite values rendered
|
|
* compact:false/sorted through the checked-dynamic tree and diffed with the real myers
|
|
* line printer (the design note atop scr_assert.c's dyn section lists
|
|
* the divergences). Borrows everything; throws on the failing verdict. */
|
|
void scr_assert_eq_dyn(ScrDyn *a, ScrDyn *b, bool negated, bool deep,
|
|
ScrStr *msg, bool has_msg);
|
|
/* assert.equal/notEqual over the frontend's Abstract Equality verdict;
|
|
* actual/expected are borrowed util.inspect renderings. */
|
|
void scr_assert_loose_result(bool equal, bool negated, ScrStr *actual,
|
|
ScrStr *expected, ScrStr *msg, bool has_msg);
|
|
/* assert.throws / assert.rejects whose callback returned (or whose
|
|
* promise fulfilled): "Missing expected exception|rejection" with Node's
|
|
* details — ` (${expected.name})` when the expected class/shape carries a
|
|
* name (has_ename), then `: message` or `.`. */
|
|
/* Node's expectsError over an error-INSTANCE expected: the expected dyn
|
|
* error's keys (minus the %error marker) each deep-compare against the
|
|
* caught value's; mismatches throw the deep-equal AssertionError. */
|
|
void scr_assert_expects_err_dyn(ScrDyn *actual, ScrDyn *expected, ScrStr *msg, bool has_msg);
|
|
void scr_assert_throws_none(bool rejection, ScrStr *ename, bool has_ename,
|
|
ScrStr *msg, bool has_msg);
|
|
void scr_assert_throws_mismatch(ScrStr *expected_name, ScrError *err,
|
|
ScrStr *msg, bool has_msg, bool rejection);
|
|
/* assert.throws(fn, <object shape>) — Node's expectedException over the
|
|
* static error surface (name/message/code). A tiny per-call accumulator:
|
|
* begin stashes the caught error, each slot call adds one expected key
|
|
* (key ids: 0 code, 1 message, 2 name — inspect's SORTED render order),
|
|
* and end runs the comparison, throwing Node's deep-equal Comparison
|
|
* diff (byte-exact: the bounded key set makes the full rendering
|
|
* enumerable) or the custom message. Regex-valued slots enter
|
|
* through scr_regex.c (scr_assert_shape_re) which tests eagerly and
|
|
* stores the verdict + rendered source, so this file stays libregexp-free;
|
|
* scr_assert_shape_actual is its borrowed key-value getter (NULL =
|
|
* absent). Straight-line calls between begin and end — no fiber
|
|
* suspension, so the accumulator is safely a static. */
|
|
void scr_assert_shape_begin(ScrError *err);
|
|
void scr_assert_shape_str(int key, ScrStr *v);
|
|
void scr_assert_shape_slot_re(int key, bool matched, ScrStr *rendered /* moves */);
|
|
ScrStr *scr_assert_shape_actual(int key); /* borrowed; NULL = absent */
|
|
void scr_assert_shape_end(ScrStr *msg, bool has_msg, bool rejection);
|
|
/* assert.doesNotReject whose rejection MATCHED (or had no expected):
|
|
* "Got unwanted rejection[: message].\nActual message: \"...\"". */
|
|
void scr_assert_unwanted_rejection(ScrError *err, ScrStr *msg, bool has_msg);
|
|
/* No-error assertions share Node's unwanted-exception/rejection message.
|
|
* The frontend reads and coerces actual?.message, preserving getter throws. */
|
|
void scr_assert_unwanted_error(ScrStr *actual_message, bool rejection, ScrStr *msg, bool has_msg);
|
|
bool scr_assert_no_error_predicate(ScrDyn *predicate, ScrDyn *actual);
|
|
bool scr_assert_regex_dyn_test(ScrRegex *re, ScrDyn *actual);
|
|
/* assert.ifError over the static surface: throws for ANY value the
|
|
* frontend routes here (Node: everything but null/undefined, falsy
|
|
* included) — "ifError got unwanted exception: " + the error's message
|
|
* (its name when the message is empty — Node reads constructor.name,
|
|
* identical for the builtin hierarchy, SEMANTICS.md 105's stance for
|
|
* subclasses) or the value's inspection. */
|
|
void scr_assert_iferror_err(ScrError *err);
|
|
void scr_assert_iferror_f64(double x);
|
|
void scr_assert_iferror_str(ScrStr *s);
|
|
void scr_assert_iferror_bool(bool b);
|
|
/* The checked-dynamic argument: dyn-kind dispatch — units pass quietly,
|
|
* %error-marked objects throw with the error's message, everything else
|
|
* with the inspection. */
|
|
void scr_assert_iferror_dyn(const ScrDyn *v);
|
|
/* assert.match / assert.doesNotMatch (scr_regex.c): RegExp.test semantics,
|
|
* including global/sticky lastIndex transitions. */
|
|
void scr_assert_match(ScrStr *s, ScrRegex *re, bool negated, ScrStr *msg, bool has_msg);
|
|
/* assert.throws(fn, /regex/) whose thrown ERROR did not match: Node tests
|
|
* String(actual) ("Name: message") and reports the regex-mismatch message
|
|
* with the input inspected (scr_regex.c). Passing calls return. */
|
|
void scr_assert_throws_regex(ScrRegex *re, ScrError *err, ScrStr *msg, bool has_msg,
|
|
bool rejection);
|
|
/* assert.throws(fn, {message: /re/, ...}): the regex-valued shape slot —
|
|
* tests the stashed actual key eagerly, stores verdict + rendered
|
|
* /source/flags into the accumulator (scr_regex.c). */
|
|
void scr_assert_shape_re(int key, ScrRegex *re);
|
|
/* assert.doesNotReject's regex predicate over String(error) — never
|
|
* throws (scr_regex.c). */
|
|
bool scr_assert_regex_err_test(ScrRegex *re, ScrError *err);
|
|
/* strictEqual/notStrictEqual/deep twins over symbol values: pointer
|
|
* identity (a symbol IS its identity), messages from the symbols'
|
|
* "Symbol(desc)" rendering — string-style stacked diffs with the `^`
|
|
* first-difference indicator, v24 exactly (scr_symbol.c). */
|
|
void scr_assert_eq_sym(ScrSym *a, ScrSym *b, bool negated, bool deep,
|
|
ScrStr *msg, bool has_msg);
|
|
|
|
#endif /* SCR_ASSERT_H */
|