@scriptc/runtime 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/package.json +16 -6
- package/src/scr_array.c +488 -0
- package/src/scr_assert.c +1393 -0
- package/src/scr_async.c +2593 -0
- package/src/scr_async_dyn.c +607 -0
- package/src/scr_bytes.c +1425 -0
- package/src/scr_bytes_io.c +161 -0
- package/src/scr_child.c +3587 -0
- package/src/scr_closure.c +214 -0
- package/src/scr_console.c +143 -0
- package/src/scr_cycle.c +218 -0
- package/src/scr_dc.c +805 -0
- package/src/scr_dgram.c +1007 -0
- package/src/scr_dyn_handle.c +154 -0
- package/src/scr_dyn_invoke.c +644 -0
- package/src/scr_error.c +332 -0
- package/src/scr_events.c +714 -0
- package/src/scr_events_emitter.c +699 -0
- package/src/scr_exception.c +242 -0
- package/src/scr_fetch.c +1130 -0
- package/src/scr_fetch_curl.c +654 -0
- package/src/scr_http.c +3482 -0
- package/src/scr_http2.c +3030 -0
- package/src/scr_inspect.c +803 -0
- package/src/scr_inspect_island.c +51 -0
- package/src/scr_island.c +9363 -0
- package/src/scr_json.c +2151 -0
- package/src/scr_lib.c +3612 -0
- package/src/scr_loop_epoll.c +241 -0
- package/src/scr_loop_kqueue.c +121 -0
- package/src/scr_loop_wsapoll.c +208 -0
- package/src/scr_map.c +591 -0
- package/src/scr_net.c +3017 -0
- package/src/scr_net_island.c +458 -0
- package/src/scr_number.c +115 -0
- package/src/scr_object.c +25 -0
- package/src/scr_path.c +1266 -0
- package/src/scr_platform.h +119 -0
- package/src/scr_readline.c +287 -0
- package/src/scr_regex.c +1080 -0
- package/src/scr_runtime.h +5046 -0
- package/src/scr_stream.c +2877 -0
- package/src/scr_string.c +1264 -0
- package/src/scr_symbol.c +132 -0
- package/src/scr_test.c +662 -0
- package/src/scr_tls.c +1520 -0
- package/src/scr_union.c +105 -0
- package/src/scr_url.c +911 -0
- package/src/scr_url_internal.h +29 -0
- package/src/scr_url_params.c +561 -0
- package/src/scr_watch.c +568 -0
- package/src/scr_web.c +1778 -0
- package/src/scr_win.c +76 -0
- package/src/scr_zlib.c +197 -0
- package/src/scr_zlib_island.c +15 -0
- package/vendor/README.md +52 -0
- package/vendor/curl/COPYRIGHT +534 -0
- package/vendor/curl/include/curl/curl.h +3214 -0
- package/vendor/curl/include/curl/curlver.h +79 -0
- package/vendor/curl/include/curl/easy.h +125 -0
- package/vendor/curl/include/curl/header.h +74 -0
- package/vendor/curl/include/curl/mprintf.h +52 -0
- package/vendor/curl/include/curl/multi.h +460 -0
- package/vendor/curl/include/curl/options.h +70 -0
- package/vendor/curl/include/curl/stdcheaders.h +35 -0
- package/vendor/curl/include/curl/system.h +508 -0
- package/vendor/curl/include/curl/typecheck-gcc.h +716 -0
- package/vendor/curl/include/curl/urlapi.h +149 -0
- package/vendor/curl/include/curl/websockets.h +84 -0
- package/vendor/mbedtls/LICENSE +553 -0
- package/vendor/mbedtls/include/CMakeLists.txt +22 -0
- package/vendor/mbedtls/include/mbedtls/aes.h +631 -0
- package/vendor/mbedtls/include/mbedtls/aria.h +343 -0
- package/vendor/mbedtls/include/mbedtls/asn1.h +642 -0
- package/vendor/mbedtls/include/mbedtls/asn1write.h +390 -0
- package/vendor/mbedtls/include/mbedtls/base64.h +82 -0
- package/vendor/mbedtls/include/mbedtls/bignum.h +1088 -0
- package/vendor/mbedtls/include/mbedtls/block_cipher.h +76 -0
- package/vendor/mbedtls/include/mbedtls/build_info.h +194 -0
- package/vendor/mbedtls/include/mbedtls/camellia.h +305 -0
- package/vendor/mbedtls/include/mbedtls/ccm.h +526 -0
- package/vendor/mbedtls/include/mbedtls/chacha20.h +209 -0
- package/vendor/mbedtls/include/mbedtls/chachapoly.h +351 -0
- package/vendor/mbedtls/include/mbedtls/check_config.h +1149 -0
- package/vendor/mbedtls/include/mbedtls/cipher.h +1250 -0
- package/vendor/mbedtls/include/mbedtls/cmac.h +246 -0
- package/vendor/mbedtls/include/mbedtls/compat-2.x.h +46 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h +578 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_from_psa.h +873 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h +359 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_superset_legacy.h +145 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h +91 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_x509.h +35 -0
- package/vendor/mbedtls/include/mbedtls/config_psa.h +61 -0
- package/vendor/mbedtls/include/mbedtls/constant_time.h +36 -0
- package/vendor/mbedtls/include/mbedtls/ctr_drbg.h +596 -0
- package/vendor/mbedtls/include/mbedtls/debug.h +156 -0
- package/vendor/mbedtls/include/mbedtls/des.h +385 -0
- package/vendor/mbedtls/include/mbedtls/dhm.h +972 -0
- package/vendor/mbedtls/include/mbedtls/ecdh.h +455 -0
- package/vendor/mbedtls/include/mbedtls/ecdsa.h +674 -0
- package/vendor/mbedtls/include/mbedtls/ecjpake.h +298 -0
- package/vendor/mbedtls/include/mbedtls/ecp.h +1517 -0
- package/vendor/mbedtls/include/mbedtls/entropy.h +274 -0
- package/vendor/mbedtls/include/mbedtls/error.h +201 -0
- package/vendor/mbedtls/include/mbedtls/gcm.h +387 -0
- package/vendor/mbedtls/include/mbedtls/hkdf.h +124 -0
- package/vendor/mbedtls/include/mbedtls/hmac_drbg.h +434 -0
- package/vendor/mbedtls/include/mbedtls/lms.h +440 -0
- package/vendor/mbedtls/include/mbedtls/mbedtls_config.h +4446 -0
- package/vendor/mbedtls/include/mbedtls/md.h +526 -0
- package/vendor/mbedtls/include/mbedtls/md5.h +190 -0
- package/vendor/mbedtls/include/mbedtls/memory_buffer_alloc.h +142 -0
- package/vendor/mbedtls/include/mbedtls/net_sockets.h +299 -0
- package/vendor/mbedtls/include/mbedtls/nist_kw.h +166 -0
- package/vendor/mbedtls/include/mbedtls/oid.h +727 -0
- package/vendor/mbedtls/include/mbedtls/pem.h +160 -0
- package/vendor/mbedtls/include/mbedtls/pk.h +1303 -0
- package/vendor/mbedtls/include/mbedtls/pkcs12.h +186 -0
- package/vendor/mbedtls/include/mbedtls/pkcs5.h +198 -0
- package/vendor/mbedtls/include/mbedtls/pkcs7.h +252 -0
- package/vendor/mbedtls/include/mbedtls/platform.h +516 -0
- package/vendor/mbedtls/include/mbedtls/platform_time.h +79 -0
- package/vendor/mbedtls/include/mbedtls/platform_util.h +247 -0
- package/vendor/mbedtls/include/mbedtls/poly1305.h +168 -0
- package/vendor/mbedtls/include/mbedtls/private_access.h +20 -0
- package/vendor/mbedtls/include/mbedtls/psa_util.h +207 -0
- package/vendor/mbedtls/include/mbedtls/ripemd160.h +136 -0
- package/vendor/mbedtls/include/mbedtls/rsa.h +1170 -0
- package/vendor/mbedtls/include/mbedtls/sha1.h +219 -0
- package/vendor/mbedtls/include/mbedtls/sha256.h +200 -0
- package/vendor/mbedtls/include/mbedtls/sha3.h +172 -0
- package/vendor/mbedtls/include/mbedtls/sha512.h +208 -0
- package/vendor/mbedtls/include/mbedtls/ssl.h +5887 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cache.h +187 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ciphersuites.h +482 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cookie.h +106 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ticket.h +199 -0
- package/vendor/mbedtls/include/mbedtls/threading.h +167 -0
- package/vendor/mbedtls/include/mbedtls/timing.h +94 -0
- package/vendor/mbedtls/include/mbedtls/version.h +78 -0
- package/vendor/mbedtls/include/mbedtls/x509.h +500 -0
- package/vendor/mbedtls/include/mbedtls/x509_crl.h +184 -0
- package/vendor/mbedtls/include/mbedtls/x509_crt.h +1208 -0
- package/vendor/mbedtls/include/mbedtls/x509_csr.h +382 -0
- package/vendor/mbedtls/include/psa/build_info.h +20 -0
- package/vendor/mbedtls/include/psa/crypto.h +4998 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_auto_enabled.h +31 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_dependencies.h +51 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_key_pair_types.h +101 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_synonyms.h +49 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_composites.h +214 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_key_derivation.h +118 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_primitives.h +114 -0
- package/vendor/mbedtls/include/psa/crypto_compat.h +230 -0
- package/vendor/mbedtls/include/psa/crypto_config.h +145 -0
- package/vendor/mbedtls/include/psa/crypto_driver_common.h +44 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_composites.h +151 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_key_derivation.h +52 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_primitives.h +105 -0
- package/vendor/mbedtls/include/psa/crypto_extra.h +2145 -0
- package/vendor/mbedtls/include/psa/crypto_legacy.h +88 -0
- package/vendor/mbedtls/include/psa/crypto_platform.h +102 -0
- package/vendor/mbedtls/include/psa/crypto_se_driver.h +1383 -0
- package/vendor/mbedtls/include/psa/crypto_sizes.h +1319 -0
- package/vendor/mbedtls/include/psa/crypto_struct.h +527 -0
- package/vendor/mbedtls/include/psa/crypto_types.h +508 -0
- package/vendor/mbedtls/include/psa/crypto_values.h +2782 -0
- package/vendor/mbedtls/library/aes.c +2294 -0
- package/vendor/mbedtls/library/aesce.c +624 -0
- package/vendor/mbedtls/library/aesce.h +136 -0
- package/vendor/mbedtls/library/aesni.c +846 -0
- package/vendor/mbedtls/library/aesni.h +162 -0
- package/vendor/mbedtls/library/alignment.h +704 -0
- package/vendor/mbedtls/library/aria.c +969 -0
- package/vendor/mbedtls/library/asn1parse.c +468 -0
- package/vendor/mbedtls/library/asn1write.c +440 -0
- package/vendor/mbedtls/library/base64.c +322 -0
- package/vendor/mbedtls/library/base64_internal.h +45 -0
- package/vendor/mbedtls/library/bignum.c +2583 -0
- package/vendor/mbedtls/library/bignum_core.c +1240 -0
- package/vendor/mbedtls/library/bignum_core.h +872 -0
- package/vendor/mbedtls/library/bignum_core_invasive.h +38 -0
- package/vendor/mbedtls/library/bignum_internal.h +122 -0
- package/vendor/mbedtls/library/bignum_mod.c +394 -0
- package/vendor/mbedtls/library/bignum_mod.h +452 -0
- package/vendor/mbedtls/library/bignum_mod_raw.c +276 -0
- package/vendor/mbedtls/library/bignum_mod_raw.h +416 -0
- package/vendor/mbedtls/library/bignum_mod_raw_invasive.h +34 -0
- package/vendor/mbedtls/library/block_cipher.c +207 -0
- package/vendor/mbedtls/library/block_cipher_internal.h +99 -0
- package/vendor/mbedtls/library/bn_mul.h +1094 -0
- package/vendor/mbedtls/library/camellia.c +1058 -0
- package/vendor/mbedtls/library/ccm.c +777 -0
- package/vendor/mbedtls/library/chacha20.c +563 -0
- package/vendor/mbedtls/library/chacha20_internal.h +23 -0
- package/vendor/mbedtls/library/chachapoly.c +487 -0
- package/vendor/mbedtls/library/check_crypto_config.h +136 -0
- package/vendor/mbedtls/library/cipher.c +1712 -0
- package/vendor/mbedtls/library/cipher_invasive.h +28 -0
- package/vendor/mbedtls/library/cipher_wrap.c +2482 -0
- package/vendor/mbedtls/library/cipher_wrap.h +178 -0
- package/vendor/mbedtls/library/cmac.c +1067 -0
- package/vendor/mbedtls/library/common.h +487 -0
- package/vendor/mbedtls/library/constant_time.c +247 -0
- package/vendor/mbedtls/library/constant_time_impl.h +541 -0
- package/vendor/mbedtls/library/constant_time_internal.h +579 -0
- package/vendor/mbedtls/library/ctr.h +35 -0
- package/vendor/mbedtls/library/ctr_drbg.c +1016 -0
- package/vendor/mbedtls/library/debug.c +475 -0
- package/vendor/mbedtls/library/debug_internal.h +185 -0
- package/vendor/mbedtls/library/des.c +1042 -0
- package/vendor/mbedtls/library/dhm.c +700 -0
- package/vendor/mbedtls/library/ecdh.c +696 -0
- package/vendor/mbedtls/library/ecdsa.c +858 -0
- package/vendor/mbedtls/library/ecjpake.c +1216 -0
- package/vendor/mbedtls/library/ecp.c +3674 -0
- package/vendor/mbedtls/library/ecp_curves.c +6125 -0
- package/vendor/mbedtls/library/ecp_curves_new.c +9 -0
- package/vendor/mbedtls/library/ecp_internal_alt.h +287 -0
- package/vendor/mbedtls/library/ecp_invasive.h +305 -0
- package/vendor/mbedtls/library/entropy.c +680 -0
- package/vendor/mbedtls/library/entropy_poll.c +233 -0
- package/vendor/mbedtls/library/entropy_poll.h +64 -0
- package/vendor/mbedtls/library/error.c +878 -0
- package/vendor/mbedtls/library/gcm.c +1330 -0
- package/vendor/mbedtls/library/hkdf.c +161 -0
- package/vendor/mbedtls/library/hmac_drbg.c +633 -0
- package/vendor/mbedtls/library/lmots.c +789 -0
- package/vendor/mbedtls/library/lmots.h +288 -0
- package/vendor/mbedtls/library/lms.c +778 -0
- package/vendor/mbedtls/library/md.c +1108 -0
- package/vendor/mbedtls/library/md5.c +426 -0
- package/vendor/mbedtls/library/md_psa.h +26 -0
- package/vendor/mbedtls/library/md_wrap.h +46 -0
- package/vendor/mbedtls/library/memory_buffer_alloc.c +751 -0
- package/vendor/mbedtls/library/mps_common.h +181 -0
- package/vendor/mbedtls/library/mps_error.h +89 -0
- package/vendor/mbedtls/library/mps_reader.c +538 -0
- package/vendor/mbedtls/library/mps_reader.h +366 -0
- package/vendor/mbedtls/library/mps_trace.c +112 -0
- package/vendor/mbedtls/library/mps_trace.h +154 -0
- package/vendor/mbedtls/library/net_sockets.c +694 -0
- package/vendor/mbedtls/library/nist_kw.c +729 -0
- package/vendor/mbedtls/library/oid.c +1166 -0
- package/vendor/mbedtls/library/padlock.c +157 -0
- package/vendor/mbedtls/library/padlock.h +111 -0
- package/vendor/mbedtls/library/pem.c +554 -0
- package/vendor/mbedtls/library/pk.c +1602 -0
- package/vendor/mbedtls/library/pk_ecc.c +261 -0
- package/vendor/mbedtls/library/pk_internal.h +241 -0
- package/vendor/mbedtls/library/pk_wrap.c +1618 -0
- package/vendor/mbedtls/library/pk_wrap.h +138 -0
- package/vendor/mbedtls/library/pkcs12.c +437 -0
- package/vendor/mbedtls/library/pkcs5.c +500 -0
- package/vendor/mbedtls/library/pkcs7.c +787 -0
- package/vendor/mbedtls/library/pkparse.c +1392 -0
- package/vendor/mbedtls/library/pkwrite.c +631 -0
- package/vendor/mbedtls/library/pkwrite.h +121 -0
- package/vendor/mbedtls/library/platform.c +402 -0
- package/vendor/mbedtls/library/platform_util.c +258 -0
- package/vendor/mbedtls/library/poly1305.c +492 -0
- package/vendor/mbedtls/library/psa_crypto.c +9532 -0
- package/vendor/mbedtls/library/psa_crypto_aead.c +646 -0
- package/vendor/mbedtls/library/psa_crypto_aead.h +499 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.c +747 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.h +316 -0
- package/vendor/mbedtls/library/psa_crypto_client.c +22 -0
- package/vendor/mbedtls/library/psa_crypto_core.h +983 -0
- package/vendor/mbedtls/library/psa_crypto_core_common.h +52 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers.h +2896 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.c +256 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.h +31 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.c +594 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.h +267 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.c +361 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_hash.c +470 -0
- package/vendor/mbedtls/library/psa_crypto_hash.h +211 -0
- package/vendor/mbedtls/library/psa_crypto_invasive.h +92 -0
- package/vendor/mbedtls/library/psa_crypto_its.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_mac.c +505 -0
- package/vendor/mbedtls/library/psa_crypto_mac.h +264 -0
- package/vendor/mbedtls/library/psa_crypto_pake.c +571 -0
- package/vendor/mbedtls/library/psa_crypto_pake.h +159 -0
- package/vendor/mbedtls/library/psa_crypto_random.c +181 -0
- package/vendor/mbedtls/library/psa_crypto_random.h +72 -0
- package/vendor/mbedtls/library/psa_crypto_random_impl.h +200 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.c +714 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.h +321 -0
- package/vendor/mbedtls/library/psa_crypto_se.c +373 -0
- package/vendor/mbedtls/library/psa_crypto_se.h +192 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.c +1137 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.h +344 -0
- package/vendor/mbedtls/library/psa_crypto_storage.c +481 -0
- package/vendor/mbedtls/library/psa_crypto_storage.h +392 -0
- package/vendor/mbedtls/library/psa_its_file.c +254 -0
- package/vendor/mbedtls/library/psa_util.c +614 -0
- package/vendor/mbedtls/library/psa_util_internal.h +100 -0
- package/vendor/mbedtls/library/ripemd160.c +490 -0
- package/vendor/mbedtls/library/rsa.c +3121 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.c +455 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.h +209 -0
- package/vendor/mbedtls/library/rsa_internal.h +188 -0
- package/vendor/mbedtls/library/sha1.c +480 -0
- package/vendor/mbedtls/library/sha256.c +983 -0
- package/vendor/mbedtls/library/sha3.c +721 -0
- package/vendor/mbedtls/library/sha512.c +1115 -0
- package/vendor/mbedtls/library/ssl_cache.c +410 -0
- package/vendor/mbedtls/library/ssl_ciphersuites.c +2050 -0
- package/vendor/mbedtls/library/ssl_ciphersuites_internal.h +154 -0
- package/vendor/mbedtls/library/ssl_client.c +1023 -0
- package/vendor/mbedtls/library/ssl_client.h +22 -0
- package/vendor/mbedtls/library/ssl_cookie.c +384 -0
- package/vendor/mbedtls/library/ssl_debug_helpers.h +85 -0
- package/vendor/mbedtls/library/ssl_debug_helpers_generated.c +251 -0
- package/vendor/mbedtls/library/ssl_misc.h +3198 -0
- package/vendor/mbedtls/library/ssl_msg.c +6619 -0
- package/vendor/mbedtls/library/ssl_ticket.c +556 -0
- package/vendor/mbedtls/library/ssl_tls.c +10234 -0
- package/vendor/mbedtls/library/ssl_tls12_client.c +3688 -0
- package/vendor/mbedtls/library/ssl_tls12_server.c +4311 -0
- package/vendor/mbedtls/library/ssl_tls13_client.c +3208 -0
- package/vendor/mbedtls/library/ssl_tls13_generic.c +1793 -0
- package/vendor/mbedtls/library/ssl_tls13_invasive.h +23 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.c +1918 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.h +668 -0
- package/vendor/mbedtls/library/ssl_tls13_server.c +3624 -0
- package/vendor/mbedtls/library/threading.c +193 -0
- package/vendor/mbedtls/library/threading_internal.h +28 -0
- package/vendor/mbedtls/library/timing.c +152 -0
- package/vendor/mbedtls/library/version.c +32 -0
- package/vendor/mbedtls/library/version_features.c +856 -0
- package/vendor/mbedtls/library/x509.c +1776 -0
- package/vendor/mbedtls/library/x509_create.c +570 -0
- package/vendor/mbedtls/library/x509_crl.c +708 -0
- package/vendor/mbedtls/library/x509_crt.c +3311 -0
- package/vendor/mbedtls/library/x509_csr.c +648 -0
- package/vendor/mbedtls/library/x509_internal.h +101 -0
- package/vendor/mbedtls/library/x509write.c +174 -0
- package/vendor/mbedtls/library/x509write_crt.c +688 -0
- package/vendor/mbedtls/library/x509write_csr.c +336 -0
- package/vendor/quickjs-ng/CMakeLists.txt +566 -0
- package/vendor/quickjs-ng/LICENSE +24 -0
- package/vendor/quickjs-ng/README.md +24 -0
- package/vendor/quickjs-ng/api-test.c +1195 -0
- package/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/vendor/quickjs-ng/cutils.h +1998 -0
- package/vendor/quickjs-ng/dtoa.c +1619 -0
- package/vendor/quickjs-ng/dtoa.h +87 -0
- package/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/vendor/quickjs-ng/gen/hello.c +53 -0
- package/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/vendor/quickjs-ng/gen/repl.c +3036 -0
- package/vendor/quickjs-ng/gen/standalone.c +323 -0
- package/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/vendor/quickjs-ng/libregexp-opcode.h +73 -0
- package/vendor/quickjs-ng/libregexp.c +3474 -0
- package/vendor/quickjs-ng/libregexp.h +101 -0
- package/vendor/quickjs-ng/libunicode-table.h +5173 -0
- package/vendor/quickjs-ng/libunicode.c +2069 -0
- package/vendor/quickjs-ng/libunicode.h +172 -0
- package/vendor/quickjs-ng/list.h +107 -0
- package/vendor/quickjs-ng/lre-test.c +52 -0
- package/vendor/quickjs-ng/qjs.c +762 -0
- package/vendor/quickjs-ng/qjsc.c +673 -0
- package/vendor/quickjs-ng/quickjs-atom.h +280 -0
- package/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/vendor/quickjs-ng/quickjs-libc.c +5037 -0
- package/vendor/quickjs-ng/quickjs-libc.h +87 -0
- package/vendor/quickjs-ng/quickjs-opcode.h +377 -0
- package/vendor/quickjs-ng/quickjs.c +64041 -0
- package/vendor/quickjs-ng/quickjs.h +1447 -0
- package/vendor/quickjs-ng/run-test262.c +2374 -0
- package/vendor/quickjs-ng/unicode_gen.c +3121 -0
- package/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/vendor/ryu/LICENSE-Boost +23 -0
- package/vendor/ryu/common.h +114 -0
- package/vendor/ryu/d2s.c +509 -0
- package/vendor/ryu/d2s_full_table.h +367 -0
- package/vendor/ryu/d2s_intrinsics.h +357 -0
- package/vendor/ryu/d2s_small_table.h +186 -0
- package/vendor/ryu/digit_table.h +35 -0
- package/vendor/ryu/ryu.h +46 -0
- package/vendor/zlib/LICENSE +22 -0
- package/vendor/zlib/adler32.c +164 -0
- package/vendor/zlib/compress.c +75 -0
- package/vendor/zlib/crc32.c +1049 -0
- package/vendor/zlib/crc32.h +9446 -0
- package/vendor/zlib/deflate.c +2139 -0
- package/vendor/zlib/deflate.h +377 -0
- package/vendor/zlib/gzclose.c +23 -0
- package/vendor/zlib/gzguts.h +214 -0
- package/vendor/zlib/gzlib.c +582 -0
- package/vendor/zlib/gzread.c +602 -0
- package/vendor/zlib/gzwrite.c +631 -0
- package/vendor/zlib/infback.c +628 -0
- package/vendor/zlib/inffast.c +320 -0
- package/vendor/zlib/inffast.h +11 -0
- package/vendor/zlib/inffixed.h +94 -0
- package/vendor/zlib/inflate.c +1526 -0
- package/vendor/zlib/inflate.h +126 -0
- package/vendor/zlib/inftrees.c +299 -0
- package/vendor/zlib/inftrees.h +62 -0
- package/vendor/zlib/trees.c +1117 -0
- package/vendor/zlib/trees.h +128 -0
- package/vendor/zlib/uncompr.c +85 -0
- package/vendor/zlib/zconf.h +543 -0
- package/vendor/zlib/zlib.h +1938 -0
- package/vendor/zlib/zutil.c +299 -0
- package/vendor/zlib/zutil.h +254 -0
- package/README.md +0 -3
- package/index.js +0 -2
package/src/scr_assert.c
ADDED
|
@@ -0,0 +1,1393 @@
|
|
|
1
|
+
/* node:assert — the static assertion surface. Every failure throws a
|
|
2
|
+
* catchable AssertionError: a runtime %Error instance whose name is
|
|
3
|
+
* "AssertionError" and whose code slot is "ERR_ASSERTION" (Node's
|
|
4
|
+
* ERR_ASSERTION), so catch-side `instanceof Error`, `.name`, `.message`,
|
|
5
|
+
* and `.code` reads all answer exactly like Node's.
|
|
6
|
+
*
|
|
7
|
+
* Generated messages reproduce Node's assertion_error.js for the SCALAR
|
|
8
|
+
* comparisons this file receives (numbers, strings, booleans): the short
|
|
9
|
+
* `a !== b` form under the 12-character budget (string quotes excluded),
|
|
10
|
+
* the stacked `+ actual - expected` diff above it — including the `^`
|
|
11
|
+
* first-difference indicator for string pairs — and the inline-vs-block
|
|
12
|
+
* split of the not-equal operators (single-line inspect over 5 chars goes
|
|
13
|
+
* on its own block). One deliberate divergence (SEMANTICS.md 103): Node
|
|
14
|
+
* renders a COLORED character diff for string pairs when stderr is a
|
|
15
|
+
* color TTY; this runtime always emits the plain stacked form (the
|
|
16
|
+
* message text itself would be terminal-dependent in Node).
|
|
17
|
+
* Deep-equality over composite values compares honestly in
|
|
18
|
+
* compiler-synthesized helpers; their generated failure messages carry
|
|
19
|
+
* Node's header line WITHOUT the rendered value diff (a full
|
|
20
|
+
* util.inspect has no static lowering — SEMANTICS.md 102).
|
|
21
|
+
*
|
|
22
|
+
* Ownership: all ScrStr arguments are BORROWED; the throw helpers that
|
|
23
|
+
* take ownership say so. Value inspection follows util.inspect's default
|
|
24
|
+
* quoting (single quotes, then double, then backtick; C0 controls and
|
|
25
|
+
* DEL escaped) — exotic C1/Unicode escapes are out of scope
|
|
26
|
+
* (SEMANTICS.md 106). */
|
|
27
|
+
#include "scr_runtime.h"
|
|
28
|
+
|
|
29
|
+
#include <math.h>
|
|
30
|
+
#include <stdio.h>
|
|
31
|
+
#include <stdlib.h>
|
|
32
|
+
#include <string.h>
|
|
33
|
+
|
|
34
|
+
static void scr_assert_oom(void) {
|
|
35
|
+
fputs("scriptc: out of memory\n", stderr);
|
|
36
|
+
abort();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* ── a tiny append-only byte buffer for message assembly ─────────────── */
|
|
40
|
+
|
|
41
|
+
typedef struct {
|
|
42
|
+
char *data;
|
|
43
|
+
size_t len;
|
|
44
|
+
size_t cap;
|
|
45
|
+
} ScrAssertBuf;
|
|
46
|
+
|
|
47
|
+
static void ab_grow(ScrAssertBuf *b, size_t need) {
|
|
48
|
+
if (b->len + need <= b->cap) return;
|
|
49
|
+
size_t cap = b->cap ? b->cap * 2 : 64;
|
|
50
|
+
while (cap < b->len + need) cap *= 2;
|
|
51
|
+
char *data = realloc(b->data, cap);
|
|
52
|
+
if (!data) scr_assert_oom();
|
|
53
|
+
b->data = data;
|
|
54
|
+
b->cap = cap;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static void ab_bytes(ScrAssertBuf *b, const char *s, size_t len) {
|
|
58
|
+
ab_grow(b, len);
|
|
59
|
+
memcpy(b->data + b->len, s, len);
|
|
60
|
+
b->len += len;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static void ab_cstr(ScrAssertBuf *b, const char *s) { ab_bytes(b, s, strlen(s)); }
|
|
64
|
+
|
|
65
|
+
static void ab_char(ScrAssertBuf *b, char c) { ab_bytes(b, &c, 1); }
|
|
66
|
+
|
|
67
|
+
static void ab_str(ScrAssertBuf *b, const ScrStr *s) { ab_bytes(b, s->data, s->len); }
|
|
68
|
+
|
|
69
|
+
static ScrStr *ab_take(ScrAssertBuf *b) {
|
|
70
|
+
ScrStr *out = scr_str_new(b->data ? b->data : "", b->len);
|
|
71
|
+
free(b->data);
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* ── value inspection (util.inspect's scalar slice) ──────────────────── */
|
|
76
|
+
|
|
77
|
+
/* Number inspection: JS ToString EXCEPT that inspect distinguishes -0. */
|
|
78
|
+
static size_t scr_assert_inspect_f64(double x, char *buf /* >= 33 */) {
|
|
79
|
+
if (x == 0.0 && signbit(x)) {
|
|
80
|
+
memcpy(buf, "-0", 3);
|
|
81
|
+
return 2;
|
|
82
|
+
}
|
|
83
|
+
return scr_f64_to_str(x, buf);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* String inspection: util.inspect's quoting — single quotes by default,
|
|
87
|
+
* double quotes when the text contains ' but no ", backticks when it
|
|
88
|
+
* contains both; backslash/quote/C0/DEL escaped (\b \t \n \f \r named,
|
|
89
|
+
* \x0B and the rest as \xNN — inspect's own table). +1. */
|
|
90
|
+
ScrStr *scr_assert_inspect_str(const ScrStr *s) {
|
|
91
|
+
char quote = '\'';
|
|
92
|
+
bool hasSingle = false, hasDouble = false;
|
|
93
|
+
for (size_t i = 0; i < s->len; i++) {
|
|
94
|
+
if (s->data[i] == '\'') hasSingle = true;
|
|
95
|
+
if (s->data[i] == '"') hasDouble = true;
|
|
96
|
+
}
|
|
97
|
+
if (hasSingle) quote = hasDouble ? '`' : '"';
|
|
98
|
+
ScrAssertBuf b = {0};
|
|
99
|
+
ab_char(&b, quote);
|
|
100
|
+
for (size_t i = 0; i < s->len; i++) {
|
|
101
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
102
|
+
if (c == (unsigned char)quote || c == '\\') {
|
|
103
|
+
ab_char(&b, '\\');
|
|
104
|
+
ab_char(&b, (char)c);
|
|
105
|
+
} else if (c == '\b') {
|
|
106
|
+
ab_cstr(&b, "\\b");
|
|
107
|
+
} else if (c == '\t') {
|
|
108
|
+
ab_cstr(&b, "\\t");
|
|
109
|
+
} else if (c == '\n') {
|
|
110
|
+
ab_cstr(&b, "\\n");
|
|
111
|
+
} else if (c == '\f') {
|
|
112
|
+
ab_cstr(&b, "\\f");
|
|
113
|
+
} else if (c == '\r') {
|
|
114
|
+
ab_cstr(&b, "\\r");
|
|
115
|
+
} else if (c < 0x20 || c == 0x7f) {
|
|
116
|
+
char esc[5];
|
|
117
|
+
snprintf(esc, sizeof esc, "\\x%02X", c);
|
|
118
|
+
ab_cstr(&b, esc);
|
|
119
|
+
} else {
|
|
120
|
+
ab_char(&b, (char)c);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
ab_char(&b, quote);
|
|
124
|
+
return ab_take(&b);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* ── the AssertionError throw ─────────────────────────────────────────── */
|
|
128
|
+
|
|
129
|
+
/* Throws an AssertionError with `message` (ownership MOVES in): a runtime
|
|
130
|
+
* %Error whose name/code are Node's. The exception is pending on return —
|
|
131
|
+
* callers return through the emitter's pending check like every other
|
|
132
|
+
* throwing libCall. */
|
|
133
|
+
void scr_assert_fail_msg(ScrStr *message) {
|
|
134
|
+
ScrError *e = scr_error_new(SCR_ERR_ERROR, message);
|
|
135
|
+
scr_str_release(message); /* scr_error_new retained its copy */
|
|
136
|
+
scr_str_release(e->name);
|
|
137
|
+
e->name = scr_str_new("AssertionError", 14);
|
|
138
|
+
scr_error_set_code(e, "ERR_ASSERTION");
|
|
139
|
+
scr_throw_obj(e, &scr_error_retain_v, &scr_error_release_v, scr_error_trace_arg());
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* assert(value) / assert.ok(value[, message]) / assert.fail([message]):
|
|
143
|
+
* the frontend computed the truthiness and the FULL message (the user's
|
|
144
|
+
* string, or the compile-time "The expression evaluated to a falsy
|
|
145
|
+
* value:\n\n <source text>\n" — the source is a compile-time constant
|
|
146
|
+
* where Node re-reads the file). */
|
|
147
|
+
void scr_assert_ok(bool pass, ScrStr *message) {
|
|
148
|
+
if (pass) return;
|
|
149
|
+
scr_assert_fail_msg(scr_str_retain(message));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* SameValue over doubles — Object.is, the comparison of strictEqual AND
|
|
153
|
+
* deepStrictEqual for numbers (NaN equals NaN; +0 and -0 differ). */
|
|
154
|
+
bool scr_assert_same_value_f64(double a, double b) {
|
|
155
|
+
if (a == b) return a != 0.0 || signbit(a) == signbit(b);
|
|
156
|
+
return isnan(a) && isnan(b);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* ── generated equality messages (assertion_error.js, scalar slice) ──── */
|
|
160
|
+
|
|
161
|
+
static const char *scr_assert_eq_header(bool deep) {
|
|
162
|
+
return deep ? "Expected values to be strictly deep-equal:"
|
|
163
|
+
: "Expected values to be strictly equal:";
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
static const char *scr_assert_neq_header(bool deep) {
|
|
167
|
+
return deep ? "Expected \"actual\" not to be strictly deep-equal to:"
|
|
168
|
+
: "Expected \"actual\" to be strictly unequal to:";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* The failing NOT-equal operators (values compared equal): the custom
|
|
172
|
+
* message stands alone; the generated one inlines a short single-line
|
|
173
|
+
* inspect after the header (<= 5 chars), block form otherwise. `insp` is
|
|
174
|
+
* the inspected actual value (borrowed bytes). Exported for the spoke
|
|
175
|
+
* files that carry their own inspection (scr_symbol.c). */
|
|
176
|
+
void scr_assert_neq_fail(const char *insp, size_t ilen, bool deep,
|
|
177
|
+
ScrStr *msg, bool has_msg) {
|
|
178
|
+
if (has_msg) {
|
|
179
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
ScrAssertBuf b = {0};
|
|
183
|
+
ab_cstr(&b, scr_assert_neq_header(deep));
|
|
184
|
+
ab_cstr(&b, ilen > 5 ? "\n\n" : " ");
|
|
185
|
+
ab_bytes(&b, insp, ilen);
|
|
186
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* The failing EQUAL operators: createErrDiff's scalar paths — a custom
|
|
190
|
+
* message replaces the HEADER (Node appends the diff below it; the empty
|
|
191
|
+
* string falls back to the default header, `message ||` in Node).
|
|
192
|
+
* `quotes` counts the string-typed sides (each contributes 2 quote
|
|
193
|
+
* characters excluded from the short-form budget); `both_zero` is the
|
|
194
|
+
* ±0-vs-±0 special case (never short); `strings` enables the stacked
|
|
195
|
+
* form's first-difference `^` indicator (string pairs only, combined
|
|
196
|
+
* inspected length within the 80-column non-TTY default). Exported for
|
|
197
|
+
* scr_symbol.c's symbol comparison. */
|
|
198
|
+
void scr_assert_eq_fail(const char *ia, size_t la, const char *ib, size_t lb,
|
|
199
|
+
int quotes, bool both_zero, bool strings, bool deep,
|
|
200
|
+
ScrStr *msg, bool has_msg) {
|
|
201
|
+
ScrAssertBuf b = {0};
|
|
202
|
+
if (has_msg && msg->len > 0) {
|
|
203
|
+
ab_str(&b, msg);
|
|
204
|
+
} else {
|
|
205
|
+
ab_cstr(&b, scr_assert_eq_header(deep));
|
|
206
|
+
}
|
|
207
|
+
size_t stringsLen = la + lb - (size_t)(2 * quotes);
|
|
208
|
+
if (stringsLen <= 12 && !both_zero) {
|
|
209
|
+
ab_cstr(&b, "\n\n");
|
|
210
|
+
ab_bytes(&b, ia, la);
|
|
211
|
+
ab_cstr(&b, " !== ");
|
|
212
|
+
ab_bytes(&b, ib, lb);
|
|
213
|
+
ab_cstr(&b, "\n");
|
|
214
|
+
} else {
|
|
215
|
+
ab_cstr(&b, "\n+ actual - expected\n\n+ ");
|
|
216
|
+
ab_bytes(&b, ia, la);
|
|
217
|
+
ab_cstr(&b, "\n- ");
|
|
218
|
+
ab_bytes(&b, ib, lb);
|
|
219
|
+
if (strings && la + lb <= 80) {
|
|
220
|
+
/* The first-difference indicator (getStackedDiff): the first index
|
|
221
|
+
* where actual's characters stop matching expected's — skipped when
|
|
222
|
+
* that lands within the first two content characters (i < 3 over the
|
|
223
|
+
* quoted text) or when actual is a prefix of expected. Node computes
|
|
224
|
+
* this over the INSPECTED text of every simple stacked diff (numbers
|
|
225
|
+
* and symbols included — getSimpleDiff hands getStackedDiff the
|
|
226
|
+
* rendered strings, so its typeof-string test is always true), so
|
|
227
|
+
* every scalar caller passes `strings` true. */
|
|
228
|
+
size_t i = 0;
|
|
229
|
+
while (i < la && i < lb && ia[i] == ib[i]) i++;
|
|
230
|
+
if (i < la && i >= 3) {
|
|
231
|
+
ab_char(&b, '\n');
|
|
232
|
+
for (size_t k = 0; k < i + 2; k++) ab_char(&b, ' ');
|
|
233
|
+
ab_char(&b, '^');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
ab_cstr(&b, "\n");
|
|
237
|
+
}
|
|
238
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* strictEqual / notStrictEqual / deepStrictEqual / notDeepStrictEqual over
|
|
242
|
+
* numbers: Object.is comparison, inspect distinguishes -0. */
|
|
243
|
+
void scr_assert_eq_f64(double a, double b, bool negated, bool deep,
|
|
244
|
+
ScrStr *msg, bool has_msg) {
|
|
245
|
+
bool same = scr_assert_same_value_f64(a, b);
|
|
246
|
+
if ((negated && !same) || (!negated && same)) return;
|
|
247
|
+
char ia[40], ib[40];
|
|
248
|
+
size_t la = scr_assert_inspect_f64(a, ia);
|
|
249
|
+
if (negated) {
|
|
250
|
+
scr_assert_neq_fail(ia, la, deep, msg, has_msg);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
size_t lb = scr_assert_inspect_f64(b, ib);
|
|
254
|
+
scr_assert_eq_fail(ia, la, ib, lb, 0, a == 0.0 && b == 0.0, true, deep, msg, has_msg);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* The string forms: byte equality IS SameValue for well-formed UTF-8. */
|
|
258
|
+
void scr_assert_eq_str(ScrStr *a, ScrStr *b, bool negated, bool deep,
|
|
259
|
+
ScrStr *msg, bool has_msg) {
|
|
260
|
+
bool same = a->len == b->len && memcmp(a->data, b->data, a->len) == 0;
|
|
261
|
+
if ((negated && !same) || (!negated && same)) return;
|
|
262
|
+
ScrStr *ia = scr_assert_inspect_str(a);
|
|
263
|
+
if (negated) {
|
|
264
|
+
scr_assert_neq_fail(ia->data, ia->len, deep, msg, has_msg);
|
|
265
|
+
scr_str_release(ia);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
ScrStr *ib = scr_assert_inspect_str(b);
|
|
269
|
+
scr_assert_eq_fail(ia->data, ia->len, ib->data, ib->len, 2, false, true, deep,
|
|
270
|
+
msg, has_msg);
|
|
271
|
+
scr_str_release(ia);
|
|
272
|
+
scr_str_release(ib);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* The boolean forms. */
|
|
276
|
+
void scr_assert_eq_bool(bool a, bool b, bool negated, bool deep,
|
|
277
|
+
ScrStr *msg, bool has_msg) {
|
|
278
|
+
bool same = a == b;
|
|
279
|
+
if ((negated && !same) || (!negated && same)) return;
|
|
280
|
+
const char *ia = a ? "true" : "false";
|
|
281
|
+
if (negated) {
|
|
282
|
+
scr_assert_neq_fail(ia, strlen(ia), deep, msg, has_msg);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const char *ib = b ? "true" : "false";
|
|
286
|
+
scr_assert_eq_fail(ia, strlen(ia), ib, strlen(ib), 0, false, true, deep, msg,
|
|
287
|
+
has_msg);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* deepStrictEqual / notDeepStrictEqual over COMPOSITE values: the frontend
|
|
291
|
+
* synthesized the honest structural comparison; this only turns its verdict
|
|
292
|
+
* into Node's throw. The generated message is the header line alone —
|
|
293
|
+
* rendering the value diff needs util.inspect, which has no static
|
|
294
|
+
* lowering (SEMANTICS.md 102). */
|
|
295
|
+
void scr_assert_deep_result(bool equal, bool negated, ScrStr *msg, bool has_msg) {
|
|
296
|
+
if ((negated && !equal) || (!negated && equal)) return;
|
|
297
|
+
if (has_msg && (negated || msg->len > 0)) {
|
|
298
|
+
/* Node: the not-equal operators use the message ALONE (even empty);
|
|
299
|
+
* the equal operators use it as the diff HEADER when non-empty —
|
|
300
|
+
* without a rendered diff below it the two collapse to the same
|
|
301
|
+
* shape here. */
|
|
302
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const char *base = negated ? scr_assert_neq_header(true) : scr_assert_eq_header(true);
|
|
306
|
+
scr_assert_fail_msg(scr_str_new(base, strlen(base)));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* deepStrictEqual's content comparison over bytes values (the brand is
|
|
310
|
+
* the frontend's compile-time question — see the header). One elem kind
|
|
311
|
+
* by construction (the frontend's same-static-type gate), but the elem
|
|
312
|
+
* check stays: a defensive answer beats a miscompare. */
|
|
313
|
+
static bool scr_assert_bytes_content_eq(const ScrBytes *a, const ScrBytes *b) {
|
|
314
|
+
if (a->elem != b->elem || a->len != b->len) return false;
|
|
315
|
+
size_t nbytes = a->len * scr_bytes_elem_size(a->elem);
|
|
316
|
+
return nbytes == 0 || memcmp(a->data, b->data, nbytes) == 0;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
bool scr_assert_bytes_deep_eq(const ScrBytes *a, const ScrBytes *b, bool brands_eq) {
|
|
320
|
+
return brands_eq && scr_assert_bytes_content_eq(a, b);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* strictEqual / notStrictEqual over bytes values: reference identity.
|
|
324
|
+
* The generated messages are Node's OBJECT-comparison headers (createErrDiff
|
|
325
|
+
* routes objects through the reference-equality wording, not the scalar
|
|
326
|
+
* "strictly equal" one); the value renderings below them need the
|
|
327
|
+
* assert-style diff engine, so the header stands alone — the composite
|
|
328
|
+
* stance (SEMANTICS.md 102). */
|
|
329
|
+
void scr_assert_ref_eq_bytes(const ScrBytes *a, const ScrBytes *b, bool negated,
|
|
330
|
+
bool brands_eq, ScrStr *msg, bool has_msg) {
|
|
331
|
+
bool same = a == b;
|
|
332
|
+
if ((negated && !same) || (!negated && same)) return;
|
|
333
|
+
if (has_msg && (negated || msg->len > 0)) {
|
|
334
|
+
/* The deepResult message stance: not-equal operators use it alone
|
|
335
|
+
* (even empty); the equal operators use a non-empty one as the diff
|
|
336
|
+
* header — headerless diffs collapse both to the message itself. */
|
|
337
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const char *h;
|
|
341
|
+
if (negated) {
|
|
342
|
+
h = "Expected \"actual\" not to be reference-equal to \"expected\":";
|
|
343
|
+
} else if (brands_eq && scr_assert_bytes_content_eq(a, b)) {
|
|
344
|
+
h = "Values have same structure but are not reference-equal:";
|
|
345
|
+
} else {
|
|
346
|
+
h = "Expected \"actual\" to be reference-equal to \"expected\":";
|
|
347
|
+
}
|
|
348
|
+
scr_assert_fail_msg(scr_str_new(h, strlen(h)));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* strictEqual / notStrictEqual over function values: reference identity.
|
|
352
|
+
* Two distinct functions are never deep-equal, so the failing equal form
|
|
353
|
+
* always takes the reference-equality expectation header. */
|
|
354
|
+
void scr_assert_ref_eq_fn(const ScrClosure *a, const ScrClosure *b, bool negated,
|
|
355
|
+
ScrStr *msg, bool has_msg) {
|
|
356
|
+
bool same = a == b;
|
|
357
|
+
if ((negated && !same) || (!negated && same)) return;
|
|
358
|
+
if (has_msg && (negated || msg->len > 0)) {
|
|
359
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const char *h = negated
|
|
363
|
+
? "Expected \"actual\" not to be reference-equal to \"expected\":"
|
|
364
|
+
: "Expected \"actual\" to be reference-equal to \"expected\":";
|
|
365
|
+
scr_assert_fail_msg(scr_str_new(h, strlen(h)));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* ── strictEqual / deepStrictEqual over CHECKED-DYNAMIC (dyn) operands ──
|
|
369
|
+
* The DOM carries the value's kind at runtime, so one entry point serves
|
|
370
|
+
* the whole quartet: SameValue for the strict pair (numbers by Object.is,
|
|
371
|
+
* strings by bytes, units by kind, arrays/objects/bytes by node identity,
|
|
372
|
+
* functions by the BOXED CLOSURE — two dyn crossings of one function are
|
|
373
|
+
* the same JS function), a structural DOM walk for the deep pair.
|
|
374
|
+
*
|
|
375
|
+
* Failure messages reproduce Node's assertion_error.js against the v24
|
|
376
|
+
* sources: inspectValue is a compact:false / sorted:true / depth-1000
|
|
377
|
+
* rendering of the DOM (each entry on its own line, entries sorted by
|
|
378
|
+
* their RENDERED text — Node's `sorted: true` sorts formatted entries),
|
|
379
|
+
* the simple/stacked scalar forms match the static paths byte-for-byte,
|
|
380
|
+
* and composite diffs run the real myers line diff with Node's printer
|
|
381
|
+
* (5 context lines, then "..." and the "... Skipped lines" banner, comma
|
|
382
|
+
* disparity between object lines treated as equal). Known divergences:
|
|
383
|
+
* key sorting is UTF-8 byte order where Node sorts UTF-16 code units
|
|
384
|
+
* (identical for ASCII keys), dyn function props are not rendered after
|
|
385
|
+
* the [Function: name] form, and values rendering past ~4096 lines fall
|
|
386
|
+
* back to the whole-value +/- form without context collapsing. */
|
|
387
|
+
|
|
388
|
+
/* JS SameValue over two DOM values (Object.is — the strictEqual and
|
|
389
|
+
* notStrictEqual comparison). Functions compare by boxed closure: the
|
|
390
|
+
* ScrDyn box is a boundary artifact, the closure IS the JS identity. */
|
|
391
|
+
static bool scr_assert_dyn_same_value(const ScrDyn *a, const ScrDyn *b) {
|
|
392
|
+
if (a->kind != b->kind) return false;
|
|
393
|
+
switch (a->kind) {
|
|
394
|
+
case SCR_DYN_UNDEF:
|
|
395
|
+
case SCR_DYN_NULL:
|
|
396
|
+
return true;
|
|
397
|
+
case SCR_DYN_BOOL:
|
|
398
|
+
return a->v.b == b->v.b;
|
|
399
|
+
case SCR_DYN_NUM:
|
|
400
|
+
return scr_assert_same_value_f64(a->v.num, b->v.num);
|
|
401
|
+
case SCR_DYN_STR:
|
|
402
|
+
return a->v.str->len == b->v.str->len &&
|
|
403
|
+
memcmp(a->v.str->data, b->v.str->data, a->v.str->len) == 0;
|
|
404
|
+
case SCR_DYN_FUNC:
|
|
405
|
+
return a == b || a->v.fn.clo == b->v.fn.clo;
|
|
406
|
+
case SCR_DYN_HANDLE:
|
|
407
|
+
/* Identity is the HANDLE (the strict_eq stance). */
|
|
408
|
+
return a->v.handle.tag == b->v.handle.tag && a->v.handle.ptr == b->v.handle.ptr;
|
|
409
|
+
case SCR_DYN_PROMISE:
|
|
410
|
+
/* Identity is the PROMISE (the strict_eq stance). */
|
|
411
|
+
return a->v.promise == b->v.promise;
|
|
412
|
+
default:
|
|
413
|
+
return a == b; /* ARR/OBJ/BYTES: node identity */
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/* Node's strict deep equality over two DOM values: kind-wise — Object.is
|
|
418
|
+
* numbers, byte-equal strings, units by kind, per-element arrays,
|
|
419
|
+
* key-set-plus-values objects (DOM keys are unique, so equal lengths and
|
|
420
|
+
* an a⊆b value walk prove the bijection), brand-aware bytes (the buffer
|
|
421
|
+
* flavor bit IS the Buffer-vs-Uint8Array prototype Node compares first),
|
|
422
|
+
* reference identity for functions (boxed closure). Plain recursion:
|
|
423
|
+
* JSON-origin DOMs are trees; a keyed-write cycle (h.self = h) has no
|
|
424
|
+
* memo here where Node carries one (documented divergence). */
|
|
425
|
+
static bool scr_assert_dyn_deep_eq(const ScrDyn *a, const ScrDyn *b) {
|
|
426
|
+
if (a == b) return true;
|
|
427
|
+
if (a->kind != b->kind) return false;
|
|
428
|
+
switch (a->kind) {
|
|
429
|
+
case SCR_DYN_UNDEF:
|
|
430
|
+
case SCR_DYN_NULL:
|
|
431
|
+
return true;
|
|
432
|
+
case SCR_DYN_BOOL:
|
|
433
|
+
return a->v.b == b->v.b;
|
|
434
|
+
case SCR_DYN_NUM:
|
|
435
|
+
return scr_assert_same_value_f64(a->v.num, b->v.num);
|
|
436
|
+
case SCR_DYN_STR:
|
|
437
|
+
return a->v.str->len == b->v.str->len &&
|
|
438
|
+
memcmp(a->v.str->data, b->v.str->data, a->v.str->len) == 0;
|
|
439
|
+
case SCR_DYN_FUNC:
|
|
440
|
+
return a->v.fn.clo == b->v.fn.clo;
|
|
441
|
+
case SCR_DYN_HANDLE:
|
|
442
|
+
/* Node's deepStrictEqual over two distinct live handles walks own
|
|
443
|
+
* enumerable props we do not model; same-handle is the only case a
|
|
444
|
+
* compiled test can honestly answer (documented). */
|
|
445
|
+
return a->v.handle.tag == b->v.handle.tag && a->v.handle.ptr == b->v.handle.ptr;
|
|
446
|
+
case SCR_DYN_PROMISE:
|
|
447
|
+
/* Node compares promises structurally (no own props → equal); the
|
|
448
|
+
* honest arm here is identity — two distinct promises with equal
|
|
449
|
+
* settlements would diverge (documented with the handle stance). */
|
|
450
|
+
return a->v.promise == b->v.promise;
|
|
451
|
+
case SCR_DYN_BYTES: {
|
|
452
|
+
if (a->buffer != b->buffer) return false; /* the prototype gate */
|
|
453
|
+
const ScrBytes *x = a->v.bytes, *y = b->v.bytes;
|
|
454
|
+
if (x->elem != y->elem || x->len != y->len) return false;
|
|
455
|
+
size_t nbytes = x->len * scr_bytes_elem_size(x->elem);
|
|
456
|
+
return nbytes == 0 || memcmp(x->data, y->data, nbytes) == 0;
|
|
457
|
+
}
|
|
458
|
+
case SCR_DYN_ARR: {
|
|
459
|
+
if (a->v.arr.len != b->v.arr.len) return false;
|
|
460
|
+
for (size_t i = 0; i < a->v.arr.len; i++) {
|
|
461
|
+
if (!scr_assert_dyn_deep_eq(a->v.arr.items[i], b->v.arr.items[i])) return false;
|
|
462
|
+
}
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
case SCR_DYN_OBJ: {
|
|
466
|
+
if (a->v.obj.len != b->v.obj.len) return false;
|
|
467
|
+
for (size_t i = 0; i < a->v.obj.len; i++) {
|
|
468
|
+
const ScrDynEntry *ent = &a->v.obj.entries[i];
|
|
469
|
+
ScrDyn *bv = scr_dyn_obj_get(b, ent->key, ent->key_len);
|
|
470
|
+
if (!bv || !scr_assert_dyn_deep_eq(ent->value, bv)) return false;
|
|
471
|
+
}
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return false; /* unreachable */
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/* ── inspectValue over the DOM (assertion_error.js's inspect options:
|
|
479
|
+
* compact:false, sorted:true, depth 1000, maxArrayLength Infinity) ───── */
|
|
480
|
+
|
|
481
|
+
#define SCR_ASSERT_CF_DEPTH 1000
|
|
482
|
+
|
|
483
|
+
static void scr_assert_cf_pad(ScrAssertBuf *b, size_t n) {
|
|
484
|
+
ab_grow(b, n);
|
|
485
|
+
memset(b->data + b->len, ' ', n);
|
|
486
|
+
b->len += n;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* Property-key rendering: __proto__ bracketed, identifier-shaped keys
|
|
490
|
+
* bare (the scr_inspect.c ladder), everything else inspect-quoted. */
|
|
491
|
+
static void scr_assert_cf_key(ScrAssertBuf *b, const char *key, size_t len) {
|
|
492
|
+
if (len == 9 && memcmp(key, "__proto__", 9) == 0) {
|
|
493
|
+
ab_cstr(b, "['__proto__']");
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
bool bare = len > 0;
|
|
497
|
+
for (size_t i = 0; bare && i < len; i++) {
|
|
498
|
+
char c = key[i];
|
|
499
|
+
bool head_ok = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
|
500
|
+
bool tail_ok = head_ok || (c >= '0' && c <= '9');
|
|
501
|
+
bare = i == 0 ? head_ok : tail_ok;
|
|
502
|
+
}
|
|
503
|
+
if (bare) {
|
|
504
|
+
ab_bytes(b, key, len);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
ScrStr *raw = scr_str_new(key, len);
|
|
508
|
+
ScrStr *q = scr_assert_inspect_str(raw);
|
|
509
|
+
ab_str(b, q);
|
|
510
|
+
scr_str_release(q);
|
|
511
|
+
scr_str_release(raw);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* One rendered object entry, for sorting before emission. */
|
|
515
|
+
typedef struct {
|
|
516
|
+
char *text;
|
|
517
|
+
size_t len;
|
|
518
|
+
} ScrCfEntry;
|
|
519
|
+
|
|
520
|
+
static int scr_assert_cf_entry_cmp(const void *pa, const void *pb) {
|
|
521
|
+
const ScrCfEntry *a = pa, *b = pb;
|
|
522
|
+
size_t n = a->len < b->len ? a->len : b->len;
|
|
523
|
+
int c = n ? memcmp(a->text, b->text, n) : 0;
|
|
524
|
+
if (c) return c;
|
|
525
|
+
return a->len < b->len ? -1 : (a->len > b->len ? 1 : 0);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/* Renders `d` at `indent` (the column its CONTINUATION lines start at);
|
|
529
|
+
* the first line is appended in place. */
|
|
530
|
+
static void scr_assert_cf_value(ScrAssertBuf *b, const ScrDyn *d, size_t indent,
|
|
531
|
+
size_t depth) {
|
|
532
|
+
switch (d->kind) {
|
|
533
|
+
case SCR_DYN_UNDEF:
|
|
534
|
+
ab_cstr(b, "undefined");
|
|
535
|
+
return;
|
|
536
|
+
case SCR_DYN_NULL:
|
|
537
|
+
ab_cstr(b, "null");
|
|
538
|
+
return;
|
|
539
|
+
case SCR_DYN_BOOL:
|
|
540
|
+
ab_cstr(b, d->v.b ? "true" : "false");
|
|
541
|
+
return;
|
|
542
|
+
case SCR_DYN_NUM: {
|
|
543
|
+
char tmp[40];
|
|
544
|
+
size_t n = scr_assert_inspect_f64(d->v.num, tmp);
|
|
545
|
+
ab_bytes(b, tmp, n);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
case SCR_DYN_STR: {
|
|
549
|
+
ScrStr *q = scr_assert_inspect_str(d->v.str);
|
|
550
|
+
ab_str(b, q);
|
|
551
|
+
scr_str_release(q);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
case SCR_DYN_FUNC: {
|
|
555
|
+
const char *name = d->v.fn.name;
|
|
556
|
+
if (name && name[0]) {
|
|
557
|
+
ab_cstr(b, "[Function: ");
|
|
558
|
+
ab_cstr(b, name);
|
|
559
|
+
ab_char(b, ']');
|
|
560
|
+
} else {
|
|
561
|
+
ab_cstr(b, "[Function (anonymous)]");
|
|
562
|
+
}
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
case SCR_DYN_HANDLE: {
|
|
566
|
+
/* The depth-elided class form ([ServerResponse]) — the full own-
|
|
567
|
+
* property dump Node renders is internals we do not model; this
|
|
568
|
+
* text only appears inside FAILURE diffs, which already diverge in
|
|
569
|
+
* report format. */
|
|
570
|
+
ab_char(b, '[');
|
|
571
|
+
ab_cstr(b, scr_dyn_handle_cls(d));
|
|
572
|
+
ab_char(b, ']');
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
case SCR_DYN_PROMISE: {
|
|
576
|
+
/* The depth-elided form (Node renders Promise { <state> }; failure
|
|
577
|
+
* diffs already diverge in report format — the handle stance). */
|
|
578
|
+
ab_cstr(b, "[Promise]");
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
case SCR_DYN_BYTES: {
|
|
582
|
+
const ScrBytes *bs = d->v.bytes;
|
|
583
|
+
char prefix[64];
|
|
584
|
+
int pn = snprintf(prefix, sizeof prefix, "%s(%zu) %s[",
|
|
585
|
+
d->buffer ? "Buffer" : "Uint8Array", bs->len,
|
|
586
|
+
d->buffer ? "[Uint8Array] " : "");
|
|
587
|
+
ab_bytes(b, prefix, (size_t)pn);
|
|
588
|
+
if (bs->len == 0) {
|
|
589
|
+
ab_char(b, ']');
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
for (size_t i = 0; i < bs->len; i++) {
|
|
593
|
+
ab_char(b, '\n');
|
|
594
|
+
scr_assert_cf_pad(b, indent + 2);
|
|
595
|
+
char tmp[40];
|
|
596
|
+
size_t n = scr_assert_inspect_f64((double)((const unsigned char *)bs->data)[i], tmp);
|
|
597
|
+
ab_bytes(b, tmp, n);
|
|
598
|
+
if (i + 1 < bs->len) ab_char(b, ',');
|
|
599
|
+
}
|
|
600
|
+
ab_char(b, '\n');
|
|
601
|
+
scr_assert_cf_pad(b, indent);
|
|
602
|
+
ab_char(b, ']');
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
case SCR_DYN_ARR: {
|
|
606
|
+
if (d->v.arr.len == 0) {
|
|
607
|
+
ab_cstr(b, "[]");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (depth == 0) {
|
|
611
|
+
ab_cstr(b, "[Array]");
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
ab_char(b, '[');
|
|
615
|
+
for (size_t i = 0; i < d->v.arr.len; i++) {
|
|
616
|
+
ab_char(b, '\n');
|
|
617
|
+
scr_assert_cf_pad(b, indent + 2);
|
|
618
|
+
scr_assert_cf_value(b, d->v.arr.items[i], indent + 2, depth - 1);
|
|
619
|
+
if (i + 1 < d->v.arr.len) ab_char(b, ',');
|
|
620
|
+
}
|
|
621
|
+
ab_char(b, '\n');
|
|
622
|
+
scr_assert_cf_pad(b, indent);
|
|
623
|
+
ab_char(b, ']');
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
case SCR_DYN_OBJ: {
|
|
627
|
+
if (d->v.obj.len == 0) {
|
|
628
|
+
ab_cstr(b, "{}");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (depth == 0) {
|
|
632
|
+
ab_cstr(b, "[Object]");
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
/* Render every entry, then sort the RENDERED texts (Node's
|
|
636
|
+
* sorted:true sorts formatted entries, quotes included). */
|
|
637
|
+
ScrCfEntry *ents = malloc(d->v.obj.len * sizeof *ents);
|
|
638
|
+
if (!ents) scr_assert_oom();
|
|
639
|
+
for (size_t i = 0; i < d->v.obj.len; i++) {
|
|
640
|
+
const ScrDynEntry *ent = &d->v.obj.entries[i];
|
|
641
|
+
ScrAssertBuf eb = {0};
|
|
642
|
+
scr_assert_cf_key(&eb, ent->key, ent->key_len);
|
|
643
|
+
ab_cstr(&eb, ": ");
|
|
644
|
+
scr_assert_cf_value(&eb, ent->value, indent + 2, depth - 1);
|
|
645
|
+
ents[i].text = eb.data ? eb.data : malloc(1);
|
|
646
|
+
if (!ents[i].text) scr_assert_oom();
|
|
647
|
+
ents[i].len = eb.len;
|
|
648
|
+
}
|
|
649
|
+
qsort(ents, d->v.obj.len, sizeof *ents, scr_assert_cf_entry_cmp);
|
|
650
|
+
ab_char(b, '{');
|
|
651
|
+
for (size_t i = 0; i < d->v.obj.len; i++) {
|
|
652
|
+
ab_char(b, '\n');
|
|
653
|
+
scr_assert_cf_pad(b, indent + 2);
|
|
654
|
+
ab_bytes(b, ents[i].text, ents[i].len);
|
|
655
|
+
if (i + 1 < d->v.obj.len) ab_char(b, ',');
|
|
656
|
+
free(ents[i].text);
|
|
657
|
+
}
|
|
658
|
+
free(ents);
|
|
659
|
+
ab_char(b, '\n');
|
|
660
|
+
scr_assert_cf_pad(b, indent);
|
|
661
|
+
ab_char(b, '}');
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
static ScrStr *scr_assert_cf_inspect(const ScrDyn *d) {
|
|
668
|
+
ScrAssertBuf b = {0};
|
|
669
|
+
scr_assert_cf_value(&b, d, 0, SCR_ASSERT_CF_DEPTH);
|
|
670
|
+
return ab_take(&b);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/* ── the myers line diff (internal/assert/myers_diff.js) ─────────────── */
|
|
674
|
+
|
|
675
|
+
typedef struct {
|
|
676
|
+
const char *s;
|
|
677
|
+
size_t len;
|
|
678
|
+
} ScrLine;
|
|
679
|
+
|
|
680
|
+
/* Splits rendered text into lines (no trailing-newline convention: the
|
|
681
|
+
* renderer never emits a final \n, matching String.prototype.split). */
|
|
682
|
+
static ScrLine *scr_assert_split_lines(const ScrStr *text, size_t *out_n) {
|
|
683
|
+
size_t n = 1;
|
|
684
|
+
for (size_t i = 0; i < text->len; i++) {
|
|
685
|
+
if (text->data[i] == '\n') n++;
|
|
686
|
+
}
|
|
687
|
+
ScrLine *lines = malloc(n * sizeof *lines);
|
|
688
|
+
if (!lines) scr_assert_oom();
|
|
689
|
+
size_t li = 0, start = 0;
|
|
690
|
+
for (size_t i = 0; i <= text->len; i++) {
|
|
691
|
+
if (i == text->len || text->data[i] == '\n') {
|
|
692
|
+
lines[li].s = text->data + start;
|
|
693
|
+
lines[li].len = i - start;
|
|
694
|
+
li++;
|
|
695
|
+
start = i + 1;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
*out_n = n;
|
|
699
|
+
return lines;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/* areLinesEqual with the comma-disparity rule: object lines differing
|
|
703
|
+
* only by a trailing comma count as equal. */
|
|
704
|
+
static bool scr_assert_lines_eq(ScrLine a, ScrLine b, bool comma) {
|
|
705
|
+
if (a.len == b.len && (a.len == 0 || memcmp(a.s, b.s, a.len) == 0)) return true;
|
|
706
|
+
if (!comma) return false;
|
|
707
|
+
if (a.len + 1 == b.len && b.s[b.len - 1] == ',' &&
|
|
708
|
+
(a.len == 0 || memcmp(a.s, b.s, a.len) == 0))
|
|
709
|
+
return true;
|
|
710
|
+
if (b.len + 1 == a.len && a.s[a.len - 1] == ',' &&
|
|
711
|
+
(b.len == 0 || memcmp(a.s, b.s, b.len) == 0))
|
|
712
|
+
return true;
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
typedef struct {
|
|
717
|
+
int8_t op; /* 1 INSERT (actual), -1 DELETE (expected), 0 NOP */
|
|
718
|
+
ScrLine line;
|
|
719
|
+
} ScrDiffOp;
|
|
720
|
+
|
|
721
|
+
/* The greedy O((N+M)·D) forward walk plus backtrack — a straight port of
|
|
722
|
+
* myersDiff/backtrack. The result array is in REVERSE document order
|
|
723
|
+
* (built back-to-front, like Node's), so the printer walks it from the
|
|
724
|
+
* end. Returns NULL when the inputs exceed the line cap (the caller falls
|
|
725
|
+
* back to the whole-value form). */
|
|
726
|
+
#define SCR_ASSERT_MYERS_CAP 4096
|
|
727
|
+
|
|
728
|
+
static ScrDiffOp *scr_assert_myers(ScrLine *a, size_t an, ScrLine *b, size_t bn,
|
|
729
|
+
bool comma, size_t *out_n) {
|
|
730
|
+
size_t max = an + bn;
|
|
731
|
+
if (max == 0 || max > SCR_ASSERT_MYERS_CAP) return NULL;
|
|
732
|
+
size_t width = 2 * max + 1;
|
|
733
|
+
int32_t *v = calloc(width, sizeof *v);
|
|
734
|
+
int32_t **trace = malloc((max + 1) * sizeof *trace);
|
|
735
|
+
if (!v || !trace) scr_assert_oom();
|
|
736
|
+
size_t traceN = 0;
|
|
737
|
+
size_t foundLevel = 0;
|
|
738
|
+
bool found = false;
|
|
739
|
+
for (size_t d = 0; d <= max && !found; d++) {
|
|
740
|
+
int32_t *snap = malloc(width * sizeof *snap);
|
|
741
|
+
if (!snap) scr_assert_oom();
|
|
742
|
+
memcpy(snap, v, width * sizeof *snap);
|
|
743
|
+
trace[traceN++] = snap;
|
|
744
|
+
for (long k = -(long)d; k <= (long)d; k += 2) {
|
|
745
|
+
size_t off = (size_t)(k + (long)max);
|
|
746
|
+
long x;
|
|
747
|
+
if (k == -(long)d || (k != (long)d && v[off - 1] < v[off + 1])) {
|
|
748
|
+
x = v[off + 1];
|
|
749
|
+
} else {
|
|
750
|
+
x = v[off - 1] + 1;
|
|
751
|
+
}
|
|
752
|
+
long y = x - k;
|
|
753
|
+
while (x < (long)an && y < (long)bn && scr_assert_lines_eq(a[x], b[y], comma)) {
|
|
754
|
+
x++;
|
|
755
|
+
y++;
|
|
756
|
+
}
|
|
757
|
+
v[off] = (int32_t)x;
|
|
758
|
+
if (x >= (long)an && y >= (long)bn) {
|
|
759
|
+
foundLevel = d;
|
|
760
|
+
found = true;
|
|
761
|
+
break;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
free(v);
|
|
766
|
+
if (!found) { /* unreachable: D <= max always terminates */
|
|
767
|
+
for (size_t i = 0; i < traceN; i++) free(trace[i]);
|
|
768
|
+
free(trace);
|
|
769
|
+
return NULL;
|
|
770
|
+
}
|
|
771
|
+
ScrDiffOp *result = malloc((an + bn + 1) * sizeof *result);
|
|
772
|
+
if (!result) scr_assert_oom();
|
|
773
|
+
size_t rn = 0;
|
|
774
|
+
long x = (long)an, y = (long)bn;
|
|
775
|
+
for (long level = (long)foundLevel; level >= 0; level--) {
|
|
776
|
+
int32_t *vv = trace[level];
|
|
777
|
+
long k = x - y;
|
|
778
|
+
long prevK;
|
|
779
|
+
if (k == -level || (k != level && vv[k + (long)max - 1] < vv[k + (long)max + 1])) {
|
|
780
|
+
prevK = k + 1;
|
|
781
|
+
} else {
|
|
782
|
+
prevK = k - 1;
|
|
783
|
+
}
|
|
784
|
+
long prevX = vv[prevK + (long)max];
|
|
785
|
+
long prevY = prevX - prevK;
|
|
786
|
+
while (x > prevX && y > prevY) {
|
|
787
|
+
ScrLine ai = a[x - 1];
|
|
788
|
+
bool aComma = ai.len > 0 && ai.s[ai.len - 1] == ',';
|
|
789
|
+
result[rn].op = 0;
|
|
790
|
+
result[rn].line = (comma && !aComma) ? b[y - 1] : ai;
|
|
791
|
+
rn++;
|
|
792
|
+
x--;
|
|
793
|
+
y--;
|
|
794
|
+
}
|
|
795
|
+
if (level > 0) {
|
|
796
|
+
if (x > prevX) {
|
|
797
|
+
x--;
|
|
798
|
+
result[rn].op = 1;
|
|
799
|
+
result[rn].line = a[x];
|
|
800
|
+
} else {
|
|
801
|
+
y--;
|
|
802
|
+
result[rn].op = -1;
|
|
803
|
+
result[rn].line = b[y];
|
|
804
|
+
}
|
|
805
|
+
rn++;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
for (size_t i = 0; i < traceN; i++) free(trace[i]);
|
|
809
|
+
free(trace);
|
|
810
|
+
*out_n = rn;
|
|
811
|
+
return result;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
static void scr_assert_line_out(ScrAssertBuf *b, const char *prefix, ScrLine l) {
|
|
815
|
+
ab_cstr(b, prefix);
|
|
816
|
+
ab_bytes(b, l.s, l.len);
|
|
817
|
+
ab_char(b, '\n');
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/* printMyersDiff: document order (the diff array reversed), 5 context
|
|
821
|
+
* lines per common run, then "..." plus the run's last line and the
|
|
822
|
+
* skipped flag. Trailing common lines past the window drop silently —
|
|
823
|
+
* Node's printer does the same. The message lands WITHOUT its leading
|
|
824
|
+
* newline (the caller places it); trailing whitespace trimmed. */
|
|
825
|
+
static bool scr_assert_print_myers(ScrAssertBuf *b, const ScrDiffOp *diff, size_t n) {
|
|
826
|
+
bool skipped = false;
|
|
827
|
+
size_t nopCount = 0;
|
|
828
|
+
size_t startLen = b->len;
|
|
829
|
+
for (size_t i = n; i-- > 0;) {
|
|
830
|
+
int8_t op = diff[i].op;
|
|
831
|
+
bool hasPrev = i + 1 < n;
|
|
832
|
+
if (hasPrev && diff[i + 1].op == 0 && op != 0) {
|
|
833
|
+
if (nopCount == 6) {
|
|
834
|
+
scr_assert_line_out(b, " ", diff[i + 1].line);
|
|
835
|
+
} else if (nopCount == 7) {
|
|
836
|
+
scr_assert_line_out(b, " ", diff[i + 2].line);
|
|
837
|
+
scr_assert_line_out(b, " ", diff[i + 1].line);
|
|
838
|
+
} else if (nopCount >= 8) {
|
|
839
|
+
ab_cstr(b, "...\n");
|
|
840
|
+
scr_assert_line_out(b, " ", diff[i + 1].line);
|
|
841
|
+
skipped = true;
|
|
842
|
+
}
|
|
843
|
+
nopCount = 0;
|
|
844
|
+
}
|
|
845
|
+
if (op == 1) {
|
|
846
|
+
scr_assert_line_out(b, "+ ", diff[i].line);
|
|
847
|
+
} else if (op == -1) {
|
|
848
|
+
scr_assert_line_out(b, "- ", diff[i].line);
|
|
849
|
+
} else {
|
|
850
|
+
if (nopCount < 5) scr_assert_line_out(b, " ", diff[i].line);
|
|
851
|
+
nopCount++;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
while (b->len > startLen &&
|
|
855
|
+
(b->data[b->len - 1] == '\n' || b->data[b->len - 1] == ' ')) {
|
|
856
|
+
b->len--; /* trimEnd */
|
|
857
|
+
}
|
|
858
|
+
return skipped;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/* ── the dyn entry point ─────────────────────────────────────────────── */
|
|
862
|
+
|
|
863
|
+
/* Is this DOM kind `typeof == "object" && != null` to assertion_error.js? */
|
|
864
|
+
static bool scr_assert_dyn_is_object(const ScrDyn *d) {
|
|
865
|
+
return d->kind == SCR_DYN_ARR || d->kind == SCR_DYN_OBJ || d->kind == SCR_DYN_BYTES ||
|
|
866
|
+
d->kind == SCR_DYN_HANDLE || d->kind == SCR_DYN_PROMISE;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/* The failing EQUAL operators over dyn operands — createErrDiff. */
|
|
870
|
+
static void scr_assert_dyn_eq_fail(ScrDyn *a, ScrDyn *b, bool deep,
|
|
871
|
+
ScrStr *msg, bool has_msg) {
|
|
872
|
+
/* checkOperator: strictEqual over two objects (or two functions)
|
|
873
|
+
* reports the reference-equality expectation. */
|
|
874
|
+
bool objOp = !deep && ((scr_assert_dyn_is_object(a) && scr_assert_dyn_is_object(b)) ||
|
|
875
|
+
(a->kind == SCR_DYN_FUNC && b->kind == SCR_DYN_FUNC));
|
|
876
|
+
const char *header =
|
|
877
|
+
deep ? "Expected values to be strictly deep-equal:"
|
|
878
|
+
: (objOp ? "Expected \"actual\" to be reference-equal to \"expected\":"
|
|
879
|
+
: "Expected values to be strictly equal:");
|
|
880
|
+
ScrStr *ia = scr_assert_cf_inspect(a);
|
|
881
|
+
ScrStr *ib = scr_assert_cf_inspect(b);
|
|
882
|
+
size_t an, en;
|
|
883
|
+
ScrLine *alines = scr_assert_split_lines(ia, &an);
|
|
884
|
+
ScrLine *elines = scr_assert_split_lines(ib, &en);
|
|
885
|
+
ScrAssertBuf out = {0};
|
|
886
|
+
const char *customOrHeader = header; /* resolved after operator morphing */
|
|
887
|
+
bool simple = an == 1 && en == 1 &&
|
|
888
|
+
(!scr_assert_dyn_is_object(a) || !scr_assert_dyn_is_object(b));
|
|
889
|
+
bool inspEq = ia->len == ib->len && memcmp(ia->data, ib->data, ia->len) == 0;
|
|
890
|
+
|
|
891
|
+
if (simple) {
|
|
892
|
+
if (has_msg && msg->len > 0) {
|
|
893
|
+
ab_str(&out, msg);
|
|
894
|
+
} else {
|
|
895
|
+
ab_cstr(&out, customOrHeader);
|
|
896
|
+
}
|
|
897
|
+
size_t la = ia->len, lb = ib->len;
|
|
898
|
+
size_t stringsLen = la + lb;
|
|
899
|
+
if (a->kind == SCR_DYN_STR) stringsLen -= 2;
|
|
900
|
+
if (b->kind == SCR_DYN_STR) stringsLen -= 2;
|
|
901
|
+
bool bothZero = a->kind == SCR_DYN_NUM && b->kind == SCR_DYN_NUM &&
|
|
902
|
+
a->v.num == 0.0 && b->v.num == 0.0;
|
|
903
|
+
if (stringsLen <= 12 && !bothZero) {
|
|
904
|
+
ab_cstr(&out, "\n\n");
|
|
905
|
+
ab_str(&out, ia);
|
|
906
|
+
ab_cstr(&out, " !== ");
|
|
907
|
+
ab_str(&out, ib);
|
|
908
|
+
ab_cstr(&out, "\n");
|
|
909
|
+
} else {
|
|
910
|
+
ab_cstr(&out, "\n+ actual - expected\n\n+ ");
|
|
911
|
+
ab_str(&out, ia);
|
|
912
|
+
ab_cstr(&out, "\n- ");
|
|
913
|
+
ab_str(&out, ib);
|
|
914
|
+
/* getStackedDiff's ^ indicator runs over the INSPECTED text of
|
|
915
|
+
* every simple stacked diff (its typeof-string test sees the
|
|
916
|
+
* rendered strings), all kinds included. */
|
|
917
|
+
if (la + lb <= 80) {
|
|
918
|
+
size_t i = 0;
|
|
919
|
+
while (i < la && i < lb && ia->data[i] == ib->data[i]) i++;
|
|
920
|
+
if (i < la && i >= 3) {
|
|
921
|
+
ab_char(&out, '\n');
|
|
922
|
+
for (size_t k = 0; k < i + 2; k++) ab_char(&out, ' ');
|
|
923
|
+
ab_char(&out, '^');
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
ab_cstr(&out, "\n");
|
|
927
|
+
}
|
|
928
|
+
} else if (inspEq) {
|
|
929
|
+
/* Structurally identical renderings that are not the same reference:
|
|
930
|
+
* the notIdentical banner over the single rendering. */
|
|
931
|
+
const char *ident = "Values have same structure but are not reference-equal:";
|
|
932
|
+
if (has_msg && msg->len > 0) {
|
|
933
|
+
ab_str(&out, msg);
|
|
934
|
+
} else {
|
|
935
|
+
ab_cstr(&out, ident);
|
|
936
|
+
}
|
|
937
|
+
ab_cstr(&out, "\n");
|
|
938
|
+
if (an > 50) {
|
|
939
|
+
ab_cstr(&out, "\n... Skipped lines");
|
|
940
|
+
ab_cstr(&out, "\n");
|
|
941
|
+
for (size_t i = 0; i < 50; i++) {
|
|
942
|
+
ab_bytes(&out, alines[i].s, alines[i].len);
|
|
943
|
+
ab_char(&out, '\n');
|
|
944
|
+
}
|
|
945
|
+
ab_cstr(&out, "...}\n");
|
|
946
|
+
} else {
|
|
947
|
+
ab_cstr(&out, "\n");
|
|
948
|
+
ab_str(&out, ia);
|
|
949
|
+
ab_cstr(&out, "\n");
|
|
950
|
+
}
|
|
951
|
+
} else {
|
|
952
|
+
/* The myers line diff with Node's printer. checkCommaDisparity is
|
|
953
|
+
* Node's `actual != null && typeof actual === 'object'`. */
|
|
954
|
+
bool comma = scr_assert_dyn_is_object(a);
|
|
955
|
+
size_t dn = 0;
|
|
956
|
+
ScrDiffOp *diff = scr_assert_myers(alines, an, elines, en, comma, &dn);
|
|
957
|
+
if (has_msg && msg->len > 0) {
|
|
958
|
+
ab_str(&out, msg);
|
|
959
|
+
} else {
|
|
960
|
+
ab_cstr(&out, customOrHeader);
|
|
961
|
+
}
|
|
962
|
+
ab_cstr(&out, "\n+ actual - expected");
|
|
963
|
+
if (diff) {
|
|
964
|
+
ScrAssertBuf body = {0};
|
|
965
|
+
bool skipped = scr_assert_print_myers(&body, diff, dn);
|
|
966
|
+
if (skipped) ab_cstr(&out, "\n... Skipped lines");
|
|
967
|
+
ab_cstr(&out, "\n\n");
|
|
968
|
+
ab_bytes(&out, body.data ? body.data : "", body.len);
|
|
969
|
+
ab_cstr(&out, "\n");
|
|
970
|
+
free(body.data);
|
|
971
|
+
free(diff);
|
|
972
|
+
} else {
|
|
973
|
+
/* Past the line cap: the whole-value fallback (documented). */
|
|
974
|
+
ab_cstr(&out, "\n\n");
|
|
975
|
+
for (size_t i = 0; i < an; i++) scr_assert_line_out(&out, "+ ", alines[i]);
|
|
976
|
+
for (size_t i = 0; i < en; i++) {
|
|
977
|
+
ab_cstr(&out, "- ");
|
|
978
|
+
ab_bytes(&out, elines[i].s, elines[i].len);
|
|
979
|
+
if (i + 1 < en) ab_char(&out, '\n');
|
|
980
|
+
}
|
|
981
|
+
ab_cstr(&out, "\n");
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
free(alines);
|
|
985
|
+
free(elines);
|
|
986
|
+
scr_str_release(ia);
|
|
987
|
+
scr_str_release(ib);
|
|
988
|
+
scr_assert_fail_msg(ab_take(&out));
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/* The failing NOT-equal operators over dyn operands (values compared
|
|
992
|
+
* same): a custom message stands alone; the generated one renders the
|
|
993
|
+
* actual value under the operator's banner (the object banner for
|
|
994
|
+
* notStrictEqual over objects/functions), inline when a single short
|
|
995
|
+
* line, block form otherwise, >50-line renderings collapsed. */
|
|
996
|
+
static void scr_assert_dyn_neq_fail(ScrDyn *a, bool deep, ScrStr *msg, bool has_msg) {
|
|
997
|
+
if (has_msg) {
|
|
998
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
const char *base =
|
|
1002
|
+
deep ? "Expected \"actual\" not to be strictly deep-equal to:"
|
|
1003
|
+
: ((scr_assert_dyn_is_object(a) || a->kind == SCR_DYN_FUNC)
|
|
1004
|
+
? "Expected \"actual\" not to be reference-equal to \"expected\":"
|
|
1005
|
+
: "Expected \"actual\" to be strictly unequal to:");
|
|
1006
|
+
ScrStr *ia = scr_assert_cf_inspect(a);
|
|
1007
|
+
size_t an;
|
|
1008
|
+
ScrLine *lines = scr_assert_split_lines(ia, &an);
|
|
1009
|
+
ScrAssertBuf out = {0};
|
|
1010
|
+
ab_cstr(&out, base);
|
|
1011
|
+
if (an == 1) {
|
|
1012
|
+
ab_cstr(&out, lines[0].len > 5 ? "\n\n" : " ");
|
|
1013
|
+
ab_str(&out, ia);
|
|
1014
|
+
} else {
|
|
1015
|
+
ab_cstr(&out, "\n\n");
|
|
1016
|
+
/* res.length > 50: line 47 becomes "..." and the rest drop. */
|
|
1017
|
+
size_t shown = an > 50 ? 47 : an;
|
|
1018
|
+
for (size_t i = 0; i < shown; i++) {
|
|
1019
|
+
if (an > 50 && i == 46) {
|
|
1020
|
+
ab_cstr(&out, "...");
|
|
1021
|
+
} else {
|
|
1022
|
+
ab_bytes(&out, lines[i].s, lines[i].len);
|
|
1023
|
+
}
|
|
1024
|
+
ab_char(&out, '\n');
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
free(lines);
|
|
1028
|
+
scr_str_release(ia);
|
|
1029
|
+
scr_assert_fail_msg(ab_take(&out));
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/* strictEqual / notStrictEqual / deepStrictEqual / notDeepStrictEqual
|
|
1033
|
+
* where either operand is a checked-dynamic value (both arrive as DOM
|
|
1034
|
+
* values — the frontend boxes a static side). Borrows everything. */
|
|
1035
|
+
void scr_assert_eq_dyn(ScrDyn *a, ScrDyn *b, bool negated, bool deep,
|
|
1036
|
+
ScrStr *msg, bool has_msg) {
|
|
1037
|
+
bool same = deep ? scr_assert_dyn_deep_eq(a, b) : scr_assert_dyn_same_value(a, b);
|
|
1038
|
+
if ((negated && !same) || (!negated && same)) return;
|
|
1039
|
+
if (negated) {
|
|
1040
|
+
scr_assert_dyn_neq_fail(a, deep, msg, has_msg);
|
|
1041
|
+
} else {
|
|
1042
|
+
scr_assert_dyn_eq_fail(a, b, deep, msg, has_msg);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/* Node's expectsError over an error-INSTANCE expected (assert.throws/
|
|
1047
|
+
* rejects second argument): every key of the expected DOM error (the
|
|
1048
|
+
* %error marker skipped; name/message/code is the encoding's surface)
|
|
1049
|
+
* must deep-strict-equal the caught value's — extra ACTUAL keys are fine
|
|
1050
|
+
* (Node walks the expected's keys only). A mismatch fails through the
|
|
1051
|
+
* deep-equal report (a mismatched key implies the full comparison
|
|
1052
|
+
* differs, so the diff is honest); a non-object pair falls back to the
|
|
1053
|
+
* full deep comparison outright. */
|
|
1054
|
+
void scr_assert_expects_err_dyn(ScrDyn *actual, ScrDyn *expected, ScrStr *msg, bool has_msg) {
|
|
1055
|
+
if (actual->kind == SCR_DYN_OBJ && expected->kind == SCR_DYN_OBJ) {
|
|
1056
|
+
bool ok = true;
|
|
1057
|
+
for (size_t i = 0; i < expected->v.obj.len && ok; i++) {
|
|
1058
|
+
const ScrDynEntry *e = &expected->v.obj.entries[i];
|
|
1059
|
+
if (e->key_len == 6 && memcmp(e->key, "%error", 6) == 0) continue;
|
|
1060
|
+
ScrDyn *av = scr_dyn_obj_get(actual, e->key, e->key_len);
|
|
1061
|
+
if (av == NULL || !scr_assert_dyn_deep_eq(av, e->value)) ok = false;
|
|
1062
|
+
}
|
|
1063
|
+
if (ok) return;
|
|
1064
|
+
}
|
|
1065
|
+
scr_assert_eq_dyn(actual, expected, false, true, msg, has_msg);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/* assert.throws(fn) that did NOT throw / assert.rejects whose promise
|
|
1069
|
+
* fulfilled: "Missing expected exception|rejection" with Node's details —
|
|
1070
|
+
* ` (${expected.name})` when the expected class or shape carries a name,
|
|
1071
|
+
* then `: message` or `.` (expectsError's NO_EXCEPTION_SENTINEL arm). */
|
|
1072
|
+
void scr_assert_throws_none(bool rejection, ScrStr *ename, bool has_ename,
|
|
1073
|
+
ScrStr *msg, bool has_msg) {
|
|
1074
|
+
ScrAssertBuf b = {0};
|
|
1075
|
+
ab_cstr(&b, rejection ? "Missing expected rejection" : "Missing expected exception");
|
|
1076
|
+
if (has_ename) {
|
|
1077
|
+
ab_cstr(&b, " (");
|
|
1078
|
+
ab_str(&b, ename);
|
|
1079
|
+
ab_char(&b, ')');
|
|
1080
|
+
}
|
|
1081
|
+
if (has_msg) {
|
|
1082
|
+
ab_cstr(&b, ": ");
|
|
1083
|
+
ab_str(&b, msg);
|
|
1084
|
+
} else {
|
|
1085
|
+
ab_cstr(&b, ".");
|
|
1086
|
+
}
|
|
1087
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/* assert.throws(fn, ErrorClass) where the thrown Error is NOT an instance
|
|
1091
|
+
* of the expected class: Node's mismatch AssertionError, built from the
|
|
1092
|
+
* received error's name and message. (Node prefers constructor.name; this
|
|
1093
|
+
* runtime carries the `name` slot — identical for the builtin hierarchy,
|
|
1094
|
+
* SEMANTICS.md 105 for subclasses whose constructor name differs.)
|
|
1095
|
+
* Borrows both. */
|
|
1096
|
+
void scr_assert_throws_mismatch(ScrStr *expected_name, ScrError *err,
|
|
1097
|
+
ScrStr *msg, bool has_msg) {
|
|
1098
|
+
if (has_msg) {
|
|
1099
|
+
/* A custom message stands alone (Node's innerFail with the user's
|
|
1100
|
+
* message — the instance-of text is the generated form only). */
|
|
1101
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
ScrAssertBuf b = {0};
|
|
1105
|
+
ab_cstr(&b, "The error is expected to be an instance of \"");
|
|
1106
|
+
ab_str(&b, expected_name);
|
|
1107
|
+
ab_cstr(&b, "\". Received \"");
|
|
1108
|
+
if (err->name) ab_str(&b, err->name);
|
|
1109
|
+
ab_char(&b, '"');
|
|
1110
|
+
if (err->message && err->message->len > 0) {
|
|
1111
|
+
ab_cstr(&b, "\n\nError message:\n\n");
|
|
1112
|
+
ab_str(&b, err->message);
|
|
1113
|
+
}
|
|
1114
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
/* ── assert.throws(fn, <object shape>) — expectedException over the
|
|
1118
|
+
* static error surface ─────────────────────────────────────────────────
|
|
1119
|
+
* Node compares each own key of the expected object against the thrown
|
|
1120
|
+
* error: strings by deep-equal (byte equality here), regex values by
|
|
1121
|
+
* test against the actual string. The bounded key set (name/message/
|
|
1122
|
+
* code — everything the static surface carries) makes Node's generated
|
|
1123
|
+
* failure message — a deep-equal diff of two `Comparison` placeholder
|
|
1124
|
+
* objects, keys in inspect's SORTED order (code < message < name), a
|
|
1125
|
+
* regex-valued key that MATCHED rendering as the actual's own value on
|
|
1126
|
+
* both sides — fully enumerable, so the rendering is byte-exact, not
|
|
1127
|
+
* header-only. The accumulator is a static: the begin/slot/end calls are
|
|
1128
|
+
* straight-line inside one synthesized helper, no suspension between. */
|
|
1129
|
+
|
|
1130
|
+
enum { SHAPE_CODE = 0, SHAPE_MESSAGE = 1, SHAPE_NAME = 2 };
|
|
1131
|
+
|
|
1132
|
+
typedef struct {
|
|
1133
|
+
bool present;
|
|
1134
|
+
bool is_re;
|
|
1135
|
+
bool re_matched;
|
|
1136
|
+
ScrStr *val; /* owned: the string value, or the regex's /source/flags */
|
|
1137
|
+
} ScrShapeSlot;
|
|
1138
|
+
|
|
1139
|
+
static struct {
|
|
1140
|
+
ScrError *err; /* borrowed — alive across the straight-line sequence */
|
|
1141
|
+
ScrShapeSlot slots[3];
|
|
1142
|
+
} scr_shape;
|
|
1143
|
+
|
|
1144
|
+
static void scr_shape_clear(void) {
|
|
1145
|
+
for (int k = 0; k < 3; k++) {
|
|
1146
|
+
if (scr_shape.slots[k].val) scr_str_release(scr_shape.slots[k].val);
|
|
1147
|
+
scr_shape.slots[k] = (ScrShapeSlot){0};
|
|
1148
|
+
}
|
|
1149
|
+
scr_shape.err = NULL;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
void scr_assert_shape_begin(ScrError *err) {
|
|
1153
|
+
scr_shape_clear();
|
|
1154
|
+
scr_shape.err = err;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
void scr_assert_shape_str(int key, ScrStr *v) {
|
|
1158
|
+
scr_shape.slots[key] = (ScrShapeSlot){
|
|
1159
|
+
.present = true, .is_re = false, .re_matched = false, .val = scr_str_retain(v)};
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/* The regex slot's storage half — scr_regex.c tested the actual value
|
|
1163
|
+
* already and rendered the /source/flags form (moves in). */
|
|
1164
|
+
void scr_assert_shape_slot_re(int key, bool matched, ScrStr *rendered) {
|
|
1165
|
+
scr_shape.slots[key] = (ScrShapeSlot){
|
|
1166
|
+
.present = true, .is_re = true, .re_matched = matched, .val = rendered};
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/* The actual error's key value, borrowed; NULL = absent (a NULL code
|
|
1170
|
+
* slot — Node's `!(key in actual)`). name/message are always present. */
|
|
1171
|
+
ScrStr *scr_assert_shape_actual(int key) {
|
|
1172
|
+
switch (key) {
|
|
1173
|
+
case SHAPE_CODE:
|
|
1174
|
+
return scr_shape.err->code;
|
|
1175
|
+
case SHAPE_MESSAGE:
|
|
1176
|
+
return scr_shape.err->message;
|
|
1177
|
+
default:
|
|
1178
|
+
return scr_shape.err->name;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
static bool scr_shape_str_eq(const ScrStr *a, const ScrStr *b) {
|
|
1183
|
+
return a->len == b->len && memcmp(a->data, b->data, a->len) == 0;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/* Does every expected key match the caught error? (The pass check and
|
|
1187
|
+
* doesNotReject's predicate.) */
|
|
1188
|
+
static bool scr_shape_matches(void) {
|
|
1189
|
+
for (int k = 0; k < 3; k++) {
|
|
1190
|
+
const ScrShapeSlot *s = &scr_shape.slots[k];
|
|
1191
|
+
if (!s->present) continue;
|
|
1192
|
+
ScrStr *actual = scr_assert_shape_actual(k);
|
|
1193
|
+
if (!actual) return false;
|
|
1194
|
+
if (s->is_re ? !s->re_matched : !scr_shape_str_eq(actual, s->val)) return false;
|
|
1195
|
+
}
|
|
1196
|
+
return true;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/* One rendered Comparison line: " <key>: <value>" (+ "," unless last).
|
|
1200
|
+
* The value is util.inspect of a string, or the regex's own rendering. */
|
|
1201
|
+
static ScrStr *scr_shape_line(int key, ScrStr *value, bool inspect, bool last) {
|
|
1202
|
+
static const char *names[3] = {"code", "message", "name"};
|
|
1203
|
+
ScrAssertBuf b = {0};
|
|
1204
|
+
ab_cstr(&b, " ");
|
|
1205
|
+
ab_cstr(&b, names[key]);
|
|
1206
|
+
ab_cstr(&b, ": ");
|
|
1207
|
+
if (inspect) {
|
|
1208
|
+
ScrStr *q = scr_assert_inspect_str(value);
|
|
1209
|
+
ab_str(&b, q);
|
|
1210
|
+
scr_str_release(q);
|
|
1211
|
+
} else {
|
|
1212
|
+
ab_str(&b, value);
|
|
1213
|
+
}
|
|
1214
|
+
if (!last) ab_char(&b, ',');
|
|
1215
|
+
return ab_take(&b);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
/* The failing shape comparison's generated message: Node's deep-equal
|
|
1219
|
+
* diff of the two Comparison renderings. A line diff over two tiny
|
|
1220
|
+
* arrays (<= 5 lines): common lines print with a two-space margin; each
|
|
1221
|
+
* maximal differing gap prints its actual lines (+) then its expected
|
|
1222
|
+
* lines (-) — the myers printer's grouping, verified against v24 across
|
|
1223
|
+
* the enumerable case space. */
|
|
1224
|
+
static void scr_shape_diff_fail(void) {
|
|
1225
|
+
ScrStr *alines[5], *elines[5];
|
|
1226
|
+
size_t an = 0, en = 0;
|
|
1227
|
+
/* Actual Comparison: the expected keys present on the error, sorted
|
|
1228
|
+
* render order (code < message < name); zero keys collapse to the
|
|
1229
|
+
* one-line "Comparison {}". */
|
|
1230
|
+
int akeys[3], ekeys[3];
|
|
1231
|
+
int ank = 0, enk = 0;
|
|
1232
|
+
for (int k = 0; k < 3; k++) {
|
|
1233
|
+
if (!scr_shape.slots[k].present) continue;
|
|
1234
|
+
ekeys[enk++] = k;
|
|
1235
|
+
if (scr_assert_shape_actual(k)) akeys[ank++] = k;
|
|
1236
|
+
}
|
|
1237
|
+
if (ank == 0) {
|
|
1238
|
+
alines[an++] = scr_str_new("Comparison {}", 13);
|
|
1239
|
+
} else {
|
|
1240
|
+
alines[an++] = scr_str_new("Comparison {", 12);
|
|
1241
|
+
for (int i = 0; i < ank; i++) {
|
|
1242
|
+
alines[an++] =
|
|
1243
|
+
scr_shape_line(akeys[i], scr_assert_shape_actual(akeys[i]), true, i == ank - 1);
|
|
1244
|
+
}
|
|
1245
|
+
alines[an++] = scr_str_new("}", 1);
|
|
1246
|
+
}
|
|
1247
|
+
elines[en++] = scr_str_new("Comparison {", 12);
|
|
1248
|
+
for (int i = 0; i < enk; i++) {
|
|
1249
|
+
const ScrShapeSlot *s = &scr_shape.slots[ekeys[i]];
|
|
1250
|
+
/* A regex value that MATCHED renders as the actual's own value on
|
|
1251
|
+
* the expected side too (Node's Comparison constructor), making the
|
|
1252
|
+
* two lines identical. */
|
|
1253
|
+
ScrStr *v = s->is_re && s->re_matched ? scr_assert_shape_actual(ekeys[i]) : s->val;
|
|
1254
|
+
bool inspect = !s->is_re || s->re_matched;
|
|
1255
|
+
elines[en++] = scr_shape_line(ekeys[i], v, inspect, i == enk - 1);
|
|
1256
|
+
}
|
|
1257
|
+
elines[en++] = scr_str_new("}", 1);
|
|
1258
|
+
|
|
1259
|
+
/* LCS table over the two line arrays (byte-equal lines), then the
|
|
1260
|
+
* matched pairs — unique here: distinct keys never render equal lines,
|
|
1261
|
+
* so ambiguity cannot arise. */
|
|
1262
|
+
size_t L[6][6] = {{0}};
|
|
1263
|
+
for (size_t i = an; i-- > 0;) {
|
|
1264
|
+
for (size_t j = en; j-- > 0;) {
|
|
1265
|
+
L[i][j] = scr_shape_str_eq(alines[i], elines[j])
|
|
1266
|
+
? L[i + 1][j + 1] + 1
|
|
1267
|
+
: (L[i + 1][j] > L[i][j + 1] ? L[i + 1][j] : L[i][j + 1]);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
/* The walk: common lines print with a two-space margin; inside a gap
|
|
1271
|
+
* the >= tie-break prefers actual, so each maximal differing run
|
|
1272
|
+
* groups its + lines before its - lines — the myers printer's
|
|
1273
|
+
* grouping, verified against v24 across the enumerable case space
|
|
1274
|
+
* (the first "\n" doubles as the blank line under the banner). */
|
|
1275
|
+
ScrAssertBuf b = {0};
|
|
1276
|
+
ab_cstr(&b, "Expected values to be strictly deep-equal:\n+ actual - expected\n");
|
|
1277
|
+
size_t i = 0, j = 0;
|
|
1278
|
+
while (i < an && j < en) {
|
|
1279
|
+
if (scr_shape_str_eq(alines[i], elines[j])) {
|
|
1280
|
+
ab_cstr(&b, "\n ");
|
|
1281
|
+
ab_str(&b, alines[i]);
|
|
1282
|
+
i++;
|
|
1283
|
+
j++;
|
|
1284
|
+
} else if (L[i + 1][j] >= L[i][j + 1]) {
|
|
1285
|
+
ab_cstr(&b, "\n+ ");
|
|
1286
|
+
ab_str(&b, alines[i]);
|
|
1287
|
+
i++;
|
|
1288
|
+
} else {
|
|
1289
|
+
ab_cstr(&b, "\n- ");
|
|
1290
|
+
ab_str(&b, elines[j]);
|
|
1291
|
+
j++;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
for (; i < an; i++) {
|
|
1295
|
+
ab_cstr(&b, "\n+ ");
|
|
1296
|
+
ab_str(&b, alines[i]);
|
|
1297
|
+
}
|
|
1298
|
+
for (; j < en; j++) {
|
|
1299
|
+
ab_cstr(&b, "\n- ");
|
|
1300
|
+
ab_str(&b, elines[j]);
|
|
1301
|
+
}
|
|
1302
|
+
ab_cstr(&b, "\n");
|
|
1303
|
+
for (size_t k = 0; k < an; k++) scr_str_release(alines[k]);
|
|
1304
|
+
for (size_t k = 0; k < en; k++) scr_str_release(elines[k]);
|
|
1305
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
void scr_assert_shape_end(ScrStr *msg, bool has_msg) {
|
|
1309
|
+
if (scr_shape_matches()) {
|
|
1310
|
+
scr_shape_clear();
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
if (has_msg) {
|
|
1314
|
+
scr_shape_clear();
|
|
1315
|
+
scr_assert_fail_msg(scr_str_retain(msg));
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
scr_shape_diff_fail();
|
|
1319
|
+
scr_shape_clear();
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/* assert.doesNotReject whose rejection matched the expectation (or had
|
|
1323
|
+
* none): expectsNoError's generated message. */
|
|
1324
|
+
void scr_assert_unwanted_rejection(ScrError *err, ScrStr *msg, bool has_msg) {
|
|
1325
|
+
ScrAssertBuf b = {0};
|
|
1326
|
+
ab_cstr(&b, "Got unwanted rejection");
|
|
1327
|
+
if (has_msg) {
|
|
1328
|
+
ab_cstr(&b, ": ");
|
|
1329
|
+
ab_str(&b, msg);
|
|
1330
|
+
} else {
|
|
1331
|
+
ab_char(&b, '.');
|
|
1332
|
+
}
|
|
1333
|
+
ab_cstr(&b, "\nActual message: \"");
|
|
1334
|
+
if (err->message) ab_str(&b, err->message);
|
|
1335
|
+
ab_char(&b, '"');
|
|
1336
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/* ── assert.ifError ───────────────────────────────────────────────────
|
|
1340
|
+
* Node throws for ANY value but null/undefined (falsy included); the
|
|
1341
|
+
* frontend routes null/undefined to a no-op and everything else here.
|
|
1342
|
+
* The detail is the error's message (its name when the message is
|
|
1343
|
+
* empty — Node reads constructor.name, identical for the builtin
|
|
1344
|
+
* hierarchy) or the value's inspection. */
|
|
1345
|
+
|
|
1346
|
+
static void scr_assert_iferror_fail(const char *detail, size_t len) {
|
|
1347
|
+
ScrAssertBuf b = {0};
|
|
1348
|
+
ab_cstr(&b, "ifError got unwanted exception: ");
|
|
1349
|
+
ab_bytes(&b, detail, len);
|
|
1350
|
+
scr_assert_fail_msg(ab_take(&b));
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
void scr_assert_iferror_err(ScrError *err) {
|
|
1354
|
+
const ScrStr *d = err->message && err->message->len > 0 ? err->message : err->name;
|
|
1355
|
+
scr_assert_iferror_fail(d ? d->data : "", d ? d->len : 0);
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
void scr_assert_iferror_f64(double x) {
|
|
1359
|
+
char buf[40];
|
|
1360
|
+
size_t n = scr_assert_inspect_f64(x, buf);
|
|
1361
|
+
scr_assert_iferror_fail(buf, n);
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
void scr_assert_iferror_str(ScrStr *s) {
|
|
1365
|
+
ScrStr *q = scr_assert_inspect_str(s);
|
|
1366
|
+
scr_assert_iferror_fail(q->data, q->len);
|
|
1367
|
+
scr_str_release(q);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
void scr_assert_iferror_bool(bool v) {
|
|
1371
|
+
scr_assert_iferror_fail(v ? "true" : "false", v ? 4 : 5);
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
/* The checked-dynamic argument (test/common's mustSucceed wrapper): the
|
|
1375
|
+
* DOM kind dispatches — units pass quietly, %error-marked objects (the
|
|
1376
|
+
* caughtToDyn encoding) throw with the error's message (its name when
|
|
1377
|
+
* the message is empty, Node's rule), everything else throws with the
|
|
1378
|
+
* value's inspection. */
|
|
1379
|
+
void scr_assert_iferror_dyn(const ScrDyn *v) {
|
|
1380
|
+
if (v->kind == SCR_DYN_UNDEF || v->kind == SCR_DYN_NULL) return;
|
|
1381
|
+
if (v->kind == SCR_DYN_OBJ && scr_dyn_obj_get(v, "%error", 6) != NULL) {
|
|
1382
|
+
const ScrDyn *msg = scr_dyn_obj_get(v, "message", 7);
|
|
1383
|
+
const ScrDyn *name = scr_dyn_obj_get(v, "name", 4);
|
|
1384
|
+
const ScrDyn *d = msg != NULL && msg->kind == SCR_DYN_STR && msg->v.str->len > 0 ? msg : name;
|
|
1385
|
+
if (d != NULL && d->kind == SCR_DYN_STR) {
|
|
1386
|
+
scr_assert_iferror_fail(d->v.str->data, d->v.str->len);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
ScrStr *q = scr_assert_cf_inspect(v);
|
|
1391
|
+
scr_assert_iferror_fail(q->data, q->len);
|
|
1392
|
+
scr_str_release(q);
|
|
1393
|
+
}
|