1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "jsapi.h"
9 #include "jsfriendapi.h"
10 #include "js/experimental/TypedData.h" // JS_GetArrayBufferViewData, JS_IsUint8Array
11 #include "js/Stream.h"
12 #include "jsapi-tests/tests.h"
13
14 using namespace JS;
15
16 char testBufferData[] =
17 "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
18
19 struct StubExternalUnderlyingSource
20 : public JS::ReadableStreamUnderlyingSource {
21 void* buffer = testBufferData;
22 bool dataRequestCBCalled = false;
23 bool writeIntoRequestBufferCBCalled = false;
24 bool cancelStreamCBCalled = false;
25 Value cancelStreamReason;
26 bool streamClosedCBCalled = false;
27 Value streamClosedReason;
28 bool streamErroredCBCalled = false;
29 Value streamErroredReason;
30 bool finalizeStreamCBCalled = false;
31 void* finalizedStreamUnderlyingSource;
32
33 static StubExternalUnderlyingSource instance;
34
requestDataStubExternalUnderlyingSource35 void requestData(JSContext* cx, HandleObject stream,
36 size_t desiredSize) override {
37 js::AssertSameCompartment(cx, stream);
38 MOZ_RELEASE_ASSERT(!dataRequestCBCalled, "Invalid test setup");
39 dataRequestCBCalled = true;
40 }
41
writeIntoReadRequestBufferStubExternalUnderlyingSource42 void writeIntoReadRequestBuffer(JSContext* cx, HandleObject stream,
43 void* buffer, size_t length,
44 size_t* bytesWritten) override {
45 js::AssertSameCompartment(cx, stream);
46 MOZ_RELEASE_ASSERT(!writeIntoRequestBufferCBCalled, "Invalid test setup");
47 writeIntoRequestBufferCBCalled = true;
48
49 MOZ_RELEASE_ASSERT(this == &StubExternalUnderlyingSource::instance);
50 MOZ_RELEASE_ASSERT(StubExternalUnderlyingSource::instance.buffer ==
51 testBufferData);
52 MOZ_RELEASE_ASSERT(length <= sizeof(testBufferData));
53 memcpy(buffer, testBufferData, length);
54 *bytesWritten = length;
55 }
56
cancelStubExternalUnderlyingSource57 Value cancel(JSContext* cx, HandleObject stream,
58 HandleValue reason) override {
59 js::AssertSameCompartment(cx, stream);
60 js::AssertSameCompartment(cx, reason);
61 MOZ_RELEASE_ASSERT(!cancelStreamCBCalled, "Invalid test setup");
62 cancelStreamCBCalled = true;
63 cancelStreamReason = reason;
64 return reason;
65 }
66
onClosedStubExternalUnderlyingSource67 void onClosed(JSContext* cx, HandleObject stream) override {
68 js::AssertSameCompartment(cx, stream);
69 MOZ_RELEASE_ASSERT(!streamClosedCBCalled, "Invalid test setup");
70 streamClosedCBCalled = true;
71 }
72
onErroredStubExternalUnderlyingSource73 void onErrored(JSContext* cx, HandleObject stream,
74 HandleValue reason) override {
75 js::AssertSameCompartment(cx, stream);
76 js::AssertSameCompartment(cx, reason);
77 MOZ_RELEASE_ASSERT(!streamErroredCBCalled, "Invalid test setup");
78 streamErroredCBCalled = true;
79 streamErroredReason = reason;
80 }
81
finalizeStubExternalUnderlyingSource82 void finalize() override {
83 MOZ_RELEASE_ASSERT(!finalizeStreamCBCalled, "Invalid test setup");
84 finalizeStreamCBCalled = true;
85 finalizedStreamUnderlyingSource = this;
86 }
87
resetStubExternalUnderlyingSource88 void reset() {
89 dataRequestCBCalled = false;
90 writeIntoRequestBufferCBCalled = false;
91 cancelStreamReason = UndefinedValue();
92 cancelStreamCBCalled = false;
93 streamClosedCBCalled = false;
94 streamErroredCBCalled = false;
95 finalizeStreamCBCalled = false;
96 }
97 };
98
99 StubExternalUnderlyingSource StubExternalUnderlyingSource::instance;
100
101 static_assert(MOZ_ALIGNOF(StubExternalUnderlyingSource) > 1,
102 "UnderlyingSource pointers must not have the low bit set");
103
NewDefaultStream(JSContext * cx,HandleObject source=nullptr,HandleFunction size=nullptr,double highWaterMark=1,HandleObject proto=nullptr)104 static JSObject* NewDefaultStream(JSContext* cx, HandleObject source = nullptr,
105 HandleFunction size = nullptr,
106 double highWaterMark = 1,
107 HandleObject proto = nullptr) {
108 RootedObject stream(cx, NewReadableDefaultStreamObject(cx, source, size,
109 highWaterMark, proto));
110 if (stream) {
111 MOZ_RELEASE_ASSERT(IsReadableStream(stream));
112 }
113 return stream;
114 }
115
GetIterResult(JSContext * cx,HandleObject promise,MutableHandleValue value,bool * done)116 static bool GetIterResult(JSContext* cx, HandleObject promise,
117 MutableHandleValue value, bool* done) {
118 RootedObject iterResult(cx, &GetPromiseResult(promise).toObject());
119
120 bool found;
121 if (!JS_HasProperty(cx, iterResult, "value", &found)) {
122 return false;
123 }
124 MOZ_RELEASE_ASSERT(found);
125 if (!JS_HasProperty(cx, iterResult, "done", &found)) {
126 return false;
127 }
128 MOZ_RELEASE_ASSERT(found);
129
130 RootedValue doneVal(cx);
131 if (!JS_GetProperty(cx, iterResult, "value", value)) {
132 return false;
133 }
134 if (!JS_GetProperty(cx, iterResult, "done", &doneVal)) {
135 return false;
136 }
137
138 *done = doneVal.toBoolean();
139 if (*done) {
140 MOZ_RELEASE_ASSERT(value.isUndefined());
141 }
142
143 return true;
144 }
145
GetReadChunk(JSContext * cx,HandleObject readRequest)146 static JSObject* GetReadChunk(JSContext* cx, HandleObject readRequest) {
147 MOZ_RELEASE_ASSERT(GetPromiseState(readRequest) == PromiseState::Fulfilled);
148 RootedValue resultVal(cx, GetPromiseResult(readRequest));
149 MOZ_RELEASE_ASSERT(resultVal.isObject());
150 RootedObject result(cx, &resultVal.toObject());
151 RootedValue chunkVal(cx);
152 JS_GetProperty(cx, result, "value", &chunkVal);
153 return &chunkVal.toObject();
154 }
155
156 struct StreamTestFixture : public JSAPITest {
~StreamTestFixtureStreamTestFixture157 virtual ~StreamTestFixture() {}
158 };
159
BEGIN_FIXTURE_TEST(StreamTestFixture,testReadableStream_NewReadableStream)160 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_NewReadableStream) {
161 RootedObject stream(cx, NewDefaultStream(cx));
162 CHECK(stream);
163 ReadableStreamMode mode;
164 CHECK(ReadableStreamGetMode(cx, stream, &mode));
165 CHECK(mode == ReadableStreamMode::Default);
166 return true;
167 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_NewReadableStream)168 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_NewReadableStream)
169
170 BEGIN_FIXTURE_TEST(StreamTestFixture,
171 testReadableStream_ReadableStreamGetReaderDefault) {
172 RootedObject stream(cx, NewDefaultStream(cx));
173 CHECK(stream);
174
175 RootedObject reader(cx, ReadableStreamGetReader(
176 cx, stream, ReadableStreamReaderMode::Default));
177 CHECK(reader);
178 CHECK(IsReadableStreamDefaultReader(reader));
179 bool locked;
180 CHECK(ReadableStreamIsLocked(cx, stream, &locked));
181 CHECK(locked);
182 bool closed;
183 CHECK(ReadableStreamReaderIsClosed(cx, reader, &closed));
184 CHECK(!closed);
185
186 return true;
187 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamGetReaderDefault)188 END_FIXTURE_TEST(StreamTestFixture,
189 testReadableStream_ReadableStreamGetReaderDefault)
190
191 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamTee) {
192 RootedObject stream(cx, NewDefaultStream(cx));
193 CHECK(stream);
194
195 RootedObject leftStream(cx);
196 RootedObject rightStream(cx);
197 CHECK(ReadableStreamTee(cx, stream, &leftStream, &rightStream));
198 bool locked;
199 CHECK(ReadableStreamIsLocked(cx, stream, &locked));
200 CHECK(locked);
201 CHECK(leftStream);
202 CHECK(IsReadableStream(leftStream));
203 CHECK(rightStream);
204 CHECK(IsReadableStream(rightStream));
205
206 return true;
207 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamTee)208 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamTee)
209
210 BEGIN_FIXTURE_TEST(StreamTestFixture,
211 testReadableStream_ReadableStreamEnqueue) {
212 RootedObject stream(cx, NewDefaultStream(cx));
213 CHECK(stream);
214
215 RootedObject chunk(cx, JS_NewPlainObject(cx));
216 CHECK(chunk);
217 RootedValue chunkVal(cx, ObjectValue(*chunk));
218 CHECK(ReadableStreamEnqueue(cx, stream, chunkVal));
219
220 return true;
221 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamEnqueue)222 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamEnqueue)
223
224 BEGIN_FIXTURE_TEST(StreamTestFixture,
225 testReadableStream_ReadableStreamDefaultReaderRead) {
226 RootedObject stream(cx, NewDefaultStream(cx));
227 CHECK(stream);
228 RootedObject reader(cx, ReadableStreamGetReader(
229 cx, stream, ReadableStreamReaderMode::Default));
230 CHECK(reader);
231
232 RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
233 CHECK(request);
234 CHECK(IsPromiseObject(request));
235 CHECK(GetPromiseState(request) == PromiseState::Pending);
236
237 RootedObject chunk(cx, JS_NewPlainObject(cx));
238 CHECK(chunk);
239 RootedValue chunkVal(cx, ObjectValue(*chunk));
240 CHECK(ReadableStreamEnqueue(cx, stream, chunkVal));
241
242 CHECK(GetReadChunk(cx, request) == chunk);
243
244 return true;
245 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamDefaultReaderRead)246 END_FIXTURE_TEST(StreamTestFixture,
247 testReadableStream_ReadableStreamDefaultReaderRead)
248
249 BEGIN_FIXTURE_TEST(StreamTestFixture,
250 testReadableStream_ReadableStreamDefaultReaderClose) {
251 RootedObject stream(cx, NewDefaultStream(cx));
252 CHECK(stream);
253 RootedObject reader(cx, ReadableStreamGetReader(
254 cx, stream, ReadableStreamReaderMode::Default));
255 CHECK(reader);
256
257 RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
258 CHECK(request);
259 CHECK(IsPromiseObject(request));
260 CHECK(GetPromiseState(request) == PromiseState::Pending);
261
262 CHECK(ReadableStreamClose(cx, stream));
263
264 bool done;
265 RootedValue value(cx);
266 CHECK(GetPromiseState(request) == PromiseState::Fulfilled);
267 CHECK(GetIterResult(cx, request, &value, &done));
268 CHECK(value.isUndefined());
269 CHECK(done);
270
271 // The callbacks are only invoked for external streams.
272 CHECK(!StubExternalUnderlyingSource::instance.streamClosedCBCalled);
273
274 return true;
275 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamDefaultReaderClose)276 END_FIXTURE_TEST(StreamTestFixture,
277 testReadableStream_ReadableStreamDefaultReaderClose)
278
279 BEGIN_FIXTURE_TEST(StreamTestFixture,
280 testReadableStream_ReadableStreamDefaultReaderError) {
281 StubExternalUnderlyingSource::instance.reset();
282 RootedObject stream(cx, NewDefaultStream(cx));
283 CHECK(stream);
284 RootedObject reader(cx, ReadableStreamGetReader(
285 cx, stream, ReadableStreamReaderMode::Default));
286 CHECK(reader);
287
288 RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
289 CHECK(request);
290 CHECK(IsPromiseObject(request));
291 CHECK(GetPromiseState(request) == PromiseState::Pending);
292
293 bool locked;
294 CHECK(ReadableStreamIsLocked(cx, stream, &locked));
295 CHECK(locked);
296 bool readable;
297 CHECK(ReadableStreamIsReadable(cx, stream, &readable));
298 CHECK(readable);
299 RootedValue error(cx, Int32Value(42));
300 CHECK(ReadableStreamError(cx, stream, error));
301
302 CHECK(GetPromiseState(request) == PromiseState::Rejected);
303 RootedValue reason(cx, GetPromiseResult(request));
304 CHECK(reason.isInt32());
305 CHECK(reason.toInt32() == 42);
306
307 // The callbacks are only invoked for external streams.
308 CHECK(!StubExternalUnderlyingSource::instance.streamErroredCBCalled);
309
310 return true;
311 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamDefaultReaderError)312 END_FIXTURE_TEST(StreamTestFixture,
313 testReadableStream_ReadableStreamDefaultReaderError)
314
315 static JSObject* NewExternalSourceStream(
316 JSContext* cx, ReadableStreamUnderlyingSource* source) {
317 RootedObject stream(cx, NewReadableExternalSourceStreamObject(cx, source));
318 if (stream) {
319 MOZ_RELEASE_ASSERT(IsReadableStream(stream));
320 }
321 return stream;
322 }
323
NewExternalSourceStream(JSContext * cx)324 static JSObject* NewExternalSourceStream(JSContext* cx) {
325 return NewExternalSourceStream(cx, &StubExternalUnderlyingSource::instance);
326 }
327
BEGIN_FIXTURE_TEST(StreamTestFixture,testReadableStream_CreateReadableByteStreamWithExternalSource)328 BEGIN_FIXTURE_TEST(
329 StreamTestFixture,
330 testReadableStream_CreateReadableByteStreamWithExternalSource) {
331 StubExternalUnderlyingSource::instance.reset();
332
333 RootedObject stream(cx, NewExternalSourceStream(cx));
334 CHECK(stream);
335 ReadableStreamMode mode;
336 CHECK(ReadableStreamGetMode(cx, stream, &mode));
337 CHECK(mode == ReadableStreamMode::ExternalSource);
338 ReadableStreamUnderlyingSource* underlyingSource;
339 CHECK(
340 ReadableStreamGetExternalUnderlyingSource(cx, stream, &underlyingSource));
341 CHECK(underlyingSource == &StubExternalUnderlyingSource::instance);
342 bool locked;
343 CHECK(ReadableStreamIsLocked(cx, stream, &locked));
344 CHECK(locked);
345 CHECK(ReadableStreamReleaseExternalUnderlyingSource(cx, stream));
346
347 return true;
348 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_CreateReadableByteStreamWithExternalSource)349 END_FIXTURE_TEST(StreamTestFixture,
350 testReadableStream_CreateReadableByteStreamWithExternalSource)
351
352 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_ExternalSourceCancel) {
353 StubExternalUnderlyingSource::instance.reset();
354
355 RootedObject stream(cx, NewExternalSourceStream(cx));
356 CHECK(stream);
357 RootedValue reason(cx, Int32Value(42));
358 CHECK(ReadableStreamCancel(cx, stream, reason));
359 CHECK(StubExternalUnderlyingSource::instance.cancelStreamCBCalled);
360 CHECK(StubExternalUnderlyingSource::instance.cancelStreamReason == reason);
361
362 return true;
363 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ExternalSourceCancel)364 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ExternalSourceCancel)
365
366 BEGIN_FIXTURE_TEST(StreamTestFixture,
367 testReadableStream_ExternalSourceGetReader) {
368 StubExternalUnderlyingSource::instance.reset();
369
370 RootedObject stream(cx, NewExternalSourceStream(cx));
371 CHECK(stream);
372
373 RootedValue streamVal(cx, ObjectValue(*stream));
374 CHECK(JS_SetProperty(cx, global, "stream", streamVal));
375 RootedValue rval(cx);
376 EVAL("stream.getReader()", &rval);
377 CHECK(rval.isObject());
378 RootedObject reader(cx, &rval.toObject());
379 CHECK(IsReadableStreamDefaultReader(reader));
380
381 return true;
382 }
383 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ExternalSourceGetReader)
384
385 enum class CompartmentMode {
386 Same,
387 Cross,
388 };
389
390 struct ReadFromExternalSourceFixture : public StreamTestFixture {
~ReadFromExternalSourceFixtureReadFromExternalSourceFixture391 virtual ~ReadFromExternalSourceFixture() {}
392
393 // On success, streamGlobal is a global object (not a wrapper)
394 // and stream is in the same compartment as cx (it may be a CCW).
createExternalSourceStreamReadFromExternalSourceFixture395 bool createExternalSourceStream(CompartmentMode compartmentMode,
396 MutableHandleObject streamGlobal,
397 MutableHandleObject stream) {
398 if (compartmentMode == CompartmentMode::Same) {
399 streamGlobal.set(global);
400 stream.set(NewExternalSourceStream(cx));
401 if (!stream) {
402 return false;
403 }
404 } else {
405 RootedObject savedGlobal(cx, global);
406 streamGlobal.set(createGlobal());
407 if (!streamGlobal) {
408 return false;
409 }
410 global = savedGlobal;
411
412 {
413 JSAutoRealm ar(cx, streamGlobal);
414 stream.set(NewExternalSourceStream(cx));
415 if (!stream) {
416 return false;
417 }
418 }
419 if (!JS_WrapObject(cx, stream)) {
420 return false;
421 }
422 }
423 return true;
424 }
425
readWithoutDataAvailableReadFromExternalSourceFixture426 bool readWithoutDataAvailable(CompartmentMode compartmentMode,
427 const char* evalSrc, const char* evalSrc2,
428 uint32_t writtenLength) {
429 StubExternalUnderlyingSource::instance.reset();
430 definePrint();
431
432 // Create the stream.
433 RootedObject streamGlobal(cx);
434 RootedObject stream(cx); // can be a wrapper
435 CHECK(createExternalSourceStream(compartmentMode, &streamGlobal, &stream));
436 js::RunJobs(cx);
437
438 // GetExternalUnderlyingSource locks the stream.
439 ReadableStreamUnderlyingSource* underlyingSource;
440 CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream,
441 &underlyingSource));
442 CHECK(underlyingSource == &StubExternalUnderlyingSource::instance);
443 bool locked;
444 CHECK(ReadableStreamIsLocked(cx, stream, &locked));
445 CHECK(locked);
446 CHECK(ReadableStreamReleaseExternalUnderlyingSource(cx, stream));
447
448 // Run caller-supplied JS code to read from the stream.
449 RootedValue streamVal(cx, ObjectValue(*stream));
450 CHECK(JS_SetProperty(cx, global, "stream", streamVal));
451 RootedValue rval(cx);
452 EVAL(evalSrc, &rval);
453 CHECK(StubExternalUnderlyingSource::instance.dataRequestCBCalled);
454 CHECK(
455 !StubExternalUnderlyingSource::instance.writeIntoRequestBufferCBCalled);
456 CHECK(rval.isObject());
457 RootedObject unwrappedPromise(cx,
458 js::CheckedUnwrapStatic(&rval.toObject()));
459 CHECK(unwrappedPromise);
460 CHECK(IsPromiseObject(unwrappedPromise));
461 CHECK(GetPromiseState(unwrappedPromise) == PromiseState::Pending);
462
463 // Stream in some data; this resolves the read() result promise.
464 size_t length = sizeof(testBufferData);
465 CHECK(ReadableStreamUpdateDataAvailableFromSource(cx, stream, length));
466 CHECK(
467 StubExternalUnderlyingSource::instance.writeIntoRequestBufferCBCalled);
468 CHECK(GetPromiseState(unwrappedPromise) == PromiseState::Fulfilled);
469 RootedObject chunk(cx);
470 {
471 JSAutoRealm ar(cx, unwrappedPromise);
472 RootedValue iterVal(cx);
473 bool done;
474 if (!GetIterResult(cx, unwrappedPromise, &iterVal, &done)) {
475 return false;
476 }
477 CHECK(!done);
478 chunk = &iterVal.toObject();
479 }
480 CHECK(JS_WrapObject(cx, &chunk));
481 CHECK(JS_IsUint8Array(chunk));
482
483 {
484 JS::AutoCheckCannotGC noGC(cx);
485 bool dummy;
486 void* buffer = JS_GetArrayBufferViewData(chunk, &dummy, noGC);
487 CHECK(!memcmp(buffer, testBufferData, writtenLength));
488 }
489
490 // Check the callbacks fired by calling read() again.
491 StubExternalUnderlyingSource::instance.dataRequestCBCalled = false;
492 StubExternalUnderlyingSource::instance.writeIntoRequestBufferCBCalled =
493 false;
494 EVAL(evalSrc2, &rval);
495 CHECK(StubExternalUnderlyingSource::instance.dataRequestCBCalled);
496 CHECK(
497 !StubExternalUnderlyingSource::instance.writeIntoRequestBufferCBCalled);
498
499 return true;
500 }
501
readWithDataAvailableReadFromExternalSourceFixture502 bool readWithDataAvailable(CompartmentMode compartmentMode,
503 const char* evalSrc, uint32_t writtenLength) {
504 StubExternalUnderlyingSource::instance.reset();
505 definePrint();
506
507 // Create a stream.
508 RootedObject streamGlobal(cx);
509 RootedObject stream(cx);
510 CHECK(createExternalSourceStream(compartmentMode, &streamGlobal, &stream));
511
512 // Getting the underlying source locks the stream.
513 ReadableStreamUnderlyingSource* underlyingSource;
514 CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream,
515 &underlyingSource));
516 CHECK(underlyingSource == &StubExternalUnderlyingSource::instance);
517 bool locked;
518 CHECK(ReadableStreamIsLocked(cx, stream, &locked));
519 CHECK(locked);
520 CHECK(ReadableStreamReleaseExternalUnderlyingSource(cx, stream));
521
522 // Make some data available.
523 size_t length = sizeof(testBufferData);
524 CHECK(ReadableStreamUpdateDataAvailableFromSource(cx, stream, length));
525
526 // Read from the stream.
527 RootedValue streamVal(cx, ObjectValue(*stream));
528 CHECK(JS_SetProperty(cx, global, "stream", streamVal));
529 RootedValue rval(cx);
530 EVAL(evalSrc, &rval);
531 CHECK(
532 StubExternalUnderlyingSource::instance.writeIntoRequestBufferCBCalled);
533 CHECK(rval.isObject());
534 RootedObject unwrappedPromise(cx,
535 js::CheckedUnwrapStatic(&rval.toObject()));
536 CHECK(unwrappedPromise);
537 CHECK(IsPromiseObject(unwrappedPromise));
538 CHECK(GetPromiseState(unwrappedPromise) == PromiseState::Fulfilled);
539 RootedObject chunk(cx);
540 {
541 JSAutoRealm ar(cx, unwrappedPromise);
542 RootedValue iterVal(cx);
543 bool done;
544 if (!GetIterResult(cx, unwrappedPromise, &iterVal, &done)) {
545 return false;
546 }
547 CHECK(!done);
548 chunk = &iterVal.toObject();
549 }
550 CHECK(JS_WrapObject(cx, &chunk));
551 CHECK(JS_IsUint8Array(chunk));
552
553 {
554 JS::AutoCheckCannotGC noGC(cx);
555 bool dummy;
556 void* buffer = JS_GetArrayBufferViewData(chunk, &dummy, noGC);
557 CHECK(!memcmp(buffer, testBufferData, writtenLength));
558 }
559
560 return true;
561 }
562 };
563
BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable)564 BEGIN_FIXTURE_TEST(
565 ReadFromExternalSourceFixture,
566 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable) {
567 return readWithoutDataAvailable(CompartmentMode::Same,
568 "r = stream.getReader(); r.read()",
569 "r.read()", sizeof(testBufferData));
570 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable)571 END_FIXTURE_TEST(
572 ReadFromExternalSourceFixture,
573 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable)
574
575 BEGIN_FIXTURE_TEST(
576 ReadFromExternalSourceFixture,
577 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment1) {
578 // Scenario 1: The stream and reader are both in the same compartment, but
579 // ReadableStreamUpdateDataAvailableFromSource is applied to a wrapper.
580 return readWithoutDataAvailable(CompartmentMode::Cross,
581 "r = stream.getReader(); r.read()",
582 "r.read()", sizeof(testBufferData));
583 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment1)584 END_FIXTURE_TEST(
585 ReadFromExternalSourceFixture,
586 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment1)
587
588 BEGIN_FIXTURE_TEST(
589 ReadFromExternalSourceFixture,
590 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment2) {
591 // Scenario 2: The stream and reader are in the same compartment, but a
592 // `read` method from another compartment is used on the reader.
593 return readWithoutDataAvailable(
594 CompartmentMode::Cross,
595 "r = stream.getReader(); read = new "
596 "ReadableStream({start(){}}).getReader().read; read.call(r)",
597 "read.call(r)", sizeof(testBufferData));
598 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment2)599 END_FIXTURE_TEST(
600 ReadFromExternalSourceFixture,
601 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment2)
602
603 BEGIN_FIXTURE_TEST(
604 ReadFromExternalSourceFixture,
605 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment3) {
606 // Scenario 3: The stream and reader are in different compartments.
607 return readWithoutDataAvailable(
608 CompartmentMode::Cross,
609 "r = ReadableStream.prototype.getReader.call(stream); r.read()",
610 "r.read()", sizeof(testBufferData));
611 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment3)612 END_FIXTURE_TEST(
613 ReadFromExternalSourceFixture,
614 testReadableStream_ExternalSourceReadDefaultWithoutDataAvailable_CrossCompartment3)
615
616 BEGIN_FIXTURE_TEST(ReadFromExternalSourceFixture,
617 testReadableStream_ExternalSourceCloseWithPendingRead) {
618 CHECK(readWithoutDataAvailable(CompartmentMode::Same,
619 "r = stream.getReader(); request0 = r.read(); "
620 "request1 = r.read(); request0",
621 "r.read()", sizeof(testBufferData)));
622
623 RootedValue val(cx);
624 CHECK(JS_GetProperty(cx, global, "request1", &val));
625 CHECK(val.isObject());
626 RootedObject request(cx, &val.toObject());
627 CHECK(IsPromiseObject(request));
628 CHECK(GetPromiseState(request) == PromiseState::Pending);
629
630 CHECK(JS_GetProperty(cx, global, "stream", &val));
631 RootedObject stream(cx, &val.toObject());
632 ReadableStreamClose(cx, stream);
633
634 val = GetPromiseResult(request);
635 CHECK(val.isObject());
636 RootedObject result(cx, &val.toObject());
637
638 JS_GetProperty(cx, result, "done", &val);
639 CHECK(val.isBoolean());
640 CHECK(val.toBoolean() == true);
641
642 JS_GetProperty(cx, result, "value", &val);
643 CHECK(val.isUndefined());
644 return true;
645 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceCloseWithPendingRead)646 END_FIXTURE_TEST(ReadFromExternalSourceFixture,
647 testReadableStream_ExternalSourceCloseWithPendingRead)
648
649 BEGIN_FIXTURE_TEST(
650 ReadFromExternalSourceFixture,
651 testReadableStream_ExternalSourceReadDefaultWithDataAvailable) {
652 return readWithDataAvailable(CompartmentMode::Same,
653 "r = stream.getReader(); r.read()",
654 sizeof(testBufferData));
655 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithDataAvailable)656 END_FIXTURE_TEST(ReadFromExternalSourceFixture,
657 testReadableStream_ExternalSourceReadDefaultWithDataAvailable)
658
659 BEGIN_FIXTURE_TEST(
660 ReadFromExternalSourceFixture,
661 testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment1) {
662 // Scenario 1: The stream and reader are both in the same compartment, but
663 // ReadableStreamUpdateDataAvailableFromSource is applied to a wrapper.
664 return readWithDataAvailable(CompartmentMode::Cross,
665 "r = stream.getReader(); r.read()",
666 sizeof(testBufferData));
667 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment1)668 END_FIXTURE_TEST(
669 ReadFromExternalSourceFixture,
670 testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment1)
671
672 BEGIN_FIXTURE_TEST(
673 ReadFromExternalSourceFixture,
674 testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment2) {
675 // Scenario 2: The stream and reader are in the same compartment, but a
676 // `read` method from another compartment is used on the reader.
677 return readWithDataAvailable(
678 CompartmentMode::Cross,
679 "r = stream.getReader(); read = new "
680 "ReadableStream({start(){}}).getReader().read; read.call(r)",
681 sizeof(testBufferData));
682 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment2)683 END_FIXTURE_TEST(
684 ReadFromExternalSourceFixture,
685 testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment2)
686
687 BEGIN_FIXTURE_TEST(
688 ReadFromExternalSourceFixture,
689 testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment3) {
690 // Scenario 3: The stream and reader are in different compartments.
691 return readWithDataAvailable(
692 CompartmentMode::Cross,
693 "r = ReadableStream.prototype.getReader.call(stream); r.read()",
694 sizeof(testBufferData));
695 }
END_FIXTURE_TEST(ReadFromExternalSourceFixture,testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment3)696 END_FIXTURE_TEST(
697 ReadFromExternalSourceFixture,
698 testReadableStream_ExternalSourceReadDefaultWithDataAvailable_CrossCompartment3)
699
700 // Cross-global tests:
701 BEGIN_FIXTURE_TEST(
702 StreamTestFixture,
703 testReadableStream_ReadableStreamOtherGlobalDefaultReaderRead) {
704 RootedObject stream(cx, NewDefaultStream(cx));
705 CHECK(stream);
706 RootedObject otherGlobal(cx, createGlobal());
707 CHECK(otherGlobal);
708
709 {
710 JSAutoRealm ar(cx, otherGlobal);
711 CHECK(JS_WrapObject(cx, &stream));
712 RootedObject reader(cx, ReadableStreamGetReader(
713 cx, stream, ReadableStreamReaderMode::Default));
714 CHECK(reader);
715
716 RootedObject request(cx, ReadableStreamDefaultReaderRead(cx, reader));
717 CHECK(request);
718 CHECK(IsPromiseObject(request));
719 CHECK(!js::IsWrapper(request));
720 CHECK(GetPromiseState(request) == PromiseState::Pending);
721
722 RootedObject chunk(cx, JS_NewPlainObject(cx));
723 CHECK(chunk);
724 RootedValue chunkVal(cx, ObjectValue(*chunk));
725 CHECK(ReadableStreamEnqueue(cx, stream, chunkVal));
726
727 CHECK(GetReadChunk(cx, request) == chunk);
728 }
729
730 return true;
731 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamOtherGlobalDefaultReaderRead)732 END_FIXTURE_TEST(StreamTestFixture,
733 testReadableStream_ReadableStreamOtherGlobalDefaultReaderRead)
734
735 BEGIN_FIXTURE_TEST(
736 StreamTestFixture,
737 testReadableStream_ReadableStreamGetExternalUnderlyingSource) {
738 StubExternalUnderlyingSource::instance.reset();
739
740 RootedObject stream(cx, NewExternalSourceStream(cx));
741 CHECK(stream);
742 ReadableStreamUnderlyingSource* source;
743 CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream, &source));
744 CHECK(source == &StubExternalUnderlyingSource::instance);
745 CHECK(ReadableStreamReleaseExternalUnderlyingSource(cx, stream));
746
747 RootedObject otherGlobal(cx, createGlobal());
748 CHECK(otherGlobal);
749 {
750 JSAutoRealm ar(cx, otherGlobal);
751 CHECK(JS_WrapObject(cx, &stream));
752 ReadableStreamUnderlyingSource* source;
753 CHECK(ReadableStreamGetExternalUnderlyingSource(cx, stream, &source));
754 CHECK(source == &StubExternalUnderlyingSource::instance);
755 CHECK(ReadableStreamReleaseExternalUnderlyingSource(cx, stream));
756 }
757
758 return true;
759 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamGetExternalUnderlyingSource)760 END_FIXTURE_TEST(StreamTestFixture,
761 testReadableStream_ReadableStreamGetExternalUnderlyingSource)
762
763 BEGIN_FIXTURE_TEST(
764 StreamTestFixture,
765 testReadableStream_ReadableStreamUpdateDataAvailableFromSource) {
766 RootedObject stream(cx, NewExternalSourceStream(cx));
767 CHECK(stream);
768 CHECK(ReadableStreamUpdateDataAvailableFromSource(cx, stream, 0));
769
770 RootedObject otherGlobal(cx, createGlobal());
771 CHECK(otherGlobal);
772 {
773 JSAutoRealm ar(cx, otherGlobal);
774 CHECK(JS_WrapObject(cx, &stream));
775 CHECK(ReadableStreamUpdateDataAvailableFromSource(cx, stream, 1));
776 }
777
778 return true;
779 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamUpdateDataAvailableFromSource)780 END_FIXTURE_TEST(StreamTestFixture,
781 testReadableStream_ReadableStreamUpdateDataAvailableFromSource)
782
783 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_IsReadableStream) {
784 RootedObject stream(cx, NewDefaultStream(cx));
785 CHECK(stream);
786 CHECK(IsReadableStream(stream));
787
788 RootedObject otherGlobal(cx, createGlobal());
789 CHECK(otherGlobal);
790 {
791 JSAutoRealm ar(cx, otherGlobal);
792 CHECK(JS_WrapObject(cx, &stream));
793 CHECK(IsReadableStream(stream));
794 }
795
796 return true;
797 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_IsReadableStream)798 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_IsReadableStream)
799
800 BEGIN_FIXTURE_TEST(StreamTestFixture,
801 testReadableStream_ReadableStreamGetMode) {
802 RootedObject stream(cx, NewDefaultStream(cx));
803 CHECK(stream);
804 ReadableStreamMode mode;
805 CHECK(ReadableStreamGetMode(cx, stream, &mode));
806 CHECK(mode == ReadableStreamMode::Default);
807
808 RootedObject otherGlobal(cx, createGlobal());
809 CHECK(otherGlobal);
810 {
811 JSAutoRealm ar(cx, otherGlobal);
812 CHECK(JS_WrapObject(cx, &stream));
813 CHECK(ReadableStreamGetMode(cx, stream, &mode));
814 CHECK(mode == ReadableStreamMode::Default);
815 }
816
817 return true;
818 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamGetMode)819 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamGetMode)
820
821 BEGIN_FIXTURE_TEST(StreamTestFixture,
822 testReadableStream_ReadableStreamIsReadable) {
823 RootedObject stream(cx, NewDefaultStream(cx));
824 CHECK(stream);
825 bool result;
826 CHECK(ReadableStreamIsReadable(cx, stream, &result));
827 CHECK(result);
828
829 RootedObject otherGlobal(cx, createGlobal());
830 CHECK(otherGlobal);
831 {
832 JSAutoRealm ar(cx, otherGlobal);
833 CHECK(JS_WrapObject(cx, &stream));
834 CHECK(ReadableStreamIsReadable(cx, stream, &result));
835 CHECK(result);
836 }
837
838 return true;
839 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamIsReadable)840 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamIsReadable)
841
842 BEGIN_FIXTURE_TEST(StreamTestFixture,
843 testReadableStream_ReadableStreamIsLocked) {
844 RootedObject stream(cx, NewDefaultStream(cx));
845 CHECK(stream);
846 bool result;
847 CHECK(ReadableStreamIsLocked(cx, stream, &result));
848 CHECK_EQUAL(result, false);
849
850 RootedObject otherGlobal(cx, createGlobal());
851 CHECK(otherGlobal);
852 {
853 JSAutoRealm ar(cx, otherGlobal);
854 CHECK(JS_WrapObject(cx, &stream));
855 CHECK(ReadableStreamIsLocked(cx, stream, &result));
856 CHECK_EQUAL(result, false);
857 }
858
859 return true;
860 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamIsLocked)861 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamIsLocked)
862
863 BEGIN_FIXTURE_TEST(StreamTestFixture,
864 testReadableStream_ReadableStreamIsDisturbed) {
865 RootedObject stream(cx, NewDefaultStream(cx));
866 CHECK(stream);
867 bool result;
868 CHECK(ReadableStreamIsDisturbed(cx, stream, &result));
869 CHECK_EQUAL(result, false);
870
871 RootedObject otherGlobal(cx, createGlobal());
872 CHECK(otherGlobal);
873 {
874 JSAutoRealm ar(cx, otherGlobal);
875 CHECK(JS_WrapObject(cx, &stream));
876 CHECK(ReadableStreamIsDisturbed(cx, stream, &result));
877 CHECK_EQUAL(result, false);
878 }
879
880 return true;
881 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamIsDisturbed)882 END_FIXTURE_TEST(StreamTestFixture,
883 testReadableStream_ReadableStreamIsDisturbed)
884
885 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamCancel) {
886 RootedObject stream(cx, NewDefaultStream(cx));
887 CHECK(stream);
888
889 RootedValue reason(cx);
890 JSObject* callResult = ReadableStreamCancel(cx, stream, reason);
891 CHECK(callResult);
892
893 RootedObject otherGlobal(cx, createGlobal());
894 CHECK(otherGlobal);
895 {
896 JSAutoRealm ar(cx, otherGlobal);
897 CHECK(JS_WrapObject(cx, &stream));
898 RootedValue reason(cx);
899 JSObject* callResult = ReadableStreamCancel(cx, stream, reason);
900 CHECK(callResult);
901 }
902
903 return true;
904 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamCancel)905 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamCancel)
906
907 BEGIN_FIXTURE_TEST(StreamTestFixture,
908 testReadableStream_ReadableStreamGetReader) {
909 RootedObject stream(cx, NewDefaultStream(cx));
910 CHECK(stream);
911
912 RootedObject reader(cx);
913 reader =
914 ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default);
915 CHECK(reader);
916 CHECK(IsReadableStreamDefaultReader(reader));
917 CHECK(ReadableStreamReaderReleaseLock(cx, reader));
918
919 RootedObject otherGlobal(cx, createGlobal());
920 CHECK(otherGlobal);
921 {
922 JSAutoRealm ar(cx, otherGlobal);
923 CHECK(JS_WrapObject(cx, &stream));
924 JSObject* callResult =
925 ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default);
926 CHECK(callResult);
927 }
928
929 return true;
930 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamGetReader)931 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamGetReader)
932
933 BEGIN_FIXTURE_TEST(StreamTestFixture,
934 testReadableStream_ReadableStreamTee_CrossCompartment) {
935 RootedObject stream(cx, NewDefaultStream(cx));
936 CHECK(stream);
937
938 RootedObject branch1Stream(cx);
939 RootedObject branch2Stream(cx);
940 CHECK(ReadableStreamTee(cx, stream, &branch1Stream, &branch2Stream));
941 CHECK(IsReadableStream(branch1Stream));
942 CHECK(IsReadableStream(branch2Stream));
943 stream = branch1Stream;
944
945 RootedObject otherGlobal(cx, createGlobal());
946 CHECK(otherGlobal);
947 {
948 JSAutoRealm ar(cx, otherGlobal);
949 CHECK(JS_WrapObject(cx, &stream));
950 CHECK(ReadableStreamTee(cx, stream, &branch1Stream, &branch2Stream));
951 CHECK(IsReadableStream(branch1Stream));
952 CHECK(IsReadableStream(branch2Stream));
953 }
954
955 return true;
956 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamTee_CrossCompartment)957 END_FIXTURE_TEST(StreamTestFixture,
958 testReadableStream_ReadableStreamTee_CrossCompartment)
959
960 BEGIN_FIXTURE_TEST(StreamTestFixture,
961 testReadableStream_ReadableStreamGetDesiredSize) {
962 RootedObject stream(cx, NewDefaultStream(cx));
963 CHECK(stream);
964 bool hasValue;
965 double value;
966 CHECK(ReadableStreamGetDesiredSize(cx, stream, &hasValue, &value));
967 CHECK_EQUAL(hasValue, true);
968 CHECK_EQUAL(value, 1.0);
969
970 RootedObject otherGlobal(cx, createGlobal());
971 CHECK(otherGlobal);
972 {
973 JSAutoRealm ar(cx, otherGlobal);
974 CHECK(JS_WrapObject(cx, &stream));
975 hasValue = false;
976 value = 0;
977 CHECK(ReadableStreamGetDesiredSize(cx, stream, &hasValue, &value));
978 CHECK_EQUAL(hasValue, true);
979 CHECK_EQUAL(value, 1.0);
980 }
981
982 return true;
983 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamGetDesiredSize)984 END_FIXTURE_TEST(StreamTestFixture,
985 testReadableStream_ReadableStreamGetDesiredSize)
986
987 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamClose) {
988 RootedObject stream(cx, NewDefaultStream(cx));
989 CHECK(stream);
990 CHECK(ReadableStreamClose(cx, stream));
991
992 stream = NewDefaultStream(cx);
993 CHECK(stream);
994 RootedObject otherGlobal(cx, createGlobal());
995 CHECK(otherGlobal);
996 {
997 JSAutoRealm ar(cx, otherGlobal);
998 CHECK(JS_WrapObject(cx, &stream));
999 CHECK(ReadableStreamClose(cx, stream));
1000 }
1001
1002 return true;
1003 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamClose)1004 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamClose)
1005
1006 BEGIN_FIXTURE_TEST(StreamTestFixture,
1007 testReadableStream_ReadableStreamEnqueue_CrossCompartment) {
1008 RootedObject stream(cx, NewDefaultStream(cx));
1009 CHECK(stream);
1010 RootedValue chunk(cx);
1011 CHECK(ReadableStreamEnqueue(cx, stream, chunk));
1012
1013 RootedObject otherGlobal(cx, createGlobal());
1014 CHECK(otherGlobal);
1015 {
1016 JSAutoRealm ar(cx, otherGlobal);
1017 CHECK(JS_WrapObject(cx, &stream));
1018 RootedValue chunk(cx);
1019 CHECK(ReadableStreamEnqueue(cx, stream, chunk));
1020 }
1021
1022 return true;
1023 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamEnqueue_CrossCompartment)1024 END_FIXTURE_TEST(StreamTestFixture,
1025 testReadableStream_ReadableStreamEnqueue_CrossCompartment)
1026
1027 BEGIN_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamError) {
1028 RootedObject stream(cx, NewDefaultStream(cx));
1029 CHECK(stream);
1030 RootedValue error(cx);
1031 CHECK(ReadableStreamError(cx, stream, error));
1032
1033 stream = NewDefaultStream(cx);
1034 RootedObject otherGlobal(cx, createGlobal());
1035 CHECK(otherGlobal);
1036 {
1037 JSAutoRealm ar(cx, otherGlobal);
1038 CHECK(JS_WrapObject(cx, &stream));
1039 RootedValue error(cx);
1040 CHECK(ReadableStreamError(cx, stream, error));
1041 }
1042
1043 return true;
1044 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamError)1045 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_ReadableStreamError)
1046
1047 BEGIN_FIXTURE_TEST(StreamTestFixture,
1048 testReadableStream_IsReadableStreamReader) {
1049 RootedObject stream(cx, NewDefaultStream(cx));
1050 CHECK(stream);
1051 RootedObject reader(cx, ReadableStreamGetReader(
1052 cx, stream, ReadableStreamReaderMode::Default));
1053 CHECK(reader);
1054 CHECK(IsReadableStreamReader(reader));
1055
1056 RootedObject otherGlobal(cx, createGlobal());
1057 CHECK(otherGlobal);
1058 {
1059 JSAutoRealm ar(cx, otherGlobal);
1060 CHECK(JS_WrapObject(cx, &reader));
1061 CHECK(IsReadableStreamReader(reader));
1062 }
1063
1064 return true;
1065 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_IsReadableStreamReader)1066 END_FIXTURE_TEST(StreamTestFixture, testReadableStream_IsReadableStreamReader)
1067
1068 BEGIN_FIXTURE_TEST(StreamTestFixture,
1069 testReadableStream_IsReadableStreamDefaultReader) {
1070 RootedObject stream(cx, NewDefaultStream(cx));
1071 CHECK(stream);
1072 RootedObject reader(cx, ReadableStreamGetReader(
1073 cx, stream, ReadableStreamReaderMode::Default));
1074 CHECK(IsReadableStreamDefaultReader(reader));
1075
1076 RootedObject otherGlobal(cx, createGlobal());
1077 CHECK(otherGlobal);
1078 {
1079 JSAutoRealm ar(cx, otherGlobal);
1080 CHECK(JS_WrapObject(cx, &reader));
1081 CHECK(IsReadableStreamDefaultReader(reader));
1082 }
1083
1084 return true;
1085 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_IsReadableStreamDefaultReader)1086 END_FIXTURE_TEST(StreamTestFixture,
1087 testReadableStream_IsReadableStreamDefaultReader)
1088
1089 BEGIN_FIXTURE_TEST(StreamTestFixture,
1090 testReadableStream_ReadableStreamReaderIsClosed) {
1091 RootedObject stream(cx, NewDefaultStream(cx));
1092 CHECK(stream);
1093
1094 RootedObject reader(cx, ReadableStreamGetReader(
1095 cx, stream, ReadableStreamReaderMode::Default));
1096 bool result;
1097 CHECK(ReadableStreamReaderIsClosed(cx, reader, &result));
1098 CHECK_EQUAL(result, false);
1099
1100 RootedObject otherGlobal(cx, createGlobal());
1101 CHECK(otherGlobal);
1102 {
1103 JSAutoRealm ar(cx, otherGlobal);
1104 CHECK(JS_WrapObject(cx, &reader));
1105 bool result;
1106 CHECK(ReadableStreamReaderIsClosed(cx, reader, &result));
1107 }
1108
1109 return true;
1110 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamReaderIsClosed)1111 END_FIXTURE_TEST(StreamTestFixture,
1112 testReadableStream_ReadableStreamReaderIsClosed)
1113
1114 BEGIN_FIXTURE_TEST(StreamTestFixture,
1115 testReadableStream_ReadableStreamReaderCancel) {
1116 RootedObject stream(cx, NewDefaultStream(cx));
1117 CHECK(stream);
1118 RootedObject reader(cx, ReadableStreamGetReader(
1119 cx, stream, ReadableStreamReaderMode::Default));
1120 RootedValue reason(cx);
1121 CHECK(ReadableStreamReaderCancel(cx, reader, reason));
1122
1123 RootedObject otherGlobal(cx, createGlobal());
1124 CHECK(otherGlobal);
1125 {
1126 JSAutoRealm ar(cx, otherGlobal);
1127 CHECK(JS_WrapObject(cx, &reader));
1128 RootedValue reason(cx);
1129 CHECK(ReadableStreamReaderCancel(cx, reader, reason));
1130 }
1131
1132 return true;
1133 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamReaderCancel)1134 END_FIXTURE_TEST(StreamTestFixture,
1135 testReadableStream_ReadableStreamReaderCancel)
1136
1137 BEGIN_FIXTURE_TEST(StreamTestFixture,
1138 testReadableStream_ReadableStreamReaderReleaseLock) {
1139 RootedObject stream(cx, NewDefaultStream(cx));
1140 CHECK(stream);
1141 RootedObject reader(cx, ReadableStreamGetReader(
1142 cx, stream, ReadableStreamReaderMode::Default));
1143 CHECK(reader);
1144 CHECK(ReadableStreamReaderReleaseLock(cx, reader));
1145
1146 // Repeat the test cross-compartment. This creates a new reader, since
1147 // releasing the lock above deactivated the first reader.
1148 reader =
1149 ReadableStreamGetReader(cx, stream, ReadableStreamReaderMode::Default);
1150 CHECK(reader);
1151 RootedObject otherGlobal(cx, createGlobal());
1152 CHECK(otherGlobal);
1153 {
1154 JSAutoRealm ar(cx, otherGlobal);
1155 CHECK(JS_WrapObject(cx, &reader));
1156 CHECK(ReadableStreamReaderReleaseLock(cx, reader));
1157 }
1158
1159 return true;
1160 }
END_FIXTURE_TEST(StreamTestFixture,testReadableStream_ReadableStreamReaderReleaseLock)1161 END_FIXTURE_TEST(StreamTestFixture,
1162 testReadableStream_ReadableStreamReaderReleaseLock)
1163
1164 BEGIN_FIXTURE_TEST(
1165 StreamTestFixture,
1166 testReadableStream_ReadableStreamDefaultReaderRead_CrossCompartment) {
1167 RootedObject stream(cx, NewDefaultStream(cx));
1168 CHECK(stream);
1169 RootedObject reader(cx, ReadableStreamGetReader(
1170 cx, stream, ReadableStreamReaderMode::Default));
1171 JSObject* callResult = ReadableStreamDefaultReaderRead(cx, reader);
1172 CHECK(callResult);
1173
1174 RootedObject otherGlobal(cx, createGlobal());
1175 CHECK(otherGlobal);
1176 {
1177 JSAutoRealm ar(cx, otherGlobal);
1178 CHECK(JS_WrapObject(cx, &reader));
1179 JSObject* callResult = ReadableStreamDefaultReaderRead(cx, reader);
1180 CHECK(callResult);
1181 }
1182
1183 return true;
1184 }
1185 END_FIXTURE_TEST(
1186 StreamTestFixture,
1187 testReadableStream_ReadableStreamDefaultReaderRead_CrossCompartment)
1188