From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/tests/non262/ReadableStream/basic-pull.js | 37 +++ js/src/tests/non262/ReadableStream/basic-push.js | 53 +++ js/src/tests/non262/ReadableStream/bug-1501502.js | 25 ++ js/src/tests/non262/ReadableStream/bug-1549768.js | 18 + .../non262/ReadableStream/closed-is-handled.js | 27 ++ .../non262/ReadableStream/constructor-default.js | 27 ++ .../ReadableStream/readable-stream-globals.js | 367 +++++++++++++++++++++ js/src/tests/non262/ReadableStream/shell.js | 30 ++ js/src/tests/non262/ReadableStream/subclassing.js | 111 +++++++ js/src/tests/non262/ReadableStream/tee-start.js | 11 + 10 files changed, 706 insertions(+) create mode 100644 js/src/tests/non262/ReadableStream/basic-pull.js create mode 100644 js/src/tests/non262/ReadableStream/basic-push.js create mode 100644 js/src/tests/non262/ReadableStream/bug-1501502.js create mode 100644 js/src/tests/non262/ReadableStream/bug-1549768.js create mode 100644 js/src/tests/non262/ReadableStream/closed-is-handled.js create mode 100644 js/src/tests/non262/ReadableStream/constructor-default.js create mode 100644 js/src/tests/non262/ReadableStream/readable-stream-globals.js create mode 100644 js/src/tests/non262/ReadableStream/shell.js create mode 100644 js/src/tests/non262/ReadableStream/subclassing.js create mode 100644 js/src/tests/non262/ReadableStream/tee-start.js (limited to 'js/src/tests/non262/ReadableStream') diff --git a/js/src/tests/non262/ReadableStream/basic-pull.js b/js/src/tests/non262/ReadableStream/basic-pull.js new file mode 100644 index 0000000000..760937c67a --- /dev/null +++ b/js/src/tests/non262/ReadableStream/basic-pull.js @@ -0,0 +1,37 @@ +// |reftest| skip-if(!this.ReadableStream||!this.drainJobQueue) + +if ("ignoreUnhandledRejections" in this) { + ignoreUnhandledRejections(); +} + +// Example of a stream that produces data on demand, the "pull" model. +let fibStream = new ReadableStream({ + start(controller) { + this.a = 0; + this.b = 1; + controller.enqueue(0); + controller.enqueue(1); + }, + + pull(controller) { + [this.a, this.b] = [this.b, this.a + this.b]; + controller.enqueue(this.b); + } +}); + +async function test() { + assertEq(fibStream.locked, false); + let reader = fibStream.getReader(); + assertEq(fibStream.locked, true); + + let results = []; + while (results.length < 10) { + results.push((await reader.read()).value); + } + + assertEq(results.join(), "0,1,1,2,3,5,8,13,21,34"); + reader.releaseLock(); + assertEq(fibStream.locked, false); +} + +runAsyncTest(test); diff --git a/js/src/tests/non262/ReadableStream/basic-push.js b/js/src/tests/non262/ReadableStream/basic-push.js new file mode 100644 index 0000000000..65bb29880d --- /dev/null +++ b/js/src/tests/non262/ReadableStream/basic-push.js @@ -0,0 +1,53 @@ +// |reftest| skip-if(!this.ReadableStream||!this.drainJobQueue) + +if ("ignoreUnhandledRejections" in this) { + ignoreUnhandledRejections(); +} + +// Example of a stream that enqueues data asynchronously, whether the reader +// wants it or not, the "push" model. +let fbStream = new ReadableStream({ + start(controller) { + simulatePacketsDriftingIn(controller); + }, +}); + +async function simulatePacketsDriftingIn(controller) { + for (let i = 1; i <= 30; i++) { + let importantData = + (i % 15 == 0 ? "FizzBuzz" : + i % 5 == 0 ? "Buzz": + i % 3 == 0 ? "Fizz" : + String(i)); + controller.enqueue(importantData); + await asyncSleep(1 + i % 7); + } + controller.close(); +} + +const expected = [ + "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", + "11", "Fizz", "13", "14", "FizzBuzz", "16", "17", "Fizz", "19", "Buzz", + "Fizz", "22", "23", "Fizz", "Buzz", "26", "Fizz", "28", "29", "FizzBuzz" +]; + +async function test() { + assertEq(fbStream.locked, false); + let reader = fbStream.getReader(); + assertEq(fbStream.locked, true); + + let results = []; + while (true) { + let r = await reader.read(); + if (r.done) { + break; + } + results.push(r.value); + } + + assertEq(results.join("-"), expected.join("-")); + reader.releaseLock(); + assertEq(fbStream.locked, false); +} + +runAsyncTest(test); diff --git a/js/src/tests/non262/ReadableStream/bug-1501502.js b/js/src/tests/non262/ReadableStream/bug-1501502.js new file mode 100644 index 0000000000..e6b5c0c85b --- /dev/null +++ b/js/src/tests/non262/ReadableStream/bug-1501502.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!this.hasOwnProperty('ReadableStream')) +// A stream can become errored with an exception from another realm. + +let g = newGlobal(); +let g_enqueue; +new g.ReadableStream({ + start(controller) { + g_enqueue = controller.enqueue; + }, +}); + +let controller; +let stream = new ReadableStream({ + start(c) { + controller = c; + } +}, { + size(chunk) {} +}); + +assertThrowsInstanceOf(() => g_enqueue.call(controller, {}), g.RangeError); + +if (typeof reportCompare == 'function') + reportCompare(0, 0); + diff --git a/js/src/tests/non262/ReadableStream/bug-1549768.js b/js/src/tests/non262/ReadableStream/bug-1549768.js new file mode 100644 index 0000000000..747cb895a9 --- /dev/null +++ b/js/src/tests/non262/ReadableStream/bug-1549768.js @@ -0,0 +1,18 @@ +// |reftest| skip-if(!this.hasOwnProperty('ReadableStream')) + +var otherGlobal = newGlobal({ newCompartment: true }); +var obj = { start(c) { } }; +var Cancel = otherGlobal.ReadableStream.prototype.tee.call(new ReadableStream(obj))[0].cancel; + +var stream = new ReadableStream(obj); +var [branch1, branch2] = ReadableStream.prototype.tee.call(stream); + +Cancel.call(branch1, {}); + +gczeal(2, 1); + +Cancel.call(branch2, {}); + +if (typeof reportCompare === 'function') { + reportCompare(0, 0); +} diff --git a/js/src/tests/non262/ReadableStream/closed-is-handled.js b/js/src/tests/non262/ReadableStream/closed-is-handled.js new file mode 100644 index 0000000000..276cfbbaff --- /dev/null +++ b/js/src/tests/non262/ReadableStream/closed-is-handled.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.ReadableStream||!this.drainJobQueue) + +// 3.5.6. ReadableStreamError ( stream, e ) nothrow +// +// 9. Reject reader.[[closedPromise]] with e. +// 10. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true. +// +// Rejection for [[closedPromise]] shouldn't be reported as unhandled. + +const rs = new ReadableStream({ + start() { + return Promise.reject(new Error("test")); + } +}); + +let rejected = false; +rs.getReader().read().then(() => {}, () => { rejected = true; }); + +drainJobQueue(); + +assertEq(rejected, true); + +if (typeof reportCompare === 'function') { + reportCompare(0, 0); +} + +// Shell itself reports unhandled rejection if there's any. diff --git a/js/src/tests/non262/ReadableStream/constructor-default.js b/js/src/tests/non262/ReadableStream/constructor-default.js new file mode 100644 index 0000000000..9f60204c72 --- /dev/null +++ b/js/src/tests/non262/ReadableStream/constructor-default.js @@ -0,0 +1,27 @@ +// |reftest| skip-if(!this.hasOwnProperty('ReadableStream')) + +// The second argument to `new ReadableStream` defaults to `{}`, so it observes +// properties hacked onto Object.prototype. + +let log = []; + +Object.defineProperty(Object.prototype, "size", { + configurable: true, + get() { + log.push("size"); + log.push(this); + return undefined; + } +}); +Object.prototype.highWaterMark = 1337; + +let s = new ReadableStream({ + start(controller) { + log.push("start"); + log.push(controller.desiredSize); + } +}); +assertDeepEq(log, ["size", {}, "start", 1337]); + +if (typeof reportCompare == "function") + reportCompare(0, 0); diff --git a/js/src/tests/non262/ReadableStream/readable-stream-globals.js b/js/src/tests/non262/ReadableStream/readable-stream-globals.js new file mode 100644 index 0000000000..37e73d5cbf --- /dev/null +++ b/js/src/tests/non262/ReadableStream/readable-stream-globals.js @@ -0,0 +1,367 @@ +// |reftest| skip-if(!this.hasOwnProperty("ReadableStream")) + +if ("ignoreUnhandledRejections" in this) { + ignoreUnhandledRejections(); +} + +async function test() { + if (typeof newGlobal !== 'undefined') { + otherGlobal = newGlobal(); + } + + OtherReadableStream = otherGlobal.ReadableStream; + + ReadableStreamReader = new ReadableStream().getReader().constructor; + OtherReadableStreamReader = new otherGlobal.ReadableStream().getReader().constructor; + + let byteStreamsSupported = false; + try { + let controller; + let reader = new ReadableStream({ + start(c) { + ByteStreamController = c.constructor; + controller = c; + }, + type: "bytes" + }).getReader({ mode: "byob" }) + ReadableStreamBYOBReader = reader.constructor; + reader.read(new Uint8Array(10)); + BYOBRequest = controller.byobRequest.constructor; + reader = new otherGlobal.ReadableStream({ + start(c) { + OtherByteStreamController = c.constructor; + controller = c; + }, + type: "bytes" + }).getReader({ mode: "byob" }); + OtherReadableStreamBYOBReader = reader.constructor; + reader.read(new Uint8Array(10)); + OtherBYOBRequest = controller.byobRequest.constructor; + + BYOBRequestGetter = Object.getOwnPropertyDescriptor(ByteStreamController.prototype, + "byobRequest").get; + OtherBYOBRequestGetter = Object.getOwnPropertyDescriptor(OtherByteStreamController.prototype, + "byobRequest").get; + + byteStreamsSupported = true; + } catch (e) { + } + + let chunk = { name: "chunk" }; + let enqueuedError = { name: "enqueuedError" }; + + let controller; + let stream; + let otherStream; + let otherController; + let reader; + let otherReader; + + function getFreshInstances(type, otherType = type) { + stream = new ReadableStream({ start(c) { controller = c; }, type }); + + otherStream = new OtherReadableStream({ start(c) { otherController = c; }, type: otherType }); + } + + getFreshInstances(); + + Controller = controller.constructor; + OtherController = otherController.constructor; + + + otherReader = OtherReadableStream.prototype.getReader.call(stream); + assertEq(otherReader instanceof ReadableStreamReader, false); + assertEq(otherReader instanceof OtherReadableStreamReader, true); + assertEq(otherController instanceof Controller, false); + + assertEq(stream.locked, true); + Object.defineProperty(stream, "locked", + Object.getOwnPropertyDescriptor(OtherReadableStream.prototype, "locked")); + assertEq(stream.locked, true); + + + request = otherReader.read(); + assertEq(request instanceof otherGlobal.Promise, true); + controller.close(); + assertEq(await request instanceof Object, true); + + getFreshInstances(); + otherReader = new OtherReadableStreamReader(stream); + + getFreshInstances(); + otherReader = new OtherReadableStreamReader(stream); + let cancelSucceeded = false; + let cancelPromise = ReadableStreamReader.prototype.cancel.call(otherReader); + assertEq(cancelPromise instanceof Promise, true); + assertEq(await cancelPromise, undefined); + + getFreshInstances(); + otherReader = new OtherReadableStreamReader(stream); + let closeSucceeded = false; + Object.defineProperty(otherReader, "closed", + Object.getOwnPropertyDescriptor(ReadableStreamReader.prototype, "closed")); + let closedPromise = otherReader.closed; + assertEq(closedPromise instanceof otherGlobal.Promise, true); + controller.close(); + assertEq(await closedPromise, undefined); + + getFreshInstances(); + + otherReader = OtherReadableStream.prototype.getReader.call(stream); + request = otherReader.read(); + assertEq(request instanceof otherGlobal.Promise, true); + otherController.close.call(controller); + assertEq(await request instanceof otherGlobal.Object, true); + + getFreshInstances(); + + assertEq(controller.desiredSize, 1); + Object.defineProperty(controller, "desiredSize", + Object.getOwnPropertyDescriptor(OtherController.prototype, "desiredSize")); + assertEq(controller.desiredSize, 1); + + + request = otherReader.read(); + + controller.error(enqueuedError); + + expectException(() => controller.close(), TypeError); + expectException(() => otherController.close.call(controller), otherGlobal.TypeError); + + otherReader.releaseLock(); + + reader = stream.getReader(); + assertEq(await expectAsyncException(async () => reader.read(), enqueuedError.constructor), + enqueuedError); + + otherReader.releaseLock.call(reader); + assertEq(reader.closed instanceof otherGlobal.Promise, true); + + // getFreshInstances(); + + // reader = stream.getReader(); + // request = otherReader.read.call(reader); + // assertEq(request instanceof otherGlobal.Promise, true); + // controller.enqueue(chunk); + // assertEq((await request).value, chunk); + + // reader.releaseLock(); + + // getFreshInstances(); + + // reader = stream.getReader(); + // request = otherReader.read.call(reader); + // otherController.enqueue.call(controller, chunk); + // otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10)); + // controller.enqueue(new otherGlobal.Uint8Array(10)); + // request = otherReader.read.call(reader); + + getFreshInstances(); + + stream = new ReadableStream({ start(c) { controller = c; } }, { size() {return 1} }); + otherController.enqueue.call(controller, chunk); + otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10)); + controller.enqueue(new otherGlobal.Uint8Array(10)); + + getFreshInstances(); + + controller.close(); + expectException(() => controller.enqueue(new otherGlobal.Uint8Array(10)), TypeError); + expectException(() => otherController.enqueue.call(controller, chunk), otherGlobal.TypeError); + expectException(() => otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10)), + otherGlobal.TypeError); + + getFreshInstances(); + + let [branch1, branch2] = otherGlobal.ReadableStream.prototype.tee.call(stream); + assertEq(branch1 instanceof otherGlobal.ReadableStream, true); + assertEq(branch2 instanceof otherGlobal.ReadableStream, true); + + controller.enqueue(chunk); + reader = branch1.getReader(); + result = await reader.read(); + reader.releaseLock(); + let subPromiseCreated = false; + let speciesInvoked = false; + class SubPromise extends Promise { + constructor(executor) { + super(executor); + subPromiseCreated = true; + } + } + Object.defineProperty(Promise, Symbol.species, {get: function() { + speciesInvoked = true; + return SubPromise; + } + }); + + otherGlobal.eval(` + subPromiseCreated = false; + speciesInvoked = false; + class OtherSubPromise extends Promise { + constructor(executor) { + super(executor); + subPromiseCreated = true; + } + } + Object.defineProperty(Promise, Symbol.species, {get: function() { + speciesInvoked = true; + return OtherSubPromise; + } + });`); + + controller.error(enqueuedError); + subPromiseCreated = false; + speciesInvoked = false; + otherGlobal.subPromiseCreated = false; + otherGlobal.speciesInvoked = false; + let cancelPromise1 = branch1.cancel({ name: "cancel 1" }); + assertEq(cancelPromise1 instanceof otherGlobal.Promise, true); + assertEq(subPromiseCreated, false); + assertEq(speciesInvoked, false); + assertEq(otherGlobal.subPromiseCreated, false); + assertEq(otherGlobal.speciesInvoked, false); + subPromiseCreated = false; + speciesInvoked = false; + otherGlobal.subPromiseCreated = false; + otherGlobal.speciesInvoked = false; + let cancelPromise2 = branch2.cancel({ name: "cancel 2" }); + assertEq(cancelPromise2 instanceof otherGlobal.Promise, true); + assertEq(subPromiseCreated, false); + assertEq(speciesInvoked, false); + assertEq(otherGlobal.subPromiseCreated, false); + assertEq(otherGlobal.speciesInvoked, false); + await 1; + + + getFreshInstances(); + + [branch1, branch2] = otherGlobal.ReadableStream.prototype.tee.call(stream); + assertEq(branch1 instanceof otherGlobal.ReadableStream, true); + assertEq(branch2 instanceof otherGlobal.ReadableStream, true); + + controller.enqueue(chunk); + reader = branch1.getReader(); + result = await reader.read(); + reader.releaseLock(); + + + assertEq(result.value, chunk); + + controller.error(enqueuedError); + subPromiseCreated = false; + speciesInvoked = false; + otherGlobal.subPromiseCreated = false; + otherGlobal.speciesInvoked = false; + cancelPromise1 = ReadableStream.prototype.cancel.call(branch1, { name: "cancel 1" }); + assertEq(cancelPromise1 instanceof Promise, true); + assertEq(subPromiseCreated, false); + assertEq(speciesInvoked, false); + assertEq(otherGlobal.subPromiseCreated, false); + assertEq(otherGlobal.speciesInvoked, false); + subPromiseCreated = false; + speciesInvoked = false; + otherGlobal.subPromiseCreated = false; + otherGlobal.speciesInvoked = false; + cancelPromise2 = ReadableStream.prototype.cancel.call(branch2, { name: "cancel 2" }); + assertEq(cancelPromise2 instanceof Promise, true); + assertEq(subPromiseCreated, false); + assertEq(speciesInvoked, false); + assertEq(otherGlobal.subPromiseCreated, false); + assertEq(otherGlobal.speciesInvoked, false); + + if (!byteStreamsSupported) { + return; + } + + if (typeof nukeCCW === 'function') { + getFreshInstances("bytes"); + assertEq(otherController instanceof OtherByteStreamController, true); + reader = ReadableStream.prototype.getReader.call(otherStream); + otherGlobal.reader = reader; + otherGlobal.nukeCCW(otherGlobal.reader); + let chunk = new Uint8Array(10); + expectException(() => otherController.enqueue(chunk), otherGlobal.TypeError); + // otherController.error(); + expectException(() => reader.read(), TypeError); + } + + function testBYOBRequest(controller, view) { + const request = new BYOBRequest(controller, view); + let storedView = request.view; + assertEq(storedView, view); + storedView = Object.getOwnPropertyDescriptor(OtherBYOBRequest.prototype, "view").get.call(request); + assertEq(storedView, view); + request.respond(10); + OtherBYOBRequest.prototype.respond.call(request, 10); + request.respondWithNewView(new view.constructor(10)); + OtherBYOBRequest.prototype.respondWithNewView.call(request, new view.constructor(10)); + } + + expectException(() => new BYOBRequest(), TypeError); + getFreshInstances("bytes"); + expectException(() => new BYOBRequest(controller, new Uint8Array(10)), TypeError); + expectException(() => new BYOBRequest(otherController, new Uint8Array(10)), TypeError); + expectException(() => new BYOBRequest(otherController, new Uint8Array(10)), TypeError); + expectException(() => new BYOBRequest(otherController, new otherGlobal.Uint8Array(10)), TypeError); + + getFreshInstances("bytes"); + + reader = stream.getReader({ mode: "byob" }); + request = OtherReadableStreamBYOBReader.prototype.read.call(reader, new Uint8Array(10)); + assertEq(request instanceof otherGlobal.Promise, true); + controller.enqueue(new Uint8Array([1, 2, 3, 4])); + result = await request; + + getFreshInstances("bytes"); + + reader = stream.getReader({ mode: "byob" }); + request = OtherReadableStreamBYOBReader.prototype.read.call(reader, new Uint8Array(10)); + assertEq(request instanceof otherGlobal.Promise, true); + try { + let byobRequest = OtherBYOBRequestGetter.call(controller); + } catch (e) { + print(e, '\n', e.stack); + } + controller.enqueue(new Uint8Array([1, 2, 3, 4])); + result = await request; + + await 1; +} + +function expectException(closure, errorType) { + let error; + try { + closure(); + } catch (e) { + error = e; + } + assertEq(error !== undefined, true); + assertEq(error.constructor, errorType); + return error; +} + +async function expectAsyncException(closure, errorType) { + let error; + try { + await closure(); + } catch (e) { + error = e; + } + assertEq(error !== undefined, true); + assertEq(error.constructor, errorType); + return error; +} + +async function runTest() { + try { + await test(); + } catch (e) { + assertEq(false, true, `Unexpected exception ${e}\n${e.stack}`); + } + console.log("done"); + if (typeof reportCompare === "function") + reportCompare(true, true); +} + +runTest(); diff --git a/js/src/tests/non262/ReadableStream/shell.js b/js/src/tests/non262/ReadableStream/shell.js new file mode 100644 index 0000000000..7e83ed2934 --- /dev/null +++ b/js/src/tests/non262/ReadableStream/shell.js @@ -0,0 +1,30 @@ +// Return a promise that will resolve to `undefined` the next time jobs are +// processed. +// +// `ticks` indicates how long the promise should "wait" before resolving: a +// promise created with `asyncSleep(n)` will become settled and fire its handlers +// before a promise created with `asyncSleep(n+1)`. +// +function asyncSleep(ticks) { + let p = Promise.resolve(); + if (ticks > 0) { + return p.then(() => asyncSleep(ticks - 1)); + } + return p; +} + +// Run the async function `test`. Wait for it to finish running. Throw if it +// throws or if it fails to finish (awaiting a value forever). +function runAsyncTest(test) { + let passed = false; + let problem = "test did not finish"; + test() + .then(_ => { passed = true; }) + .catch(exc => { problem = exc; }); + drainJobQueue(); + if (!passed) { + throw problem; + } + + reportCompare(0, 0); +} diff --git a/js/src/tests/non262/ReadableStream/subclassing.js b/js/src/tests/non262/ReadableStream/subclassing.js new file mode 100644 index 0000000000..813ed278c2 --- /dev/null +++ b/js/src/tests/non262/ReadableStream/subclassing.js @@ -0,0 +1,111 @@ +// |reftest| skip-if(!xulRuntime.shell||!this.hasOwnProperty('ReadableStream')) -- needs drainJobQueue + +if ("ignoreUnhandledRejections" in this) { + ignoreUnhandledRejections(); +} + +// Spot-check subclassing of stream constructors. + +// ReadableStream can be subclassed. +class PartyStreamer extends ReadableStream {} + +// The base class constructor is called. +let started = false; +let stream = new PartyStreamer({ + // (The ReadableStream constructor calls this start method.) + start(c) { started = true; } +}); +drainJobQueue(); +assertEq(started, true); + +// The instance's prototype chain is correct. +assertEq(stream.__proto__, PartyStreamer.prototype); +assertEq(stream.__proto__.__proto__, ReadableStream.prototype); +assertEq(stream.__proto__.__proto__.__proto__, Object.prototype); +assertEq(stream.__proto__.__proto__.__proto__.__proto__, null); +assertEq(stream instanceof ReadableStream, true); + +// Non-generic methods can be called on the resulting stream. +let reader = stream.getReader(); +assertEq(stream.locked, true); + + +// CountQueuingStrategy can be subclassed. +class PixelStrategy extends CountQueuingStrategy {} +assertEq(new PixelStrategy({highWaterMark: 4}).__proto__, PixelStrategy.prototype); + +// The base class constructor is called. +assertThrowsInstanceOf(() => new PixelStrategy, TypeError); +assertEq(new PixelStrategy({highWaterMark: -1}).highWaterMark, -1); + + +// VerySmartStrategy can be subclassed. +class VerySmartStrategy extends ByteLengthQueuingStrategy { + size(chunk) { + return super.size(chunk) * 8; + } +} +let vss = new VerySmartStrategy({highWaterMark: 12}); +assertEq(vss.size(new ArrayBuffer(8)), 64); +assertEq(vss.__proto__, VerySmartStrategy.prototype); + + +// Even ReadableStreamDefaultReader can be subclassed. +async function readerTest() { + const ReadableStreamDefaultReader = new ReadableStream().getReader().constructor; + class MindReader extends ReadableStreamDefaultReader { + async read() { + let foretold = {value: "death", done: false}; + let actual = await super.read(); + actual = foretold; // ZOMG I WAS RIGHT, EXACTLY AS FORETOLD they should call me a righter + return actual; + } + } + + let stream = new ReadableStream({ + start(c) { c.enqueue("one"); c.enqueue("two"); }, + pull(c) { c.close(); } + }); + let reader = new MindReader(stream); + let result = await reader.read(); + assertEq(result.value, "death"); + reader.releaseLock(); + + reader = stream.getReader(); + result = await reader.read(); + assertEq(result.done, false); + assertEq(result.value, "two"); + result = await reader.read(); + assertEq(result.done, true); + assertEq(result.value, undefined); +} +runAsyncTest(readerTest); + + +// Even ReadableStreamDefaultController, which can't be constructed, +// can be subclassed. +let ReadableStreamDefaultController; +new ReadableStream({ + start(c) { + ReadableStreamDefaultController = c.constructor; + } +}); +class MasterController extends ReadableStreamDefaultController { + constructor() { + // don't call super, it'll just throw + return Object.create(MasterController.prototype); + } +} +let c = new MasterController(); + +// The prototype chain is per spec. +assertEq(c instanceof ReadableStreamDefaultController, true); + +// But the instance does not have the internal slots of a +// ReadableStreamDefaultController, so the non-generic methods can't be used. +assertThrowsInstanceOf(() => c.enqueue("horse"), TypeError); + + +if (typeof reportCompare === 'function') { + reportCompare(0, 0); +} diff --git a/js/src/tests/non262/ReadableStream/tee-start.js b/js/src/tests/non262/ReadableStream/tee-start.js new file mode 100644 index 0000000000..dbb6b1142d --- /dev/null +++ b/js/src/tests/non262/ReadableStream/tee-start.js @@ -0,0 +1,11 @@ +// |reftest| skip-if(!this.ReadableStream||!this.drainJobQueue) +// stream.tee() shouldn't try to call a .start() method. + +Object.prototype.start = function () { throw "FAIL"; }; +let source = Object.create(null); +new ReadableStream(source).tee(); + +drainJobQueue(); + +if (typeof reportCompare == 'function') + reportCompare(0, 0); -- cgit v1.2.3