tst_QVariant: overhaul the conversion-comparison tests with templates

This makes the tests more exhaustive than they were, with far less
repetition. Also adding the testing of conversions for which we don't
have a toXxx() getter, because those exercise different code paths
inside of QVariant, and yet should produce the same result.

Pick-to: 6.8 6.5
Task-number: QTBUG-134756
Change-Id: I99664a53da674bcbd992fffd5f290cfe51259d5b
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 42e0f9811095fc73c5c1209632247446e6229b3a)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Thiago Macieira 2025-03-17 11:21:38 -07:00 committed by Qt Cherry-pick Bot
parent 1f6346df1c
commit d0665d2628

View File

@ -215,6 +215,24 @@ private slots:
void toBool_data();
void toBool();
void toSChar_data();
void toSChar();
void toUChar_data();
void toUChar();
void toShort_data();
void toShort();
void toUShort_data();
void toUShort();
void toLong_data();
void toLong();
void toULong_data();
void toULong();
void toLongLong_data();
void toLongLong();
@ -829,47 +847,92 @@ void tst_QVariant::convert()
QCOMPARE(var.toInt(), 0);
}
void tst_QVariant::toInt_data()
template <typename To, typename From> static void addNumberConversionHelper(From v)
{
if constexpr (std::is_same_v<From, To>)
return;
To to = To(v);
QVariant var = QVariant::fromValue(v);
// std::numeric_limits is specialized for qfloat16, std::is_floating_point isn't.
if constexpr (std::numeric_limits<From>::is_iec559 && std::is_unsigned_v<To>) {
using STo = std::make_signed_t<To>;
STo s = STo(v);
Q_ASSERT(v < 0);
Q_ASSERT(s < 0);
QTest::addRow("negative-%s", var.typeName()) << var << To(s) << true;
v = -v;
to = To(v);
var = QVariant::fromValue(v);
}
QTest::addRow("%s", var.typeName()) << var << to << true;
}
template <typename To> static void addNumberConversions()
{
QTest::addColumn<QVariant>("value");
QTest::addColumn<int>("result");
QTest::addColumn<To>("result");
QTest::addColumn<bool>("valueOK");
QTest::newRow( "invalid" ) << QVariant() << 0 << false;
QTest::newRow( "int" ) << QVariant( 123 ) << 123 << true;
QTest::newRow( "char" ) << QVariant::fromValue('a') << int('a') << true;
signed char signedChar = -13;
QTest::newRow( "signed char" ) << QVariant::fromValue(signedChar) << -13 << true;
QTest::newRow( "short" ) << QVariant::fromValue(short(-7)) << int(-7) << true;
QTest::newRow( "ushort" ) << QVariant::fromValue(ushort(30000)) << 30000 << true;
QTest::newRow( "double" ) << QVariant( 3.1415927 ) << 3 << true;
QTest::newRow( "float" ) << QVariant( 3.1415927f ) << 3 << true;
QTest::newRow( "uint" ) << QVariant( 123u ) << 123 << true;
QTest::newRow( "int-string" ) << QVariant( QString("123") ) << 123 << true;
QTest::newRow( "string" ) << QVariant( QString("Unicode String") ) << 0 << false;
QTest::newRow( "longlong0" ) << QVariant( (qlonglong)34 ) << 34 << true;
QTest::newRow( "longlong1" ) << QVariant( intMax1 ) << (int)INT_MIN << true;
QTest::newRow( "ulonglong0" ) << QVariant( (qulonglong)34 ) << 34 << true;
QTest::newRow( "ulonglong1" ) << QVariant( uintMax1 ) << 0 << true;
QTest::newRow( "signedint" ) << QVariant( -123 ) << -123 << true;
QTest::newRow( "signeddouble" ) << QVariant( -3.1415927 ) << -3 << true;
QTest::newRow( "signedfloat" ) << QVariant( -3.1415927f ) << -3 << true;
QTest::newRow( "signedint-string" ) << QVariant( QString("-123") ) << -123 << true;
QTest::newRow( "signedlonglong0" ) << QVariant( (qlonglong)-34 ) << -34 << true;
QTest::newRow( "QChar" ) << QVariant(QChar('a')) << int('a') << true;
QByteArray bytearray(4, ' ');
bytearray[0] = 'T';
bytearray[1] = 'e';
bytearray[2] = 's';
bytearray[3] = 't';
QTest::newRow( "QByteArray1" ) << QVariant( bytearray ) << 0 << false;
bytearray[0] = '4';
bytearray[1] = '5';
bytearray[2] = '0';
bytearray[3] = '0';
QTest::newRow( "QByteArray2" ) << QVariant( bytearray ) << 4500 << true;
QTest::newRow("int-QJsonValue") << QVariant(QJsonValue(321)) << 321 << true;
QTest::newRow("undefined-QJsonValue") << QVariant(QJsonValue(QJsonValue::Undefined)) << 0 << false;
QTest::newRow("invalid") << QVariant() << To{} << false;
auto addNumber = [](auto v) { addNumberConversionHelper<To>(v); };
addNumber(true);
addNumber(char(1));
addNumber(qint8(-1));
addNumber(quint8(2));
// addNumber(u'A');
addNumber(short(-256));
addNumber(ushort(256));
// addNumber(U'\U00010000');
addNumber(-65536);
addNumber(65536U);
addNumber(-0x8000'0000L);
addNumber(0x8000'0000UL);
addNumber(-0x1'0000'0000LL);
addNumber(0x1'0000'000'0000ULL);
addNumber(-3.1415927f);
addNumber(-3.1415927);
if constexpr (sizeof(To) > sizeof(int)) {
// note: this includes double
qint64 value64 = (Q_INT64_C(12) << 35) + 8;
QTest::newRow("qint64") << QVariant::fromValue(value64) << To(value64) << true;
QTest::newRow("-qint64") << QVariant::fromValue(-value64) << To(-value64) << true;
QTest::newRow("LONG_MIN") << QVariant::fromValue(LONG_MIN) << To(LONG_MIN) << true;
QTest::newRow("-LONG_MIN/2") << QVariant::fromValue(-(LONG_MIN / 2)) << -To(LONG_MIN/2) << true;
if constexpr (std::is_integral_v<To>) {
QTest::newRow("LONG_MAX") << QVariant::fromValue(LONG_MAX) << To(LONG_MAX) << true;
QTest::newRow("ULONG_MAX") << QVariant::fromValue(ULONG_MAX) << To(ULONG_MAX) << true;
}
}
if constexpr (std::is_integral_v<To>)
QTest::newRow("QChar") << QVariant(QChar('a')) << To('a') << true;
QTest::newRow("nonint-QByteArray") << QVariant(QByteArray("zzzz")) << To{} << false;
QTest::newRow("nonint-QString") << QVariant(QString("zzzz")) << To{} << false;
QTest::newRow("undefined-QCborValue") << QVariant::fromValue<QCborValue>({}) << To{} << false;
QTest::newRow("undefined-QJsonValue") << QVariant(QJsonValue()) << To{} << false;
QTest::newRow("int-QByteArray") << QVariant(QByteArray("123")) << To(123) << true;
QTest::newRow("int-QCborValue") << QVariant::fromValue(QCborValue(321)) << To(321) << true;
QTest::newRow("int-QJsonValue") << QVariant(QJsonValue(321)) << To(321) << true;
QTest::newRow("int-QString") << QVariant(QString("123")) << To(123) << true;
if constexpr (std::numeric_limits<To>::is_iec559) {
QTest::newRow("fp-QByteArray") << QVariant(QByteArray("32.1")) << To(32.1) << true;
QTest::newRow("fp-QCborValue") << QVariant::fromValue(QCborValue(32.1)) << To(32.1) << true;
QTest::newRow("fp-QJsonValue") << QVariant(QJsonValue(32.1)) << To(32.1) << true;
QTest::newRow("fp-QString") << QVariant(QString("32.1")) << To(32.1) << true;
}
}
void tst_QVariant::toInt_data()
{
addNumberConversions<int>();
}
#if QT_DEPRECATED_SINCE(6, 0)
@ -878,71 +941,47 @@ void tst_QVariant::toInt_data()
# define EXEC_DEPRECATED_CALL(x)
#endif
void tst_QVariant::toInt()
template <typename T> static void checkNumberConversions(T (QVariant:: *toType)(bool *) const = nullptr)
{
QFETCH( QVariant, value );
QFETCH( int, result );
QFETCH( T, result );
QFETCH( bool, valueOK );
EXEC_DEPRECATED_CALL(QVERIFY( value.isValid() == value.canConvert( QVariant::Int ) );)
QVERIFY( value.isValid() == value.canConvert(QMetaType::fromType<int>()) );
bool ok;
int i = value.toInt( &ok );
QCOMPARE( i, result );
QVERIFY( ok == valueOK );
QMetaType mt = QMetaType::fromType<T>();
int typeId = mt.id();
EXEC_DEPRECATED_CALL(QVERIFY(value.isValid() == value.canConvert(typeId));)
QCOMPARE(value.isValid(), value.canConvert(mt));
if (toType) {
// QVariant conversion API
bool ok;
T i = (value.*toType)(&ok);
QCOMPARE(i, result);
QVERIFY(ok == valueOK);
}
if (value.isValid()) {
// test the conversion API (through QMetaType)
QCOMPARE(value.convert(mt), valueOK);
QCOMPARE(qvariant_cast<T>(value), result);
}
}
void tst_QVariant::toInt()
{
checkNumberConversions(&QVariant::toInt);
}
void tst_QVariant::toUInt_data()
{
QTest::addColumn<QVariant>("value");
QTest::addColumn<uint>("result");
QTest::addColumn<bool>("valueOK");
QTest::newRow( "int" ) << QVariant( 123 ) << (uint)123 << true;
QTest::newRow( "char" ) << QVariant::fromValue('a') << uint('a') << true;
signed char signedChar = 12;
QTest::newRow( "signed char" ) << QVariant::fromValue(signedChar) << uint(12) << true;
QTest::newRow( "double" ) << QVariant( 3.1415927 ) << (uint)3 << true;
QTest::newRow( "float" ) << QVariant( 3.1415927f ) << (uint)3 << true;
QTest::newRow( "uint" ) << QVariant( 123u ) << (uint)123 << true;
QTest::newRow( "int-string" ) << QVariant( QString("123") ) << (uint)123 << true;
QTest::newRow( "string" ) << QVariant( QString("Unicode String") ) << (uint)0 << false;
QTest::newRow( "string2" ) << QVariant( QString("4") ) << (uint)4 << true;
QTest::newRow( "longlong0" ) << QVariant( (qlonglong)34 ) << (uint)34 << true;
QTest::newRow( "longlong1" ) << QVariant( intMax1 ) << (uint)INT_MIN << true;
QTest::newRow( "ulonglong0" ) << QVariant( (qulonglong)34 ) << (uint)34 << true;
QTest::newRow( "ulonglong1" ) << QVariant( uintMax1 ) << (uint)0 << true;
QTest::newRow( "negativeint" ) << QVariant( -123 ) << (uint)-123 << true;
QTest::newRow( "negativedouble" ) << QVariant( -3.1415927 ) << (uint)-3 << true;
QTest::newRow( "negativefloat" ) << QVariant( -3.1415927f ) << (uint)-3 << true;
QTest::newRow( "negativeint-string" ) << QVariant( QString("-123") ) << (uint)0 << false;
QTest::newRow( "negativelonglong0" ) << QVariant( (qlonglong)-34 ) << (uint)-34 << true;
QTest::newRow( "QChar" ) << QVariant(QChar('a')) << uint('a') << true;
QByteArray bytearray(4, ' ');
bytearray[0] = '4';
bytearray[1] = '3';
bytearray[2] = '2';
bytearray[3] = '1';
QTest::newRow( "QByteArray" ) << QVariant( bytearray ) << (uint)4321 << true;
QTest::newRow("int-QJsonValue") << QVariant(QJsonValue(321)) << (uint)321 << true;
QTest::newRow("null-QJsonValue") << QVariant(QJsonValue(QJsonValue::Null)) << (uint)0 << false;
addNumberConversions<uint>();
}
void tst_QVariant::toUInt()
{
QFETCH( QVariant, value );
QFETCH( uint, result );
QFETCH( bool, valueOK );
QVERIFY( value.isValid() );
EXEC_DEPRECATED_CALL(QVERIFY( value.canConvert( QVariant::UInt ) );)
QVERIFY( value.canConvert(QMetaType::fromType<uint>()) );
bool ok;
uint i = value.toUInt( &ok );
QVERIFY( ok == valueOK );
QCOMPARE( i, result );
checkNumberConversions(&QVariant::toUInt);
}
void tst_QVariant::toSize_data()
{
QTest::addColumn<QVariant>("value");
@ -1120,6 +1159,8 @@ void tst_QVariant::toBool_data()
QTest::newRow( "Null_QChar" ) << QVariant(QChar(0)) << false;
QTest::newRow("QJsonValue(true)") << QVariant(QJsonValue(true)) << true;
QTest::newRow("QJsonValue(false)") << QVariant(QJsonValue(false)) << false;
QTest::newRow("QCborValue(true)") << QVariant::fromValue(QCborValue(true)) << true;
QTest::newRow("QCborValue(false)") << QVariant::fromValue(QCborValue(false)) << false;
}
void tst_QVariant::toBool()
@ -1132,6 +1173,9 @@ void tst_QVariant::toBool()
bool i = value.toBool();
QCOMPARE( i, result );
QVERIFY(value.convert(QMetaType::fromType<bool>()));
QCOMPARE(value.toBool(), result);
}
void tst_QVariant::toPointF_data()
@ -1176,170 +1220,103 @@ void tst_QVariant::toRectF()
void tst_QVariant::toDouble_data()
{
QTest::addColumn<QVariant>("value");
QTest::addColumn<double>("result");
QTest::addColumn<bool>("valueOK");
QByteArray bytearray(4, ' ');
bytearray[0] = '3';
bytearray[1] = '2';
bytearray[2] = '.';
bytearray[3] = '1';
QTest::newRow( "bytearray" ) << QVariant( bytearray ) << 32.1 << true;
QTest::newRow("double-QJsonValue") << QVariant(QJsonValue(32.1)) << 32.1 << true;
QTest::newRow("null-QJsonValue") << QVariant(QJsonValue(QJsonValue::Null)) << 0.0 << false;
addNumberConversions<double>();
}
void tst_QVariant::toDouble()
{
QFETCH( QVariant, value );
QFETCH( double, result );
QFETCH( bool, valueOK );
QVERIFY( value.isValid() );
EXEC_DEPRECATED_CALL(QVERIFY( value.canConvert( QVariant::Double ) );)
QVERIFY( value.canConvert(QMetaType::fromType<double>()) );
bool ok;
double d = value.toDouble( &ok );
QCOMPARE( d, result );
QVERIFY( ok == valueOK );
checkNumberConversions(&QVariant::toDouble);
}
void tst_QVariant::toFloat_data()
{
QTest::addColumn<QVariant>("value");
QTest::addColumn<float>("result");
QTest::addColumn<bool>("valueOK");
QByteArray bytearray(4, ' ');
bytearray[0] = '3';
bytearray[1] = '2';
bytearray[2] = '.';
bytearray[3] = '1';
QTest::newRow("QByteArray") << QVariant(bytearray) << float(32.1) << true;
QTest::newRow("double-QJsonValue") << QVariant(QJsonValue(32.1)) << float(32.1) << true;
QTest::newRow("undefined-QJsonValue") << QVariant(QJsonValue(QJsonValue::Undefined)) << float(0.0) << false;
addNumberConversions<float>();
}
void tst_QVariant::toFloat()
{
QFETCH(QVariant, value );
QFETCH(float, result);
QFETCH(bool, valueOK);
QVERIFY(value.isValid());
EXEC_DEPRECATED_CALL(QVERIFY(value.canConvert(QMetaType::Float));)
QVERIFY(value.canConvert(QMetaType::fromType<float>()));
bool ok;
float d = value.toFloat(&ok);
QCOMPARE(d, result);
QCOMPARE(ok, valueOK);
checkNumberConversions(&QVariant::toFloat);
}
void tst_QVariant::toSChar_data()
{
addNumberConversions<signed char>();
}
void tst_QVariant::toSChar()
{
checkNumberConversions<signed char>();
}
void tst_QVariant::toUChar_data()
{
addNumberConversions<uchar>();
}
void tst_QVariant::toUChar()
{
checkNumberConversions<uchar>();
}
void tst_QVariant::toShort_data()
{
addNumberConversions<short>();
}
void tst_QVariant::toShort()
{
checkNumberConversions<short>();
}
void tst_QVariant::toUShort_data()
{
addNumberConversions<ushort>();
}
void tst_QVariant::toUShort()
{
checkNumberConversions<ushort>();
}
void tst_QVariant::toLong_data()
{
addNumberConversions<long>();
}
void tst_QVariant::toLong()
{
checkNumberConversions<long>();
}
void tst_QVariant::toULong_data()
{
addNumberConversions<ulong>();
}
void tst_QVariant::toULong()
{
checkNumberConversions<ulong>();
}
void tst_QVariant::toLongLong_data()
{
QTest::addColumn<QVariant>("value");
QTest::addColumn<qlonglong>("result");
QTest::addColumn<bool>("valueOK");
addNumberConversions<qlonglong>();
QTest::newRow( "int0" ) << QVariant( 123 ) << (qlonglong)123 << true;
QTest::newRow( "double" ) << QVariant( 3.1415927 ) << (qlonglong)3 << true;
QTest::newRow( "float" ) << QVariant( 3.1415927f ) << (qlonglong)3 << true;
QTest::newRow( "uint" ) << QVariant( 123u ) << (qlonglong)123 << true;
QTest::newRow( "int-string" ) << QVariant( QString("123") )
<< (qlonglong)123 << true;
QTest::newRow( "string" ) << QVariant( QString("Unicode fun") ) << (qlonglong)0
<< false;
QTest::newRow( "longlong" ) << QVariant( intMax1 ) << intMax1 << true;
QTest::newRow( "ulonglong" ) << QVariant( uintMax1 ) << (qlonglong)uintMax1 << true;
QTest::newRow( "QChar" ) << QVariant(QChar('a')) << qlonglong('a') << true;
QByteArray bytearray(4, ' ');
bytearray[0] = '3';
bytearray[1] = '2';
bytearray[2] = '0';
bytearray[3] = '0';
QTest::newRow( "QByteArray" ) << QVariant( bytearray ) << (qlonglong) 3200 << true;
QTest::newRow("int-QJsonValue") << QVariant(QJsonValue(321)) << (qlonglong)321 << true;
QTest::newRow("string-QJsonValue") << QVariant(QJsonValue(QString("string"))) << (qlonglong)0 << false;
qint64 value64 = (Q_INT64_C(12) << 35) + 8;
QTest::newRow("qint64") << QVariant::fromValue(value64) << qlonglong(value64) << true;
QTest::newRow("-qint64") << QVariant::fromValue(-value64) << qlonglong(-value64) << true;
QTest::newRow("long") << QVariant::fromValue(long(464646)) << qlonglong(464646) << true;
QTest::newRow("LONG_MAX") << QVariant::fromValue( LONG_MAX ) << qlonglong(LONG_MAX) << true;
QTest::newRow("LONG_MIN") << QVariant::fromValue( LONG_MIN ) << qlonglong(LONG_MIN) << true;
QTest::newRow( "short" ) << QVariant(short(12)) << qlonglong(12) << true;
QTest::newRow( "-short" ) << QVariant(short(-24)) << qlonglong(-24) << true;
QTest::newRow( "ushort" ) << QVariant(ushort(15)) << qlonglong(15) << true;
}
void tst_QVariant::toLongLong()
{
QFETCH( QVariant, value );
QFETCH( qlonglong, result );
QFETCH( bool, valueOK );
QVERIFY( value.isValid() );
EXEC_DEPRECATED_CALL(QVERIFY( value.canConvert( QVariant::LongLong ) );)
QVERIFY( value.canConvert(QMetaType::fromType<qlonglong>()) );
bool ok;
qlonglong ll = value.toLongLong( &ok );
QCOMPARE( ll, result );
QVERIFY( ok == valueOK );
checkNumberConversions(&QVariant::toLongLong);
}
void tst_QVariant::toULongLong_data()
{
QTest::addColumn<QVariant>("value");
QTest::addColumn<qulonglong>("result");
QTest::addColumn<bool>("valueOK");
QTest::newRow( "int0" ) << QVariant( 123 ) << (qulonglong)123 << true;
QTest::newRow( "double" ) << QVariant( 3.1415927 ) << (qulonglong)3 << true;
QTest::newRow( "float" ) << QVariant( 3.1415927f ) << (qulonglong)3 << true;
QTest::newRow( "uint" ) << QVariant( 123u ) << (qulonglong)123 << true;
QTest::newRow( "int-string" ) << QVariant( QString("123") )
<< (qulonglong)123 << true;
QTest::newRow( "string" ) << QVariant( QString("Unicode fun") ) << (qulonglong)0
<< false;
QTest::newRow( "ulonglong-string" ) << QVariant( QString("18446744073709551615") )
<< Q_UINT64_C(18446744073709551615)
<< true;
QTest::newRow( "bytaa-string" ) << QVariant( QString("18446744073709551615") )
<< Q_UINT64_C(18446744073709551615)
<< true;
QTest::newRow( "longlong" ) << QVariant( intMax1 ) << (qulonglong)intMax1 << true;
QTest::newRow( "ulonglong" ) << QVariant( uintMax1 ) << uintMax1 << true;
QTest::newRow( "QChar" ) << QVariant(QChar('a')) << qulonglong('a') << true;
QByteArray bytearray(4, ' ');
bytearray[0] = '3';
bytearray[1] = '2';
bytearray[2] = '0';
bytearray[3] = '1';
QTest::newRow( "QByteArray" ) << QVariant( bytearray ) << (qulonglong) 3201 << true;
QTest::newRow("int-QJsonValue") << QVariant(QJsonValue(321)) << (qulonglong)321 << true;
QTest::newRow("bool-QJsonValue") << QVariant(QJsonValue(true)) << (qulonglong)0 << false;
quint64 value64 = (Q_INT64_C(12) << 35) + 8;
QTest::newRow("qint64") << QVariant::fromValue(value64) << qulonglong(value64) << true;
QTest::newRow("long") << QVariant::fromValue(long(464646)) << qulonglong(464646) << true;
QTest::newRow("LONG_MAX") << QVariant::fromValue( LONG_MAX ) << qulonglong(LONG_MAX) << true;
QTest::newRow("ULONG_MAX") << QVariant::fromValue( ULONG_MAX ) << qulonglong(ULONG_MAX) << true;
QTest::newRow( "short" ) << QVariant(short(12)) << qulonglong(12) << true;
QTest::newRow( "-short" ) << QVariant(short(-24)) << qulonglong(-24) << true;
QTest::newRow( "ushort" ) << QVariant(ushort(15)) << qulonglong(15) << true;
addNumberConversions<qulonglong>();
}
void tst_QVariant::toULongLong()
{
QFETCH( QVariant, value );
QFETCH( qulonglong, result );
QFETCH( bool, valueOK );
QVERIFY( value.isValid() );
EXEC_DEPRECATED_CALL(QVERIFY( value.canConvert( QVariant::ULongLong ) );)
QVERIFY( value.canConvert(QMetaType::fromType<qulonglong>()) );
bool ok;
qulonglong ll = value.toULongLong( &ok );
QCOMPARE( ll, result );
QVERIFY( ok == valueOK );
checkNumberConversions(&QVariant::toULongLong);
}
void tst_QVariant::toByteArray_data()