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