refactor tests to use the microtest framework
This commit is contained in:
parent
2890cd368e
commit
681fbe42d2
14
Makefile
14
Makefile
|
@ -7,18 +7,18 @@ SRCPARSER = src/parser
|
|||
PARSERFILES = $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
||||
LIBCPP = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(SRCPARSER)/bison_parser.cpp $(SRCPARSER)/flex_lexer.cpp
|
||||
LIBOBJ = $(LIBCPP:%.cpp=%.o)
|
||||
TESTCPP = $(shell find test/lib/ -name '*.cpp')
|
||||
TESTCPP = $(shell find test/ -name '*.cpp')
|
||||
|
||||
ALLLIB = $(shell find $(SRC) -name '*.cpp' -not -path "$(SRCPARSER)/*") $(shell find $(SRC) -name '*.h' -not -path "$(SRCPARSER)/*")
|
||||
ALLTEST = $(shell find test/lib/ -name '*.cpp') $(shell find test/lib/ -name '*.h')
|
||||
|
||||
# compile & link flages
|
||||
CFLAGS = -std=c++11 -Wall -fPIC
|
||||
CFLAGS = -std=c++11 -Wall -fPIC -g
|
||||
LIBFLAGS = -shared
|
||||
TARGET = libsqlparser.so
|
||||
INSTALL = /usr/local
|
||||
|
||||
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++
|
||||
CTESTFLAGS = -Wall -Isrc/ -Itest/ -L./ -std=c++11 -lstdc++ -g
|
||||
|
||||
all: library
|
||||
|
||||
|
@ -58,7 +58,7 @@ format:
|
|||
### Test ###
|
||||
############
|
||||
|
||||
test: $(BIN)/sql_tests $(BIN)/sql_grammar_test
|
||||
test: $(BIN)/sql_tests
|
||||
bash test/test.sh
|
||||
|
||||
# test whete
|
||||
|
@ -68,8 +68,4 @@ test_install:
|
|||
|
||||
$(BIN)/sql_tests: library
|
||||
@mkdir -p $(BIN)/
|
||||
$(CXX) $(CTESTFLAGS) $(TESTCPP) test/sql_tests.cpp -o $(BIN)/sql_tests -lsqlparser
|
||||
|
||||
$(BIN)/sql_grammar_test: library
|
||||
@mkdir -p $(BIN)/
|
||||
$(CXX) $(CTESTFLAGS) test/sql_grammar_test.cpp -o $(BIN)/sql_grammar_test -lsqlparser
|
||||
$(CXX) $(CTESTFLAGS) $(TESTCPP) -o $(BIN)/sql_tests -lsqlparser
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
|
||||
#include "test.h"
|
||||
|
||||
|
||||
class TestsManager {
|
||||
// Note: static initialization fiasco
|
||||
// http://www.parashift.com/c++-faq-lite/static-init-order.html
|
||||
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
||||
public:
|
||||
static std::vector<std::string>& testNames() {
|
||||
static std::vector<std::string> testNames;
|
||||
return testNames;
|
||||
}
|
||||
|
||||
static std::vector<void (*)(void)>& tests() {
|
||||
static std::vector<void (*)(void)> tests;
|
||||
return tests;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int AddTest(void (*foo)(void), std::string name) {
|
||||
TestsManager::tests().push_back(foo);
|
||||
TestsManager::testNames().push_back(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t RunTests() {
|
||||
size_t numFailed = 0;
|
||||
for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
|
||||
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::testNames()[i].c_str());
|
||||
|
||||
try {
|
||||
// Run test
|
||||
(*TestsManager::tests()[i])();
|
||||
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::testNames()[i].c_str());
|
||||
|
||||
} catch (AssertionFailedException& e) {
|
||||
printf("\033[1;31m{ failed} %s\n", TestsManager::testNames()[i].c_str());
|
||||
printf("\tAssertion failed: %s\n\033[0m", e.what());
|
||||
numFailed++;
|
||||
}
|
||||
}
|
||||
return numFailed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
size_t numFailed = RunTests();
|
||||
if (numFailed == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#ifndef __TEST_H__
|
||||
#define __TEST_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#define TEST(name) \
|
||||
void name();\
|
||||
namespace g_dummy {\
|
||||
int _##name = AddTest(name, #name);\
|
||||
}\
|
||||
void name()
|
||||
|
||||
|
||||
#define ASSERT(cond) if (!(cond)) throw AssertionFailedException(#cond);
|
||||
|
||||
#define ASSERT_TRUE(cond) ASSERT(cond);
|
||||
#define ASSERT_FALSE(cond) if (cond) throw AssertionFailedException(#cond);
|
||||
|
||||
#define ASSERT_NULL(value) ASSERT_TRUE(value == NULL);
|
||||
#define ASSERT_NOTNULL(value) ASSERT_TRUE(value != NULL);
|
||||
|
||||
#define ASSERT_STREQ(a, b) \
|
||||
if (std::string(a).compare(std::string(b)) != 0) throw AssertionFailedException(#a " == " #b)
|
||||
#define ASSERT_EQ(a, b) \
|
||||
if (a != b) { \
|
||||
std::cout << "Actual values: " << a << " != " << b << std::endl; \
|
||||
} \
|
||||
ASSERT(a == b);
|
||||
|
||||
|
||||
|
||||
class AssertionFailedException: public std::exception {
|
||||
public:
|
||||
AssertionFailedException(std::string msg) :
|
||||
std::exception(),
|
||||
_msg(msg) {};
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return _msg.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string _msg;
|
||||
};
|
||||
|
||||
int AddTest(void (*foo)(void), std::string name);
|
||||
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
|
||||
#include "test.h"
|
||||
#include "helper.h"
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
#include "sql_asserts.h"
|
||||
#include "SQLParser.h"
|
||||
|
||||
using namespace hsql;
|
|
@ -5,6 +5,8 @@
|
|||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
#include "SQLParser.h"
|
||||
|
||||
using namespace hsql;
|
||||
|
@ -30,10 +32,11 @@ std::vector<std::string> readlines(std::string path) {
|
|||
|
||||
#define STREQ(a, b) (std::string(a).compare(std::string(b)) == 0)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc <= 1) {
|
||||
TEST(AutoGrammarTest) {
|
||||
const std::vector<std::string>& args = mt::Runtime::args();
|
||||
if (args.size() <= 1) {
|
||||
fprintf(stderr, "Usage: grammar_test [--false] [-f path] query, ...\n");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
bool globalExpectFalse = false;
|
||||
|
@ -41,12 +44,12 @@ int main(int argc, char *argv[]) {
|
|||
std::string filePath = "";
|
||||
|
||||
// Parse command line arguments
|
||||
int i = 1;
|
||||
for (; i < argc; ++i) {
|
||||
if (STREQ(argv[i], "--false")) globalExpectFalse = true;
|
||||
else if (STREQ(argv[i], "-f")) {
|
||||
uint i = 1;
|
||||
for (; i < args.size(); ++i) {
|
||||
if (STREQ(args[i], "--false")) globalExpectFalse = true;
|
||||
else if (STREQ(args[i], "-f")) {
|
||||
useFile = true;
|
||||
filePath = argv[++i];
|
||||
filePath = args[++i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -58,7 +61,7 @@ int main(int argc, char *argv[]) {
|
|||
if (useFile) {
|
||||
queries = readlines(filePath);
|
||||
} else {
|
||||
for (; i < argc; ++i) queries.push_back(argv[i]);
|
||||
for (; i < args.size(); ++i) queries.push_back(args[i]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -97,9 +100,9 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if (numFailed == 0) {
|
||||
printf("\033[0;32m{ ok} \033[0mAll %lu grammar tests completed successfully!\n", queries.size());
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "\033[0;31m{ failed} \033[0mSome grammar tests failed! %d out of %lu tests failed!\n", numFailed, queries.size());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(numFailed, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* sql_tests.cpp
|
||||
*/
|
||||
|
||||
#include "lib/test.h"
|
||||
#include "lib/helper.h"
|
||||
#include "thirdparty/microtest/microtest.h"
|
||||
#include "sql_asserts.h"
|
||||
#include "SQLParser.h"
|
||||
#include "sqlhelper.h"
|
||||
|
||||
|
@ -166,3 +166,5 @@ TEST(ExecuteStatementTest) {
|
|||
|
||||
delete result;
|
||||
}
|
||||
|
||||
TEST_MAIN();
|
27
test/test.sh
27
test/test.sh
|
@ -6,23 +6,16 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
|
|||
|
||||
RET=0
|
||||
|
||||
# Running the tests.
|
||||
bin/sql_grammar_test -f "test/lib/valid_queries.sql"
|
||||
RET=$(($RET + $?))
|
||||
bin/sql_tests -f "test/valid_queries.sql"
|
||||
RET=$?
|
||||
|
||||
bin/sql_tests
|
||||
RET=$(($RET + $?))
|
||||
|
||||
# Running memory leak checks.
|
||||
echo ""
|
||||
echo "Running memory leak checks..."
|
||||
|
||||
valgrind --leak-check=full --error-exitcode=1 \
|
||||
./bin/sql_grammar_test -f "test/lib/valid_queries.sql" >> /dev/null
|
||||
RET=$(($RET + $?))
|
||||
|
||||
valgrind --leak-check=full --error-exitcode=1 \
|
||||
./bin/sql_tests -f "test/lib/valid_queries.sql" >> /dev/null
|
||||
RET=$(($RET + $?))
|
||||
if [ $RET -eq 0 ]; then
|
||||
# Running memory leak checks.
|
||||
echo ""
|
||||
echo "Running memory leak checks..."
|
||||
valgrind --leak-check=full --error-exitcode=1 --log-fd=3 \
|
||||
./bin/sql_tests -f "test/valid_queries.sql" 3>&1 >/dev/null 2>/dev/null
|
||||
RET=$?
|
||||
fi
|
||||
|
||||
exit $RET
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
//
|
||||
// microtest
|
||||
//
|
||||
// URL: https://github.com/torpedro/microtest
|
||||
// Author: Pedro Flemming (http://torpedro.com/)
|
||||
// License: MIT License (https://github.com/torpedro/microtest/blob/master/LICENSE)
|
||||
// Copyright (c) 2017 Pedro Flemming
|
||||
//
|
||||
// This is a small header-only C++ unit testing framework.
|
||||
// It allows to define small unit tests with set of assertions available.
|
||||
//
|
||||
#ifndef __MICROTEST_H__
|
||||
#define __MICROTEST_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
||||
#define ASSERT(cond)\
|
||||
ASSERT_TRUE(cond);
|
||||
|
||||
#define ASSERT_TRUE(cond)\
|
||||
if (!(cond)) throw mt::AssertFailedException(#cond, __FILE__, __LINE__);
|
||||
|
||||
#define ASSERT_FALSE(cond)\
|
||||
if (cond) throw mt::AssertFailedException(#cond, __FILE__, __LINE__);
|
||||
|
||||
#define ASSERT_NULL(value)\
|
||||
ASSERT_TRUE(value == NULL);
|
||||
|
||||
#define ASSERT_NOTNULL(value)\
|
||||
ASSERT_TRUE(value != NULL);
|
||||
|
||||
#define ASSERT_STREQ(a, b)\
|
||||
if (std::string(a).compare(std::string(b)) != 0)\
|
||||
throw mt::AssertFailedException(#a " == " #b, __FILE__, __LINE__);
|
||||
|
||||
#define ASSERT_EQ(a, b)\
|
||||
if (a != b) {\
|
||||
printf("%s{ info} %s", mt::yellow(), mt::def());\
|
||||
std::cout << "Actual values: " << a << " != " << b << std::endl;\
|
||||
}\
|
||||
ASSERT(a == b);
|
||||
|
||||
#define ASSERT_NEQ(a, b)\
|
||||
if (a == b) {\
|
||||
printf("%s{ info} %s", mt::yellow(), mt::def());\
|
||||
std::cout << "Actual values: " << a << " == " << b << std::endl;\
|
||||
}\
|
||||
ASSERT(a != b);
|
||||
|
||||
|
||||
////////////////
|
||||
// Unit Tests //
|
||||
////////////////
|
||||
|
||||
#define TEST(name) \
|
||||
void name();\
|
||||
namespace {\
|
||||
bool __##name = mt::TestsManager::AddTest(name, #name);\
|
||||
}\
|
||||
void name()
|
||||
|
||||
|
||||
///////////////
|
||||
// Framework //
|
||||
///////////////
|
||||
|
||||
namespace mt {
|
||||
|
||||
inline const char* red() {
|
||||
return "\033[1;31m";
|
||||
}
|
||||
|
||||
inline const char* green() {
|
||||
return "\033[0;32m";
|
||||
}
|
||||
|
||||
inline const char* yellow() {
|
||||
return "\033[0;33m";
|
||||
}
|
||||
|
||||
inline const char* def() {
|
||||
return "\033[0m";
|
||||
}
|
||||
|
||||
inline void printRunning(const char* message, FILE* file = stdout) {
|
||||
fprintf(file, "%s{ running}%s %s\n", green(), def(), message);
|
||||
}
|
||||
|
||||
inline void printOk(const char* message, FILE* file = stdout) {
|
||||
fprintf(file, "%s{ ok}%s %s\n", green(), def(), message);
|
||||
}
|
||||
|
||||
inline void printFailed(const char* message, FILE* file = stdout) {
|
||||
fprintf(file, "%s{ failed} %s%s\n", red(), message, def());
|
||||
}
|
||||
|
||||
// Exception that is thrown when an assertion fails.
|
||||
class AssertFailedException : public std::exception {
|
||||
public:
|
||||
AssertFailedException(std::string description, std::string filepath, int line) :
|
||||
std::exception(),
|
||||
description_(description),
|
||||
filepath_(filepath),
|
||||
line_(line) {};
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return description_.c_str();
|
||||
}
|
||||
|
||||
inline const char* getFilepath() {
|
||||
return filepath_.c_str();
|
||||
}
|
||||
|
||||
inline int getLine() {
|
||||
return line_;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string description_;
|
||||
std::string filepath_;
|
||||
int line_;
|
||||
};
|
||||
|
||||
class TestsManager {
|
||||
// Note: static initialization fiasco
|
||||
// http://www.parashift.com/c++-faq-lite/static-init-order.html
|
||||
// http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html
|
||||
public:
|
||||
struct Test {
|
||||
const char* name;
|
||||
void (*fn)(void);
|
||||
};
|
||||
|
||||
static std::vector<Test>& tests() {
|
||||
static std::vector<Test> tests_;
|
||||
return tests_;
|
||||
}
|
||||
|
||||
// Adds a new test to the current set of tests.
|
||||
// Returns false if a test with the same name already exists.
|
||||
inline static bool AddTest(void (*fn)(void), const char* name) {
|
||||
tests().push_back({ name, fn });
|
||||
return true;
|
||||
}
|
||||
|
||||
// Run all tests that are registered.
|
||||
// Returns the number of tests that failed.
|
||||
inline static size_t RunAllTests(FILE* file = stdout) {
|
||||
size_t num_failed = 0;
|
||||
|
||||
for (const Test& test : tests()) {
|
||||
// Run the test.
|
||||
// If an AsserFailedException is thrown, the test has failed.
|
||||
try {
|
||||
printRunning(test.name, file);
|
||||
|
||||
(*test.fn)();
|
||||
|
||||
printOk(test.name, file);
|
||||
|
||||
} catch (AssertFailedException& e) {
|
||||
printFailed(test.name, file);
|
||||
fprintf(file, " %sAssertion failed: %s%s\n",
|
||||
red(), e.what(), def());
|
||||
fprintf(file, " %s%s:%d%s\n",
|
||||
red(), e.getFilepath(), e.getLine(), def());
|
||||
++num_failed;
|
||||
}
|
||||
}
|
||||
|
||||
return num_failed;
|
||||
}
|
||||
};
|
||||
|
||||
// Class that will capture the arguments passed to the program.
|
||||
class Runtime {
|
||||
public:
|
||||
static const std::vector<std::string>& args(int argc = -1, char** argv = NULL) {
|
||||
static std::vector<std::string> args_;
|
||||
if (argc >= 0) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
args_.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
return args_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#define TEST_MAIN() \
|
||||
int main(int argc, char *argv[]) {\
|
||||
mt::Runtime::args(argc, argv);\
|
||||
\
|
||||
size_t num_failed = mt::TestsManager::RunAllTests(stdout);\
|
||||
if (num_failed == 0) {\
|
||||
fprintf(stdout, "%s{ summary} All tests succeeded!%s\n", mt::green(), mt::def());\
|
||||
return 0;\
|
||||
} else {\
|
||||
double percentage = 100.0 * num_failed / mt::TestsManager::tests().size();\
|
||||
fprintf(stderr, "%s{ summary} %lu tests failed (%.2f%%)%s\n", mt::red(), num_failed, percentage, mt::def());\
|
||||
return -1;\
|
||||
}\
|
||||
}
|
||||
|
||||
#endif // __MICROTEST_H__
|
|
@ -43,4 +43,5 @@ DEALLOCATE PREPARE prep;
|
|||
!gibberish;
|
||||
!SELECT abc;
|
||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';SELECT 1
|
||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1
|
||||
!CREATE TABLE "table" FROM TBL FILE 'students.tbl';1
|
||||
!INSERT INTO test_table VALUESd (1, 2, 'test');
|
Loading…
Reference in New Issue