Add missing exception checks in expect matchers, mock functions and error construction

Merged
DY
2mo ago
+257-296

What does this PR do?

Second batch from an audit of native code that performs another JSC operation (or returns) while a JS exception may be pending. This one covers bun:test matchers/mocks and error construction; every site is reachable from user JS.

  • Asymmetric matchers (bindings.cpp): check after isArray in expect.any(Array); after each getIndex in expect.arrayContaining (a throwing index getter previously reached Bun__deepEquals with the exception pending); after toString/RegExp::match in expect.stringMatching; after toInt32 in expect.closeTo (its two numbers are validated at construction, so they are read with asNumber). Bun__deepMatch and toHaveProperty(path) check after isArray (revoked Proxy) before using the result.
  • mockResolvedValue / mockResolvedValueOnce: JSPromise::resolvedPromise reads the value's constructor and can throw; that was stored as a null implementation. Now propagates.
  • mockRestore / jest.restoreAllMocks: putting the original back (overrideExportValue on a module namespace, putDirectIndex) can throw; clearSpy gets a scope and its callers propagate.
  • createInvalidThisError → throwInvalidThisError(scope, …): describing the receiver reads constructor.name. The old function handed the pending exception to createError, whose catch scope then adopted the thrown value as the ERR_INVALID_THIS error. It now propagates the getter's exception; all callers (Mock, BunRequest, MIMEType/MIMEParams accessors, node:sqlite) are switched.
  • $ERR_OUT_OF_RANGE: check after building the message, same reason.
  • Test-runner diff output: DiffFormatter formatted both values with JestPrettyFormat (runs getters / Proxy traps) inside Display::fmt and dropped the result; it now formats in a fallible DiffFormatter::new(...)? and fmt only prints. Snapshot matchers propagate the pretty-format error instead of throwing "Failed to pretty format value" over it.

How did you verify your code works?

New test for mockResolvedValue (fails on release). mock-fn, expect, mock-module, node-sqlite suites pass under BUN_JSC_validateExceptionChecks=1 on a debug build. The matcher cases (arrayContaining with a throwing index getter, revoked-Proxy receivers) already surfaced the right error in release; the missing checks there are what the validator flags.