test262/INTERPRETING.md

402 lines
16 KiB
Markdown
Raw Normal View History

# Interpreting Test262 Tests
All tests are declared as text files located within this project's `test`
directory. In order to execute Test262 tests, runtimes must observe the
following semantics.
**Note** When these instructions change in any substantive way, the `version`
property of the JSON-formatted `package.json` file will be incremented. In this
way, consumers who are transitioning between revisions of Test262 can more
easily determine the cause of new test failures.
## Test Execution
Test262 tests are only valid under the runtime environment conditions described
here. Test environments may be further modified according to the metadata
contained with each test--refer to the [Metadata](#metadata) section for more details.
### Realm Isolation
Each test must be executed in a new [ECMAScript
realm](https://tc39.github.io/ecma262/#sec-code-realms) dedicated to that test.
Unless configured otherwise (via the `module` flag), source text must be
interpreted as [global
2017-04-28 01:38:14 +02:00
code](https://tc39.github.io/ecma262/#sec-types-of-source-code).
### Test262-Defined Bindings
The contents of the following files must be evaluated in the test realm's
global scope prior to test execution:
1. `harness/assert.js`
2. `harness/sta.js`
### Host-Defined Functions
The following values must be defined as writable, configurable, non-enumerable
properties of the global scope prior to test execution.
- **`print`** A function that exposes the string value of its first argument to
the test runner. This is used as a communication mechanism for asynchronous
tests (via the `async` flag, described below).
- **`$262`** An ordinary object with the following properties:
- **`createRealm`** - a function which creates a new [ECMAScript
2017-04-28 01:38:14 +02:00
Realm](https://tc39.github.io/ecma262/#sec-code-realms),
defines this API on the new realm's global object, and returns the `$262`
property of the new realm's global object
- **`detachArrayBuffer`** - a function which implements [the
DetachArrayBuffer abstract
2017-04-28 01:38:14 +02:00
operation](https://tc39.github.io/ecma262/#sec-detacharraybuffer)
- **`evalScript`** - a function which accepts a string value as its first
2020-02-27 01:59:26 +01:00
argument and executes it as [an ECMAScript
2017-04-28 01:38:14 +02:00
script](https://tc39.github.io/ecma262/#sec-scripts) according to the
following algorithm:
1. Let hostDefined be any host-defined values for the provided
sourceText (obtained in an implementation dependent manner)
2. Let realm be the current Realm Record.
3. Let s be ParseScript(sourceText, realm, hostDefined).
4. If s is a List of errors, then
a. Let error be the first element of s.
b. Return
Completion{[[Type]]: throw, [[Value]]: error, [[Target]]: empty}.
5. Let status be ScriptEvaluation(s).
6. Return Completion(status).
- **`gc`** - a function that wraps the host's garbage collection invocation mechanism, if such a capability exists. Must throw an exception if no capability exists. This is necessary for testing the semantics of any feature that relies on garbage collection, e.g. the `WeakRef` API.
- **`global`** - a reference to the global object on which `$262` was initially defined
- **`IsHTMLDDA`** - (present only in implementations that can provide it) an
object that 1) has an [[IsHTMLDDA]] internal slot, and 2) when called with
no arguments or with the single argument `""` returns `null`. Use this
property to test that ECMAScript algorithms aren't mis-implemented to treat
`document.all` as being `undefined` or of type Undefined (instead of
Object). (The peculiar second requirement permits testing algorithms when
they also call `document.all` with such arguments, so that testing for
correct behavior requires knowing how the call behaves. This is rarely
necessary.) Tests using this function must be tagged with the `IsHTMLDDA`
feature so that only hosts supporting this property will run them.
- **`agent`** - an ordinary object with the following properties:
- **`start`** - a function that takes a script source string and runs
the script in a concurrent agent. Will block until that agent is
running. The agent has no representation. The agent script will be
run in an environment that has an object `$262` with a property `agent`
with the following properties:
2017-04-28 01:38:14 +02:00
- **`receiveBroadcast`** - a function that takes a function and
calls the function when it has received a broadcast from the parent,
passing it the broadcast as two arguments, a SharedArrayBuffer and
an Int32 or BigInt. This function may return before a broadcast is received
(eg to return to an event loop to await a message) and no code should
follow the call to this function.
- **`report`** - a function that accepts a single "message" argument,
which is converted to a string\* and placed in a transmit queue whence the parent will retrieve it. Messages should be short. (\* Note that string conversion has been implicit since the introduction of this host API, but is now explicit.)
- **`sleep`** - a function that takes a millisecond argument and
sleeps the agent for approximately that duration.
- **`leaving`** - a function that signals that the agent is done and
may be terminated (if possible).
2018-04-27 16:29:27 +02:00
- **`monotonicNow`** - a function that returns a value that conforms to [`DOMHighResTimeStamp`][] and is produced in such a way that its semantics conform to **[Monotonic Clock][]**.
- **`broadcast`** - a function that takes a SharedArrayBuffer and an
Int32 or BigInt and broadcasts the two values to all concurrent
agents. The function blocks until all agents have retrieved the
message. Note, this assumes that all agents that were started are
still running.
- **`getReport`** - a function that reads an incoming string from any agent,
and returns it if it exists, or returns `null` otherwise.
- **`sleep`** - a function that takes a millisecond argument and
sleeps the execution for approximately that duration.
- **`monotonicNow`** - a function that returns a value that conforms to [`DOMHighResTimeStamp`][] and is produced in such a way that its semantics conform to **[Monotonic Clock][]**.
2018-04-27 16:29:27 +02:00
In addition, consumers may choose to override any of the [the available test harness helper functions](https://github.com/tc39/test262/blob/master/CONTRIBUTING.md#test-environment) as they see fit. See [the documentation on handling errors and negative test cases](https://github.com/tc39/test262/blob/master/CONTRIBUTING.md#handling-errors-and-negative-test-cases) for a useful example of this.
2018-04-27 16:29:27 +02:00
#### Normative references
[`DOMHighResTimeStamp`][], **[Monotonic Clock][]**<br>
Ilya Grigorik, James Simonsen, Jatinder Mann.<br>
[High Resolution Time Level 2](https://www.w3.org/TR/hr-time-2/) March 2018. W3C. URL: [https://www.w3.org/TR/hr-time-2/](https://www.w3.org/TR/hr-time-2/)
[`DOMHighResTimeStamp`]: https://www.w3.org/TR/hr-time-2/#sec-domhighrestimestamp "**DOMHighResTimeStamp**"
[Monotonic Clock]: https://www.w3.org/TR/hr-time-2/#sec-monotonic-clock "**Monotonic Clock**"
### Strict Mode
Unless configured otherwise (via the `noStrict`, `onlyStrict`, `module`, or
`raw` flags), each test must be executed twice: once in ECMAScript's non-strict
mode, and again in ECMAScript's strict mode. To run in strict mode, the test
contents must be modified prior to execution--[a "use strict"
directive](https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive)
must be inserted as the initial character sequence of the file, followed by a
semicolon (`;`) and newline character (`\n`):
"use strict";
This must precede any additional text modifications described by test metadata.
2016-06-21 18:17:51 +02:00
### Modules
Test262 includes tests for ECMAScript 2015 module code, denoted by the "module"
metadata flag. Files bearing a name ending in `_FIXTURE.js` **MUST NOT** be interpreted as standalone tests; they are intended to be referenced by test files. Realm modifications, including [Test262-Defined Bindings](#test262-defined-bindings) and [Host-Defined Functions](#host-defined-functions), are not applied to code executed from `_FIXTURE.js` files. See the [**Rules For Module `_FIXTURE.js` Files** section of CONTRIBUTING.md](https://github.com/tc39/test262/blob/master/CONTRIBUTING.md#rules-for-module-fixturejs-files) for more information.
2016-06-21 18:17:51 +02:00
All module specifiers used by Test262 begin with the character sequence `./`.
The remaining characters should be interpreted as the name of a file within the
same directory as the file under test. The contents of this file must be
interpreted as UTF-8-encoded text and supplied to the Source Text Module
Record's ParseModule abstract operation. The result of that operation must be
returned by the implementation-defined HostResolveImportedModule directly.
For example, consider a test file located at
`test/language/import/nested/index.js` with the following contents:
```js
import * as ns from './dep.js';
```
Implementers should attempt to resolve this module specifier by loading a file
located at `test/language/import/nested/dep.js`.
## Test Results
By default, tests signal failure by generating an uncaught exception. If
execution completes without generating an exception, the test must be
interpreted as "passing." Any uncaught exception must be interpreted as test
failure. These semantics may be modified by any test according to the metadata
declared within the test itself (via the `negative` attribute and the `async`
flag, described below).
## Metadata
Each test file may define metadata that describe additional requirements. This
information is delimited by the token sequence `/*---` and `---*/` and is
structured as [YAML](http://yaml.org/).
### `negative`
These tests are expected to generate an uncaught exception. The value of this
2016-03-13 18:26:10 +01:00
attribute is a YAML dictonary with two keys:
- `phase` - the stage of the test interpretation process that the error is
expected to be produced; valid phases are:
- `parse`: occurs while parsing the source text.
- `early`: occurs prior to evaluation.
- `resolution`: occurs during module resolution.
- `runtime`: occurs during evaluation.
2016-03-13 18:26:10 +01:00
- `type` - the name of the constructor of the expected error
If a test configured with the `negative` attribute completes without throwing
an exception, or if the name of the thrown exception's constructor does not
match the specified constructor name, or if the error occurs at a phase that
differs from the indicated phase, the test must be interpreted as "failing."
*Examples:*
```js
/*---
2016-03-13 18:26:10 +01:00
negative:
phase: runtime
type: ReferenceError
---*/
unresolvable;
```
```js
/*---
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
var a\u2E2F;
```
```js
/*---
negative:
phase: resolution
type: ReferenceError
flags: [module]
---*/
$DONOTEVALUATE();
export {} from './instn-resolve-empty-export_FIXTURE.js';
// instn-resolve-empty-export_FIXTURE.js contains only:
// 0++;
```
### `includes`
One or more files whose content must be evaluated in the test realm's global
scope prior to test execution. These files are located within the `harness/`
directory of the Test262 project.
*Example*
```js
/*---
includes: [propertyHelper.js]
---*/
verifyProperty(this, "Object", {
value: Object,
writable: true,
enumerable: false,
configurable: true,
});
```
### `flags`
The `flags` attribute is an optional value that specifies one or more of the
following strings:
- **`onlyStrict`** The test must be executed just once--in strict mode, only.
This must be accomplished using the transformation described in the section
titled "Strict Mode".
*Example*
```js
/*---
flags: [onlyStrict]
---*/
var thisVal = null;
[null].forEach(function() {
thisVal = this;
});
assert.sameValue(thisVal, undefined);
```
- **`noStrict`** The test must be executed just once--in non-strict mode, only.
In other words, the transformation described by the section titled "Strict
Mode" must **not** be applied to these tests.
*Example*
```js
/*---
flags: [noStrict]
---*/
var thisVal = null;
[null].forEach(function() {
thisVal = this;
});
assert.notSameValue(thisVal, undefined);
assert.sameValue(thisVal, this);
```
- **`module`** The test source code must be interpreted as [module
2017-04-28 01:38:14 +02:00
code](https://tc39.github.io/ecma262/#sec-types-of-source-code).
In addition, this flag negates the default requirement to execute the test
both in strict mode and in non-strict mode. In other words, the
transformation described by the section titled "Strict Mode" must **not** be
2016-06-21 18:17:51 +02:00
applied to these tests. Refer to the section titled "Modules" for more
information on interpreting these tests.
*Example*
```js
/*---
flags: [module]
---*/
export default function* g() {}
```
- **`raw`** The test source code must not be modified in any way, and the test
must be executed just once (in non-strict mode, only).
*Example*
```js
/*---
flags: [raw]
---*/
'use strict'
[0]
's'.p = null;
```
- **`async`** The file `harness/doneprintHandle.js` must be evaluated in the
test realm's global scope prior to test execution. The test must not be
considered complete until the implementation-defined `print` function has
been invoked or some length of time has passed without any such invocation.
In the event of a passing test run, this function will be invoked with the
string `'Test262:AsyncTestComplete'`. If invoked with a string that is
prefixed with the character sequence `Test262:AsyncTestFailure:`, the test
must be interpreted as failed. The implementation is free to select an
appropriate length of time to wait before considering the test "timed out"
and failing.
*Example*
```js
/*---
flags: [async]
---*/
Promise.resolve()
.then(function() {
print('Test262:AsyncTestComplete');
}, function(reason) {
print('Test262:AsyncTestFailure: ' + reason);
});
```
- **`generated`** The test file was created procedurally using the project's
test generation tool. This flag is specified for informational purposes only
and has no bearing on how the test should be interpreted.
Make Atomics tests more resilient against intermittent failures (#1617) Also fixes multiple issues and bugs in various Atomics tests. CONTRIBUTING.md and INTERPRETING.md: - Add missing description for `CanBlockIsFalse` flag and also introduce `CanBlockIsTrue` flag which is needed for some tests (see below). harness/atomicsHelper.js: - Updated `$262.agent.waitUntil` to clarify it can also be called with BigInt64Array objects. - Added `$262.agent.timeouts` constants to unify the various, inconsistently used timeouts in the Atomics tests. Each timeout constant has a brief description and a usage example to clarify when it should or should not be used. The default values were tested in SpiderMonkey (locally and CI) under various system load levels and should hopefully also be valid for other engines. - Added `$262.agent.tryYield` to yield control from the main thread. The default implementation simply calls `$262.agent.sleep`, but test262 hosts could theoretically provide a different implementation. - Added `$262.agent.trySleep` to replace direct calls to `$262.agent.sleep` from the main thread. Motivation for this function: Some test262 hosts (like browsers) may be able to pause and sleep on the main thread, so they could provide their implementation for `trySleep` which performs a busy-wait or something do nothing. harness/testAtomics.js: - Replace `let`, `arrow-functions`, and `for-of` loops to avoid creating extremely long `features` lists in tests using this helper. Removed `Map`, `WeakMap`, `Set`, and `WeakSet` (these weren't even listed in features.yaml) for the same reason and added the missing `Symbol` entry for this file to features.yaml. - Updated all files including "harness/testAtomics.js" to match the new feature requirements. test/built-ins/Atomics/store/good-views.js and test/built-ins/Atomics/store/bigint/good-views.js: - Replace `arrow-functions` and `for-of` loops with ES5 alternatives. test/built-ins/Atomics/wait/bigint/*.js and test/built-ins/Atomics/wake/bigint/*.js - Some tests were using `BigInt64Array.BYTES_PER_ELEMENT * 8` for the SharedArrayBuffer length, but their non-BigInt counterparts are using `Int32Array.BYTES_PER_ELEMENT * 4`. For consistency and to make it easier to compare the BigInt against the non-BigInt versions, I've changed it to `BigInt64Array.BYTES_PER_ELEMENT * 4`. - Also aligned formatting and statement placement when they differed between the non-BigInt and the BigInt version of a test file. (I've diffed some of the non-BigInt and BigInt files against each other and different formatting was a nuisance.) Test files using `$262.agent.monotonicNow()`: - Moved `$262.agent.report()` calls outside of the block of code measured `$262.agent.monotonicNow()` to avoid measuring how long it takes to execute `$262.agent.report()`. - Without this change some tests failed intermittently in certain test configurations in SpiderMonkey. For example with the flags `--ion-eager -- ion-offthread-compile=off` which forces early Ion compilation on the main thread. The `$262.agent.report()` implementation in the SpiderMonkey test262 host embedding uses a for-loop which was forcefully Ion compiled under these settings. And because Ion compilation can take some time, the test case ran longer than `$262.agent.MAX_TIME_EPSILON` which lead to intermittent failures. Test files using `CanBlockIsFalse` / `CanBlockIsTrue`: - Some of these tests actually expected that the main thread can wait and [[CanBlock]] is `true` for the agent record executing the test. Therefore I've added a new `CanBlockIsTrue` flag and replaced the flags where needed. test/built-ins/Atomics/wait/**/*.js and test/built-ins/Atomics/wake/**/*.js: - Use an atomic counter `RUNNING` in more tests to have better control when a worker agent was actually started. - Replace the various `$262.agent.sleep(/* Sleep X ms to ensure worker actually sleeps */)` calls with the new `$262.agent.tryYield()` function. This `X` was sometimes as low as 10 milliseconds, which is definitely too short for CI systems under heavy load (observed by intermittent CI failures for SpiderMonkey) and sometimes as high as 500 milliseconds, which is probably much longer than needed even when the system is under heavy load. - Removed duplicate strings in assertion messages, presumably from copy-pasting the messages between different files. - Removed extra empty lines at the end of multiple files. test/built-ins/Atomics/wake/bad-range.js, test/built-ins/Atomics/wake/bigint/bad-range.js, and test/built-ins/Atomics/wait/bigint/non-bigint64-typedarray-throws.js: - Removed unnecessary `features` and `includes` from this file. test/built-ins/Atomics/wait/waiterlist-order-of-operations-is-fifo.js and test/built-ins/Atomics/wait/bigint/waiterlist-order-of-operations-is-fifo.js: - The test was actually broken and didn't test what it said it does. This probably explains #1530. - The test wants to ensure the waiterlist is implemented as a FIFO structure. This requires that the waiting agents all wait on the same index position, because the waiterlists are defined by each index. But if the agents wait on different indices, each agent is inserted into a different FIFO structure and therefore we can't observe any FIFO ordering between the agents when they're woken up. - All this requires a bit of synchronization between the main agent and the waiting agent, I hope the added comments help to review these changes. test/built-ins/Atomics/wait/good-views.js: - The agent sends multiple reports to the main agent, but only the first one was read. - This error was introduced during previous refactorings. I've changed it to back to use a while-loop as used in the first version of this file. test/built-ins/Atomics/wait/no-spurious-wakeup-no-operation.js: - Only the BigInt version of this test was present, copied it so we also get code coverage for the non-BigInt case. test/built-ins/Atomics/wait/waiterlist-block-indexedposition-wake.js: - Added extra while loops to avoid intermittent failures when the agent worker haven't started to wait. - This should help to avoid some of the intermittent failures we saw for SpiderMonkey. test/built-ins/Atomics/wake/wake-all-on-loc.js and test/built-ins/Atomics/wake/bigint/wake-all-on-loc.js: - This test was also no longer after previous refactoring sessions. - The "B" agent only waited for 10 milliseconds, which made it likely that it already timed out before the main agent was able to call `Atomics.wake`, which in turn rendered the test useless, because the test case wants to ensure that `Atomics.wake` cannot wake "B". But if "B" was already timed out, it can trivially not be woken by `Atomics.wake`. - Added some safety measure to catch the case when "B" timed out before `Atomics.wake` was called and made it a test error if that happens. test/built-ins/Atomics/wake/count-defaults-to-infinity-missing.js, test/built-ins/Atomics/wake/count-defaults-to-infinity-undefined.js, and test/built-ins/Atomics/wake/undefined-index-defaults-to-zero.js: - Changed the `$262.agent.start()` calls to use a for-loop to avoid code duplication. - (Forgot to undo the code formatting around `assert.sameValue`, still need to change it back.) - Also more while-loops around `Atomics.wake`. - These changes should fix #1529 and #1566. test/built-ins/Atomics/wake/wake-all.js: - Removed "B" worker agent. - Without this removal the test case would be exactly equal to test/built-ins/Atomics/wake/wake-all-on-loc.js. test/built-ins/Atomics/wake/wake-in-order-one-time.js: - Add for-loops to avoid code duplication and make the test more readable. - Make the `Atomics.wake` assertion messages unique by adding the current loop counter. - Add `$262.agent.tryYield()` to give the worker agents enough time to actually start waiting. test/built-ins/Atomics/wake/wake-in-order.js: - Removed the outer loop `attempt < 10` because it uses `$262.agent` in a way currently not required to work. And which actually also doesn't work in SpiderMonkey's implementation of `$262.agent`. - According to INTERPRETING.md `$262.agent.broadcast()` broadcasts its message to all agents ever started by `$262.agent.start()` and then blocks until all agents received the broadcast. It is not required that the agents started by the first `$262.agent.broadcast()` call will all be disabled/destroyed/whatever when the second `$262.agent.broadcast()` call occurs, which then means the second `$262.agent.broadcast()` call still tries to reach the agents started in the first loop iteration, but these may no longer accept broadcasts and therefore won't acknowledge they've received the broadcast. Which then means the second `$262.agent.broadcast()` call waits forever.
2018-07-03 18:34:54 +02:00
- **`CanBlockIsFalse`** The test file should only be run when the [[CanBlock]] property of the [Agent Record](https://tc39.github.io/ecma262/#sec-agents) executing the file is `false`.
*Example*
```js
/*---
flags: [CanBlockIsFalse]
---*/
var i32 = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
assert.throws(TypeError, function() { Atomics.wait(i32, 0, 0, 1000); });
```
- **`CanBlockIsTrue`** The test file should only be run when the [[CanBlock]] property of the [Agent Record](https://tc39.github.io/ecma262/#sec-agents) executing the file is `true`.
*Example*
```js
/*---
flags: [CanBlockIsTrue]
---*/
var i32 = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
Atomics.wait(i32, 0, 0, 1000); // Sleep for one second.
```
2019-09-19 22:14:31 +02:00
- **`non-deterministic`** Due to implementation defined parts in the matching
specs, a test may have more than one path to pass, without failures during
the execution. While passing state still refers to a compatible implementation,
it doesn't guarantee all the assertions in the test will execute. In the same
way, it's not possible to tell the assertions would pass whenever they are
executed.
### `locale`
The `locale` attribute allows tests to declare explicit information regarding locale specificity. Its value is an array of one or more valid language tags or subtags.
*Example*
```js
/*---
locale: [en, en-US, ar]
---*/
var en = new Intl.PluralRules('en');
assert.sameValue(en.select(1), 'one', 'en.select(1) returns "one"');
assert.sameValue(en.select(2), 'other', 'en.select(2) returns "other"');
var enUS = new Intl.PluralRules('en-US');
assert.sameValue(enUS.select(1), 'one', 'enUS.select(1) returns "one"');
assert.sameValue(enUS.select(2), 'other', 'enUS.select(2) returns "other"');
var ar = new Intl.PluralRules('ar');
assert.sameValue(ar.select(1), 'one', 'ar.select(1) returns "one"');
assert.sameValue(ar.select(2), 'other', 'ar.select(2) returns "two"');
```