[go: nahoru, domu]

blob: 1df58244ffbbed71a2a6196cfb9c6f9d27dfa5b2 [file] [log] [blame]
Avi Drissman4e1b7bc2022-09-15 14:03:501// Copyright 2012 The Chromium Authors
raymes@chromium.org7e346102013-05-16 18:03:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
jam@chromium.org20790a222013-07-25 02:23:055#include "content/renderer/pepper/v8_var_converter.h"
raymes@chromium.org7e346102013-05-16 18:03:576
avi1023d012015-12-25 02:39:147#include <stddef.h>
8#include <stdint.h>
9
raymes@chromium.org7e346102013-05-16 18:03:5710#include <cmath>
dchengcedca5612016-04-09 01:40:1511#include <memory>
Takuto Ikutaadf31eb2019-01-05 00:32:4812#include <unordered_map>
raymes@chromium.org7e346102013-05-16 18:03:5713
Hans Wennborg0917de892020-04-28 20:21:1514#include "base/check.h"
Avi Drissmanadac21992023-01-11 23:46:3915#include "base/functional/bind.h"
Kalvin Leebc3754ae2023-10-01 22:37:3416#include "base/memory/raw_ptr.h"
raymes@chromium.org7e346102013-05-16 18:03:5717#include "base/memory/ref_counted.h"
Hans Wennborg0917de892020-04-28 20:21:1518#include "base/notreached.h"
dmichael@chromium.orgdd6d2212013-09-16 17:09:1419#include "base/run_loop.h"
raymes@chromium.org36dcbed2013-08-16 05:19:2220#include "base/synchronization/waitable_event.h"
Gabriel Charettec7108742019-08-23 03:31:4021#include "base/test/task_environment.h"
raymes@chromium.org7e346102013-05-16 18:03:5722#include "base/values.h"
raymes@chromium.orgba36957a2013-08-23 05:26:3923#include "content/renderer/pepper/resource_converter.h"
Etienne Pierre-dorayd952e092021-11-01 21:56:2124#include "gin/public/isolate_holder.h"
raymes@chromium.org7e346102013-05-16 18:03:5725#include "ppapi/c/pp_bool.h"
26#include "ppapi/c/pp_var.h"
27#include "ppapi/shared_impl/array_var.h"
28#include "ppapi/shared_impl/dictionary_var.h"
29#include "ppapi/shared_impl/ppapi_globals.h"
30#include "ppapi/shared_impl/proxy_lock.h"
31#include "ppapi/shared_impl/scoped_pp_var.h"
32#include "ppapi/shared_impl/test_globals.h"
tommyclia88b6092015-05-14 17:54:0133#include "ppapi/shared_impl/test_utils.h"
raymes@chromium.org7e346102013-05-16 18:03:5734#include "ppapi/shared_impl/var.h"
35#include "ppapi/shared_impl/var_tracker.h"
36#include "testing/gtest/include/gtest/gtest.h"
Dan Elphickc9256736002021-09-16 09:30:1137#include "v8/include/v8-container.h"
38#include "v8/include/v8-context.h"
39#include "v8/include/v8-isolate.h"
40#include "v8/include/v8-microtask-queue.h"
41#include "v8/include/v8-object.h"
42#include "v8/include/v8-persistent-handle.h"
43#include "v8/include/v8-primitive.h"
44#include "v8/include/v8-script.h"
45#include "v8/include/v8-template.h"
raymes@chromium.org7e346102013-05-16 18:03:5746
47using ppapi::ArrayBufferVar;
48using ppapi::ArrayVar;
49using ppapi::DictionaryVar;
50using ppapi::PpapiGlobals;
51using ppapi::ProxyLock;
52using ppapi::ScopedPPVar;
53using ppapi::StringVar;
54using ppapi::TestGlobals;
55using ppapi::TestEqual;
56using ppapi::VarTracker;
57
jam@chromium.orgadab2332013-07-25 18:04:3258namespace content {
raymes@chromium.org7e346102013-05-16 18:03:5759
60namespace {
61
raymes@chromium.org6d48e7072014-06-16 07:23:4062void FromV8ValueComplete(const ScopedPPVar& scoped_var,
63 bool success) {
64 NOTREACHED();
65}
66
raymes@chromium.orgba36957a2013-08-23 05:26:3967class MockResourceConverter : public content::ResourceConverter {
68 public:
dcheng6d18e402014-10-21 12:32:5269 ~MockResourceConverter() override {}
70 void Reset() override {}
71 bool NeedsFlush() override { return false; }
danakj9d03ab62019-05-21 16:34:1272 void Flush(base::OnceCallback<void(bool)> callback) override { NOTREACHED(); }
deepak.s750d68f2015-04-30 07:32:4173 bool FromV8Value(v8::Local<v8::Object> val,
74 v8::Local<v8::Context> context,
dcheng6d18e402014-10-21 12:32:5275 PP_Var* result,
76 bool* was_resource) override {
mgiuca@chromium.org7b21fb432013-09-30 09:48:5977 *was_resource = false;
78 return true;
79 }
dcheng6d18e402014-10-21 12:32:5280 bool ToV8Value(const PP_Var& var,
deepak.s750d68f2015-04-30 07:32:4181 v8::Local<v8::Context> context,
82 v8::Local<v8::Value>* result) override {
mgiuca@chromium.org06242752014-02-24 02:13:2183 return false;
84 }
raymes@chromium.orgba36957a2013-08-23 05:26:3985};
86
raymes@chromium.org7e346102013-05-16 18:03:5787// Maps PP_Var IDs to the V8 value handle they correspond to.
Takuto Ikutaadf31eb2019-01-05 00:32:4888typedef std::unordered_map<int64_t, v8::Local<v8::Value>> VarHandleMap;
raymes@chromium.org7e346102013-05-16 18:03:5789
90bool Equals(const PP_Var& var,
deepak.s750d68f2015-04-30 07:32:4191 v8::Local<v8::Value> val,
Dave Tapuska28169c92023-09-13 14:50:0092 v8::Isolate* isolate,
raymes@chromium.org7e346102013-05-16 18:03:5793 VarHandleMap* visited_ids) {
jam@chromium.org49323b32013-08-09 16:05:0694 if (ppapi::VarTracker::IsVarTypeRefcounted(var.type)) {
jdoerrie5a73d0f2018-10-02 23:54:0595 auto it = visited_ids->find(var.value.as_id);
raymes@chromium.org7e346102013-05-16 18:03:5796 if (it != visited_ids->end())
97 return it->second == val;
98 (*visited_ids)[var.value.as_id] = val;
99 }
100
Ross McIlroyceb8e982018-11-28 11:06:50101 v8::Local<v8::Context> context = isolate->GetCurrentContext();
raymes@chromium.org7e346102013-05-16 18:03:57102 if (val->IsUndefined()) {
103 return var.type == PP_VARTYPE_UNDEFINED;
104 } else if (val->IsNull()) {
105 return var.type == PP_VARTYPE_NULL;
106 } else if (val->IsBoolean() || val->IsBooleanObject()) {
107 return var.type == PP_VARTYPE_BOOL &&
dcarney04cd9642014-11-21 13:58:11108 PP_FromBool(val->ToBoolean(isolate)->Value()) == var.value.as_bool;
raymes@chromium.org7e346102013-05-16 18:03:57109 } else if (val->IsInt32()) {
110 return var.type == PP_VARTYPE_INT32 &&
Ross McIlroyceb8e982018-11-28 11:06:50111 val.As<v8::Int32>()->Value() == var.value.as_int;
raymes@chromium.org7e346102013-05-16 18:03:57112 } else if (val->IsNumber() || val->IsNumberObject()) {
113 return var.type == PP_VARTYPE_DOUBLE &&
Ross McIlroyceb8e982018-11-28 11:06:50114 fabs(val->NumberValue(context).ToChecked() - var.value.as_double) <=
dcarney04cd9642014-11-21 13:58:11115 1.0e-4;
raymes@chromium.org7e346102013-05-16 18:03:57116 } else if (val->IsString() || val->IsStringObject()) {
117 if (var.type != PP_VARTYPE_STRING)
118 return false;
119 StringVar* string_var = StringVar::FromPPVar(var);
120 DCHECK(string_var);
Adam Klein686c0e52018-01-17 23:42:33121 v8::String::Utf8Value utf8(isolate, val);
raymes@chromium.org7e346102013-05-16 18:03:57122 return std::string(*utf8, utf8.length()) == string_var->value();
123 } else if (val->IsArray()) {
124 if (var.type != PP_VARTYPE_ARRAY)
125 return false;
126 ArrayVar* array_var = ArrayVar::FromPPVar(var);
127 DCHECK(array_var);
deepak.s750d68f2015-04-30 07:32:41128 v8::Local<v8::Array> v8_array = val.As<v8::Array>();
raymes@chromium.org7e346102013-05-16 18:03:57129 if (v8_array->Length() != array_var->elements().size())
130 return false;
avi1023d012015-12-25 02:39:14131 for (uint32_t i = 0; i < v8_array->Length(); ++i) {
Dan Elphickcc7538d02019-02-01 13:41:47132 v8::Local<v8::Value> child_v8 =
133 v8_array->Get(context, i).ToLocalChecked();
Dave Tapuska28169c92023-09-13 14:50:00134 if (!Equals(array_var->elements()[i].get(), child_v8, isolate,
135 visited_ids)) {
raymes@chromium.org7e346102013-05-16 18:03:57136 return false;
Dave Tapuska28169c92023-09-13 14:50:00137 }
raymes@chromium.org7e346102013-05-16 18:03:57138 }
139 return true;
140 } else if (val->IsObject()) {
141 if (var.type == PP_VARTYPE_ARRAY_BUFFER) {
142 // TODO(raymes): Implement this when we have tests for array buffers.
143 NOTIMPLEMENTED();
144 return false;
145 } else {
deepak.s750d68f2015-04-30 07:32:41146 v8::Local<v8::Object> v8_object = val.As<v8::Object>();
raymes@chromium.org7e346102013-05-16 18:03:57147 if (var.type != PP_VARTYPE_DICTIONARY)
148 return false;
149 DictionaryVar* dict_var = DictionaryVar::FromPPVar(var);
150 DCHECK(dict_var);
Ross McIlroyceb8e982018-11-28 11:06:50151 v8::Local<v8::Array> property_names(
152 v8_object->GetOwnPropertyNames(context).ToLocalChecked());
raymes@chromium.org7e346102013-05-16 18:03:57153 if (property_names->Length() != dict_var->key_value_map().size())
154 return false;
avi1023d012015-12-25 02:39:14155 for (uint32_t i = 0; i < property_names->Length(); ++i) {
Ross McIlroyceb8e982018-11-28 11:06:50156 v8::Local<v8::Value> key(
157 property_names->Get(context, i).ToLocalChecked());
raymes@chromium.org7e346102013-05-16 18:03:57158
159 if (!key->IsString() && !key->IsNumber())
160 return false;
Ross McIlroyceb8e982018-11-28 11:06:50161 v8::Local<v8::Value> child_v8 =
162 v8_object->Get(context, key).ToLocalChecked();
raymes@chromium.org7e346102013-05-16 18:03:57163
Adam Klein686c0e52018-01-17 23:42:33164 v8::String::Utf8Value name_utf8(isolate, key);
raymes@chromium.org7e346102013-05-16 18:03:57165 ScopedPPVar release_key(ScopedPPVar::PassRef(),
dmichael@chromium.orgad63b5c2014-04-11 21:12:36166 StringVar::StringToPPVar(std::string(
167 *name_utf8, name_utf8.length())));
raymes@chromium.org7e346102013-05-16 18:03:57168 if (!dict_var->HasKey(release_key.get()))
169 return false;
170 ScopedPPVar release_value(ScopedPPVar::PassRef(),
171 dict_var->Get(release_key.get()));
Dave Tapuska28169c92023-09-13 14:50:00172 if (!Equals(release_value.get(), child_v8, isolate, visited_ids)) {
raymes@chromium.org7e346102013-05-16 18:03:57173 return false;
Dave Tapuska28169c92023-09-13 14:50:00174 }
raymes@chromium.org7e346102013-05-16 18:03:57175 }
176 return true;
177 }
178 }
179 return false;
180}
181
Dave Tapuska28169c92023-09-13 14:50:00182bool Equals(const PP_Var& var, v8::Local<v8::Value> val, v8::Isolate* isolate) {
raymes@chromium.org7e346102013-05-16 18:03:57183 VarHandleMap var_handle_map;
Dave Tapuska28169c92023-09-13 14:50:00184 return Equals(var, val, isolate, &var_handle_map);
raymes@chromium.org7e346102013-05-16 18:03:57185}
186
187class V8VarConverterTest : public testing::Test {
188 public:
marja@chromium.org52d6c3202013-06-11 04:28:12189 V8VarConverterTest()
Etienne Pierre-dorayd952e092021-11-01 21:56:21190 : isolate_holder_(task_environment_.GetMainThreadTaskRunner(),
191 gin::IsolateHolder::IsolateType::kTest),
192 isolate_scope_(isolate_holder_.isolate()) {
193 isolate_ = isolate_holder_.isolate();
raymes@chromium.orgbe981852013-08-27 08:07:10194 PP_Instance dummy = 1234;
Peter Boströmdd7e40ec2021-04-05 20:40:10195 converter_ = std::make_unique<V8VarConverter>(
196 dummy, std::unique_ptr<ResourceConverter>(new MockResourceConverter));
raymes@chromium.org4a52cf252013-08-22 09:29:08197 }
dchengf5762152014-10-29 02:12:06198 ~V8VarConverterTest() override {}
raymes@chromium.org7e346102013-05-16 18:03:57199
200 // testing::Test implementation.
dchengf5762152014-10-29 02:12:06201 void SetUp() override {
dmichael@chromium.orgaafb1d42013-09-12 20:01:14202 ProxyLock::Acquire();
marja@chromium.org52d6c3202013-06-11 04:28:12203 v8::HandleScope handle_scope(isolate_);
deepak.s750d68f2015-04-30 07:32:41204 v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
Ivan Kotenkov2c0d2bb32017-11-01 15:41:28205 context_.Reset(isolate_, v8::Context::New(isolate_, nullptr, global));
raymes@chromium.org7e346102013-05-16 18:03:57206 }
dchengf5762152014-10-29 02:12:06207 void TearDown() override {
punithnayak24fe2292023-10-17 12:21:45208 isolate_ = nullptr;
jochen@chromium.orgd3c97d12013-12-02 12:19:23209 context_.Reset();
raymes@chromium.org7e346102013-05-16 18:03:57210 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
211 ProxyLock::Release();
212 }
213
214 protected:
deepak.s750d68f2015-04-30 07:32:41215 bool FromV8ValueSync(v8::Local<v8::Value> val,
216 v8::Local<v8::Context> context,
raymes@chromium.org36dcbed2013-08-16 05:19:22217 PP_Var* result) {
danakj9d03ab62019-05-21 16:34:12218 V8VarConverter::VarResult conversion_result = converter_->FromV8Value(
219 val, context, base::BindOnce(&FromV8ValueComplete));
raymes@chromium.org6d48e7072014-06-16 07:23:40220 DCHECK(conversion_result.completed_synchronously);
221 if (conversion_result.success)
222 *result = conversion_result.var.Release();
raymes@chromium.org36dcbed2013-08-16 05:19:22223
raymes@chromium.org6d48e7072014-06-16 07:23:40224 return conversion_result.success;
raymes@chromium.org36dcbed2013-08-16 05:19:22225 }
226
raymes@chromium.org7e346102013-05-16 18:03:57227 bool RoundTrip(const PP_Var& var, PP_Var* result) {
marja@chromium.org52d6c3202013-06-11 04:28:12228 v8::HandleScope handle_scope(isolate_);
marja@chromium.org52d6c3202013-06-11 04:28:12229 v8::Local<v8::Context> context =
230 v8::Local<v8::Context>::New(isolate_, context_);
jochen@chromium.orgd3c97d12013-12-02 12:19:23231 v8::Context::Scope context_scope(context);
Camillo Brunid0313f7a2023-07-03 17:44:52232 v8::MicrotasksScope microtasks(context,
Jochen Eisingerd00cc712021-04-17 07:23:13233 v8::MicrotasksScope::kDoNotRunMicrotasks);
deepak.s750d68f2015-04-30 07:32:41234 v8::Local<v8::Value> v8_result;
raymes@chromium.orgba36957a2013-08-23 05:26:39235 if (!converter_->ToV8Value(var, context, &v8_result))
raymes@chromium.org7e346102013-05-16 18:03:57236 return false;
Dave Tapuska28169c92023-09-13 14:50:00237 if (!Equals(var, v8_result, isolate_)) {
raymes@chromium.org7e346102013-05-16 18:03:57238 return false;
Dave Tapuska28169c92023-09-13 14:50:00239 }
raymes@chromium.org36dcbed2013-08-16 05:19:22240 if (!FromV8ValueSync(v8_result, context, result))
raymes@chromium.org7e346102013-05-16 18:03:57241 return false;
242 return true;
243 }
244
245 // Assumes a ref for var.
246 bool RoundTripAndCompare(const PP_Var& var) {
247 ScopedPPVar expected(ScopedPPVar::PassRef(), var);
248 PP_Var actual_var;
249 if (!RoundTrip(expected.get(), &actual_var))
250 return false;
251 ScopedPPVar actual(ScopedPPVar::PassRef(), actual_var);
raymes@chromium.org2c6b74d72014-03-26 05:04:16252 return TestEqual(expected.get(), actual.get(), false);
raymes@chromium.org7e346102013-05-16 18:03:57253 }
254
punithnayak24fe2292023-10-17 12:21:45255 raw_ptr<v8::Isolate> isolate_;
marja@chromium.org52d6c3202013-06-11 04:28:12256
raymes@chromium.org7e346102013-05-16 18:03:57257 // Context for the JavaScript in the test.
258 v8::Persistent<v8::Context> context_;
259
dchengcedca5612016-04-09 01:40:15260 std::unique_ptr<V8VarConverter> converter_;
raymes@chromium.orgba36957a2013-08-23 05:26:39261
raymes@chromium.org7e346102013-05-16 18:03:57262 private:
Tomasz Moniuszko8fbe5d882019-09-23 14:49:49263 // Required to receive callbacks.
264 base::test::TaskEnvironment task_environment_;
Etienne Pierre-dorayd952e092021-11-01 21:56:21265 gin::IsolateHolder isolate_holder_;
266 v8::Isolate::Scope isolate_scope_;
raymes@chromium.org4a52cf252013-08-22 09:29:08267
skyostil23490d42015-06-12 12:54:26268 TestGlobals globals_;
raymes@chromium.org7e346102013-05-16 18:03:57269};
270
271} // namespace
272
273TEST_F(V8VarConverterTest, SimpleRoundTripTest) {
274 EXPECT_TRUE(RoundTripAndCompare(PP_MakeUndefined()));
275 EXPECT_TRUE(RoundTripAndCompare(PP_MakeNull()));
276 EXPECT_TRUE(RoundTripAndCompare(PP_MakeInt32(100)));
277 EXPECT_TRUE(RoundTripAndCompare(PP_MakeBool(PP_TRUE)));
278 EXPECT_TRUE(RoundTripAndCompare(PP_MakeDouble(53.75)));
279}
280
281TEST_F(V8VarConverterTest, StringRoundTripTest) {
282 EXPECT_TRUE(RoundTripAndCompare(StringVar::StringToPPVar("")));
283 EXPECT_TRUE(RoundTripAndCompare(StringVar::StringToPPVar("hello world!")));
284}
285
286TEST_F(V8VarConverterTest, ArrayBufferRoundTripTest) {
287 // TODO(raymes): Testing this here requires spinning up some of WebKit.
288 // Work out how to do this.
289}
290
291TEST_F(V8VarConverterTest, DictionaryArrayRoundTripTest) {
292 // Empty array.
293 scoped_refptr<ArrayVar> array(new ArrayVar);
294 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
295 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
296
297 size_t index = 0;
298
299 // Array with primitives.
300 array->Set(index++, PP_MakeUndefined());
301 array->Set(index++, PP_MakeNull());
302 array->Set(index++, PP_MakeInt32(100));
303 array->Set(index++, PP_MakeBool(PP_FALSE));
304 array->Set(index++, PP_MakeDouble(0.123));
305 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
306
307 // Array with 2 references to the same string.
dmichael@chromium.orgad63b5c2014-04-11 21:12:36308 ScopedPPVar release_string(ScopedPPVar::PassRef(),
309 StringVar::StringToPPVar("abc"));
raymes@chromium.org7e346102013-05-16 18:03:57310 array->Set(index++, release_string.get());
311 array->Set(index++, release_string.get());
312 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
313
314 // Array with nested array that references the same string.
315 scoped_refptr<ArrayVar> array2(new ArrayVar);
316 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar());
317 array2->Set(0, release_string.get());
318 array->Set(index++, release_array2.get());
319 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
320
321 // Empty dictionary.
322 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
323 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
324 dictionary->GetPPVar());
325 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
326
327 // Dictionary with primitives.
328 dictionary->SetWithStringKey("1", PP_MakeUndefined());
329 dictionary->SetWithStringKey("2", PP_MakeNull());
330 dictionary->SetWithStringKey("3", PP_MakeInt32(-100));
331 dictionary->SetWithStringKey("4", PP_MakeBool(PP_TRUE));
332 dictionary->SetWithStringKey("5", PP_MakeDouble(-103.52));
333 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
334
335 // Dictionary with 2 references to the same string.
336 dictionary->SetWithStringKey("6", release_string.get());
337 dictionary->SetWithStringKey("7", release_string.get());
338 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
339
340 // Dictionary with nested dictionary that references the same string.
341 scoped_refptr<DictionaryVar> dictionary2(new DictionaryVar);
342 ScopedPPVar release_dictionary2(ScopedPPVar::PassRef(),
343 dictionary2->GetPPVar());
344 dictionary2->SetWithStringKey("abc", release_string.get());
345 dictionary->SetWithStringKey("8", release_dictionary2.get());
346 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
347
348 // Array with dictionary.
349 array->Set(index++, release_dictionary.get());
350 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
351
352 // Array with dictionary with array.
353 array2->Set(0, PP_MakeInt32(100));
354 dictionary->SetWithStringKey("9", release_array2.get());
355 EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar()));
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36356}
raymes@chromium.org7e346102013-05-16 18:03:57357
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36358TEST_F(V8VarConverterTest, Cycles) {
359 // Check that cycles aren't converted.
360 v8::HandleScope handle_scope(isolate_);
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36361 v8::Local<v8::Context> context =
362 v8::Local<v8::Context>::New(isolate_, context_);
jochen@chromium.orgd3c97d12013-12-02 12:19:23363 v8::Context::Scope context_scope(context);
Camillo Brunid0313f7a2023-07-03 17:44:52364 v8::MicrotasksScope microtasks(context,
Jochen Eisingerd00cc712021-04-17 07:23:13365 v8::MicrotasksScope::kDoNotRunMicrotasks);
raymes@chromium.org7e346102013-05-16 18:03:57366
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36367 // Var->V8 conversion.
368 {
369 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
370 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(),
371 dictionary->GetPPVar());
372 scoped_refptr<ArrayVar> array(new ArrayVar);
373 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar());
374
375 dictionary->SetWithStringKey("1", release_array.get());
376 array->Set(0, release_dictionary.get());
377
deepak.s750d68f2015-04-30 07:32:41378 v8::Local<v8::Value> v8_result;
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36379
380 // Array <-> dictionary cycle.
381 dictionary->SetWithStringKey("1", release_array.get());
dmichael@chromium.orgad63b5c2014-04-11 21:12:36382 ASSERT_FALSE(
383 converter_->ToV8Value(release_dictionary.get(), context, &v8_result));
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36384 // Break the cycle.
385 // TODO(raymes): We need some better machinery for releasing vars with
386 // cycles. Remove the code below once we have that.
387 dictionary->DeleteWithStringKey("1");
388
389 // Array with self reference.
390 array->Set(0, release_array.get());
dmichael@chromium.orgad63b5c2014-04-11 21:12:36391 ASSERT_FALSE(
392 converter_->ToV8Value(release_array.get(), context, &v8_result));
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36393 // Break the self reference.
394 array->Set(0, PP_MakeUndefined());
395 }
396
397 // V8->Var conversion.
398 {
deepak.s750d68f2015-04-30 07:32:41399 v8::Local<v8::Object> object = v8::Object::New(isolate_);
400 v8::Local<v8::Array> array = v8::Array::New(isolate_);
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36401
402 PP_Var var_result;
403
404 // Array <-> dictionary cycle.
405 std::string key = "1";
Ross McIlroyceb8e982018-11-28 11:06:50406 object
407 ->Set(context,
408 v8::String::NewFromUtf8(isolate_, key.c_str(),
409 v8::NewStringType::kInternalized,
410 key.length())
411 .ToLocalChecked(),
412 array)
413 .ToChecked();
414 array->Set(context, 0, object).ToChecked();
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36415
raymes@chromium.org36dcbed2013-08-16 05:19:22416 ASSERT_FALSE(FromV8ValueSync(object, context, &var_result));
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36417
418 // Array with self reference.
Dan Elphickcc7538d02019-02-01 13:41:47419 array->Set(context, 0, array).Check();
raymes@chromium.org36dcbed2013-08-16 05:19:22420 ASSERT_FALSE(FromV8ValueSync(array, context, &var_result));
raymes@chromium.orgb3e3595a9d2013-06-19 03:10:36421 }
raymes@chromium.org7e346102013-05-16 18:03:57422}
423
424TEST_F(V8VarConverterTest, StrangeDictionaryKeyTest) {
425 {
426 // Test keys with '.'.
427 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar);
428 dictionary->SetWithStringKey(".", PP_MakeUndefined());
429 dictionary->SetWithStringKey("x.y", PP_MakeUndefined());
430 EXPECT_TRUE(RoundTripAndCompare(dictionary->GetPPVar()));
431 }
432
433 {
434 // Test non-string key types. They should be cast to strings.
marja@chromium.org52d6c3202013-06-11 04:28:12435 v8::HandleScope handle_scope(isolate_);
jochen@chromium.orgd3c97d12013-12-02 12:19:23436 v8::Local<v8::Context> context =
437 v8::Local<v8::Context>::New(isolate_, context_);
438 v8::Context::Scope context_scope(context);
Camillo Brunid0313f7a2023-07-03 17:44:52439 v8::MicrotasksScope microtasks(context,
440 v8::MicrotasksScope::kDoNotRunMicrotasks);
raymes@chromium.org7e346102013-05-16 18:03:57441
dmichael@chromium.orgad63b5c2014-04-11 21:12:36442 const char* source =
443 "(function() {"
raymes@chromium.org7e346102013-05-16 18:03:57444 "return {"
dmichael@chromium.orgad63b5c2014-04-11 21:12:36445 "1: 'foo',"
446 "'2': 'bar',"
447 "true: 'baz',"
448 "false: 'qux',"
449 "null: 'quux',"
450 "undefined: 'oops'"
raymes@chromium.org7e346102013-05-16 18:03:57451 "};"
452 "})();";
453
deepak.s750d68f2015-04-30 07:32:41454 v8::Local<v8::Script> script(
Camillo Brunie5440c762020-09-10 11:53:35455 v8::Script::Compile(
456 context, v8::String::NewFromUtf8(isolate_, source).ToLocalChecked())
Adam Klein8a35b5b2018-01-17 00:51:00457 .ToLocalChecked());
458 v8::Local<v8::Object> object =
459 script->Run(context).ToLocalChecked().As<v8::Object>();
raymes@chromium.org7e346102013-05-16 18:03:57460
raymes@chromium.org7e346102013-05-16 18:03:57461 PP_Var actual;
dmichael@chromium.orgad63b5c2014-04-11 21:12:36462 ASSERT_TRUE(FromV8ValueSync(
463 object, v8::Local<v8::Context>::New(isolate_, context_), &actual));
raymes@chromium.org7e346102013-05-16 18:03:57464 ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual);
465
466 scoped_refptr<DictionaryVar> expected(new DictionaryVar);
467 ScopedPPVar foo(ScopedPPVar::PassRef(), StringVar::StringToPPVar("foo"));
468 expected->SetWithStringKey("1", foo.get());
469 ScopedPPVar bar(ScopedPPVar::PassRef(), StringVar::StringToPPVar("bar"));
470 expected->SetWithStringKey("2", bar.get());
471 ScopedPPVar baz(ScopedPPVar::PassRef(), StringVar::StringToPPVar("baz"));
472 expected->SetWithStringKey("true", baz.get());
473 ScopedPPVar qux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("qux"));
474 expected->SetWithStringKey("false", qux.get());
475 ScopedPPVar quux(ScopedPPVar::PassRef(), StringVar::StringToPPVar("quux"));
476 expected->SetWithStringKey("null", quux.get());
477 ScopedPPVar oops(ScopedPPVar::PassRef(), StringVar::StringToPPVar("oops"));
478 expected->SetWithStringKey("undefined", oops.get());
dmichael@chromium.orgad63b5c2014-04-11 21:12:36479 ScopedPPVar release_expected(ScopedPPVar::PassRef(), expected->GetPPVar());
raymes@chromium.org7e346102013-05-16 18:03:57480
raymes@chromium.org2c6b74d72014-03-26 05:04:16481 ASSERT_TRUE(TestEqual(release_expected.get(), release_actual.get(), true));
raymes@chromium.org7e346102013-05-16 18:03:57482 }
483}
484
jam@chromium.orgadab2332013-07-25 18:04:32485} // namespace content