blob: 6c7da7e81ba1329f967cdbb0b9b29c7711d10a1b [file] [log] [blame]
import {InterfaceVersionTest, InterfaceVersionTestReceiver, InterfaceVersionTestRemote, StructVersionTest_Deserialize} from '/gen/content/test/data/mojo_bindings_web_test.test-mojom.m.js';
async function waitForMessage(handle) {
let watcher;
await new Promise(r => {
watcher = handle.watch({readable: true}, r);
});
watcher.cancel();
}
promise_test(async () => {
// A manually serialized encoding of the StructVersionTest struct at version
// 0, with just two string fields `a` and `b`. Assumes a little-endian host.
const kTestStructV0 = new Uint32Array([
24, 0, // size and version
16, 0, 24, 0, // offset of string fields `a` and `b`
9, 1, 120, 0, // string `a` header and value 'x'
9, 1, 121, 0, // string `b` header and value 'y'
]);
assert_object_equals(
StructVersionTest_Deserialize(new DataView(kTestStructV0.buffer)),
{a: 'x', b: 'y', c: null, d: null});
// Adding field `c` as a version 1 struct
const kTestStructV1 = new Uint32Array([
32, 1, // size and version
24, 0, 32, 0, 40, 0, // offsets of string fields
9, 1, 120, 0, // string `a` header and value 'x'
9, 1, 121, 0, // string `b` header and value 'y'
9, 1, 122, 0, // string `c` header and value 'z'
]);
assert_object_equals(
StructVersionTest_Deserialize(new DataView(kTestStructV1.buffer)),
{a: 'x', b: 'y', c: 'z', d: null});
// Adding field `d` as a version 2 struct
const kTestStructV2 = new Uint32Array([
40, 2, // size and version
32, 0, 40, 0, 48, 0, 56, 0, // offsets of string fields
9, 1, 120, 0, // string `a` header and value 'x'
9, 1, 121, 0, // string `b` header and value 'y'
9, 1, 122, 0, // string `c` header and value 'z'
9, 1, 119, 0, // string `d` header and value 'w'
]);
assert_object_equals(
StructVersionTest_Deserialize(new DataView(kTestStructV2.buffer)),
{a: 'x', b: 'y', c: 'z', d: 'w'});
}, 'current and older versions can be deserialized');
promise_test(async () => {
// A manually serialized encoding of the StructVersionTest struct at an
// imaginary version newer than the one defined in the committed mojom file we
// have. This version has an extra string field unknown to our generated
// bindings.
const kTestStructV7 = new Uint32Array([
48, 7, // size and version
40, 0, 48, 0, 56, 0, 64, 0, 72, 0, // offset of string fields
9, 1, 120, 0, // string `a` header and value 'x'
9, 1, 121, 0, // string `b` header and value 'y'
9, 1, 122, 0, // string `c` header and value 'z'
9, 1, 119, 0, // string `d` header and value 'w'
11, 3, 0x6c6f6c, 0, // unknown new string field header and contents
]);
// The `e` field is not present because it is not part of our local mojom
// definition and is therefore not known to our generated deserializer. We can
// still deserialize what we know about though.
assert_object_equals(
StructVersionTest_Deserialize(new DataView(kTestStructV7.buffer)),
{a: 'x', b: 'y', c: 'z', d: 'w'});
}, 'newer versions can be partially deserialized');
promise_test(async () => {
const kTestTooSmall = new Uint32Array([8, 0]);
assert_throws_js(
Error,
() => StructVersionTest_Deserialize(new DataView(kTestTooSmall.buffer)));
}, 'reject struct encoding that is too small even for version 0');
promise_test(async () => {
const kTestWrongSize = new Uint32Array([
32, 2, // size and version. size should be 40 but isn't.
16, 0, 24, 0, // offsets of string fields
9, 1, 120, 0, // string `a` header and value 'x'
9, 1, 121, 0, // string `b` header and value 'y'
]);
assert_throws_js(
Error,
() => StructVersionTest_Deserialize(new DataView(kTestWrongSize.buffer)));
}, 'reject struct encoding whose size does not match the version');
class InterfaceVersionTestImpl {
constructor() {
const {handle0, handle1} = Mojo.createMessagePipe();
this.remoteHandle_ = handle0;
this.receiver_ = new InterfaceVersionTestReceiver(this);
this.receiver_.$.bindHandle(handle1);
this.nextFooResolvers_ = [];
}
sendRawMessage(message) {
this.remoteHandle_.writeMessage(message, []);
}
receiveNextFoo() {
return new Promise(resolve => {
this.nextFooResolvers_.push(resolve);
});
}
foo(x, y) {
const resolvers = this.nextFooResolvers_;
this.nextFooResolvers = [];
for (const r of resolvers) {
r({z: y, w: x});
}
return {z: y, w: x};
}
}
promise_test(async () => {
const impl = new InterfaceVersionTestImpl;
const kTestMessageV0 = new Uint32Array([
// Mojo message header. This is request 0 of message ID 0 on interface 0,
// expecting a reply. See the definition of MessageHeaderV1 within
// mojo/public/cpp/bindings/lib/message_internal.h.
32, 1, 0, 0, 1, 0, 0, 0,
16, 0, // Foo params struct size and version
42, 0, // value of `x` and padding
]);
// The implementation returns the inputs x,y swapped, so z=y and w=x. The
// message was v0 and does not include y, so we should have z=0 and w=42.
impl.sendRawMessage(kTestMessageV0);
const {z: z0, w: w0} = await impl.receiveNextFoo();
assert_equals(z0, 0);
assert_equals(w0, 42);
// Current version (1)
const kTestMessageV1 = new Uint32Array([
32, 1, 0, 0, 1, 0, 1, 0, // Mojo message header. See above.
16, 1, // Foo params struct size and version
42, 37, // `x` and `y` values
]);
impl.sendRawMessage(kTestMessageV1);
const {z: z1, w: w1} = await impl.receiveNextFoo();
assert_equals(z1, 37);
assert_equals(w1, 42);
// Imaginary future version 2.
const kTestMessageV2 = new Uint32Array([
32, 1, 0, 0, 1, 0, 2, 0, // Mojo message header
24, 2, // Foo params struct size and version
42, 37, // `x` and `y` values
19, 0, // new unknown field value
]);
impl.sendRawMessage(kTestMessageV2);
const {z: z2, w: w2} = await impl.receiveNextFoo();
assert_equals(z2, 37);
assert_equals(w2, 42);
}, 'interface receivers can handle requests from all versions old and new');
promise_test(async () => {
const {handle0, handle1} = Mojo.createMessagePipe();
const remote = new InterfaceVersionTestRemote(handle1);
const kTestReplyV0 = new Uint32Array([
// Mojo message header. This is reply 0 for message ID 0 on interface 0.
// See the definition of MessageHeaderV1 within
// mojo/public/cpp/bindings/lib/message_internal.h.
32, 1, 0, 0, 2, 0, 0, 0,
16, 0, // Foo reply struct size and version
19, 0, // `z` value and padding
]);
// Send the expected reply before we actually send the corresponding request.
// The receiver won't see it until after the request happens below.
handle0.writeMessage(kTestReplyV0, []);
const {z: z0, w: w0} = await remote.foo(1, 2);
assert_equals(z0, 19);
assert_equals(w0, 0);
const kTestReplyV1 = new Uint32Array([
32, 1, 0, 0, 2, 0, 1, 0, // Mojo message header
16, 1, // Foo reply struct size and version
19, 7, // `z` and `w` values
]);
// Send the expected reply before we actually send the corresponding request.
// The receiver won't see it until after the request happens below.
handle0.writeMessage(kTestReplyV1, []);
const {z: z1, w: w1} = await remote.foo(1, 2);
assert_equals(z1, 19);
assert_equals(w1, 7);
const kTestReplyV2 = new Uint32Array([
32, 1, 0, 0, 2, 0, 2, 0, // Mojo message header
24, 2, // Foo reply struct size and version
19, 7, // `z` and `w` values
0x12345678, // new unknown field value
]);
// Send the expected reply before we actually send the corresponding request.
// The receiver won't see it until after the request happens below.
handle0.writeMessage(kTestReplyV2, []);
const {z: z2, w: w2} = await remote.foo(1, 2);
assert_equals(z2, 19);
assert_equals(w2, 7);
}, 'interface remotes can handle responses from all versions old and new');
promise_test(async () => {
const {handle0, handle1} = Mojo.createMessagePipe();
const remote = new InterfaceVersionTestRemote(handle0);
remote.foo(1, 2);
await waitForMessage(handle1);
const {result, buffer} = handle1.readMessage();
assert_equals(result, Mojo.RESULT_OK);
// First some quick general validity checks.
const data = new DataView(buffer);
assert_equals(data.getUint32(0, true), 32); // message header size
assert_equals(data.getUint32(4, true), 1); // message header version
// Ensure the parameter structure reflects version 1 of the Foo message, since
// that's the current version in the mojom we're using.
assert_equals(data.getUint32(32, true), 16); // Foo request size
assert_equals(data.getUint32(36, true), 1); // Foo request version
}, 'structures properly encode their current version in outgoing messages');