mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +01:00
Merge branch 'move_assert-msg-test' into 'main'
Convert tests/assert-msg-test* to glib/tests/assert-msg-test* Closes #1434 See merge request GNOME/glib!2767
This commit is contained in:
commit
bd56345f23
@ -25,9 +25,9 @@ for filename in in_files:
|
||||
with open(filename, "rb") as f:
|
||||
for line in f:
|
||||
line = line.rstrip(b"\n").rstrip(b"\r")
|
||||
match = re.search(br"\bg_[a-zA-Z0-9_]*_get_type\b", line)
|
||||
match = re.search(rb"\bg_[a-zA-Z0-9_]*_get_type\b", line)
|
||||
if match:
|
||||
func = match.group(0).decode('utf-8')
|
||||
func = match.group(0).decode("utf-8")
|
||||
if func not in funcs:
|
||||
funcs.append(func)
|
||||
if debug:
|
||||
|
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
|
||||
|
||||
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,
|
||||
|
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
|
@ -25,7 +25,6 @@ import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from textwrap import dedent
|
||||
import unittest
|
||||
|
||||
import taptestrunner
|
||||
|
@ -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)
|
||||
|
@ -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