Use UnitTest-Cpp library for testing

This commit is contained in:
Ilusha 2024-03-15 16:03:33 +03:00
parent ecaa2bbdfb
commit 00d8fa0886
53 changed files with 1046 additions and 1383 deletions

6
.gitmodules vendored
View file

@ -13,9 +13,9 @@
[submodule "Externals/nanovg"] [submodule "Externals/nanovg"]
path = Externals/nanovg path = Externals/nanovg
url = https://github.com/elushaX/nanovg.git url = https://github.com/elushaX/nanovg.git
[submodule "Externals/asio"]
path = Externals/asio
url = https://github.com/elushaX/asio.git
[submodule "Externals/lalr"] [submodule "Externals/lalr"]
path = Externals/lalr path = Externals/lalr
url = https://github.com/elushaX/lalr.git url = https://github.com/elushaX/lalr.git
[submodule "Externals/asio"]
path = Externals/asio
url = https://github.com/elushaX/asio.git

View file

@ -11,5 +11,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -13,7 +13,10 @@ using namespace tp;
// ----------------------- Release Implementation ---------------------------- // // ----------------------- Release Implementation ---------------------------- //
void* HeapAlloc::allocate(ualni aBlockSize) { return malloc(aBlockSize); } void* HeapAlloc::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
void HeapAlloc::deallocate(void* aPtr) { free(aPtr); } void HeapAlloc::deallocate(void* aPtr) {
if (!aPtr) return;
free(aPtr);
}
HeapAlloc::~HeapAlloc() {} HeapAlloc::~HeapAlloc() {}
#else #else
@ -45,6 +48,8 @@ void* HeapAlloc::allocate(ualni aBlockSize) {
} }
void HeapAlloc::deallocate(void* aPtr) { void HeapAlloc::deallocate(void* aPtr) {
if (!aPtr) return;
auto head = ((MemHeadLocal*) (aPtr)) - 1; auto head = ((MemHeadLocal*) (aPtr)) - 1;
mNumAllocations--; mNumAllocations--;
@ -60,7 +65,7 @@ void HeapAlloc::deallocate(void* aPtr) {
HeapAlloc::~HeapAlloc() { HeapAlloc::~HeapAlloc() {
if (mNumAllocations) { if (mNumAllocations) {
DEBUG_BREAK("Destruction of not freed Allocator") DEBUG_ASSERT(0 && "Destruction of not freed Allocator")
#ifdef MEM_STACK_TRACE #ifdef MEM_STACK_TRACE
// TODO : log leaks and free them up // TODO : log leaks and free them up

View file

@ -16,7 +16,10 @@ using namespace tp;
// ----------------------- Release Implementation ---------------------------- // // ----------------------- Release Implementation ---------------------------- //
void* HeapAllocGlobal::allocate(ualni aBlockSize) { return malloc(aBlockSize); } void* HeapAllocGlobal::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
void HeapAllocGlobal::deallocate(void* aPtr) { free(aPtr); } void HeapAllocGlobal::deallocate(void* aPtr) {
if (!aPtr) return;
free(aPtr);
}
HeapAllocGlobal::~HeapAllocGlobal() = default; HeapAllocGlobal::~HeapAllocGlobal() = default;
bool HeapAllocGlobal::checkLeaks() { return false; } bool HeapAllocGlobal::checkLeaks() { return false; }
void HeapAllocGlobal::startIgnore() {} void HeapAllocGlobal::startIgnore() {}

View file

@ -132,6 +132,7 @@ namespace tp {
} }
void deallocate(void* aPtr) { void deallocate(void* aPtr) {
if (!aPtr) return;
auto chunk = mChunks.find(aPtr); auto chunk = mChunks.find(aPtr);
(*chunk)->deallocate(aPtr); (*chunk)->deallocate(aPtr);
if ((*chunk)->isEmpty()) { if ((*chunk)->isEmpty()) {

View file

@ -1,12 +1,9 @@
#include "Testing.hpp" #include "UnitTest++/UnitTest++.h"
#include "Allocators.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "ChunkAllocator.hpp"
#include "HeapAllocator.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "PoolAllocator.hpp"
#include <cmath> #include <cmath>
using namespace tp; using namespace tp;
@ -80,7 +77,7 @@ private:
if (mIsLoaded[idx]) return; if (mIsLoaded[idx]) return;
verifyIntegrity(); verifyIntegrity();
mLoaded[idx] = new (mAlloc.allocate(sizeof(TestStruct))) TestStruct(mData[idx]); mLoaded[idx] = new (mAlloc.allocate(sizeof(TestStruct))) TestStruct(mData[idx]);
TEST(mLoaded[idx]); ASSERT(mLoaded[idx]);
mIsLoaded[idx] = true; mIsLoaded[idx] = true;
mLoadedNum++; mLoadedNum++;
verifyIntegrity(); verifyIntegrity();
@ -181,7 +178,7 @@ private:
uint1 val = *address; uint1 val = *address;
*address = 5; *address = 5;
TEST(!mAlloc.checkWrap()); ASSERT(!mAlloc.checkWrap());
*address = val; *address = val;
} }
@ -208,38 +205,45 @@ void testAlloc() {
TestBenches<size, Alloc> heapTests{}; TestBenches<size, Alloc> heapTests{};
heapTests.runTests(); heapTests.runTests();
} catch (...) { } catch (...) {
TEST(false); ASSERT(false);
} }
} }
TEST_DEF_STATIC(GlobalHeap) { testAlloc<HeapAllocGlobal>(); } SUITE(Allocators) {
TEST(GlobalHeap) { testAlloc<HeapAllocGlobal>(); }
TEST_DEF_STATIC(Heap) { testAlloc<tp::HeapAlloc>(); } TEST(Heap) { testAlloc<tp::HeapAlloc>(); }
TEST_DEF_STATIC(Chunk) { TEST(Chunk) {
testAlloc<ChunkAlloc<TestStruct, size>>(); testAlloc<ChunkAlloc<TestStruct, size>>();
testAlloc<ChunkAlloc<TestStruct, size * 2>>(); testAlloc<ChunkAlloc<TestStruct, size * 2>>();
}
TEST(Pool) {
testAlloc<PoolAlloc<TestStruct, 1>>();
testAlloc<PoolAlloc<TestStruct, size / 100>>();
testAlloc<PoolAlloc<TestStruct, size>>();
}
TEST(Simple) {
auto a = new TestStruct(-1);
delete a;
}
} }
TEST_DEF_STATIC(Pool) {
testAlloc<PoolAlloc<TestStruct, 1>>(); int main() {
testAlloc<PoolAlloc<TestStruct, size / 100>>();
testAlloc<PoolAlloc<TestStruct, size>>(); tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
} tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
TEST_DEF_STATIC(Simple) { if (!testModule.initialize()) {
auto a = new TestStruct(-1); return 1;
delete a; }
}
bool res = UnitTest::RunAllTests();
TEST_DEF(All) {
testSimple(); testModule.deinitialize();
testGlobalHeap(); return res;
testHeap();
testChunk();
testPool();
// TEST(HeapAllocGlobal::checkLeaks());
// TEST(false);
} }

View file

@ -1,20 +0,0 @@
#include "Allocators.hpp"
#include "Tests.hpp"
using namespace tp;
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testAll();
testModule.deinitialize();
}

View file

@ -1,6 +0,0 @@
#pragma once
#include "Testing.hpp"
#include "Utils.hpp"
void testAll();

View file

@ -14,5 +14,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -1,41 +0,0 @@
#pragma once
#include "ConnectionCommon.hpp"
#include "List.hpp"
namespace tp {
class RemoteConnectionContext;
class RemoteConnection : public Connection {
public:
class Location {
ualni mId = 0;
public:
Location() = default;
};
public:
RemoteConnection(){ MODULE_SANITY_CHECK(gModuleConnection) };
virtual ~RemoteConnection() {
if (mStatus.isOpened()) RemoteConnection::disconnect();
}
public:
virtual bool connect(const Location& location, const Type& connectionInfo);
virtual bool disconnect();
public:
virtual const Location& getLocation() { return mLocation; }
public:
virtual bool readBytes(Byte* bytes, SizeBytes size);
virtual bool writeBytes(const Byte* bytes, SizeBytes size);
private:
RemoteConnectionContext* mHandle = nullptr;
Location mLocation;
};
}

51
Connection/tests/Test.cpp Normal file
View file

@ -0,0 +1,51 @@
#include "ConnectionCommon.hpp"
#include "LocalConnection.hpp"
#include "UnitTest++/UnitTest++.h"
using namespace tp;
SUITE(Connection) {
TEST(LocalConnection) {
const int1* data = "abcde\0";
int1 dataRead[6]{};
{
LocalConnection file;
file.connect(LocalConnection::Location(String("tmp2.txt")), LocalConnection::Type(false));
file.writeBytes(data, 6);
file.disconnect();
}
{
LocalConnection file;
file.connect(LocalConnection::Location(String("tmp2.txt")), LocalConnection::Type(true));
file.readBytes(dataRead, 6);
file.disconnect();
}
for (auto i = 0; i < 5; i++) {
CHECK(data[i] == dataRead[i]);
}
}
TEST(NO_TESTS) { CHECK(false); }
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleConnection, nullptr };
tp::ModuleManifest testModule("ConnectionTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
bool res = UnitTest::RunAllTests();
testModule.deinitialize();
return res;
}

View file

@ -1,31 +0,0 @@
#include "LocalConnection.hpp"
#include "Testing.hpp"
using namespace tp;
TEST_DEF_STATIC(Simple) {
const int1* data = "abcde\0";
int1 dataRead[6]{};
{
LocalConnection file;
file.connect(LocalConnection::Location(String("tmp2.txt")), LocalConnection::Type(false));
file.writeBytes(data, 6);
file.disconnect();
}
{
LocalConnection file;
file.connect(LocalConnection::Location(String("tmp2.txt")), LocalConnection::Type(true));
file.readBytes(dataRead, 6);
file.disconnect();
}
for (auto i = 0; i < 5; i++) {
TEST(data[i] == dataRead[i]);
}
}
TEST_DEF(LocalConnection) { testSimple(); }

View file

@ -1,11 +0,0 @@
#include "RemoteConnection.hpp"
#include "Testing.hpp"
using namespace tp;
TEST_DEF_STATIC(Simple) {
TEST(false);
}
TEST_DEF(RemoteConnection) { testSimple(); }

View file

@ -1,19 +0,0 @@
#include "ConnectionCommon.hpp"
#include "Testing.hpp"
void testLocalConnection();
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleConnection, nullptr };
tp::ModuleManifest testModule("ConnectionTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testLocalConnection();
testModule.deinitialize();
}

View file

@ -11,5 +11,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Allocators) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Allocators UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -245,6 +245,7 @@ namespace tp {
} }
removeAll(); removeAll();
mNSlots = in.mNSlots; mNSlots = in.mNSlots;
deleteTable(mTable);
mTable = newTable(mNSlots); mTable = newTable(mNSlots);
for (alni i = 0; i < mNSlots; i++) { for (alni i = 0; i < mNSlots; i++) {
if (in.mTable[i] && !isDeletedNode(in.mTable[i])) { if (in.mTable[i] && !isDeletedNode(in.mTable[i])) {

View file

@ -1,5 +1,4 @@
#include "Buffer2D.hpp" #include "Buffer2D.hpp"
#include "Testing.hpp"
#include "Tests.hpp" #include "Tests.hpp"
#include "HeapAllocator.hpp" #include "HeapAllocator.hpp"
@ -8,18 +7,15 @@ using namespace tp;
const ualni size = 1000; const ualni size = 1000;
TEST_DEF_STATIC(Simple1) { SUITE(Buffer2D) {
Buffer2D<int, tp::HeapAlloc> buff; TEST(Simple) {
buff.reserve({ 4, 4 }); Buffer2D<int, tp::HeapAlloc> buff;
buff.set({ 2, 2 }, 5); buff.reserve({ 4, 4 });
TEST(buff.get({ 2, 2 }) == 5); buff.set({ 2, 2 }, 5);
} CHECK(buff.get({ 2, 2 }) == 5);
}
TEST_DEF_STATIC(Simple2) { TEST(NO_TESTS) {
// TEST(false); CHECK(false);
} }
TEST_DEF(Buffer2d) {
testSimple1();
testSimple2();
} }

View file

@ -1,35 +1,33 @@
#include "Buffer.hpp" #include "Buffer.hpp"
#include "Testing.hpp"
#include "Tests.hpp" #include "Tests.hpp"
using namespace tp; using namespace tp;
const ualni size = 1000; const ualni size = 1000;
TEST_DEF_STATIC(Simple1) { SUITE(Buffer) {
Buffer<TestClass, tp::HeapAlloc> buff; TEST(Simple1) {
TEST(buff.size() == 0); Buffer<TestClass, tp::HeapAlloc> buff;
for (auto i : Range(size * 10)) { CHECK(buff.size() == 0);
buff.append(TestClass(i)); for (auto i : Range(size * 10)) {
buff.append(TestClass(i));
}
CHECK(buff.size() == size * 10);
while (buff.size())
buff.pop();
CHECK(buff.size() == 0);
} }
TEST(buff.size() == size * 10);
while (buff.size())
buff.pop();
TEST(buff.size() == 0);
}
TEST_DEF_STATIC(Simple2) { TEST(Simple2) {
Buffer<TestClass, tp::HeapAlloc> buff(size); Buffer<TestClass, tp::HeapAlloc> buff(size);
TEST(buff.size() == size); CHECK(buff.size() == size);
for (auto i : Range(size * 10)) for (auto i : Range(size * 10))
buff.append(TestClass(i)); buff.append(TestClass(i));
TEST(buff.size() == size + size * 10); CHECK(buff.size() == size + size * 10);
while (buff.size()) while (buff.size())
buff.pop(); buff.pop();
TEST(buff.size() == 0); CHECK(buff.size() == 0);
} }
TEST_DEF(Buffer) { TEST(NO_TEST) { CHECK(false); }
testSimple1();
testSimple2();
} }

View file

@ -1,5 +1,4 @@
#include "IntervalTree.hpp" #include "IntervalTree.hpp"
#include "Testing.hpp"
#include "Tests.hpp" #include "Tests.hpp"
#include "Buffer.hpp" #include "Buffer.hpp"
@ -34,246 +33,242 @@ struct Interval {
} }
}; };
TEST_DEF_STATIC(FunctionalitySimple) { SUITE(IntervalTree) {
TEST(FunctionalitySimple) {
IntervalTree<ualni, ualni> intervalTree; IntervalTree<ualni, ualni> intervalTree;
intervalTree.insert({ 0, 10 }, 1); intervalTree.insert({ 0, 10 }, 1);
intervalTree.insert({ 3, 6 }, 2); intervalTree.insert({ 3, 6 }, 2);
intervalTree.insert({ 8, 12 }, 3); intervalTree.insert({ 8, 12 }, 3);
intervalTree.forEachIntersection(4, 5, [](alni start, ualni end, ualni data) { intervalTree.forEachIntersection(4, 5, [](alni start, ualni end, ualni data) {
printf("%i", int(data)); printf("%i", int(data));
printf("\n"); printf("\n");
}); });
}
TEST_DEF_STATIC(FunctionalityScale) {
const int NUM_TEST_INTERVALS = 1000;
const halnf SPAN = 100;
Buffer<Interval> pool;
IntervalTree<halnf, ualni> intervalTree;
Buffer<Interval> testIntervals;
auto test = [&]() {
for (auto testInterval : testIntervals) {
Buffer<ualni> correct;
Buffer<ualni> result;
ualni idx = 0;
for (auto interval : pool) {
if (!interval->ignore && interval->overlaps(testInterval.data())) {
correct.append(idx);
}
idx++;
}
intervalTree.forEachIntersection(testInterval->start, testInterval->end, [&](alni start, ualni end, ualni data) {
result.append(data);
});
TEST(correct.size() == result.size());
if (!(correct.size() == result.size())) {
printf("intersections - \n");
for (auto i : correct) {
printf(" %i", (int) i.data());
}
printf("\n");
for (auto i : result) {
printf(" %i", (int) i.data());
}
printf("\n\n");
}
// todo compare containers
}
};
// initialize
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
auto interval = Interval();
interval.random(SPAN);
pool.append(interval);
intervalTree.insert({ interval.start, interval.end }, i);
interval.random(SPAN * 2.f, (halnf) randomFloat());
testIntervals.append(interval);
} }
test(); TEST(FunctionalityScale) {
// remove some const int NUM_TEST_INTERVALS = 1000;
for (auto i : Range<ualni>(NUM_TEST_INTERVALS / 2)) { const halnf SPAN = 100;
auto idx = ualni(randomFloat() * (alnf) pool.size());
pool[idx].ignore = true;
intervalTree.remove({ pool[idx].start, pool[idx].end });
}
test();
}
TEST_DEF_STATIC(Efficency) {
struct Stat {
halnf numItems = 0;
halnf avgFound = 0;
halnf avgChecks = 0;
};
auto test = [&](ualni NUM_TEST_INTERVALS, ualni NUM_CHECKS) {
const auto SPAN = (halnf) (halnf(NUM_TEST_INTERVALS));
const auto SCALE = (halnf) (2.f);
Buffer<Interval> pool;
IntervalTree<halnf, ualni> intervalTree; IntervalTree<halnf, ualni> intervalTree;
Buffer<Interval> testIntervals; Buffer<Interval> testIntervals;
auto WOBBLE = SPAN * 0; auto test = [&]() {
for (auto testInterval : testIntervals) {
Buffer<ualni> correct;
Buffer<ualni> result;
ualni idx = 0;
for (auto interval : pool) {
if (!interval->ignore && interval->overlaps(testInterval.data())) {
correct.append(idx);
}
idx++;
}
intervalTree.forEachIntersection(testInterval->start, testInterval->end, [&](alni start, ualni end, ualni data) {
result.append(data);
});
CHECK(correct.size() == result.size());
if (!(correct.size() == result.size())) {
printf("intersections - \n");
for (auto i : correct) {
printf(" %i", (int) i.data());
}
printf("\n");
for (auto i : result) {
printf(" %i", (int) i.data());
}
printf("\n\n");
}
// todo compare containers
}
};
// initialize
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) { for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
auto interval = Interval(); auto interval = Interval();
interval.randomSized(SPAN, SCALE, WOBBLE); interval.random(SPAN);
pool.append(interval);
intervalTree.insert({ interval.start, interval.end }, i); intervalTree.insert({ interval.start, interval.end }, i);
// WOBBLE -= 1.f;
}
for (auto i : Range(0)) interval.random(SPAN * 2.f, (halnf) randomFloat());
intervalTree.insert({ (halnf) i * 0.01f, SPAN }, 0);
WOBBLE = 0;
for (auto i : Range<ualni>(NUM_CHECKS)) {
auto interval = Interval();
interval.randomSized(SPAN, SCALE, WOBBLE);
testIntervals.append(interval); testIntervals.append(interval);
} }
ualni debugMaxChecks = 0; test();
ualni debugMaxFound = 0;
halnf debugAvgChecks = 0;
halnf debugAvgFound = 0;
for (auto testInterval : testIntervals) { // remove some
ualni debugFound = 0; for (auto i : Range<ualni>(NUM_TEST_INTERVALS / 2)) {
ualni debug = intervalTree.forEachIntersection( auto idx = ualni(randomFloat() * (alnf) pool.size());
testInterval->start, pool[idx].ignore = true;
testInterval->end, intervalTree.remove({ pool[idx].start, pool[idx].end });
[&](ualni start, ualni end, ualni data) {
debugFound++;
//
}
);
if (debug > debugMaxChecks) {
debugMaxChecks = debug;
debugMaxFound = debugFound;
}
debugMaxChecks = max(debug, debugMaxChecks);
debugAvgChecks += (halnf) debug;
debugAvgFound += (halnf) debugFound;
} }
debugAvgChecks /= (halnf) testIntervals.size(); test();
debugAvgFound /= (halnf) testIntervals.size();
printf("\nItems : %llu\n", NUM_TEST_INTERVALS);
printf("Avg(checks) : %f\n", debugAvgChecks);
printf("Avg(found) : %f\n", debugAvgFound);
printf("Max checks : %llu\n", debugMaxChecks);
printf("Max checks found : %llu\n", debugMaxFound);
printf("N(Avg(checks) / Avg(N(items)) : %f\n", debugAvgChecks / (halnf) intervalTree.size());
printf("N(Avg(found)) / Avg(N(items)) : %f\n", debugAvgFound / (halnf) intervalTree.size());
printf("Avg(found) / Avg(checks) : %f\n", debugAvgFound / debugAvgChecks);
return Stat{ (halnf) NUM_TEST_INTERVALS,
debugAvgFound / (halnf) intervalTree.size(),
debugAvgChecks / (halnf) intervalTree.size() };
};
Buffer<Stat> stats;
for (auto i : Range(2, 5)) {
Stat stat = test(pow(10, i), 100);
stats.append(stat);
} }
printf("\nChecks: "); TEST(Efficency) {
for (auto stat : stats)
printf("%e ", stat->avgChecks);
printf("\nHits: "); struct Stat {
for (auto stat : stats) halnf numItems = 0;
printf("%e ", stat->avgFound); halnf avgFound = 0;
halnf avgChecks = 0;
};
printf("\nItems: "); auto test = [&](ualni NUM_TEST_INTERVALS, ualni NUM_CHECKS) {
for (auto stat : stats) const auto SPAN = (halnf) (halnf(NUM_TEST_INTERVALS));
printf("%e ", stat->numItems); const auto SCALE = (halnf) (2.f);
IntervalTree<halnf, ualni> intervalTree;
Buffer<Interval> testIntervals;
auto WOBBLE = SPAN * 0;
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
auto interval = Interval();
interval.randomSized(SPAN, SCALE, WOBBLE);
intervalTree.insert({ interval.start, interval.end }, i);
// WOBBLE -= 1.f;
}
for (auto i : Range(0))
intervalTree.insert({ (halnf) i * 0.01f, SPAN }, 0);
WOBBLE = 0;
for (auto i : Range<ualni>(NUM_CHECKS)) {
auto interval = Interval();
interval.randomSized(SPAN, SCALE, WOBBLE);
testIntervals.append(interval);
}
ualni debugMaxChecks = 0;
ualni debugMaxFound = 0;
halnf debugAvgChecks = 0;
halnf debugAvgFound = 0;
for (auto testInterval : testIntervals) {
ualni debugFound = 0;
ualni debug = intervalTree.forEachIntersection(
testInterval->start,
testInterval->end,
[&](ualni start, ualni end, ualni data) {
debugFound++;
//
}
);
if (debug > debugMaxChecks) {
debugMaxChecks = debug;
debugMaxFound = debugFound;
}
debugMaxChecks = max(debug, debugMaxChecks);
debugAvgChecks += (halnf) debug;
debugAvgFound += (halnf) debugFound;
}
debugAvgChecks /= (halnf) testIntervals.size();
debugAvgFound /= (halnf) testIntervals.size();
printf("\nItems : %llu\n", NUM_TEST_INTERVALS);
printf("Avg(checks) : %f\n", debugAvgChecks);
printf("Avg(found) : %f\n", debugAvgFound);
printf("Max checks : %llu\n", debugMaxChecks);
printf("Max checks found : %llu\n", debugMaxFound);
printf("N(Avg(checks) / Avg(N(items)) : %f\n", debugAvgChecks / (halnf) intervalTree.size());
printf("N(Avg(found)) / Avg(N(items)) : %f\n", debugAvgFound / (halnf) intervalTree.size());
printf("Avg(found) / Avg(checks) : %f\n", debugAvgFound / debugAvgChecks);
return Stat{ (halnf) NUM_TEST_INTERVALS,
debugAvgFound / (halnf) intervalTree.size(),
debugAvgChecks / (halnf) intervalTree.size() };
};
Buffer<Stat> stats;
for (auto i : Range(2, 5)) {
Stat stat = test(pow(10, i), 100);
stats.append(stat);
}
printf("\nChecks: ");
for (auto stat : stats)
printf("%e ", stat->avgChecks);
printf("\nHits: ");
for (auto stat : stats)
printf("%e ", stat->avgFound);
printf("\nItems: ");
for (auto stat : stats)
printf("%e ", stat->numItems);
printf("\n\n");
}
TEST(FunctionalityComplex) {
IntervalTree<ualni, ualni> intervals;
struct QueryResult {
ualni numFound = 0;
ualni lastDataFound = 0;
[[nodiscard]] bool isSingleData(ualni aData) const { return numFound == 1 & lastDataFound == aData; }
[[nodiscard]] bool notFound() const { return numFound == 0; }
[[nodiscard]] bool found(ualni num) const { return numFound == num; }
};
auto makeQuery = [&](ualni aStart, ualni aEnd) {
QueryResult out;
intervals.forEachIntersection(aStart, aEnd, [&](alni start, ualni end, ualni data) {
out.numFound++;
out.lastDataFound = data;
});
return out;
};
intervals.insert({ 2, 5 }, 1);
intervals.insert({ 12, 15 }, 2);
intervals.insert({ 22, 25 }, 3);
CHECK(makeQuery(1, 6).isSingleData(1));
CHECK(makeQuery(1, 3).isSingleData(1));
CHECK(makeQuery(3, 6).isSingleData(1));
CHECK(makeQuery(0, 1).notFound());
CHECK(makeQuery(7, 8).notFound());
CHECK(makeQuery(3, 4).isSingleData(1));
CHECK(makeQuery(13, 14).isSingleData(2));
CHECK(makeQuery(1, 35).found(3));
CHECK(makeQuery(11, 35).found(2));
// check opened
CHECK(makeQuery(5, 12).found(2));
CHECK(makeQuery(15, 22).found(2));
CHECK(makeQuery(1, 2).isSingleData(1));
CHECK(makeQuery(25, 35).isSingleData(3));
intervals.removeAll();
intervals.insert({ 0, 3 }, 1);
intervals.insert({ 0, 13 }, 2);
CHECK(makeQuery(0, 1).found(2));
}
printf("\n\n");
}
TEST_DEF_STATIC(FunctionalityComplex) {
IntervalTree<ualni, ualni> intervals;
struct QueryResult {
ualni numFound = 0;
ualni lastDataFound = 0;
[[nodiscard]] bool isSingleData(ualni aData) const { return numFound == 1 & lastDataFound == aData; }
[[nodiscard]] bool notFound() const { return numFound == 0; }
[[nodiscard]] bool found(ualni num) const { return numFound == num; }
};
auto makeQuery = [&](ualni aStart, ualni aEnd) {
QueryResult out;
intervals.forEachIntersection(aStart, aEnd, [&](alni start, ualni end, ualni data) {
out.numFound++;
out.lastDataFound = data;
});
return out;
};
intervals.insert({ 2, 5 }, 1);
intervals.insert({ 12, 15 }, 2);
intervals.insert({ 22, 25 }, 3);
TEST(makeQuery(1, 6).isSingleData(1));
TEST(makeQuery(1, 3).isSingleData(1));
TEST(makeQuery(3, 6).isSingleData(1));
TEST(makeQuery(0, 1).notFound());
TEST(makeQuery(7, 8).notFound());
TEST(makeQuery(3, 4).isSingleData(1));
TEST(makeQuery(13, 14).isSingleData(2));
TEST(makeQuery(1, 35).found(3));
TEST(makeQuery(11, 35).found(2));
// check opened
TEST(makeQuery(5, 12).found(2));
TEST(makeQuery(15, 22).found(2));
TEST(makeQuery(1, 2).isSingleData(1));
TEST(makeQuery(25, 35).isSingleData(3));
intervals.removeAll();
intervals.insert({ 0, 3 }, 1);
intervals.insert({ 0, 13 }, 2);
TEST(makeQuery(0, 1).found(2));
}
TEST_DEF(IntervalTree) {
testFunctionalitySimple();
testFunctionalityScale();
testEfficency();
testFunctionalityComplex();
} }

View file

@ -1,83 +1,80 @@
#include "Archiver.hpp" #include "Archiver.hpp"
#include "Testing.hpp"
#include "Tests.hpp" #include "Tests.hpp"
#include "List.hpp"
using namespace tp; using namespace tp;
TEST_DEF_STATIC(SimpleReference) { SUITE(DoubleLinkedList) {
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
list.pushBack(TestClass(5)); TEST(SimpleReference) {
list.pushFront(TestClass(0)); tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
ualni i = -1; list.pushBack(TestClass(5));
for (auto iter : list) { list.pushFront(TestClass(0));
i++;
TEST_EQUAL(iter->getVal(), i); ualni i = -1;
for (auto iter : list) {
i++;
CHECK_EQUAL(iter->getVal(), i);
}
CHECK(i == 5);
list.removeAll();
} }
TEST(i == 5); TEST(SimplePointer) {
tp::List<TestClass*, tp::HeapAlloc> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) };
list.removeAll(); list.pushBack(new TestClass(5));
} list.pushFront(new TestClass(0));
TEST_DEF_STATIC(SimplePointer) { ualni i = -1;
tp::List<TestClass*, tp::HeapAlloc> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) }; for (auto iter : list) {
i++;
CHECK_EQUAL(iter->getVal(), i);
}
list.pushBack(new TestClass(5)); CHECK(i == 5);
list.pushFront(new TestClass(0));
ualni i = -1; for (auto iter : list) {
for (auto iter : list) { delete iter.data();
i++; }
TEST_EQUAL(iter->getVal(), i);
list.removeAll();
} }
TEST(i == 5); TEST(Copy) {
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
tp::List<TestClass, tp::HeapAlloc> list2 = list;
for (auto iter : list) { CHECK(list == list2);
delete iter.data();
list.removeAll();
list2.removeAll();
} }
list.removeAll(); TEST(Serialization) {
} tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
TEST_DEF_STATIC(Copy) { ArchiverExample<1024, false> write;
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) }; ArchiverExample<1024, true> read;
tp::List<TestClass, tp::HeapAlloc> list2 = list;
TEST_EQUAL(list, list2); write % list;
list.removeAll(); list.removeAll();
list2.removeAll();
}
TEST_DEF_STATIC(Serialization) { memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
tp::List<TestClass, tp::HeapAlloc> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
ArchiverExample<1024, false> write; read % list;
ArchiverExample<1024, true> read;
write % list; ualni i = 0;
for (auto iter : list) {
i++;
CHECK(iter->getVal() == i);
}
CHECK(i == 4);
list.removeAll(); list.removeAll();
memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
read % list;
ualni i = 0;
for (auto iter : list) {
i++;
TEST_EQUAL(iter->getVal(), i);
} }
TEST(i == 4);
list.removeAll();
}
TEST_DEF(List) {
testSimplePointer();
testSimpleReference();
testSerialization();
} }

View file

@ -1,129 +1,124 @@
#include "Archiver.hpp" #include "Archiver.hpp"
#include "Map.hpp" #include "Map.hpp"
#include "Testing.hpp"
#include "Tests.hpp" #include "Tests.hpp"
using namespace tp; using namespace tp;
TEST_DEF_STATIC(SimpleReference) { SUITE(HashTable) {
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map; TEST(SimpleReference) {
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
for (auto i : Range(1000, 100000)) { for (auto i : Range(1000, 100000)) {
map.put(i, TestClass(i)); map.put(i, TestClass(i));
}
for (auto i : Range(1000, 100000)) {
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
}
for (auto i : Range(1000, 100000)) {
map.put(i, TestClass(i));
}
for (auto i : Range(1000, 2000)) {
CHECK(map.presents(i));
map.remove(i);
CHECK(!map.presents(i));
}
for (auto i : Range(2000, 100000)) {
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
}
for (auto i : map) {
i->val.setVal(3);
}
map.removeAll();
} }
for (auto i : Range(1000, 100000)) { TEST(SimplePointer) {
TEST(map.presents(i)); tp::Map<tp::ualni, TestClass*, tp::HeapAlloc> map;
TEST_EQUAL(map.get(i).getVal(), i);
for (auto i : Range(1000)) {
map.put(i, new TestClass(i));
}
for (auto i : Range(1000)) {
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
}
for (auto i : Range(1000)) {
auto del = map.get(i);
map.put(i, new TestClass(i));
delete del;
}
for (auto i : Range(900, 1000)) {
CHECK(map.presents(i));
delete map.get(i);
map.remove(i);
CHECK(!map.presents(i));
}
for (auto i : Range(900)) {
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
}
for (auto i : map) {
i->val->setVal(3);
delete i->val;
}
map.removeAll();
} }
for (auto i : Range(1000, 100000)) { TEST(Copy) {
map.put(i, TestClass(i)); tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
for (auto i : Range(10)) {
map.put(i, TestClass(i));
}
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map2 = map;
CHECK(map == map2);
map.removeAll();
map2.removeAll();
} }
for (auto i : Range(1000, 2000)) { TEST(SaveLoad) {
TEST(map.presents(i)); tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
map.remove(i);
TEST(!map.presents(i));
}
for (auto i : Range(2000, 100000)) { for (auto i : Range(10)) {
TEST(map.presents(i)); map.put(i, TestClass(i));
TEST_EQUAL(map.get(i).getVal(), i); }
}
for (auto i : map) { ArchiverExample<1024, false> write;
i->val.setVal(3); ArchiverExample<1024, true> read;
}
map.removeAll(); write % map;
}
map.removeAll();
TEST_DEF_STATIC(SimplePointer) {
tp::Map<tp::ualni, TestClass*, tp::HeapAlloc> map; CHECK(map.size() == 0);
for (auto i : Range(1000)) { memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
map.put(i, new TestClass(i));
} read % map;
for (auto i : Range(1000)) { CHECK(map.size() == 10);
TEST(map.presents(i));
TEST_EQUAL(map.get(i)->getVal(), i); for (auto i : Range(10)) {
} CHECK(map.presents(i));
CHECK_EQUAL(map.get(i).getVal(), i);
for (auto i : Range(1000)) { }
auto del = map.get(i);
map.put(i, new TestClass(i)); map.removeAll();
delete del; }
}
for (auto i : Range(900, 1000)) {
TEST(map.presents(i));
delete map.get(i);
map.remove(i);
TEST(!map.presents(i));
}
for (auto i : Range(900)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i)->getVal(), i);
}
for (auto i : map) {
i->val->setVal(3);
delete i->val;
}
map.removeAll();
}
TEST_DEF_STATIC(Copy) {
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
for (auto i : Range(10)) {
map.put(i, TestClass(i));
}
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map2 = map;
TEST_EQUAL(map, map2);
map.removeAll();
map2.removeAll();
}
TEST_DEF_STATIC(SaveLoad) {
tp::Map<tp::ualni, TestClass, tp::HeapAlloc> map;
for (auto i : Range(10)) {
map.put(i, TestClass(i));
}
ArchiverExample<1024, false> write;
ArchiverExample<1024, true> read;
write % map;
map.removeAll();
TEST(map.size() == 0);
memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
read % map;
TEST(map.size() == 10);
for (auto i : Range(10)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i);
}
map.removeAll();
}
TEST_DEF(Map) {
testSimplePointer();
testSimpleReference();
testSaveLoad();
} }

View file

@ -1,27 +1,19 @@
#include "Tests.hpp" #include "Tests.hpp"
#include "Testing.hpp" #include "UnitTest++/UnitTest++.h"
static bool init(const tp::ModuleManifest* self) {
tp::gTesting.setRootName(self->getName());
return true;
}
int main() { int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr }; tp::ModuleManifest* deps[] = { &tp::gModuleUtils, &tp::gModuleAllocators, nullptr };
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps); tp::ModuleManifest testModule("ContainersTest", nullptr, nullptr, deps);
if (!testModule.initialize()) { if (!testModule.initialize()) {
return 1; return 1;
} }
testIntervalTree(); bool res = UnitTest::RunAllTests();
testList();
testMap();
testAvl();
testBuffer();
testBuffer2d();
testModule.deinitialize(); testModule.deinitialize();
return res;
} }

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "UnitTest++/UnitTest++.h"
#include "Allocators.hpp" #include "Allocators.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@ -28,10 +30,3 @@ public:
[[nodiscard]] tp::ualni getVal() const { return val1; } [[nodiscard]] tp::ualni getVal() const { return val1; }
void setVal(tp::ualni val) { val1 = val; } void setVal(tp::ualni val) { val1 = val; }
}; };
void testList();
void testMap();
void testAvl();
void testBuffer();
void testBuffer2d();
void testIntervalTree();

View file

@ -1,127 +1,124 @@
#include "Testing.hpp"
#include "Tests.hpp" #include "Tests.hpp"
#include "Tree.hpp" #include "Tree.hpp"
using namespace tp; using namespace tp;
TEST_DEF_STATIC(Simple) { SUITE(AvlTree) {
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree; TEST(Simple) {
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
TEST(tree.size() == 0); CHECK(tree.size() == 0);
TEST(tree.head() == nullptr); CHECK(tree.head() == nullptr);
tree.insert(6, TestClass(6)); tree.insert(6, TestClass(6));
TEST(tree.isValid()); CHECK(tree.isValid());
TEST(tree.size() == 1); CHECK(tree.size() == 1);
TEST(tree.head()->data == TestClass(6)); CHECK(tree.head()->data == TestClass(6));
tree.remove(6); tree.remove(6);
TEST(tree.isValid()); CHECK(tree.isValid());
TEST(tree.size() == 0); CHECK(tree.size() == 0);
TEST(tree.head() == nullptr); CHECK(tree.head() == nullptr);
}
TEST_DEF_STATIC(Persistance) {
AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
const auto size = 1000;
struct Item {
Item() :
data(0) {}
bool presents = false;
TestClass data;
};
Item buff[size];
for (auto i : Range(size)) {
buff[i].data.setVal(i);
} }
// random load TEST(Persistance) {
ualni loadSize = 0; AvlTree<AvlNumericKey<alni>, TestClass, tp::HeapAlloc> tree;
while (loadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
DEBUG_ASSERT(idx < size)
if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data.getVal(), buff[idx].data);
loadSize++;
buff[idx].presents = true;
TEST(tree.isValid()); const auto size = 1000;
TEST(tree.size() == loadSize);
struct Item {
Item() :
data(0) {}
bool presents = false;
TestClass data;
};
Item buff[size];
for (auto i : Range(size)) {
buff[i].data.setVal(i);
} }
}
for (auto& item : buff) { // random load
if (item.presents) continue; ualni loadSize = 0;
tree.insert((alni) item.data.getVal(), item.data); while (loadSize < size / 2) {
loadSize++; auto idx = ualni(randomFloat() * (size - 1));
item.presents = true; DEBUG_ASSERT(idx < size)
if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data.getVal(), buff[idx].data);
loadSize++;
buff[idx].presents = true;
TEST(tree.isValid()); CHECK(tree.isValid());
TEST(tree.size() == loadSize); CHECK(tree.size() == loadSize);
}
TEST(tree.size() == size);
TEST(tree.maxNode(tree.head())->data.getVal() == size - 1);
TEST(tree.minNode(tree.head())->data.getVal() == 0);
// find
for (auto item : buff) {
auto node = tree.find((alni) item.data.getVal());
TEST(node);
if (!node) continue;
TEST(node->data.getVal() == item.data.getVal());
}
TEST(!tree.find(size + 1));
TEST(!tree.find(-1));
// random unload
ualni unloadSize = 0;
while (unloadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
if (buff[idx].presents) {
tree.remove((alni) buff[idx].data.getVal());
unloadSize++;
buff[idx].presents = false;
// find
for (auto item : buff) {
if (!item.presents) continue;
auto node = tree.find((alni) item.data.getVal());
TEST(node);
if (!node) continue;
TEST(node->data.getVal() == item.data.getVal());
} }
TEST(tree.isValid());
TEST(tree.size() == size - unloadSize);
} }
for (auto& item : buff) {
if (item.presents) continue;
tree.insert((alni) item.data.getVal(), item.data);
loadSize++;
item.presents = true;
CHECK(tree.isValid());
CHECK(tree.size() == loadSize);
}
CHECK(tree.size() == size);
CHECK(tree.maxNode(tree.head())->data.getVal() == size - 1);
CHECK(tree.minNode(tree.head())->data.getVal() == 0);
// find
for (auto item : buff) {
auto node = tree.find((alni) item.data.getVal());
CHECK(node);
if (!node) continue;
CHECK(node->data.getVal() == item.data.getVal());
}
CHECK(!tree.find(size + 1));
CHECK(!tree.find(-1));
// random unload
ualni unloadSize = 0;
while (unloadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
if (buff[idx].presents) {
tree.remove((alni) buff[idx].data.getVal());
unloadSize++;
buff[idx].presents = false;
// find
for (auto item : buff) {
if (!item.presents) continue;
auto node = tree.find((alni) item.data.getVal());
CHECK(node);
if (!node) continue;
CHECK(node->data.getVal() == item.data.getVal());
}
CHECK(tree.isValid());
CHECK(tree.size() == size - unloadSize);
}
}
for (auto& item : buff) {
if (item.presents) {
tree.remove((alni) item.data.getVal());
unloadSize++;
item.presents = false;
CHECK(tree.isValid());
CHECK(tree.size() == size - unloadSize);
}
}
CHECK(tree.size() == 0);
CHECK(tree.head() == nullptr);
CHECK(tree.maxNode(tree.head()) == nullptr);
CHECK(tree.minNode(tree.head()) == nullptr);
} }
for (auto& item : buff) {
if (item.presents) {
tree.remove((alni) item.data.getVal());
unloadSize++;
item.presents = false;
TEST(tree.isValid());
TEST(tree.size() == size - unloadSize);
}
}
TEST(tree.size() == 0);
TEST(tree.head() == nullptr);
TEST(tree.maxNode(tree.head()) == nullptr);
TEST(tree.minNode(tree.head()) == nullptr);
}
TEST_DEF(Avl) {
testSimple();
testPersistance();
} }

View file

@ -28,5 +28,5 @@ add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_include_directories(${PROJECT_NAME}Tests PUBLIC ./applications/) target_include_directories(${PROJECT_NAME}Tests PUBLIC ./applications/)
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -1,39 +1,40 @@
#include "NewPlacement.hpp" #include "UnitTest++/UnitTest++.h"
#include "FCNN.hpp" #include "FCNN.hpp"
#include "Testing.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <cstdio> #include <cstdio>
using namespace tp; using namespace tp;
void test() { SUITE(FCNN) {
Buffer<halni> layers = { 100, 70, 50, 30, 20 }; TEST(Basic) {
Buffer<halnf> input(layers.first()); Buffer<halni> layers = { 100, 70, 50, 30, 20 };
Buffer<halnf> outputExpected(layers.last()); Buffer<halnf> input(layers.first());
Buffer<halnf> output(layers.last()); Buffer<halnf> outputExpected(layers.last());
Buffer<halnf> output(layers.last());
for (auto inputVal : Range(layers.first())) { for (auto inputVal : Range(layers.first())) {
input[inputVal] = (halnf) randomFloat() * 100; input[inputVal] = (halnf) randomFloat() * 100;
} }
for (auto outIdx : Range(layers.last())) { for (auto outIdx : Range(layers.last())) {
outputExpected[outIdx] = (halnf) randomFloat(); outputExpected[outIdx] = (halnf) randomFloat();
} }
FCNN nn(layers); FCNN nn(layers);
halnf steppingValue = 100; halnf steppingValue = 100;
for (auto i : Range(50)) { for (auto i : Range(50)) {
nn.evaluate(input, output); nn.evaluate(input, output);
nn.calcGrad(outputExpected); nn.calcGrad(outputExpected);
nn.applyGrad(steppingValue); nn.applyGrad(steppingValue);
printf("Loss %f \n", nn.calcCost(outputExpected)); printf("Loss %f \n", nn.calcCost(outputExpected));
}
} }
} }
@ -45,9 +46,9 @@ int main() {
return 1; return 1;
} }
test(); bool res = UnitTest::RunAllTests();
testModule.deinitialize(); testModule.deinitialize();
return 0; return res;
} }

2
Externals/asio vendored

@ -1 +1 @@
Subproject commit d6b95c0188e0359a8cdbdb6571f0cbacf11a538c Subproject commit 3a7078a2002c670d98ee3044802a5086f3e49634

View file

@ -18,9 +18,3 @@ add_executable(${PROJECT_NAME}Example ./examples/Example.cpp)
target_link_libraries(${PROJECT_NAME}Example ${PROJECT_NAME} ${BINDINGS_LIBS}) target_link_libraries(${PROJECT_NAME}Example ${PROJECT_NAME} ${BINDINGS_LIBS})
target_include_directories(${PROJECT_NAME}Example PRIVATE ${BINDINGS_INCLUDE}) target_include_directories(${PROJECT_NAME}Example PRIVATE ${BINDINGS_INCLUDE})
### -------------------------- Tests -------------------------- ###
enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -1 +0,0 @@
int main() {}

View file

@ -16,7 +16,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)

View file

@ -11,5 +11,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Allocators)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -1,41 +0,0 @@
#include "ComplexNumbers.hpp"
#include "Testing.hpp"
using namespace tp;
TEST_DEF(ComplexNumber) {
TEST((ComplexCart{ 3, 4 }.mod() == 5));
TEST((abs(ComplexCart{ 1, 1 }.arg() - 0.7853981633974483) < 0.001));
TEST((ComplexCart{ 3, 4 }.norm2() == 25));
{
ComplexCart cn{ 3, 4 };
ComplexCart expected{ 0.12, -0.16 };
auto val = cn.reciprocal();
TEST((val == expected));
}
{
ComplexCart cn{ 3, 4 };
ComplexCart expected{ 3, -4 };
TEST((cn.conjugate() == expected));
}
{
ComplexCart cn1{ 3, 4 };
ComplexCart cn2{ 1, 2 };
ComplexCart expected{ -5, 10 };
TEST((cn1 * cn2 == expected));
}
{
ComplexRad c1{ 5, 7 };
ComplexRad c2{ 10, 3 };
ComplexCart tmp1 = (c1 * c2).cart();
ComplexCart tmp2 = (c1.cart() * c2.cart());
TEST((tmp1 - tmp2).mod() < 0.001);
}
}
TEST_DEF(Math) { testComplexNumber(); }

View file

@ -1,23 +1,59 @@
#include "MathCommon.hpp" #include "ComplexNumbers.hpp"
#include "Testing.hpp"
static bool init(const tp::ModuleManifest* self) { #include "UnitTest++/UnitTest++.h"
tp::gTesting.setRootName(self->getName());
return true; using namespace tp;
SUITE(Math) {
TEST(ComplexNumber) {
CHECK((ComplexCart{ 3, 4 }.mod() == 5));
CHECK((abs(ComplexCart{ 1, 1 }.arg() - 0.7853981633974483) < 0.001));
CHECK((ComplexCart{ 3, 4 }.norm2() == 25));
{
ComplexCart cn{ 3, 4 };
ComplexCart expected{ 0.12, -0.16 };
auto val = cn.reciprocal();
CHECK((val == expected));
}
{
ComplexCart cn{ 3, 4 };
ComplexCart expected{ 3, -4 };
CHECK((cn.conjugate() == expected));
}
{
ComplexCart cn1{ 3, 4 };
ComplexCart cn2{ 1, 2 };
ComplexCart expected{ -5, 10 };
CHECK((cn1 * cn2 == expected));
}
{
ComplexRad c1{ 5, 7 };
ComplexRad c2{ 10, 3 };
ComplexCart tmp1 = (c1 * c2).cart();
ComplexCart tmp2 = (c1.cart() * c2.cart());
CHECK((tmp1 - tmp2).mod() < 0.001);
}
}
TEST(NO_TESTS) { CHECK(false); }
} }
void testMath();
int main() { int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleMath, &tp::gModuleUtils, nullptr }; tp::ModuleManifest* deps[] = { &tp::gModuleMath, &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("MathTest", init, nullptr, deps); tp::ModuleManifest testModule("MathTest", nullptr, nullptr, deps);
if (!testModule.initialize()) { if (!testModule.initialize()) {
return 1; return 1;
} }
testMath(); bool res = UnitTest::RunAllTests();
testModule.deinitialize(); testModule.deinitialize();
return res;
} }

View file

@ -9,5 +9,5 @@ target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
enable_testing() enable_testing()
file(GLOB SOURCES_TEST "./tests/*.cpp") file(GLOB SOURCES_TEST "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${SOURCES_TEST}) add_executable(${PROJECT_NAME}Tests ${SOURCES_TEST})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -1,12 +1,14 @@
#include "Module.hpp"
#include "UnitTest++/UnitTest++.h"
#include "Archiver.hpp" #include "Archiver.hpp"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
using namespace tp; using namespace tp;
bool sFailed = false;
struct Undef { struct Undef {
char character1 = 'a'; char character1 = 'a';
bool boolean = true; bool boolean = true;
@ -202,10 +204,7 @@ void test() {
read % res; read % res;
if (val != res) { CHECK(!(val != res));
printf("Test %s Failed\n", typeid(tType).name());
sFailed = true;
}
} }
template <typename T, typename A, typename = void> template <typename T, typename A, typename = void>
@ -214,17 +213,32 @@ struct HasArchive : FalseType {};
template <typename T, typename A> template <typename T, typename A>
struct HasArchive<T, A, VoidType<decltype(DeclareValue<T>()().archive(DeclareValue<A&>()()))>> : TrueType {}; struct HasArchive<T, A, VoidType<decltype(DeclareValue<T>()().archive(DeclareValue<A&>()()))>> : TrueType {};
void testArchiver() {
printf("has archive method - %i\n", HasArchive<SimpleArchive, ArchiverExample<10, false>>::value);
printf("has archive method - %i\n", ArchiverExample<10, false>::HasFunc::Archive<SimpleArchive>::value);
printf("has archive method - %i\n", ArchiverExample<10, false>::HasFunc::Archive<Simple>::value);
test<SimpleArchive>(); SUITE(BaseModule) {
test<Simple>(); TEST(Basic) {
test<Set<Simple>>(); tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleBase, nullptr };
test<ComplexCart<Simple>>(); tp::ModuleManifest TestModule("Test", nullptr, nullptr, ModuleDependencies);
if (sFailed) { REQUIRE CHECK(TestModule.initialize());
exit(1);
REQUIRE CHECK(tp::gEnvironment.mWidth == tp::Environment::ArchWidth::X64);
CHECK(tp::max(2, 1) == 2);
CHECK(tp::max(-1, 0) == 0);
CHECK(tp::max(0, -1) == 0);
CHECK(tp::min(0, -1) == -1);
printf("has archive method - %i\n", HasArchive<SimpleArchive, ArchiverExample<10, false>>::value);
printf("has archive method - %i\n", ArchiverExample<10, false>::HasFunc::Archive<SimpleArchive>::value);
printf("has archive method - %i\n", ArchiverExample<10, false>::HasFunc::Archive<Simple>::value);
test<SimpleArchive>();
test<Simple>();
test<Set<Simple>>();
test<ComplexCart<Simple>>();
TestModule.deinitialize();
} }
} }
int main() { return UnitTest::RunAllTests(); }

View file

@ -1,24 +0,0 @@
#include "Module.hpp"
void testArchiver();
int main() {
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleBase, nullptr };
tp::ModuleManifest TestModule("Test", nullptr, nullptr, ModuleDependencies);
if (!TestModule.initialize()) {
return 1;
}
ASSERT(tp::gEnvironment.mWidth == tp::Environment::ArchWidth::X64);
ASSERT(tp::max(2, 1) == 2)
ASSERT(tp::max(-1, 0) == 0)
ASSERT(tp::max(0, -1) == 0)
ASSERT(tp::min(0, -1) == -1)
testArchiver();
TestModule.deinitialize();
}

View file

@ -24,5 +24,5 @@ add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_include_directories(${PROJECT_NAME}Tests PUBLIC ./applications/) target_include_directories(${PROJECT_NAME}Tests PUBLIC ./applications/)
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils ImageIO) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++ ImageIO)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -2,7 +2,7 @@
// #include "NewPlacement.hpp" // #include "NewPlacement.hpp"
#include "RayTracer.hpp" #include "RayTracer.hpp"
#include "Testing.hpp" #include "UnitTest++/UnitTest++.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h" #include "stb_image_write.h"
@ -47,63 +47,67 @@ bool compareCols(const RGBA& l, const RGBA& r) {
return true; return true;
} }
void testRT() { SUITE(RayTracer) {
using namespace tp; TEST(Basic) {
using namespace tp;
Scene scene; Scene scene;
scene.mCamera.lookAtPoint({ 0, 0, 0 }, { 2, 2, 2 }, { 0, 0, 1 }); scene.mCamera.lookAtPoint({ 0, 0, 0 }, { 2, 2, 2 }, { 0, 0, 1 });
scene.mCamera.setFOV(3.14 / 4); scene.mCamera.setFOV(3.14 / 4);
scene.mLights.append({ { 0, 0, 1.1f }, 1.f, 0.3f }); scene.mLights.append({ { 0, 0, 1.1f }, 1.f, 0.3f });
scene.mObjects.append(Object()); scene.mObjects.append(Object());
auto& object = scene.mObjects.last(); auto& object = scene.mObjects.last();
object.mTopology.Points = { object.mTopology.Points = {
{ 1.000000, 0.000000, 0.000000 }, { 1.000000, 0.000000, 0.000000 },
{ 0.000000, 1.000000, 0.000000 }, { 0.000000, 1.000000, 0.000000 },
{ 0.000000, 0.000000, 1.000000 }, { 0.000000, 0.000000, 1.000000 },
}; };
object.mTopology.Normals = { object.mTopology.Normals = {
{ 1.000000, 1.000000, 1.000000 }, { 1.000000, 1.000000, 1.000000 },
{ 1.000000, 1.000000, 1.000000 }, { 1.000000, 1.000000, 1.000000 },
{ 1.000000, 1.000000, 1.000000 }, { 1.000000, 1.000000, 1.000000 },
}; };
object.mTopology.Indexes = { object.mTopology.Indexes = {
{ 0, 1, 2 }, { 0, 1, 2 },
}; };
object.mCache.Source = &object.mTopology; object.mCache.Source = &object.mTopology;
object.mCache.updateCache(); object.mCache.updateCache();
RayTracer::RenderSettings settings = { RayTracer::RenderSettings settings = {
0, 0,
0, 0,
1, 1,
{ 10, 10 }, { 10, 10 },
}; };
RayTracer::OutputBuffers output; RayTracer::OutputBuffers output;
// output.reserve(RayTracer::RenderBuffer::Index2D(settings.size.x, settings.size.y)); // output.reserve(RayTracer::RenderBuffer::Index2D(settings.size.x, settings.size.y));
RayTracer rt; RayTracer rt;
rt.render(scene, output, settings); rt.render(scene, output, settings);
TEST(compareCols(output.color.get({ 6, 4 }), RGBA{ 0.560100f, 0.560100f, 0.560100f, 1.000000f })); CHECK(compareCols(output.color.get({ 6, 4 }), RGBA{ 0.560100f, 0.560100f, 0.560100f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 5 }), RGBA{ 0.353739f, 0.353739f, 0.353739f, 1.000000f })); CHECK(compareCols(output.color.get({ 6, 5 }), RGBA{ 0.353739f, 0.353739f, 0.353739f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 6 }), RGBA{ 0.242577f, 0.242577f, 0.242577f, 1.000000f })); CHECK(compareCols(output.color.get({ 6, 6 }), RGBA{ 0.242577f, 0.242577f, 0.242577f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 7 }), RGBA{ 0.176313f, 0.176313f, 0.176313f, 1.000000f })); CHECK(compareCols(output.color.get({ 6, 7 }), RGBA{ 0.176313f, 0.176313f, 0.176313f, 1.000000f }));
TEST(compareCols(output.color.get({ 6, 8 }), RGBA{ 0.000000f, 0.000000f, 0.000000f, 0.000000f })); CHECK(compareCols(output.color.get({ 6, 8 }), RGBA{ 0.000000f, 0.000000f, 0.000000f, 0.000000f }));
if (0) { if (0) {
writeImage(output.color); writeImage(output.color);
for (auto i = 0; i < output.color.size().x; i++) { for (auto i = 0; i < output.color.size().x; i++) {
for (auto j = 0; j < output.color.size().y; j++) { for (auto j = 0; j < output.color.size().y; j++) {
auto tmp = output.color.get({ i, j }); auto tmp = output.color.get({ i, j });
printf("TEST(compareCols(output.get({%i, %i}), RGBA{ %ff, %ff, %ff, %ff }));\n", i, j, tmp.r, tmp.g, tmp.b, tmp.a); printf(
"TEST(compareCols(output.get({%i, %i}), RGBA{ %ff, %ff, %ff, %ff }));\n", i, j, tmp.r, tmp.g, tmp.b, tmp.a
);
}
} }
} }
} }
@ -117,7 +121,9 @@ int main(int argc, char* argv[]) {
return 1; return 1;
} }
testRT(); bool res = UnitTest::RunAllTests();
TestModule.deinitialize(); TestModule.deinitialize();
return res;
} }

View file

@ -11,5 +11,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Allocators Containers)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

244
Strings/tests/Test.cpp Normal file
View file

@ -0,0 +1,244 @@
#include "UnitTest++/UnitTest++.h"
#include "Strings.hpp"
#include "StringLogic.hpp"
SUITE(Strings) {
using namespace tp;
typedef StringLogic<char> Logic;
struct TestStruct {
String str = "test data";
};
TEST(CoreLogic) {
String str;
CHECK(str.getIsConstFlag());
CHECK(str.getReferenceCount() == 2);
String str2;
CHECK(str.getIsConstFlag());
CHECK(str.getReferenceCount() == 3);
auto tmp = new TestStruct();
CHECK(tmp->str.getIsConstFlag());
CHECK(tmp->str.getReferenceCount() == 1);
str = tmp->str;
CHECK(str.getIsConstFlag());
CHECK(str.getReferenceCount() == 2);
delete tmp;
CHECK(str.getIsConstFlag());
CHECK(str.getReferenceCount() == 1);
}
TEST(Addition) {
String str1 = "abc";
String str2 = "def";
{ str1 + str2; }
{
CHECK(str1 + str2 == "abcdef");
CHECK(str1 + "aaaccc" == "abcaaaccc");
}
}
TEST(isNewLineChar) {
CHECK(Logic::isNewLineChar('\n'));
CHECK(Logic::isNewLineChar('\r'));
CHECK(!Logic::isNewLineChar('a'));
}
TEST(isEndChar) {
CHECK(Logic::isEndChar('\0'));
CHECK(!Logic::isEndChar('a'));
}
TEST(calcLength) {
const char* str1 = "Hello";
const char* str2 = "Wor\nld2";
CHECK(Logic::calcLength(str1) == 5);
CHECK(Logic::calcLength(str2) == 7);
}
TEST(insertLogic_emptyTarget) {
char inserted[40] = { "" };
const char* cur = "Hello";
const char* tar = "";
const char* result = "Hello";
Logic::insertLogic(inserted, 40, cur, tar, 5, 0);
CHECK(Logic::isEqualLogic(inserted, result));
}
TEST(insertLogic_emptyCurrent) {
char inserted[40] = { "" };
const char* cur = "";
const char* tar = "World";
const char* result = "World";
Logic::insertLogic(inserted, 40, cur, tar, 0, 5);
CHECK(Logic::isEqualLogic(inserted, result));
}
TEST(insertLogic_curLengthLessThanPos) {
char inserted[40] = { "" };
const char* cur = "Hello";
const char* tar = "World";
const char* result = "HelloWorld";
Logic::insertLogic(inserted, 40, cur, tar, 5, 5);
CHECK(Logic::isEqualLogic(inserted, result));
}
TEST(removeLogic_emptyCurrent) {
char removed[40] = { "" };
const char* cur = "";
const char* result = "";
Logic::removeLogic(removed, 40, cur, 0, 0);
CHECK(Logic::isEqualLogic(removed, result));
}
TEST(removeLogic_removeUntilEnd) {
char removed[40] = { "" };
const char* cur = "HelloWorld";
const char* result = "World";
Logic::removeLogic(removed, 40, cur, 0, 5);
CHECK(Logic::isEqualLogic(removed, result));
}
TEST(removeLogic_removeMiddleCharacters) {
char removed[40] = { "" };
const char* cur = "HelloWorld";
const char* result = "Helrld";
Logic::removeLogic(removed, 40, cur, 3, 7);
CHECK(Logic::isEqualLogic(removed, result));
}
TEST(insertLogicGood) {
char inserted[40] = { "" };
const char* cur = "Hello";
const char* tar = "World";
const char* result = "HelloWorld";
Logic::insertLogic(inserted, 40, cur, tar, 5, 5);
CHECK(Logic::isEqualLogic(inserted, result));
}
TEST(removeLogicGood) {
char removed[40] = { "" };
const char* cur = "HelloWorld";
const char* result = "Helld";
Logic::removeLogic(removed, 40, cur, 3, 8);
CHECK(Logic::isEqualLogic(removed, result));
}
TEST(convertStringToValue_alni) {
const char* str1 = "123";
const char* str2 = "456xyz";
const char* str3 = "789";
alni output;
CHECK(Logic::convertStringToValue(str1, output) && output == 123);
CHECK(!Logic::convertStringToValue(str2, output));
CHECK(Logic::convertStringToValue(str3, output) && output == 789);
}
TEST(convertStringToValue_alnf) {
const char* str1 = "12.34";
const char* str2 = "56.78xyz";
const char* str3 = "90.12";
alnf output;
CHECK(Logic::convertStringToValue(str1, output) && output == 12.34);
CHECK(!Logic::convertStringToValue(str2, output));
CHECK(Logic::convertStringToValue(str3, output) && output == 90.12);
}
TEST(convertStringToValue_bool) {
const char* str1 = "true";
const char* str2 = "false";
const char* str3 = "1";
const char* str4 = "0";
bool output;
CHECK(Logic::convertStringToValue(str1, output) && output == true);
CHECK(Logic::convertStringToValue(str2, output) && output == false);
CHECK(Logic::convertStringToValue(str3, output) && output == true);
CHECK(Logic::convertStringToValue(str4, output) && output == false);
}
TEST(convertValueToString_alni) {
alni input1 = 123;
alni input2 = -456;
char output[10];
CHECK(Logic::convertValueToString(input1, output, 10));
CHECK(Logic::isEqualLogic(output, "123"));
CHECK(Logic::convertValueToString(input2, output, 10));
CHECK(Logic::isEqualLogic(output, "-456"));
}
TEST(convertValueToString_alnf) {
alnf input1 = 12.34;
alnf input2 = -56.78;
char output[10];
CHECK(Logic::convertValueToString(input1, output, 10));
CHECK(Logic::isEqualLogic(output, "12.340000"));
CHECK(Logic::convertValueToString(input2, output, 10));
CHECK(Logic::isEqualLogic(output, "-56.78000"));
}
TEST(convertValueToString_bool) {
bool input1 = true;
bool input2 = false;
char output[10];
CHECK(Logic::convertValueToString(input1, output, 10));
CHECK(Logic::isEqualLogic(output, "true"));
CHECK(Logic::convertValueToString(input2, output, 10));
CHECK(Logic::isEqualLogic(output, "false"));
}
TEST(isEqualLogic) {
const char* str1 = "Hello";
const char* str2 = "Hello";
const char* str3 = "World";
const char* str4 = "Hello2";
CHECK(Logic::isEqualLogic(str1, str2));
CHECK(!Logic::isEqualLogic(str1, str4));
CHECK(!Logic::isEqualLogic(str1, str3));
}
TEST(calcLineOffsets) {
const char* str = "\n\nHello\nWorld\n\n ";
Buffer<Logic::Index> offsets;
Logic::calcLineOffsets(str, Logic::calcLength(str), offsets);
CHECK(offsets.size() == 7);
CHECK(offsets[0] == 0);
CHECK(offsets[1] == 1);
CHECK(offsets[2] == 2);
CHECK(offsets[3] == 8);
CHECK(offsets[4] == 14);
CHECK(offsets[5] == 15);
CHECK(offsets[6] == 16);
}
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleStrings, &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("StringsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
auto res = UnitTest::RunAllTests();
testModule.deinitialize();
return res;
}

View file

@ -1,24 +0,0 @@
#include "Tests.hpp"
#include "Strings.hpp"
void testStringLogic();
void testStrings();
void testLogging();
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleStrings, &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("StringsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testStringLogic();
testStrings();
testLogging();
testModule.deinitialize();
}

View file

@ -1,4 +0,0 @@
#pragma once
#include "Allocators.hpp"
#include "Testing.hpp"

View file

@ -1,7 +0,0 @@
#include "Logging.hpp"
#include "Tests.hpp"
using namespace tp;
TEST_DEF(Logging) {}

View file

@ -1,47 +0,0 @@
#include "Strings.hpp"
#include "Tests.hpp"
using namespace tp;
struct TestStruct {
String str = "test data";
};
TEST_DEF_STATIC(Addition) {
String str1 = "abc";
String str2 = "def";
{ str1 + str2; }
{
TEST(str1 + str2 == "abcdef");
TEST(str1 + "aaaccc" == "abcaaaccc");
}
}
TEST_DEF_STATIC(Simple) {
String str;
TEST(str.getIsConstFlag());
TEST(str.getReferenceCount() == 2);
String str2;
TEST(str.getIsConstFlag());
TEST(str.getReferenceCount() == 3);
auto tmp = new TestStruct();
TEST(tmp->str.getIsConstFlag());
TEST(tmp->str.getReferenceCount() == 1);
str = tmp->str;
TEST(str.getIsConstFlag());
TEST(str.getReferenceCount() == 2);
delete tmp;
TEST(str.getIsConstFlag());
TEST(str.getReferenceCount() == 1);
}
TEST_DEF(Strings) {
testSimple();
testAddition();
}

View file

@ -1,243 +0,0 @@
#include "StringLogic.hpp"
#include "Tests.hpp"
using namespace tp;
typedef StringLogic<char> Logic;
TEST_DEF(isNewLineChar) {
// Test isNewLineChar function
TEST(Logic::isNewLineChar('\n'));
TEST(Logic::isNewLineChar('\r'));
TEST(!Logic::isNewLineChar('a'));
}
TEST_DEF(isEndChar) {
// Test isEndChar function
TEST(Logic::isEndChar('\0'));
TEST(!Logic::isEndChar('a'));
}
TEST_DEF(calcLength) {
// Test calcLength function
const char* str1 = "Hello";
const char* str2 = "Wor\nld2";
TEST(Logic::calcLength(str1) == 5);
TEST(Logic::calcLength(str2) == 7);
}
// ------------------------------- Inserting / Removing ----------------------------------------- //
TEST_DEF(insertLogic_emptyTarget) {
// Test insertLogic function with an empty target string
char inserted[40] = { "" };
const char* cur = "Hello";
const char* tar = "";
const char* result = "Hello";
Logic::insertLogic(inserted, 40, cur, tar, 5, 0);
TEST(Logic::isEqualLogic(inserted, result));
}
TEST_DEF(insertLogic_emptyCurrent) {
// Test insertLogic function with an empty current string
char inserted[40] = { "" };
const char* cur = "";
const char* tar = "World";
const char* result = "World";
Logic::insertLogic(inserted, 40, cur, tar, 0, 5);
TEST(Logic::isEqualLogic(inserted, result));
}
TEST_DEF(insertLogic_curLengthLessThanPos) {
// Test insertLogic function with current length less than the insert position
char inserted[40] = { "" };
const char* cur = "Hello";
const char* tar = "World";
const char* result = "HelloWorld";
Logic::insertLogic(inserted, 40, cur, tar, 10, 5);
TEST(Logic::isEqualLogic(inserted, result));
}
TEST_DEF(removeLogic_emptyCurrent) {
// Test removeLogic function with an empty current string
char removed[40] = { "" };
const char* cur = "";
const char* result = "";
Logic::removeLogic(removed, 40, cur, 0, 0);
TEST(Logic::isEqualLogic(removed, result));
}
TEST_DEF(removeLogic_removeUntilEnd) {
// Test removeLogic function by removing until the end of the current string
char removed[40] = { "" };
const char* cur = "HelloWorld";
const char* result = "World";
Logic::removeLogic(removed, 40, cur, 0, 5);
TEST(Logic::isEqualLogic(removed, result));
}
TEST_DEF(removeLogic_removeMiddleCharacters) {
// Test removeLogic function by removing characters in the middle of the current string
char removed[40] = { "" };
const char* cur = "HelloWorld";
const char* result = "Helrld";
Logic::removeLogic(removed, 40, cur, 3, 7);
TEST(Logic::isEqualLogic(removed, result));
}
TEST_DEF(insertLogicGood) {
// Test insertLogic function
char inserted[40] = { "" };
const char* cur = "Hello";
const char* tar = "World";
const char* result = "HelloWorld";
Logic::insertLogic(inserted, 40, cur, tar, 5, 5);
TEST(Logic::isEqualLogic(inserted, result));
}
TEST_DEF(removeLogicGood) {
// Test removeLogic function
char removed[40] = { "" };
const char* cur = "HelloWorld";
const char* result = "Helo";
Logic::removeLogic(removed, 40, cur, 3, 8);
TEST(Logic::isEqualLogic(removed, result));
}
TEST_DEF(insertLogic) {
// Test insertLogic function
testinsertLogicGood();
testinsertLogic_emptyTarget();
testinsertLogic_emptyCurrent();
// testinsertLogic_curLengthLessThanPos();
}
TEST_DEF(removeLogic) {
// Test removeLogic function
// testremoveLogicGood();
testremoveLogic_emptyCurrent();
testremoveLogic_removeUntilEnd();
testremoveLogic_removeMiddleCharacters();
}
// -------------------------------- Conversions --------------------------------------- //
TEST_DEF(convertStringToValue_alni) {
const char* str1 = "123";
const char* str2 = "456xyz";
const char* str3 = "789";
alni output;
TEST(Logic::convertStringToValue(str1, output) && output == 123);
TEST(!Logic::convertStringToValue(str2, output));
TEST(Logic::convertStringToValue(str3, output) && output == 789);
}
TEST_DEF(convertStringToValue_alnf) {
const char* str1 = "12.34";
const char* str2 = "56.78xyz";
const char* str3 = "90.12";
alnf output;
TEST(Logic::convertStringToValue(str1, output) && output == 12.34);
TEST(!Logic::convertStringToValue(str2, output));
TEST(Logic::convertStringToValue(str3, output) && output == 90.12);
}
TEST_DEF(convertStringToValue_bool) {
const char* str1 = "true";
const char* str2 = "false";
const char* str3 = "1";
const char* str4 = "0";
bool output;
TEST(Logic::convertStringToValue(str1, output) && output == true);
TEST(Logic::convertStringToValue(str2, output) && output == false);
TEST(Logic::convertStringToValue(str3, output) && output == true);
TEST(Logic::convertStringToValue(str4, output) && output == false);
}
TEST_DEF(convertValueToString_alni) {
alni input1 = 123;
alni input2 = -456;
char output[10];
TEST(Logic::convertValueToString(input1, output, 10));
TEST(Logic::isEqualLogic(output, "123"));
TEST(Logic::convertValueToString(input2, output, 10));
TEST(Logic::isEqualLogic(output, "-456"));
}
TEST_DEF(convertValueToString_alnf) {
alnf input1 = 12.34;
alnf input2 = -56.78;
char output[10];
TEST(Logic::convertValueToString(input1, output, 10));
TEST(Logic::isEqualLogic(output, "12.340000"));
TEST(Logic::convertValueToString(input2, output, 10));
TEST(Logic::isEqualLogic(output, "-56.78000"));
}
TEST_DEF(convertValueToString_bool) {
bool input1 = true;
bool input2 = false;
char output[10];
TEST(Logic::convertValueToString(input1, output, 10));
TEST(Logic::isEqualLogic(output, "true"));
TEST(Logic::convertValueToString(input2, output, 10));
TEST(Logic::isEqualLogic(output, "false"));
}
TEST_DEF(Conversions) {
testconvertValueToString_bool();
testconvertValueToString_alnf();
testconvertValueToString_alni();
testconvertStringToValue_bool();
testconvertStringToValue_alnf();
testconvertStringToValue_alni();
}
// ------------------------------------------------------------------------ //
TEST_DEF(isEqualLogic) {
// Test isEqualLogic function
const char* str1 = "Hello";
const char* str2 = "Hello";
const char* str3 = "World";
const char* str4 = "Hello2";
TEST(Logic::isEqualLogic(str1, str2));
TEST(!Logic::isEqualLogic(str1, str4));
TEST(!Logic::isEqualLogic(str1, str3));
}
TEST_DEF(calcLineOffsets) {
// Test calcLineOffsets function
const char* str = "\n\nHello\nWorld\n\n ";
Buffer<Logic::Index> offsets;
Logic::calcLineOffsets(str, Logic::calcLength(str), offsets);
TEST(offsets.size() == 7);
TEST(offsets[0] == 0);
TEST(offsets[1] == 1);
TEST(offsets[2] == 2);
TEST(offsets[3] == 8);
TEST(offsets[4] == 14);
TEST(offsets[5] == 15);
TEST(offsets[6] == 16);
}
TEST_DEF(StringLogic) {
testisNewLineChar();
testisEndChar();
testcalcLength();
testisEqualLogic();
testcalcLineOffsets();
testinsertLogic();
testremoveLogic();
testConversions();
}

8
TODO
View file

@ -1,5 +1,13 @@
ALL: ALL:
Remove utils module
add scoped api for module manifest
Add windows old beautifull window to graphics
add windows callstack support
remove loki library
remove archiver and add boost serialization
Check Warnings Check Warnings
Gradually introduce STL into the project (replace own classes or add seamless interface and conversions into STL) Gradually introduce STL into the project (replace own classes or add seamless interface and conversions into STL)
Make all modules stable with tests Make all modules stable with tests

View file

@ -12,5 +12,5 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Containers)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)

View file

@ -1,79 +0,0 @@
#include "Testing.hpp"
#include "Utils.hpp"
#include <iostream>
#include <string>
using namespace tp;
Testing tp::gTesting;
void Testing::startTest(const char* name) {
auto newNode = new (malloc(sizeof(TestingNode))) TestingNode{ {}, {}, name, mCurrent };
mCurrent->mSubTests.pushBack(newNode);
mCurrent = mCurrent->mSubTests.last()->data;
}
void Testing::endTest() {
if (mCurrent->mParent) {
mCurrent = mCurrent->mParent;
}
}
void Testing::addFailedCheck(const FailedCheck& info) {
auto lastRecord = &mCurrent->mFailedChecks.last()->data;
if (lastRecord && lastRecord->failedCheck.file == info.file && lastRecord->failedCheck.line == info.line) {
lastRecord->times++;
return;
}
mCurrent->mFailedChecks.pushBack({ info, 1 });
}
void Testing::reportState() {
mRootTest.updateState();
printf("\n");
mRootTest.report();
}
bool Testing::hasFailed() {
mRootTest.updateState();
return mRootTest.mHasFailed;
}
void Testing::setRootName(const char* name) { mRootTest.mName = name; }
void Testing::TestingNode::updateState() {
for (auto child : mSubTests) {
child->updateState();
mHasFailed = child->mHasFailed;
if (mHasFailed) return;
}
mHasFailed = mFailedChecks.length();
}
void Testing::TestingNode::report(const char* path) const {
if (!mHasFailed) {
return;
}
auto newPath = path ? std::string(path) + "/" + mName : std::string(mName);
for (auto check : mFailedChecks) {
auto failedCheck = &check.data().failedCheck;
auto times = check.data().times;
printf("%s Failed - (%s) %s:%llu x%i\n", newPath.c_str(), failedCheck->expression, failedCheck->file, failedCheck->line, (halni) times);
}
for (const auto& child : mSubTests) {
child->report(newPath.c_str());
}
}
Testing::TestingNode::~TestingNode() {
for (const auto& child : mSubTests) {
child.data()->~TestingNode();
free(child.data());
}
}

View file

@ -3,8 +3,6 @@
#include "ContainersCommon.hpp" #include "ContainersCommon.hpp"
#include "Testing.hpp"
#include <ctime> #include <ctime>
#include <random> #include <random>
@ -19,10 +17,6 @@ static bool initialize(const tp::ModuleManifest*) {
static void deinitialize(const tp::ModuleManifest*) { static void deinitialize(const tp::ModuleManifest*) {
deinitializeCallStackCapture(); deinitializeCallStackCapture();
tp::gTesting.reportState();
if (tp::gTesting.hasFailed()) {
exit(1);
}
} }
namespace tp { namespace tp {

View file

@ -1,71 +0,0 @@
#pragma once
#include "List.hpp"
namespace tp {
class Testing {
public:
struct FailedCheck {
const char* expression = nullptr;
const char* file = nullptr;
ualni line = 0;
};
Testing() = default;
void startTest(const char* name);
void endTest();
void addFailedCheck(const FailedCheck& info);
void reportState();
void setRootName(const char* name);
[[nodiscard]] bool hasFailed();
private:
struct TestingNode {
struct FailedCheckRecord {
FailedCheck failedCheck;
ualni times;
};
List<FailedCheckRecord> mFailedChecks;
List<TestingNode*> mSubTests;
const char* mName = "Unnamed";
TestingNode* mParent = nullptr;
bool mHasFailed = false;
void report(const char* path = nullptr) const;
void updateState();
~TestingNode();
};
TestingNode mRootTest;
TestingNode* mCurrent = &mRootTest;
};
extern Testing gTesting;
}
#define TEST_DEF(Name) \
static void Name##FunctorBody(); \
void test##Name() { \
tp::gTesting.startTest(#Name); \
Name##FunctorBody(); \
tp::gTesting.endTest(); \
} \
void Name##FunctorBody()
#define TEST_DEF_STATIC(Name) \
static void Name##FunctorBody(); \
static void test##Name() { \
tp::gTesting.startTest(#Name); \
Name##FunctorBody(); \
tp::gTesting.endTest(); \
} \
void Name##FunctorBody()
#define TEST(expr) \
if (!(expr)) tp::gTesting.addFailedCheck({ #expr, __FILE__, __LINE__ })
#define TEST_ASSERT(expr) \
TEST(expr); \
if (!(expr)) return
#define TEST_EQUAL(l, r) \
if (!((l) == (r))) tp::gTesting.addFailedCheck({ #l " == " #r, __FILE__, __LINE__ })

View file

@ -1,6 +1,7 @@
#include "UnitTest++/UnitTest++.h"
#include "Debugging.hpp" #include "Debugging.hpp"
#include "Testing.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <cstdio> #include <cstdio>
@ -42,22 +43,23 @@ void root() {
third(); third();
} }
TEST_DEF(Debugging) { SUITE(Utils) {
root(); TEST(CallStackCapture) {
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("UtilsTest", nullptr, nullptr, deps);
gCSCapture->logAll(); REQUIRE CHECK(testModule.initialize());
}
int main() { root();
tp::ModuleManifest* deps[] = { &tp::gModuleUtils, nullptr }; gCSCapture->logAll();
tp::ModuleManifest testModule("UtilsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) { testModule.deinitialize();
return 1;
} }
testDebugging(); TEST(CAllStackCaptureContent) {
CHECK(false);
testModule.deinitialize(); }
} }
int main() { return UnitTest::RunAllTests(); }

View file

@ -12,7 +12,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Math Strings)
enable_testing() enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp") file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES}) add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils) target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests) add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
### -------------------------- Applications -------------------------- ### ### -------------------------- Applications -------------------------- ###

View file

@ -1 +1,6 @@
int main() {}
#include "UnitTest++/UnitTest++.h"
TEST(NO_TESTS) { CHECK(false); }
int main() { return UnitTest::RunAllTests(); }