mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-18 13:21:55 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
#####################
|
||||
### Failed Tests ###
|
||||
#####################
|
||||
|
||||
# Comments start with `#` or `;`.
|
||||
# Paths are relative to the `test262/test` directory.
|
||||
# Paths may contain globs.
|
||||
|
||||
# TODO: import defer
|
||||
language/expressions/dynamic-import/import-defer/import-defer-transitive-async-module/main.js
|
||||
language/expressions/dynamic-import/import-defer/sync/main.js
|
||||
language/expressions/dynamic-import/import-defer/sync-dependency-of-deferred-async-module/main.js
|
||||
|
||||
# Non-strict mode
|
||||
# Annex B
|
||||
## RegExp.prototype.compile
|
||||
staging/sm/RegExp/compile-lastIndex.js
|
||||
staging/sm/RegExp/constructor-ordering.js
|
||||
staging/sm/RegExp/flags-param-handling.js
|
||||
staging/sm/RegExp/match-local-tolength-recompilation.js
|
||||
staging/sm/RegExp/prototype.js
|
||||
staging/sm/RegExp/replace-compile-elembase.js
|
||||
staging/sm/RegExp/replace-compile.js
|
||||
staging/sm/RegExp/replace-local-tolength-recompilation.js
|
||||
staging/sm/String/matchAll.js
|
||||
# SourceCharacterIdentityEscape
|
||||
language/literals/regexp/S7.8.5_A1.4_T2.js
|
||||
language/literals/regexp/S7.8.5_A2.4_T2.js
|
||||
# IdentityEscape + ExtendedPatternCharacter
|
||||
staging/sm/RegExp/unicode-braced.js
|
||||
built-ins/String/prototype/split/separator-regexp.js # references /\k<x>/, /\XA0/, /\X/
|
||||
# Block
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-eval.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-if.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-label.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-notapplicable.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-parameter.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-same-name.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b-with.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-annex-b.js
|
||||
staging/sm/lexical-environment/block-scoped-functions-deprecated-redecl.js
|
||||
|
||||
# TODO: https://github.com/tc39/ecma262/issues/3592
|
||||
built-ins/RegExp/regexp-modifiers/add-ignoreCase-affects-slash-upper-p.js
|
||||
|
||||
# Failed tests appended by --update-failed-tests
|
||||
built-ins/String/prototype/localeCompare/15.5.4.9_CE.js
|
||||
staging/sm/Array/toLocaleString-01.js
|
||||
staging/sm/async-functions/await-in-arrow-parameters.js
|
||||
staging/sm/async-functions/await-in-parameters-of-async-func.js
|
||||
staging/sm/async-functions/property.js
|
||||
staging/sm/AsyncGenerators/for-await-bad-syntax.js
|
||||
staging/sm/Atomics/cross-compartment.js
|
||||
staging/sm/Atomics/detached-buffers.js
|
||||
staging/sm/class/newTargetDefaults.js
|
||||
staging/sm/class/superCallBadNewTargetPrototype.js
|
||||
staging/sm/class/superPropDestructuring.js
|
||||
staging/sm/Date/setTime-argument-shortcircuiting.js
|
||||
staging/sm/Date/time-components-negative-zero.js
|
||||
staging/sm/Date/toISOString-01.js
|
||||
staging/sm/destructuring/bug1396261.js
|
||||
staging/sm/destructuring/order-super.js
|
||||
staging/sm/expressions/destructuring-pattern-parenthesized.js
|
||||
staging/sm/expressions/nullish-coalescing.js
|
||||
staging/sm/expressions/optional-chain.js
|
||||
staging/sm/extensions/arguments-property-access-in-function.js
|
||||
staging/sm/extensions/censor-strict-caller.js
|
||||
staging/sm/extensions/clone-v1-typed-array-data.dat
|
||||
staging/sm/extensions/function-caller-skips-eval-frames.js
|
||||
staging/sm/extensions/function-properties.js
|
||||
staging/sm/extensions/recursion.js
|
||||
staging/sm/fields/await-identifier-module-3.js
|
||||
staging/sm/fields/await-identifier-script.js
|
||||
staging/sm/Function/function-caller-restrictions.js
|
||||
staging/sm/Function/function-name-for.js
|
||||
staging/sm/Function/function-toString-builtin-name.js
|
||||
staging/sm/Function/function-toString-builtin.js
|
||||
staging/sm/Function/invalid-parameter-list.js
|
||||
staging/sm/generators/runtime.js
|
||||
staging/sm/generators/syntax.js
|
||||
staging/sm/generators/yield-star-throw-htmldda.js
|
||||
staging/sm/lexical-environment/for-loop.js
|
||||
staging/sm/lexical-environment/var-in-catch-body-annex-b-eval.js
|
||||
staging/sm/Math/f16round.js
|
||||
staging/sm/misc/explicit-undefined-optional-argument.js
|
||||
staging/sm/misc/future-reserved-words.js
|
||||
staging/sm/Proxy/revoked-get-function-realm-typeerror.js
|
||||
staging/sm/regress/regress-554955-5.js
|
||||
staging/sm/regress/regress-577648-1.js
|
||||
staging/sm/regress/regress-577648-2.js
|
||||
staging/sm/regress/regress-584355.js
|
||||
staging/sm/regress/regress-586482-1.js
|
||||
staging/sm/regress/regress-586482-2.js
|
||||
staging/sm/regress/regress-586482-3.js
|
||||
staging/sm/regress/regress-586482-4.js
|
||||
staging/sm/regress/regress-586482-5.js
|
||||
staging/sm/regress/regress-602621.js
|
||||
staging/sm/statements/for-in-with-declaration.js
|
||||
staging/sm/statements/regress-642975.js
|
||||
staging/sm/strict/strict-function-statements.js
|
||||
staging/sm/String/unicode-braced.js
|
||||
staging/sm/syntax/declaration-forbidden-in-label.js
|
||||
staging/sm/syntax/linefeed-at-eof-in-unterminated-string-or-template.js
|
||||
staging/sm/TypedArray/sort-negative-nan.js
|
||||
staging/sm/TypedArray/toString.js
|
||||
@@ -0,0 +1,27 @@
|
||||
# https://github.com/tc39/test262/blob/main/features.txt
|
||||
|
||||
# Start with `-` to skip feature
|
||||
# Map feature to engine262 feature using `feature = engine262featurename`
|
||||
# e.g.:
|
||||
# import-defer = import-defer
|
||||
decorators = decorators
|
||||
Temporal = temporal
|
||||
|
||||
# Update with test262 on Feb 2025, to be investigated/implemented
|
||||
-Float16Array
|
||||
-arraybuffer-transfer
|
||||
-explicit-resource-management
|
||||
-source-phase-imports
|
||||
-source-phase-imports-module-source
|
||||
-immutable-arraybuffer
|
||||
|
||||
# Added before Feb 2025
|
||||
|
||||
-Atomics
|
||||
-Atomics.waitAsync
|
||||
-Atomics.pause
|
||||
-caller
|
||||
-SharedArrayBuffer
|
||||
-tail-call-optimization
|
||||
-Temporal
|
||||
-resizable-arraybuffer
|
||||
@@ -0,0 +1,124 @@
|
||||
#####################
|
||||
### Skipped Tests ###
|
||||
#####################
|
||||
|
||||
# Comments start with `#` or `;`.
|
||||
# Paths are relative to the `test262/test` directory.
|
||||
# Paths may contain globs.
|
||||
|
||||
annexB
|
||||
intl402
|
||||
|
||||
# fix CI?
|
||||
harness/nativeFunctionMatcher.js
|
||||
|
||||
# Our date parser is now calling the host algorithm, may unstable based on the host.
|
||||
built-ins/Date/parse/without-utc-offset.js
|
||||
|
||||
# Decorators (not merged yet) https://github.com/tc39/test262/pull/4103/
|
||||
## wrong test, we are correct
|
||||
language/expressions/class/decorator/class/error/class-deco-invalid-return-arrow.js
|
||||
language/statements/class/decorator/class/error/class-deco-invalid-return-arrow.js
|
||||
language/expressions/class/decorator/class/class-deco-returns-proxy.js
|
||||
language/statements/class/decorator/class/class-deco-returns-proxy.js
|
||||
|
||||
# TODO (Feb 2026)
|
||||
language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js
|
||||
language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js
|
||||
language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js
|
||||
language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from.js
|
||||
language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js
|
||||
language/identifiers/start-unicode-17.0.0-escaped.js
|
||||
language/identifiers/part-unicode-17.0.0-class-escaped.js
|
||||
language/identifiers/part-unicode-17.0.0.js
|
||||
language/identifiers/start-unicode-17.0.0-class-escaped.js
|
||||
language/identifiers/part-unicode-17.0.0-class.js
|
||||
language/identifiers/start-unicode-17.0.0.js
|
||||
language/identifiers/start-unicode-17.0.0-class.js
|
||||
language/identifiers/part-unicode-17.0.0-escaped.js
|
||||
built-ins/Promise/allSettledKeyed/not-a-constructor.js
|
||||
built-ins/Promise/allSettledKeyed/proto.js
|
||||
built-ins/Promise/allSettledKeyed/name.js
|
||||
built-ins/Promise/allSettledKeyed/extensible.js
|
||||
built-ins/Promise/allSettledKeyed/prop-desc.js
|
||||
built-ins/Promise/allSettledKeyed/length.js
|
||||
built-ins/Promise/allKeyed/not-a-constructor.js
|
||||
built-ins/Promise/allKeyed/prop-desc.js
|
||||
built-ins/Promise/allKeyed/proto.js
|
||||
built-ins/Promise/allKeyed/extensible.js
|
||||
built-ins/Promise/allKeyed/length.js
|
||||
built-ins/Promise/allKeyed/name.js
|
||||
built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-return.js
|
||||
built-ins/Iterator/zipKeyed/iterables-containing-string-objects.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-step-value-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/results-object-has-default-attributes.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-next.js
|
||||
built-ins/Iterator/zipKeyed/padding-iteration.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/proto.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-inherited.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-symbol-key.js
|
||||
built-ins/Iterator/zipKeyed/basic-longest.js
|
||||
built-ins/Iterator/zipKeyed/basic-strict.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-get-iterator-flattenable-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-after-reading-options.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-next.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/padding-iteration-get-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/prop-desc.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-get-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/results-object-from-array.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration.js
|
||||
built-ins/Iterator/zipKeyed/is-function.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-undefined.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-get-own-property-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/options.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-deleted.js
|
||||
built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-return.js
|
||||
built-ins/Iterator/zipKeyed/basic-shortest.js
|
||||
built-ins/Iterator/zipKeyed/options-padding.js
|
||||
built-ins/Iterator/zipKeyed/iterables-iteration-enumerable.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js
|
||||
built-ins/Iterator/zipKeyed/length.js
|
||||
built-ins/Iterator/zipKeyed/results-object-has-no-undefined-iterables-properties.js
|
||||
built-ins/Iterator/zipKeyed/options-mode.js
|
||||
built-ins/Iterator/zipKeyed/name.js
|
||||
built-ins/Iterator/zipKeyed/result-is-iterator.js
|
||||
built-ins/Iterator/zipKeyed/iterator-zip-iteration.js
|
||||
built-ins/Iterator/zip/iterables-containing-string-objects.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js
|
||||
built-ins/Iterator/zip/padding-iteration-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zip/suspended-start-iterator-close-calls-return.js
|
||||
built-ins/Iterator/zip/suspended-start-iterator-close-calls-next.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js
|
||||
built-ins/Iterator/zip/padding-iteration.js
|
||||
built-ins/Iterator/zip/padding-iteration-get-iterator-abrupt-completion.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zip/proto.js
|
||||
built-ins/Iterator/zip/basic-longest.js
|
||||
built-ins/Iterator/zip/basic-strict.js
|
||||
built-ins/Iterator/zip/iterables-iteration-get-iterator-flattenable-abrupt-completion.js
|
||||
built-ins/Iterator/zip/iterables-iteration-after-reading-options.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js
|
||||
built-ins/Iterator/zip/suspended-yield-iterator-close-calls-next.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js
|
||||
built-ins/Iterator/zip/prop-desc.js
|
||||
built-ins/Iterator/zip/iterables-iteration.js
|
||||
built-ins/Iterator/zip/is-function.js
|
||||
built-ins/Iterator/zip/padding-iteration-iterator-step-value-abrupt-completion.js
|
||||
built-ins/Iterator/zip/options.js
|
||||
built-ins/Iterator/zip/suspended-yield-iterator-close-calls-return.js
|
||||
built-ins/Iterator/zip/options-padding.js
|
||||
built-ins/Iterator/zip/iterables-iteration-iterator-step-value-abrupt-completion.js
|
||||
built-ins/Iterator/zip/basic-shortest.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js
|
||||
built-ins/Iterator/zip/length.js
|
||||
built-ins/Iterator/zip/name.js
|
||||
built-ins/Iterator/zip/iterator-zip-iteration.js
|
||||
built-ins/Iterator/zip/result-is-iterator.js
|
||||
built-ins/Iterator/zip/options-mode.js
|
||||
built-ins/RegExp/unicodeSets/generated/rgi-emoji-17.0.js
|
||||
@@ -0,0 +1,97 @@
|
||||
##################
|
||||
### Slow Tests ###
|
||||
##################
|
||||
|
||||
# Comments start with `#` or `;`.
|
||||
# Paths are relative to the `test262/test` directory.
|
||||
# Paths may contain globs.
|
||||
|
||||
built-ins/RegExp/property-escapes/generated
|
||||
built-ins/RegExp/CharacterClassEscapes
|
||||
|
||||
# Slow on CI
|
||||
built-ins/Array/prototype/concat/Array.prototype.concat_small-typed-array.js
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-2.js
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-10-1.js
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-9-1.js
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-1.js
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-2.js
|
||||
built-ins/decodeURI
|
||||
built-ins/encodeURIComponent
|
||||
language/literals/regexp/S7.8.5_A1.4_T2.js
|
||||
language/literals/regexp/S7.8.5_A2.4_T2.js
|
||||
staging/sm/expressions/object-literal-__proto__.js
|
||||
staging/sm/misc/getter-setter-outerize-this.js
|
||||
staging/sm/Proxy/ownkeys-linear.js
|
||||
staging/sm/RegExp/unicode-class-braced.js
|
||||
staging/sm/String/replace-math.js
|
||||
staging/sm/TypedArray/entries.js
|
||||
staging/sm/TypedArray/fill.js
|
||||
staging/sm/TypedArray/forEach.js
|
||||
staging/sm/TypedArray/sort_small.js
|
||||
staging/sm/TypedArray/sort-negative-nan.js
|
||||
|
||||
# Slow tests appended by --update-slow-tests=10
|
||||
built-ins/Array/fromAsync/asyncitems-arraylike-too-long.js
|
||||
built-ins/Array/prototype/concat/Array.prototype.concat_large-typed-array.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.10_T1.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.11_T1.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.11_T2.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.12_T1.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.12_T2.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.12_T3.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.2_T1.js
|
||||
built-ins/decodeURI/S15.1.3.1_A1.2_T2.js
|
||||
built-ins/decodeURI/S15.1.3.1_A2.1_T1.js
|
||||
built-ins/decodeURI/S15.1.3.1_A2.4_T1.js
|
||||
built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.10_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.11_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.12_T2.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.12_T3.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.2_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A1.2_T2.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A2.1_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A2.4_T1.js
|
||||
built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
|
||||
built-ins/encodeURI/S15.1.3.3_A2.3_T1.js
|
||||
built-ins/encodeURI/S15.1.3.3_A2.5_T1.js
|
||||
built-ins/encodeURIComponent/S15.1.3.4_A2.3_T1.js
|
||||
built-ins/encodeURIComponent/S15.1.3.4_A2.5_T1.js
|
||||
built-ins/Function/prototype/toString/built-in-function-object.js
|
||||
built-ins/parseFloat/S15.1.2.3_A6.js
|
||||
built-ins/parseInt/S15.1.2.2_A8.js
|
||||
built-ins/RegExp/character-class-escape-non-whitespace.js
|
||||
language/comments/S7.4_A5.js
|
||||
language/comments/S7.4_A6.js
|
||||
language/literals/regexp/S7.8.5_A1.1_T2.js
|
||||
language/literals/regexp/S7.8.5_A2.1_T2.js
|
||||
staging/sm/Array/length-truncate-nonconfigurable-sparse.js
|
||||
staging/sm/Array/toSpliced-dense.js
|
||||
staging/sm/Date/dst-offset-caching-1-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-2-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-3-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-4-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-5-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-6-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-7-of-8.js
|
||||
staging/sm/Date/dst-offset-caching-8-of-8.js
|
||||
staging/sm/Date/two-digit-years.js
|
||||
staging/sm/expressions/short-circuit-compound-assignment.js
|
||||
staging/sm/Function/has-instance-jitted.js
|
||||
staging/sm/JSON/parse-mega-huge-array.js
|
||||
staging/sm/RegExp/unicode-ignoreCase.js
|
||||
staging/sm/regress/regress-1507322-deep-weakmap.js
|
||||
staging/sm/regress/regress-610026.js
|
||||
staging/sm/String/fromCodePoint.js
|
||||
staging/sm/String/string-upper-lower-mapping.js
|
||||
staging/sm/TypedArray/element-setting-converts-using-ToNumber.js
|
||||
staging/sm/TypedArray/every-and-some.js
|
||||
staging/sm/TypedArray/map-and-filter.js
|
||||
staging/sm/TypedArray/set-same-buffer-different-source-target-types.js
|
||||
staging/sm/TypedArray/sort_large_countingsort.js
|
||||
staging/sm/TypedArray/sort_modifications.js
|
||||
staging/sm/TypedArray/sort_snans.js
|
||||
staging/sm/TypedArray/sort_sorted.js
|
||||
@@ -0,0 +1,37 @@
|
||||
##########################
|
||||
### Slow Tests (on CI) ###
|
||||
##########################
|
||||
|
||||
# Comments start with `#` or `;`.
|
||||
# Paths are relative to the `test262/test` directory.
|
||||
# Paths may contain globs.
|
||||
|
||||
built-ins/Array/prototype/concat/Array.prototype.concat_small-typed-array.js
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-2.js
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-1.js
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-1.js
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-10-1.js
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-9-1.js
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-1.js
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-2.js
|
||||
built-ins/encodeURI/S15.1.3.3_A2.4_T1.js
|
||||
built-ins/encodeURI/S15.1.3.3_A2.4_T2.js
|
||||
built-ins/encodeURIComponent/S15.1.3.4_A2.4_T1.js
|
||||
built-ins/encodeURIComponent/S15.1.3.4_A2.4_T2.js
|
||||
built-ins/String/prototype/repeat/empty-string-returns-empty.js
|
||||
built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached-prototype.js
|
||||
built-ins/TypedArray/prototype/copyWithin/coerced-values-end-detached.js
|
||||
built-ins/TypedArray/prototype/copyWithin/coerced-values-start-detached.js
|
||||
language/literals/regexp/S7.8.5_A1.4_T2.js
|
||||
language/literals/regexp/S7.8.5_A2.4_T2.js
|
||||
staging/sm/expressions/object-literal-__proto__.js
|
||||
staging/sm/misc/getter-setter-outerize-this.js
|
||||
staging/sm/Proxy/ownkeys-linear.js
|
||||
staging/sm/RegExp/unicode-class-braced.js
|
||||
staging/sm/String/replace-math.js
|
||||
staging/sm/TypedArray/entries.js
|
||||
staging/sm/TypedArray/fill.js
|
||||
staging/sm/TypedArray/forEach.js
|
||||
staging/sm/TypedArray/sort_small.js
|
||||
staging/sm/TypedArray/sort_small.js
|
||||
staging/sm/TypedArray/sort-negative-nan.js
|
||||
Submodule
+1
Submodule engine262/test/test262/test262 added at 3aa9cb2c71
@@ -0,0 +1,446 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { join, resolve, relative } from 'node:path';
|
||||
import { createWriteStream } from 'node:fs';
|
||||
import { opendir, readFile, stat } from 'node:fs/promises';
|
||||
import { stripVTControlCharacters, styleText } from 'node:util';
|
||||
import { fork } from 'node:child_process';
|
||||
import { cpus } from 'node:os';
|
||||
import { glob, isDynamicPattern } from 'tinyglobby';
|
||||
import YAML from 'js-yaml';
|
||||
import { highlight } from 'cli-highlight';
|
||||
import {
|
||||
type WorkerToSupervisor, type SupervisorToWorker, Test,
|
||||
readList,
|
||||
type WorkerToSupervisor_Failed,
|
||||
type Stack,
|
||||
} from '../base.mts';
|
||||
import { annotateFileWithURL, isCI } from '../tui.mts';
|
||||
import {
|
||||
createTestReporter,
|
||||
supportColor,
|
||||
type SkipReason,
|
||||
} from '../tui.mts';
|
||||
import { fatal_exit } from '../base.mts';
|
||||
import { args } from './test262.mts';
|
||||
|
||||
const inputs = {
|
||||
Test262TestsPath: join(process.env.TEST262 || resolve(import.meta.dirname, 'test262'), 'test'),
|
||||
AllTests: async () => {
|
||||
const files: string[] = [];
|
||||
for await (const file of readdir(inputs.Test262TestsPath)) {
|
||||
files.push(file);
|
||||
}
|
||||
inputs.AllTests = async () => files;
|
||||
return files;
|
||||
},
|
||||
AssertToBeFailedList: resolve(import.meta.dirname, 'failed'),
|
||||
SkipList: resolve(import.meta.dirname, 'skip'),
|
||||
SlowList: resolve(import.meta.dirname, 'slow'),
|
||||
SlowListCI: resolve(import.meta.dirname, 'slow-ci'),
|
||||
Features: resolve(import.meta.dirname, 'features'),
|
||||
};
|
||||
|
||||
const outputs = {
|
||||
LastRunFailedList: resolve(import.meta.dirname, 'last-failed-list'),
|
||||
CurrentRunFailureLog: resolve(import.meta.dirname, 'last-failed.log'),
|
||||
};
|
||||
|
||||
if (args.values['failed-only']) {
|
||||
args.positionals = (await readFile(outputs.LastRunFailedList, { encoding: 'utf-8' })).split('\n');
|
||||
}
|
||||
|
||||
const outputStreams = {
|
||||
SlowList: args.values['update-slow'] ? createWriteStream(inputs.SlowList, { encoding: 'utf-8', flags: 'a' }) : undefined,
|
||||
LastRunFailedList: createWriteStream(outputs.LastRunFailedList, { encoding: 'utf-8' }),
|
||||
CurrentRunFailureLog: createWriteStream(outputs.CurrentRunFailureLog, { encoding: 'utf-8' }),
|
||||
AssertToBeFailedList: args.values['update-failed'] ? createWriteStream(inputs.AssertToBeFailedList, { encoding: 'utf-8', flags: 'a' }) : undefined,
|
||||
};
|
||||
|
||||
let allTestsDiscovered = false;
|
||||
|
||||
const disabledFeatures = new Set<string>();
|
||||
readList(inputs.Features).forEach((feature) => {
|
||||
if (feature.startsWith('-')) {
|
||||
disabledFeatures.add(feature.slice(1));
|
||||
}
|
||||
});
|
||||
disabledFeatures.delete(args.values.features!);
|
||||
|
||||
const workersToStart = Math.max(
|
||||
1,
|
||||
process.env.NUM_WORKERS
|
||||
? Number.parseInt(process.env.NUM_WORKERS, 10)
|
||||
: cpus().length - 2,
|
||||
);
|
||||
const workers = Array.from({ length: workersToStart }, (_, index) => createWorker(index));
|
||||
/**
|
||||
* Do not replace this with reporter.workers.
|
||||
* This variable maintains the state in the main thread, but reporter.workers is updated asynchronously based on the feedback from workers.
|
||||
*/
|
||||
const workerHasPendingTask: boolean[] = new Array(workersToStart).fill(false);
|
||||
|
||||
const [
|
||||
slowList,
|
||||
slowListCI,
|
||||
skipList,
|
||||
assertToBeFailedList,
|
||||
] = await Promise.all([
|
||||
readListPaths(inputs.SlowList, false),
|
||||
readListPaths(inputs.SlowListCI, true),
|
||||
readListPaths(inputs.SkipList, false),
|
||||
readListPaths(inputs.AssertToBeFailedList, false),
|
||||
]);
|
||||
|
||||
if (outputStreams.AssertToBeFailedList) {
|
||||
outputStreams.AssertToBeFailedList.write('\n# Failed tests appended by --update-failed-tests\n');
|
||||
}
|
||||
|
||||
/** This is for skipping the report of a test if it's variant (strict version) has already failed. */
|
||||
const currentRunFailedTestFiles = new Set<string>();
|
||||
const pendingTests: Test[] = [];
|
||||
const reporter = createTestReporter();
|
||||
|
||||
if (outputStreams.SlowList) {
|
||||
const second = parseInt(args.values['update-slow']!, 10);
|
||||
if (Number.isNaN(second)) {
|
||||
fatal_exit('--update-slow must be a number');
|
||||
}
|
||||
outputStreams.SlowList.write(`\n# Slow tests appended by --update-slow=${second}\n`);
|
||||
reporter.setSlowTestReporting(second, outputStreams.SlowList);
|
||||
}
|
||||
|
||||
function discoverTest(test: Test) {
|
||||
reporter.addTest(test);
|
||||
const disabledFeature = test.attrs.features?.find((feature: string) => disabledFeatures.has(feature));
|
||||
if (disabledFeature) {
|
||||
return reporter.skipTest(test.id, 'feature-disabled', disabledFeature);
|
||||
}
|
||||
if (skipList.has(test.file)) {
|
||||
return reporter.skipTest(test.id, 'skip-list');
|
||||
}
|
||||
if (slowList.has(test.file) && !args.values['run-slow']) {
|
||||
return reporter.skipTest(test.id, 'slow-list');
|
||||
}
|
||||
if (isCI && slowListCI.has(test.file) && !args.values['run-slow']) {
|
||||
return reporter.skipTest(test.id, 'slow-list');
|
||||
}
|
||||
pendingTests.push(test);
|
||||
distributeTest();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function distributeTest() {
|
||||
while (true) {
|
||||
const candidate = workerHasPendingTask.findIndex((work) => !work);
|
||||
if (candidate === -1) {
|
||||
return;
|
||||
}
|
||||
if (!pendingTests.length) {
|
||||
if (allTestsDiscovered && workerHasPendingTask.every((work) => !work)) {
|
||||
reporter.exit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
workers[candidate].send(pendingTests.shift()! satisfies SupervisorToWorker);
|
||||
workerHasPendingTask[candidate] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const visited = new Set<string>();
|
||||
reporter.start();
|
||||
reporter.addEventListener('exit', () => {
|
||||
workers.forEach((worker) => worker.kill());
|
||||
});
|
||||
reporter.onExit.promise.then(() => {
|
||||
if (args.values.verbose || args.values.vv) {
|
||||
const skip: Record<SkipReason, Set<string>> = {
|
||||
'feature-disabled': new Set<string>(),
|
||||
'skip-list': new Set<string>(),
|
||||
'slow-list': new Set<string>(),
|
||||
};
|
||||
const passed: Set<string> = new Set<string>();
|
||||
const skipByFeature: Record<string, Set<string>> = {};
|
||||
const failed: Set<string> = new Set<string>();
|
||||
for (const test of reporter.tests.values()) {
|
||||
if (test.status === 'skipped') {
|
||||
if (test.skipFeature) {
|
||||
(skipByFeature[test.skipFeature] ??= new Set()).add(test.file);
|
||||
} else if (test.skipReason) {
|
||||
skip[test.skipReason].add(test.file);
|
||||
}
|
||||
} else if (test.status === 'failed') {
|
||||
failed.add(test.file);
|
||||
} else if (args.values.vv && test.status === 'passed') {
|
||||
passed.add(test.file);
|
||||
}
|
||||
}
|
||||
if (args.values.vv && passed.size > 0) {
|
||||
console.log(styleText('green', 'The following tests passed:'));
|
||||
for (const test of passed) {
|
||||
console.log(`- ./test/test262/test262/test/${test}`);
|
||||
}
|
||||
}
|
||||
let skipPrint = () => {
|
||||
console.log(styleText('yellow', 'The following tests were skipped:'));
|
||||
skipPrint = () => { };
|
||||
};
|
||||
for (const [reason, tests] of Object.entries(skip)) {
|
||||
if (tests.size === 0) {
|
||||
continue;
|
||||
}
|
||||
skipPrint();
|
||||
console.log(`- Reason: ${styleText('yellow', reason)} (${tests.size} tests)`);
|
||||
for (const test of tests) {
|
||||
console.log(` - ./test/test262/test262/test/${test}`);
|
||||
}
|
||||
}
|
||||
for (const [feature, tests] of Object.entries(skipByFeature)) {
|
||||
skipPrint();
|
||||
console.log(`- Reason: ${styleText('yellow', `feature-disabled (${feature})`)} (${tests.size} tests)`);
|
||||
for (const test of tests) {
|
||||
console.log(` - ./test/test262/test262/test/${test}`);
|
||||
}
|
||||
}
|
||||
if (failed.size > 0) {
|
||||
console.log(styleText('red', '\nThe following tests failed:'));
|
||||
for (const test of failed) {
|
||||
console.log(`- ./test/test262/test262/test/${test}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const engineFeatures = [...args.values['engine-features'] || []];
|
||||
|
||||
const promises = [];
|
||||
for await (const file of parsePositionals(args.positionals, true)) {
|
||||
if (visited.has(file) || /_FIXTURE|README\.md|\.py|\.map|\.mts/.test(file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visited.add(file);
|
||||
promises.push(readFile(file, 'utf8').then((contents) => {
|
||||
const frontmatterYaml = contents.match(/\/\*---(.*?)---\*\//s)?.[1];
|
||||
const attrs: any = frontmatterYaml ? YAML.load(frontmatterYaml) : {};
|
||||
|
||||
if (args.values.features && (!attrs.features || !attrs.features.includes(args.values.features))) {
|
||||
// feature not match
|
||||
return;
|
||||
}
|
||||
|
||||
attrs.flags = (attrs.flags || []).reduce((acc: any, c: any) => {
|
||||
acc[c] = true;
|
||||
return acc;
|
||||
}, {});
|
||||
attrs.includes = attrs.includes || [];
|
||||
|
||||
const test = new Test(relative(inputs.Test262TestsPath, file), file, engineFeatures, attrs, '', contents);
|
||||
|
||||
if (test.attrs.flags.module) {
|
||||
discoverTest(test.withDifferentTestFlag('module'));
|
||||
} else {
|
||||
if (!test.attrs.flags.onlyStrict && !args.values['strict-only'] && !args.values.fast) {
|
||||
discoverTest(test);
|
||||
}
|
||||
|
||||
if (!test.attrs.flags.noStrict && !test.attrs.flags.raw) {
|
||||
discoverTest(test.withDifferentTestFlag('strict', `'use strict';${test.content}`));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (args.positionals.length && !promises.length) {
|
||||
fatal_exit(`No tests found based on the given globs: ${args.positionals.join(', ')}`);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
|
||||
allTestsDiscovered = true;
|
||||
reporter.allTestsDiscovered();
|
||||
distributeTest();
|
||||
|
||||
async function readListPaths(file: string, defaults: boolean) {
|
||||
const list = readList(file);
|
||||
const files = new Set<string>();
|
||||
for await (const file of parsePositionals(list, defaults)) {
|
||||
files.add(relative(inputs.Test262TestsPath, file));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
async function* readdir(dir: string): AsyncGenerator<string> {
|
||||
for await (const dirent of await opendir(dir)) {
|
||||
const p = join(dir, dirent.name);
|
||||
if (dirent.isDirectory()) {
|
||||
yield* readdir(p);
|
||||
} else {
|
||||
yield p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function* parsePositional(pattern: string): AsyncGenerator<string> {
|
||||
if (!isDynamicPattern(pattern)) {
|
||||
const a_path = join(inputs.Test262TestsPath, pattern);
|
||||
const a = await stat(a_path).catch(() => undefined);
|
||||
if (a?.isDirectory()) {
|
||||
return yield* readdir(a_path);
|
||||
} else if (a?.isFile()) {
|
||||
return yield a_path;
|
||||
}
|
||||
|
||||
const b_path = join(process.cwd(), pattern);
|
||||
const b = await stat(b_path).catch(() => undefined);
|
||||
if (b?.isDirectory()) {
|
||||
return yield* readdir(b_path);
|
||||
} else if (b?.isFile()) {
|
||||
return yield b_path;
|
||||
}
|
||||
|
||||
const files = await inputs.AllTests();
|
||||
const matched = files.filter((f) => f.toLowerCase().includes(pattern.toLowerCase()));
|
||||
if (matched.length) {
|
||||
return yield* matched;
|
||||
}
|
||||
}
|
||||
|
||||
const files1 = await glob(pattern, { cwd: inputs.Test262TestsPath, absolute: true, caseSensitiveMatch: false });
|
||||
if (files1.length) {
|
||||
return yield* files1;
|
||||
}
|
||||
|
||||
const files2 = await glob(pattern, { cwd: process.cwd(), absolute: true, caseSensitiveMatch: false });
|
||||
if (files2.length) {
|
||||
return yield* files2;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function* parsePositionals(pattern: string[], defaults: boolean): AsyncGenerator<string> {
|
||||
if (!pattern.length) {
|
||||
if (defaults) {
|
||||
yield* readdir(inputs.Test262TestsPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (const p of pattern) {
|
||||
if (p) {
|
||||
yield* parsePositional(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createWorker(workerId: number) {
|
||||
const c = fork(resolve(import.meta.dirname, './test262-worker.mts'));
|
||||
c.on('message', (message: WorkerToSupervisor) => {
|
||||
switch (message.status) {
|
||||
case 'RUNNING':
|
||||
return reporter.updateWorker(workerId, message.testId);
|
||||
case 'PASS':
|
||||
workerHasPendingTask[workerId] = false;
|
||||
reporter.updateWorker(workerId, null);
|
||||
distributeTest();
|
||||
if (assertToBeFailedList.has(message.file)) {
|
||||
if (currentRunFailedTestFiles.has(message.file)) {
|
||||
return reporter.testFailed(message.testId);
|
||||
} else {
|
||||
currentRunFailedTestFiles.add(message.file);
|
||||
return fail({
|
||||
file: message.file,
|
||||
description: 'The test is declared to be failed, but passed.',
|
||||
error: '',
|
||||
flags: message.flags,
|
||||
status: 'FAIL',
|
||||
testId: message.testId,
|
||||
stack: [],
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
return reporter.testPassed(message.testId);
|
||||
case 'FAIL': {
|
||||
workerHasPendingTask[workerId] = false;
|
||||
reporter.updateWorker(workerId, null);
|
||||
distributeTest();
|
||||
if (assertToBeFailedList.has(message.file)) {
|
||||
return reporter.assertFailedTestFails(message.testId);
|
||||
}
|
||||
if (currentRunFailedTestFiles.has(message.file)) {
|
||||
return reporter.testFailed(message.testId);
|
||||
}
|
||||
currentRunFailedTestFiles.add(message.file);
|
||||
outputStreams.LastRunFailedList.write(`${message.file}\n`);
|
||||
if (outputStreams.AssertToBeFailedList) {
|
||||
outputStreams.AssertToBeFailedList.write(`${message.file}\n`);
|
||||
}
|
||||
return fail(message, true);
|
||||
}
|
||||
default:
|
||||
console.error(message);
|
||||
throw new RangeError('Unknown message from worker');
|
||||
}
|
||||
});
|
||||
c.on('exit', (code) => {
|
||||
if (code !== 0 && code !== null) {
|
||||
fatal_exit(`Worker ${workerId} exited with code ${code}`);
|
||||
}
|
||||
});
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
function fail(message: WorkerToSupervisor_Failed, showSource: boolean) {
|
||||
const { description, testId, file } = message;
|
||||
let error = message.error;
|
||||
error = error.replaceAll(`${process.cwd()}/`, '');
|
||||
process.exitCode = 1;
|
||||
|
||||
const desc = styleText('yellow', description.trim());
|
||||
const descNeedOwnLine = desc.includes('\n') || desc.length > (process.stdout.columns - file.length - 8);
|
||||
// FAILED filename.js
|
||||
const line1 = `${styleText(['bgRed', 'white', 'bold'], ' FAIL ')} ${annotateFileWithURL(file)}${descNeedOwnLine ? '' : ` ${desc}`}\n`;
|
||||
// Test description in the header
|
||||
const line2 = descNeedOwnLine ? `${indent(desc, ' ')}\n` : '';
|
||||
// Source code with error position annotated
|
||||
const line3 = showSource ? annotateSourceWithErrorPosition(error, reporter.tests.get(testId)!.content, message.stack) : '';
|
||||
// Error message
|
||||
const line4 = `${indent(error, ' ')}\n`;
|
||||
const line5 = styleText('red', `${'⎯'.repeat(process.stdout.columns)}\n`);
|
||||
const output = line1 + line2 + line3 + line4;
|
||||
reporter.stdout(output, line5);
|
||||
outputStreams.CurrentRunFailureLog.write(stripVTControlCharacters(output));
|
||||
reporter.testFailed(testId);
|
||||
}
|
||||
|
||||
function indent(string: string, space: string) {
|
||||
return string.split('\n').map((line) => space + line).join('\n');
|
||||
}
|
||||
|
||||
function annotateSourceWithErrorPosition(error: string, sourceCode: string, [stack]: Stack[]) {
|
||||
sourceCode = stack?.source || sourceCode;
|
||||
if (!stack) {
|
||||
return '';
|
||||
}
|
||||
if (sourceCode.endsWith('\n')) {
|
||||
sourceCode = sourceCode.slice(0, -1);
|
||||
}
|
||||
const highLightedLines = (supportColor ? highlight(sourceCode, { language: 'js' }) : sourceCode).split('\n');
|
||||
const linesPad = (highLightedLines.length + 1).toString().length;
|
||||
const decoratedLines = highLightedLines.map((line, index) => ` ${styleText('red', (index + 1).toString().padStart(linesPad))} | ${line}`);
|
||||
const LINES_BEFORE = 3;
|
||||
const LINES_AFTER = 2;
|
||||
const slicedLines = decoratedLines.slice(
|
||||
Math.max(0, Number(stack.line) - LINES_BEFORE),
|
||||
Math.min(decoratedLines.length, Number(stack.line)),
|
||||
);
|
||||
slicedLines.push(''.padStart(linesPad + 5) + styleText('red', `${'-'.repeat(Math.max(Number(stack.column) - 1, 0))}^ ${error.split('\n')[0].trim()}`));
|
||||
slicedLines.push(
|
||||
decoratedLines.slice(
|
||||
Number(stack.line),
|
||||
Math.min(decoratedLines.length, Number(stack.line) + LINES_AFTER),
|
||||
).join('\n'),
|
||||
);
|
||||
|
||||
sourceCode = `${slicedLines.join('\n')}`;
|
||||
sourceCode += '\n';
|
||||
return sourceCode;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-multi-assign */
|
||||
import * as path from 'node:path';
|
||||
import * as fs from 'node:fs';
|
||||
import * as util from 'node:util';
|
||||
import {
|
||||
readList, type Stack, type SupervisorToWorker, type Test, type WorkerToSupervisor,
|
||||
} from '../base.mts';
|
||||
import { createRealm, createAgent } from '../base.mts';
|
||||
import {
|
||||
AbruptCompletion, ObjectValue, evalQ,
|
||||
setSurroundingAgent,
|
||||
inspect,
|
||||
Value,
|
||||
IsCallable,
|
||||
IsDataDescriptor,
|
||||
JSStringValue,
|
||||
skipDebugger,
|
||||
boostTest262Harness,
|
||||
ThrowCompletion,
|
||||
getHostDefinedErrorStack,
|
||||
CallSite,
|
||||
} from '#self';
|
||||
|
||||
const TEST262 = process.env.TEST262 || path.resolve(import.meta.dirname, 'test262');
|
||||
const TEST262_TESTS = path.join(TEST262, 'test');
|
||||
|
||||
const featureMap: Record<string, string> = Object.create(null);
|
||||
readList(path.resolve(import.meta.dirname, 'features')).forEach((f) => {
|
||||
if (f.includes('=')) {
|
||||
const [k, v] = f.split('=');
|
||||
featureMap[k.trim()] = v.trim();
|
||||
}
|
||||
});
|
||||
|
||||
const includeCache: Record<string, undefined | { source: string, specifier: string }> = {};
|
||||
|
||||
process.on('message', (test: SupervisorToWorker) => {
|
||||
try {
|
||||
process.send!({ status: 'RUNNING', testId: test.id } satisfies WorkerToSupervisor, handleSendError);
|
||||
const result = run(test);
|
||||
if (result.status === 'PASS') {
|
||||
process.send!({
|
||||
status: 'PASS', file: test.file, flags: test.currentTestFlag, testId: test.id,
|
||||
} satisfies WorkerToSupervisor, handleSendError);
|
||||
} else {
|
||||
process.send!(result satisfies WorkerToSupervisor, handleSendError);
|
||||
}
|
||||
} catch (e) {
|
||||
process.send!(fails(test, util.inspect(e), []), handleSendError);
|
||||
}
|
||||
});
|
||||
|
||||
function run(test: Test): WorkerToSupervisor {
|
||||
const features = [...test.engineFeatures];
|
||||
if (test.attrs.features) {
|
||||
test.attrs.features.forEach((f) => {
|
||||
if (featureMap[f]) {
|
||||
features.push(featureMap[f]);
|
||||
}
|
||||
});
|
||||
}
|
||||
const agent = createAgent({ features });
|
||||
const parsedScripts = new Map<string, string>();
|
||||
setSurroundingAgent(agent);
|
||||
agent.hostDefinedOptions.errorStackAttachNativeStack = true;
|
||||
agent.hostDefinedOptions.onScriptParsed = (script, id) => {
|
||||
parsedScripts.set(id, script.ECMAScriptCode.sourceText);
|
||||
};
|
||||
|
||||
|
||||
function fail(test: Test, error: Value): WorkerToSupervisor {
|
||||
const stacks = getHostDefinedErrorStack(error);
|
||||
const reportStack: Stack[] = [];
|
||||
for (const stack of stacks || []) {
|
||||
if (!(stack instanceof CallSite)) {
|
||||
continue;
|
||||
}
|
||||
const scriptId = stack.getScriptId();
|
||||
if (!scriptId || stack.columnNumber === null || stack.lineNumber === null) {
|
||||
continue;
|
||||
}
|
||||
const source = parsedScripts.get(scriptId);
|
||||
const record = agent.parsedSources.get(scriptId);
|
||||
if (record?.HostDefined.specifier?.includes('harness')) {
|
||||
continue;
|
||||
}
|
||||
reportStack.push({
|
||||
column: stack.columnNumber,
|
||||
line: stack.lineNumber,
|
||||
source: source === test.content ? undefined : source,
|
||||
specifier: stack.getSpecifier(),
|
||||
});
|
||||
}
|
||||
return {
|
||||
status: 'FAIL',
|
||||
file: test.file,
|
||||
flags: test.currentTestFlag,
|
||||
testId: test.id,
|
||||
description: test.attrs.description,
|
||||
error: inspect(error),
|
||||
stack: reportStack,
|
||||
};
|
||||
}
|
||||
|
||||
const { realm, resolverCache, setPrintHandle } = createRealm({ specifier: test.specifier });
|
||||
const r = realm.scope((): WorkerToSupervisor => {
|
||||
test.attrs.includes.unshift('assert.js', 'sta.js');
|
||||
if (test.attrs.flags.async) {
|
||||
test.attrs.includes.unshift('doneprintHandle.js');
|
||||
}
|
||||
|
||||
for (const include of test.attrs.includes) {
|
||||
if (includeCache[include] === undefined) {
|
||||
const p = path.resolve(TEST262, `harness/${include}`);
|
||||
includeCache[include] = {
|
||||
source: fs.readFileSync(p, 'utf8'),
|
||||
specifier: p,
|
||||
};
|
||||
}
|
||||
const entry = includeCache[include];
|
||||
const completion = realm.evaluateScript(entry.source, { specifier: entry.specifier });
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
return fail(test, completion.Value);
|
||||
}
|
||||
}
|
||||
boostTest262Harness(realm);
|
||||
|
||||
{
|
||||
const DONE = `
|
||||
function $DONE(error) {
|
||||
if (error) {
|
||||
if (typeof error === 'object' && error !== null && 'stack' in error) {
|
||||
print('Test262:AsyncTestFailure:' + error.stack, error);
|
||||
} else {
|
||||
print('Test262:AsyncTestFailure:Test262Error: ' + error, error);
|
||||
}
|
||||
} else {
|
||||
print('Test262:AsyncTestComplete');
|
||||
}
|
||||
}`;
|
||||
const completion = realm.evaluateScript(`\
|
||||
var Test262Error = class Test262Error extends Error {};
|
||||
Test262Error.thrower = (...args) => {
|
||||
throw new Test262Error(...args);
|
||||
};
|
||||
${test.attrs.flags.async ? DONE : ''}`);
|
||||
if (completion instanceof AbruptCompletion) {
|
||||
return fail(test, completion.Value);
|
||||
}
|
||||
}
|
||||
|
||||
let asyncResult: WorkerToSupervisor | undefined;
|
||||
if (test.attrs.flags.async) {
|
||||
setPrintHandle((m, value) => {
|
||||
if (m === 'Test262:AsyncTestComplete') {
|
||||
asyncResult = {
|
||||
status: 'PASS', flags: test.currentTestFlag, testId: test.id, file: test.file,
|
||||
};
|
||||
} else {
|
||||
asyncResult = fail(test, value);
|
||||
}
|
||||
setPrintHandle(undefined);
|
||||
});
|
||||
}
|
||||
|
||||
const specifier = path.resolve(TEST262_TESTS, test.file);
|
||||
|
||||
const completion = evalQ((Q) => {
|
||||
if (test.attrs.flags.module) {
|
||||
const module = Q(realm.compileModule(test.content, { specifier }));
|
||||
resolverCache.set(specifier, module);
|
||||
const loadModuleCompletion = module.LoadRequestedModules();
|
||||
if (loadModuleCompletion.PromiseState === 'rejected') {
|
||||
Q(ThrowCompletion(loadModuleCompletion.PromiseResult!));
|
||||
} else if (loadModuleCompletion.PromiseState === 'pending') {
|
||||
throw new Error('Internal error: .LoadRequestedModules() returned a pending promise');
|
||||
}
|
||||
Q(module.Link());
|
||||
const evaluateCompletion = Q(skipDebugger(module.Evaluate()));
|
||||
if (evaluateCompletion.PromiseState === 'rejected') {
|
||||
Q(ThrowCompletion(evaluateCompletion.PromiseResult!));
|
||||
}
|
||||
} else {
|
||||
Q(realm.evaluateScript(test.content, { specifier }));
|
||||
}
|
||||
});
|
||||
|
||||
if (completion.Type === 'throw') {
|
||||
if (test.attrs.negative && isError(test.attrs.negative.type, completion.Value)) {
|
||||
return {
|
||||
status: 'PASS', flags: test.currentTestFlag, testId: test.id, file: test.file,
|
||||
};
|
||||
} else {
|
||||
return fail(test, completion.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (test.attrs.flags.async) {
|
||||
if (!asyncResult) {
|
||||
throw new Error('missing async result');
|
||||
}
|
||||
return asyncResult;
|
||||
}
|
||||
|
||||
if (test.attrs.negative) {
|
||||
return fails(test, `Expected ${test.attrs.negative.type} during ${test.attrs.negative.phase}`, []);
|
||||
} else {
|
||||
return {
|
||||
status: 'PASS', flags: test.currentTestFlag, testId: test.id, file: test.file,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
function handleSendError(e: any) {
|
||||
if (e) {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function isError(type: string, value: unknown) {
|
||||
if (!(value instanceof ObjectValue)) {
|
||||
return false;
|
||||
}
|
||||
const proto = (value as any).Prototype;
|
||||
if (!proto || !(proto instanceof ObjectValue)) {
|
||||
return false;
|
||||
}
|
||||
const ctorDesc = proto.properties.get(Value('constructor'));
|
||||
if (!ctorDesc || !IsDataDescriptor(ctorDesc)) {
|
||||
return false;
|
||||
}
|
||||
const ctor = ctorDesc.Value;
|
||||
if (!(ctor instanceof ObjectValue) || !IsCallable(ctor)) {
|
||||
return false;
|
||||
}
|
||||
const namePropDesc = ctor.properties.get(Value('name'));
|
||||
if (!namePropDesc || !IsDataDescriptor(namePropDesc)) {
|
||||
return false;
|
||||
}
|
||||
const nameProp = namePropDesc.Value;
|
||||
return nameProp instanceof JSStringValue && nameProp.stringValue() === type;
|
||||
}
|
||||
|
||||
function fails(test: Test, error: string, stack: Stack[]): WorkerToSupervisor {
|
||||
return {
|
||||
status: 'FAIL',
|
||||
file: test.file,
|
||||
flags: test.currentTestFlag,
|
||||
testId: test.id,
|
||||
description: test.attrs.description,
|
||||
error,
|
||||
stack,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { relative } from 'node:path';
|
||||
import util, { styleText } from 'node:util';
|
||||
import { cpus } from 'node:os';
|
||||
import { link } from '../base.mts';
|
||||
import { isCI } from '../tui.mts';
|
||||
|
||||
export const args = util.parseArgs({
|
||||
args: process.argv.slice(2),
|
||||
allowNegative: true,
|
||||
allowPositionals: true,
|
||||
strict: true,
|
||||
options: {
|
||||
'help': { type: 'boolean', short: 'h' },
|
||||
'features': { type: 'string', short: 'f' },
|
||||
'engine-features': { type: 'string', multiple: true, short: 'e' },
|
||||
'update-slow': { type: 'string' },
|
||||
'update-failed': { type: 'boolean', short: 'u' },
|
||||
|
||||
'run-slow': { type: 'boolean' },
|
||||
'failed-only': { type: 'boolean', short: 'f' },
|
||||
'strict-only': { type: 'boolean' },
|
||||
'fast': { type: 'boolean', short: 'q', default: !!isCI },
|
||||
|
||||
'verbose': { type: 'boolean', short: 'v' },
|
||||
'vv': { type: 'boolean', short: 'V' },
|
||||
},
|
||||
});
|
||||
|
||||
async function main() {
|
||||
if (args.values.help) {
|
||||
const TEST_PATTERN = styleText('gray', '[TEST-PATTERN]');
|
||||
const SLOW_LIST = link('the slow list file', new URL('./slow', import.meta.url));
|
||||
const LAST_FAILED_LIST = link('last-failed-list', new URL('./last-failed-list', import.meta.url));
|
||||
const LOCAL_FILE = styleText('gray', '(Local file)');
|
||||
const usage = `
|
||||
Usage: node ${relative(process.cwd(), import.meta.filename)} ${TEST_PATTERN} ...
|
||||
Run ${link('test262 tests', 'https://github.com/tc39/test262')} against engine262.
|
||||
|
||||
${TEST_PATTERN} supports glob syntax, and is interpreted relative to
|
||||
${link('the test262 "test" subdirectory', new URL('./test262/test262/test/', import.meta.url))} or (if that fails for any pattern)
|
||||
relative to the working directory. If no patterns are specified,
|
||||
all tests are run.
|
||||
|
||||
${styleText('magentaBright', 'Environment variables:')}
|
||||
${styleText('magenta', 'TEST262')} ${styleText('gray', process.env.TEST262 ? `(set to '${process.env.TEST262}')` : '(unset)')}
|
||||
The test262 directory, which contains the "test" subdirectory.
|
||||
If empty, it defaults to the "test262" sibling of this file.
|
||||
${styleText('magenta', 'NUM_WORKERS')} ${styleText('gray', process.env.NUM_WORKERS ? `(set to '${process.env.NUM_WORKERS}')` : '(unset)')}
|
||||
The count of child processes that should be created to run tests.
|
||||
If empty, it defaults to ${cpus().length}.
|
||||
|
||||
${styleText('greenBright', 'Options:')}
|
||||
${styleText('green', '--features / -f')} ${styleText('gray', '[feature]')}
|
||||
Only run tests that has the specified feature.
|
||||
${styleText('green', '--engine-features / -e')} ${styleText('gray', '[feature]')}
|
||||
Enable specified engine features during test execution.
|
||||
${styleText('green', '--update-slow')} ${styleText('gray', '[seconds]')}
|
||||
Append tests that take longer than the given time to ${SLOW_LIST}.
|
||||
${styleText('green', '--update-failed / -u')}
|
||||
Append failed tests to ${link('the failed list', new URL('./failed', import.meta.url))}.
|
||||
If test in this list passes, it will be an error.
|
||||
${styleText('green', '--run-slow')}
|
||||
Run slow tests that are listed in ${SLOW_LIST}.
|
||||
${styleText('green', '--failed-only / -f')}
|
||||
Run only the tests that failed in the previous run.
|
||||
Listed in ${LAST_FAILED_LIST}.
|
||||
${styleText('green', '--strict-only / --fast / --q')}
|
||||
Only run strict mode tests.
|
||||
${styleText('green', '--verbose / -v')}
|
||||
Print why tests are skipped or failed.
|
||||
${styleText('green', '--vv / -V')}
|
||||
Print why tests are skipped or failed, and also print passed tests.
|
||||
|
||||
${styleText('yellowBright', 'Files:')}
|
||||
${link(styleText('yellow', 'features'), new URL('./features', import.meta.url))}
|
||||
Specifies handling of test262 features, notably which ones to skip.
|
||||
${link(styleText('yellow', 'skip'), new URL('./skip', import.meta.url))}
|
||||
Includes patterns of test files to skip.
|
||||
${link(styleText('yellow', 'slow'), new URL('./slow', import.meta.url))}
|
||||
Includes patterns of test files to skip in the absence of ${styleText('green', '--run-slow-tests')}.
|
||||
${link(styleText('yellow', 'failed'), new URL('./failed', import.meta.url))}
|
||||
Includes patterns of test files that are expected to fail.
|
||||
${styleText('yellow', LAST_FAILED_LIST)} ${LOCAL_FILE}
|
||||
The list of test files that failed in the last run.
|
||||
${link(styleText('yellow', 'last-failed.log'), new URL('./last-failed.log', import.meta.url))} ${LOCAL_FILE}
|
||||
The detailed log of test files that failed in the last run.
|
||||
`.slice(1);
|
||||
const indent = usage.match(/^\s*/)![0];
|
||||
process.stdout.write(
|
||||
`${usage
|
||||
.trimEnd()
|
||||
.split('\n')
|
||||
.map((line) => line.replace(indent, ''))
|
||||
.join('\n')}\n`,
|
||||
);
|
||||
process.exit(64);
|
||||
}
|
||||
|
||||
await import('./test262-runner.mts');
|
||||
}
|
||||
main();
|
||||
Reference in New Issue
Block a user