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.
### Run tests
To execute all tests run: `./run_tests.sh`.
### Update in 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('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
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 employees FROM TBL FILE 'test/tables/employees.tbl';
# SELECT
@ -14,4 +14,15 @@ SELECT * FROM students WHERE grade = 1.3 UNION SELECT * FROM students WHERE grad
# JOIN
SELECT * FROM companies JOIN employees ON company_id = employee_company_id;
# 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
echo "Compiling..."
make clean -C src/ >/dev/null
make tests -C src/ >/dev/null
make grammar_test -C src/ >/dev/null
make clean -C src/ >/dev/null || exit 1
make tests -C src/ >/dev/null || exit 1
make grammar_test -C src/ >/dev/null || exit 1
echo "Running tests:"
./bin/grammar_test -f "test/valid_queries.sql"
./bin/tests

View File

@ -1,10 +1,14 @@
BUILD_DIR = ../build/
BIN_DIR = ../bin
CC = 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/
BIN_DIR = ../bin
LIB_SOURCES = $(shell find lib/ -name '*.cpp') parser/bison_parser.cpp parser/flex_lexer.cpp parser/SQLParser.cpp
TEST_SOURCES = $(shell find tests/ -name '*.cpp')
# release build is always using bison
@ -16,16 +20,16 @@ build: clean
cp parser/*.cpp $(BUILD_DIR)
analysis: $(SOURCES) sql_analysis.cpp
$(CC) $(CFLAGS) $(SOURCES) sql_analysis.cpp -o $(BIN_DIR)/analysis
analysis: $(LIB_SOURCES) sql_analysis.cpp
$(CC) $(CFLAGS) $(LIB_SOURCES) sql_analysis.cpp -o $(BIN_DIR)/analysis
grammar_test: $(SOURCES) sql_grammar_test.cpp
$(CC) $(CFLAGS) $(SOURCES) sql_grammar_test.cpp -o $(BIN_DIR)/grammar_test
grammar_test: $(LIB_SOURCES) sql_grammar_test.cpp
$(CC) $(CFLAGS) $(LIB_SOURCES) sql_grammar_test.cpp -o $(BIN_DIR)/grammar_test
tests: $(SOURCES) $(TESTS_MAIN)
$(CC) $(CFLAGS) $(SOURCES) sql_tests.cpp -o $(BIN_DIR)/tests
tests: $(LIB_SOURCES) $(TEST_SOURCES) sql_tests.cpp
$(CC) $(CFLAGS) $(LIB_SOURCES) $(TEST_SOURCES) sql_tests.cpp -o $(BIN_DIR)/tests
parser/bison_parser.cpp:

View File

@ -108,8 +108,8 @@ typedef void* yyscan_t;
** Token Definition
*********************************/
%token <sval> IDENTIFIER STRING
%token <fval> FLOAT
%token <ival> INT
%token <fval> FLOATVAL
%token <ival> INTVAL
%token <uval> NOTEQUALS LESSEQ GREATEREQ
/* SQL Keywords */
@ -124,7 +124,7 @@ typedef void* yyscan_t;
%token LIMIT LOCAL MERGE MINUS ORDER OUTER RIGHT TABLE UNION
%token USING WHERE CALL DATE DESC DROP FILE FROM FULL HASH
%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
@ -268,8 +268,10 @@ column_def:
}
;
column_type:
INTEGER { $$ = ColumnDefinition::INT; }
INT { $$ = ColumnDefinition::INT; }
| INTEGER { $$ = ColumnDefinition::INT; }
| DOUBLE { $$ = ColumnDefinition::DOUBLE; }
| TEXT { $$ = ColumnDefinition::TEXT; }
;
@ -522,12 +524,12 @@ string_literal:
num_literal:
FLOAT { $$ = Expr::makeLiteral($1); }
FLOATVAL { $$ = Expr::makeLiteral($1); }
| int_literal
;
int_literal:
INT { $$ = Expr::makeLiteral($1); }
INTVAL { $$ = Expr::makeLiteral($1); }
;
star_expr:

View File

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

View File

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

View File

@ -2,27 +2,12 @@
* sql_tests.cpp
*/
#include "tests/test.h"
#include "SQLParser.h"
#include "sqlhelper.h"
#include "tests/test.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);
}
TEST(Delete) {
StatementList* stmt_list = SQLParser::parseSQLString("DELETE FROM students WHERE grade > 2.0;");
ASSERT(stmt_list->isValid);
@ -38,7 +23,7 @@ TEST(Delete) {
}
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_EQ(stmt_list->size(), 1);
ASSERT_EQ(stmt_list->at(0)->type, kStmtCreate);
@ -49,8 +34,12 @@ TEST(Create) {
ASSERT_NOTNULL(stmt->columns);
ASSERT_EQ(stmt->columns->size(), 4);
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_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);
}

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__
#define __TEST_H__
#include <vector>
#include <string>
#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() {
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;
}
int AddTest(void (*foo)(void), std::string name);