From e70f68dfaba95f7b8a419d5e9f31aa4fc5f01aa7 Mon Sep 17 00:00:00 2001 From: Hamed Masafi Date: Wed, 19 Aug 2020 13:56:15 +0430 Subject: [PATCH] Phrase test (#112) * initial * fix: ci test fail * more test rules for phrases --- src/nut/generators/abstractsqlgenerator.cpp | 15 +- src/nut/phrases/abstractfieldphrase.cpp | 2 +- src/nut/phrases/conditionalphrase.cpp | 5 +- tests/auto/common/nut-lib.pri | 27 ---- tests/auto/tst_phrases/generator.cpp | 21 +++ tests/auto/tst_phrases/generator.h | 16 ++ tests/auto/tst_phrases/tst_phrases.cpp | 165 ++++++++++++++------ tests/auto/tst_phrases/tst_phrases.h | 15 +- tests/auto/tst_phrases/tst_phrases.pro | 2 + 9 files changed, 179 insertions(+), 89 deletions(-) create mode 100644 tests/auto/tst_phrases/generator.cpp create mode 100644 tests/auto/tst_phrases/generator.h diff --git a/src/nut/generators/abstractsqlgenerator.cpp b/src/nut/generators/abstractsqlgenerator.cpp index 98c9459..f11479b 100644 --- a/src/nut/generators/abstractsqlgenerator.cpp +++ b/src/nut/generators/abstractsqlgenerator.cpp @@ -889,14 +889,25 @@ QString AbstractSqlGenerator::escapeValue(const QVariant &v) const if (v.type() == QVariant::String && v.toString().isEmpty()) return QStringLiteral("''"); + if (v.type() == QVariant::List) { + auto list = v.toList(); + QStringList ret; + foreach (QVariant vi, list) { + ret.append(QStringLiteral("'") + + _serializer->serialize(vi) + + QStringLiteral("'")); + } + return QStringLiteral("(") + + ret.join(QStringLiteral(", ")) + + QStringLiteral(")"); + } + QString serialized = _serializer->serialize(v); if (serialized.isEmpty()) { qWarning("No field escape rule for: %s", v.typeName()); return QString(); } - if (v.type() == QVariant::List) - return serialized; return QStringLiteral("'") + serialized + QStringLiteral("'"); } diff --git a/src/nut/phrases/abstractfieldphrase.cpp b/src/nut/phrases/abstractfieldphrase.cpp index 4d51091..7995103 100644 --- a/src/nut/phrases/abstractfieldphrase.cpp +++ b/src/nut/phrases/abstractfieldphrase.cpp @@ -131,7 +131,7 @@ AbstractFieldPhrase AbstractFieldPhrase::operator ~() AbstractFieldPhrase AbstractFieldPhrase::operator !() { - AbstractFieldPhrase f(data->className, data->fieldName); + AbstractFieldPhrase f(data->clone()); f.data->isNot = !data->isNot; return f; } diff --git a/src/nut/phrases/conditionalphrase.cpp b/src/nut/phrases/conditionalphrase.cpp index 248d6e9..98fe440 100644 --- a/src/nut/phrases/conditionalphrase.cpp +++ b/src/nut/phrases/conditionalphrase.cpp @@ -185,8 +185,9 @@ DECLARE_CONDITIONALPHRASE_OPERATORS_IMPL(&&, PhraseData::And) ConditionalPhrase ConditionalPhrase::operator !() { - ConditionalPhrase f(data); - f.data->isNot = !data->isNot; + ConditionalPhrase f; + f.data = data->clone(); + f.data->isNot = !f.data->isNot; return f; } diff --git a/tests/auto/common/nut-lib.pri b/tests/auto/common/nut-lib.pri index c3f5c99..83873b9 100644 --- a/tests/auto/common/nut-lib.pri +++ b/tests/auto/common/nut-lib.pri @@ -51,38 +51,11 @@ debug_and_release:!ReleaseBuild:!DebugBuild { } } -win32 { - CONFIG(debug,debug|release): LIBDIR = $$absolute_path($$OUT_PWD/../../../src/nut/debug) - CONFIG(release,debug|release): LIBDIR = $$absolute_path($$OUT_PWD/../../../src/nut/release) -# LIBS += -L$$LIBDIR -lnut -} else { - LIBDIR = $$absolute_path($$OUT_PWD/../../../lib) - android: { - - contains(ANDROID_TARGET_ARCH,armeabi-v7a) { - LIBS += -L$$LIBDIR -lnut_armeabi-v7a - } - contains(ANDROID_TARGET_ARCH,arm64-v8a) { - LIBS += -L$$LIBDIR -lnut_arm64-v8a - } - contains(ANDROID_TARGET_ARCH,x86) { - LIBS += -L$$LIBDIR -lnut_x86 - } - contains(ANDROID_TARGET_ARCH,x86_64) { - LIBS += -L$$LIBDIR -lnut_x86_64 - } - } else { -# LIBS += -L$$LIBDIR - } -} - -#INCLUDEPATH += $$PWD/../../../src/nut INCLUDEPATH += $$PWD/../common QT += nut CONFIG += testcase -DEFINES += NUT_SHARED_POINTER DEFINES += NUT_PATH=\\\"$$PWD/../../\\\" runtarget.target = run-tests diff --git a/tests/auto/tst_phrases/generator.cpp b/tests/auto/tst_phrases/generator.cpp new file mode 100644 index 0000000..c83cf79 --- /dev/null +++ b/tests/auto/tst_phrases/generator.cpp @@ -0,0 +1,21 @@ +#include "generator.h" + +Generator::Generator() : Nut::SqliteGenerator() +{ + +} + +QString Generator::where(const Nut::ConditionalPhrase &where) +{ + return createConditionalPhrase(where.data); +} + +QString Generator::order(const Nut::PhraseList &order) +{ + return createOrderPhrase(order); +} + +QString Generator::select(const Nut::PhraseList &select) +{ + return createFieldPhrase(select); +} diff --git a/tests/auto/tst_phrases/generator.h b/tests/auto/tst_phrases/generator.h new file mode 100644 index 0000000..535dd1b --- /dev/null +++ b/tests/auto/tst_phrases/generator.h @@ -0,0 +1,16 @@ +#ifndef GENERATOR_H +#define GENERATOR_H + +#include + +class Generator : public Nut::SqliteGenerator +{ +public: + Generator(); + + QString where(const Nut::ConditionalPhrase &where); + QString order(const Nut::PhraseList &order); + QString select(const Nut::PhraseList &select); +}; + +#endif // GENERATOR_H diff --git a/tests/auto/tst_phrases/tst_phrases.cpp b/tests/auto/tst_phrases/tst_phrases.cpp index bdb7ed3..e24662c 100644 --- a/tests/auto/tst_phrases/tst_phrases.cpp +++ b/tests/auto/tst_phrases/tst_phrases.cpp @@ -1,14 +1,24 @@ #include #include +#include #include "tst_phrases.h" #include "phrase.h" -#include "sqlitegenerator.h" +#include "generator.h" using namespace Nut; +#define COMPARE_WHERE(w, sql) QCOMPARE(g.where(w), sql); +#define COMPARE_ORDER(o, sql) QCOMPARE(g.order(o), sql); +#define COMPARE_SELECT(s, sql) QCOMPARE(g.select(s), sql); + +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") +QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") + PhrasesTest::PhrasesTest(QObject *parent) : QObject(parent) { + } void PhrasesTest::initTestCase() @@ -25,94 +35,143 @@ void PhrasesTest::no1() FieldPhrase date("main", "date"); auto w = (id == 4 && name == QStringLiteral("hi")); - SqliteGenerator g; + Generator g; + + COMPARE_WHERE(id == 10 || id.in({1, 2, 3, 4}), "([main].id = '10' OR [main].id IN ('1', '2', '3', '4'))"); } } -void PhrasesTest::numeric() +void PhrasesTest::condition_numeric_sqlite() { + Generator g; + + FieldPhrase n("main", "int"); FieldPhrase f("main", "float"); - auto p1 = n == 1; - auto p2 = n <= 1; - auto p3 = n >= 1; - auto p4 = n < 1; - auto p5 = n > 1; - auto p6 = n != 1; - auto p7 = n = n + 1; - auto p8 = n < n + 1; - auto p9 = n <= n + 1; - auto p10 = n > n + 1; - auto p11 = n >= n + 1; - auto p12 = n + 1 > n - 2; - auto p13 = ++n; - auto p14 = n++; - auto p15 = n.between(1, 2); - auto p16 = n + 1 < n + 2; + COMPARE_WHERE(n < 1, "[main].int < '1'"); + COMPARE_WHERE(n > 1, "[main].int > '1'"); + COMPARE_WHERE(n <= 1, "[main].int <= '1'"); + COMPARE_WHERE(n >= 1, "[main].int >= '1'"); + COMPARE_WHERE(n != 1, "[main].int <> '1'"); + COMPARE_WHERE(n == 1, "[main].int = '1'"); + COMPARE_WHERE(n++, "[main].int + '1'"); + COMPARE_WHERE(++n, "[main].int + '1'"); + COMPARE_WHERE(n.between(10, 20), "[main].int BETWEEN '10' AND '20'"); + COMPARE_WHERE(n + 1 < n + 4, "[main].int + '1' < [main].int + '4'"); - auto p21 = p1 && p2; - auto p22 = p3 == p4; - auto p23 = f == n + 1; + auto p1 = n == 1; + auto p2 = n <= 4; + auto p3 = n >= 5; + auto p4 = n < 7; + + COMPARE_WHERE(p1 && p2, "([main].int = '1' AND [main].int <= '4')"); + COMPARE_WHERE(p3 == p4, "[main].int >= '5' = [main].int < '7'"); + COMPARE_WHERE(f == n + 1, "[main].float = [main].int + '1'"); + COMPARE_WHERE(f == 1.4 || (n == n + 1 && n < 100), + "([main].float = '1.4' OR ([main].int = [main].int + '1' AND [main].int < '100'))"); auto p24 = n = 4; auto p26 = (n = 4) & (n = 5); auto p27 = n | f; } -void PhrasesTest::string() +void PhrasesTest::condition_string_sqlite() { + Generator g; FieldPhrase str("main", "string"); - auto p1 = str == "salam"; - auto p2 = str.like("%hi%"); - auto p3 = str.isNull(); - auto p4 = str.in(QStringList() << "one" << "two" << "three"); - auto p5 = str != "hi" && str.like("%s"); + COMPARE_WHERE(str == "Hi", "[main].string = 'Hi'"); + COMPARE_WHERE(str.like("%hi%"), "[main].string LIKE '%hi%'"); + COMPARE_WHERE(str.isNull(), "[main].string IS NULL"); + COMPARE_WHERE(!str.isNull(), "[main].string IS NOT NULL"); + COMPARE_WHERE(str.in(QStringList() << "one" + << "two" + << "three"), + "[main].string IN ('one', 'two', 'three')"); + + COMPARE_WHERE(!str.in(QStringList() << "one" + << "two" + << "three"), + "[main].string NOT IN ('one', 'two', 'three')"); + COMPARE_WHERE(str != "hi" && str.like("%s"), + "([main].string <> 'hi' AND [main].string LIKE '%s')"); } -void PhrasesTest::boolean() +void PhrasesTest::condition_bool_sqlite() { + Generator g; FieldPhrase b("main", "bool"); - auto p1 = b; - auto p2 = !b; - auto p3 = b == false; - - QTEST_ASSERT(p1.data); - QTEST_ASSERT(p2.data); - QTEST_ASSERT(p3.data); + COMPARE_WHERE(b, "[main].bool = 'true'"); + COMPARE_WHERE(!b, "[main].bool = 'false'"); + COMPARE_WHERE(b == true, "[main].bool = 'true'"); + COMPARE_WHERE(b == false, "[main].bool = 'false'"); } -void PhrasesTest::datetime() +void PhrasesTest::condition_datetime_sqlite() { + Generator g; + FieldPhrase time("main", "time"); FieldPhrase date("main", "date"); FieldPhrase datetime("main", "datetime"); - auto p1 = time <= QTime::currentTime(); - auto p2 = time.addHours(2) < QTime::currentTime(); - auto p3 = date == QDate::currentDate(); - auto p4 = date.addDays(1) == QDate::currentDate(); - auto p5 = datetime > QDateTime::currentDateTime(); - auto p6 = datetime.addMonths(1) >= QDateTime::currentDateTime(); - auto p7 = time.between(QTime::currentTime().addSecs(-100), QTime::currentTime()); - auto p8 = time.hour() == 3; - auto p9 = time = QTime::currentTime(); + QDate d(2020, 2, 20); + QTime t(12, 34, 56); + QDateTime dt(d, t); -// auto pi1 = time.addYears(1); -// auto pi2 = date.addMinutes(3); + COMPARE_WHERE(time.hour() == 1, "CAST(strftime('%H', [main].time) AS INT) = '1'"); + COMPARE_WHERE(time.minute() == 2, "CAST(strftime('%M', [main].time) AS INT) = '2'"); + COMPARE_WHERE(time.second() == 3, "CAST(strftime('%S', [main].time) AS INT) = '3'"); -// QTEST_ASSERT(!pi1.data); -// QTEST_ASSERT(!pi2.data); + COMPARE_WHERE(date.year() == 1, "CAST(strftime('%Y', [main].date) AS INT) = '1'"); + COMPARE_WHERE(date.month() == 2, "CAST(strftime('%m', [main].date) AS INT) = '2'"); + COMPARE_WHERE(date.day() == 3, "CAST(strftime('%d', [main].date) AS INT) = '3'"); + + COMPARE_WHERE(time.isNull(), "[main].time IS NULL"); + COMPARE_WHERE(!time.isNull(), "[main].time IS NOT NULL"); + COMPARE_WHERE(time == t, "[main].time = '12:34:56'"); + COMPARE_WHERE(time.between(t.addSecs(-10), + t), + "[main].time BETWEEN '12:34:46' AND '12:34:56'"); + COMPARE_WHERE(date.addDays(2) == d, "DATE([main].date,'+2 DAY') = '2020-02-20'"); + COMPARE_WHERE(time.addMinutes(-3) == t, "TIME([main].time,'-3 MINUTE') = '12:34:56'"); + COMPARE_WHERE(datetime.addMinutes(1) == dt, "DATETIME([main].datetime,'+1 MINUTE') = '2020-02-20 12:34:56'"); +} + +void PhrasesTest::order_sqlite() +{ + Generator g; + + FieldPhrase id("main", "id"); + FieldPhrase name("main", "name"); + FieldPhrase last_name("main", "last_name"); + + COMPARE_ORDER(id, "[main].id"); + COMPARE_ORDER(id | name, "[main].id, [main].name"); + COMPARE_ORDER(id | !name | last_name, "[main].id, [main].name DESC, [main].last_name"); +} + +void PhrasesTest::select_sqlite() +{ + Generator g; + + FieldPhrase id("main", "id"); + FieldPhrase name("main", "name"); + FieldPhrase last_name("main", "last_name"); + + COMPARE_ORDER(id, "[main].id"); + COMPARE_ORDER(id | name, "[main].id, [main].name"); + COMPARE_ORDER(id | name | last_name, "[main].id, [main].name, [main].last_name"); } void PhrasesTest::extra() { + Generator g; FieldPhrase url("main", "url"); - auto p1 = url == QUrl(); - auto p2 = url == "http://google.com"; + COMPARE_WHERE(url == QUrl("http://google.com"), "[main].url = 'http://google.com'"); } void PhrasesTest::mix() @@ -157,3 +216,5 @@ void PhrasesTest::order_by(const PhraseList &ph) } QTEST_MAIN(PhrasesTest) + +QT_WARNING_POP diff --git a/tests/auto/tst_phrases/tst_phrases.h b/tests/auto/tst_phrases/tst_phrases.h index fe0c825..2911dad 100644 --- a/tests/auto/tst_phrases/tst_phrases.h +++ b/tests/auto/tst_phrases/tst_phrases.h @@ -23,13 +23,18 @@ signals: private slots: void initTestCase(); - void no1(); - void numeric(); - void string(); - void boolean(); - void datetime(); + void condition_numeric_sqlite(); + void condition_string_sqlite(); + void condition_bool_sqlite(); + void condition_datetime_sqlite(); + + void order_sqlite(); + void select_sqlite(); + void extra(); + + void no1(); void mix(); private: diff --git a/tests/auto/tst_phrases/tst_phrases.pro b/tests/auto/tst_phrases/tst_phrases.pro index 80a4ed7..b4b94d4 100644 --- a/tests/auto/tst_phrases/tst_phrases.pro +++ b/tests/auto/tst_phrases/tst_phrases.pro @@ -8,8 +8,10 @@ CONFIG += warn_on c++11 include(../common/nut-lib.pri) SOURCES += \ + generator.cpp \ tst_phrases.cpp HEADERS += \ + generator.h \ tst_phrases.h