Commit 3345aeb3 authored by Giovanni Ortuño Urquidi's avatar Giovanni Ortuño Urquidi Committed by Commit Bot

mojo-js: Fix encoding and decoding of optional unions

Previously we assumed nullable unions were always encoded as/decoded
from pointers, but unions are only encoded as/decoded from pointers
when they are nested in another union.

This CL changes encodeUnion/decodeUnion to use encodeUnionAsPointer()
and decodeUnionFromPointer() when a union field is another union.

Fixed: 1101849
Change-Id: I7615207fe4052eadb544749fe89225c37d52fa58
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2325458Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Commit-Queue: Giovanni Ortuño Urquidi <ortuno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#794363}
parent 1114cb2b
...@@ -53,6 +53,7 @@ if (support_web_tests) { ...@@ -53,6 +53,7 @@ if (support_web_tests) {
mojom("web_test_common_mojom") { mojom("web_test_common_mojom") {
sources = [ sources = [
"common/web_test/fake_bluetooth_chooser.mojom", "common/web_test/fake_bluetooth_chooser.mojom",
"common/web_test/mojo_echo.mojom",
"common/web_test/web_test.mojom", "common/web_test/web_test.mojom",
"common/web_test/web_test_bluetooth_fake_adapter_setter.mojom", "common/web_test/web_test_bluetooth_fake_adapter_setter.mojom",
] ]
...@@ -112,6 +113,8 @@ if (support_web_tests) { ...@@ -112,6 +113,8 @@ if (support_web_tests) {
"browser/web_test/fake_bluetooth_delegate.h", "browser/web_test/fake_bluetooth_delegate.h",
"browser/web_test/leak_detector.cc", "browser/web_test/leak_detector.cc",
"browser/web_test/leak_detector.h", "browser/web_test/leak_detector.h",
"browser/web_test/mojo_echo.cc",
"browser/web_test/mojo_echo.h",
"browser/web_test/mojo_web_test_helper.cc", "browser/web_test/mojo_web_test_helper.cc",
"browser/web_test/mojo_web_test_helper.h", "browser/web_test/mojo_web_test_helper.h",
"browser/web_test/test_info_extractor.cc", "browser/web_test/test_info_extractor.cc",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/shell/browser/web_test/mojo_echo.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace content {
// static
void MojoEcho::Bind(mojo::PendingReceiver<mojom::MojoEcho> receiver) {
mojo::MakeSelfOwnedReceiver(std::make_unique<MojoEcho>(),
std::move(receiver));
}
MojoEcho::MojoEcho() = default;
MojoEcho::~MojoEcho() = default;
void MojoEcho::EchoBoolFromUnion(mojom::TestUnionPtr test_union,
EchoBoolFromUnionCallback callback) {
std::move(callback).Run(test_union->get_bool_value());
}
void MojoEcho::EchoInt32FromUnion(mojom::TestUnionPtr test_union,
EchoInt32FromUnionCallback callback) {
std::move(callback).Run(test_union->get_int32_value());
}
void MojoEcho::EchoStringFromUnion(mojom::TestUnionPtr test_union,
EchoStringFromUnionCallback callback) {
std::move(callback).Run(test_union->get_string_value());
}
void MojoEcho::EchoBoolAsUnion(bool value, EchoBoolAsUnionCallback callback) {
std::move(callback).Run(mojom::TestUnion::NewBoolValue(value));
}
void MojoEcho::EchoInt32AsUnion(int32_t value,
EchoInt32AsUnionCallback callback) {
std::move(callback).Run(mojom::TestUnion::NewInt32Value(value));
}
void MojoEcho::EchoStringAsUnion(const std::string& value,
EchoStringAsUnionCallback callback) {
std::move(callback).Run(mojom::TestUnion::NewStringValue(value));
}
void MojoEcho::EchoNullFromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoNullFromOptionalUnionCallback callback) {
DCHECK(!test_union);
std::move(callback).Run();
}
void MojoEcho::EchoBoolFromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoBoolFromOptionalUnionCallback callback) {
std::move(callback).Run(test_union->get_bool_value());
}
void MojoEcho::EchoInt32FromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoInt32FromOptionalUnionCallback callback) {
std::move(callback).Run(test_union->get_int32_value());
}
void MojoEcho::EchoStringFromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoStringFromOptionalUnionCallback callback) {
std::move(callback).Run(test_union->get_string_value());
}
void MojoEcho::EchoNullAsOptionalUnion(
EchoNullAsOptionalUnionCallback callback) {
std::move(callback).Run(nullptr);
}
void MojoEcho::EchoBoolAsOptionalUnion(
bool value,
EchoBoolAsOptionalUnionCallback callback) {
std::move(callback).Run(mojom::TestUnion::NewBoolValue(value));
}
void MojoEcho::EchoInt32AsOptionalUnion(
int32_t value,
EchoInt32AsOptionalUnionCallback callback) {
std::move(callback).Run(mojom::TestUnion::NewInt32Value(value));
}
void MojoEcho::EchoStringAsOptionalUnion(
const std::string& value,
EchoStringAsOptionalUnionCallback callback) {
std::move(callback).Run(mojom::TestUnion::NewStringValue(value));
}
void MojoEcho::EchoInt8FromNestedUnion(
mojom::NestedUnionPtr test_union,
EchoInt8FromNestedUnionCallback callback) {
std::move(callback).Run(test_union->get_int8_value());
}
void MojoEcho::EchoBoolFromNestedUnion(
mojom::NestedUnionPtr test_union,
EchoBoolFromNestedUnionCallback callback) {
std::move(callback).Run(test_union->get_union_value()->get_bool_value());
}
void MojoEcho::EchoStringFromNestedUnion(
mojom::NestedUnionPtr test_union,
EchoStringFromNestedUnionCallback callback) {
std::move(callback).Run(test_union->get_union_value()->get_string_value());
}
void MojoEcho::EchoInt8AsNestedUnion(int8_t value,
EchoInt8AsNestedUnionCallback callback) {
std::move(callback).Run(mojom::NestedUnion::NewInt8Value(value));
}
void MojoEcho::EchoBoolAsNestedUnion(bool value,
EchoBoolAsNestedUnionCallback callback) {
std::move(callback).Run(
mojom::NestedUnion::NewUnionValue(mojom::TestUnion::NewBoolValue(value)));
}
void MojoEcho::EchoStringAsNestedUnion(
const std::string& value,
EchoStringAsNestedUnionCallback callback) {
std::move(callback).Run(mojom::NestedUnion::NewUnionValue(
mojom::TestUnion::NewStringValue(value)));
}
void MojoEcho::EchoNullFromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoNullFromOptionalNestedUnionCallback callback) {
DCHECK(!test_union);
std::move(callback).Run();
}
void MojoEcho::EchoInt8FromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoInt8FromOptionalNestedUnionCallback callback) {
std::move(callback).Run(test_union->get_int8_value());
}
void MojoEcho::EchoBoolFromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoBoolFromOptionalNestedUnionCallback callback) {
std::move(callback).Run(test_union->get_union_value()->get_bool_value());
}
void MojoEcho::EchoStringFromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoStringFromOptionalNestedUnionCallback callback) {
std::move(callback).Run(test_union->get_union_value()->get_string_value());
}
void MojoEcho::EchoNullAsOptionalNestedUnion(
EchoNullAsOptionalNestedUnionCallback callback) {
std::move(callback).Run(nullptr);
}
void MojoEcho::EchoInt8AsOptionalNestedUnion(
int8_t value,
EchoInt8AsOptionalNestedUnionCallback callback) {
std::move(callback).Run(mojom::NestedUnion::NewInt8Value(value));
}
void MojoEcho::EchoBoolAsOptionalNestedUnion(
bool value,
EchoBoolAsOptionalNestedUnionCallback callback) {
std::move(callback).Run(
mojom::NestedUnion::NewUnionValue(mojom::TestUnion::NewBoolValue(value)));
}
void MojoEcho::EchoStringAsOptionalNestedUnion(
const std::string& value,
EchoStringAsOptionalNestedUnionCallback callback) {
std::move(callback).Run(mojom::NestedUnion::NewUnionValue(
mojom::TestUnion::NewStringValue(value)));
}
} // namespace content
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_SHELL_BROWSER_WEB_TEST_MOJO_ECHO_H_
#define CONTENT_SHELL_BROWSER_WEB_TEST_MOJO_ECHO_H_
#include "content/shell/common/web_test/mojo_echo.mojom.h"
namespace content {
class MojoEcho : public mojom::MojoEcho {
public:
static void Bind(mojo::PendingReceiver<mojom::MojoEcho> receiver);
MojoEcho();
~MojoEcho() override;
// mojom::MojoEcho
void EchoBoolFromUnion(mojom::TestUnionPtr test_union,
EchoBoolFromUnionCallback callback) override;
void EchoInt32FromUnion(mojom::TestUnionPtr test_union,
EchoInt32FromUnionCallback callback) override;
void EchoStringFromUnion(mojom::TestUnionPtr test_union,
EchoStringFromUnionCallback callback) override;
void EchoBoolAsUnion(bool value, EchoBoolAsUnionCallback callback) override;
void EchoInt32AsUnion(int32_t value,
EchoInt32AsUnionCallback callback) override;
void EchoStringAsUnion(const std::string& value,
EchoStringAsUnionCallback callback) override;
void EchoNullFromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoNullFromOptionalUnionCallback callback) override;
void EchoBoolFromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoBoolFromOptionalUnionCallback callback) override;
void EchoInt32FromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoInt32FromOptionalUnionCallback callback) override;
void EchoStringFromOptionalUnion(
mojom::TestUnionPtr test_union,
EchoStringFromOptionalUnionCallback callback) override;
void EchoNullAsOptionalUnion(
EchoNullAsOptionalUnionCallback callback) override;
void EchoBoolAsOptionalUnion(
bool value,
EchoBoolAsOptionalUnionCallback callback) override;
void EchoInt32AsOptionalUnion(
int32_t value,
EchoInt32AsOptionalUnionCallback callback) override;
void EchoStringAsOptionalUnion(
const std::string& value,
EchoStringAsOptionalUnionCallback callback) override;
void EchoInt8FromNestedUnion(
mojom::NestedUnionPtr test_union,
EchoInt8FromNestedUnionCallback callback) override;
void EchoBoolFromNestedUnion(
mojom::NestedUnionPtr test_union,
EchoBoolFromNestedUnionCallback callback) override;
void EchoStringFromNestedUnion(
mojom::NestedUnionPtr test_union,
EchoStringFromNestedUnionCallback callback) override;
void EchoInt8AsNestedUnion(int8_t value,
EchoInt8AsNestedUnionCallback callback) override;
void EchoBoolAsNestedUnion(bool value,
EchoBoolAsNestedUnionCallback callback) override;
void EchoStringAsNestedUnion(
const std::string& value,
EchoStringAsNestedUnionCallback callback) override;
void EchoNullFromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoNullFromOptionalNestedUnionCallback callback) override;
void EchoInt8FromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoInt8FromOptionalNestedUnionCallback callback) override;
void EchoBoolFromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoBoolFromOptionalNestedUnionCallback callback) override;
void EchoStringFromOptionalNestedUnion(
mojom::NestedUnionPtr test_union,
EchoStringFromOptionalNestedUnionCallback callback) override;
void EchoNullAsOptionalNestedUnion(
EchoNullAsOptionalNestedUnionCallback callback) override;
void EchoInt8AsOptionalNestedUnion(
int8_t value,
EchoInt8AsOptionalNestedUnionCallback callback) override;
void EchoBoolAsOptionalNestedUnion(
bool value,
EchoBoolAsOptionalNestedUnionCallback callback) override;
void EchoStringAsOptionalNestedUnion(
const std::string& value,
EchoStringAsOptionalNestedUnionCallback callback) override;
};
} // namespace content
#endif // CONTENT_SHELL_BROWSER_WEB_TEST_MOJO_ECHO_H_
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "content/shell/browser/web_test/fake_bluetooth_chooser.h" #include "content/shell/browser/web_test/fake_bluetooth_chooser.h"
#include "content/shell/browser/web_test/fake_bluetooth_chooser_factory.h" #include "content/shell/browser/web_test/fake_bluetooth_chooser_factory.h"
#include "content/shell/browser/web_test/fake_bluetooth_delegate.h" #include "content/shell/browser/web_test/fake_bluetooth_delegate.h"
#include "content/shell/browser/web_test/mojo_echo.h"
#include "content/shell/browser/web_test/mojo_web_test_helper.h" #include "content/shell/browser/web_test/mojo_web_test_helper.h"
#include "content/shell/browser/web_test/web_test_bluetooth_fake_adapter_setter_impl.h" #include "content/shell/browser/web_test/web_test_bluetooth_fake_adapter_setter_impl.h"
#include "content/shell/browser/web_test/web_test_browser_context.h" #include "content/shell/browser/web_test/web_test_browser_context.h"
...@@ -204,6 +205,7 @@ void WebTestContentBrowserClient::ExposeInterfacesToRenderer( ...@@ -204,6 +205,7 @@ void WebTestContentBrowserClient::ExposeInterfacesToRenderer(
RenderProcessHost* render_process_host) { RenderProcessHost* render_process_host) {
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner =
content::GetUIThreadTaskRunner({}); content::GetUIThreadTaskRunner({});
registry->AddInterface(base::BindRepeating(&MojoEcho::Bind), ui_task_runner);
registry->AddInterface( registry->AddInterface(
base::BindRepeating(&WebTestBluetoothFakeAdapterSetterImpl::Create), base::BindRepeating(&WebTestBluetoothFakeAdapterSetterImpl::Create),
ui_task_runner); ui_task_runner);
......
// Copyright 2018 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.
module content.mojom;
// Interfaces used to test that encoding/decoding between JS and C++ works
// correctly.
union TestUnion {
bool bool_value;
int32 int32_value;
string string_value;
};
union NestedUnion {
int8 int8_value;
TestUnion union_value;
};
// Interface that echos the arguments by extracting them from structs, unions,
// etc. or by adding them to structs, unions, etc.
interface MojoEcho {
// The following methods help test that JS can correctly encode unions. They
// CHECK if the union has not the expected type.
//
// Runs callback with |test_union.bool_value|.
EchoBoolFromUnion(TestUnion test_union) => (bool value);
// Runs callback with |test_union.int32_value|.
EchoInt32FromUnion(TestUnion test_union) => (int32 value);
// Runs callback with |test_union.string_value|.
EchoStringFromUnion(TestUnion test_union) => (string value);
// The following methods help test that JS can correctly decode unions.
//
// Runs callback with |value| as the TestUnion's value.
EchoBoolAsUnion(bool value) => (TestUnion test_union);
// Runs callback with |value| as the TestUnion's value.
EchoInt32AsUnion(int32 value) => (TestUnion test_union);
// Runs callback with |value| as the TestUnion's value.
EchoStringAsUnion(string value) => (TestUnion test_union);
// The following methods help test that JS can correctly encode optional
// unions. They CHECK if the union has not the expected type.
//
// Runs the empty callback.
EchoNullFromOptionalUnion(TestUnion? test_union) => ();
// Runs callback with |test_union.bool_value|.
EchoBoolFromOptionalUnion(TestUnion? test_union) => (bool value);
// Runs callback with |test_union.int32_value|.
EchoInt32FromOptionalUnion(TestUnion? test_union) => (int32 value);
// Runs callback with |test_union.string_value|.
EchoStringFromOptionalUnion(TestUnion? test_union) => (string value);
// The following methods help test that JS can correctly decode optional
// unions.
//
// Runs callback with a null TestUnion.
EchoNullAsOptionalUnion() => (TestUnion? test_union);
// Runs callback with |value| as the TestUnion's value.
EchoBoolAsOptionalUnion(bool value) => (TestUnion? test_union);
// Runs callback with |value| as the TestUnion's value.
EchoInt32AsOptionalUnion(int32 value) => (TestUnion? test_union);
// Runs callback with |value| as the TestUnion's value.
EchoStringAsOptionalUnion(string value) => (TestUnion? test_union);
// The following methods help test that JS can correctly encode nested unions.
// They CHECK if the union has not the expected type.
//
// Runs callback with |test_union.int8_value|.
EchoInt8FromNestedUnion(NestedUnion test_union) => (int8 value);
// Runs callback with |test_union.union_value.bool_value|.
EchoBoolFromNestedUnion(NestedUnion test_union) => (bool value);
// Runs callback with |test_union.union_value.string_value|.
EchoStringFromNestedUnion(NestedUnion test_union) => (string value);
// The following methods help test that JS can correctly decode nested unions.
//
// Runs callback with |value| as the NestedUnion's value.
EchoInt8AsNestedUnion(int8 value) => (NestedUnion test_union);
// Runs callback with |value| as the NestedUnion.TestUnion's value.
EchoBoolAsNestedUnion(bool value) => (NestedUnion test_union);
// Runs callback with |value| as the NestedUnion.TestUnion's value.
EchoStringAsNestedUnion(string value) => (NestedUnion test_union);
// The following methods help test that JS can correctly encode optional
// nested unions. They CHECK if the union has not the expected type.
//
// Runs the empty callback.
EchoNullFromOptionalNestedUnion(NestedUnion? test_union) => ();
// Runs callback with |test_union.int8_value|.
EchoInt8FromOptionalNestedUnion(NestedUnion? test_union) => (int8 value);
// Runs callback with |test_union.union_value.bool_value|.
EchoBoolFromOptionalNestedUnion(NestedUnion? test_union) => (bool value);
// Runs callback with |test_union.union_value.string_value|.
EchoStringFromOptionalNestedUnion(NestedUnion? test_union) => (string value);
// The following methods help test that JS can correctly decode optional
// nested unions.
//
// Runs the empty callback.
EchoNullAsOptionalNestedUnion() => (NestedUnion? test_union);
// Runs callback with |test_union.int8_value|.
EchoInt8AsOptionalNestedUnion(int8 value) => (NestedUnion? test_union);
// Runs callback with |test_union.union_value.bool_value|.
EchoBoolAsOptionalNestedUnion(bool value) => (NestedUnion? test_union);
// Runs callback with |test_union.union_value.string_value|.
EchoStringAsOptionalNestedUnion(string value) => (NestedUnion? test_union);
};
...@@ -35,6 +35,9 @@ mojo.internal.kArrayHeaderSize = 8; ...@@ -35,6 +35,9 @@ mojo.internal.kArrayHeaderSize = 8;
/** @const {number} */ /** @const {number} */
mojo.internal.kStructHeaderSize = 8; mojo.internal.kStructHeaderSize = 8;
/** @const {number} */
mojo.internal.kUnionHeaderSize = 8;
/** @const {number} */ /** @const {number} */
mojo.internal.kUnionDataSize = 16; mojo.internal.kUnionDataSize = 16;
...@@ -540,18 +543,21 @@ mojo.internal.Encoder = class { ...@@ -540,18 +543,21 @@ mojo.internal.Encoder = class {
/** /**
* @param {!mojo.internal.UnionSpec} unionSpec * @param {!mojo.internal.UnionSpec} unionSpec
* @param {number} offset * @param {number} offset
* @param {boolean} nullable
* @param {!Object} value * @param {!Object} value
*/ */
encodeUnion(unionSpec, offset, nullable, value) { encodeUnionAsPointer(unionSpec, offset, value) {
let unionEncoder = this; const unionData = this.message_.allocate(mojo.internal.kUnionDataSize);
if (nullable) { const unionEncoder = new mojo.internal.Encoder(this.message_, unionData);
const unionData = this.message_.allocate(mojo.internal.kUnionDataSize); this.encodeOffset(offset, unionData.byteOffset);
this.encodeOffset(offset, unionData.byteOffset); unionEncoder.encodeUnion(unionSpec, /*offset=*/0, value);
offset = 0; }
unionEncoder = new mojo.internal.Encoder(this.message_, unionData);
}
/**
* @param {!mojo.internal.UnionSpec} unionSpec
* @param {number} offset
* @param {!Object} value
*/
encodeUnion(unionSpec, offset, value) {
const keys = Object.keys(value); const keys = Object.keys(value);
if (keys.length !== 1) { if (keys.length !== 1) {
throw new Error( throw new Error(
...@@ -562,10 +568,18 @@ mojo.internal.Encoder = class { ...@@ -562,10 +568,18 @@ mojo.internal.Encoder = class {
const tag = keys[0]; const tag = keys[0];
const field = unionSpec.fields[tag]; const field = unionSpec.fields[tag];
unionEncoder.encodeUint32(offset, mojo.internal.kUnionDataSize); this.encodeUint32(offset, mojo.internal.kUnionDataSize);
unionEncoder.encodeUint32(offset + 4, field['ordinal']); this.encodeUint32(offset + 4, field['ordinal']);
const fieldByteOffset = offset + mojo.internal.kUnionHeaderSize;
if (typeof field['type'].$.unionSpec !== 'undefined') {
// Unions are encoded as pointers when inside unions.
this.encodeUnionAsPointer(field['type'].$.unionSpec,
fieldByteOffset,
value[tag]);
return;
}
field['type'].$.encode( field['type'].$.encode(
value[tag], unionEncoder, offset + 8, 0, field['nullable']); value[tag], this, fieldByteOffset, 0, field['nullable']);
} }
/** /**
...@@ -786,25 +800,42 @@ mojo.internal.Decoder = class { ...@@ -786,25 +800,42 @@ mojo.internal.Decoder = class {
/** /**
* @param {!mojo.internal.UnionSpec} unionSpec * @param {!mojo.internal.UnionSpec} unionSpec
* @param {number} offset * @param {number} offset
* @param {boolean} nullable
*/ */
decodeUnion(unionSpec, offset, nullable) { decodeUnionFromPointer(unionSpec, offset) {
let unionDecoder = this; const unionOffset = this.decodeOffset(offset);
if (nullable) { if (!unionOffset)
const unionOffset = this.decodeOffset(offset); return null;
if (!unionOffset)
return null;
unionDecoder = new mojo.internal.Decoder(
new DataView(this.data_.buffer, unionOffset), this.handles_);
offset = 0;
}
const ordinal = unionDecoder.decodeUint32(offset + 4); const decoder = new mojo.internal.Decoder(
new DataView(this.data_.buffer, unionOffset), this.handles_);
return decoder.decodeUnion(unionSpec, 0);
}
/**
* @param {!mojo.internal.UnionSpec} unionSpec
* @param {number} offset
*/
decodeUnion(unionSpec, offset) {
const size = this.decodeUint32(offset);
if (size === 0)
return null;
const ordinal = this.decodeUint32(offset + 4);
for (const fieldName in unionSpec.fields) { for (const fieldName in unionSpec.fields) {
const field = unionSpec.fields[fieldName]; const field = unionSpec.fields[fieldName];
if (field['ordinal'] === ordinal) { if (field['ordinal'] === ordinal) {
const fieldValue = field['type'].$.decode( const fieldValue = (() => {
unionDecoder, offset + 8, 0, field['nullable']); const fieldByteOffset = offset + mojo.internal.kUnionHeaderSize;
// Unions are encoded as pointers when inside other
// unions.
if (typeof field['type'].$.unionSpec !== 'undefined') {
return this.decodeUnionFromPointer(
field['type'].$.unionSpec, fieldByteOffset);
}
return field['type'].$.decode(
this, fieldByteOffset, 0, field['nullable'])
})();
if (fieldValue === null && !field['nullable']) { if (fieldValue === null && !field['nullable']) {
throw new Error( throw new Error(
`Received ${unionSpec.name} with invalid null ` + `Received ${unionSpec.name} with invalid null ` +
...@@ -1372,11 +1403,11 @@ mojo.internal.Union = function(objectToBlessAsUnion, name, fields) { ...@@ -1372,11 +1403,11 @@ mojo.internal.Union = function(objectToBlessAsUnion, name, fields) {
objectToBlessAsUnion.$ = { objectToBlessAsUnion.$ = {
unionSpec: unionSpec, unionSpec: unionSpec,
encode: function(value, encoder, byteOffset, bitOffset, nullable) { encode: function(value, encoder, byteOffset, bitOffset, nullable) {
encoder.encodeUnion(unionSpec, byteOffset, nullable, value); encoder.encodeUnion(unionSpec, byteOffset, value);
}, },
encodeNull: function(encoder, byteOffset) {}, encodeNull: function(encoder, byteOffset) {},
decode: function(decoder, byteOffset, bitOffset, nullable) { decode: function(decoder, byteOffset, bitOffset, nullable) {
return decoder.decodeUnion(unionSpec, byteOffset, nullable); return decoder.decodeUnion(unionSpec, byteOffset);
}, },
computePayloadSize: function(value, nullable) { computePayloadSize: function(value, nullable) {
return mojo.internal.computeTotalUnionSize(unionSpec, nullable, value); return mojo.internal.computeTotalUnionSize(unionSpec, nullable, value);
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
<script type="module"> <script type="module">
import '/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js'; import '/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js';
import '/gen/content/test/data/lite_js_test.mojom-lite.js'; import '/gen/content/test/data/lite_js_test.mojom-lite.js';
import '/gen/content/shell/common/web_test/mojo_echo.mojom-lite.js';
import './bindings-lite-tests.js'; import './bindings-lite-tests.js';
</script> </script>
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
importScripts('/resources/testharness.js'); importScripts('/resources/testharness.js');
importScripts('/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js'); importScripts('/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js');
importScripts('/gen/content/test/data/lite_js_test.mojom-lite.js'); importScripts('/gen/content/test/data/lite_js_test.mojom-lite.js');
importScripts('/gen/content/shell/common/web_test/mojo_echo.mojom-lite.js');
importScripts('./bindings-lite-tests.js'); importScripts('./bindings-lite-tests.js');
...@@ -229,3 +229,163 @@ promise_test(() => { ...@@ -229,3 +229,163 @@ promise_test(() => {
remote.$.close(); remote.$.close();
return disconnectPromise; return disconnectPromise;
}, 'InterfaceTarget connection error handler runs when set on an InterfaceCallbackRouter object'); }, 'InterfaceTarget connection error handler runs when set on an InterfaceCallbackRouter object');
function getMojoEchoRemote() {
// content.mojom.MojoEchoRemote.getRemote() only works for frame interfaces
// and MojoEcho is a process interface.
let remote = new content.mojom.MojoEchoRemote;
Mojo.bindInterface(content.mojom.MojoEcho.$interfaceName,
remote.$.bindNewPipeAndPassReceiver().handle,
'process');
return remote;
}
promise_test(async () => {
const remote = getMojoEchoRemote();
{
const {value} = await remote.echoBoolFromUnion({boolValue: true});
assert_true(value);
}
{
const {value} = await remote.echoInt32FromUnion({int32Value: 123});
assert_equals(value, 123);
}
{
const {value} = await remote.echoStringFromUnion({stringValue: "foo"});
assert_equals(value, "foo");
}
}, 'JS encoding and C++ decoding of unions work as expected.');
promise_test(async() => {
const remote = getMojoEchoRemote();
{
const {testUnion: {boolValue}} = await remote.echoBoolAsUnion(true);
assert_equals(boolValue, true);
}
{
const {testUnion: {int32Value}} = await remote.echoInt32AsUnion(123);
assert_equals(int32Value, 123);
}
{
const {testUnion: {stringValue}} = await remote.echoStringAsUnion("foo");
assert_equals(stringValue, "foo");
}
}, 'JS decoding and C++ encoding of unions work as expected.');
promise_test(async () => {
const remote = getMojoEchoRemote();
{
const response = await remote.echoNullFromOptionalUnion();
assert_equals(Object.keys(response).length, 0);
}
{
const {value} = await remote.echoBoolFromOptionalUnion({boolValue: true});
assert_true(value);
}
{
const {value} = await remote.echoInt32FromOptionalUnion({int32Value: 123});
assert_equals(value, 123);
}
{
const {value} = await remote.echoStringFromOptionalUnion({stringValue: "foo"});
assert_equals(value, "foo");
}
}, 'JS encoding and C++ decoding of optional unions work as expected.');
promise_test(async() => {
const remote = getMojoEchoRemote();
{
const {testUnion} = await remote.echoNullAsOptionalUnion();
assert_equals(testUnion, null);
}
{
const {testUnion: {boolValue}} = await remote.echoBoolAsOptionalUnion(true);
assert_equals(boolValue, true);
}
{
const {testUnion: {int32Value}} = await remote.echoInt32AsOptionalUnion(123);
assert_equals(int32Value, 123);
}
{
const {testUnion: {stringValue}} =
await remote.echoStringAsOptionalUnion("foo");
assert_equals(stringValue, "foo");
}
}, 'JS decoding and C++ encoding of optional unions work as expected.');
promise_test(async() => {
const remote = getMojoEchoRemote();
{
const {value} = await remote.echoInt8FromNestedUnion({int8Value: -10});
assert_equals(value, -10);
}
{
const {value} = await remote.echoBoolFromNestedUnion({unionValue: {boolValue: true}});
assert_true(value);
}
{
const {value} = await remote.echoStringFromNestedUnion({unionValue: {stringValue: 'foo'}});
assert_equals(value, 'foo');
}
}, 'JS encoding and C++ decoding of nested unions work as expected.');
promise_test(async() => {
const remote = getMojoEchoRemote();
{
const {testUnion: {int8Value}} = await remote.echoInt8AsNestedUnion(-10);
assert_equals(int8Value, -10);
}
{
const {testUnion: {unionValue: {boolValue}}} = await remote.echoBoolAsNestedUnion(true);
assert_true(boolValue);
}
{
const {testUnion: {unionValue: {stringValue}}} =
await remote.echoStringAsNestedUnion('foo');
assert_equals(stringValue, 'foo');
}
}, 'JS decoding and C++ encoding of nested unions work as expected.');
promise_test(async() => {
const remote = getMojoEchoRemote();
{
const response = await remote.echoNullFromOptionalNestedUnion();
assert_equals(Object.keys(response).length, 0);
}
{
const {value} = await remote.echoInt8FromOptionalNestedUnion({int8Value: -10});
assert_equals(value, -10);
}
{
const {value} = await remote.echoBoolFromOptionalNestedUnion({unionValue: {boolValue: true}});
assert_true(value);
}
{
const {value} = await remote.echoStringFromOptionalNestedUnion({unionValue: {stringValue: 'foo'}});
assert_equals(value, 'foo');
}
}, 'JS encoding and C++ decoding of optional nested unions work as expected.');
promise_test(async() => {
const remote = getMojoEchoRemote();
{
const {testUnion} = await remote.echoNullAsOptionalNestedUnion();
assert_equals(testUnion, null);
}
{
const {testUnion: {int8Value}} = await remote.echoInt8AsOptionalNestedUnion(-10);
assert_equals(int8Value, -10);
}
{
const {testUnion: {unionValue: {boolValue}}} =
await remote.echoBoolAsOptionalNestedUnion(true);
assert_true(boolValue);
}
{
const {testUnion: {unionValue: {stringValue}}} =
await remote.echoStringAsOptionalNestedUnion('foo');
assert_equals(stringValue, 'foo');
}
}, 'JS decoding and C++ encoding of optional nested unions work as expected.');
...@@ -3,4 +3,5 @@ ...@@ -3,4 +3,5 @@
<script src="/resources/testharnessreport.js"></script> <script src="/resources/testharnessreport.js"></script>
<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js"></script> <script src="/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js"></script>
<script src="/gen/content/test/data/lite_js_test.mojom-lite.js"></script> <script src="/gen/content/test/data/lite_js_test.mojom-lite.js"></script>
<script src="/gen/content/shell/common/web_test/mojo_echo.mojom-lite.js"></script>
<script src="./bindings-lite-tests.js"></script> <script src="./bindings-lite-tests.js"></script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment