1 // Copyright 2019 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 "third_party/blink/renderer/core/streams/stream_promise_resolver.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
9 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
10 #include "third_party/blink/renderer/core/streams/promise_handler.h"
11 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
12 #include "third_party/blink/renderer/platform/heap/heap.h"
13 #include "third_party/blink/renderer/platform/heap/visitor.h"
14
15 namespace blink {
16
17 namespace {
18
TEST(StreamPromiseResolverTest,Construct)19 TEST(StreamPromiseResolverTest, Construct) {
20 V8TestingScope scope;
21 auto* promise =
22 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
23 EXPECT_TRUE(promise->V8Promise(scope.GetIsolate())->IsPromise());
24 EXPECT_FALSE(promise->IsSettled());
25 }
26
TEST(StreamPromiseResolverTest,Resolve)27 TEST(StreamPromiseResolverTest, Resolve) {
28 V8TestingScope scope;
29 auto* isolate = scope.GetIsolate();
30 auto* promise =
31 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
32 promise->Resolve(scope.GetScriptState(), v8::Null(isolate));
33 ASSERT_EQ(promise->State(isolate), v8::Promise::kFulfilled);
34 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsNull());
35 EXPECT_TRUE(promise->IsSettled());
36 }
37
TEST(StreamPromiseResolverTest,ResolveWithUndefined)38 TEST(StreamPromiseResolverTest, ResolveWithUndefined) {
39 V8TestingScope scope;
40 auto* isolate = scope.GetIsolate();
41 auto* promise =
42 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
43 promise->ResolveWithUndefined(scope.GetScriptState());
44 ASSERT_EQ(promise->State(isolate), v8::Promise::kFulfilled);
45 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsUndefined());
46 EXPECT_TRUE(promise->IsSettled());
47 }
48
TEST(StreamPromiseResolverTest,Reject)49 TEST(StreamPromiseResolverTest, Reject) {
50 V8TestingScope scope;
51 auto* isolate = scope.GetIsolate();
52 auto* promise =
53 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
54 promise->Reject(scope.GetScriptState(), v8::Number::New(isolate, 2));
55 ASSERT_EQ(promise->State(isolate), v8::Promise::kRejected);
56 auto result = promise->V8Promise(isolate)->Result();
57 ASSERT_TRUE(result->IsNumber());
58 EXPECT_EQ(result.As<v8::Number>()->Value(), 2.0);
59 EXPECT_TRUE(promise->IsSettled());
60 }
61
TEST(StreamPromiseResolverTest,RejectDoesNothingAfterResolve)62 TEST(StreamPromiseResolverTest, RejectDoesNothingAfterResolve) {
63 V8TestingScope scope;
64 auto* isolate = scope.GetIsolate();
65 auto* promise =
66 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
67 promise->Resolve(scope.GetScriptState(), v8::Undefined(isolate));
68 promise->Reject(scope.GetScriptState(), v8::Null(isolate));
69 ASSERT_EQ(promise->State(isolate), v8::Promise::kFulfilled);
70 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsUndefined());
71 }
72
TEST(StreamPromiseResolverTest,ResolveDoesNothingAfterReject)73 TEST(StreamPromiseResolverTest, ResolveDoesNothingAfterReject) {
74 V8TestingScope scope;
75 auto* isolate = scope.GetIsolate();
76 auto* promise =
77 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
78 promise->Reject(scope.GetScriptState(), v8::Null(isolate));
79 promise->Resolve(scope.GetScriptState(), v8::Undefined(isolate));
80 ASSERT_EQ(promise->State(isolate), v8::Promise::kRejected);
81 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsNull());
82 }
83
TEST(StreamPromiseResolverTest,ResolveDoesNothingInsideResolve)84 TEST(StreamPromiseResolverTest, ResolveDoesNothingInsideResolve) {
85 V8TestingScope scope;
86 auto* isolate = scope.GetIsolate();
87 auto* promise =
88 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
89
90 // Create an object equivalent to
91 // value = {
92 // get then() {
93 // resolvePromise(promise, undefined);
94 // runMicrotasks();
95 // }
96 // }
97 class ThenGetter final : public ScriptFunction {
98 public:
99 static v8::Local<v8::Function> Create(ScriptState* script_state,
100 StreamPromiseResolver* promise) {
101 return MakeGarbageCollected<ThenGetter>(script_state, promise)
102 ->BindToV8Function();
103 }
104
105 ThenGetter(ScriptState* script_state, StreamPromiseResolver* promise)
106 : ScriptFunction(script_state), promise_(promise) {}
107
108 void Trace(Visitor* visitor) override {
109 visitor->Trace(promise_);
110 ScriptFunction::Trace(visitor);
111 }
112
113 private:
114 void CallRaw(const v8::FunctionCallbackInfo<v8::Value>&) override {
115 auto* isolate = GetScriptState()->GetIsolate();
116 EXPECT_TRUE(promise_->IsSettled());
117 promise_->Resolve(GetScriptState(), v8::Undefined(isolate));
118 v8::MicrotasksScope::PerformCheckpoint(isolate);
119 }
120
121 Member<StreamPromiseResolver> promise_;
122 };
123
124 auto value = v8::Object::New(isolate);
125 v8::PropertyDescriptor property_descriptor(
126 ThenGetter::Create(scope.GetScriptState(), promise),
127 v8::Undefined(isolate));
128 const auto then = V8String(isolate, "then");
129 value->DefineProperty(scope.GetContext(), then, property_descriptor).Check();
130
131 // Resolving with |value| will call the "then" getter synchronously.
132 promise->Resolve(scope.GetScriptState(), value);
133 ASSERT_EQ(promise->State(isolate), v8::Promise::kFulfilled);
134 EXPECT_EQ(promise->V8Promise(isolate)->Result(), value);
135 }
136
TEST(StreamPromiseResolverTest,GetScriptPromise)137 TEST(StreamPromiseResolverTest, GetScriptPromise) {
138 V8TestingScope scope;
139 auto* promise =
140 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
141 ScriptPromise script_promise =
142 promise->GetScriptPromise(scope.GetScriptState());
143 EXPECT_FALSE(script_promise.IsEmpty());
144 }
145
TEST(StreamPromiseResolverTest,MarkAsHandled)146 TEST(StreamPromiseResolverTest, MarkAsHandled) {
147 V8TestingScope scope;
148 auto* promise =
149 MakeGarbageCollected<StreamPromiseResolver>(scope.GetScriptState());
150 auto* isolate = scope.GetIsolate();
151 promise->MarkAsHandled(isolate);
152 EXPECT_TRUE(promise->V8Promise(isolate)->HasHandler());
153 }
154
TEST(StreamPromiseResolverTest,CreateResolved)155 TEST(StreamPromiseResolverTest, CreateResolved) {
156 V8TestingScope scope;
157 auto* isolate = scope.GetIsolate();
158 auto* promise = StreamPromiseResolver::CreateResolved(scope.GetScriptState(),
159 v8::Null(isolate));
160 ASSERT_EQ(promise->State(isolate), v8::Promise::kFulfilled);
161 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsNull());
162 EXPECT_TRUE(promise->IsSettled());
163 }
164
TEST(StreamPromiseResolverTest,CreateResolvedWithUndefined)165 TEST(StreamPromiseResolverTest, CreateResolvedWithUndefined) {
166 V8TestingScope scope;
167 auto* isolate = scope.GetIsolate();
168 auto* promise = StreamPromiseResolver::CreateResolvedWithUndefined(
169 scope.GetScriptState());
170 ASSERT_EQ(promise->State(isolate), v8::Promise::kFulfilled);
171 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsUndefined());
172 EXPECT_TRUE(promise->IsSettled());
173 }
174
TEST(StreamPromiseResolverTest,CreateRejected)175 TEST(StreamPromiseResolverTest, CreateRejected) {
176 V8TestingScope scope;
177 auto* isolate = scope.GetIsolate();
178 auto* promise = StreamPromiseResolver::CreateRejected(scope.GetScriptState(),
179 v8::Null(isolate));
180 ASSERT_EQ(promise->State(isolate), v8::Promise::kRejected);
181 EXPECT_TRUE(promise->V8Promise(isolate)->Result()->IsNull());
182 EXPECT_TRUE(promise->IsSettled());
183 }
184
185 } // namespace
186
187 } // namespace blink
188