| OLD | NEW | 
|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "bindings/core/v8/ReadableStreamOperations.h" | 5 #include "bindings/core/v8/ReadableStreamOperations.h" | 
| 6 | 6 | 
| 7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" | 
| 8 #include "bindings/core/v8/ScriptFunction.h" | 8 #include "bindings/core/v8/ScriptFunction.h" | 
| 9 #include "bindings/core/v8/ScriptState.h" | 9 #include "bindings/core/v8/ScriptState.h" | 
|  | 10 #include "bindings/core/v8/ScriptValue.h" | 
|  | 11 #include "bindings/core/v8/ScriptWrappable.h" | 
| 10 #include "bindings/core/v8/V8Binding.h" | 12 #include "bindings/core/v8/V8Binding.h" | 
| 11 #include "bindings/core/v8/V8BindingForTesting.h" | 13 #include "bindings/core/v8/V8BindingForTesting.h" | 
| 12 #include "bindings/core/v8/V8BindingMacros.h" | 14 #include "bindings/core/v8/V8BindingMacros.h" | 
| 13 #include "bindings/core/v8/V8IteratorResultValue.h" | 15 #include "bindings/core/v8/V8IteratorResultValue.h" | 
| 14 #include "bindings/core/v8/V8ThrowException.h" | 16 #include "bindings/core/v8/V8ThrowException.h" | 
|  | 17 #include "core/dom/Document.h" | 
|  | 18 #include "core/streams/ReadableStreamController.h" | 
|  | 19 #include "core/streams/UnderlyingSourceBase.h" | 
| 15 #include "platform/heap/Handle.h" | 20 #include "platform/heap/Handle.h" | 
| 16 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" | 
| 17 #include <v8.h> | 22 #include <v8.h> | 
| 18 | 23 | 
| 19 namespace blink { | 24 namespace blink { | 
| 20 | 25 | 
| 21 namespace { | 26 namespace { | 
| 22 | 27 | 
| 23 class NotReached : public ScriptFunction { | 28 class NotReached : public ScriptFunction { | 
| 24 public: | 29 public: | 
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 101 | 106 | 
| 102     ScriptValue call(ScriptValue value) override | 107     ScriptValue call(ScriptValue value) override | 
| 103     { | 108     { | 
| 104         m_iteration->set(value); | 109         m_iteration->set(value); | 
| 105         return value; | 110         return value; | 
| 106     } | 111     } | 
| 107 | 112 | 
| 108     Member<Iteration> m_iteration; | 113     Member<Iteration> m_iteration; | 
| 109 }; | 114 }; | 
| 110 | 115 | 
|  | 116 class UnderlyingSourceTest final : public UnderlyingSourceBase { | 
|  | 117 public: | 
|  | 118     UnderlyingSourceTest(ScriptState* scriptState) | 
|  | 119         : UnderlyingSourceBase(scriptState) | 
|  | 120     { | 
|  | 121     } | 
|  | 122 | 
|  | 123     // Just expose the controller methods for easy testing | 
|  | 124     void enqueue(ScriptValue v) { controller()->enqueue(v); } | 
|  | 125     void close() { controller()->close(); } | 
|  | 126     void error(ScriptValue e) { controller()->error(e); } | 
|  | 127     double desiredSize() { return controller()->desiredSize(); } | 
|  | 128 }; | 
|  | 129 | 
| 111 class ReadableStreamOperationsTest : public ::testing::Test { | 130 class ReadableStreamOperationsTest : public ::testing::Test { | 
| 112 public: | 131 public: | 
| 113     ReadableStreamOperationsTest() : m_scope(v8::Isolate::GetCurrent()), m_block
     (isolate()) {} | 132     ReadableStreamOperationsTest() | 
|  | 133         : m_scope(v8::Isolate::GetCurrent()) | 
|  | 134         , m_block(isolate()) | 
|  | 135         , m_document(Document::create()) | 
|  | 136     { | 
|  | 137         scriptState()->setExecutionContext(m_document.get()); | 
|  | 138     } | 
| 114     ~ReadableStreamOperationsTest() override | 139     ~ReadableStreamOperationsTest() override | 
| 115     { | 140     { | 
| 116         // Execute all pending microtasks | 141         // Execute all pending microtasks | 
| 117         isolate()->RunMicrotasks(); | 142         isolate()->RunMicrotasks(); | 
| 118         EXPECT_FALSE(m_block.HasCaught()); | 143         EXPECT_FALSE(m_block.HasCaught()); | 
| 119     } | 144     } | 
| 120 | 145 | 
| 121     ScriptState* scriptState() const { return m_scope.scriptState(); } | 146     ScriptState* scriptState() const { return m_scope.scriptState(); } | 
| 122     v8::Isolate* isolate() const { return scriptState()->isolate(); } | 147     v8::Isolate* isolate() const { return scriptState()->isolate(); } | 
| 123 | 148 | 
| 124     v8::MaybeLocal<v8::Value> eval(const char* s) | 149     ScriptValue eval(const char* s) | 
| 125     { | 150     { | 
| 126         v8::Local<v8::String> source; | 151         v8::Local<v8::String> source; | 
| 127         v8::Local<v8::Script> script; | 152         v8::Local<v8::Script> script; | 
| 128         if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNo
     rmal), source)) { | 153         if (!v8Call(v8::String::NewFromUtf8(isolate(), s, v8::NewStringType::kNo
     rmal), source)) { | 
| 129             ADD_FAILURE(); | 154             ADD_FAILURE(); | 
| 130             return v8::MaybeLocal<v8::Value>(); | 155             return ScriptValue(); | 
| 131         } | 156         } | 
| 132         if (!v8Call(v8::Script::Compile(scriptState()->context(), source), scrip
     t)) { | 157         if (!v8Call(v8::Script::Compile(scriptState()->context(), source), scrip
     t)) { | 
| 133             ADD_FAILURE() << "Compilation fails"; | 158             ADD_FAILURE() << "Compilation fails"; | 
| 134             return v8::MaybeLocal<v8::Value>(); | 159             return ScriptValue(); | 
| 135         } | 160         } | 
| 136         return script->Run(scriptState()->context()); | 161         return ScriptValue(scriptState(), script->Run(scriptState()->context()))
     ; | 
| 137     } | 162     } | 
| 138     v8::MaybeLocal<v8::Value> evalWithPrintingError(const char* s) | 163     ScriptValue evalWithPrintingError(const char* s) | 
| 139     { | 164     { | 
| 140         v8::TryCatch block(isolate()); | 165         v8::TryCatch block(isolate()); | 
| 141         v8::MaybeLocal<v8::Value> r = eval(s); | 166         ScriptValue r = eval(s); | 
| 142         if (block.HasCaught()) { | 167         if (block.HasCaught()) { | 
| 143             ADD_FAILURE() << toCoreString(block.Exception()->ToString(isolate())
     ).utf8().data(); | 168             ADD_FAILURE() << toCoreString(block.Exception()->ToString(isolate())
     ).utf8().data(); | 
| 144             block.ReThrow(); | 169             block.ReThrow(); | 
| 145         } | 170         } | 
| 146         return r; | 171         return r; | 
| 147     } | 172     } | 
| 148 | 173 | 
| 149     V8TestingScope m_scope; | 174     V8TestingScope m_scope; | 
| 150     v8::TryCatch m_block; | 175     v8::TryCatch m_block; | 
|  | 176     RefPtrWillBePersistent<Document> m_document; | 
| 151 }; | 177 }; | 
| 152 | 178 | 
| 153 TEST_F(ReadableStreamOperationsTest, IsReadableStream) | 179 TEST_F(ReadableStreamOperationsTest, IsReadableStream) | 
| 154 { | 180 { | 
| 155     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), v8::U
     ndefined(isolate()))); | 181     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), Scrip
     tValue(scriptState(), v8::Undefined(isolate())))); | 
| 156     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), v8::N
     ull(isolate()))); | 182     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), Scrip
     tValue::createNull(scriptState()))); | 
| 157     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), v8::O
     bject::New(isolate()))); | 183     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), Scrip
     tValue(scriptState(), v8::Object::New(isolate())))); | 
| 158     v8::Local<v8::Value> stream; | 184     ScriptValue stream = evalWithPrintingError("new ReadableStream()"); | 
| 159     ASSERT_TRUE(v8Call(evalWithPrintingError("new ReadableStream()"), stream)); | 185     EXPECT_FALSE(stream.isEmpty()); | 
| 160     EXPECT_TRUE(ReadableStreamOperations::isReadableStream(scriptState(), stream
     )); | 186     EXPECT_TRUE(ReadableStreamOperations::isReadableStream(scriptState(), stream
     )); | 
| 161 } | 187 } | 
| 162 | 188 | 
| 163 TEST_F(ReadableStreamOperationsTest, IsReadableStreamReaderInvalid) | 189 TEST_F(ReadableStreamOperationsTest, IsReadableStreamReaderInvalid) | 
| 164 { | 190 { | 
| 165     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      v8::Undefined(isolate()))); | 191     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      ScriptValue(scriptState(), v8::Undefined(isolate())))); | 
| 166     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      v8::Null(isolate()))); | 192     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      ScriptValue::createNull(scriptState()))); | 
| 167     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      v8::Object::New(isolate()))); | 193     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      ScriptValue(scriptState(), v8::Object::New(isolate())))); | 
| 168     v8::Local<v8::Value> stream; | 194     ScriptValue stream = evalWithPrintingError("new ReadableStream()"); | 
| 169     ASSERT_TRUE(v8Call(evalWithPrintingError("new ReadableStream()"), stream)); | 195     EXPECT_FALSE(stream.isEmpty()); | 
| 170 | 196 | 
| 171     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      stream)); | 197     EXPECT_FALSE(ReadableStreamOperations::isReadableStreamReader(scriptState(),
      stream)); | 
| 172 } | 198 } | 
| 173 | 199 | 
| 174 TEST_F(ReadableStreamOperationsTest, GetReader) | 200 TEST_F(ReadableStreamOperationsTest, GetReader) | 
| 175 { | 201 { | 
| 176     v8::Local<v8::Value> stream; | 202     ScriptValue stream = evalWithPrintingError("new ReadableStream()"); | 
| 177     ASSERT_TRUE(v8Call(evalWithPrintingError("new ReadableStream()"), stream)); | 203     EXPECT_FALSE(stream.isEmpty()); | 
| 178 | 204 | 
| 179     EXPECT_FALSE(ReadableStreamOperations::isLocked(scriptState(), stream)); | 205     EXPECT_FALSE(ReadableStreamOperations::isLocked(scriptState(), stream)); | 
| 180     ScriptValue reader; | 206     ScriptValue reader; | 
| 181     { | 207     { | 
| 182         TrackExceptionState es; | 208         TrackExceptionState es; | 
| 183         reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 209         reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 
| 184         ASSERT_FALSE(es.hadException()); | 210         ASSERT_FALSE(es.hadException()); | 
| 185     } | 211     } | 
| 186     EXPECT_TRUE(ReadableStreamOperations::isLocked(scriptState(), stream)); | 212     EXPECT_TRUE(ReadableStreamOperations::isLocked(scriptState(), stream)); | 
| 187     ASSERT_FALSE(reader.isEmpty()); | 213     ASSERT_FALSE(reader.isEmpty()); | 
| 188 | 214 | 
| 189     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), reade
     r.v8Value())); | 215     EXPECT_FALSE(ReadableStreamOperations::isReadableStream(scriptState(), reade
     r)); | 
| 190     EXPECT_TRUE(ReadableStreamOperations::isReadableStreamReader(scriptState(), 
     reader.v8Value())); | 216     EXPECT_TRUE(ReadableStreamOperations::isReadableStreamReader(scriptState(), 
     reader)); | 
| 191 | 217 | 
| 192     // Already locked! | 218     // Already locked! | 
| 193     { | 219     { | 
| 194         TrackExceptionState es; | 220         TrackExceptionState es; | 
| 195         reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 221         reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 
| 196         ASSERT_TRUE(es.hadException()); | 222         ASSERT_TRUE(es.hadException()); | 
| 197     } | 223     } | 
| 198     ASSERT_TRUE(reader.isEmpty()); | 224     ASSERT_TRUE(reader.isEmpty()); | 
| 199 } | 225 } | 
| 200 | 226 | 
| 201 TEST_F(ReadableStreamOperationsTest, IsDisturbed) | 227 TEST_F(ReadableStreamOperationsTest, IsDisturbed) | 
| 202 { | 228 { | 
| 203     v8::Local<v8::Value> stream; | 229     ScriptValue stream = evalWithPrintingError("stream = new ReadableStream()"); | 
| 204     ASSERT_TRUE(v8Call(evalWithPrintingError("stream = new ReadableStream()"), s
     tream)); | 230     EXPECT_FALSE(stream.isEmpty()); | 
| 205 | 231 | 
| 206     EXPECT_FALSE(ReadableStreamOperations::isDisturbed(scriptState(), stream)); | 232     EXPECT_FALSE(ReadableStreamOperations::isDisturbed(scriptState(), stream)); | 
| 207 | 233 | 
| 208     ASSERT_FALSE(evalWithPrintingError("stream.cancel()").IsEmpty()); | 234     ASSERT_FALSE(evalWithPrintingError("stream.cancel()").isEmpty()); | 
| 209 | 235 | 
| 210     EXPECT_TRUE(ReadableStreamOperations::isDisturbed(scriptState(), stream)); | 236     EXPECT_TRUE(ReadableStreamOperations::isDisturbed(scriptState(), stream)); | 
| 211 } | 237 } | 
| 212 | 238 | 
| 213 TEST_F(ReadableStreamOperationsTest, Read) | 239 TEST_F(ReadableStreamOperationsTest, Read) | 
| 214 { | 240 { | 
| 215     v8::Local<v8::Value> reader; | 241     ScriptValue reader = evalWithPrintingError( | 
| 216     ASSERT_TRUE(v8Call(evalWithPrintingError( |  | 
| 217         "var controller;" | 242         "var controller;" | 
| 218         "function start(c) { controller = c; }" | 243         "function start(c) { controller = c; }" | 
| 219         "new ReadableStream({start}).getReader()"), reader)); | 244         "new ReadableStream({start}).getReader()"); | 
|  | 245     EXPECT_FALSE(reader.isEmpty()); | 
| 220     ASSERT_TRUE(ReadableStreamOperations::isReadableStreamReader(scriptState(), 
     reader)); | 246     ASSERT_TRUE(ReadableStreamOperations::isReadableStreamReader(scriptState(), 
     reader)); | 
| 221 | 247 | 
| 222     Iteration* it1 = new Iteration(); | 248     Iteration* it1 = new Iteration(); | 
| 223     Iteration* it2 = new Iteration(); | 249     Iteration* it2 = new Iteration(); | 
| 224     ReadableStreamOperations::read(scriptState(), reader).then( | 250     ReadableStreamOperations::read(scriptState(), reader).then( | 
| 225         Function::createFunction(scriptState(), it1), | 251         Function::createFunction(scriptState(), it1), | 
| 226         NotReached::createFunction(scriptState())); | 252         NotReached::createFunction(scriptState())); | 
| 227     ReadableStreamOperations::read(scriptState(), reader).then( | 253     ReadableStreamOperations::read(scriptState(), reader).then( | 
| 228         Function::createFunction(scriptState(), it2), | 254         Function::createFunction(scriptState(), it2), | 
| 229         NotReached::createFunction(scriptState())); | 255         NotReached::createFunction(scriptState())); | 
| 230 | 256 | 
| 231     isolate()->RunMicrotasks(); | 257     isolate()->RunMicrotasks(); | 
| 232     EXPECT_FALSE(it1->isSet()); | 258     EXPECT_FALSE(it1->isSet()); | 
| 233     EXPECT_FALSE(it2->isSet()); | 259     EXPECT_FALSE(it2->isSet()); | 
| 234 | 260 | 
| 235     ASSERT_FALSE(evalWithPrintingError("controller.enqueue('hello')").IsEmpty())
     ; | 261     ASSERT_FALSE(evalWithPrintingError("controller.enqueue('hello')").isEmpty())
     ; | 
| 236     isolate()->RunMicrotasks(); | 262     isolate()->RunMicrotasks(); | 
| 237     EXPECT_TRUE(it1->isSet()); | 263     EXPECT_TRUE(it1->isSet()); | 
| 238     EXPECT_TRUE(it1->isValid()); | 264     EXPECT_TRUE(it1->isValid()); | 
| 239     EXPECT_FALSE(it1->isDone()); | 265     EXPECT_FALSE(it1->isDone()); | 
| 240     EXPECT_EQ("hello", it1->value()); | 266     EXPECT_EQ("hello", it1->value()); | 
| 241     EXPECT_FALSE(it2->isSet()); | 267     EXPECT_FALSE(it2->isSet()); | 
| 242 | 268 | 
| 243     ASSERT_FALSE(evalWithPrintingError("controller.close()").IsEmpty()); | 269     ASSERT_FALSE(evalWithPrintingError("controller.close()").isEmpty()); | 
| 244     isolate()->RunMicrotasks(); | 270     isolate()->RunMicrotasks(); | 
| 245     EXPECT_TRUE(it1->isSet()); | 271     EXPECT_TRUE(it1->isSet()); | 
| 246     EXPECT_TRUE(it1->isValid()); | 272     EXPECT_TRUE(it1->isValid()); | 
| 247     EXPECT_FALSE(it1->isDone()); | 273     EXPECT_FALSE(it1->isDone()); | 
| 248     EXPECT_EQ("hello", it1->value()); | 274     EXPECT_EQ("hello", it1->value()); | 
| 249     EXPECT_TRUE(it2->isSet()); | 275     EXPECT_TRUE(it2->isSet()); | 
| 250     EXPECT_TRUE(it2->isValid()); | 276     EXPECT_TRUE(it2->isValid()); | 
| 251     EXPECT_TRUE(it2->isDone()); | 277     EXPECT_TRUE(it2->isDone()); | 
| 252 } | 278 } | 
| 253 | 279 | 
|  | 280 TEST_F(ReadableStreamOperationsTest, CreateReadableStreamWithCustomUnderlyingSou
     rceAndStrategy) | 
|  | 281 { | 
|  | 282     auto underlyingSource = new UnderlyingSourceTest(scriptState()); | 
|  | 283 | 
|  | 284     ScriptValue strategy = ReadableStreamOperations::createCountQueuingStrategy(
     scriptState(), 10); | 
|  | 285     ASSERT_FALSE(strategy.isEmpty()); | 
|  | 286 | 
|  | 287     ScriptValue stream = ReadableStreamOperations::createReadableStream(scriptSt
     ate(), underlyingSource, strategy); | 
|  | 288     ASSERT_FALSE(stream.isEmpty()); | 
|  | 289 | 
|  | 290     EXPECT_EQ(10, underlyingSource->desiredSize()); | 
|  | 291 | 
|  | 292     underlyingSource->enqueue(ScriptValue::from(scriptState(), "a")); | 
|  | 293     EXPECT_EQ(9, underlyingSource->desiredSize()); | 
|  | 294 | 
|  | 295     underlyingSource->enqueue(ScriptValue::from(scriptState(), "b")); | 
|  | 296     EXPECT_EQ(8, underlyingSource->desiredSize()); | 
|  | 297 | 
|  | 298     ScriptValue reader; | 
|  | 299     { | 
|  | 300         TrackExceptionState es; | 
|  | 301         reader = ReadableStreamOperations::getReader(scriptState(), stream, es); | 
|  | 302         ASSERT_FALSE(es.hadException()); | 
|  | 303     } | 
|  | 304     ASSERT_FALSE(reader.isEmpty()); | 
|  | 305 | 
|  | 306     Iteration* it1 = new Iteration(); | 
|  | 307     Iteration* it2 = new Iteration(); | 
|  | 308     Iteration* it3 = new Iteration(); | 
|  | 309     ReadableStreamOperations::read(scriptState(), reader).then(Function::createF
     unction(scriptState(), it1), NotReached::createFunction(scriptState())); | 
|  | 310     ReadableStreamOperations::read(scriptState(), reader).then(Function::createF
     unction(scriptState(), it2), NotReached::createFunction(scriptState())); | 
|  | 311     ReadableStreamOperations::read(scriptState(), reader).then(Function::createF
     unction(scriptState(), it3), NotReached::createFunction(scriptState())); | 
|  | 312 | 
|  | 313     isolate()->RunMicrotasks(); | 
|  | 314 | 
|  | 315     EXPECT_EQ(10, underlyingSource->desiredSize()); | 
|  | 316 | 
|  | 317     EXPECT_TRUE(it1->isSet()); | 
|  | 318     EXPECT_TRUE(it1->isValid()); | 
|  | 319     EXPECT_FALSE(it1->isDone()); | 
|  | 320     EXPECT_EQ("a", it1->value()); | 
|  | 321 | 
|  | 322     EXPECT_TRUE(it2->isSet()); | 
|  | 323     EXPECT_TRUE(it2->isValid()); | 
|  | 324     EXPECT_FALSE(it2->isDone()); | 
|  | 325     EXPECT_EQ("b", it2->value()); | 
|  | 326 | 
|  | 327     EXPECT_FALSE(it3->isSet()); | 
|  | 328 | 
|  | 329     underlyingSource->close(); | 
|  | 330     isolate()->RunMicrotasks(); | 
|  | 331 | 
|  | 332     EXPECT_TRUE(it3->isSet()); | 
|  | 333     EXPECT_TRUE(it3->isValid()); | 
|  | 334     EXPECT_TRUE(it3->isDone()); | 
|  | 335 } | 
|  | 336 | 
| 254 } // namespace | 337 } // namespace | 
| 255 | 338 | 
| 256 } // namespace blink | 339 } // namespace blink | 
| 257 | 340 | 
| OLD | NEW | 
|---|