1 /* This file is part of the KDE project
2 Copyright (C) 2011-2016 Jarosław Staniek <staniek@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "ExpressionsTest.h"
21
22 #include <QtTest>
23
24 #include <KDbDateTime>
25 #include <KDbExpression>
26 #include "parser/generated/sqlparser.h"
27 #include "parser/KDbParser_p.h"
28
29 Q_DECLARE_METATYPE(KDb::ExpressionClass)
30 Q_DECLARE_METATYPE(KDbEscapedString)
31 Q_DECLARE_METATYPE(KDbField::Type)
32 Q_DECLARE_METATYPE(KDbToken)
33
34 namespace QTest {
35 template<>
toString(const KDbEscapedString & string)36 char *toString(const KDbEscapedString &string)
37 {
38 return qstrdup(qPrintable(string.toString()));
39 }
40
41 template<>
toString(const KDbField::Type & type)42 char *toString(const KDbField::Type &type)
43 {
44 return qstrdup(qPrintable(KDbField::typeString(type)));
45 }
46
47 //! Adds a quote if this is the single-character token to match the format of Bison
48 template<>
toString(const KDbToken & token)49 char* toString(const KDbToken &token)
50 {
51 return qstrdup(qPrintable(
52 token.toChar() ? QString::fromLatin1("'%1'").arg(token.toString())
53 : token.toString()
54 ));
55 }
56 }
57
QTEST_GUILESS_MAIN(ExpressionsTest)58 QTEST_GUILESS_MAIN(ExpressionsTest)
59
60 //! Used in macros so characters and KDbTokens can be used interchangeably
61 static inline KDbToken TO_TOKEN(char charValue)
62 {
63 return KDbToken(charValue);
64 }
65
66 //! Used in macros so characters and KDbTokens can be used interchangeably
TO_TOKEN(KDbToken token)67 static inline KDbToken TO_TOKEN(KDbToken token)
68 {
69 return token;
70 }
71
initTestCase()72 void ExpressionsTest::initTestCase()
73 {
74 }
75
76 //! compares two expression @a e1 and @a e2 based on strings/debug strings
77 //! and token strings
78 template <typename T1, typename T2>
compareStrings(const T1 & e1,const T2 & e2)79 static void compareStrings(const T1 &e1, const T2 &e2)
80 {
81 //qDebug() << "compareStrings():"
82 // << "\ne1:" << e1.toString() << e1.token() << e1.token().ToString()
83 // << "\ne2:" << e2.toString() << e2.token() << e2.token().toString();
84 QCOMPARE(e1.toString(nullptr), e2.toString(nullptr));
85 QCOMPARE(e1.token(), e2.token());
86 QCOMPARE(e1.token().value(), e2.token().value());
87 QCOMPARE(e1.token().toString(), e2.token().toString());
88 }
89
90 //! tests clone and copy ctor for @a e1
91 template <typename T>
testCloneExpression(const T & e1)92 static void testCloneExpression(const T &e1)
93 {
94 KDbExpression e1clone = e1.clone();
95 //qDebug() << e1;
96 //qDebug() << e1clone;
97 QVERIFY(e1 != e1.clone());
98 QVERIFY(e1 != e1clone);
99 QVERIFY(e1.clone() != e1clone);
100 QVERIFY(e1.expressionClass() == e1clone.expressionClass());
101 QVERIFY(e1.token() == e1clone.token());
102 compareStrings(e1, e1clone);
103
104 const T copied(e1);
105 QVERIFY(e1 == copied);
106 QVERIFY(e1.clone() != copied);
107 QVERIFY(e1.expressionClass() == copied.expressionClass());
108 QVERIFY(e1.token() == copied.token());
109 compareStrings(e1, copied);
110 }
111
112 //! Validates expression @a expr and shows error message on failure
validate(KDbExpression * expr)113 static bool validate(KDbExpression *expr)
114 {
115 KDbParseInfoInternal parseInfo(nullptr);
116 bool ok = expr->validate(&parseInfo);
117 if (!ok) {
118 qInfo() << "Validation of" << *expr << "FAILED.";
119 if (!parseInfo.errorMessage().isEmpty()) {
120 qInfo() << "Error message:" << parseInfo.errorMessage();
121 }
122 if (!parseInfo.errorDescription().isEmpty()) {
123 qInfo() << "Error description:" << parseInfo.errorDescription();
124 }
125 }
126 return ok;
127 }
128
testNullExpression()129 void ExpressionsTest::testNullExpression()
130 {
131 QVERIFY(KDbExpression() != KDbExpression());
132
133 KDbExpression e1;
134 KDbExpression e2;
135 QVERIFY(e1.isNull());
136 QVERIFY(!e1.isValid());
137 QVERIFY(!e1.isBinary());
138 QVERIFY(e1.toBinary().isNull());
139 QVERIFY(!e1.isConst());
140 QVERIFY(e1.toConst().isNull());
141 QVERIFY(!e1.isFunction());
142 QVERIFY(e1.toFunction().isNull());
143 QVERIFY(!e1.isNArg());
144 QVERIFY(e1.toNArg().isNull());
145 QVERIFY(!e1.isQueryParameter());
146 QVERIFY(e1.toQueryParameter().isNull());
147 QVERIFY(!e1.isUnary());
148 QVERIFY(e1.toUnary().isNull());
149 QVERIFY(!e1.isVariable());
150 QVERIFY(e1.toVariable().isNull());
151 QCOMPARE(e1.expressionClass(), KDb::UnknownExpression);
152 QCOMPARE(e1.token(), KDbToken());
153 QVERIFY(e1 != KDbExpression());
154 QVERIFY(e1 == e1);
155 QVERIFY(e1 != e2);
156
157 e1 = e2;
158 QVERIFY(e1.isNull());
159 QCOMPARE(e1, e2);
160 QCOMPARE(e1.toString(nullptr), KDbEscapedString("<UNKNOWN!>"));
161 QCOMPARE(e1.token().name(), QLatin1String("<INVALID_TOKEN>"));
162 QCOMPARE(e1.token().toString(nullptr), QString("<INVALID_TOKEN>"));
163 compareStrings(e1, e2);
164
165 KDbExpression e3(e2);
166 QVERIFY(e3.isNull());
167 QCOMPARE(e2, e3);
168 compareStrings(e2, e3);
169 //ExpressionDebug << "$$$" << e1.toString() << e1.token() << e1.token().toString();
170
171 e1 = KDbExpression();
172 testCloneExpression(e1);
173 }
174
testExpressionClassName_data()175 void ExpressionsTest::testExpressionClassName_data()
176 {
177 QTest::addColumn<KDb::ExpressionClass>("expClass");
178 QTest::addColumn<QString>("name");
179
180 int c = 0;
181 #define T(n, t) ++c; QTest::newRow(n) << t << n
182 T("Unknown", KDb::UnknownExpression);
183 T("Unary", KDb::UnaryExpression);
184 T("Arithm", KDb::ArithmeticExpression);
185 T("Logical", KDb::LogicalExpression);
186 T("Relational", KDb::RelationalExpression);
187 T("SpecialBinary", KDb::SpecialBinaryExpression);
188 T("Const", KDb::ConstExpression);
189 T("Variable", KDb::VariableExpression);
190 T("Function", KDb::FunctionExpression);
191 T("Aggregation", KDb::AggregationExpression);
192 T("FieldList", KDb::FieldListExpression);
193 T("TableList", KDb::TableListExpression);
194 T("ArgumentList", KDb::ArgumentListExpression);
195 T("QueryParameter", KDb::QueryParameterExpression);
196 #undef T
197 QCOMPARE(c, int(KDb::LastExpressionClass) + 1);
198 }
199
testExpressionClassName()200 void ExpressionsTest::testExpressionClassName()
201 {
202 QFETCH(KDb::ExpressionClass, expClass);
203 QTEST(expressionClassName(expClass), "name");
204 }
205
206 #include "KDbUtils_p.h"
207
testExpressionToken()208 void ExpressionsTest::testExpressionToken()
209 {
210 KDbExpression e1;
211 QVERIFY(!e1.isValid());
212 QVERIFY(!KDbToken().isValid());
213 QCOMPARE(e1.token(), KDbToken());
214 QVERIFY(KDbToken('+').toChar() > 0);
215 QCOMPARE(KDbToken('*'), KDbToken('*'));
216 QCOMPARE(KDbToken('*').toChar(), '*');
217 QCOMPARE(KDbToken('*').value(), int('*'));
218 QCOMPARE(KDbToken('*').name(), QString::fromLatin1("*"));
219 QCOMPARE(KDbToken('*').toString(), QString::fromLatin1("*"));
220 QCOMPARE(KDbToken::LEFT.toChar(), char(0));
221 QCOMPARE(KDbToken().toChar(), char(0));
222 QVERIFY(KDbToken::LEFT.isValid());
223 QVERIFY(KDbToken::maxCharTokenValue > 0);
224 QVERIFY(KDbToken::LEFT.value() > KDbToken::maxCharTokenValue);
225 const QList<KDbToken> allTokens(KDbToken::allTokens());
226 QVERIFY(!allTokens.isEmpty());
227
228 for(const KDbToken &t : allTokens) {
229 //qDebug() << t << t.value();
230 if (t.toChar() > 0) {
231 QVERIFY(t.value() <= KDbToken::maxCharTokenValue);
232 QCOMPARE(t, KDbToken(char(t.value())));
233 QCOMPARE(t.name(), isprint(t.value()) ? QString(QLatin1Char(uchar(t.value())))
234 : QString::number(t.value()));
235 QCOMPARE(QTest::toString(t), QString::fromLatin1(g_tokenName(t.value())).toLatin1().data());
236 }
237 else {
238 QCOMPARE(t.name(), QString::fromLatin1(g_tokenName(t.value())));
239 }
240 }
241 }
242
testNArgExpression()243 void ExpressionsTest::testNArgExpression()
244 {
245 KDbNArgExpression n;
246 KDbNArgExpression n2;
247 KDbConstExpression c;
248 KDbConstExpression c1;
249 KDbConstExpression c2;
250 KDbConstExpression c3;
251
252 // -- empty
253 KDbNArgExpression emptyNarg;
254 QVERIFY(emptyNarg.isNArg());
255 QVERIFY(emptyNarg.clone().isNArg());
256 QVERIFY(emptyNarg.isEmpty());
257 QCOMPARE(emptyNarg.argCount(), 0);
258 QVERIFY(emptyNarg.arg(-1).isNull());
259 QVERIFY(emptyNarg.arg(0).isNull());
260 QVERIFY(!emptyNarg.containsInvalidArgument());
261 QVERIFY(!emptyNarg.containsNullArgument());
262
263 // -- copy ctor & cloning
264 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
265 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 7);
266 c2 = KDbConstExpression(KDbToken::INTEGER_CONST, 8);
267 n.append(c1);
268 n.append(c2);
269 testCloneExpression(n);
270
271 // copy on stack
272 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
273 {
274 KDbConstExpression s1(KDbToken::INTEGER_CONST, 7);
275 KDbConstExpression s2(KDbToken::INTEGER_CONST, 8);
276 n.append(s1);
277 n.append(s2);
278 c1 = s1;
279 c2 = s2;
280 }
281 QCOMPARE(n.argCount(), 2);
282 QCOMPARE(n.arg(0).toConst(), c1);
283 QCOMPARE(n.arg(1).toConst(), c2);
284
285 QCOMPARE(n.token().name(), QString("+"));
286 QCOMPARE(n.toString(nullptr), KDbEscapedString("7, 8"));
287 n.setToken('*');
288 QCOMPARE(n.token().name(), QString("*"));
289
290 // -- append(KDbExpression), prepend(KDbExpression)
291 KDbExpression e;
292 KDbNArgExpression nNull;
293 QCOMPARE(nNull.argCount(), 0); // empty
294 nNull.append(e);
295 QCOMPARE(nNull.argCount(), 1); // n-arg expression can have null elements
296 nNull = KDbNArgExpression();
297 QCOMPARE(nNull.argCount(), 0); // cleared
298
299 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
300 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 1);
301 n.append(c1);
302 QVERIFY(!n.isEmpty());
303 QCOMPARE(n.argCount(), 1);
304 QCOMPARE(n.arg(0).toConst(), c1);
305 QCOMPARE(c1.parent().toNArg(), n);
306
307 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
308 n.append(n);
309 QCOMPARE(n.argCount(), 0); // append should fail since appending expression
310 // to itself is not allowed
311 n.prepend(n);
312 QCOMPARE(n.argCount(), 0); // append should fail since prepending expression
313 // to itself is not allowed
314
315 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
316 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 2);
317 n.append(c1);
318 n.append(c1); // cannot append the same expression twice
319 QCOMPARE(n.argCount(), 1);
320 QCOMPARE(n.arg(0).toConst(), c1);
321
322 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
323 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
324 n.prepend(c1);
325 n.prepend(c1); // cannot prepend the same expression twice
326 QCOMPARE(n.argCount(), 1);
327 QCOMPARE(n.arg(0).toConst(), c1);
328 n.append(c1); // cannot append/prepend the same expression twice
329 QCOMPARE(n.argCount(), 1);
330 QCOMPARE(n.arg(0).toConst(), c1);
331
332 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
333 n2 = KDbNArgExpression(KDb::ArithmeticExpression, '+');
334 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 4);
335 n.append(c1);
336 n2.append(c1); // c moves from n to n2
337 QVERIFY(n.isEmpty());
338 QCOMPARE(n2.argCount(), 1);
339 QCOMPARE(c1.parent().toNArg(), n2);
340 n.prepend(c1); // c moves from n2 to n
341 QCOMPARE(n.argCount(), 1);
342 QVERIFY(n2.isEmpty());
343 QCOMPARE(c1.parent().toNArg(), n);
344
345 // -- insert(int, KDbExpression)
346 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
347 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
348 c2 = KDbConstExpression(KDbToken::INTEGER_CONST, 4);
349 // it must be a valid index position in the list (i.e., 0 <= i < argCount()).
350 n.insert(-10, c1);
351 QVERIFY(n.isEmpty());
352 n.insert(1, c1);
353 QVERIFY(n.isEmpty());
354 // if i is 0, the expression is prepended to the list of arguments
355 n.insert(0, c1);
356 QCOMPARE(n.arg(0).toConst(), c1);
357 QCOMPARE(n.argCount(), 1);
358 QCOMPARE(c1.parent().toNArg(), n);
359 n.insert(0, c2);
360 QCOMPARE(n.argCount(), 2);
361 QCOMPARE(n.arg(0).toConst(), c2);
362 QCOMPARE(n.arg(1).toConst(), c1);
363
364 // if i is argCount(), the value is appended to the list of arguments
365 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
366 n.insert(0, c1);
367 n.insert(1, c2);
368 QCOMPARE(n.argCount(), 2);
369 QCOMPARE(n.arg(0).toConst(), c1);
370 QCOMPARE(n.arg(1).toConst(), c2);
371
372 // expression cannot be own child
373 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
374 n.insert(0, n);
375 QVERIFY(n.isEmpty());
376
377 // cannot insert child twice
378 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
379 n.insert(0, c1);
380 n.insert(1, c1);
381 QCOMPARE(n.argCount(), 1);
382
383 // -- remove(KDbExpression)
384 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
385 n.append(c1);
386 n.append(c2);
387 n.remove(c1); // remove first
388 QCOMPARE(n.argCount(), 1);
389 QCOMPARE(n.arg(0).toConst(), c2);
390
391 // -- remove(KDbExpression)
392 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
393 n.prepend(c1);
394 n.append(c2);
395 c3 = KDbConstExpression(KDbToken::INTEGER_CONST, 5);
396 QVERIFY(!n.remove(c3)); // not found
397 QCOMPARE(n.argCount(), 2);
398 n.append(c3);
399 QCOMPARE(n.argCount(), 3);
400 QVERIFY(n.remove(c2)); // remove 2nd of 3, leaves c1 and c3
401 QCOMPARE(n.argCount(), 2);
402 QCOMPARE(n.arg(0).toConst(), c1);
403 QCOMPARE(n.arg(1).toConst(), c3);
404
405 // -- removeAt(int)
406 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
407 n.prepend(c1);
408 n.append(c2);
409 n.removeAt(-1); // not found
410 QCOMPARE(n.argCount(), 2);
411 n.removeAt(3); // not found
412 QCOMPARE(n.argCount(), 2);
413 n.append(c3);
414 n.removeAt(1); // remove 2nd of 3, leaves c1 and c3
415 QCOMPARE(n.argCount(), 2);
416 QCOMPARE(n.arg(0).toConst(), c1);
417 QCOMPARE(n.arg(1).toConst(), c3);
418 n.removeAt(0);
419 QCOMPARE(n.argCount(), 1);
420 n.removeAt(0);
421 QCOMPARE(n.argCount(), 0);
422
423 // -- takeAt(int)
424 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
425 n2 = n;
426 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 1);
427 c2 = KDbConstExpression(KDbToken::INTEGER_CONST, 2);
428 c3 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
429 n.append(c1);
430 n.append(c2);
431 n.append(c3);
432 n.takeAt(-1); // not found
433 QCOMPARE(n.argCount(), 3);
434 n.takeAt(3); // not found
435 QCOMPARE(n.argCount(), 3);
436 e = n.takeAt(1);
437 QCOMPARE(e.toConst(), c2); // e is 2nd
438 QCOMPARE(n.argCount(), 2); // 1 arg taken
439 QCOMPARE(n, n2);
440
441 // -- indexOf(KDbExpression, int)
442 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
443 c = KDbConstExpression(KDbToken::INTEGER_CONST, 0);
444 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 1);
445 c2 = KDbConstExpression(KDbToken::INTEGER_CONST, 2);
446 c3 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
447 n.append(c1);
448 n.append(c2);
449 n.append(c3);
450
451 QCOMPARE(n.indexOf(c), -1);
452 QCOMPARE(n.indexOf(c1), 0);
453 QCOMPARE(n.indexOf(c2), 1);
454 QCOMPARE(n.indexOf(c3), 2);
455 QCOMPARE(n.indexOf(c1, 1), -1);
456 QCOMPARE(n.indexOf(c2, 1), 1);
457
458 // -- lastIndexOf(KDbExpression, int)
459 QCOMPARE(n.lastIndexOf(c), -1);
460 QCOMPARE(n.lastIndexOf(c1), 0);
461 QCOMPARE(n.lastIndexOf(c2), 1);
462 QCOMPARE(n.lastIndexOf(c3), 2);
463 QCOMPARE(n.lastIndexOf(c1, 1), 0);
464 QCOMPARE(n.lastIndexOf(c2, 0), -1);
465
466 // -- a list of arguments
467 n = KDbNArgExpression(KDb::ArgumentListExpression, ',');
468 n.append(KDbConstExpression(KDbToken::INTEGER_CONST, 1));
469 n.append(KDbConstExpression(KDbToken::INTEGER_CONST, 2));
470 n.append(KDbConstExpression(KDbToken::INTEGER_CONST, 3));
471 QCOMPARE(n.toString(nullptr), KDbEscapedString("1, 2, 3"));
472 QCOMPARE(n.argCount(), 3);
473 QVERIFY(!n.containsInvalidArgument());
474 QVERIFY(!n.containsNullArgument());
475
476 // -- a list of arguments contains invalid argument
477 n = KDbNArgExpression(KDb::ArgumentListExpression, ',');
478 n.append(KDbConstExpression(KDbToken::INTEGER_CONST, 1));
479 n.append(KDbExpression());
480 n.append(KDbConstExpression(KDbToken::INTEGER_CONST, 3));
481 QVERIFY(n.containsInvalidArgument());
482 QVERIFY(!n.containsNullArgument());
483 QVERIFY(!n.isNull());
484 QCOMPARE(n.toString(nullptr), KDbEscapedString("1, <UNKNOWN!>, 3"));
485
486 // -- a list of arguments contains null argument
487 n = KDbNArgExpression(KDb::ArgumentListExpression, ',');
488 n.append(KDbConstExpression(KDbToken::INTEGER_CONST, 1));
489 n.append(KDbConstExpression(KDbToken::SQL_NULL, QVariant()));
490 n.prepend(KDbConstExpression(KDbToken::INTEGER_CONST, 0));
491 QVERIFY(!n.containsInvalidArgument());
492 QVERIFY(n.containsNullArgument());
493 QCOMPARE(n.toString(nullptr), KDbEscapedString("0, 1, NULL"));
494 }
495
testUnaryExpression()496 void ExpressionsTest::testUnaryExpression()
497 {
498 KDbUnaryExpression u;
499 KDbUnaryExpression u2;
500 KDbConstExpression c;
501 KDbConstExpression c1;
502
503 // -- empty
504 KDbUnaryExpression emptyUnary;
505 QVERIFY(emptyUnary.isUnary());
506 QVERIFY(emptyUnary.clone().isUnary());
507 QVERIFY(emptyUnary.arg().isNull());
508
509 u = KDbUnaryExpression('-', KDbExpression());
510 QVERIFY(u.arg().isNull());
511
512 // -- copy ctor & cloning
513 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 7);
514 u = KDbUnaryExpression('-', c1);
515 testCloneExpression(u);
516 QCOMPARE(u.token().name(), QString("-"));
517 QCOMPARE(u.toString(nullptr), KDbEscapedString("-7"));
518 QCOMPARE(c1, u.arg().toConst());
519
520 u2 = KDbUnaryExpression('-', u);
521 testCloneExpression(u);
522 QCOMPARE(u2.token().name(), QString("-"));
523 QCOMPARE(u2.toString(nullptr), KDbEscapedString("--7"));
524 QCOMPARE(u, u2.arg().toUnary());
525
526 u = KDbUnaryExpression('(', c1);
527 testCloneExpression(u);
528 QCOMPARE(u.toString(nullptr), KDbEscapedString("(7)"));
529 QCOMPARE(c1, u.arg().toConst());
530
531 c1 = KDbConstExpression(KDbToken::SQL_TRUE, true);
532 u = KDbUnaryExpression(KDbToken::NOT, c1);
533 testCloneExpression(u);
534 QCOMPARE(u.toString(nullptr), KDbEscapedString("NOT TRUE"));
535 QCOMPARE(c1, u.arg().toConst());
536
537 c1 = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
538 u = KDbUnaryExpression(KDbToken::NOT, c1);
539 testCloneExpression(u);
540 QCOMPARE(u.toString(nullptr), KDbEscapedString("NOT NULL"));
541 QCOMPARE(c1, u.arg().toConst());
542
543 c1 = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
544 u = KDbUnaryExpression(KDbToken::SQL_IS_NULL, c1);
545 testCloneExpression(u);
546 QCOMPARE(u.toString(nullptr), KDbEscapedString("NULL IS NULL"));
547 QCOMPARE(c1, u.arg().toConst());
548
549 c1 = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
550 u = KDbUnaryExpression(KDbToken::SQL_IS_NOT_NULL, c1);
551 testCloneExpression(u);
552 QCOMPARE(u.toString(nullptr), KDbEscapedString("NULL IS NOT NULL"));
553 QCOMPARE(c1, u.arg().toConst());
554
555 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 17);
556 u = KDbUnaryExpression(KDbToken::SQL, c1);
557 testCloneExpression(u);
558 QCOMPARE(u.toString(nullptr), KDbEscapedString("SQL 17"));
559 QCOMPARE(c1, u.arg().toConst());
560
561 // -- exchanging arg between two unary expressions
562 c = KDbConstExpression(KDbToken::INTEGER_CONST, 17);
563 u = KDbUnaryExpression('-', c);
564 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
565 u2 = KDbUnaryExpression('+', c1);
566 u2.setArg(c); // this should take c arg from u to u2
567 QCOMPARE(c, u2.arg().toConst()); // c is now in u2
568 QVERIFY(u.arg().isNull()); // u has null arg now
569
570 c = KDbConstExpression(KDbToken::INTEGER_CONST, 17);
571 u = KDbUnaryExpression('-', c);
572 u2 = KDbUnaryExpression('+', c);
573 // u2 takes c arg from u
574 QCOMPARE(c, u2.arg().toConst()); // c is now in u2
575 QVERIFY(u.arg().isNull()); // u has null arg now
576
577 // -- cycles
578 c = KDbConstExpression(KDbToken::INTEGER_CONST, 17);
579 u = KDbUnaryExpression('-', c);
580 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
581 u2 = KDbUnaryExpression('+', c1);
582 u2.setArg(u);
583 u.setArg(u2);
584
585 QTest::ignoreMessage(QtWarningMsg, R"w(Cycle detected in expression (depth 2):
586 1: Unary -
587 2: Unary +)w");
588 QCOMPARE(u.toString(nullptr), KDbEscapedString("-+<CYCLE!>"));
589
590 QTest::ignoreMessage(QtWarningMsg, R"w(Cycle detected in expression (depth 2):
591 1: Unary +
592 2: Unary -)w");
593 QCOMPARE(u2.toString(nullptr), KDbEscapedString("+-<CYCLE!>"));
594 }
595
testBinaryExpression()596 void ExpressionsTest::testBinaryExpression()
597 {
598 KDbBinaryExpression b;
599 KDbBinaryExpression b2;
600 KDbConstExpression c;
601 KDbConstExpression c1;
602
603 // -- empty
604 KDbBinaryExpression emptyBinary;
605 QVERIFY(emptyBinary.isNull());
606 QVERIFY(emptyBinary.isBinary());
607 QVERIFY(emptyBinary.clone().isBinary());
608 QVERIFY(emptyBinary.left().isNull());
609 QVERIFY(emptyBinary.right().isNull());
610
611 QTest::ignoreMessage(QtWarningMsg,
612 "Setting KDbBinaryExpression to null because left argument is not specified");
613 b = KDbBinaryExpression(KDbExpression(), '-', KDbExpression());
614 QVERIFY(b.left().isNull());
615 QVERIFY(b.right().isNull());
616 QVERIFY(b.isNull()); // it's null because args are null
617 //qDebug() << b.toString(nullptr);
618 QCOMPARE(b.toString(nullptr), KDbEscapedString("<UNKNOWN!>"));
619 c = KDbConstExpression(KDbToken::INTEGER_CONST, 10);
620 QTest::ignoreMessage(QtWarningMsg,
621 "Setting KDbBinaryExpression to null because right argument is not specified");
622 b = KDbBinaryExpression(c, '-', KDbExpression());
623 QVERIFY(b.left().isNull());
624 QVERIFY(b.right().isNull());
625 QVERIFY(b.isNull()); // it's null because one arg is null
626 //qDebug() << b.toString(nullptr);
627 QCOMPARE(b.toString(nullptr), KDbEscapedString("<UNKNOWN!>"));
628 QTest::ignoreMessage(QtWarningMsg,
629 "Setting KDbBinaryExpression to null because left argument is not specified");
630 b = KDbBinaryExpression(KDbExpression(), '-', c);
631 QVERIFY(b.left().isNull());
632 QVERIFY(b.right().isNull());
633 QVERIFY(b.isNull()); // it's null because one arg is null
634 //qDebug() << b.toString(nullptr);
635 QCOMPARE(b.toString(nullptr), KDbEscapedString("<UNKNOWN!>"));
636
637 // -- copy ctor & cloning
638 c = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
639 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 4);
640 b = KDbBinaryExpression(c, '/', c1);
641 testCloneExpression(b);
642 QCOMPARE(b.token().name(), QString("/"));
643 QCOMPARE(b.toString(nullptr), KDbEscapedString("3 / 4"));
644 QCOMPARE(c1, b.right().toConst());
645
646 b2 = KDbBinaryExpression(b, '*', b.clone());
647 testCloneExpression(b2);
648 QCOMPARE(b2.token().name(), QString("*"));
649 QCOMPARE(b2.toString(nullptr), KDbEscapedString("3 / 4 * 3 / 4"));
650 QCOMPARE(b, b2.left().toBinary());
651
652 // -- cycles
653 // --- ref to parent
654 b = KDbBinaryExpression(
655 KDbConstExpression(KDbToken::INTEGER_CONST, 1), '+', KDbConstExpression(KDbToken::INTEGER_CONST, 2));
656 KDbEscapedString s = b.toString(nullptr);
657 QTest::ignoreMessage(QtWarningMsg,
658 QRegularExpression("Expression BinaryExp(.*) cannot be set as own child"));
659 b.setLeft(b); // should not work
660 //qDebug() << b.toString(nullptr);
661 QCOMPARE(s, b.toString(nullptr));
662 // --- cannot set twice
663 c = b.left().toConst();
664 b.setLeft(c);
665 QCOMPARE(s, b.toString(nullptr));
666 // --- ref to grandparent
667 b = KDbBinaryExpression(
668 KDbConstExpression(KDbToken::INTEGER_CONST, 1), '+', KDbConstExpression(KDbToken::INTEGER_CONST, 2));
669 c = KDbConstExpression(KDbToken::INTEGER_CONST, 10);
670 b2 = KDbBinaryExpression(b, '-', c);
671 //qDebug() << b2.toString(nullptr);
672 QCOMPARE(b2.toString(nullptr), KDbEscapedString("1 + 2 - 10"));
673 QTest::ignoreMessage(QtWarningMsg, R"w(Cycle detected in expression (depth 2):
674 1: Arithm -
675 2: Arithm +)w");
676 b.setRight(b2);
677 //qDebug() << b2.toString(nullptr);
678 QCOMPARE(b2.toString(nullptr), KDbEscapedString("1 + <CYCLE!> - 10"));
679
680 // -- moving right argument to left should remove right arg
681 b = KDbBinaryExpression(
682 KDbConstExpression(KDbToken::INTEGER_CONST, 1), '+', KDbConstExpression(KDbToken::INTEGER_CONST, 2));
683 c = b.right().toConst();
684 b.setLeft(c);
685 //qDebug() << b.toString(nullptr);
686 QCOMPARE(b.toString(nullptr), KDbEscapedString("2 + <UNKNOWN!>"));
687
688 // -- moving left argument to right should remove left arg
689 b = KDbBinaryExpression(
690 KDbConstExpression(KDbToken::INTEGER_CONST, 1), '+', KDbConstExpression(KDbToken::INTEGER_CONST, 2));
691 c = b.left().toConst();
692 b.setRight(c);
693 //qDebug() << b.toString(nullptr);
694 QCOMPARE(b.toString(nullptr), KDbEscapedString("<UNKNOWN!> + 1"));
695 }
696
testBinaryExpressionCloning_data()697 void ExpressionsTest::testBinaryExpressionCloning_data()
698 {
699 QTest::addColumn<KDbToken>("type1");
700 QTest::addColumn<QVariant>("const1");
701 QTest::addColumn<KDbToken>("token");
702 QTest::addColumn<KDbToken>("type2");
703 QTest::addColumn<QVariant>("const2");
704 QTest::addColumn<QString>("string");
705
706 #define T(type1, const1, token, type2, const2, string) \
707 QTest::newRow(qPrintable(TO_TOKEN(token).name())) \
708 << type1 << QVariant(const1) << TO_TOKEN(token) \
709 << type2 << QVariant(const2) << QString(string)
710
711 T(KDbToken::INTEGER_CONST, 3, '/', KDbToken::INTEGER_CONST, 4, "3 / 4");
712 T(KDbToken::INTEGER_CONST, 3, KDbToken::BITWISE_SHIFT_RIGHT, KDbToken::INTEGER_CONST, 4, "3 >> 4");
713 T(KDbToken::INTEGER_CONST, 3, KDbToken::BITWISE_SHIFT_LEFT, KDbToken::INTEGER_CONST, 4, "3 << 4");
714 T(KDbToken::INTEGER_CONST, 3, KDbToken::NOT_EQUAL, KDbToken::INTEGER_CONST, 4, "3 <> 4");
715 T(KDbToken::INTEGER_CONST, 3, KDbToken::NOT_EQUAL2, KDbToken::INTEGER_CONST, 4, "3 != 4");
716 T(KDbToken::INTEGER_CONST, 3, KDbToken::LESS_OR_EQUAL, KDbToken::INTEGER_CONST, 4, "3 <= 4");
717 T(KDbToken::INTEGER_CONST, 3, KDbToken::GREATER_OR_EQUAL, KDbToken::INTEGER_CONST, 4, "3 >= 4");
718 T(KDbToken::CHARACTER_STRING_LITERAL, "ABC", KDbToken::LIKE, KDbToken::CHARACTER_STRING_LITERAL, "A%", "'ABC' LIKE 'A%'");
719 T(KDbToken::INTEGER_CONST, 3, KDbToken::SQL_IN, KDbToken::INTEGER_CONST, 4, "3 IN 4");
720 T(KDbToken::INTEGER_CONST, 3, KDbToken::SIMILAR_TO, KDbToken::INTEGER_CONST, 4, "3 SIMILAR TO 4");
721 T(KDbToken::INTEGER_CONST, 3, KDbToken::NOT_SIMILAR_TO, KDbToken::INTEGER_CONST, 4, "3 NOT SIMILAR TO 4");
722 T(KDbToken::SQL_TRUE, true, KDbToken::OR, KDbToken::SQL_FALSE, false, "TRUE OR FALSE");
723 T(KDbToken::INTEGER_CONST, 3, KDbToken::AND, KDbToken::INTEGER_CONST, 4, "3 AND 4");
724 T(KDbToken::INTEGER_CONST, 3, KDbToken::XOR, KDbToken::INTEGER_CONST, 4, "3 XOR 4");
725 T(KDbToken::CHARACTER_STRING_LITERAL, "AB", KDbToken::CONCATENATION, KDbToken::CHARACTER_STRING_LITERAL, "CD", "'AB' || 'CD'");
726 T(KDbToken::CHARACTER_STRING_LITERAL, "AB", '+', KDbToken::CHARACTER_STRING_LITERAL, "CD", "'AB' + 'CD'");
727 #undef T
728 }
729
testBinaryExpressionCloning()730 void ExpressionsTest::testBinaryExpressionCloning()
731 {
732 QFETCH(KDbToken, type1);
733 QFETCH(QVariant, const1);
734 QFETCH(KDbToken, token);
735 QFETCH(KDbToken, type2);
736 QFETCH(QVariant, const2);
737 QFETCH(QString, string);
738
739 KDbConstExpression c(type1, const1);
740 KDbConstExpression c1(type2, const2);
741 KDbBinaryExpression b(c, token, c1);
742 testCloneExpression(b);
743 QCOMPARE(b.token(), token);
744 QCOMPARE(b.token().name(), token.name());
745 //qDebug() << token << b;
746 QCOMPARE(b.toString(nullptr), KDbEscapedString(string));
747 QCOMPARE(c, b.left().toConst());
748 QCOMPARE(c1, b.right().toConst());
749 }
750
testFunctionExpression()751 void ExpressionsTest::testFunctionExpression()
752 {
753 KDbFunctionExpression emptyFunction;
754 QVERIFY(emptyFunction.isFunction());
755 QVERIFY(emptyFunction.clone().isFunction());
756 QVERIFY(emptyFunction.arguments().isEmpty());
757 QVERIFY(emptyFunction.isNull());
758
759 KDbNArgExpression args;
760 args.append(KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, "abc"));
761 args.append(KDbConstExpression(KDbToken::INTEGER_CONST, 2));
762 KDbFunctionExpression f_substr("SUBSTR", args);
763 //qDebug() << f_substr.toString();
764 //qDebug() << f_substr.token().name();
765 //qDebug() << f_substr.token().toString();
766
767 testCloneExpression(f_substr);
768 QCOMPARE(f_substr.type(), KDbField::Text);
769
770 args.append(KDbConstExpression(KDbToken::INTEGER_CONST, 1));
771 KDbFunctionExpression f_substr2("SUBSTR", args);
772 testCloneExpression(f_substr2);
773 QCOMPARE(f_substr2.type(), KDbField::Text);
774 //qDebug() << f_substr.toString();
775 //qDebug() << f_substr2.toString();
776 QVERIFY(f_substr != f_substr2); // other objects
777 QCOMPARE(f_substr.toString(nullptr), f_substr2.toString(nullptr)); // the same signatures
778 QCOMPARE(f_substr.arguments(), f_substr2.arguments()); // the same arg lists
779
780 // clone the args
781 KDbNArgExpression args2 = args.clone().toNArg();
782 //qDebug() << f_substr2;
783 f_substr2.setArguments(args2);
784 //qDebug() << f_substr2;
785 QCOMPARE(f_substr.toString(nullptr), f_substr2.toString(nullptr)); // still the same signatures
786 QVERIFY(f_substr.arguments() != f_substr2.arguments()); // not the same arg lists
787
788 KDbExpression e = f_substr;
789 QCOMPARE(e.toFunction(), f_substr);
790 QCOMPARE(e.toFunction(), f_substr.toFunction());
791 QVERIFY(e.isFunction());
792
793 // nested functions
794 f_substr2.arguments().replace(0, f_substr);
795 QCOMPARE(f_substr2.type(), KDbField::Text);
796 }
797
testConstExpressionValidate()798 void ExpressionsTest::testConstExpressionValidate()
799 {
800 KDbConstExpression c;
801
802 c = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
803 QCOMPARE(c.type(), KDbField::Null);
804 QVERIFY(c.isValid());
805 QVERIFY(!c.isNull());
806 QVERIFY(validate(&c));
807
808 // null
809 c = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
810 QCOMPARE(c.type(), KDbField::Null);
811 QVERIFY(validate(&c));
812 testCloneExpression(c);
813 //qDebug() << c;
814
815 // integer
816 c = KDbConstExpression(KDbToken::INTEGER_CONST, -0x7f);
817 QCOMPARE(c.type(), KDbField::Byte);
818 QVERIFY(c.isValid());
819 QVERIFY(c.isNumericType());
820 QVERIFY(!c.isNull());
821 QCOMPARE(c.value(), QVariant(-0x7f));
822 QVERIFY(validate(&c));
823 testCloneExpression(c);
824 c.setValue(-0x80);
825 QCOMPARE(c.type(), KDbField::ShortInteger); // type has been changed by setValue
826 QCOMPARE(c.value(), QVariant(-0x80));
827 QVERIFY(validate(&c));
828 testCloneExpression(c);
829 //qDebug() << c;
830
831 c = KDbConstExpression(KDbToken::INTEGER_CONST, -10);
832 QCOMPARE(c.type(), KDbField::Byte);
833 QVERIFY(c.isValid());
834 QVERIFY(c.isNumericType());
835 QCOMPARE(c.value(), QVariant(-10));
836 QVERIFY(validate(&c));
837 testCloneExpression(c);
838 //qDebug() << c;
839
840 c = KDbConstExpression(KDbToken::INTEGER_CONST, 0);
841 QCOMPARE(c.type(), KDbField::Byte);
842 QVERIFY(c.isValid());
843 QVERIFY(c.isNumericType());
844 QCOMPARE(c.value(), QVariant(0));
845 QVERIFY(validate(&c));
846 testCloneExpression(c);
847 //qDebug() << c;
848
849 c = KDbConstExpression(KDbToken::INTEGER_CONST, 20);
850 QCOMPARE(c.type(), KDbField::Byte);
851 QVERIFY(c.isValid());
852 QVERIFY(c.isNumericType());
853 QCOMPARE(c.value(), QVariant(20));
854 QVERIFY(validate(&c));
855 testCloneExpression(c);
856 //qDebug() << c;
857
858 c = KDbConstExpression(KDbToken::INTEGER_CONST, 255);
859 QCOMPARE(c.type(), KDbField::Byte);
860 QVERIFY(c.isValid());
861 QVERIFY(c.isNumericType());
862 QCOMPARE(c.value(), QVariant(255));
863 QVERIFY(validate(&c));
864 testCloneExpression(c);
865 //qDebug() << c;
866
867 c = KDbConstExpression(KDbToken::INTEGER_CONST, -0x80);
868 QCOMPARE(c.type(), KDbField::ShortInteger);
869 QVERIFY(c.isValid());
870 QVERIFY(c.isNumericType());
871 QCOMPARE(c.value(), QVariant(-0x80));
872 QVERIFY(validate(&c));
873 testCloneExpression(c);
874 //qDebug() << c;
875
876 c = KDbConstExpression(KDbToken::INTEGER_CONST, -0x7fff);
877 QCOMPARE(c.type(), KDbField::ShortInteger);
878 QVERIFY(c.isValid());
879 QVERIFY(c.isNumericType());
880 QCOMPARE(c.value(), QVariant(-0x7fff));
881 QVERIFY(validate(&c));
882 testCloneExpression(c);
883 //qDebug() << c;
884
885 c = KDbConstExpression(KDbToken::INTEGER_CONST, 256);
886 QCOMPARE(c.type(), KDbField::ShortInteger);
887 QVERIFY(c.isValid());
888 QVERIFY(c.isNumericType());
889 QCOMPARE(c.value(), QVariant(256));
890 QVERIFY(validate(&c));
891 testCloneExpression(c);
892 //qDebug() << c;
893
894 c = KDbConstExpression(KDbToken::INTEGER_CONST, 0xffff);
895 QCOMPARE(c.type(), KDbField::ShortInteger);
896 QVERIFY(c.isValid());
897 QVERIFY(c.isNumericType());
898 QCOMPARE(c.value(), QVariant(0xffff));
899 QVERIFY(validate(&c));
900 testCloneExpression(c);
901 //qDebug() << c;
902
903 c = KDbConstExpression(KDbToken::INTEGER_CONST, -0x8000);
904 QCOMPARE(c.type(), KDbField::Integer);
905 QVERIFY(c.isValid());
906 QVERIFY(c.isNumericType());
907 QCOMPARE(c.value(), QVariant(-0x8000));
908 QVERIFY(validate(&c));
909 testCloneExpression(c);
910 //qDebug() << c;
911
912 c = KDbConstExpression(KDbToken::INTEGER_CONST, uint(0x10000));
913 QCOMPARE(c.type(), KDbField::Integer);
914 QVERIFY(c.isValid());
915 QVERIFY(c.isNumericType());
916 QCOMPARE(c.value(), QVariant(0x10000));
917 QVERIFY(validate(&c));
918 testCloneExpression(c);
919 //qDebug() << c;
920
921 c = KDbConstExpression(KDbToken::INTEGER_CONST, qlonglong(-0x100000));
922 QCOMPARE(c.type(), KDbField::BigInteger);
923 QVERIFY(c.isValid());
924 QVERIFY(c.isNumericType());
925 QCOMPARE(c.value(), QVariant(-0x100000));
926 QVERIFY(validate(&c));
927 testCloneExpression(c);
928 //qDebug() << c;
929
930 c = KDbConstExpression(KDbToken::INTEGER_CONST, qulonglong(0x1000000));
931 QCOMPARE(c.type(), KDbField::BigInteger);
932 QVERIFY(c.isValid());
933 QVERIFY(c.isNumericType());
934 QCOMPARE(c.value(), QVariant(0x1000000));
935 QVERIFY(validate(&c));
936 testCloneExpression(c);
937 //qDebug() << c;
938
939 // string
940 int oldMaxLen = KDbField::defaultMaxLength(); // save
941 KDbField::setDefaultMaxLength(0);
942 c = KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, "01234567890");
943 QVERIFY(c.isValid());
944 QVERIFY(c.isTextType());
945 QCOMPARE(c.type(), KDbField::Text);
946 QCOMPARE(c.value(), QVariant("01234567890"));
947 QVERIFY(validate(&c));
948 testCloneExpression(c);
949 //qDebug() << c;
950
951 KDbField::setDefaultMaxLength(10);
952 c = KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, QString());
953 QCOMPARE(c.type(), KDbField::Text);
954 QVERIFY(c.isValid());
955 QVERIFY(c.isTextType());
956 QCOMPARE(c.value(), QVariant(QString()));
957 QVERIFY(validate(&c));
958 testCloneExpression(c);
959 //qDebug() << c;
960
961 c = KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, QVariant());
962 QCOMPARE(c.type(), KDbField::Text);
963 QVERIFY(c.isValid());
964 QVERIFY(c.isTextType());
965 QCOMPARE(c.value(), QVariant());
966 QVERIFY(validate(&c));
967 testCloneExpression(c);
968 //qDebug() << c;
969
970 c = KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, "01234567890");
971 QCOMPARE(c.type(), KDbField::LongText);
972 QVERIFY(c.isValid());
973 QVERIFY(c.isTextType());
974 QCOMPARE(c.value(), QVariant("01234567890"));
975 QVERIFY(validate(&c));
976 //qDebug() << c;
977 c.setValue("ąćę");
978 QCOMPARE(c.value(), QVariant("ąćę"));
979 QCOMPARE(c.type(), KDbField::Text);
980 QVERIFY(validate(&c));
981 testCloneExpression(c);
982 //qDebug() << c;
983
984 KDbField::setDefaultMaxLength(oldMaxLen); // restore
985
986 // bool
987 c = KDbConstExpression(KDbToken::SQL_TRUE, true);
988 QCOMPARE(c.type(), KDbField::Boolean);
989 QVERIFY(c.isValid());
990 QVERIFY(!c.isTextType());
991 QVERIFY(!c.isNumericType());
992 QCOMPARE(c.value(), QVariant(true));
993 QVERIFY(validate(&c));
994 //qDebug() << c;
995 c.setValue(false);
996 QCOMPARE(c.value(), QVariant(false));
997 QVERIFY(validate(&c));
998 testCloneExpression(c);
999 //qDebug() << c;
1000
1001 c = KDbConstExpression(KDbToken::SQL_FALSE, false);
1002 QCOMPARE(c.type(), KDbField::Boolean);
1003 QVERIFY(c.isValid());
1004 QVERIFY(!c.isTextType());
1005 QVERIFY(!c.isNumericType());
1006 QCOMPARE(c.value(), QVariant(false));
1007 QVERIFY(validate(&c));
1008 testCloneExpression(c);
1009 //qDebug() << c;
1010
1011 // real
1012 c = KDbConstExpression(KDbToken::REAL_CONST, QVariant());
1013 QCOMPARE(c.type(), KDbField::Double);
1014 QVERIFY(c.isValid());
1015 QVERIFY(c.isNumericType());
1016 QVERIFY(c.isFPNumericType());
1017 QCOMPARE(c.value(), QVariant());
1018 QCOMPARE(c.toString(nullptr), KDbEscapedString());
1019 QVERIFY(validate(&c));
1020 testCloneExpression(c);
1021 //qDebug() << c;
1022
1023 c = KDbConstExpression(KDbToken::REAL_CONST, 3.14159);
1024 QCOMPARE(c.type(), KDbField::Double);
1025 QVERIFY(c.isValid());
1026 QVERIFY(c.isNumericType());
1027 QVERIFY(c.isFPNumericType());
1028 QCOMPARE(c.value(), QVariant(3.14159));
1029 QString piString("3.14159");
1030 // limit precision because it depends on the OS
1031 QCOMPARE(c.toString(nullptr).toString().left(piString.length() - 1), piString.left(piString.length() - 1));
1032 QVERIFY(validate(&c));
1033 //qDebug() << c;
1034 c.setValue(-18.012);
1035 QCOMPARE(c.value(), QVariant(-18.012));
1036 QCOMPARE(c.toString(nullptr), KDbEscapedString("-18.012"));
1037 QVERIFY(validate(&c));
1038 testCloneExpression(c);
1039 //qDebug() << c;
1040
1041 QByteArray largeDecimal("2147483647.2147483647");
1042 c = KDbConstExpression(KDbToken::REAL_CONST, largeDecimal);
1043 QCOMPARE(c.type(), KDbField::Double);
1044 QVERIFY(c.isValid());
1045 QVERIFY(c.isNumericType());
1046 QVERIFY(c.isFPNumericType());
1047 QCOMPARE(c.value(), QVariant(largeDecimal));
1048 QCOMPARE(c.toString(nullptr), KDbEscapedString(largeDecimal));
1049 largeDecimal = "-10.2147483647";
1050 QVERIFY(validate(&c));
1051 testCloneExpression(c);
1052 //qDebug() << c;
1053 c = KDbConstExpression(KDbToken::REAL_CONST, largeDecimal);
1054 QCOMPARE(c.value(), QVariant(largeDecimal));
1055 QCOMPARE(c.toString(nullptr), KDbEscapedString(largeDecimal));
1056 QVERIFY(validate(&c));
1057 testCloneExpression(c);
1058 //qDebug() << c;
1059
1060 // date
1061 QDate date(QDate::currentDate());
1062 c = KDbConstExpression(KDbToken::DATE_CONST, date);
1063 QVERIFY(c.isValid());
1064 QVERIFY(c.isDateTimeType());
1065 QCOMPARE(c.type(), KDbField::Date);
1066 QCOMPARE(c.value(), QVariant(date));
1067 QVERIFY(validate(&c));
1068 testCloneExpression(c);
1069 //qDebug() << c;
1070 date = date.addDays(17);
1071 c.setValue(date);
1072 QCOMPARE(c.value(), QVariant(date));
1073 QVERIFY(c.isValid());
1074 QVERIFY(c.isDateTimeType());
1075 QVERIFY(validate(&c));
1076 testCloneExpression(c);
1077
1078 KDbDate dateKDb(KDbYear("2018"), "11", "27");
1079 c.setValue(QVariant::fromValue(dateKDb));
1080 QCOMPARE(c.value(), QVariant::fromValue(dateKDb));
1081 QVERIFY(c.isValid());
1082 QVERIFY(c.isDateTimeType());
1083 QVERIFY(validate(&c));
1084 testCloneExpression(c);
1085
1086 // time
1087 QTime time(QTime::currentTime());
1088 c = KDbConstExpression(KDbToken::TIME_CONST, time);
1089 QCOMPARE(c.type(), KDbField::Time);
1090 QVERIFY(c.isValid());
1091 QVERIFY(c.isDateTimeType());
1092 QCOMPARE(c.value(), QVariant(time));
1093 testCloneExpression(c);
1094 QVERIFY(validate(&c));
1095 time = time.addMSecs(1200123);
1096 c.setValue(time);
1097 QCOMPARE(c.value(), QVariant(time));
1098 QVERIFY(c.isValid());
1099 QVERIFY(c.isDateTimeType());
1100 QVERIFY(validate(&c));
1101 testCloneExpression(c);
1102
1103 KDbTime timeKDb("12", "34", "56", "789");
1104 c.setValue(QVariant::fromValue(timeKDb));
1105 QCOMPARE(c.value(), QVariant::fromValue(timeKDb));
1106 QVERIFY(c.isValid());
1107 QVERIFY(c.isDateTimeType());
1108 QVERIFY(validate(&c));
1109 testCloneExpression(c);
1110
1111 // date/time
1112 QDateTime dateTime(QDateTime::currentDateTime());
1113 c = KDbConstExpression(KDbToken::DATETIME_CONST, dateTime);
1114 QCOMPARE(c.type(), KDbField::DateTime);
1115 QVERIFY(c.isValid());
1116 QVERIFY(c.isDateTimeType());
1117 QCOMPARE(c.value(), QVariant(dateTime));
1118 QVERIFY(validate(&c));
1119 testCloneExpression(c);
1120 //qDebug() << c;
1121 dateTime = dateTime.addDays(-17);
1122 c.setValue(dateTime);
1123 QCOMPARE(c.value(), QVariant(dateTime));
1124 QVERIFY(c.isValid());
1125 QVERIFY(c.isDateTimeType());
1126 QVERIFY(validate(&c));
1127 testCloneExpression(c);
1128 //qDebug() << c;
1129 KDbDateTime dateTimeKDb(dateKDb, timeKDb);
1130 c.setValue(QVariant::fromValue(dateTimeKDb));
1131 // qDebug() << QVariant::fromValue(dateTimeKDb);
1132 // qDebug() << QVariant::fromValue(dateTimeKDb).isValid();
1133 // qDebug() << c.value();
1134 // qDebug() << c.value().isValid();
1135 // qDebug() << (QVariant::fromValue(dateTimeKDb) == c.value());
1136 QCOMPARE(c.value(), QVariant::fromValue(dateTimeKDb));
1137 QVERIFY(c.isValid());
1138 QVERIFY(c.isDateTimeType());
1139 QVERIFY(validate(&c));
1140 testCloneExpression(c);
1141
1142 // setValue()
1143 c = KDbConstExpression(KDbToken::INTEGER_CONST, 124);
1144 QCOMPARE(c.value(), QVariant(124));
1145 c.setValue(299);
1146 QCOMPARE(c.value(), QVariant(299));
1147 QVERIFY(c.isValid());
1148 QVERIFY(c.isNumericType());
1149 QVERIFY(!c.isFPNumericType());
1150 testCloneExpression(c);
1151 //qDebug() << c;
1152 }
1153
testUnaryExpressionValidate()1154 void ExpressionsTest::testUnaryExpressionValidate()
1155 {
1156 KDbConstExpression c;
1157 KDbConstExpression c1;
1158 KDbUnaryExpression u;
1159 KDbUnaryExpression u2;
1160
1161 // cycles detected by validate()
1162 c = KDbConstExpression(KDbToken::INTEGER_CONST, 17);
1163 u = KDbUnaryExpression('-', c);
1164 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
1165 u2 = KDbUnaryExpression('+', c1);
1166 u2.setArg(u);
1167 u.setArg(u2);
1168 const char *warning = R"w(Cycle detected in expression (depth 2):
1169 1: Unary -
1170 2: Unary +)w";
1171 QTest::ignoreMessage(QtWarningMsg, warning);
1172 warning = R"w(Cycle detected in expression (depth 2):
1173 1: Unary +
1174 2: Unary -)w";
1175 QTest::ignoreMessage(QtWarningMsg, warning);
1176 warning = R"w(Cycle detected in expression (depth 2):
1177 1: Unary -
1178 2: Unary +)w";
1179 QTest::ignoreMessage(QtWarningMsg, warning);
1180 QTest::ignoreMessage(QtWarningMsg, warning);
1181 QVERIFY(!validate(&u));
1182 ////qDebug() << c << u << c1 << u2;
1183
1184 // NOT NULL is NULL
1185 c = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
1186 u = KDbUnaryExpression(KDbToken::NOT, c);
1187 QCOMPARE(u.type(), KDbField::Null);
1188 QVERIFY(validate(&u));
1189 testCloneExpression(u);
1190
1191 // NOT "abc" is INVALID
1192 c = KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, "abc");
1193 u = KDbUnaryExpression(KDbToken::NOT, c);
1194 QCOMPARE(u.type(), KDbField::InvalidType);
1195 QVERIFY(!validate(&u));
1196 testCloneExpression(u);
1197 }
1198
testNArgExpressionValidate()1199 void ExpressionsTest::testNArgExpressionValidate()
1200 {
1201 KDbNArgExpression n;
1202 KDbConstExpression c;
1203 KDbConstExpression c1;
1204 KDbConstExpression c2;
1205
1206 c = KDbConstExpression(KDbToken::SQL_NULL, QVariant());
1207 QCOMPARE(c.type(), KDbField::Null);
1208 QVERIFY(validate(&c));
1209
1210 n = KDbNArgExpression(KDb::ArithmeticExpression, '+');
1211 c = KDbConstExpression(KDbToken::INTEGER_CONST, 0);
1212 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 1);
1213 n.append(c);
1214 n.append(c1);
1215 QCOMPARE(n.type(), KDbField::Tuple);
1216 QVERIFY(validate(&n));
1217 testCloneExpression(n);
1218 ////qDebug() << c << c1 << n;
1219
1220 // -- a list of arguments
1221 n = KDbNArgExpression(KDb::ArgumentListExpression, ',');
1222 c = KDbConstExpression(KDbToken::INTEGER_CONST, 1);
1223 c1 = KDbConstExpression(KDbToken::INTEGER_CONST, 2);
1224 c2 = KDbConstExpression(KDbToken::INTEGER_CONST, 3);
1225 n.append(c);
1226 n.append(c1);
1227 n.append(c2);
1228 QCOMPARE(n.type(), KDbField::Tuple);
1229 QVERIFY(validate(&n));
1230 QVERIFY(n.isValid());
1231 }
1232
testBinaryExpressionValidate_data()1233 void ExpressionsTest::testBinaryExpressionValidate_data()
1234 {
1235 QTest::addColumn<KDbToken>("type1");
1236 QTest::addColumn<QVariant>("const1");
1237 QTest::addColumn<KDbToken>("token");
1238 QTest::addColumn<KDbToken>("type2");
1239 QTest::addColumn<QVariant>("const2");
1240 QTest::addColumn<KDbField::Type>("type3");
1241
1242 // invalid
1243 KDbConstExpression c(KDbToken::INTEGER_CONST, 7);
1244 QTest::ignoreMessage(QtWarningMsg,
1245 "Setting KDbBinaryExpression to null because right argument is not specified");
1246 KDbBinaryExpression b(c, '+', KDbExpression());
1247 QCOMPARE(b.type(), KDbField::InvalidType);
1248 QVERIFY(!validate(&b));
1249 testCloneExpression(b);
1250 //qDebug() << b;
1251
1252 QTest::ignoreMessage(QtWarningMsg,
1253 "Setting KDbBinaryExpression to null because left argument is not specified");
1254 b = KDbBinaryExpression(KDbExpression(), '/', KDbExpression());
1255 QCOMPARE(b.type(), KDbField::InvalidType);
1256 QVERIFY(!validate(&b)); // unknown class
1257 testCloneExpression(b);
1258 //qDebug() << b;
1259
1260 // invalid left or right
1261 QTest::ignoreMessage(QtWarningMsg,
1262 "Setting KDbBinaryExpression to null because left argument is not specified");
1263 KDbBinaryExpression b2(b, '*', c.clone());
1264 QCOMPARE(b2.type(), KDbField::InvalidType);
1265 QVERIFY(!validate(&b2)); // unknown class
1266 testCloneExpression(b2);
1267 //qDebug() << b2;
1268
1269 QTest::ignoreMessage(QtWarningMsg,
1270 "Setting KDbBinaryExpression to null because right argument is not specified");
1271 KDbBinaryExpression b3(c.clone(), '*', b);
1272 QCOMPARE(b3.type(), KDbField::InvalidType);
1273 QVERIFY(!validate(&b3)); // unknown class
1274 testCloneExpression(b3);
1275 //qDebug() << b3;
1276
1277 #define TNAME(type) type.name().toLatin1()
1278
1279 #define T1(type1, const1, tokenOrChar, type2, const2, type3) \
1280 QTest::newRow( \
1281 qPrintable(QString::number(__LINE__) + ": " + TNAME(type1) + " " \
1282 + QVariant(const1).toString() + " " \
1283 + TNAME(TO_TOKEN(tokenOrChar)) + " " \
1284 + TNAME(type2) + " " \
1285 + QVariant(const2).toString().toLatin1())) \
1286 << type1 << QVariant(const1) \
1287 << TO_TOKEN(tokenOrChar) << type2 << QVariant(const2) \
1288 << type3
1289 // tests both f(x, y) and f(y, x)
1290 #define T(type1, const1, token, type2, const2, type3) \
1291 T1(type1, const1, token, type2, const2, type3); \
1292 T1(type2, const2, token, type1, const1, type3)
1293
1294 // null
1295 T(KDbToken::SQL_NULL, QVariant(), '+', KDbToken::INTEGER_CONST, 7, KDbField::Null);
1296 // NULL OR true is true
1297 T(KDbToken::SQL_NULL, QVariant(), KDbToken::OR, KDbToken::SQL_TRUE, true, KDbField::Boolean);
1298 // NULL AND true is NULL
1299 T(KDbToken::SQL_NULL, QVariant(), KDbToken::AND, KDbToken::SQL_TRUE, true, KDbField::Null);
1300 // NULL OR false is NULL
1301 T(KDbToken::SQL_NULL, QVariant(), KDbToken::OR, KDbToken::SQL_FALSE, false, KDbField::Null);
1302 // NULL AND false is false
1303 T(KDbToken::SQL_NULL, QVariant(), KDbToken::AND, KDbToken::SQL_FALSE, false, KDbField::Boolean);
1304 // NULL AND NULL is NULL
1305 T(KDbToken::SQL_NULL, QVariant(), KDbToken::AND, KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1306 // NULL OR NULL is NULL
1307 T(KDbToken::SQL_NULL, QVariant(), KDbToken::OR, KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1308 // NULL XOR TRUE is NULL
1309 T(KDbToken::SQL_NULL, QVariant(), KDbToken::XOR, KDbToken::SQL_TRUE, true, KDbField::Null);
1310 // NULL XOR NULL is NULL
1311 T(KDbToken::SQL_NULL, QVariant(), KDbToken::XOR, KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1312 // NULL AND "xyz" is invalid
1313 T(KDbToken::SQL_NULL, QVariant(), KDbToken::OR, KDbToken::CHARACTER_STRING_LITERAL, "xyz", KDbField::InvalidType);
1314 // integer
1315 // -- KDb::ArithmeticExpression only: resulting type is Integer or more
1316 // see explanation for KDb::maximumForIntegerFieldTypes()
1317 T(KDbToken::INTEGER_CONST, 50, '+', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1318 T(KDbToken::INTEGER_CONST, 50, '-', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1319 T(KDbToken::INTEGER_CONST, 50, '*', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1320 T(KDbToken::INTEGER_CONST, 50, '/', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1321 T(KDbToken::INTEGER_CONST, 50, '&', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1322 T(KDbToken::INTEGER_CONST, 50, '|', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1323 T(KDbToken::INTEGER_CONST, 50, '%', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1324 T(KDbToken::INTEGER_CONST, 50, KDbToken::BITWISE_SHIFT_RIGHT, KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1325 T(KDbToken::INTEGER_CONST, 50, KDbToken::BITWISE_SHIFT_LEFT, KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1326 T(KDbToken::INTEGER_CONST, 300, '+', KDbToken::INTEGER_CONST, 20, KDbField::Integer);
1327 T(KDbToken::INTEGER_CONST, 300, '+', KDbToken::INTEGER_CONST, 300, KDbField::Integer);
1328 T(KDbToken::INTEGER_CONST, 300, '+', KDbToken::INTEGER_CONST, 300, KDbField::Integer);
1329 T(KDbToken::INTEGER_CONST, 50, '+', KDbToken::INTEGER_CONST, qulonglong(INT_MAX), KDbField::BigInteger);
1330 T(KDbToken::INTEGER_CONST, INT_MAX, '+', KDbToken::INTEGER_CONST, qulonglong(INT_MAX), KDbField::BigInteger);
1331
1332 T(KDbToken::INTEGER_CONST, 50, '<', KDbToken::INTEGER_CONST, 20, KDbField::Boolean);
1333 T(KDbToken::INTEGER_CONST, 50, '=', KDbToken::INTEGER_CONST, 20, KDbField::Boolean);
1334 T(KDbToken::INTEGER_CONST, 50, '>', KDbToken::INTEGER_CONST, 20, KDbField::Boolean);
1335 T(KDbToken::INTEGER_CONST, 50, '<', KDbToken::INTEGER_CONST, INT_MAX, KDbField::Boolean);
1336 T(KDbToken::INTEGER_CONST, 50, '<', KDbToken::INTEGER_CONST, qulonglong(INT_MAX), KDbField::Boolean);
1337 T(KDbToken::INTEGER_CONST, qulonglong(INT_MAX), '<', KDbToken::INTEGER_CONST, INT_MAX, KDbField::Boolean);
1338 T(KDbToken::INTEGER_CONST, 300, KDbToken::LESS_OR_EQUAL, KDbToken::INTEGER_CONST, 20, KDbField::Boolean);
1339 T(KDbToken::INTEGER_CONST, 300, KDbToken::GREATER_OR_EQUAL, KDbToken::INTEGER_CONST, 300, KDbField::Boolean);
1340 T(KDbToken::INTEGER_CONST, 300, '>', KDbToken::INTEGER_CONST, 300, KDbField::Boolean);
1341
1342 T(KDbToken::INTEGER_CONST, 300, KDbToken::OR, KDbToken::INTEGER_CONST, 20, KDbField::InvalidType);
1343 T(KDbToken::INTEGER_CONST, 300, KDbToken::AND, KDbToken::INTEGER_CONST, 20, KDbField::InvalidType);
1344 T(KDbToken::INTEGER_CONST, 300, KDbToken::XOR, KDbToken::INTEGER_CONST, 20, KDbField::InvalidType);
1345 T(KDbToken::INTEGER_CONST, 300, KDbToken::OR, KDbToken::SQL_NULL, QVariant(), KDbField::InvalidType);
1346 // real
1347 T(KDbToken::REAL_CONST, 0.5, '+', KDbToken::REAL_CONST, -9.4, KDbField::Double);
1348 T(KDbToken::REAL_CONST, 0.5, '-', KDbToken::REAL_CONST, -9.4, KDbField::Double);
1349 T(KDbToken::REAL_CONST, 0.5, '*', KDbToken::REAL_CONST, -9.4, KDbField::Double);
1350 T(KDbToken::REAL_CONST, 0.5, '/', KDbToken::REAL_CONST, -9.4, KDbField::Double);
1351 T(KDbToken::REAL_CONST, 0.5, '&', KDbToken::REAL_CONST, -9.4, KDbField::Integer);
1352 T(KDbToken::REAL_CONST, 0.5, '&', KDbToken::INTEGER_CONST, 9, KDbField::Byte);
1353 T(KDbToken::REAL_CONST, 0.5, '&', KDbToken::INTEGER_CONST, 1000, KDbField::ShortInteger);
1354 T(KDbToken::REAL_CONST, 0.5, '&', KDbToken::INTEGER_CONST, qulonglong(INT_MAX), KDbField::BigInteger);
1355 T(KDbToken::REAL_CONST, 0.5, '%', KDbToken::REAL_CONST, -9.4, KDbField::Double);
1356 T(KDbToken::REAL_CONST, 0.5, KDbToken::BITWISE_SHIFT_RIGHT, KDbToken::REAL_CONST, 9.4, KDbField::Integer);
1357 T(KDbToken::REAL_CONST, 0.5, KDbToken::BITWISE_SHIFT_LEFT, KDbToken::REAL_CONST, 9.4, KDbField::Integer);
1358 T(KDbToken::REAL_CONST, 0.5, '+', KDbToken::INTEGER_CONST, 300, KDbField::Double);
1359 T(KDbToken::REAL_CONST, 0.5, '-', KDbToken::INTEGER_CONST, 300, KDbField::Double);
1360 T(KDbToken::REAL_CONST, 0.5, '/', KDbToken::INTEGER_CONST, 300, KDbField::Double);
1361 T(KDbToken::REAL_CONST, 0.5, '-', KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1362
1363 T(KDbToken::REAL_CONST, 0.5, '>', KDbToken::REAL_CONST, -9.4, KDbField::Boolean);
1364 T(KDbToken::REAL_CONST, 0.5, '>', KDbToken::INTEGER_CONST, 300, KDbField::Boolean);
1365 T(KDbToken::REAL_CONST, 0.5, '=', KDbToken::INTEGER_CONST, 300, KDbField::Boolean);
1366 T(KDbToken::REAL_CONST, 0.5, '<', KDbToken::INTEGER_CONST, qulonglong(INT_MAX), KDbField::Boolean);
1367 T(KDbToken::REAL_CONST, 0.5, KDbToken::LESS_OR_EQUAL, KDbToken::INTEGER_CONST, 300, KDbField::Boolean);
1368 T(KDbToken::REAL_CONST, 0.5, KDbToken::GREATER_OR_EQUAL, KDbToken::INTEGER_CONST, 300, KDbField::Boolean);
1369 T(KDbToken::REAL_CONST, 0.5, '>', KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1370
1371 T(KDbToken::REAL_CONST, 30.2, KDbToken::OR, KDbToken::REAL_CONST, 20, KDbField::InvalidType);
1372 T(KDbToken::REAL_CONST, 30.2, KDbToken::AND, KDbToken::REAL_CONST, 20, KDbField::InvalidType);
1373 T(KDbToken::REAL_CONST, 30.2, KDbToken::XOR, KDbToken::REAL_CONST, 20, KDbField::InvalidType);
1374 // string
1375 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", KDbToken::CONCATENATION, KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Text);
1376 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Text);
1377
1378 T(KDbToken::SQL_NULL, QVariant(), KDbToken::CONCATENATION, KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Null);
1379 T(KDbToken::SQL_NULL, QVariant(), '+', KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Null);
1380
1381 T(KDbToken::INTEGER_CONST, 50, KDbToken::CONCATENATION, KDbToken::INTEGER_CONST, 20, KDbField::InvalidType);
1382 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", KDbToken::CONCATENATION, KDbToken::INTEGER_CONST, 20, KDbField::InvalidType);
1383 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', KDbToken::INTEGER_CONST, 20, KDbField::InvalidType);
1384
1385 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", KDbToken::GREATER_OR_EQUAL, KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Boolean);
1386 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '<', KDbToken::INTEGER_CONST, 3, KDbField::InvalidType);
1387 T(KDbToken::CHARACTER_STRING_LITERAL, "ab", '+', KDbToken::CHARACTER_STRING_LITERAL, "cd", KDbField::Text);
1388 T(KDbToken::CHARACTER_STRING_LITERAL, "A", KDbToken::OR, KDbToken::REAL_CONST, 20, KDbField::InvalidType);
1389 T(KDbToken::CHARACTER_STRING_LITERAL, "A", KDbToken::AND, KDbToken::REAL_CONST, 20, KDbField::InvalidType);
1390 T(KDbToken::CHARACTER_STRING_LITERAL, "A", KDbToken::XOR, KDbToken::REAL_CONST, 20, KDbField::InvalidType);
1391 // bool
1392 T(KDbToken::SQL_TRUE, true, '<', KDbToken::SQL_FALSE, false, KDbField::Boolean);
1393 T(KDbToken::SQL_TRUE, true, '=', KDbToken::SQL_FALSE, false, KDbField::Boolean);
1394 T(KDbToken::SQL_TRUE, true, '+', KDbToken::SQL_FALSE, false, KDbField::InvalidType);
1395 T(KDbToken::SQL_TRUE, true, '<', KDbToken::INTEGER_CONST, 20, KDbField::Boolean);
1396 T(KDbToken::SQL_TRUE, true, '<', KDbToken::REAL_CONST, -10.1, KDbField::Boolean);
1397 T(KDbToken::SQL_TRUE, true, '-', KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1398 T(KDbToken::SQL_TRUE, true, '<', KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1399 T(KDbToken::SQL_TRUE, true, KDbToken::OR, KDbToken::SQL_FALSE, false, KDbField::Boolean);
1400 T(KDbToken::SQL_TRUE, true, KDbToken::AND, KDbToken::SQL_FALSE, false, KDbField::Boolean);
1401 T(KDbToken::SQL_TRUE, true, KDbToken::XOR, KDbToken::SQL_FALSE, false, KDbField::Boolean);
1402 // date/time
1403 T(KDbToken::DATE_CONST, QDate(2001, 1, 2), '=', KDbToken::DATE_CONST, QDate(2002, 1, 2), KDbField::Boolean);
1404 T(KDbToken::DATETIME_CONST, QDateTime(QDate(2001, 1, 2), QTime(1, 2, 3)), KDbToken::LESS_OR_EQUAL, KDbToken::DATE_CONST, QDateTime::currentDateTime(), KDbField::Boolean);
1405 T(KDbToken::TIME_CONST, QTime(1, 2, 3), '<', KDbToken::TIME_CONST, QTime::currentTime(), KDbField::Boolean);
1406 T(KDbToken::DATE_CONST, QDate(2001, 1, 2), '=', KDbToken::INTEGER_CONST, 17, KDbField::InvalidType);
1407 T(KDbToken::DATE_CONST, QDate(2001, 1, 2), '=', KDbToken::SQL_NULL, QVariant(), KDbField::Null);
1408 T(KDbToken::DATE_CONST, QDate(2001, 1, 2), KDbToken::OR, KDbToken::SQL_FALSE, false, KDbField::InvalidType);
1409 T(KDbToken::DATE_CONST, QDate(2001, 1, 2), KDbToken::AND, KDbToken::SQL_FALSE, false, KDbField::InvalidType);
1410 T(KDbToken::DATE_CONST, QDate(2001, 1, 2), KDbToken::XOR, KDbToken::SQL_FALSE, false, KDbField::InvalidType);
1411 #undef T
1412 #undef T1
1413 #undef TNAME
1414 }
1415
testBinaryExpressionValidate()1416 void ExpressionsTest::testBinaryExpressionValidate()
1417 {
1418 QFETCH(KDbToken, type1);
1419 QFETCH(QVariant, const1);
1420 QFETCH(KDbToken, token);
1421 QFETCH(KDbToken, type2);
1422 QFETCH(QVariant, const2);
1423 QFETCH(KDbField::Type, type3);
1424
1425 KDbConstExpression c(type1, const1);
1426 KDbConstExpression c1(type2, const2);
1427 KDbBinaryExpression b(c, token, c1);
1428 //qDebug() << b.type();
1429 //qDebug() << type3;
1430 QCOMPARE(b.type(), type3);
1431 QVERIFY(validate(&b) == (type3 != KDbField::InvalidType));
1432 testCloneExpression(b);
1433 }
1434
testFunctionExpressionValidate()1435 void ExpressionsTest::testFunctionExpressionValidate()
1436 {
1437 KDbFunctionExpression emptyFunction;
1438 QVERIFY(!validate(&emptyFunction));
1439
1440 KDbNArgExpression args;
1441 args.append(KDbConstExpression(KDbToken::CHARACTER_STRING_LITERAL, "abc"));
1442 args.append(KDbConstExpression(KDbToken::INTEGER_CONST, 2));
1443 KDbFunctionExpression f_substr("SUBSTR", args);
1444 QVERIFY(validate(&f_substr));
1445
1446 args.append(KDbConstExpression(KDbToken::INTEGER_CONST, 1));
1447 KDbFunctionExpression f_substr2("SUBSTR", args);
1448 QVERIFY(validate(&f_substr2));
1449
1450 // clone the args
1451 KDbNArgExpression args2 = args.clone().toNArg();
1452 f_substr2.setArguments(args2);
1453 QVERIFY(validate(&f_substr2));
1454
1455 // wrong type (1st arg)
1456 args = KDbNArgExpression();
1457 args.append(KDbConstExpression(KDbToken::DATETIME_CONST, QDateTime::currentDateTime()));
1458 args.append(KDbConstExpression(KDbToken::INTEGER_CONST, 1));
1459 f_substr2.setArguments(args);
1460 QVERIFY(!validate(&f_substr2));
1461
1462 // fixed type
1463 KDbConstExpression first = args.arg(0).toConst();
1464 first.setToken(KDbToken::CHARACTER_STRING_LITERAL);
1465 first.setValue("xyz");
1466 QVERIFY(validate(&f_substr2));
1467
1468 // wrong type (2nd arg)
1469 KDbConstExpression second = args.arg(1).toConst();
1470 second.setToken(KDbToken::REAL_CONST);
1471 second.setValue(3.14);
1472 QVERIFY(!validate(&f_substr2));
1473
1474 // nested functions
1475 KDbFunctionExpression f_substr3 = f_substr.clone().toFunction();
1476 f_substr3.arguments().replace(0, f_substr.clone());
1477 QVERIFY(validate(&f_substr3));
1478
1479 // fixed type
1480 args.replace(1, KDbConstExpression(KDbToken::INTEGER_CONST, 1));
1481 QVERIFY(validate(&f_substr2));
1482
1483 // wrong type (3rd arg)
1484 args.append(KDbConstExpression(KDbToken::REAL_CONST, 1.111));
1485 //qDebug() << args;
1486 //qDebug() << f_substr2;
1487 QVERIFY(!validate(&f_substr2));
1488
1489 // wrong number of args
1490 f_substr2.setArguments(KDbNArgExpression());
1491 args.append(KDbConstExpression(KDbToken::INTEGER_CONST, 77));
1492 QVERIFY(!validate(&f_substr2));
1493
1494 KDbFunctionExpression f_noname("", args);
1495 QVERIFY(!validate(&f_noname));
1496 }
1497
cleanupTestCase()1498 void ExpressionsTest::cleanupTestCase()
1499 {
1500 }
1501