11cb0ef41Sopenharmony_ci<!doctype html> 21cb0ef41Sopenharmony_ci<meta charset="utf-8"> 31cb0ef41Sopenharmony_ci<title>Ensure Stream objects are created in expected globals. </title> 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci<script src="/resources/testharness.js"></script> 61cb0ef41Sopenharmony_ci<script src="/resources/testharnessreport.js"></script> 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci<body></body> 91cb0ef41Sopenharmony_ci<script> 101cb0ef41Sopenharmony_ci// These tests are loosely derived from Gecko's readable-stream-globals.js, 111cb0ef41Sopenharmony_ci// which is a test case designed around the JS Streams implementation. 121cb0ef41Sopenharmony_ci// 131cb0ef41Sopenharmony_ci// Unlike in JS Streams, where function calls switch realms and change 141cb0ef41Sopenharmony_ci// the resulting global of the resulting objects, in WebIDL streams, 151cb0ef41Sopenharmony_ci// the global of an object is (currently underspecified, but) intended 161cb0ef41Sopenharmony_ci// to be the "Relevant Global" of the 'this' object. 171cb0ef41Sopenharmony_ci// 181cb0ef41Sopenharmony_ci// See: 191cb0ef41Sopenharmony_ci// https://html.spec.whatwg.org/multipage/webappapis.html#relevant 201cb0ef41Sopenharmony_ci// https://github.com/whatwg/streams/issues/1213 211cb0ef41Sopenharmony_ci"use strict" 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ciconst iframe = document.createElement("iframe") 241cb0ef41Sopenharmony_cidocument.body.append(iframe) 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciconst otherGlobal = iframe.contentWindow; 271cb0ef41Sopenharmony_ciconst OtherReadableStream = otherGlobal.ReadableStream 281cb0ef41Sopenharmony_ciconst OtherReadableStreamDefaultReader = otherGlobal.ReadableStreamDefaultReader; 291cb0ef41Sopenharmony_ciconst OtherReadableStreamDefaultController = otherGlobal.ReadableStreamDefaultController; 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_cipromise_test(async () => { 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci // Controllers 341cb0ef41Sopenharmony_ci let controller; 351cb0ef41Sopenharmony_ci let otherController; 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci // Get Stream Prototypes and controllers. 381cb0ef41Sopenharmony_ci let streamController; 391cb0ef41Sopenharmony_ci let stream = new ReadableStream({start(c) { streamController = c; }}); 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci const callReaderThisGlobal = OtherReadableStream.prototype.getReader.call(stream); 421cb0ef41Sopenharmony_ci const newReaderOtherGlobal = new OtherReadableStreamDefaultReader(new ReadableStream()); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci // Relevant Global Checking. 451cb0ef41Sopenharmony_ci assert_equals(callReaderThisGlobal instanceof ReadableStreamDefaultReader, true, "reader was created in this global (.call)"); 461cb0ef41Sopenharmony_ci assert_equals(newReaderOtherGlobal instanceof ReadableStreamDefaultReader, false, "reader was created in other global (new)"); 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci assert_equals(callReaderThisGlobal instanceof OtherReadableStreamDefaultReader, false, "reader isn't coming from other global (.call)" ); 491cb0ef41Sopenharmony_ci assert_equals(newReaderOtherGlobal instanceof OtherReadableStreamDefaultReader, true, "reader isn't coming from other global (new)"); 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci assert_equals(otherController instanceof ReadableStreamDefaultController, false, "otherController should come from other gloal") 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci const request = callReaderThisGlobal.read(); 551cb0ef41Sopenharmony_ci assert_equals(request instanceof Promise, true, "Promise comes from this global"); 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci streamController.close(); 581cb0ef41Sopenharmony_ci const requestResult = await request; 591cb0ef41Sopenharmony_ci assert_equals(requestResult instanceof Object, true, "returned object comes from this global"); 601cb0ef41Sopenharmony_ci}, "Stream objects created in expected globals") 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cipromise_test(async () => { 631cb0ef41Sopenharmony_ci const stream = new ReadableStream(); 641cb0ef41Sopenharmony_ci const otherReader = new OtherReadableStreamDefaultReader(stream); 651cb0ef41Sopenharmony_ci const cancelPromise = ReadableStreamDefaultReader.prototype.cancel.call(otherReader); 661cb0ef41Sopenharmony_ci assert_equals(cancelPromise instanceof Promise, true, "Cancel promise comes from the same global as the stream"); 671cb0ef41Sopenharmony_ci assert_equals(await cancelPromise, undefined, "Cancel promise resolves to undefined"); 681cb0ef41Sopenharmony_ci}, "Cancel promise is created in same global as stream") 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci// Refresh the streams and controllers. 711cb0ef41Sopenharmony_cifunction getFreshInstances() { 721cb0ef41Sopenharmony_ci let controller; 731cb0ef41Sopenharmony_ci let otherController; 741cb0ef41Sopenharmony_ci let stream = new ReadableStream({ 751cb0ef41Sopenharmony_ci start(c) { 761cb0ef41Sopenharmony_ci controller = c; 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci }); 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci new OtherReadableStream({ 811cb0ef41Sopenharmony_ci start(c) { 821cb0ef41Sopenharmony_ci otherController = c; 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci }); 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci return {stream, controller, otherController} 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_cipromise_test(async () => { 911cb0ef41Sopenharmony_ci // Test closed promise on reader from another global (connected to a this-global stream) 921cb0ef41Sopenharmony_ci const {stream, controller, otherController} = getFreshInstances(); 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci const otherReader = new OtherReadableStreamDefaultReader(stream); 951cb0ef41Sopenharmony_ci const closedPromise = otherReader.closed; 961cb0ef41Sopenharmony_ci assert_equals(closedPromise instanceof otherGlobal.Promise, true, "Closed promise in other global."); 971cb0ef41Sopenharmony_ci}, "Closed Promise in correct global"); 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_cipromise_test(async () => { 1001cb0ef41Sopenharmony_ci const {stream, controller, otherController} = getFreshInstances(); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci const otherReader = OtherReadableStream.prototype.getReader.call(stream); 1031cb0ef41Sopenharmony_ci assert_equals(otherReader instanceof ReadableStreamDefaultReader, true, "Reader comes from this global") 1041cb0ef41Sopenharmony_ci const request = otherReader.read(); 1051cb0ef41Sopenharmony_ci assert_equals(request instanceof Promise, true, "Promise still comes from stream's realm (this realm)"); 1061cb0ef41Sopenharmony_ci otherController.close.call(controller); 1071cb0ef41Sopenharmony_ci assert_equals((await request) instanceof otherGlobal.Object, true, "Object comes from other realm"); 1081cb0ef41Sopenharmony_ci}, "Reader objects in correct global"); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_cipromise_test(async () => { 1121cb0ef41Sopenharmony_ci const {stream, controller, otherController} = getFreshInstances(); 1131cb0ef41Sopenharmony_ci assert_equals(controller.desiredSize, 1, "Desired size is expected"); 1141cb0ef41Sopenharmony_ci Object.defineProperty(controller, "desiredSize", 1151cb0ef41Sopenharmony_ci Object.getOwnPropertyDescriptor(OtherReadableStreamDefaultController.prototype, "desiredSize")); 1161cb0ef41Sopenharmony_ci assert_equals(controller.desiredSize, 1, "Grafting getter from other prototype still returns desired size"); 1171cb0ef41Sopenharmony_ci}, "Desired size can be grafted from one prototype to another"); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_cipromise_test(async () => { 1201cb0ef41Sopenharmony_ci const {stream, controller, otherController} = getFreshInstances(); 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci // Make sure the controller close method returns the correct TypeError 1231cb0ef41Sopenharmony_ci const enqueuedError = { name: "enqueuedError" }; 1241cb0ef41Sopenharmony_ci controller.error(enqueuedError); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci assert_throws_js(TypeError, () => controller.close(), "Current Global controller"); 1271cb0ef41Sopenharmony_ci assert_throws_js(otherGlobal.TypeError, () => otherController.close.call(controller), "Other global controller"); 1281cb0ef41Sopenharmony_ci}, "Closing errored stream throws object in appropriate global") 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_cipromise_test(async () => { 1311cb0ef41Sopenharmony_ci const {otherController} = getFreshInstances(); 1321cb0ef41Sopenharmony_ci // We can enqueue chunks from multiple globals 1331cb0ef41Sopenharmony_ci const chunk = { name: "chunk" }; 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci let controller; 1361cb0ef41Sopenharmony_ci const stream = new ReadableStream({ start(c) { controller = c; } }, { size() {return 1} }); 1371cb0ef41Sopenharmony_ci otherController.enqueue.call(controller, chunk); 1381cb0ef41Sopenharmony_ci otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10)); 1391cb0ef41Sopenharmony_ci controller.enqueue(new otherGlobal.Uint8Array(10)); 1401cb0ef41Sopenharmony_ci}, "Can enqueue chunks from multiple globals") 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_cipromise_test(async () => { 1431cb0ef41Sopenharmony_ci const {stream, controller, otherController} = getFreshInstances(); 1441cb0ef41Sopenharmony_ci const chunk = { name: "chunk" }; 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci // We get the correct type errors out of a closed stream. 1471cb0ef41Sopenharmony_ci controller.close(); 1481cb0ef41Sopenharmony_ci assert_throws_js(TypeError, () => controller.enqueue(new otherGlobal.Uint8Array(10))); 1491cb0ef41Sopenharmony_ci assert_throws_js(otherGlobal.TypeError, () => otherController.enqueue.call(controller, chunk)); 1501cb0ef41Sopenharmony_ci assert_throws_js(otherGlobal.TypeError, () => otherController.enqueue.call(controller, new otherGlobal.Uint8Array(10))); 1511cb0ef41Sopenharmony_ci}, "Correct errors and globals for closed streams"); 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_cipromise_test(async () => { 1551cb0ef41Sopenharmony_ci const {stream, controller, otherController} = getFreshInstances(); 1561cb0ef41Sopenharmony_ci // Branches out of tee are in the correct global 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci const [branch1, branch2] = otherGlobal.ReadableStream.prototype.tee.call(stream); 1591cb0ef41Sopenharmony_ci assert_equals(branch1 instanceof ReadableStream, true, "Branch created in this global (as stream is in this global)"); 1601cb0ef41Sopenharmony_ci assert_equals(branch2 instanceof ReadableStream, true, "Branch created in this global (as stream is in this global)"); 1611cb0ef41Sopenharmony_ci}, "Tee Branches in correct global"); 1621cb0ef41Sopenharmony_ci</script> 163