xref: /aosp_15_r20/external/pdfium/fxjs/cfx_v8_unittest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2018 The PDFium Authors
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 "fxjs/cfx_v8.h"
6 
7 #include <math.h>
8 
9 #include <memory>
10 
11 #include "testing/fxv8_unittest.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "v8/include/v8-container.h"
14 #include "v8/include/v8-context.h"
15 #include "v8/include/v8-date.h"
16 #include "v8/include/v8-isolate.h"
17 
18 namespace {
19 bool getter_sentinel = false;
20 bool setter_sentinel = false;
21 }  // namespace
22 
23 class CFXV8UnitTest : public FXV8UnitTest {
24  public:
25   CFXV8UnitTest() = default;
26   ~CFXV8UnitTest() override = default;
27 
28   // FXV8UnitTest:
SetUp()29   void SetUp() override {
30     FXV8UnitTest::SetUp();
31     cfx_v8_ = std::make_unique<CFX_V8>(isolate());
32   }
33 
cfx_v8() const34   CFX_V8* cfx_v8() const { return cfx_v8_.get(); }
35 
36  protected:
37   std::unique_ptr<CFX_V8> cfx_v8_;
38 };
39 
TEST_F(CFXV8UnitTest,EmptyLocal)40 TEST_F(CFXV8UnitTest, EmptyLocal) {
41   v8::Isolate::Scope isolate_scope(isolate());
42   v8::HandleScope handle_scope(isolate());
43   v8::Context::Scope context_scope(v8::Context::New(isolate()));
44 
45   v8::Local<v8::Value> empty;
46   EXPECT_FALSE(cfx_v8()->ToBoolean(empty));
47   EXPECT_EQ(0, cfx_v8()->ToInt32(empty));
48   EXPECT_EQ(0.0, cfx_v8()->ToDouble(empty));
49   EXPECT_EQ("", cfx_v8()->ToByteString(empty));
50   EXPECT_EQ(L"", cfx_v8()->ToWideString(empty));
51   EXPECT_TRUE(cfx_v8()->ToObject(empty).IsEmpty());
52   EXPECT_TRUE(cfx_v8()->ToArray(empty).IsEmpty());
53 
54   // Can't set properties on empty objects, but does not fault.
55   v8::Local<v8::Value> marker = cfx_v8()->NewNumber(2);
56   v8::Local<v8::Object> empty_object;
57   cfx_v8()->PutObjectProperty(empty_object, "clams", marker);
58   EXPECT_TRUE(cfx_v8()->GetObjectProperty(empty_object, "clams").IsEmpty());
59   EXPECT_EQ(0u, cfx_v8()->GetObjectPropertyNames(empty_object).size());
60 
61   // Can't set elements in empty arrays, but does not fault.
62   v8::Local<v8::Array> empty_array;
63   cfx_v8()->PutArrayElement(empty_array, 0, marker);
64   EXPECT_TRUE(cfx_v8()->GetArrayElement(empty_array, 0).IsEmpty());
65   EXPECT_EQ(0u, cfx_v8()->GetArrayLength(empty_array));
66 }
67 
TEST_F(CFXV8UnitTest,NewNull)68 TEST_F(CFXV8UnitTest, NewNull) {
69   v8::Isolate::Scope isolate_scope(isolate());
70   v8::HandleScope handle_scope(isolate());
71   v8::Context::Scope context_scope(v8::Context::New(isolate()));
72 
73   auto nullz = cfx_v8()->NewNull();
74   EXPECT_FALSE(cfx_v8()->ToBoolean(nullz));
75   EXPECT_EQ(0, cfx_v8()->ToInt32(nullz));
76   EXPECT_EQ(0.0, cfx_v8()->ToDouble(nullz));
77   EXPECT_EQ("null", cfx_v8()->ToByteString(nullz));
78   EXPECT_EQ(L"null", cfx_v8()->ToWideString(nullz));
79   EXPECT_TRUE(cfx_v8()->ToObject(nullz).IsEmpty());
80   EXPECT_TRUE(cfx_v8()->ToArray(nullz).IsEmpty());
81 }
82 
TEST_F(CFXV8UnitTest,NewUndefined)83 TEST_F(CFXV8UnitTest, NewUndefined) {
84   v8::Isolate::Scope isolate_scope(isolate());
85   v8::HandleScope handle_scope(isolate());
86   v8::Context::Scope context_scope(v8::Context::New(isolate()));
87 
88   auto undef = cfx_v8()->NewUndefined();
89   EXPECT_FALSE(cfx_v8()->ToBoolean(undef));
90   EXPECT_EQ(0, cfx_v8()->ToInt32(undef));
91   EXPECT_TRUE(isnan(cfx_v8()->ToDouble(undef)));
92   EXPECT_EQ("undefined", cfx_v8()->ToByteString(undef));
93   EXPECT_EQ(L"undefined", cfx_v8()->ToWideString(undef));
94   EXPECT_TRUE(cfx_v8()->ToObject(undef).IsEmpty());
95   EXPECT_TRUE(cfx_v8()->ToArray(undef).IsEmpty());
96 }
97 
TEST_F(CFXV8UnitTest,NewBoolean)98 TEST_F(CFXV8UnitTest, NewBoolean) {
99   v8::Isolate::Scope isolate_scope(isolate());
100   v8::HandleScope handle_scope(isolate());
101   v8::Context::Scope context_scope(v8::Context::New(isolate()));
102 
103   auto boolz = cfx_v8()->NewBoolean(true);
104   EXPECT_TRUE(cfx_v8()->ToBoolean(boolz));
105   EXPECT_EQ(1, cfx_v8()->ToInt32(boolz));
106   EXPECT_EQ(1.0, cfx_v8()->ToDouble(boolz));
107   EXPECT_EQ("true", cfx_v8()->ToByteString(boolz));
108   EXPECT_EQ(L"true", cfx_v8()->ToWideString(boolz));
109   EXPECT_TRUE(cfx_v8()->ToObject(boolz).IsEmpty());
110   EXPECT_TRUE(cfx_v8()->ToArray(boolz).IsEmpty());
111 
112   boolz = cfx_v8()->NewBoolean(false);
113   EXPECT_FALSE(cfx_v8()->ToBoolean(boolz));
114   EXPECT_EQ(0, cfx_v8()->ToInt32(boolz));
115   EXPECT_EQ(0.0, cfx_v8()->ToDouble(boolz));
116   EXPECT_EQ("false", cfx_v8()->ToByteString(boolz));
117   EXPECT_EQ(L"false", cfx_v8()->ToWideString(boolz));
118   EXPECT_TRUE(cfx_v8()->ToObject(boolz).IsEmpty());
119   EXPECT_TRUE(cfx_v8()->ToArray(boolz).IsEmpty());
120 }
121 
TEST_F(CFXV8UnitTest,NewNumber)122 TEST_F(CFXV8UnitTest, NewNumber) {
123   v8::Isolate::Scope isolate_scope(isolate());
124   v8::HandleScope handle_scope(isolate());
125   v8::Context::Scope context_scope(v8::Context::New(isolate()));
126 
127   auto num = cfx_v8()->NewNumber(42.1);
128   EXPECT_TRUE(cfx_v8()->ToBoolean(num));
129   EXPECT_EQ(42, cfx_v8()->ToInt32(num));
130   EXPECT_EQ(42.1, cfx_v8()->ToDouble(num));
131   EXPECT_EQ("42.1", cfx_v8()->ToByteString(num));
132   EXPECT_EQ(L"42.1", cfx_v8()->ToWideString(num));
133   EXPECT_TRUE(cfx_v8()->ToObject(num).IsEmpty());
134   EXPECT_TRUE(cfx_v8()->ToArray(num).IsEmpty());
135 }
136 
TEST_F(CFXV8UnitTest,NewString)137 TEST_F(CFXV8UnitTest, NewString) {
138   v8::Isolate::Scope isolate_scope(isolate());
139   v8::HandleScope handle_scope(isolate());
140   v8::Context::Scope context_scope(v8::Context::New(isolate()));
141 
142   auto str = cfx_v8()->NewString("123");
143   EXPECT_TRUE(cfx_v8()->ToBoolean(str));
144   EXPECT_EQ(123, cfx_v8()->ToInt32(str));
145   EXPECT_EQ(123, cfx_v8()->ToDouble(str));
146   EXPECT_EQ("123", cfx_v8()->ToByteString(str));
147   EXPECT_EQ(L"123", cfx_v8()->ToWideString(str));
148   EXPECT_TRUE(cfx_v8()->ToObject(str).IsEmpty());
149   EXPECT_TRUE(cfx_v8()->ToArray(str).IsEmpty());
150 
151   auto str2 = cfx_v8()->NewString(L"123");
152   EXPECT_TRUE(cfx_v8()->ToBoolean(str2));
153   EXPECT_EQ(123, cfx_v8()->ToInt32(str2));
154   EXPECT_EQ(123, cfx_v8()->ToDouble(str2));
155   EXPECT_EQ("123", cfx_v8()->ToByteString(str2));
156   EXPECT_EQ(L"123", cfx_v8()->ToWideString(str2));
157   EXPECT_TRUE(cfx_v8()->ToObject(str2).IsEmpty());
158   EXPECT_TRUE(cfx_v8()->ToArray(str2).IsEmpty());
159 }
160 
TEST_F(CFXV8UnitTest,NewDate)161 TEST_F(CFXV8UnitTest, NewDate) {
162   v8::Isolate::Scope isolate_scope(isolate());
163   v8::HandleScope handle_scope(isolate());
164   v8::Context::Scope context_scope(v8::Context::New(isolate()));
165 
166   auto date = cfx_v8()->NewDate(1111111111);
167   EXPECT_TRUE(cfx_v8()->ToBoolean(date));
168   EXPECT_EQ(1111111111, cfx_v8()->ToInt32(date));
169   EXPECT_EQ(1111111111.0, cfx_v8()->ToDouble(date));
170   EXPECT_NE("", cfx_v8()->ToByteString(date));   // exact format varies.
171   EXPECT_NE(L"", cfx_v8()->ToWideString(date));  // exact format varies.
172   EXPECT_TRUE(cfx_v8()->ToObject(date)->IsObject());
173   EXPECT_TRUE(cfx_v8()->ToArray(date).IsEmpty());
174 }
175 
TEST_F(CFXV8UnitTest,NewArray)176 TEST_F(CFXV8UnitTest, NewArray) {
177   v8::Isolate::Scope isolate_scope(isolate());
178   v8::HandleScope handle_scope(isolate());
179   v8::Context::Scope context_scope(v8::Context::New(isolate()));
180 
181   auto array = cfx_v8()->NewArray();
182   EXPECT_EQ(0u, cfx_v8()->GetArrayLength(array));
183   EXPECT_FALSE(cfx_v8()->GetArrayElement(array, 2).IsEmpty());
184   EXPECT_TRUE(cfx_v8()->GetArrayElement(array, 2)->IsUndefined());
185   EXPECT_EQ(0u, cfx_v8()->GetArrayLength(array));
186 
187   cfx_v8()->PutArrayElement(array, 3, cfx_v8()->NewNumber(12));
188   EXPECT_FALSE(cfx_v8()->GetArrayElement(array, 2).IsEmpty());
189   EXPECT_TRUE(cfx_v8()->GetArrayElement(array, 2)->IsUndefined());
190   EXPECT_FALSE(cfx_v8()->GetArrayElement(array, 3).IsEmpty());
191   EXPECT_TRUE(cfx_v8()->GetArrayElement(array, 3)->IsNumber());
192   EXPECT_EQ(4u, cfx_v8()->GetArrayLength(array));
193 
194   EXPECT_TRUE(cfx_v8()->ToBoolean(array));
195   EXPECT_EQ(0, cfx_v8()->ToInt32(array));
196   double d = cfx_v8()->ToDouble(array);
197   EXPECT_NE(d, d);  // i.e. NaN.
198   EXPECT_EQ(L",,,12", cfx_v8()->ToWideString(array));
199   EXPECT_TRUE(cfx_v8()->ToObject(array)->IsObject());
200   EXPECT_TRUE(cfx_v8()->ToArray(array)->IsArray());
201 }
202 
TEST_F(CFXV8UnitTest,NewObject)203 TEST_F(CFXV8UnitTest, NewObject) {
204   v8::Isolate::Scope isolate_scope(isolate());
205   v8::HandleScope handle_scope(isolate());
206   v8::Context::Scope context_scope(v8::Context::New(isolate()));
207 
208   auto object = cfx_v8()->NewObject();
209   ASSERT_FALSE(object.IsEmpty());
210   EXPECT_EQ(0u, cfx_v8()->GetObjectPropertyNames(object).size());
211   EXPECT_FALSE(cfx_v8()->GetObjectProperty(object, "clams").IsEmpty());
212   EXPECT_TRUE(cfx_v8()->GetObjectProperty(object, "clams")->IsUndefined());
213   EXPECT_EQ(0u, cfx_v8()->GetObjectPropertyNames(object).size());
214 
215   cfx_v8()->PutObjectProperty(object, "clams", cfx_v8()->NewNumber(12));
216   EXPECT_FALSE(cfx_v8()->GetObjectProperty(object, "clams").IsEmpty());
217   EXPECT_TRUE(cfx_v8()->GetObjectProperty(object, "clams")->IsNumber());
218   EXPECT_EQ(1u, cfx_v8()->GetObjectPropertyNames(object).size());
219   EXPECT_EQ(L"clams", cfx_v8()->GetObjectPropertyNames(object)[0]);
220 
221   EXPECT_TRUE(cfx_v8()->ToBoolean(object));
222   EXPECT_EQ(0, cfx_v8()->ToInt32(object));
223   double d = cfx_v8()->ToDouble(object);
224   EXPECT_NE(d, d);  // i.e. NaN.
225   EXPECT_EQ(L"[object Object]", cfx_v8()->ToWideString(object));
226   EXPECT_TRUE(cfx_v8()->ToObject(object)->IsObject());
227   EXPECT_TRUE(cfx_v8()->ToArray(object).IsEmpty());
228 }
229 
TEST_F(CFXV8UnitTest,ThrowFromGetter)230 TEST_F(CFXV8UnitTest, ThrowFromGetter) {
231   v8::Isolate::Scope isolate_scope(isolate());
232   v8::HandleScope handle_scope(isolate());
233   v8::Local<v8::Context> context = v8::Context::New(isolate());
234   v8::Context::Scope context_scope(context);
235 
236   v8::Local<v8::Object> object = cfx_v8()->NewObject();
237   v8::Local<v8::String> name = cfx_v8()->NewString("clams");
238   EXPECT_TRUE(
239       object
240           ->SetAccessor(context, name,
241                         [](v8::Local<v8::Name> property,
242                            const v8::PropertyCallbackInfo<v8::Value>& info) {
243                           getter_sentinel = true;
244                           info.GetIsolate()->ThrowException(property);
245                         })
246           .FromJust());
247   getter_sentinel = false;
248   EXPECT_TRUE(cfx_v8()->GetObjectProperty(object, "clams").IsEmpty());
249   EXPECT_TRUE(getter_sentinel);
250 }
251 
TEST_F(CFXV8UnitTest,ThrowFromSetter)252 TEST_F(CFXV8UnitTest, ThrowFromSetter) {
253   v8::Isolate::Scope isolate_scope(isolate());
254   v8::HandleScope handle_scope(isolate());
255   v8::Local<v8::Context> context = v8::Context::New(isolate());
256   v8::Context::Scope context_scope(context);
257 
258   v8::Local<v8::Object> object = cfx_v8()->NewObject();
259   v8::Local<v8::String> name = cfx_v8()->NewString("clams");
260   EXPECT_TRUE(object
261                   ->SetAccessor(context, name, nullptr,
262                                 [](v8::Local<v8::Name> property,
263                                    v8::Local<v8::Value> value,
264                                    const v8::PropertyCallbackInfo<void>& info) {
265                                   setter_sentinel = true;
266                                   info.GetIsolate()->ThrowException(property);
267                                 })
268                   .FromJust());
269   setter_sentinel = false;
270   cfx_v8()->PutObjectProperty(object, "clams", name);
271   EXPECT_TRUE(setter_sentinel);
272 }
273