[Streams API] Import the web-platform-tests directly from the spec
authorcalvaris@igalia.com <calvaris@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 Dec 2015 13:09:20 +0000 (13:09 +0000)
committercalvaris@igalia.com <calvaris@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 9 Dec 2015 13:09:20 +0000 (13:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=152051

Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

These are the web platform tests imported directly (or almost) from the Streams API repository. Tests work out
of the box (all but a small flakiness that we are forcing as failure to not disrupt the execution of the rest of
tests).

To make them work we are importing also the service worker test helpers that is used by the tests.

* web-platform-tests/service-workers/service-workers/resources/README.txt: Added.
* web-platform-tests/service-workers/service-workers/resources/test-helpers.js: Added. Imported from the web-platform-tests.
* web-platform-tests/streams-api/README.txt: Added.
* web-platform-tests/streams-api/byte-length-queuing-strategy-expected.txt: Added.
* web-platform-tests/streams-api/byte-length-queuing-strategy.html: Added.
* web-platform-tests/streams-api/byte-length-queuing-strategy.js: Added.
* web-platform-tests/streams-api/count-queuing-strategy-expected.txt: Added.
* web-platform-tests/streams-api/count-queuing-strategy.html: Added.
* web-platform-tests/streams-api/count-queuing-strategy.js: Added.
* web-platform-tests/streams-api/readable-streams/bad-strategies-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/bad-strategies.html: Added.
* web-platform-tests/streams-api/readable-streams/bad-strategies.js: Added.
* web-platform-tests/streams-api/readable-streams/bad-underlying-sources-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/bad-underlying-sources.html: Added.
* web-platform-tests/streams-api/readable-streams/bad-underlying-sources.js: Added.
* web-platform-tests/streams-api/readable-streams/brand-checks-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/brand-checks.html: Added.
* web-platform-tests/streams-api/readable-streams/brand-checks.js: Added.
* web-platform-tests/streams-api/readable-streams/cancel-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/cancel.html: Added. There's a test with a forced failure
because it is flaky.
* web-platform-tests/streams-api/readable-streams/cancel.js: Added.
* web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.html: Added.
* web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.js: Added.
* web-platform-tests/streams-api/readable-streams/garbage-collection-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/garbage-collection.html: Added.
* web-platform-tests/streams-api/readable-streams/garbage-collection.js: Added.
* web-platform-tests/streams-api/readable-streams/general-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/general.html: Added.
* web-platform-tests/streams-api/readable-streams/general.js: Added.
* web-platform-tests/streams-api/readable-streams/pipe-through-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/pipe-through.html: Added.
* web-platform-tests/streams-api/readable-streams/pipe-through.js: Added.
* web-platform-tests/streams-api/readable-streams/readable-stream-reader-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/readable-stream-reader.html: Added.
* web-platform-tests/streams-api/readable-streams/readable-stream-reader.js: Added.
* web-platform-tests/streams-api/readable-streams/tee-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/tee.html: Added.
* web-platform-tests/streams-api/readable-streams/tee.js: Added.
* web-platform-tests/streams-api/readable-streams/templated-expected.txt: Added.
* web-platform-tests/streams-api/readable-streams/templated.html: Added.
* web-platform-tests/streams-api/readable-streams/templated.js: Added.
* web-platform-tests/streams-api/resources/rs-test-templates.js: Added.
* web-platform-tests/streams-api/resources/rs-utils.js: Added.
* web-platform-tests/streams-api/resources/test-initializer.js: Added.
* web-platform-tests/streams-api/resources/test-utils.js: Added.

LayoutTests:

Removed the tests that are already imported directly from the spec.

* streams/brand-checks-expected.txt: Added.
* streams/brand-checks.html: Added. This includes some tests that vanished from the spec.
* streams/reference-implementation/bad-strategies-expected.txt:
* streams/reference-implementation/bad-strategies.html:
* streams/reference-implementation/bad-underlying-sources.html: Removed.
* streams/reference-implementation/brand-checks-expected.txt:
* streams/reference-implementation/brand-checks.html:
* streams/reference-implementation/byte-length-queuing-strategy-expected.txt:
* streams/reference-implementation/byte-length-queuing-strategy.html:
* streams/reference-implementation/count-queuing-strategy-expected.txt:
* streams/reference-implementation/count-queuing-strategy.html:
* streams/reference-implementation/readable-stream-cancel.html: Removed.
* streams/reference-implementation/readable-stream-reader.html: Removed.
* streams/reference-implementation/readable-stream-tee.html: Removed.
* streams/reference-implementation/readable-stream-templated-expected.txt:
* streams/reference-implementation/readable-stream-templated.html:
* streams/reference-implementation/readable-stream.html: Removed.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@193824 268f45cc-cd09-0410-ab3c-d52691b4dbfc

65 files changed:
LayoutTests/ChangeLog
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-workers/resources/README.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-workers/resources/test-helpers.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/README.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/rs-test-templates.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/rs-utils.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/test-initializer.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/test-utils.js [new file with mode: 0644]
LayoutTests/streams/brand-checks-expected.txt [new file with mode: 0644]
LayoutTests/streams/brand-checks.html [new file with mode: 0644]
LayoutTests/streams/reference-implementation/bad-strategies-expected.txt
LayoutTests/streams/reference-implementation/bad-strategies.html
LayoutTests/streams/reference-implementation/bad-underlying-sources.html [deleted file]
LayoutTests/streams/reference-implementation/brand-checks-expected.txt
LayoutTests/streams/reference-implementation/brand-checks.html
LayoutTests/streams/reference-implementation/byte-length-queuing-strategy-expected.txt
LayoutTests/streams/reference-implementation/byte-length-queuing-strategy.html
LayoutTests/streams/reference-implementation/count-queuing-strategy-expected.txt
LayoutTests/streams/reference-implementation/count-queuing-strategy.html
LayoutTests/streams/reference-implementation/readable-stream-cancel.html [deleted file]
LayoutTests/streams/reference-implementation/readable-stream-reader.html [deleted file]
LayoutTests/streams/reference-implementation/readable-stream-tee.html [deleted file]
LayoutTests/streams/reference-implementation/readable-stream-templated-expected.txt
LayoutTests/streams/reference-implementation/readable-stream-templated.html
LayoutTests/streams/reference-implementation/readable-stream.html [deleted file]

index 0070c9f..d01fa9e 100644 (file)
@@ -1,3 +1,30 @@
+2015-12-09  Xabier Rodriguez Calvar  <calvaris@igalia.com>
+
+        [Streams API] Import the web-platform-tests directly from the spec
+        https://bugs.webkit.org/show_bug.cgi?id=152051
+
+        Reviewed by Youenn Fablet.
+
+        Removed the tests that are already imported directly from the spec.
+
+        * streams/brand-checks-expected.txt: Added.
+        * streams/brand-checks.html: Added. This includes some tests that vanished from the spec.
+        * streams/reference-implementation/bad-strategies-expected.txt:
+        * streams/reference-implementation/bad-strategies.html:
+        * streams/reference-implementation/bad-underlying-sources.html: Removed.
+        * streams/reference-implementation/brand-checks-expected.txt:
+        * streams/reference-implementation/brand-checks.html:
+        * streams/reference-implementation/byte-length-queuing-strategy-expected.txt:
+        * streams/reference-implementation/byte-length-queuing-strategy.html:
+        * streams/reference-implementation/count-queuing-strategy-expected.txt:
+        * streams/reference-implementation/count-queuing-strategy.html:
+        * streams/reference-implementation/readable-stream-cancel.html: Removed.
+        * streams/reference-implementation/readable-stream-reader.html: Removed.
+        * streams/reference-implementation/readable-stream-tee.html: Removed.
+        * streams/reference-implementation/readable-stream-templated-expected.txt:
+        * streams/reference-implementation/readable-stream-templated.html:
+        * streams/reference-implementation/readable-stream.html: Removed.
+
 2015-12-09  Joanmarie Diggs  <jdiggs@igalia.com>
 
         [AX][GTK] combobox-descendants-orientation-crash.html needs new baseline after r190648
index bb6e304..3fa59dd 100644 (file)
@@ -1,3 +1,64 @@
+2015-12-09  Xabier Rodriguez Calvar  <calvaris@igalia.com>
+
+        [Streams API] Import the web-platform-tests directly from the spec
+        https://bugs.webkit.org/show_bug.cgi?id=152051
+
+        Reviewed by Youenn Fablet.
+
+        These are the web platform tests imported directly (or almost) from the Streams API repository. Tests work out
+        of the box (all but a small flakiness that we are forcing as failure to not disrupt the execution of the rest of
+        tests).
+
+        To make them work we are importing also the service worker test helpers that is used by the tests.
+
+        * web-platform-tests/service-workers/service-workers/resources/README.txt: Added.
+        * web-platform-tests/service-workers/service-workers/resources/test-helpers.js: Added. Imported from the web-platform-tests.
+        * web-platform-tests/streams-api/README.txt: Added.
+        * web-platform-tests/streams-api/byte-length-queuing-strategy-expected.txt: Added.
+        * web-platform-tests/streams-api/byte-length-queuing-strategy.html: Added.
+        * web-platform-tests/streams-api/byte-length-queuing-strategy.js: Added.
+        * web-platform-tests/streams-api/count-queuing-strategy-expected.txt: Added.
+        * web-platform-tests/streams-api/count-queuing-strategy.html: Added.
+        * web-platform-tests/streams-api/count-queuing-strategy.js: Added.
+        * web-platform-tests/streams-api/readable-streams/bad-strategies-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/bad-strategies.html: Added.
+        * web-platform-tests/streams-api/readable-streams/bad-strategies.js: Added.
+        * web-platform-tests/streams-api/readable-streams/bad-underlying-sources-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/bad-underlying-sources.html: Added.
+        * web-platform-tests/streams-api/readable-streams/bad-underlying-sources.js: Added.
+        * web-platform-tests/streams-api/readable-streams/brand-checks-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/brand-checks.html: Added.
+        * web-platform-tests/streams-api/readable-streams/brand-checks.js: Added.
+        * web-platform-tests/streams-api/readable-streams/cancel-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/cancel.html: Added. There's a test with a forced failure
+        because it is flaky.
+        * web-platform-tests/streams-api/readable-streams/cancel.js: Added.
+        * web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.html: Added.
+        * web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.js: Added.
+        * web-platform-tests/streams-api/readable-streams/garbage-collection-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/garbage-collection.html: Added.
+        * web-platform-tests/streams-api/readable-streams/garbage-collection.js: Added.
+        * web-platform-tests/streams-api/readable-streams/general-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/general.html: Added.
+        * web-platform-tests/streams-api/readable-streams/general.js: Added.
+        * web-platform-tests/streams-api/readable-streams/pipe-through-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/pipe-through.html: Added.
+        * web-platform-tests/streams-api/readable-streams/pipe-through.js: Added.
+        * web-platform-tests/streams-api/readable-streams/readable-stream-reader-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/readable-stream-reader.html: Added.
+        * web-platform-tests/streams-api/readable-streams/readable-stream-reader.js: Added.
+        * web-platform-tests/streams-api/readable-streams/tee-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/tee.html: Added.
+        * web-platform-tests/streams-api/readable-streams/tee.js: Added.
+        * web-platform-tests/streams-api/readable-streams/templated-expected.txt: Added.
+        * web-platform-tests/streams-api/readable-streams/templated.html: Added.
+        * web-platform-tests/streams-api/readable-streams/templated.js: Added.
+        * web-platform-tests/streams-api/resources/rs-test-templates.js: Added.
+        * web-platform-tests/streams-api/resources/rs-utils.js: Added.
+        * web-platform-tests/streams-api/resources/test-initializer.js: Added.
+        * web-platform-tests/streams-api/resources/test-utils.js: Added.
+
 2015-12-02  Ryan Haddad  <ryanhaddad@apple.com>
 
         Rebaseline imported/w3c/web-platform-tests/html/dom/interfaces.html after r192953
diff --git a/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-workers/resources/README.txt b/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-workers/resources/README.txt
new file mode 100644 (file)
index 0000000..38a16ee
--- /dev/null
@@ -0,0 +1,5 @@
+This file is here because of the importation of Streams API tests that need this file.
+
+When Streams API tests are moved to the web-platform-tests repository, this importation will be automatic.
+
+Current version: https://github.com/w3c/web-platform-tests/blob/188bb569f032b1e78189aef725de3d85b75d944b/service-workers/service-workers/resources/test-helpers.js
diff --git a/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-workers/resources/test-helpers.js b/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-workers/resources/test-helpers.js
new file mode 100644 (file)
index 0000000..147ea61
--- /dev/null
@@ -0,0 +1,222 @@
+// Adapter for testharness.js-style tests with Service Workers
+
+function service_worker_unregister_and_register(test, url, scope) {
+  if (!scope || scope.length == 0)
+    return Promise.reject(new Error('tests must define a scope'));
+
+  var options = { scope: scope };
+  return service_worker_unregister(test, scope)
+    .then(function() {
+        return navigator.serviceWorker.register(url, options);
+      })
+    .catch(unreached_rejection(test,
+                               'unregister and register should not fail'));
+}
+
+function service_worker_unregister(test, documentUrl) {
+  return navigator.serviceWorker.getRegistration(documentUrl)
+    .then(function(registration) {
+        if (registration)
+          return registration.unregister();
+      })
+    .catch(unreached_rejection(test, 'unregister should not fail'));
+}
+
+function service_worker_unregister_and_done(test, scope) {
+  return service_worker_unregister(test, scope)
+    .then(test.done.bind(test));
+}
+
+function unreached_fulfillment(test, prefix) {
+  return test.step_func(function(result) {
+      var error_prefix = prefix || 'unexpected fulfillment';
+      assert_unreached(error_prefix + ': ' + result);
+    });
+}
+
+// Rejection-specific helper that provides more details
+function unreached_rejection(test, prefix) {
+  return test.step_func(function(error) {
+      var reason = error.message || error.name || error;
+      var error_prefix = prefix || 'unexpected rejection';
+      assert_unreached(error_prefix + ': ' + reason);
+    });
+}
+
+// Adds an iframe to the document and returns a promise that resolves to the
+// iframe when it finishes loading. The caller is responsible for removing the
+// iframe later if needed.
+function with_iframe(url) {
+  return new Promise(function(resolve) {
+      var frame = document.createElement('iframe');
+      frame.src = url;
+      frame.onload = function() { resolve(frame); };
+      document.body.appendChild(frame);
+    });
+}
+
+function normalizeURL(url) {
+  return new URL(url, self.location).toString().replace(/#.*$/, '');
+}
+
+function wait_for_update(test, registration) {
+  if (!registration || registration.unregister == undefined) {
+    return Promise.reject(new Error(
+      'wait_for_update must be passed a ServiceWorkerRegistration'));
+  }
+
+  return new Promise(test.step_func(function(resolve) {
+      registration.addEventListener('updatefound', test.step_func(function() {
+          resolve(registration.installing);
+        }));
+    }));
+}
+
+function wait_for_state(test, worker, state) {
+  if (!worker || worker.state == undefined) {
+    return Promise.reject(new Error(
+      'wait_for_state must be passed a ServiceWorker'));
+  }
+  if (worker.state === state)
+    return Promise.resolve(state);
+
+  if (state === 'installing') {
+    switch (worker.state) {
+      case 'installed':
+      case 'activating':
+      case 'activated':
+      case 'redundant':
+        return Promise.reject(new Error(
+          'worker is ' + worker.state + ' but waiting for ' + state));
+    }
+  }
+
+  if (state === 'installed') {
+    switch (worker.state) {
+      case 'activating':
+      case 'activated':
+      case 'redundant':
+        return Promise.reject(new Error(
+          'worker is ' + worker.state + ' but waiting for ' + state));
+    }
+  }
+
+  if (state === 'activating') {
+    switch (worker.state) {
+      case 'activated':
+      case 'redundant':
+        return Promise.reject(new Error(
+          'worker is ' + worker.state + ' but waiting for ' + state));
+    }
+  }
+
+  if (state === 'activated') {
+    switch (worker.state) {
+      case 'redundant':
+        return Promise.reject(new Error(
+          'worker is ' + worker.state + ' but waiting for ' + state));
+    }
+  }
+
+  return new Promise(test.step_func(function(resolve) {
+      worker.addEventListener('statechange', test.step_func(function() {
+          if (worker.state === state)
+            resolve(state);
+        }));
+    }));
+}
+
+// Declare a test that runs entirely in the ServiceWorkerGlobalScope. The |url|
+// is the service worker script URL. This function:
+// - Instantiates a new test with the description specified in |description|.
+//   The test will succeed if the specified service worker can be successfully
+//   registered and installed.
+// - Creates a new ServiceWorker registration with a scope unique to the current
+//   document URL. Note that this doesn't allow more than one
+//   service_worker_test() to be run from the same document.
+// - Waits for the new worker to begin installing.
+// - Imports tests results from tests running inside the ServiceWorker.
+function service_worker_test(url, description) {
+  // If the document URL is https://example.com/document and the script URL is
+  // https://example.com/script/worker.js, then the scope would be
+  // https://example.com/script/scope/document.
+  var scope = new URL('scope' + window.location.pathname,
+                      new URL(url, window.location)).toString();
+  promise_test(function(test) {
+      return service_worker_unregister_and_register(test, url, scope)
+        .then(function(registration) {
+            add_completion_callback(function() {
+                registration.unregister();
+              });
+            return wait_for_update(test, registration)
+              .then(function(worker) {
+                  return fetch_tests_from_worker(worker);
+                });
+          });
+    }, description);
+}
+
+function get_host_info() {
+  var ORIGINAL_HOST = '127.0.0.1';
+  var REMOTE_HOST = 'localhost';
+  var UNAUTHENTICATED_HOST = 'example.test';
+  var HTTP_PORT = 8000;
+  var HTTPS_PORT = 8443;
+  try {
+    // In W3C test, we can get the hostname and port number in config.json
+    // using wptserve's built-in pipe.
+    // http://wptserve.readthedocs.org/en/latest/pipes.html#built-in-pipes
+    HTTP_PORT = eval('{{ports[http][0]}}');
+    HTTPS_PORT = eval('{{ports[https][0]}}');
+    ORIGINAL_HOST = eval('\'{{host}}\'');
+    REMOTE_HOST = 'www1.' + ORIGINAL_HOST;
+  } catch (e) {
+  }
+  return {
+    HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + ':' + HTTP_PORT,
+    HTTPS_ORIGIN: 'https://' + ORIGINAL_HOST + ':' + HTTPS_PORT,
+    HTTP_REMOTE_ORIGIN: 'http://' + REMOTE_HOST + ':' + HTTP_PORT,
+    HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + ':' + HTTPS_PORT,
+    UNAUTHENTICATED_ORIGIN: 'http://' + UNAUTHENTICATED_HOST + ':' + HTTP_PORT
+  };
+}
+
+function base_path() {
+  return location.pathname.replace(/\/[^\/]*$/, '/');
+}
+
+function test_login(test, origin, username, password, cookie) {
+  return new Promise(function(resolve, reject) {
+      with_iframe(
+        origin +
+        '/serviceworker/resources/fetch-access-control-login.html')
+        .then(test.step_func(function(frame) {
+            var channel = new MessageChannel();
+            channel.port1.onmessage = test.step_func(function() {
+                frame.remove();
+                resolve();
+              });
+            frame.contentWindow.postMessage(
+              {username: username, password: password, cookie: cookie},
+              origin, [channel.port2]);
+          }));
+    });
+}
+
+function login(test) {
+  return test_login(test, 'http://127.0.0.1:8000',
+                    'username1', 'password1', 'cookie1')
+    .then(function() {
+        return test_login(test, 'http://localhost:8000',
+                          'username2', 'password2', 'cookie2');
+      });
+}
+
+function login_https(test) {
+  return test_login(test, 'https://127.0.0.1:8443',
+                    'username1s', 'password1s', 'cookie1')
+    .then(function() {
+        return test_login(test, 'https://localhost:8443',
+                          'username2s', 'password2s', 'cookie2');
+      });
+}
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/README.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/README.txt
new file mode 100644 (file)
index 0000000..567ad10
--- /dev/null
@@ -0,0 +1,6 @@
+This directory is imported from the the Streams API repository.
+
+There is a plan to move these tests to web-platform-tests repository so from that moment on this importation will be
+automatic.
+
+Current version: https://github.com/whatwg/streams/tree/18ed463e50c189c0198e2336dfbd10b17f379081/reference-implementation/web-platform-tests
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy-expected.txt
new file mode 100644 (file)
index 0000000..284c6d2
--- /dev/null
@@ -0,0 +1,18 @@
+
+PASS Can construct a ByteLengthQueuingStrategy with a valid high water mark 
+PASS Can construct a ByteLengthQueuingStrategy with any value as its high water mark 
+PASS ByteLengthQueuingStrategy constructor behaves as expected with strange arguments 
+PASS ByteLengthQueuingStrategy size behaves as expected with strange arguments 
+PASS ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments 
+PASS ByteLengthQueuingStrategy instances have the correct properties 
+PASS ByteLengthQueuingStrategy's highWaterMark property can be set to anything 
+FAIL Load byte-length-queuing-strategy.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Can construct a ByteLengthQueuingStrategy with a valid high water mark Can't find variable: ByteLengthQueuingStrategy
+FAIL Can construct a ByteLengthQueuingStrategy with any value as its high water mark Can't find variable: ByteLengthQueuingStrategy
+FAIL ByteLengthQueuingStrategy constructor behaves as expected with strange arguments assert_throws: construction fails with undefined function "() => new ByteLengthQueuingStrategy()" threw object "ReferenceError: Can't find variable: ByteLengthQueuingStr..." ("ReferenceError") expected object "[object Object]" ("TypeError")
+FAIL ByteLengthQueuingStrategy size behaves as expected with strange arguments assert_throws: size fails with undefined function "() => ByteLengthQueuingStrategy.prototype.size()" threw object "ReferenceError: Can't find variable: ByteLengthQueuingStr..." ("ReferenceError") expected object "[object Object]" ("TypeError")
+FAIL ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments Can't find variable: ByteLengthQueuingStrategy
+FAIL ByteLengthQueuingStrategy instances have the correct properties Can't find variable: ByteLengthQueuingStrategy
+FAIL ByteLengthQueuingStrategy's highWaterMark property can be set to anything Can't find variable: ByteLengthQueuingStrategy
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy.html
new file mode 100644 (file)
index 0000000..13f15ac
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="resources/test-initializer.js"></script>
+
+<script src="byte-length-queuing-strategy.js"></script>
+<script>
+'use strict';
+worker_test('byte-length-queuing-strategy.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/byte-length-queuing-strategy.js
new file mode 100644 (file)
index 0000000..54407af
--- /dev/null
@@ -0,0 +1,107 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  new ByteLengthQueuingStrategy({ highWaterMark: 4 });
+
+}, 'Can construct a ByteLengthQueuingStrategy with a valid high water mark');
+
+test(() => {
+
+  for (const highWaterMark of [-Infinity, NaN, 'foo', {}, () => {}]) {
+    const strategy = new ByteLengthQueuingStrategy({ highWaterMark });
+    assert_equals(strategy.highWaterMark, highWaterMark, `${highWaterMark} gets set correctly`);
+  }
+
+}, 'Can construct a ByteLengthQueuingStrategy with any value as its high water mark');
+
+test(() => {
+
+  const highWaterMark = 1;
+  const highWaterMarkObjectGetter = {
+    get highWaterMark() { return highWaterMark; }
+  };
+  const error = new Error('wow!');
+  const highWaterMarkObjectGetterThrowing = {
+    get highWaterMark() { throw error; }
+  };
+
+  assert_throws({ name: 'TypeError' }, () => new ByteLengthQueuingStrategy(), 'construction fails with undefined');
+  assert_throws({ name: 'TypeError' }, () => new ByteLengthQueuingStrategy(null), 'construction fails with null');
+  assert_throws({ name: 'Error' }, () => new ByteLengthQueuingStrategy(highWaterMarkObjectGetterThrowing),
+    'construction fails with an object with a throwing highWaterMark getter');
+
+  // Should not fail:
+  new ByteLengthQueuingStrategy('potato');
+  new ByteLengthQueuingStrategy({});
+  new ByteLengthQueuingStrategy(highWaterMarkObjectGetter);
+
+}, 'ByteLengthQueuingStrategy constructor behaves as expected with strange arguments');
+
+test(() => {
+
+  const size = 1024;
+  const chunk = { byteLength: size };
+  const chunkGetter = {
+    get byteLength() { return size; }
+  };
+  const error = new Error('wow!');
+  const chunkGetterThrowing = {
+    get byteLength() { throw error; }
+  };
+  assert_throws({ name: 'TypeError' }, () => ByteLengthQueuingStrategy.prototype.size(), 'size fails with undefined');
+  assert_throws({ name: 'TypeError' }, () => ByteLengthQueuingStrategy.prototype.size(null), 'size fails with null');
+  assert_equals(ByteLengthQueuingStrategy.prototype.size('potato'), undefined,
+    'size succeeds with undefined with a random non-object type');
+  assert_equals(ByteLengthQueuingStrategy.prototype.size({}), undefined,
+    'size succeeds with undefined with an object without hwm property');
+  assert_equals(ByteLengthQueuingStrategy.prototype.size(chunk), size,
+    'size succeeds with the right amount with an object with a hwm');
+  assert_equals(ByteLengthQueuingStrategy.prototype.size(chunkGetter), size,
+    'size succeeds with the right amount with an object with a hwm getter');
+  assert_throws({ name: 'Error' }, () => ByteLengthQueuingStrategy.prototype.size(chunkGetterThrowing),
+    'size fails with the error thrown by the getter');
+
+}, 'ByteLengthQueuingStrategy size behaves as expected with strange arguments');
+
+test(() => {
+
+  const thisValue = null;
+  const returnValue = { 'returned from': 'byteLength getter' };
+  const chunk = {
+    get byteLength() { return returnValue; }
+  };
+
+  assert_equals(ByteLengthQueuingStrategy.prototype.size.call(thisValue, chunk), returnValue);
+
+}, 'ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments');
+
+test(() => {
+
+  const strategy = new ByteLengthQueuingStrategy({ highWaterMark: 4 });
+
+  assert_object_equals(Object.getOwnPropertyDescriptor(strategy, 'highWaterMark'),
+    { value: 4, writable: true, enumerable: true, configurable: true },
+    'highWaterMark property should be a data property with the value passed the constructor');
+  assert_equals(typeof strategy.size, 'function');
+
+}, 'ByteLengthQueuingStrategy instances have the correct properties');
+
+test(() => {
+
+  const strategy = new ByteLengthQueuingStrategy({ highWaterMark: 4 });
+  assert_equals(strategy.highWaterMark, 4);
+
+  strategy.highWaterMark = 10;
+  assert_equals(strategy.highWaterMark, 10);
+
+  strategy.highWaterMark = 'banana';
+  assert_equals(strategy.highWaterMark, 'banana');
+
+}, 'ByteLengthQueuingStrategy\'s highWaterMark property can be set to anything');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy-expected.txt
new file mode 100644 (file)
index 0000000..2358c5f
--- /dev/null
@@ -0,0 +1,18 @@
+
+PASS Can construct a CountQueuingStrategy with a valid high water mark 
+PASS Can construct a CountQueuingStrategy with any value as its high water mark 
+PASS CountQueuingStrategy constructor behaves as expected with strange arguments 
+PASS CountQueuingStrategy.prototype.size should work generically on its this and its arguments 
+PASS CountQueuingStrategy size behaves as expected with strange arguments 
+PASS CountQueuingStrategy instances have the correct properties 
+PASS CountQueuingStrategy's highWaterMark property can be set to anything 
+FAIL Load count-queuing-strategy.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Can construct a CountQueuingStrategy with a valid high water mark Can't find variable: CountQueuingStrategy
+FAIL Can construct a CountQueuingStrategy with any value as its high water mark Can't find variable: CountQueuingStrategy
+FAIL CountQueuingStrategy constructor behaves as expected with strange arguments assert_throws: construction fails with undefined function "() => new CountQueuingStrategy()" threw object "ReferenceError: Can't find variable: CountQueuingStrategy" ("ReferenceError") expected object "[object Object]" ("TypeError")
+FAIL CountQueuingStrategy.prototype.size should work generically on its this and its arguments Can't find variable: CountQueuingStrategy
+FAIL CountQueuingStrategy size behaves as expected with strange arguments Can't find variable: CountQueuingStrategy
+FAIL CountQueuingStrategy instances have the correct properties Can't find variable: CountQueuingStrategy
+FAIL CountQueuingStrategy's highWaterMark property can be set to anything Can't find variable: CountQueuingStrategy
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy.html
new file mode 100644 (file)
index 0000000..2afd126
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="resources/test-initializer.js"></script>
+
+<script src="count-queuing-strategy.js"></script>
+<script>
+'use strict';
+worker_test('count-queuing-strategy.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/count-queuing-strategy.js
new file mode 100644 (file)
index 0000000..5ae0063
--- /dev/null
@@ -0,0 +1,106 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  new CountQueuingStrategy({ highWaterMark: 4 });
+
+}, 'Can construct a CountQueuingStrategy with a valid high water mark');
+
+test(() => {
+
+  for (const highWaterMark of [-Infinity, NaN, 'foo', {}, () => {}]) {
+    const strategy = new CountQueuingStrategy({ highWaterMark });
+    assert_equals(strategy.highWaterMark, highWaterMark, `${highWaterMark} gets set correctly`);
+  }
+
+}, 'Can construct a CountQueuingStrategy with any value as its high water mark');
+
+test(() => {
+
+  const highWaterMark = 1;
+  const highWaterMarkObjectGetter = {
+    get highWaterMark() { return highWaterMark; }
+  };
+  const error = new Error('wow!');
+  const highWaterMarkObjectGetterThrowing = {
+    get highWaterMark() { throw error; }
+  };
+
+  assert_throws({ name: 'TypeError' }, () => new CountQueuingStrategy(), 'construction fails with undefined');
+  assert_throws({ name: 'TypeError' }, () => new CountQueuingStrategy(null), 'construction fails with null');
+  assert_throws({ name: 'Error' }, () => new CountQueuingStrategy(highWaterMarkObjectGetterThrowing),
+    'construction fails with an object with a throwing highWaterMark getter');
+
+  // Should not fail:
+  new CountQueuingStrategy('potato');
+  new CountQueuingStrategy({});
+  new CountQueuingStrategy(highWaterMarkObjectGetter);
+
+}, 'CountQueuingStrategy constructor behaves as expected with strange arguments');
+
+
+test(() => {
+
+  const thisValue = null;
+  const chunk = {
+    get byteLength() {
+      throw new TypeError('shouldn\'t be called');
+    }
+  };
+
+  assert_equals(CountQueuingStrategy.prototype.size.call(thisValue, chunk), 1);
+
+}, 'CountQueuingStrategy.prototype.size should work generically on its this and its arguments');
+
+test(() => {
+
+  const size = 1024;
+  const chunk = { byteLength: size };
+  const chunkGetter = {
+    get byteLength() { return size; }
+  };
+  const error = new Error('wow!');
+  const chunkGetterThrowing = {
+    get byteLength() { throw error; }
+  };
+
+  assert_equals(CountQueuingStrategy.prototype.size(), 1, 'size returns 1 with undefined');
+  assert_equals(CountQueuingStrategy.prototype.size(null), 1, 'size returns 1 with null');
+  assert_equals(CountQueuingStrategy.prototype.size('potato'), 1, 'size returns 1 with non-object type');
+  assert_equals(CountQueuingStrategy.prototype.size({}), 1, 'size returns 1 with empty object');
+  assert_equals(CountQueuingStrategy.prototype.size(chunk), 1, 'size returns 1 with a chunk');
+  assert_equals(CountQueuingStrategy.prototype.size(chunkGetter), 1, 'size returns 1 with chunk getter');
+  assert_equals(CountQueuingStrategy.prototype.size(chunkGetterThrowing), 1,
+    'size returns 1 with chunk getter that throws');
+
+}, 'CountQueuingStrategy size behaves as expected with strange arguments');
+
+test(() => {
+
+  const strategy = new CountQueuingStrategy({ highWaterMark: 4 });
+
+  assert_object_equals(Object.getOwnPropertyDescriptor(strategy, 'highWaterMark'),
+    { value: 4, writable: true, enumerable: true, configurable: true },
+    'highWaterMark property should be a data property with the value passed the constructor');
+  assert_equals(typeof strategy.size, 'function');
+
+}, 'CountQueuingStrategy instances have the correct properties');
+
+test(() => {
+
+  const strategy = new CountQueuingStrategy({ highWaterMark: 4 });
+  assert_equals(strategy.highWaterMark, 4);
+
+  strategy.highWaterMark = 10;
+  assert_equals(strategy.highWaterMark, 10);
+
+  strategy.highWaterMark = 'banana';
+  assert_equals(strategy.highWaterMark, 'banana');
+
+}, 'CountQueuingStrategy\'s highWaterMark property can be set to anything');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies-expected.txt
new file mode 100644 (file)
index 0000000..8c9d27c
--- /dev/null
@@ -0,0 +1,23 @@
+
+PASS Readable stream: throwing strategy.size getter 
+PASS Readable stream: throwing strategy.size method 
+PASS Readable stream: throwing strategy.highWaterMark getter 
+PASS Readable stream: invalid strategy.highWaterMark 
+PASS Readable stream: invalid strategy.size return value 
+FAIL Load bad-strategies.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Readable stream: throwing strategy.size getter assert_throws: construction should re-throw the error function "() => {
+    new ReadableStream({}, {
+      get size() {
+ ..." threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "Error: a unique string" ("Error")
+FAIL Readable stream: throwing strategy.size method Can't find variable: ReadableStream
+FAIL Readable stream: throwing strategy.highWaterMark getter assert_throws: construction should re-throw the error function "() => {
+    new ReadableStream({}, {
+      size() {
+     ..." threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "Error: a unique string" ("Error")
+FAIL Readable stream: invalid strategy.highWaterMark assert_throws: construction should throw a RangeError for -1 function "() => {
+      new ReadableStream({}, {
+        size() {
+ ..." threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "RangeError" ("RangeError")
+FAIL Readable stream: invalid strategy.size return value Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies.html
new file mode 100644 (file)
index 0000000..4fab931
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="bad-strategies.js"></script>
+<script>
+'use strict';
+worker_test('bad-strategies.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-strategies.js
new file mode 100644 (file)
index 0000000..7d085c7
--- /dev/null
@@ -0,0 +1,122 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  const theError = new Error('a unique string');
+
+  assert_throws(theError, () => {
+    new ReadableStream({}, {
+      get size() {
+        throw theError;
+      },
+      highWaterMark: 5
+    });
+  }, 'construction should re-throw the error');
+
+}, 'Readable stream: throwing strategy.size getter');
+
+promise_test(() => {
+
+  const theError = new Error('a unique string');
+  const rs = new ReadableStream(
+    {
+      start(c) {
+        assert_throws(theError, () => c.enqueue('a'), 'enqueue should throw the error');
+      }
+    },
+    {
+      size() {
+        throw theError;
+      },
+      highWaterMark: 5
+    }
+  );
+
+  return rs.getReader().closed.catch(e => {
+    assert_equals(e, theError, 'closed should reject with the error');
+  });
+
+}, 'Readable stream: throwing strategy.size method');
+
+test(() => {
+
+  const theError = new Error('a unique string');
+
+  assert_throws(theError, () => {
+    new ReadableStream({}, {
+      size() {
+        return 1;
+      },
+      get highWaterMark() {
+        throw theError;
+      }
+    });
+  }, 'construction should re-throw the error');
+
+}, 'Readable stream: throwing strategy.highWaterMark getter');
+
+test(() => {
+
+  for (const highWaterMark of [-1, -Infinity]) {
+    assert_throws(new RangeError(), () => {
+      new ReadableStream({}, {
+        size() {
+          return 1;
+        },
+        highWaterMark
+      });
+    }, 'construction should throw a RangeError for ' + highWaterMark);
+  }
+
+  for (const highWaterMark of [NaN, 'foo', {}]) {
+    assert_throws(new TypeError(), () => {
+      new ReadableStream({}, {
+        size() {
+          return 1;
+        },
+        highWaterMark
+      });
+    }, 'construction should throw a TypeError for ' + highWaterMark);
+  }
+
+}, 'Readable stream: invalid strategy.highWaterMark');
+
+promise_test(() => {
+
+  const promises = [];
+  for (const size of [NaN, -Infinity, Infinity, -1]) {
+    let theError;
+    const rs = new ReadableStream(
+      {
+        start(c) {
+          try {
+            c.enqueue('hi');
+            assert_unreached('enqueue didn\'t throw');
+          } catch (error) {
+            assert_equals(error.name, 'RangeError', 'enqueue should throw a RangeError for ' + size);
+            theError = error;
+          }
+        }
+      },
+      {
+        size() {
+          return size;
+        },
+        highWaterMark: 5
+      }
+    );
+
+    promises.push(rs.getReader().closed.catch(e => {
+      assert_equals(e, theError, 'closed should reject with the error for ' + size);
+    }));
+  }
+
+  return Promise.all(promises);
+
+}, 'Readable stream: invalid strategy.size return value');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources-expected.txt
new file mode 100644 (file)
index 0000000..61fe624
--- /dev/null
@@ -0,0 +1,52 @@
+
+PASS Underlying source start: throwing getter 
+PASS Underlying source start: throwing method 
+PASS Underlying source: throwing pull getter (initial pull) 
+PASS Underlying source: throwing pull method (initial pull) 
+PASS Underlying source pull: throwing getter (second pull) 
+PASS Underlying source pull: throwing method (second pull) 
+PASS Underlying source cancel: throwing getter 
+PASS Underlying source cancel: throwing method 
+PASS Underlying source: calling enqueue on an empty canceled stream should not throw 
+PASS Underlying source: calling enqueue on a non-empty canceled stream should not throw 
+PASS Underlying source: calling enqueue on a closed stream should throw 
+PASS Underlying source: calling enqueue on an errored stream should throw 
+PASS Underlying source: calling close twice on an empty stream should throw the second time 
+PASS Underlying source: calling close twice on a non-empty stream should throw the second time 
+PASS Underlying source: calling close on an empty canceled stream should not throw 
+PASS Underlying source: calling close on a non-empty canceled stream should not throw 
+PASS Underlying source: calling close after error should throw 
+PASS Underlying source: calling error twice should throw the second time 
+PASS Underlying source: calling error after close should throw 
+PASS Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error 
+PASS Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error 
+FAIL Load bad-underlying-sources.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Underlying source start: throwing getter assert_throws: constructing the stream should re-throw the error function "() => {
+    new ReadableStream({
+      get start() {
+    ..." threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "Error: a unique string" ("Error")
+FAIL Underlying source start: throwing method assert_throws: constructing the stream should re-throw the error function "() => {
+    new ReadableStream({
+      start() {
+        ..." threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "Error: a unique string" ("Error")
+FAIL Underlying source: throwing pull getter (initial pull) Can't find variable: ReadableStream
+FAIL Underlying source: throwing pull method (initial pull) Can't find variable: ReadableStream
+FAIL Underlying source pull: throwing getter (second pull) Can't find variable: ReadableStream
+FAIL Underlying source pull: throwing method (second pull) Can't find variable: ReadableStream
+FAIL Underlying source cancel: throwing getter Can't find variable: ReadableStream
+FAIL Underlying source cancel: throwing method Can't find variable: ReadableStream
+FAIL Underlying source: calling enqueue on an empty canceled stream should not throw Can't find variable: ReadableStream
+FAIL Underlying source: calling enqueue on a non-empty canceled stream should not throw Can't find variable: ReadableStream
+FAIL Underlying source: calling enqueue on a closed stream should throw Can't find variable: ReadableStream
+FAIL Underlying source: calling enqueue on an errored stream should throw Can't find variable: ReadableStream
+FAIL Underlying source: calling close twice on an empty stream should throw the second time Can't find variable: ReadableStream
+FAIL Underlying source: calling close twice on a non-empty stream should throw the second time Can't find variable: ReadableStream
+FAIL Underlying source: calling close on an empty canceled stream should not throw Can't find variable: ReadableStream
+FAIL Underlying source: calling close on a non-empty canceled stream should not throw Can't find variable: ReadableStream
+FAIL Underlying source: calling close after error should throw Can't find variable: ReadableStream
+FAIL Underlying source: calling error twice should throw the second time Can't find variable: ReadableStream
+FAIL Underlying source: calling error after close should throw Can't find variable: ReadableStream
+FAIL Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error Can't find variable: ReadableStream
+FAIL Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources.html
new file mode 100644 (file)
index 0000000..ecb11fe
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="bad-underlying-sources.js"></script>
+<script>
+'use strict';
+worker_test('bad-underlying-sources.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/bad-underlying-sources.js
new file mode 100644 (file)
index 0000000..f2fd0fd
--- /dev/null
@@ -0,0 +1,383 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('/resources/testharness.js');
+}
+
+
+test(() => {
+
+  const theError = new Error('a unique string');
+
+  assert_throws(theError, () => {
+    new ReadableStream({
+      get start() {
+        throw theError;
+      }
+    });
+  }, 'constructing the stream should re-throw the error');
+
+}, 'Underlying source start: throwing getter');
+
+
+test(() => {
+
+  const theError = new Error('a unique string');
+
+  assert_throws(theError, () => {
+    new ReadableStream({
+      start() {
+        throw theError;
+      }
+    });
+  }, 'constructing the stream should re-throw the error');
+
+}, 'Underlying source start: throwing method');
+
+
+promise_test(t => {
+
+  const theError = new Error('a unique string');
+  const rs = new ReadableStream({
+    get pull() {
+      throw theError;
+    }
+  });
+
+  return promise_rejects(t, theError, rs.getReader().closed);
+
+}, 'Underlying source: throwing pull getter (initial pull)');
+
+
+promise_test(t => {
+
+  const theError = new Error('a unique string');
+  const rs = new ReadableStream({
+    pull() {
+      throw theError;
+    }
+  });
+
+  return promise_rejects(t, theError, rs.getReader().closed);
+
+}, 'Underlying source: throwing pull method (initial pull)');
+
+
+promise_test(t => {
+
+  const theError = new Error('a unique string');
+
+  let counter = 0;
+  const rs = new ReadableStream({
+    get pull() {
+      ++counter;
+      if (counter === 1) {
+        return c => c.enqueue('a');
+      }
+
+      throw theError;
+    }
+  });
+  const reader = rs.getReader();
+
+  return Promise.all([
+    reader.read().then(r => {
+      assert_object_equals(r, { value: 'a', done: false }, 'the chunk read should be correct');
+    }),
+    promise_rejects(t, theError, reader.closed)
+  ]);
+
+}, 'Underlying source pull: throwing getter (second pull)');
+
+
+promise_test(t => {
+
+  const theError = new Error('a unique string');
+
+  let counter = 0;
+  const rs = new ReadableStream({
+    pull(c) {
+      ++counter;
+      if (counter === 1) {
+        c.enqueue('a');
+        return;
+      }
+
+      throw theError;
+    }
+  });
+  const reader = rs.getReader();
+
+  return Promise.all([
+    reader.read().then(r => {
+      assert_object_equals(r, { value: 'a', done: false }, 'the chunk read should be correct');
+    }),
+    promise_rejects(t, theError, reader.closed)
+  ]);
+
+}, 'Underlying source pull: throwing method (second pull)');
+
+promise_test(t => {
+
+  const theError = new Error('a unique string');
+  const rs = new ReadableStream({
+    get cancel() {
+      throw theError;
+    }
+  });
+
+  return promise_rejects(t, theError, rs.cancel());
+
+}, 'Underlying source cancel: throwing getter');
+
+promise_test(t => {
+
+  const theError = new Error('a unique string');
+  const rs = new ReadableStream({
+    cancel() {
+      throw theError;
+    }
+  });
+
+  return promise_rejects(t, theError, rs.cancel());
+
+}, 'Underlying source cancel: throwing method');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  rs.cancel();
+  controller.enqueue('a'); // Calling enqueue after canceling should not throw anything.
+
+  return rs.getReader().closed;
+
+}, 'Underlying source: calling enqueue on an empty canceled stream should not throw');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.enqueue('b');
+      controller = c;
+    }
+  });
+
+  rs.cancel();
+  controller.enqueue('c'); // Calling enqueue after canceling should not throw anything.
+
+  return rs.getReader().closed;
+
+}, 'Underlying source: calling enqueue on a non-empty canceled stream should not throw');
+
+promise_test(() => {
+
+  return new ReadableStream({
+    start(c) {
+      c.close();
+      assert_throws(new TypeError(), () => c.enqueue('a'), 'call to enqueue should throw a TypeError');
+    }
+  }).getReader().closed;
+
+}, 'Underlying source: calling enqueue on a closed stream should throw');
+
+promise_test(t => {
+
+  const theError = new Error('boo');
+  const closed = new ReadableStream({
+    start(c) {
+      c.error(theError);
+      assert_throws(theError, () => c.enqueue('a'), 'call to enqueue should throw the error');
+    }
+  }).getReader().closed;
+
+  return promise_rejects(t, theError, closed);
+
+}, 'Underlying source: calling enqueue on an errored stream should throw');
+
+promise_test(() => {
+
+  return new ReadableStream({
+    start(c) {
+      c.close();
+      assert_throws(new TypeError(), () => c.close(), 'second call to close should throw a TypeError');
+    }
+  }).getReader().closed;
+
+}, 'Underlying source: calling close twice on an empty stream should throw the second time');
+
+promise_test(() => {
+
+  let startCalled = false;
+  let readCalled = false;
+  const reader = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.close();
+      assert_throws(new TypeError(), () => c.close(), 'second call to close should throw a TypeError');
+      startCalled = true;
+    }
+  }).getReader();
+
+  return Promise.all([
+    reader.read().then(r => {
+      assert_object_equals(r, { value: 'a', done: false }, 'read() should read the enqueued chunk');
+      readCalled = true;
+    }),
+    reader.closed.then(() => {
+      assert_true(startCalled);
+      assert_true(readCalled);
+    })
+  ]);
+
+}, 'Underlying source: calling close twice on a non-empty stream should throw the second time');
+
+promise_test(() => {
+
+  let controller;
+  let startCalled = false;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+      startCalled = true;
+    }
+  });
+
+  rs.cancel();
+  controller.close(); // Calling close after canceling should not throw anything.
+
+  return rs.getReader().closed.then(() => {
+    assert_true(startCalled);
+  });
+
+}, 'Underlying source: calling close on an empty canceled stream should not throw');
+
+promise_test(() => {
+
+  let controller;
+  let startCalled = false;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+      c.enqueue('a');
+      startCalled = true;
+    }
+  });
+
+  rs.cancel();
+  controller.close(); // Calling close after canceling should not throw anything.
+
+  return rs.getReader().closed.then(() => {
+    assert_true(startCalled);
+  });
+
+}, 'Underlying source: calling close on a non-empty canceled stream should not throw');
+
+promise_test(() => {
+
+  const theError = new Error('boo');
+  let startCalled = false;
+
+  const closed = new ReadableStream({
+    start(c) {
+      c.error(theError);
+      assert_throws(new TypeError(), () => c.close(), 'call to close should throw a TypeError');
+      startCalled = true;
+    }
+  }).getReader().closed;
+
+  return closed.catch(e => {
+    assert_true(startCalled);
+    assert_equals(e, theError, 'closed should reject with the error');
+  });
+
+}, 'Underlying source: calling close after error should throw');
+
+promise_test(() => {
+
+  const theError = new Error('boo');
+  let startCalled = false;
+
+  const closed = new ReadableStream({
+    start(c) {
+      c.error(theError);
+      assert_throws(new TypeError(), () => c.error(), 'second call to error should throw a TypeError');
+      startCalled = true;
+    }
+  }).getReader().closed;
+
+  return closed.catch(e => {
+    assert_true(startCalled);
+    assert_equals(e, theError, 'closed should reject with the error');
+  });
+
+}, 'Underlying source: calling error twice should throw the second time');
+
+promise_test(() => {
+
+  let startCalled = false;
+
+  const closed = new ReadableStream({
+    start(c) {
+      c.close();
+      assert_throws(new TypeError(), () => c.error(), 'second call to error should throw a TypeError');
+      startCalled = true;
+    }
+  }).getReader().closed;
+
+  return closed.then(() => assert_true(startCalled));
+
+}, 'Underlying source: calling error after close should throw');
+
+promise_test(() => {
+
+  let startCalled = false;
+  const firstError = new Error('1');
+  const secondError = new Error('2');
+
+  const closed = new ReadableStream({
+    start(c) {
+      c.error(firstError);
+      startCalled = true;
+      return Promise.reject(secondError);
+    }
+  }).getReader().closed;
+
+  return closed.catch(e => {
+    assert_true(startCalled);
+    assert_equals(e, firstError, 'closed should reject with the first error');
+  });
+
+}, 'Underlying source: calling error and returning a rejected promise from start should cause the stream to error ' +
+   'with the first error');
+
+promise_test(() => {
+
+  let startCalled = false;
+  const firstError = new Error('1');
+  const secondError = new Error('2');
+
+  const closed = new ReadableStream({
+    pull(c) {
+      c.error(firstError);
+      startCalled = true;
+      return Promise.reject(secondError);
+    }
+  }).getReader().closed;
+
+  return closed.catch(e => {
+    assert_true(startCalled);
+    assert_equals(e, firstError, 'closed should reject with the first error');
+  });
+
+}, 'Underlying source: calling error and returning a rejected promise from pull should cause the stream to error ' +
+   'with the first error');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks-expected.txt
new file mode 100644 (file)
index 0000000..3c7f1bb
--- /dev/null
@@ -0,0 +1,34 @@
+
+PASS Can get the ReadableStreamReader constructor indirectly 
+PASS Can get the ReadableStreamController constructor indirectly 
+PASS ReadableStream.prototype.cancel enforces a brand check 
+PASS ReadableStream.prototype.getReader enforces a brand check 
+PASS ReadableStream.prototype.tee enforces a brand check 
+PASS ReadableStreamReader enforces a brand check on its argument 
+PASS ReadableStreamReader.prototype.closed enforces a brand check 
+PASS ReadableStreamReader.prototype.cancel enforces a brand check 
+PASS ReadableStreamReader.prototype.read enforces a brand check 
+PASS ReadableStreamReader.prototype.releaseLock enforces a brand check 
+PASS ReadableStreamController enforces a brand check on its argument 
+PASS ReadableStreamController can't be given a fully-constructed ReadableStream 
+PASS ReadableStreamController.prototype.close enforces a brand check 
+PASS ReadableStreamController.prototype.enqueue enforces a brand check 
+PASS ReadableStreamController.prototype.error enforces a brand check 
+FAIL Load brand-checks.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Can get the ReadableStreamReader constructor indirectly Can't find variable: ReadableStream
+FAIL Can get the ReadableStreamController constructor indirectly Can't find variable: ReadableStream
+FAIL ReadableStream.prototype.cancel enforces a brand check Can't find variable: ReadableStream
+FAIL ReadableStream.prototype.getReader enforces a brand check Can't find variable: ReadableStream
+FAIL ReadableStream.prototype.tee enforces a brand check Can't find variable: ReadableStream
+PASS ReadableStreamReader enforces a brand check on its argument 
+FAIL ReadableStreamReader.prototype.closed enforces a brand check undefined is not an object (evaluating 'ReadableStreamReader.prototype')
+FAIL ReadableStreamReader.prototype.cancel enforces a brand check undefined is not an object (evaluating 'ReadableStreamReader.prototype')
+FAIL ReadableStreamReader.prototype.read enforces a brand check undefined is not an object (evaluating 'ReadableStreamReader.prototype')
+FAIL ReadableStreamReader.prototype.releaseLock enforces a brand check undefined is not an object (evaluating 'ReadableStreamReader.prototype')
+PASS ReadableStreamController enforces a brand check on its argument 
+FAIL ReadableStreamController can't be given a fully-constructed ReadableStream assert_throws: Constructing a ReadableStreamController should throw function "() => new ReadableStreamController(realReadableStream())" threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "TypeError" ("TypeError")
+FAIL ReadableStreamController.prototype.close enforces a brand check undefined is not an object (evaluating 'ReadableStreamController.prototype')
+FAIL ReadableStreamController.prototype.enqueue enforces a brand check undefined is not an object (evaluating 'ReadableStreamController.prototype')
+FAIL ReadableStreamController.prototype.error enforces a brand check undefined is not an object (evaluating 'ReadableStreamController.prototype')
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks.html
new file mode 100644 (file)
index 0000000..9dfed12
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+<script src="brand-checks.js"></script>
+<script>
+'use strict';
+worker_test('brand-checks.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/brand-checks.js
new file mode 100644 (file)
index 0000000..32553cf
--- /dev/null
@@ -0,0 +1,151 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+let ReadableStreamReader;
+let ReadableStreamController;
+
+test(() => {
+
+  // It's not exposed globally, but we test a few of its properties here.
+  ReadableStreamReader = (new ReadableStream()).getReader().constructor;
+
+}, 'Can get the ReadableStreamReader constructor indirectly');
+
+test(() => {
+
+  // It's not exposed globally, but we test a few of its properties here.
+  new ReadableStream({
+    start(c) {
+      ReadableStreamController = c.constructor;
+    }
+  });
+
+}, 'Can get the ReadableStreamController constructor indirectly');
+
+function fakeReadableStream() {
+  return {
+    cancel() { return Promise.resolve(); },
+    getReader() { return new ReadableStreamReader(new ReadableStream()); },
+    pipeThrough(obj) { return obj.readable; },
+    pipeTo() { return Promise.resolve(); },
+    tee() { return [realReadableStream(), realReadableStream()]; }
+  };
+}
+
+function realReadableStream() {
+  return new ReadableStream();
+}
+
+function fakeReadableStreamReader() {
+  return {
+    get closed() { return Promise.resolve(); },
+    cancel() { return Promise.resolve(); },
+    read() { return Promise.resolve({ value: undefined, done: true }); },
+    releaseLock() { return; }
+  };
+}
+
+function fakeReadableStreamController() {
+  return {
+    close() { },
+    enqueue() { },
+    error() { }
+  };
+}
+
+promise_test(t => {
+
+  return methodRejects(t, ReadableStream.prototype, 'cancel', fakeReadableStream());
+
+}, 'ReadableStream.prototype.cancel enforces a brand check');
+
+test(() => {
+
+  methodThrows(ReadableStream.prototype, 'getReader', fakeReadableStream());
+
+}, 'ReadableStream.prototype.getReader enforces a brand check');
+
+test(() => {
+
+  methodThrows(ReadableStream.prototype, 'tee', fakeReadableStream());
+
+}, 'ReadableStream.prototype.tee enforces a brand check');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStreamReader(fakeReadableStream()),
+                'Constructing a ReadableStreamReader should throw');
+
+}, 'ReadableStreamReader enforces a brand check on its argument');
+
+promise_test(t => {
+
+  return Promise.all([
+    getterRejects(t, ReadableStreamReader.prototype, 'closed', fakeReadableStreamReader()),
+    getterRejects(t, ReadableStreamReader.prototype, 'closed', realReadableStream())
+  ]);
+
+}, 'ReadableStreamReader.prototype.closed enforces a brand check');
+
+promise_test(t => {
+
+  return Promise.all([
+    methodRejects(t, ReadableStreamReader.prototype, 'cancel', fakeReadableStreamReader()),
+    methodRejects(t, ReadableStreamReader.prototype, 'cancel', realReadableStream())
+  ]);
+
+}, 'ReadableStreamReader.prototype.cancel enforces a brand check');
+
+promise_test(t => {
+
+  return Promise.all([
+    methodRejects(t, ReadableStreamReader.prototype, 'read', fakeReadableStreamReader()),
+    methodRejects(t, ReadableStreamReader.prototype, 'read', realReadableStream())
+  ]);
+
+}, 'ReadableStreamReader.prototype.read enforces a brand check');
+
+test(() => {
+
+  methodThrows(ReadableStreamReader.prototype, 'releaseLock', fakeReadableStreamReader());
+  methodThrows(ReadableStreamReader.prototype, 'releaseLock', realReadableStream());
+
+}, 'ReadableStreamReader.prototype.releaseLock enforces a brand check');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStreamController(fakeReadableStream()),
+                'Constructing a ReadableStreamController should throw');
+
+}, 'ReadableStreamController enforces a brand check on its argument');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStreamController(realReadableStream()),
+                'Constructing a ReadableStreamController should throw');
+
+}, 'ReadableStreamController can\'t be given a fully-constructed ReadableStream');
+
+test(() => {
+
+  methodThrows(ReadableStreamController.prototype, 'close', fakeReadableStreamController());
+
+}, 'ReadableStreamController.prototype.close enforces a brand check');
+
+test(() => {
+
+  methodThrows(ReadableStreamController.prototype, 'enqueue', fakeReadableStreamController());
+
+}, 'ReadableStreamController.prototype.enqueue enforces a brand check');
+
+test(() => {
+
+  methodThrows(ReadableStreamController.prototype, 'error', fakeReadableStreamController());
+
+}, 'ReadableStreamController.prototype.error enforces a brand check');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel-expected.txt
new file mode 100644 (file)
index 0000000..7f27e45
--- /dev/null
@@ -0,0 +1,24 @@
+
+FAIL ReadableStream cancellation: integration test on an infinite stream derived from a random push source promise_test: Unhandled rejection with value: object "Error: forced error"
+PASS ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source 
+PASS ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel 
+PASS ReadableStream cancellation: should fulfill promise when cancel callback went fine 
+PASS ReadableStream cancellation: returning a value from the underlying source's cancel should not affect the fulfillment value of the promise returned by the stream's cancel 
+PASS ReadableStream cancellation: should reject promise when cancel callback raises an exception 
+PASS ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (1) 
+PASS ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (2) 
+PASS ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should reject when that one does 
+PASS ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called 
+FAIL Load cancel.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL ReadableStream cancellation: integration test on an infinite stream derived from a random push source promise_test: Unhandled rejection with value: object "Error: forced error"
+FAIL ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: should fulfill promise when cancel callback went fine Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: returning a value from the underlying source's cancel should not affect the fulfillment value of the promise returned by the stream's cancel Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: should reject promise when cancel callback raises an exception Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (1) Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should fulfill when that one does (2) Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: if the underlying source's cancel method returns a promise, the promise returned by the stream's cancel should reject when that one does Can't find variable: ReadableStream
+FAIL ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel.html
new file mode 100644 (file)
index 0000000..f767429
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+<script src="../resources/rs-utils.js"></script>
+<script src="cancel.js"></script>
+<script>
+'use strict';
+worker_test('cancel.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/cancel.js
new file mode 100644 (file)
index 0000000..82027db
--- /dev/null
@@ -0,0 +1,242 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('../resources/rs-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+promise_test(() => {
+
+  // WebKit edit. We force a failure in this tests for now because it is flaky.
+  return Promise.reject(new Error("forced error"));
+
+  const randomSource = new RandomPushSource();
+
+  let cancellationFinished = false;
+  const rs = new ReadableStream({
+    start(c) {
+      randomSource.ondata = c.enqueue.bind(c);
+      randomSource.onend = c.close.bind(c);
+      randomSource.onerror = c.error.bind(c);
+    },
+
+    pull() {
+      randomSource.readStart();
+    },
+
+    cancel() {
+      randomSource.readStop();
+      randomSource.onend();
+
+      return new Promise(resolve => {
+        setTimeout(() => {
+          cancellationFinished = true;
+          resolve();
+        }, 1);
+      });
+    }
+  });
+
+  const reader = rs.getReader();
+
+  // We call delay multiple times to avoid cancelling too early for the
+  // source to enqueue at least one chunk.
+  const cancel = delay(5).then(() => delay(5)).then(() => delay(5)).then(() => reader.cancel());
+
+  return readableStreamToArray(rs, reader).then(chunks => {
+    assert_greater_than(chunks.length, 0, 'at least one chunk should be read');
+    for (let i = 0; i < chunks.length; i++) {
+      assert_equals(chunks[i].length, 128, 'chunk ' + i + ' should have 128 bytes');
+    }
+    assert_false(cancellationFinished, 'it did not wait for the cancellation process to finish before closing');
+    return cancel;
+  }).then(() => {
+    assert_true(cancellationFinished, 'it returns a promise that is fulfilled when the cancellation finishes');
+  });
+
+}, 'ReadableStream cancellation: integration test on an infinite stream derived from a random push source');
+
+test(() => {
+
+  let recordedReason;
+  const rs = new ReadableStream({
+    cancel(reason) {
+      recordedReason = reason;
+    }
+  });
+
+  const passedReason = new Error('Sorry, it just wasn\'t meant to be.');
+  rs.cancel(passedReason);
+
+  assert_equals(recordedReason, passedReason,
+    'the error passed to the underlying source\'s cancel method should equal the one passed to the stream\'s cancel');
+
+}, 'ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.close();
+    },
+    cancel() {
+      assert_unreached('underlying source cancel() should not have been called');
+    }
+  });
+
+  const reader = rs.getReader();
+
+  return rs.cancel().then(() => {
+    assert_unreached('cancel() should be rejected');
+  }, e => {
+    assert_equals(e.name, 'TypeError', 'cancel() should be rejected with a TypeError');
+  }).then(() => {
+    return reader.read();
+  }).then(result => {
+    assert_object_equals(result, { value: 'a', done: false }, 'read() should still work after the attempted cancel');
+    return reader.closed;
+  });
+
+}, 'ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel');
+
+promise_test(() => {
+
+  let cancelReceived = false;
+  const cancelReason = new Error('I am tired of this stream, I prefer to cancel it');
+  const rs = new ReadableStream({
+    cancel(reason) {
+      cancelReceived = true;
+      assert_equals(reason, cancelReason, 'cancellation reason given to the underlying source should be equal to the one passed');
+    }
+  });
+
+  return rs.cancel(cancelReason).then(() => {
+    assert_true(cancelReceived);
+  });
+
+}, 'ReadableStream cancellation: should fulfill promise when cancel callback went fine');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    cancel() {
+      return 'Hello';
+    }
+  });
+
+  return rs.cancel().then(v => {
+    assert_equals(v, undefined, 'cancel() return value should be fulfilled with undefined');
+  });
+
+}, 'ReadableStream cancellation: returning a value from the underlying source\'s cancel should not affect the fulfillment value of the promise returned by the stream\'s cancel');
+
+promise_test(() => {
+
+  const thrownError = new Error('test');
+  let cancelCalled = false;
+
+  const rs = new ReadableStream({
+    cancel() {
+      cancelCalled = true;
+      throw thrownError;
+    }
+  });
+
+  return rs.cancel('test').then(() => {
+    assert_unreached('cancel should reject');
+  }, e => {
+    assert_true(cancelCalled);
+    assert_equals(e, thrownError);
+  });
+
+}, 'ReadableStream cancellation: should reject promise when cancel callback raises an exception');
+
+promise_test(() => {
+
+  const cancelReason = new Error('test');
+
+  const rs = new ReadableStream({
+    cancel(error) {
+      assert_equals(error, cancelReason);
+      return delay(1);
+    }
+  });
+
+  return rs.cancel(cancelReason);
+
+}, 'ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does (1)');
+
+promise_test(() => {
+
+  let resolveSourceCancelPromise;
+  let sourceCancelPromiseHasFulfilled = false;
+
+  const rs = new ReadableStream({
+    cancel() {
+      const sourceCancelPromise = new Promise(resolve => resolveSourceCancelPromise = resolve);
+
+      sourceCancelPromise.then(() => {
+        sourceCancelPromiseHasFulfilled = true;
+      });
+
+      return sourceCancelPromise;
+    }
+  });
+
+  setTimeout(() => resolveSourceCancelPromise('Hello'), 1);
+
+  return rs.cancel().then(value => {
+    assert_true(sourceCancelPromiseHasFulfilled, 'cancel() return value should be fulfilled only after the promise returned by the underlying source\'s cancel');
+    assert_equals(value, undefined, 'cancel() return value should be fulfilled with undefined');
+  });
+
+}, 'ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does (2)');
+
+promise_test(() => {
+
+  let rejectSourceCancelPromise;
+  let sourceCancelPromiseHasRejected = false;
+
+  const rs = new ReadableStream({
+    cancel() {
+      const sourceCancelPromise = new Promise((resolve, reject) => rejectSourceCancelPromise = reject);
+
+      sourceCancelPromise.catch(() => {
+        sourceCancelPromiseHasRejected = true;
+      });
+
+      return sourceCancelPromise;
+    }
+  });
+
+  const errorInCancel = new Error('Sorry, it just wasn\'t meant to be.');
+
+  setTimeout(() => rejectSourceCancelPromise(errorInCancel), 1);
+
+  return rs.cancel().then(() => {
+    assert_unreached('cancel() return value should be rejected');
+  }, r => {
+    assert_true(sourceCancelPromiseHasRejected, 'cancel() return value should be rejected only after the promise returned by the underlying source\'s cancel');
+    assert_equals(r, errorInCancel, 'cancel() return value should be rejected with the underlying source\'s rejection reason');
+  });
+
+}, 'ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should reject when that one does');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    start() {
+      return new Promise(() => {});
+    },
+    pull() {
+      assert_unreached('pull should not have been called');
+    }
+  });
+
+  return Promise.all([rs.cancel(), rs.getReader().closed]);
+
+}, 'ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration-expected.txt
new file mode 100644 (file)
index 0000000..b9880f6
--- /dev/null
@@ -0,0 +1,12 @@
+
+PASS Can construct a readable stream with a valid CountQueuingStrategy 
+PASS Correctly governs a ReadableStreamController's desiredSize property (HWM = 0) 
+PASS Correctly governs a ReadableStreamController's desiredSize property (HWM = 1) 
+PASS Correctly governs a ReadableStreamController's desiredSize property (HWM = 4) 
+FAIL Load count-queuing-strategy-integration.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Can construct a readable stream with a valid CountQueuingStrategy Can't find variable: ReadableStream
+FAIL Correctly governs a ReadableStreamController's desiredSize property (HWM = 0) Can't find variable: ReadableStream
+FAIL Correctly governs a ReadableStreamController's desiredSize property (HWM = 1) Can't find variable: ReadableStream
+FAIL Correctly governs a ReadableStreamController's desiredSize property (HWM = 4) Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.html
new file mode 100644 (file)
index 0000000..bc38166
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="count-queuing-strategy-integration.js"></script>
+<script>
+'use strict';
+worker_test('count-queuing-strategy-integration.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/count-queuing-strategy-integration.js
new file mode 100644 (file)
index 0000000..fb9a1aa
--- /dev/null
@@ -0,0 +1,213 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  new ReadableStream({}, new CountQueuingStrategy({ highWaterMark: 4 }));
+
+}, 'Can construct a readable stream with a valid CountQueuingStrategy');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream(
+    {
+      start(c) {
+        controller = c;
+      }
+    },
+    new CountQueuingStrategy({ highWaterMark: 0 })
+  );
+  const reader = rs.getReader();
+
+  assert_equals(controller.desiredSize, 0, '0 reads, 0 enqueues: desiredSize should be 0');
+  controller.enqueue('a');
+  assert_equals(controller.desiredSize, -1, '0 reads, 1 enqueue: desiredSize should be -1');
+  controller.enqueue('b');
+  assert_equals(controller.desiredSize, -2, '0 reads, 2 enqueues: desiredSize should be -2');
+  controller.enqueue('c');
+  assert_equals(controller.desiredSize, -3, '0 reads, 3 enqueues: desiredSize should be -3');
+  controller.enqueue('d');
+  assert_equals(controller.desiredSize, -4, '0 reads, 4 enqueues: desiredSize should be -4');
+
+  return reader.read()
+    .then(result => {
+      assert_object_equals(result, { value: 'a', done: false },
+                           '1st read gives back the 1st chunk enqueued (queue now contains 3 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'b', done: false },
+                           '2nd read gives back the 2nd chunk enqueued (queue now contains 2 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'c', done: false },
+                           '3rd read gives back the 3rd chunk enqueued (queue now contains 1 chunk)');
+
+      assert_equals(controller.desiredSize, -1, '3 reads, 4 enqueues: desiredSize should be -1');
+      controller.enqueue('e');
+      assert_equals(controller.desiredSize, -2, '3 reads, 5 enqueues: desiredSize should be -2');
+
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'd', done: false },
+                           '4th read gives back the 4th chunk enqueued (queue now contains 1 chunks)');
+      return reader.read();
+
+    }).then(result => {
+      assert_object_equals(result, { value: 'e', done: false },
+                           '5th read gives back the 5th chunk enqueued (queue now contains 0 chunks)');
+
+      assert_equals(controller.desiredSize, 0, '5 reads, 5 enqueues: desiredSize should be 0');
+      controller.enqueue('f');
+      assert_equals(controller.desiredSize, -1, '5 reads, 6 enqueues: desiredSize should be -1');
+      controller.enqueue('g');
+      assert_equals(controller.desiredSize, -2, '5 reads, 7 enqueues: desiredSize should be -2');
+    });
+
+}, 'Correctly governs a ReadableStreamController\'s desiredSize property (HWM = 0)');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream(
+    {
+      start(c) {
+        controller = c;
+      }
+    },
+    new CountQueuingStrategy({ highWaterMark: 1 })
+  );
+  const reader = rs.getReader();
+
+  assert_equals(controller.desiredSize, 1, '0 reads, 0 enqueues: desiredSize should be 1');
+  controller.enqueue('a');
+  assert_equals(controller.desiredSize, 0, '0 reads, 1 enqueue: desiredSize should be 0');
+  controller.enqueue('b');
+  assert_equals(controller.desiredSize, -1, '0 reads, 2 enqueues: desiredSize should be -1');
+  controller.enqueue('c');
+  assert_equals(controller.desiredSize, -2, '0 reads, 3 enqueues: desiredSize should be -2');
+  controller.enqueue('d');
+  assert_equals(controller.desiredSize, -3, '0 reads, 4 enqueues: desiredSize should be -3');
+
+  return reader.read()
+    .then(result => {
+      assert_object_equals(result, { value: 'a', done: false },
+                           '1st read gives back the 1st chunk enqueued (queue now contains 3 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'b', done: false },
+                           '2nd read gives back the 2nd chunk enqueued (queue now contains 2 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'c', done: false },
+                           '3rd read gives back the 3rd chunk enqueued (queue now contains 1 chunk)');
+
+      assert_equals(controller.desiredSize, 0, '3 reads, 4 enqueues: desiredSize should be 0');
+      controller.enqueue('e');
+      assert_equals(controller.desiredSize, -1, '3 reads, 5 enqueues: desiredSize should be -1');
+
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'd', done: false },
+                           '4th read gives back the 4th chunk enqueued (queue now contains 1 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'e', done: false },
+                           '5th read gives back the 5th chunk enqueued (queue now contains 0 chunks)');
+
+      assert_equals(controller.desiredSize, 1, '5 reads, 5 enqueues: desiredSize should be 1');
+      controller.enqueue('f');
+      assert_equals(controller.desiredSize, 0, '5 reads, 6 enqueues: desiredSize should be 0');
+      controller.enqueue('g');
+      assert_equals(controller.desiredSize, -1, '5 reads, 7 enqueues: desiredSize should be -1');
+    });
+
+}, 'Correctly governs a ReadableStreamController\'s desiredSize property (HWM = 1)');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream(
+    {
+      start(c) {
+        controller = c;
+      }
+    },
+    new CountQueuingStrategy({ highWaterMark: 4 })
+  );
+  const reader = rs.getReader();
+
+  assert_equals(controller.desiredSize, 4, '0 reads, 0 enqueues: desiredSize should be 4');
+  controller.enqueue('a');
+  assert_equals(controller.desiredSize, 3, '0 reads, 1 enqueue: desiredSize should be 3');
+  controller.enqueue('b');
+  assert_equals(controller.desiredSize, 2, '0 reads, 2 enqueues: desiredSize should be 2');
+  controller.enqueue('c');
+  assert_equals(controller.desiredSize, 1, '0 reads, 3 enqueues: desiredSize should be 1');
+  controller.enqueue('d');
+  assert_equals(controller.desiredSize, 0, '0 reads, 4 enqueues: desiredSize should be 0');
+  controller.enqueue('e');
+  assert_equals(controller.desiredSize, -1, '0 reads, 5 enqueues: desiredSize should be -1');
+  controller.enqueue('f');
+  assert_equals(controller.desiredSize, -2, '0 reads, 6 enqueues: desiredSize should be -2');
+
+
+  reader.read()
+    .then(result => {
+      assert_object_equals(result, { value: 'a', done: false },
+                           '1st read gives back the 1st chunk enqueued (queue now contains 5 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'b', done: false },
+                           '2nd read gives back the 2nd chunk enqueued (queue now contains 4 chunks)');
+
+      assert_equals(controller.desiredSize, 0, '2 reads, 6 enqueues: desiredSize should be 0');
+      controller.enqueue('g');
+      assert_equals(controller.desiredSize, -1, '2 reads, 7 enqueues: desiredSize should be -1');
+
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'c', done: false },
+                           '3rd read gives back the 3rd chunk enqueued (queue now contains 4 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'd', done: false },
+                           '4th read gives back the 4th chunk enqueued (queue now contains 3 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'e', done: false },
+                           '5th read gives back the 5th chunk enqueued (queue now contains 2 chunks)');
+      return reader.read();
+    })
+    .then(result => {
+      assert_object_equals(result, { value: 'f', done: false },
+                           '6th read gives back the 6th chunk enqueued (queue now contains 0 chunks)');
+
+      assert_equals(controller.desiredSize, 3, '6 reads, 7 enqueues: desiredSize should be 3');
+      controller.enqueue('h');
+      assert_equals(controller.desiredSize, 2, '6 reads, 8 enqueues: desiredSize should be 2');
+      controller.enqueue('i');
+      assert_equals(controller.desiredSize, 1, '6 reads, 9 enqueues: desiredSize should be 1');
+      controller.enqueue('j');
+      assert_equals(controller.desiredSize, 0, '6 reads, 10 enqueues: desiredSize should be 0');
+      controller.enqueue('k');
+      assert_equals(controller.desiredSize, -1, '6 reads, 11 enqueues: desiredSize should be -1');
+    });
+
+}, 'Correctly governs a ReadableStreamController\'s desiredSize property (HWM = 4)');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection-expected.txt
new file mode 100644 (file)
index 0000000..d03770c
--- /dev/null
@@ -0,0 +1,12 @@
+
+PASS ReadableStreamController methods should continue working properly when scripts lose their reference to the readable stream 
+PASS ReadableStream closed promise should fulfill even if the stream and reader JS references are lost 
+PASS ReadableStream closed promise should reject even if stream and reader JS references are lost 
+PASS Garbage-collecting a ReadableStreamReader should not unlock its stream 
+FAIL Load garbage-collection.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL ReadableStreamController methods should continue working properly when scripts lose their reference to the readable stream Can't find variable: ReadableStream
+FAIL ReadableStream closed promise should fulfill even if the stream and reader JS references are lost Can't find variable: ReadableStream
+FAIL ReadableStream closed promise should reject even if stream and reader JS references are lost Can't find variable: ReadableStream
+FAIL Garbage-collecting a ReadableStreamReader should not unlock its stream Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection.html
new file mode 100644 (file)
index 0000000..a38ed20
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+<script src="garbage-collection.js"></script>
+<script>
+'use strict';
+worker_test('garbage-collection.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/garbage-collection.js
new file mode 100644 (file)
index 0000000..fb00c94
--- /dev/null
@@ -0,0 +1,75 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+promise_test(() => {
+
+  let controller;
+  new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  garbageCollect();
+
+  return delay(50).then(() => {
+    controller.close();
+    assert_throws(new TypeError(), () => controller.close(), 'close should throw a TypeError the second time');
+    assert_throws(new TypeError(), () => controller.error(), 'error should throw a TypeError on a closed stream');
+  });
+
+}, 'ReadableStreamController methods should continue working properly when scripts lose their reference to the ' +
+   'readable stream');
+
+promise_test(() => {
+
+  let controller;
+
+  const closedPromise = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  }).getReader().closed;
+
+  garbageCollect();
+
+  return delay(50).then(() => controller.close()).then(() => closedPromise);
+
+}, 'ReadableStream closed promise should fulfill even if the stream and reader JS references are lost');
+
+promise_test(t => {
+
+  const theError = new Error('boo');
+  let controller;
+
+  const closedPromise = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  }).getReader().closed;
+
+  garbageCollect();
+
+  return delay(50).then(() => controller.error(theError))
+                  .then(() => promise_rejects(t, theError, closedPromise));
+
+}, 'ReadableStream closed promise should reject even if stream and reader JS references are lost');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({});
+
+  rs.getReader();
+
+  garbageCollect();
+
+  return delay(50).then(() => assert_throws(new TypeError(), () => rs.getReader(),
+    'old reader should still be locking the stream even after garbage collection'));
+
+}, 'Garbage-collecting a ReadableStreamReader should not unlock its stream');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general-expected.txt
new file mode 100644 (file)
index 0000000..c5b5d6f
--- /dev/null
@@ -0,0 +1,72 @@
+
+PASS ReadableStream can be constructed with no errors 
+PASS ReadableStream can't be constructed with garbage 
+FAIL ReadableStream instances should have the correct list of properties assert_false: method should be non-enumerable expected false got true
+PASS ReadableStream constructor should throw for non-function start arguments 
+PASS ReadableStream constructor can get initial garbage as cancel argument 
+PASS ReadableStream constructor can get initial garbage as pull argument 
+FAIL ReadableStream start should be called with the proper parameters assert_false: close should be non-enumerable expected false got true
+PASS ReadableStream start controller parameter should be extensible 
+PASS ReadableStream should be able to call start method within prototype chain of its source 
+PASS ReadableStream start should be able to return a promise 
+PASS ReadableStream start should be able to return a promise and reject it 
+PASS ReadableStream should be able to enqueue different objects. 
+PASS ReadableStream: if pull rejects, it should error the stream 
+PASS ReadableStream: should only call pull once upon starting the stream 
+PASS ReadableStream: should call pull when trying to read from a started, empty stream 
+PASS ReadableStream: should only call pull once on a non-empty stream read from before start fulfills 
+PASS ReadableStream: should only call pull once on a non-empty stream read from after start fulfills 
+PASS ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining 
+PASS ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining 
+PASS ReadableStream: should not call pull until the previous pull call's promise fulfills 
+PASS ReadableStream: should pull after start, and after every read 
+PASS ReadableStream: should not call pull after start if the stream is now closed 
+PASS ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows 
+PASS ReadableStream pull should be able to close a stream. 
+PASS ReadableStream: enqueue should throw when the stream is readable but draining 
+PASS ReadableStream: enqueue should throw when the stream is closed 
+PASS ReadableStream: enqueue should throw the stored error when the stream is errored 
+PASS ReadableStream: should call underlying source methods as methods 
+PASS ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue 
+PASS ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately 
+PASS ReadableStream integration test: adapting a random push source 
+PASS ReadableStream integration test: adapting a sync pull source 
+PASS ReadableStream integration test: adapting an async pull source 
+FAIL Load general.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL ReadableStream can be constructed with no errors Can't find variable: ReadableStream
+FAIL ReadableStream can't be constructed with garbage assert_throws: constructor should throw when the source is null function "() => new ReadableStream(null)" threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "TypeError" ("TypeError")
+FAIL ReadableStream instances should have the correct list of properties Can't find variable: ReadableStream
+FAIL ReadableStream constructor should throw for non-function start arguments assert_throws: constructor should throw when start is not a function function "() => {
+    new ReadableStream({ start: 'potato' });
+  }" threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "TypeError" ("TypeError")
+FAIL ReadableStream constructor can get initial garbage as cancel argument Can't find variable: ReadableStream
+FAIL ReadableStream constructor can get initial garbage as pull argument Can't find variable: ReadableStream
+FAIL ReadableStream start should be called with the proper parameters Can't find variable: ReadableStream
+FAIL ReadableStream start controller parameter should be extensible Can't find variable: ReadableStream
+FAIL ReadableStream should be able to call start method within prototype chain of its source Can't find variable: ReadableStream
+FAIL ReadableStream start should be able to return a promise Can't find variable: ReadableStream
+FAIL ReadableStream start should be able to return a promise and reject it Can't find variable: ReadableStream
+FAIL ReadableStream should be able to enqueue different objects. Can't find variable: ReadableStream
+FAIL ReadableStream: if pull rejects, it should error the stream Can't find variable: ReadableStream
+FAIL ReadableStream: should only call pull once upon starting the stream Can't find variable: ReadableStream
+FAIL ReadableStream: should call pull when trying to read from a started, empty stream Can't find variable: ReadableStream
+FAIL ReadableStream: should only call pull once on a non-empty stream read from before start fulfills Can't find variable: ReadableStream
+FAIL ReadableStream: should only call pull once on a non-empty stream read from after start fulfills Can't find variable: ReadableStream
+FAIL ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining Can't find variable: ReadableStream
+FAIL ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining Can't find variable: ReadableStream
+FAIL ReadableStream: should not call pull until the previous pull call's promise fulfills Can't find variable: ReadableStream
+FAIL ReadableStream: should pull after start, and after every read Can't find variable: ReadableStream
+FAIL ReadableStream: should not call pull after start if the stream is now closed Can't find variable: ReadableStream
+FAIL ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows Can't find variable: ReadableStream
+FAIL ReadableStream pull should be able to close a stream. Can't find variable: ReadableStream
+FAIL ReadableStream: enqueue should throw when the stream is readable but draining Can't find variable: ReadableStream
+FAIL ReadableStream: enqueue should throw when the stream is closed Can't find variable: ReadableStream
+FAIL ReadableStream: enqueue should throw the stored error when the stream is errored Can't find variable: ReadableStream
+FAIL ReadableStream: should call underlying source methods as methods Can't find variable: ReadableStream
+FAIL ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue Can't find variable: ReadableStream
+FAIL ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately Can't find variable: ReadableStream
+FAIL ReadableStream integration test: adapting a random push source Can't find variable: ReadableStream
+FAIL ReadableStream integration test: adapting a sync pull source Can't find variable: ReadableStream
+FAIL ReadableStream integration test: adapting an async pull source Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general.html
new file mode 100644 (file)
index 0000000..f5241ff
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+<script src="../resources/rs-utils.js"></script>
+<script src="general.js"></script>
+<script>
+'use strict';
+worker_test('general.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/general.js
new file mode 100644 (file)
index 0000000..44d1a4a
--- /dev/null
@@ -0,0 +1,831 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('../resources/rs-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  new ReadableStream(); // ReadableStream constructed with no parameters
+  new ReadableStream({ }); // ReadableStream constructed with an empty object as parameter
+  new ReadableStream(undefined); // ReadableStream constructed with undefined as parameter
+
+  let x;
+  new ReadableStream(x); // ReadableStream constructed with an undefined variable as parameter
+
+}, 'ReadableStream can be constructed with no errors');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStream(null), 'constructor should throw when the source is null');
+
+}, 'ReadableStream can\'t be constructed with garbage');
+
+test(() => {
+
+  const methods = ['cancel', 'constructor', 'getReader', 'pipeThrough', 'pipeTo', 'tee'];
+  const properties = methods.concat(['locked']).sort();
+
+  const rs = new ReadableStream();
+  const proto = Object.getPrototypeOf(rs);
+
+  assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties, 'should have all the correct methods');
+
+  for (const m of methods) {
+    const propDesc = Object.getOwnPropertyDescriptor(proto, m);
+    assert_false(propDesc.enumerable, 'method should be non-enumerable');
+    assert_true(propDesc.configurable, 'method should be configurable');
+    assert_true(propDesc.writable, 'method should be writable');
+    assert_equals(typeof rs[m], 'function', 'method should be a function');
+  }
+
+  const lockedPropDesc = Object.getOwnPropertyDescriptor(proto, 'locked');
+  assert_false(lockedPropDesc.enumerable, 'locked should be non-enumerable');
+  assert_equals(lockedPropDesc.writable, undefined, 'locked should not be a data property');
+  assert_equals(typeof lockedPropDesc.get, 'function', 'locked should have a getter');
+  assert_equals(lockedPropDesc.set, undefined, 'locked should not have a setter');
+  assert_true(lockedPropDesc.configurable, 'locked should be configurable');
+
+  assert_equals(rs.cancel.length, 1, 'cancel should have 1 parameter');
+  assert_equals(rs.constructor.length, 0, 'constructor should have no parameters');
+  assert_equals(rs.getReader.length, 0, 'getReader should have no parameters');
+  assert_equals(rs.pipeThrough.length, 2, 'pipeThrough should have 2 parameters');
+  assert_equals(rs.pipeTo.length, 1, 'pipeTo should have 1 parameter');
+  assert_equals(rs.tee.length, 0, 'tee should have no parameters');
+
+}, 'ReadableStream instances should have the correct list of properties');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => {
+    new ReadableStream({ start: 'potato' });
+  }, 'constructor should throw when start is not a function');
+
+}, 'ReadableStream constructor should throw for non-function start arguments');
+
+test(() => {
+
+  new ReadableStream({ cancel: '2' });
+
+}, 'ReadableStream constructor can get initial garbage as cancel argument');
+
+test(() => {
+
+  new ReadableStream({ pull: { } });
+
+}, 'ReadableStream constructor can get initial garbage as pull argument');
+
+test(() => {
+
+  let startCalled = false;
+
+  const source = {
+    start(controller) {
+      assert_equals(this, source, 'source is this during start');
+
+      const methods = ['close', 'enqueue', 'error', 'constructor'];
+      const properties = ['desiredSize'].concat(methods).sort();
+      const proto = Object.getPrototypeOf(controller);
+
+      assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties,
+        'the controller should have the right properties');
+
+      for (const m of methods) {
+        const propDesc = Object.getOwnPropertyDescriptor(proto, m);
+        assert_equals(typeof controller[m], 'function', `should have a ${m} method`);
+        assert_false(propDesc.enumerable, m + ' should be non-enumerable');
+        assert_true(propDesc.configurable, m + ' should be configurable');
+        assert_true(propDesc.writable, m + ' should be writable');
+      }
+
+      const desiredSizePropDesc = Object.getOwnPropertyDescriptor(proto, 'desiredSize');
+      assert_false(desiredSizePropDesc.enumerable, 'desiredSize should be non-enumerable');
+      assert_equals(desiredSizePropDesc.writable, undefined, 'desiredSize should not be a data property');
+      assert_equals(typeof desiredSizePropDesc.get, 'function', 'desiredSize should have a getter');
+      assert_equals(desiredSizePropDesc.set, undefined, 'desiredSize should not have a setter');
+      assert_true(desiredSizePropDesc.configurable, 'desiredSize should be configurable');
+
+      assert_equals(controller.close.length, 0, 'close should have no parameters');
+      assert_equals(controller.constructor.length, 1, 'constructor should have 1 parameter');
+      assert_equals(controller.enqueue.length, 1, 'enqueue should have 1 parameter');
+      assert_equals(controller.error.length, 1, 'error should have 1 parameter');
+
+      startCalled = true;
+    }
+  };
+
+  new ReadableStream(source);
+  assert_true(startCalled);
+
+}, 'ReadableStream start should be called with the proper parameters');
+
+test(() => {
+
+  let startCalled = false;
+  const source = {
+    start(controller) {
+      const properties = ['close', 'constructor', 'desiredSize', 'enqueue', 'error'];
+      assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties,
+        'prototype should have the right properties');
+
+      controller.test = '';
+      assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties,
+        'prototype should still have the right properties');
+      assert_not_equals(Object.getOwnPropertyNames(controller).indexOf('test'), -1,
+        '"test" should be a property of the controller');
+
+      startCalled = true;
+    }
+  };
+
+  new ReadableStream(source);
+  assert_true(startCalled);
+
+}, 'ReadableStream start controller parameter should be extensible');
+
+promise_test(() => {
+
+  function SimpleStreamSource() {}
+  let resolve;
+  const promise = new Promise(r => resolve = r);
+  SimpleStreamSource.prototype = {
+    start: resolve
+  };
+
+  new ReadableStream(new SimpleStreamSource());
+  return promise;
+
+}, 'ReadableStream should be able to call start method within prototype chain of its source');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      return delay(5).then(() => {
+        c.enqueue('a');
+        c.close();
+      });
+    }
+  });
+
+  const reader = rs.getReader();
+  return reader.read().then(r => {
+    assert_object_equals(r, { value: 'a', done: false }, 'value read should be the one enqueued');
+    return reader.closed;
+  });
+
+}, 'ReadableStream start should be able to return a promise');
+
+promise_test(() => {
+
+  const theError = new Error('rejected!');
+  const rs = new ReadableStream({
+    start() {
+      return delay(1).then(() => { throw theError; });
+    }
+  });
+
+  return rs.getReader().closed.then(() => {
+    assert_unreached('closed promise should be rejected');
+  }, e => {
+    assert_equals(e, theError, 'promise should be rejected with the same error');
+  });
+
+}, 'ReadableStream start should be able to return a promise and reject it');
+
+promise_test(() => {
+
+  const objects = [
+    { potato: 'Give me more!' },
+    'test',
+    1
+  ];
+
+  const rs = new ReadableStream({
+    start(c) {
+      for (const o of objects) {
+        c.enqueue(o);
+      }
+      c.close();
+    }
+  });
+
+  const reader = rs.getReader();
+
+  return Promise.all([reader.read(), reader.read(), reader.read(), reader.closed]).then(r => {
+    assert_object_equals(r[0], { value: objects[0], done: false }, 'value read should be the one enqueued');
+    assert_object_equals(r[1], { value: objects[1], done: false }, 'value read should be the one enqueued');
+    assert_object_equals(r[2], { value: objects[2], done: false }, 'value read should be the one enqueued');
+  });
+
+}, 'ReadableStream should be able to enqueue different objects.');
+
+promise_test(() => {
+
+  const error = new Error('pull failure');
+  const rs = new ReadableStream({
+    pull() {
+      return Promise.reject(error);
+    }
+  });
+
+  const reader = rs.getReader();
+
+  let closed = false;
+  let read = false;
+
+  return Promise.all([
+    reader.closed.then(() => {
+      assert_unreached('closed should be rejected');
+    }, e => {
+      closed = true;
+      assert_true(read);
+      assert_equals(e, error, 'closed should be rejected with the thrown error');
+    }),
+    reader.read().then(() => {
+      assert_unreached('read() should be rejected');
+    }, e => {
+      read = true;
+      assert_false(closed);
+      assert_equals(e, error, 'read() should be rejected with the thrown error');
+    })
+  ]);
+
+}, 'ReadableStream: if pull rejects, it should error the stream');
+
+promise_test(() => {
+
+  let pullCount = 0;
+  const startPromise = Promise.resolve();
+
+  new ReadableStream({
+    start() {
+      return startPromise;
+    },
+    pull() {
+      pullCount++;
+    }
+  });
+
+  return startPromise.then(() => {
+    assert_equals(pullCount, 1, 'pull should be called once start finishes');
+    return delay(10);
+  }).then(() => {
+    assert_equals(pullCount, 1, 'pull should be called exactly once');
+  });
+
+}, 'ReadableStream: should only call pull once upon starting the stream');
+
+promise_test(() => {
+
+  let pullCount = 0;
+
+  const rs = new ReadableStream({
+    pull(c) {
+      // Don't enqueue immediately after start. We want the stream to be empty when we call .read() on it.
+      if (pullCount > 0) {
+        c.enqueue(pullCount);
+      }
+      ++pullCount;
+    }
+  });
+
+  return delay(1).then(() => {
+    assert_equals(pullCount, 1, 'pull should be called once start finishes');
+
+    const reader = rs.getReader();
+    const read = reader.read();
+    assert_equals(pullCount, 2, 'pull should be called when read is called');
+    return read;
+  }).then(result => {
+    assert_equals(pullCount, 3, 'pull should be called again in reaction to calling read');
+    assert_object_equals(result, { value: 1, done: false }, 'the result read should be the one enqueued');
+  });
+
+}, 'ReadableStream: should call pull when trying to read from a started, empty stream');
+
+promise_test(() => {
+
+  let pullCount = 0;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      return startPromise;
+    },
+    pull() {
+      pullCount++;
+    }
+  });
+
+  const read = rs.getReader().read();
+  assert_equals(pullCount, 0, 'calling read() should not cause pull to be called yet');
+
+  return startPromise.then(() => {
+    assert_equals(pullCount, 1, 'pull should be called once start finishes');
+    return read;
+  }).then(r => {
+    assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk');
+    assert_equals(pullCount, 1, 'pull should not have been called again');
+    return delay(10);
+  }).then(() => {
+    assert_equals(pullCount, 1, 'pull should be called exactly once');
+  });
+
+}, 'ReadableStream: should only call pull once on a non-empty stream read from before start fulfills');
+
+promise_test(() => {
+
+  let pullCount = 0;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      return startPromise;
+    },
+    pull() {
+      pullCount++;
+    }
+  });
+
+  return startPromise.then(() => {
+    assert_equals(pullCount, 0, 'pull should not be called once start finishes, since the queue is full');
+
+    const read = rs.getReader().read();
+    assert_equals(pullCount, 1, 'calling read() should cause pull to be called immediately');
+    return read;
+  }).then(r => {
+    assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk');
+    return delay(10);
+  }).then(() => {
+    assert_equals(pullCount, 1, 'pull should be called exactly once');
+  });
+
+}, 'ReadableStream: should only call pull once on a non-empty stream read from after start fulfills');
+
+promise_test(() => {
+
+  let pullCount = 0;
+  let controller;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+      return startPromise;
+    },
+    pull() {
+      ++pullCount;
+    }
+  });
+
+  const reader = rs.getReader();
+  return startPromise.then(() => {
+    assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts');
+
+    controller.enqueue('a');
+    assert_equals(pullCount, 1, 'pull should not have been called again after enqueue');
+
+    return reader.read();
+  }).then(() => {
+    assert_equals(pullCount, 2, 'pull should have been called again after read');
+
+    return delay(10);
+  }).then(() => {
+    assert_equals(pullCount, 2, 'pull should be called exactly twice');
+  });
+}, 'ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining');
+
+promise_test(() => {
+
+  let pullCount = 0;
+  let controller;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+      return startPromise;
+    },
+    pull() {
+      ++pullCount;
+    }
+  });
+
+  const reader = rs.getReader();
+
+  return startPromise.then(() => {
+    assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts');
+
+    controller.enqueue('a');
+    assert_equals(pullCount, 1, 'pull should not have been called again after enqueue');
+
+    controller.close();
+
+    return reader.read();
+  }).then(() => {
+    assert_equals(pullCount, 1, 'pull should not have been called a second time after read');
+
+    return delay(10);
+  }).then(() => {
+    assert_equals(pullCount, 1, 'pull should be called exactly once');
+  });
+
+}, 'ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining');
+
+promise_test(() => {
+
+  let resolve;
+  let returnedPromise;
+  let timesCalled = 0;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream({
+    start() {
+      return startPromise;
+    },
+    pull(c) {
+      c.enqueue(++timesCalled);
+      returnedPromise = new Promise(r => resolve = r);
+      return returnedPromise;
+    }
+  });
+  const reader = rs.getReader();
+
+  return startPromise.then(() => {
+    return reader.read();
+  }).then(result1 => {
+    assert_equals(timesCalled, 1,
+      'pull should have been called once after start, but not yet have been called a second time');
+    assert_object_equals(result1, { value: 1, done: false }, 'read() should fulfill with the enqueued value');
+
+    return delay(10);
+  }).then(() => {
+    assert_equals(timesCalled, 1, 'after 10 ms, pull should still only have been called once');
+
+    resolve();
+    return returnedPromise;
+  }).then(() => {
+    assert_equals(timesCalled, 2,
+      'after the promise returned by pull is fulfilled, pull should be called a second time');
+  });
+
+}, 'ReadableStream: should not call pull until the previous pull call\'s promise fulfills');
+
+promise_test(() => {
+
+  let timesCalled = 0;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream(
+    {
+      start(c) {
+        c.enqueue('a');
+        c.enqueue('b');
+        c.enqueue('c');
+        return startPromise;
+      },
+      pull() {
+        ++timesCalled;
+      }
+    },
+    {
+      size() {
+        return 1;
+      },
+      highWaterMark: Infinity
+    }
+  );
+  const reader = rs.getReader();
+
+  return startPromise.then(() => {
+    return reader.read();
+  }).then(result1 => {
+    assert_object_equals(result1, { value: 'a', done: false }, 'first chunk should be as expected');
+
+    return reader.read();
+  }).then(result2 => {
+    assert_object_equals(result2, { value: 'b', done: false }, 'second chunk should be as expected');
+
+    return reader.read();
+  }).then(result3 => {
+    assert_object_equals(result3, { value: 'c', done: false }, 'third chunk should be as expected');
+
+    return delay(10);
+  }).then(() => {
+    // Once for after start, and once for every read.
+    assert_equals(timesCalled, 4, 'pull() should be called exactly four times');
+  });
+
+}, 'ReadableStream: should pull after start, and after every read');
+
+promise_test(() => {
+
+  let timesCalled = 0;
+  const startPromise = Promise.resolve();
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.close();
+      return startPromise;
+    },
+    pull() {
+      ++timesCalled;
+    }
+  });
+
+  const reader = rs.getReader();
+  return startPromise.then(() => {
+    assert_equals(timesCalled, 0, 'after start finishes, pull should not have been called');
+
+    return reader.read();
+  }).then(() => {
+    assert_equals(timesCalled, 0, 'reading should not have triggered a pull call');
+
+    return reader.closed;
+  }).then(() => {
+    assert_equals(timesCalled, 0, 'stream should have closed with still no calls to pull');
+  });
+
+}, 'ReadableStream: should not call pull after start if the stream is now closed');
+
+promise_test(() => {
+
+  let timesCalled = 0;
+  let resolve;
+  const ready = new Promise(r => resolve = r);
+
+  new ReadableStream(
+    {
+      start() {},
+      pull(c) {
+        c.enqueue(++timesCalled);
+
+        if (timesCalled === 4) {
+          resolve();
+        }
+      }
+    },
+    {
+      size() {
+        return 1;
+      },
+      highWaterMark: 4
+    }
+  );
+
+  return ready.then(() => {
+    // after start: size = 0, pull()
+    // after enqueue(1): size = 1, pull()
+    // after enqueue(2): size = 2, pull()
+    // after enqueue(3): size = 3, pull()
+    // after enqueue(4): size = 4, do not pull
+    assert_equals(timesCalled, 4, 'pull() should have been called four times');
+  });
+
+}, 'ReadableStream: should call pull after enqueueing from inside pull (with no read requests), if strategy allows');
+
+promise_test(() => {
+
+  let pullCalled = false;
+
+  const rs = new ReadableStream({
+    pull(c) {
+      pullCalled = true;
+      c.close();
+    }
+  });
+
+  const reader = rs.getReader();
+  return reader.closed.then(() => {
+    assert_true(pullCalled);
+  });
+
+}, 'ReadableStream pull should be able to close a stream.');
+
+test(() => {
+
+  let startCalled = false;
+
+  new ReadableStream({
+    start(c) {
+      assert_equals(c.enqueue('a'), undefined, 'the first enqueue should return undefined');
+      c.close();
+
+      assert_throws(new TypeError(), () => c.enqueue('b'), 'enqueue after close should throw a TypeError');
+      startCalled = true;
+    }
+  });
+
+  assert_true(startCalled);
+
+}, 'ReadableStream: enqueue should throw when the stream is readable but draining');
+
+test(() => {
+
+  let startCalled = false;
+
+  new ReadableStream({
+    start(c) {
+      c.close();
+
+      assert_throws(new TypeError(), () => c.enqueue('a'), 'enqueue after close should throw a TypeError');
+      startCalled = true;
+    }
+  });
+
+  assert_true(startCalled);
+
+}, 'ReadableStream: enqueue should throw when the stream is closed');
+
+test(() => {
+
+  let startCalled = false;
+  const expectedError = new Error('i am sad');
+
+  new ReadableStream({
+    start(c) {
+      c.error(expectedError);
+
+      assert_throws(expectedError, () => c.enqueue('a'), 'enqueue after error should throw that error');
+      startCalled = true;
+    }
+  });
+
+  assert_true(startCalled);
+
+}, 'ReadableStream: enqueue should throw the stored error when the stream is errored');
+
+promise_test(() => {
+
+  let startCalled = 0;
+  let pullCalled = 0;
+  let cancelCalled = 0;
+
+  /* eslint-disable no-use-before-define */
+  class Source {
+    start(c) {
+      startCalled++;
+      assert_equals(this, theSource, 'start() should be called with the correct this');
+      c.enqueue('a');
+    }
+
+    pull() {
+      pullCalled++;
+      assert_equals(this, theSource, 'pull() should be called with the correct this');
+    }
+
+    cancel() {
+      cancelCalled++;
+      assert_equals(this, theSource, 'cancel() should be called with the correct this');
+    }
+  }
+  /* eslint-enable no-use-before-define */
+
+  const theSource = new Source();
+  theSource.debugName = 'the source object passed to the constructor'; // makes test failures easier to diagnose
+
+  const rs = new ReadableStream(theSource);
+  const reader = rs.getReader();
+
+  return reader.read().then(() => {
+    reader.releaseLock();
+    rs.cancel();
+    assert_equals(startCalled, 1);
+    assert_equals(pullCalled, 1);
+    assert_equals(cancelCalled, 1);
+    return rs.getReader().closed;
+  });
+
+}, 'ReadableStream: should call underlying source methods as methods');
+
+test(() => {
+
+  let startCalled = false;
+  new ReadableStream({
+    start(c) {
+      assert_equals(c.desiredSize, 1);
+      c.enqueue('a');
+      assert_equals(c.desiredSize, 0);
+      c.enqueue('b');
+      assert_equals(c.desiredSize, -1);
+      c.enqueue('c');
+      assert_equals(c.desiredSize, -2);
+      c.enqueue('d');
+      assert_equals(c.desiredSize, -3);
+      c.enqueue('e');
+      startCalled = true;
+    }
+  });
+
+  assert_true(startCalled);
+
+}, 'ReadableStream strategies: the default strategy should give desiredSize of 1 to start, decreasing by 1 per enqueue');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+  const reader = rs.getReader();
+
+  assert_equals(controller.desiredSize, 1, 'desiredSize should start at 1');
+  controller.enqueue('a');
+  assert_equals(controller.desiredSize, 0, 'desiredSize should decrease to 0 after first enqueue');
+
+  return reader.read().then(result1 => {
+    assert_object_equals(result1, { value: 'a', done: false }, 'first chunk read should be correct');
+
+    assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the first read');
+    controller.enqueue('b');
+    assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the second enqueue');
+
+    return reader.read();
+  }).then(result2 => {
+    assert_object_equals(result2, { value: 'b', done: false }, 'second chunk read should be correct');
+
+    assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the second read');
+    controller.enqueue('c');
+    assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the third enqueue');
+
+    return reader.read();
+  }).then(result3 => {
+    assert_object_equals(result3, { value: 'c', done: false }, 'third chunk read should be correct');
+
+    assert_equals(controller.desiredSize, 1, 'desiredSize should go up to 1 after the third read');
+    controller.enqueue('d');
+    assert_equals(controller.desiredSize, 0, 'desiredSize should go down to 0 after the fourth enqueue');
+  });
+
+}, 'ReadableStream strategies: the default strategy should continue giving desiredSize of 1 if the chunks are read immediately');
+
+promise_test(t => {
+
+  const randomSource = new RandomPushSource(8);
+
+  const rs = new ReadableStream({
+    start(c) {
+      assert_equals(typeof c, 'object', 'c should be an object in start');
+      assert_equals(typeof c.enqueue, 'function', 'enqueue should be a function in start');
+      assert_equals(typeof c.close, 'function', 'close should be a function in start');
+      assert_equals(typeof c.error, 'function', 'error should be a function in start');
+
+      randomSource.ondata = t.step_func(chunk => {
+        if (!c.enqueue(chunk) <= 0) {
+          randomSource.readStop();
+        }
+      });
+
+      randomSource.onend = c.close.bind(c);
+      randomSource.onerror = c.error.bind(c);
+    },
+
+    pull(c) {
+      assert_equals(typeof c, 'object', 'c should be an object in pull');
+      assert_equals(typeof c.enqueue, 'function', 'enqueue should be a function in pull');
+      assert_equals(typeof c.close, 'function', 'close should be a function in pull');
+
+      randomSource.readStart();
+    }
+  });
+
+  return readableStreamToArray(rs).then(chunks => {
+    assert_equals(chunks.length, 8, '8 chunks should be read');
+    for (const chunk of chunks) {
+      assert_equals(chunk.length, 128, 'chunk should have 128 bytes');
+    }
+  });
+
+}, 'ReadableStream integration test: adapting a random push source');
+
+promise_test(() => {
+
+  const rs = sequentialReadableStream(10);
+
+  return readableStreamToArray(rs).then(chunks => {
+    assert_true(rs.source.closed, 'source should be closed after all chunks are read');
+    assert_array_equals(chunks, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'the expected 10 chunks should be read');
+  });
+
+}, 'ReadableStream integration test: adapting a sync pull source');
+
+promise_test(() => {
+
+  const rs = sequentialReadableStream(10, { async: true });
+
+  return readableStreamToArray(rs).then(chunks => {
+    assert_true(rs.source.closed, 'source should be closed after all chunks are read');
+    assert_array_equals(chunks, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'the expected 10 chunks should be read');
+  });
+
+}, 'ReadableStream integration test: adapting an async pull source');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through-expected.txt
new file mode 100644 (file)
index 0000000..8fb3320
--- /dev/null
@@ -0,0 +1,14 @@
+
+PASS ReadableStream.prototype.pipeThrough should work generically on its this and its arguments 
+PASS ReadableStream.prototype.pipeThrough should throw when its first argument is not convertible to an object 
+PASS ReadableStream.prototype.pipeThrough should throw when "this" has no pipeTo method 
+FAIL ReadableStream.prototype.pipeThrough should rethrow errors from accessing pipeTo, readable, or writable assert_unreached: pipeTo should not be called Reached unreachable code
+PASS ReadableStream.prototype.pipeThrough should work with missing readable, writable, or options 
+FAIL Load pipe-through.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL ReadableStream.prototype.pipeThrough should work generically on its this and its arguments Can't find variable: ReadableStream
+FAIL ReadableStream.prototype.pipeThrough should throw when its first argument is not convertible to an object Can't find variable: ReadableStream
+FAIL ReadableStream.prototype.pipeThrough should throw when "this" has no pipeTo method Can't find variable: ReadableStream
+FAIL ReadableStream.prototype.pipeThrough should rethrow errors from accessing pipeTo, readable, or writable assert_throws: pipeThrough should rethrow the error thrown by pipeTo function "() => ReadableStream.prototype.pipeThrough.call(throwingP..." threw object "ReferenceError: Can't find variable: ReadableStream" ("ReferenceError") expected object "Error: potato" ("Error")
+FAIL ReadableStream.prototype.pipeThrough should work with missing readable, writable, or options Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through.html
new file mode 100644 (file)
index 0000000..62d98d4
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+<script src="pipe-through.js"></script>
+<script>
+'use strict';
+worker_test('pipe-through.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/pipe-through.js
new file mode 100644 (file)
index 0000000..4988928
--- /dev/null
@@ -0,0 +1,108 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  let pipeToArguments;
+  const thisValue = {
+    pipeTo() {
+      pipeToArguments = arguments;
+    }
+  };
+
+  const input = { readable: {}, writable: {} };
+  const options = {};
+  const result = ReadableStream.prototype.pipeThrough.call(thisValue, input, options);
+
+  assert_array_equals(pipeToArguments, [input.writable, options],
+    'correct arguments should be passed to thisValue.pipeTo');
+  assert_equals(result, input.readable, 'return value should be the passed readable property');
+
+}, 'ReadableStream.prototype.pipeThrough should work generically on its this and its arguments');
+
+test(() => {
+
+  const thisValue = {
+    pipeTo() {
+      assert_unreached('pipeTo should not be called');
+    }
+  };
+
+  methodThrows(ReadableStream.prototype, 'pipeThrough', thisValue, [undefined, {}]);
+  methodThrows(ReadableStream.prototype, 'pipeThrough', thisValue, [null, {}]);
+
+}, 'ReadableStream.prototype.pipeThrough should throw when its first argument is not convertible to an object');
+
+test(() => {
+
+  const args = [{ readable: {}, writable: {} }, {}];
+
+  methodThrows(ReadableStream.prototype, 'pipeThrough', undefined, args);
+  methodThrows(ReadableStream.prototype, 'pipeThrough', null, args);
+  methodThrows(ReadableStream.prototype, 'pipeThrough', 1, args);
+  methodThrows(ReadableStream.prototype, 'pipeThrough', { pipeTo: 'test' }, args);
+
+}, 'ReadableStream.prototype.pipeThrough should throw when "this" has no pipeTo method');
+
+test(() => {
+  const error = new Error('potato');
+
+  const throwingPipeTo = {
+    get pipeTo() {
+      throw error;
+    }
+  };
+  assert_throws(error,
+    () => ReadableStream.prototype.pipeThrough.call(throwingPipeTo, { readable: { }, writable: { } }, {}),
+    'pipeThrough should rethrow the error thrown by pipeTo');
+
+  const thisValue = {
+    pipeTo() {
+      assert_unreached('pipeTo should not be called');
+    }
+  };
+
+  const throwingWritable = {
+    readable: {},
+    get writable() {
+      throw error;
+    }
+  };
+  assert_throws(error,
+    () => ReadableStream.prototype.pipeThrough.call(thisValue, throwingWritable, {}),
+    'pipeThrough should rethrow the error thrown by the writable getter');
+
+  const throwingReadable = {
+    get readable() {
+      throw error;
+    },
+    writable: {}
+  };
+  assert_throws(error,
+    () => ReadableStream.prototype.pipeThrough.call(thisValue, throwingReadable, {}),
+    'pipeThrough should rethrow the error thrown by the readable getter');
+
+}, 'ReadableStream.prototype.pipeThrough should rethrow errors from accessing pipeTo, readable, or writable');
+
+test(() => {
+
+  let count = 0;
+  const thisValue = {
+    pipeTo() {
+      ++count;
+    }
+  };
+
+  ReadableStream.prototype.pipeThrough.call(thisValue, { readable: {}, writable: {} });
+  ReadableStream.prototype.pipeThrough.call(thisValue, { readable: {} }, {});
+  ReadableStream.prototype.pipeThrough.call(thisValue, { writable: {} }, {});
+
+  assert_equals(count, 3, 'pipeTo was called 3 times');
+
+}, 'ReadableStream.prototype.pipeThrough should work with missing readable, writable, or options');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader-expected.txt
new file mode 100644 (file)
index 0000000..9e4fc22
--- /dev/null
@@ -0,0 +1,56 @@
+
+PASS Can get the ReadableStreamReader constructor indirectly 
+PASS ReadableStreamReader constructor should get a ReadableStream object as argument 
+FAIL ReadableStreamReader instances should have the correct list of properties assert_equals: method should be non-enumerable expected false but got true
+PASS ReadableStreamReader closed should always return the same promise object 
+PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction) 
+PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction) 
+PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader) 
+PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader) 
+PASS Constructing a ReadableStreamReader directly should be OK if the stream is closed 
+PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored 
+PASS Reading from a reader for an empty stream will wait until a chunk is available 
+PASS cancel() on a reader does not release the reader 
+PASS closed should be fulfilled after stream is closed (.closed access before acquiring) 
+PASS closed should be rejected after reader releases its lock (multiple stream locks) 
+PASS Multiple readers can access the stream in sequence 
+PASS Cannot use an already-released reader to unlock a stream again 
+PASS cancel() on a released reader is a no-op and does not pass through 
+PASS Getting a second reader after erroring the stream and releasing the reader should succeed 
+PASS ReadableStreamReader closed promise should be rejected with undefined if that is the error 
+PASS ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error 
+PASS Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise 
+PASS Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise 
+PASS Reading twice on a stream that gets closed 
+PASS Reading twice on a closed stream 
+PASS Reading twice on an errored stream 
+PASS Reading twice on a stream that gets errored 
+FAIL Load readable-stream-reader.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL Can get the ReadableStreamReader constructor indirectly Can't find variable: ReadableStream
+PASS ReadableStreamReader constructor should get a ReadableStream object as argument 
+FAIL ReadableStreamReader instances should have the correct list of properties Can't find variable: ReadableStream
+FAIL ReadableStreamReader closed should always return the same promise object Can't find variable: ReadableStream
+FAIL Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction) Can't find variable: ReadableStream
+FAIL Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction) Can't find variable: ReadableStream
+FAIL Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader) Can't find variable: ReadableStream
+FAIL Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader) Can't find variable: ReadableStream
+FAIL Constructing a ReadableStreamReader directly should be OK if the stream is closed Can't find variable: ReadableStream
+FAIL Constructing a ReadableStreamReader directly should be OK if the stream is errored Can't find variable: ReadableStream
+FAIL Reading from a reader for an empty stream will wait until a chunk is available Can't find variable: ReadableStream
+FAIL cancel() on a reader does not release the reader Can't find variable: ReadableStream
+FAIL closed should be fulfilled after stream is closed (.closed access before acquiring) Can't find variable: ReadableStream
+FAIL closed should be rejected after reader releases its lock (multiple stream locks) Can't find variable: ReadableStream
+FAIL Multiple readers can access the stream in sequence Can't find variable: ReadableStream
+FAIL Cannot use an already-released reader to unlock a stream again Can't find variable: ReadableStream
+FAIL cancel() on a released reader is a no-op and does not pass through Can't find variable: ReadableStream
+FAIL Getting a second reader after erroring the stream and releasing the reader should succeed Can't find variable: ReadableStream
+FAIL ReadableStreamReader closed promise should be rejected with undefined if that is the error Can't find variable: ReadableStream
+FAIL ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error Can't find variable: ReadableStream
+FAIL Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise Can't find variable: ReadableStream
+FAIL Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise Can't find variable: ReadableStream
+FAIL Reading twice on a stream that gets closed Can't find variable: ReadableStream
+FAIL Reading twice on a closed stream Can't find variable: ReadableStream
+FAIL Reading twice on an errored stream Can't find variable: ReadableStream
+FAIL Reading twice on a stream that gets errored Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader.html
new file mode 100644 (file)
index 0000000..df0db11
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="readable-stream-reader.js"></script>
+<script>
+'use strict';
+worker_test('readable-stream-reader.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/readable-stream-reader.js
new file mode 100644 (file)
index 0000000..1d5bc13
--- /dev/null
@@ -0,0 +1,485 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/rs-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+let ReadableStreamReader;
+
+test(() => {
+
+  // It's not exposed globally, but we test a few of its properties here.
+  ReadableStreamReader = (new ReadableStream()).getReader().constructor;
+
+}, 'Can get the ReadableStreamReader constructor indirectly');
+
+test(() => {
+
+  assert_throws(new TypeError(), () => new ReadableStreamReader('potato'));
+  assert_throws(new TypeError(), () => new ReadableStreamReader({}));
+  assert_throws(new TypeError(), () => new ReadableStreamReader());
+
+}, 'ReadableStreamReader constructor should get a ReadableStream object as argument');
+
+test(() => {
+
+  const methods = ['cancel', 'constructor', 'read', 'releaseLock'];
+  const properties = methods.concat(['closed']).sort();
+
+  const rsReader = new ReadableStreamReader(new ReadableStream());
+  const proto = Object.getPrototypeOf(rsReader);
+
+  assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
+
+  for (const m of methods) {
+    const propDesc = Object.getOwnPropertyDescriptor(proto, m);
+    assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
+    assert_equals(propDesc.configurable, true, 'method should be configurable');
+    assert_equals(propDesc.writable, true, 'method should be writable');
+    assert_equals(typeof rsReader[m], 'function', 'should have be a method');
+  }
+
+  const closedPropDesc = Object.getOwnPropertyDescriptor(proto, 'closed');
+  assert_equals(closedPropDesc.enumerable, false, 'closed should be non-enumerable');
+  assert_equals(closedPropDesc.configurable, true, 'closed should be configurable');
+  assert_not_equals(closedPropDesc.get, undefined, 'closed should have a getter');
+  assert_equals(closedPropDesc.set, undefined, 'closed should not have a setter');
+
+  assert_equals(rsReader.cancel.length, 1, 'cancel has 1 parameter');
+  assert_not_equals(rsReader.closed, undefined, 'has a non-undefined closed property');
+  assert_equals(typeof rsReader.closed.then, 'function', 'closed property is thenable');
+  assert_equals(typeof rsReader.constructor, 'function', 'has a constructor method');
+  assert_equals(rsReader.constructor.length, 1, 'constructor has 1 parameter');
+  assert_equals(typeof rsReader.read, 'function', 'has a getReader method');
+  assert_equals(rsReader.read.length, 0, 'read has no parameters');
+  assert_equals(typeof rsReader.releaseLock, 'function', 'has a releaseLock method');
+  assert_equals(rsReader.releaseLock.length, 0, 'releaseLock has no parameters');
+
+}, 'ReadableStreamReader instances should have the correct list of properties');
+
+test(() => {
+
+  const rsReader = new ReadableStreamReader(new ReadableStream());
+  assert_equals(rsReader.closed, rsReader.closed, 'closed should return the same promise');
+
+}, 'ReadableStreamReader closed should always return the same promise object');
+
+test(() => {
+
+  const rs = new ReadableStream();
+  new ReadableStreamReader(rs); // Constructing directly the first time should be fine.
+  assert_throws(new TypeError(), () => new ReadableStreamReader(rs),
+                'constructing directly the second time should fail');
+
+}, 'Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct ' +
+   'construction)');
+
+test(() => {
+
+  const rs = new ReadableStream();
+  new ReadableStreamReader(rs); // Constructing directly should be fine.
+  assert_throws(new TypeError(), () => rs.getReader(), 'getReader() should fail');
+
+}, 'Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct ' +
+   'construction)');
+
+test(() => {
+
+  const rs = new ReadableStream();
+  rs.getReader(); // getReader() should be fine.
+  assert_throws(new TypeError(), () => new ReadableStreamReader(rs), 'constructing directly should fail');
+
+}, 'Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)');
+
+test(() => {
+
+  const rs = new ReadableStream();
+  rs.getReader(); // getReader() should be fine.
+  assert_throws(new TypeError(), () => rs.getReader(), 'getReader() should fail');
+
+}, 'Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)');
+
+test(() => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.close();
+    }
+  });
+
+  new ReadableStreamReader(rs); // Constructing directly should not throw.
+
+}, 'Constructing a ReadableStreamReader directly should be OK if the stream is closed');
+
+test(() => {
+
+  const theError = new Error('don\'t say i didn\'t warn ya');
+  const rs = new ReadableStream({
+    start(c) {
+      c.error(theError);
+    }
+  });
+
+  new ReadableStreamReader(rs); // Constructing directly should not throw.
+
+}, 'Constructing a ReadableStreamReader directly should be OK if the stream is errored');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+  const reader = rs.getReader();
+
+  const promise = reader.read().then(result => {
+    assert_object_equals(result, { value: 'a', done: false }, 'read() should fulfill with the enqueued chunk');
+  });
+
+  controller.enqueue('a');
+  return promise;
+
+}, 'Reading from a reader for an empty stream will wait until a chunk is available');
+
+promise_test(() => {
+
+  let cancelCalled = false;
+  const passedReason = new Error('it wasn\'t the right time, sorry');
+  const rs = new ReadableStream({
+    cancel(reason) {
+      assert_true(rs.locked, 'the stream should still be locked');
+      assert_throws(new TypeError(), () => rs.getReader(), 'should not be able to get another reader');
+      assert_equals(reason, passedReason, 'the cancellation reason is passed through to the underlying source');
+      cancelCalled = true;
+    }
+  });
+
+  const reader = rs.getReader();
+  return reader.cancel(passedReason).then(() => assert_true(cancelCalled));
+
+}, 'cancel() on a reader does not release the reader');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const reader = rs.getReader();
+  const promise = reader.closed;
+
+  controller.close();
+  return promise;
+
+}, 'closed should be fulfilled after stream is closed (.closed access before acquiring)');
+
+promise_test(t => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const reader1 = rs.getReader();
+
+  reader1.releaseLock();
+
+  const reader2 = rs.getReader();
+  controller.close();
+
+  return Promise.all([
+    promise_rejects(t, new TypeError(), reader1.closed),
+    reader2.closed
+  ]);
+
+}, 'closed should be rejected after reader releases its lock (multiple stream locks)');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.enqueue('b');
+      c.close();
+    }
+  });
+
+  const reader1 = rs.getReader();
+  const promise1 = reader1.read().then(r => {
+    assert_object_equals(r, { value: 'a', done: false }, 'reading the first chunk from reader1 works');
+  });
+  reader1.releaseLock();
+
+  const reader2 = rs.getReader();
+  const promise2 = reader2.read().then(r => {
+    assert_object_equals(r, { value: 'b', done: false }, 'reading the second chunk from reader2 works');
+  });
+  reader2.releaseLock();
+
+  return Promise.all([promise1, promise2]);
+
+}, 'Multiple readers can access the stream in sequence');
+
+promise_test(() => {
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+    }
+  });
+
+  const reader1 = rs.getReader();
+  reader1.releaseLock();
+
+  const reader2 = rs.getReader();
+
+  // Should be a no-op
+  reader1.releaseLock();
+
+  return reader2.read().then(result => {
+    assert_object_equals(result, { value: 'a', done: false },
+                         'read() should still work on reader2 even after reader1 is released');
+  });
+
+}, 'Cannot use an already-released reader to unlock a stream again');
+
+promise_test(t => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+    },
+    cancel() {
+      assert_unreached('underlying source cancel should not be called');
+    }
+  });
+
+  const reader = rs.getReader();
+  reader.releaseLock();
+  const cancelPromise = reader.cancel();
+
+  const reader2 = rs.getReader();
+  const readPromise = reader2.read().then(r => {
+    assert_object_equals(r, { value: 'a', done: false }, 'a new reader should be able to read a chunk');
+  });
+
+  return Promise.all([
+    promise_rejects(t, new TypeError(), cancelPromise),
+    readPromise
+  ]);
+
+}, 'cancel() on a released reader is a no-op and does not pass through');
+
+promise_test(t => {
+
+  const promiseAsserts = [];
+
+  let controller;
+  const theError = { name: 'unique error' };
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const reader1 = rs.getReader();
+
+  promiseAsserts.push(
+    promise_rejects(t, theError, reader1.closed),
+    promise_rejects(t, theError, reader1.read())
+  );
+
+  assert_throws(new TypeError(), () => rs.getReader(), 'trying to get another reader before erroring should throw');
+
+  controller.error(theError);
+
+  reader1.releaseLock();
+
+  const reader2 = rs.getReader();
+
+  promiseAsserts.push(
+    promise_rejects(t, theError, reader2.closed),
+    promise_rejects(t, theError, reader2.read())
+  );
+
+  return Promise.all(promiseAsserts);
+
+}, 'Getting a second reader after erroring the stream and releasing the reader should succeed');
+
+promise_test(t => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const promise = rs.getReader().closed.then(
+    t.unreached_func('closed promise should not be fulfilled when stream is errored'),
+    err => {
+      assert_equals(err, undefined, 'passed error should be undefined as it was');
+    }
+  );
+
+  controller.error();
+  return promise;
+
+}, 'ReadableStreamReader closed promise should be rejected with undefined if that is the error');
+
+
+promise_test(t => {
+
+  const rs = new ReadableStream({
+    start() {
+      return Promise.reject();
+    }
+  });
+
+  return rs.getReader().read().then(
+    t.unreached_func('read promise should not be fulfilled when stream is errored'),
+    err => {
+      assert_equals(err, undefined, 'passed error should be undefined as it was');
+    }
+  );
+
+}, 'ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error');
+
+promise_test(t => {
+
+  const theError = { name: 'unique string' };
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const promise = promise_rejects(t, theError, rs.getReader().closed);
+
+  controller.error(theError);
+  return promise;
+
+}, 'Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise');
+
+promise_test(t => {
+
+  const theError = { name: 'unique string' };
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  controller.error(theError);
+
+  // Let's call getReader twice for extra test coverage of this code path.
+  rs.getReader().releaseLock();
+
+  return promise_rejects(t, theError, rs.getReader().closed);
+
+}, 'Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+  const reader = rs.getReader();
+
+  const promise = Promise.all([
+    reader.read().then(result => {
+      assert_object_equals(result, { value: undefined, done: true }, 'read() should fulfill with close (1)');
+    }),
+    reader.read().then(result => {
+      assert_object_equals(result, { value: undefined, done: true }, 'read() should fulfill with close (2)');
+    }),
+    reader.closed
+  ]);
+
+  controller.close();
+  return promise;
+
+}, 'Reading twice on a stream that gets closed');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  controller.close();
+  const reader = rs.getReader();
+
+  return Promise.all([
+    reader.read().then(result => {
+      assert_object_equals(result, { value: undefined, done: true }, 'read() should fulfill with close (1)');
+    }),
+    reader.read().then(result => {
+      assert_object_equals(result, { value: undefined, done: true }, 'read() should fulfill with close (2)');
+    }),
+    reader.closed
+  ]);
+
+}, 'Reading twice on a closed stream');
+
+promise_test(t => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const myError = { name: 'mashed potatoes' };
+  controller.error(myError);
+
+  const reader = rs.getReader();
+
+  return Promise.all([
+    promise_rejects(t, myError, reader.read()),
+    promise_rejects(t, myError, reader.read()),
+    promise_rejects(t, myError, reader.closed)
+  ]);
+
+}, 'Reading twice on an errored stream');
+
+promise_test(t => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const myError = { name: 'mashed potatoes' };
+  const reader = rs.getReader();
+
+  const promise = Promise.all([
+    promise_rejects(t, myError, reader.read()),
+    promise_rejects(t, myError, reader.read()),
+    promise_rejects(t, myError, reader.closed)
+  ]);
+
+  controller.error(myError);
+  return promise;
+
+}, 'Reading twice on a stream that gets errored');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee-expected.txt
new file mode 100644 (file)
index 0000000..e2f3a4b
--- /dev/null
@@ -0,0 +1,24 @@
+
+PASS ReadableStream teeing: rs.tee() returns an array of two ReadableStreams 
+PASS ReadableStream teeing: should be able to read one branch to the end without affecting the other 
+PASS ReadableStream teeing: values should be equal across each branch 
+PASS ReadableStream teeing: errors in the source should propagate to both branches 
+PASS ReadableStream teeing: canceling branch1 should not impact branch2 
+PASS ReadableStream teeing: canceling branch2 should not impact branch2 
+PASS ReadableStream teeing: canceling both branches should aggregate the cancel reasons into an array 
+PASS ReadableStream teeing: failing to cancel the original stream should cause cancel() to reject on branches 
+PASS ReadableStream teeing: closing the original should immediately close the branches 
+PASS ReadableStream teeing: erroring the original should immediately error the branches 
+FAIL Load tee.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+FAIL ReadableStream teeing: rs.tee() returns an array of two ReadableStreams Can't find variable: ReadableStream
+FAIL ReadableStream teeing: should be able to read one branch to the end without affecting the other Can't find variable: ReadableStream
+FAIL ReadableStream teeing: values should be equal across each branch Can't find variable: ReadableStream
+FAIL ReadableStream teeing: errors in the source should propagate to both branches Can't find variable: ReadableStream
+FAIL ReadableStream teeing: canceling branch1 should not impact branch2 Can't find variable: ReadableStream
+FAIL ReadableStream teeing: canceling branch2 should not impact branch2 Can't find variable: ReadableStream
+FAIL ReadableStream teeing: canceling both branches should aggregate the cancel reasons into an array Can't find variable: ReadableStream
+FAIL ReadableStream teeing: failing to cancel the original stream should cause cancel() to reject on branches Can't find variable: ReadableStream
+FAIL ReadableStream teeing: closing the original should immediately close the branches Can't find variable: ReadableStream
+FAIL ReadableStream teeing: erroring the original should immediately error the branches Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee.html
new file mode 100644 (file)
index 0000000..02c847b
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/rs-utils.js"></script>
+<script src="tee.js"></script>
+<script>
+'use strict';
+worker_test('tee.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/tee.js
new file mode 100644 (file)
index 0000000..485f2af
--- /dev/null
@@ -0,0 +1,254 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('../resources/rs-utils.js');
+  self.importScripts('/resources/testharness.js');
+}
+
+test(() => {
+
+  const rs = new ReadableStream();
+  const result = rs.tee();
+
+  assert_true(Array.isArray(result), 'return value should be an array');
+  assert_equals(result.length, 2, 'array should have length 2');
+  assert_equals(result[0].constructor, ReadableStream, '0th element should be a ReadableStream');
+  assert_equals(result[1].constructor, ReadableStream, '1st element should be a ReadableStream');
+
+}, 'ReadableStream teeing: rs.tee() returns an array of two ReadableStreams');
+
+promise_test(t => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.enqueue('b');
+      c.close();
+    }
+  });
+
+  const branch = rs.tee();
+  const branch1 = branch[0];
+  const branch2 = branch[1];
+  const reader1 = branch1.getReader();
+  const reader2 = branch2.getReader();
+
+  reader2.closed.then(t.unreached_func('branch2 should not be closed'));
+
+  return Promise.all([
+    reader1.closed,
+    reader1.read().then(r => {
+      assert_object_equals(r, { value: 'a', done: false }, 'first chunk from branch1 should be correct');
+    }),
+    reader1.read().then(r => {
+      assert_object_equals(r, { value: 'b', done: false }, 'second chunk from branch1 should be correct');
+    }),
+    reader1.read().then(r => {
+      assert_object_equals(r, { value: undefined, done: true }, 'third read() from branch1 should be done');
+    }),
+    reader2.read().then(r => {
+      assert_object_equals(r, { value: 'a', done: false }, 'first chunk from branch2 should be correct');
+    })
+  ]);
+
+}, 'ReadableStream teeing: should be able to read one branch to the end without affecting the other');
+
+promise_test(() => {
+
+  const theObject = { the: 'test object' };
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue(theObject);
+    }
+  });
+
+  const branch = rs.tee();
+  const branch1 = branch[0];
+  const branch2 = branch[1];
+  const reader1 = branch1.getReader();
+  const reader2 = branch2.getReader();
+
+  return Promise.all([reader1.read(), reader2.read()]).then(values => {
+    assert_object_equals(values[0], values[1], 'the values should be equal');
+  });
+
+}, 'ReadableStream teeing: values should be equal across each branch');
+
+promise_test(t => {
+
+  const theError = { name: 'boo!' };
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.enqueue('b');
+    },
+    pull() {
+      throw theError;
+    }
+  });
+
+  const branches = rs.tee();
+  const reader1 = branches[0].getReader();
+  const reader2 = branches[1].getReader();
+
+  reader1.label = 'reader1';
+  reader2.label = 'reader2';
+
+  return Promise.all([
+    promise_rejects(t, theError, reader1.closed),
+    promise_rejects(t, theError, reader2.closed),
+    reader1.read().then(r => {
+      assert_object_equals(r, { value: 'a', done: false }, 'should be able to read the first chunk in branch1');
+    }),
+    reader1.read().then(r => {
+      assert_object_equals(r, { value: 'b', done: false }, 'should be able to read the second chunk in branch1');
+
+      return promise_rejects(t, theError, reader2.read());
+    })
+    .then(() => promise_rejects(t, theError, reader1.read()))
+  ]);
+
+}, 'ReadableStream teeing: errors in the source should propagate to both branches');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.enqueue('b');
+      c.close();
+    }
+  });
+
+  const branches = rs.tee();
+  const branch1 = branches[0];
+  const branch2 = branches[1];
+  branch1.cancel();
+
+  return Promise.all([
+    readableStreamToArray(branch1).then(chunks => {
+      assert_array_equals(chunks, [], 'branch1 should have no chunks');
+    }),
+    readableStreamToArray(branch2).then(chunks => {
+      assert_array_equals(chunks, ['a', 'b'], 'branch2 should have two chunks');
+    })
+  ]);
+
+}, 'ReadableStream teeing: canceling branch1 should not impact branch2');
+
+promise_test(() => {
+
+  const rs = new ReadableStream({
+    start(c) {
+      c.enqueue('a');
+      c.enqueue('b');
+      c.close();
+    }
+  });
+
+  const branches = rs.tee();
+  const branch1 = branches[0];
+  const branch2 = branches[1];
+  branch2.cancel();
+
+  return Promise.all([
+    readableStreamToArray(branch1).then(chunks => {
+      assert_array_equals(chunks, ['a', 'b'], 'branch1 should have two chunks');
+    }),
+    readableStreamToArray(branch2).then(chunks => {
+      assert_array_equals(chunks, [], 'branch2 should have no chunks');
+    })
+  ]);
+
+}, 'ReadableStream teeing: canceling branch2 should not impact branch2');
+
+promise_test(() => {
+
+  const reason1 = new Error('We\'re wanted men.');
+  const reason2 = new Error('I have the death sentence on twelve systems.');
+
+  let resolve;
+  const promise = new Promise(r => resolve = r);
+  const rs = new ReadableStream({
+    cancel(reason) {
+      assert_array_equals(reason, [reason1, reason2],
+                          'the cancel reason should be an array containing those from the branches');
+      resolve();
+    }
+  });
+
+  const branch = rs.tee();
+  const branch1 = branch[0];
+  const branch2 = branch[1];
+  branch1.cancel(reason1);
+  branch2.cancel(reason2);
+
+  return promise;
+
+}, 'ReadableStream teeing: canceling both branches should aggregate the cancel reasons into an array');
+
+promise_test(t => {
+
+  const theError = { name: 'I\'ll be careful.' };
+  const rs = new ReadableStream({
+    cancel() {
+      throw theError;
+    }
+  });
+
+  const branch = rs.tee();
+  const branch1 = branch[0];
+  const branch2 = branch[1];
+
+  return Promise.all([
+    promise_rejects(t, theError, branch1.cancel()),
+    promise_rejects(t, theError, branch2.cancel())
+  ]);
+
+}, 'ReadableStream teeing: failing to cancel the original stream should cause cancel() to reject on branches');
+
+promise_test(() => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const branches = rs.tee();
+  const reader1 = branches[0].getReader();
+  const reader2 = branches[1].getReader();
+
+  const promise = Promise.all([reader1.closed, reader2.closed]);
+
+  controller.close();
+  return promise;
+
+}, 'ReadableStream teeing: closing the original should immediately close the branches');
+
+promise_test(t => {
+
+  let controller;
+  const rs = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+
+  const branches = rs.tee();
+  const reader1 = branches[0].getReader();
+  const reader2 = branches[1].getReader();
+
+  const theError = { name: 'boo!' };
+  const promise = Promise.all([
+    promise_rejects(t, theError, reader1.closed),
+    promise_rejects(t, theError, reader2.closed)
+  ]);
+
+  controller.error(theError);
+  return promise;
+
+}, 'ReadableStream teeing: erroring the original should immediately error the branches');
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated-expected.txt
new file mode 100644 (file)
index 0000000..1709d10
--- /dev/null
@@ -0,0 +1,174 @@
+
+PASS Running templatedRSEmpty with ReadableStream (empty) 
+PASS instances have the correct methods and properties 
+PASS Running templatedRSEmptyReader with ReadableStream (empty) reader 
+PASS instances have the correct methods and properties 
+PASS locked should be true 
+PASS read() should never settle 
+PASS two read()s should both never settle 
+PASS read() should return distinct promises each time 
+PASS getReader() again on the stream should fail 
+PASS releasing the lock with pending read requests should throw but the read requests should stay pending 
+PASS releasing the lock should cause further read() calls to reject with a TypeError 
+PASS releasing the lock should cause closed calls to reject with a TypeError 
+PASS releasing the lock should cause locked to become false 
+PASS canceling via the reader should cause the reader to act closed 
+PASS canceling via the stream should fail 
+PASS Running templatedRSClosed with ReadableStream (closed via call in start) 
+PASS cancel() should return a distinct fulfilled promise each time 
+PASS locked should be false 
+PASS getReader() should be OK 
+PASS should be able to acquire multiple readers if they are released in succession 
+PASS should not be able to acquire a second reader if we don't release the first one 
+PASS Running templatedRSClosedReader with ReadableStream reader (closed before getting reader) 
+PASS read() should fulfill with { value: undefined, done: true } 
+PASS read() multiple times should fulfill with { value: undefined, done: true } 
+PASS read() should work when used within another read() fulfill callback 
+PASS closed should fulfill with undefined 
+PASS releasing the lock should cause closed to reject and change identity 
+PASS cancel() should return a distinct fulfilled promise each time 
+PASS Running templatedRSClosedReader with ReadableStream reader (closed after getting reader) 
+PASS read() should fulfill with { value: undefined, done: true } 
+PASS read() multiple times should fulfill with { value: undefined, done: true } 
+PASS read() should work when used within another read() fulfill callback 
+PASS closed should fulfill with undefined 
+PASS releasing the lock should cause closed to reject and change identity 
+PASS cancel() should return a distinct fulfilled promise each time 
+PASS Running templatedRSClosed with ReadableStream (closed via cancel) 
+PASS cancel() should return a distinct fulfilled promise each time 
+PASS locked should be false 
+PASS getReader() should be OK 
+PASS should be able to acquire multiple readers if they are released in succession 
+PASS should not be able to acquire a second reader if we don't release the first one 
+PASS Running templatedRSClosedReader with ReadableStream reader (closed via cancel after getting reader) 
+PASS read() should fulfill with { value: undefined, done: true } 
+PASS read() multiple times should fulfill with { value: undefined, done: true } 
+PASS read() should work when used within another read() fulfill callback 
+PASS closed should fulfill with undefined 
+PASS releasing the lock should cause closed to reject and change identity 
+PASS cancel() should return a distinct fulfilled promise each time 
+PASS Running templatedRSErrored with ReadableStream (errored via call in start) 
+PASS getReader() should return a reader that acts errored 
+PASS read() twice should give the error each time 
+PASS locked should be false 
+PASS Running templatedRSErroredSyncOnly with ReadableStream (errored via call in start) 
+PASS should be able to obtain a second reader, with the correct closed promise 
+PASS should not be able to obtain additional readers if we don't release the first lock 
+PASS cancel() should return a distinct rejected promise each time 
+PASS reader cancel() should return a distinct rejected promise each time 
+PASS Running templatedRSErrored with ReadableStream (errored via returning a rejected promise in start) 
+PASS getReader() should return a reader that acts errored 
+PASS read() twice should give the error each time 
+PASS locked should be false 
+PASS Running templatedRSErroredReader with ReadableStream (errored via returning a rejected promise in start) reader 
+PASS closed should reject with the error 
+PASS releasing the lock should cause closed to reject and change identity 
+PASS read() should reject with the error 
+PASS Running templatedRSErroredReader with ReadableStream reader (errored before getting reader) 
+PASS closed should reject with the error 
+PASS releasing the lock should cause closed to reject and change identity 
+PASS read() should reject with the error 
+PASS Running templatedRSErroredReader with ReadableStream reader (errored after getting reader) 
+PASS closed should reject with the error 
+PASS releasing the lock should cause closed to reject and change identity 
+PASS read() should reject with the error 
+PASS Running templatedRSTwoChunksOpenReader with ReadableStream (two chunks enqueued, still open) reader 
+PASS calling read() twice without waiting will eventually give both chunks (sequential) 
+PASS calling read() twice without waiting will eventually give both chunks (nested) 
+PASS read() should return distinct promises each time 
+PASS cancel() after a read() should still give that single read result 
+PASS Running templatedRSTwoChunksClosedReader with ReadableStream (two chunks enqueued, then closed) reader 
+PASS third read(), without waiting, should give { value: undefined, done: true } (sequential) 
+PASS third read(), without waiting, should give { value: undefined, done: true } (nested) 
+PASS draining the stream via read() should cause the reader closed promise to fulfill, but locked stays true 
+PASS releasing the lock after the stream is closed should cause locked to become false 
+PASS releasing the lock should cause further read() calls to reject with a TypeError 
+PASS reader's closed property always returns the same promise 
+FAIL Load templated.js with SharedWorker assert_unreached: SharedWorker is unavailable Reached unreachable code
+FAIL Untitled undefined is not an object (evaluating 'navigator.serviceWorker.getRegistration')
+PASS Running templatedRSEmpty with ReadableStream (empty) 
+FAIL instances have the correct methods and properties Can't find variable: ReadableStream
+PASS Running templatedRSEmptyReader with ReadableStream (empty) reader 
+FAIL instances have the correct methods and properties Can't find variable: ReadableStream
+FAIL locked should be true Can't find variable: ReadableStream
+FAIL read() should never settle Can't find variable: ReadableStream
+FAIL two read()s should both never settle Can't find variable: ReadableStream
+FAIL read() should return distinct promises each time Can't find variable: ReadableStream
+FAIL getReader() again on the stream should fail Can't find variable: ReadableStream
+FAIL releasing the lock with pending read requests should throw but the read requests should stay pending Can't find variable: ReadableStream
+FAIL releasing the lock should cause further read() calls to reject with a TypeError Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed calls to reject with a TypeError Can't find variable: ReadableStream
+FAIL releasing the lock should cause locked to become false Can't find variable: ReadableStream
+FAIL canceling via the reader should cause the reader to act closed Can't find variable: ReadableStream
+FAIL canceling via the stream should fail Can't find variable: ReadableStream
+PASS Running templatedRSClosed with ReadableStream (closed via call in start) 
+FAIL cancel() should return a distinct fulfilled promise each time Can't find variable: ReadableStream
+FAIL locked should be false Can't find variable: ReadableStream
+FAIL getReader() should be OK Can't find variable: ReadableStream
+FAIL should be able to acquire multiple readers if they are released in succession Can't find variable: ReadableStream
+FAIL should not be able to acquire a second reader if we don't release the first one Can't find variable: ReadableStream
+PASS Running templatedRSClosedReader with ReadableStream reader (closed before getting reader) 
+FAIL read() should fulfill with { value: undefined, done: true } Can't find variable: ReadableStream
+FAIL read() multiple times should fulfill with { value: undefined, done: true } Can't find variable: ReadableStream
+FAIL read() should work when used within another read() fulfill callback Can't find variable: ReadableStream
+FAIL closed should fulfill with undefined Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed to reject and change identity Can't find variable: ReadableStream
+FAIL cancel() should return a distinct fulfilled promise each time Can't find variable: ReadableStream
+PASS Running templatedRSClosedReader with ReadableStream reader (closed after getting reader) 
+FAIL read() should fulfill with { value: undefined, done: true } Can't find variable: ReadableStream
+FAIL read() multiple times should fulfill with { value: undefined, done: true } Can't find variable: ReadableStream
+FAIL read() should work when used within another read() fulfill callback Can't find variable: ReadableStream
+FAIL closed should fulfill with undefined Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed to reject and change identity Can't find variable: ReadableStream
+FAIL cancel() should return a distinct fulfilled promise each time Can't find variable: ReadableStream
+PASS Running templatedRSClosed with ReadableStream (closed via cancel) 
+FAIL cancel() should return a distinct fulfilled promise each time Can't find variable: ReadableStream
+FAIL locked should be false Can't find variable: ReadableStream
+FAIL getReader() should be OK Can't find variable: ReadableStream
+FAIL should be able to acquire multiple readers if they are released in succession Can't find variable: ReadableStream
+FAIL should not be able to acquire a second reader if we don't release the first one Can't find variable: ReadableStream
+PASS Running templatedRSClosedReader with ReadableStream reader (closed via cancel after getting reader) 
+FAIL read() should fulfill with { value: undefined, done: true } Can't find variable: ReadableStream
+FAIL read() multiple times should fulfill with { value: undefined, done: true } Can't find variable: ReadableStream
+FAIL read() should work when used within another read() fulfill callback Can't find variable: ReadableStream
+FAIL closed should fulfill with undefined Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed to reject and change identity Can't find variable: ReadableStream
+FAIL cancel() should return a distinct fulfilled promise each time Can't find variable: ReadableStream
+PASS Running templatedRSErrored with ReadableStream (errored via call in start) 
+FAIL getReader() should return a reader that acts errored Can't find variable: ReadableStream
+FAIL read() twice should give the error each time Can't find variable: ReadableStream
+FAIL locked should be false Can't find variable: ReadableStream
+PASS Running templatedRSErroredSyncOnly with ReadableStream (errored via call in start) 
+FAIL should be able to obtain a second reader, with the correct closed promise Can't find variable: ReadableStream
+FAIL should not be able to obtain additional readers if we don't release the first lock Can't find variable: ReadableStream
+FAIL cancel() should return a distinct rejected promise each time Can't find variable: ReadableStream
+FAIL reader cancel() should return a distinct rejected promise each time Can't find variable: ReadableStream
+PASS Running templatedRSErrored with ReadableStream (errored via returning a rejected promise in start) 
+FAIL getReader() should return a reader that acts errored Can't find variable: ReadableStream
+FAIL read() twice should give the error each time Can't find variable: ReadableStream
+FAIL locked should be false Can't find variable: ReadableStream
+PASS Running templatedRSErroredReader with ReadableStream (errored via returning a rejected promise in start) reader 
+FAIL closed should reject with the error Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed to reject and change identity Can't find variable: ReadableStream
+FAIL read() should reject with the error Can't find variable: ReadableStream
+PASS Running templatedRSErroredReader with ReadableStream reader (errored before getting reader) 
+FAIL closed should reject with the error Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed to reject and change identity Can't find variable: ReadableStream
+FAIL read() should reject with the error Can't find variable: ReadableStream
+PASS Running templatedRSErroredReader with ReadableStream reader (errored after getting reader) 
+FAIL closed should reject with the error Can't find variable: ReadableStream
+FAIL releasing the lock should cause closed to reject and change identity Can't find variable: ReadableStream
+FAIL read() should reject with the error Can't find variable: ReadableStream
+PASS Running templatedRSTwoChunksOpenReader with ReadableStream (two chunks enqueued, still open) reader 
+FAIL calling read() twice without waiting will eventually give both chunks (sequential) Can't find variable: ReadableStream
+FAIL calling read() twice without waiting will eventually give both chunks (nested) Can't find variable: ReadableStream
+FAIL read() should return distinct promises each time Can't find variable: ReadableStream
+FAIL cancel() after a read() should still give that single read result Can't find variable: ReadableStream
+PASS Running templatedRSTwoChunksClosedReader with ReadableStream (two chunks enqueued, then closed) reader 
+FAIL third read(), without waiting, should give { value: undefined, done: true } (sequential) Can't find variable: ReadableStream
+FAIL third read(), without waiting, should give { value: undefined, done: true } (nested) Can't find variable: ReadableStream
+FAIL draining the stream via read() should cause the reader closed promise to fulfill, but locked stays true Can't find variable: ReadableStream
+FAIL releasing the lock after the stream is closed should cause locked to become false Can't find variable: ReadableStream
+FAIL releasing the lock should cause further read() calls to reject with a TypeError Can't find variable: ReadableStream
+FAIL reader's closed property always returns the same promise Can't find variable: ReadableStream
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated.html b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated.html
new file mode 100644 (file)
index 0000000..95c6a6a
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-workers/resources/test-helpers.js"></script>
+<script src="../resources/test-initializer.js"></script>
+
+<script src="../resources/test-utils.js"></script>
+<script src="../resources/rs-test-templates.js"></script>
+<script src="templated.js"></script>
+<script>
+'use strict';
+worker_test('templated.js');
+</script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/readable-streams/templated.js
new file mode 100644 (file)
index 0000000..6db0429
--- /dev/null
@@ -0,0 +1,148 @@
+'use strict';
+
+if (self.importScripts) {
+  self.importScripts('/resources/testharness.js');
+  self.importScripts('../resources/test-utils.js');
+  self.importScripts('../resources/rs-test-templates.js');
+}
+
+// Run the readable stream test templates against readable streams created directly using the constructor
+
+const theError = { name: 'boo!' };
+const chunks = ['a', 'b'];
+
+templatedRSEmpty('ReadableStream (empty)', () => {
+  return new ReadableStream();
+});
+
+templatedRSEmptyReader('ReadableStream (empty) reader', () => {
+  return streamAndDefaultReader(new ReadableStream());
+});
+
+templatedRSClosed('ReadableStream (closed via call in start)', () => {
+  return new ReadableStream({
+    start(c) {
+      c.close();
+    }
+  });
+});
+
+templatedRSClosedReader('ReadableStream reader (closed before getting reader)', () => {
+  let controller;
+  const stream = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+  controller.close();
+  const result = streamAndDefaultReader(stream);
+  return result;
+});
+
+templatedRSClosedReader('ReadableStream reader (closed after getting reader)', () => {
+  let controller;
+  const stream = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+  const result = streamAndDefaultReader(stream);
+  controller.close();
+  return result;
+});
+
+templatedRSClosed('ReadableStream (closed via cancel)', () => {
+  const stream = new ReadableStream();
+  stream.cancel();
+  return stream;
+});
+
+templatedRSClosedReader('ReadableStream reader (closed via cancel after getting reader)', () => {
+  const stream = new ReadableStream();
+  const result = streamAndDefaultReader(stream);
+  result.reader.cancel();
+  return result;
+});
+
+templatedRSErrored('ReadableStream (errored via call in start)', () => {
+  return new ReadableStream({
+    start(c) {
+      c.error(theError);
+    }
+  });
+}, theError);
+
+templatedRSErroredSyncOnly('ReadableStream (errored via call in start)', () => {
+  return new ReadableStream({
+    start(c) {
+      c.error(theError);
+    }
+  });
+}, theError);
+
+templatedRSErrored('ReadableStream (errored via returning a rejected promise in start)', () => {
+  return new ReadableStream({
+    start() {
+      return Promise.reject(theError);
+    }
+  });
+}, theError);
+
+templatedRSErroredReader('ReadableStream (errored via returning a rejected promise in start) reader', () => {
+  return streamAndDefaultReader(new ReadableStream({
+    start() {
+      return Promise.reject(theError);
+    }
+  }));
+}, theError);
+
+templatedRSErroredReader('ReadableStream reader (errored before getting reader)', () => {
+  let controller;
+  const stream = new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  });
+  controller.error(theError);
+  return streamAndDefaultReader(stream);
+}, theError);
+
+templatedRSErroredReader('ReadableStream reader (errored after getting reader)', () => {
+  let controller;
+  const result = streamAndDefaultReader(new ReadableStream({
+    start(c) {
+      controller = c;
+    }
+  }));
+  controller.error(theError);
+  return result;
+}, theError);
+
+templatedRSTwoChunksOpenReader('ReadableStream (two chunks enqueued, still open) reader', () => {
+  return streamAndDefaultReader(new ReadableStream({
+    start(c) {
+      c.enqueue(chunks[0]);
+      c.enqueue(chunks[1]);
+    }
+  }));
+}, chunks);
+
+templatedRSTwoChunksClosedReader('ReadableStream (two chunks enqueued, then closed) reader', () => {
+  let doClose;
+  const stream = new ReadableStream({
+    start(c) {
+      c.enqueue(chunks[0]);
+      c.enqueue(chunks[1]);
+      doClose = c.close.bind(c);
+    }
+  });
+  const result = streamAndDefaultReader(stream);
+  doClose();
+  return result;
+}, chunks);
+
+function streamAndDefaultReader(stream) {
+  return { stream, reader: stream.getReader() };
+}
+
+done();
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/rs-test-templates.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/rs-test-templates.js
new file mode 100644 (file)
index 0000000..852b565
--- /dev/null
@@ -0,0 +1,624 @@
+'use strict';
+
+// These tests can be run against any readable stream produced by the web platform that meets the given descriptions.
+// For readable stream tests, the factory should return the stream. For reader tests, the factory should return a
+// { stream, reader } object. (You can use this to vary the time at which you acquire a reader.)
+
+self.templatedRSEmpty = (label, factory) => {
+  test(() => {}, 'Running templatedRSEmpty with ' + label);
+
+  test(() => {
+
+    const rs = factory();
+
+    assert_equals(typeof rs.locked, 'boolean', 'has a boolean locked getter');
+    assert_equals(typeof rs.cancel, 'function', 'has a cancel method');
+    assert_equals(typeof rs.getReader, 'function', 'has a getReader method');
+    assert_equals(typeof rs.pipeThrough, 'function', 'has a pipeThrough method');
+    assert_equals(typeof rs.pipeTo, 'function', 'has a pipeTo method');
+    assert_equals(typeof rs.tee, 'function', 'has a tee method');
+
+  }, 'instances have the correct methods and properties');
+};
+
+self.templatedRSClosed = (label, factory) => {
+  test(() => {}, 'Running templatedRSClosed with ' + label);
+
+  promise_test(() => {
+
+    const rs = factory();
+    const cancelPromise1 = rs.cancel();
+    const cancelPromise2 = rs.cancel();
+
+    assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
+
+    return Promise.all([
+      cancelPromise1.then(v => assert_equals(v, undefined, 'first cancel() call should fulfill with undefined')),
+      cancelPromise2.then(v => assert_equals(v, undefined, 'second cancel() call should fulfill with undefined'))
+    ]);
+
+  }, 'cancel() should return a distinct fulfilled promise each time');
+
+  test(() => {
+
+    const rs = factory();
+    assert_false(rs.locked, 'locked getter should return false');
+
+  }, 'locked should be false');
+
+  test(() => {
+
+    const rs = factory();
+    rs.getReader(); // getReader() should not throw.
+
+  }, 'getReader() should be OK');
+
+  test(() => {
+
+    const rs = factory();
+
+    const reader = rs.getReader();
+    reader.releaseLock();
+
+    const reader2 = rs.getReader(); // Getting a second reader should not throw.
+    reader2.releaseLock();
+
+    rs.getReader(); // Getting a third reader should not throw.
+
+  }, 'should be able to acquire multiple readers if they are released in succession');
+
+  test(() => {
+
+    const rs = factory();
+
+    rs.getReader();
+
+    assert_throws(new TypeError(), () => rs.getReader(), 'getting a second reader should throw');
+    assert_throws(new TypeError(), () => rs.getReader(), 'getting a third reader should throw');
+
+  }, 'should not be able to acquire a second reader if we don\'t release the first one');
+};
+
+self.templatedRSErrored = (label, factory, error) => {
+  test(() => {}, 'Running templatedRSErrored with ' + label);
+
+  promise_test(t => {
+
+    const rs = factory();
+    const reader = rs.getReader();
+
+    return Promise.all([
+      promise_rejects(t, error, reader.closed),
+      promise_rejects(t, error, reader.read())
+    ]);
+
+  }, 'getReader() should return a reader that acts errored');
+
+  promise_test(t => {
+
+    const rs = factory();
+    const reader = rs.getReader();
+
+    return Promise.all([
+      promise_rejects(t, error, reader.read()),
+      promise_rejects(t, error, reader.read()),
+      promise_rejects(t, error, reader.closed)
+    ]);
+
+  }, 'read() twice should give the error each time');
+
+  test(() => {
+    const rs = factory();
+
+    assert_false(rs.locked, 'locked getter should return false');
+  }, 'locked should be false');
+};
+
+self.templatedRSErroredSyncOnly = (label, factory, error) => {
+  test(() => {}, 'Running templatedRSErroredSyncOnly with ' + label);
+
+  promise_test(t => {
+
+    const rs = factory();
+    rs.getReader().releaseLock();
+    const reader = rs.getReader(); // Calling getReader() twice does not throw (the stream is not locked).
+
+    return promise_rejects(t, error, reader.closed);
+
+  }, 'should be able to obtain a second reader, with the correct closed promise');
+
+  test(() => {
+
+    const rs = factory();
+    rs.getReader();
+
+    assert_throws(new TypeError(), () => rs.getReader(), 'getting a second reader should throw a TypeError');
+    assert_throws(new TypeError(), () => rs.getReader(), 'getting a third reader should throw a TypeError');
+
+  }, 'should not be able to obtain additional readers if we don\'t release the first lock');
+
+  promise_test(t => {
+
+    const rs = factory();
+    const cancelPromise1 = rs.cancel();
+    const cancelPromise2 = rs.cancel();
+
+    assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
+
+    return Promise.all([
+      promise_rejects(t, error, cancelPromise1),
+      promise_rejects(t, error, cancelPromise2)
+    ]);
+
+  }, 'cancel() should return a distinct rejected promise each time');
+
+  promise_test(t => {
+
+    const rs = factory();
+    const reader = rs.getReader();
+    const cancelPromise1 = reader.cancel();
+    const cancelPromise2 = reader.cancel();
+
+    assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
+
+    return Promise.all([
+      promise_rejects(t, error, cancelPromise1),
+      promise_rejects(t, error, cancelPromise2)
+    ]);
+
+  }, 'reader cancel() should return a distinct rejected promise each time');
+};
+
+self.templatedRSEmptyReader = (label, factory) => {
+  test(() => {}, 'Running templatedRSEmptyReader with ' + label);
+
+  test(() => {
+
+    const reader = factory().reader;
+
+    assert_true('closed' in reader, 'has a closed property');
+    assert_equals(typeof reader.closed.then, 'function', 'closed property is thenable');
+
+    assert_equals(typeof reader.cancel, 'function', 'has a cancel method');
+    assert_equals(typeof reader.read, 'function', 'has a read method');
+    assert_equals(typeof reader.releaseLock, 'function', 'has a releaseLock method');
+
+  }, 'instances have the correct methods and properties');
+
+  test(() => {
+
+    const stream = factory().stream;
+
+    assert_true(stream.locked, 'locked getter should return true');
+
+  }, 'locked should be true');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+
+    reader.read().then(
+      t.unreached_func('read() should not fulfill'),
+      t.unreached_func('read() should not reject')
+    );
+
+    return delay(500);
+
+  }, 'read() should never settle');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+
+    reader.read().then(
+      t.unreached_func('read() should not fulfill'),
+      t.unreached_func('read() should not reject')
+    );
+
+    reader.read().then(
+      t.unreached_func('read() should not fulfill'),
+      t.unreached_func('read() should not reject')
+    );
+
+    return delay(500);
+
+  }, 'two read()s should both never settle');
+
+  test(() => {
+
+    const reader = factory().reader;
+    assert_not_equals(reader.read(), reader.read(), 'the promises returned should be distinct');
+
+  }, 'read() should return distinct promises each time');
+
+  test(() => {
+
+    const stream = factory().stream;
+    assert_throws(new TypeError(), () => stream.getReader(), 'stream.getReader() should throw a TypeError');
+
+  }, 'getReader() again on the stream should fail');
+
+  promise_test(t => {
+
+    const streamAndReader = factory();
+    const stream = streamAndReader.stream;
+    const reader = streamAndReader.reader;
+
+    reader.read().then(
+      t.unreached_func('first read() should not fulfill'),
+      t.unreached_func('first read() should not reject')
+    );
+
+    reader.read().then(
+      t.unreached_func('second read() should not fulfill'),
+      t.unreached_func('second read() should not reject')
+    );
+
+    reader.closed.then(
+      t.unreached_func('closed should not fulfill'),
+      t.unreached_func('closed should not reject')
+    );
+
+    assert_throws(new TypeError(), () => reader.releaseLock(), 'releaseLock should throw a TypeError');
+
+    assert_true(stream.locked, 'the stream should still be locked');
+
+    return delay(500);
+
+  }, 'releasing the lock with pending read requests should throw but the read requests should stay pending');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+    reader.releaseLock();
+
+    return Promise.all([
+      promise_rejects(t, new TypeError(), reader.read()),
+      promise_rejects(t, new TypeError(), reader.read())
+    ]);
+
+  }, 'releasing the lock should cause further read() calls to reject with a TypeError');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+
+    const closedBefore = reader.closed;
+    reader.releaseLock();
+    const closedAfter = reader.closed;
+
+    assert_equals(closedBefore, closedAfter, 'the closed promise should not change identity');
+
+    return promise_rejects(t, new TypeError(), closedBefore);
+
+  }, 'releasing the lock should cause closed calls to reject with a TypeError');
+
+  test(() => {
+
+    const streamAndReader = factory();
+    const stream = streamAndReader.stream;
+    const reader = streamAndReader.reader;
+
+    reader.releaseLock();
+    assert_false(stream.locked, 'locked getter should return false');
+
+  }, 'releasing the lock should cause locked to become false');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+    reader.cancel();
+
+    return reader.read().then(r => {
+      assert_object_equals(r, { value: undefined, done: true }, 'read()ing from the reader should give a done result');
+    });
+
+  }, 'canceling via the reader should cause the reader to act closed');
+
+  promise_test(t => {
+
+    const stream = factory().stream;
+    return promise_rejects(t, new TypeError(), stream.cancel());
+
+  }, 'canceling via the stream should fail');
+};
+
+self.templatedRSClosedReader = (label, factory) => {
+  test(() => {}, 'Running templatedRSClosedReader with ' + label);
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return reader.read().then(v => {
+      assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
+    });
+
+  }, 'read() should fulfill with { value: undefined, done: true }');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return Promise.all([
+      reader.read().then(v => {
+        assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
+      }),
+      reader.read().then(v => {
+        assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
+      })
+    ]);
+
+  }, 'read() multiple times should fulfill with { value: undefined, done: true }');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return reader.read().then(() => reader.read()).then(v => {
+      assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
+    });
+
+  }, 'read() should work when used within another read() fulfill callback');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return reader.closed.then(v => assert_equals(v, undefined, 'reader closed should fulfill with undefined'));
+
+  }, 'closed should fulfill with undefined');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+
+    const closedBefore = reader.closed;
+    reader.releaseLock();
+    const closedAfter = reader.closed;
+
+    assert_not_equals(closedBefore, closedAfter, 'the closed promise should change identity');
+
+    return Promise.all([
+      closedBefore.then(v => assert_equals(v, undefined, 'reader.closed acquired before release should fulfill')),
+      promise_rejects(t, new TypeError(), closedAfter)
+    ]);
+
+  }, 'releasing the lock should cause closed to reject and change identity');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+    const cancelPromise1 = reader.cancel();
+    const cancelPromise2 = reader.cancel();
+    const closedReaderPromise = reader.closed;
+
+    assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
+    assert_not_equals(cancelPromise1, closedReaderPromise, 'cancel() promise 1 should be distinct from reader.closed');
+    assert_not_equals(cancelPromise2, closedReaderPromise, 'cancel() promise 2 should be distinct from reader.closed');
+
+    return Promise.all([
+      cancelPromise1.then(v => assert_equals(v, undefined, 'first cancel() should fulfill with undefined')),
+      cancelPromise2.then(v => assert_equals(v, undefined, 'second cancel() should fulfill with undefined'))
+    ]);
+
+  }, 'cancel() should return a distinct fulfilled promise each time');
+};
+
+self.templatedRSErroredReader = (label, factory, error) => {
+  test(() => {}, 'Running templatedRSErroredReader with ' + label);
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+    return promise_rejects(t, error, reader.closed);
+
+  }, 'closed should reject with the error');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+    const closedBefore = reader.closed;
+
+    return promise_rejects(t, error, closedBefore).then(() => {
+      reader.releaseLock();
+
+      const closedAfter = reader.closed;
+      assert_not_equals(closedBefore, closedAfter, 'the closed promise should change identity');
+
+      return promise_rejects(t, new TypeError(), closedAfter);
+    });
+
+  }, 'releasing the lock should cause closed to reject and change identity');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+    return promise_rejects(t, error, reader.read());
+
+  }, 'read() should reject with the error');
+};
+
+self.templatedRSTwoChunksOpenReader = (label, factory, chunks) => {
+  test(() => {}, 'Running templatedRSTwoChunksOpenReader with ' + label);
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return Promise.all([
+      reader.read().then(r => {
+        assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
+      }),
+      reader.read().then(r => {
+        assert_object_equals(r, { value: chunks[1], done: false }, 'second result should be correct');
+      })
+    ]);
+
+  }, 'calling read() twice without waiting will eventually give both chunks (sequential)');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return reader.read().then(r => {
+      assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
+
+      return reader.read().then(r2 => {
+        assert_object_equals(r2, { value: chunks[1], done: false }, 'second result should be correct');
+      });
+    });
+
+  }, 'calling read() twice without waiting will eventually give both chunks (nested)');
+
+  test(() => {
+
+    const reader = factory().reader;
+    assert_not_equals(reader.read(), reader.read(), 'the promises returned should be distinct');
+
+  }, 'read() should return distinct promises each time');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    const promise1 = reader.closed.then(v => {
+      assert_equals(v, undefined, 'reader closed should fulfill with undefined');
+    });
+
+    const promise2 = reader.read().then(r => {
+      assert_object_equals(r, { value: chunks[0], done: false },
+                           'promise returned before cancellation should fulfill with a chunk');
+    });
+
+    reader.cancel();
+
+    const promise3 = reader.read().then(r => {
+      assert_object_equals(r, { value: undefined, done: true },
+                           'promise returned after cancellation should fulfill with an end-of-stream signal');
+    });
+
+    return Promise.all([promise1, promise2, promise3]);
+
+  }, 'cancel() after a read() should still give that single read result');
+};
+
+self.templatedRSTwoChunksClosedReader = function (label, factory, chunks) {
+  test(() => {}, 'Running templatedRSTwoChunksClosedReader with ' + label);
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return Promise.all([
+      reader.read().then(r => {
+        assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
+      }),
+      reader.read().then(r => {
+        assert_object_equals(r, { value: chunks[1], done: false }, 'second result should be correct');
+      }),
+      reader.read().then(r => {
+        assert_object_equals(r, { value: undefined, done: true }, 'third result should be correct');
+      })
+    ]);
+
+  }, 'third read(), without waiting, should give { value: undefined, done: true } (sequential)');
+
+  promise_test(() => {
+
+    const reader = factory().reader;
+
+    return reader.read().then(r => {
+      assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
+
+      return reader.read().then(r2 => {
+        assert_object_equals(r2, { value: chunks[1], done: false }, 'second result should be correct');
+
+        return reader.read().then(r3 => {
+          assert_object_equals(r3, { value: undefined, done: true }, 'third result should be correct');
+        });
+      });
+    });
+
+  }, 'third read(), without waiting, should give { value: undefined, done: true } (nested)');
+
+  promise_test(() => {
+
+    const streamAndReader = factory();
+    const stream = streamAndReader.stream;
+    const reader = streamAndReader.reader;
+
+    assert_true(stream.locked, 'stream should start locked');
+
+    const promise = reader.closed.then(v => {
+      assert_equals(v, undefined, 'reader closed should fulfill with undefined');
+      assert_true(stream.locked, 'stream should remain locked');
+    });
+
+    reader.read();
+    reader.read();
+
+    return promise;
+
+  }, 'draining the stream via read() should cause the reader closed promise to fulfill, but locked stays true');
+
+  promise_test(() => {
+
+    const streamAndReader = factory();
+    const stream = streamAndReader.stream;
+    const reader = streamAndReader.reader;
+
+    const promise = reader.closed.then(() => {
+      assert_true(stream.locked, 'the stream should start locked');
+      reader.releaseLock(); // Releasing the lock after reader closed should not throw.
+      assert_false(stream.locked, 'the stream should end unlocked');
+    });
+
+    reader.read();
+    reader.read();
+
+    return promise;
+
+  }, 'releasing the lock after the stream is closed should cause locked to become false');
+
+  promise_test(t => {
+
+    const reader = factory().reader;
+
+    reader.releaseLock();
+
+    return Promise.all([
+      promise_rejects(t, new TypeError(), reader.read()),
+      promise_rejects(t, new TypeError(), reader.read()),
+      promise_rejects(t, new TypeError(), reader.read())
+    ]);
+
+  }, 'releasing the lock should cause further read() calls to reject with a TypeError');
+
+  promise_test(() => {
+
+    const streamAndReader = factory();
+    const stream = streamAndReader.stream;
+    const reader = streamAndReader.reader;
+
+    const readerClosed = reader.closed;
+
+    assert_equals(reader.closed, readerClosed, 'accessing reader.closed twice in succession gives the same value');
+
+    const promise = reader.read().then(() => {
+      assert_equals(reader.closed, readerClosed, 'reader.closed is the same after read() fulfills');
+
+      reader.releaseLock();
+
+      assert_equals(reader.closed, readerClosed, 'reader.closed is the same after releasing the lock');
+
+      const newReader = stream.getReader();
+      return newReader.read();
+    });
+
+    assert_equals(reader.closed, readerClosed, 'reader.closed is the same after calling read()');
+
+    return promise;
+
+  }, 'reader\'s closed property always returns the same promise');
+};
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/rs-utils.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/rs-utils.js
new file mode 100644 (file)
index 0000000..0f3222e
--- /dev/null
@@ -0,0 +1,185 @@
+'use strict';
+(function () {
+
+  class RandomPushSource {
+    constructor(toPush) {
+      this.pushed = 0;
+      this.toPush = toPush;
+      this.started = false;
+      this.paused = false;
+      this.closed = false;
+
+      this._intervalHandle = null;
+    }
+
+    readStart() {
+      if (this.closed) {
+        return;
+      }
+
+      if (!this.started) {
+        this._intervalHandle = setInterval(writeChunk, 2);
+        this.started = true;
+      }
+
+      if (this.paused) {
+        this._intervalHandle = setInterval(writeChunk, 2);
+        this.paused = false;
+      }
+
+      const source = this;
+      function writeChunk() {
+        if (source.paused) {
+          return;
+        }
+
+        source.pushed++;
+
+        if (source.toPush > 0 && source.pushed > source.toPush) {
+          if (source._intervalHandle) {
+            clearInterval(source._intervalHandle);
+            source._intervalHandle = undefined;
+          }
+          source.closed = true;
+          source.onend();
+        } else {
+          source.ondata(randomChunk(128));
+        }
+      }
+    }
+
+    readStop() {
+      if (this.paused) {
+        return;
+      }
+
+      if (this.started) {
+        this.paused = true;
+        clearInterval(this._intervalHandle);
+        this._intervalHandle = undefined;
+      } else {
+        throw new Error('Can\'t pause reading an unstarted source.');
+      }
+    }
+  }
+
+  function randomChunk(size) {
+    let chunk = '';
+
+    for (let i = 0; i < size; ++i) {
+      // Add a random character from the basic printable ASCII set.
+      chunk += String.fromCharCode(Math.round(Math.random() * 84) + 32);
+    }
+
+    return chunk;
+  }
+
+  function readableStreamToArray(readable, reader) {
+    if (reader === undefined) {
+      reader = readable.getReader();
+    }
+
+    const chunks = [];
+
+    return pump();
+
+    function pump() {
+      return reader.read().then(result => {
+        if (result.done) {
+          return chunks;
+        }
+
+        chunks.push(result.value);
+        return pump();
+      });
+    }
+  }
+
+  class SequentialPullSource {
+    constructor(limit, options) {
+      const async = options && options.async;
+
+      this.current = 0;
+      this.limit = limit;
+      this.opened = false;
+      this.closed = false;
+
+      this._exec = f => f();
+      if (async) {
+        this._exec = f => setTimeout(f, 0);
+      }
+    }
+
+    open(cb) {
+      this._exec(() => {
+        this.opened = true;
+        cb();
+      });
+    }
+
+    read(cb) {
+      this._exec(() => {
+        if (++this.current <= this.limit) {
+          cb(null, false, this.current);
+        } else {
+          cb(null, true, null);
+        }
+      });
+    }
+
+    close(cb) {
+      this._exec(() => {
+        this.closed = true;
+        cb();
+      });
+    }
+  }
+
+  function sequentialReadableStream(limit, options) {
+    const sequentialSource = new SequentialPullSource(limit, options);
+
+    const stream = new ReadableStream({
+      start() {
+        return new Promise((resolve, reject) => {
+          sequentialSource.open(err => {
+            if (err) {
+              reject(err);
+            }
+            resolve();
+          });
+        });
+      },
+
+      pull(c) {
+        return new Promise((resolve, reject) => {
+          sequentialSource.read((err, done, chunk) => {
+            if (err) {
+              reject(err);
+            } else if (done) {
+              sequentialSource.close(err2 => {
+                if (err2) {
+                  reject(err2);
+                }
+                c.close();
+                resolve();
+              });
+            } else {
+              c.enqueue(chunk);
+              resolve();
+            }
+          });
+        });
+      }
+    });
+
+    stream.source = sequentialSource;
+
+    return stream;
+  }
+
+
+  self.RandomPushSource = RandomPushSource;
+  self.readableStreamToArray = readableStreamToArray;
+  self.sequentialReadableStream = sequentialReadableStream;
+
+}());
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/test-initializer.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/test-initializer.js
new file mode 100644 (file)
index 0000000..d6ed4a7
--- /dev/null
@@ -0,0 +1,14 @@
+'use strict';
+
+function worker_test(file) {
+  fetch_tests_from_worker(new Worker(file));
+  if (typeof SharedWorker === 'function') {
+    fetch_tests_from_worker(new SharedWorker(file));
+  } else {
+    test(() => {
+      assert_unreached('SharedWorker is unavailable');
+    }, 'Load ' + file + ' with SharedWorker');
+  }
+  service_worker_test(file);
+}
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/test-utils.js b/LayoutTests/imported/w3c/web-platform-tests/streams-api/resources/test-utils.js
new file mode 100644 (file)
index 0000000..cc47898
--- /dev/null
@@ -0,0 +1,43 @@
+'use strict';
+
+self.getterRejects = (t, obj, getterName, target) => {
+  const getter = Object.getOwnPropertyDescriptor(obj, getterName).get;
+
+  return promise_rejects(t, new TypeError(), getter.call(target));
+};
+
+self.methodRejects = (t, obj, methodName, target) => {
+  const method = obj[methodName];
+
+  return promise_rejects(t, new TypeError(), method.call(target));
+};
+
+self.getterThrows = (obj, getterName, target) => {
+  const getter = Object.getOwnPropertyDescriptor(obj, getterName).get;
+
+  assert_throws(new TypeError(), () => getter.call(target), getterName + ' should throw a TypeError');
+};
+
+self.methodThrows = (obj, methodName, target, args) => {
+  const method = obj[methodName];
+
+  assert_throws(new TypeError(), () => method.apply(target, args), methodName + ' should throw a TypeError');
+};
+
+self.garbageCollect = () => {
+  if (self.gc) {
+    // Use --expose_gc for V8 (and Node.js)
+    // Exposed in SpiderMonkey shell as well
+    self.gc();
+  } else if (self.GCController) {
+    // Present in some WebKit development environments
+    GCController.collect();
+  } else {
+    /* eslint-disable no-console */
+    console.warn('Tests are running without the ability to do manual garbage collection. They will still work, but ' +
+      'coverage will be suboptimal.');
+    /* eslint-enable no-console */
+  }
+};
+
+self.delay = ms => new Promise(resolve => step_timeout(resolve, ms));
diff --git a/LayoutTests/streams/brand-checks-expected.txt b/LayoutTests/streams/brand-checks-expected.txt
new file mode 100644 (file)
index 0000000..1487ab5
--- /dev/null
@@ -0,0 +1,6 @@
+
+PASS ReadableStream.prototype.pipeThrough works generically on its this and its arguments 
+PASS ReadableStream.prototype.pipeTo works generically on its this and its arguments 
+PASS ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments 
+PASS CountQueuingStrategy.prototype.size should work generically on its this and its arguments 
+
diff --git a/LayoutTests/streams/brand-checks.html b/LayoutTests/streams/brand-checks.html
new file mode 100644 (file)
index 0000000..3b7b25d
--- /dev/null
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<script src='../resources/testharness.js'></script>
+<script src='../resources/testharnessreport.js'></script>
+<script src='reference-implementation/resources/streams-utils.js'></script>
+<script>
+let ReadableStreamReader = (new ReadableStream()).getReader().constructor;
+
+function fakeWritableStream() {
+  return {
+    get closed() { return Promise.resolve(); },
+    get ready() { return Promise.resolve(); },
+    get state() { return 'closed' },
+    abort(reason) { return Promise.resolve(); },
+    close() { return Promise.resolve(); },
+    write(chunk) { return Promise.resolve(); }
+  };
+}
+
+function realReadableStream() {
+    return new ReadableStream();
+}
+
+function fakeReadableStream() {
+    return {
+        cancel: function(reason) { return Promise.resolve(); },
+        getReader: function() { return new ReadableStreamReader(new ReadableStream()); },
+        pipeThrough: function(obj, options) { return obj.readable; },
+        pipeTo: function() { return Promise.resolve(); },
+        tee: function() { return [realReadableStream(), realReadableStream()]; }
+    };
+}
+
+test(function() {
+    var pipeToArguments;
+    var thisValue = {
+        pipeTo: function() {
+            pipeToArguments = arguments;
+        }
+    };
+
+    var input = { readable: {}, writable: {} };
+    var options = {};
+    var result = ReadableStream.prototype.pipeThrough.call(thisValue, input, options);
+
+    assert_array_equals(pipeToArguments, [input.writable, options], 'correct arguments should be passed to thisValue.pipeTo');
+    assert_equals(result, input.readable, 'return value should be the passed readable property');
+}, 'ReadableStream.prototype.pipeThrough works generically on its this and its arguments');
+
+test(function() {
+    ReadableStream.prototype.pipeTo.call(fakeReadableStream(), fakeWritableStream()); // Check it does not throw.
+}, 'ReadableStream.prototype.pipeTo works generically on its this and its arguments');
+
+test(function() {
+    var thisValue = null;
+    var returnValue = { 'returned from': 'byteLength getter' };
+    var chunk = {
+        get byteLength() {
+            return returnValue;
+        }
+    };
+
+    assert_equals(ByteLengthQueuingStrategy.prototype.size.call(thisValue, chunk), returnValue);
+}, 'ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments');
+
+test(function() {
+    var thisValue = null;
+    var chunk = {
+        get byteLength() {
+            throw new TypeError('shouldn\'t be called');
+        }
+    };
+
+    assert_equals(CountQueuingStrategy.prototype.size.call(thisValue, chunk), 1);
+}, 'CountQueuingStrategy.prototype.size should work generically on its this and its arguments');
+</script>
index aae57be..219f383 100644 (file)
@@ -1,9 +1,4 @@
 
-PASS Readable stream: throwing strategy.size getter 
-PASS Readable stream: throwing strategy.size method 
-PASS Readable stream: throwing strategy.highWaterMark getter 
-PASS Readable stream: invalid strategy.highWaterMark 
-PASS Readable stream: invalid strategy.size return value 
 PASS Writable stream: throwing strategy.size getter 
 PASS Writable stream: throwing strategy.size method 
 PASS Writable stream: invalid strategy.size return value 
index 6635472..1f55626 100644 (file)
@@ -8,116 +8,6 @@ test(function() {
     var theError = new Error('a unique string');
 
     assert_throws(theError, function() {
-        new ReadableStream({}, {
-            get size() {
-                throw theError;
-            },
-            highWaterMark: 5
-        });
-    }, 'construction should re-throw the error');
-}, 'Readable stream: throwing strategy.size getter');
-
-var test1 = async_test('Readable stream: throwing strategy.size method');
-test1.step(function() {
-    var theError = new Error('a unique string');
-    var rs = new ReadableStream(
-        {
-            start: function(c) {
-                assert_throws(theError, function() { c.enqueue('a'); }, 'enqueue should throw the error');
-            }
-        },
-        {
-            size: function() {
-                throw theError;
-            },
-            highWaterMark: 5
-        }
-    );
-
-    rs.getReader().closed.catch(test1.step_func(function(e) {
-        assert_equals(e, theError, 'closed should reject with the error');
-        test1.done();
-    }))
-});
-
-test(function() {
-    var theError = new Error('a unique string');
-
-    assert_throws(theError, function() {
-        new ReadableStream({}, {
-            size: function() {
-                return 1;
-            },
-            get highWaterMark() {
-                throw theError;
-            }
-        });
-    }, 'construction should re-throw the error');
-}, 'Readable stream: throwing strategy.highWaterMark getter');
-
-test(function() {
-    for (var highWaterMark of [-1, -Infinity]) {
-        assert_throws(new RangeError(), function() {
-            new ReadableStream({}, {
-                size: function() {
-                    return 1;
-                },
-                highWaterMark
-            });
-        }, 'construction should throw a RangeError for ' + highWaterMark);
-    }
-
-    for (var highWaterMark of [NaN, 'foo', {}]) {
-        assert_throws(new TypeError(), function() {
-            new ReadableStream({}, {
-                size: function() {
-                    return 1;
-                },
-                highWaterMark
-            });
-        }, 'construction should throw a TypeError for ' + highWaterMark);
-    }
-}, 'Readable stream: invalid strategy.highWaterMark');
-
-var test2 = async_test('Readable stream: invalid strategy.size return value');
-test2.step(function() {
-    var numberOfCalls = 0;
-    var elements = [NaN, -Infinity, +Infinity, -1];
-    var theError = [];
-    for (var i = 0; i < elements.length; i++) {
-        var rs = new ReadableStream({
-            start: function(c) {
-                try {
-                    c.enqueue('hi');
-                    assert_unreached('enqueue didn\'t throw');
-                } catch (error) {
-                    assert_throws(new RangeError(), function() { throw error; }, 'enqueue should throw a RangeError for ' + elements[i]);
-                    theError[i] = error;
-                }
-            }
-        },
-        {
-            size: function() {
-                return elements[i];
-            },
-            highWaterMark: 5
-        });
-
-        var catchFunction = function(i, e) {
-            assert_equals(e, theError[i], 'closed should reject with the error for ' + elements[i]);
-            if (++numberOfCalls, elements.length) {
-                test2.done();
-            }
-        };
-
-        rs.getReader().closed.catch(test2.step_func(catchFunction.bind(this, i)));
-    }
-});
-
-test(function() {
-    var theError = new Error('a unique string');
-
-    assert_throws(theError, function() {
         new WritableStream({}, {
             get size() {
                 throw theError;
diff --git a/LayoutTests/streams/reference-implementation/bad-underlying-sources.html b/LayoutTests/streams/reference-implementation/bad-underlying-sources.html
deleted file mode 100644 (file)
index b2fe0b1..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-<!DOCTYPE html>
-<script src='../../resources/testharness.js'></script>
-<script src='../../resources/testharnessreport.js'></script>
-<script src='resources/streams-utils.js'></script>
-<script>
-// This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
-
-test(function() {
-    var theError = new Error('a unique string');
-
-    assert_throws(theError, function() {
-        new ReadableStream({
-            get start() {
-                throw theError;
-            }
-        });
-    }, 'constructing the stream should re-throw the error');
-}, 'Underlying source start: throwing getter');
-
-test(function() {
-    var theError = new Error('a unique string');
-
-    assert_throws(theError, function() {
-        new ReadableStream({
-            start: function() {
-                throw theError;
-            }
-        });
-    }, 'constructing the stream should re-throw the error');
-}, 'Underlying source start: throwing method');
-
-var test1 = async_test('Underlying source: throwing pull getter (initial pull)');
-test1.step(function() {
-    var theError = new Error('a unique string');
-    var rs = new ReadableStream({
-        get pull() {
-            throw theError;
-        }
-    });
-
-    rs.getReader().closed.then(
-        test1.step_func(function() { assert_unreached('closed should not fulfill'); }),
-        test1.step_func(function(r) {
-            assert_equals(r, theError, 'closed should reject with the thrown error');
-            test1.done();
-        }));
-});
-
-var test2 = async_test('Underlying source: throwing pull method (initial pull)');
-test2.step(function() {
-    var theError = new Error('a unique string');
-    var rs = new ReadableStream({
-        pull: function() {
-            throw theError;
-        }
-    });
-
-    rs.getReader().closed.then(
-        test2.step_func(function() { assert_unreached('closed should not fulfill'); }),
-        test2.step_func(function(r) {
-            assert_equals(r, theError, 'closed should reject with the thrown error');
-            test2.done();
-        }));
-});
-
-var test3 = async_test('Underlying source: throwing pull getter (second pull)');
-test3.step(function() {
-    var theError = new Error('a unique string');
-    var counter = 0;
-    var rs = new ReadableStream({
-        get pull() {
-            ++counter;
-            if (counter === 1) {
-                return test3.step_func(function(c) { c.enqueue('a'); })
-            }
-
-            throw theError;
-        }
-    });
-    var reader = rs.getReader();
-
-    reader.read().then(test3.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'the chunk read should be correct');
-    }));
-
-    reader.closed.then(
-        test3.step_func(function() { assert_unreached('closed should not fulfill'); }),
-        test3.step_func(function(r) {
-            assert_equals(r, theError, 'closed should reject with the thrown error');
-            test3.done();
-        }));
-});
-
-var test4 = async_test('Underlying source: throwing pull method (second pull)');
-test4.step(function() {
-    var theError = new Error('a unique string');
-    var counter = 0;
-    var rs = new ReadableStream({
-        pull: function(c) {
-            ++counter;
-            if (counter === 1) {
-                c.enqueue('a');
-            } else {
-                throw theError;
-            }
-        }
-    });
-    var reader = rs.getReader();
-
-    reader.read().then(test4.step_func(function(r) { assert_object_equals(r, { value: 'a', done: false }, 'the chunk read should be correct'); }));
-
-    reader.closed.then(
-        test4.step_func(function() { assert_unreached('closed should not fulfill'); }),
-        test4.step_func(function(r) {
-            assert_equals(r, theError, 'closed should reject with the thrown error');
-            test4.done();
-        }));
-});
-
-var test5 = async_test('Underlying source: throwing cancel getter');
-test5.step(function() {
-    var theError = new Error('a unique string');
-    var rs = new ReadableStream({
-        get cancel() {
-            throw theError;
-        }
-    });
-
-    rs.cancel().then(
-        test5.step_func(function() { assert_unreached('cancel should not fulfill'); }),
-        test5.step_func(function(r) {
-            assert_equals(r, theError, 'cancel should reject with the thrown error');
-            test5.done();
-        }));
-});
-
-var test6 = async_test('Underlying source: throwing cancel method');
-test6.step(function() {
-    var theError = new Error('a unique string');
-    var rs = new ReadableStream({
-        cancel: function() {
-            throw theError;
-        }
-    });
-
-    rs.cancel().then(
-        test6.step_func(function() { assert_unreached('cancel should not fulfill'); }),
-        test6.step_func(function(r) {
-            assert_equals(r, theError, 'cancel should reject with the thrown error');
-            test6.done();
-        }));
-});
-
-var test7 = async_test('Underlying source: calling enqueue on an empty canceled stream should not throw');
-test7.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-
-    rs.cancel();
-    controller.enqueue('a') // Calling enqueue after canceling should not throw anything.
-
-    rs.getReader().closed.then(test7.step_func(function() {
-        test7.done('closed should fulfill');
-    }));
-});
-
-var test8 = async_test('Underlying source: calling enqueue on a non-empty canceled stream should not throw');
-test8.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.enqueue('b');
-            controller = c;
-        }
-    });
-
-    rs.cancel();
-    controller.enqueue('c') // Calling enqueue after canceling should not throw anything.
-
-    rs.getReader().closed.then(test8.step_func(function() {
-        test8.done('closed should fulfill');
-    }));
-});
-
-var test9 = async_test('Underlying source: calling enqueue on a closed stream should throw');
-test9.step(function() {
-    new ReadableStream({
-        start: function(c) {
-            c.close();
-            assert_throws(new TypeError(), function() { c.enqueue('a') }, 'call to enqueue should throw a TypeError');
-        }
-    }).getReader().closed.then(test9.step_func(function() {
-        test9.done('closed should fulfill');
-    }));
-});
-
-var test10 = async_test('Underlying source: calling enqueue on an errored stream should throw');
-test10.step(function() {
-    var theError = new Error('boo');
-    new ReadableStream({
-        start: function(c) {
-            c.error(theError);
-            assert_throws(theError, function() { c.enqueue('a') }, 'call to enqueue should throw the error');
-        }
-    }).getReader().closed.catch(test10.step_func(function(e) {
-        assert_equals(e, theError, 'closed should reject with the error');
-        test10.done();
-    }));
-});
-
-var test11 = async_test('Underlying source: calling close twice on an empty stream should throw the second time');
-test11.step(function() {
-    new ReadableStream({
-        start: function(c) {
-            c.close();
-            assert_throws(new TypeError(), c.close, 'second call to close should throw a TypeError');
-        }
-    }).getReader().closed.then(test11.step_func(function() { test11.done('closed should fulfill'); }));
-});
-
-var test12 = async_test('Underlying source: calling close twice on a non-empty stream should throw the second time');
-test12.step(function() {
-    var startCalled = false;
-    var readCalled = false;
-    var reader = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.close();
-            assert_throws(new TypeError(), c.close, 'second call to close should throw a TypeError');
-            startCalled = true;
-        }
-    }).getReader();
-
-    reader.read().then(test12.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'read() should read the enqueued chunk');
-        readCalled = true;
-    }));
-    reader.closed.then(test12.step_func(function() {
-        assert_true(startCalled);
-        assert_true(readCalled);
-        test12.done('closed should fulfill');
-    }));
-});
-
-var test13 = async_test('Underlying source: calling close on an empty canceled stream should not throw');
-test13.step(function() {
-    var controller;
-    var startCalled = false;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-            startCalled = true;
-        }
-    });
-
-    rs.cancel();
-    controller.close(); // Calling close after canceling should not throw anything.
-
-    rs.getReader().closed.then(test13.step_func(function() {
-        assert_true(startCalled);
-        test13.done('closed should fulfill');
-    }));
-});
-
-var test14 = async_test('Underlying source: calling close on a non-empty canceled stream should not throw');
-test14.step(function() {
-    var controller;
-    var startCalled = false;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-            c.enqueue('a');
-            startCalled = true;
-        }
-    });
-
-    rs.cancel();
-    controller.close(); // Calling close after canceling should not throw anything.
-
-    rs.getReader().closed.then(test14.step_func(function() {
-        assert_true(startCalled);
-        test14.done('closed should fulfill');
-    }));
-});
-
-var test15 = async_test('Underlying source: calling close after error should throw');
-test15.step(function() {
-    var theError = new Error('boo');
-    var startCalled = false;
-    new ReadableStream({
-        start: function(c) {
-            c.error(theError);
-            assert_throws(new TypeError(), c.close, 'call to close should throw a TypeError');
-            startCalled = true;
-        }
-    }).getReader().closed.catch(test15.step_func(function(e) {
-        assert_true(startCalled);
-        assert_equals(e, theError, 'closed should reject with the error')
-        test15.done();
-    }));
-});
-
-var test16 = async_test('Underlying source: calling error twice should throw the second time');
-test16.step(function() {
-    var theError = new Error('boo');
-    var startCalled = false;
-    new ReadableStream({
-        start: function(c) {
-            c.error(theError);
-            assert_throws(new TypeError(), c.error, 'second call to error should throw a TypeError');
-            startCalled = true;
-        }
-    }).getReader().closed.catch(test16.step_func(function(e) {
-        assert_true(startCalled);
-        assert_equals(e, theError, 'closed should reject with the error');
-        test16.done();
-    }));
-});
-
-var test17 = async_test('Underlying source: calling error after close should throw');
-test17.step(function() {
-    var startCalled = false;
-    new ReadableStream({
-        start: function(c) {
-            c.close();
-            assert_throws(new TypeError(), c.error, 'call to error should throw a TypeError');
-            startCalled = true;
-        }
-    }).getReader().closed.then(test17.step_func(function() {
-        assert_true(startCalled);
-        test17.done('closed should fulfill');
-    }));
-});
-
-var test18 = async_test('Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error');
-test18.step(function() {
-    var startCalled = false;
-    var firstError = new Error('1');
-    var secondError = new Error('2');
-    new ReadableStream({
-        start: function(c) {
-            c.error(firstError);
-
-            startCalled = true;
-
-            return Promise.reject(secondError);
-        }
-    }).getReader().closed.catch(test18.step_func(function(e) {
-        assert_true(startCalled);
-        assert_equals(e, firstError, 'stream should error with the first error');
-        test18.done();
-    }));
-});
-
-var test19 = async_test('Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error');
-test19.step(function() {
-    var startCalled = false;
-    var firstError = new Error('1');
-    var secondError = new Error('2');
-    new ReadableStream({
-        pull: function(c) {
-            c.error(firstError);
-
-            startCalled = true;
-
-            return Promise.reject(secondError);
-        }
-    }).getReader().closed.catch(test19.step_func(function(e) {
-        assert_true(startCalled);
-        assert_equals(e, firstError, 'stream should error with the first error');
-        test19.done();
-    }));
-});
-</script>
index 1166986..612622f 100644 (file)
@@ -1,28 +1,8 @@
 
-PASS Can get the ReadableStreamReader constructor indirectly 
-PASS Can get the ReadableStreamController constructor indirectly 
-PASS ReadableStream.prototype.cancel enforces a brand check 
-PASS ReadableStream.prototype.getReader enforces a brand check 
-PASS ReadableStream.prototype.pipeThrough works generically on its this and its arguments 
-PASS ReadableStream.prototype.pipeTo works generically on its this and its arguments 
-PASS ReadableStream.prototype.tee enforces a brand check 
-PASS ReadableStreamReader enforces a brand check on its argument 
-PASS ReadableStreamReader.prototype.closed enforces a brand check 
-PASS ReadableStreamReader.prototype.cancel enforces a brand check 
-PASS ReadableStreamReader.prototype.read enforces a brand check 
-PASS ReadableStreamReader.prototype.read enforces a brand check 
-PASS ReadableStreamReader.prototype.releaseLock enforces a brand check 
-PASS ReadableStreamController enforces a brand check on its argument 
-PASS ReadableStreamController can't be given a fully-constructed ReadableStream 
-PASS ReadableStreamController.prototype.close enforces a brand check 
-PASS ReadableStreamController.prototype.enqueue enforces a brand check 
-PASS ReadableStreamController.prototype.error enforces a brand check 
 PASS WritableStream.prototype.closed enforces a brand check 
 PASS WritableStream.prototype.ready enforces a brand check 
 PASS WritableStream.prototype.state enforces a brand check 
 PASS WritableStream.prototype.abort enforces a brand check 
 PASS WritableStream.prototype.write enforces a brand check 
 PASS WritableStream.prototype.close enforces a brand check 
-PASS ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments 
-PASS CountQueuingStrategy.prototype.size should work generically on its this and its arguments 
 
index ef41fe6..e50889d 100644 (file)
@@ -5,37 +5,6 @@
 <script>
 // This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
 
-var ReadableStreamReader;
-var ReadableStreamController;
-
-test(function() {
-    // It's not exposed globally, but we test a few of its properties here.
-    ReadableStreamReader = (new ReadableStream()).getReader().constructor;
-}, 'Can get the ReadableStreamReader constructor indirectly');
-
-test(function() {
-    // It's not exposed globally, but we test a few of its properties here.
-    new ReadableStream({
-        start: function(c) {
-            ReadableStreamController = c.constructor;
-        }
-    });
-}, 'Can get the ReadableStreamController constructor indirectly');
-
-function fakeReadableStream() {
-    return {
-        cancel: function(reason) { return Promise.resolve(); },
-        getReader: function() { return new ReadableStreamReader(new ReadableStream()); },
-        pipeThrough: function(obj, options) { return obj.readable; },
-        pipeTo: function() { return Promise.resolve(); },
-        tee: function() { return [realReadableStream(), realReadableStream()]; }
-    };
-}
-
-function realReadableStream() {
-    return new ReadableStream();
-}
-
 function fakeWritableStream() {
   return {
     get closed() { return Promise.resolve(); },
@@ -47,51 +16,8 @@ function fakeWritableStream() {
   };
 }
 
-function realWritableStream() {
-  return new WritableStream();
-}
-
-function fakeReadableStreamReader() {
-    return {
-        get closed() { return Promise.resolve(); },
-        cancel: function(reason) { return Promise.resolve(); },
-        read: function() { return Promise.resolve({ value: undefined, done: true }); },
-        releaseLock: function() { return; }
-    };
-}
-
-function fakeReadableStreamController() {
-    return {
-        close: function() { },
-        enqueue: function(chunk) { },
-        error: function(e) { }
-    };
-}
-
-function fakeByteLengthQueuingStrategy() {
-    return {
-        highWaterMark: 0,
-        size: function(chunk) {
-            return chunk.byteLength;
-        }
-    };
-}
-
-function realByteLengthQueuingStrategy() {
-    return new ByteLengthQueuingStrategy({ highWaterMark: 1 });
-}
-
-function fakeCountQueuingStrategy() {
-    return {
-        highWaterMark: 0,
-        size: function(chunk) {
-            return 1;
-        }
-    }
-}
-
-function realCountQueuingStrategy() {
-    return new CountQueuingStrategy({ highWaterMark: 1 });
+function realReadableStream() {
+    return new ReadableStream();
 }
 
 function getterRejects(test, obj, getterName, target, endTest) {
@@ -126,101 +52,6 @@ function getterThrows(obj, getterName, target) {
     assert_throws(new TypeError(), function() { getter.call(target); }, getterName + ' should throw a TypeError');
 }
 
-function methodThrows(obj, methodName, target) {
-    var method = obj[methodName];
-
-    assert_throws(new TypeError(), function() { method.call(target); }, methodName + ' should throw a TypeError');
-}
-
-var test1 = async_test('ReadableStream.prototype.cancel enforces a brand check');
-test1.step(function() {
-    methodRejects(test1, ReadableStream.prototype, 'cancel', fakeReadableStream());
-    methodRejects(test1, ReadableStream.prototype, 'cancel', realWritableStream(), true);
-});
-
-test(function() {
-    methodThrows(ReadableStream.prototype, 'getReader', fakeReadableStream());
-    methodThrows(ReadableStream.prototype, 'getReader', realWritableStream());
-}, 'ReadableStream.prototype.getReader enforces a brand check');
-
-test(function() {
-    var pipeToArguments;
-    var thisValue = {
-        pipeTo: function() {
-            pipeToArguments = arguments;
-        }
-    };
-
-    var input = { readable: {}, writable: {} };
-    var options = {};
-    var result = ReadableStream.prototype.pipeThrough.call(thisValue, input, options);
-
-    assert_array_equals(pipeToArguments, [input.writable, options], 'correct arguments should be passed to thisValue.pipeTo');
-    assert_equals(result, input.readable, 'return value should be the passed readable property');
-}, 'ReadableStream.prototype.pipeThrough works generically on its this and its arguments');
-
-test(function() {
-    ReadableStream.prototype.pipeTo.call(fakeReadableStream(), fakeWritableStream()); // Check it does not throw.
-}, 'ReadableStream.prototype.pipeTo works generically on its this and its arguments');
-
-test(function() {
-    methodThrows(ReadableStream.prototype, 'tee', fakeReadableStream());
-    methodThrows(ReadableStream.prototype, 'tee', realWritableStream());
-}, 'ReadableStream.prototype.tee enforces a brand check');
-
-test(function() {
-    assert_throws(new TypeError(), function() { new ReadableStreamReader(fakeReadableStream()); }, 'Constructing a ReadableStreamReader should throw');
-}, 'ReadableStreamReader enforces a brand check on its argument');
-
-var test2 = async_test('ReadableStreamReader.prototype.closed enforces a brand check');
-test2.step(function() {
-    getterRejects(test2, ReadableStreamReader.prototype, 'closed', fakeReadableStreamReader());
-    getterRejects(test2, ReadableStreamReader.prototype, 'closed', realReadableStream(), true);
-});
-
-var test3 = async_test('ReadableStreamReader.prototype.cancel enforces a brand check');
-test3.step(function() {
-    methodRejects(test3, ReadableStreamReader.prototype, 'cancel', fakeReadableStreamReader());
-    methodRejects(test3, ReadableStreamReader.prototype, 'cancel', realReadableStream(), true);
-});
-
-var test4 = async_test('ReadableStreamReader.prototype.read enforces a brand check');
-test4.step(function() {
-    methodRejects(test4, ReadableStreamReader.prototype, 'read', fakeReadableStreamReader());
-    methodRejects(test4, ReadableStreamReader.prototype, 'read', realReadableStream(), true);
-});
-
-var test5 = async_test('ReadableStreamReader.prototype.read enforces a brand check');
-test5.step(function() {
-    methodRejects(test5, ReadableStreamReader.prototype, 'read', fakeReadableStreamReader());
-    methodRejects(test5, ReadableStreamReader.prototype, 'read', realReadableStream(), true);
-});
-
-test(function() {
-    methodThrows(ReadableStreamReader.prototype, 'releaseLock', fakeReadableStreamReader());
-    methodThrows(ReadableStreamReader.prototype, 'releaseLock', realReadableStream());
-}, 'ReadableStreamReader.prototype.releaseLock enforces a brand check');
-
-test(function() {
-    assert_throws(new TypeError(), function() { new ReadableStreamController(fakeReadableStream()); }, 'Constructing a ReadableStreamController should throw');
-}, 'ReadableStreamController enforces a brand check on its argument');
-
-test(function() {
-    assert_throws(new TypeError(), function() { new ReadableStreamController(realReadableStream()); }, 'Constructing a ReadableStreamController should throw');
-}, 'ReadableStreamController can\'t be given a fully-constructed ReadableStream');
-
-test(function() {
-  methodThrows(ReadableStreamController.prototype, 'close', fakeReadableStreamController());
-}, 'ReadableStreamController.prototype.close enforces a brand check');
-
-test(function() {
-  methodThrows(ReadableStreamController.prototype, 'enqueue', fakeReadableStreamController());
-}, 'ReadableStreamController.prototype.enqueue enforces a brand check');
-
-test(function() {
-  methodThrows(ReadableStreamController.prototype, 'error', fakeReadableStreamController());
-}, 'ReadableStreamController.prototype.error enforces a brand check');
-
 var test6 = async_test('WritableStream.prototype.closed enforces a brand check');
 test6.step(function() {
     getterRejects(test6, WritableStream.prototype, 'closed', fakeWritableStream());
@@ -255,27 +86,4 @@ test10.step(function() {
     methodRejects(test10, WritableStream.prototype, 'close', fakeWritableStream());
     methodRejects(test10, WritableStream.prototype, 'close', realReadableStream(), true);
 });
-
-test(function() {
-    var thisValue = null;
-    var returnValue = { 'returned from': 'byteLength getter' };
-    var chunk = {
-        get byteLength() {
-            return returnValue;
-        }
-    };
-
-    assert_equals(ByteLengthQueuingStrategy.prototype.size.call(thisValue, chunk), returnValue);
-}, 'ByteLengthQueuingStrategy.prototype.size should work generically on its this and its arguments');
-
-test(function() {
-    var thisValue = null;
-    var chunk = {
-        get byteLength() {
-            throw new TypeError('shouldn\'t be called');
-        }
-    };
-
-    assert_equals(CountQueuingStrategy.prototype.size.call(thisValue, chunk), 1);
-}, 'CountQueuingStrategy.prototype.size should work generically on its this and its arguments');
 </script>
index 19127ae..5b1fc91 100644 (file)
@@ -1,8 +1,3 @@
 
-PASS Can construct a ByteLengthQueuingStrategy with a valid high water mark 
-PASS Can construct a ByteLengthQueuingStrategy with any value as its high water mark 
-PASS ByteLengthQueuingStrategy constructor behaves as expected with wrong arguments 
-PASS ByteLengthQueuingStrategy size behaves as expected with wrong arguments 
-PASS ByteLengthQueuingStrategy instances have the correct properties 
 PASS Closing a writable stream with in-flight writes below the high water mark delays the close call properly 
 
index 4fadb64..003800b 100644 (file)
@@ -5,68 +5,6 @@
 <script>
 // This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
 
-test(function() {
-    var strategy = new ByteLengthQueuingStrategy({ highWaterMark: 4 });
-}, 'Can construct a ByteLengthQueuingStrategy with a valid high water mark');
-
-test(function() {
-    for (var highWaterMark of [-Infinity, NaN, 'foo', {}, function () {}]) {
-        var strategy = new ByteLengthQueuingStrategy({ highWaterMark });
-        assert_true(Object.is(strategy.highWaterMark, highWaterMark), highWaterMark + ' gets set correctly');
-    }
-}, 'Can construct a ByteLengthQueuingStrategy with any value as its high water mark');
-
-test(function() {
-    var highWaterMark = 1;
-    var highWaterMarkObjectGetter = {
-        get highWaterMark() { return highWaterMark; },
-    };
-    var error = new Error('wow!');
-    var highWaterMarkObjectGetterThrowing = {
-        get highWaterMark() { throw error; },
-    };
-    assert_throws(new TypeError(), function() { new ByteLengthQueuingStrategy(); }, 'construction fails with undefined');
-    assert_throws(new TypeError(), function() { new ByteLengthQueuingStrategy(null); }, 'construction fails with null');
-    new ByteLengthQueuingStrategy('potato'); // Construction succeeds with a random non-object type.
-    new ByteLengthQueuingStrategy({}); // Construction succeeds with an object without a highWaterMark property.
-    new ByteLengthQueuingStrategy(highWaterMarkObjectGetter); // Construction succeeds with an object with a highWaterMark getter.
-    assert_throws(error, function() { new ByteLengthQueuingStrategy(highWaterMarkObjectGetterThrowing); },
-                  'construction fails with an object with a throwing highWaterMark getter');
-}, 'ByteLengthQueuingStrategy constructor behaves as expected with wrong arguments');
-
-test(function() {
-    var size = 1024;
-    var chunk = { byteLength: size };
-    var chunkGetter = {
-        get byteLength() { return size; },
-    }
-    var error = new Error('wow!');
-    var chunkGetterThrowing = {
-        get byteLength() { throw error; },
-    }
-    assert_throws(new TypeError(), function() { ByteLengthQueuingStrategy.prototype.size(); }, 'size fails with undefined');
-    assert_throws(new TypeError(), function() { ByteLengthQueuingStrategy.prototype.size(null); }, 'size fails with null');
-    assert_equals(ByteLengthQueuingStrategy.prototype.size('potato'), undefined,
-                  'size succeeds with undefined with a random non-object type');
-    assert_equals(ByteLengthQueuingStrategy.prototype.size({}), undefined,
-                  'size succeeds with undefined with an object without hwm property');
-    assert_equals(ByteLengthQueuingStrategy.prototype.size(chunk), size,
-                  'size succeeds with the right amount with an object with a hwm');
-    assert_equals(ByteLengthQueuingStrategy.prototype.size(chunkGetter), size,
-                  'size succeeds with the right amount with an object with a hwm getter');
-    assert_throws(error, function() { ByteLengthQueuingStrategy.prototype.size(chunkGetterThrowing); },
-                  'size fails with the error thrown by the getter');
-}, 'ByteLengthQueuingStrategy size behaves as expected with wrong arguments');
-
-test(function() {
-    var strategy = new ByteLengthQueuingStrategy({ highWaterMark: 4 });
-
-    assert_object_equals(Object.getOwnPropertyDescriptor(strategy, 'highWaterMark'),
-                         { value: 4, writable: true, enumerable: true, configurable: true },
-                         'highWaterMark property should be a data property with the value passed the connstructor');
-    assert_equals(typeof strategy.size, 'function');
-}, 'ByteLengthQueuingStrategy instances have the correct properties');
-
 var test1 = async_test('Closing a writable stream with in-flight writes below the high water mark delays the close call properly');
 test1.step(function() {
     var isDone = false;
index 131f50f..9457d6f 100644 (file)
@@ -1,13 +1,4 @@
 
-PASS Can construct a CountQueuingStrategy with a valid high water mark 
-PASS Can construct a CountQueuingStrategy with any value as its high water mark 
-PASS CountQueuingStrategy constructor behaves as expected with wrong arguments 
-PASS CountQueuingStrategy size behaves as expected with wrong arguments 
-PASS CountQueuingStrategy instances have the correct properties 
-PASS Can construct a readable stream with a valid CountQueuingStrategy 
-PASS Correctly governs the return value of a ReadableStream's enqueue function (HWM = 0) 
-PASS Correctly governs a ReadableStreamController's desiredSize property (HWM = 1) 
-PASS Correctly governs a ReadableStreamController's desiredSize property (HWM = 4) 
 PASS Can construct a writable stream with a valid CountQueuingStrategy 
 PASS Correctly governs the value of a WritableStream's state property (HWM = 0) 
 PASS Correctly governs the value of a WritableStream's state property (HWM = 4) 
index 19cf7f0..2ef7f68 100644 (file)
@@ -6,235 +6,6 @@
 // This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
 
 test(function() {
-    new CountQueuingStrategy({ highWaterMark: 4 });
-}, 'Can construct a CountQueuingStrategy with a valid high water mark');
-
-test(function() {
-    for (var highWaterMark of [-Infinity, NaN, 'foo', {}, function () {}]) {
-        var strategy = new CountQueuingStrategy({ highWaterMark });
-        assert_true(Object.is(strategy.highWaterMark, highWaterMark), highWaterMark + ' gets set correctly');
-    }
-}, 'Can construct a CountQueuingStrategy with any value as its high water mark');
-
-test(function() {
-    var highWaterMark = 1;
-    var highWaterMarkObjectGetter = {
-        get highWaterMark() { return highWaterMark; },
-    };
-    var error = new Error('wow!');
-    var highWaterMarkObjectGetterThrowing = {
-        get highWaterMark() { throw error; },
-    };
-    assert_throws(new TypeError(), function() { new CountQueuingStrategy(); }, 'construction fails with undefined');
-    assert_throws(new TypeError(), function() { new CountQueuingStrategy(null); }, 'construction fails with null');
-    new CountQueuingStrategy('potato'); // Construction succeeds with a random non-object type.
-    new CountQueuingStrategy({}); // Construction succeeds with an object without a highWaterMark property.
-    new CountQueuingStrategy(highWaterMarkObjectGetter); // Construction succeeds with an object with a highWaterMark getter.
-    assert_throws(error, function() { new CountQueuingStrategy(highWaterMarkObjectGetterThrowing); },
-                  'construction fails with an object with a throwing highWaterMark getter');
-}, 'CountQueuingStrategy constructor behaves as expected with wrong arguments');
-
-test(function() {
-    var size = 1024;
-    var chunk = { byteLength: size };
-    var chunkGetter = {
-        get byteLength() { return size; },
-    }
-    var error = new Error('wow!');
-    var chunkGetterThrowing = {
-        get byteLength() { throw error; },
-    }
-    assert_equals(CountQueuingStrategy.prototype.size(), 1, 'size returns 1 with undefined');
-    assert_equals(CountQueuingStrategy.prototype.size(null), 1, 'size returns 1 with null');
-    assert_equals(CountQueuingStrategy.prototype.size('potato'), 1, 'size returns 1 with non-object type');
-    assert_equals(CountQueuingStrategy.prototype.size({}), 1, 'size returns 1 with empty object');
-    assert_equals(CountQueuingStrategy.prototype.size(chunk), 1, 'size returns 1 with a chunk');
-    assert_equals(CountQueuingStrategy.prototype.size(chunkGetter), 1, 'size returns 1 with chunk getter');
-    assert_equals(CountQueuingStrategy.prototype.size(chunkGetterThrowing), 1, 'size returns 1 with chunk getter that throws');
-}, 'CountQueuingStrategy size behaves as expected with wrong arguments');
-
-test(function() {
-    var strategy = new CountQueuingStrategy({ highWaterMark: 4 });
-
-    assert_object_equals(Object.getOwnPropertyDescriptor(strategy, 'highWaterMark'),
-                         { value: 4, writable: true, enumerable: true, configurable: true },
-                         'highWaterMark property should be a data property with the value passed the connstructor');
-    assert_equals(typeof strategy.size, 'function');
-}, 'CountQueuingStrategy instances have the correct properties');
-
-test(function() {
-    new ReadableStream({}, new CountQueuingStrategy({ highWaterMark: 4 }));
-}, 'Can construct a readable stream with a valid CountQueuingStrategy');
-
-var test1 = async_test('Correctly governs the return value of a ReadableStream\'s enqueue function (HWM = 0)');
-test1.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    },
-    new CountQueuingStrategy({ highWaterMark: 0 })
-    );
-    var reader = rs.getReader();
-
-    assert_equals(controller.desiredSize, 0, '0 reads, 0 enqueues: desiredSize should be 0');
-    controller.enqueue('a');
-    assert_equals(controller.desiredSize, -1, '0 reads, 1 enqueue: desiredSize should be -1');
-    controller.enqueue('b');
-    assert_equals(controller.desiredSize, -2, '0 reads, 2 enqueues: desiredSize should be -2');
-    controller.enqueue('c');
-    assert_equals(controller.desiredSize, -3, '0 reads, 3 enqueues: desiredSize should be -3');
-    controller.enqueue('d');
-    assert_equals(controller.desiredSize, -4, '0 reads, 4 enqueues: desiredSize should be -4');
-
-    reader.read().then(test1.step_func(function(result) {
-        assert_object_equals(result, { value: 'a', done: false }, '1st read gives back the 1st chunk enqueued (queue now contains 3 chunks)');
-        return reader.read();
-    })).then(test1.step_func(function(result) {
-        assert_object_equals(result, { value: 'b', done: false }, '2nd read gives back the 2nd chunk enqueued (queue now contains 2 chunks)');
-        return reader.read();
-    })).then(test1.step_func(function(result) {
-        assert_object_equals(result, { value: 'c', done: false }, '3rd read gives back the 3rd chunk enqueued (queue now contains 1 chunk)');
-
-        assert_equals(controller.desiredSize, -1, '3 reads, 4 enqueues: desiredSize should be -1');
-        controller.enqueue('e');
-        assert_equals(controller.desiredSize, -2, '3 reads, 5 enqueues: desiredSize should be -2');
-
-        return reader.read();
-    })).then(test1.step_func(function(result) {
-        assert_object_equals(result, { value: 'd', done: false }, '4th read gives back the 4th chunk enqueued (queue now contains 1 chunks)');
-        return reader.read();
-    })).then(test1.step_func(function(result) {
-        assert_object_equals(result, { value: 'e', done: false }, '5th read gives back the 5th chunk enqueued (queue now contains 0 chunks)');
-
-        assert_equals(controller.desiredSize, 0, '5 reads, 5 enqueues: desiredSize should be 0');
-        controller.enqueue('f');
-        assert_equals(controller.desiredSize, -1, '5 reads, 6 enqueues: desiredSize should be -1');
-        controller.enqueue('g');
-        assert_equals(controller.desiredSize, -2, '5 reads, 7 enqueues: desiredSize should be -2');
-
-        test1.done();
-    })).catch(test1.step_func(function(e) { assert_unreached(e); } ));
-});
-
-var test2 = async_test('Correctly governs a ReadableStreamController\'s desiredSize property (HWM = 1)');
-test2.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        },
-    },
-    new CountQueuingStrategy({ highWaterMark: 1 })
-    );
-    var reader = rs.getReader();
-
-    assert_equals(controller.desiredSize, 1, '0 reads, 0 enqueues: desiredSize should be 1');
-    controller.enqueue('a');
-    assert_equals(controller.desiredSize, 0, '0 reads, 1 enqueue: desiredSize should be 0');
-    controller.enqueue('b');
-    assert_equals(controller.desiredSize, -1, '0 reads, 2 enqueues: desiredSize should be -1');
-    controller.enqueue('c');
-    assert_equals(controller.desiredSize, -2, '0 reads, 3 enqueues: desiredSize should be -2');
-    controller.enqueue('d');
-    assert_equals(controller.desiredSize, -3, '0 reads, 4 enqueues: desiredSize should be -3');
-
-    reader.read().then(test2.step_func(function(result) {
-        assert_object_equals(result, { value: 'a', done: false }, '1st read gives back the 1st chunk enqueued (queue now contains 3 chunks)');
-        return reader.read();
-    })).then(test2.step_func(function(result) {
-        assert_object_equals(result, { value: 'b', done: false }, '2nd read gives back the 2nd chunk enqueued (queue now contains 2 chunks)');
-        return reader.read();
-    })).then(test2.step_func(function(result) {
-        assert_object_equals(result, { value: 'c', done: false }, '3rd read gives back the 3rd chunk enqueued (queue now contains 1 chunk)');
-
-        assert_equals(controller.desiredSize, 0, '3 reads, 4 enqueues: desiredSize should be 0');
-        controller.enqueue('e');
-        assert_equals(controller.desiredSize, -1, '3 reads, 5 enqueues: desiredSize should be -1');
-
-        return reader.read();
-    })).then(test2.step_func(function(result) {
-        assert_object_equals(result, { value: 'd', done: false }, '4th read gives back the 4th chunk enqueued (queue now contains 1 chunks)');
-        return reader.read();
-    })).then(test2.step_func(function(result) {
-        assert_object_equals(result, { value: 'e', done: false }, '5th read gives back the 5th chunk enqueued (queue now contains 0 chunks)');
-
-        assert_equals(controller.desiredSize, 1, '5 reads, 5 enqueues: desiredSize should be 1');
-        controller.enqueue('f');
-        assert_equals(controller.desiredSize, 0, '5 reads, 6 enqueues: desiredSize should be 0');
-        controller.enqueue('g');
-        assert_equals(controller.desiredSize, -1, '5 reads, 7 enqueues: desiredSize should be -1');
-
-        test2.done();
-    })).catch(test2.step_func(function(e) { assert_unreached(e); } ));
-});
-
-var test3 = async_test('Correctly governs a ReadableStreamController\'s desiredSize property (HWM = 4)');
-test3.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    },
-    new CountQueuingStrategy({ highWaterMark: 4 })
-    );
-    var reader = rs.getReader();
-
-    assert_equals(controller.desiredSize, 4, '0 reads, 0 enqueues: desiredSize should be 4');
-    controller.enqueue('a');
-    assert_equals(controller.desiredSize, 3, '0 reads, 1 enqueue: desiredSize should be 3');
-    controller.enqueue('b');
-    assert_equals(controller.desiredSize, 2, '0 reads, 2 enqueues: desiredSize should be 2');
-    controller.enqueue('c');
-    assert_equals(controller.desiredSize, 1, '0 reads, 3 enqueues: desiredSize should be 1');
-    controller.enqueue('d');
-    assert_equals(controller.desiredSize, 0, '0 reads, 4 enqueues: desiredSize should be 0');
-    controller.enqueue('e');
-    assert_equals(controller.desiredSize, -1, '0 reads, 5 enqueues: desiredSize should be -1');
-    controller.enqueue('f');
-    assert_equals(controller.desiredSize, -2, '0 reads, 6 enqueues: desiredSize should be -2');
-
-
-    reader.read().then(test3.step_func(function(result) {
-        assert_object_equals(result, { value: 'a', done: false }, '1st read gives back the 1st chunk enqueued (queue now contains 5 chunks)');
-        return reader.read();
-    })).then(test3.step_func(function(result) {
-        assert_object_equals(result, { value: 'b', done: false }, '2nd read gives back the 2nd chunk enqueued (queue now contains 4 chunks)');
-
-        assert_equals(controller.desiredSize, 0, '2 reads, 6 enqueues: desiredSize should be 0');
-        controller.enqueue('g');
-        assert_equals(controller.desiredSize, -1, '2 reads, 7 enqueues: desiredSize should be -1');
-
-        return reader.read();
-    })).then(test3.step_func(function(result) {
-        assert_object_equals(result, { value: 'c', done: false }, '3rd read gives back the 3rd chunk enqueued (queue now contains 4 chunks)');
-        return reader.read();
-    })).then(test3.step_func(function(result) {
-        assert_object_equals(result, { value: 'd', done: false }, '4th read gives back the 4th chunk enqueued (queue now contains 3 chunks)');
-        return reader.read();
-    })).then(test3.step_func(function(result) {
-        assert_object_equals(result, { value: 'e', done: false }, '5th read gives back the 5th chunk enqueued (queue now contains 2 chunks)');
-        return reader.read();
-    })).then(test3.step_func(function(result) {
-        assert_object_equals(result, { value: 'f', done: false }, '6th read gives back the 6th chunk enqueued (queue now contains 0 chunks)');
-
-        assert_equals(controller.desiredSize, 3, '6 reads, 7 enqueues: desiredSize should be 3');
-        controller.enqueue('h');
-        assert_equals(controller.desiredSize, 2, '6 reads, 8 enqueues: desiredSize should be 2');
-        controller.enqueue('i');
-        assert_equals(controller.desiredSize, 1, '6 reads, 9 enqueues: desiredSize should be 1');
-        controller.enqueue('j');
-        assert_equals(controller.desiredSize, 0, '6 reads, 10 enqueues: desiredSize should be 0');
-        controller.enqueue('k');
-        assert_equals(controller.desiredSize, -1, '6 reads, 11 enqueues: desiredSize should be -1');
-
-        test3.done();
-    })).catch(test3.step_func(function(e) { assert_unreached(e); } ));
-});
-
-test(function() {
     new WritableStream({}, new CountQueuingStrategy({ highWaterMark: 4 })); // Does not throw.
 }, 'Can construct a writable stream with a valid CountQueuingStrategy');
 
diff --git a/LayoutTests/streams/reference-implementation/readable-stream-cancel.html b/LayoutTests/streams/reference-implementation/readable-stream-cancel.html
deleted file mode 100644 (file)
index d69ae11..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-<!DOCTYPE html>
-<script src='../../resources/testharness.js'></script>
-<script src='../../resources/testharnessreport.js'></script>
-<script src='resources/streams-utils.js'></script>
-<script>
-// This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
-
-var test1 = async_test('ReadableStream cancellation: integration test on an infinite stream derived from a random push source');
-test1.step(function() {
-    var randomSource = new RandomPushSource();
-
-    var cancellationFinished = false;
-    var rs = new ReadableStream({
-        start: function(c) {
-            randomSource.ondata = c.enqueue.bind(c);
-            randomSource.onend = c.close.bind(c);
-            randomSource.onerror = c.error.bind(c);
-        },
-
-        pull: function() {
-            randomSource.readStart();
-        },
-
-        cancel: function() {
-            randomSource.readStop();
-            randomSource.onend();
-
-            return new Promise(test1.step_func(function(resolve) {
-                setTimeout(test1.step_func(function() {
-                    cancellationFinished = true;
-                    resolve();
-                }), 500);
-            }));
-        }
-    });
-    var reader = rs.getReader();
-
-    readableStreamToArray(rs, reader).then(test1.step_func(function(chunks) {
-        assert_equals(cancellationFinished, false, 'it did not wait for the cancellation process to finish before closing');
-        assert_greater_than(chunks.length, 0, 'at least one chunk should be read');
-        for (var i = 0; i < chunks.length; i++) {
-            assert_equals(chunks[i].length, 128, 'chunk ' + i + ' should have 128 bytes');
-        }
-    }), test1.step_func(function(e) { assert_unreached(e); }));
-
-    setTimeout(test1.step_func(function() {
-        reader.cancel().then(test1.step_func(function() {
-            assert_equals(cancellationFinished, true, 'it returns a promise that is fulfilled when the cancellation finishes');
-            test1.done();
-        })).catch(test1.step_func(function(e) { assert_unreached(e); }));
-    }), 1000);
-});
-
-test(function() {
-    var recordedReason;
-    var rs = new ReadableStream({
-        cancel: function(reason) {
-            recordedReason = reason;
-        }
-    });
-
-    var passedReason = new Error('Sorry, it just wasn\'t meant to be.');
-    rs.cancel(passedReason);
-
-    assert_equals(recordedReason, passedReason,
-                  'the error passed to the underlying source\'s cancel method should equal the one passed to the stream\'s cancel');
-}, 'ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source');
-
-var test2 = async_test('ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel');
-test2.step(function() {
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.close();
-        },
-        cancel: function() {
-            assert_unreached('underlying source cancel() should not have been called');
-        }
-    });
-
-    var reader = rs.getReader();
-
-    rs.cancel().catch(test2.step_func(function(e) {
-        assert_throws(new TypeError(), e, 'cancel() should be rejected with a TypeError')
-    }));
-
-    reader.read().then(test2.step_func(function(result) {
-        assert_object_equals(result, { value: 'a', done: false }, 'read() should still work after the attempted cancel');
-    }));
-
-    reader.closed.then(test2.step_func(function() {
-        test2.done('closed should fulfill without underlying source cancel ever being called');
-    }));
-});
-
-var test3 = async_test('ReadableStream cancellation: should fulfill promise when cancel callback went fine');
-test3.step(function()
-{
-    var cancelReceived = false;
-    var cancelReason = new Error('I am tired of this stream, I prefer to cancel it');
-    var rs = new ReadableStream({
-        cancel: function(reason) {
-            cancelReceived = true;
-            assert_equals(reason, cancelReason, 'cancellation reason given to the underlying source should be equal to the one passed');
-        }
-    });
-
-    rs.cancel(cancelReason).then(
-        test3.step_func(function() {
-            assert_true(cancelReceived);
-            test3.done('stream was successfully cancelled');
-        }),
-        test3.step_func(function(e) {
-            assert_unreached("received error " + e)
-        }));
-});
-
-var test4 = async_test('ReadableStream cancellation: returning a value from the underlying source\'s cancel should not affect the fulfillment value of the promise returned by the stream\'s cancel');
-test4.step(function() {
-    var rs = new ReadableStream({
-        cancel: function(reason) {
-            return 'Hello';
-        }
-    });
-
-    rs.cancel().then(test4.step_func(function(v) {
-        assert_equals(v, undefined, 'cancel() return value should be fulfilled with undefined');
-        test4.done();
-    }), test4.step_func(function() {
-        assert_unreached('cancel() return value should not be rejected');
-    }));
-});
-
-var test5 = async_test('ReadableStream cancellation: should reject promise when cancel callback raises an exception');
-test5.step(function()
-{
-    var thrownError = new Error('test');
-    var cancelCalled = false;
-
-    var rs = new ReadableStream({
-        cancel: function() {
-            cancelCalled = true;
-            throw thrownError;
-        }
-    });
-
-    rs.cancel('test').then(
-        test5.step_func(function() { assert_unreached('cancel should reject'); }),
-        test5.step_func(function(e) {
-            assert_true(cancelCalled);
-            assert_equals(e, thrownError);
-            test5.done();
-        })
-    );
-});
-
-var test6 = async_test('ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does (1)');
-test6.step(function()
-{
-    var cancelReason = new Error('test');
-
-    var rs = new ReadableStream({
-        cancel: function(error) {
-            assert_equals(error, cancelReason);
-            return new Promise(test6.step_func(function(resolve, reject) {
-                setTimeout(test6.step_func(function() {
-                    resolve();
-                }), 500);
-            }))
-        }
-    })
-
-    rs.cancel(cancelReason).then(
-        test6.step_func(function() {
-            test6.done('stream successfully cancelled');
-        }),
-        test6.step_func(function(e) {
-            assert_unreached("received error " + e)
-        }))
-});
-
-var test7 = async_test('ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does (2)');
-test7.step(function() {
-    var resolveSourceCancelPromise;
-    var sourceCancelPromiseHasFulfilled = false;
-    var rs = new ReadableStream({
-        cancel: function() {
-            var sourceCancelPromise = new Promise(test7.step_func(function(resolve, reject) {
-                resolveSourceCancelPromise = resolve;
-            }));
-
-            sourceCancelPromise.then(test7.step_func(function() {
-                sourceCancelPromiseHasFulfilled = true;
-            }));
-
-            return sourceCancelPromise;
-        }
-    });
-
-
-    rs.cancel().then(
-        test7.step_func(function(value) {
-            assert_true(sourceCancelPromiseHasFulfilled, 'cancel() return value should be fulfilled only after the promise returned by the underlying source\'s cancel');
-            assert_equals(value, undefined, 'cancel() return value should be fulfilled with undefined');
-            test7.done();
-        }),
-        test7.step_func(function() { assert_unreached('cancel() return value should not be rejected'); })
-    );
-
-    setTimeout(test7.step_func(function() {
-        resolveSourceCancelPromise('Hello');
-    }), 500);
-});
-
-var test8 = async_test('ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should reject when that one does');
-test8.step(function() {
-    var rejectSourceCancelPromise;
-    var sourceCancelPromiseHasRejected = false;
-    var rs = new ReadableStream({
-        cancel: function() {
-            var sourceCancelPromise = new Promise(test8.step_func(function(resolve, reject) {
-                rejectSourceCancelPromise = reject;
-            }));
-
-            sourceCancelPromise.catch(test8.step_func(function() {
-                sourceCancelPromiseHasRejected = true;
-            }));
-
-            return sourceCancelPromise;
-        }
-    });
-
-    var errorInCancel = new Error('Sorry, it just wasn\'t meant to be.');
-
-    rs.cancel().then(
-        test8.step_func(function() { assert_unreached('cancel() return value should not be rejected'); }),
-        test8.step_func(function(r) {
-            assert_true(sourceCancelPromiseHasRejected, 'cancel() return value should be rejected only after the promise returned by the underlying source\'s cancel');
-            assert_equals(r, errorInCancel, 'cancel() return value should be rejected with the underlying source\'s rejection reason');
-            test8.done();
-        })
-    );
-
-    setTimeout(test8.step_func(function() {
-        rejectSourceCancelPromise(errorInCancel);
-    }), 500);
-});
-
-var test9 = async_test('ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called');
-test9.step(function() {
-    var rs = new ReadableStream({
-        pull: function() {
-            assert_unreached('pull should not have been called');
-        }
-    });
-
-    Promise.all([rs.cancel(), rs.getReader().closed]).then(test9.step_func(function() {
-        test9.done('pull should never have been called');
-    })).catch(test9.step_func(function(e) { assert_reached(e); } ));
-});
-</script>
diff --git a/LayoutTests/streams/reference-implementation/readable-stream-reader.html b/LayoutTests/streams/reference-implementation/readable-stream-reader.html
deleted file mode 100644 (file)
index 602cc8d..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-<!DOCTYPE html>
-<script src='../../resources/testharness.js'></script>
-<script src='../../resources/testharnessreport.js'></script>
-<script src='resources/streams-utils.js'></script>
-<script src='../../resources/gc.js'></script>
-<script>
-// This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
-
-var ReadableStreamReader;
-
-test(function() {
-    // It's not exposed globally, but we test a few of its properties here.
-    ReadableStreamReader = (new ReadableStream()).getReader().constructor;
-}, 'Can get the ReadableStreamReader constructor indirectly');
-
-test(function() {
-    assert_throws(new TypeError(), function() {
-        new ReadableStreamReader('potato');
-    });
-    assert_throws(new TypeError(), function() {
-        new ReadableStreamReader({});
-    });
-    assert_throws(new TypeError(), function() {
-        new ReadableStreamReader();
-    });
-}, 'ReadableStreamReader constructor should get a ReadableStream object as argument');
-
-test(function() {
-    var methods = ['cancel', 'constructor', 'read', 'releaseLock'];
-    var properties = methods.concat(['closed']).sort();
-
-    var rsReader = new ReadableStreamReader(new ReadableStream());
-    var proto = Object.getPrototypeOf(rsReader);
-
-    assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties);
-
-    for (var m of methods) {
-        var propDesc = Object.getOwnPropertyDescriptor(proto, m);
-        assert_equals(propDesc.enumerable, false, 'method should be non-enumerable');
-        assert_equals(propDesc.configurable, true, 'method should be configurable');
-        assert_equals(propDesc.writable, true, 'method should be writable');
-        assert_equals(typeof rsReader[m], 'function', 'should have be a method');
-    }
-
-    var closedPropDesc = Object.getOwnPropertyDescriptor(proto, 'closed');
-    assert_equals(closedPropDesc.enumerable, false, 'closed should be non-enumerable');
-    assert_equals(closedPropDesc.configurable, true, 'closed should be configurable');
-    assert_not_equals(closedPropDesc.get, undefined, 'closed should have a getter');
-    assert_equals(closedPropDesc.set, undefined, 'closed should not have a setter');
-
-    assert_equals(rsReader.cancel.length, 1, 'cancel has 1 parameter');
-    assert_not_equals(rsReader.closed, undefined, 'has a non-undefined closed property');
-    assert_equals(typeof rsReader.closed.then, 'function', 'closed property is thenable');
-    assert_equals(typeof rsReader.constructor, 'function', 'has a constructor method');
-    assert_equals(rsReader.constructor.length, 1, 'constructor has 1 parameter');
-    assert_equals(typeof rsReader.read, 'function', 'has a getReader method');
-    assert_equals(rsReader.read.length, 0, 'read has no parameters');
-    assert_equals(typeof rsReader.releaseLock, 'function', 'has a releaseLock method');
-    assert_equals(rsReader.releaseLock.length, 0, 'releaseLock has no parameters');
-}, 'ReadableStreamReader instances should have the correct list of properties');
-
-test(function() {
-    var rsReader = new ReadableStreamReader(new ReadableStream());
-
-    assert_equals(rsReader.closed, rsReader.closed, 'closed should return the same promise');
-}, 'ReadableStreamReader closed should always return the same promise object');
-
-test(function() {
-    var rs = new ReadableStream();
-    new ReadableStreamReader(rs); // Constructing directly the first time should be fine.
-    assert_throws(new TypeError(), function() { new ReadableStreamReader(rs); }, 'constructing directly the second time should fail');
-}, 'Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)');
-
-test(function() {
-    var rs = new ReadableStream();
-    new ReadableStreamReader(rs); // Constructing directly should be fine.
-    assert_throws(new TypeError(), function() { rs.getReader(); }, 'getReader() should fail');
-}, 'Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)');
-
-test(function() {
-    var rs = new ReadableStream();
-    rs.getReader(); // getReader() should be fine.
-    assert_throws(new TypeError(), function() { new ReadableStreamReader(rs); }, 'constructing directly should fail');
-}, 'Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)');
-
-test(function() {
-    var rs = new ReadableStream();
-    rs.getReader(); // getReader() should be fine.
-    assert_throws(new TypeError(), function() { rs.getReader(); }, 'getReader() should fail');
-}, 'Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)');
-
-test(function() {
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.close();
-        }
-    });
-
-    new ReadableStreamReader(rs); // Constructing directly should not throw.
-}, 'Constructing a ReadableStreamReader directly should be OK if the stream is closed');
-
-test(function() {
-    var theError = new Error('don\'t say i didn\'t warn ya');
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.error(theError);
-        }
-    });
-
-    new ReadableStreamReader(rs); // Constructing directly should not throw.
-}, 'Constructing a ReadableStreamReader directly should be OK if the stream is errored');
-
-var test1 = async_test('Reading from a reader for an empty stream will wait until a chunk is available');
-test1.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-    var reader = rs.getReader();
-
-    reader.read().then(test1.step_func(function(result) {
-        assert_object_equals(result, { value: 'a', done: false }, 'read() should fulfill with the enqueued chunk');
-        test1.done();
-    }));
-
-    controller.enqueue('a');
-});
-
-var test2 = async_test('cancel() on a reader does not release the reader');
-test2.step(function() {
-    var cancelCalled = false;
-    var passedReason = new Error('it wasn\'t the right time, sorry');
-    var rs = new ReadableStream({
-        cancel: function(reason) {
-            assert_true(rs.locked, 'the stream should still be locked');
-            assert_throws(new TypeError(), function() { rs.getReader(); }, 'should not be able to get another reader');
-            assert_equals(reason, passedReason, 'the cancellation reason is passed through to the underlying source');
-            cancelCalled = true;
-        }
-    });
-
-    var reader = rs.getReader();
-    reader.cancel(passedReason).then(
-        test2.step_func(function() {
-            assert_true(cancelCalled);
-            test2.done('reader.cancel() should fulfill');
-        }),
-        test2.step_func(function(e) { assert_unreached('reader.cancel() should not reject'); })
-    );
-});
-
-var test3 = async_test('closed should be fulfilled after stream is closed (.closed access before acquiring)');
-test3.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-
-    var reader = rs.getReader();
-    reader.closed.then(test3.step_func(function() {
-        test3.done('reader closed should be fulfilled');
-    }));
-
-    controller.close();
-});
-
-var test4 = async_test('closed should be rejected after reader releases its lock (multiple stream locks)');
-test4.step(function() {
-    var promiseCalls = 0;
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-
-    var reader1 = rs.getReader();
-
-    reader1.releaseLock();
-
-    var reader2 = rs.getReader();
-    controller.close();
-
-    reader1.closed.catch(test4.step_func(function(e) {
-        assert_throws(new TypeError(), function() { throw e; }, 'reader1 closed should be rejected with a TypeError');
-        assert_equals(++promiseCalls, 1);
-    }));
-
-    reader2.closed.then(test4.step_func(function() {
-        assert_equals(++promiseCalls, 2);
-        test4.done('reader2 closed should be fulfilled');
-    }));
-});
-
-var test5 = async_test('Multiple readers can access the stream in sequence');
-test5.step(function() {
-    var readCount = 0;
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.enqueue('b');
-            c.close();
-        }
-    });
-
-    var reader1 = rs.getReader();
-    reader1.read().then(test5.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'reading the first chunk from reader1 works');
-        ++readCount;
-    }));
-    reader1.releaseLock();
-
-    var reader2 = rs.getReader();
-    reader2.read().then(test5.step_func(function(r) {
-        assert_object_equals(r, { value: 'b', done: false }, 'reading the second chunk from reader2 works');
-        assert_equals(++readCount, 2);
-        test5.done();
-    }));
-    reader2.releaseLock();
-});
-
-var test6 = async_test('Cannot use an already-released reader to unlock a stream again');
-test6.step(function() {
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-        }
-    });
-
-    var reader1 = rs.getReader();
-    reader1.releaseLock();
-
-    var reader2 = rs.getReader();
-
-    reader1.releaseLock();
-    reader2.read().then(test6.step_func(function(result) {
-        assert_object_equals(result, { value: 'a', done: false }, 'read() should still work on reader2 even after reader1 is released');
-        test6.done();
-    }));
-});
-
-var test7 = async_test('cancel() on a released reader is a no-op and does not pass through');
-test7.step(function() {
-    var promiseCalls = 0;
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-        },
-        cancel: function() {
-            assert_unreached('underlying source cancel should not be called');
-        }
-    });
-
-    var reader = rs.getReader();
-    reader.releaseLock();
-    reader.cancel().then(test7.step_func(function(v) {
-        assert_unreached('cancel promise should not fulfill');
-    })).catch(test7.step_func(function(e) {
-        assert_equals(++promiseCalls, 2);
-        test7.done();
-    }));
-
-    var reader2 = rs.getReader();
-    reader2.read().then(test7.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'a new reader should be able to read a chunk');
-        assert_equals(++promiseCalls, 1);
-    }));
-});
-
-var test8 = async_test('Getting a second reader after erroring the stream should succeed');
-test8.step(function() {
-    var controller;
-    var receivedErrors = 0;
-    var theError = new Error('bad');
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-
-    var reader1 = rs.getReader();
-
-    reader1.closed.catch(test8.step_func(function(e) {
-        assert_equals(e, theError, 'the first reader closed getter should be rejected with the error');
-        ++receivedErrors;
-    }));
-
-    reader1.read().catch(test8.step_func(function(e) {
-        assert_equals(e, theError, 'the first reader read() should be rejected with the error');
-        ++receivedErrors;
-    }));
-
-    assert_throws(new TypeError(), function() { rs.getReader(); }, 'trying to get another reader before erroring should throw');
-
-    controller.error(theError);
-
-    reader1.releaseLock();
-
-    var reader2 = rs.getReader();
-
-    reader2.closed.catch(test8.step_func(function(e) {
-        assert_equals(e, theError, 'the second reader closed getter should be rejected with the error');
-        ++receivedErrors;
-    }));
-
-    reader2.read().catch(test8.step_func(function(e) {
-        assert_equals(e, theError, 'the third reader read() should be rejected with the error');
-        assert_equals(++receivedErrors, 4);
-        test8.done();
-    }));
-});
-
-test(function() {
-    var rs = new ReadableStream({});
-
-    rs.getReader();
-    window.gc();
-
-    assert_throws(new TypeError(), function() { rs.getReader(); }, 'old reader should still be locking the stream even after garbage collection');
-}, 'Garbage-collecting a ReadableStreamReader should not unlock its stream');
-
-var test9 = async_test('ReadableStreamReader closed promise should be rejected with undefined if that is the error');
-test9.step(function() {
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-
-    rs.getReader().closed.then(test9.step_func(function() {
-        assert_unreached("closed promise should not be resolved when stream is errored");
-    }), test9.step_func(function(err) {
-        assert_equals(err, undefined, 'passed error should be undefined as it was');
-        test9.done();
-    }));
-
-    controller.error();
-});
-</script>
diff --git a/LayoutTests/streams/reference-implementation/readable-stream-tee.html b/LayoutTests/streams/reference-implementation/readable-stream-tee.html
deleted file mode 100644 (file)
index 920dd34..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-<!DOCTYPE html>
-<script src='../../resources/testharness.js'></script>
-<script src='../../resources/testharnessreport.js'></script>
-<script src='resources/streams-utils.js'></script>
-<script>
-// This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
-
-test(function() {
-    var rs = new ReadableStream();
-
-    var result = rs.tee();
-
-    assert_true(Array.isArray(result), 'return value should be an array');
-    assert_equals(result.length, 2, 'array should have length 2');
-    assert_equals(result[0].constructor, ReadableStream, '0th element should be a ReadableStream');
-    assert_equals(result[1].constructor, ReadableStream, '1st element should be a ReadableStream');
-}, 'ReadableStream teeing: rs.tee() returns an array of two ReadableStreams');
-
-var test1 = async_test('ReadableStream teeing: should be able to read one branch to the end without affecting the other');
-test1.step(function() {
-    var readCalls = 0;
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.enqueue('b');
-            c.close();
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    var reader1 = branch1.getReader();
-    var reader2 = branch2.getReader();
-
-    reader1.closed.then(test1.step_func(function() {
-        assert_equals(readCalls, 4);
-        test1.done();
-    })).catch(test1.step_func(function(e) { assert_unreached(e); }));
-    reader2.closed.then(test1.step_func(function() { assert_unreached('branch2 should not be closed'); }));
-
-    reader1.read().then(test1.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'first chunk from branch1 should be correct');
-        ++readCalls;
-    }));
-    reader1.read().then(test1.step_func(function(r) {
-        assert_object_equals(r, { value: 'b', done: false }, 'second chunk from branch1 should be correct');
-        ++readCalls;
-    }));
-    reader1.read().then(test1.step_func(function(r) {
-        assert_object_equals(r, { value: undefined, done: true }, 'third read() from branch1 should be done');
-        ++readCalls;
-    }));
-
-    reader2.read().then(test1.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'first chunk from branch2 should be correct');
-        ++readCalls;
-    }));
-});
-
-var test2 = async_test('ReadableStream teeing: values should be equal across each branch');
-test2.step(function() {
-    var theObject = { the: 'test object' };
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue(theObject);
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    var reader1 = branch1.getReader();
-    var reader2 = branch2.getReader();
-
-    Promise.all([reader1.read(), reader2.read()]).then(test2.step_func(function(values) {
-        assert_object_equals(values[0], values[1], 'the values should be equal');
-        test2.done();
-    }));
-});
-
-var test3 = async_test('ReadableStream teeing: errors in the source should propagate to both branches');
-test3.step(function() {
-    var closedRejects = 0;
-    var readCalls = 0;
-    var readRejects = 0;
-    var theError = new Error('boo!');
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.enqueue('b');
-        },
-        pull: function() {
-            throw theError;
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    var reader1 = branch1.getReader();
-    var reader2 = branch2.getReader();
-
-    reader1.label = 'reader1';
-    reader2.label = 'reader2';
-
-    reader1.closed.catch(test3.step_func(function(e) {
-        ++closedRejects;
-        assert_equals(e, theError, 'branch1 closed promise should reject with the error');
-    }));
-    reader2.closed.catch(test3.step_func(function(e) {
-        ++closedRejects;
-        assert_equals(e, theError, 'branch2 closed promise should reject with the error');
-    }));
-
-    reader1.read().then(test3.step_func(function(r) {
-        ++readCalls;
-        assert_object_equals(r, { value: 'a', done: false }, 'should be able to read the first chunk in branch1');
-    }));
-
-    reader1.read().then(test3.step_func(function(r) {
-        ++readCalls;
-        assert_object_equals(r, { value: 'b', done: false }, 'should be able to read the second chunk in branch1');
-
-        return reader2.read().then(
-            test3.step_func(function() { assert_unreached('once the root stream has errored, you should not be able to read from branch2'); }),
-            test3.step_func(function(e) {
-                ++readRejects;
-                assert_equals(e, theError, 'branch2 read() promise should reject with the error');
-            }));
-    })).then(test3.step_func(function() {
-        return reader1.read().then(
-            test3.step_func(function() { assert_unreached('once the root stream has errored, you should not be able to read from branch1 either'); }),
-            test3.step_func(function(e) {
-                assert_equals(closedRejects, 2);
-                assert_equals(readCalls, 2);
-                assert_equals(++readRejects, 2);
-                assert_equals(e, theError, 'branch1 read() promise should reject with the error');
-                test3.done();
-            })
-        );
-    })).catch(test3.step_func(function(e) { assert_unreached(e); }));
-});
-
-var test4 = async_test('ReadableStream teeing: canceling branch1 should not impact branch2');
-test4.step(function() {
-    var branch1Read = false;
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.enqueue('b');
-            c.close();
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    branch1.cancel();
-
-    readableStreamToArray(branch1).then(test4.step_func(function(chunks) {
-        assert_array_equals(chunks, [], 'branch1 should have no chunks');
-        branch1Read = true;
-    }));
-
-    readableStreamToArray(branch2).then(test4.step_func(function(chunks) {
-        assert_array_equals(chunks, ['a', 'b'], 'branch2 should have two chunks');
-        assert_true(branch1Read);
-        test4.done();
-    }));
-});
-
-var test5 = async_test('ReadableStream teeing: canceling branch2 should not impact branch1');
-test5.step(function() {
-    var branch2Read = false;
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            c.enqueue('b');
-            c.close();
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    branch2.cancel();
-
-    readableStreamToArray(branch1).then(test5.step_func(function(chunks) {
-        assert_array_equals(chunks, ['a', 'b'], 'branch1 should have two chunks');
-        assert_true(branch2Read);
-        test5.done();
-    }));
-    readableStreamToArray(branch2).then(test5.step_func(function(chunks) {
-        assert_array_equals(chunks, [], 'branch2 should have no chunks');
-        branch2Read = true;
-    }));
-});
-
-var test6 = async_test('ReadableStream teeing: canceling both branches should aggregate the cancel reasons into an array');
-test6.step(function() {
-    var reason1 = new Error('We\'re wanted men.');
-    var reason2 = new Error('I have the death sentence on twelve systems.');
-
-    var rs = new ReadableStream({
-        cancel: function(reason) {
-            assert_array_equals(reason, [reason1, reason2], 'the cancel reason should be an array containing those from the branches');
-            test6.done();
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    branch1.cancel(reason1);
-    branch2.cancel(reason2);
-});
-
-var test7 = async_test('ReadableStream teeing: failing to cancel the original stream should cause cancel() to reject on branches');
-test7.step(function() {
-    var cancelRejected = false;
-    var theError = new Error('I\'ll be careful.');
-    var rs = new ReadableStream({
-        cancel: function() {
-            throw theError;
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    branch1.cancel().catch(test7.step_func(function(e) {
-        assert_equals(e, theError, 'branch1.cancel() should reject with the error');
-        cancelRejected = true;
-    }));
-    branch2.cancel().catch(test7.step_func(function(e) {
-        assert_equals(e, theError, 'branch2.cancel() should reject with the error');
-        assert_true(cancelRejected);
-        test7.done();
-    }));
-});
-
-var test8 = async_test('ReadableStream teeing: closing the original should immediately close the branches');
-test8.step(function() {
-    var reader1Closed = false;
-    var controller;
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    var reader1 = branch1.getReader();
-    var reader2 = branch2.getReader();
-
-    reader1.closed.then(test8.step_func(function() {
-        reader1Closed = true; //branch1 should be closed
-    })).catch(test8.step_func(function(e) { assert_unreached(e); }));
-    reader2.closed.then(test8.step_func(function() {
-        assert_true(reader1Closed);
-        test8.done('branch2 should be closed');
-    })).catch(test8.step_func(function(e) { assert_unreached(e); }));
-
-    controller.close();
-});
-
-var test9 = async_test('ReadableStream teeing: erroring the original should immediately error the branches');
-test9.step(function() {
-    var reader1Rejected = false;
-    var controller;
-    var rs = new ReadableStream({
-        start(c) {
-            controller = c;
-        }
-    });
-
-    var branch = rs.tee();
-    var branch1 = branch[0];
-    var branch2 = branch[1];
-    var reader1 = branch1.getReader();
-    var reader2 = branch2.getReader();
-
-    var theError = new Error('boo!');
-
-    reader1.closed.then(
-        test9.step_func(function() { assert_unreached('branch1 should not be closed'); }),
-        test9.step_func(function(e) {
-            assert_equals(e, theError, 'branch1 should be errored with the error');
-            reader1Rejected = true;
-        })
-    );
-    reader2.closed.then(
-        test9.step_func(function() { assert_unreached('branch2 should not be closed'); }),
-        test9.step_func(function(e) {
-            assert_equals(e, theError, 'branch2 should be errored with the error');
-            assert_true(reader1Rejected);
-            test9.done();
-        })
-    );
-
-    controller.error(theError);
-});
-</script>
index 1f7afb2..8764da7 100644 (file)
@@ -1,92 +1,18 @@
 
-PASS Running templatedRSEmpty with ReadableStream (empty) 
-PASS instances have the correct methods and properties 
-PASS Running templatedRSEmptyReader with ReadableStream (empty) reader 
-PASS instances have the correct methods and properties 
-PASS locked should be true 
-PASS read() should never settle 
-PASS two read()s should both never settle 
-PASS read() should return distinct promises each time 
-PASS getReader() again on the stream should fail 
-PASS releasing the lock with pending read requests should throw but the read requests should stay pending 
-PASS releasing the lock should cause further read() calls to reject with a TypeError 
-PASS releasing the lock should cause closed to reject 
-PASS releasing the lock should cause locked to become false 
-PASS canceling via the reader should cause the reader to act closed 
-PASS canceling via the stream should fail 
 PASS Running templatedRSClosed with ReadableStream (closed via call in start) 
-PASS cancel() should return a distinct fulfilled promise each time 
-PASS locked should be false 
-PASS getReader() should be OK 
 PASS piping to a WritableStream in the writable state should close the writable stream 
 PASS piping to a WritableStream in the writable state with { preventClose: true } should do nothing 
-PASS should be able to acquire multiple readers if they are released in succession 
-PASS should not be able to acquire a second reader if we don't release the first one 
-PASS Running templatedRSClosedReader with ReadableStream reader (closed before getting reader) 
-PASS read() should fulfill with { value: undefined, done: true } 
-PASS read() multiple times should fulfill with { value: undefined, done: true } 
-PASS read() should work when used within another read() fulfill callback 
-PASS closed should fulfill with undefined 
-PASS releasing the lock should cause closed to reject and change identity 
-PASS cancel() should return a distinct fulfilled promise each time 
-PASS Running templatedRSClosedReader with ReadableStream reader (closed after getting reader) 
-PASS read() should fulfill with { value: undefined, done: true } 
-PASS read() multiple times should fulfill with { value: undefined, done: true } 
-PASS read() should work when used within another read() fulfill callback 
-PASS closed should fulfill with undefined 
-PASS releasing the lock should cause closed to reject and change identity 
-PASS cancel() should return a distinct fulfilled promise each time 
 PASS Running templatedRSClosed with ReadableStream (closed via cancel) 
-PASS cancel() should return a distinct fulfilled promise each time 
-PASS locked should be false 
-PASS getReader() should be OK 
 PASS piping to a WritableStream in the writable state should close the writable stream 
 PASS piping to a WritableStream in the writable state with { preventClose: true } should do nothing 
-PASS should be able to acquire multiple readers if they are released in succession 
-PASS should not be able to acquire a second reader if we don't release the first one 
-PASS Running templatedRSClosedReader with ReadableStream reader (closed via cancel after getting reader) 
-PASS read() should fulfill with { value: undefined, done: true } 
-PASS read() multiple times should fulfill with { value: undefined, done: true } 
-PASS read() should work when used within another read() fulfill callback 
-PASS closed should fulfill with undefined 
-PASS releasing the lock should cause closed to reject and change identity 
-PASS cancel() should return a distinct fulfilled promise each time 
 PASS Running templatedRSErrored with ReadableStream (errored via call in start) 
 PASS piping to a WritableStream in the writable state should abort the writable stream 
-PASS getReader() should return a reader that acts errored 
-PASS read() twice should give the error each time 
-PASS locked should be false 
-PASS Running templatedRSErroredSyncOnly with ReadableStream (errored via call in start) 
-PASS should be able to obtain a second reader, with the correct closed promise 
-PASS should not be able to obtain additional readers if we don't release the first lock 
-PASS cancel() should return a distinct rejected promise each time 
-PASS reader cancel() should return a distinct rejected promise each time 
 PASS Running templatedRSErrored with ReadableStream (errored via returning a rejected promise in start) 
 PASS piping to a WritableStream in the writable state should abort the writable stream 
-PASS getReader() should return a reader that acts errored 
-PASS read() twice should give the error each time 
-PASS locked should be false 
 PASS Running templatedRSErroredAsyncOnly with ReadableStream (errored via returning a rejected promise in start) reader 
 PASS piping with no options 
 PASS piping with { preventAbort: false } 
 PASS piping with { preventAbort: true } 
-PASS Running templatedRSErroredReader with ReadableStream (errored via returning a rejected promise in start) reader 
-PASS closed should reject with the error 
-PASS releasing the lock should cause closed to reject and change identity 
-PASS read() should reject with the error 
-PASS Running templatedRSErroredReader with ReadableStream reader (errored before getting reader) 
-PASS closed should reject with the error 
-PASS releasing the lock should cause closed to reject and change identity 
-PASS read() should reject with the error 
-PASS Running templatedRSErroredReader with ReadableStream reader (errored after getting reader) 
-PASS closed should reject with the error 
-PASS releasing the lock should cause closed to reject and change identity 
-PASS read() should reject with the error 
-PASS Running templatedRSTwoChunksOpenReader with ReadableStream (two chunks enqueued, still open) reader 
-PASS calling read() twice without waiting will eventually give both chunks 
-PASS calling read() twice with waiting will eventually give both chunks 
-PASS read() should return distinct promises each time 
-PASS cancel() after a read() should still give that single read result 
 PASS Running templatedRSTwoChunksClosed with ReadableStream (two chunks enqueued, then closed) 
 PASS piping with no options and no destination errors 
 PASS piping with { preventClose: false } and no destination errors 
@@ -108,11 +34,4 @@ PASS piping with { preventClose: true } and no destination errors
 PASS piping with { preventClose: false } and a destination with that errors synchronously 
 PASS piping with { preventClose: true } and a destination with that errors synchronously 
 PASS piping with { preventClose: true } and a destination that errors on the last chunk 
-PASS Running templatedRSTwoChunksClosedReader with ReadableStream (two chunks enqueued, then closed) reader 
-PASS third read(), without waiting, should give { value: undefined, done: true } 
-PASS third read, with waiting, should give { value: undefined, done: true } 
-PASS draining the stream via read() should cause the reader closed promise to fulfill, but locked stays true 
-PASS releasing the lock after the stream is closed should cause locked to become false 
-PASS releasing the lock should cause further read() calls to reject with a TypeError 
-PASS reader's closed property always returns the same promise 
 
index 7c20d09..b5fa59d 100644 (file)
@@ -5,61 +5,10 @@
 <script>
 // This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
 
-function templatedRSEmpty(label, factory) {
-    test(function() {
-    }, 'Running templatedRSEmpty with ' + label);
-
-    test(function() {
-        var rs = factory();
-
-        assert_equals(typeof rs.locked, 'boolean', 'has a boolean locked getter');
-        assert_equals(typeof rs.cancel, 'function', 'has a cancel method');
-        assert_equals(typeof rs.getReader, 'function', 'has a getReader method');
-        assert_equals(typeof rs.pipeThrough, 'function', 'has a pipeThrough method');
-        assert_equals(typeof rs.pipeTo, 'function', 'has a pipeTo method');
-        assert_equals(typeof rs.tee, 'function', 'has a tee method');
-    }, 'instances have the correct methods and properties');
-}
-
 function templatedRSClosed(label, factory) {
     test(function() {
     }, 'Running templatedRSClosed with ' + label);
 
-    var test1 = async_test('cancel() should return a distinct fulfilled promise each time');
-    test1.step(function() {
-        var rs = factory();
-        var promisesCount = 0;
-        var allChecked = false;
-
-        var cancelPromise1 = rs.cancel();
-        var cancelPromise2 = rs.cancel();
-
-        cancelPromise1.then(test1.step_func(function(v) {
-            assert_equals(v, undefined, 'first cancel() call should fulfill with undefined');
-            ++promisesCount;
-        }));
-        cancelPromise2.then(test1.step_func(function(v) {
-            assert_equals(v, undefined, 'second cancel() call should fulfill with undefined');
-            assert_equals(++promisesCount, 2);
-            assert_true(allChecked);
-            test1.done();
-        }));
-        assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
-        allChecked = true;
-    });
-
-    test(function() {
-        var rs = factory();
-
-        assert_false(rs.locked, 'locked getter should return false');
-    }, 'locked should be false');
-
-    test(function() {
-        var rs = factory();
-
-        rs.getReader(); // getReader() should not throw.
-    }, 'getReader() should be OK');
-
     var test2 = async_test('piping to a WritableStream in the writable state should close the writable stream');
     test2.step(function() {
         var closeCalled = false;
@@ -122,27 +71,6 @@ function templatedRSClosed(label, factory) {
             }));
         })).catch(test3.step_func(function(e) { assert_unreached(e); }));
     });
-
-    test(function() {
-        var rs = factory();
-
-        var reader = rs.getReader();
-        reader.releaseLock();
-
-        reader = rs.getReader(); // Getting a second reader should not throw.
-        reader.releaseLock();
-
-        rs.getReader(); // Getting a third reader should not throw.
-    }, 'should be able to acquire multiple readers if they are released in succession');
-
-    test(function() {
-        var rs = factory();
-
-        rs.getReader();
-
-        assert_throws(new TypeError(), function() { rs.getReader(); }, 'getting a second reader should throw');
-        assert_throws(new TypeError(), function() { rs.getReader(); }, 'getting a third reader should throw');
-    }, 'should not be able to acquire a second reader if we don\'t release the first one');
 };
 
 function templatedRSErrored(label, factory, error) {
@@ -182,53 +110,6 @@ function templatedRSErrored(label, factory, error) {
             );
         }));
     });
-
-    var test2 = async_test('getReader() should return a reader that acts errored');
-    test2.step(function() {
-        var rs = factory();
-        var promisesCount = 0;
-
-        var reader = rs.getReader();
-
-        reader.closed.catch(test2.step_func(function(e) {
-            assert_equals(e, error, 'reader.closed should reject with the error');
-            if (++promisesCount === 2)
-                test2.done();
-        }));
-        reader.read().catch(test2.step_func(function(e) {
-            assert_equals(e, error, 'reader.read() should reject with the error');
-            if (++promisesCount === 2)
-                test2.done();
-        }));
-    });
-
-    var test3 = async_test('read() twice should give the error each time');
-    test3.step(function() {
-        var rs = factory();
-        var promiseCount = 0;
-
-        var reader = rs.getReader();
-
-        reader.read().catch(test3.step_func(function(e) {
-            assert_equals(e, error, 'reader.read() should reject with the error');
-            assert_equals(++promiseCount, 1);
-        }));
-        reader.read().catch(test3.step_func(function(e) {
-            assert_equals(e, error, 'reader.read() should reject with the error');
-            assert_equals(++promiseCount, 2);
-        }));
-        reader.closed.catch(test3.step_func(function(e) {
-            assert_equals(e, error, 'reader.closed should reject with the error');
-            assert_equals(++promiseCount, 3);
-            test3.done();
-        }));
-   });
-
-    test(function() {
-        var rs = factory();
-
-        assert_false(rs.locked, 'locked getter should return false');
-    }, 'locked should be false');
 };
 
 function templatedRSErroredAsyncOnly(label, factory, error) {
@@ -306,84 +187,6 @@ function templatedRSErroredAsyncOnly(label, factory, error) {
    });
 };
 
-function templatedRSErroredSyncOnly(label, factory, error) {
-    test(function() {
-    }, 'Running templatedRSErroredSyncOnly with ' + label);
-
-    var test1 = async_test('should be able to obtain a second reader, with the correct closed promise');
-    test1.step(function() {
-        var rs = factory();
-
-        rs.getReader().releaseLock();
-
-        var reader = rs.getReader(); // Calling getReader() twice does not throw (the stream is not locked).
-
-        reader.closed.then(
-            test1.step_func(function() { assert_unreached('closed promise should not be fulfilled when stream is errored'); }),
-            test1.step_func(function(err) {
-                assert_equals(err, error);
-                test1.done();
-            })
-        );
-    });
-
-    test(function() {
-        var rs = factory();
-
-        rs.getReader();
-
-        assert_throws(new TypeError(), function() { rs.getReader(); }, 'getting a second reader should throw a TypeError');
-        assert_throws(new TypeError(), function() { rs.getReader(); }, 'getting a third reader should throw a TypeError');
-    }, 'should not be able to obtain additional readers if we don\'t release the first lock');
-
-    var test2 = async_test('cancel() should return a distinct rejected promise each time');
-    test2.step(function() {
-        var rs = factory();
-        var promisesCount = 0;
-        var allChecked = false;
-
-        var cancelPromise1 = rs.cancel();
-        var cancelPromise2 = rs.cancel();
-
-        cancelPromise1.catch(test2.step_func(function(e) {
-            assert_equals(e, error, 'first cancel() call should reject with the error');
-            ++promisesCount;
-        }));
-        cancelPromise2.catch(test2.step_func(function(e) {
-            assert_equals(e, error, 'second cancel() call should reject with the error');
-            assert_equals(++promisesCount, 2);
-            assert_true(allChecked);
-            test2.done();
-        }));
-        assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
-        allChecked = true;
-    });
-
-    var test3 = async_test('reader cancel() should return a distinct rejected promise each time');
-    test3.step(function() {
-        var rs = factory();
-        var reader = rs.getReader();
-        var promisesCount = 0;
-        var allChecked = false;
-
-        var cancelPromise1 = reader.cancel();
-        var cancelPromise2 = reader.cancel();
-
-        cancelPromise1.catch(test3.step_func(function(e) {
-            assert_equals(e, error, 'first cancel() call should reject with the error');
-            ++promisesCount;
-        }));
-        cancelPromise2.catch(test3.step_func(function(e) {
-            assert_equals(e, error, 'second cancel() call should reject with the error');
-            assert_equals(++promisesCount, 2);
-            assert_true(allChecked);
-            test3.done();
-        }));
-        assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
-        allChecked = true;
-    });
-};
-
 function templatedRSTwoChunksClosed(label, factory, error) {
     test(function() {
     }, 'Running templatedRSTwoChunksClosed with ' + label);
@@ -542,513 +345,6 @@ function templatedRSTwoChunksClosed(label, factory, error) {
     });
 };
 
-function templatedRSEmptyReader(label, factory) {
-    test(function() {
-    }, 'Running templatedRSEmptyReader with ' + label);
-
-    test(function() {
-        var { reader } = factory();
-
-        assert_true('closed' in reader, 'has a closed property');
-        assert_equals(typeof reader.closed.then, 'function', 'closed property is thenable');
-
-        assert_equals(typeof reader.cancel, 'function', 'has a cancel method');
-        assert_equals(typeof reader.read, 'function', 'has a read method');
-        assert_equals(typeof reader.releaseLock, 'function', 'has a releaseLock method');
-    }, 'instances have the correct methods and properties');
-
-    test(function() {
-        var { stream } = factory();
-
-        assert_true(stream.locked, 'locked getter should return true');
-    }, 'locked should be true');
-
-    var test1 = async_test('read() should never settle');
-    test1.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(
-            test1.step_func(function() { assert_unreached('read() should not fulfill'); }),
-            test1.step_func(function() { assert_unreached('read() should not reject'); })
-        );
-
-        setTimeout(test1.step_func(function() { test1.done(); }), 1000);
-    });
-
-    var test2 = async_test('two read()s should both never settle');
-    test2.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(
-            test2.step_func(function() { assert_unreached('first read() should not fulfill'); }),
-            test2.step_func(function() { assert_unreached('first read() should not reject'); })
-        );
-
-        reader.read().then(
-            test2.step_func(function() { assert_unreached('second read() should not fulfill'); }),
-            test2.step_func(function() { assert_unreached('second read() should not reject'); })
-        );
-
-        setTimeout(test2.step_func(function() { test2.done(); }), 1000);
-    });
-
-    test(function() {
-        var { reader } = factory();
-
-        assert_not_equals(reader.read(), reader.read(), 'the promises returned should be distinct');
-    }, 'read() should return distinct promises each time');
-
-    test(function() {
-        var { stream } = factory();
-
-        assert_throws(new TypeError(), function() { stream.getReader(); }, 'stream.getReader() should throw a TypeError');
-    }, 'getReader() again on the stream should fail');
-
-    var test3 = async_test('releasing the lock with pending read requests should throw but the read requests should stay pending');
-    test3.step(function() {
-        var { stream, reader } = factory();
-
-        reader.read().then(
-            test3.step_func(function() { assert_unreached('first read() should not fulfill'); }),
-            test3.step_func(function() { assert_unreached('first read() should not reject'); })
-        );
-
-        reader.read().then(
-            test3.step_func(function() { assert_unreached('second read() should not fulfill'); }),
-            test3.step_func(function() { assert_unreached('second read() should not reject'); })
-        );
-
-        reader.closed.then(
-            test3.step_func(function() { assert_unreached('closed should not fulfill'); }),
-            test3.step_func(function() { assert_unreached('closed should not reject'); })
-        );
-
-        assert_throws(new TypeError(), function() { reader.releaseLock(); }, 'releaseLock should throw a TypeError');
-
-        assert_true(stream.locked, 'the stream should still be locked');
-
-        setTimeout(test3.step_func(function() { test3.done(); }), 1000);
-    });
-
-    var test4 = async_test('releasing the lock should cause further read() calls to reject with a TypeError');
-    test4.step(function() {
-        var promiseCalls = 0;
-        var { reader } = factory();
-
-        reader.releaseLock();
-
-        reader.read().catch(test4.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'first read() should reject with a TypeError');
-            assert_equals(++promiseCalls, 1);
-        }));
-        reader.read().catch(test4.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'second read() should reject with a TypeError');
-            assert_equals(++promiseCalls, 2);
-            test4.done();
-        }));
-    });
-
-    var test5 = async_test('releasing the lock should cause closed to reject');
-    test5.step(function() {
-        var { reader } = factory();
-
-        var closedBefore = reader.closed;
-        reader.releaseLock();
-        var closedAfter = reader.closed;
-
-        assert_equals(closedBefore, closedAfter, 'the closed promise should not change identity')
-        closedBefore.catch(test5.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'reader.closed should reject with a TypeError');
-            test5.done();
-        }));
-    });
-
-    test(function() {
-        var { stream, reader } = factory();
-
-        reader.releaseLock();
-        assert_false(stream.locked, 'locked getter should return false');
-    }, 'releasing the lock should cause locked to become false');
-
-    var test6 = async_test('canceling via the reader should cause the reader to act closed');
-    test6.step(function() {
-        var { reader } = factory();
-
-        reader.cancel();
-        reader.read().then(test6.step_func(function(r) {
-            assert_object_equals(r, { value: undefined, done: true }, 'read()ing from the reader should give a done result');
-            test6.done();
-        }));
-    });
-
-    var test7 = async_test('canceling via the stream should fail');
-    test7.step(function() {
-        var { stream } = factory();
-
-        stream.cancel().catch(test7.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'cancel() should reject with a TypeError');
-            test7.done();
-        }));
-    });
-};
-
-function templatedRSClosedReader(label, factory) {
-    test(function() {
-    }, 'Running templatedRSClosedReader with ' + label);
-
-    var  test1 = async_test('read() should fulfill with { value: undefined, done: true }');
-    test1.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(
-            test1.step_func(function(v) {
-                assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
-                test1.done();
-            }),
-            test1.step_func(function() { assert_unreached('read() should not return a rejected promise'); })
-        );
-    });
-
-    var test2 = async_test('read() multiple times should fulfill with { value: undefined, done: true }');
-    test2.step(function() {
-        var { reader } = factory();
-        var readCount = 0;
-
-        reader.read().then(
-            test2.step_func(function(v) {
-                assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
-                ++readCount;
-            }),
-            test2.step_func(function() { assert_unreached('read() should not return a rejected promise'); })
-        );
-        reader.read().then(
-            test2.step_func(function(v) {
-                assert_object_equals(v, { value: undefined, done: true }, 'read() should fulfill correctly');
-                assert_equals(++readCount, 2);
-                test2.done();
-            }),
-            test2.step_func(function() { assert_unreached('read() should not return a rejected promise'); })
-        );
-    });
-
-    var test3 = async_test('read() should work when used within another read() fulfill callback');
-    test3.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(test3.step_func(function() { reader.read().then(test3.step_func(function() { test3.done('read() should fulfill'); })); }));
-    });
-
-    var test4 = async_test('closed should fulfill with undefined');
-    test4.step(function() {
-        var { reader } = factory();
-
-        reader.closed.then(
-            test4.step_func(function(v) {
-                assert_equals(v, undefined, 'reader closed should fulfill with undefined');
-                test4.done();
-            }),
-            test4.step_func(function() { assert_unreached('reader closed should not reject'); })
-        );
-    });
-
-    var test5 = async_test('releasing the lock should cause closed to reject and change identity');
-    test5.step(function() {
-        var promiseCalls = 0;
-        var { reader } = factory();
-
-        var closedBefore = reader.closed;
-        reader.releaseLock();
-        var closedAfter = reader.closed;
-
-        assert_not_equals(closedBefore, closedAfter, 'the closed promise should change identity')
-        closedBefore.then(test5.step_func(function(v) {
-            assert_equals(v, undefined, 'reader.closed acquired before release should fulfill');
-            assert_equals(++promiseCalls, 1);
-        }));
-        closedAfter.catch(test5.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'reader.closed acquired after release should reject with a TypeError');
-            assert_equals(++promiseCalls, 2);
-            test5.done();
-        }));
-    });
-
-    var test6 = async_test('cancel() should return a distinct fulfilled promise each time');
-    test6.step(function() {
-        var { reader } = factory();
-        var promiseCount = 0;
-        var allChecked = false;
-
-        var cancelPromise1 = reader.cancel();
-        var cancelPromise2 = reader.cancel();
-        var closedReaderPromise = reader.closed;
-
-        cancelPromise1.then(test6.step_func(function(v) {
-            assert_equals(v, undefined, 'first cancel() call should fulfill with undefined');
-            ++promiseCount;
-        }));
-        cancelPromise2.then(test6.step_func(function(v) {
-            assert_equals(v, undefined, 'second cancel() call should fulfill with undefined');
-            assert_equals(++promiseCount, 2);
-            assert_true(allChecked);
-            test6.done();
-        }));
-        assert_not_equals(cancelPromise1, cancelPromise2, 'cancel() calls should return distinct promises');
-        assert_not_equals(cancelPromise1, closedReaderPromise, 'cancel() promise 1 should be distinct from reader.closed');
-        assert_not_equals(cancelPromise2, closedReaderPromise, 'cancel() promise 2 should be distinct from reader.closed');
-        allChecked = true;
-    });
-};
-
-function templatedRSErroredReader(label, factory, error) {
-    test(function() {
-    }, 'Running templatedRSErroredReader with ' + label);
-
-    var test1 = async_test('closed should reject with the error');
-    test1.step(function() {
-        var { reader } = factory();
-
-        reader.closed.then(
-            test1.step_func(function() { assert_unreached('stream closed should not fulfill'); }),
-            test1.step_func(function(r) {
-                assert_equals(r, error, 'stream closed should reject with the error');
-                test1.done();
-            })
-        );
-    });
-
-    var test2 = async_test('releasing the lock should cause closed to reject and change identity');
-    test2.step(function() {
-        var { reader } = factory();
-
-        var closedBefore = reader.closed;
-
-        closedBefore.catch(test2.step_func(function(e) {
-            assert_equals(e, error, 'reader.closed acquired before release should reject with the error');
-
-            reader.releaseLock();
-            var closedAfter = reader.closed;
-
-            assert_not_equals(closedBefore, closedAfter, 'the closed promise should change identity');
-
-            return closedAfter.catch(test2.step_func(function(e) {
-                assert_throws(new TypeError(), function() { throw e; }, 'reader.closed acquired after release should reject with a TypeError');
-                test2.done();
-            }));
-        })).catch(test2.step_func(function(e) { assert_unreached(e); }));
-    });
-
-    var test3 = async_test('read() should reject with the error');
-    test3.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(
-            test3.step_func(function() {
-                assert_unreached('read() should not fulfill');
-            }),
-            test3.step_func(function(r) {
-                assert_equals(r, error, 'read() should reject with the error');
-                test3.done();
-            })
-        );
-    });
-};
-
-function templatedRSTwoChunksOpenReader(label, factory, chunks) {
-    test(function() {
-    }, 'Running templatedRSTwoChunksOpenReader with ' + label);
-
-    var test1 = async_test('calling read() twice without waiting will eventually give both chunks');
-    test1.step(function() {
-        var { reader } = factory();
-        var promiseCount = 0;
-
-        reader.read().then(test1.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
-            ++promiseCount;
-        }));
-        reader.read().then(test1.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[1], done: false }, 'second result should be correct');
-            assert_equals(++promiseCount, 2);
-            test1.done();
-        }));
-    });
-
-    var test2 = async_test('calling read() twice with waiting will eventually give both chunks');
-    test2.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(test2.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
-
-            return reader.read().then(test2.step_func(function(r) {
-                assert_object_equals(r, { value: chunks[1], done: false }, 'second result should be correct');
-                test2.done();
-            }));
-        })).catch(test2.step_func(function(e) { assert_unreached(e); }));
-    });
-
-    test(function() {
-        var { reader } = factory();
-
-        assert_not_equals(reader.read(), reader.read(), 'the promises returned should be distinct');
-    }, 'read() should return distinct promises each time');
-
-    var test3 = async_test('cancel() after a read() should still give that single read result');
-    test3.step(function() {
-        var { reader } = factory();
-        var promiseCount = 0;
-
-        reader.closed.then(test3.step_func(function(v) {
-            assert_equals(v, undefined, 'reader closed should fulfill with undefined');
-            ++promiseCount;
-        }));
-
-        reader.read().then(test3.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[0], done: false }, 'promise returned before cancellation should fulfill with a chunk');
-            ++promiseCount;
-        }));
-
-        reader.cancel();
-
-        reader.read().then(test3.step_func(function(r) {
-            assert_object_equals(r, { value: undefined, done: true }, 'promise returned after cancellation should fulfill with an end-of-stream signal');
-            assert_equals(++promiseCount, 3);
-            test3.done();
-        }))
-    });
-};
-
-function templatedRSTwoChunksClosedReader(label, factory, chunks) {
-    test(function() {
-    }, 'Running templatedRSTwoChunksClosedReader with ' + label);
-
-    var test1 = async_test('third read(), without waiting, should give { value: undefined, done: true }');
-    test1.step(function() {
-        var { reader } = factory();
-        var promiseCount = 0;
-
-        reader.read().then(test1.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
-            ++promiseCount;
-        }));
-        reader.read().then(test1.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[1], done: false }, 'second result should be correct');
-            ++promiseCount;
-        }));
-        reader.read().then(test1.step_func(function(r) {
-            assert_object_equals(r, { value: undefined, done: true }, 'third result should be correct');
-            assert_equals(++promiseCount, 3);
-            test1.done();
-        }))
-    });
-
-    var test2 = async_test('third read, with waiting, should give { value: undefined, done: true }');
-    test2.step(function() {
-        var { reader } = factory();
-
-        reader.read().then(test2.step_func(function(r) {
-            assert_object_equals(r, { value: chunks[0], done: false }, 'first result should be correct');
-
-            return reader.read().then(test2.step_func(function(r) {
-                assert_object_equals(r, { value: chunks[1], done: false }, 'second result should be correct');
-
-                return reader.read().then(test2.step_func(function(r) {
-                    assert_object_equals(r, { value: undefined, done: true }, 'third result should be correct');
-                    test2.done();
-                }));
-            }));
-        })).catch(test2.step_func(function(e) { assert_unreached(e); }));
-    });
-
-    var test3 = async_test('draining the stream via read() should cause the reader closed promise to fulfill, but locked stays true');
-    test3.step(function() {
-        var { stream, reader } = factory();
-
-        assert_true(stream.locked, 'stream should start locked');
-
-        reader.closed.then(
-            test3.step_func(function(v) {
-                assert_equals(v, undefined, 'reader closed should fulfill with undefined');
-                assert_true(stream.locked, 'stream should remain locked');
-                test3.done();
-            }),
-            test3.step_func(function() { assert_unreached('reader closed should not reject'); })
-        );
-
-        reader.read();
-        reader.read();
-    });
-
-    var test4 = async_test('releasing the lock after the stream is closed should cause locked to become false');
-    test4.step(function() {
-        var { stream, reader } = factory();
-
-        reader.closed.then(test4.step_func(function() {
-            assert_true(stream.locked, 'the stream should start locked');
-            reader.releaseLock(); // Releasing the lock after reader closed should not throw.
-            assert_false(stream.locked, 'the stream should end unlocked');
-            test4.done();
-        }));
-
-        reader.read();
-        reader.read();
-    });
-
-    var test5 = async_test('releasing the lock should cause further read() calls to reject with a TypeError');
-    test5.step(function() {
-        var promiseCalls = 0;
-        var { reader } = factory();
-
-        reader.releaseLock();
-
-        reader.read().catch(test5.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'first read() should reject with a TypeError');
-            assert_equals(++promiseCalls, 1);
-        }));
-        reader.read().catch(test5.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'second read() should reject with a TypeError');
-            assert_equals(++promiseCalls, 2);
-        }));
-        reader.read().catch(test5.step_func(function(e) {
-            assert_throws(new TypeError(), function() { throw e; }, 'third read() should reject with a TypeError');
-            assert_equals(++promiseCalls, 3);
-            test5.done();
-        }));
-    });
-
-    var test6 = async_test('reader\'s closed property always returns the same promise');
-    test6.step(function() {
-        var { reader, stream } = factory();
-
-        var readerClosed = reader.closed;
-
-        assert_equals(reader.closed, readerClosed, 'accessing reader.closed twice in succession gives the same value');
-
-        reader.read().then(test6.step_func(function() {
-            assert_equals(reader.closed, readerClosed, 'reader.closed is the same after read() fulfills');
-
-            reader.releaseLock();
-
-            assert_equals(reader.closed, readerClosed, 'reader.closed is the same after releasing the lock');
-
-            var newReader = stream.getReader();
-            newReader.read();
-
-            test6.done();
-        }));
-
-        assert_equals(reader.closed, readerClosed, 'reader.closed is the same after calling read()');
-    });
-};
-
-templatedRSEmpty('ReadableStream (empty)', function() {
-    return new ReadableStream();
-});
-
-templatedRSEmptyReader('ReadableStream (empty) reader', function() {
-    return streamAndDefaultReader(new ReadableStream());
-});
-
 templatedRSClosed('ReadableStream (closed via call in start)', function() {
     return new ReadableStream({
         start: function(c) {
@@ -1057,43 +353,11 @@ templatedRSClosed('ReadableStream (closed via call in start)', function() {
     });
 });
 
-templatedRSClosedReader('ReadableStream reader (closed before getting reader)', function() {
-    var controller;
-    var stream = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-    controller.close();
-    var result = streamAndDefaultReader(stream);
-    return result;
-});
-
-templatedRSClosedReader('ReadableStream reader (closed after getting reader)', function() {
-    var controller;
-    var stream = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-    var result = streamAndDefaultReader(stream);
-    controller.close();
-    return result;
-});
-
 templatedRSClosed('ReadableStream (closed via cancel)', function() {
     var stream = new ReadableStream();
     stream.cancel();
     return stream;
 });
-
-templatedRSClosedReader('ReadableStream reader (closed via cancel after getting reader)', function() {
-    var stream = new ReadableStream();
-    var result = streamAndDefaultReader(stream);
-    result.reader.cancel();
-    return result;
-});
-
 var theError = new Error('boo!');
 
 templatedRSErrored('ReadableStream (errored via call in start)', function() {
@@ -1105,15 +369,6 @@ templatedRSErrored('ReadableStream (errored via call in start)', function() {
     theError
 );
 
-templatedRSErroredSyncOnly('ReadableStream (errored via call in start)', function() {
-    return new ReadableStream({
-        start: function(c) {
-            c.error(theError);
-        }
-    })},
-    theError
-);
-
 templatedRSErrored('ReadableStream (errored via returning a rejected promise in start)', function() {
     return new ReadableStream({
         start: function() {
@@ -1130,49 +385,8 @@ templatedRSErroredAsyncOnly('ReadableStream (errored via returning a rejected pr
     theError
 );
 
-templatedRSErroredReader('ReadableStream (errored via returning a rejected promise in start) reader', function() {
-    return streamAndDefaultReader(new ReadableStream({
-        start: function() {
-            return Promise.reject(theError);
-        }
-    }))},
-    theError
-);
-
-templatedRSErroredReader('ReadableStream reader (errored before getting reader)', function() {
-    var controller;
-    var stream = new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    });
-    controller.error(theError);
-    return streamAndDefaultReader(stream);
-}, theError);
-
-templatedRSErroredReader('ReadableStream reader (errored after getting reader)', function() {
-    var controller;
-    var result = streamAndDefaultReader(new ReadableStream({
-        start: function(c) {
-            controller = c;
-        }
-    }));
-    controller.error(theError);
-    return result;
-}, theError);
-
 var chunks = ['a', 'b'];
 
-templatedRSTwoChunksOpenReader('ReadableStream (two chunks enqueued, still open) reader', function() {
-    return streamAndDefaultReader(new ReadableStream({
-        start: function(c) {
-            c.enqueue(chunks[0]);
-            c.enqueue(chunks[1]);
-        }
-    }))},
-    chunks
-);
-
 templatedRSTwoChunksClosed('ReadableStream (two chunks enqueued, then closed)', function() {
     return new ReadableStream({
         start: function(c) {
@@ -1210,22 +424,4 @@ templatedRSTwoChunksClosed('ReadableStream (two chunks enqueued via pull, then c
 },
 chunks
 );
-
-templatedRSTwoChunksClosedReader('ReadableStream (two chunks enqueued, then closed) reader', function() {
-    var doClose;
-    var stream = new ReadableStream({
-        start: function(c) {
-            c.enqueue(chunks[0]);
-            c.enqueue(chunks[1]);
-            doClose = c.close.bind(c);
-        }
-    });
-    var result = streamAndDefaultReader(stream);
-    doClose();
-    return result;
-}, chunks);
-
-function streamAndDefaultReader(stream) {
-  return { stream: stream, reader: stream.getReader() };
-}
 </script>
diff --git a/LayoutTests/streams/reference-implementation/readable-stream.html b/LayoutTests/streams/reference-implementation/readable-stream.html
deleted file mode 100644 (file)
index 7c8d638..0000000
+++ /dev/null
@@ -1,880 +0,0 @@
-<!DOCTYPE html>
-<script src='../../resources/testharness.js'></script>
-<script src='../../resources/testharnessreport.js'></script>
-<script src='resources/streams-utils.js'></script>
-<script src='../../resources/gc.js'></script>
-<script>
-// This is updated till https://github.com/whatwg/streams/commit/ec5ffa036308d9f6350d2946560d48cdbf090939
-
-test(function() {
-    new ReadableStream(); // ReadableStream constructed with no parameters.
-    new ReadableStream({ }); // ReadableStream constructed with an empty object as parameter.
-    new ReadableStream(undefined); // ReadableStream constructed with undefined as parameter.
-    var x;
-    new ReadableStream(x) // ReadableStream constructed with an undefined variable as parameter.
-}, 'ReadableStream can be constructed with no errors');
-
-test(function() {
-    assert_throws(new TypeError(), function() { new ReadableStream(null); }, 'constructor should throw when the source is null');
-}, 'ReadableStream can\'t be constructed with garbage');
-
-test(function() {
-    var methods = ['cancel', 'constructor', 'getReader', 'pipeThrough', 'pipeTo', 'tee'];
-    var properties = methods.concat(['locked']).sort();
-
-    var rs = new ReadableStream();
-    var proto = Object.getPrototypeOf(rs);
-
-    assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties, 'should have all the correct methods');
-
-    for (var m of methods) {
-        var propDesc = Object.getOwnPropertyDescriptor(proto, m);
-        assert_false(propDesc.enumerable, 'method should be non-enumerable');
-        assert_true(propDesc.configurable, 'method should be configurable');
-        assert_true(propDesc.writable, 'method should be writable');
-        assert_equals(typeof rs[m], 'function', 'should have be a method');
-    }
-
-    var lockedPropDesc = Object.getOwnPropertyDescriptor(proto, 'locked');
-    assert_false(lockedPropDesc.enumerable, 'locked should be non-enumerable');
-    assert_equals(lockedPropDesc.writable, undefined, 'locked should not be a data property');
-    assert_equals(typeof lockedPropDesc.get, 'function', 'locked should have a getter');
-    assert_equals(lockedPropDesc.set, undefined, 'locked should not have a setter');
-    assert_true(lockedPropDesc.configurable, 'locked should be configurable');
-
-    assert_equals(rs.cancel.length, 1, 'cancel should have 1 parameter');
-    assert_equals(rs.constructor.length, 0, 'constructor should have no parameters');
-    assert_equals(rs.getReader.length, 0, 'getReader should have no parameters');
-    assert_equals(rs.pipeThrough.length, 2, 'pipeThrough should have 2 parameters');
-    assert_equals(rs.pipeTo.length, 1, 'pipeTo should have 1 parameter');
-    assert_equals(rs.tee.length, 0, 'tee should have no parameters');
-}, 'ReadableStream instances should have the correct list of properties');
-
-test(function() {
-    assert_throws(new TypeError(), function() {
-        new ReadableStream({ start: 'potato'});
-    }, 'constructor should throw when start is not a function');
-}, 'ReadableStream constructor should throw for non-function start arguments');
-
-test(function() {
-    new ReadableStream({ cancel: '2'}); // Constructor should not throw when cancel is not a function.
-}, 'ReadableStream constructor can get initial garbage as cancel argument');
-
-test(function() {
-    new ReadableStream({ pull: { } }); // Constructor should not throw when pull is not a function.
-}, 'ReadableStream constructor can get initial garbage as pull argument');
-
-test(function() {
-    var startCalled = false;
-    var source = {
-        start: function(controller) {
-            assert_equals(this, source, 'source is this during start');
-
-            var methods = ['close', 'enqueue', 'error', 'constructor'];
-            var properties = ['desiredSize'].concat(methods).sort();
-            var proto = Object.getPrototypeOf(controller);
-
-            assert_array_equals(Object.getOwnPropertyNames(proto).sort(), properties,
-                                'the controller should have the right properties');
-
-            for (var m of methods) {
-                var propDesc = Object.getOwnPropertyDescriptor(proto, m);
-                assert_equals(typeof controller[m], 'function', `should have a ${m} method`);
-                assert_false(propDesc.enumerable, m + " should be non-enumerable");
-                assert_true(propDesc.configurable, m + " should be configurable");
-                assert_true(propDesc.writable, m + " should be writable");
-            }
-
-            var desiredSizePropDesc = Object.getOwnPropertyDescriptor(proto, 'desiredSize');
-            assert_false(desiredSizePropDesc.enumerable, 'desiredSize should be non-enumerable');
-            assert_equals(desiredSizePropDesc.writable, undefined, 'desiredSize should not be a data property');
-            assert_equals(typeof desiredSizePropDesc.get, 'function', 'desiredSize should have a getter');
-            assert_equals(desiredSizePropDesc.set, undefined, 'desiredSize should not have a setter');
-            assert_true(desiredSizePropDesc.configurable, 'desiredSize should be configurable');
-
-            assert_equals(controller.close.length, 0, 'close should have no parameters');
-            assert_equals(controller.constructor.length, 1, 'constructor should have 1 parameter');
-            assert_equals(controller.enqueue.length, 1, 'enqueue should have 1 parameter');
-            assert_equals(controller.error.length, 1, 'error should have 1 parameter');
-
-            startCalled = true;
-        }
-    };
-
-    new ReadableStream(source);
-    assert_true(startCalled);
-}, 'ReadableStream start should be called with the proper parameters');
-
-test(function() {
-    var startCalled = false;
-    var source = {
-        start: function(controller) {
-            var properties = ['close', 'constructor', 'desiredSize', 'enqueue', 'error'];
-            assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties,
-                                'prototype should have the right properties');
-            controller.test = '';
-            assert_array_equals(Object.getOwnPropertyNames(Object.getPrototypeOf(controller)).sort(), properties,
-                                'prototype should still have the right properties');
-            assert_not_equals(Object.getOwnPropertyNames(controller).indexOf('test'), -1,
-                              '"test" should be a property of the controller');
-
-            startCalled = true;
-        }
-    };
-
-    var rs = new ReadableStream(source);
-    assert_true(startCalled);
-}, 'ReadableStream start controller parameter should be extensible');
-
-var test1 = async_test('ReadableStream should be able to call start method within prototype chain of its source');
-test1.step(function()
-{
-    function SimpleStreamSource() {
-    };
-    SimpleStreamSource.prototype = {
-        start: function() {
-            test1.done('start should be called');
-        },
-    }
-
-    new ReadableStream(new SimpleStreamSource());
-});
-
-var test2 = async_test('ReadableStream start should be able to return a promise');
-test2.step(function()
-{
-    var readCalled = false;
-    var rs = new ReadableStream({
-        start: function(c) {
-            return new Promise(test2.step_func(function(resolve, reject) {
-                setTimeout(test2.step_func(function() {
-                    c.enqueue('a');
-                    c.close();
-                    resolve();
-                }), 500);
-            }));
-        },
-    });
-
-    var reader = rs.getReader();
-
-    reader.read().then(test2.step_func(function(r) {
-        readCalled = true;
-        assert_object_equals(r, { value: 'a', done: false }, 'value read should be the one enqueued');
-    }));
-
-    reader.closed.then(test2.step_func(function() {
-        assert_true(readCalled);
-        test2.done('stream should close successfully');
-    }));
-});
-
-var test3 = async_test('ReadableStream start should be able to return a promise and reject it');
-test3.step(function()
-{
-    var theError = new Error('rejected!');
-    var rs = new ReadableStream({
-        start: function() {
-            return new Promise(test3.step_func(function(resolve, reject) {
-                setTimeout(test3.step_func(function() {
-                    reject(theError);
-                }), 500);
-            }));
-        },
-    });
-
-    rs.getReader().closed.catch(test3.step_func(function(e) {
-        assert_equals(e, theError, 'promise should be rejected with the same error');
-        test3.done();
-    }));
-});
-
-var test4 = async_test('ReadableStream should be able to enqueue different objects.');
-test4.step(function() {
-    var readCalls = 0;
-    var objects = [
-    { potato: 'Give me more!'},
-    'test',
-    1
-    ];
-
-    var rs = new ReadableStream({
-        start: function(c) {
-            for (var o of objects) {
-                c.enqueue(o);
-            }
-            c.close();
-        }
-    });
-
-    var reader = rs.getReader();
-
-    reader.read().then(test4.step_func(function(r) {
-        assert_object_equals(r, { value: objects[readCalls++], done: false }, 'value read should be the one enqueued');
-    }));
-
-    reader.read().then(test4.step_func(function(r) {
-        assert_object_equals(r, { value: objects[readCalls++], done: false }, 'value read should be the one enqueued');
-    }));
-
-    reader.read().then(test4.step_func(function(r) {
-        assert_object_equals(r, { value: objects[readCalls++], done: false }, 'value read should be the one enqueued');
-    }));
-
-    reader.closed.then(test4.step_func(function() {
-        assert_equals(readCalls, 3);
-        test4.done('stream should close correctly correctly');
-    }));
-});
-
-var test5 = async_test('ReadableStream: if pull rejects, it should error the stream');
-test5.step(function() {
-    var error = new Error('pull failure');
-    var rs = new ReadableStream({
-        pull: function() {
-            return Promise.reject(error);
-        }
-    });
-
-    var reader = rs.getReader();
-
-    var closed = false;
-    var read = false;
-
-    reader.closed.catch(test5.step_func(function(e) {
-        closed = true;
-        assert_true(read);
-        assert_equals(e, error, 'closed should reject with the thrown error');
-        test5.done();
-    }));
-
-    reader.read().catch(test5.step_func(function(e) {
-        read = true;
-        assert_false(closed);
-        assert_equals(e, error, 'read() should reject with the thrown error');
-    }));
-});
-
-var test6 = async_test('ReadableStream: should only call pull once upon starting the stream');
-test6.step(function() {
-    var pullCount = 0;
-    var startPromise = Promise.resolve();
-    var rs = new ReadableStream({
-        start: function() {
-            return startPromise;
-        },
-        pull: function() {
-            pullCount++;
-        }
-    });
-
-    startPromise.then(test6.step_func(function() {
-        assert_equals(pullCount, 1, 'pull should be called once start finishes');
-
-        setTimeout(test6.step_func(function() {
-            assert_equals(pullCount, 1, 'pull should be called exactly once');
-            test6.done();
-        }), 1000);
-    }));
-
-});
-
-var test7 = async_test('ReadableStream: should call pull when trying to read from a started, empty stream');
-test7.step(function() {
-    var pullCount = 0;
-    var startPromise = Promise.resolve();
-    var rs = new ReadableStream({
-        start: function() {
-            return startPromise;
-        },
-        pull: function(c) {
-            // Don't enqueue immediately after start. We want the stream to be empty when we call .read() on it.
-            if (pullCount > 0) {
-                c.enqueue(pullCount);
-            }
-
-            ++pullCount;
-        }
-    });
-
-    startPromise.then(test7.step_func(function() {
-        assert_equals(pullCount, 1, 'pull should be called once start finishes');
-
-        var reader = rs.getReader();
-        return reader.read().then(test7.step_func(function(result) {
-            assert_equals(pullCount, 2, 'pull should be called again in reaction to calling read');
-            assert_object_equals(result, { value: 1, done: false }, 'the result read should be the one enqueued');
-            test7.done();
-        }));
-    })).catch(test7.step_func(function(e) { assert_unreached(e); }));
-});
-
-var test8 = async_test('ReadableStream: should only call pull once on a non-empty stream read from before start fulfills');
-test8.step(function() {
-    var pullCount = 0;
-    var startPromise = Promise.resolve();
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            return startPromise;
-        },
-        pull: function() {
-            pullCount++;
-        }
-    });
-
-    startPromise.then(test8.step_func(function() {
-        assert_equals(pullCount, 1, 'pull should be called once start finishes');
-    }));
-
-    rs.getReader().read().then(test8.step_func(function(r) {
-        assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk');
-        assert_equals(pullCount, 1, 'pull should not have been called again');
-
-        setTimeout(test8.step_func(function() {
-            assert_equals(pullCount, 1, 'pull should be called exactly once');
-            test8.done();
-        }), 1000);
-    }));
-
-    assert_equals(pullCount, 0, 'calling read() should not cause pull to be called yet');
-});
-
-var test9 = async_test('ReadableStream: should only call pull once on a non-empty stream read from after start fulfills');
-test9.step(function() {
-    var pullCount = 0;
-    var startPromise = Promise.resolve();
-    var rs = new ReadableStream({
-        start: function(c) {
-            c.enqueue('a');
-            return startPromise;
-        },
-        pull: function() {
-            pullCount++;
-        }
-    });
-
-    startPromise.then(test9.step_func(function() {
-        assert_equals(pullCount, 0, 'pull should not be called once start finishes, since the queue is full');
-
-        rs.getReader().read().then(test9.step_func(function(r) {
-            assert_object_equals(r, { value: 'a', done: false }, 'first read() should return first chunk');
-
-            setTimeout(test9.step_func(function() {
-                assert_equals(pullCount, 1, 'pull should be called exactly once');
-                test9.done();
-            }), 1000);
-                                       
-        }));
-
-        assert_equals(pullCount, 1, 'calling read() should not cause pull to be called immediately');
-    }));
-});
-
-var test10 = async_test('ReadableStream: should call pull in reaction to read()ing the last chunk, if not draining');
-test10.step(function() {
-    var pullCount = 0;
-    var controller;
-    var startPromise = Promise.resolve();
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-            return startPromise;
-        },
-        pull: function() {
-            ++pullCount;
-        }
-    });
-
-    var reader = rs.getReader();
-
-    startPromise.then(test10.step_func(function() {
-        assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts');
-
-        controller.enqueue('a');
-        assert_equals(pullCount, 1, 'pull should not have been called again after enqueue');
-
-        return reader.read().then(test10.step_func(function() {
-            assert_equals(pullCount, 2, 'pull should have been called again after read');
-
-            setTimeout(test10.step_func(function() {
-                assert_equals(pullCount, 2, 'pull should be called exactly twice');
-                test10.done();
-            }), 500);
-        }));
-    })).catch(test10.step_func(function(e) { assert_unreached(e); }));
-});
-
-var test11 = async_test('ReadableStream: should not call pull() in reaction to read()ing the last chunk, if draining');
-test11.step(function() {
-    var pullCount = 0;
-    var controller;
-    var startPromise = Promise.resolve();
-    var pullPromise = Promise.resolve();
-    var rs = new ReadableStream({
-        start: function(c) {
-            controller = c;
-            return startPromise;
-        },
-        pull: function() {
-            ++pullCount;
-            return pullPromise;
-        }
-    });
-
-    var reader = rs.getReader();
-
-    startPromise.then(test11.step_func(function() {
-        assert_equals(pullCount, 1, 'pull should have been called once by the time the stream starts');
-
-        controller.enqueue('a');
-        assert_equals(pullCount, 1, 'pull should not have been called again after enqueue');
-
-        controller.close();