summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
Diffstat (limited to 'mojo')
-rw-r--r--mojo/apps/js/DEPS1
-rw-r--r--mojo/apps/js/main.cc4
-rw-r--r--mojo/apps/js/v8_environment.cc49
-rw-r--r--mojo/apps/js/v8_environment.h16
-rw-r--r--mojo/mojo.gyp45
-rw-r--r--mojo/public/bindings/js/DEPS5
-rw-r--r--mojo/public/bindings/js/core.cc161
-rw-r--r--mojo/public/bindings/js/core.h18
-rw-r--r--mojo/public/bindings/js/handle.cc19
-rw-r--r--mojo/public/bindings/js/handle.h23
-rw-r--r--mojo/public/bindings/js/mojo.cc34
-rw-r--r--mojo/public/bindings/js/mojo.h18
-rw-r--r--mojo/public/bindings/js/mojo_unittests.js8
-rw-r--r--mojo/public/bindings/js/runner_delegate.cc23
-rw-r--r--mojo/public/bindings/js/runner_delegate.h29
-rw-r--r--mojo/public/bindings/js/test/DEPS3
-rw-r--r--mojo/public/bindings/js/test/harness.cc69
17 files changed, 454 insertions, 71 deletions
diff --git a/mojo/apps/js/DEPS b/mojo/apps/js/DEPS
index 719fd94..0b70f92 100644
--- a/mojo/apps/js/DEPS
+++ b/mojo/apps/js/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+gin",
"+v8",
"-base",
]
diff --git a/mojo/apps/js/main.cc b/mojo/apps/js/main.cc
index 8e57371..6f8cdb3 100644
--- a/mojo/apps/js/main.cc
+++ b/mojo/apps/js/main.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "mojo/apps/js/v8_environment.h"
+#include "gin/initialize.h"
#include "mojo/public/system/core.h"
#include "mojo/public/system/macros.h"
@@ -18,7 +18,7 @@
extern "C" MOJO_APPS_JS_EXPORT MojoResult CDECL MojoMain(
mojo::Handle pipe) {
- mojo::apps::InitializeV8();
+ gin::Initialize();
// TODO(abarth): Load JS off the network and execute it.
return MOJO_RESULT_OK;
}
diff --git a/mojo/apps/js/v8_environment.cc b/mojo/apps/js/v8_environment.cc
deleted file mode 100644
index 1b4ee83..0000000
--- a/mojo/apps/js/v8_environment.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 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 "mojo/apps/js/v8_environment.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "mojo/public/system/macros.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace apps {
-
-namespace {
-
-class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
- virtual void* Allocate(size_t length) MOJO_OVERRIDE {
- return calloc(1, length);
- }
- virtual void* AllocateUninitialized(size_t length) MOJO_OVERRIDE {
- return malloc(length);
- }
- virtual void Free(void* data, size_t length) MOJO_OVERRIDE {
- free(data);
- }
-};
-
-bool GenerateEntropy(unsigned char* buffer, size_t amount) {
- // TODO(abarth): Mojo needs a source of entropy.
- // https://code.google.com/p/chromium/issues/detail?id=316387
- return false;
-}
-
-const char kFlags[] = "--use_strict --harmony";
-
-}
-
-void InitializeV8() {
- v8::V8::SetArrayBufferAllocator(new ArrayBufferAllocator());
- v8::V8::InitializeICU();
- v8::V8::SetFlagsFromString(kFlags, strlen(kFlags));
- v8::V8::SetEntropySource(&GenerateEntropy);
- v8::V8::Initialize();
-}
-
-} // namespace apps
-} // mojo
diff --git a/mojo/apps/js/v8_environment.h b/mojo/apps/js/v8_environment.h
deleted file mode 100644
index 88d1963..0000000
--- a/mojo/apps/js/v8_environment.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2013 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 MOJO_APPS_JS_V8_ENVIRONMENT_H_
-#define MOJO_APPS_JS_V8_ENVIRONMENT_H_
-
-namespace mojo {
-namespace apps {
-
-void InitializeV8();
-
-} // namespace apps
-} // mojo
-
-#endif // MOJO_APPS_JS_V8_ENVIRONMENT_H_
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
index 46d3f94..a01aa88 100644
--- a/mojo/mojo.gyp
+++ b/mojo/mojo.gyp
@@ -25,7 +25,9 @@
'sample_app',
'mojo_bindings',
'mojo_bindings_test',
- 'native_viewport',
+ 'mojo_js_bindings',
+ 'mojo_js_bindings_unittests',
+ 'mojo_bindings',
],
},
{
@@ -288,12 +290,10 @@
'..'
],
'dependencies': [
- '../v8/tools/gyp/v8.gyp:v8',
+ 'mojo_js_bindings',
],
'sources': [
'apps/js/main.cc',
- 'apps/js/v8_environment.cc',
- 'apps/js/v8_environment.h',
],
},
{
@@ -353,6 +353,43 @@
'public/bindings/sample/sample_test.cc',
],
},
+ {
+ 'target_name': 'mojo_js_bindings',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '..'
+ ],
+ 'dependencies': [
+ '../gin/gin.gyp:gin',
+ 'mojo_system',
+ ],
+ 'export_dependent_settings': [
+ '../gin/gin.gyp:gin',
+ ],
+ 'sources': [
+ 'public/bindings/js/core.cc',
+ 'public/bindings/js/core.h',
+ 'public/bindings/js/handle.cc',
+ 'public/bindings/js/handle.h',
+ 'public/bindings/js/mojo.cc',
+ 'public/bindings/js/mojo.h',
+ 'public/bindings/js/runner_delegate.cc',
+ 'public/bindings/js/runner_delegate.h',
+ ],
+ },
+ {
+ 'target_name': 'mojo_js_bindings_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../base/base.gyp:run_all_unittests',
+ '../gin/gin.gyp:gin_test',
+ 'mojo_js_bindings',
+ ],
+ 'sources': [
+ '../gin/test/run_all_unittests.cc',
+ 'public/bindings/js/test/harness.cc',
+ ],
+ },
{
'target_name': 'native_viewport',
'type': 'static_library',
diff --git a/mojo/public/bindings/js/DEPS b/mojo/public/bindings/js/DEPS
new file mode 100644
index 0000000..ac120ba
--- /dev/null
+++ b/mojo/public/bindings/js/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ "+gin",
+ "+testing",
+ "+v8",
+]
diff --git a/mojo/public/bindings/js/core.cc b/mojo/public/bindings/js/core.cc
new file mode 100644
index 0000000..fadbf75
--- /dev/null
+++ b/mojo/public/bindings/js/core.cc
@@ -0,0 +1,161 @@
+// Copyright 2013 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 "mojo/public/bindings/js/core.h"
+
+#include "gin/arguments.h"
+#include "gin/array_buffer.h"
+#include "gin/converter.h"
+#include "gin/dictionary.h"
+#include "gin/per_isolate_data.h"
+#include "gin/wrapper_info.h"
+#include "mojo/public/bindings/js/handle.h"
+
+namespace mojo {
+namespace js {
+
+namespace {
+
+void Close(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ mojo::Handle handle = mojo::kInvalidHandle;
+ if (!args.GetNext(&handle))
+ return args.ThrowError();
+
+ args.Return(mojo::Close(handle));
+}
+
+void Wait(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ mojo::Handle handle = mojo::kInvalidHandle;
+ MojoWaitFlags flags = MOJO_WAIT_FLAG_NONE;
+ MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE;
+
+ if (!args.GetNext(&handle) ||
+ !args.GetNext(&flags) ||
+ !args.GetNext(&deadline)) {
+ return args.ThrowError();
+ }
+
+ args.Return(mojo::Wait(handle, flags, deadline));
+}
+
+void WaitMany(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ std::vector<mojo::Handle> handles;
+ std::vector<MojoWaitFlags> flags;
+ MojoDeadline deadline = MOJO_DEADLINE_INDEFINITE;
+
+ if (!args.GetNext(&handles) ||
+ !args.GetNext(&flags) ||
+ !args.GetNext(&deadline)) {
+ return args.ThrowError();
+ }
+
+ if (handles.size() != flags.size())
+ return args.ThrowTypeError("Arrays must have the same length.");
+
+ args.Return(mojo::WaitMany(handles.data(), flags.data(),
+ handles.size(), deadline));
+}
+
+void CreateMessagePipe(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ mojo::Handle handle_0 = mojo::kInvalidHandle;
+ mojo::Handle handle_1 = mojo::kInvalidHandle;
+ MojoResult result = mojo::CreateMessagePipe(&handle_0, &handle_1);
+
+ gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(info.GetIsolate());
+ dictionary.Set("result", result);
+ dictionary.Set("handle0", handle_0);
+ dictionary.Set("handle1", handle_1);
+ args.Return(dictionary);
+}
+
+void WriteMessage(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ mojo::Handle handle = mojo::kInvalidHandle;
+ gin::ArrayBufferView buffer(args.isolate());
+ std::vector<mojo::Handle> handles;
+ MojoWaitFlags flags = MOJO_WAIT_FLAG_NONE;
+
+ if (!args.GetNext(&handle) ||
+ !args.GetNext(&buffer) ||
+ !args.GetNext(&handles) ||
+ !args.GetNext(&flags)) {
+ return args.ThrowError();
+ }
+
+ args.Return(mojo::WriteMessage(handle, buffer.bytes(), buffer.num_bytes(),
+ handles.data(), handles.size(), flags));
+}
+
+void ReadMessage(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ gin::Arguments args(info);
+
+ mojo::Handle handle = mojo::kInvalidHandle;
+ gin::ArrayBufferView buffer(args.isolate());
+ uint32_t num_handles = 0;
+ MojoWaitFlags flags = MOJO_WAIT_FLAG_NONE;
+
+ if (!args.GetNext(&handle) ||
+ !args.GetNext(&buffer) ||
+ !args.GetNext(&num_handles) ||
+ !args.GetNext(&flags)) {
+ return args.ThrowError();
+ }
+
+ uint32_t num_bytes = buffer.num_bytes();
+ std::vector<mojo::Handle> handles(num_handles);
+ MojoResult result = mojo::ReadMessage(handle, buffer.bytes(), &num_bytes,
+ handles.data(), &num_handles, flags);
+ handles.resize(num_handles);
+
+ // TODO(abarth): We should benchmark this codepath to make sure it's ok to
+ // allocate all this memory on each read.
+ gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(info.GetIsolate());
+ dictionary.Set("result", result);
+ dictionary.Set("bytesRead", num_bytes);
+ dictionary.Set("handles", handles);
+ args.Return(dictionary);
+}
+
+gin::WrapperInfo g_core_wrapper_info = {};
+
+}
+
+v8::Local<v8::ObjectTemplate> GetCoreTemplate(v8::Isolate* isolate) {
+ gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
+ v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
+ &g_core_wrapper_info);
+
+ if (templ.IsEmpty()) {
+ templ = v8::ObjectTemplate::New();
+
+ templ->Set(gin::StringToSymbol(isolate, "close"),
+ v8::FunctionTemplate::New(Close));
+ templ->Set(gin::StringToSymbol(isolate, "wait"),
+ v8::FunctionTemplate::New(Wait));
+ templ->Set(gin::StringToSymbol(isolate, "waitMany"),
+ v8::FunctionTemplate::New(WaitMany));
+ templ->Set(gin::StringToSymbol(isolate, "createMessagePipe"),
+ v8::FunctionTemplate::New(CreateMessagePipe));
+ templ->Set(gin::StringToSymbol(isolate, "writeMessage"),
+ v8::FunctionTemplate::New(WriteMessage));
+ templ->Set(gin::StringToSymbol(isolate, "readMessage"),
+ v8::FunctionTemplate::New(ReadMessage));
+
+ data->SetObjectTemplate(&g_core_wrapper_info, templ);
+ }
+
+ return templ;
+}
+
+} // namespace js
+} // namespace mojo
diff --git a/mojo/public/bindings/js/core.h b/mojo/public/bindings/js/core.h
new file mode 100644
index 0000000..32cd0aa
--- /dev/null
+++ b/mojo/public/bindings/js/core.h
@@ -0,0 +1,18 @@
+// Copyright 2013 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 MOJO_PUBLIC_BINDINGS_JS_CORE_H_
+#define MOJO_PUBLIC_BINDINGS_JS_CORE_H_
+
+#include "v8/include/v8.h"
+
+namespace mojo {
+namespace js {
+
+v8::Local<v8::ObjectTemplate> GetCoreTemplate(v8::Isolate* isolate);
+
+} // namespace js
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_BINDINGS_JS_CORE_H_
diff --git a/mojo/public/bindings/js/handle.cc b/mojo/public/bindings/js/handle.cc
new file mode 100644
index 0000000..f52ef1c
--- /dev/null
+++ b/mojo/public/bindings/js/handle.cc
@@ -0,0 +1,19 @@
+// Copyright 2013 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 "mojo/public/bindings/js/handle.h"
+
+namespace gin {
+
+v8::Handle<v8::Value> Converter<mojo::Handle>::ToV8(v8::Isolate* isolate,
+ mojo::Handle val) {
+ return Converter<MojoHandle>::ToV8(isolate, val.value);
+}
+
+bool Converter<mojo::Handle>::FromV8(v8::Handle<v8::Value> val,
+ mojo::Handle* out) {
+ return Converter<MojoHandle>::FromV8(val, &out->value);
+}
+
+} // namespace gin
diff --git a/mojo/public/bindings/js/handle.h b/mojo/public/bindings/js/handle.h
new file mode 100644
index 0000000..16a4e81
--- /dev/null
+++ b/mojo/public/bindings/js/handle.h
@@ -0,0 +1,23 @@
+// Copyright 2013 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 MOJO_PUBLIC_BINDINGS_JS_HANDLE_H_
+#define MOJO_PUBLIC_BINDINGS_JS_HANDLE_H_
+
+#include "gin/converter.h"
+#include "mojo/public/system/core.h"
+
+namespace gin {
+
+template<>
+struct Converter<mojo::Handle> {
+ static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
+ mojo::Handle val);
+ static bool FromV8(v8::Handle<v8::Value> val,
+ mojo::Handle* out);
+};
+
+} // namespace gin
+
+#endif // MOJO_PUBLIC_BINDINGS_JS_HANDLE_H_
diff --git a/mojo/public/bindings/js/mojo.cc b/mojo/public/bindings/js/mojo.cc
new file mode 100644
index 0000000..a380bb6
--- /dev/null
+++ b/mojo/public/bindings/js/mojo.cc
@@ -0,0 +1,34 @@
+// Copyright 2013 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 "mojo/public/bindings/js/mojo.h"
+
+#include "gin/converter.h"
+#include "gin/per_isolate_data.h"
+#include "gin/wrapper_info.h"
+#include "mojo/public/bindings/js/core.h"
+
+namespace mojo {
+namespace js {
+
+namespace {
+
+gin::WrapperInfo g_mojo_wrapper_info = {};
+
+}
+
+v8::Local<v8::ObjectTemplate> GetMojoTemplate(v8::Isolate* isolate) {
+ gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
+ v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
+ &g_mojo_wrapper_info);
+ if (templ.IsEmpty()) {
+ templ = v8::ObjectTemplate::New();
+ templ->Set(gin::StringToSymbol(isolate, "core"), GetCoreTemplate(isolate));
+ data->SetObjectTemplate(&g_mojo_wrapper_info, templ);
+ }
+ return templ;
+}
+
+} // namespace js
+} // namespace mojo
diff --git a/mojo/public/bindings/js/mojo.h b/mojo/public/bindings/js/mojo.h
new file mode 100644
index 0000000..95d6e13
--- /dev/null
+++ b/mojo/public/bindings/js/mojo.h
@@ -0,0 +1,18 @@
+// Copyright 2013 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 MOJO_PUBLIC_BINDINGS_JS_MOJO_H_
+#define MOJO_PUBLIC_BINDINGS_JS_MOJO_H_
+
+#include "v8/include/v8.h"
+
+namespace mojo {
+namespace js {
+
+v8::Local<v8::ObjectTemplate> GetMojoTemplate(v8::Isolate* isolate);
+
+} // namespace js
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_BINDINGS_JS_MOJO_H_
diff --git a/mojo/public/bindings/js/mojo_unittests.js b/mojo/public/bindings/js/mojo_unittests.js
new file mode 100644
index 0000000..1e24ed8
--- /dev/null
+++ b/mojo/public/bindings/js/mojo_unittests.js
@@ -0,0 +1,8 @@
+// Copyright 2013 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.
+
+function main(mojo) {
+ mojo.gtest.expectTrue(mojo.core, "mojo.core");
+ mojo.gtest.expectFalse(mojo.foo, "mojo.foo");
+}
diff --git a/mojo/public/bindings/js/runner_delegate.cc b/mojo/public/bindings/js/runner_delegate.cc
new file mode 100644
index 0000000..f990caa
--- /dev/null
+++ b/mojo/public/bindings/js/runner_delegate.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 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 "mojo/public/bindings/js/runner_delegate.h"
+
+#include "mojo/public/bindings/js/mojo.h"
+
+namespace mojo {
+namespace js {
+
+RunnerDelegate::RunnerDelegate() {
+}
+
+RunnerDelegate::~RunnerDelegate() {
+}
+
+v8::Handle<v8::Object> RunnerDelegate::CreateRootObject(gin::Runner* runner) {
+ return GetMojoTemplate(runner->isolate())->NewInstance();
+}
+
+} // namespace js
+} // namespace mojo
diff --git a/mojo/public/bindings/js/runner_delegate.h b/mojo/public/bindings/js/runner_delegate.h
new file mode 100644
index 0000000..8bacf44
--- /dev/null
+++ b/mojo/public/bindings/js/runner_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2013 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 MOJO_PUBLIC_BINDINGS_JS_RUNNER_H_
+#define MOJO_PUBLIC_BINDINGS_JS_RUNNER_H_
+
+#include "gin/runner.h"
+#include "mojo/public/system/macros.h"
+
+namespace mojo {
+namespace js {
+
+class RunnerDelegate : public gin::RunnerDelegate {
+ public:
+ RunnerDelegate();
+ virtual ~RunnerDelegate();
+
+ virtual v8::Handle<v8::Object> CreateRootObject(
+ gin::Runner* runner) MOJO_OVERRIDE;
+
+ private:
+ MOJO_DISALLOW_COPY_AND_ASSIGN(RunnerDelegate);
+};
+
+} // namespace js
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_BINDINGS_JS_RUNNER_H_
diff --git a/mojo/public/bindings/js/test/DEPS b/mojo/public/bindings/js/test/DEPS
new file mode 100644
index 0000000..5cd0867
--- /dev/null
+++ b/mojo/public/bindings/js/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+base",
+]
diff --git a/mojo/public/bindings/js/test/harness.cc b/mojo/public/bindings/js/test/harness.cc
new file mode 100644
index 0000000..b4b81f4
--- /dev/null
+++ b/mojo/public/bindings/js/test/harness.cc
@@ -0,0 +1,69 @@
+// Copyright 2013 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 "base/file_util.h"
+#include "base/path_service.h"
+#include "gin/converter.h"
+#include "gin/runner.h"
+#include "gin/test/gtest.h"
+#include "mojo/public/bindings/js/runner_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using v8::Isolate;
+using v8::Object;
+using v8::Script;
+using v8::Value;
+
+namespace mojo {
+namespace js {
+namespace {
+
+class TestRunnerDelegate : public RunnerDelegate {
+ public:
+ virtual ~TestRunnerDelegate() {}
+
+ virtual v8::Handle<Object> CreateRootObject(
+ gin::Runner* runner) MOJO_OVERRIDE {
+ v8::Handle<Object> root = RunnerDelegate::CreateRootObject(runner);
+ root->Set(gin::StringToSymbol(runner->isolate(), "gtest"),
+ gin::GetGTestTemplate(runner->isolate())->NewInstance());
+ return root;
+ }
+};
+
+void RunTestFromFile(const base::FilePath& path) {
+ EXPECT_TRUE(base::PathExists(path)) << path.LossyDisplayName();
+ std::string source;
+ EXPECT_TRUE(ReadFileToString(path, &source));
+ Isolate* isolate = Isolate::GetCurrent();
+
+ TestRunnerDelegate delegate;
+ gin::Runner runner(&delegate, isolate);
+ gin::Runner::Scope scope(&runner);
+
+ v8::TryCatch try_catch;
+ runner.Run(Script::New(gin::StringToV8(isolate, source)));
+
+ EXPECT_FALSE(try_catch.HasCaught());
+}
+
+void RunTest(std::string test) {
+ base::FilePath path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ path = path.AppendASCII("mojo")
+ .AppendASCII("public")
+ .AppendASCII("bindings")
+ .AppendASCII("js")
+ .AppendASCII(test);
+ RunTestFromFile(path);
+}
+
+// TODO(abarth): Should we autogenerate these stubs from GYP?
+TEST(Harness, mojo_unittests_js) {
+ RunTest("mojo_unittests.js");
+}
+
+} // namespace
+} // namespace js
+} // namespace mojo