Commit 39f676e6 authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

[mojo-bindings] JS lite union and FlushForTesting

Adds a |flushForTesting()| method to generated interface proxies.

This requires use of interface control message bindings, which in turn
requires union support. So union support is added here as well.

Finally, this also required compiling the interface control message
bindings into the mojo_bindings_lite.js binary, so some minimal changes
were made to generated JS code to make it compiler-friendly.

Net code size increase of about 2kB.

Bug: 849993
Change-Id: Id44d2d0e5e85693937f5bcd5419429766d25e062
Reviewed-on: https://chromium-review.googlesource.com/c/1336065
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarcalamity <calamity@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608669}
parent 6a1db25d
...@@ -8,6 +8,11 @@ struct TestStruct { ...@@ -8,6 +8,11 @@ struct TestStruct {
int32 x; int32 x;
}; };
union TestUnion {
int32 x;
TestStruct s;
};
// An interface whose definition covers various types of message signatures in // An interface whose definition covers various types of message signatures in
// order to exercise the lite JS mojom bindings. // order to exercise the lite JS mojom bindings.
interface TestMessageTarget { interface TestMessageTarget {
...@@ -22,6 +27,7 @@ interface TestMessageTarget { ...@@ -22,6 +27,7 @@ interface TestMessageTarget {
=> (string? message, array<int32>? numbers); => (string? message, array<int32>? numbers);
Flatten(array<TestStruct> values) => (array<int32> values); Flatten(array<TestStruct> values) => (array<int32> values);
FlattenUnions(array<TestUnion> unions) => (array<int32> x, array<int32> s);
RequestSubinterface(Subinterface& request, SubinterfaceClient client); RequestSubinterface(Subinterface& request, SubinterfaceClient client);
}; };
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import("//third_party/closure_compiler/compile_js.gni") import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni") import("//tools/grit/grit_rule.gni")
import("//ui/webui/webui_features.gni")
interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings" interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings"
...@@ -52,15 +53,27 @@ action("bindings") { ...@@ -52,15 +53,27 @@ action("bindings") {
} }
bindings_lite_sources = [ "bindings_lite.js" ] bindings_lite_sources = [ "bindings_lite.js" ]
interface_control_messages_sources = [ "$root_gen_dir/mojo/public/interfaces/bindings/interface_control_messages.mojom-lite.js" ]
bindings_lite_compiled_file = "$target_gen_dir/mojo_bindings_lite.js" bindings_lite_compiled_file = "$target_gen_dir/mojo_bindings_lite.js"
if (closure_compile) { if (closure_compile && optimize_webui) {
js_binary("bindings_lite") { js_library("control_message_bindings_lite") {
sources = interface_control_messages_sources
extra_deps = [ "//mojo/public/interfaces/bindings:bindings_js" ]
}
js_library("bindings_lite_sources") {
sources = [ "compile_preamble.js" ] + bindings_lite_sources sources = [ "compile_preamble.js" ] + bindings_lite_sources
}
js_binary("bindings_lite") {
outputs = [ outputs = [
bindings_lite_compiled_file, bindings_lite_compiled_file,
] ]
deps = [
":bindings_lite_sources",
":control_message_bindings_lite",
]
externs_list = [ externs_list = [
"$externs_path/mojo_core.js", "$externs_path/mojo_core.js",
"$externs_path/pending.js", "$externs_path/pending.js",
...@@ -73,11 +86,12 @@ if (closure_compile) { ...@@ -73,11 +86,12 @@ if (closure_compile) {
} else { } else {
action("bindings_lite") { action("bindings_lite") {
script = "//v8/tools/concatenate-files.py" script = "//v8/tools/concatenate-files.py"
sources = bindings_lite_sources sources = bindings_lite_sources + interface_control_messages_sources
outputs = [ outputs = [
bindings_lite_compiled_file, bindings_lite_compiled_file,
] ]
args = rebase_path(bindings_lite_sources, root_build_dir) args = rebase_path(bindings_lite_sources, root_build_dir) +
rebase_path(interface_control_messages_sources, root_build_dir)
args += [ rebase_path(bindings_lite_compiled_file, root_build_dir) ] args += [ rebase_path(bindings_lite_compiled_file, root_build_dir) ]
deps = [ deps = [
"//mojo/public/interfaces/bindings:bindings_js__generator", "//mojo/public/interfaces/bindings:bindings_js__generator",
......
This diff is collapsed.
...@@ -72,6 +72,7 @@ action("precompile_templates") { ...@@ -72,6 +72,7 @@ action("precompile_templates") {
"$mojom_generator_root/generators/js_templates/lite/struct_definition.tmpl", "$mojom_generator_root/generators/js_templates/lite/struct_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/struct_externs.tmpl", "$mojom_generator_root/generators/js_templates/lite/struct_externs.tmpl",
"$mojom_generator_root/generators/js_templates/lite/union_definition.tmpl", "$mojom_generator_root/generators/js_templates/lite/union_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/union_externs.tmpl",
"$mojom_generator_root/generators/js_templates/module.amd.tmpl", "$mojom_generator_root/generators/js_templates/module.amd.tmpl",
"$mojom_generator_root/generators/js_templates/module_definition.tmpl", "$mojom_generator_root/generators/js_templates/module_definition.tmpl",
"$mojom_generator_root/generators/js_templates/struct_definition.tmpl", "$mojom_generator_root/generators/js_templates/struct_definition.tmpl",
......
...@@ -71,6 +71,12 @@ class {{interface.name}}Proxy { ...@@ -71,6 +71,12 @@ class {{interface.name}}Proxy {
]); ]);
} }
{%- endfor %} {%- endfor %}
/** @return {!Promise} */
flushForTesting() {
return this.proxy.flushForTesting();
}
} }
/** /**
......
...@@ -28,3 +28,8 @@ goog.provide('{{module.namespace}}.{{constant.name}}'); ...@@ -28,3 +28,8 @@ goog.provide('{{module.namespace}}.{{constant.name}}');
{%- for struct in structs -%} {%- for struct in structs -%}
{%- include "lite/struct_externs.tmpl" %} {%- include "lite/struct_externs.tmpl" %}
{% endfor -%} {% endfor -%}
{#--- Union definitions #}
{%- for union in unions -%}
{%- include "lite/union_externs.tmpl" %}
{% endfor -%}
...@@ -14,35 +14,39 @@ let {{ enum_def(enum.name, enum) }} ...@@ -14,35 +14,39 @@ let {{ enum_def(enum.name, enum) }}
{% include "lite/interface_definition.tmpl" %} {% include "lite/interface_definition.tmpl" %}
{%- endfor %} {%- endfor %}
{#--- Struct definitions #} {#--- Struct and Union forward declarations #}
{% for struct in structs %} {% for struct in structs %}
let {{struct.name}} = {}; const {{struct.name}} = {};
{%- endfor -%} {%- endfor %}
{%- for union in unions %}
const {{union.name}} = {};
{%- endfor %}
{#--- Struct definitions #}
{% for struct in structs %} {% for struct in structs %}
{%- include "lite/struct_definition.tmpl" %} {%- include "lite/struct_definition.tmpl" %}
{%- endfor -%} {%- endfor -%}
{#--- Union definitions #} {#--- Union definitions #}
{% from "lite/union_definition.tmpl" import union_def %} {% for union in unions %}
{%- for union in unions %} {%- include "lite/union_definition.tmpl" %}
{{union_def(union, generate_fuzzing)|indent(2)}} {% endfor %}
{%- endfor %}
{%- for constant in module.constants %} {%- for constant in module.constants %}
exports.{{constant.name}} = {{constant.name}}; exports['{{constant.name}}'] = {{constant.name}};
{%- endfor %} {%- endfor %}
{%- for enum in enums %} {%- for enum in enums %}
exports.{{enum.name}} = {{enum.name}}; exports['{{enum.name}}'] = {{enum.name}};
{%- endfor %} {%- endfor %}
{%- for struct in structs if struct.exported %} {%- for struct in structs if struct.exported %}
exports.{{struct.name}} = {{struct.name}}; exports['{{struct.name}}'] = {{struct.name}};
{%- endfor %} {%- endfor %}
{%- for union in unions %} {%- for union in unions %}
exports.{{union.name}} = {{union.name}}; exports['{{union.name}}'] = {{union.name}};
{%- endfor %} {%- endfor %}
{%- for interface in interfaces %} {%- for interface in interfaces %}
exports.{{interface.name}} = {{interface.name}}; exports['{{interface.name}}'] = {{interface.name}};
exports.{{interface.name}}Request = {{interface.name}}Request; exports['{{interface.name}}Request'] = {{interface.name}}Request;
exports.{{interface.name}}Proxy = {{interface.name}}Proxy; exports['{{interface.name}}Proxy'] = {{interface.name}}Proxy;
exports.{{interface.name}}CallbackRouter = {{interface.name}}CallbackRouter; exports['{{interface.name}}CallbackRouter'] = {{interface.name}}CallbackRouter;
{%- endfor %} {%- endfor %}
{%- macro union_def(union, generate_fuzzing) -%}
{%- endmacro %} mojo.mojom.Union(
{{union.name}}, '{{union.name}}',
{
{%- for field in union.fields %}
'{{field.name}}': {
'ordinal': {{field.ordinal}},
'type': {{field.kind|lite_js_type}},
{%- if field.kind.is_nullable %}
'nullable': true,
{%- endif %}
},
{%- endfor %}
});
{# Note that goog.provide is understood by the Closure Compiler even if the
Closure base library is unavailable. See https://crbug.com/898692 #}
goog.provide('{{module.namespace}}.{{union.name}}');
{{module.namespace}}.{{union.name}} = class {
constructor() {
{%- for field in fields %}
/** @type { {{field.kind|lite_closure_type_with_nullability}} } */
this.{{field.name}};
{%- endfor %}
}
};
...@@ -417,9 +417,8 @@ class Generator(generator.Generator): ...@@ -417,9 +417,8 @@ class Generator(generator.Generator):
if (mojom.IsStructKind(kind) or if (mojom.IsStructKind(kind) or
mojom.IsEnumKind(kind)): mojom.IsEnumKind(kind)):
return kind.module.namespace + "." + kind.name return kind.module.namespace + "." + kind.name
# TODO(calamity): Support unions properly.
if mojom.IsUnionKind(kind): if mojom.IsUnionKind(kind):
return "Object" return kind.module.namespace + "." + kind.name
if mojom.IsArrayKind(kind): if mojom.IsArrayKind(kind):
return "Array<%s>" % self._ClosureType(kind.kind) return "Array<%s>" % self._ClosureType(kind.kind)
if mojom.IsMapKind(kind) and self._IsStringableKind(kind.key_kind): if mojom.IsMapKind(kind) and self._IsStringableKind(kind.key_kind):
......
...@@ -19,6 +19,7 @@ class TargetImpl { ...@@ -19,6 +19,7 @@ class TargetImpl {
ping() { return Promise.resolve(); } ping() { return Promise.resolve(); }
repeat(message, numbers) { return {message: message, numbers: numbers}; } repeat(message, numbers) { return {message: message, numbers: numbers}; }
flatten(values) {} flatten(values) {}
flattenUnions(unions) {}
requestSubinterface(request, client) {} requestSubinterface(request, client) {}
} }
...@@ -121,11 +122,42 @@ promise_test(() => { ...@@ -121,11 +122,42 @@ promise_test(() => {
}, 'can send and receive interface requests and proxies'); }, 'can send and receive interface requests and proxies');
promise_test(() => { promise_test(() => {
let targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter; const targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
let targetProxy = targetRouter.createProxy(); const targetProxy = targetRouter.createProxy();
targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)})); targetRouter.flatten.addListener(values => ({values: values.map(v => v.x)}));
return targetProxy.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => { return targetProxy.flatten([{x: 1}, {x: 2}, {x: 3}]).then(reply => {
assert_array_equals(reply.values, [1, 2, 3]); assert_array_equals(reply.values, [1, 2, 3]);
}); });
}, 'regression test for complex array serialization'); }, 'regression test for complex array serialization');
promise_test(() => {
const targetRouter = new liteJsTest.mojom.TestMessageTargetCallbackRouter;
const targetProxy = targetRouter.createProxy();
targetRouter.flattenUnions.addListener(unions => {
return {x: unions.filter(u => u.x !== undefined).map(u => u.x),
s: unions.filter(u => u.s !== undefined).map(u => u.s.x)};
});
return targetProxy.flattenUnions(
[{x: 1}, {x: 2}, {s: {x: 3}}, {s: {x: 4}}, {x: 5}, {s: {x: 6}}])
.then(reply => {
assert_array_equals(reply.x, [1, 2, 5]);
assert_array_equals(reply.s, [3, 4, 6]);
});
}, 'can serialize and deserialize unions');
promise_test(() => {
let impl = new TargetImpl;
let proxy = impl.target.createProxy();
// Poke a bunch of times. These should never race with the assertion below,
// because the |flushForTesting| request/response is ordered against other
// messages on |proxy|.
const kNumPokes = 100;
for (let i = 0; i < kNumPokes; ++i)
proxy.poke();
return proxy.flushForTesting().then(() => {
assert_equals(impl.numPokes, kNumPokes);
});
}, 'can use generated flushForTesting API for synchronization in tests');
</script> </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