#include "parser/parser.h" #include "parser/ast/sqliteselect.h" #include "parser/ast/sqlitecreatetable.h" #include "parser/keywords.h" #include "parser/lexer.h" #include "parser/parsererror.h" #include #include #include class ParserTest : public QObject { Q_OBJECT public: ParserTest(); private: Parser* parser2 = nullptr; Parser* parser3 = nullptr; private Q_SLOTS: void testGetTableTokens(); void testGetTableTokens2(); void testGetDatabaseTokens(); void testGetFullObjects(); void testGetFullObjects2(); void testUnfinishedSingleSourceWithTolerance(); void testCommentEnding1(); void testCommentEnding2(); void testOper1(); void testBig1(); void testTableFk(); void testDoubleQuotes(); void testInsertError(); void testExpr(); void testCommentBeginMultiline(); void initTestCase(); void cleanupTestCase(); }; ParserTest::ParserTest() { } void ParserTest::testGetTableTokens() { QString sql = "select someTable.* FROM someTable;"; parser3->parse(sql); QVERIFY(parser3->getErrors().size() == 0); SqliteQueryPtr query = parser3->getQueries()[0]; TokenList tokens = query->getContextTableTokens(); QVERIFY(tokens.size() == 2); QVERIFY(tokens[0]->type == Token::OTHER); QVERIFY(tokens[1]->type == Token::OTHER); } void ParserTest::testGetTableTokens2() { QString sql = "select db.tab.col FROM someTable;"; parser3->parse(sql); QVERIFY(parser3->getErrors().size() == 0); SqliteQueryPtr query = parser3->getQueries()[0]; TokenList tokens = query->getContextTableTokens(); QVERIFY(tokens.size() == 2); QVERIFY(tokens[0]->type == Token::OTHER); QVERIFY(tokens[1]->type == Token::OTHER); } void ParserTest::testGetDatabaseTokens() { QString sql = "select * FROM someDb.[table];"; parser3->parse(sql); QVERIFY(parser3->getErrors().size() == 0); SqliteQueryPtr query = parser3->getQueries()[0]; TokenList tokens = query->getContextTableTokens(); QVERIFY(tokens.size() == 1); QVERIFY(tokens[0]->type == Token::OTHER); } void ParserTest::testGetFullObjects() { QString sql = "select col FROM someDb.[table];"; parser3->parse(sql); QVERIFY(parser3->getErrors().size() == 0); SqliteQueryPtr query = parser3->getQueries()[0]; QList fullObjects = query->getContextFullObjects(); QVERIFY(fullObjects.size() == 2); foreach (const SqliteStatement::FullObject& fullObj, fullObjects) { switch (fullObj.type) { case SqliteStatement::FullObject::TABLE: QVERIFY(fullObj.database && fullObj.database->value == "someDb"); QVERIFY(fullObj.object && fullObj.object->value == "[table]"); break; case SqliteStatement::FullObject::DATABASE: QVERIFY(fullObj.database && fullObj.database->value == "someDb"); break; default: QFAIL("Unexpected FullObject type."); } } } void ParserTest::testGetFullObjects2() { QString sql = "select col, tab2.*, abcDb.abcTab.abcCol FROM someDb.[table];"; parser3->parse(sql); QVERIFY(parser3->getErrors().size() == 0); SqliteQueryPtr query = parser3->getQueries()[0]; QList fullObjects = query->getContextFullObjects(); QVERIFY(fullObjects.size() == 5); foreach (const SqliteStatement::FullObject& fullObj, fullObjects) { switch (fullObj.type) { case SqliteStatement::FullObject::TABLE: { QVERIFY(fullObj.object); if (fullObj.database && fullObj.database->value == "someDb") QVERIFY(fullObj.object->value == "[table]"); else if (fullObj.database && fullObj.database->value == "abcDb") QVERIFY(fullObj.object->value == "abcTab"); else if (!fullObj.database) QVERIFY(fullObj.object->value == "tab2"); else QFAIL("Invalid TABLE full object."); break; } case SqliteStatement::FullObject::DATABASE: { if (fullObj.database) QVERIFY(fullObj.database->value == "someDb" || fullObj.database->value == "abcDb"); else QFAIL("Invalid DATABASE full object."); break; } default: QFAIL("Unexpected FullObject type."); } } } void ParserTest::testUnfinishedSingleSourceWithTolerance() { QString sql = "SELECT * FROM test.;"; bool res = parser3->parse(sql, true); QVERIFY(res); } void ParserTest::testCommentEnding1() { QString sql = "select 1 --aaa"; bool res = parser3->parse(sql); QVERIFY(res); } void ParserTest::testCommentEnding2() { QString sql = "select 1 /*aaa"; bool res = parser3->parse(sql); QVERIFY(res); } void ParserTest::testOper1() { QString sql = "SELECT dfgd<=2"; TokenList tokens = Lexer::tokenize(sql, Dialect::Sqlite3); QVERIFY(tokens[2]->value == "dfgd"); QVERIFY(tokens[3]->value == "<="); QVERIFY(tokens[4]->value == "2"); } void ParserTest::testBig1() { QString sql = "select " "''|| " "''|| " "''|| " "''|| " "''|| " "''|| " "''|| " "'Ð�TH;°Ñ禅TH;°Ð»Ñ즅TH;½Ð¸Ðº Ñ㦅TH;¿ÑঅTH;°Ð²Ð»ÐµÐ½Ð¸Ñ怜t;/P1>'|| " "''|| " "''||strftime('%d.%m.%Y',d.demdate)||''|| " "'4642'||substr('000000'||d.id, -6, 6)||''|| " "''|| " "''||ins.fullname||''|| " "''||ins.shortname||''|| " "'0'||ins.regnum||''|| " "''|| " "''||ins.inn||''|| " "''||ins.kpp||''|| " "''||ins.addr||''|| " "''||ins.postaddr||''|| " "''||round(dem_s+dem_n+dem_f+dem_t,2)||''|| " "''||strftime('%d.%m.%Y',d.demdate,'+15 day')||''|| " "'0,00'|| " "'0,00'|| " "''|| " "'0,00'|| " "''|| " "'0,00'|| " "'0,00'|| " "''|| " "'0,00'|| " "''|| " "'0,00'|| " "'0,00'|| " "''||round(dem_s+dem_n+dem_f+dem_t,2)||''|| " "''||round(dem_s+dem_n,2)||''|| " "'0,00'|| " "''||round(dem_s,2)||''|| " "''||case when d.dem_s>0 then '(ÐꦅTH;ᦅTH;ꠧ'||kbk.kbk_s||')' else '' end || ''|| " "''||round(dem_n,2)||''|| " "''||case when d.dem_n>0 then '(ÐꦅTH;ᦅTH;ꠧ'||kbk.kbk_n||')' else '' end||''|| " "''||round(dem_f,2)||''|| " "''||case when d.dem_f>0 then '(ÐꦅTH;ᦅTH;ꠧ'||kbk.kbk_f||')' else '' end||''|| " "''||round(dem_t,2)||''|| " "''||case when d.dem_t>0 then '(ÐꦅTH;ᦅTH;ꠧ'||kbk.kbk_t||')' else '' end||''|| " "'0,00'|| " "'0,00 0,00 0,00 0,00'|| " "'Ñ঎tilde;㦅TH;±.;'|| " "'0,00'|| " "''|| " "'0,00'|| " "''|| " "'0,00'|| " "''|| " "'0,00'|| " "''|| " "'0,00'|| " "''|| " "''|| " "''|| " "''||strftime('%d.%m.%Y',d.demdate)||''|| " "'0'|| " "''|| " "'0'|| " "''|| " "''||ins.Specname||''|| " "''|| " "'' " "from demands d " "left join ins on ins.regnum=d.regnum " "left join kbk on kbk.cat=ins.Cat " "limit 1"; bool res = parser3->parse(sql); if (!res) { qWarning() << parser3->getErrorString(); ParserError* error = parser3->getErrors().first(); qDebug() << "Error starts at:" << sql.mid(error->getFrom()); } QVERIFY(res); } void ParserTest::testTableFk() { QString sql = "CREATE TABLE test (id INTEGER, FOREIGN KEY (id) REFERENCES test2 (id2));"; parser3->parse(sql); QVERIFY(parser3->getErrors().size() == 0); SqliteQueryPtr query = parser3->getQueries()[0]; SqliteCreateTablePtr creatrTable = query.dynamicCast(); QVERIFY(creatrTable->constraints.size() == 1); QVERIFY(creatrTable->constraints.first()->indexedColumns.size() == 1); QVERIFY(creatrTable->constraints.first()->indexedColumns.first()->name == "id"); QVERIFY(creatrTable->constraints.first()->type == SqliteCreateTable::Constraint::FOREIGN_KEY); QVERIFY(creatrTable->constraints.first()->foreignKey != nullptr); QVERIFY(creatrTable->constraints.first()->foreignKey->foreignTable == "test2"); QVERIFY(creatrTable->constraints.first()->foreignKey->indexedColumns.size() == 1); QVERIFY(creatrTable->constraints.first()->foreignKey->indexedColumns.first()->name == "id2"); } void ParserTest::testDoubleQuotes() { QString sql = "select \"1\""; bool res = parser3->parse(sql); QVERIFY(res); QVERIFY(parser3->getQueries().size() > 0); SqliteQueryPtr query = parser3->getQueries().first(); QVERIFY(query); SqliteSelectPtr select = query.dynamicCast(); QVERIFY(select); QVERIFY(select->coreSelects.size() > 0); QVERIFY(select->coreSelects.first()->resultColumns.size() > 0); SqliteSelect::Core::ResultColumn* rc = select->coreSelects.first()->resultColumns.first(); SqliteExpr* e = rc->expr; QVERIFY(e); QVERIFY(e->mode == SqliteExpr::Mode::ID); QVERIFY(e->possibleDoubleQuotedString); } void ParserTest::testInsertError() { QString sql = "INSERT INTO test "; bool res = parser3->parse(sql); QVERIFY(!res); QVERIFY(parser3->getErrors().size() == 1); } void ParserTest::testExpr() { QString sql = "CAST (CASE WHEN port REGEXP '^[A-Z]' THEN substr(port, 2) ELSE port END AS INT) AS port"; SqliteExpr* expr = parser3->parseExpr(sql); QVERIFY(expr); } void ParserTest::testCommentBeginMultiline() { QString sql = "/*"; TokenList tokens = Lexer::tokenize(sql, Dialect::Sqlite3); QVERIFY(tokens.size() == 1); QVERIFY(tokens[0]->type == Token::COMMENT); } void ParserTest::initTestCase() { initKeywords(); Lexer::staticInit(); parser2 = new Parser(Dialect::Sqlite2); parser3 = new Parser(Dialect::Sqlite3); } void ParserTest::cleanupTestCase() { delete parser2; delete parser3; } QTEST_APPLESS_MAIN(ParserTest) #include "tst_parsertest.moc"