TEST_F(ReadableStreamTest, CloseWhenReadable)
{
    ScriptState::Scope scope(scriptState());
    ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", scriptState()->context()->Global(), isolate());
    StringStream* stream = construct();

    EXPECT_TRUE(stream->enqueue("hello"));
    EXPECT_TRUE(stream->enqueue("bye"));
    stream->close();
    EXPECT_FALSE(stream->enqueue("should be ignored"));

    EXPECT_EQ(ReadableStream::Readable, stream->stateInternal());
    EXPECT_FALSE(stream->isPulling());
    EXPECT_TRUE(stream->isDraining());

    stream->read(scriptState());

    isolate()->RunMicrotasks();

    EXPECT_EQ(ReadableStream::Readable, stream->stateInternal());
    EXPECT_FALSE(stream->isPulling());
    EXPECT_TRUE(stream->isDraining());

    stream->read(scriptState());

    EXPECT_EQ(ReadableStream::Closed, stream->stateInternal());
    EXPECT_FALSE(stream->isPulling());
    EXPECT_TRUE(stream->isDraining());
}
int main(int argc, char *argv[])
{
    try
    {

        std::string input("abcdefghijklmnopqrstuvwxyz");
        char buffer[32];
        memset(buffer, 0, 32);
        StringStream sStream;

        sStream.write((const sys::byte*) input.c_str(), 5);
        sStream.read((sys::byte*) buffer, 3);
        cout << buffer << endl;

        memset(buffer, 0, 32);
        sStream.write((const sys::byte*) input.c_str(), 10);
        sStream.read((sys::byte*) buffer, 11);
        cout << buffer << endl;

        memset(buffer, 0, 32);
        sStream.read((sys::byte*) buffer, 100);
        cout << buffer << endl;

    }
    catch (Throwable& t)
    {
        cerr << "Caught throwable: " << t.toString() << endl;
    }
    catch (...)
    {
        cerr << "Caught unknown exception" << endl;
    }
    return 0;
}
TEST_F(ReadableStreamTest, BackpressureOnReading)
{
    ScriptState::Scope scope(scriptState());
    ExceptionState exceptionState(ExceptionState::ConstructionContext, "property", "interface", scriptState()->context()->Global(), isolate());
    auto strategy = MockStrategy::create();
    Checkpoint checkpoint;

    StringStream* stream = construct(strategy);
    EXPECT_EQ(ReadableStream::Readable, stream->stateInternal());

    {
        InSequence s;
        EXPECT_CALL(*strategy, size(String("hello"), stream)).WillOnce(Return(2));
        EXPECT_CALL(*strategy, shouldApplyBackpressure(2, stream)).WillOnce(Return(false));
        EXPECT_CALL(*strategy, size(String("world"), stream)).WillOnce(Return(3));
        EXPECT_CALL(*strategy, shouldApplyBackpressure(5, stream)).WillOnce(Return(false));

        EXPECT_CALL(checkpoint, Call(0));
        EXPECT_CALL(*strategy, shouldApplyBackpressure(3, stream)).WillOnce(Return(false));
        EXPECT_CALL(*m_underlyingSource, pullSource()).Times(1);
        EXPECT_CALL(checkpoint, Call(1));
        // shouldApplyBackpressure and pullSource are not called because the
        // stream is pulling.
        EXPECT_CALL(checkpoint, Call(2));
        EXPECT_CALL(*strategy, size(String("foo"), stream)).WillOnce(Return(4));
        EXPECT_CALL(*strategy, shouldApplyBackpressure(4, stream)).WillOnce(Return(true));
        EXPECT_CALL(*strategy, size(String("bar"), stream)).WillOnce(Return(5));
        EXPECT_CALL(*strategy, shouldApplyBackpressure(9, stream)).WillOnce(Return(true));
        EXPECT_CALL(checkpoint, Call(3));
        EXPECT_CALL(*strategy, shouldApplyBackpressure(5, stream)).WillOnce(Return(true));
        EXPECT_CALL(checkpoint, Call(4));
    }
    stream->enqueue("hello");
    stream->enqueue("world");

    checkpoint.Call(0);
    stream->read(scriptState());
    checkpoint.Call(1);
    stream->read(scriptState());
    checkpoint.Call(2);
    stream->enqueue("foo");
    stream->enqueue("bar");
    checkpoint.Call(3);
    stream->read(scriptState());
    checkpoint.Call(4);

    stream->error(DOMException::create(AbortError, "done"));
}