1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/streams/ReadableStream.h"
8 #include "bindings/core/v8/ExceptionState.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h"
10 #include "bindings/core/v8/ScriptState.h"
11 #include "bindings/core/v8/V8Binding.h"
12 #include "core/dom/DOMArrayBuffer.h"
13 #include "core/dom/DOMException.h"
14 #include "core/dom/Document.h"
15 #include "core/dom/ExceptionCode.h"
16 #include "core/streams/ReadableStreamImpl.h"
17 #include "core/streams/UnderlyingSource.h"
18 #include "core/testing/DummyPageHolder.h"
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
25 using ::testing::InSequence;
26 using ::testing::Invoke;
27 using ::testing::Return;
31 typedef ::testing::StrictMock<::testing::MockFunction<void(int)> > Checkpoint;
32 typedef ReadableStreamImpl<ReadableStreamChunkTypeTraits<String> > StringStream;
34 class StringCapturingFunction : public ScriptFunction {
36 static v8::Handle<v8::Function> createFunction(ScriptState* scriptState, String* value)
38 StringCapturingFunction* self = new StringCapturingFunction(scriptState, value);
39 return self->bindToV8Function();
43 StringCapturingFunction(ScriptState* scriptState, String* value)
44 : ScriptFunction(scriptState)
49 virtual ScriptValue call(ScriptValue value) override
51 ASSERT(!value.isEmpty());
52 *m_value = toCoreString(value.v8Value()->ToString());
59 class MockUnderlyingSource : public GarbageCollectedFinalized<MockUnderlyingSource>, public UnderlyingSource {
60 USING_GARBAGE_COLLECTED_MIXIN(MockUnderlyingSource);
62 virtual ~MockUnderlyingSource() { }
64 MOCK_METHOD0(pullSource, void());
65 MOCK_METHOD2(cancelSource, ScriptPromise(ScriptState*, ScriptValue));
70 explicit ThrowError(const String& message)
71 : m_message(message) { }
73 void operator()(ExceptionState* exceptionState)
75 exceptionState->throwTypeError(m_message);
82 } // unnamed namespace
84 class ReadableStreamTest : public ::testing::Test {
87 : m_page(DummyPageHolder::create(IntSize(1, 1)))
88 , m_scope(scriptState())
89 , m_underlyingSource(new ::testing::StrictMock<MockUnderlyingSource>)
90 , m_exceptionState(ExceptionState::ConstructionContext, "property", "interface", scriptState()->context()->Global(), isolate())
94 virtual ~ReadableStreamTest()
98 ScriptState* scriptState() { return ScriptState::forMainWorld(m_page->document().frame()); }
99 v8::Isolate* isolate() { return scriptState()->isolate(); }
101 v8::Handle<v8::Function> createCaptor(String* value)
103 return StringCapturingFunction::createFunction(scriptState(), value);
106 StringStream* construct()
108 StringStream* stream = new StringStream(scriptState()->executionContext(), m_underlyingSource);
109 stream->didSourceStart();
113 OwnPtr<DummyPageHolder> m_page;
114 ScriptState::Scope m_scope;
115 Persistent<MockUnderlyingSource> m_underlyingSource;
116 ExceptionState m_exceptionState;
119 TEST_F(ReadableStreamTest, Start)
121 StringStream* stream = new StringStream(scriptState()->executionContext(), m_underlyingSource);
122 EXPECT_FALSE(m_exceptionState.hadException());
123 EXPECT_FALSE(stream->isStarted());
124 EXPECT_FALSE(stream->isDraining());
125 EXPECT_FALSE(stream->isPulling());
126 EXPECT_EQ(stream->state(), ReadableStream::Waiting);
128 stream->didSourceStart();
130 EXPECT_TRUE(stream->isStarted());
131 EXPECT_FALSE(stream->isDraining());
132 EXPECT_FALSE(stream->isPulling());
133 EXPECT_EQ(stream->state(), ReadableStream::Waiting);
136 TEST_F(ReadableStreamTest, StartFail)
138 StringStream* stream = new StringStream(scriptState()->executionContext(), m_underlyingSource);
139 EXPECT_FALSE(m_exceptionState.hadException());
140 EXPECT_FALSE(stream->isStarted());
141 EXPECT_FALSE(stream->isDraining());
142 EXPECT_FALSE(stream->isPulling());
143 EXPECT_EQ(stream->state(), ReadableStream::Waiting);
145 stream->error(DOMException::create(NotFoundError));
147 EXPECT_FALSE(stream->isStarted());
148 EXPECT_FALSE(stream->isDraining());
149 EXPECT_FALSE(stream->isPulling());
150 EXPECT_EQ(stream->state(), ReadableStream::Errored);
153 TEST_F(ReadableStreamTest, WaitOnWaiting)
155 StringStream* stream = construct();
156 Checkpoint checkpoint;
158 EXPECT_EQ(ReadableStream::Waiting, stream->state());
159 EXPECT_TRUE(stream->isStarted());
160 EXPECT_FALSE(stream->isPulling());
164 EXPECT_CALL(checkpoint, Call(0));
165 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
166 EXPECT_CALL(checkpoint, Call(1));
170 ScriptPromise p = stream->wait(scriptState());
171 ScriptPromise q = stream->wait(scriptState());
174 EXPECT_EQ(ReadableStream::Waiting, stream->state());
175 EXPECT_TRUE(stream->isPulling());
179 TEST_F(ReadableStreamTest, WaitDuringStarting)
181 StringStream* stream = new StringStream(scriptState()->executionContext(), m_underlyingSource);
182 Checkpoint checkpoint;
184 EXPECT_EQ(ReadableStream::Waiting, stream->state());
185 EXPECT_FALSE(stream->isStarted());
186 EXPECT_FALSE(stream->isPulling());
190 EXPECT_CALL(checkpoint, Call(0));
191 EXPECT_CALL(checkpoint, Call(1));
192 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
196 stream->wait(scriptState());
199 EXPECT_TRUE(stream->isPulling());
201 stream->didSourceStart();
203 EXPECT_EQ(ReadableStream::Waiting, stream->state());
204 EXPECT_TRUE(stream->isPulling());
207 TEST_F(ReadableStreamTest, WaitAndError)
209 StringStream* stream = construct();
210 String onFulfilled, onRejected;
214 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
217 ScriptPromise promise = stream->wait(scriptState());
218 promise.then(createCaptor(&onFulfilled), createCaptor(&onRejected));
219 EXPECT_EQ(ReadableStream::Waiting, stream->state());
220 EXPECT_TRUE(stream->isPulling());
221 stream->error(DOMException::create(NotFoundError, "hello, error"));
222 EXPECT_EQ(ReadableStream::Errored, stream->state());
223 EXPECT_TRUE(stream->isPulling());
224 EXPECT_TRUE(onFulfilled.isNull());
225 EXPECT_TRUE(onRejected.isNull());
227 isolate()->RunMicrotasks();
228 EXPECT_TRUE(onFulfilled.isNull());
229 EXPECT_EQ(promise, stream->wait(scriptState()));
230 EXPECT_EQ("NotFoundError: hello, error", onRejected);
233 TEST_F(ReadableStreamTest, ErrorAndEnqueue)
235 StringStream* stream = construct();
237 stream->error(DOMException::create(NotFoundError, "error"));
238 EXPECT_EQ(ReadableStream::Errored, stream->state());
240 bool result = stream->enqueue("hello");
241 EXPECT_FALSE(result);
242 EXPECT_EQ(ReadableStream::Errored, stream->state());
245 TEST_F(ReadableStreamTest, CloseAndEnqueue)
247 StringStream* stream = construct();
250 EXPECT_EQ(ReadableStream::Closed, stream->state());
252 bool result = stream->enqueue("hello");
253 EXPECT_FALSE(result);
254 EXPECT_EQ(ReadableStream::Closed, stream->state());
257 TEST_F(ReadableStreamTest, EnqueueAndWait)
259 StringStream* stream = construct();
260 String onFulfilled, onRejected;
261 EXPECT_EQ(ReadableStream::Waiting, stream->state());
263 bool result = stream->enqueue("hello");
265 EXPECT_EQ(ReadableStream::Readable, stream->state());
267 stream->wait(scriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected));
268 EXPECT_EQ(ReadableStream::Readable, stream->state());
269 EXPECT_FALSE(stream->isPulling());
270 EXPECT_TRUE(onFulfilled.isNull());
271 EXPECT_TRUE(onRejected.isNull());
273 isolate()->RunMicrotasks();
274 EXPECT_EQ(ReadableStream::Readable, stream->state());
275 EXPECT_FALSE(stream->isPulling());
276 EXPECT_EQ("undefined", onFulfilled);
277 EXPECT_TRUE(onRejected.isNull());
280 TEST_F(ReadableStreamTest, WaitAndEnqueue)
282 StringStream* stream = construct();
283 String onFulfilled, onRejected;
284 EXPECT_EQ(ReadableStream::Waiting, stream->state());
288 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
291 stream->wait(scriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected));
292 isolate()->RunMicrotasks();
294 EXPECT_EQ(ReadableStream::Waiting, stream->state());
295 EXPECT_TRUE(stream->isPulling());
296 EXPECT_TRUE(onFulfilled.isNull());
297 EXPECT_TRUE(onRejected.isNull());
299 bool result = stream->enqueue("hello");
301 EXPECT_EQ(ReadableStream::Readable, stream->state());
302 EXPECT_FALSE(stream->isPulling());
303 EXPECT_TRUE(onFulfilled.isNull());
304 EXPECT_TRUE(onRejected.isNull());
306 isolate()->RunMicrotasks();
307 EXPECT_EQ("undefined", onFulfilled);
308 EXPECT_TRUE(onRejected.isNull());
311 TEST_F(ReadableStreamTest, WaitAndEnqueueAndError)
313 StringStream* stream = construct();
314 String onFulfilled, onRejected;
315 EXPECT_EQ(ReadableStream::Waiting, stream->state());
319 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
322 ScriptPromise promise = stream->wait(scriptState());
323 promise.then(createCaptor(&onFulfilled), createCaptor(&onRejected));
324 isolate()->RunMicrotasks();
326 EXPECT_EQ(ReadableStream::Waiting, stream->state());
327 EXPECT_TRUE(stream->isPulling());
328 EXPECT_TRUE(onFulfilled.isNull());
329 EXPECT_TRUE(onRejected.isNull());
331 bool result = stream->enqueue("hello");
333 EXPECT_EQ(ReadableStream::Readable, stream->state());
334 EXPECT_FALSE(stream->isPulling());
335 EXPECT_TRUE(onFulfilled.isNull());
336 EXPECT_TRUE(onRejected.isNull());
338 isolate()->RunMicrotasks();
339 EXPECT_EQ("undefined", onFulfilled);
340 EXPECT_TRUE(onRejected.isNull());
342 stream->error(DOMException::create(NotFoundError, "error"));
343 EXPECT_EQ(ReadableStream::Errored, stream->state());
345 EXPECT_NE(promise, stream->wait(scriptState()));
348 TEST_F(ReadableStreamTest, CloseWhenWaiting)
350 String onWaitFulfilled, onWaitRejected;
351 String onClosedFulfilled, onClosedRejected;
353 StringStream* stream = construct();
357 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
360 EXPECT_EQ(ReadableStream::Waiting, stream->state());
361 stream->wait(scriptState()).then(createCaptor(&onWaitFulfilled), createCaptor(&onWaitRejected));
362 stream->closed(scriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected));
364 isolate()->RunMicrotasks();
365 EXPECT_TRUE(onWaitFulfilled.isNull());
366 EXPECT_TRUE(onWaitRejected.isNull());
367 EXPECT_TRUE(onClosedFulfilled.isNull());
368 EXPECT_TRUE(onClosedRejected.isNull());
371 EXPECT_EQ(ReadableStream::Closed, stream->state());
372 isolate()->RunMicrotasks();
373 EXPECT_EQ("undefined", onWaitFulfilled);
374 EXPECT_TRUE(onWaitRejected.isNull());
375 EXPECT_EQ("undefined", onClosedFulfilled);
376 EXPECT_TRUE(onClosedRejected.isNull());
379 TEST_F(ReadableStreamTest, CloseWhenErrored)
381 String onFulfilled, onRejected;
382 StringStream* stream = construct();
383 EXPECT_EQ(ReadableStream::Waiting, stream->state());
384 stream->closed(scriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected));
386 stream->error(DOMException::create(NotFoundError, "error"));
389 EXPECT_EQ(ReadableStream::Errored, stream->state());
390 isolate()->RunMicrotasks();
392 EXPECT_TRUE(onFulfilled.isNull());
393 EXPECT_EQ("NotFoundError: error", onRejected);
396 TEST_F(ReadableStreamTest, ReadWhenWaiting)
398 StringStream* stream = construct();
399 EXPECT_EQ(ReadableStream::Waiting, stream->state());
400 EXPECT_FALSE(m_exceptionState.hadException());
402 stream->read(scriptState(), m_exceptionState);
403 EXPECT_EQ(ReadableStream::Waiting, stream->state());
404 EXPECT_TRUE(m_exceptionState.hadException());
405 EXPECT_EQ(V8TypeError, m_exceptionState.code());
406 EXPECT_EQ("read is called while state is waiting", m_exceptionState.message());
409 TEST_F(ReadableStreamTest, ReadWhenClosed)
411 StringStream* stream = construct();
414 EXPECT_EQ(ReadableStream::Closed, stream->state());
415 EXPECT_FALSE(m_exceptionState.hadException());
417 stream->read(scriptState(), m_exceptionState);
418 EXPECT_EQ(ReadableStream::Closed, stream->state());
419 EXPECT_TRUE(m_exceptionState.hadException());
420 EXPECT_EQ(V8TypeError, m_exceptionState.code());
421 EXPECT_EQ("read is called while state is closed", m_exceptionState.message());
424 TEST_F(ReadableStreamTest, ReadWhenErrored)
426 // DOMException values specified in the spec are different from enum values
427 // defined in ExceptionCode.h.
428 const int notFoundExceptionCode = 8;
429 StringStream* stream = construct();
430 stream->error(DOMException::create(NotFoundError, "error"));
432 EXPECT_EQ(ReadableStream::Errored, stream->state());
433 EXPECT_FALSE(m_exceptionState.hadException());
435 stream->read(scriptState(), m_exceptionState);
436 EXPECT_EQ(ReadableStream::Errored, stream->state());
437 EXPECT_TRUE(m_exceptionState.hadException());
438 EXPECT_EQ(notFoundExceptionCode, m_exceptionState.code());
439 EXPECT_EQ("error", m_exceptionState.message());
442 TEST_F(ReadableStreamTest, EnqueuedAndRead)
444 StringStream* stream = construct();
445 String onFulfilled, onRejected;
446 Checkpoint checkpoint;
450 EXPECT_CALL(checkpoint, Call(0));
451 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
452 EXPECT_CALL(checkpoint, Call(1));
455 stream->enqueue("hello");
456 ScriptPromise promise = stream->wait(scriptState());
457 EXPECT_EQ(ReadableStream::Readable, stream->state());
458 EXPECT_FALSE(stream->isPulling());
462 EXPECT_TRUE(stream->read(scriptState(), m_exceptionState).toString(chunk));
464 EXPECT_FALSE(m_exceptionState.hadException());
465 EXPECT_EQ("hello", chunk);
466 EXPECT_EQ(ReadableStream::Waiting, stream->state());
467 EXPECT_TRUE(stream->isPulling());
468 EXPECT_FALSE(stream->isDraining());
470 ScriptPromise newPromise = stream->wait(scriptState());
471 newPromise.then(createCaptor(&onFulfilled), createCaptor(&onRejected));
472 isolate()->RunMicrotasks();
473 EXPECT_NE(promise, newPromise);
474 EXPECT_TRUE(onFulfilled.isNull());
475 EXPECT_TRUE(onRejected.isNull());
478 TEST_F(ReadableStreamTest, EnqueTwiceAndRead)
480 StringStream* stream = construct();
481 Checkpoint checkpoint;
485 EXPECT_CALL(checkpoint, Call(0));
486 EXPECT_CALL(checkpoint, Call(1));
489 EXPECT_TRUE(stream->enqueue("hello"));
490 EXPECT_TRUE(stream->enqueue("bye"));
491 ScriptPromise promise = stream->wait(scriptState());
492 EXPECT_EQ(ReadableStream::Readable, stream->state());
493 EXPECT_FALSE(stream->isPulling());
497 EXPECT_TRUE(stream->read(scriptState(), m_exceptionState).toString(chunk));
499 EXPECT_FALSE(m_exceptionState.hadException());
500 EXPECT_EQ("hello", chunk);
501 EXPECT_EQ(ReadableStream::Readable, stream->state());
502 EXPECT_FALSE(stream->isPulling());
503 EXPECT_FALSE(stream->isDraining());
505 ScriptPromise newPromise = stream->wait(scriptState());
506 EXPECT_EQ(promise, newPromise);
509 TEST_F(ReadableStreamTest, CloseWhenReadable)
511 StringStream* stream = construct();
512 String onWaitFulfilled, onWaitRejected;
513 String onClosedFulfilled, onClosedRejected;
515 stream->closed(scriptState()).then(createCaptor(&onClosedFulfilled), createCaptor(&onClosedRejected));
516 EXPECT_TRUE(stream->enqueue("hello"));
517 EXPECT_TRUE(stream->enqueue("bye"));
519 EXPECT_FALSE(stream->enqueue("should be ignored"));
521 ScriptPromise promise = stream->wait(scriptState());
522 EXPECT_EQ(ReadableStream::Readable, stream->state());
523 EXPECT_FALSE(stream->isPulling());
524 EXPECT_TRUE(stream->isDraining());
527 EXPECT_TRUE(stream->read(scriptState(), m_exceptionState).toString(chunk));
528 EXPECT_EQ("hello", chunk);
529 EXPECT_EQ(promise, stream->wait(scriptState()));
531 isolate()->RunMicrotasks();
533 EXPECT_EQ(ReadableStream::Readable, stream->state());
534 EXPECT_FALSE(stream->isPulling());
535 EXPECT_TRUE(stream->isDraining());
537 EXPECT_TRUE(stream->read(scriptState(), m_exceptionState).toString(chunk));
538 EXPECT_EQ("bye", chunk);
539 EXPECT_FALSE(m_exceptionState.hadException());
541 EXPECT_NE(promise, stream->wait(scriptState()));
542 stream->wait(scriptState()).then(createCaptor(&onWaitFulfilled), createCaptor(&onWaitRejected));
544 EXPECT_EQ(ReadableStream::Closed, stream->state());
545 EXPECT_FALSE(stream->isPulling());
546 EXPECT_TRUE(stream->isDraining());
548 EXPECT_TRUE(onWaitFulfilled.isNull());
549 EXPECT_TRUE(onWaitRejected.isNull());
550 EXPECT_TRUE(onClosedFulfilled.isNull());
551 EXPECT_TRUE(onClosedRejected.isNull());
553 isolate()->RunMicrotasks();
554 EXPECT_EQ("undefined", onWaitFulfilled);
555 EXPECT_TRUE(onWaitRejected.isNull());
556 EXPECT_EQ("undefined", onClosedFulfilled);
557 EXPECT_TRUE(onClosedRejected.isNull());
560 TEST_F(ReadableStreamTest, CancelWhenClosed)
562 StringStream* stream = construct();
563 String onFulfilled, onRejected;
565 EXPECT_EQ(ReadableStream::Closed, stream->state());
567 ScriptPromise promise = stream->cancel(scriptState(), ScriptValue());
568 EXPECT_EQ(ReadableStream::Closed, stream->state());
570 promise.then(createCaptor(&onFulfilled), createCaptor(&onRejected));
571 EXPECT_TRUE(onFulfilled.isNull());
572 EXPECT_TRUE(onRejected.isNull());
574 isolate()->RunMicrotasks();
575 EXPECT_EQ("undefined", onFulfilled);
576 EXPECT_TRUE(onRejected.isNull());
579 TEST_F(ReadableStreamTest, CancelWhenErrored)
581 StringStream* stream = construct();
582 String onFulfilled, onRejected;
583 stream->error(DOMException::create(NotFoundError, "error"));
584 EXPECT_EQ(ReadableStream::Errored, stream->state());
586 ScriptPromise promise = stream->cancel(scriptState(), ScriptValue());
587 EXPECT_EQ(ReadableStream::Errored, stream->state());
589 promise.then(createCaptor(&onFulfilled), createCaptor(&onRejected));
590 EXPECT_TRUE(onFulfilled.isNull());
591 EXPECT_TRUE(onRejected.isNull());
593 isolate()->RunMicrotasks();
594 EXPECT_TRUE(onFulfilled.isNull());
595 EXPECT_EQ("NotFoundError: error", onRejected);
598 TEST_F(ReadableStreamTest, CancelWhenWaiting)
600 StringStream* stream = construct();
601 String onFulfilled, onRejected;
602 ScriptValue reason(scriptState(), v8String(scriptState()->isolate(), "reason"));
603 ScriptPromise promise = ScriptPromise::cast(scriptState(), v8String(scriptState()->isolate(), "hello"));
607 EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
608 EXPECT_CALL(*m_underlyingSource, cancelSource(scriptState(), reason)).WillOnce(Return(promise));
611 EXPECT_EQ(ReadableStream::Waiting, stream->state());
612 ScriptPromise wait = stream->wait(scriptState());
613 EXPECT_EQ(promise, stream->cancel(scriptState(), reason));
614 EXPECT_EQ(ReadableStream::Closed, stream->state());
615 EXPECT_EQ(stream->wait(scriptState()), wait);
617 wait.then(createCaptor(&onFulfilled), createCaptor(&onRejected));
618 EXPECT_TRUE(onFulfilled.isNull());
619 EXPECT_TRUE(onRejected.isNull());
621 isolate()->RunMicrotasks();
622 EXPECT_EQ("undefined", onFulfilled);
623 EXPECT_TRUE(onRejected.isNull());
626 TEST_F(ReadableStreamTest, CancelWhenReadable)
628 StringStream* stream = construct();
629 String onFulfilled, onRejected;
630 ScriptValue reason(scriptState(), v8String(scriptState()->isolate(), "reason"));
631 ScriptPromise promise = ScriptPromise::cast(scriptState(), v8String(scriptState()->isolate(), "hello"));
635 EXPECT_CALL(*m_underlyingSource, cancelSource(scriptState(), reason)).WillOnce(Return(promise));
638 stream->enqueue("hello");
639 ScriptPromise wait = stream->wait(scriptState());
640 EXPECT_EQ(ReadableStream::Readable, stream->state());
641 EXPECT_EQ(promise, stream->cancel(scriptState(), reason));
642 EXPECT_EQ(ReadableStream::Closed, stream->state());
644 EXPECT_NE(stream->wait(scriptState()), wait);
646 stream->wait(scriptState()).then(createCaptor(&onFulfilled), createCaptor(&onRejected));
647 EXPECT_TRUE(onFulfilled.isNull());
648 EXPECT_TRUE(onRejected.isNull());
650 isolate()->RunMicrotasks();
651 EXPECT_EQ("undefined", onFulfilled);
652 EXPECT_TRUE(onRejected.isNull());
655 TEST_F(ReadableStreamTest, ReadableArrayBufferCompileTest)
657 // This test tests if ReadableStreamImpl<DOMArrayBuffer> can be instantiated.
658 new ReadableStreamImpl<ReadableStreamChunkTypeTraits<DOMArrayBuffer> >(scriptState()->executionContext(), m_underlyingSource);