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