From 49d3b8c14fe3fa1812b251f52a9a6f2a32af0e09 Mon Sep 17 00:00:00 2001 From: Pedro Date: Wed, 26 Nov 2014 16:20:55 +0100 Subject: [PATCH] added test-framework --- run_analysis.sh | 11 +++ run_tests.sh | 27 ++---- src/Makefile | 2 +- src/sql_grammar_test.cpp | 4 +- src/sql_tests.cpp | 167 +++++------------------------------- src/tests/helper.h | 21 +++++ src/tests/test.h | 69 +++++++++++++++ src/tests/valid-queries.sql | 26 ++++++ 8 files changed, 157 insertions(+), 170 deletions(-) create mode 100755 run_analysis.sh create mode 100644 src/tests/helper.h create mode 100644 src/tests/test.h create mode 100644 src/tests/valid-queries.sql diff --git a/run_analysis.sh b/run_analysis.sh new file mode 100755 index 0000000..35132a3 --- /dev/null +++ b/run_analysis.sh @@ -0,0 +1,11 @@ +#!/bin/sh +make clean -C src/ +make analysis -C src/ + +echo "\n\n" + +./bin/analysis "SELECT * FROM t1 UNION SELECT abc AS t FROM t2 ORDER BY col3 LIMIT 10;" +./bin/analysis "INSERT INTO students (name, city, age) VALUES ('Max', 'Musterhausen', 5);" +./bin/analysis "INSERT INTO students (name, city) SELECT * FROM employees;" + +echo "\n\n" \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh index 4b0ad08..e0f7a43 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1,23 +1,6 @@ #!/bin/sh - - -make clean -C src/ - -# make tests -make analysis -C src/ -make grammar_test -C src/ - -echo "\n\n" - - -# ./bin/analysis "SELECT t1.a AS id, t1.b, t2.c FROM \"tbl\" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5" -# ./bin/analysis "CREATE TABLE \"table\" FROM TBL FILE 'students.tbl'" -./bin/analysis "SELECT * FROM t1 UNION SELECT abc AS t FROM t2 ORDER BY col3 LIMIT 10;" -./bin/analysis "INSERT INTO students (name, city, age) VALUES ('Max', 'Musterhausen', 5);" -./bin/analysis "INSERT INTO students (name, city) SELECT * FROM employees;" - -echo "\n\n" - -./bin/grammar_test -f "test/valid_queries.sql" - -echo "\n\n" \ No newline at end of file +echo "Compiling..." +make clean -C src/ >/dev/null +make tests -C src/ >/dev/null +echo "Running tests:" +./bin/tests \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index 7bb962b..09d46ce 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,6 +33,6 @@ parser/bison_parser.cpp: clean: - rm -f *.o *~ $(BIN_DIR)/analysis $(TESTS_BIN) $(BIN_DIR)/grammar_test + rm -f *.o *~ $(BIN_DIR)/analysis $(TESTS_BIN) $(BIN_DIR)/grammar_test $(BIN_DIR)/tests rm -rf $(BUILD_DIR) make clean -C parser/ diff --git a/src/sql_grammar_test.cpp b/src/sql_grammar_test.cpp index 016eb14..34f5a4e 100644 --- a/src/sql_grammar_test.cpp +++ b/src/sql_grammar_test.cpp @@ -86,9 +86,9 @@ int main(int argc, char *argv[]) { } if (num_failed == 0) { - printf("All %lu grammar tests completed successfully!", queries.size()); + printf("All %lu grammar tests completed successfully!\n", queries.size()); } else { - fprintf(stderr, "Some grammar tests failed! %d out of %lu tests failed!", num_failed, queries.size()); + fprintf(stderr, "Some grammar tests failed! %d out of %lu tests failed!\n", num_failed, queries.size()); } diff --git a/src/sql_tests.cpp b/src/sql_tests.cpp index f6473bc..9075def 100644 --- a/src/sql_tests.cpp +++ b/src/sql_tests.cpp @@ -3,159 +3,36 @@ */ #include "SQLParser.h" -#include -#include -#include -#include -#include - -#define STREQUALS(str1, str2) std::string(str1).compare(std::string(str2)) == 0 - -#define ASSERT(cond) if (!(cond)) { fprintf(stderr, "failed! Assertion (" #cond ")\n"); return; } -#define ASSERT_STR(STR1, STR2) ASSERT(STREQUALS(STR1, STR2)); +#include "tests/test.h" -void SelectTest1() { - printf("Test: SelectTest1... "); fflush(stdout); - - const char* sql = "SELECT age, (name), address from table WHERE age < 12.5;"; - Statement* sqlStatement = SQLParser::parseSQLString(sql); - ASSERT(sqlStatement != NULL); - ASSERT(sqlStatement->type == eSelect); - - SelectStatement* stmt = (SelectStatement*) sqlStatement; - - ASSERT(stmt->select_list->size() == 3); - ASSERT_STR(stmt->select_list->at(0)->name, "age"); - ASSERT_STR(stmt->select_list->at(1)->name, "name"); - ASSERT_STR(stmt->select_list->at(2)->name, "address"); - - ASSERT(stmt->from_table != NULL); - ASSERT(stmt->from_table->type == eTableName); - ASSERT_STR(stmt->from_table->name, "table"); - - // WHERE - ASSERT(stmt->where_clause != NULL); - ASSERT(stmt->where_clause->expr->type == eExprColumnRef); - ASSERT_STR(stmt->where_clause->expr->name, "age"); - ASSERT(stmt->where_clause->pred_type == SQL_LESS); - ASSERT(stmt->where_clause->expr2->type == eExprLiteralFloat); - ASSERT(stmt->where_clause->expr2->float_literal == 12.5); - - printf("passed!\n"); -} - -void SelectTest2() { - printf("Test: SelectTest2... "); fflush(stdout); - - const char* sql = "SELECT * FROM (SELECT age+zipcode FROM table, table2);"; - Statement* stmt = SQLParser::parseSQLString(sql); - ASSERT(stmt != NULL); - ASSERT(stmt->type == eSelect); - - SelectStatement* select = (SelectStatement*) stmt; - - ASSERT(select->select_list->size() == 1); - ASSERT(select->select_list->at(0)->type == eExprStar); - - ASSERT(select->from_table != NULL); - ASSERT(select->from_table->type == eTableSelect); - ASSERT(select->from_table->stmt != NULL); - ASSERT(select->from_table->stmt->select_list->size() == 1); - ASSERT(select->from_table->stmt->from_table->type == eTableCrossProduct); - // ASSERT_STR(select->from_table->stmt->from_table->table_names->at(0), "table"); - // ASSERT_STR(select->from_table->stmt->from_table->table_names->at(1), "table2"); - - printf("passed!\n"); -} - -uint parse_count = 0; -uint conflicts = 0; -void SelectTest3(bool print) { - if (print) { printf("Test: SelectTest3... "); fflush(stdout); } - - const char* sql = "SELECT name, AVG(age) FROM table GROUP BY name"; - parse_count++; - - Statement* stmt = SQLParser::parseSQLString(sql); - - if (parse_count != 1) conflicts++; - parse_count--; - - ASSERT(stmt != NULL); - ASSERT(stmt->type == eSelect); - - SelectStatement* select = (SelectStatement*) stmt; - - ASSERT(select->select_list->size() == 2); - - ASSERT(select->select_list->at(0)->type == eExprColumnRef); - ASSERT(select->select_list->at(1)->type == eExprFunctionRef); - ASSERT_STR("name", select->select_list->at(0)->name); +using namespace hsql; - ASSERT(select->group_by != NULL); - ASSERT(select->group_by->size() == 1); - ASSERT_STR("name", select->group_by->at(0)->name); - if (print) printf("passed!\n"); +TEST(SelectTest) { + StatementList* stmt_list = SQLParser::parseSQLString("SELECT * FROM students;"); + ASSERT(stmt_list->isValid); + ASSERT(stmt_list->size() == 1); + ASSERT(stmt_list->at(0)->type == kStmtSelect); + + SelectStatement* stmt = (SelectStatement*) stmt_list->at(0); + ASSERT(stmt->where_clause == NULL); } -/** Multithread Test **/ -void multithreadTest(int numberOfRuns, int id) { - for (int n = 0; n < numberOfRuns; ++n) { - SelectTest3(false); - } -} -void ThreadSafeTest(uint numThreads, uint runsPerThread) { - printf("Multithread-Test... "); - conflicts = 0; - std::thread* threads = new std::thread[numThreads]; - for (int n = 0; n < numThreads; ++n) { - threads[n] = std::thread(multithreadTest, runsPerThread, n); - } - for (int n = 0; n < numThreads; ++n) { - threads[n].join(); - } - printf("there were %u concurrent parses... ", conflicts); - printf("finished!\n"); +TEST(DeleteTest) { + StatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;"); + ASSERT(stmt_list->isValid); + ASSERT(stmt_list->size() == 1); + ASSERT(stmt_list->at(0)->type == kStmtDelete); + + DeleteStatement* stmt = (DeleteStatement*) stmt_list->at(0); + ASSERT_STREQ(stmt->table_name, "students"); + ASSERT(stmt->expr != NULL); + ASSERT(stmt->expr->isType(kExprOperator)); + ASSERT_STREQ(stmt->expr->expr->name, "grade"); + ASSERT_EQ(stmt->expr->expr2->fval, 2.0); } -/** Performance Test **/ -void Benchmark1(uint numRuns) { - printf("Benchmarking... "); - - clock_t start, end; - const char* sql = "SELECT SUM(age), name, address FROM (SELECT age FROM (SELECT age FROM (SELECT age FROM table, table2))) WHERE income > 10 GROUP BY age;"; - - start = clock(); - for (uint n = 0; n < numRuns; ++n) { - Statement* stmt = SQLParser::parseSQLString(sql); - } - end = clock(); - - long diff = end-start; - printf("Total Time: %ld ticks (~%.4fms)\n", diff, 1000.0*diff/CLOCKS_PER_SEC); - printf("Time per exec: ~%.2f ticks (~%.4fms)\n", (double)diff/numRuns, (1000.0*diff/numRuns)/CLOCKS_PER_SEC); - printf("Benchmarking done!\n"); -} - - -int main(int argc, char *argv[]) { - - printf("\n######################################\n"); - printf("## Running all tests...\n\n"); - - SelectTest1(); - SelectTest2(); - SelectTest3(true); - ThreadSafeTest(10, 1000); - Benchmark1(10000); - - printf("\n## Finished running all tests...\n"); - printf("######################################\n"); - - return 0; -} diff --git a/src/tests/helper.h b/src/tests/helper.h new file mode 100644 index 0000000..89e3bca --- /dev/null +++ b/src/tests/helper.h @@ -0,0 +1,21 @@ +#ifndef __HELPER_H__ +#define __HELPER_H__ + + +std::vector readlines(std::string path) { + std::ifstream infile(path); + std::vector lines; + std::string line; + while (std::getline(infile, line)) { + std::istringstream iss(line); + + // Skip comments + if (line[0] != '#') { + lines.push_back(line); + } + } + return lines; +} + + +#endif \ No newline at end of file diff --git a/src/tests/test.h b/src/tests/test.h new file mode 100644 index 0000000..6af0b60 --- /dev/null +++ b/src/tests/test.h @@ -0,0 +1,69 @@ +#ifndef __TEST_H__ +#define __TEST_H__ + +#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_STREQ(a, b) \ + if (std::string(a).compare(std::string(b)) != 0) throw AssertionFailedException(#a " == " #b) +#define ASSERT_EQ(a, b) \ + 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; +}; + + +std::vector g_test_names; +std::vector g_tests; + +int AddTest(void (*foo)(void), std::string name) { + g_tests.push_back(foo); + g_test_names.push_back(name); + return 0; +} + + +void RunTests() { + size_t num_failed = 0; + for (size_t i = 0; i < g_tests.size(); ++i) { + printf("\033[0;32m{ running}\033[0m %s\n", g_test_names[i].c_str()); + + try { + // Run test + (*g_tests[i])(); + printf("\033[0;32m{ ok}\033[0m %s\n", g_test_names[i].c_str()); + + } catch (AssertionFailedException& e) { + printf("\033[1;31m{ failed} %s\n", g_test_names[i].c_str()); + printf("\tAssertion failed: %s\n\033[0m", e.what()); + num_failed++; + } + + } +} + + +int main() { + RunTests(); + return 0; +} + + + +#endif \ No newline at end of file diff --git a/src/tests/valid-queries.sql b/src/tests/valid-queries.sql new file mode 100644 index 0000000..b3d7e35 --- /dev/null +++ b/src/tests/valid-queries.sql @@ -0,0 +1,26 @@ +# SELECT statement +SELECT * FROM orders; +SELECT a FROM foo WHERE a > 12 OR b > 3 AND NOT c LIMIT 10 +SELECT col1 AS myname, col2, 'test' FROM "table", foo AS t WHERE age > 12 AND zipcode = 12345 GROUP BY col1; +SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5 +(SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10); +SELECT * FROM "table" LIMIT 10 OFFSET 10; +SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1; +# SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1; +# JOIN +SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5 +SELECT * FROM t1 JOIN t2 ON c1 = c2; +# CREATE statement +CREATE TABLE "table" FROM TBL FILE 'students.tbl' +CREATE TABLE IF NOT EXISTS "table" FROM TBL FILE 'students.tbl' +CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE) +# Multiple statements +CREATE TABLE "table" FROM TBL FILE 'students.tbl'; SELECT * FROM "table"; +# INSERT +INSERT INTO test_table VALUES (1, 2, 'test'); +INSERT INTO test_table (id, value, name) VALUES (1, 2, 'test'); +INSERT INTO test_table SELECT * FROM students; +# DELETE +DELETE FROM students WHERE grade > 3.0 +DELETE FROM students +TRUNCATE students \ No newline at end of file