summaryrefslogtreecommitdiffstats
path: root/chrome/test
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-16 01:38:49 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-16 01:38:49 +0000
commit7896d694115cb2e64971ed0df60f61e3df2f7375 (patch)
treec2778927f7bbef5ee5c1e7cae3a941b097e139ae /chrome/test
parent6fa342707a9979b60fa0321f27983d170d728c66 (diff)
downloadchromium_src-7896d694115cb2e64971ed0df60f61e3df2f7375.zip
chromium_src-7896d694115cb2e64971ed0df60f61e3df2f7375.tar.gz
chromium_src-7896d694115cb2e64971ed0df60f61e3df2f7375.tar.bz2
Commit issue 19737: Partial implementation of tests for
Greasemonkey API. Review URL: http://codereview.chromium.org/21387 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9847 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test')
-rw-r--r--chrome/test/DEPS1
-rw-r--r--chrome/test/data/extensions/greasemonkey_api_test.js408
-rw-r--r--chrome/test/unit/unit_tests.scons3
-rw-r--r--chrome/test/unit/unittests.vcproj12
-rw-r--r--chrome/test/v8_unit_test.cc93
-rw-r--r--chrome/test/v8_unit_test.h100
6 files changed, 617 insertions, 0 deletions
diff --git a/chrome/test/DEPS b/chrome/test/DEPS
index f6a76e9..fdb76c3 100644
--- a/chrome/test/DEPS
+++ b/chrome/test/DEPS
@@ -4,4 +4,5 @@ include_rules = [
"+sandbox/src",
"+sandbox/tests",
"+webkit/glue",
+ "+v8/include", # We have unit tests which use v8 to exercise JavaScript.
]
diff --git a/chrome/test/data/extensions/greasemonkey_api_test.js b/chrome/test/data/extensions/greasemonkey_api_test.js
new file mode 100644
index 0000000..d43e2a0
--- /dev/null
+++ b/chrome/test/data/extensions/greasemonkey_api_test.js
@@ -0,0 +1,408 @@
+var localStorage;
+var document;
+var window;
+
+function testGetSetValue() {
+ localStorage = new LocalStorageFake();
+ GM_setValue('string', 'value');
+ assert('value', GM_getValue('string'));
+ GM_setValue('integer', 123);
+ assert(123, GM_getValue('integer'));
+ GM_setValue('boolean', true);
+ assert(true, GM_getValue('boolean'));
+
+ assert(undefined, GM_getValue('notset'));
+ assert('default', GM_getValue('notset', 'default'));
+
+ // illegal values
+ assertThrow(function() {
+ GM_setValue('illegal value', null);
+ });
+ assertThrow(function() {
+ GM_setValue('illegal value', 1.5);
+ });
+}
+
+function testDeleteValue() {
+ localStorage = new LocalStorageFake();
+ GM_setValue('delete', 'value');
+ assert('value', GM_getValue('delete'));
+ GM_deleteValue('delete');
+ assert(undefined, GM_getValue('delete'));
+ GM_deleteValue('notset');
+}
+
+function testListValues() {
+ localStorage = new LocalStorageFake();
+ var a = GM_listValues();
+ assert(0, a.length);
+
+ GM_setValue('one', 'first');
+ a = GM_listValues();
+ assert(1, a.length);
+ assert('one', a[0]);
+
+ GM_setValue('two', 'second');
+ a = GM_listValues();
+
+ // Test that keys that are not namespaced can't be read.
+ localStorage.setItem('three', 'third');
+ assert(2, a.length);
+ assert(true, a.indexOf('one') >= 0);
+ assert(true, a.indexOf('two') >= 0);
+}
+
+function testGetResourceURL() {
+ assertThrow(function() {
+ var resource = GM_getResourceURL('urlResourceName');
+ });
+}
+
+function testGetResourceText() {
+ assertThrow(function() {
+ var resource = GM_getResourceText('textResourceName');
+ });
+}
+
+function testAddStyle() {
+ var head = new ElementFake('head');
+ document = new DocumentFake(head);
+ var css = 'color: #decaff;';
+ GM_addStyle(css);
+ assert(1, head.childNodes.length);
+ var style = head.childNodes[0];
+ assert("style", style.tagName);
+ assert("text/css", style.type);
+ assert(css, style.innerHTML);
+}
+
+function testXmlhttpRequest() {
+ var xhr = GM_xmlhttpRequest({});
+}
+
+function testRegisterMenuCommand() {
+ assertThrow(function() {
+ GM_registerMenuCommand('name', function() {}, 'a', '', 'a');
+ });
+}
+
+function testOpenInTab() {
+ var mockWindow = {
+ open: function(url, name, opt_options) {
+ this.openedUrl = url;
+ this.openedName = name;
+ this.openedOptions = opt_options;
+ }
+ };
+ window = mockWindow;
+ var url = 'http://example.com';
+ GM_openInTab(url);
+ assert(mockWindow.openedUrl, url);
+}
+
+function testLog() {
+ var mockWindow = {
+ console: {
+ message: null,
+ log: function(message) {
+ this.message = message;
+ }
+ }
+ };
+ window = mockWindow;
+ var message = 'hello world';
+ GM_log(message);
+ assert(message, mockWindow.console.message);
+}
+
+function LocalStorageFake() {
+ this.map_ = {};
+ this.keys_ = [];
+}
+LocalStorageFake.prototype = {
+ length: 0,
+ key: function(index) {
+ if (index >= this.length) {
+ throw new Error('INDEX_SIZE_ERR');
+ }
+ return this.keys_[index];
+ },
+ getItem: function(key) {
+ if (key in this.map_) {
+ return this.map_[key];
+ }
+ return null;
+ },
+ setItem: function(key, data) {
+ this.map_[key] = data;
+ this.updateKeys_();
+ },
+ removeItem: function(key) {
+ delete this.map_[key];
+ this.updateKeys_();
+ },
+ clear: function() {
+ this.map_ = {};
+ this.updateKeys_();
+ },
+ updateKeys_: function() {
+ var keys = [];
+ for (var key in this.map_) {
+ keys.push(key);
+ }
+ this.keys_ = keys;
+ this.length = keys.length;
+ }
+}
+
+function DocumentFake(head) {
+ this.head_ = head;
+}
+DocumentFake.prototype = {
+ getElementsByTagName: function(tagName) {
+ if (tagName == 'head' && this.head_) {
+ return [this.head_];
+ }
+ return [];
+ },
+ createElement: function(tagName) {
+ return new ElementFake(tagName);
+ }
+}
+
+function ElementFake(tagName) {
+ this.tagName = tagName;
+}
+ElementFake.prototype = {
+ childNodes: [],
+ appendChild: function(e) {
+ this.childNodes.push(e);
+ return e;
+ },
+}
+
+function assert(expected, actual) {
+ if (expected !== actual) {
+ throw new Error('Assert failed: "' + expected + '" !== "' + actual + '"');
+ }
+}
+
+function fail() {
+ throw new Error('Fail');
+}
+
+function assertThrow(f) {
+ var threw = false;
+ try {
+ f();
+ } catch(e) {
+ threw = true;
+ }
+ if (!threw) {
+ throw new Error('Assert failed, expression did not throw.');
+ }
+}
+var localStorage;
+var document;
+var window;
+
+function testGetSetValue() {
+ localStorage = new LocalStorageFake();
+ GM_setValue('string', 'value');
+ assert('value', GM_getValue('string'));
+ GM_setValue('integer', 123);
+ assert(123, GM_getValue('integer'));
+ GM_setValue('boolean', true);
+ assert(true, GM_getValue('boolean'));
+
+ assert(undefined, GM_getValue('notset'));
+ assert('default', GM_getValue('notset', 'default'));
+
+ // illegal values
+ assertThrow(function() {
+ GM_setValue('illegal value', null);
+ });
+ assertThrow(function() {
+ GM_setValue('illegal value', 1.5);
+ });
+}
+
+function testDeleteValue() {
+ localStorage = new LocalStorageFake();
+ GM_setValue('delete', 'value');
+ assert('value', GM_getValue('delete'));
+ GM_deleteValue('delete');
+ assert(undefined, GM_getValue('delete'));
+ GM_deleteValue('notset');
+}
+
+function testListValues() {
+ localStorage = new LocalStorageFake();
+ var a = GM_listValues();
+ assert(0, a.length);
+
+ GM_setValue('one', 'first');
+ a = GM_listValues();
+ assert(1, a.length);
+ assert('one', a[0]);
+
+ GM_setValue('two', 'second');
+ a = GM_listValues();
+
+ // Test that keys that are not namespaced can't be read.
+ localStorage.setItem('three', 'third');
+ assert(2, a.length);
+ assert(true, a.indexOf('one') >= 0);
+ assert(true, a.indexOf('two') >= 0);
+}
+
+function testGetResourceURL() {
+ assertThrow(function() {
+ var resource = GM_getResourceURL('urlResourceName');
+ });
+}
+
+function testGetResourceText() {
+ assertThrow(function() {
+ var resource = GM_getResourceText('textResourceName');
+ });
+}
+
+function testAddStyle() {
+ var head = new ElementFake('head');
+ document = new DocumentFake(head);
+ var css = 'color: #decaff;';
+ GM_addStyle(css);
+ assert(1, head.childNodes.length);
+ var style = head.childNodes[0];
+ assert("style", style.tagName);
+ assert("text/css", style.type);
+ assert(css, style.innerHTML);
+}
+
+function testXmlhttpRequest() {
+ var xhr = GM_xmlhttpRequest({});
+}
+
+function testRegisterMenuCommand() {
+ assertThrow(function() {
+ GM_registerMenuCommand('name', function() {}, 'a', '', 'a');
+ });
+}
+
+function testOpenInTab() {
+ var mockWindow = {
+ open: function(url, name, opt_options) {
+ this.openedUrl = url;
+ this.openedName = name;
+ this.openedOptions = opt_options;
+ }
+ };
+ window = mockWindow;
+ var url = 'http://example.com';
+ GM_openInTab(url);
+ assert(mockWindow.openedUrl, url);
+}
+
+function testLog() {
+ var mockWindow = {
+ console: {
+ message: null,
+ log: function(message) {
+ this.message = message;
+ }
+ }
+ };
+ window = mockWindow;
+ var message = 'hello world';
+ GM_log(message);
+ assert(message, mockWindow.console.message);
+}
+
+function LocalStorageFake() {
+ this.map_ = {};
+ this.keys_ = [];
+}
+LocalStorageFake.prototype = {
+ length: 0,
+ key: function(index) {
+ if (index >= this.length) {
+ throw new Error('INDEX_SIZE_ERR');
+ }
+ return this.keys_[index];
+ },
+ getItem: function(key) {
+ if (key in this.map_) {
+ return this.map_[key];
+ }
+ return null;
+ },
+ setItem: function(key, data) {
+ this.map_[key] = data;
+ this.updateKeys_();
+ },
+ removeItem: function(key) {
+ delete this.map_[key];
+ this.updateKeys_();
+ },
+ clear: function() {
+ this.map_ = {};
+ this.updateKeys_();
+ },
+ updateKeys_: function() {
+ var keys = [];
+ for (var key in this.map_) {
+ keys.push(key);
+ }
+ this.keys_ = keys;
+ this.length = keys.length;
+ }
+}
+
+function DocumentFake(head) {
+ this.head_ = head;
+}
+DocumentFake.prototype = {
+ getElementsByTagName: function(tagName) {
+ if (tagName == 'head' && this.head_) {
+ return [this.head_];
+ }
+ return [];
+ },
+ createElement: function(tagName) {
+ return new ElementFake(tagName);
+ }
+}
+
+function ElementFake(tagName) {
+ this.tagName = tagName;
+}
+ElementFake.prototype = {
+ childNodes: [],
+ appendChild: function(e) {
+ this.childNodes.push(e);
+ return e;
+ },
+}
+
+function assert(expected, actual) {
+ if (expected !== actual) {
+ throw new Error('Assert failed: "' + expected + '" !== "' + actual + '"');
+ }
+}
+
+function fail() {
+ throw new Error('Fail');
+}
+
+function assertThrow(f) {
+ var threw = false;
+ try {
+ f();
+ } catch(e) {
+ threw = true;
+ }
+ if (!threw) {
+ throw new Error('Assert failed, expression did not throw.');
+ }
+}
diff --git a/chrome/test/unit/unit_tests.scons b/chrome/test/unit/unit_tests.scons
index 2a37fa6..c03c439 100644
--- a/chrome/test/unit/unit_tests.scons
+++ b/chrome/test/unit/unit_tests.scons
@@ -250,6 +250,7 @@ input_files = ChromeFileList([
'$CHROME_DIR/third_party/hunspell/google/hunspell_tests.cc',
]),
MSVSFilter('renderer', [
+ '$CHROME_DIR/renderer/extensions/greasemonkey_api_unittest.cc',
'$CHROME_DIR/renderer/net/render_dns_master_unittest.cc',
'$CHROME_DIR/renderer/net/render_dns_queue_unittest.cc',
'$CHROME_DIR/renderer/render_view_unittest.cc',
@@ -262,6 +263,8 @@ input_files = ChromeFileList([
'$CHROME_DIR/renderer/mock_render_process.h',
'$CHROME_DIR/renderer/mock_render_thread.cc',
'$CHROME_DIR/renderer/mock_render_thread.h',
+ '$CHROME_DIR/test/v8_unit_test.h',
+ '$CHROME_DIR/test/v8_unit_test.cc',
]),
MSVSFilter('resources', [
'$CHROME_DIR/browser/browser_resources.h',
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index 7c2daa2..6c58075 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -230,6 +230,14 @@
RelativePath="..\..\..\net\url_request\url_request_test_job.h"
>
</File>
+ <File
+ RelativePath="..\v8_unit_test.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\v8_unit_test.h"
+ >
+ </File>
</Filter>
<Filter
Name="hunspell"
@@ -795,6 +803,10 @@
Name="renderer"
>
<File
+ RelativePath="..\..\renderer\extensions\greasemonkey_api_unittest.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\renderer\net\render_dns_master_unittest.cc"
>
</File>
diff --git a/chrome/test/v8_unit_test.cc b/chrome/test/v8_unit_test.cc
new file mode 100644
index 0000000..43db5f1
--- /dev/null
+++ b/chrome/test/v8_unit_test.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iostream>
+
+#include "base/string_util.h"
+#include "chrome/test/v8_unit_test.h"
+
+void V8UnitTest::SetUp() {
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ global->Set(v8::String::New("log"),
+ v8::FunctionTemplate::New(&V8UnitTest::Log));
+ context_ = v8::Context::New(NULL, global);
+}
+
+void V8UnitTest::ExecuteScriptInContext(const StringPiece& script_source,
+ const StringPiece& script_name) {
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> source = v8::String::New(script_source.data(),
+ script_source.size());
+ v8::Handle<v8::String> name = v8::String::New(script_name.data(),
+ script_source.size());
+
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
+ // Ensure the script compiled without errors.
+ if (script.IsEmpty()) {
+ FAIL() << ExceptionToString(&try_catch);
+ }
+ v8::Handle<v8::Value> result = script->Run();
+ // Ensure the script ran without errors.
+ if (result.IsEmpty()) {
+ FAIL() << ExceptionToString(&try_catch);
+ }
+}
+
+std::string V8UnitTest::ExceptionToString(v8::TryCatch* try_catch) {
+ std::string str;
+ v8::HandleScope handle_scope;
+ v8::String::Utf8Value exception(try_catch->Exception());
+ v8::Handle<v8::Message> message = try_catch->Message();
+ if (message.IsEmpty()) {
+ str.append(StringPrintf("%s\n", *exception));
+ } else {
+ v8::String::Utf8Value filename(message->GetScriptResourceName());
+ int linenum = message->GetLineNumber();
+ int colnum = message->GetStartColumn();
+ str.append(StringPrintf("%s:%i:%i %s\n", *filename, linenum, colnum,
+ *exception));
+ v8::String::Utf8Value sourceline(message->GetSourceLine());
+ str.append(StringPrintf("%s\n", *sourceline));
+ }
+ return str;
+}
+
+void V8UnitTest::TestFunction(const std::string& function_name) {
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope handle_scope;
+
+ v8::Handle<v8::Value> functionProperty =
+ context_->Global()->Get(v8::String::New(function_name.c_str()));
+ ASSERT_FALSE(functionProperty.IsEmpty());
+ ASSERT_TRUE(functionProperty->IsFunction());
+ v8::Handle<v8::Function> function =
+ v8::Handle<v8::Function>::Cast(functionProperty);
+
+ v8::TryCatch try_catch;
+ v8::Handle<v8::Value> result = function->Call(context_->Global(), 0, NULL);
+ // The test fails if an exception was thrown.
+ if (result.IsEmpty()) {
+ FAIL() << ExceptionToString(&try_catch);
+ }
+}
+
+// static
+v8::Handle<v8::Value> V8UnitTest::Log(const v8::Arguments& args) {
+ std::string message;
+ bool first = true;
+ for (int i = 0; i < args.Length(); i++) {
+ v8::HandleScope handle_scope;
+ if (first) {
+ first = false;
+ } else {
+ message += " ";
+ }
+ v8::String::Utf8Value str(args[i]);
+ message += *str;
+ }
+ std::cout << message << "\n";
+ return v8::Undefined();
+}
diff --git a/chrome/test/v8_unit_test.h b/chrome/test/v8_unit_test.h
new file mode 100644
index 0000000..5b4c4ce
--- /dev/null
+++ b/chrome/test/v8_unit_test.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_V8_UNIT_TEST_H_
+#define CHROME_TEST_V8_UNIT_TEST_H_
+
+#include <string>
+
+#include "base/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+// A superclass for unit tests that involve running JavaeScript. This class
+// sets up V8 context and has methods that make it easy to execute scripts in
+// this context as well as call functions in the context.
+class V8UnitTest : public testing::Test {
+ public:
+ V8UnitTest() {}
+ virtual void SetUp();
+
+ protected:
+ // Executes the given script source in the context. The specified script
+ // name is used when reporting errors.
+ virtual void ExecuteScriptInContext(const StringPiece& script_source,
+ const StringPiece& script_name);
+
+ // Converts a v8::TryCatch into a human readable string.
+ virtual std::string ExceptionToString(v8::TryCatch* try_catch);
+
+ // Calls the specified function that resides in the global scope of the
+ // context. If the function throws an exception, FAIL() is called to
+ // indicate a unit test failure. This is useful for executing unit test
+ // functions implemented in JavaScript.
+ virtual void TestFunction(const std::string& function_name);
+
+ // This method is bound to a global function "log" in the context.
+ // Scripts running in the context can call this to print out logging
+ // information to the console.
+ static v8::Handle<v8::Value> Log(const v8::Arguments& args);
+
+ // Handle scope that is used throughout the life of this class.
+ v8::HandleScope handle_scope_;
+
+ // Context for the JavaScript in the test.
+ v8::Handle<v8::Context> context_;
+};
+
+#endif // CHROME_TEST_V8_UNIT_TEST_H_
+
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_V8_UNIT_TEST_H_
+#define CHROME_TEST_V8_UNIT_TEST_H_
+
+#include <string>
+
+#include "base/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+// A superclass for unit tests that involve running JavaeScript. This class
+// sets up V8 context and has methods that make it easy to execute scripts in
+// this context as well as call functions in the context.
+class V8UnitTest : public testing::Test {
+ public:
+ V8UnitTest() {}
+ virtual void SetUp();
+
+ protected:
+ // Executes the given script source in the context. The specified script
+ // name is used when reporting errors.
+ virtual void ExecuteScriptInContext(const StringPiece& script_source,
+ const StringPiece& script_name);
+
+ // Converts a v8::TryCatch into a human readable string.
+ virtual std::string ExceptionToString(v8::TryCatch* try_catch);
+
+ // Calls the specified function that resides in the global scope of the
+ // context. If the function throws an exception, FAIL() is called to
+ // indicate a unit test failure. This is useful for executing unit test
+ // functions implemented in JavaScript.
+ virtual void TestFunction(const std::string& function_name);
+
+ // This method is bound to a global function "log" in the context.
+ // Scripts running in the context can call this to print out logging
+ // information to the console.
+ static v8::Handle<v8::Value> Log(const v8::Arguments& args);
+
+ // Handle scope that is used throughout the life of this class.
+ v8::HandleScope handle_scope_;
+
+ // Context for the JavaScript in the test.
+ v8::Handle<v8::Context> context_;
+};
+
+#endif // CHROME_TEST_V8_UNIT_TEST_H_
+