gdbus-codegen: Generate marshallers for method handlers signals

Get rid completely of the usage of the generic marshaller in gdbus
generated code, using instead specific marshallers.

Code is not yet optimized fully since we may still have duplicated
functions to be generated.

Closes: https://gitlab.gnome.org/GNOME/glib/-/issues/3028
This commit is contained in:
Marco Trevisan (Treviño)
2023-06-30 06:19:17 +02:00
parent 6de362fcae
commit 8943ceae6c
3 changed files with 317 additions and 13 deletions

View File

@@ -903,6 +903,247 @@ G_END_DECLS
)
index += 1
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshaller_simple_method(self):
"""Test that methods marshaller is generated for simple method"""
interface_xml = """
<node>
<interface name="org.project.CallableIface">
<method name="SimpleMethod"/>
</interface>
<interface name="org.project.OtherCallableIface">
<method name="SimpleMethod"/>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml, "--output", "/dev/stdout", "--body"
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(stripped_out.count("g_cclosure_marshal_generic"), 0)
func_name = "org_project_callable_iface_method_marshal_simple_method"
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
func_name = "org_project_other_callable_iface_method_marshal_simple_method"
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
self.assertIs(stripped_out.count("g_value_get_object (param_values + 1)"), 2)
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 2
)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshaller_single_typed_in_args(self):
"""Test that methods marshallers are generated for each known type"""
for t, props in self.ARGUMENTS_TYPES.items():
camel_type = t[0].upper() + t[1:]
interface_xml = f"""
<node>
<interface name="org.project.UsefulInterface">
<method name="SingleArgMethod{camel_type}">
<arg name="arg_{t}" type="{props.get("variant_type", t)}"/>
</method>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml, "--output", "/dev/stdout", "--body"
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertEqual(stripped_out.count("g_cclosure_marshal_generic"), 0)
func_name = (
f"org_project_useful_interface_method_marshal_single_arg_method_{t}"
)
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
self.assertIs(
stripped_out.count("g_value_get_object (param_values + 1)"), 1
)
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
self.assertIs(
stripped_out.count(
f"g_value_get_{props['value_type']} (param_values + 2)"
),
1,
)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshaller_single_typed_out_args(self):
"""Test that methods marshallers are generated for each known type"""
for t, props in self.ARGUMENTS_TYPES.items():
camel_type = t[0].upper() + t[1:]
interface_xml = f"""
<node>
<interface name="org.project.UsefulInterface">
<method name="SingleArgMethod{camel_type}">
<arg name="arg_{t}" type="{props.get("variant_type", t)}" direction="out"/>
</method>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml, "--output", "/dev/stdout", "--body"
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertEqual(stripped_out.count("g_cclosure_marshal_generic"), 0)
func_name = (
f"org_project_useful_interface_method_marshal_single_arg_method_{t}"
)
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
self.assertIs(
stripped_out.count("g_value_get_object (param_values + 1)"), 1
)
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
self.assertIs(stripped_out.count("(param_values + 2)"), 0)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshallers_multiple_in_args(self):
"""Test that methods marshallers are generated"""
generated_args = [
f"<arg name='an_{t}' type='{props.get('variant_type', t)}'/>\n"
for t, props in self.ARGUMENTS_TYPES.items()
]
interface_xml = f"""
<node>
<interface name="org.project.CallableIface">
<method name="MethodWithManyArgs">
{''.join(generated_args)}
</method>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml, "--output", "/dev/stdout", "--body"
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(stripped_out.count("g_cclosure_marshal_generic"), 0)
func_name = f"org_project_callable_iface_method_marshal_method_with_many_args"
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
# Check access to MultipleArgsMethod arguments
index = 1
self.assertIs(
stripped_out.count(f"g_value_get_object (param_values + {index})"), 1
)
index += 1
for props in self.ARGUMENTS_TYPES.values():
self.assertIs(
stripped_out.count(
f"g_value_get_{props['value_type']} (param_values + {index})"
),
1,
)
index += 1
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshallers_multiple_out_args(self):
"""Test that methods marshallers are generated"""
generated_args = [
f"<arg name='an_{t}' type='{props.get('variant_type', t)}' direction='out'/>\n"
for t, props in self.ARGUMENTS_TYPES.items()
]
interface_xml = f"""
<node>
<interface name="org.project.CallableIface">
<method name="MethodWithManyArgs">
{''.join(generated_args)}
</method>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml, "--output", "/dev/stdout", "--body"
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(stripped_out.count("g_cclosure_marshal_generic"), 0)
func_name = f"org_project_callable_iface_method_marshal_method_with_many_args"
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
# Check access to MultipleArgsMethod arguments
index = 1
self.assertIs(
stripped_out.count(f"g_value_get_object (param_values + {index})"), 1
)
index += 1
for index in range(index, len(self.ARGUMENTS_TYPES)):
self.assertIs(stripped_out.count(f"(param_values + {index})"), 0)
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
@unittest.skipIf(on_win32(), "requires /dev/stdout")
def test_generate_methods_marshallers_with_unix_fds(self):
"""Test an interface with `h` arguments"""
interface_xml = """
<node>
<interface name="test.FDPassing">
<method name="HelloFD">
<annotation name="org.gtk.GDBus.C.UnixFD" value="1"/>
<arg name="greeting" direction="in" type="s"/>
<arg name="response" direction="out" type="s"/>
</method>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml, "--output", "/dev/stdout", "--body"
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(stripped_out.count("g_cclosure_marshal_generic"), 0)
func_name = f"test_fdpassing_method_marshal_hello_fd"
self.assertIs(stripped_out.count(f"{func_name},"), 1)
self.assertIs(stripped_out.count(f"{func_name} ("), 1)
index = 1
self.assertIs(
stripped_out.count(f"g_value_get_object (param_values + {index})"), 1
)
index += 1
self.assertIs(
stripped_out.count(f"g_value_get_object (param_values + {index})"), 1
)
index += 1
self.assertIs(
stripped_out.count(f"g_value_get_string (param_values + {index})"), 1
)
index += 1
self.assertIs(
stripped_out.count("g_value_set_boolean (return_value, v_return);"), 1
)
def test_generate_valid_docbook(self):
"""Test the basic functionality of the docbook generator."""
xml_contents = """