QMetaType: add a test to confirm that types are equal across libraries

Because of the template shenanigans. This is just to make sure.

Pick-to: 6.4
Change-Id: Id0fb9ab0089845ee8843fffd16f989e7d555894f
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Thiago Macieira 2022-06-17 15:46:06 -07:00
parent bbcdee2afa
commit 985e24dd5f
7 changed files with 193 additions and 5 deletions

View File

@ -10,6 +10,35 @@
# Collect test data
list(APPEND test_data "./typeFlags.bin")
qt_internal_add_cmake_library(qmetatype_lib1
INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qmetatype"
SOURCES
lib1.cpp
PUBLIC_LIBRARIES
Qt::Core
)
qt_internal_add_cmake_library(qmetatype_lib2
INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qmetatype"
SOURCES
lib2.cpp
PUBLIC_LIBRARIES
Qt::Core
)
set_target_properties(qmetatype_lib1 PROPERTIES
VERSION 1.0.0
SOVERSION 0
C_VISIBILITY_PRESET "hidden"
CXX_VISIBILITY_PRESET "hidden"
VISIBILITY_INLINES_HIDDEN ON
)
set_target_properties(qmetatype_lib2 PROPERTIES
VERSION 1.0.0
SOVERSION 0
C_VISIBILITY_PRESET "hidden"
CXX_VISIBILITY_PRESET "hidden"
VISIBILITY_INLINES_HIDDEN ON
)
qt_internal_add_test(tst_qmetatype
SOURCES
tst_qmetatype.h tst_qmetatype.cpp tst_qmetatype2.cpp
@ -21,6 +50,8 @@ qt_internal_add_test(tst_qmetatype
LIBRARIES
Qt::CorePrivate
Qt::Gui
qmetatype_lib1
qmetatype_lib2
TESTDATA ${test_data}
)
@ -28,7 +59,3 @@ qt_internal_extend_target(tst_qmetatype CONDITION MSVC
COMPILE_OPTIONS
/bigobj
)
#### Keys ignored in scope 3:.:.:qmetatype.pro:CLANG:
# QMAKE_CFLAGS_RELEASE = "--O2" "--g"
# QMAKE_CXXFLAGS_RELEASE = "--O2" "--g"

View File

@ -0,0 +1,5 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#define LIB_NAMESPACE Lib1
#include "lib_common.cpp"

View File

@ -0,0 +1,5 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#define LIB_NAMESPACE Lib2
#include "lib_common.cpp"

View File

@ -0,0 +1,13 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qcollator.h>
#include "tst_qmetatype_libs.h"
#define DECLARE_FUNCTION(TYPE, ID) \
Q_DECL_EXPORT QMetaType metatype_ ## TYPE() \
{ return QMetaType::fromType<TYPE>(); }
namespace LIB_NAMESPACE {
FOR_EACH_METATYPE_LIBS(DECLARE_FUNCTION)
}

View File

@ -108,6 +108,10 @@ private slots:
void fromType();
void operatorEq_data();
void operatorEq();
void operatorEq2_data();
void operatorEq2();
void operatorEqAcrossLibs_data();
void operatorEqAcrossLibs();
void typesWithInaccessibleDTors();
void voidIsNotUnknown();
void typeNameNormalization();

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "tst_qmetatype.h"
#include "tst_qvariant_common.h"
#include "tst_qmetatype_libs.h"
#include <QtCore/private/qmetaobjectbuilder_p.h>
@ -412,6 +412,116 @@ void tst_QMetaType::operatorEq()
QCOMPARE(typeB == typeA, eq);
QCOMPARE(typeA != typeB, !eq);
QCOMPARE(typeB != typeA, !eq);
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
// for built-in types or locally-defined types, this must also hold true
if (eq)
QCOMPARE(typeA.iface(), typeB.iface());
#endif
}
void tst_QMetaType::operatorEq2_data()
{
create_data();
}
void tst_QMetaType::operatorEq2()
{
QFETCH(int, type);
QMetaType fromType1, fromType2;
QMetaType fromId1(type), fromId2(type);
switch (type) {
case QMetaType::UnknownType:
break;
#define GET_METATYPE_FROM_TYPE(MetaTypeName, MetaTypeId, RealType) \
case QMetaType::MetaTypeName: \
fromType1 = QMetaType::fromType<RealType>(); \
fromType2 = QMetaType::fromType<RealType>(); \
break;
FOR_EACH_CORE_METATYPE(GET_METATYPE_FROM_TYPE)
#undef GET_METATYPE_FROM_TYPE
}
// sanity check
QCOMPARE(fromId1.id(), type);
QCOMPARE(fromId2.id(), type);
// confirm that they're all equal
QCOMPARE(fromId1, fromId2);
QCOMPARE(fromType1, fromType2);
QCOMPARE(fromType1, fromId1);
QCOMPARE(fromType2, fromId2);
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
// for built-in types (other than void), this must be true
if (type != QMetaType::Void) {
QCOMPARE(fromType1.iface(), fromId1.iface());
QCOMPARE(fromType2.iface(), fromId1.iface());
}
#endif
}
#define DECLARE_LIB_FUNCTION(TYPE, ID) \
Q_DECL_IMPORT QMetaType metatype_ ## TYPE();
namespace Lib1 { FOR_EACH_METATYPE_LIBS(DECLARE_LIB_FUNCTION) }
namespace Lib2 { FOR_EACH_METATYPE_LIBS(DECLARE_LIB_FUNCTION) }
#undef DECLARE_LIB_FUNCTION
using LibMetatypeFunction = QMetaType (*)();
void tst_QMetaType::operatorEqAcrossLibs_data()
{
QTest::addColumn<int>("builtinTypeId");
QTest::addColumn<QMetaType>("localType");
QTest::addColumn<LibMetatypeFunction>("lib1Function");
QTest::addColumn<LibMetatypeFunction>("lib2Function");
#define ADD_ROW(TYPE, ID) \
QTest::addRow(QT_STRINGIFY(TYPE)) << int(ID) \
<< QMetaType::fromType<TYPE>() \
<< &Lib1::metatype_ ## TYPE \
<< &Lib2::metatype_ ## TYPE;
FOR_EACH_METATYPE_LIBS(ADD_ROW)
#undef ADD_ROW
}
void tst_QMetaType::operatorEqAcrossLibs()
{
QFETCH(int, builtinTypeId);
QFETCH(QMetaType, localType);
QFETCH(LibMetatypeFunction, lib1Function);
QFETCH(LibMetatypeFunction, lib2Function);
QMetaType lib1Type = lib1Function();
QMetaType lib2Type = lib2Function();
const QtPrivate::QMetaTypeInterface *localIface = localType.iface();
const QtPrivate::QMetaTypeInterface *lib1Iface = lib1Type.iface();
const QtPrivate::QMetaTypeInterface *lib2Iface = lib2Type.iface();
// DO THIS FIRST:
// if this isn't a built-in type, then the QMetaTypeInterface::typeId is
// initially set to 0
QCOMPARE(lib1Type, lib2Type);
int actualTypeId = localType.id();
bool builtinTypeExpected = builtinTypeId != QMetaType::UnknownType;
bool builtinTypeActually = actualTypeId < QMetaType::User;
qDebug() << "QMetaType for type" << QByteArray(localType.name())
<< "(type ID" << (actualTypeId >= 0x1000 ? Qt::hex : Qt::dec) << actualTypeId << ')'
<< (builtinTypeActually ? "IS" : "is NOT") << "a built-in type;"
<< "local interface:" << static_cast<const void *>(localIface)
<< "lib1 interface:" << static_cast<const void *>(lib1Iface)
<< "lib2 interface:" << static_cast<const void *>(lib2Iface);
QCOMPARE(builtinTypeActually, builtinTypeExpected);
QCOMPARE(lib1Type.id(), actualTypeId);
QCOMPARE(lib2Type.id(), actualTypeId);
QCOMPARE(QByteArray(lib1Type.name()), QByteArray(localType.name()));
QCOMPARE(QByteArray(lib2Type.name()), QByteArray(localType.name()));
QCOMPARE(lib1Type, localType);
QCOMPARE(lib2Type, localType);
}
class WithPrivateDTor {

View File

@ -0,0 +1,24 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef TST_QMETATYPE_LIBS_H
#define TST_QMETATYPE_LIBS_H
#include <qmetatype.h>
#include <stdlib.h> // for div_t
// void: builtin metatype, special
// int: builtin metatype, primitive type
// QString: builtin metatype, class
// QCollator: not builtin, class, Q_CORE_EXPORT
// div_t: not builtin, class, no export
#define FOR_EACH_METATYPE_LIBS(F) \
F(void, QMetaType::Void) \
F(int, QMetaType::Int) \
F(QString, QMetaType::QString) \
F(QCollator, QMetaType::UnknownType) \
F(div_t, QMetaType::UnknownType) \
/**/
#endif // TST_QMETATYPE_LIBS_H