Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / test / base / v8_unit_test.cc
1 // Copyright (c) 2011 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 "chrome/test/base/v8_unit_test.h"
6
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/path_service.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/common/chrome_paths.h"
13 #include "third_party/WebKit/public/web/WebKit.h"
14
15 namespace {
16
17 // |args| are passed through the various JavaScript logging functions such as
18 // console.log. Returns a string appropriate for logging with LOG(severity).
19 std::string LogArgs2String(const v8::FunctionCallbackInfo<v8::Value>& args) {
20   std::string message;
21   bool first = true;
22   for (int i = 0; i < args.Length(); i++) {
23     v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
24     if (first)
25       first = false;
26     else
27       message += " ";
28
29     v8::String::Utf8Value str(args[i]);
30     message += *str;
31   }
32   return message;
33 }
34
35 // Whether errors were seen.
36 bool had_errors = false;
37
38 // testDone results.
39 bool testResult_ok = false;
40
41 // Location of test data (currently test/data/webui).
42 base::FilePath test_data_directory;
43
44 // Location of generated test data (<(PROGRAM_DIR)/test_data).
45 base::FilePath gen_test_data_directory;
46
47 }  // namespace
48
49 V8UnitTest::V8UnitTest() : handle_scope_(blink::mainThreadIsolate()) {
50   InitPathsAndLibraries();
51 }
52
53 V8UnitTest::~V8UnitTest() {
54 }
55
56 void V8UnitTest::AddLibrary(const base::FilePath& library_path) {
57   user_libraries_.push_back(library_path);
58 }
59
60 bool V8UnitTest::ExecuteJavascriptLibraries() {
61   std::string utf8_content;
62   for (std::vector<base::FilePath>::iterator user_libraries_iterator =
63            user_libraries_.begin();
64        user_libraries_iterator != user_libraries_.end();
65        ++user_libraries_iterator) {
66     std::string library_content;
67     base::FilePath library_file(*user_libraries_iterator);
68     if (!user_libraries_iterator->IsAbsolute()) {
69       base::FilePath gen_file = gen_test_data_directory.Append(library_file);
70       library_file = base::PathExists(gen_file)
71                          ? gen_file
72                          : test_data_directory.Append(*user_libraries_iterator);
73     }
74     library_file = base::MakeAbsoluteFilePath(library_file);
75     if (!base::ReadFileToString(library_file, &library_content)) {
76       ADD_FAILURE() << library_file.value();
77       return false;
78     }
79     ExecuteScriptInContext(library_content, library_file.MaybeAsASCII());
80     if (::testing::Test::HasFatalFailure())
81       return false;
82   }
83   return true;
84 }
85
86 bool V8UnitTest::RunJavascriptTestF(const std::string& testFixture,
87                                     const std::string& testName) {
88   had_errors = false;
89   testResult_ok = false;
90   std::string test_js;
91   if (!ExecuteJavascriptLibraries())
92     return false;
93
94   v8::Isolate* isolate = blink::mainThreadIsolate();
95   v8::HandleScope handle_scope(isolate);
96   v8::Local<v8::Context> context =
97       v8::Local<v8::Context>::New(isolate, context_);
98   v8::Context::Scope context_scope(context);
99
100   v8::Handle<v8::Value> functionProperty =
101       context->Global()->Get(v8::String::NewFromUtf8(isolate, "runTest"));
102   EXPECT_FALSE(functionProperty.IsEmpty());
103   if (::testing::Test::HasNonfatalFailure())
104     return false;
105   EXPECT_TRUE(functionProperty->IsFunction());
106   if (::testing::Test::HasNonfatalFailure())
107     return false;
108   v8::Handle<v8::Function> function =
109       v8::Handle<v8::Function>::Cast(functionProperty);
110
111   v8::Local<v8::Array> params = v8::Array::New(isolate);
112   params->Set(0,
113               v8::String::NewFromUtf8(isolate,
114                                       testFixture.data(),
115                                       v8::String::kNormalString,
116                                       testFixture.size()));
117   params->Set(1,
118               v8::String::NewFromUtf8(isolate,
119                                       testName.data(),
120                                       v8::String::kNormalString,
121                                       testName.size()));
122   v8::Handle<v8::Value> args[] = {
123       v8::Boolean::New(isolate, false),
124       v8::String::NewFromUtf8(isolate, "RUN_TEST_F"), params};
125
126   v8::TryCatch try_catch;
127   v8::Handle<v8::Value> result = function->Call(context->Global(), 3, args);
128   // The test fails if an exception was thrown.
129   EXPECT_FALSE(result.IsEmpty());
130   if (::testing::Test::HasNonfatalFailure())
131     return false;
132
133   // Ok if ran successfully, passed tests, and didn't have console errors.
134   return result->BooleanValue() && testResult_ok && !had_errors;
135 }
136
137 void V8UnitTest::InitPathsAndLibraries() {
138   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory));
139   test_data_directory = test_data_directory.AppendASCII("webui");
140   ASSERT_TRUE(
141       PathService::Get(chrome::DIR_GEN_TEST_DATA, &gen_test_data_directory));
142
143   base::FilePath mockPath;
144   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &mockPath));
145   mockPath = mockPath.AppendASCII("chrome");
146   mockPath = mockPath.AppendASCII("third_party");
147   mockPath = mockPath.AppendASCII("mock4js");
148   mockPath = mockPath.AppendASCII("mock4js.js");
149   AddLibrary(mockPath);
150
151   base::FilePath accessibilityAuditPath;
152   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &accessibilityAuditPath));
153   accessibilityAuditPath = accessibilityAuditPath.AppendASCII("third_party");
154   accessibilityAuditPath =
155       accessibilityAuditPath.AppendASCII("accessibility-audit");
156   accessibilityAuditPath = accessibilityAuditPath.AppendASCII("axs_testing.js");
157   AddLibrary(accessibilityAuditPath);
158
159   base::FilePath testApiPath;
160   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &testApiPath));
161   testApiPath = testApiPath.AppendASCII("webui");
162   testApiPath = testApiPath.AppendASCII("test_api.js");
163   AddLibrary(testApiPath);
164 }
165
166 void V8UnitTest::SetUp() {
167   v8::Isolate* isolate = blink::mainThreadIsolate();
168   v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
169   v8::Handle<v8::String> logString = v8::String::NewFromUtf8(isolate, "log");
170   v8::Handle<v8::FunctionTemplate> logFunction =
171       v8::FunctionTemplate::New(isolate, &V8UnitTest::Log);
172   global->Set(logString, logFunction);
173
174   // Set up chrome object for chrome.send().
175   v8::Handle<v8::ObjectTemplate> chrome = v8::ObjectTemplate::New(isolate);
176   global->Set(v8::String::NewFromUtf8(isolate, "chrome"), chrome);
177   chrome->Set(v8::String::NewFromUtf8(isolate, "send"),
178               v8::FunctionTemplate::New(isolate, &V8UnitTest::ChromeSend));
179
180   // Set up console object for console.log(), etc.
181   v8::Handle<v8::ObjectTemplate> console = v8::ObjectTemplate::New(isolate);
182   global->Set(v8::String::NewFromUtf8(isolate, "console"), console);
183   console->Set(logString, logFunction);
184   console->Set(v8::String::NewFromUtf8(isolate, "info"), logFunction);
185   console->Set(v8::String::NewFromUtf8(isolate, "warn"), logFunction);
186   console->Set(v8::String::NewFromUtf8(isolate, "error"),
187                v8::FunctionTemplate::New(isolate, &V8UnitTest::Error));
188
189   context_.Reset(isolate, v8::Context::New(isolate, NULL, global));
190 }
191
192 void V8UnitTest::SetGlobalStringVar(const std::string& var_name,
193                                     const std::string& value) {
194   v8::Isolate* isolate = blink::mainThreadIsolate();
195   v8::Local<v8::Context> context =
196       v8::Local<v8::Context>::New(isolate, context_);
197   v8::Context::Scope context_scope(context);
198   context->Global()->Set(
199       v8::String::NewFromUtf8(isolate,
200                               var_name.c_str(),
201                               v8::String::kNormalString,
202                               var_name.length()),
203       v8::String::NewFromUtf8(
204           isolate, value.c_str(), v8::String::kNormalString, value.length()));
205 }
206
207 void V8UnitTest::ExecuteScriptInContext(const base::StringPiece& script_source,
208                                         const base::StringPiece& script_name) {
209   v8::Isolate* isolate = blink::mainThreadIsolate();
210   v8::HandleScope handle_scope(isolate);
211   v8::Local<v8::Context> context =
212       v8::Local<v8::Context>::New(isolate, context_);
213   v8::Context::Scope context_scope(context);
214   v8::Handle<v8::String> source =
215       v8::String::NewFromUtf8(isolate,
216                               script_source.data(),
217                               v8::String::kNormalString,
218                               script_source.size());
219   v8::Handle<v8::String> name =
220       v8::String::NewFromUtf8(isolate,
221                               script_name.data(),
222                               v8::String::kNormalString,
223                               script_name.size());
224
225   v8::TryCatch try_catch;
226   v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
227   // Ensure the script compiled without errors.
228   if (script.IsEmpty())
229     FAIL() << ExceptionToString(try_catch);
230
231   v8::Handle<v8::Value> result = script->Run();
232   // Ensure the script ran without errors.
233   if (result.IsEmpty())
234     FAIL() << ExceptionToString(try_catch);
235 }
236
237 std::string V8UnitTest::ExceptionToString(const v8::TryCatch& try_catch) {
238   std::string str;
239   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
240   v8::String::Utf8Value exception(try_catch.Exception());
241   v8::Local<v8::Message> message(try_catch.Message());
242   if (message.IsEmpty()) {
243     str.append(base::StringPrintf("%s\n", *exception));
244   } else {
245     v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
246     int linenum = message->GetLineNumber();
247     int colnum = message->GetStartColumn();
248     str.append(base::StringPrintf(
249         "%s:%i:%i %s\n", *filename, linenum, colnum, *exception));
250     v8::String::Utf8Value sourceline(message->GetSourceLine());
251     str.append(base::StringPrintf("%s\n", *sourceline));
252   }
253   return str;
254 }
255
256 void V8UnitTest::TestFunction(const std::string& function_name) {
257   v8::Isolate* isolate = blink::mainThreadIsolate();
258   v8::HandleScope handle_scope(isolate);
259   v8::Local<v8::Context> context =
260       v8::Local<v8::Context>::New(isolate, context_);
261   v8::Context::Scope context_scope(context);
262
263   v8::Handle<v8::Value> functionProperty = context->Global()->Get(
264       v8::String::NewFromUtf8(isolate, function_name.c_str()));
265   ASSERT_FALSE(functionProperty.IsEmpty());
266   ASSERT_TRUE(functionProperty->IsFunction());
267   v8::Handle<v8::Function> function =
268       v8::Handle<v8::Function>::Cast(functionProperty);
269
270   v8::TryCatch try_catch;
271   v8::Handle<v8::Value> result = function->Call(context->Global(), 0, NULL);
272   // The test fails if an exception was thrown.
273   if (result.IsEmpty())
274     FAIL() << ExceptionToString(try_catch);
275 }
276
277 // static
278 void V8UnitTest::Log(const v8::FunctionCallbackInfo<v8::Value>& args) {
279   LOG(INFO) << LogArgs2String(args);
280 }
281
282 void V8UnitTest::Error(const v8::FunctionCallbackInfo<v8::Value>& args) {
283   had_errors = true;
284   LOG(ERROR) << LogArgs2String(args);
285 }
286
287 void V8UnitTest::ChromeSend(const v8::FunctionCallbackInfo<v8::Value>& args) {
288   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
289   // We expect to receive 2 args: ("testResult", [ok, message]). However,
290   // chrome.send may pass only one. Therefore we need to ensure we have at least
291   // 1, then ensure that the first is "testResult" before checking again for 2.
292   EXPECT_LE(1, args.Length());
293   if (::testing::Test::HasNonfatalFailure())
294     return;
295   v8::String::Utf8Value message(args[0]);
296   EXPECT_EQ("testResult", std::string(*message, message.length()));
297   if (::testing::Test::HasNonfatalFailure())
298     return;
299   EXPECT_EQ(2, args.Length());
300   if (::testing::Test::HasNonfatalFailure())
301     return;
302   v8::Handle<v8::Array> testResult(args[1].As<v8::Array>());
303   EXPECT_EQ(2U, testResult->Length());
304   if (::testing::Test::HasNonfatalFailure())
305     return;
306   testResult_ok = testResult->Get(0)->BooleanValue();
307   if (!testResult_ok) {
308     v8::String::Utf8Value message(testResult->Get(1));
309     LOG(ERROR) << *message;
310   }
311 }