refactored test framework

This commit is contained in:
Pedro 2014-12-03 16:32:56 +01:00
parent 4d33ea21bf
commit 48b473e7c5
12 changed files with 127 additions and 74 deletions

View File

@ -14,6 +14,10 @@ To create the full parser code run `make build`. The parser library code is crea
To use the SQL Parser in your own code, you only need to include `SQLParser.h` and build+link all the source files from the parser with your project. See `hyrise/src/lib/access/sql/SQLQueryParser.cpp` for how it's used in Hyrise. To use the SQL Parser in your own code, you only need to include `SQLParser.h` and build+link all the source files from the parser with your project. See `hyrise/src/lib/access/sql/SQLQueryParser.cpp` for how it's used in Hyrise.
### Run tests
To execute all tests run: `./run_tests.sh`.
### Update in Hyrise ### Update in Hyrise
Run `./deploy_to_hyris.sh path/to/hyrise` to update the SQL parser within Hyrise. Run `./deploy_to_hyris.sh path/to/hyrise` to update the SQL parser within Hyrise.

View File

@ -177,7 +177,7 @@ $(function() {
}); });
addBuggyQuery('GROUP', 'SELECT AVG(grade) FROM (SELECT city, AVG(grade) FROM students GROUP BY city) t1'); addBuggyQuery('GROUP', 'SELECT AVG(grade) FROM (SELECT city, AVG(grade) FROM students GROUP BY city) t1');
addBuggyQuery('UNION', 'SELECT name FROM students WHERE grade > 2.0 UNION SELECT name FROM students'); addBuggyQuery('UNION (kills hyrise)', 'SELECT name FROM students WHERE grade > 2.0 UNION SELECT name FROM students');
////////////////////////////////////////////////// //////////////////////////////////////////////////

View File

@ -1,6 +1,6 @@
# Load Tables # Load Tables
CREATE TABLE IF NOT EXISTS students FROM TBL FILE 'test/students.tbl'; CREATE TABLE IF NOT EXISTS students FROM TBL FILE 'test/students.tbl';
CREATE TABLE IF NOT EXISTS test FROM TBL FILE 'test/lin_xxs.tbl'; CREATE TABLE IF NOT EXISTS test_big FROM TBL FILE 'test/lin_xxs.tbl';
CREATE TABLE IF NOT EXISTS companies FROM TBL FILE 'test/tables/companies.tbl'; CREATE TABLE IF NOT EXISTS companies FROM TBL FILE 'test/tables/companies.tbl';
CREATE TABLE IF NOT EXISTS employees FROM TBL FILE 'test/tables/employees.tbl'; CREATE TABLE IF NOT EXISTS employees FROM TBL FILE 'test/tables/employees.tbl';
# SELECT # SELECT
@ -14,4 +14,15 @@ SELECT * FROM students WHERE grade = 1.3 UNION SELECT * FROM students WHERE grad
# JOIN # JOIN
SELECT * FROM companies JOIN employees ON company_id = employee_company_id; SELECT * FROM companies JOIN employees ON company_id = employee_company_id;
# INSERT # INSERT
INSERT INTO students VALUES ('Max', 10101, 'Musterhausen', 3.3); INSERT INTO students VALUES ('Max Mustermann', 10101, 'Musterhausen', 1.7);
# CREATE
CREATE TABLE IF NOT EXISTS test (v1 INTEGER, v2 INTEGER, v3 INTEGER);
# INSERT/SELECT
INSERT INTO test VALUES (1, 23, 45);|
INSERT INTO test VALUES (1, 23, 45);
INSERT INTO test VALUES (1, 23, 45);
SELECT * FROM test;
# CREATE/INSERT/SELECT
CREATE TABLE IF NOT EXISTS test (v1 INTEGER, v2 INTEGER, v3 INTEGER);
INSERT INTO test VALUES (1, 12, 43);
SELECT * FROM test;

View File

@ -1,8 +1,9 @@
#!/bin/sh #!/bin/sh
echo "Compiling..." echo "Compiling..."
make clean -C src/ >/dev/null make clean -C src/ >/dev/null || exit 1
make tests -C src/ >/dev/null make tests -C src/ >/dev/null || exit 1
make grammar_test -C src/ >/dev/null make grammar_test -C src/ >/dev/null || exit 1
echo "Running tests:" echo "Running tests:"
./bin/grammar_test -f "test/valid_queries.sql" ./bin/grammar_test -f "test/valid_queries.sql"
./bin/tests ./bin/tests

View File

@ -1,10 +1,14 @@
BUILD_DIR = ../build/
BIN_DIR = ../bin
CC = g++ CC = g++
CFLAGS = -O3 -Ilib/ -I./ -Iparser/ -std=c++11 -pthread -Wall -g CFLAGS = -O3 -Ilib/ -I./ -Iparser/ -std=c++11 -pthread -Wall -g
SOURCES = $(shell find lib/ -name '*.cpp') parser/bison_parser.cpp parser/flex_lexer.cpp parser/SQLParser.cpp
BUILD_DIR = ../build/ LIB_SOURCES = $(shell find lib/ -name '*.cpp') parser/bison_parser.cpp parser/flex_lexer.cpp parser/SQLParser.cpp
BIN_DIR = ../bin TEST_SOURCES = $(shell find tests/ -name '*.cpp')
# release build is always using bison # release build is always using bison
@ -16,16 +20,16 @@ build: clean
cp parser/*.cpp $(BUILD_DIR) cp parser/*.cpp $(BUILD_DIR)
analysis: $(SOURCES) sql_analysis.cpp analysis: $(LIB_SOURCES) sql_analysis.cpp
$(CC) $(CFLAGS) $(SOURCES) sql_analysis.cpp -o $(BIN_DIR)/analysis $(CC) $(CFLAGS) $(LIB_SOURCES) sql_analysis.cpp -o $(BIN_DIR)/analysis
grammar_test: $(SOURCES) sql_grammar_test.cpp grammar_test: $(LIB_SOURCES) sql_grammar_test.cpp
$(CC) $(CFLAGS) $(SOURCES) sql_grammar_test.cpp -o $(BIN_DIR)/grammar_test $(CC) $(CFLAGS) $(LIB_SOURCES) sql_grammar_test.cpp -o $(BIN_DIR)/grammar_test
tests: $(SOURCES) $(TESTS_MAIN) tests: $(LIB_SOURCES) $(TEST_SOURCES) sql_tests.cpp
$(CC) $(CFLAGS) $(SOURCES) sql_tests.cpp -o $(BIN_DIR)/tests $(CC) $(CFLAGS) $(LIB_SOURCES) $(TEST_SOURCES) sql_tests.cpp -o $(BIN_DIR)/tests
parser/bison_parser.cpp: parser/bison_parser.cpp:

View File

@ -108,8 +108,8 @@ typedef void* yyscan_t;
** Token Definition ** Token Definition
*********************************/ *********************************/
%token <sval> IDENTIFIER STRING %token <sval> IDENTIFIER STRING
%token <fval> FLOAT %token <fval> FLOATVAL
%token <ival> INT %token <ival> INTVAL
%token <uval> NOTEQUALS LESSEQ GREATEREQ %token <uval> NOTEQUALS LESSEQ GREATEREQ
/* SQL Keywords */ /* SQL Keywords */
@ -124,7 +124,7 @@ typedef void* yyscan_t;
%token LIMIT LOCAL MERGE MINUS ORDER OUTER RIGHT TABLE UNION %token LIMIT LOCAL MERGE MINUS ORDER OUTER RIGHT TABLE UNION
%token USING WHERE CALL DATE DESC DROP FILE FROM FULL HASH %token USING WHERE CALL DATE DESC DROP FILE FROM FULL HASH
%token INTO JOIN LEFT LIKE LOAD NULL PART PLAN SHOW TEXT %token INTO JOIN LEFT LIKE LOAD NULL PART PLAN SHOW TEXT
%token TIME VIEW WITH ADD ALL AND ASC CSV FOR KEY NOT OFF %token TIME VIEW WITH ADD ALL AND ASC CSV FOR INT KEY NOT OFF
%token SET TBL TOP AS BY IF IN IS OF ON OR TO %token SET TBL TOP AS BY IF IN IS OF ON OR TO
@ -268,8 +268,10 @@ column_def:
} }
; ;
column_type: column_type:
INTEGER { $$ = ColumnDefinition::INT; } INT { $$ = ColumnDefinition::INT; }
| INTEGER { $$ = ColumnDefinition::INT; }
| DOUBLE { $$ = ColumnDefinition::DOUBLE; } | DOUBLE { $$ = ColumnDefinition::DOUBLE; }
| TEXT { $$ = ColumnDefinition::TEXT; } | TEXT { $$ = ColumnDefinition::TEXT; }
; ;
@ -522,12 +524,12 @@ string_literal:
num_literal: num_literal:
FLOAT { $$ = Expr::makeLiteral($1); } FLOATVAL { $$ = Expr::makeLiteral($1); }
| int_literal | int_literal
; ;
int_literal: int_literal:
INT { $$ = Expr::makeLiteral($1); } INTVAL { $$ = Expr::makeLiteral($1); }
; ;
star_expr: star_expr:

View File

@ -149,6 +149,7 @@ AND TOKEN(AND)
ASC TOKEN(ASC) ASC TOKEN(ASC)
CSV TOKEN(CSV) CSV TOKEN(CSV)
FOR TOKEN(FOR) FOR TOKEN(FOR)
INT TOKEN(INT)
KEY TOKEN(KEY) KEY TOKEN(KEY)
NOT TOKEN(NOT) NOT TOKEN(NOT)
OFF TOKEN(OFF) OFF TOKEN(OFF)
@ -177,12 +178,12 @@ TO TOKEN(TO)
[0-9]+"."[0-9]* | [0-9]+"."[0-9]* |
"."[0-9]* { "."[0-9]* {
yylval->fval = atof(yytext); yylval->fval = atof(yytext);
return SQL_FLOAT; return SQL_FLOATVAL;
} }
[0-9]+ { [0-9]+ {
yylval->ival = atol(yytext); yylval->ival = atol(yytext);
return SQL_INT; return SQL_INTVAL;
} }
\"[^\"\n]+\" { \"[^\"\n]+\" {

View File

@ -147,6 +147,7 @@ DATE
TIME TIME
TIMESTAMP TIMESTAMP
INTEGER INTEGER
INT
DOUBLE DOUBLE
NVARCHAR NVARCHAR
TEXT TEXT

View File

@ -2,27 +2,12 @@
* sql_tests.cpp * sql_tests.cpp
*/ */
#include "tests/test.h"
#include "SQLParser.h" #include "SQLParser.h"
#include "sqlhelper.h" #include "sqlhelper.h"
#include "tests/test.h"
using namespace hsql; using namespace hsql;
TEST(Select) {
StatementList* stmt_list = SQLParser::parseSQLString("SELECT * FROM students;");
ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1);
ASSERT(stmt_list->at(0)->type == kStmtSelect);
SelectStatement* stmt = (SelectStatement*) stmt_list->at(0);
ASSERT_NULL(stmt->where_clause);
}
TEST(Delete) { TEST(Delete) {
StatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;"); StatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
@ -38,7 +23,7 @@ TEST(Delete) {
} }
TEST(Create) { TEST(Create) {
StatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INTEGER, city TEXT, grade DOUBLE)"); StatementList* stmt_list = SQLParser::parseSQLString("CREATE TABLE students (name TEXT, student_number INT, city INTEGER, grade DOUBLE)");
ASSERT(stmt_list->isValid); ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1); ASSERT_EQ(stmt_list->size(), 1);
ASSERT_EQ(stmt_list->at(0)->type, kStmtCreate); ASSERT_EQ(stmt_list->at(0)->type, kStmtCreate);
@ -49,8 +34,12 @@ TEST(Create) {
ASSERT_NOTNULL(stmt->columns); ASSERT_NOTNULL(stmt->columns);
ASSERT_EQ(stmt->columns->size(), 4); ASSERT_EQ(stmt->columns->size(), 4);
ASSERT_STREQ(stmt->columns->at(0)->name, "name"); ASSERT_STREQ(stmt->columns->at(0)->name, "name");
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT); ASSERT_STREQ(stmt->columns->at(1)->name, "student_number");
ASSERT_STREQ(stmt->columns->at(2)->name, "city");
ASSERT_STREQ(stmt->columns->at(3)->name, "grade"); ASSERT_STREQ(stmt->columns->at(3)->name, "grade");
ASSERT_EQ(stmt->columns->at(0)->type, ColumnDefinition::TEXT);
ASSERT_EQ(stmt->columns->at(1)->type, ColumnDefinition::INT);
ASSERT_EQ(stmt->columns->at(2)->type, ColumnDefinition::INT);
ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE); ASSERT_EQ(stmt->columns->at(3)->type, ColumnDefinition::DOUBLE);
} }

15
src/tests/select.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "test.h"
#include "SQLParser.h"
using namespace hsql;
TEST(Select) {
StatementList* stmt_list = SQLParser::parseSQLString("SELECT * FROM students;");
ASSERT(stmt_list->isValid);
ASSERT_EQ(stmt_list->size(), 1);
ASSERT(stmt_list->at(0)->type == kStmtSelect);
SelectStatement* stmt = (SelectStatement*) stmt_list->at(0);
ASSERT_NULL(stmt->where_clause);
}

55
src/tests/test.cpp Normal file
View File

@ -0,0 +1,55 @@
#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>& test_names() {
static std::vector<std::string>* test_names = new std::vector<std::string>;
return *test_names;
}
static std::vector<void (*)(void)>& tests() {
static std::vector<void (*)(void)>* tests = new std::vector<void (*)(void)>;
return *tests;
}
};
int AddTest(void (*foo)(void), std::string name) {
TestsManager::tests().push_back(foo);
TestsManager::test_names().push_back(name);
return 0;
}
void RunTests() {
size_t num_failed = 0;
for (size_t i = 0; i < TestsManager::tests().size(); ++i) {
printf("\033[0;32m{ running}\033[0m %s\n", TestsManager::test_names()[i].c_str());
try {
// Run test
(*TestsManager::tests()[i])();
printf("\033[0;32m{ ok}\033[0m %s\n", TestsManager::test_names()[i].c_str());
} catch (AssertionFailedException& e) {
printf("\033[1;31m{ failed} %s\n", TestsManager::test_names()[i].c_str());
printf("\tAssertion failed: %s\n\033[0m", e.what());
num_failed++;
}
}
}
int main() {
RunTests();
return 0;
}

View File

@ -1,7 +1,8 @@
#ifndef __TEST_H__ #ifndef __TEST_H__
#define __TEST_H__ #define __TEST_H__
#include <vector>
#include <string>
#include <iostream> #include <iostream>
@ -44,40 +45,9 @@ protected:
}; };
std::vector<std::string> g_test_names;
std::vector<void (*)(void)> 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() { int AddTest(void (*foo)(void), std::string name);
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;
}