1
0

Merge pull request #2231 from cuberite/SelfTestRegistering

SelfTests are registered and executed after logging framework init.
This commit is contained in:
Alexander Harkness 2015-06-12 11:00:47 +01:00
commit 001305247f
11 changed files with 198 additions and 33 deletions

View File

@ -5,6 +5,7 @@
#include "Globals.h" #include "Globals.h"
#include "BoundingBox.h" #include "BoundingBox.h"
#include "Defines.h" #include "Defines.h"
#include "SelfTests.h"
@ -17,6 +18,11 @@ static class SelfTest_BoundingBox
{ {
public: public:
SelfTest_BoundingBox(void) SelfTest_BoundingBox(void)
{
cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&Test), "Bounding box intersections");
}
static void Test(void)
{ {
Vector3d Min(1, 1, 1); Vector3d Min(1, 1, 1);
Vector3d Max(2, 2, 2); Vector3d Max(2, 2, 2);
@ -41,7 +47,7 @@ public:
bool res = cBoundingBox::CalcLineIntersection(Min, Max, Line1, Line2, LineCoeff, Face); bool res = cBoundingBox::CalcLineIntersection(Min, Max, Line1, Line2, LineCoeff, Face);
if (res != Results[i]) if (res != Results[i])
{ {
fprintf(stderr, "LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", LOGERROR("LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d",
Line1.x, Line1.y, Line1.z, Line1.x, Line1.y, Line1.z,
Line2.x, Line2.y, Line2.z, Line2.x, Line2.y, Line2.z,
res ? 1 : 0, LineCoeff, Face res ? 1 : 0, LineCoeff, Face
@ -52,7 +58,7 @@ public:
{ {
if (LineCoeff != LineCoeffs[i]) if (LineCoeff != LineCoeffs[i])
{ {
fprintf(stderr, "LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n", LOGERROR("LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d",
Line1.x, Line1.y, Line1.z, Line1.x, Line1.y, Line1.z,
Line2.x, Line2.y, Line2.z, Line2.x, Line2.y, Line2.z,
res ? 1 : 0, LineCoeff, Face res ? 1 : 0, LineCoeff, Face
@ -61,9 +67,8 @@ public:
} }
} }
} // for i - LineDefs[] } // for i - LineDefs[]
fprintf(stderr, "BoundingBox selftest complete.\n");
} }
} gTest; } g_BoundingBoxTest;
#endif #endif

View File

@ -8,6 +8,7 @@
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "Endianness.h" #include "Endianness.h"
#include "OSSupport/IsThread.h" #include "OSSupport/IsThread.h"
#include "SelfTests.h"
@ -55,18 +56,18 @@ Unfortunately it is very slow, so it is disabled even for regular DEBUG builds.
#ifdef SELF_TEST #ifdef SELF_TEST
/// Self-test of the VarInt-reading and writing code /** Self-test of the VarInt-reading and writing code */
static class cByteBufferSelfTest static class cByteBufferSelfTest
{ {
public: public:
cByteBufferSelfTest(void) cByteBufferSelfTest(void)
{ {
TestRead(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestRead), "ByteBuffer read");
TestWrite(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestWrite), "ByteBuffer write");
TestWrap(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestWrap), "ByteBuffer wraparound");
} }
void TestRead(void) static void TestRead(void)
{ {
cByteBuffer buf(50); cByteBuffer buf(50);
buf.Write("\x05\xac\x02\x00", 4); buf.Write("\x05\xac\x02\x00", 4);
@ -78,7 +79,7 @@ public:
assert_test(buf.ReadVarInt(v3) && (v3 == 0)); assert_test(buf.ReadVarInt(v3) && (v3 == 0));
} }
void TestWrite(void) static void TestWrite(void)
{ {
cByteBuffer buf(50); cByteBuffer buf(50);
buf.WriteVarInt32(5); buf.WriteVarInt32(5);
@ -90,7 +91,7 @@ public:
assert_test(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0); assert_test(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
} }
void TestWrap(void) static void TestWrap(void)
{ {
cByteBuffer buf(3); cByteBuffer buf(3);
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)

View File

@ -61,6 +61,7 @@ SET (SRCS
RCONServer.cpp RCONServer.cpp
Root.cpp Root.cpp
Scoreboard.cpp Scoreboard.cpp
SelfTests.cpp
Server.cpp Server.cpp
SetChunkData.cpp SetChunkData.cpp
SpawnPrepare.cpp SpawnPrepare.cpp
@ -134,6 +135,7 @@ SET (HDRS
RCONServer.h RCONServer.h
Root.h Root.h
Scoreboard.h Scoreboard.h
SelfTests.h
Server.h Server.h
SetChunkData.h SetChunkData.h
SettingsRepositoryInterface.h SettingsRepositoryInterface.h

View File

@ -6,6 +6,7 @@
#include "Globals.h" #include "Globals.h"
#include "CompositeChat.h" #include "CompositeChat.h"
#include "ClientHandle.h" #include "ClientHandle.h"
#include "SelfTests.h"
@ -19,16 +20,14 @@ class SelfTest_CompositeChat
public: public:
SelfTest_CompositeChat(void) SelfTest_CompositeChat(void)
{ {
fprintf(stderr, "cCompositeChat self test...\n"); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestParser1), "CompositeChat parser test 1");
TestParser1(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestParser2), "CompositeChat parser test 2");
TestParser2(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestParser3), "CompositeChat parser test 3");
TestParser3(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestParser4), "CompositeChat parser test 4");
TestParser4(); cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&TestParser5), "CompositeChat parser test 5");
TestParser5();
fprintf(stderr, "cCompositeChat self test finished.\n");
} }
void TestParser1(void) static void TestParser1(void)
{ {
cCompositeChat Msg; cCompositeChat Msg;
Msg.ParseText("Testing @2color codes and http://links parser"); Msg.ParseText("Testing @2color codes and http://links parser");
@ -44,7 +43,7 @@ public:
assert_test(Parts[3]->m_Style == "@2"); assert_test(Parts[3]->m_Style == "@2");
} }
void TestParser2(void) static void TestParser2(void)
{ {
cCompositeChat Msg; cCompositeChat Msg;
Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling"); Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling");
@ -60,7 +59,7 @@ public:
assert_test(Parts[3]->m_Style == "@5"); assert_test(Parts[3]->m_Style == "@5");
} }
void TestParser3(void) static void TestParser3(void)
{ {
cCompositeChat Msg; cCompositeChat Msg;
Msg.ParseText("http://links.starting the text"); Msg.ParseText("http://links.starting the text");
@ -72,7 +71,7 @@ public:
assert_test(Parts[1]->m_Style == ""); assert_test(Parts[1]->m_Style == "");
} }
void TestParser4(void) static void TestParser4(void)
{ {
cCompositeChat Msg; cCompositeChat Msg;
Msg.ParseText("links finishing the text: http://some.server"); Msg.ParseText("links finishing the text: http://some.server");
@ -84,7 +83,7 @@ public:
assert_test(Parts[1]->m_Style == ""); assert_test(Parts[1]->m_Style == "");
} }
void TestParser5(void) static void TestParser5(void)
{ {
cCompositeChat Msg; cCompositeChat Msg;
Msg.ParseText("http://only.links"); Msg.ParseText("http://only.links");

View File

@ -6,6 +6,7 @@
#include "Globals.h" #include "Globals.h"
#include "PieceGenerator.h" #include "PieceGenerator.h"
#include "../SelfTests.h"
@ -21,6 +22,11 @@ static class cPieceGeneratorSelfTest :
{ {
public: public:
cPieceGeneratorSelfTest(void) cPieceGeneratorSelfTest(void)
{
cSelfTests::Get().Register(std::bind(&cPieceGeneratorSelfTest::Test, this), "PieceGenerator");
}
void Test(void)
{ {
// Prepare the internal state: // Prepare the internal state:
InitializePieces(); InitializePieces();
@ -31,14 +37,14 @@ public:
Gen.PlacePieces(500, 50, 500, 3, OutPieces); Gen.PlacePieces(500, 50, 500, 3, OutPieces);
// Print out the pieces: // Print out the pieces:
printf("OutPieces.size() = " SIZE_T_FMT "\n", OutPieces.size()); LOG("OutPieces.size() = " SIZE_T_FMT, OutPieces.size());
size_t idx = 0; size_t idx = 0;
for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx) for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx)
{ {
const Vector3i & Coords = (*itr)->GetCoords(); const Vector3i & Coords = (*itr)->GetCoords();
cCuboid Hitbox = (*itr)->GetHitBox(); cCuboid Hitbox = (*itr)->GetHitBox();
Hitbox.Sort(); Hitbox.Sort();
printf(SIZE_T_FMT ": {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", idx, LOG(SIZE_T_FMT ": {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)", idx,
Coords.x, Coords.y, Coords.z, Coords.x, Coords.y, Coords.z,
(*itr)->GetNumCCWRotations(), (*itr)->GetNumCCWRotations(),
Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z, Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
@ -46,7 +52,7 @@ public:
Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1 Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
); );
} // itr - OutPieces[] } // itr - OutPieces[]
printf("Done.\n"); LOG("Done.");
// Free the placed pieces properly: // Free the placed pieces properly:
Gen.FreePieces(OutPieces); Gen.FreePieces(OutPieces);

View File

@ -6,6 +6,8 @@
#include "Globals.h" #include "Globals.h"
#include "Network.h" #include "Network.h"
#include "event2/util.h" #include "event2/util.h"
#include "../SelfTests.h"
#ifdef _WIN32 #ifdef _WIN32
#include <IPHlpApi.h> #include <IPHlpApi.h>
#pragma comment(lib, "IPHLPAPI.lib") #pragma comment(lib, "IPHLPAPI.lib")
@ -27,13 +29,18 @@ static class cEnumIPAddressTest
public: public:
cEnumIPAddressTest(void) cEnumIPAddressTest(void)
{ {
printf("Enumerating all IP addresses...\n"); cSelfTests::Get().Register(std::function<void(void)>(&Test), "Network IP enumeration");
}
static void Test(void)
{
LOG("Enumerating all IP addresses...");
auto IPs = cNetwork::EnumLocalIPAddresses(); auto IPs = cNetwork::EnumLocalIPAddresses();
for (auto & ip: IPs) for (auto & ip: IPs)
{ {
printf(" %s\n", ip.c_str()); LOG(" %s", ip.c_str());
} }
printf("Done.\n"); LOG("Done.");
} }
} g_EnumIPAddressTest; } g_EnumIPAddressTest;

View File

@ -21,6 +21,7 @@
#include "IniFile.h" #include "IniFile.h"
#include "SettingsRepositoryInterface.h" #include "SettingsRepositoryInterface.h"
#include "OverridesSettingsRepository.h" #include "OverridesSettingsRepository.h"
#include "SelfTests.h"
#ifdef _WIN32 #ifdef _WIN32
#include <conio.h> #include <conio.h>
@ -111,13 +112,18 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
cLogger::GetInstance().AttachListener(consoleLogListener); cLogger::GetInstance().AttachListener(consoleLogListener);
cLogger::GetInstance().AttachListener(fileLogListener); cLogger::GetInstance().AttachListener(fileLogListener);
LOG("--- Started Log ---\n"); LOG("--- Started Log ---");
#ifdef BUILD_ID #ifdef BUILD_ID
LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID); LOG("MCServer " BUILD_SERIES_NAME " build id: " BUILD_ID);
LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME); LOG("from commit id: " BUILD_COMMIT_ID " built at: " BUILD_DATETIME);
#endif #endif
// Run the self-tests registered previously via cSelfTests::Register():
#if SELF_TEST
cSelfTests::ExecuteAll();
#endif
cDeadlockDetect dd; cDeadlockDetect dd;
m_ShouldStop = false; m_ShouldStop = false;
@ -869,3 +875,8 @@ int cRoot::GetFurnaceFuelBurnTime(const cItem & a_Fuel)
cFurnaceRecipe * FR = Get()->GetFurnaceRecipe(); cFurnaceRecipe * FR = Get()->GetFurnaceRecipe();
return FR->GetBurnTime(a_Fuel); return FR->GetBurnTime(a_Fuel);
} }

View File

@ -38,7 +38,7 @@ namespace Json
/// The root of the object hierarchy /** The root of the object hierarchy */
// tolua_begin // tolua_begin
class cRoot class cRoot
{ {
@ -217,6 +217,7 @@ private:
bool m_bRestart; bool m_bRestart;
void LoadGlobalSettings(); void LoadGlobalSettings();
/// Loads the worlds from settings.ini, creates the worldmap /// Loads the worlds from settings.ini, creates the worldmap
@ -238,3 +239,8 @@ private:
static void InputThread(cRoot & a_Params); static void InputThread(cRoot & a_Params);
}; // tolua_export }; // tolua_export

71
src/SelfTests.cpp Normal file
View File

@ -0,0 +1,71 @@
// SelfTests.h
// Implements the cSelfTests class representing the singleton used for registering self-tests
// This class is only declared if SELF_TEST macro is defined.
#include "Globals.h"
#include "SelfTests.h"
#if SELF_TEST
cSelfTests::cSelfTests(void):
m_AllowRegistering(true)
{
}
cSelfTests & cSelfTests::Get(void)
{
static cSelfTests singleton;
return singleton;
}
void cSelfTests::Register(cSelfTests::SelfTestFunction a_FnToExecute, const AString & a_TestName)
{
ASSERT(Get().m_AllowRegistering);
Get().m_SelfTests.push_back(std::make_pair(a_FnToExecute, a_TestName));
}
void cSelfTests::ExecuteAll(void)
{
Get().m_AllowRegistering = false;
LOG("--- Performing self-tests ---");
for (auto & test: Get().m_SelfTests)
{
LOG("Performing self-test: %s", test.second.c_str());
try
{
test.first();
}
catch (const std::exception & exc)
{
LOGWARNING("Exception in test %s: %s", test.second.c_str(), exc.what());
}
catch (...)
{
LOGWARNING("Unknown exception in test %s", test.second.c_str());
}
} // for test - m_SelfTests[]
LOG("--- Self-tests finished ---");
}
#endif // SELF_TEST

51
src/SelfTests.h Normal file
View File

@ -0,0 +1,51 @@
// SelfTests.h
// Declares the cSelfTests class representing the singleton used for registering self-tests
// This class is only declared if SELF_TEST macro is defined.
#pragma once
#ifdef SELF_TEST
/** Singleton containing registered self-tests.
Used to schedule self-tests to run after the logging framework is initialized (#2228). */
class cSelfTests
{
public:
/** Returns the singleton instance of this class. */
static cSelfTests & Get(void);
// typedef void (* SelfTestFunction)(void);
typedef std::function<void(void)> SelfTestFunction;
/** Registers a self-test to be executed once the logging framework is initialized. */
static void Register(SelfTestFunction a_FnToExecute, const AString & a_TestName);
/** Executes all the registered self-tests. */
static void ExecuteAll(void);
protected:
typedef std::vector<std::pair<SelfTestFunction, AString>> SelfTestFunctions;
/** Functions (registered self-tests) to call once the logging framework is initialized. */
SelfTestFunctions m_SelfTests;
/** If true, tests may be registered. Set to false once the tests are executed, to detect tests that are registered too late. */
bool m_AllowRegistering;
cSelfTests(void);
};
#endif // SELF_TEST

View File

@ -9,6 +9,7 @@
#include "FastNBT.h" #include "FastNBT.h"
#include "SchematicFileSerializer.h" #include "SchematicFileSerializer.h"
#include "../StringCompression.h" #include "../StringCompression.h"
#include "../SelfTests.h"
@ -20,6 +21,11 @@ static class cSchematicStringSelfTest
{ {
public: public:
cSchematicStringSelfTest(void) cSchematicStringSelfTest(void)
{
cSelfTests::Get().Register(cSelfTests::SelfTestFunction(&Test), "Schematic-to-string serialization");
}
static void Test(void)
{ {
cBlockArea ba; cBlockArea ba;
ba.Create(21, 256, 21); ba.Create(21, 256, 21);