1 // Copyright 2016 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 "extensions/renderer/bindings/api_binding_test_util.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/strings/string_util.h"
10 #include "base/values.h"
11 #include "content/public/renderer/v8_value_converter.h"
12 #include "gin/converter.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace extensions {
16
17 namespace {
18
19 // Common call function implementation. Calls the given |function| with the
20 // specified |receiver| and arguments. If the call succeeds (doesn't throw an
21 // error), populates |out_value| with the returned result. If the call does
22 // throw, populates |out_error| with the thrown error.
23 // Returns true if the function runs without throwing an error.
RunFunctionImpl(v8::Local<v8::Function> function,v8::Local<v8::Context> context,v8::Local<v8::Value> receiver,int argc,v8::Local<v8::Value> argv[],v8::Local<v8::Value> * out_value,std::string * out_error)24 bool RunFunctionImpl(v8::Local<v8::Function> function,
25 v8::Local<v8::Context> context,
26 v8::Local<v8::Value> receiver,
27 int argc,
28 v8::Local<v8::Value> argv[],
29 v8::Local<v8::Value>* out_value,
30 std::string* out_error) {
31 v8::TryCatch try_catch(context->GetIsolate());
32 v8::MaybeLocal<v8::Value> maybe_result =
33 function->Call(context, receiver, argc, argv);
34 if (try_catch.HasCaught()) {
35 *out_error =
36 gin::V8ToString(context->GetIsolate(), try_catch.Message()->Get());
37 return false;
38 }
39 v8::Local<v8::Value> result;
40 if (!maybe_result.ToLocal(&result)) {
41 *out_error = "Could not convert result to v8::Local.";
42 return false;
43 }
44 *out_value = result;
45 return true;
46 }
47
48 } // namespace
49
ReplaceSingleQuotes(base::StringPiece str)50 std::string ReplaceSingleQuotes(base::StringPiece str) {
51 std::string result;
52 base::ReplaceChars(str.as_string(), "'", "\"", &result);
53 return result;
54 }
55
ValueFromString(base::StringPiece str)56 std::unique_ptr<base::Value> ValueFromString(base::StringPiece str) {
57 std::unique_ptr<base::Value> value =
58 base::JSONReader::ReadDeprecated(ReplaceSingleQuotes(str));
59 EXPECT_TRUE(value) << str;
60 return value;
61 }
62
ListValueFromString(base::StringPiece str)63 std::unique_ptr<base::ListValue> ListValueFromString(base::StringPiece str) {
64 return base::ListValue::From(ValueFromString(str));
65 }
66
DictionaryValueFromString(base::StringPiece str)67 std::unique_ptr<base::DictionaryValue> DictionaryValueFromString(
68 base::StringPiece str) {
69 return base::DictionaryValue::From(ValueFromString(str));
70 }
71
ValueToString(const base::Value & value)72 std::string ValueToString(const base::Value& value) {
73 std::string json;
74 EXPECT_TRUE(base::JSONWriter::Write(value, &json));
75 return json;
76 }
77
V8ToString(v8::Local<v8::Value> value,v8::Local<v8::Context> context)78 std::string V8ToString(v8::Local<v8::Value> value,
79 v8::Local<v8::Context> context) {
80 if (value.IsEmpty())
81 return "empty";
82 if (value->IsNull())
83 return "null";
84 if (value->IsUndefined())
85 return "undefined";
86 if (value->IsFunction())
87 return "function";
88 std::unique_ptr<base::Value> json = V8ToBaseValue(value, context);
89 if (!json)
90 return "unserializable";
91 return ValueToString(*json);
92 }
93
V8ValueFromScriptSource(v8::Local<v8::Context> context,base::StringPiece source)94 v8::Local<v8::Value> V8ValueFromScriptSource(v8::Local<v8::Context> context,
95 base::StringPiece source) {
96 v8::MaybeLocal<v8::Script> maybe_script = v8::Script::Compile(
97 context, gin::StringToV8(context->GetIsolate(), source));
98 v8::Local<v8::Script> script;
99 if (!maybe_script.ToLocal(&script))
100 return v8::Local<v8::Value>();
101 return script->Run(context).ToLocalChecked();
102 }
103
FunctionFromString(v8::Local<v8::Context> context,base::StringPiece source)104 v8::Local<v8::Function> FunctionFromString(v8::Local<v8::Context> context,
105 base::StringPiece source) {
106 v8::Local<v8::Value> value = V8ValueFromScriptSource(context, source);
107 v8::Local<v8::Function> function;
108 EXPECT_TRUE(gin::ConvertFromV8(context->GetIsolate(), value, &function));
109 return function;
110 }
111
V8ToBaseValue(v8::Local<v8::Value> value,v8::Local<v8::Context> context)112 std::unique_ptr<base::Value> V8ToBaseValue(v8::Local<v8::Value> value,
113 v8::Local<v8::Context> context) {
114 return content::V8ValueConverter::Create()->FromV8Value(value, context);
115 }
116
RunFunction(v8::Local<v8::Function> function,v8::Local<v8::Context> context,v8::Local<v8::Value> receiver,int argc,v8::Local<v8::Value> argv[])117 v8::Local<v8::Value> RunFunction(v8::Local<v8::Function> function,
118 v8::Local<v8::Context> context,
119 v8::Local<v8::Value> receiver,
120 int argc,
121 v8::Local<v8::Value> argv[]) {
122 std::string error;
123 v8::Local<v8::Value> result;
124 EXPECT_TRUE(
125 RunFunctionImpl(function, context, receiver, argc, argv, &result, &error))
126 << error;
127 EXPECT_FALSE(result.IsEmpty());
128 return result;
129 }
130
RunFunction(v8::Local<v8::Function> function,v8::Local<v8::Context> context,int argc,v8::Local<v8::Value> argv[])131 v8::Local<v8::Value> RunFunction(v8::Local<v8::Function> function,
132 v8::Local<v8::Context> context,
133 int argc,
134 v8::Local<v8::Value> argv[]) {
135 return RunFunction(function, context, v8::Undefined(context->GetIsolate()),
136 argc, argv);
137 }
138
RunFunctionOnGlobal(v8::Local<v8::Function> function,v8::Local<v8::Context> context,int argc,v8::Local<v8::Value> argv[])139 v8::Local<v8::Value> RunFunctionOnGlobal(v8::Local<v8::Function> function,
140 v8::Local<v8::Context> context,
141 int argc,
142 v8::Local<v8::Value> argv[]) {
143 return RunFunction(function, context, context->Global(), argc, argv);
144 }
145
RunFunctionOnGlobalAndIgnoreResult(v8::Local<v8::Function> function,v8::Local<v8::Context> context,int argc,v8::Local<v8::Value> argv[])146 void RunFunctionOnGlobalAndIgnoreResult(v8::Local<v8::Function> function,
147 v8::Local<v8::Context> context,
148 int argc,
149 v8::Local<v8::Value> argv[]) {
150 RunFunction(function, context, context->Global(), argc, argv);
151 }
152
RunFunctionOnGlobalAndReturnHandle(v8::Local<v8::Function> function,v8::Local<v8::Context> context,int argc,v8::Local<v8::Value> argv[])153 v8::Global<v8::Value> RunFunctionOnGlobalAndReturnHandle(
154 v8::Local<v8::Function> function,
155 v8::Local<v8::Context> context,
156 int argc,
157 v8::Local<v8::Value> argv[]) {
158 return v8::Global<v8::Value>(
159 context->GetIsolate(),
160 RunFunction(function, context, context->Global(), argc, argv));
161 }
162
RunFunctionAndExpectError(v8::Local<v8::Function> function,v8::Local<v8::Context> context,v8::Local<v8::Value> receiver,int argc,v8::Local<v8::Value> argv[],const std::string & expected_error)163 void RunFunctionAndExpectError(v8::Local<v8::Function> function,
164 v8::Local<v8::Context> context,
165 v8::Local<v8::Value> receiver,
166 int argc,
167 v8::Local<v8::Value> argv[],
168 const std::string& expected_error) {
169 std::string error;
170 v8::Local<v8::Value> result;
171 EXPECT_FALSE(RunFunctionImpl(function, context, receiver, argc, argv, &result,
172 &error));
173 EXPECT_TRUE(result.IsEmpty());
174 EXPECT_EQ(expected_error, error);
175 }
176
RunFunctionAndExpectError(v8::Local<v8::Function> function,v8::Local<v8::Context> context,int argc,v8::Local<v8::Value> argv[],const std::string & expected_error)177 void RunFunctionAndExpectError(v8::Local<v8::Function> function,
178 v8::Local<v8::Context> context,
179 int argc,
180 v8::Local<v8::Value> argv[],
181 const std::string& expected_error) {
182 RunFunctionAndExpectError(function, context,
183 v8::Undefined(context->GetIsolate()), argc, argv,
184 expected_error);
185 }
186
GetPropertyFromObject(v8::Local<v8::Object> object,v8::Local<v8::Context> context,base::StringPiece key)187 v8::Local<v8::Value> GetPropertyFromObject(v8::Local<v8::Object> object,
188 v8::Local<v8::Context> context,
189 base::StringPiece key) {
190 v8::Local<v8::Value> result;
191 EXPECT_TRUE(object->Get(context, gin::StringToV8(context->GetIsolate(), key))
192 .ToLocal(&result));
193 return result;
194 }
195
GetBaseValuePropertyFromObject(v8::Local<v8::Object> object,v8::Local<v8::Context> context,base::StringPiece key)196 std::unique_ptr<base::Value> GetBaseValuePropertyFromObject(
197 v8::Local<v8::Object> object,
198 v8::Local<v8::Context> context,
199 base::StringPiece key) {
200 return V8ToBaseValue(GetPropertyFromObject(object, context, key), context);
201 }
202
GetStringPropertyFromObject(v8::Local<v8::Object> object,v8::Local<v8::Context> context,base::StringPiece key)203 std::string GetStringPropertyFromObject(v8::Local<v8::Object> object,
204 v8::Local<v8::Context> context,
205 base::StringPiece key) {
206 return V8ToString(GetPropertyFromObject(object, context, key), context);
207 }
208
209 } // namespace extensions
210