[glib: 1/3] Convert tests/assert-msg-test* to glib/tests/assert-msg-test*
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 1/3] Convert tests/assert-msg-test* to glib/tests/assert-msg-test*
- Date: Tue, 28 Jun 2022 10:42:08 +0000 (UTC)
commit 207b8cb8a50d68e207d28b59e588311a5cbd9772
Author: Emmanuel Fleury <emmanuel fleury gmail com>
Date: Tue Jun 21 18:49:25 2022 +0200
Convert tests/assert-msg-test* to glib/tests/assert-msg-test*
Closes issue #1434
{tests => glib/tests}/assert-msg-test.c | 0
glib/tests/assert-msg-test.py | 155 ++++++++++++++++++++++++++
glib/tests/meson.build | 41 +++++++
glib/tests/taptestrunner.py | 188 ++++++++++++++++++++++++++++++++
meson.build | 3 -
tests/assert-msg-test.gdb | 5 -
tests/meson.build | 29 -----
tests/run-assert-msg-test.sh | 49 ---------
8 files changed, 384 insertions(+), 86 deletions(-)
---
diff --git a/tests/assert-msg-test.c b/glib/tests/assert-msg-test.c
similarity index 100%
rename from tests/assert-msg-test.c
rename to glib/tests/assert-msg-test.c
diff --git a/glib/tests/assert-msg-test.py b/glib/tests/assert-msg-test.py
new file mode 100755
index 0000000000..2d54a56192
--- /dev/null
+++ b/glib/tests/assert-msg-test.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2022 Emmanuel Fleury <emmanuel fleury gmail com>
+#
+# 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
+
+""" Integration tests for g_assert() functions. """
+
+import collections
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import unittest
+
+import taptestrunner
+
+Result = collections.namedtuple("Result", ("info", "out", "err"))
+
+GDB_SCRIPT = """
+# Work around https://sourceware.org/bugzilla/show_bug.cgi?id=22501
+set confirm off
+set print elements 0
+set auto-load safe-path /
+run
+print *((char**) &__glib_assert_msg)
+quit
+"""
+
+
+class TestAssertMessage(unittest.TestCase):
+ """Integration test for throwing message on g_assert().
+
+ This can be run when installed or uninstalled. When uninstalled,
+ it requires G_TEST_BUILDDIR and G_TEST_SRCDIR to be set.
+
+ The idea with this test harness is to test if g_assert() prints
+ an error message when called, and that it saves this error
+ message in a global variable accessible to gdb, so that developers
+ and automated tools can more easily debug assertion failures.
+ """
+
+ def setUp(self):
+ self.__gdb = shutil.which("gdb")
+ self.timeout_seconds = 10 # seconds per test
+
+ if "G_TEST_BUILDDIR" in os.environ:
+ self.__assert_msg_test = os.path.join(
+ os.environ["G_TEST_BUILDDIR"], "assert-msg-test"
+ )
+ else:
+ self.__assert_msg_test = shutil.which("assert-msg-test")
+ print("assert-msg-test:", self.__assert_msg_test)
+
+ def runAssertMessage(self, *args):
+ argv = [self.__assert_msg_test]
+ # shebang lines are not supported on native
+ # Windows consoles
+ if os.name == "nt":
+ argv.insert(0, sys.executable)
+ argv.extend(args)
+ print("Running:", argv)
+
+ env = os.environ.copy()
+ env["LC_ALL"] = "C.UTF-8"
+ print("Environment:", env)
+
+ # We want to ensure consistent line endings...
+ info = subprocess.run(
+ argv,
+ timeout=self.timeout_seconds,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env,
+ universal_newlines=True,
+ )
+ out = info.stdout.strip()
+ err = info.stderr.strip()
+
+ result = Result(info, out, err)
+
+ print("Output:", result.out)
+ return result
+
+ def runGdbAssertMessage(self, *args):
+ if self.__gdb is None:
+ return Result(None, "", "")
+
+ argv = ["gdb", "--batch"]
+ argv.extend(args)
+ print("Running:", argv)
+
+ env = os.environ.copy()
+ env["LC_ALL"] = "C.UTF-8"
+ print("Environment:", env)
+
+ # We want to ensure consistent line endings...
+ info = subprocess.run(
+ argv,
+ timeout=self.timeout_seconds,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env,
+ universal_newlines=True,
+ )
+ info.check_returncode()
+ out = info.stdout.strip()
+ err = info.stderr.strip()
+
+ result = Result(info, out, err)
+
+ print("Output:", result.out)
+ return result
+
+ def test_gassert(self):
+ """Test running g_assert() and fail the program."""
+ result = self.runAssertMessage()
+
+ self.assertEqual(result.info.returncode, -6)
+ self.assertIn("assertion failed: (42 < 0)", result.out)
+
+ def test_gdb_gassert(self):
+ """Test running g_assert() within gdb and fail the program."""
+ if self.__gdb is None:
+ self.skipTest("GDB is not installed, skipping this test!")
+
+ with tempfile.NamedTemporaryFile(
+ prefix="assert-msg-test-", suffix=".gdb", mode="w"
+ ) as tmp:
+ tmp.write(GDB_SCRIPT)
+ tmp.flush()
+
+ result = self.runGdbAssertMessage("-x", tmp.name, self.__assert_msg_test)
+ self.assertEqual(result.info.returncode, 0)
+ self.assertIn("$1 = 0x", result.out)
+ self.assertIn("assertion failed: (42 < 0)", result.out)
+
+
+if __name__ == "__main__":
+ unittest.main(testRunner=taptestrunner.TAPTestRunner())
diff --git a/glib/tests/meson.build b/glib/tests/meson.build
index d16a071e56..9b3b3bfa4e 100644
--- a/glib/tests/meson.build
+++ b/glib/tests/meson.build
@@ -282,6 +282,47 @@ if installed_tests_enabled
)
endif
+python_tests = [
+ 'assert-msg-test.py',
+]
+
+executable('assert-msg-test', ['assert-msg-test.c'],
+ c_args : test_cargs,
+ dependencies : test_deps,
+ install_dir : installed_tests_execdir,
+ install : installed_tests_enabled,
+ win_subsystem : extra_args.get('win_subsystem', 'console'),
+)
+
+foreach test_name : python_tests
+ test(
+ test_name,
+ python,
+ args: ['-B', files(test_name)],
+ env: test_env,
+ suite: ['glib', 'no-valgrind'],
+ )
+
+ if installed_tests_enabled
+ install_data(
+ files(test_name),
+ install_dir: installed_tests_execdir,
+ install_mode: 'rwxr-xr-x',
+ )
+
+ test_conf = configuration_data()
+ test_conf.set('installed_tests_dir', installed_tests_execdir)
+ test_conf.set('program', test_name)
+ test_conf.set('env', '')
+ configure_file(
+ input: installed_tests_template_tap,
+ output: test_name + '.test',
+ install_dir: installed_tests_metadir,
+ configuration: test_conf,
+ )
+ endif
+endforeach
+
executable('spawn-path-search-helper', 'spawn-path-search-helper.c',
c_args : test_cargs,
dependencies : test_deps,
diff --git a/glib/tests/taptestrunner.py b/glib/tests/taptestrunner.py
new file mode 100644
index 0000000000..9adbd8daa4
--- /dev/null
+++ b/glib/tests/taptestrunner.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# coding=utf-8
+
+# Copyright (c) 2015 Remko Tronçon (https://el-tramo.be)
+# Copied from https://github.com/remko/pycotap/
+#
+# SPDX-License-Identifier: MIT
+#
+# Released under the MIT license
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
+import unittest
+import sys
+import base64
+from io import StringIO
+
+
+# Log modes
+class LogMode(object):
+ LogToError, LogToDiagnostics, LogToYAML, LogToAttachment = range(4)
+
+
+class TAPTestResult(unittest.TestResult):
+ def __init__(self, output_stream, error_stream, message_log, test_output_log):
+ super(TAPTestResult, self).__init__(self, output_stream)
+ self.output_stream = output_stream
+ self.error_stream = error_stream
+ self.orig_stdout = None
+ self.orig_stderr = None
+ self.message = None
+ self.test_output = None
+ self.message_log = message_log
+ self.test_output_log = test_output_log
+ self.output_stream.write("TAP version 13\n")
+ self._set_streams()
+
+ def printErrors(self):
+ self.print_raw("1..%d\n" % self.testsRun)
+ self._reset_streams()
+
+ def _set_streams(self):
+ self.orig_stdout = sys.stdout
+ self.orig_stderr = sys.stderr
+ if self.message_log == LogMode.LogToError:
+ self.message = self.error_stream
+ else:
+ self.message = StringIO()
+ if self.test_output_log == LogMode.LogToError:
+ self.test_output = self.error_stream
+ else:
+ self.test_output = StringIO()
+
+ if self.message_log == self.test_output_log:
+ self.test_output = self.message
+ sys.stdout = sys.stderr = self.test_output
+
+ def _reset_streams(self):
+ sys.stdout = self.orig_stdout
+ sys.stderr = self.orig_stderr
+
+ def print_raw(self, text):
+ self.output_stream.write(text)
+ self.output_stream.flush()
+
+ def print_result(self, result, test, directive=None):
+ self.output_stream.write("%s %d %s" % (result, self.testsRun, test.id()))
+ if directive:
+ self.output_stream.write(" # " + directive)
+ self.output_stream.write("\n")
+ self.output_stream.flush()
+
+ def ok(self, test, directive=None):
+ self.print_result("ok", test, directive)
+
+ def not_ok(self, test):
+ self.print_result("not ok", test)
+
+ def startTest(self, test):
+ super(TAPTestResult, self).startTest(test)
+
+ def stopTest(self, test):
+ super(TAPTestResult, self).stopTest(test)
+ if self.message_log == self.test_output_log:
+ logs = [(self.message_log, self.message, "output")]
+ else:
+ logs = [
+ (self.test_output_log, self.test_output, "test_output"),
+ (self.message_log, self.message, "message"),
+ ]
+ for log_mode, log, log_name in logs:
+ if log_mode != LogMode.LogToError:
+ output = log.getvalue()
+ if len(output):
+ if log_mode == LogMode.LogToYAML:
+ self.print_raw(" ---\n")
+ self.print_raw(" " + log_name + ": |\n")
+ self.print_raw(
+ " " + output.rstrip().replace("\n", "\n ") + "\n"
+ )
+ self.print_raw(" ...\n")
+ elif log_mode == LogMode.LogToAttachment:
+ self.print_raw(" ---\n")
+ self.print_raw(" " + log_name + ":\n")
+ self.print_raw(" File-Name: " + log_name + ".txt\n")
+ self.print_raw(" File-Type: text/plain\n")
+ self.print_raw(
+ " File-Content: " + base64.b64encode(output) + "\n"
+ )
+ self.print_raw(" ...\n")
+ else:
+ self.print_raw(
+ "# " + output.rstrip().replace("\n", "\n# ") + "\n"
+ )
+ # Truncate doesn't change the current stream position.
+ # Seek to the beginning to avoid extensions on subsequent writes.
+ log.seek(0)
+ log.truncate(0)
+
+ def addSuccess(self, test):
+ super(TAPTestResult, self).addSuccess(test)
+ self.ok(test)
+
+ def addError(self, test, err):
+ super(TAPTestResult, self).addError(test, err)
+ self.message.write(self.errors[-1][1] + "\n")
+ self.not_ok(test)
+
+ def addFailure(self, test, err):
+ super(TAPTestResult, self).addFailure(test, err)
+ self.message.write(self.failures[-1][1] + "\n")
+ self.not_ok(test)
+
+ def addSkip(self, test, reason):
+ super(TAPTestResult, self).addSkip(test, reason)
+ self.ok(test, "SKIP " + reason)
+
+ def addExpectedFailure(self, test, err):
+ super(TAPTestResult, self).addExpectedFailure(test, err)
+ self.ok(test)
+
+ def addUnexpectedSuccess(self, test):
+ super(TAPTestResult, self).addUnexpectedSuccess(test)
+ self.message.write("Unexpected success" + "\n")
+ self.not_ok(test)
+
+
+class TAPTestRunner(object):
+ def __init__(
+ self,
+ message_log=LogMode.LogToYAML,
+ test_output_log=LogMode.LogToDiagnostics,
+ output_stream=sys.stdout,
+ error_stream=sys.stderr,
+ ):
+ self.output_stream = output_stream
+ self.error_stream = error_stream
+ self.message_log = message_log
+ self.test_output_log = test_output_log
+
+ def run(self, test):
+ result = TAPTestResult(
+ self.output_stream,
+ self.error_stream,
+ self.message_log,
+ self.test_output_log,
+ )
+ test(result)
+ result.printErrors()
+
+ return result
diff --git a/meson.build b/meson.build
index e44bad35bd..5c85db9b2f 100644
--- a/meson.build
+++ b/meson.build
@@ -2346,9 +2346,6 @@ subdir('gthread')
subdir('gmodule')
subdir('gio')
subdir('fuzzing')
-if build_tests
- subdir('tests')
-endif
subdir('tools')
# xgettext is optional (on Windows for instance)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]