gdbsupport/selftest: Replace for_each_selftest with an iterator_range

Remove the callback-based selftests::for_each_selftest function and use
an iterator_range instead.

Also use this iterator range in run_tests so all iterations over the
selftests are done in a consistent way.  This will become useful in a
later commit.

Change-Id: I0b3a5349a7987fbcb0071f11c394e353df986583
This commit is contained in:
Lancelot SIX 2022-03-23 15:29:53 +00:00
parent 2aaee75f81
commit c57207c15c
3 changed files with 42 additions and 29 deletions

View file

@ -1181,11 +1181,11 @@ maintenance_selftest_completer (cmd_list_element *cmd,
return; return;
#if GDB_SELF_TEST #if GDB_SELF_TEST
selftests::for_each_selftest ([&tracker, text] (const std::string &name) for (const auto &test : selftests::all_selftests ())
{ {
if (startswith (name.c_str (), text)) if (startswith (test.name.c_str (), text))
tracker.add_completion (make_unique_xstrdup (name.c_str ())); tracker.add_completion (make_unique_xstrdup (test.name.c_str ()));
}); }
#endif #endif
} }
@ -1194,9 +1194,8 @@ maintenance_info_selftests (const char *arg, int from_tty)
{ {
#if GDB_SELF_TEST #if GDB_SELF_TEST
gdb_printf ("Registered selftests:\n"); gdb_printf ("Registered selftests:\n");
selftests::for_each_selftest ([] (const std::string &name) { for (const auto &test : selftests::all_selftests ())
gdb_printf (" - %s\n", name.c_str ()); gdb_printf (" - %s\n", test.name.c_str ());
});
#else #else
gdb_printf (_("\ gdb_printf (_("\
Selftests have been disabled for this build.\n")); Selftests have been disabled for this build.\n"));

View file

@ -20,16 +20,15 @@
#include "common-exceptions.h" #include "common-exceptions.h"
#include "common-debug.h" #include "common-debug.h"
#include "selftest.h" #include "selftest.h"
#include <map>
#include <functional> #include <functional>
namespace selftests namespace selftests
{ {
/* All the tests that have been registered. Using an std::map allows keeping /* All the tests that have been registered. Using an std::set allows keeping
the order of tests stable and easily looking up whether a test name the order of tests stable and easily looking up whether a test name
exists. */ exists. */
static std::map<std::string, std::function<void(void)>> tests; static selftests_registry tests;
/* See selftest.h. */ /* See selftest.h. */
@ -38,9 +37,9 @@ register_test (const std::string &name,
std::function<void(void)> function) std::function<void(void)> function)
{ {
/* Check that no test with this name already exist. */ /* Check that no test with this name already exist. */
gdb_assert (tests.find (name) == tests.end ()); auto status = tests.emplace (name, std::move (function));
if (!status.second)
tests[name] = function; gdb_assert_not_reached ("Test already registered");
} }
/* See selftest.h. */ /* See selftest.h. */
@ -63,10 +62,8 @@ run_tests (gdb::array_view<const char *const> filters, bool verbose)
int ran = 0, failed = 0; int ran = 0, failed = 0;
run_verbose_ = verbose; run_verbose_ = verbose;
for (const auto &pair : tests) for (const auto &test : all_selftests ())
{ {
const std::string &name = pair.first;
const auto &test = pair.second;
bool run = false; bool run = false;
if (filters.empty ()) if (filters.empty ())
@ -75,7 +72,7 @@ run_tests (gdb::array_view<const char *const> filters, bool verbose)
{ {
for (const char *filter : filters) for (const char *filter : filters)
{ {
if (name.find (filter) != std::string::npos) if (test.name.find (filter) != std::string::npos)
run = true; run = true;
} }
} }
@ -85,9 +82,9 @@ run_tests (gdb::array_view<const char *const> filters, bool verbose)
try try
{ {
debug_printf (_("Running selftest %s.\n"), name.c_str ()); debug_printf (_("Running selftest %s.\n"), test.name.c_str ());
++ran; ++ran;
test (); test.test ();
} }
catch (const gdb_exception_error &ex) catch (const gdb_exception_error &ex)
{ {
@ -104,10 +101,10 @@ run_tests (gdb::array_view<const char *const> filters, bool verbose)
/* See selftest.h. */ /* See selftest.h. */
void for_each_selftest (for_each_selftest_ftype func) selftests_range
all_selftests ()
{ {
for (const auto &pair : tests) return selftests_range (tests.cbegin (), tests.cend ());
func (pair.first);
} }
} // namespace selftests } // namespace selftests

View file

@ -21,6 +21,8 @@
#include "gdbsupport/array-view.h" #include "gdbsupport/array-view.h"
#include "gdbsupport/function-view.h" #include "gdbsupport/function-view.h"
#include "gdbsupport/iterator-range.h"
#include <set>
/* A test is just a function that does some checks and throws an /* A test is just a function that does some checks and throws an
exception if something has gone wrong. */ exception if something has gone wrong. */
@ -28,6 +30,28 @@
namespace selftests namespace selftests
{ {
/* Selftests are registered under a unique name. */
struct selftest
{
selftest (std::string name, std::function<void (void)> test)
: name { std::move (name) }, test { std::move (test) }
{ }
bool operator< (const selftest &rhs) const
{ return name < rhs.name; }
std::string name;
std::function<void (void)> test;
};
/* Type of the container of all the registered selftests. */
using selftests_registry = std::set<selftest>;
using selftests_range = iterator_range<selftests_registry::const_iterator>;
/* Create a range to iterate over all registered tests. */
selftests_range all_selftests ();
/* True if selftest should run verbosely. */ /* True if selftest should run verbosely. */
extern bool run_verbose (); extern bool run_verbose ();
@ -48,13 +72,6 @@ extern void run_tests (gdb::array_view<const char *const> filters,
/* Reset GDB or GDBserver's internal state. */ /* Reset GDB or GDBserver's internal state. */
extern void reset (); extern void reset ();
using for_each_selftest_ftype
= gdb::function_view<void(const std::string &name)>;
/* Call FUNC for each registered selftest. */
extern void for_each_selftest (for_each_selftest_ftype func);
} }
/* Check that VALUE is true, and, if not, throw an exception. */ /* Check that VALUE is true, and, if not, throw an exception. */