From 2c2d4e44bbf0f688a52fa182a34cb7a7db27ced6 Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 24 Feb 2026 23:15:02 -0500 Subject: [PATCH] Consolidate unit testing code --- Docs/Module-Dependencies-in-Luprex.md | 3 - luprex/Makefile | 4 +- luprex/cpp/core/eng-tests.hpp | 5 - luprex/cpp/core/source.cpp | 37 -------- luprex/cpp/core/source.hpp | 7 -- .../core/{eng-tests.cpp => unit-testing.cpp} | 95 ++++++++++++++----- luprex/cpp/core/unit-testing.hpp | 1 + luprex/cpp/core/world-core.cpp | 6 -- luprex/cpp/core/world.hpp | 4 - luprex/{cpp/core => ext}/bytell-hash-map.hpp | 0 luprex/{cpp/core => ext}/fast-float.hpp | 0 luprex/{cpp/core => ext}/flat-hash-map.hpp | 0 12 files changed, 74 insertions(+), 88 deletions(-) delete mode 100644 luprex/cpp/core/eng-tests.hpp rename luprex/cpp/core/{eng-tests.cpp => unit-testing.cpp} (72%) create mode 100644 luprex/cpp/core/unit-testing.hpp rename luprex/{cpp/core => ext}/bytell-hash-map.hpp (100%) rename luprex/{cpp/core => ext}/fast-float.hpp (100%) rename luprex/{cpp/core => ext}/flat-hash-map.hpp (100%) diff --git a/Docs/Module-Dependencies-in-Luprex.md b/Docs/Module-Dependencies-in-Luprex.md index 286135c3..e9554f85 100644 --- a/Docs/Module-Dependencies-in-Luprex.md +++ b/Docs/Module-Dependencies-in-Luprex.md @@ -4,11 +4,8 @@ Modules are listed in dependency order — each module's dependencies all appear earlier in the list. Where a dependency comes only from the `.cpp` file (not the `.hpp`), it is marked **(cpp-only)**. -- **bytell-hash-map** — third-party hash map (header-only) - **eng-malloc** — custom deterministic memory allocator - **enginewrapper** — pure C interface for driver/driven boundary -- **fast-float** — third-party float parser (header-only) -- **flat-hash-map** — third-party hash map (header-only) - **spookyv2** — hash function - **util** → spookyv2 - **luastack** → util diff --git a/luprex/Makefile b/luprex/Makefile index 79713c7a..3112eee8 100644 --- a/luprex/Makefile +++ b/luprex/Makefile @@ -29,7 +29,7 @@ ifeq "$(OS)" "Linux" LUPREX_EXE:=luprex LUPREXLIB_DLL:=luprexlib.so LUPREXSTATIC_EXE:=luprexstatic - COMPILE:=g++ -Wall $(OPT) -std=c++20 -fvisibility=hidden -c -MMD -fPIC -o + COMPILE:=g++ -Wall $(OPT) -std=c++20 -fvisibility=hidden -c -MMD -MP -fPIC -o LINKDLL:=g++ -Wall $(OPT) -std=c++20 -export-dynamic -Wl,--no-allow-shlib-undefined -Wl,-z,defs -shared -o LINKEXE:=g++ -Wall $(OPT) -std=c++20 -export-dynamic -o MAKEDEPS:=true @@ -84,7 +84,7 @@ BASE_CORE := \ traceback planemap pprint luavector idalloc sched http \ json table luasnap animqueue streambuffer source world-core world-accessor \ world-difftab world-diffxmit world-pairtab world-testing lpxserver lpxclient \ - eng-tests printbuffer serializelua + unit-testing printbuffer serializelua BASE_DRV := driver drvutil sslutil readline diff --git a/luprex/cpp/core/eng-tests.hpp b/luprex/cpp/core/eng-tests.hpp deleted file mode 100644 index 4d1945e5..00000000 --- a/luprex/cpp/core/eng-tests.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef DRIVERTESTS_HPP -#define DRIVERTESTS_HPP - -#endif // DRIVERTESTS_HPP - diff --git a/luprex/cpp/core/source.cpp b/luprex/cpp/core/source.cpp index 69fab08e..5d6b35f7 100644 --- a/luprex/cpp/core/source.cpp +++ b/luprex/cpp/core/source.cpp @@ -433,43 +433,6 @@ eng::string SourceDB::rebuild_module(const eng::string &mod) { } } -void SourceDB::run_unittests() { - lua_State *L = lua_state_; - LuaVar unittests, name, func, err, globtab; - LuaExtStack LS(L, unittests, name, func, err, globtab); - - LS.getglobaltable(globtab); - LS.rawget(unittests, globtab, "unittests"); - - // Sort the unit test names. - eng::set names; - LS.set(name, LuaNil); - while (LS.next(unittests, name, func) != 0) { - if (LS.isfunction(func) && LS.isstring(name)) { - names.insert(LS.ckstring(name)); - } - } - - // Run the functions in order - bool any = false; - for (const eng::string &name : names) { - util::dprint("Running unittests: ", name); - LS.rawget(func, unittests, name); - - lua_pushvalue(L, func.index()); - eng::string msg = traceback_pcall(L, 0, 0); - if (!msg.empty()) { - LS.set(err, msg); - util::dprint(msg); - any = true; - } - } - - if (any) { - exit(1); - } -} - void SourceDB::init(lua_State *L) { lua_state_ = L; LuaVar globtab, persist, unpersist, classname, classtab, funcname, funcp, rawfunc, nullstring; diff --git a/luprex/cpp/core/source.hpp b/luprex/cpp/core/source.hpp index b21f0ab6..fed584f1 100644 --- a/luprex/cpp/core/source.hpp +++ b/luprex/cpp/core/source.hpp @@ -181,13 +181,6 @@ public: void diff(const SourceDB &auth, StreamBuffer *sb); bool patch(StreamBuffer *sb, DebugCollector *dbc); - // run_unittests - // - // Run all the lua unit tests. Print any errors to console. If there - // are any errors, exits the program. - // - void run_unittests(); - // Get/Set code (for unit testing). // // These functions are direct getters/setters for values in the source diff --git a/luprex/cpp/core/eng-tests.cpp b/luprex/cpp/core/unit-testing.cpp similarity index 72% rename from luprex/cpp/core/eng-tests.cpp rename to luprex/cpp/core/unit-testing.cpp index 4f9ab0bf..6c8014cf 100644 --- a/luprex/cpp/core/eng-tests.cpp +++ b/luprex/cpp/core/unit-testing.cpp @@ -3,9 +3,80 @@ #include "drivenengine.hpp" #include "streambuffer.hpp" #include "world.hpp" +#include "traceback.hpp" #include +static void run_unittests(lua_State *L) { + LuaVar unittests, name, func, err, globtab; + LuaExtStack LS(L, unittests, name, func, err, globtab); + + LS.getglobaltable(globtab); + LS.rawget(unittests, globtab, "unittests"); + + // Sort the unit test names. + eng::set names; + LS.set(name, LuaNil); + while (LS.next(unittests, name, func) != 0) { + if (LS.isfunction(func) && LS.isstring(name)) { + names.insert(LS.ckstring(name)); + } + } + + // Run the functions in order + bool any = false; + for (const eng::string &name : names) { + util::dprint("Running unittests: ", name); + LS.rawget(func, unittests, name); + + lua_pushvalue(L, func.index()); + eng::string msg = traceback_pcall(L, 0, 0); + if (!msg.empty()) { + LS.set(err, msg); + util::dprint(msg); + any = true; + } + } + + if (any) { + exit(1); + } +} + +class RunUnitTests : public DrivenEngine { +public: + UniqueWorld world_; + + RunUnitTests(EngineWrapper *) { + world_.reset(new World(WORLD_TYPE_MASTER)); + rescan_lua_source(true); + } + + virtual void event_access(AccessKind kind, int64_t place_id, std::string_view datapk, StreamBuffer *retpk) override { + switch (kind) { + case AccessKind::INVOKE_LUA_SOURCE: { + world_->update_source(datapk); + run_unittests(world_->state()); + stop_driver(); + break; + } + default: break; + } + } + + void event_update() override {} +}; + +//////////////////////////////////////////////////////////// +// +// Driver tests. +// +// These tests can't go through the unit testing framework, +// because they're tests of the driver-engine interface +// and the driver. +// +//////////////////////////////////////////////////////////// + static void write_closed_message(Channel *ch) { util::dprint("Chan ", ch->chid(), " closed [", ch->error(), "]\n"); } @@ -89,30 +160,6 @@ public: }; -class RunUnitTests : public DrivenEngine { -public: - UniqueWorld world_; - - RunUnitTests(EngineWrapper *) { - world_.reset(new World(WORLD_TYPE_MASTER)); - rescan_lua_source(true); - } - - virtual void event_access(AccessKind kind, int64_t place_id, std::string_view datapk, StreamBuffer *retpk) override { - switch (kind) { - case AccessKind::INVOKE_LUA_SOURCE: { - world_->update_source(datapk); - world_->run_unittests(); - stop_driver(); - break; - } - default: break; - } - } - - void event_update() override {} -}; - DrivenEngineDefine("driverwebservertest", DriverWebServerTest); DrivenEngineDefine("driverdnsfailtest", DriverDNSFailTest); DrivenEngineDefine("driverprintclocktest", DriverPrintClockTest); diff --git a/luprex/cpp/core/unit-testing.hpp b/luprex/cpp/core/unit-testing.hpp new file mode 100644 index 00000000..6f70f09b --- /dev/null +++ b/luprex/cpp/core/unit-testing.hpp @@ -0,0 +1 @@ +#pragma once diff --git a/luprex/cpp/core/world-core.cpp b/luprex/cpp/core/world-core.cpp index 876fbec9..fabd02cd 100644 --- a/luprex/cpp/core/world-core.cpp +++ b/luprex/cpp/core/world-core.cpp @@ -713,12 +713,6 @@ HttpServerResponse World::http_serve(const HttpParser &request) { return response; } -void World::run_unittests() { - assert(stack_is_clear()); - source_db_.run_unittests(); - assert(stack_is_clear()); -} - void World::invoke(const Invocation &inv) { switch (inv.kind()) { case AccessKind::INVOKE_LUA_CALL: diff --git a/luprex/cpp/core/world.hpp b/luprex/cpp/core/world.hpp index 20605521..791c7a12 100644 --- a/luprex/cpp/core/world.hpp +++ b/luprex/cpp/core/world.hpp @@ -317,10 +317,6 @@ public: // HttpServerResponse http_serve(const HttpParser &request); - // Run all unit tests. - // - void run_unittests(); - // Install this world into an EngineWrapper's function pointers. // void expose_world_to_driver(EngineWrapper *w); diff --git a/luprex/cpp/core/bytell-hash-map.hpp b/luprex/ext/bytell-hash-map.hpp similarity index 100% rename from luprex/cpp/core/bytell-hash-map.hpp rename to luprex/ext/bytell-hash-map.hpp diff --git a/luprex/cpp/core/fast-float.hpp b/luprex/ext/fast-float.hpp similarity index 100% rename from luprex/cpp/core/fast-float.hpp rename to luprex/ext/fast-float.hpp diff --git a/luprex/cpp/core/flat-hash-map.hpp b/luprex/ext/flat-hash-map.hpp similarity index 100% rename from luprex/cpp/core/flat-hash-map.hpp rename to luprex/ext/flat-hash-map.hpp