From e2bc9c1abaf511ae1e2e6c048c725876fd24e466 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Fri, 24 Oct 2025 01:57:05 +0200 Subject: [PATCH] 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. --- gio/tests/codegen-test-extension.py | 56 ++++++++ gio/tests/codegen.py | 200 +++++++++++++++++++++++++++- gio/tests/meson.build | 7 +- 3 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 gio/tests/codegen-test-extension.py diff --git a/gio/tests/codegen-test-extension.py b/gio/tests/codegen-test-extension.py new file mode 100644 index 000000000..42fea3353 --- /dev/null +++ b/gio/tests/codegen-test-extension.py @@ -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 + ) diff --git a/gio/tests/codegen.py b/gio/tests/codegen.py index 0a054202f..7925c4e3b 100644 --- a/gio/tests/codegen.py +++ b/gio/tests/codegen.py @@ -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 +/* 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 = """ + + + + + + """ + + 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 = """ + + + + + + """ + + 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 = """ + + + + + """ + + 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()) diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 916b826aa..e719008e4 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -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',