File indexing completed on 2024-04-21 15:29:47
0001 /* This file is part of the KDE project 0002 Copyright (C) 2015-2016 Jarosław Staniek <staniek@kde.org> 0003 0004 This program is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this program; see the file COPYING. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KDbTest.h" 0021 0022 #include <KDb> 0023 #include <KDbConnectionData> 0024 #include <KDbVersionInfo> 0025 0026 #include <QRegularExpression> 0027 #include <QTest> 0028 0029 QTEST_GUILESS_MAIN(KDbTest) 0030 0031 void KDbTest::initTestCase() 0032 { 0033 } 0034 0035 void KDbTest::testVersionInfo() 0036 { 0037 KDbVersionInfo info = KDb::version(); 0038 KDbVersionInfo info2(KDb::version()); 0039 QCOMPARE(info, info2); 0040 KDbVersionInfo info3(info.major(), info.minor(), info.release()); 0041 QCOMPARE(info, info3); 0042 QVERIFY(KDbVersionInfo(0, 0, 0).isNull()); 0043 QVERIFY(!info.isNull()); 0044 QVERIFY(!info2.isNull()); 0045 QVERIFY(!info3.isNull()); 0046 } 0047 0048 //! @todo add tests requiring connection 0049 #if 0 0050 //! @overload bool deleteRecord(KDbConnection*, const KDbTableSchema&, const QString &, KDbField::Type, const QVariant &) 0051 KDB_EXPORT bool deleteRecords(KDbConnection* conn, const QString &tableName, 0052 const QString &keyname, KDbField::Type keytype, const QVariant &keyval); 0053 //! Deletes records using one generic criteria. 0054 inline bool deleteRecords(KDbConnection* conn, const KDbTableSchema &table, 0055 const QString &keyname, KDbField::Type keytype, const QVariant &keyval) 0056 //! @overload bool deleteRecords(KDbConnection*, const QString&, const QString&, KDbField::Type, const QVariant&); 0057 inline bool deleteRecords(KDbConnection* conn, const QString &tableName, 0058 const QString &keyname, const QString &keyval) 0059 //! @overload bool deleteRecords(KDbConnection*, const QString&, const QString&, const QString&); 0060 inline bool deleteRecords(KDbConnection* conn, const KDbTableSchema &table, 0061 const QString &keyname, const QString &keyval) 0062 //! @overload bool deleteRecords(KDbConnection*, const KDbTableSchema&, const QString&, const QString&); 0063 inline bool deleteRecords(KDbConnection* conn, const KDbTableSchema &table, 0064 const QString& keyname, int keyval) 0065 //! @overload bool deleteRecords(KDbConnection*, const KDbTableSchema&, const QString&, int); 0066 inline bool deleteRecords(KDbConnection* conn, const QString &tableName, 0067 const QString& keyname, int keyval) 0068 //! Deletes records with two generic criterias. 0069 KDB_EXPORT bool deleteRecords(KDbConnection* conn, const QString &tableName, 0070 const QString &keyname1, KDbField::Type keytype1, const QVariant& keyval1, 0071 const QString &keyname2, KDbField::Type keytype2, const QVariant& keyval2); 0072 //! Deletes records with three generic criterias. 0073 KDB_EXPORT bool deleteRecords(KDbConnection* conn, const QString &tableName, 0074 const QString &keyname1, KDbField::Type keytype1, const QVariant& keyval1, 0075 const QString &keyname2, KDbField::Type keytype2, const QVariant& keyval2, 0076 const QString &keyname3, KDbField::Type keytype3, const QVariant& keyval3); 0077 //! Deletes all records from table @a tableName. 0078 KDB_EXPORT bool deleteAllRecords(KDbConnection* conn, const QString &tableName); 0079 //! @overload bool deleteAllRecords(KDbConnection*, const QString&); 0080 inline bool deleteAllRecords(KDbConnection* conn, const KDbTableSchema &table) 0081 #endif 0082 0083 void KDbTest::testFieldTypes() 0084 { 0085 QCOMPARE(KDbField::FirstType, KDbField::Byte); 0086 QCOMPARE(KDbField::LastType, KDbField::BLOB); 0087 QVERIFY(KDbField::FirstType < KDbField::LastType); 0088 } 0089 0090 void KDbTest::testFieldTypesForGroup_data() 0091 { 0092 QTest::addColumn<KDbField::TypeGroup>("typeGroup"); 0093 QTest::addColumn<QList<KDbField::Type>>("types"); 0094 0095 int c = 0; 0096 ++c; QTest::newRow("invalid") << KDbField::InvalidGroup 0097 << (QList<KDbField::Type>() << KDbField::InvalidType); 0098 ++c; QTest::newRow("text") << KDbField::TextGroup << (QList<KDbField::Type>() 0099 << KDbField::Text << KDbField::LongText); 0100 ++c; QTest::newRow("integer") << KDbField::IntegerGroup 0101 << (QList<KDbField::Type>() 0102 << KDbField::Byte << KDbField::ShortInteger << KDbField::Integer << KDbField::BigInteger); 0103 ++c; QTest::newRow("float") << KDbField::FloatGroup 0104 << (QList<KDbField::Type>() << KDbField::Float << KDbField::Double); 0105 ++c; QTest::newRow("boolean") << KDbField::BooleanGroup 0106 << (QList<KDbField::Type>() << KDbField::Boolean); 0107 ++c; QTest::newRow("datetime") << KDbField::DateTimeGroup 0108 << (QList<KDbField::Type>() << KDbField::Date << KDbField::DateTime << KDbField::Time); 0109 ++c; QTest::newRow("blob") << KDbField::BLOBGroup 0110 << (QList<KDbField::Type>() << KDbField::BLOB); 0111 QCOMPARE(c, KDbField::typeGroupsCount()); // make sure we're checking everything 0112 } 0113 0114 void KDbTest::testFieldTypesForGroup() 0115 { 0116 QFETCH(KDbField::TypeGroup, typeGroup); 0117 QFETCH(QList<KDbField::Type>, types); 0118 QCOMPARE(KDb::fieldTypesForGroup(typeGroup), types); 0119 } 0120 0121 void KDbTest::testFieldTypeNamesAndStringsForGroup_data() 0122 { 0123 QTest::addColumn<KDbField::TypeGroup>("typeGroup"); 0124 QTest::addColumn<QList<QByteArray>>("typeNames"); 0125 QTest::addColumn<QStringList>("typeStrings"); 0126 0127 int c = 0; 0128 ++c; QTest::newRow("invalid") << KDbField::InvalidGroup 0129 << (QList<QByteArray>() << "Invalid Type") 0130 << (QStringList() << "InvalidType"); 0131 ++c; QTest::newRow("text") << KDbField::TextGroup << (QList<QByteArray>() 0132 << "Text" << "Long Text") 0133 << (QStringList() << "Text" << "LongText"); 0134 ++c; QTest::newRow("integer") << KDbField::IntegerGroup 0135 << (QList<QByteArray>() 0136 << "Byte" << "Short Integer Number" << "Integer Number" << "Big Integer Number") 0137 << (QStringList() << "Byte" << "ShortInteger" << "Integer" << "BigInteger"); 0138 ++c; QTest::newRow("float") << KDbField::FloatGroup 0139 << (QList<QByteArray>() << "Single Precision Number" << "Double Precision Number") 0140 << (QStringList() << "Float" << "Double"); 0141 ++c; QTest::newRow("boolean") << KDbField::BooleanGroup 0142 << (QList<QByteArray>() << "Yes/No Value") 0143 << (QStringList() << "Boolean"); 0144 ++c; QTest::newRow("datetime") << KDbField::DateTimeGroup 0145 << (QList<QByteArray>() << "Date" << "Date and Time" << "Time") 0146 << (QStringList() << "Date" << "DateTime" << "Time"); 0147 ++c; QTest::newRow("blob") << KDbField::BLOBGroup 0148 << (QList<QByteArray>() << "Object") 0149 << (QStringList() << "BLOB"); 0150 QCOMPARE(c, KDbField::typeGroupsCount()); // make sure we're checking everything 0151 } 0152 0153 void KDbTest::testFieldTypeNamesAndStringsForGroup() 0154 { 0155 QFETCH(KDbField::TypeGroup, typeGroup); 0156 QFETCH(QList<QByteArray>, typeNames); 0157 QFETCH(QStringList, typeStrings); 0158 QStringList translatedNames; 0159 foreach(const QByteArray &name, typeNames) { 0160 translatedNames.append(KDbField::tr(name.constData())); 0161 } 0162 QCOMPARE(KDb::fieldTypeNamesForGroup(typeGroup), translatedNames); 0163 QCOMPARE(KDb::fieldTypeStringsForGroup(typeGroup), typeStrings); 0164 } 0165 0166 void KDbTest::testDefaultFieldTypeForGroup() 0167 { 0168 int c = 0; 0169 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::InvalidGroup), KDbField::InvalidType); 0170 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::TextGroup), KDbField::Text); 0171 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::IntegerGroup), KDbField::Integer); 0172 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::FloatGroup), KDbField::Double); 0173 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::BooleanGroup), KDbField::Boolean); 0174 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::DateTimeGroup), KDbField::Date); 0175 ++c; QCOMPARE(KDb::defaultFieldTypeForGroup(KDbField::BLOBGroup), KDbField::BLOB); 0176 QCOMPARE(c, KDbField::typeGroupsCount()); // make sure we're checking everything 0177 } 0178 0179 void KDbTest::testSimplifiedFieldTypeName() 0180 { 0181 int c = 0; 0182 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::InvalidType), KDbField::tr("Invalid Group")); 0183 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Byte), KDbField::tr("Number")); 0184 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::ShortInteger), KDbField::tr("Number")); 0185 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Integer), KDbField::tr("Number")); 0186 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::BigInteger), KDbField::tr("Number")); 0187 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Boolean), KDbField::tr("Yes/No")); 0188 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Date), KDbField::tr("Date/Time")); 0189 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::DateTime), KDbField::tr("Date/Time")); 0190 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Time), KDbField::tr("Date/Time")); 0191 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Float), KDbField::tr("Number")); 0192 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Double), KDbField::tr("Number")); 0193 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Text), KDbField::tr("Text")); 0194 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::LongText), KDbField::tr("Text")); 0195 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::BLOB), KDbField::tr("Image")); 0196 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Null), KDbField::tr("Invalid Group")); 0197 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Asterisk), KDbField::tr("Invalid Group")); 0198 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Enum), KDbField::tr("Invalid Group")); 0199 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Map), KDbField::tr("Invalid Group")); 0200 ++c; QCOMPARE(KDb::simplifiedFieldTypeName(KDbField::Tuple), KDbField::tr("Invalid Group")); 0201 QCOMPARE(c, KDbField::typesCount() + KDbField::specialTypesCount()); // make sure we're checking everything 0202 } 0203 0204 void KDbTest::testIsEmptyValue_data() 0205 { 0206 QTest::addColumn<KDbField::Type>("type"); 0207 QTest::addColumn<QVariant>("value"); 0208 QTest::addColumn<bool>("result"); 0209 QTest::addColumn<bool>("resultForNullValue"); 0210 QTest::addColumn<bool>("resultForEmptyString"); 0211 0212 int c = 0; 0213 ++c; QTest::newRow("Invalid") << KDbField::InvalidType << QVariant("abc") << false << true << false; 0214 ++c; QTest::newRow("Byte") << KDbField::Byte << QVariant(17) << false << true << false; 0215 ++c; QTest::newRow("ShortInteger") << KDbField::ShortInteger << QVariant(1733) << false << true << false; 0216 ++c; QTest::newRow("Integer") << KDbField::Integer << QVariant(11733) << false << true << false; 0217 ++c; QTest::newRow("BigInteger") << KDbField::BigInteger << QVariant(0xffffff12) << false << true << false; 0218 ++c; QTest::newRow("Boolean") << KDbField::Boolean << QVariant(false) << false << true << false; 0219 ++c; QTest::newRow("Date") << KDbField::Date << QVariant(QDate(2015, 11, 07)) << false << true << false; 0220 ++c; QTest::newRow("DateTime") << KDbField::DateTime << QVariant(QDateTime(QDate(2015, 11, 07), QTime(12, 58, 17))) << false << true << false; 0221 ++c; QTest::newRow("Time") << KDbField::Time << QVariant(QTime(12, 58, 17)) << false << true << false; 0222 ++c; QTest::newRow("Float") << KDbField::Float << QVariant(3.14) << false << true << false; 0223 ++c; QTest::newRow("Double") << KDbField::Double << QVariant(3.1415) << false << true << false; 0224 ++c; QTest::newRow("Text") << KDbField::Text << QVariant(QLatin1String("abc")) << false << false << true; 0225 ++c; QTest::newRow("LongText") << KDbField::LongText << QVariant(QLatin1String("abc")) << false << false << true; 0226 ++c; QTest::newRow("BLOB") << KDbField::LongText << QVariant(QByteArray(5, 'X')) << false << false << true; 0227 ++c; QTest::newRow("Null") << KDbField::Null << QVariant(123) << false << true << false; 0228 ++c; QTest::newRow("Asterisk") << KDbField::Asterisk << QVariant(123) << false << true << false; 0229 ++c; QTest::newRow("Enum") << KDbField::Enum << QVariant(123) << false << true << false; 0230 ++c; QTest::newRow("Map") << KDbField::Map << QVariant(123) << false << true << false; 0231 ++c; QTest::newRow("Tuple") << KDbField::Tuple << QVariant(123) << false << true << false; 0232 QCOMPARE(c, KDbField::typesCount() + KDbField::specialTypesCount()); 0233 } 0234 0235 void KDbTest::testIsEmptyValue() 0236 { 0237 QFETCH(KDbField::Type, type); 0238 QFETCH(QVariant, value); 0239 QFETCH(bool, result); 0240 QFETCH(bool, resultForNullValue); 0241 QFETCH(bool, resultForEmptyString); 0242 0243 QCOMPARE(KDb::isEmptyValue(type, QVariant()), resultForNullValue); 0244 QCOMPARE(KDb::isEmptyValue(type, QVariant(QString(""))), resultForEmptyString); 0245 QCOMPARE(KDb::isEmptyValue(type, value), result); 0246 } 0247 0248 //! @todo add tests 0249 #if 0 0250 /*! Sets string pointed by @a msg to an error message retrieved from @a resultable, 0251 and string pointed by @a details to details of this error (server message and result number). 0252 Does nothing if @a result is empty. In this case @a msg and @a details strings are not overwritten. 0253 If the string pointed by @a msg is not empty, @a result message is appended to the string 0254 pointed by @a details. 0255 */ 0256 KDB_EXPORT void getHTMLErrorMesage(const KDbResultable& resultable, QString *msg, QString *details); 0257 0258 /*! This methods works like above, but appends both a message and a description 0259 to string pointed by @a msg. */ 0260 KDB_EXPORT void getHTMLErrorMesage(const KDbResultable& resultable, QString *msg); 0261 0262 /*! This methods works like above, but works on @a result's members instead. */ 0263 KDB_EXPORT void getHTMLErrorMesage(const KDbResultable& resultable, KDbResultInfo *info); 0264 0265 /*! Function useful for building WHERE parts of SQL statements. 0266 Constructs an SQL string like "fielname = value" for specific @a drv driver, 0267 field type @a t, @a fieldName and @a value. If @a value is null, "fieldname is NULL" 0268 string is returned. */ 0269 KDB_EXPORT KDbEscapedString sqlWhere(KDbDriver *drv, KDbField::Type t, 0270 const QString& fieldName, const QVariant& value); 0271 0272 /*! Find an identifier for object @a objName of type @a objType. 0273 On success true is returned and *id is set to the value of the identifier. 0274 On failure false is returned. If there is no such object, @c cancelled value is returned. */ 0275 KDB_EXPORT tristate idForObjectName(KDbConnection* conn, int *id, const QString& objName, 0276 int objType); 0277 0278 /*! @return a number of columns that can be retrieved from table or query schema. 0279 In case of query, expanded fields are counted. Can return -1 if @a tableOrQuery 0280 has neither table or query assigned. */ 0281 KDB_EXPORT int fieldCount(KDbTableOrQuerySchema* tableOrQuery); 0282 0283 /*! shows connection test dialog with a progress bar indicating connection testing 0284 (within a second thread). 0285 @a data is used to perform a (temporary) test connection. @a msgHandler is used to display errors. 0286 On successful connecting, a message is displayed. After testing, temporary connection is closed. */ 0287 KDB_EXPORT void connectionTestDialog(QWidget* parent, const KDbConnectionData& data, 0288 KDbMessageHandler* msgHandler); 0289 0290 //! Used in splitToTableAndFieldParts(). 0291 enum SplitToTableAndFieldPartsOptions { 0292 FailIfNoTableOrFieldName = 0, //!< default value for splitToTableAndFieldParts() 0293 SetFieldNameIfNoTableName = 1 //!< see splitToTableAndFieldParts() 0294 }; 0295 0296 /*! Splits @a string like "table.field" into "table" and "field" parts. 0297 On success, a table name is passed to @a tableName and a field name is passed to @a fieldName. 0298 The function fails if either: 0299 - @a string is empty, or 0300 - @a string does not contain '.' character and @a option is FailIfNoTableOrFieldName 0301 (the default), or 0302 - '.' character is the first of last character of @a string (in this case table name 0303 or field name could become empty what is not allowed). 0304 0305 If @a option is SetFieldNameIfNoTableName and @a string does not contain '.', 0306 @a string is passed to @a fieldName and @a tableName is set to QString() 0307 without failure. 0308 0309 If function fails, @a tableName and @a fieldName remain unchanged. 0310 @return true on success. */ 0311 KDB_EXPORT bool splitToTableAndFieldParts(const QString& string, 0312 QString *tableName, QString *fieldName, 0313 SplitToTableAndFieldPartsOptions option = FailIfNoTableOrFieldName); 0314 0315 /*! @return true if @a type supports "visibleDecimalPlaces" property. */ 0316 KDB_EXPORT bool supportsVisibleDecimalPlacesProperty(KDbField::Type type); 0317 0318 //*! @return string constructed by converting @a value. 0319 * If @a decimalPlaces is < 0, all meaningful fractional digits are returned (up to 10). 0320 * If @a automatically is 0, just integer part is returned. 0321 * If @a automatically is > 0, fractional part should take exactly 0322 N digits: if the fractional part is shorter than N, additional zeros are appended. 0323 Examples: 0324 * numberToString(12.345, 6) == "12.345000" 0325 * numberToString(12.345, 0) == "12" 0326 * numberToString(12.345, -1) == "12.345" 0327 * numberToString(12.0, -1) == "12" 0328 * numberToString(0.0, -1) == "0" 0329 0330 @note No rounding is performed 0331 @note No thousands group separator is used. Decimal symbol is '.'. 0332 0333 @see KDb::numberToLocaleString() KDbField::visibleDecimalPlaces() */ 0334 KDB_EXPORT QString numberToString(double value, int decimalPlaces); 0335 0336 /*! Like KDb::numberToString() but formats the string using locale.toString(). 0337 If @a locale if @c nullptr, desault QLocale is used. 0338 0339 @see KDb::numberToString() KDbField::visibleDecimalPlaces() */ 0340 KDB_EXPORT QString numberToLocaleString(double value, int decimalPlaces, const QLocale *locale = nullptr); 0341 0342 //! @return true if @a propertyName is a builtin field property. 0343 KDB_EXPORT bool isBuiltinTableFieldProperty(const QByteArray& propertyName); 0344 0345 //! @return true if @a propertyName is an extended field property. 0346 KDB_EXPORT bool isExtendedTableFieldProperty(const QByteArray& propertyName); 0347 0348 //! @return true if @a propertyName is belongs to lookup field's schema. 0349 KDB_EXPORT bool isLookupFieldSchemaProperty(const QByteArray& propertyName); 0350 0351 /*! @return type of field for integer value @a type. 0352 If @a type cannot be casted to KDbField::Type, KDbField::InvalidType is returned. 0353 This can be used when type information is deserialized from a string or QVariant. */ 0354 KDB_EXPORT KDbField::Type intToFieldType(int type); 0355 0356 /*! @return type group of field for integer value @a typeGroup. 0357 If @a typeGroup cannot be casted to KDbField::TypeGroup, KDbField::InvalidGroup is returned. 0358 This can be used when type information is deserialized from a string or QVariant. */ 0359 KDB_EXPORT KDbField::TypeGroup intToFieldTypeGroup(int typeGroup); 0360 0361 /*! Gets property values for the lookup schema @a lookup. 0362 @a values is cleared before filling. This function is used e.g. for altering table design. */ 0363 KDB_EXPORT void getProperties(const KDbLookupFieldSchema *lookup, QMap<QByteArray, QVariant> *values); 0364 0365 /*! Gets property values for @a field. 0366 Properties from extended schema are included. @a values is cleared before filling. 0367 The same number of properties in the same order is returned. 0368 This function is used e.g. for altering table design. 0369 */ 0370 KDB_EXPORT void getFieldProperties(const KDbField &field, QMap<QByteArray, QVariant> *values); 0371 0372 /*! Sets property values for @a field. @return true if all the values are valid and allowed. 0373 On failure contents of @a field is undefined. 0374 Properties from extended schema are also supported. 0375 This function is used e.g. by KDbAlterTableHandler when property information comes in form of text. 0376 */ 0377 KDB_EXPORT bool setFieldProperties(KDbField *field, const QMap<QByteArray, QVariant>& values); 0378 0379 /*! Sets property value for @a field. @return true if the property has been found and 0380 the value is valid for this property. On failure contents of @a field is undefined. 0381 Properties from extended schema are also supported as well as 0382 QVariant customProperty(const QString& propertyName) const; 0383 0384 This function is used e.g. by KDbAlterTableHandler when property information comes in form of text. 0385 */ 0386 KDB_EXPORT bool setFieldProperty(KDbField *field, const QByteArray& propertyName, 0387 const QVariant& value); 0388 0389 /*! @return property value loaded from a DOM @a node, written in a QtDesigner-like 0390 notation: <number>int</number> or <bool>bool</bool>, etc. Supported types are 0391 "string", "cstring", "bool", "number". For invalid values null QVariant is returned. 0392 You can check the validity of the returned value using QVariant::type(). */ 0393 KDB_EXPORT QVariant loadPropertyValueFromDom(const QDomNode& node, bool *ok); 0394 0395 /*! Convenience version of loadPropertyValueFromDom(). @return int value. */ 0396 KDB_EXPORT int loadIntPropertyValueFromDom(const QDomNode& node, bool* ok); 0397 0398 /*! Convenience version of loadPropertyValueFromDom(). @return QString value. */ 0399 KDB_EXPORT QString loadStringPropertyValueFromDom(const QDomNode& node, bool* ok); 0400 0401 /*! Saves integer element for value @a value to @a doc document within parent element 0402 @a parentEl. The value will be enclosed in "number" element and "elementName" element. 0403 Example: saveNumberElementToDom(doc, parentEl, "height", 15) will create 0404 @code 0405 <height><number>15</number></height> 0406 @endcode 0407 @return the reference to element created with tag elementName. */ 0408 KDB_EXPORT QDomElement saveNumberElementToDom(QDomDocument *doc, QDomElement *parentEl, 0409 const QString& elementName, int value); 0410 0411 /*! Saves boolean element for value @a value to @a doc document within parent element 0412 @a parentEl. Like saveNumberElementToDom() but creates "bool" tags. True/false values will be 0413 saved as "true"/"false" strings. 0414 @return the reference to element created with tag elementName. */ 0415 KDB_EXPORT QDomElement saveBooleanElementToDom(QDomDocument *doc, QDomElement *parentEl, 0416 const QString& elementName, bool value); 0417 0418 //! @return equivalent of empty (default) value that can be set for a database field of type @a type 0419 /*! In particular returns: 0420 - empty string for text types, 0421 - 0 for integer and floating-point types, 0422 - false for boolean types, 0423 - a null byte array for BLOB type, 0424 - current date, time, date+time is returned (measured at client side) for date, time and 0425 date/time types respectively, 0426 - a null QVariant for unsupported values such as KDbField::InvalidType. */ 0427 KDB_EXPORT QVariant emptyValueForFieldType(KDbField::Type type); 0428 0429 //! @return a value that can be set for a database field of type @a type having "notEmpty" property set. 0430 /*! It works in a similar way as @ref QVariant KDb::emptyValueForFieldType(KDbField::Type type) 0431 with the following differences: 0432 - " " string (a single space) is returned for Text and LongText types 0433 - a byte array with saved "filenew" PNG image (icon) for BLOB type 0434 Returns null QVariant for unsupported values like KDbField::InvalidType. */ 0435 KDB_EXPORT QVariant notEmptyValueForFieldType(KDbField::Type type); 0436 0437 /*! @return true if the @a word is an reserved KDbSQL keyword 0438 See src/generated/sqlkeywords.cpp in the KDb source code. 0439 @todo add function returning list of keywords. */ 0440 KDB_EXPORT bool isKDbSqlKeyword(const QByteArray& word); 0441 0442 //! @return @a string string with applied KDbSQL identifier escaping 0443 /*! This escaping can be used for field, table, database names, etc. 0444 Use it for user-visible backend-independent statements. 0445 @see KDb::escapeIdentifierAndAddQuotes() */ 0446 KDB_EXPORT QString escapeIdentifier(const QString& string); 0447 0448 //! @overload QString escapeIdentifier(const QString&) 0449 KDB_EXPORT QByteArray escapeIdentifier(const QByteArray& string); 0450 0451 //! @return @a string string with applied KDbSQL identifier escaping and enclosed in " quotes 0452 /*! This escaping can be used for field, table, database names, etc. 0453 Use it for user-visible backend-independent statements. 0454 @see KDb::escapeIdentifier */ 0455 KDB_EXPORT QString escapeIdentifierAndAddQuotes(const QString& string); 0456 0457 //! @overload QString escapeIdentifierAndAddQuotes(const QString&) 0458 KDB_EXPORT QByteArray escapeIdentifierAndAddQuotes(const QByteArray& string); 0459 0460 /*! @return escaped string @a string w using KDbSQL dialect, 0461 i.e. doubles single quotes ("'") and inserts the string into single quotes. 0462 Quotes "'" are prepended and appended. 0463 Also escapes \\n, \\r, \\t, \\\\, \\0. 0464 Use it for user-visible backend-independent statements. */ 0465 KDB_EXPORT QString escapeString(const QString& string); 0466 0467 /** 0468 * @brief Returns escaped string @a string 0469 * 0470 * If @a drv driver is present, it is used to perform escaping, otherwise escapeString() is used 0471 * so the KDbSQL dialect-escaping is performed. 0472 */ 0473 KDB_EXPORT KDbEscapedString escapeString(KDbDriver *drv, const QString& string); 0474 0475 /** 0476 * @brief Returns escaped string @a string 0477 * 0478 * If @a conn is present, its driver is used to perform escaping, otherwise escapeString() is used 0479 * so the KDbSQL dialect-escaping is performed. 0480 */ 0481 KDB_EXPORT KDbEscapedString escapeString(KDbConnection *conn, const QString& string); 0482 #endif 0483 0484 void KDbTest::testUnescapeString_data() 0485 { 0486 QTest::addColumn<QString>("sequence"); 0487 QTest::addColumn<QString>("result"); 0488 QTest::addColumn<char>("quote"); // can be ' or ", if 0 then both variants are checked 0489 QTest::addColumn<int>("errorPosition"); 0490 QTest::addColumn<int>("errorPositionWhenAppended"); 0491 0492 // quote-independent cases, success 0493 #define T2(tag, sequence, result, quote) QTest::newRow(tag) << QString::fromUtf8(sequence) \ 0494 << QString::fromUtf8(result) << quote << -1 << -1 0495 #define T(tag, sequence, result) T2(tag, sequence, result, '\0') 0496 QTest::newRow("null") << QString() << QString() << '\0' << -1 << -1; 0497 QTest::newRow("\\0") << QString("\\0") << QString(QLatin1Char('\0')) << '\0' << -1 << -1; 0498 const char *s = " String without escaping %_? 𝌆 ©"; 0499 T("without escaping", s, s); 0500 T("empty", "", ""); 0501 T("\\'", "\\'", "'"); 0502 T("\\\"", "\\\"", "\""); 0503 T("\\\\", "\\\\", "\\"); 0504 T("\\b", "\\b", "\b"); 0505 T("\\f", "\\f", "\f"); 0506 T("\\n", "\\n", "\n"); 0507 T("\\r", "\\r", "\r"); 0508 T("\\t", "\\t", "\t"); 0509 T("\\v", "\\v", "\v"); 0510 T("_\\_", "_\\_", "__"); 0511 T("?\\?", "?\\?", "??"); 0512 T("%\\%", "%\\%", "%%"); 0513 T("ignored \\ in \\a", "\\a", "a"); 0514 T("ignored \\ in \\♥", "\\♥ ", "♥ "); 0515 T("ignored \\ in 𝌆\\\\\\a", "𝌆\\\\\\a", "𝌆\\a"); 0516 T("unfinished \\", "\\", ""); 0517 T("unfinished \\ 2", "one two\\", "one two"); 0518 T("\\xA9", "\\xA9", "©"); 0519 T("\\xa9\\xa9", "\\xa9\\xa9", "©©"); 0520 QTest::newRow("\\x00") << QString("\\x00") << QString(QLatin1Char('\0')) << '\0' << -1 << -1; 0521 QTest::newRow("\\u0000") << QString("\\u0000") << QString(QChar(static_cast<unsigned short>(0))) 0522 << '\0' << -1 << -1; 0523 T("\\u2665", "\\u2665", "♥"); 0524 #ifndef _MSC_VER // does not work with MSVC: "warning C4566: character represented 0525 // by universal-character-name cannot be represented in the current code page" 0526 T("\\xff", "\\xff", "\u00ff"); 0527 T("\\uffff", "\\uffff", "\uffff"); 0528 #endif 0529 QTest::newRow("\\u{0}") << QString("\\u{0}") << QString(QLatin1Char('\0')) << '\0' << -1 << -1; 0530 QTest::newRow("\\u{0000000000}") << QString("\\u{0000000000}") 0531 << QString(QLatin1Char('\0')) << '\0' << -1 << -1; 0532 T("\\u{A9}", "\\u{A9}", "©"); 0533 T("\\u{a9}", "\\u{a9}", "©"); 0534 T("\\u{0a9}", "\\u{0a9}", "©"); 0535 T("\\u{00a9}", "\\u{00a9}", "©"); 0536 T("\\u{2665}", "\\u{2665}", "♥"); 0537 T("\\u{02665}", "\\u{02665}", "♥"); 0538 QTest::newRow("\\u{1D306}") << QString("\\u{1D306}") << QString(QChar(0x1D306)) << '\0' << -1 << -1; 0539 QTest::newRow("\\u{1d306}") << QString("\\u{1d306}") << QString(QChar(0x1d306)) << '\0' << -1 << -1; 0540 QTest::newRow("\\u{01D306}") << QString("\\u{01D306}") << QString(QChar(0x1D306)) << '\0' << -1 << -1; 0541 QTest::newRow("\\u{01d306}") << QString("\\u{01d306}") << QString(QChar(0x1d306)) << '\0' << -1 << -1; 0542 QTest::newRow("\\u{00001D306}") << QString("\\u{00001D306}") << QString(QChar(0x1D306)) << '\0' << -1 << -1; 0543 QTest::newRow("\\u{10FFFF}") << QString("\\u{10FFFF}") << QString(QChar(0x10FFFF)) << '\0' << -1 << -1; 0544 0545 // quote-dependent cases, success 0546 T2("2x ' for ' quote", "''", "'", '\''); 0547 T2("4x ' for ' quote", "''''", "''", '\''); 0548 T2("2x \" for ' quote", "\"\"", "\"\"", '\''); 0549 T2("3x \" for ' quote", "\"\"\"", "\"\"\"", '\''); 0550 T2("2x ' for \" quote", "''", "''", '"'); 0551 T2("3x ' for \" quote", "'''", "'''", '"'); 0552 T2("2x \" for \" quote", "\"\"", "\"", '"'); 0553 T2("4x \" for \" quote", "\"\"\"\"", "\"\"", '"'); 0554 #undef T 0555 #undef T2 0556 // failures 0557 QTest::newRow("invalid quote") << QString::fromUtf8("abc") << QString() << 'x' << 0 << 0; 0558 #define T(tag, sequence, quote, errorPosition, errorPositionWhenAppended) \ 0559 QTest::newRow(tag) << QString::fromUtf8(sequence) << QString() << quote \ 0560 << errorPosition << errorPositionWhenAppended 0561 T("missing ' quote", "'", '\'', 0, 0); 0562 T("missing \" quote", "\"", '"', 0, 0); 0563 T("invalid \\x", "\\x", '\0', 1, 2); 0564 T("invalid \\xQ", "\\xQ", '\0', 2, 2); 0565 T("invalid \\xQt", "\\xQt", '\0', 2, 2); 0566 T("invalid \\xAQ", "\\xAQ", '\0', 3, 3); 0567 T("invalid \\u", "\\u", '\0', 1, 2); 0568 T("invalid \\ua", "\\ua", '\0', 2, 3); 0569 T("invalid \\u40", "\\u40", '\0', 3, 4); 0570 T("invalid \\u405", "\\u405", '\0', 4, 5); 0571 T("invalid \\uQ", "\\uQ", '\0', 2, 2); 0572 T("invalid \\uQt", "\\uQt", '\0', 2, 2); 0573 T("invalid \\uQt5", "\\uQt5", '\0', 2, 2); 0574 T("invalid \\uQt57", "\\uQt57", '\0', 2, 2); 0575 T("invalid \\uaQ", "\\uaQ", '\0', 3, 3); 0576 T("invalid \\uabQ", "\\uabQ", '\0', 4, 4); 0577 T("invalid \\uabcQ", "\\uabcQ", '\0', 5, 5); 0578 T("invalid \\u{", "\\u{", '\0', 2, 3); 0579 T("invalid \\u{26", "\\u{26", '\0', 4, 5); 0580 T("invalid \\u{266", "\\u{266", '\0', 5, 6); 0581 T("invalid \\u{2665", "\\u{2665", '\0', 6, 7); 0582 T("invalid \\u{2665a", "\\u{2665a", '\0', 7, 8); 0583 T("invalid \\u{}", "\\u{}", '\0', 3, 3); 0584 T("invalid \\u{Q}", "\\u{Q}", '\0', 3, 3); 0585 T("invalid \\u{Qt}", "\\u{Qt}", '\0', 3, 3); 0586 T("invalid \\u{Qt5}", "\\u{Qt5}", '\0', 3, 3); 0587 T("invalid \\u{Qt57}", "\\u{Qt57}", '\0', 3, 3); 0588 T("invalid \\u{Qt57", "\\u{Qt57", '\0', 3, 3); 0589 T("invalid \\u{aQ}", "\\u{aQ}", '\0', 4, 4); 0590 T("invalid \\u{abQ}", "\\u{abQ}", '\0', 5, 5); 0591 T("invalid \\u{abcQ}", "\\u{abcQ}", '\0', 6, 6); 0592 T("invalid \\u{abcdQ}", "\\u{abcdQ}", '\0', 7, 7); 0593 T("invalid \\u{abcdQ}", "\\u{abcdQ}", '\0', 7, 7); 0594 T("invalid \\u{abcdfQ}", "\\u{abcdfQ}", '\0', 8, 8); 0595 T("invalid too large \\u{110000}", "\\u{110000}", '\0', 8, 8); 0596 T("invalid too large \\u{1100000}", "\\u{1100000}", '\0', 8, 8); 0597 T("invalid too large \\u{00110000}", "\\u{00110000}", '\0', 10, 10); 0598 } 0599 0600 void KDbTest::testUnescapeStringHelper(const QString &sequenceString, const QString &resultString_, 0601 char quote, int errorPosition, int offset) 0602 { 0603 int actualErrorPosition = -2; 0604 QString resultString(resultString_); 0605 if (errorPosition >= 0) { 0606 errorPosition += offset; 0607 resultString.clear(); 0608 } 0609 //qDebug() << KDb::unescapeString("\\0bar", '\'', &errorPosition); 0610 0611 #define COMPARE(x, y) \ 0612 if (x != y) { \ 0613 qDebug() << "sequenceString:" << sequenceString << "resultString:" << resultString; \ 0614 } \ 0615 QCOMPARE(x, y) 0616 0617 if (quote == 0) { // both cases 0618 COMPARE(KDb::unescapeString(sequenceString, '\'', &actualErrorPosition), resultString); 0619 COMPARE(actualErrorPosition, errorPosition); 0620 COMPARE(KDb::unescapeString(sequenceString, '\'', nullptr), resultString); 0621 0622 COMPARE(KDb::unescapeString(sequenceString, '"', &actualErrorPosition), resultString); 0623 COMPARE(actualErrorPosition, errorPosition); 0624 COMPARE(KDb::unescapeString(sequenceString, '"', nullptr), resultString); 0625 } else { 0626 if (quote != '\'' && quote != '"') { 0627 resultString.clear(); 0628 errorPosition = 0; 0629 } 0630 COMPARE(KDb::unescapeString(sequenceString, quote, &actualErrorPosition), resultString); 0631 COMPARE(actualErrorPosition, errorPosition); 0632 COMPARE(KDb::unescapeString(sequenceString, quote, nullptr), resultString); 0633 } 0634 #undef CHECK_POS 0635 } 0636 0637 void KDbTest::testUnescapeString() 0638 { 0639 QFETCH(QString, sequence); 0640 QFETCH(QString, result); 0641 QFETCH(char, quote); 0642 QFETCH(int, errorPosition); 0643 QFETCH(int, errorPositionWhenAppended); 0644 testUnescapeStringHelper(sequence, result, quote, errorPosition, 0); 0645 testUnescapeStringHelper("foo" + sequence, "foo" + result, quote, errorPosition, 3); 0646 testUnescapeStringHelper(sequence + " bar", result + " bar", quote, errorPositionWhenAppended, 0647 0); 0648 testUnescapeStringHelper("foo" + sequence + " bar", "foo" + result + " bar", 0649 quote, errorPositionWhenAppended, 3); 0650 } 0651 0652 void KDbTest::testEscapeBLOB_data() 0653 { 0654 QTest::addColumn<QByteArray>("blob"); 0655 QTest::addColumn<QString>("escapedX"); 0656 QTest::addColumn<QString>("escaped0x"); 0657 QTest::addColumn<QString>("escapedHex"); 0658 QTest::addColumn<QString>("escapedOctal"); 0659 QTest::addColumn<QString>("escapedBytea"); 0660 0661 QTest::newRow("") << QByteArray() 0662 << QString("X''") << QString() << QString("") << QString("''") << QString("E'\\\\x'::bytea"); 0663 QTest::newRow("0,1,k") << QByteArray("\0\1k", 3) 0664 << QString("X'00016B'") << QString("0x00016B") << QString("00016B") << QString("'\\\\000\\\\001k'") << QString("E'\\\\x00016B'::bytea"); 0665 QTest::newRow("ABC\\\\0") << QByteArray("ABC\0", 4) 0666 << QString("X'41424300'") << QString("0x41424300") << QString("41424300") << QString("'ABC\\\\000'") << QString("E'\\\\x41424300'::bytea"); 0667 QTest::newRow("'") << QByteArray("'") 0668 << QString("X'27'") << QString("0x27") << QString("27") << QString("'\\\\047'") << QString("E'\\\\x27'::bytea"); 0669 QTest::newRow("\\") << QByteArray("\\") 0670 << QString("X'5C'") << QString("0x5C") << QString("5C") << QString("'\\\\134'") << QString("E'\\\\x5C'::bytea"); 0671 } 0672 0673 void KDbTest::testEscapeBLOB() 0674 { 0675 QFETCH(QByteArray, blob); 0676 QFETCH(QString, escapedX); 0677 QFETCH(QString, escaped0x); 0678 QFETCH(QString, escapedHex); 0679 QFETCH(QString, escapedOctal); 0680 QFETCH(QString, escapedBytea); 0681 0682 QCOMPARE(KDb::escapeBLOB(blob, KDb::BLOBEscapingType::XHex), escapedX); 0683 QCOMPARE(KDb::escapeBLOB(blob, KDb::BLOBEscapingType::ZeroXHex), escaped0x); 0684 QCOMPARE(KDb::escapeBLOB(blob, KDb::BLOBEscapingType::Hex), escapedHex); 0685 QCOMPARE(KDb::escapeBLOB(blob, KDb::BLOBEscapingType::Octal), escapedOctal); 0686 QCOMPARE(KDb::escapeBLOB(blob, KDb::BLOBEscapingType::ByteaHex), escapedBytea); 0687 } 0688 0689 void KDbTest::testPgsqlByteaToByteArray() 0690 { 0691 QCOMPARE(KDb::pgsqlByteaToByteArray(nullptr, 0), QByteArray()); 0692 QCOMPARE(KDb::pgsqlByteaToByteArray("", 0), QByteArray()); 0693 QCOMPARE(KDb::pgsqlByteaToByteArray(" ", 0), QByteArray()); 0694 QCOMPARE(KDb::pgsqlByteaToByteArray("\\101"), QByteArray("A")); 0695 QCOMPARE(KDb::pgsqlByteaToByteArray("\\101", 4), QByteArray("A")); 0696 QCOMPARE(KDb::pgsqlByteaToByteArray("\\101B", 4), QByteArray("A")); // cut-off at #4 0697 QCOMPARE(KDb::pgsqlByteaToByteArray("\\'\\\\\\'"), QByteArray("\'\\\'")); 0698 QCOMPARE(KDb::pgsqlByteaToByteArray("\\\\a\\377bc\\'d\"\n"), QByteArray("\\a\377bc\'d\"\n")); 0699 } 0700 0701 void KDbTest::testXHexToByteArray_data() 0702 { 0703 QTest::addColumn<QByteArray>("data"); 0704 QTest::addColumn<int>("length"); // -2 means "compute length", other values: pass it as is 0705 QTest::addColumn<bool>("ok"); 0706 QTest::addColumn<QByteArray>("result"); 0707 0708 QTest::newRow("") << QByteArray() << 0 << false << QByteArray(); 0709 QTest::newRow("bad prefix") << QByteArray("bad") << -2 << false << QByteArray(); 0710 QTest::newRow("X") << QByteArray("X") << -2 << false << QByteArray(); 0711 QTest::newRow("X'") << QByteArray("X'") << -2 << false << QByteArray(); 0712 QTest::newRow("X''") << QByteArray("X''") << -2 << true << QByteArray(); 0713 QTest::newRow("X'1") << QByteArray("X'1") << -2 << false << QByteArray(); 0714 QTest::newRow("X'1' cut") << QByteArray("X'1'") << 3 << false << QByteArray(); 0715 QTest::newRow("X'1'") << QByteArray("X'1'") << -2 << true << QByteArray("\1"); 0716 QTest::newRow("X'0'") << QByteArray("X'0'") << -2 << true << QByteArray("\0", 1); 0717 QTest::newRow("X'000'") << QByteArray("X'000'") << -2 << true << QByteArray("\0\0", 2); 0718 QTest::newRow("X'01'") << QByteArray("X'01'") << -2 << true << QByteArray("\1"); 0719 QTest::newRow("X'FeAb2C'") << QByteArray("X'FeAb2C'") << -2 << true << QByteArray("\376\253\54"); 0720 } 0721 0722 void KDbTest::testXHexToByteArray() 0723 { 0724 QFETCH(QByteArray, data); 0725 QFETCH(int, length); 0726 QFETCH(bool, ok); 0727 QFETCH(QByteArray, result); 0728 0729 bool actualOk; 0730 QCOMPARE(KDb::xHexToByteArray(data.constData(), length == -1 ? data.length() : length, &actualOk), result); 0731 QCOMPARE(actualOk, ok); 0732 QCOMPARE(KDb::xHexToByteArray(data.constData(), length, nullptr), result); 0733 } 0734 0735 void KDbTest::testZeroXHexToByteArray_data() 0736 { 0737 QTest::addColumn<QByteArray>("data"); 0738 QTest::addColumn<int>("length"); // -2 means "compute length", other values: pass it as is 0739 QTest::addColumn<bool>("ok"); 0740 QTest::addColumn<QByteArray>("result"); 0741 0742 QTest::newRow("") << QByteArray() << 0 << false << QByteArray(); 0743 QTest::newRow("0") << QByteArray("0") << -2 << false << QByteArray(); 0744 QTest::newRow("0x") << QByteArray("0x") << -2 << false << QByteArray(); 0745 QTest::newRow("0X22") << QByteArray("0X22") << -2 << false << QByteArray(); 0746 QTest::newRow("bad prefix") << QByteArray("bad") << -2 << false << QByteArray(); 0747 QTest::newRow("0x0") << QByteArray("0x0") << -2 << true << QByteArray("\0", 1); 0748 QTest::newRow("0x0 cut") << QByteArray("0x0") << 2 << false << QByteArray(); 0749 QTest::newRow("0X0") << QByteArray("0X0") << -2 << false << QByteArray(); 0750 QTest::newRow("0x0123") << QByteArray("0x0123") << -2 << true << QByteArray("\1\43"); 0751 QTest::newRow("0x0123 cut") << QByteArray("0x0123") << 4 << true << QByteArray("\1"); 0752 QTest::newRow("0x00000'") << QByteArray("0x00000") << -2 << true << QByteArray("\0\0\0", 3); 0753 QTest::newRow("0xFeAb2C") << QByteArray("0xFeAb2C") << -2 << true << QByteArray("\376\253\54"); 0754 } 0755 0756 void KDbTest::testZeroXHexToByteArray() 0757 { 0758 QFETCH(QByteArray, data); 0759 QFETCH(int, length); 0760 QFETCH(bool, ok); 0761 QFETCH(QByteArray, result); 0762 0763 bool actualOk; 0764 QCOMPARE(KDb::zeroXHexToByteArray(data.constData(), length == -1 ? data.length() : length, &actualOk), result); 0765 QCOMPARE(actualOk, ok); 0766 QCOMPARE(KDb::zeroXHexToByteArray(data.constData(), length, nullptr), result); 0767 } 0768 0769 //! @todo add tests 0770 #if 0 0771 /*! @return int list converted from string list. 0772 If @a ok is not 0, *ok is set to result of the conversion. */ 0773 KDB_EXPORT QList<int> stringListToIntList(const QStringList &list, bool *ok); 0774 0775 /*! @return string converted from list @a list. 0776 Separators are ',' characters, "," and "\\" are escaped. 0777 @see KDb::deserializeList() */ 0778 KDB_EXPORT QString serializeList(const QStringList &list); 0779 0780 /*! @return string list converted from @a data which was built using serializeList(). 0781 Separators are ',' characters, escaping is assumed as "\\,". */ 0782 KDB_EXPORT QStringList deserializeList(const QString &data); 0783 0784 /*! @return int list converted from @a data which was built using serializeList(). 0785 Separators are ',' characters, escaping is assumed as "\\,". 0786 If @a ok is not 0, *ok is set to result of the conversion. 0787 @see KDb::stringListToIntList() */ 0788 KDB_EXPORT QList<int> deserializeIntList(const QString &data, bool *ok); 0789 0790 /*! @return string value serialized from a variant value @a v. 0791 This functions works like QVariant::toString() except the case when @a v is of type: 0792 - QByteArray - in this case KDb::escapeBLOB(v.toByteArray(), KDb::BLOBEscapeHex) is used. 0793 - QStringList - in this case KDb::serializeList(v.toStringList()) is used. 0794 0795 This function is needed for handling values of random type, for example "defaultValue" 0796 property of table fields can contain value of any type. 0797 Note: the returned string is an unescaped string. */ 0798 KDB_EXPORT QString variantToString(const QVariant& v); 0799 0800 /*! @return variant value of type @a type for a string @a s that was previously serialized using 0801 @ref variantToString( const QVariant& v ) function. 0802 @a ok is set to the result of the operation. With exception for types mentioned in documentation 0803 of variantToString(), QVariant::convert() is used for conversion. */ 0804 KDB_EXPORT QVariant stringToVariant(const QString& s, QVariant::Type type, bool* ok); 0805 0806 /*! @return true if setting default value for @a field field is allowed. Fields with unique 0807 (and thus primary key) flags set do not accept default values. */ 0808 KDB_EXPORT bool isDefaultValueAllowed(const KDbField &field); 0809 0810 //! Provides limits for values of type @a type 0811 /*! The result is put into integers pointed by @a minValue and @a maxValue. 0812 The limits are machine-independent,. what is useful for format and protocol compatibility. 0813 Supported types are Byte, ShortInteger, Integer and BigInteger. 0814 The value of @a signedness controls the values; they can be limited to unsigned or not. 0815 Results for BigInteger or non-integer types are the same as for Integer due to limitation 0816 of int type. Signed integers are assumed. @a minValue and @a maxValue must not be 0. */ 0817 KDB_EXPORT void getLimitsForFieldType(KDbField::Type type, qlonglong *minValue, qlonglong *maxValue, 0818 KDb::Signedness signedness = KDb::Signed); 0819 0820 /*! @return type that's maximum of two integer types @a t1 and @a t2, e.g. Integer for (Byte, Integer). 0821 If one of the types is not of the integer group, KDbField::InvalidType is returned. 0822 Returned type may not fit to the result of evaluated expression that involves the arguments. 0823 For example, 100 is within Byte type, maximumForIntegerFieldTypes(Byte, Byte) is Byte but result 0824 of 100 * 100 exceeds the range of Byte. */ 0825 KDB_EXPORT KDbField::Type maximumForIntegerFieldTypes(KDbField::Type t1, KDbField::Type t2); 0826 #endif 0827 0828 void KDbTest::testCstringToVariant_data() 0829 { 0830 QTest::addColumn<QString>("data"); // QString() -> 0, QString("") -> empty string "" 0831 QTest::addColumn<KDbField::Type>("type"); 0832 QTest::addColumn<int>("length"); 0833 QTest::addColumn<QVariant>("variant"); 0834 QTest::addColumn<KDb::Signedness>("signedness"); 0835 QTest::addColumn<bool>("okResult"); 0836 0837 int c = 0; 0838 ++c; 0839 QTest::newRow("invalid1") << QString() << KDbField::InvalidType << -1 << QVariant() << KDb::Signed << false; 0840 QTest::newRow("invalid2") << "" << KDbField::InvalidType << -1 << QVariant() << KDb::Signed << false; 0841 QTest::newRow("invalid3") << "abc" << KDbField::InvalidType << 3 << QVariant() << KDb::Signed << false; 0842 ++c; 0843 QTest::newRow("byte1") << "0" << KDbField::Byte << 1 << QVariant(0) << KDb::Signed << true; 0844 QTest::newRow("ubyte1") << "0" << KDbField::Byte << 1 << QVariant(0) << KDb::Unsigned << true; 0845 QTest::newRow("byte2") << "42" << KDbField::Byte << -1 << QVariant(42) << KDb::Signed << true; 0846 QTest::newRow("ubyte2") << "42" << KDbField::Byte << -1 << QVariant(42) << KDb::Unsigned << true; 0847 QTest::newRow("byte3") << "129" << KDbField::Byte << -1 << QVariant() << KDb::Signed << false; 0848 QTest::newRow("ubyte3") << "129" << KDbField::Byte << -1 << QVariant(129) << KDb::Unsigned << true; 0849 QTest::newRow("byte4") << "-128" << KDbField::Byte << -1 << QVariant(-128) << KDb::Signed << true; 0850 QTest::newRow("ubyte4") << "-128" << KDbField::Byte << -1 << QVariant() << KDb::Unsigned << false; 0851 ++c; 0852 QTest::newRow("short1") << "-123" << KDbField::ShortInteger << -1 << QVariant(-123) << KDb::Signed << true; 0853 QTest::newRow("short2") << "942" << KDbField::ShortInteger << -1 << QVariant(942) << KDb::Signed << true; 0854 QTest::newRow("short3") << "32767" << KDbField::ShortInteger << -1 << QVariant(32767) << KDb::Signed << true; 0855 QTest::newRow("short4") << "32768" << KDbField::ShortInteger << -1 << QVariant() << KDb::Signed << false; 0856 QTest::newRow("ushort4") << "32768" << KDbField::ShortInteger << -1 << QVariant(32768) << KDb::Unsigned << true; 0857 QTest::newRow("short5") << "-32768" << KDbField::ShortInteger << -1 << QVariant(-32768) << KDb::Signed << true; 0858 QTest::newRow("ushort5") << "-32768" << KDbField::ShortInteger << -1 << QVariant() << KDb::Unsigned << false; 0859 ++c; 0860 QTest::newRow("int1") << QString::number(0x07FFFFFFF) << KDbField::Integer << -1 << QVariant(0x07FFFFFFF) << KDb::Signed << true; 0861 QTest::newRow("uint1") << QString::number(0x07FFFFFFF) << KDbField::Integer << -1 << QVariant(0x07FFFFFFF) << KDb::Unsigned << true; 0862 QTest::newRow("int2") << QString::number(-0x07FFFFFFF) << KDbField::Integer << -1 << QVariant(-0x07FFFFFFF) << KDb::Signed << true; 0863 QTest::newRow("uint2") << QString::number(-0x07FFFFFFF) << KDbField::Integer << -1 << QVariant() << KDb::Unsigned << false; 0864 QTest::newRow("int3") << QString::number(std::numeric_limits<qlonglong>::min()) << KDbField::Integer << -1 << QVariant() << KDb::Signed << false; 0865 QTest::newRow("uint4") << "-1" << KDbField::Integer << -1 << QVariant() << KDb::Unsigned << false; 0866 QTest::newRow("int4") << "-1" << KDbField::Integer << -1 << QVariant(-1) << KDb::Signed << true; 0867 //!< @todo cannot be larger? 0868 ++c; 0869 QTest::newRow("bigint1") << QString::number(0x07FFFFFFF) << KDbField::BigInteger << -1 << QVariant(0x07FFFFFFF) << KDb::Signed << true; 0870 QTest::newRow("ubigint1") << QString::number(0x07FFFFFFF) << KDbField::BigInteger << -1 << QVariant(0x07FFFFFFF) << KDb::Unsigned << true; 0871 QTest::newRow("bigint2") << QString::number(-0x07FFFFFFF) << KDbField::BigInteger << -1 << QVariant(-0x07FFFFFFF) << KDb::Signed << true; 0872 QTest::newRow("ubigint2") << QString::number(-0x07FFFFFFF) << KDbField::BigInteger << -1 << QVariant() << KDb::Unsigned << false; 0873 QTest::newRow("bigint3") << QString::number(std::numeric_limits<qlonglong>::min()) << KDbField::BigInteger << -1 << QVariant() << KDb::Signed << false; 0874 QTest::newRow("ubigint4") << "-1" << KDbField::BigInteger << -1 << QVariant() << KDb::Unsigned << false; 0875 QTest::newRow("bigint4") << "-1" << KDbField::BigInteger << -1 << QVariant(-1) << KDb::Signed << true; 0876 ++c; 0877 QTest::newRow("bool0") << "0" << KDbField::Boolean << -1 << QVariant(false) << KDb::Signed << true; 0878 QTest::newRow("bool1") << "1" << KDbField::Boolean << -1 << QVariant(true) << KDb::Signed << true; 0879 QTest::newRow("bool-") << "-" << KDbField::Boolean << -1 << QVariant(true) << KDb::Signed << true; 0880 QTest::newRow("bool5") << "5" << KDbField::Boolean << -1 << QVariant(true) << KDb::Signed << true; 0881 QTest::newRow("bool false") << "false" << KDbField::Boolean << -1 << QVariant(false) << KDb::Signed << true; 0882 QTest::newRow("bool False") << "False" << KDbField::Boolean << -1 << QVariant(false) << KDb::Signed << true; 0883 QTest::newRow("bool TRUE") << "TRUE" << KDbField::Boolean << -1 << QVariant(true) << KDb::Signed << true; 0884 QTest::newRow("bool true") << "true" << KDbField::Boolean << -1 << QVariant(true) << KDb::Signed << true; 0885 QTest::newRow("bool no") << "no" << KDbField::Boolean << -1 << QVariant(true) << KDb::Signed << true; // surprised? See docs for QVariant::toBool(). 0886 ++c; 0887 //! @todo support Date 0888 ++c; 0889 //! @todo support DateTime 0890 ++c; 0891 //! @todo support Time 0892 ++c; 0893 //! @todo support Float 0894 ++c; 0895 //! @todo support Double 0896 ++c; 0897 //! @todo support Text 0898 ++c; 0899 //! @todo support LongText 0900 ++c; 0901 //! @todo support BLOB 0902 0903 ++c; QTest::newRow("Null") << " " << KDbField::Null << -1 << QVariant() << KDb::Signed << false; 0904 ++c; QTest::newRow("Asterisk") << " " << KDbField::Asterisk << -1 << QVariant() << KDb::Signed << false; 0905 ++c; QTest::newRow("Enum") << " " << KDbField::Enum << -1 << QVariant() << KDb::Signed << false; 0906 ++c; QTest::newRow("Map") << " " << KDbField::Map << -1 << QVariant() << KDb::Signed << false; 0907 ++c; QTest::newRow("Tuple") << " " << KDbField::Tuple << -1 << QVariant() << KDb::Signed << false; 0908 QCOMPARE(c, KDbField::typesCount() + KDbField::specialTypesCount()); 0909 } 0910 0911 void KDbTest::testCstringToVariant() 0912 { 0913 QFETCH(QString, data); 0914 QFETCH(KDbField::Type, type); 0915 QFETCH(int, length); 0916 QFETCH(QVariant, variant); 0917 QFETCH(KDb::Signedness, signedness); 0918 QFETCH(bool, okResult); 0919 bool ok; 0920 const QByteArray ba(data.toUtf8()); // to avoid pointer to temp. 0921 const char *realData = ba.isNull() ? nullptr : ba.constData(); 0922 QCOMPARE(KDb::cstringToVariant(realData, type, &ok, length, signedness), variant); 0923 QCOMPARE(ok, okResult); 0924 QCOMPARE(KDb::cstringToVariant(realData, type, nullptr, length, signedness), variant); // a case where ok == 0 0925 if (realData) { 0926 QCOMPARE(KDb::cstringToVariant(realData, type, &ok, data.length(), signedness), variant); // a case where length is set 0927 QCOMPARE(ok, okResult); 0928 } 0929 QCOMPARE(KDb::cstringToVariant(nullptr, type, &ok, length, signedness), QVariant()); // a case where data == 0 (NULL) 0930 QVERIFY(ok || type < KDbField::Byte || type > KDbField::LastType); // fails for NULL if this type isn't allowed 0931 if (type != KDbField::Boolean) { 0932 QCOMPARE(KDb::cstringToVariant(realData, type, &ok, 0, signedness), QVariant()); // a case where length == 0 0933 QVERIFY(!ok); 0934 } 0935 if (KDbField::isTextType(type)) { // a case where data == "" 0936 QCOMPARE(KDb::cstringToVariant("", type, &ok, length, signedness), QVariant("")); 0937 QVERIFY(ok); 0938 } 0939 else if (type != KDbField::Boolean) { 0940 QCOMPARE(KDb::cstringToVariant("", type, &ok, length, signedness), QVariant()); 0941 QVERIFY(!ok); 0942 } 0943 } 0944 0945 //! @todo add tests 0946 #if 0 0947 0948 /*! @return default file-based driver MIME type 0949 (typically something like "application/x-kexiproject-sqlite") */ 0950 KDB_EXPORT QString defaultFileBasedDriverMimeType(); 0951 0952 /*! @return default file-based driver ID (currently, "org.kde.kdb.sqlite"). */ 0953 KDB_EXPORT QString defaultFileBasedDriverId(); 0954 0955 /*! Escapes and converts value @a v (for type @a ftype) 0956 to string representation required by KDbSQL commands. 0957 For Date/Time type KDb::dateTimeToSql() is used. 0958 For BLOB type KDb::escapeBlob() with BLOBEscapingType::ZeroXHex conversion type is used. */ 0959 KDB_EXPORT KDbEscapedString valueToSql(KDbField::Type ftype, const QVariant& v); 0960 0961 /*! Converts value @a v to string representation required by KDbSQL commands: 0962 ISO 8601 DateTime format - with "T" delimiter/ 0963 For specification see https://www.w3.org/TR/NOTE-datetime. 0964 Example: "1994-11-05T13:15:30" not "1994-11-05 13:15:30". 0965 @todo Add support for time zones */ 0966 KDB_EXPORT KDbEscapedString dateTimeToSql(const QDateTime& v); 0967 0968 #ifdef KDB_DEBUG_GUI 0969 //! A prototype of handler for GUI debugger 0970 typedef void(*DebugGUIHandler)(const QString&); 0971 0972 //! Sets handler for GUI debugger 0973 KDB_EXPORT void setDebugGUIHandler(DebugGUIHandler handler); 0974 0975 //! Outputs string @a text to the GUI debugger 0976 KDB_EXPORT void debugGUI(const QString& text); 0977 0978 //! A prototype of handler for GUI debugger (specialized for the Alter Table feature) 0979 typedef void(*AlterTableActionDebugGUIHandler)(const QString&, int); 0980 0981 //! Sets handler for GUI debugger (specialized for the Alter Table feature) 0982 KDB_EXPORT void setAlterTableActionDebugHandler(AlterTableActionDebugGUIHandler handler); 0983 0984 //! Outputs string @a text to the GUI debugger (specialized for the Alter Table feature); 0985 //! @a nestingLevel can be provided for nested outputs. 0986 KDB_EXPORT void alterTableActionDebugGUI(const QString& text, int nestingLevel = 0); 0987 #endif 0988 0989 //! @return @a string if it is not empty, else returns @a stringIfEmpty. 0990 /*! This function is an optimization in cases when @a string is a result of expensive 0991 functioncall because any evaluation will be performed once, not twice. Another advantage 0992 is simpified code through the functional approach. 0993 The function expects bool isEmpty() method to be present in type T, so T can typically 0994 be QString or QByteArray. */ 0995 template<typename T> 0996 T iifNotEmpty(const T &string, const T &stringIfEmpty) 0997 { 0998 return string.isEmpty() ? stringIfEmpty : string; 0999 } 1000 1001 //! @overload iifNotEmpty(const T &string, const T &stringIfEmpty) 1002 template<typename T> 1003 T iifNotEmpty(const QByteArray &string, const T &stringIfEmpty) 1004 { 1005 return iifNotEmpty(QLatin1String(string), stringIfEmpty); 1006 } 1007 1008 //! @overload iifNotEmpty(const T &string, const T &stringIfEmpty) 1009 template<typename T> 1010 T iifNotEmpty(const T &string, const QByteArray &stringIfEmpty) 1011 { 1012 return iifNotEmpty(string, QLatin1String(stringIfEmpty)); 1013 } 1014 1015 //! @return @a value if @a ok is true, else returns default value T(). 1016 template<typename T> 1017 T iif(bool ok, const T &value) 1018 { 1019 if (ok) { 1020 return value; 1021 } 1022 return T(); 1023 } 1024 1025 /*! @return a list of paths that KDb will search when dynamically loading libraries (plugins) 1026 This is basicaly list of directories returned QCoreApplication::libraryPaths() that have readable 1027 subdirectory "kdb". 1028 @see QCoreApplication::libraryPaths() */ 1029 KDB_EXPORT QStringList libraryPaths(); 1030 #endif 1031 1032 void KDbTest::testTemporaryTableName() 1033 { 1034 QVERIFY(utils.testCreateDbWithTables("KDbTest")); 1035 1036 QString baseName = QLatin1String("foobar"); 1037 QString tempName1 = KDb::temporaryTableName(utils.connection(), baseName); 1038 QVERIFY(!tempName1.isEmpty()); 1039 QVERIFY(tempName1.contains(baseName)); 1040 QString tempName2 = KDb::temporaryTableName(utils.connection(), baseName); 1041 QVERIFY(!tempName2.isEmpty()); 1042 QVERIFY(tempName2.contains(baseName)); 1043 QVERIFY(tempName1 != tempName2); 1044 1045 utils.connection()->closeDatabase(); 1046 QTest::ignoreMessage(QtWarningMsg, "Missing database handle"); 1047 QTest::ignoreMessage(QtWarningMsg, QRegularExpression("!executeQuery().*")); 1048 QString tempName = KDb::temporaryTableName(utils.connection(), baseName); 1049 QVERIFY2(tempName.isEmpty(), "Temporary name should not be created when database is closed "); 1050 1051 utils.connection()->disconnect(); 1052 QTest::ignoreMessage(QtWarningMsg, "Missing database handle"); 1053 QTest::ignoreMessage(QtWarningMsg, QRegularExpression("!executeQuery().*")); 1054 tempName = KDb::temporaryTableName(utils.connection(), baseName); 1055 QVERIFY2(tempName.isEmpty(), "Temporary name should not be created connection is missing"); 1056 1057 utils.connection()->dropDatabase(utils.connection()->data().databaseName()); 1058 } 1059 1060 //! @todo add tests 1061 #if 0 1062 /*! @return absolute path to "sqlite3" program. 1063 Empty string is returned if the program was not found. */ 1064 KDB_EXPORT QString sqlite3ProgramPath(); 1065 1066 /*! Imports file in SQL format from @a inputFileName into @a outputFileName. 1067 Works for any SQLite 3 dump file. Requires access to executing the "sqlite3" command. 1068 File named @a outputFileName will be silently overwritten with a new SQLite 3 database file. 1069 @return true on success. */ 1070 KDB_EXPORT bool importSqliteFile(const QString &inputFileName, const QString &outputFileName); 1071 1072 /*! @return @c true if @a s is a valid identifier, i.e. starts with a letter or '_' character 1073 and contains only letters, numbers and '_' character. */ 1074 KDB_EXPORT bool isIdentifier(const QString& s); 1075 1076 /*! @return valid identifier based on @a s. 1077 Non-alphanumeric characters (or spaces) are replaced with '_'. 1078 If a number is at the beginning, '_' is added at start. 1079 Empty strings are not changed. Case remains unchanged. */ 1080 KDB_EXPORT QString stringToIdentifier(const QString &s); 1081 1082 /*! @return useful message "Value of "valueName" column must be an identifier. 1083 "v" is not a valid identifier.". It is also used by KDbIdentifierValidator. */ 1084 KDB_EXPORT QString identifierExpectedMessage(const QString &valueName, 1085 const QVariant& v); 1086 #endif 1087 1088 void KDbTest::deleteRecordWithOneConstraintsTest() 1089 { 1090 QVERIFY(utils.testCreateDbWithTables("KDbTest")); 1091 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "id", 2)); 1092 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "id", "3"), 1093 "Passing a valid Integer in String Format"); 1094 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "id", "Foo")); 1095 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "name", "Jaroslaw")); 1096 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "surname", "FooBar")); 1097 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "age", 45)); 1098 // and empty data. 1099 KDbTableSchema *kdb_t = utils.connection()->tableSchema("persons"); 1100 QVERIFY(kdb_t); 1101 QVERIFY2(utils.connection()->insertRecord(kdb_t, 10, 20, QVariant(), "Bar"), 1102 "Inserting NULL data"); 1103 QVERIFY2(utils.connection()->insertRecord(kdb_t,15, 20, "", "Bar"), 1104 "Inserting empty data"); 1105 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "name", QString()), 1106 "Passing a null value instead of string"); 1107 // 1108 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "name", ""), 1109 "Passing an empty string"); 1110 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "age", "Nitish")); 1111 QVERIFY(utils.testDisconnectAndDropDb()); 1112 } 1113 1114 static QRegularExpression resultRegExp(const QString &code, const QString &message, 1115 const QString &sql, const QString &serverErrorCode, 1116 const QString &serverMessage) 1117 { 1118 return QRegularExpression( 1119 QString::fromLatin1("KDbResult: CODE=%1 MESSAGE=\\\"%2\\\" ERR_SQL=KDbEscapedString:" 1120 "\\\"%3\\\" SERVER_ERROR_CODE=%4 SERVER_MESSAGE=\\\"%5") 1121 .arg(code.isEmpty() ? "[0-9]*" : code, message, sql, 1122 serverErrorCode.isEmpty() ? "[0-9]*" : serverErrorCode, serverMessage)); 1123 } 1124 1125 void KDbTest::deleteNonExistingRecordTest() 1126 { 1127 QVERIFY(utils.testCreateDbWithTables("KDbTest")); 1128 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "id", 400)); 1129 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "name", "FooBar")); 1130 QTest::ignoreMessage(QtWarningMsg, resultRegExp("260", "Error while executing SQL statement.", 1131 "DELETE FROM \\[persons\\] WHERE \\[Foo\\]='FooBar'", "0", "no such column: Foo")); 1132 QVERIFY2(!KDb::deleteRecords(utils.connection(), "persons", "Foo", "FooBar"), 1133 "Passing a NonExisting Column - should fail because 'Foo' column does not exist, " 1134 "See also https://bugs.kde.org/376052"); 1135 QVERIFY(utils.testDisconnectAndDropDb()); 1136 } 1137 1138 void KDbTest::deleteRecordWithTwoConstraintsTest() 1139 { 1140 QVERIFY(utils.testCreateDbWithTables("KDbTest")); 1141 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "id", KDbField::Integer, 1142 2, "age", KDbField::Integer, 60), 1143 "Both fields are INTEGER"); 1144 KDbTableSchema *kdb_t = utils.connection()->tableSchema("persons"); 1145 QVERIFY(kdb_t); 1146 utils.connection()->insertRecord(kdb_t, 10, QVariant(), "Foo", "Bar") ; 1147 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "id", KDbField::Integer, 1148 10, "age", KDbField::Integer, QVariant()), 1149 "Passing NULL value for integer field"); 1150 QVERIFY(utils.connection()->insertRecord(kdb_t, 20, QVariant(), QVariant(), "Bar")); 1151 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, 1152 QVariant(), "name", KDbField::Text, QVariant()), 1153 "Passing 2 NULL values"); 1154 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, 1155 20, "name", KDbField::Text, "Jaroslaw"), 1156 "One argument is Integer and another is Text"); 1157 QVERIFY2(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, 1158 20, "name", KDbField::Text, 56), 1159 "Two arguments, passing second integer instead of text but it is converted to text"); 1160 QTest::ignoreMessage(QtWarningMsg, resultRegExp("260", "Error while executing SQL statement.", 1161 "DELETE FROM \\[persons\\] WHERE \\[age\\]=TRAP AND \\[name\\]='56'", "0", "no such column: TRAP")); 1162 QVERIFY2(!KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, 1163 "TRAP", "name", KDbField::Text, 56), 1164 "Passing text instead of integer, conversion error expected"); 1165 QVERIFY(utils.testDisconnectAndDropDb()); 1166 } 1167 1168 void KDbTest::deleteRecordWithThreeConstraintsTest() 1169 { 1170 QVERIFY(utils.testCreateDbWithTables("KDbTest")); 1171 KDbTableSchema *kdb_t = utils.connection()->tableSchema("persons"); 1172 QVERIFY(kdb_t); 1173 //One null value. 1174 QVERIFY(utils.connection()->insertRecord(kdb_t, 10, QVariant(), "Foo", "Bar")); 1175 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, QVariant(), 1176 "name", KDbField::Text, "Foo", "surname", KDbField::Text, "Bar")); 1177 //Mix of null and empty values 1178 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, QVariant(), 1179 "name", KDbField::Text, "", "surname", KDbField::Text, "")); 1180 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer,27, 1181 "name", KDbField::Text, "Jaraslaw", "id", KDbField::Integer, 1)); 1182 QVERIFY(KDb::deleteRecords(utils.connection(), "persons", "age", KDbField::Integer, 60, 1183 "name", KDbField::Text, "Lech", "id", KDbField::Integer, 2)); 1184 QVERIFY(utils.testDisconnectAndDropDb()); 1185 } 1186 1187 void KDbTest::deleteAllRecordsTest() 1188 { 1189 QVERIFY(utils.testCreateDbWithTables("KDbTest")); 1190 QVERIFY(KDb::deleteAllRecords(utils.connection(), "persons")); 1191 1192 QRegularExpression deleteAllErrorRegExp = resultRegExp( 1193 "", "Error while executing SQL statement.", "DELETE FROM \\[.*\\]", "0", "no such table: .*"); 1194 QTest::ignoreMessage(QtWarningMsg, deleteAllErrorRegExp); 1195 QVERIFY2(!KDb::deleteAllRecords(utils.connection(), QString()), 1196 "Passing a null table name"); 1197 QTest::ignoreMessage(QtWarningMsg, deleteAllErrorRegExp); 1198 QVERIFY2(!KDb::deleteAllRecords(utils.connection(), ""), 1199 "Passing an empty table name"); 1200 QVERIFY(KDb::deleteAllRecords(utils.connection(), "cars")); 1201 QTest::ignoreMessage(QtWarningMsg, deleteAllErrorRegExp); 1202 QVERIFY2(!KDb::deleteAllRecords(utils.connection(), "NonExistingTable"), 1203 "Passing a nonexisting table name"); 1204 QVERIFY(utils.testDisconnectAndDropDb()); 1205 } 1206 1207 void KDbTest::cleanupTestCase() 1208 { 1209 }