Add self-test framework to gdb

I wanted to unit test the Rust lexer, so I added a simple unit testing
command to gdb.

The intent is that self tests will only be compiled into gdb in
development mode.  In release mode they simply won't exist.  So, this
exposes $development to C code as GDB_SELF_TEST.

In development mode, test functions are registered with the self test
module.  A test function is just a function that does some checks, and
throws an exception on failure.

Then this adds a new "maint selftest" command which invokes the test
functions, and a new dejagnu test case that invokes it.

2016-05-17  Tom Tromey  <tom@tromey.com>

	* NEWS: Add "maint selftest" entry.
	* selftest.h: New file.
	* selftest.c: New file.
	* maint.c: Include selftest.h.
	(maintenance_selftest): New function.
	(_initialize_maint_cmds): Add "maint selftest" command.
	* configure.ac (GDB_SELF_TEST): Maybe define.
	* config.in, configure: Rebuild.
	* Makefile.in (SFILES): Add selftest.c.
	(COMMON_OBS): Add selftest.o.

2016-05-17  Tom Tromey  <tom@tromey.com>

	* gdb.texinfo (Maintenance Commands): Document "maint selftest".

2016-05-17  Tom Tromey  <tom@tromey.com>

	* gdb.gdb/unittest.exp: New file.
This commit is contained in:
Tom Tromey 2016-04-20 10:09:53 -06:00
parent e4b8a1c839
commit dcd1f97951
13 changed files with 191 additions and 2 deletions

View File

@ -1,3 +1,16 @@
2016-05-17 Tom Tromey <tom@tromey.com>
* NEWS: Add "maint selftest" entry.
* selftest.h: New file.
* selftest.c: New file.
* maint.c: Include selftest.h.
(maintenance_selftest): New function.
(_initialize_maint_cmds): Add "maint selftest" command.
* configure.ac (GDB_SELF_TEST): Maybe define.
* config.in, configure: Rebuild.
* Makefile.in (SFILES): Add selftest.c.
(COMMON_OBS): Add selftest.o.
2016-05-17 Tom Tromey <tom@tromey.com>
* expprint.c: Include f-lang.h.

View File

@ -869,7 +869,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
proc-service.list progspace.c \
prologue-value.c psymtab.c \
regcache.c reggroups.c remote.c remote-fileio.c remote-notif.c reverse.c \
sentinel-frame.c \
selftest.c sentinel-frame.c \
serial.c ser-base.c ser-unix.c ser-event.c skip.c \
solib.c solib-target.c source.c \
stabsread.c stack.c probe.c stap-probe.c std-regs.c \
@ -1060,7 +1060,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
go-lang.o go-valprint.o go-typeprint.o \
jv-lang.o jv-valprint.o jv-typeprint.o jv-varobj.o \
m2-lang.o opencl-lang.o p-lang.o p-typeprint.o p-valprint.o \
sentinel-frame.o \
selftest.o sentinel-frame.o \
complaints.o typeprint.o \
ada-typeprint.o c-typeprint.o f-typeprint.o m2-typeprint.o \
ada-valprint.o c-valprint.o cp-valprint.o d-valprint.o f-valprint.o \

View File

@ -40,6 +40,9 @@ skip -rfunction regular-expression
maint info line-table REGEXP
Display the contents of GDB's internal line table data struture.
maint selftest
Run any GDB unit tests that were compiled in.
* Support for tracepoints and fast tracepoints on s390-linux and s390x-linux
was added in GDBserver, including JIT compiling fast tracepoint's
conditional expression bytecode into native code.

View File

@ -65,6 +65,9 @@
/* Define to the default OS ABI for this configuration. */
#undef GDB_OSABI_DEFAULT
/* Define if self-testing features should be enabled */
#undef GDB_SELF_TEST
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA

6
gdb/configure vendored
View File

@ -16500,6 +16500,12 @@ ac_config_links="$ac_config_links $ac_config_links_1"
$as_echo "#define GDB_DEFAULT_HOST_CHARSET \"UTF-8\"" >>confdefs.h
if $development; then
$as_echo "#define GDB_SELF_TEST 1" >>confdefs.h
fi
gdb_ac_transform=`echo "$program_transform_name" | sed -e 's/\\$\\$/\\$/g'`
GDB_TRANSFORM_NAME=`echo gdb | sed -e "$gdb_ac_transform"`

View File

@ -2348,6 +2348,11 @@ dnl At the moment, we just assume it's UTF-8.
AC_DEFINE(GDB_DEFAULT_HOST_CHARSET, "UTF-8",
[Define to be a string naming the default host character set.])
if $development; then
AC_DEFINE(GDB_SELF_TEST, 1,
[Define if self-testing features should be enabled])
fi
GDB_AC_TRANSFORM([gdb], [GDB_TRANSFORM_NAME])
GDB_AC_TRANSFORM([gcore], [GCORE_TRANSFORM_NAME])
AC_CONFIG_FILES([gcore], [chmod +x gcore])

View File

@ -1,3 +1,7 @@
2016-05-17 Tom Tromey <tom@tromey.com>
* gdb.texinfo (Maintenance Commands): Document "maint selftest".
2016-04-27 Yao Qi <yao.qi@linaro.org>
* gdb.texinfo (tfind): Complete doc about tfind without

View File

@ -34451,6 +34451,11 @@ that symbol is described. The type chain produced by this command is
a recursive definition of the data type as stored in @value{GDBN}'s
data structures, including its flags and contained types.
@kindex maint selftest
@cindex self tests
Run any self tests that were compiled in to @value{GDBN}. This will
print a message showing how many tests were run, and how many failed.
@kindex maint set dwarf always-disassemble
@kindex maint show dwarf always-disassemble
@item maint set dwarf always-disassemble

View File

@ -41,6 +41,7 @@
#include "top.h"
#include "timeval-utils.h"
#include "maint.h"
#include "selftest.h"
#include "cli/cli-decode.h"
#include "cli/cli-utils.h"
@ -980,6 +981,16 @@ show_per_command_cmd (char *args, int from_tty)
{
cmd_show_list (per_command_showlist, from_tty, "");
}
/* The "maintenance selftest" command. */
static void
maintenance_selftest (char *args, int from_tty)
{
run_self_tests ();
}
void
_initialize_maint_cmds (void)
@ -1153,6 +1164,13 @@ testsuite can check the command deprecator. You probably shouldn't use this,\n\
If you decide you want to use it: maintenance undeprecate 'commandname'"),
&maintenancelist);
add_cmd ("selftest", class_maintenance, maintenance_selftest, _("\
Run gdb's unit tests.\n\
Usage: maintenance selftest\n\
This will run any unit tests that were built in to gdb.\n\
gdb will abort if any test fails."),
&maintenancelist);
add_setshow_zinteger_cmd ("watchdog", class_maintenance, &watchdog, _("\
Set watchdog timer."), _("\
Show watchdog timer."), _("\

67
gdb/selftest.c Normal file
View File

@ -0,0 +1,67 @@
/* GDB self-testing.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "selftest.h"
#include "vec.h"
typedef self_test_function *self_test_function_ptr;
DEF_VEC_P (self_test_function_ptr);
/* All the tests that have been registered. */
static VEC (self_test_function_ptr) *tests;
/* See selftest.h. */
void
register_self_test (self_test_function *function)
{
VEC_safe_push (self_test_function_ptr, tests, function);
}
/* See selftest.h. */
void
run_self_tests (void)
{
int i;
self_test_function_ptr func;
int failed = 0;
for (i = 0; VEC_iterate (self_test_function_ptr, tests, i, func); ++i)
{
QUIT;
TRY
{
(*func) ();
}
CATCH (ex, RETURN_MASK_ERROR)
{
++failed;
exception_fprintf (gdb_stderr, ex,
_("Self test threw exception"));
}
END_CATCH
}
printf_filtered (_("Ran %u unit tests, %d failed\n"),
VEC_length (self_test_function_ptr, tests), failed);
}

44
gdb/selftest.h Normal file
View File

@ -0,0 +1,44 @@
/* GDB self-testing.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef SELFTEST_H
#define SELFTEST_H
/* A test is just a function that does some checks and throws an
exception if something has gone wrong. */
typedef void self_test_function (void);
/* Register a new self-test. */
extern void register_self_test (self_test_function *function);
/* Run all the self tests. This print a message describing the number
of test and the number of failures. */
extern void run_self_tests (void);
/* Check that VALUE is true, and, if not, throw an exception. */
#define SELF_CHECK(VALUE) \
do { \
if (!(VALUE)) \
error (_("self-test failed at %s:%d"), __FILE__, __LINE__); \
} while (0)
#endif /* SELFTEST_H */

View File

@ -1,3 +1,7 @@
2016-05-17 Tom Tromey <tom@tromey.com>
* gdb.gdb/unittest.exp: New file.
2016-05-16 Yao Qi <yao.qi@linaro.org>
* gdb.base/batch-preserve-term-settings.exp: Remove variable

View File

@ -0,0 +1,17 @@
# Copyright 2016 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
gdb_start
gdb_test "maintenance selftest" "Ran $decimal unit tests, 0 failed"