aboutsummaryrefslogtreecommitdiff
path: root/mojo/public/js
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/public/js')
-rw-r--r--mojo/public/js/BUILD.gn29
-rw-r--r--mojo/public/js/bindings.js336
-rw-r--r--mojo/public/js/codec.js81
-rw-r--r--mojo/public/js/codec_unittests.js296
-rw-r--r--mojo/public/js/connection.js176
-rw-r--r--mojo/public/js/connector.js27
-rw-r--r--mojo/public/js/constants.cc11
-rw-r--r--mojo/public/js/constants.h7
-rw-r--r--mojo/public/js/core.js75
-rw-r--r--mojo/public/js/core_unittests.js198
-rw-r--r--mojo/public/js/router.js91
-rw-r--r--mojo/public/js/struct_unittests.js279
-rw-r--r--mojo/public/js/test/validation_test_input_parser.js299
-rw-r--r--mojo/public/js/threading.js2
-rw-r--r--mojo/public/js/union_unittests.js184
-rw-r--r--mojo/public/js/validation_unittests.js349
-rw-r--r--mojo/public/js/validator.js153
17 files changed, 627 insertions, 1966 deletions
diff --git a/mojo/public/js/BUILD.gn b/mojo/public/js/BUILD.gn
index eda7e04..0fae4b4 100644
--- a/mojo/public/js/BUILD.gn
+++ b/mojo/public/js/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings"
+
source_set("js") {
sources = [
"constants.cc",
@@ -11,34 +13,43 @@ source_set("js") {
group("bindings") {
data = [
+ "$interfaces_bindings_gen_dir/interface_control_messages.mojom.js",
"bindings.js",
"buffer.js",
"codec.js",
- "connection.js",
"connector.js",
- "constants.cc",
- "constants.h",
"core.js",
+ "interface_types.js",
+ "lib/control_message_handler.js",
+ "lib/control_message_proxy.js",
"router.js",
"support.js",
"threading.js",
"unicode.js",
"validator.js",
]
+
+ deps = [
+ "//mojo/public/interfaces/bindings:bindings__generator",
+ ]
}
group("tests") {
testonly = true
data = [
- "codec_unittests.js",
- "core_unittests.js",
- "struct_unittests.js",
- "test/validation_test_input_parser.js",
- "union_unittests.js",
- "validation_unittests.js",
"//mojo/public/interfaces/bindings/tests/data/validation/",
+ "tests/codec_unittest.js",
+ "tests/connection_unittest.js",
+ "tests/core_unittest.js",
+ "tests/interface_ptr_unittest.js",
+ "tests/sample_service_unittest.js",
+ "tests/struct_unittest.js",
+ "tests/union_unittest.js",
+ "tests/validation_test_input_parser.js",
+ "tests/validation_unittest.js",
]
+
public_deps = [
":bindings",
]
diff --git a/mojo/public/js/bindings.js b/mojo/public/js/bindings.js
index 2fdcae3..f3e40d2 100644
--- a/mojo/public/js/bindings.js
+++ b/mojo/public/js/bindings.js
@@ -3,115 +3,283 @@
// found in the LICENSE file.
define("mojo/public/js/bindings", [
- "mojo/public/js/router",
"mojo/public/js/core",
-], function(router, core) {
-
- var Router = router.Router;
+ "mojo/public/js/lib/control_message_proxy",
+ "mojo/public/js/interface_types",
+ "mojo/public/js/router",
+], function(core, controlMessageProxy, types, router) {
- var kProxyProperties = Symbol("proxyProperties");
- var kStubProperties = Symbol("stubProperties");
+ // ---------------------------------------------------------------------------
- // Public proxy class properties that are managed at runtime by the JS
- // bindings. See ProxyBindings below.
- function ProxyProperties(receiver) {
- this.receiver = receiver;
+ function makeRequest(interfacePtr) {
+ var pipe = core.createMessagePipe();
+ interfacePtr.ptr.bind(new types.InterfacePtrInfo(pipe.handle0, 0));
+ return new types.InterfaceRequest(pipe.handle1);
}
- // TODO(hansmuller): remove then after 'Client=' has been removed from Mojom.
- ProxyProperties.prototype.getLocalDelegate = function() {
- return this.local && StubBindings(this.local).delegate;
- }
+ // ---------------------------------------------------------------------------
- // TODO(hansmuller): remove then after 'Client=' has been removed from Mojom.
- ProxyProperties.prototype.setLocalDelegate = function(impl) {
- if (this.local)
- StubBindings(this.local).delegate = impl;
- else
- throw new Error("no stub object");
- }
+ // Operations used to setup/configure an interface pointer. Exposed as the
+ // |ptr| field of generated interface pointer classes.
+ // |ptrInfoOrHandle| could be omitted and passed into bind() later.
+ function InterfacePtrController(interfaceType, ptrInfoOrHandle) {
+ this.version = 0;
- ProxyProperties.prototype.close = function() {
- this.connection.close();
- }
+ this.interfaceType_ = interfaceType;
+ this.router_ = null;
+ this.proxy_ = null;
- // Public stub class properties that are managed at runtime by the JS
- // bindings. See StubBindings below.
- function StubProperties(delegate) {
- this.delegate = delegate;
- }
+ // |router_| is lazily initialized. |handle_| is valid between bind() and
+ // the initialization of |router_|.
+ this.handle_ = null;
+ this.controlMessageProxy_ = null;
- StubProperties.prototype.close = function() {
- this.connection.close();
+ if (ptrInfoOrHandle)
+ this.bind(ptrInfoOrHandle);
}
- // The base class for generated proxy classes.
- function ProxyBase(receiver) {
- this[kProxyProperties] = new ProxyProperties(receiver);
+ InterfacePtrController.prototype.bind = function(ptrInfoOrHandle) {
+ this.reset();
- // TODO(hansmuller): Temporary, for Chrome backwards compatibility.
- if (receiver instanceof Router)
- this.receiver_ = receiver;
- }
+ if (ptrInfoOrHandle instanceof types.InterfacePtrInfo) {
+ this.version = ptrInfoOrHandle.version;
+ this.handle_ = ptrInfoOrHandle.handle;
+ } else {
+ this.handle_ = ptrInfoOrHandle;
+ }
+ };
- // The base class for generated stub classes.
- function StubBase(delegate) {
- this[kStubProperties] = new StubProperties(delegate);
- }
+ InterfacePtrController.prototype.isBound = function() {
+ return this.router_ !== null || this.handle_ !== null;
+ };
- // TODO(hansmuller): remove everything except the connection property doc
- // after 'Client=' has been removed from Mojom.
+ // Although users could just discard the object, reset() closes the pipe
+ // immediately.
+ InterfacePtrController.prototype.reset = function() {
+ this.version = 0;
+ if (this.router_) {
+ this.router_.close();
+ this.router_ = null;
- // Provides access to properties added to a proxy object without risking
- // Mojo interface name collisions. Unless otherwise specified, the initial
- // value of all properties is undefined.
- //
- // ProxyBindings(proxy).connection - The Connection object that links the
- // proxy for a remote Mojo service to an optional local stub for a local
- // service. The value of ProxyBindings(proxy).connection.remote == proxy.
+ this.proxy_ = null;
+ }
+ if (this.handle_) {
+ core.close(this.handle_);
+ this.handle_ = null;
+ }
+ };
+
+ InterfacePtrController.prototype.setConnectionErrorHandler
+ = function(callback) {
+ if (!this.isBound())
+ throw new Error("Cannot set connection error handler if not bound.");
+
+ this.configureProxyIfNecessary_();
+ this.router_.setErrorHandler(callback);
+ };
+
+ InterfacePtrController.prototype.passInterface = function() {
+ var result;
+ if (this.router_) {
+ // TODO(yzshen): Fix Router interface to support extracting handle.
+ result = new types.InterfacePtrInfo(
+ this.router_.connector_.handle_, this.version);
+ this.router_.connector_.handle_ = null;
+ } else {
+ // This also handles the case when this object is not bound.
+ result = new types.InterfacePtrInfo(this.handle_, this.version);
+ this.handle_ = null;
+ }
+
+ this.reset();
+ return result;
+ };
+
+ InterfacePtrController.prototype.getProxy = function() {
+ this.configureProxyIfNecessary_();
+ return this.proxy_;
+ };
+
+ InterfacePtrController.prototype.enableTestingMode = function() {
+ this.configureProxyIfNecessary_();
+ return this.router_.enableTestingMode();
+ };
+
+ InterfacePtrController.prototype.configureProxyIfNecessary_ = function() {
+ if (!this.handle_)
+ return;
+
+ this.router_ = new router.Router(this.handle_);
+ this.handle_ = null;
+ this.router_ .setPayloadValidators([this.interfaceType_.validateResponse]);
+
+ this.controlMessageProxy_ = new
+ controlMessageProxy.ControlMessageProxy(this.router_);
+
+ this.proxy_ = new this.interfaceType_.proxyClass(this.router_);
+ };
+
+ InterfacePtrController.prototype.queryVersion = function() {
+ function onQueryVersion(version) {
+ this.version = version;
+ return version;
+ }
+
+ this.configureProxyIfNecessary_();
+ return this.controlMessageProxy_.queryVersion().then(
+ onQueryVersion.bind(this));
+ };
+
+ InterfacePtrController.prototype.requireVersion = function(version) {
+ this.configureProxyIfNecessary_();
+
+ if (this.version >= version) {
+ return;
+ }
+ this.version = version;
+ this.controlMessageProxy_.requireVersion(version);
+ };
+
+ // ---------------------------------------------------------------------------
+
+ // |request| could be omitted and passed into bind() later.
//
- // ProxyBindings(proxy).local - The "local" stub object whose delegate
- // implements the proxy's Mojo client interface.
+ // Example:
//
- // ProxyBindings(proxy).setLocalDelegate(impl) - Sets the implementation
- // delegate of the proxy's client stub object. This is just shorthand
- // for |StubBindings(ProxyBindings(proxy).local).delegate = impl|.
+ // // FooImpl implements mojom.Foo.
+ // function FooImpl() { ... }
+ // FooImpl.prototype.fooMethod1 = function() { ... }
+ // FooImpl.prototype.fooMethod2 = function() { ... }
//
- // ProxyBindings(proxy).getLocalDelegate() - Returns the implementation
- // delegate of the proxy's client stub object. This is just shorthand
- // for |StubBindings(ProxyBindings(proxy).local).delegate|.
+ // var fooPtr = new mojom.FooPtr();
+ // var request = makeRequest(fooPtr);
+ // var binding = new Binding(mojom.Foo, new FooImpl(), request);
+ // fooPtr.fooMethod1();
+ function Binding(interfaceType, impl, requestOrHandle) {
+ this.interfaceType_ = interfaceType;
+ this.impl_ = impl;
+ this.router_ = null;
+ this.stub_ = null;
- function ProxyBindings(proxy) {
- return (proxy instanceof ProxyBase) ? proxy[kProxyProperties] : proxy;
+ if (requestOrHandle)
+ this.bind(requestOrHandle);
}
- // TODO(hansmuller): remove the remote doc after 'Client=' has been
- // removed from Mojom.
+ Binding.prototype.isBound = function() {
+ return this.router_ !== null;
+ };
- // Provides access to properties added to a stub object without risking
- // Mojo interface name collisions. Unless otherwise specified, the initial
- // value of all properties is undefined.
- //
- // StubBindings(stub).delegate - The optional implementation delegate for
- // the Mojo interface stub.
- //
- // StubBindings(stub).connection - The Connection object that links an
- // optional proxy for a remote service to this stub. The value of
- // StubBindings(stub).connection.local == stub.
- //
- // StubBindings(stub).remote - A proxy for the the stub's Mojo client
- // service.
+ Binding.prototype.createInterfacePtrAndBind = function() {
+ var ptr = new this.interfaceType_.ptrClass();
+ // TODO(yzshen): Set the version of the interface pointer.
+ this.bind(makeRequest(ptr));
+ return ptr;
+ }
+
+ Binding.prototype.bind = function(requestOrHandle) {
+ this.close();
+
+ var handle = requestOrHandle instanceof types.InterfaceRequest ?
+ requestOrHandle.handle : requestOrHandle;
+ if (!core.isHandle(handle))
+ return;
+
+ this.stub_ = new this.interfaceType_.stubClass(this.impl_);
+ this.router_ = new router.Router(handle, this.interfaceType_.kVersion);
+ this.router_.setIncomingReceiver(this.stub_);
+ this.router_ .setPayloadValidators([this.interfaceType_.validateRequest]);
+ };
+
+ Binding.prototype.close = function() {
+ if (!this.isBound())
+ return;
+
+ this.router_.close();
+ this.router_ = null;
+ this.stub_ = null;
+ };
+
+ Binding.prototype.setConnectionErrorHandler
+ = function(callback) {
+ if (!this.isBound())
+ throw new Error("Cannot set connection error handler if not bound.");
+ this.router_.setErrorHandler(callback);
+ };
+
+ Binding.prototype.unbind = function() {
+ if (!this.isBound())
+ return new types.InterfaceRequest(null);
+
+ var result = new types.InterfaceRequest(this.router_.connector_.handle_);
+ this.router_.connector_.handle_ = null;
+ this.close();
+ return result;
+ };
+
+ Binding.prototype.enableTestingMode = function() {
+ return this.router_.enableTestingMode();
+ };
- function StubBindings(stub) {
- return stub instanceof StubBase ? stub[kStubProperties] : stub;
+ // ---------------------------------------------------------------------------
+
+ function BindingSetEntry(bindingSet, interfaceType, impl, requestOrHandle,
+ bindingId) {
+ this.bindingSet_ = bindingSet;
+ this.bindingId_ = bindingId;
+ this.binding_ = new Binding(interfaceType, impl, requestOrHandle);
+
+ this.binding_.setConnectionErrorHandler(function() {
+ this.bindingSet_.onConnectionError(bindingId);
+ }.bind(this));
+ }
+
+ BindingSetEntry.prototype.close = function() {
+ this.binding_.close();
+ };
+
+ function BindingSet(interfaceType) {
+ this.interfaceType_ = interfaceType;
+ this.nextBindingId_ = 0;
+ this.bindings_ = new Map();
+ this.errorHandler_ = null;
}
+ BindingSet.prototype.isEmpty = function() {
+ return this.bindings_.size == 0;
+ };
+
+ BindingSet.prototype.addBinding = function(impl, requestOrHandle) {
+ this.bindings_.set(
+ this.nextBindingId_,
+ new BindingSetEntry(this, this.interfaceType_, impl, requestOrHandle,
+ this.nextBindingId_));
+ ++this.nextBindingId_;
+ };
+
+ BindingSet.prototype.closeAllBindings = function() {
+ for (var entry of this.bindings_.values())
+ entry.close();
+ this.bindings_.clear();
+ };
+
+ BindingSet.prototype.setConnectionErrorHandler = function(callback) {
+ this.errorHandler_ = callback;
+ };
+
+ BindingSet.prototype.onConnectionError = function(bindingId) {
+ this.bindings_.delete(bindingId);
+
+ if (this.errorHandler_)
+ this.errorHandler_();
+ };
+
var exports = {};
- exports.EmptyProxy = ProxyBase;
- exports.EmptyStub = StubBase;
- exports.ProxyBase = ProxyBase;
- exports.ProxyBindings = ProxyBindings;
- exports.StubBase = StubBase;
- exports.StubBindings = StubBindings;
+ exports.InterfacePtrInfo = types.InterfacePtrInfo;
+ exports.InterfaceRequest = types.InterfaceRequest;
+ exports.makeRequest = makeRequest;
+ exports.InterfacePtrController = InterfacePtrController;
+ exports.Binding = Binding;
+ exports.BindingSet = BindingSet;
+
return exports;
});
diff --git a/mojo/public/js/codec.js b/mojo/public/js/codec.js
index 4003b51..ff5d31a 100644
--- a/mojo/public/js/codec.js
+++ b/mojo/public/js/codec.js
@@ -3,9 +3,10 @@
// found in the LICENSE file.
define("mojo/public/js/codec", [
- "mojo/public/js/unicode",
"mojo/public/js/buffer",
-], function(unicode, buffer) {
+ "mojo/public/js/interface_types",
+ "mojo/public/js/unicode",
+], function(buffer, types, unicode) {
var kErrorUnsigned = "Passing negative value to unsigned";
var kErrorArray = "Passing non Array for array type";
@@ -303,8 +304,12 @@ define("mojo/public/js/codec", [
};
Encoder.prototype.encodeHandle = function(handle) {
- this.handles.push(handle);
- this.writeUint32(this.handles.length - 1);
+ if (handle) {
+ this.handles.push(handle);
+ this.writeUint32(this.handles.length - 1);
+ } else {
+ this.writeUint32(kEncodedInvalidHandleValue);
+ }
};
Encoder.prototype.encodeString = function(val) {
@@ -711,6 +716,20 @@ define("mojo/public/js/codec", [
encoder.writeDouble(val);
};
+ function Enum(cls) {
+ this.cls = cls;
+ }
+
+ Enum.prototype.encodedSize = 4;
+
+ Enum.prototype.decode = function(decoder) {
+ return decoder.readInt32();
+ };
+
+ Enum.prototype.encode = function(encoder, val) {
+ encoder.writeInt32(val);
+ };
+
function PointerTo(cls) {
this.cls = cls;
}
@@ -788,33 +807,54 @@ define("mojo/public/js/codec", [
NullableHandle.encode = Handle.encode;
- function Interface() {
+ function Interface(cls) {
+ this.cls = cls;
}
- Interface.encodedSize = 8;
+ Interface.prototype.encodedSize = 8;
- Interface.decode = function(decoder) {
- var handle = decoder.decodeHandle();
- // Ignore the version field for now.
- decoder.readUint32();
+ Interface.prototype.decode = function(decoder) {
+ var interfacePtrInfo = new types.InterfacePtrInfo(
+ decoder.decodeHandle(), decoder.readUint32());
+ var interfacePtr = new this.cls();
+ interfacePtr.ptr.bind(interfacePtrInfo);
+ return interfacePtr;
+ };
- return handle;
+ Interface.prototype.encode = function(encoder, val) {
+ var interfacePtrInfo =
+ val ? val.ptr.passInterface() : new types.InterfacePtrInfo(null, 0);
+ encoder.encodeHandle(interfacePtrInfo.handle);
+ encoder.writeUint32(interfacePtrInfo.version);
};
- Interface.encode = function(encoder, val) {
- encoder.encodeHandle(val);
- // Set the version field to 0 for now.
- encoder.writeUint32(0);
+ function NullableInterface(cls) {
+ Interface.call(this, cls);
+ }
+
+ NullableInterface.prototype = Object.create(Interface.prototype);
+
+ function InterfaceRequest() {
+ }
+
+ InterfaceRequest.encodedSize = 4;
+
+ InterfaceRequest.decode = function(decoder) {
+ return new types.InterfaceRequest(decoder.decodeHandle());
+ };
+
+ InterfaceRequest.encode = function(encoder, val) {
+ encoder.encodeHandle(val ? val.handle : null);
};
- function NullableInterface() {
+ function NullableInterfaceRequest() {
}
- NullableInterface.encodedSize = Interface.encodedSize;
+ NullableInterfaceRequest.encodedSize = InterfaceRequest.encodedSize;
- NullableInterface.decode = Interface.decode;
+ NullableInterfaceRequest.decode = InterfaceRequest.decode;
- NullableInterface.encode = Interface.encode;
+ NullableInterfaceRequest.encode = InterfaceRequest.encode;
function MapOf(keyClass, valueClass) {
this.keyClass = keyClass;
@@ -863,6 +903,7 @@ define("mojo/public/js/codec", [
exports.Float = Float;
exports.Double = Double;
exports.String = String;
+ exports.Enum = Enum;
exports.NullableString = NullableString;
exports.PointerTo = PointerTo;
exports.NullablePointerTo = NullablePointerTo;
@@ -873,6 +914,8 @@ define("mojo/public/js/codec", [
exports.NullableHandle = NullableHandle;
exports.Interface = Interface;
exports.NullableInterface = NullableInterface;
+ exports.InterfaceRequest = InterfaceRequest;
+ exports.NullableInterfaceRequest = NullableInterfaceRequest;
exports.MapOf = MapOf;
exports.NullableMapOf = NullableMapOf;
return exports;
diff --git a/mojo/public/js/codec_unittests.js b/mojo/public/js/codec_unittests.js
deleted file mode 100644
index b610d9a..0000000
--- a/mojo/public/js/codec_unittests.js
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright 2014 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.
-
-define([
- "gin/test/expect",
- "mojo/public/js/codec",
- "mojo/public/interfaces/bindings/tests/rect.mojom",
- "mojo/public/interfaces/bindings/tests/sample_service.mojom",
- "mojo/public/interfaces/bindings/tests/test_structs.mojom",
- ], function(expect, codec, rect, sample, structs) {
- testBar();
- testFoo();
- testNamedRegion();
- testTypes();
- testAlign();
- testUtf8();
- testTypedPointerValidation();
- this.result = "PASS";
-
- function testBar() {
- var bar = new sample.Bar();
- bar.alpha = 1;
- bar.beta = 2;
- bar.gamma = 3;
- bar.type = 0x08070605;
- bar.extraProperty = "banana";
-
- var messageName = 42;
- var payloadSize = sample.Bar.encodedSize;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- builder.encodeStruct(sample.Bar, bar);
-
- var message = builder.finish();
-
- var expectedMemory = new Uint8Array([
- 24, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 42, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
-
- 16, 0, 0, 0,
- 0, 0, 0, 0,
-
- 1, 2, 3, 0,
- 5, 6, 7, 8,
- ]);
-
- var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
- expect(actualMemory).toEqual(expectedMemory);
-
- var reader = new codec.MessageReader(message);
-
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
-
- var bar2 = reader.decodeStruct(sample.Bar);
-
- expect(bar2.alpha).toBe(bar.alpha);
- expect(bar2.beta).toBe(bar.beta);
- expect(bar2.gamma).toBe(bar.gamma);
- expect("extraProperty" in bar2).toBeFalsy();
- }
-
- function testFoo() {
- var foo = new sample.Foo();
- foo.x = 0x212B4D5;
- foo.y = 0x16E93;
- foo.a = 1;
- foo.b = 0;
- foo.c = 3; // This will get truncated to one bit.
- foo.bar = new sample.Bar();
- foo.bar.alpha = 91;
- foo.bar.beta = 82;
- foo.bar.gamma = 73;
- foo.data = [
- 4, 5, 6, 7, 8,
- ];
- foo.extra_bars = [
- new sample.Bar(), new sample.Bar(), new sample.Bar(),
- ];
- for (var i = 0; i < foo.extra_bars.length; ++i) {
- foo.extra_bars[i].alpha = 1 * i;
- foo.extra_bars[i].beta = 2 * i;
- foo.extra_bars[i].gamma = 3 * i;
- }
- foo.name = "I am a banana";
- // This is supposed to be a handle, but we fake it with an integer.
- foo.source = 23423782;
- foo.array_of_array_of_bools = [
- [true], [false, true]
- ];
- foo.array_of_bools = [
- true, false, true, false, true, false, true, true
- ];
-
-
- var messageName = 31;
- var payloadSize = 304;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- builder.encodeStruct(sample.Foo, foo);
-
- var message = builder.finish();
-
- var expectedMemory = new Uint8Array([
- /* 0: */ 24, 0, 0, 0, 0, 0, 0, 0,
- /* 8: */ 0, 0, 0, 0, 31, 0, 0, 0,
- /* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 24: */ 96, 0, 0, 0, 0, 0, 0, 0,
- /* 32: */ 0xD5, 0xB4, 0x12, 0x02, 0x93, 0x6E, 0x01, 0,
- /* 40: */ 5, 0, 0, 0, 0, 0, 0, 0,
- /* 48: */ 72, 0, 0, 0, 0, 0, 0, 0,
- ]);
- // TODO(abarth): Test more of the message's raw memory.
- var actualMemory = new Uint8Array(message.buffer.arrayBuffer,
- 0, expectedMemory.length);
- expect(actualMemory).toEqual(expectedMemory);
-
- var expectedHandles = [
- 23423782,
- ];
-
- expect(message.handles).toEqual(expectedHandles);
-
- var reader = new codec.MessageReader(message);
-
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
-
- var foo2 = reader.decodeStruct(sample.Foo);
-
- expect(foo2.x).toBe(foo.x);
- expect(foo2.y).toBe(foo.y);
-
- expect(foo2.a).toBe(foo.a & 1 ? true : false);
- expect(foo2.b).toBe(foo.b & 1 ? true : false);
- expect(foo2.c).toBe(foo.c & 1 ? true : false);
-
- expect(foo2.bar).toEqual(foo.bar);
- expect(foo2.data).toEqual(foo.data);
-
- expect(foo2.extra_bars).toEqual(foo.extra_bars);
- expect(foo2.name).toBe(foo.name);
- expect(foo2.source).toEqual(foo.source);
-
- expect(foo2.array_of_bools).toEqual(foo.array_of_bools);
- }
-
- function createRect(x, y, width, height) {
- var r = new rect.Rect();
- r.x = x;
- r.y = y;
- r.width = width;
- r.height = height;
- return r;
- }
-
- // Verify that the references to the imported Rect type in test_structs.mojom
- // are generated correctly.
- function testNamedRegion() {
- var r = new structs.NamedRegion();
- r.name = "rectangle";
- r.rects = new Array(createRect(1, 2, 3, 4), createRect(10, 20, 30, 40));
-
- var builder = new codec.MessageBuilder(1, structs.NamedRegion.encodedSize);
- builder.encodeStruct(structs.NamedRegion, r);
- var reader = new codec.MessageReader(builder.finish());
- var result = reader.decodeStruct(structs.NamedRegion);
-
- expect(result.name).toEqual("rectangle");
- expect(result.rects[0]).toEqual(createRect(1, 2, 3, 4));
- expect(result.rects[1]).toEqual(createRect(10, 20, 30, 40));
- }
-
- function testTypes() {
- function encodeDecode(cls, input, expectedResult, encodedSize) {
- var messageName = 42;
- var payloadSize = encodedSize || cls.encodedSize;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- builder.encodeStruct(cls, input)
- var message = builder.finish();
-
- var reader = new codec.MessageReader(message);
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
- var result = reader.decodeStruct(cls);
- expect(result).toEqual(expectedResult);
- }
- encodeDecode(codec.String, "banana", "banana", 24);
- encodeDecode(codec.NullableString, null, null, 8);
- encodeDecode(codec.Int8, -1, -1);
- encodeDecode(codec.Int8, 0xff, -1);
- encodeDecode(codec.Int16, -1, -1);
- encodeDecode(codec.Int16, 0xff, 0xff);
- encodeDecode(codec.Int16, 0xffff, -1);
- encodeDecode(codec.Int32, -1, -1);
- encodeDecode(codec.Int32, 0xffff, 0xffff);
- encodeDecode(codec.Int32, 0xffffffff, -1);
- encodeDecode(codec.Float, 1.0, 1.0);
- encodeDecode(codec.Double, 1.0, 1.0);
- }
-
- function testAlign() {
- var aligned = [
- 0, // 0
- 8, // 1
- 8, // 2
- 8, // 3
- 8, // 4
- 8, // 5
- 8, // 6
- 8, // 7
- 8, // 8
- 16, // 9
- 16, // 10
- 16, // 11
- 16, // 12
- 16, // 13
- 16, // 14
- 16, // 15
- 16, // 16
- 24, // 17
- 24, // 18
- 24, // 19
- 24, // 20
- ];
- for (var i = 0; i < aligned.length; ++i)
- expect(codec.align(i)).toBe(aligned[i]);
- }
-
- function testUtf8() {
- var str = "B\u03ba\u1f79"; // some UCS-2 codepoints
- var messageName = 42;
- var payloadSize = 24;
-
- var builder = new codec.MessageBuilder(messageName, payloadSize);
- var encoder = builder.createEncoder(8);
- encoder.encodeStringPointer(str);
- var message = builder.finish();
- var expectedMemory = new Uint8Array([
- /* 0: */ 24, 0, 0, 0, 0, 0, 0, 0,
- /* 8: */ 0, 0, 0, 0, 42, 0, 0, 0,
- /* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 24: */ 8, 0, 0, 0, 0, 0, 0, 0,
- /* 32: */ 14, 0, 0, 0, 6, 0, 0, 0,
- /* 40: */ 0x42, 0xCE, 0xBA, 0xE1, 0xBD, 0xB9, 0, 0,
- ]);
- var actualMemory = new Uint8Array(message.buffer.arrayBuffer);
- expect(actualMemory.length).toEqual(expectedMemory.length);
- expect(actualMemory).toEqual(expectedMemory);
-
- var reader = new codec.MessageReader(message);
- expect(reader.payloadSize).toBe(payloadSize);
- expect(reader.messageName).toBe(messageName);
- var str2 = reader.decoder.decodeStringPointer();
- expect(str2).toEqual(str);
- }
-
- function testTypedPointerValidation() {
- var encoder = new codec.MessageBuilder(42, 24).createEncoder(8);
- function DummyClass() {};
- var testCases = [
- // method, args, invalid examples, valid examples
- [encoder.encodeArrayPointer, [DummyClass], [75],
- [[], null, undefined, new Uint8Array([])]],
- [encoder.encodeStringPointer, [], [75, new String("foo")],
- ["", "bar", null, undefined]],
- [encoder.encodeMapPointer, [DummyClass, DummyClass], [75],
- [new Map(), null, undefined]],
- ];
-
- testCases.forEach(function(test) {
- var method = test[0];
- var baseArgs = test[1];
- var invalidExamples = test[2];
- var validExamples = test[3];
-
- var encoder = new codec.MessageBuilder(42, 24).createEncoder(8);
- invalidExamples.forEach(function(invalid) {
- expect(function() {
- method.apply(encoder, baseArgs.concat(invalid));
- }).toThrow();
- });
-
- validExamples.forEach(function(valid) {
- var encoder = new codec.MessageBuilder(42, 24).createEncoder(8);
- method.apply(encoder, baseArgs.concat(valid));
- });
- });
- }
-});
diff --git a/mojo/public/js/connection.js b/mojo/public/js/connection.js
deleted file mode 100644
index 3f7e839..0000000
--- a/mojo/public/js/connection.js
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2014 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.
-
-define("mojo/public/js/connection", [
- "mojo/public/js/bindings",
- "mojo/public/js/connector",
- "mojo/public/js/core",
- "mojo/public/js/router",
-], function(bindings, connector, core, router) {
-
- var Router = router.Router;
- var EmptyProxy = bindings.EmptyProxy;
- var EmptyStub = bindings.EmptyStub;
- var ProxyBindings = bindings.ProxyBindings;
- var StubBindings = bindings.StubBindings;
- var TestConnector = connector.TestConnector;
- var TestRouter = router.TestRouter;
-
- // TODO(hansmuller): the proxy receiver_ property should be receiver$
-
- function BaseConnection(localStub, remoteProxy, router) {
- this.router_ = router;
- this.local = localStub;
- this.remote = remoteProxy;
-
- this.router_.setIncomingReceiver(localStub);
- this.router_.setErrorHandler(function() {
- if (StubBindings(this.local) &&
- StubBindings(this.local).connectionErrorHandler)
- StubBindings(this.local).connectionErrorHandler();
- }.bind(this));
- if (this.remote)
- this.remote.receiver_ = router;
-
- // Validate incoming messages: remote responses and local requests.
- var validateRequest = localStub && localStub.validator;
- var validateResponse = remoteProxy && remoteProxy.validator;
- var payloadValidators = [];
- if (validateRequest)
- payloadValidators.push(validateRequest);
- if (validateResponse)
- payloadValidators.push(validateResponse);
- this.router_.setPayloadValidators(payloadValidators);
- }
-
- BaseConnection.prototype.close = function() {
- this.router_.close();
- this.router_ = null;
- this.local = null;
- this.remote = null;
- };
-
- BaseConnection.prototype.encounteredError = function() {
- return this.router_.encounteredError();
- };
-
- function Connection(
- handle, localFactory, remoteFactory, routerFactory, connectorFactory) {
- var routerClass = routerFactory || Router;
- var router = new routerClass(handle, connectorFactory);
- var remoteProxy = remoteFactory && new remoteFactory(router);
- var localStub = localFactory && new localFactory(remoteProxy);
- BaseConnection.call(this, localStub, remoteProxy, router);
- }
-
- Connection.prototype = Object.create(BaseConnection.prototype);
-
- // The TestConnection subclass is only intended to be used in unit tests.
- function TestConnection(handle, localFactory, remoteFactory) {
- Connection.call(this,
- handle,
- localFactory,
- remoteFactory,
- TestRouter,
- TestConnector);
- }
-
- TestConnection.prototype = Object.create(Connection.prototype);
-
- // Return a handle for a message pipe that's connected to a proxy
- // for remoteInterface. Used by generated code for outgoing interface&
- // (request) parameters: the caller is given the generated proxy via
- // |proxyCallback(proxy)| and the generated code sends the handle
- // returned by this function.
- function bindProxy(proxyCallback, remoteInterface) {
- var messagePipe = core.createMessagePipe();
- if (messagePipe.result != core.RESULT_OK)
- throw new Error("createMessagePipe failed " + messagePipe.result);
-
- var proxy = new remoteInterface.proxyClass;
- var router = new Router(messagePipe.handle0);
- var connection = new BaseConnection(undefined, proxy, router);
- ProxyBindings(proxy).connection = connection;
- if (proxyCallback)
- proxyCallback(proxy);
-
- return messagePipe.handle1;
- }
-
- // Return a handle for a message pipe that's connected to a stub for
- // localInterface. Used by generated code for outgoing interface
- // parameters: the caller is given the generated stub via
- // |stubCallback(stub)| and the generated code sends the handle
- // returned by this function. The caller is responsible for managing
- // the lifetime of the stub and for setting it's implementation
- // delegate with: StubBindings(stub).delegate = myImpl;
- function bindImpl(stubCallback, localInterface) {
- var messagePipe = core.createMessagePipe();
- if (messagePipe.result != core.RESULT_OK)
- throw new Error("createMessagePipe failed " + messagePipe.result);
-
- var stub = new localInterface.stubClass;
- var router = new Router(messagePipe.handle0);
- var connection = new BaseConnection(stub, undefined, router);
- StubBindings(stub).connection = connection;
- if (stubCallback)
- stubCallback(stub);
-
- return messagePipe.handle1;
- }
-
- // Return a remoteInterface proxy for handle. Used by generated code
- // for converting incoming interface parameters to proxies.
- function bindHandleToProxy(handle, remoteInterface) {
- if (!core.isHandle(handle))
- throw new Error("Not a handle " + handle);
-
- var proxy = new remoteInterface.proxyClass;
- var router = new Router(handle);
- var connection = new BaseConnection(undefined, proxy, router);
- ProxyBindings(proxy).connection = connection;
- return proxy;
- }
-
- // Return a localInterface stub for handle. Used by generated code
- // for converting incoming interface& request parameters to localInterface
- // stubs. The caller can specify the stub's implementation of localInterface
- // like this: StubBindings(stub).delegate = myStubImpl.
- function bindHandleToStub(handle, localInterface) {
- if (!core.isHandle(handle))
- throw new Error("Not a handle " + handle);
-
- var stub = new localInterface.stubClass;
- var router = new Router(handle);
- var connection = new BaseConnection(stub, undefined, router);
- StubBindings(stub).connection = connection;
- return stub;
- }
-
- /**
- * Creates a messape pipe and links one end of the pipe to the given object.
- * @param {!Object} obj The object to create a handle for. Must be a subclass
- * of an auto-generated stub class.
- * @return {!MojoHandle} The other (not yet connected) end of the message
- * pipe.
- */
- function bindStubDerivedImpl(obj) {
- var pipe = core.createMessagePipe();
- var router = new Router(pipe.handle0);
- var connection = new BaseConnection(obj, undefined, router);
- obj.connection = connection;
- return pipe.handle1;
- }
-
- var exports = {};
- exports.Connection = Connection;
- exports.TestConnection = TestConnection;
-
- exports.bindProxy = bindProxy;
- exports.bindImpl = bindImpl;
- exports.bindHandleToProxy = bindHandleToProxy;
- exports.bindHandleToStub = bindHandleToStub;
- exports.bindStubDerivedImpl = bindStubDerivedImpl;
- return exports;
-});
diff --git a/mojo/public/js/connector.js b/mojo/public/js/connector.js
index 674f36b..ee16be8 100644
--- a/mojo/public/js/connector.js
+++ b/mojo/public/js/connector.js
@@ -82,6 +82,12 @@ define("mojo/public/js/connector", [
return this.error_;
};
+ Connector.prototype.waitForNextMessageForTesting = function() {
+ var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
+ core.DEADLINE_INDEFINITE);
+ this.readMore_(wait.result);
+ };
+
Connector.prototype.readMore_ = function(result) {
for (;;) {
var read = core.readMessage(this.handle_,
@@ -98,29 +104,12 @@ define("mojo/public/js/connector", [
}
var messageBuffer = new buffer.Buffer(read.buffer);
var message = new codec.Message(messageBuffer, read.handles);
- if (this.incomingReceiver_) {
- this.incomingReceiver_.accept(message);
- }
+ if (this.incomingReceiver_)
+ this.incomingReceiver_.accept(message);
}
};
- // The TestConnector subclass is only intended to be used in unit tests. It
- // doesn't automatically listen for input messages. Instead, you need to
- // call waitForNextMessage to block and wait for the next incoming message.
- function TestConnector(handle) {
- Connector.call(this, handle);
- }
-
- TestConnector.prototype = Object.create(Connector.prototype);
-
- TestConnector.prototype.waitForNextMessage = function() {
- var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
- core.DEADLINE_INDEFINITE);
- this.readMore_(wait.result);
- }
-
var exports = {};
exports.Connector = Connector;
- exports.TestConnector = TestConnector;
return exports;
});
diff --git a/mojo/public/js/constants.cc b/mojo/public/js/constants.cc
index d29f5cb..58cf274 100644
--- a/mojo/public/js/constants.cc
+++ b/mojo/public/js/constants.cc
@@ -9,10 +9,15 @@ namespace mojo {
const char kBindingsModuleName[] = "mojo/public/js/bindings";
const char kBufferModuleName[] = "mojo/public/js/buffer";
const char kCodecModuleName[] = "mojo/public/js/codec";
-const char kConnectionModuleName[] = "mojo/public/js/connection";
const char kConnectorModuleName[] = "mojo/public/js/connector";
-const char kUnicodeModuleName[] = "mojo/public/js/unicode";
+const char kControlMessageHandlerModuleName[] =
+ "mojo/public/js/lib/control_message_handler";
+const char kControlMessageProxyModuleName[] =
+ "mojo/public/js/lib/control_message_proxy";
+const char kInterfaceControlMessagesMojom[] =
+ "mojo/public/interfaces/bindings/interface_control_messages.mojom";
+const char kInterfaceTypesModuleName[] = "mojo/public/js/interface_types";
const char kRouterModuleName[] = "mojo/public/js/router";
+const char kUnicodeModuleName[] = "mojo/public/js/unicode";
const char kValidatorModuleName[] = "mojo/public/js/validator";
-
} // namespace mojo
diff --git a/mojo/public/js/constants.h b/mojo/public/js/constants.h
index de75a90..9d32d20 100644
--- a/mojo/public/js/constants.h
+++ b/mojo/public/js/constants.h
@@ -11,10 +11,13 @@ namespace mojo {
extern const char kBindingsModuleName[];
extern const char kBufferModuleName[];
extern const char kCodecModuleName[];
-extern const char kConnectionModuleName[];
extern const char kConnectorModuleName[];
-extern const char kUnicodeModuleName[];
+extern const char kControlMessageHandlerModuleName[];
+extern const char kControlMessageProxyModuleName[];
+extern const char kInterfaceControlMessagesMojom[];
+extern const char kInterfaceTypesModuleName[];
extern const char kRouterModuleName[];
+extern const char kUnicodeModuleName[];
extern const char kValidatorModuleName[];
} // namespace mojo
diff --git a/mojo/public/js/core.js b/mojo/public/js/core.js
index b89a956..ef480ee 100644
--- a/mojo/public/js/core.js
+++ b/mojo/public/js/core.js
@@ -114,6 +114,27 @@ var READ_DATA_FLAG_QUERY;
var READ_DATA_FLAG_PEEK;
/**
+ * MojoCreateSharedBufferOptionsFlags: Used to specify options to
+ * |createSharedBuffer()|.
+ * See core.h for more information.
+ */
+var CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
+
+/**
+ * MojoDuplicateBufferHandleOptionsFlags: Used to specify options to
+ * |duplicateBufferHandle()|.
+ * See core.h for more information.
+ */
+var DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE;
+var DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
+
+/**
+ * MojoMapBufferFlags: Used to specify options to |mapBuffer()|.
+ * See core.h for more information.
+ */
+var MAP_BUFFER_FLAG_NONE;
+
+/**
* Closes the given |handle|. See MojoClose for more info.
* @param {MojoHandle} Handle to close.
* @return {MojoResult} Result code.
@@ -236,3 +257,57 @@ function readData(handle, flags) { [native code] }
* @return true or false
*/
function isHandle(value) { [native code] }
+
+/**
+ * Creates shared buffer of specified size |num_bytes|.
+ * See MojoCreateSharedBuffer for more information including error codes.
+ *
+ * @param {number} num_bytes Size of the memory to be allocated for shared
+ * @param {MojoCreateSharedBufferOptionsFlags} flags Flags.
+ * buffer.
+ * @return {object} An object of the form {
+ * result, // |RESULT_OK| on success, error code otherwise.
+ * handle, // An MojoHandle for shared buffer (only on success).
+ * }
+ */
+function createSharedBuffer(num_bytes, flags) { [native code] }
+
+/**
+ * Duplicates the |buffer_handle| to a shared buffer. Duplicated handle can be
+ * sent to another process over message pipe. See MojoDuplicateBufferHandle for
+ * more information including error codes.
+ *
+ * @param {MojoHandle} buffer_handle MojoHandle.
+ * @param {MojoCreateSharedBufferOptionsFlags} flags Flags.
+ * @return {object} An object of the form {
+ * result, // |RESULT_OK| on success, error code otherwise.
+ * handle, // A duplicated MojoHandle for shared buffer (only on success).
+ * }
+ */
+function duplicateBufferHandle(buffer_handle, flags) { [native code] }
+
+/**
+ * Maps the part (at offset |offset| of length |num_bytes|) of the buffer given
+ * by |buffer_handle| into ArrayBuffer memory |buffer|, with options specified
+ * by |flags|. See MojoMapBuffer for more information including error codes.
+ *
+ * @param {MojoHandle} buffer_handle A sharedBufferHandle returned by
+ * createSharedBuffer.
+ * @param {number} offset Offset.
+ * @param {number} num_bytes Size of the memory to be mapped.
+ * @param {MojoMapBufferFlags} flags Flags.
+ * @return {object} An object of the form {
+ * result, // |RESULT_OK| on success, error code otherwise.
+ * buffer, // An ArrayBuffer (only on success).
+ * }
+ */
+function mapBuffer(buffer_handle, offset, num_bytes, flags) { [native code] }
+
+/**
+ * Unmaps buffer that was mapped using mapBuffer.
+ * See MojoUnmapBuffer for more information including error codes.
+ *
+ * @param {ArrayBuffer} buffer ArrayBuffer.
+ * @return {MojoResult} Result code.
+ */
+function unmapBuffer(buffer) { [native code] }
diff --git a/mojo/public/js/core_unittests.js b/mojo/public/js/core_unittests.js
deleted file mode 100644
index 12364dc..0000000
--- a/mojo/public/js/core_unittests.js
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2014 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.
-
-define([
- "gin/test/expect",
- "mojo/public/js/core",
- "gc",
- ], function(expect, core, gc) {
-
- var HANDLE_SIGNAL_READWRITABLE = core.HANDLE_SIGNAL_WRITABLE |
- core.HANDLE_SIGNAL_READABLE;
- var HANDLE_SIGNAL_ALL = core.HANDLE_SIGNAL_WRITABLE |
- core.HANDLE_SIGNAL_READABLE |
- core.HANDLE_SIGNAL_PEER_CLOSED;
-
- runWithMessagePipe(testNop);
- runWithMessagePipe(testReadAndWriteMessage);
- runWithMessagePipeWithOptions(testNop);
- runWithMessagePipeWithOptions(testReadAndWriteMessage);
- runWithDataPipe(testNop);
- runWithDataPipe(testReadAndWriteDataPipe);
- runWithDataPipeWithOptions(testNop);
- runWithDataPipeWithOptions(testReadAndWriteDataPipe);
- runWithMessagePipe(testIsHandleMessagePipe);
- runWithDataPipe(testIsHandleDataPipe);
- gc.collectGarbage(); // should not crash
- this.result = "PASS";
-
- function runWithMessagePipe(test) {
- var pipe = core.createMessagePipe();
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
- expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
- }
-
- function runWithMessagePipeWithOptions(test) {
- var pipe = core.createMessagePipe({
- flags: core.CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
- });
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
- expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
- }
-
- function runWithDataPipe(test) {
- var pipe = core.createDataPipe();
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
- expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
- }
-
- function runWithDataPipeWithOptions(test) {
- var pipe = core.createDataPipe({
- flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
- elementNumBytes: 1,
- capacityNumBytes: 64
- });
- expect(pipe.result).toBe(core.RESULT_OK);
-
- test(pipe);
-
- expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
- expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
- }
-
- function testNop(pipe) {
- }
-
- function testReadAndWriteMessage(pipe) {
- var wait = core.waitMany([], [], 0);
- expect(wait.result).toBe(core.RESULT_INVALID_ARGUMENT);
- expect(wait.index).toBe(null);
- expect(wait.signalsState).toBe(null);
-
- wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_READABLE, 0);
- expect(wait.result).toBe(core.RESULT_DEADLINE_EXCEEDED);
- expect(wait.signalsState.satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- wait = core.waitMany(
- [pipe.handle0, pipe.handle1],
- [core.HANDLE_SIGNAL_READABLE,core.HANDLE_SIGNAL_READABLE],
- 0);
- expect(wait.result).toBe(core.RESULT_DEADLINE_EXCEEDED);
- expect(wait.index).toBe(null);
- expect(wait.signalsState[0].satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState[0].satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
- expect(wait.signalsState[1].satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState[1].satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_WRITABLE, 0);
- expect(wait.result).toBe(core.RESULT_OK);
- expect(wait.signalsState.satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- var senderData = new Uint8Array(42);
- for (var i = 0; i < senderData.length; ++i) {
- senderData[i] = i * i;
- }
-
- var result = core.writeMessage(
- pipe.handle0, senderData, [],
- core.WRITE_MESSAGE_FLAG_NONE);
-
- expect(result).toBe(core.RESULT_OK);
-
- wait = core.wait(pipe.handle0, core.HANDLE_SIGNAL_WRITABLE, 0);
- expect(wait.result).toBe(core.RESULT_OK);
- expect(wait.signalsState.satisfiedSignals).toBe(
- core.HANDLE_SIGNAL_WRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- wait = core.wait(pipe.handle1, core.HANDLE_SIGNAL_READABLE,
- core.DEADLINE_INDEFINITE);
- expect(wait.result).toBe(core.RESULT_OK);
- expect(wait.signalsState.satisfiedSignals).toBe(HANDLE_SIGNAL_READWRITABLE);
- expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
- var read = core.readMessage(pipe.handle1, core.READ_MESSAGE_FLAG_NONE);
-
- expect(read.result).toBe(core.RESULT_OK);
- expect(read.buffer.byteLength).toBe(42);
- expect(read.handles.length).toBe(0);
-
- var memory = new Uint8Array(read.buffer);
- for (var i = 0; i < memory.length; ++i)
- expect(memory[i]).toBe((i * i) & 0xFF);
- }
-
- function testReadAndWriteDataPipe(pipe) {
- var senderData = new Uint8Array(42);
- for (var i = 0; i < senderData.length; ++i) {
- senderData[i] = i * i;
- }
-
- var write = core.writeData(
- pipe.producerHandle, senderData,
- core.WRITE_DATA_FLAG_ALL_OR_NONE);
-
- expect(write.result).toBe(core.RESULT_OK);
- expect(write.numBytes).toBe(42);
-
- var wait = core.wait(pipe.consumerHandle, core.HANDLE_SIGNAL_READABLE,
- core.DEADLINE_INDEFINITE);
- expect(wait.result).toBe(core.RESULT_OK);
- var peeked = core.readData(
- pipe.consumerHandle,
- core.READ_DATA_FLAG_PEEK | core.READ_DATA_FLAG_ALL_OR_NONE);
- expect(peeked.result).toBe(core.RESULT_OK);
- expect(peeked.buffer.byteLength).toBe(42);
-
- var peeked_memory = new Uint8Array(peeked.buffer);
- for (var i = 0; i < peeked_memory.length; ++i)
- expect(peeked_memory[i]).toBe((i * i) & 0xFF);
-
- var read = core.readData(
- pipe.consumerHandle, core.READ_DATA_FLAG_ALL_OR_NONE);
-
- expect(read.result).toBe(core.RESULT_OK);
- expect(read.buffer.byteLength).toBe(42);
-
- var memory = new Uint8Array(read.buffer);
- for (var i = 0; i < memory.length; ++i)
- expect(memory[i]).toBe((i * i) & 0xFF);
- }
-
- function testIsHandleMessagePipe(pipe) {
- expect(core.isHandle(123).toBeFalsy);
- expect(core.isHandle("123").toBeFalsy);
- expect(core.isHandle({}).toBeFalsy);
- expect(core.isHandle([]).toBeFalsy);
- expect(core.isHandle(undefined).toBeFalsy);
- expect(core.isHandle(pipe).toBeFalsy);
- expect(core.isHandle(pipe.handle0)).toBeTruthy();
- expect(core.isHandle(pipe.handle1)).toBeTruthy();
- expect(core.isHandle(null)).toBeTruthy();
- }
-
- function testIsHandleDataPipe(pipe) {
- expect(core.isHandle(pipe.consumerHandle)).toBeTruthy();
- expect(core.isHandle(pipe.producerHandle)).toBeTruthy();
- }
-
-});
diff --git a/mojo/public/js/router.js b/mojo/public/js/router.js
index e3db0a6..e94c5eb 100644
--- a/mojo/public/js/router.js
+++ b/mojo/public/js/router.js
@@ -3,17 +3,20 @@
// found in the LICENSE file.
define("mojo/public/js/router", [
+ "console",
"mojo/public/js/codec",
"mojo/public/js/core",
"mojo/public/js/connector",
+ "mojo/public/js/lib/control_message_handler",
"mojo/public/js/validator",
-], function(codec, core, connector, validator) {
+], function(console, codec, core, connector, controlMessageHandler, validator) {
var Connector = connector.Connector;
var MessageReader = codec.MessageReader;
var Validator = validator.Validator;
+ var ControlMessageHandler = controlMessageHandler.ControlMessageHandler;
- function Router(handle, connectorFactory) {
+ function Router(handle, interface_version, connectorFactory) {
if (!core.isHandle(handle))
throw new Error("Router constructor: Not a handle");
if (connectorFactory === undefined)
@@ -24,6 +27,12 @@ define("mojo/public/js/router", [
this.nextRequestID_ = 0;
this.completers_ = new Map();
this.payloadValidators_ = [];
+ this.testingController_ = null;
+
+ if (interface_version !== undefined) {
+ this.controlMessageHandler_ = new
+ ControlMessageHandler(interface_version);
+ }
this.connector_.setIncomingReceiver({
accept: this.handleIncomingMessage_.bind(this),
@@ -36,6 +45,7 @@ define("mojo/public/js/router", [
Router.prototype.close = function() {
this.completers_.clear(); // Drop any responders.
this.connector_.close();
+ this.testingController_ = null;
};
Router.prototype.accept = function(message) {
@@ -81,6 +91,11 @@ define("mojo/public/js/router", [
return this.connector_.encounteredError();
};
+ Router.prototype.enableTestingMode = function() {
+ this.testingController_ = new RouterTestingController(this.connector_);
+ return this.testingController_;
+ };
+
Router.prototype.handleIncomingMessage_ = function(message) {
var noError = validator.validationError.NONE;
var messageValidator = new Validator(message);
@@ -95,8 +110,17 @@ define("mojo/public/js/router", [
};
Router.prototype.handleValidIncomingMessage_ = function(message) {
+ if (this.testingController_)
+ return;
+
if (message.expectsResponse()) {
- if (this.incomingReceiver_) {
+ if (controlMessageHandler.isControlMessage(message)) {
+ if (this.controlMessageHandler_) {
+ this.controlMessageHandler_.acceptWithResponder(message, this);
+ } else {
+ this.close();
+ }
+ } else if (this.incomingReceiver_) {
this.incomingReceiver_.acceptWithResponder(message, this);
} else {
// If we receive a request expecting a response when the client is not
@@ -107,17 +131,39 @@ define("mojo/public/js/router", [
var reader = new MessageReader(message);
var requestID = reader.requestID;
var completer = this.completers_.get(requestID);
- this.completers_.delete(requestID);
- completer.resolve(message);
+ if (completer) {
+ this.completers_.delete(requestID);
+ completer.resolve(message);
+ } else {
+ console.log("Unexpected response with request ID: " + requestID);
+ }
} else {
- if (this.incomingReceiver_)
+ if (controlMessageHandler.isControlMessage(message)) {
+ if (this.controlMessageHandler_) {
+ var ok = this.controlMessageHandler_.accept(message);
+ if (ok) return;
+ }
+ this.close();
+ } else if (this.incomingReceiver_) {
this.incomingReceiver_.accept(message);
+ }
}
- }
+ };
Router.prototype.handleInvalidIncomingMessage_ = function(message, error) {
- this.close();
- }
+ if (!this.testingController_) {
+ // TODO(yzshen): Consider notifying the embedder.
+ // TODO(yzshen): This should also trigger connection error handler.
+ // Consider making accept() return a boolean and let the connector deal
+ // with this, as the C++ code does.
+ console.log("Invalid message: " + validator.validationError[error]);
+
+ this.close();
+ return;
+ }
+
+ this.testingController_.onInvalidIncomingMessage(error);
+ };
Router.prototype.handleConnectionError_ = function(result) {
this.completers_.forEach(function(value) {
@@ -128,25 +174,30 @@ define("mojo/public/js/router", [
this.close();
};
- // The TestRouter subclass is only intended to be used in unit tests.
- // It defeats valid message handling and delgates invalid message handling.
+ // The RouterTestingController is used in unit tests. It defeats valid message
+ // handling and delgates invalid message handling.
- function TestRouter(handle, connectorFactory) {
- Router.call(this, handle, connectorFactory);
+ function RouterTestingController(connector) {
+ this.connector_ = connector;
+ this.invalidMessageHandler_ = null;
}
- TestRouter.prototype = Object.create(Router.prototype);
+ RouterTestingController.prototype.waitForNextMessage = function() {
+ this.connector_.waitForNextMessageForTesting();
+ };
- TestRouter.prototype.handleValidIncomingMessage_ = function() {
+ RouterTestingController.prototype.setInvalidIncomingMessageHandler =
+ function(callback) {
+ this.invalidMessageHandler_ = callback;
};
- TestRouter.prototype.handleInvalidIncomingMessage_ =
- function(message, error) {
- this.validationErrorHandler(error);
- };
+ RouterTestingController.prototype.onInvalidIncomingMessage =
+ function(error) {
+ if (this.invalidMessageHandler_)
+ this.invalidMessageHandler_(error);
+ };
var exports = {};
exports.Router = Router;
- exports.TestRouter = TestRouter;
return exports;
});
diff --git a/mojo/public/js/struct_unittests.js b/mojo/public/js/struct_unittests.js
deleted file mode 100644
index 691d51b..0000000
--- a/mojo/public/js/struct_unittests.js
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2014 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.
-
-define([
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/rect.mojom",
- "mojo/public/interfaces/bindings/tests/test_structs.mojom",
- "mojo/public/js/codec",
- "mojo/public/js/validator",
-], function(expect,
- rect,
- testStructs,
- codec,
- validator) {
-
- function testConstructors() {
- var r = new rect.Rect();
- expect(r).toEqual(new rect.Rect({x:0, y:0, width:0, height:0}));
- expect(r).toEqual(new rect.Rect({foo:100, bar:200}));
-
- r.x = 10;
- r.y = 20;
- r.width = 30;
- r.height = 40;
- var rp = new testStructs.RectPair({first: r, second: r});
- expect(rp.first).toEqual(r);
- expect(rp.second).toEqual(r);
-
- expect(new testStructs.RectPair({second: r}).first).toBeNull();
-
- var nr = new testStructs.NamedRegion();
- expect(nr.name).toBeNull();
- expect(nr.rects).toBeNull();
- expect(nr).toEqual(new testStructs.NamedRegion({}));
-
- nr.name = "foo";
- nr.rects = [r, r, r];
- expect(nr).toEqual(new testStructs.NamedRegion({
- name: "foo",
- rects: [r, r, r],
- }));
-
- var e = new testStructs.EmptyStruct();
- expect(e).toEqual(new testStructs.EmptyStruct({foo:123}));
- }
-
- function testNoDefaultFieldValues() {
- var s = new testStructs.NoDefaultFieldValues();
- expect(s.f0).toEqual(false);
-
- // f1 - f10, number type fields
- for (var i = 1; i <= 10; i++)
- expect(s["f" + i]).toEqual(0);
-
- // f11,12 strings, f13-22 handles, f23-f26 arrays, f27,28 structs
- for (var i = 11; i <= 28; i++)
- expect(s["f" + i]).toBeNull();
- }
-
- function testDefaultFieldValues() {
- var s = new testStructs.DefaultFieldValues();
- expect(s.f0).toEqual(true);
-
- // f1 - f12, number type fields
- for (var i = 1; i <= 12; i++)
- expect(s["f" + i]).toEqual(100);
-
- // f13,14 "foo"
- for (var i = 13; i <= 14; i++)
- expect(s["f" + i]).toEqual("foo");
-
- // f15,16 a default instance of Rect
- var r = new rect.Rect();
- expect(s.f15).toEqual(r);
- expect(s.f16).toEqual(r);
- }
-
- function testScopedConstants() {
- expect(testStructs.ScopedConstants.TEN).toEqual(10);
- expect(testStructs.ScopedConstants.ALSO_TEN).toEqual(10);
-
- expect(testStructs.ScopedConstants.EType.E0).toEqual(0);
- expect(testStructs.ScopedConstants.EType.E1).toEqual(1);
- expect(testStructs.ScopedConstants.EType.E2).toEqual(10);
- expect(testStructs.ScopedConstants.EType.E3).toEqual(10);
- expect(testStructs.ScopedConstants.EType.E4).toEqual(11);
-
- var s = new testStructs.ScopedConstants();
- expect(s.f0).toEqual(0);
- expect(s.f1).toEqual(1);
- expect(s.f2).toEqual(10);
- expect(s.f3).toEqual(10);
- expect(s.f4).toEqual(11);
- expect(s.f5).toEqual(10);
- expect(s.f6).toEqual(10);
- }
-
- function structEncodeDecode(struct) {
- var structClass = struct.constructor;
- var builder = new codec.MessageBuilder(1234, structClass.encodedSize);
- builder.encodeStruct(structClass, struct);
- var message = builder.finish();
-
- var messageValidator = new validator.Validator(message);
- var err = structClass.validate(messageValidator, codec.kMessageHeaderSize);
- expect(err).toEqual(validator.validationError.NONE);
-
- var reader = new codec.MessageReader(message);
- return reader.decodeStruct(structClass);
- }
-
- function testMapKeyTypes() {
- var mapFieldsStruct = new testStructs.MapKeyTypes({
- f0: new Map([[true, false], [false, true]]), // map<bool, bool>
- f1: new Map([[0, 0], [1, 127], [-1, -128]]), // map<int8, int8>
- f2: new Map([[0, 0], [1, 127], [2, 255]]), // map<uint8, uint8>
- f3: new Map([[0, 0], [1, 32767], [2, -32768]]), // map<int16, int16>
- f4: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]), // map<uint16, uint16>
- f5: new Map([[0, 0], [1, 32767], [2, -32768]]), // map<int32, int32>
- f6: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]), // map<uint32, uint32>
- f7: new Map([[0, 0], [1, 32767], [2, -32768]]), // map<int64, int64>
- f8: new Map([[0, 0], [1, 32768], [2, 0xFFFF]]), // map<uint64, uint64>
- f9: new Map([[1000.5, -50000], [100.5, 5000]]), // map<float, float>
- f10: new Map([[-100.5, -50000], [0, 50000000]]), // map<double, double>
- f11: new Map([["one", "two"], ["free", "four"]]), // map<string, string>
- });
- var decodedStruct = structEncodeDecode(mapFieldsStruct);
- expect(decodedStruct.f0).toEqual(mapFieldsStruct.f0);
- expect(decodedStruct.f1).toEqual(mapFieldsStruct.f1);
- expect(decodedStruct.f2).toEqual(mapFieldsStruct.f2);
- expect(decodedStruct.f3).toEqual(mapFieldsStruct.f3);
- expect(decodedStruct.f4).toEqual(mapFieldsStruct.f4);
- expect(decodedStruct.f5).toEqual(mapFieldsStruct.f5);
- expect(decodedStruct.f6).toEqual(mapFieldsStruct.f6);
- expect(decodedStruct.f7).toEqual(mapFieldsStruct.f7);
- expect(decodedStruct.f8).toEqual(mapFieldsStruct.f8);
- expect(decodedStruct.f9).toEqual(mapFieldsStruct.f9);
- expect(decodedStruct.f10).toEqual(mapFieldsStruct.f10);
- expect(decodedStruct.f11).toEqual(mapFieldsStruct.f11);
- }
-
- function testMapValueTypes() {
- var mapFieldsStruct = new testStructs.MapValueTypes({
- // map<string, array<string>>
- f0: new Map([["a", ["b", "c"]], ["d", ["e"]]]),
- // map<string, array<string>?>
- f1: new Map([["a", null], ["b", ["c", "d"]]]),
- // map<string, array<string?>>
- f2: new Map([["a", [null]], ["b", [null, "d"]]]),
- // map<string, array<string,2>>
- f3: new Map([["a", ["1", "2"]], ["b", ["1", "2"]]]),
- // map<string, array<array<string, 2>?>>
- f4: new Map([["a", [["1", "2"]]], ["b", [null]]]),
- // map<string, array<array<string, 2>, 1>>
- f5: new Map([["a", [["1", "2"]]]]),
- // map<string, Rect?>
- f6: new Map([["a", null]]),
- // map<string, map<string, string>>
- f7: new Map([["a", new Map([["b", "c"]])]]),
- // map<string, array<map<string, string>>>
- f8: new Map([["a", [new Map([["b", "c"]])]]]),
- // map<string, handle>
- f9: new Map([["a", 1234]]),
- // map<string, array<handle>>
- f10: new Map([["a", [1234, 5678]]]),
- // map<string, map<string, handle>>
- f11: new Map([["a", new Map([["b", 1234]])]]),
- });
- var decodedStruct = structEncodeDecode(mapFieldsStruct);
- expect(decodedStruct.f0).toEqual(mapFieldsStruct.f0);
- expect(decodedStruct.f1).toEqual(mapFieldsStruct.f1);
- expect(decodedStruct.f2).toEqual(mapFieldsStruct.f2);
- expect(decodedStruct.f3).toEqual(mapFieldsStruct.f3);
- expect(decodedStruct.f4).toEqual(mapFieldsStruct.f4);
- expect(decodedStruct.f5).toEqual(mapFieldsStruct.f5);
- expect(decodedStruct.f6).toEqual(mapFieldsStruct.f6);
- expect(decodedStruct.f7).toEqual(mapFieldsStruct.f7);
- expect(decodedStruct.f8).toEqual(mapFieldsStruct.f8);
- expect(decodedStruct.f9).toEqual(mapFieldsStruct.f9);
- expect(decodedStruct.f10).toEqual(mapFieldsStruct.f10);
- expect(decodedStruct.f11).toEqual(mapFieldsStruct.f11);
- }
-
- function testFloatNumberValues() {
- var decodedStruct = structEncodeDecode(new testStructs.FloatNumberValues);
- expect(decodedStruct.f0).toEqual(testStructs.FloatNumberValues.V0);
- expect(decodedStruct.f1).toEqual(testStructs.FloatNumberValues.V1);
- expect(decodedStruct.f2).toEqual(testStructs.FloatNumberValues.V2);
- expect(decodedStruct.f3).toEqual(testStructs.FloatNumberValues.V3);
- expect(decodedStruct.f4).toEqual(testStructs.FloatNumberValues.V4);
- expect(decodedStruct.f5).toEqual(testStructs.FloatNumberValues.V5);
- expect(decodedStruct.f6).toEqual(testStructs.FloatNumberValues.V6);
- expect(decodedStruct.f7).toEqual(testStructs.FloatNumberValues.V7);
- expect(decodedStruct.f8).toEqual(testStructs.FloatNumberValues.V8);
- expect(decodedStruct.f9).toEqual(testStructs.FloatNumberValues.V9);
- }
-
- function testIntegerNumberValues() {
- var decodedStruct = structEncodeDecode(new testStructs.IntegerNumberValues);
- expect(decodedStruct.f0).toEqual(testStructs.IntegerNumberValues.V0);
- expect(decodedStruct.f1).toEqual(testStructs.IntegerNumberValues.V1);
- expect(decodedStruct.f2).toEqual(testStructs.IntegerNumberValues.V2);
- expect(decodedStruct.f3).toEqual(testStructs.IntegerNumberValues.V3);
- expect(decodedStruct.f4).toEqual(testStructs.IntegerNumberValues.V4);
- expect(decodedStruct.f5).toEqual(testStructs.IntegerNumberValues.V5);
- expect(decodedStruct.f6).toEqual(testStructs.IntegerNumberValues.V6);
- expect(decodedStruct.f7).toEqual(testStructs.IntegerNumberValues.V7);
- expect(decodedStruct.f8).toEqual(testStructs.IntegerNumberValues.V8);
- expect(decodedStruct.f9).toEqual(testStructs.IntegerNumberValues.V9);
- expect(decodedStruct.f10).toEqual(testStructs.IntegerNumberValues.V10);
- expect(decodedStruct.f11).toEqual(testStructs.IntegerNumberValues.V11);
- expect(decodedStruct.f12).toEqual(testStructs.IntegerNumberValues.V12);
- expect(decodedStruct.f13).toEqual(testStructs.IntegerNumberValues.V13);
- expect(decodedStruct.f14).toEqual(testStructs.IntegerNumberValues.V14);
- expect(decodedStruct.f15).toEqual(testStructs.IntegerNumberValues.V15);
- expect(decodedStruct.f16).toEqual(testStructs.IntegerNumberValues.V16);
- expect(decodedStruct.f17).toEqual(testStructs.IntegerNumberValues.V17);
- expect(decodedStruct.f18).toEqual(testStructs.IntegerNumberValues.V18);
- expect(decodedStruct.f19).toEqual(testStructs.IntegerNumberValues.V19);
- }
-
- function testUnsignedNumberValues() {
- var decodedStruct =
- structEncodeDecode(new testStructs.UnsignedNumberValues);
- expect(decodedStruct.f0).toEqual(testStructs.UnsignedNumberValues.V0);
- expect(decodedStruct.f1).toEqual(testStructs.UnsignedNumberValues.V1);
- expect(decodedStruct.f2).toEqual(testStructs.UnsignedNumberValues.V2);
- expect(decodedStruct.f3).toEqual(testStructs.UnsignedNumberValues.V3);
- expect(decodedStruct.f4).toEqual(testStructs.UnsignedNumberValues.V4);
- expect(decodedStruct.f5).toEqual(testStructs.UnsignedNumberValues.V5);
- expect(decodedStruct.f6).toEqual(testStructs.UnsignedNumberValues.V6);
- expect(decodedStruct.f7).toEqual(testStructs.UnsignedNumberValues.V7);
- expect(decodedStruct.f8).toEqual(testStructs.UnsignedNumberValues.V8);
- expect(decodedStruct.f9).toEqual(testStructs.UnsignedNumberValues.V9);
- expect(decodedStruct.f10).toEqual(testStructs.UnsignedNumberValues.V10);
- expect(decodedStruct.f11).toEqual(testStructs.UnsignedNumberValues.V11);
- }
-
-
- function testBitArrayValues() {
- var bitArraysStruct = new testStructs.BitArrayValues({
- // array<bool, 1> f0;
- f0: [true],
- // array<bool, 7> f1;
- f1: [true, false, true, false, true, false, true],
- // array<bool, 9> f2;
- f2: [true, false, true, false, true, false, true, false, true],
- // array<bool> f3;
- f3: [true, false, true, false, true, false, true, false],
- // array<array<bool>> f4;
- f4: [[true], [false], [true, false], [true, false, true, false]],
- // array<array<bool>?> f5;
- f5: [[true], null, null, [true, false, true, false]],
- // array<array<bool, 2>?> f6;
- f6: [[true, false], [true, false], [true, false]],
- });
- var decodedStruct = structEncodeDecode(bitArraysStruct);
- expect(decodedStruct.f0).toEqual(bitArraysStruct.f0);
- expect(decodedStruct.f1).toEqual(bitArraysStruct.f1);
- expect(decodedStruct.f2).toEqual(bitArraysStruct.f2);
- expect(decodedStruct.f3).toEqual(bitArraysStruct.f3);
- expect(decodedStruct.f4).toEqual(bitArraysStruct.f4);
- expect(decodedStruct.f5).toEqual(bitArraysStruct.f5);
- expect(decodedStruct.f6).toEqual(bitArraysStruct.f6);
- }
-
- testConstructors();
- testNoDefaultFieldValues();
- testDefaultFieldValues();
- testScopedConstants();
- testMapKeyTypes();
- testMapValueTypes();
- testFloatNumberValues();
- testIntegerNumberValues();
- testUnsignedNumberValues();
- testBitArrayValues();
- this.result = "PASS";
-});
diff --git a/mojo/public/js/test/validation_test_input_parser.js b/mojo/public/js/test/validation_test_input_parser.js
deleted file mode 100644
index f5a57f9..0000000
--- a/mojo/public/js/test/validation_test_input_parser.js
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright 2014 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.
-
-// Support for parsing binary sequences encoded as readable strings
-// or ".data" files. The input format is described here:
-// mojo/public/cpp/bindings/tests/validation_test_input_parser.h
-
-define([
- "mojo/public/js/buffer"
- ], function(buffer) {
-
- // Files and Lines represent the raw text from an input string
- // or ".data" file.
-
- function InputError(message, line) {
- this.message = message;
- this.line = line;
- }
-
- InputError.prototype.toString = function() {
- var s = 'Error: ' + this.message;
- if (this.line)
- s += ', at line ' +
- (this.line.number + 1) + ': "' + this.line.contents + '"';
- return s;
- }
-
- function File(contents) {
- this.contents = contents;
- this.index = 0;
- this.lineNumber = 0;
- }
-
- File.prototype.endReached = function() {
- return this.index >= this.contents.length;
- }
-
- File.prototype.nextLine = function() {
- if (this.endReached())
- return null;
- var start = this.index;
- var end = this.contents.indexOf('\n', start);
- if (end == -1)
- end = this.contents.length;
- this.index = end + 1;
- return new Line(this.contents.substring(start, end), this.lineNumber++);
- }
-
- function Line(contents, number) {
- var i = contents.indexOf('//');
- var s = (i == -1) ? contents.trim() : contents.substring(0, i).trim();
- this.contents = contents;
- this.items = (s.length > 0) ? s.split(/\s+/) : [];
- this.index = 0;
- this.number = number;
- }
-
- Line.prototype.endReached = function() {
- return this.index >= this.items.length;
- }
-
- var ITEM_TYPE_SIZES = {
- u1: 1, u2: 2, u4: 4, u8: 8, s1: 1, s2: 2, s4: 4, s8: 8, b: 1, f: 4, d: 8,
- dist4: 4, dist8: 8, anchr: 0, handles: 0
- };
-
- function isValidItemType(type) {
- return ITEM_TYPE_SIZES[type] !== undefined;
- }
-
- Line.prototype.nextItem = function() {
- if (this.endReached())
- return null;
-
- var itemString = this.items[this.index++];
- var type = 'u1';
- var value = itemString;
-
- if (itemString.charAt(0) == '[') {
- var i = itemString.indexOf(']');
- if (i != -1 && i + 1 < itemString.length) {
- type = itemString.substring(1, i);
- value = itemString.substring(i + 1);
- } else {
- throw new InputError('invalid item', this);
- }
- }
- if (!isValidItemType(type))
- throw new InputError('invalid item type', this);
-
- return new Item(this, type, value);
- }
-
- // The text for each whitespace delimited binary data "item" is represented
- // by an Item.
-
- function Item(line, type, value) {
- this.line = line;
- this.type = type;
- this.value = value;
- this.size = ITEM_TYPE_SIZES[type];
- }
-
- Item.prototype.isFloat = function() {
- return this.type == 'f' || this.type == 'd';
- }
-
- Item.prototype.isInteger = function() {
- return ['u1', 'u2', 'u4', 'u8',
- 's1', 's2', 's4', 's8'].indexOf(this.type) != -1;
- }
-
- Item.prototype.isNumber = function() {
- return this.isFloat() || this.isInteger();
- }
-
- Item.prototype.isByte = function() {
- return this.type == 'b';
- }
-
- Item.prototype.isDistance = function() {
- return this.type == 'dist4' || this.type == 'dist8';
- }
-
- Item.prototype.isAnchor = function() {
- return this.type == 'anchr';
- }
-
- Item.prototype.isHandles = function() {
- return this.type == 'handles';
- }
-
- // A TestMessage represents the complete binary message loaded from an input
- // string or ".data" file. The parseTestMessage() function below constructs
- // a TestMessage from a File.
-
- function TestMessage(byteLength) {
- this.index = 0;
- this.buffer = new buffer.Buffer(byteLength);
- this.distances = {};
- this.handleCount = 0;
- }
-
- function checkItemNumberValue(item, n, min, max) {
- if (n < min || n > max)
- throw new InputError('invalid item value', item.line);
- }
-
- TestMessage.prototype.addNumber = function(item) {
- var n = item.isInteger() ? parseInt(item.value) : parseFloat(item.value);
- if (Number.isNaN(n))
- throw new InputError("can't parse item value", item.line);
-
- switch(item.type) {
- case 'u1':
- checkItemNumberValue(item, n, 0, 0xFF);
- this.buffer.setUint8(this.index, n);
- break;
- case 'u2':
- checkItemNumberValue(item, n, 0, 0xFFFF);
- this.buffer.setUint16(this.index, n);
- break;
- case 'u4':
- checkItemNumberValue(item, n, 0, 0xFFFFFFFF);
- this.buffer.setUint32(this.index, n);
- break;
- case 'u8':
- checkItemNumberValue(item, n, 0, Number.MAX_SAFE_INTEGER);
- this.buffer.setUint64(this.index, n);
- break;
- case 's1':
- checkItemNumberValue(item, n, -128, 127);
- this.buffer.setInt8(this.index, n);
- break;
- case 's2':
- checkItemNumberValue(item, n, -32768, 32767);
- this.buffer.setInt16(this.index, n);
- break;
- case 's4':
- checkItemNumberValue(item, n, -2147483648, 2147483647);
- this.buffer.setInt32(this.index, n);
- break;
- case 's8':
- checkItemNumberValue(item, n,
- Number.MIN_SAFE_INTEGER,
- Number.MAX_SAFE_INTEGER);
- this.buffer.setInt64(this.index, n);
- break;
- case 'f':
- this.buffer.setFloat32(this.index, n);
- break;
- case 'd':
- this.buffer.setFloat64(this.index, n);
- break;
-
- default:
- throw new InputError('unrecognized item type', item.line);
- }
- }
-
- TestMessage.prototype.addByte = function(item) {
- if (!/^[01]{8}$/.test(item.value))
- throw new InputError('invalid byte item value', item.line);
- function b(i) {
- return (item.value.charAt(7 - i) == '1') ? 1 << i : 0;
- }
- var n = b(0) | b(1) | b(2) | b(3) | b(4) | b(5) | b(6) | b(7);
- this.buffer.setUint8(this.index, n);
- }
-
- TestMessage.prototype.addDistance = function(item) {
- if (this.distances[item.value])
- throw new InputError('duplicate distance item', item.line);
- this.distances[item.value] = {index: this.index, item: item};
- }
-
- TestMessage.prototype.addAnchor = function(item) {
- var dist = this.distances[item.value];
- if (!dist)
- throw new InputError('unmatched anchor item', item.line);
- delete this.distances[item.value];
-
- var n = this.index - dist.index;
- // TODO(hansmuller): validate n
-
- if (dist.item.type == 'dist4')
- this.buffer.setUint32(dist.index, n);
- else if (dist.item.type == 'dist8')
- this.buffer.setUint64(dist.index, n);
- else
- throw new InputError('unrecognzed distance item type', dist.item.line);
- }
-
- TestMessage.prototype.addHandles = function(item) {
- this.handleCount = parseInt(item.value);
- if (Number.isNaN(this.handleCount))
- throw new InputError("can't parse handleCount", item.line);
- }
-
- TestMessage.prototype.addItem = function(item) {
- if (item.isNumber())
- this.addNumber(item);
- else if (item.isByte())
- this.addByte(item);
- else if (item.isDistance())
- this.addDistance(item);
- else if (item.isAnchor())
- this.addAnchor(item);
- else if (item.isHandles())
- this.addHandles(item);
- else
- throw new InputError('unrecognized item type', item.line);
-
- this.index += item.size;
- }
-
- TestMessage.prototype.unanchoredDistances = function() {
- var names = null;
- for (var name in this.distances) {
- if (this.distances.hasOwnProperty(name))
- names = (names === null) ? name : names + ' ' + name;
- }
- return names;
- }
-
- function parseTestMessage(text) {
- var file = new File(text);
- var items = [];
- var messageLength = 0;
- while(!file.endReached()) {
- var line = file.nextLine();
- while (!line.endReached()) {
- var item = line.nextItem();
- if (item.isHandles() && items.length > 0)
- throw new InputError('handles item is not first');
- messageLength += item.size;
- items.push(item);
- }
- }
-
- var msg = new TestMessage(messageLength);
- for (var i = 0; i < items.length; i++)
- msg.addItem(items[i]);
-
- if (messageLength != msg.index)
- throw new InputError('failed to compute message length');
- var names = msg.unanchoredDistances();
- if (names)
- throw new InputError('no anchors for ' + names, 0);
-
- return msg;
- }
-
- var exports = {};
- exports.parseTestMessage = parseTestMessage;
- exports.InputError = InputError;
- return exports;
-});
diff --git a/mojo/public/js/threading.js b/mojo/public/js/threading.js
index cfe5037..49ab5c9 100644
--- a/mojo/public/js/threading.js
+++ b/mojo/public/js/threading.js
@@ -7,7 +7,7 @@
// Note: This file is for documentation purposes only. The code here is not
// actually executed. The real module is implemented natively in Mojo.
//
-// This module provides a way for a Mojo application implemented in JS
+// This module provides a way for a Service implemented in JS
// to exit by quitting the current message loop. This module is not
// intended to be used by Mojo JS application started by the JS
// content handler.
diff --git a/mojo/public/js/union_unittests.js b/mojo/public/js/union_unittests.js
deleted file mode 100644
index 5dcda7d..0000000
--- a/mojo/public/js/union_unittests.js
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2015 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.
-
-define([
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/test_unions.mojom",
- "mojo/public/js/codec",
- "mojo/public/js/validator",
-], function(expect,
- unions,
- codec,
- validator) {
- function testConstructors() {
- var u = new unions.PodUnion();
- expect(u.$data).toEqual(null);
- expect(u.$tag).toBeUndefined();
-
- u.f_uint32 = 32;
-
- expect(u.f_uint32).toEqual(32);
- expect(u.$tag).toEqual(unions.PodUnion.Tags.f_uint32);
-
- var u = new unions.PodUnion({f_uint64: 64});
- expect(u.f_uint64).toEqual(64);
- expect(u.$tag).toEqual(unions.PodUnion.Tags.f_uint64);
- expect(function() {var v = u.f_uint32;}).toThrow();
-
- expect(function() {
- var u = new unions.PodUnion({
- f_uint64: 64,
- f_uint32: 32,
- });
- }).toThrow();
-
- expect(function() {
- var u = new unions.PodUnion({ foo: 64 }); }).toThrow();
-
- expect(function() {
- var u = new unions.PodUnion([1,2,3,4]); }).toThrow();
- }
-
- function structEncodeDecode(struct) {
- var structClass = struct.constructor;
- var builder = new codec.MessageBuilder(1234, structClass.encodedSize);
- builder.encodeStruct(structClass, struct);
-
- var message = builder.finish();
-
- var messageValidator = new validator.Validator(message);
- var err = structClass.validate(messageValidator, codec.kMessageHeaderSize);
- expect(err).toEqual(validator.validationError.NONE);
-
- var reader = new codec.MessageReader(message);
- var view = reader.decoder.buffer.dataView;
-
- return reader.decodeStruct(structClass);
- }
-
- function testBasicEncoding() {
- var s = new unions.WrapperStruct({
- pod_union: new unions.PodUnion({
- f_uint64: 64})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_dummy: new unions.DummyStruct({
- f_int8: 8})})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_array_int8: [1, 2, 3]})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_map_int8: new Map([
- ["first", 1],
- ["second", 2],
- ])})});
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
-
- // Encoding a union with no member set is an error.
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion()});
- expect(function() {
- structEncodeDecode(s); }).toThrow();
- }
-
- function testUnionsInArrayEncoding() {
- var s = new unions.SmallStruct({
- pod_union_array: [
- new unions.PodUnion({f_uint32: 32}),
- new unions.PodUnion({f_uint64: 64}),
- ]
- });
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
- }
-
- function testUnionsInMapEncoding() {
- var s = new unions.SmallStruct({
- pod_union_map: new Map([
- ["thirty-two", new unions.PodUnion({f_uint32: 32})],
- ["sixty-four", new unions.PodUnion({f_uint64: 64})],
- ])
- });
-
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
- }
-
- function testNestedUnionsEncoding() {
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_pod_union: new unions.PodUnion({f_uint32: 32})
- })});
- var decoded = structEncodeDecode(s);
- expect(decoded).toEqual(s);
- }
-
- function structValidate(struct) {
- var structClass = struct.constructor;
- var builder = new codec.MessageBuilder(1234, structClass.encodedSize);
- builder.encodeStruct(structClass, struct);
-
- var message = builder.finish();
-
- var messageValidator = new validator.Validator(message);
- return structClass.validate(messageValidator, codec.kMessageHeaderSize);
- }
-
- function testNullUnionMemberValidation() {
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_dummy: null})});
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.UNEXPECTED_NULL_POINTER);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_nullable: null})});
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.NONE);
- }
-
- function testNullUnionValidation() {
- var s = new unions.SmallStructNonNullableUnion({
- pod_union: null});
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.UNEXPECTED_NULL_UNION);
-
- var s = new unions.WrapperStruct({
- object_union: new unions.ObjectUnion({
- f_pod_union: null})
- });
-
- var err = structValidate(s);
- expect(err).toEqual(validator.validationError.UNEXPECTED_NULL_UNION);
- }
-
- testConstructors();
- testBasicEncoding();
- testUnionsInArrayEncoding();
- testUnionsInMapEncoding();
- testNestedUnionsEncoding();
- testNullUnionMemberValidation();
- testNullUnionValidation();
- this.result = "PASS";
-});
diff --git a/mojo/public/js/validation_unittests.js b/mojo/public/js/validation_unittests.js
deleted file mode 100644
index 817d42c..0000000
--- a/mojo/public/js/validation_unittests.js
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright 2014 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.
-
-define([
- "console",
- "file",
- "gin/test/expect",
- "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom",
- "mojo/public/js/buffer",
- "mojo/public/js/codec",
- "mojo/public/js/connection",
- "mojo/public/js/connector",
- "mojo/public/js/core",
- "mojo/public/js/test/validation_test_input_parser",
- "mojo/public/js/router",
- "mojo/public/js/validator",
-], function(console,
- file,
- expect,
- testInterface,
- buffer,
- codec,
- connection,
- connector,
- core,
- parser,
- router,
- validator) {
-
- var noError = validator.validationError.NONE;
-
- function checkTestMessageParser() {
- function TestMessageParserFailure(message, input) {
- this.message = message;
- this.input = input;
- }
-
- TestMessageParserFailure.prototype.toString = function() {
- return 'Error: ' + this.message + ' for "' + this.input + '"';
- }
-
- function checkData(data, expectedData, input) {
- if (data.byteLength != expectedData.byteLength) {
- var s = "message length (" + data.byteLength + ") doesn't match " +
- "expected length: " + expectedData.byteLength;
- throw new TestMessageParserFailure(s, input);
- }
-
- for (var i = 0; i < data.byteLength; i++) {
- if (data.getUint8(i) != expectedData.getUint8(i)) {
- var s = 'message data mismatch at byte offset ' + i;
- throw new TestMessageParserFailure(s, input);
- }
- }
- }
-
- function testFloatItems() {
- var input = '[f]+.3e9 [d]-10.03';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(12);
- expectedData.setFloat32(0, +.3e9);
- expectedData.setFloat64(4, -10.03);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testUnsignedIntegerItems() {
- var input = '[u1]0x10// hello world !! \n\r \t [u2]65535 \n' +
- '[u4]65536 [u8]0xFFFFFFFFFFFFF 0 0Xff';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(17);
- expectedData.setUint8(0, 0x10);
- expectedData.setUint16(1, 65535);
- expectedData.setUint32(3, 65536);
- expectedData.setUint64(7, 0xFFFFFFFFFFFFF);
- expectedData.setUint8(15, 0);
- expectedData.setUint8(16, 0xff);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testSignedIntegerItems() {
- var input = '[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(15);
- expectedData.setInt64(0, -0x800);
- expectedData.setInt8(8, -128);
- expectedData.setInt16(9, 0);
- expectedData.setInt32(11, -40);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testByteItems() {
- var input = '[b]00001011 [b]10000000 // hello world\n [b]00000000';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(3);
- expectedData.setUint8(0, 11);
- expectedData.setUint8(1, 128);
- expectedData.setUint8(2, 0);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testAnchors() {
- var input = '[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(14);
- expectedData.setUint32(0, 14);
- expectedData.setUint8(4, 0);
- expectedData.setUint64(5, 9);
- expectedData.setUint8(13, 0);
- checkData(msg.buffer, expectedData, input);
- }
-
- function testHandles() {
- var input = '// This message has handles! \n[handles]50 [u8]2';
- var msg = parser.parseTestMessage(input);
- var expectedData = new buffer.Buffer(8);
- expectedData.setUint64(0, 2);
-
- if (msg.handleCount != 50) {
- var s = 'wrong handle count (' + msg.handleCount + ')';
- throw new TestMessageParserFailure(s, input);
- }
- checkData(msg.buffer, expectedData, input);
- }
-
- function testEmptyInput() {
- var msg = parser.parseTestMessage('');
- if (msg.buffer.byteLength != 0)
- throw new TestMessageParserFailure('expected empty message', '');
- }
-
- function testBlankInput() {
- var input = ' \t // hello world \n\r \t// the answer is 42 ';
- var msg = parser.parseTestMessage(input);
- if (msg.buffer.byteLength != 0)
- throw new TestMessageParserFailure('expected empty message', input);
- }
-
- function testInvalidInput() {
- function parserShouldFail(input) {
- try {
- parser.parseTestMessage(input);
- } catch (e) {
- if (e instanceof parser.InputError)
- return;
- throw new TestMessageParserFailure(
- 'unexpected exception ' + e.toString(), input);
- }
- throw new TestMessageParserFailure("didn't detect invalid input", file);
- }
-
- ['/ hello world',
- '[u1]x',
- '[u2]-1000',
- '[u1]0x100',
- '[s2]-0x8001',
- '[b]1',
- '[b]1111111k',
- '[dist4]unmatched',
- '[anchr]hello [dist8]hello',
- '[dist4]a [dist4]a [anchr]a',
- // '[dist4]a [anchr]a [dist4]a [anchr]a',
- '0 [handles]50'
- ].forEach(parserShouldFail);
- }
-
- try {
- testFloatItems();
- testUnsignedIntegerItems();
- testSignedIntegerItems();
- testByteItems();
- testInvalidInput();
- testEmptyInput();
- testBlankInput();
- testHandles();
- testAnchors();
- } catch (e) {
- return e.toString();
- }
- return null;
- }
-
- function getMessageTestFiles(prefix) {
- var sourceRoot = file.getSourceRootDirectory();
- expect(sourceRoot).not.toBeNull();
-
- var testDir = sourceRoot +
- "/mojo/public/interfaces/bindings/tests/data/validation/";
- var testFiles = file.getFilesInDirectory(testDir);
- expect(testFiles).not.toBeNull();
- expect(testFiles.length).toBeGreaterThan(0);
-
- // The matching ".data" pathnames with the extension removed.
- return testFiles.filter(function(s) {
- return s.substr(-5) == ".data" && s.indexOf(prefix) == 0;
- }).map(function(s) {
- return testDir + s.slice(0, -5);
- });
- }
-
- function readTestMessage(filename) {
- var contents = file.readFileToString(filename + ".data");
- expect(contents).not.toBeNull();
- return parser.parseTestMessage(contents);
- }
-
- function readTestExpected(filename) {
- var contents = file.readFileToString(filename + ".expected");
- expect(contents).not.toBeNull();
- return contents.trim();
- }
-
- function checkValidationResult(testFile, err) {
- var actualResult = (err === noError) ? "PASS" : err;
- var expectedResult = readTestExpected(testFile);
- if (actualResult != expectedResult)
- console.log("[Test message validation failed: " + testFile + " ]");
- expect(actualResult).toEqual(expectedResult);
- }
-
- function testMessageValidation(prefix, filters) {
- var testFiles = getMessageTestFiles(prefix);
- expect(testFiles.length).toBeGreaterThan(0);
-
- for (var i = 0; i < testFiles.length; i++) {
- // TODO(hansmuller) Temporarily skipping array pointer overflow tests
- // because JS numbers are limited to 53 bits.
- // TODO(yzshen) Skipping struct versioning tests (tests with "mthd11"
- // in the name) because the feature is not supported in JS yet.
- // TODO(yzshen) Skipping enum validation tests (tests with "enum" in the
- // name) because the feature is not supported in JS yet. crbug.com/581390
- // TODO(rudominer): Temporarily skipping 'no-such-method',
- // 'invalid_request_flags', and 'invalid_response_flags' until additional
- // logic in *RequestValidator and *ResponseValidator is ported from
- // cpp to js.
- if (testFiles[i].indexOf("overflow") != -1 ||
- testFiles[i].indexOf("mthd11") != -1 ||
- testFiles[i].indexOf("enum") != -1 ||
- testFiles[i].indexOf("no_such_method") != -1 ||
- testFiles[i].indexOf("invalid_request_flags") != -1 ||
- testFiles[i].indexOf("invalid_response_flags") != -1) {
- console.log("[Skipping " + testFiles[i] + "]");
- continue;
- }
-
- var testMessage = readTestMessage(testFiles[i]);
- var handles = new Array(testMessage.handleCount);
- var message = new codec.Message(testMessage.buffer, handles);
- var messageValidator = new validator.Validator(message);
-
- var err = messageValidator.validateMessageHeader();
- for (var j = 0; err === noError && j < filters.length; ++j)
- err = filters[j](messageValidator);
-
- checkValidationResult(testFiles[i], err);
- }
- }
-
- function testConformanceMessageValidation() {
- testMessageValidation("conformance_", [
- testInterface.ConformanceTestInterface.validateRequest]);
- }
-
- function testBoundsCheckMessageValidation() {
- testMessageValidation("boundscheck_", [
- testInterface.BoundsCheckTestInterface.validateRequest]);
- }
-
- function testResponseConformanceMessageValidation() {
- testMessageValidation("resp_conformance_", [
- testInterface.ConformanceTestInterface.validateResponse]);
- }
-
- function testResponseBoundsCheckMessageValidation() {
- testMessageValidation("resp_boundscheck_", [
- testInterface.BoundsCheckTestInterface.validateResponse]);
- }
-
- function testIntegratedMessageValidation(testFilesPattern,
- localFactory,
- remoteFactory) {
- var testFiles = getMessageTestFiles(testFilesPattern);
- expect(testFiles.length).toBeGreaterThan(0);
-
- var testMessagePipe = core.createMessagePipe();
- expect(testMessagePipe.result).toBe(core.RESULT_OK);
- var testConnection = new connection.TestConnection(
- testMessagePipe.handle1, localFactory, remoteFactory);
-
- for (var i = 0; i < testFiles.length; i++) {
- var testMessage = readTestMessage(testFiles[i]);
- var handles = new Array(testMessage.handleCount);
-
- var writeMessageValue = core.writeMessage(
- testMessagePipe.handle0,
- new Uint8Array(testMessage.buffer.arrayBuffer),
- new Array(testMessage.handleCount),
- core.WRITE_MESSAGE_FLAG_NONE);
- expect(writeMessageValue).toBe(core.RESULT_OK);
-
- var validationError = noError;
- testConnection.router_.validationErrorHandler = function(err) {
- validationError = err;
- }
-
- testConnection.router_.connector_.waitForNextMessage();
- checkValidationResult(testFiles[i], validationError);
- }
-
- testConnection.close();
- expect(core.close(testMessagePipe.handle0)).toBe(core.RESULT_OK);
- }
-
- function testIntegratedMessageHeaderValidation() {
- testIntegratedMessageValidation(
- "integration_msghdr",
- testInterface.IntegrationTestInterface.stubClass,
- undefined);
- testIntegratedMessageValidation(
- "integration_msghdr",
- undefined,
- testInterface.IntegrationTestInterface.proxyClass);
- }
-
- function testIntegratedRequestMessageValidation() {
- testIntegratedMessageValidation(
- "integration_intf_rqst",
- testInterface.IntegrationTestInterface.stubClass,
- undefined);
- }
-
- function testIntegratedResponseMessageValidation() {
- testIntegratedMessageValidation(
- "integration_intf_resp",
- undefined,
- testInterface.IntegrationTestInterface.proxyClass);
- }
-
- expect(checkTestMessageParser()).toBeNull();
- testConformanceMessageValidation();
- testBoundsCheckMessageValidation();
- testResponseConformanceMessageValidation();
- testResponseBoundsCheckMessageValidation();
- testIntegratedMessageHeaderValidation();
- testIntegratedResponseMessageValidation();
- testIntegratedRequestMessageValidation();
-
- this.result = "PASS";
-});
diff --git a/mojo/public/js/validator.js b/mojo/public/js/validator.js
index cbf7521..fee742d 100644
--- a/mojo/public/js/validator.js
+++ b/mojo/public/js/validator.js
@@ -24,10 +24,15 @@ define("mojo/public/js/validator", [
'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
INVALID_UNION_SIZE: 'VALIDATION_ERROR_INVALID_UNION_SIZE',
UNEXPECTED_NULL_UNION: 'VALIDATION_ERROR_UNEXPECTED_NULL_UNION',
+ UNKNOWN_ENUM_VALUE: 'VALIDATION_ERROR_UNKNOWN_ENUM_VALUE',
};
var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
+ function isEnumClass(cls) {
+ return cls instanceof codec.Enum;
+ }
+
function isStringClass(cls) {
return cls === codec.String || cls === codec.NullableString;
}
@@ -37,12 +42,18 @@ define("mojo/public/js/validator", [
}
function isInterfaceClass(cls) {
- return cls === codec.Interface || cls === codec.NullableInterface;
+ return cls instanceof codec.Interface;
+ }
+
+ function isInterfaceRequestClass(cls) {
+ return cls === codec.InterfaceRequest ||
+ cls === codec.NullableInterfaceRequest;
}
function isNullable(type) {
return type === codec.NullableString || type === codec.NullableHandle ||
type === codec.NullableInterface ||
+ type === codec.NullableInterfaceRequest ||
type instanceof codec.NullableArrayOf ||
type instanceof codec.NullablePointerTo;
}
@@ -76,7 +87,7 @@ define("mojo/public/js/validator", [
return false;
return true;
- }
+ };
Validator.prototype.claimRange = function(start, numBytes) {
if (this.isValidRange(start, numBytes)) {
@@ -84,7 +95,7 @@ define("mojo/public/js/validator", [
return true;
}
return false;
- }
+ };
Validator.prototype.claimHandle = function(index) {
if (index === codec.kEncodedInvalidHandleValue)
@@ -96,6 +107,13 @@ define("mojo/public/js/validator", [
// This is safe because handle indices are uint32.
this.handleIndex = index + 1;
return true;
+ };
+
+ Validator.prototype.validateEnum = function(offset, enumClass) {
+ // Note: Assumes that enums are always 32 bits! But this matches
+ // mojom::generate::pack::PackedField::GetSizeForKind, so it should be okay.
+ var value = this.message.buffer.getInt32(offset);
+ return enumClass.validate(value);
}
Validator.prototype.validateHandle = function(offset, nullable) {
@@ -107,15 +125,19 @@ define("mojo/public/js/validator", [
if (!this.claimHandle(index))
return validationError.ILLEGAL_HANDLE;
+
return validationError.NONE;
- }
+ };
Validator.prototype.validateInterface = function(offset, nullable) {
return this.validateHandle(offset, nullable);
- }
+ };
+
+ Validator.prototype.validateInterfaceRequest = function(offset, nullable) {
+ return this.validateHandle(offset, nullable);
+ };
- Validator.prototype.validateStructHeader =
- function(offset, minNumBytes, minVersion) {
+ Validator.prototype.validateStructHeader = function(offset, minNumBytes) {
if (!codec.isAligned(offset))
return validationError.MISALIGNED_OBJECT;
@@ -123,20 +145,44 @@ define("mojo/public/js/validator", [
return validationError.ILLEGAL_MEMORY_RANGE;
var numBytes = this.message.buffer.getUint32(offset);
- var version = this.message.buffer.getUint32(offset + 4);
- // Backward compatibility is not yet supported.
- if (numBytes < minNumBytes || version < minVersion)
+ if (numBytes < minNumBytes)
return validationError.UNEXPECTED_STRUCT_HEADER;
if (!this.claimRange(offset, numBytes))
return validationError.ILLEGAL_MEMORY_RANGE;
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateStructVersion = function(offset, versionSizes) {
+ var numBytes = this.message.buffer.getUint32(offset);
+ var version = this.message.buffer.getUint32(offset + 4);
+
+ if (version <= versionSizes[versionSizes.length - 1].version) {
+ // Scan in reverse order to optimize for more recent versionSizes.
+ for (var i = versionSizes.length - 1; i >= 0; --i) {
+ if (version >= versionSizes[i].version) {
+ if (numBytes == versionSizes[i].numBytes)
+ break;
+ return validationError.UNEXPECTED_STRUCT_HEADER;
+ }
+ }
+ } else if (numBytes < versionSizes[versionSizes.length-1].numBytes) {
+ return validationError.UNEXPECTED_STRUCT_HEADER;
+ }
+
+ return validationError.NONE;
+ };
+
+ Validator.prototype.isFieldInStructVersion = function(offset, fieldVersion) {
+ var structVersion = this.message.buffer.getUint32(offset + 4);
+ return fieldVersion <= structVersion;
+ };
Validator.prototype.validateMessageHeader = function() {
- var err = this.validateStructHeader(0, codec.kMessageHeaderSize, 0);
+
+ var err = this.validateStructHeader(0, codec.kMessageHeaderSize);
if (err != validationError.NONE)
return err;
@@ -162,7 +208,28 @@ define("mojo/public/js/validator", [
return validationError.MESSAGE_HEADER_INVALID_FLAGS;
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateMessageIsRequestWithoutResponse = function() {
+ if (this.message.isResponse() || this.message.expectsResponse()) {
+ return validationError.MESSAGE_HEADER_INVALID_FLAGS;
+ }
+ return validationError.NONE;
+ };
+
+ Validator.prototype.validateMessageIsRequestExpectingResponse = function() {
+ if (this.message.isResponse() || !this.message.expectsResponse()) {
+ return validationError.MESSAGE_HEADER_INVALID_FLAGS;
+ }
+ return validationError.NONE;
+ };
+
+ Validator.prototype.validateMessageIsResponse = function() {
+ if (this.message.expectsResponse() || !this.message.isResponse()) {
+ return validationError.MESSAGE_HEADER_INVALID_FLAGS;
+ }
+ return validationError.NONE;
+ };
// Returns the message.buffer relative offset this pointer "points to",
// NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
@@ -173,7 +240,7 @@ define("mojo/public/js/validator", [
return NULL_MOJO_POINTER;
var bufferOffset = offset + pointerValue;
return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
- }
+ };
Validator.prototype.decodeUnionSize = function(offset) {
return this.message.buffer.getUint32(offset);
@@ -196,7 +263,7 @@ define("mojo/public/js/validator", [
return this.validateArray(arrayOffset, elementSize, elementType,
expectedDimensionSizes, currentDimension);
- }
+ };
Validator.prototype.validateStructPointer = function(
offset, structClass, nullable) {
@@ -209,7 +276,7 @@ define("mojo/public/js/validator", [
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
return structClass.validate(this, structOffset);
- }
+ };
Validator.prototype.validateUnion = function(
offset, unionClass, nullable) {
@@ -220,7 +287,7 @@ define("mojo/public/js/validator", [
}
return unionClass.validate(this, offset);
- }
+ };
Validator.prototype.validateNestedUnion = function(
offset, unionClass, nullable) {
@@ -233,7 +300,7 @@ define("mojo/public/js/validator", [
validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
return this.validateUnion(unionOffset, unionClass, nullable);
- }
+ };
// This method assumes that the array at arrayPointerOffset has
// been validated.
@@ -241,7 +308,7 @@ define("mojo/public/js/validator", [
Validator.prototype.arrayLength = function(arrayPointerOffset) {
var arrayOffset = this.decodePointer(arrayPointerOffset);
return this.message.buffer.getUint32(arrayOffset + 4);
- }
+ };
Validator.prototype.validateMapPointer = function(
offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
@@ -256,7 +323,7 @@ define("mojo/public/js/validator", [
validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
var mapEncodedSize = codec.kStructHeaderSize + codec.kMapStructPayloadSize;
- var err = this.validateStructHeader(structOffset, mapEncodedSize, 0);
+ var err = this.validateStructHeader(structOffset, mapEncodedSize);
if (err !== validationError.NONE)
return err;
@@ -289,12 +356,12 @@ define("mojo/public/js/validator", [
return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;
return validationError.NONE;
- }
+ };
Validator.prototype.validateStringPointer = function(offset, nullable) {
return this.validateArrayPointer(
offset, codec.Uint8.encodedSize, codec.Uint8, nullable, [0], 0);
- }
+ };
// Similar to Array_Data<T>::Validate()
// mojo/public/cpp/bindings/lib/array_internal.h
@@ -337,6 +404,9 @@ define("mojo/public/js/validator", [
if (isInterfaceClass(elementType))
return this.validateInterfaceElements(
elementsOffset, numElements, nullable);
+ if (isInterfaceRequestClass(elementType))
+ return this.validateInterfaceRequestElements(
+ elementsOffset, numElements, nullable);
if (isStringClass(elementType))
return this.validateArrayElements(
elementsOffset, numElements, codec.Uint8, nullable, [0], 0);
@@ -347,9 +417,12 @@ define("mojo/public/js/validator", [
return this.validateArrayElements(
elementsOffset, numElements, elementType.cls, nullable,
expectedDimensionSizes, currentDimension + 1);
+ if (isEnumClass(elementType))
+ return this.validateEnumElements(elementsOffset, numElements,
+ elementType.cls);
return validationError.NONE;
- }
+ };
// Note: the |offset + i * elementSize| computation in the validateFooElements
// methods below is "safe" because elementSize <= 8, offset and
@@ -365,11 +438,11 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
Validator.prototype.validateInterfaceElements =
function(offset, numElements, nullable) {
- var elementSize = codec.Interface.encodedSize;
+ var elementSize = codec.Interface.prototype.encodedSize;
for (var i = 0; i < numElements; i++) {
var elementOffset = offset + i * elementSize;
var err = this.validateInterface(elementOffset, nullable);
@@ -377,7 +450,19 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateInterfaceRequestElements =
+ function(offset, numElements, nullable) {
+ var elementSize = codec.InterfaceRequest.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var elementOffset = offset + i * elementSize;
+ var err = this.validateInterfaceRequest(elementOffset, nullable);
+ if (err != validationError.NONE)
+ return err;
+ }
+ return validationError.NONE;
+ };
// The elementClass parameter is the element type of the element arrays.
Validator.prototype.validateArrayElements =
@@ -393,7 +478,7 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
Validator.prototype.validateStructElements =
function(offset, numElements, structClass, nullable) {
@@ -406,7 +491,19 @@ define("mojo/public/js/validator", [
return err;
}
return validationError.NONE;
- }
+ };
+
+ Validator.prototype.validateEnumElements =
+ function(offset, numElements, enumClass) {
+ var elementSize = codec.Enum.prototype.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var elementOffset = offset + i * elementSize;
+ var err = this.validateEnum(elementOffset, enumClass);
+ if (err != validationError.NONE)
+ return err;
+ }
+ return validationError.NONE;
+ };
var exports = {};
exports.validationError = validationError;