Created
April 4, 2023 13:43
-
-
Save ialexpovad/2f5c2565e0481e720ace9bdc20ecb29a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "utest.h" | |
#include <string> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <sys/time.h> | |
#include <vector> | |
namespace common { | |
namespace test { | |
int errCount = 0; | |
namespace { | |
struct Test { | |
const char* base; | |
const char* name; | |
void(*func)(); | |
}; | |
std::vector<Test>* tests; | |
} | |
bool RegisterTest(const char* base, const char* name, void(*func)()) { | |
if (tests == NULL) { | |
tests = new std::vector<Test>; | |
} | |
Test t; | |
t.base = base; | |
t.name = name; | |
t.func = func; | |
tests->push_back(t); | |
return true; | |
} | |
int RunAllTests(const char* matcher) { | |
int num = 0; | |
if (tests != NULL) { | |
for (size_t i = 0; i < tests->size(); i++) { | |
const Test& t = (*tests)[i]; | |
if (matcher != NULL) { | |
std::string name = t.base; | |
name.push_back('.'); | |
name.append(t.name); | |
if (strstr(name.c_str(), matcher) == NULL) { | |
continue; | |
} | |
} | |
fprintf(stderr, "\033[0;32m[ RUN ] ==== Test %s.%s\n", t.base, t.name); | |
fprintf(stderr, "\033[0m"); | |
(*t.func)(); | |
++num; | |
} | |
} | |
fprintf(stderr, "\033[0;32m[ PASS ] ==== PASSED %d tests\n", num); | |
fprintf(stderr, "\033[0;31m[ NOPASS ] ==== ERROR %d tests\n", errCount); | |
fprintf(stderr, "\033[0m\n"); | |
return 0; | |
} | |
std::string TmpDir() { | |
return "/tmp"; | |
} | |
int RandomSeed() { | |
return 301; | |
} | |
TestPerfomence::TestPerfomence() { | |
startMs_ = NowMs(); | |
} | |
TestPerfomence::TestPerfomence(int size) { | |
startMs_ = NowMs(); | |
fprintf(stderr, | |
"\033[0;32m[ RUN ] ==== start to run %lu cases.\n", | |
size); | |
} | |
TestPerfomence::~TestPerfomence() { | |
long endMs = NowMs(); | |
fprintf(stderr, | |
"\033[0;32m[ RUN ] ==== start at %lu, stop at %lu, cost:[%lu]\n", | |
startMs_, endMs, endMs - startMs_); | |
} | |
long TestPerfomence::NowMs() { | |
struct timeval timeNow; | |
gettimeofday(&timeNow, NULL); | |
return (timeNow.tv_sec) * 1000 + timeNow.tv_usec / 1000; | |
} | |
} | |
} // namespace common | |
using namespace common::test; | |
int main(int argc, char** argv) { | |
common::test::RunAllTests(NULL); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sstream> | |
namespace common { | |
namespace test { | |
extern int errCount; | |
// Run some of the tests registered by the TEST() macro. If the | |
// environment variable "LEVELDB_TESTS" is not set, runs all tests. | |
// Otherwise, runs only the tests whose name contains the value of | |
// "LEVELDB_TESTS" as a substring. E.g., suppose the tests are: | |
// TEST(Foo, Hello) { ... } | |
// TEST(Foo, World) { ... } | |
// LEVELDB_TESTS=Hello will run the first test | |
// LEVELDB_TESTS=o will run both tests | |
// LEVELDB_TESTS=Junk will run no tests | |
// | |
// Returns 0 if all tests pass. | |
// Dies or returns a non-zero value if some test fails. | |
extern int RunAllTests(const char* matcher); | |
// Return the directory to use for temporary storage. | |
extern std::string TmpDir(); | |
// Return a randomization seed for this run. Typically returns the | |
// same number on repeated invocations of this binary, but automated | |
// runs may be able to vary the seed. | |
extern int RandomSeed(); | |
// An instance of Tester is allocated to hold temporary state during | |
// the execution of an assertion. | |
class Tester { | |
private: | |
bool ok_; | |
const char* fname_; | |
int line_; | |
std::stringstream ss_; | |
public: | |
Tester(const char* f, int l) | |
: ok_(true), fname_(f), line_(l) { | |
} | |
~Tester() { | |
if (!ok_) { | |
fprintf(stderr, "\033[0;31m[ ERROR ] ==== %s:%d:%s\n", | |
fname_, line_, ss_.str().c_str()); | |
fprintf(stderr, "\033[0m"); | |
errCount++; | |
//exit(1); | |
} | |
} | |
Tester& Is(bool b, const char* msg) { | |
if (!b) { | |
ss_ << " Assertion failure " << msg; | |
ok_ = false; | |
} | |
return *this; | |
} | |
#define BINARY_OP(name,op) \ | |
template <class X, class Y> \ | |
Tester& name(const X& x, const Y& y) { \ | |
if (! (x op y)) { \ | |
ss_ << " failed: Expect:" << x << (" " #op " ") << "Actual:" << y; \ | |
ok_ = false; \ | |
} \ | |
return *this; \ | |
} | |
BINARY_OP(IsEq, ==) | |
BINARY_OP(IsNe, !=) | |
BINARY_OP(IsGe, >=) | |
BINARY_OP(IsGt, >) | |
BINARY_OP(IsLe, <=) | |
BINARY_OP(IsLt, <) | |
#undef BINARY_OP | |
#define DOUBLE_OP(name,op) \ | |
template <class X, class Y> \ | |
Tester& name(const X& x, const Y& y) { \ | |
if (! (x - y > -0.000001 && x-y <0.000001)) { \ | |
ss_ << " failed: Expect:" << x << (" " #op " ") << "Actual:" << y; \ | |
ok_ = false; \ | |
} \ | |
return *this; \ | |
} | |
DOUBLE_OP(IsDoubleEq, ==) | |
#undef DOUBLE_OP | |
// Attach the specified value to the error message if an error has occurred | |
template <class V> | |
Tester& operator<<(const V& value) { | |
if (!ok_) { | |
ss_ << " " << value; | |
} | |
return *this; | |
} | |
}; | |
#define ASSERT_TRUE(c) ::common::test::Tester(__FILE__, __LINE__).Is((c), #c) | |
#define ASSERT_FALSE(c) ::common::test::Tester(__FILE__, __LINE__).Is(!(c), #c) | |
#define ASSERT_EQ(a,b) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) | |
#define ASSERT_NE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) | |
#define ASSERT_GE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsGe((a),(b)) | |
#define ASSERT_GT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsGt((a),(b)) | |
#define ASSERT_LE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLe((a),(b)) | |
#define ASSERT_LT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) | |
#define EXPECT_GT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) | |
#define EXPECT_LT(a,b) ::common::test::Tester(__FILE__, __LINE__).IsLt((a),(b)) | |
#define EXPECT_EQ(a,b) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(b)) | |
#define EXPECT_NE(a,b) ::common::test::Tester(__FILE__, __LINE__).IsNe((a),(b)) | |
#define EXPECT_DOUBLE_EQ(a,b) ::common::test::Tester(__FILE__, __LINE__).IsDoubleEq((a),(b)) | |
#define EXPECT_TRUE(a) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(true)) | |
#define EXPECT_FALSE(a) ::common::test::Tester(__FILE__, __LINE__).IsEq((a),(false)) | |
#define EXPECT_THROW(a,exceptions) try {a;} catch(exceptions e) {EXPECT_TRUE(true);} catch(...) {EXPECT_TRUE(false);} | |
#define EXPECT_ANY_THROW(a) try {a;} catch(...) {EXPECT_TRUE(true);} | |
#define TCONCAT(a,b) TCONCAT1(a,b) | |
#define TCONCAT1(a,b) a##b | |
#define TEST(base,name) \ | |
class TCONCAT(_Test_,base##name) : public ::common::test::TestBase { \ | |
public: \ | |
void _Run(); \ | |
static void _RunIt() { \ | |
TCONCAT(_Test_,base##name) t; \ | |
t._Run(); \ | |
} \ | |
}; \ | |
bool TCONCAT(_Test_ignored_,base##name) = \ | |
::common::test::RegisterTest(#base, #name, &TCONCAT(_Test_,base##name)::_RunIt); \ | |
void TCONCAT(_Test_,base##name)::_Run() | |
// Register the specified test. Typically not used directly, but | |
// invoked via the macro expansion of TEST. | |
extern bool RegisterTest(const char* base, const char* name, void (*func)()); | |
class TestBase {}; | |
class TestPerfomence { | |
public: | |
TestPerfomence(); | |
TestPerfomence(int size); | |
~TestPerfomence(); | |
long NowMs(); | |
private: | |
long startMs_; | |
}; | |
#define TEST_PERF(a,size) ::common::test::TestPerfomence a(size); | |
} // namespace test | |
} // namespace common |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment