Consolidate unit testing code
This commit is contained in:
167
luprex/cpp/core/unit-testing.cpp
Normal file
167
luprex/cpp/core/unit-testing.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "wrap-string.hpp"
|
||||
|
||||
#include "drivenengine.hpp"
|
||||
#include "streambuffer.hpp"
|
||||
#include "world.hpp"
|
||||
#include "traceback.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
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<eng::string> 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");
|
||||
}
|
||||
|
||||
static void dump_lines(StreamBuffer *in, int chid) {
|
||||
while (true) {
|
||||
eng::string l = in->readline();
|
||||
if (l == "") break;
|
||||
util::dprint("Chan ", chid, ": ", l);
|
||||
}
|
||||
}
|
||||
|
||||
// This test connects to a public webserver and prints
|
||||
// the output from the server.
|
||||
class DriverWebServerTest : public DrivenEngine {
|
||||
public:
|
||||
eng::vector<SharedChannel> channels_;
|
||||
DriverWebServerTest(EngineWrapper *) {
|
||||
SharedChannel ch = new_outgoing_channel("cert:stanford.edu:443");
|
||||
ch->out()->write_bytes("GET https://stanford.edu/xbanankjdsh.html HTTP/1.1\n\n");
|
||||
channels_.emplace_back(std::move(ch));
|
||||
}
|
||||
|
||||
virtual void event_update() override {
|
||||
eng::vector<SharedChannel> keep;
|
||||
for (SharedChannel &ch : channels_) {
|
||||
dump_lines(ch->in(), ch->chid());
|
||||
if (ch->closed()) {
|
||||
write_closed_message(ch.get());
|
||||
} else {
|
||||
keep.emplace_back(std::move(ch));
|
||||
}
|
||||
}
|
||||
channels_ = std::move(keep);
|
||||
}
|
||||
};
|
||||
|
||||
// This test produces a DNS resolution failure.
|
||||
class DriverDNSFailTest : public DrivenEngine {
|
||||
public:
|
||||
eng::vector<SharedChannel> channels_;
|
||||
DriverDNSFailTest(EngineWrapper *) {
|
||||
SharedChannel ch = new_outgoing_channel("akjsdkajshdakjshd.alk:80");
|
||||
ch->out()->write_bytes("GET http://stanford.edu/index.html HTTP/1.1\n\n");
|
||||
channels_.emplace_back(std::move(ch));
|
||||
}
|
||||
|
||||
virtual void event_update() override {
|
||||
eng::vector<SharedChannel> keep;
|
||||
for (SharedChannel &ch : channels_) {
|
||||
dump_lines(ch->in(), ch->chid());
|
||||
if (ch->closed()) {
|
||||
write_closed_message(ch.get());
|
||||
} else {
|
||||
keep.emplace_back(std::move(ch));
|
||||
}
|
||||
}
|
||||
channels_ = std::move(keep);
|
||||
}
|
||||
};
|
||||
|
||||
// This test just prints the time.
|
||||
class DriverPrintClockTest : public DrivenEngine {
|
||||
public:
|
||||
int count_;
|
||||
double last_clock_;
|
||||
DriverPrintClockTest(EngineWrapper *) {
|
||||
count_ = 0;
|
||||
last_clock_ = 0.0;
|
||||
}
|
||||
|
||||
virtual void event_update() override {
|
||||
double clock = get_clock();
|
||||
if (clock > last_clock_ + 0.5) {
|
||||
int ms = eng::memhash();
|
||||
util::dprint(std::fixed, std::setprecision(2), clock, " ", std::hex, ms);
|
||||
count_++;
|
||||
last_clock_ = clock;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DrivenEngineDefine("driverwebservertest", DriverWebServerTest);
|
||||
DrivenEngineDefine("driverdnsfailtest", DriverDNSFailTest);
|
||||
DrivenEngineDefine("driverprintclocktest", DriverPrintClockTest);
|
||||
DrivenEngineDefine("rununittests", RunUnitTests);
|
||||
|
||||
Reference in New Issue
Block a user