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. 4 5#include "config.h" 6#include "bindings/core/v8/ScriptPromiseResolver.h" 7 8#include "bindings/core/v8/ScriptFunction.h" 9#include "bindings/core/v8/ScriptValue.h" 10#include "bindings/core/v8/V8Binding.h" 11#include "core/dom/DOMException.h" 12#include "core/dom/Document.h" 13#include "core/dom/ExceptionCode.h" 14#include "core/testing/DummyPageHolder.h" 15 16#include <gtest/gtest.h> 17#include <v8.h> 18 19namespace blink { 20 21namespace { 22 23void callback(const v8::FunctionCallbackInfo<v8::Value>& info) { } 24 25class Function : public ScriptFunction { 26public: 27 static v8::Handle<v8::Function> createFunction(ScriptState* scriptState, String* value) 28 { 29 Function* self = new Function(scriptState, value); 30 return self->bindToV8Function(); 31 } 32 33private: 34 Function(ScriptState* scriptState, String* value) 35 : ScriptFunction(scriptState) 36 , m_value(value) 37 { 38 } 39 40 virtual ScriptValue call(ScriptValue value) OVERRIDE 41 { 42 ASSERT(!value.isEmpty()); 43 *m_value = toCoreString(value.v8Value()->ToString()); 44 return value; 45 } 46 47 String* m_value; 48}; 49 50class ScriptPromiseResolverTest : public ::testing::Test { 51public: 52 ScriptPromiseResolverTest() 53 : m_pageHolder(DummyPageHolder::create()) 54 { 55 } 56 57 virtual ~ScriptPromiseResolverTest() 58 { 59 ScriptState::Scope scope(scriptState()); 60 // FIXME: We put this statement here to clear an exception from the 61 // isolate. 62 createClosure(callback, v8::Undefined(isolate()), isolate()); 63 64 // Execute all pending microtasks 65 isolate()->RunMicrotasks(); 66 } 67 68 OwnPtr<DummyPageHolder> m_pageHolder; 69 ScriptState* scriptState() const { return ScriptState::forMainWorld(&m_pageHolder->frame()); } 70 ExecutionContext* executionContext() const { return &m_pageHolder->document(); } 71 v8::Isolate* isolate() const { return scriptState()->isolate(); } 72}; 73 74TEST_F(ScriptPromiseResolverTest, construct) 75{ 76 ASSERT_FALSE(executionContext()->activeDOMObjectsAreStopped()); 77 ScriptState::Scope scope(scriptState()); 78 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState()); 79} 80 81TEST_F(ScriptPromiseResolverTest, resolve) 82{ 83 RefPtr<ScriptPromiseResolver> resolver; 84 ScriptPromise promise; 85 { 86 ScriptState::Scope scope(scriptState()); 87 resolver = ScriptPromiseResolver::create(scriptState()); 88 promise = resolver->promise(); 89 } 90 91 String onFulfilled, onRejected; 92 ASSERT_FALSE(promise.isEmpty()); 93 { 94 ScriptState::Scope scope(scriptState()); 95 promise.then(Function::createFunction(scriptState(), &onFulfilled), Function::createFunction(scriptState(), &onRejected)); 96 } 97 98 EXPECT_EQ(String(), onFulfilled); 99 EXPECT_EQ(String(), onRejected); 100 101 isolate()->RunMicrotasks(); 102 103 EXPECT_EQ(String(), onFulfilled); 104 EXPECT_EQ(String(), onRejected); 105 106 resolver->resolve("hello"); 107 108 { 109 ScriptState::Scope scope(scriptState()); 110 EXPECT_TRUE(resolver->promise().isEmpty()); 111 } 112 113 EXPECT_EQ(String(), onFulfilled); 114 EXPECT_EQ(String(), onRejected); 115 116 isolate()->RunMicrotasks(); 117 118 EXPECT_EQ("hello", onFulfilled); 119 EXPECT_EQ(String(), onRejected); 120 121 resolver->resolve("bye"); 122 resolver->reject("bye"); 123 isolate()->RunMicrotasks(); 124 125 EXPECT_EQ("hello", onFulfilled); 126 EXPECT_EQ(String(), onRejected); 127} 128 129TEST_F(ScriptPromiseResolverTest, reject) 130{ 131 RefPtr<ScriptPromiseResolver> resolver; 132 ScriptPromise promise; 133 { 134 ScriptState::Scope scope(scriptState()); 135 resolver = ScriptPromiseResolver::create(scriptState()); 136 promise = resolver->promise(); 137 } 138 139 String onFulfilled, onRejected; 140 ASSERT_FALSE(promise.isEmpty()); 141 { 142 ScriptState::Scope scope(scriptState()); 143 promise.then(Function::createFunction(scriptState(), &onFulfilled), Function::createFunction(scriptState(), &onRejected)); 144 } 145 146 EXPECT_EQ(String(), onFulfilled); 147 EXPECT_EQ(String(), onRejected); 148 149 isolate()->RunMicrotasks(); 150 151 EXPECT_EQ(String(), onFulfilled); 152 EXPECT_EQ(String(), onRejected); 153 154 resolver->reject("hello"); 155 156 { 157 ScriptState::Scope scope(scriptState()); 158 EXPECT_TRUE(resolver->promise().isEmpty()); 159 } 160 161 EXPECT_EQ(String(), onFulfilled); 162 EXPECT_EQ(String(), onRejected); 163 164 isolate()->RunMicrotasks(); 165 166 EXPECT_EQ(String(), onFulfilled); 167 EXPECT_EQ("hello", onRejected); 168 169 resolver->resolve("bye"); 170 resolver->reject("bye"); 171 isolate()->RunMicrotasks(); 172 173 EXPECT_EQ(String(), onFulfilled); 174 EXPECT_EQ("hello", onRejected); 175} 176 177TEST_F(ScriptPromiseResolverTest, stop) 178{ 179 RefPtr<ScriptPromiseResolver> resolver; 180 ScriptPromise promise; 181 { 182 ScriptState::Scope scope(scriptState()); 183 resolver = ScriptPromiseResolver::create(scriptState()); 184 promise = resolver->promise(); 185 } 186 187 String onFulfilled, onRejected; 188 ASSERT_FALSE(promise.isEmpty()); 189 { 190 ScriptState::Scope scope(scriptState()); 191 promise.then(Function::createFunction(scriptState(), &onFulfilled), Function::createFunction(scriptState(), &onRejected)); 192 } 193 194 executionContext()->stopActiveDOMObjects(); 195 { 196 ScriptState::Scope scope(scriptState()); 197 EXPECT_TRUE(resolver->promise().isEmpty()); 198 } 199 200 resolver->resolve("hello"); 201 isolate()->RunMicrotasks(); 202 203 EXPECT_EQ(String(), onFulfilled); 204 EXPECT_EQ(String(), onRejected); 205} 206 207TEST_F(ScriptPromiseResolverTest, keepAliveUntilResolved) 208{ 209 RefPtr<ScriptPromiseResolver> resolver; 210 { 211 ScriptState::Scope scope(scriptState()); 212 resolver = ScriptPromiseResolver::create(scriptState()); 213 } 214 EXPECT_EQ(1, resolver->refCount()); 215 resolver->keepAliveWhilePending(); 216 EXPECT_EQ(2, resolver->refCount()); 217 218 resolver->resolve("hello"); 219 EXPECT_EQ(1, resolver->refCount()); 220} 221 222TEST_F(ScriptPromiseResolverTest, keepAliveUntilRejected) 223{ 224 RefPtr<ScriptPromiseResolver> resolver; 225 { 226 ScriptState::Scope scope(scriptState()); 227 resolver = ScriptPromiseResolver::create(scriptState()); 228 } 229 EXPECT_EQ(1, resolver->refCount()); 230 resolver->keepAliveWhilePending(); 231 EXPECT_EQ(2, resolver->refCount()); 232 233 resolver->reject("hello"); 234 EXPECT_EQ(1, resolver->refCount()); 235} 236 237TEST_F(ScriptPromiseResolverTest, keepAliveUntilStopped) 238{ 239 RefPtr<ScriptPromiseResolver> resolver; 240 { 241 ScriptState::Scope scope(scriptState()); 242 resolver = ScriptPromiseResolver::create(scriptState()); 243 } 244 EXPECT_EQ(1, resolver->refCount()); 245 resolver->keepAliveWhilePending(); 246 EXPECT_EQ(2, resolver->refCount()); 247 248 executionContext()->stopActiveDOMObjects(); 249 EXPECT_EQ(1, resolver->refCount()); 250} 251 252TEST_F(ScriptPromiseResolverTest, suspend) 253{ 254 RefPtr<ScriptPromiseResolver> resolver; 255 { 256 ScriptState::Scope scope(scriptState()); 257 resolver = ScriptPromiseResolver::create(scriptState()); 258 } 259 EXPECT_EQ(1, resolver->refCount()); 260 resolver->keepAliveWhilePending(); 261 EXPECT_EQ(2, resolver->refCount()); 262 executionContext()->suspendActiveDOMObjects(); 263 resolver->resolve("hello"); 264 EXPECT_EQ(3, resolver->refCount()); 265 266 executionContext()->stopActiveDOMObjects(); 267 EXPECT_EQ(1, resolver->refCount()); 268} 269 270TEST_F(ScriptPromiseResolverTest, resolveVoid) 271{ 272 RefPtr<ScriptPromiseResolver> resolver; 273 ScriptPromise promise; 274 { 275 ScriptState::Scope scope(scriptState()); 276 resolver = ScriptPromiseResolver::create(scriptState()); 277 promise = resolver->promise(); 278 } 279 280 String onFulfilled, onRejected; 281 ASSERT_FALSE(promise.isEmpty()); 282 { 283 ScriptState::Scope scope(scriptState()); 284 promise.then(Function::createFunction(scriptState(), &onFulfilled), Function::createFunction(scriptState(), &onRejected)); 285 } 286 287 resolver->resolve(); 288 isolate()->RunMicrotasks(); 289 290 EXPECT_EQ("undefined", onFulfilled); 291 EXPECT_EQ(String(), onRejected); 292} 293 294TEST_F(ScriptPromiseResolverTest, rejectVoid) 295{ 296 RefPtr<ScriptPromiseResolver> resolver; 297 ScriptPromise promise; 298 { 299 ScriptState::Scope scope(scriptState()); 300 resolver = ScriptPromiseResolver::create(scriptState()); 301 promise = resolver->promise(); 302 } 303 304 String onFulfilled, onRejected; 305 ASSERT_FALSE(promise.isEmpty()); 306 { 307 ScriptState::Scope scope(scriptState()); 308 promise.then(Function::createFunction(scriptState(), &onFulfilled), Function::createFunction(scriptState(), &onRejected)); 309 } 310 311 resolver->reject(); 312 isolate()->RunMicrotasks(); 313 314 EXPECT_EQ(String(), onFulfilled); 315 EXPECT_EQ("undefined", onRejected); 316} 317 318} // namespace 319 320} // namespace blink 321