mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-02 17:26:17 +01:00
Convert tests/assert-msg-test* to glib/tests/assert-msg-test*
Closes issue #1434
This commit is contained in:
parent
6d381c9668
commit
207b8cb8a5
155
glib/tests/assert-msg-test.py
Executable file
155
glib/tests/assert-msg-test.py
Executable file
@ -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())
|
@ -282,6 +282,47 @@ if installed_tests_enabled
|
|||||||
)
|
)
|
||||||
endif
|
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',
|
executable('spawn-path-search-helper', 'spawn-path-search-helper.c',
|
||||||
c_args : test_cargs,
|
c_args : test_cargs,
|
||||||
dependencies : test_deps,
|
dependencies : test_deps,
|
||||||
|
188
glib/tests/taptestrunner.py
Normal file
188
glib/tests/taptestrunner.py
Normal file
@ -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
|
@ -2346,9 +2346,6 @@ subdir('gthread')
|
|||||||
subdir('gmodule')
|
subdir('gmodule')
|
||||||
subdir('gio')
|
subdir('gio')
|
||||||
subdir('fuzzing')
|
subdir('fuzzing')
|
||||||
if build_tests
|
|
||||||
subdir('tests')
|
|
||||||
endif
|
|
||||||
subdir('tools')
|
subdir('tools')
|
||||||
|
|
||||||
# xgettext is optional (on Windows for instance)
|
# xgettext is optional (on Windows for instance)
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
run
|
|
||||||
set print elements 0
|
|
||||||
# Work around https://sourceware.org/bugzilla/show_bug.cgi?id=22501
|
|
||||||
print *((char**) &__glib_assert_msg)
|
|
||||||
quit
|
|
@ -1,29 +0,0 @@
|
|||||||
# tests
|
|
||||||
|
|
||||||
test_env = environment()
|
|
||||||
test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
|
|
||||||
test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
|
|
||||||
test_env.set('G_DEBUG', 'gc-friendly')
|
|
||||||
test_env.set('MALLOC_CHECK_', '2')
|
|
||||||
|
|
||||||
test_cargs = ['-DG_LOG_DOMAIN="GLib"', '-UG_DISABLE_ASSERT']
|
|
||||||
|
|
||||||
test_extra_programs = {
|
|
||||||
'assert-msg-test' : {},
|
|
||||||
}
|
|
||||||
|
|
||||||
common_c_args = test_cargs + ['-DGLIB_DISABLE_DEPRECATION_WARNINGS']
|
|
||||||
common_deps = [libm, thread_dep, libglib_dep]
|
|
||||||
|
|
||||||
foreach program_name, extra_args : test_extra_programs
|
|
||||||
source = extra_args.get('source', program_name + '.c')
|
|
||||||
extra_sources = extra_args.get('extra_sources', [])
|
|
||||||
install = installed_tests_enabled and extra_args.get('install', true)
|
|
||||||
executable(program_name, [source, extra_sources],
|
|
||||||
c_args : common_c_args,
|
|
||||||
dependencies : common_deps + extra_args.get('dependencies', []),
|
|
||||||
install_dir : installed_tests_execdir,
|
|
||||||
install : install,
|
|
||||||
win_subsystem : extra_args.get('win_subsystem', 'console'),
|
|
||||||
)
|
|
||||||
endforeach
|
|
@ -1,49 +0,0 @@
|
|||||||
#! /bin/sh
|
|
||||||
|
|
||||||
fail ()
|
|
||||||
{
|
|
||||||
echo "Test failed: $*"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
echo_v ()
|
|
||||||
{
|
|
||||||
if [ "$verbose" = "1" ]; then
|
|
||||||
echo "$*"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
error_out=/dev/null
|
|
||||||
if [ "$1" = "-v" ]; then
|
|
||||||
verbose=1
|
|
||||||
error_out=/dev/stderr
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$LIBTOOL" ]; then
|
|
||||||
if [ -f ../libtool ]; then
|
|
||||||
LIBTOOL=../libtool
|
|
||||||
else
|
|
||||||
LIBTOOL=libtool
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo_v "Running assert-msg-test"
|
|
||||||
OUT=$(./assert-msg-test 2>&1) && fail "assert-msg-test should abort"
|
|
||||||
echo "$OUT" | grep -q '^GLib:ERROR:.*assert-msg-test.c:.*:.*main.*: assertion failed: (42 < 0)' || \
|
|
||||||
fail "does not print assertion message"
|
|
||||||
|
|
||||||
if ! type gdb >/dev/null 2>&1; then
|
|
||||||
echo_v "Skipped (no gdb installed)"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo_v "Running gdb on assert-msg-test"
|
|
||||||
OUT=$($LIBTOOL --mode=execute gdb --batch -x "${srcdir:-.}/assert-msg-test.gdb" ./assert-msg-test 2> $error_out) || fail "failed to run gdb"
|
|
||||||
|
|
||||||
echo_v "Checking if assert message is in __glib_assert_msg"
|
|
||||||
# shellcheck disable=SC2016
|
|
||||||
if ! echo "$OUT" | grep -q '^$1.*"GLib:ERROR:.*assert-msg-test.c:.*:.*main.*: assertion failed: (42 < 0)"'; then
|
|
||||||
fail "__glib_assert_msg does not have assertion message"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo_v "All tests passed."
|
|
Loading…
Reference in New Issue
Block a user