tests/codegen: Add tests for the new extension system

This makes sure that extensions can generate code at the expected
places, and change the GDBusInterfaceSkeleton subtype that generated
skeletons derive from.
This commit is contained in:
Sebastian Wick
2025-10-24 01:57:05 +02:00
committed by Philip Withnall
parent 47a109c241
commit e2bc9c1aba
3 changed files with 258 additions and 5 deletions

View File

@@ -0,0 +1,56 @@
#!/usr/bin/python3
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
def init(args, options):
assert options["version"] == 1
class HeaderCodeGenerator:
def __init__(self, generator):
self.ifaces = generator.ifaces
self.outfile = generator.outfile
generator.skeleton_type_camel = "NewDBusInterfaceSkeleton"
def generate_includes(self):
self.outfile.write("/* codegen-test-extension include */\n")
def declare_types(self):
for i in self.ifaces:
self.outfile.write(
"/* codegen-test-extension declare type for iface %s */\n" % i.name
)
class CodeGenerator:
def __init__(self, generator):
self.ifaces = generator.ifaces
self.outfile = generator.outfile
generator.skeleton_type_upper = "NEW_TYPE_DBUS_INTERFACE_SKELETON"
def generate_body_preamble(self):
self.outfile.write("/* codegen-test-extension body preamble */\n")
def generate(self):
for i in self.ifaces:
self.outfile.write(
"/* codegen-test-extension generate for iface %s */\n" % i.name
)

View File

@@ -75,8 +75,8 @@ class TestCodegen(testprogramrunner.TestProgramRunner):
"asv": {"value_type": "variant", "variant_type": "a{sv}"},
}
def runCodegen(self, *args):
return self.runTestProgram(args)
def runCodegen(self, *args, **kwargs):
return self.runTestProgram(args, **kwargs)
def _getSubs(self):
# Known substitutions for standard boilerplate
@@ -276,7 +276,7 @@ class TestCodegen(testprogramrunner.TestProgramRunner):
"}",
}
def runCodegenWithInterface(self, interface_contents, *args):
def runCodegenWithInterface(self, interface_contents, *args, **kwargs):
with tempfile.NamedTemporaryFile(
dir=self.tmpdir.name, suffix=".xml", delete=False
) as interface_file:
@@ -285,7 +285,12 @@ class TestCodegen(testprogramrunner.TestProgramRunner):
print(interface_file.name + ":", interface_contents)
interface_file.flush()
return self.runCodegen(interface_file.name, *args)
return self.runCodegen(interface_file.name, *args, **kwargs)
def get_codegen_ext_path(self):
return os.path.join(
os.path.dirname(os.path.realpath(__file__)), "codegen-test-extension.py"
)
def test_help(self):
"""Test the --help argument."""
@@ -1456,6 +1461,193 @@ G_END_DECLS
with open(f"test-org.project.Bar.Frobnicator.{ext}", "r") as f:
self.assertIn(markup_list, f.read())
def test_extension_help(self):
"""Test the --help for the extension"""
result = self.runCodegen("--help")
self.assertIn("(unstable API)", result.out)
def test_extension_bad_file(self):
"""Test the --help for the extension"""
result = self.runCodegenWithInterface(
"",
"--output",
"-",
"--header",
"--extension-path",
"/path/that/does/not/exist",
should_fail=True,
)
self.assertIn(
"ERROR: Loading extension /path/that/does/not/exist failed", result.err
)
self.assertEqual("", result.out)
def test_extension_empty_interface_header(self):
"""Test generating a header with an empty interface file with the test
extension.
"""
result = self.runCodegenWithInterface(
"",
"--output",
"-",
"--header",
"--extension-path",
self.get_codegen_ext_path(),
)
self.assertEqual("", result.err)
self.assertEqual(
"""{standard_top_comment}
#ifndef __STDOUT__
#define __STDOUT__
#include <gio/gio.h>
/* codegen-test-extension include */
G_BEGIN_DECLS
G_END_DECLS
#endif /* __STDOUT__ */""".format(
**result.subs
),
result.out.strip(),
)
def test_extension_empty_interface_body(self):
"""Test generating a body with an empty interface file with the test
extension.
"""
result = self.runCodegenWithInterface(
"",
"--output",
"-",
"--body",
"--extension-path",
self.get_codegen_ext_path(),
)
self.assertEqual("", result.err)
self.assertEqual(
"""{standard_top_comment}
{standard_config_h_include}
{standard_header_includes}
{private_gvalues_getters}
{standard_typedefs_and_helpers}
/* codegen-test-extension body preamble */""".format(
**result.subs
),
result.out.strip(),
)
def test_extension_header_declare_types(self):
"""Test generating header declarations from the test extension"""
interface_xml = """
<node>
<interface name="org.project.Foo">
</interface>
<interface name="org.project.Bar">
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml,
"--output",
"-",
"--header",
"--extension-path",
self.get_codegen_ext_path(),
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(
stripped_out.count(
"/* codegen-test-extension declare type for iface org.project.Foo */"
),
1,
)
self.assertIs(
stripped_out.count(
"/* codegen-test-extension declare type for iface org.project.Bar */"
),
1,
)
def test_extension_code_generate(self):
"""Test code generation from the test extension"""
interface_xml = """
<node>
<interface name="org.project.Foo">
</interface>
<interface name="org.project.Bar">
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml,
"--output",
"-",
"--body",
"--extension-path",
self.get_codegen_ext_path(),
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(
stripped_out.count(
"/* codegen-test-extension generate for iface org.project.Foo */"
),
1,
)
self.assertIs(
stripped_out.count(
"/* codegen-test-extension generate for iface org.project.Bar */"
),
1,
)
def test_extension_code_generate(self):
"""Test changing the GDBusInterfaceSkeleton subtype from the test
extension that skeletons derive from
"""
interface_xml = """
<node>
<interface name="org.project.UsefulInterface">
<method name="UsefulMethod"/>
</interface>
</node>"""
result = self.runCodegenWithInterface(
interface_xml,
"--output",
"-",
"--body",
"--extension-path",
self.get_codegen_ext_path(),
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(stripped_out.count("G_TYPE_DBUS_INTERFACE_SKELETON"), 0)
self.assertIs(stripped_out.count("NEW_TYPE_DBUS_INTERFACE_SKELETON"), 2)
result = self.runCodegenWithInterface(
interface_xml,
"--output",
"-",
"--header",
"--extension-path",
self.get_codegen_ext_path(),
)
stripped_out = result.out.strip()
self.assertFalse(result.err)
self.assertIs(stripped_out.count("GDBusInterfaceSkeleton"), 0)
self.assertIs(stripped_out.count("NewDBusInterfaceSkeleton"), 2)
if __name__ == "__main__":
unittest.main(testRunner=taptestrunner.TAPTestRunner())

View File

@@ -206,6 +206,7 @@ python_tests = {
# FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/2764
'codegen.py' : {
'env': {'_G_TEST_PROGRAM_RUNNER_PATH': fs.parent(gdbus_codegen.full_path())},
'extra-files': ['codegen-test-extension.py'],
'can_fail' : host_system == 'freebsd',
'suite': ['gdbus-codegen', 'slow'],
'timeout': 90,
@@ -1238,9 +1239,13 @@ foreach test_name, extra_args : python_tests
suite: suite,
)
foreach file : extra_args.get('extra-files', [])
fs.copyfile(file)
endforeach
if installed_tests_enabled
install_data(
files(test_name),
files([test_name] + extra_args.get('extra-files', [])),
install_dir: installed_tests_execdir,
install_tag: 'tests',
install_mode: 'rwxr-xr-x',