diff --git a/unit-test/Makefile b/unit-test/Makefile new file mode 100644 index 0000000..da670c0 --- /dev/null +++ b/unit-test/Makefile @@ -0,0 +1,49 @@ +PROJECT = unittest + +CC=gcc -g + +SHARED_FLAG = -fPIC -shared + +SRCS = . +SRCS += ./ut +SRCS += ../crc + +LIB = -lstdc++ -lpthread + +INC = -I. +INC += -I.. + +OBJDIR = ./obj/ + +CPP_SRCS = $(foreach d,$(SRCS),$(wildcard $(d)/*.cpp)) +C_SRCS = $(foreach d,$(SRCS),$(wildcard $(d)/*.c)) + +CPP_OBJS = $(patsubst %.cpp, %.o, $(CPP_SRCS)) +C_OBJS = $(patsubst %.c, %.o, $(C_SRCS)) + +OBJS = $(CPP_OBJS) +OBJS += $(C_OBJS) +all : $(PROJECT) + +$(PROJECT) : $(OBJS) $(MODULE) + $(CC) -o $@ $(OBJS) $(LIB) + @echo "" + @echo "+--------------------------------------------+" + @echo "| Finish compilation unittest |" + @echo "+--------------------------------------------+" + @echo "| copyright(c)Wang Yaofu voipman@qq.com |" + @echo "+--------------------------------------------+" + +clean: + rm -rf *.o *.a *_unittest + +install : + test -d ../test || mkdir -p ../test + cp unittest ../test + +%.o : %.cpp + $(CC) $(INC) -c $< -o $@ +%.o : %.c + $(CC) $(INC) -c $< -o $@ +%.o : %.cc + $(CC) $(INC) -c $< -o $@ \ No newline at end of file diff --git a/unit-test/crc_test.cpp b/unit-test/crc_test.cpp new file mode 100644 index 0000000..0c9fa70 --- /dev/null +++ b/unit-test/crc_test.cpp @@ -0,0 +1,37 @@ +/* +** Copyright (C) 2018 Wang Yaofu +** All rights reserved. +** +**Author:Wang Yaofu voipman@qq.com +**Description: The unit test file of crc. +*/ + +#include "ut/test_harness.h" +#include "../crc/crc16.h" +#include "../crc/crc32.h" +#include "../crc/crc64.h" +#include + +TEST(CRC16Test, BasicTest) +{ + const char* inData = "123456789"; + uint16_t expect = 0x31C3; + + EXPECT_EQ(crc16(inData, 9), expect); +} + +TEST(CRC32Test, BasicTest) +{ + const char* inData = "123456789"; + uint32_t expect = 3421780262 ; + + EXPECT_EQ(crc32(inData, 9), expect); +} + +TEST(CRC64Test, BasicTest) +{ + const char* inData = "123456789"; + + uint64_t expect = 16845390139448941002L; + EXPECT_EQ(crc64(inData, 9), expect); +} \ No newline at end of file diff --git a/unit-test/ut/test_harness.cpp b/unit-test/ut/test_harness.cpp new file mode 100644 index 0000000..5c56b1b --- /dev/null +++ b/unit-test/ut/test_harness.cpp @@ -0,0 +1,95 @@ +#include "test_harness.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace common { + namespace test { + int errCount = 0; + namespace { + struct Test { + const char* base; + const char* name; + void(*func)(); + }; + std::vector* tests; + } + + bool RegisterTest(const char* base, const char* name, void(*func)()) { + if (tests == NULL) { + tests = new std::vector; + } + 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; +} diff --git a/unit-test/ut/test_harness.h b/unit-test/ut/test_harness.h new file mode 100644 index 0000000..e73633e --- /dev/null +++ b/unit-test/ut/test_harness.h @@ -0,0 +1,152 @@ +#pragma once +#include +#include +#include + +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 \ + 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 \ + 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 + 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 diff --git a/unit-test/ut/test_harness.o b/unit-test/ut/test_harness.o new file mode 100644 index 0000000..f7c2fdb Binary files /dev/null and b/unit-test/ut/test_harness.o differ