refactored test framework
This commit is contained in:
parent
4d33ea21bf
commit
48b473e7c5
|
@ -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.
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
|
@ -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
|
||||
|
|
22
src/Makefile
22
src/Makefile
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]+\" {
|
||||
|
|
|
@ -147,6 +147,7 @@ DATE
|
|||
TIME
|
||||
TIMESTAMP
|
||||
INTEGER
|
||||
INT
|
||||
DOUBLE
|
||||
NVARCHAR
|
||||
TEXT
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue