qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,23 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT INTEGRITY)
add_subdirectory(qcompare)
endif()
add_subdirectory(qflags)
add_subdirectory(q_func_info)
add_subdirectory(qgetputenv)
add_subdirectory(qglobal)
add_subdirectory(qnumeric)
add_subdirectory(qfloat16)
add_subdirectory(qkeycombination)
if(NOT INTEGRITY)
add_subdirectory(qnativeinterface)
endif()
add_subdirectory(qrandomgenerator)
add_subdirectory(qlogging)
add_subdirectory(qtendian)
add_subdirectory(qglobalstatic)
add_subdirectory(qhooks)
add_subdirectory(qoperatingsystemversion)
add_subdirectory(qxp)

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_q_func_info Test:
#####################################################################
qt_internal_add_test(tst_q_func_info
SOURCES
tst_q_func_info.cpp
)

View File

@ -0,0 +1,106 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QString>
#include <QTest>
#include <QtDebug>
class tst_q_func_info : public QObject
{
Q_OBJECT
private slots:
void callFunctions() const;
void isOfTypeConstChar() const;
void availableWithoutDebug() const;
private:
static void staticMember();
void regularMember() const;
void memberWithArguments(const QString &string, int value, const int value2) const;
};
static void staticRegularFunction()
{
qDebug() << Q_FUNC_INFO;
}
void regularFunction()
{
qDebug() << Q_FUNC_INFO;
}
template<typename T>
void templateFunction()
{
qDebug() << Q_FUNC_INFO;
}
template<typename T, const int value>
void valueTemplateFunction()
{
qDebug() << Q_FUNC_INFO;
}
void tst_q_func_info::staticMember()
{
qDebug() << Q_FUNC_INFO;
}
void tst_q_func_info::regularMember() const
{
qDebug() << Q_FUNC_INFO;
}
void tst_q_func_info::memberWithArguments(const QString &, int, const int) const
{
qDebug() << Q_FUNC_INFO;
}
/*! \internal
We don't do much here. We call different kinds of
functions to make sure we don't crash anything or that valgrind
is unhappy.
*/
void tst_q_func_info::callFunctions() const
{
staticRegularFunction();
regularFunction();
templateFunction<char>();
valueTemplateFunction<int, 3>();
staticMember();
regularMember();
memberWithArguments(QString(), 3, 4);
}
void tst_q_func_info::isOfTypeConstChar() const
{
#ifndef QT_NO_DEBUG
QString::fromLatin1(Q_FUNC_INFO);
#endif
}
/* \internal
Ensure that the macro is available even though QT_NO_DEBUG
is defined. If QT_NO_DEBUG is not defined, we define it
just for this function then undef it again afterwards.
*/
void tst_q_func_info::availableWithoutDebug() const
{
#ifndef QT_NO_DEBUG
# define UNDEF_NO_DEBUG
# define QT_NO_DEBUG
#endif
QVERIFY(!QString::fromLatin1(Q_FUNC_INFO).isEmpty());
#ifdef UNDEF_NO_DEBUG
# undef QT_NO_DEBUG
# undef UNDEF_NO_DEBUG
#endif
}
QTEST_MAIN(tst_q_func_info)
#include "tst_q_func_info.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qcompare Test:
#####################################################################
qt_internal_add_test(tst_qcompare
SOURCES
tst_qcompare.cpp
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,98 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/QtCompare>
#include <QtTest/QTest>
class tst_QCompare: public QObject
{
Q_OBJECT
private slots:
void partialOrdering();
};
void tst_QCompare::partialOrdering()
{
static_assert(QPartialOrdering::Unordered == QPartialOrdering::Unordered);
static_assert(QPartialOrdering::Unordered != QPartialOrdering::Less);
static_assert(QPartialOrdering::Unordered != QPartialOrdering::Equivalent);
static_assert(QPartialOrdering::Unordered != QPartialOrdering::Greater);
static_assert(QPartialOrdering::Less != QPartialOrdering::Unordered);
static_assert(QPartialOrdering::Less == QPartialOrdering::Less);
static_assert(QPartialOrdering::Less != QPartialOrdering::Equivalent);
static_assert(QPartialOrdering::Less != QPartialOrdering::Greater);
static_assert(QPartialOrdering::Equivalent != QPartialOrdering::Unordered);
static_assert(QPartialOrdering::Equivalent != QPartialOrdering::Less);
static_assert(QPartialOrdering::Equivalent == QPartialOrdering::Equivalent);
static_assert(QPartialOrdering::Equivalent != QPartialOrdering::Greater);
static_assert(QPartialOrdering::Greater != QPartialOrdering::Unordered);
static_assert(QPartialOrdering::Greater != QPartialOrdering::Less);
static_assert(QPartialOrdering::Greater != QPartialOrdering::Equivalent);
static_assert(QPartialOrdering::Greater == QPartialOrdering::Greater);
static_assert(!(QPartialOrdering::Unordered == 0));
static_assert(!(QPartialOrdering::Unordered != 0));
static_assert(!(QPartialOrdering::Unordered < 0));
static_assert(!(QPartialOrdering::Unordered <= 0));
static_assert(!(QPartialOrdering::Unordered > 0));
static_assert(!(QPartialOrdering::Unordered >= 0));
static_assert(!(0 == QPartialOrdering::Unordered));
static_assert(!(0 != QPartialOrdering::Unordered));
static_assert(!(0 < QPartialOrdering::Unordered));
static_assert(!(0 <= QPartialOrdering::Unordered));
static_assert(!(0 > QPartialOrdering::Unordered));
static_assert(!(0 >= QPartialOrdering::Unordered));
static_assert(!(QPartialOrdering::Less == 0));
static_assert( (QPartialOrdering::Less != 0));
static_assert( (QPartialOrdering::Less < 0));
static_assert( (QPartialOrdering::Less <= 0));
static_assert(!(QPartialOrdering::Less > 0));
static_assert(!(QPartialOrdering::Less >= 0));
static_assert(!(0 == QPartialOrdering::Less));
static_assert( (0 != QPartialOrdering::Less));
static_assert(!(0 < QPartialOrdering::Less));
static_assert(!(0 <= QPartialOrdering::Less));
static_assert( (0 > QPartialOrdering::Less));
static_assert( (0 >= QPartialOrdering::Less));
static_assert( (QPartialOrdering::Equivalent == 0));
static_assert(!(QPartialOrdering::Equivalent != 0));
static_assert(!(QPartialOrdering::Equivalent < 0));
static_assert( (QPartialOrdering::Equivalent <= 0));
static_assert(!(QPartialOrdering::Equivalent > 0));
static_assert( (QPartialOrdering::Equivalent >= 0));
static_assert( (0 == QPartialOrdering::Equivalent));
static_assert(!(0 != QPartialOrdering::Equivalent));
static_assert(!(0 < QPartialOrdering::Equivalent));
static_assert( (0 <= QPartialOrdering::Equivalent));
static_assert(!(0 > QPartialOrdering::Equivalent));
static_assert( (0 >= QPartialOrdering::Equivalent));
static_assert(!(QPartialOrdering::Greater == 0));
static_assert( (QPartialOrdering::Greater != 0));
static_assert(!(QPartialOrdering::Greater < 0));
static_assert(!(QPartialOrdering::Greater <= 0));
static_assert( (QPartialOrdering::Greater > 0));
static_assert( (QPartialOrdering::Greater >= 0));
static_assert(!(0 == QPartialOrdering::Greater));
static_assert( (0 != QPartialOrdering::Greater));
static_assert( (0 < QPartialOrdering::Greater));
static_assert( (0 <= QPartialOrdering::Greater));
static_assert(!(0 > QPartialOrdering::Greater));
static_assert(!(0 >= QPartialOrdering::Greater));
}
QTEST_MAIN(tst_QCompare)
#include "tst_qcompare.moc"

View File

@ -0,0 +1,18 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qflags Test:
#####################################################################
qt_internal_add_test(tst_qflags
SOURCES
tst_qflags.cpp
)
qt_internal_add_test(tst_qflags_non_typesafe
SOURCES
tst_qflags.cpp
DEFINES
QFLAGS_TEST_NO_TYPESAFE_FLAGS
)

View File

@ -0,0 +1,481 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifdef QFLAGS_TEST_NO_TYPESAFE_FLAGS
# ifdef QT_TYPESAFE_FLAGS
# undef QT_TYPESAFE_FLAGS
# endif
#else
# ifndef QT_TYPESAFE_FLAGS
# define QT_TYPESAFE_FLAGS
# endif
#endif
#include <QTest>
class tst_QFlags: public QObject
{
Q_OBJECT
private slots:
void boolCasts() const;
void operators() const;
void mixingDifferentEnums() const;
void testFlag() const;
void testFlagZeroFlag() const;
void testFlagMultiBits() const;
void testFlags();
void testAnyFlag();
void constExpr();
void signedness();
void classEnum();
void initializerLists();
void testSetFlags();
void adl();
};
void tst_QFlags::boolCasts() const
{
// This tests that the operator overloading is sufficient so that common
// idioms involving flags -> bool casts work as expected:
const Qt::Alignment nonNull = Qt::AlignCenter;
const Qt::Alignment null = {};
// basic premiss:
QVERIFY(bool(nonNull));
QVERIFY(!bool(null));
// The rest is just checking that stuff compiles:
// QVERIFY should compile:
QVERIFY(nonNull);
QVERIFY(!null);
// ifs should compile:
if (null) QFAIL("Can't contextually convert QFlags to bool!");
if (!nonNull) QFAIL("Missing operator! on QFlags (shouldn't be necessary).");
// ternary should compile:
QVERIFY(nonNull ? true : false);
QVERIFY(!null ? true : false);
// logical operators should compile:
QVERIFY(nonNull && true);
QVERIFY(nonNull || false);
QVERIFY(!null && true);
QVERIFY(!null || false);
// ... in both directions:
QVERIFY(true && nonNull);
QVERIFY(false || nonNull);
QVERIFY(true && !null);
QVERIFY(false || !null);
// ... and mixed:
QVERIFY(null || nonNull);
QVERIFY(!(null && nonNull));
}
void tst_QFlags::operators() const
{
#define CHECK(op, LHS, RHS, RES) \
do { \
QCOMPARE((LHS op RHS), (RES)); \
QCOMPARE(( /*CTAD*/ QFlags(LHS) op RHS), (RES)); \
QCOMPARE((LHS op QFlags(RHS)), (RES)); \
QCOMPARE((QFlags(LHS) op QFlags(RHS)), (RES)); \
QCOMPARE((QFlags(LHS) op ## = RHS), (RES)); \
QCOMPARE((QFlags(LHS) op ## = QFlags(RHS)), (RES)); \
} while (false)
CHECK(|, Qt::AlignHCenter, Qt::AlignVCenter, Qt::AlignCenter);
CHECK(|, Qt::AlignHCenter, Qt::AlignHCenter, Qt::AlignHCenter);
CHECK(&, Qt::AlignHCenter, Qt::AlignVCenter, Qt::Alignment());
CHECK(&, Qt::AlignHCenter, Qt::AlignHCenter, Qt::AlignHCenter);
CHECK(^, Qt::AlignHCenter, Qt::AlignVCenter, Qt::AlignCenter);
CHECK(^, Qt::AlignHCenter, Qt::AlignHCenter, Qt::Alignment());
#undef CHECK
}
void tst_QFlags::mixingDifferentEnums() const
{
#define CHECK(op, LHS, RHS, RES) \
/* LHS must be QFlags'able */ \
do { \
QCOMPARE((LHS op RHS), (RES)); \
QCOMPARE((RHS op LHS), (RES)); \
/*QCOMPARE(( / *CTAD* / QFlags(LHS) op RHS), (RES));*/ \
/*QCOMPARE((QFlags(LHS) op ## = RHS), (RES));*/ \
} while (false)
// AlignmentFlags <-> TextFlags
{
CHECK(|, Qt::AlignCenter, Qt::TextSingleLine, 0x0184);
CHECK(&, Qt::AlignCenter, Qt::TextSingleLine, 0x0000);
CHECK(^, Qt::AlignCenter, Qt::TextSingleLine, 0x0184);
}
// QFlags<AlignmentFlags> <-> TextFlags
{
#ifndef QT_TYPESAFE_FLAGS // QTBUG-101344
Qt::Alignment MyAlignCenter = Qt::AlignCenter; // convert enum to QFlags
CHECK(|, MyAlignCenter, Qt::TextSingleLine, 0x0184U); // yes, unsigned!
CHECK(&, MyAlignCenter, Qt::TextSingleLine, 0x0000U); // yes, unsigned!
CHECK(^, MyAlignCenter, Qt::TextSingleLine, 0x0184U); // yes, unsigned!
#endif
}
// TextElideMode <-> TextFlags
{
CHECK(|, Qt::ElideNone, Qt::TextSingleLine, 0x0103);
CHECK(&, Qt::ElideNone, Qt::TextSingleLine, 0x0000);
CHECK(^, Qt::ElideNone, Qt::TextSingleLine, 0x0103);
}
#undef CHECK
}
void tst_QFlags::testFlag() const
{
Qt::MouseButtons btn = Qt::LeftButton | Qt::RightButton;
QVERIFY(btn.testFlag(Qt::LeftButton));
QVERIFY(!btn.testFlag(Qt::MiddleButton));
btn = { };
QVERIFY(!btn.testFlag(Qt::LeftButton));
}
void tst_QFlags::testFlagZeroFlag() const
{
{
Qt::MouseButtons btn = Qt::LeftButton | Qt::RightButton;
/* Qt::NoButton has the value 0. */
QVERIFY(!btn.testFlag(Qt::NoButton));
}
{
/* A zero enum set should test true with zero. */
QVERIFY(Qt::MouseButtons().testFlag(Qt::NoButton));
}
{
Qt::MouseButtons btn = Qt::NoButton;
QVERIFY(btn.testFlag(Qt::NoButton));
}
}
void tst_QFlags::testFlagMultiBits() const
{
/* Qt::Window is 0x00000001
* Qt::Dialog is 0x00000002 | Window
*/
{
const Qt::WindowFlags onlyWindow(Qt::Window);
QVERIFY(!onlyWindow.testFlag(Qt::Dialog));
}
{
const Qt::WindowFlags hasDialog(Qt::Dialog);
QVERIFY(hasDialog.testFlag(Qt::Dialog));
}
}
void tst_QFlags::testFlags()
{
using Int = Qt::TextInteractionFlags::Int;
constexpr Int Zero(0);
Qt::TextInteractionFlags flags;
QCOMPARE(flags.toInt(), Zero);
QVERIFY(flags.testFlags(flags));
QVERIFY(Qt::TextInteractionFlags::fromInt(Zero).testFlags(flags));
QVERIFY(!flags.testFlags(Qt::TextSelectableByMouse));
QVERIFY(!flags.testFlags(Qt::TextSelectableByKeyboard));
QVERIFY(!flags.testFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard));
QVERIFY(flags.testFlags(Qt::TextInteractionFlags::fromInt(Zero)));
QVERIFY(flags.testFlags(Qt::TextInteractionFlags(Qt::TextSelectableByMouse) & ~Qt::TextSelectableByMouse));
flags = Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard;
QVERIFY(flags.toInt() != Zero);
QVERIFY(flags.testFlags(flags));
QVERIFY(flags.testFlags(Qt::TextSelectableByMouse));
QVERIFY(flags.testFlags(Qt::TextSelectableByKeyboard));
QVERIFY(flags.testFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse));
QVERIFY(!flags.testFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse | Qt::TextEditable));
QVERIFY(!flags.testFlags(Qt::TextInteractionFlags()));
QVERIFY(!flags.testFlags(Qt::TextInteractionFlags::fromInt(Zero)));
QVERIFY(!flags.testFlags(Qt::TextEditable));
QVERIFY(!flags.testFlags(Qt::TextSelectableByMouse | Qt::TextEditable));
}
void tst_QFlags::testAnyFlag()
{
Qt::TextInteractionFlags flags;
QVERIFY(!flags.testAnyFlags(Qt::NoTextInteraction));
QVERIFY(!flags.testAnyFlags(Qt::TextSelectableByMouse));
QVERIFY(!flags.testAnyFlags(Qt::TextSelectableByKeyboard));
QVERIFY(!flags.testAnyFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard));
QVERIFY(!flags.testAnyFlag(Qt::TextEditorInteraction));
QVERIFY(!flags.testAnyFlag(Qt::TextBrowserInteraction));
flags = Qt::TextSelectableByMouse;
QVERIFY(!flags.testAnyFlags(Qt::NoTextInteraction));
QVERIFY(flags.testAnyFlags(Qt::TextSelectableByMouse));
QVERIFY(!flags.testAnyFlags(Qt::TextSelectableByKeyboard));
QVERIFY(flags.testAnyFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard));
QVERIFY(flags.testAnyFlag(Qt::TextEditorInteraction));
QVERIFY(flags.testAnyFlag(Qt::TextBrowserInteraction));
flags = Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard;
QVERIFY(!flags.testAnyFlags(Qt::NoTextInteraction));
QVERIFY(flags.testAnyFlags(Qt::TextSelectableByMouse));
QVERIFY(flags.testAnyFlags(Qt::TextSelectableByKeyboard));
QVERIFY(flags.testAnyFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard));
QVERIFY(flags.testAnyFlag(Qt::TextEditorInteraction));
QVERIFY(flags.testAnyFlag(Qt::TextEditorInteraction));
QVERIFY(flags.testAnyFlag(Qt::TextBrowserInteraction));
}
template <unsigned int N, typename T> bool verifyConstExpr(T n) { return n == N; }
template <unsigned int N, typename T> bool verifyConstExpr(QFlags<T> n) { return n.toInt() == N; }
constexpr Qt::MouseButtons testRelaxedConstExpr()
{
Qt::MouseButtons value;
value = Qt::LeftButton | Qt::RightButton;
value |= Qt::MiddleButton;
value &= ~Qt::LeftButton;
value ^= Qt::RightButton;
return value;
}
void tst_QFlags::constExpr()
{
Qt::MouseButtons btn = Qt::LeftButton | Qt::RightButton;
switch (btn.toInt()) {
case Qt::LeftButton: QVERIFY(false); break;
case Qt::RightButton: QVERIFY(false); break;
case (Qt::LeftButton | Qt::RightButton).toInt(): QVERIFY(true); break;
default: QFAIL(qPrintable(QStringLiteral("Unexpected button: %1").arg(btn.toInt())));
}
#define VERIFY_CONSTEXPR(expression, expected) \
QVERIFY(verifyConstExpr<(expression).toInt()>(expected))
VERIFY_CONSTEXPR((Qt::LeftButton | Qt::RightButton) & Qt::LeftButton, Qt::LeftButton);
VERIFY_CONSTEXPR((Qt::LeftButton | Qt::RightButton) & Qt::MiddleButton, 0);
VERIFY_CONSTEXPR((Qt::LeftButton | Qt::RightButton) | Qt::MiddleButton, Qt::LeftButton | Qt::RightButton | Qt::MiddleButton);
VERIFY_CONSTEXPR(~(Qt::LeftButton | Qt::RightButton), ~(Qt::LeftButton | Qt::RightButton));
VERIFY_CONSTEXPR(Qt::MouseButtons(Qt::LeftButton) ^ Qt::RightButton, Qt::LeftButton ^ Qt::RightButton);
VERIFY_CONSTEXPR(Qt::MouseButtons(0), 0);
#ifndef QT_TYPESAFE_FLAGS
QVERIFY(verifyConstExpr<(Qt::MouseButtons(Qt::RightButton) & 0xff)>(Qt::RightButton));
QVERIFY(verifyConstExpr<(Qt::MouseButtons(Qt::RightButton) | 0xff)>(0xff));
#endif
QVERIFY(!verifyConstExpr<Qt::RightButton>(~Qt::MouseButtons(Qt::LeftButton)));
VERIFY_CONSTEXPR(testRelaxedConstExpr(), Qt::MiddleButton);
#undef VERIFY_CONSTEXPR
}
void tst_QFlags::signedness()
{
// these are all 'true' on GCC, but since the std says the
// underlying type is implementation-defined, we need to allow for
// a different signedness, so we only check that the relative
// signedness of the types matches:
static_assert((std::is_unsigned<typename std::underlying_type<Qt::MouseButton>::type>::value ==
std::is_unsigned<Qt::MouseButtons::Int>::value));
static_assert((std::is_signed<typename std::underlying_type<Qt::AlignmentFlag>::type>::value ==
std::is_signed<Qt::Alignment::Int>::value));
}
enum class MyStrictEnum { StrictZero, StrictOne, StrictTwo, StrictFour=4 };
Q_DECLARE_FLAGS( MyStrictFlags, MyStrictEnum )
Q_DECLARE_OPERATORS_FOR_FLAGS( MyStrictFlags )
enum class MyStrictNoOpEnum { StrictZero, StrictOne, StrictTwo, StrictFour=4 };
Q_DECLARE_FLAGS( MyStrictNoOpFlags, MyStrictNoOpEnum )
static_assert( !QTypeInfo<MyStrictFlags>::isComplex );
static_assert( QTypeInfo<MyStrictFlags>::isRelocatable );
static_assert( !QTypeInfo<MyStrictFlags>::isPointer );
void tst_QFlags::classEnum()
{
// The main aim of the test is making sure it compiles
// The QCOMPARE are there as an extra
MyStrictEnum e1 = MyStrictEnum::StrictOne;
MyStrictEnum e2 = MyStrictEnum::StrictTwo;
MyStrictFlags f1(MyStrictEnum::StrictOne);
QCOMPARE(f1, 1);
MyStrictFlags f2(e2);
QCOMPARE(f2, 2);
MyStrictFlags f0;
QCOMPARE(f0, 0);
MyStrictFlags f3(e2 | e1);
QCOMPARE(f3, 3);
QVERIFY(f3.testFlag(MyStrictEnum::StrictOne));
QVERIFY(!f1.testFlag(MyStrictEnum::StrictTwo));
QVERIFY(!f0);
#ifndef QT_TYPESAFE_FLAGS
QCOMPARE(f3 & int(1), 1);
QCOMPARE(f3 & uint(1), 1);
#endif
QCOMPARE(f3 & MyStrictEnum::StrictOne, 1);
MyStrictFlags aux;
#ifndef QT_TYPESAFE_FLAGS
aux = f3;
aux &= int(1);
QCOMPARE(aux, 1);
aux = f3;
aux &= uint(1);
QCOMPARE(aux, 1);
#endif
aux = f3;
aux &= MyStrictEnum::StrictOne;
QCOMPARE(aux, 1);
aux = f3;
aux &= f1;
QCOMPARE(aux, 1);
aux = f3 ^ f3;
QCOMPARE(aux, 0);
aux = f3 ^ f1;
QCOMPARE(aux, 2);
aux = f3 ^ f0;
QCOMPARE(aux, 3);
aux = f3 ^ MyStrictEnum::StrictOne;
QCOMPARE(aux, 2);
aux = f3 ^ MyStrictEnum::StrictZero;
QCOMPARE(aux, 3);
aux = f3;
aux ^= f3;
QCOMPARE(aux, 0);
aux = f3;
aux ^= f1;
QCOMPARE(aux, 2);
aux = f3;
aux ^= f0;
QCOMPARE(aux, 3);
aux = f3;
aux ^= MyStrictEnum::StrictOne;
QCOMPARE(aux, 2);
aux = f3;
aux ^= MyStrictEnum::StrictZero;
QCOMPARE(aux, 3);
aux = f1 | f2;
QCOMPARE(aux, 3);
aux = MyStrictEnum::StrictOne | MyStrictEnum::StrictTwo;
QCOMPARE(aux, 3);
aux = f1;
aux |= f2;
QCOMPARE(aux, 3);
aux = MyStrictEnum::StrictOne;
aux |= MyStrictEnum::StrictTwo;
QCOMPARE(aux, 3);
aux = ~f1;
QCOMPARE(aux, -2);
// Just to make sure it compiles
if (false)
qDebug() << f3;
}
void tst_QFlags::initializerLists()
{
Qt::MouseButtons bts = { Qt::LeftButton, Qt::RightButton };
QVERIFY(bts.testFlag(Qt::LeftButton));
QVERIFY(bts.testFlag(Qt::RightButton));
QVERIFY(!bts.testFlag(Qt::MiddleButton));
MyStrictNoOpFlags flags = { MyStrictNoOpEnum::StrictOne, MyStrictNoOpEnum::StrictFour };
QVERIFY(flags.testFlag(MyStrictNoOpEnum::StrictOne));
QVERIFY(flags.testFlag(MyStrictNoOpEnum::StrictFour));
QVERIFY(!flags.testFlag(MyStrictNoOpEnum::StrictTwo));
}
void tst_QFlags::testSetFlags()
{
Qt::MouseButtons btn = Qt::NoButton;
btn.setFlag(Qt::LeftButton);
QVERIFY(btn.testFlag(Qt::LeftButton));
QVERIFY(!btn.testFlag(Qt::MiddleButton));
btn.setFlag(Qt::LeftButton, false);
QVERIFY(!btn.testFlag(Qt::LeftButton));
QVERIFY(!btn.testFlag(Qt::MiddleButton));
MyStrictFlags flags;
flags.setFlag(MyStrictEnum::StrictOne);
flags.setFlag(MyStrictEnum::StrictTwo, true);
QVERIFY(flags.testFlag(MyStrictEnum::StrictOne));
QVERIFY(flags.testFlag(MyStrictEnum::StrictTwo));
QVERIFY(!flags.testFlag(MyStrictEnum::StrictFour));
flags.setFlag(MyStrictEnum::StrictTwo, false);
QVERIFY(flags.testFlag(MyStrictEnum::StrictOne));
QVERIFY(!flags.testFlag(MyStrictEnum::StrictTwo));
QVERIFY(!flags.testFlag(MyStrictEnum::StrictFour));
}
namespace SomeNS {
enum Foo { Foo_A = 1 << 0, Foo_B = 1 << 1, Foo_C = 1 << 2 };
Q_DECLARE_FLAGS(Foos, Foo)
Q_DECLARE_OPERATORS_FOR_FLAGS(Foos);
Qt::Alignment alignment()
{
// Checks that the operator| works, despite there is another operator| in this namespace.
return Qt::AlignLeft | Qt::AlignTop;
}
}
void tst_QFlags::adl()
{
SomeNS::Foos fl = SomeNS::Foo_B | SomeNS::Foo_C;
QVERIFY(fl & SomeNS::Foo_B);
QVERIFY(!(fl & SomeNS::Foo_A));
QCOMPARE(SomeNS::alignment(), Qt::AlignLeft | Qt::AlignTop);
}
// (statically) check QTypeInfo for QFlags instantiations:
enum MyEnum { Zero, One, Two, Four=4 };
Q_DECLARE_FLAGS( MyFlags, MyEnum )
Q_DECLARE_OPERATORS_FOR_FLAGS( MyFlags )
static_assert( !QTypeInfo<MyFlags>::isComplex );
static_assert( QTypeInfo<MyFlags>::isRelocatable );
static_assert( !QTypeInfo<MyFlags>::isPointer );
QTEST_MAIN(tst_QFlags)
#include "tst_qflags.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qfloat16 Test:
#####################################################################
qt_internal_add_test(tst_qfloat16
SOURCES
tst_qfloat16.cpp
LIBRARIES
Qt::TestPrivate
)

View File

@ -0,0 +1,694 @@
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2016 by Southwest Research Institute (R)
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QFloat16>
#include <QMetaType>
#include <QTextStream>
#include <math.h>
//#define DO_FULL_TEST
static_assert(sizeof(float) == sizeof(quint32), "Float not 32-bit");
class tst_qfloat16: public QObject
{
Q_OBJECT
private slots:
void fuzzyCompare_data();
void fuzzyCompare();
void fuzzyIsNull_data();
void fuzzyIsNull();
void ltgt_data();
void ltgt();
void qNaN();
void infinity();
void float_cast();
void float_cast_data();
void promotionTests();
void arithOps_data();
void arithOps();
#if defined DO_FULL_TEST
void floatToFloat16Full_data();
void floatToFloat16Full();
void floatFromFloat16Full();
#endif
void floatToFloat16();
void floatFromFloat16();
void finite_data();
void finite();
void properties();
void limits();
void mantissaOverflow();
void dataStream();
void textStream();
};
void tst_qfloat16::fuzzyCompare_data()
{
QTest::addColumn<qfloat16>("val1");
QTest::addColumn<qfloat16>("val2");
QTest::addColumn<bool>("fuzEqual");
QTest::addColumn<bool>("isEqual");
QTest::newRow("zero") << qfloat16(0.0f) << qfloat16(0.0f) << true << true;
QTest::newRow("ten") << qfloat16(1e1f) << qfloat16(1e1f) << true << true;
QTest::newRow("large") << qfloat16(1e4f) << qfloat16(1e4f) << true << true;
QTest::newRow("small") << qfloat16(1e-5f) << qfloat16(1e-5f) << true << true;
QTest::newRow("eps") << qfloat16(10.01f) << qfloat16(10.02f) << true << false;
QTest::newRow("eps2") << qfloat16(1024.f) << qfloat16(1033.f) << true << false;
QTest::newRow("mis1") << qfloat16(0.0f) << qfloat16(1.0f) << false << false;
QTest::newRow("mis2") << qfloat16(0.0f) << qfloat16(1e7f) << false << false;
QTest::newRow("mis3") << qfloat16(0.0f) << qfloat16(1e-4f) << false << false;
QTest::newRow("mis4") << qfloat16(1e8f) << qfloat16(1e-8f) << false << false;
QTest::newRow("mis5") << qfloat16(1e-4f) << qfloat16(1e-5) << false << false;
QTest::newRow("mis6") << qfloat16(1024.f) << qfloat16(1034.f) << false << false;
}
void tst_qfloat16::fuzzyCompare()
{
QFETCH(qfloat16, val1);
QFETCH(qfloat16, val2);
QFETCH(bool, fuzEqual);
QFETCH(bool, isEqual);
if (!isEqual && (val1==val2))
qWarning() << "Identical arguments provided unintentionally!";
if (fuzEqual) {
QVERIFY(::qFuzzyCompare(val1, val2));
QVERIFY(::qFuzzyCompare(val2, val1));
QVERIFY(::qFuzzyCompare(-val1, -val2));
QVERIFY(::qFuzzyCompare(-val2, -val1));
} else {
QVERIFY(!::qFuzzyCompare(val1, val2));
QVERIFY(!::qFuzzyCompare(val2, val1));
QVERIFY(!::qFuzzyCompare(-val1, -val2));
QVERIFY(!::qFuzzyCompare(-val2, -val1));
}
}
void tst_qfloat16::fuzzyIsNull_data()
{
QTest::addColumn<qfloat16>("value");
QTest::addColumn<bool>("isNull");
using Bounds = std::numeric_limits<qfloat16>;
const qfloat16 one(1), huge(1000), tiny(0.00976f);
QTest::newRow("zero") << qfloat16(0.0f) << true;
QTest::newRow("min") << Bounds::min() << true;
QTest::newRow("denorm_min") << Bounds::denorm_min() << true;
QTest::newRow("tiny") << tiny << true;
QTest::newRow("deci") << qfloat16(.1) << false;
QTest::newRow("one") << one << false;
QTest::newRow("ten") << qfloat16(10) << false;
QTest::newRow("huge") << huge << false;
}
void tst_qfloat16::fuzzyIsNull()
{
QFETCH(qfloat16, value);
QFETCH(bool, isNull);
QCOMPARE(::qFuzzyIsNull(value), isNull);
QCOMPARE(::qFuzzyIsNull(-value), isNull);
}
void tst_qfloat16::ltgt_data()
{
QTest::addColumn<float>("val1");
QTest::addColumn<float>("val2");
QTest::newRow("zero") << 0.0f << 0.0f;
QTest::newRow("-zero") << -0.0f << 0.0f;
QTest::newRow("ten") << 10.0f << 10.0f;
QTest::newRow("large") << 100000.0f << 100000.0f;
QTest::newRow("small") << 0.0000001f << 0.0000001f;
QTest::newRow("eps") << 10.000000000000001f << 10.00000000000002f;
QTest::newRow("eps2") << 10.000000000000001f << 10.000000000000009f;
QTest::newRow("mis1") << 0.0f << 1.0f;
QTest::newRow("mis2") << 0.0f << 10000000.0f;
QTest::newRow("mis3") << 0.0f << 0.0001f;
QTest::newRow("mis4") << 100000000.0f << 0.000000001f;
QTest::newRow("mis5") << 0.0001f << 0.00001f;
QTest::newRow("45,23") << 45.f << 23.f;
QTest::newRow("1000,76") << 1000.f << 76.f;
}
void tst_qfloat16::ltgt()
{
QFETCH(float, val1);
QFETCH(float, val2);
QCOMPARE(qfloat16(val1) == qfloat16(val2), val1 == val2);
QCOMPARE(qfloat16(val1) < qfloat16(val2), val1 < val2);
QCOMPARE(qfloat16(val1) <= qfloat16(val2), val1 <= val2);
QCOMPARE(qfloat16(val1) > qfloat16(val2), val1 > val2);
QCOMPARE(qfloat16(val1) >= qfloat16(val2), val1 >= val2);
QCOMPARE(qfloat16(val1) == qfloat16(-val2), val1 == -val2);
QCOMPARE(qfloat16(val1) < qfloat16(-val2), val1 < -val2);
QCOMPARE(qfloat16(val1) <= qfloat16(-val2), val1 <= -val2);
QCOMPARE(qfloat16(val1) > qfloat16(-val2), val1 > -val2);
QCOMPARE(qfloat16(val1) >= qfloat16(-val2), val1 >= -val2);
QCOMPARE(qfloat16(-val1) == qfloat16(val2), -val1 == val2);
QCOMPARE(qfloat16(-val1) < qfloat16(val2), -val1 < val2);
QCOMPARE(qfloat16(-val1) <= qfloat16(val2), -val1 <= val2);
QCOMPARE(qfloat16(-val1) > qfloat16(val2), -val1 > val2);
QCOMPARE(qfloat16(-val1) >= qfloat16(val2), -val1 >= val2);
QCOMPARE(qfloat16(-val1) == qfloat16(-val2), -val1 == -val2);
QCOMPARE(qfloat16(-val1) < qfloat16(-val2), -val1 < -val2);
QCOMPARE(qfloat16(-val1) <= qfloat16(-val2), -val1 <= -val2);
QCOMPARE(qfloat16(-val1) > qfloat16(-val2), -val1 > -val2);
QCOMPARE(qfloat16(-val1) >= qfloat16(-val2), -val1 >= -val2);
}
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
// turn -ffast-math off
# pragma GCC optimize "no-fast-math"
#endif
void tst_qfloat16::qNaN()
{
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404)
QSKIP("Non-conformant fast math mode is enabled, cannot run test");
#endif
using Bounds = std::numeric_limits<qfloat16>;
const qfloat16 nan = Bounds::quiet_NaN();
const qfloat16 zero(0), one(1);
QVERIFY(!(zero > nan));
QVERIFY(!(zero < nan));
QVERIFY(!(zero == nan));
QVERIFY(!qIsInf(nan));
QVERIFY(qIsNaN(nan));
QVERIFY(qIsNaN(nan + one));
QVERIFY(qIsNaN(-nan));
QVERIFY(qIsNaN(nan * zero));
QVERIFY(qIsNaN(Bounds::infinity() * zero));
QVERIFY(!nan.isNormal());
QVERIFY(!qIsFinite(nan));
QVERIFY(!(nan == nan));
QCOMPARE(nan, nan); // Despite the preceding
QCOMPARE(qFpClassify(nan), FP_NAN);
}
void tst_qfloat16::infinity()
{
const qfloat16 huge = std::numeric_limits<qfloat16>::infinity();
const qfloat16 zero(0), one(1), two(2);
QVERIFY(huge > -huge);
QVERIFY(huge > zero);
QVERIFY(-huge < zero);
QCOMPARE(huge, huge);
QCOMPARE(-huge, -huge);
QCOMPARE(one / huge, zero);
QVERIFY(qFuzzyCompare(one / huge, zero)); // (same thing)
QVERIFY(qIsInf(huge));
QVERIFY(qIsInf(-huge));
QVERIFY(qIsInf(two * huge));
QVERIFY(qIsInf(huge * two));
QVERIFY(!huge.isNormal());
QVERIFY(!(-huge).isNormal());
QVERIFY(!qIsNaN(huge));
QVERIFY(!qIsNaN(-huge));
QVERIFY(!qIsFinite(huge));
QVERIFY(!qIsFinite(-huge));
QCOMPARE(qFpClassify(huge), FP_INFINITE);
QCOMPARE(qFpClassify(-huge), FP_INFINITE);
}
void tst_qfloat16::float_cast_data()
{
QTest::addColumn<float>("val");
QTest::newRow("zero") << 0.f;
QTest::newRow("one") << 1e0f;
QTest::newRow("ten") << 1e1f;
QTest::newRow("hund") << 1e2f;
QTest::newRow("thou") << 1e3f;
QTest::newRow("tthou") << 1e4f;
//QTest::newRow("hthou") << 1e5f;
//QTest::newRow("mil") << 1e6f;
//QTest::newRow("tmil") << 1e7f;
//QTest::newRow("hmil") << 1e8f;
}
void tst_qfloat16::float_cast()
{
QFETCH(float, val);
QVERIFY(qFuzzyCompare((float)(qfloat16(val)),val));
QVERIFY(qFuzzyCompare((float)(qfloat16(-val)),-val));
QVERIFY(qFuzzyCompare((double)(qfloat16(val)),(double)(val)));
QVERIFY(qFuzzyCompare((double)(qfloat16(-val)),(double)(-val)));
//QVERIFY(qFuzzyCompare((long double)(qfloat16(val)),(long double)(val)));
//QVERIFY(qFuzzyCompare((long double)(qfloat16(-val)),(long double)(-val)));
}
void tst_qfloat16::promotionTests()
{
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)+qfloat16(1.f)));
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)-qfloat16(1.f)));
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)*qfloat16(1.f)));
QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)/qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f+qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f-qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f*qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(1.f/qfloat16(1.f)));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)+1.f));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)-1.f));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)*1.f));
QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)/1.f));
QCOMPARE(sizeof(double),sizeof(1.+qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1.-qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1.*qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1./qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)+1.));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)-1.));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1.));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1.));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)+qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)-qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)*qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof((long double)(1.)/qfloat16(1.f)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)+(long double)(1.)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)-(long double)(1.)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)*(long double)(1.)));
QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)/(long double)(1.)));
QCOMPARE(sizeof(double),sizeof(1+qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1-qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1*qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(1/qfloat16(1.f)));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)+1));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)-1));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1));
QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1));
QCOMPARE(QString::number(1.f),QString::number(double(qfloat16(1.f))));
}
void tst_qfloat16::arithOps_data()
{
QTest::addColumn<float>("val1");
QTest::addColumn<float>("val2");
QTest::newRow("zero") << 0.0f << 2.0f;
QTest::newRow("one") << 1.0f << 4.0f;
QTest::newRow("ten") << 10.0f << 20.0f;
}
void tst_qfloat16::arithOps()
{
QFETCH(float, val1);
QFETCH(float, val2);
QVERIFY(qFuzzyCompare(float(qfloat16(val1) + qfloat16(val2)), val1 + val2));
QVERIFY(qFuzzyCompare(float(qfloat16(val1) - qfloat16(val2)), val1 - val2));
QVERIFY(qFuzzyCompare(float(qfloat16(val1) * qfloat16(val2)), val1 * val2));
QVERIFY(qFuzzyCompare(float(qfloat16(val1) / qfloat16(val2)), val1 / val2));
QVERIFY(qFuzzyCompare(qfloat16(val1) + val2, val1 + val2));
QVERIFY(qFuzzyCompare(qfloat16(val1) - val2, val1 - val2));
QVERIFY(qFuzzyCompare(qfloat16(val1) * val2, val1 * val2));
QVERIFY(qFuzzyCompare(qfloat16(val1) / val2, val1 / val2));
QVERIFY(qFuzzyCompare(val1 + qfloat16(val2), val1 + val2));
QVERIFY(qFuzzyCompare(val1 - qfloat16(val2), val1 - val2));
QVERIFY(qFuzzyCompare(val1 * qfloat16(val2), val1 * val2));
QVERIFY(qFuzzyCompare(val1 / qfloat16(val2), val1 / val2));
float r1 = 0.f;
r1 += qfloat16(val2);
QVERIFY(qFuzzyCompare(r1,val2));
float r2 = 0.f;
r2 -= qfloat16(val2);
QVERIFY(qFuzzyCompare(r2,-val2));
float r3 = 1.f;
r3 *= qfloat16(val2);
QVERIFY(qFuzzyCompare(r3,val2));
float r4 = 1.f;
r4 /= qfloat16(val2);
QVERIFY(qFuzzyCompare(r4,1.f/val2));
}
#if defined DO_FULL_TEST
void tst_qfloat16::floatToFloat16Full_data()
{
QTest::addColumn<quint32>("group");
for (quint32 j = 0x00; j < 0x100; ++j)
QTest::addRow("%02x", j) << j;
}
void tst_qfloat16::floatToFloat16Full()
{
QFETCH(quint32, group);
for (quint32 j = 0x00; j < 0x100; ++j) {
quint32 data[1<<16];
qfloat16 out[1<<16];
qfloat16 expected[1<<16];
float in[1<<16];
for (int i = 0; i < (1<<16); ++i)
data[i] = (group << 24) | (j << 16) | i;
memcpy(in, data, (1<<16)*sizeof(float));
for (int i = 0; i < (1<<16); ++i)
expected[i] = qfloat16(in[i]);
qFloatToFloat16(out, in, 1<<16);
for (int i = 0; i < (1<<16); ++i) {
if (out[i] != expected[i])
QVERIFY(qIsNaN(out[i]) && qIsNaN(expected[i]));
}
}
}
void tst_qfloat16::floatFromFloat16Full()
{
quint16 data[1<<16];
float out[1<<16];
float expected[1<<16];
for (int i = 0; i < (1<<16); ++i)
data[i] = i;
const qfloat16 *in = reinterpret_cast<const qfloat16 *>(data);
for (int i = 0; i < (1<<16); ++i)
expected[i] = float(in[i]);
qFloatFromFloat16(out, in, 1<<16);
for (int i = 0; i < (1<<16); ++i)
if (out[i] != expected[i])
QVERIFY(qIsNaN(out[i]) && qIsNaN(expected[i]));
}
#endif
void tst_qfloat16::floatToFloat16()
{
constexpr int count = 10000;
float in[count];
qfloat16 out[count];
qfloat16 expected[count];
for (int i = 0; i < count; ++i)
in[i] = (i - count/2) * (1/13.f);
for (int i = 0; i < count; ++i)
expected[i] = qfloat16(in[i]);
qFloatToFloat16(out, in, count);
for (int i = 0; i < count; ++i)
QVERIFY(out[i] == expected[i]);
}
void tst_qfloat16::floatFromFloat16()
{
qfloat16 in[35];
float out[35];
float expected[35];
for (int i = 0; i < 35; ++i)
in[i] = qfloat16(i * (17.f / 3));
for (int i = 0; i < 35; ++i)
expected[i] = float(in[i]);
qFloatFromFloat16(out, in, 35);
for (int i = 0; i < 35; ++i)
QCOMPARE(out[i], expected[i]);
}
static qfloat16 powf16(qfloat16 base, int raise)
{
const qfloat16 one(1.f);
if (raise < 0) {
raise = -raise;
base = one / base;
}
qfloat16 answer = (raise & 1) ? base : one;
while (raise > 0) {
raise >>= 1;
base *= base;
if (raise & 1)
answer *= base;
}
return answer;
}
void tst_qfloat16::finite_data()
{
using Bounds = std::numeric_limits<qfloat16>;
QTest::addColumn<qfloat16>("value");
QTest::addColumn<int>("mode");
QTest::newRow("zero") << qfloat16(0) << FP_ZERO;
QTest::newRow("-zero") << -qfloat16(0) << FP_ZERO;
QTest::newRow("one") << qfloat16(1) << FP_NORMAL;
QTest::newRow("-one") << qfloat16(-1) << FP_NORMAL;
QTest::newRow("ten") << qfloat16(10) << FP_NORMAL;
QTest::newRow("-ten") << qfloat16(-10) << FP_NORMAL;
QTest::newRow("max") << Bounds::max() << FP_NORMAL;
QTest::newRow("lowest") << Bounds::lowest() << FP_NORMAL;
QTest::newRow("min") << Bounds::min() << FP_NORMAL;
QTest::newRow("-min") << -Bounds::min() << FP_NORMAL;
QTest::newRow("denorm_min") << Bounds::denorm_min() << FP_SUBNORMAL;
QTest::newRow("-denorm_min") << -Bounds::denorm_min() << FP_SUBNORMAL;
}
void tst_qfloat16::finite()
{
QFETCH(qfloat16, value);
QFETCH(int, mode);
QCOMPARE(value.isNormal(), mode == FP_NORMAL);
QCOMPARE(value, value); // Fuzzy
QVERIFY(value == value); // Exact
QVERIFY(qIsFinite(value));
QVERIFY(!qIsInf(value));
QVERIFY(!qIsNaN(value));
QCOMPARE(qFpClassify(value), mode);
// *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy
// comparison, and we need exact here.
const qfloat16 zero(0), plus(+1), minus(-1);
const qfloat16 magnitude = (value < zero) ? -value : value;
QVERIFY(value.copySign(plus) == magnitude);
QVERIFY(value.copySign(minus) == -magnitude);
}
void tst_qfloat16::properties()
{
using Bounds = std::numeric_limits<qfloat16>;
QVERIFY(Bounds::is_specialized);
QVERIFY(Bounds::is_signed);
QVERIFY(!Bounds::is_integer);
QVERIFY(!Bounds::is_exact);
// While we'd like to check for __STDC_IEC_559__, as per ISO/IEC 9899:2011
// Annex F (C11, normative for C++11), there are a few corner cases regarding
// denormals where GHS compiler is relying hardware behavior that is not IEC
// 559 compliant.
// On GHS the compiler reports std::numeric_limits<float>::is_iec559 as false.
// and the same supposed to be for qfloat16.
#if !defined(Q_CC_GHS)
QVERIFY(Bounds::is_iec559);
#endif //Q_CC_GHS
#if QT_CONFIG(signaling_nan)
// Technically, presence of NaN and infinities are implied from the above check, but that checkings GHS compiler complies.
QVERIFY(Bounds::has_infinity && Bounds::has_quiet_NaN && Bounds::has_signaling_NaN);
#endif
QVERIFY(Bounds::is_bounded);
QVERIFY(!Bounds::is_modulo);
QVERIFY(!Bounds::traps);
QVERIFY(Bounds::has_infinity);
QVERIFY(Bounds::has_quiet_NaN);
#if QT_CONFIG(signaling_nan)
QVERIFY(Bounds::has_signaling_NaN);
#endif
#if !defined(Q_CC_GHS)
QCOMPARE(Bounds::has_denorm, std::denorm_present);
#else
// For GHS compiler the "denorm_indeterminite" is the expected return value.
QCOMPARE(Bounds::has_denorm, std::denorm_indeterminate);
#endif // Q_CC_GHS
QCOMPARE(Bounds::round_style, std::round_to_nearest);
QCOMPARE(Bounds::radix, 2);
// Untested: has_denorm_loss
}
void tst_qfloat16::limits() // See also: qNaN() and infinity()
{
// *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy
// comparison, and we need exact here.
using Bounds = std::numeric_limits<qfloat16>;
// A few useful values:
const qfloat16 zero(0), one(1), ten(10);
// The specifics of minus zero:
// (IEEE 754 seems to want -zero < zero, but -0. == 0. and -0.f == 0.f in C++.)
QVERIFY(-zero <= zero);
QVERIFY(-zero == zero);
QVERIFY(!(-zero > zero));
// digits in the mantissa, including the implicit 1 before the binary dot at its left:
QVERIFY(qfloat16(1 << (Bounds::digits - 1)) + one > qfloat16(1 << (Bounds::digits - 1)));
QVERIFY(qfloat16(1 << Bounds::digits) + one == qfloat16(1 << Bounds::digits));
// There is a wilful of-by-one in how m(ax|in)_exponent are defined; they're
// the lowest and highest n for which radix^{n-1} are normal and finite.
const qfloat16 two(Bounds::radix);
qfloat16 bit = powf16(two, Bounds::max_exponent - 1);
QVERIFY(qIsFinite(bit));
QVERIFY(qIsInf(bit * two));
bit = powf16(two, Bounds::min_exponent - 1);
QVERIFY(bit.isNormal());
QCOMPARE(qFpClassify(bit), FP_NORMAL);
QVERIFY(!(bit / two).isNormal());
QCOMPARE(qFpClassify(bit / two), FP_SUBNORMAL);
QVERIFY(bit / two > zero);
// Base ten (with no matching off-by-one idiocy):
// the lowest negative number n such that 10^n is a valid normalized value
qfloat16 low10(powf16(ten, Bounds::min_exponent10));
QVERIFY(low10 > zero);
QVERIFY(low10.isNormal());
low10 /= ten;
QVERIFY(low10 == zero || !low10.isNormal());
// the largest positive number n such that 10^n is a representable finite value
qfloat16 high10(powf16(ten, Bounds::max_exponent10));
QVERIFY(high10 > zero);
QVERIFY(qIsFinite(high10));
QVERIFY(!qIsFinite(high10 * ten));
QCOMPARE(qFpClassify(high10), FP_NORMAL);
// How many digits are significant ? (Casts avoid linker errors ...)
QCOMPARE(int(Bounds::digits10), 3); // ~9.88e-4 has enough sigificant digits:
qfloat16 below(9.876e-4f), above(9.884e-4f); // both round to ~9.88e-4
QVERIFY(below == above);
QCOMPARE(int(Bounds::max_digits10), 5); // we need 5 to distinguish these two:
QVERIFY(qfloat16(1000.5f) != qfloat16(1001.4f));
// Actual limiting values of the type:
const qfloat16 rose(one + Bounds::epsilon());
QVERIFY(rose > one);
QVERIFY(one + Bounds::epsilon() / two == one);
QVERIFY(Bounds::max() > zero);
QVERIFY(qIsInf(Bounds::max() * rose));
QVERIFY(Bounds::lowest() < zero);
QVERIFY(qIsInf(Bounds::lowest() * rose));
QVERIFY(Bounds::min() > zero);
QVERIFY(!(Bounds::min() / rose).isNormal());
QVERIFY(Bounds::denorm_min() > zero);
QVERIFY(Bounds::denorm_min() / two == zero);
const qfloat16 under = (-Bounds::denorm_min()) / two;
QVERIFY(under == -zero);
QCOMPARE(qfloat16(1).copySign(under), qfloat16(-1));
}
void tst_qfloat16::mantissaOverflow()
{
// Test we don't change category due to mantissa overflow when rounding.
quint32 in = 0x7fffffff;
float f;
memcpy(&f, &in, 4);
qfloat16 f16 = qfloat16(f);
qfloat16 f16s[1];
qFloatToFloat16(f16s, &f, 1);
QCOMPARE(f16, f16s[0]);
QVERIFY(qIsNaN(f16));
}
void tst_qfloat16::dataStream()
{
QByteArray ba;
QDataStream ds(&ba, QIODevice::ReadWrite);
ds << qfloat16(1.5) << qfloat16(-1);
QCOMPARE(ba.size(), 4);
QCOMPARE(ds.status(), QDataStream::Ok);
QCOMPARE(ba, QByteArray("\x3e\0\xbc\0", 4));
ds.device()->seek(0);
ds.resetStatus();
ds.setByteOrder(QDataStream::LittleEndian);
ds << qfloat16(0) << qfloat16(-1);
QCOMPARE(ds.status(), QDataStream::Ok);
QCOMPARE(ba, QByteArray("\0\0\0\xbc", 4));
ds.device()->seek(0);
ds.resetStatus();
qfloat16 zero = 1;
ds >> zero;
QCOMPARE(ds.status(), QDataStream::Ok);
QCOMPARE(zero, qfloat16(0));
ds.device()->seek(0);
ds.resetStatus();
QMetaType mt = QMetaType(QMetaType::Float16);
QVERIFY(mt.save(ds, &zero));
ds.device()->seek(0);
ds.resetStatus();
zero = -1;
QVERIFY(mt.load(ds, &zero));
QCOMPARE(zero, qfloat16(0));
}
void tst_qfloat16::textStream()
{
QString buffer;
{
QTextStream ts(&buffer);
ts << qfloat16(0) << Qt::endl << qfloat16(1.5);
QCOMPARE(ts.status(), QTextStream::Ok);
}
QCOMPARE(buffer, "0\n1.5");
{
QTextStream ts(&buffer);
qfloat16 zero = qfloat16(-2.5), threehalves = 1234;
ts >> zero >> threehalves;
QCOMPARE(ts.status(), QTextStream::Ok);
QCOMPARE(zero, qfloat16(0));
QCOMPARE(threehalves, 1.5);
}
}
QTEST_APPLESS_MAIN(tst_qfloat16)
#include "tst_qfloat16.moc"

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qgetputenv Test:
#####################################################################
qt_internal_add_test(tst_qgetputenv
SOURCES
tst_qgetputenv.cpp
)

View File

@ -0,0 +1,207 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qdebug.h>
#include <QTest>
#include <qglobal.h>
#ifdef Q_OS_WIN
#include <qt_windows.h>
#endif
class tst_QGetPutEnv : public QObject
{
Q_OBJECT
private slots:
void getSetCheck();
void encoding();
void intValue_data();
void intValue();
};
void tst_QGetPutEnv::getSetCheck()
{
const char varName[] = "should_not_exist";
bool ok;
QVERIFY(!qEnvironmentVariableIsSet(varName));
QVERIFY(qEnvironmentVariableIsEmpty(varName));
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
QVERIFY(!ok);
QByteArray result = qgetenv(varName);
QVERIFY(result.isNull());
QString sresult = qEnvironmentVariable(varName);
QVERIFY(sresult.isNull());
sresult = qEnvironmentVariable(varName, "hello");
QCOMPARE(sresult, QString("hello"));
#ifndef Q_OS_WIN
QVERIFY(qputenv(varName, "")); // deletes varName instead of making it empty, on Windows
QVERIFY(qEnvironmentVariableIsSet(varName));
QVERIFY(qEnvironmentVariableIsEmpty(varName));
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
QVERIFY(!ok);
result = qgetenv(varName);
QVERIFY(!result.isNull());
QCOMPARE(result, QByteArray());
sresult = qEnvironmentVariable(varName);
QVERIFY(!sresult.isNull());
QCOMPARE(sresult, QString());
sresult = qEnvironmentVariable(varName, "hello");
QVERIFY(!sresult.isNull());
QCOMPARE(sresult, QString());
#endif
constexpr char varValueFullString[] = "supervalue123";
const auto varValueQBA = QByteArray::fromRawData(varValueFullString, sizeof varValueFullString - 4);
QCOMPARE_EQ(varValueQBA, "supervalue");
QVERIFY(qputenv(varName, varValueQBA));
QVERIFY(qEnvironmentVariableIsSet(varName));
QVERIFY(!qEnvironmentVariableIsEmpty(varName));
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
QVERIFY(!ok);
result = qgetenv(varName);
QCOMPARE(result, QByteArrayLiteral("supervalue"));
sresult = qEnvironmentVariable(varName);
QCOMPARE(sresult, QString("supervalue"));
sresult = qEnvironmentVariable(varName, "hello");
QCOMPARE(sresult, QString("supervalue"));
qputenv(varName,QByteArray());
// Now test qunsetenv
QVERIFY(qunsetenv(varName));
QVERIFY(!qEnvironmentVariableIsSet(varName)); // note: might fail on some systems!
QVERIFY(qEnvironmentVariableIsEmpty(varName));
ok = true;
QCOMPARE(qEnvironmentVariableIntValue(varName), 0);
QCOMPARE(qEnvironmentVariableIntValue(varName, &ok), 0);
QVERIFY(!ok);
result = qgetenv(varName);
QVERIFY(result.isNull());
sresult = qEnvironmentVariable(varName);
QVERIFY(sresult.isNull());
sresult = qEnvironmentVariable(varName, "hello");
QCOMPARE(sresult, QString("hello"));
}
void tst_QGetPutEnv::encoding()
{
// The test string is:
// U+0061 LATIN SMALL LETTER A
// U+00E1 LATIN SMALL LETTER A WITH ACUTE
// U+03B1 GREEK SMALL LETTER ALPHA
// U+0430 CYRILLIC SMALL LETTER A
// This has letters in three different scripts, so no locale besides
// UTF-8 is able handle them all.
// The LATIN SMALL LETTER A WITH ACUTE is NFC for NFD:
// U+0061 U+0301 LATIN SMALL LETTER A + COMBINING ACUTE ACCENT
const char varName[] = "should_not_exist";
static const wchar_t rawvalue[] = { 'a', 0x00E1, 0x03B1, 0x0430, 0 };
QString value = QString::fromWCharArray(rawvalue);
#if defined(Q_OS_WIN)
const wchar_t wvarName[] = L"should_not_exist";
_wputenv_s(wvarName, rawvalue);
#else
// confirm the locale is UTF-8
if (value.toLocal8Bit() != "a\xc3\xa1\xce\xb1\xd0\xb0")
QSKIP("Locale is not UTF-8, cannot test");
qputenv(varName, QFile::encodeName(value));
#endif
QVERIFY(qEnvironmentVariableIsSet(varName));
QCOMPARE(qEnvironmentVariable(varName), value);
}
void tst_QGetPutEnv::intValue_data()
{
QTest::addColumn<QByteArray>("value");
QTest::addColumn<int>("expected");
QTest::addColumn<bool>("ok");
// some repetition from what is tested in getSetCheck()
QTest::newRow("empty") << QByteArray() << 0 << false;
QTest::newRow("spaces-heading") << QByteArray(" \n\r\t1") << 1 << true;
QTest::newRow("spaces-trailing") << QByteArray("1 \n\r\t") << 1 << true;
QTest::newRow("junk-heading") << QByteArray("x1") << 0 << false;
QTest::newRow("junk-trailing") << QByteArray("1x") << 0 << false;
#define ROW(x, i, b) \
QTest::newRow(#x) << QByteArray(#x) << (i) << (b)
ROW(auto, 0, false);
ROW(1auto, 0, false);
ROW(0, 0, true);
ROW(+0, 0, true);
ROW(1, 1, true);
ROW(+1, 1, true);
ROW(09, 0, false);
ROW(010, 8, true);
ROW(0x10, 16, true);
ROW(0x, 0, false);
ROW(0xg, 0, false);
ROW(0x1g, 0, false);
ROW(000000000000000000000000000000000000000000000000001, 0, false);
ROW(+000000000000000000000000000000000000000000000000001, 0, false);
ROW(000000000000000000000000000000000000000000000000001g, 0, false);
ROW(-0, 0, true);
ROW(-1, -1, true);
ROW(-010, -8, true);
ROW(-000000000000000000000000000000000000000000000000001, 0, false);
ROW(2147483648, 0, false);
// ROW(0xffffffff, -1, true); // could be expected, but not how QByteArray::toInt() works
ROW(0xffffffff, 0, false);
const int bases[] = {10, 8, 16};
for (size_t i = 0; i < sizeof bases / sizeof *bases; ++i) {
QTest::addRow("INT_MAX, base %d", bases[i])
<< QByteArray::number(INT_MAX) << INT_MAX << true;
QTest::addRow("INT_MAX+1, base %d", bases[i])
<< QByteArray::number(qlonglong(INT_MAX) + 1) << 0 << false;
QTest::addRow("INT_MIN, base %d", bases[i])
<< QByteArray::number(INT_MIN) << INT_MIN << true;
QTest::addRow("INT_MIN-1, base %d", bases[i])
<< QByteArray::number(qlonglong(INT_MIN) - 1) << 0 << false;
};
}
void tst_QGetPutEnv::intValue()
{
const int maxlen = (sizeof(int) * CHAR_BIT + 2) / 3;
const char varName[] = "should_not_exist";
QFETCH(QByteArray, value);
QFETCH(int, expected);
QFETCH(bool, ok);
bool actualOk = !ok;
// Self-test: confirm that it was like the docs said it should be
if (value.size() < maxlen) {
QCOMPARE(value.toInt(&actualOk, 0), expected);
QCOMPARE(actualOk, ok);
}
actualOk = !ok;
QVERIFY(qputenv(varName, value));
QCOMPARE(qEnvironmentVariableIntValue(varName), expected);
QCOMPARE(qEnvironmentVariableIntValue(varName, &actualOk), expected);
QCOMPARE(actualOk, ok);
}
QTEST_MAIN(tst_QGetPutEnv)
#include "tst_qgetputenv.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qglobal Test:
#####################################################################
qt_internal_add_test(tst_qglobal
SOURCES
qglobal.c
tst_qglobal.cpp
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,92 @@
// Copyright (C) 2017 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/qglobal.h>
#include <QtCore/qtversion.h>
#ifdef Q_COMPILER_THREAD_LOCAL
# include <threads.h>
#endif
/*
* Certain features of qglobal.h must work in C mode too. We test that
* everything works.
*/
/* Types and Q_UNUSED */
void tst_GlobalTypes()
{
qint8 s8;
qint16 s16;
qint32 s32;
qint64 s64;
qlonglong sll;
Q_UNUSED(s8); Q_UNUSED(s16); Q_UNUSED(s32); Q_UNUSED(s64); Q_UNUSED(sll);
quint8 u8;
quint16 u16;
quint32 u32;
quint64 u64;
qulonglong ull;
Q_UNUSED(u8); Q_UNUSED(u16); Q_UNUSED(u32); Q_UNUSED(u64); Q_UNUSED(ull);
uchar uc;
ushort us;
uint ui;
ulong ul;
Q_UNUSED(uc); Q_UNUSED(us); Q_UNUSED(ui); Q_UNUSED(ul);
qreal qr;
Q_UNUSED(qr);
qsizetype qs;
qptrdiff qp;
qintptr qip;
quintptr qup;
Q_UNUSED(qs); Q_UNUSED(qp); Q_UNUSED(qip); Q_UNUSED(qup);
}
/* Qt version */
int tst_QtVersion()
{
return QT_VERSION;
}
const char *tst_qVersion() Q_DECL_NOEXCEPT;
const char *tst_qVersion()
{
#if !defined(QT_NAMESPACE)
return qVersion();
#else
return NULL;
#endif
}
/* Static assertion */
Q_STATIC_ASSERT(true);
Q_STATIC_ASSERT(1);
Q_STATIC_ASSERT_X(true, "Message");
Q_STATIC_ASSERT_X(1, "Message");
Q_STATIC_ASSERT(!false);
Q_STATIC_ASSERT(!0);
Q_STATIC_ASSERT(!!true);
Q_STATIC_ASSERT(!!1);
#ifdef __COUNTER__
// if the compiler supports __COUNTER__, multiple
// Q_STATIC_ASSERT's on a single line should compile:
Q_STATIC_ASSERT(true); Q_STATIC_ASSERT_X(!false, "");
#endif // __COUNTER__
#ifdef Q_COMPILER_THREAD_LOCAL
static thread_local int gt_var;
void thread_local_test()
{
static thread_local int t_var;
t_var = gt_var;
Q_UNUSED(t_var);
}
#endif

View File

@ -0,0 +1,695 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QPair>
#include <QSysInfo>
#include <QLatin1String>
#include <QString>
#include <QtVersion>
#include <cmath>
class tst_QGlobal: public QObject
{
Q_OBJECT
private slots:
void cMode();
void qIsNull();
void for_each();
void qassert();
void qtry();
void checkptr();
void qstaticassert();
void qConstructorFunction();
void qCoreAppStartupFunction();
void qCoreAppStartupFunctionRestart();
void integerForSize();
void buildAbiEndianness();
void testqOverload();
void testqMinMax();
void qRoundFloats_data();
void qRoundFloats();
void qRoundDoubles_data();
void qRoundDoubles();
void PRImacros();
void testqToUnderlying();
};
extern "C" { // functions in qglobal.c
void tst_GlobalTypes();
int tst_QtVersion();
const char *tst_qVersion();
}
void tst_QGlobal::cMode()
{
tst_GlobalTypes();
QCOMPARE(tst_QtVersion(), QT_VERSION);
#ifndef QT_NAMESPACE
QCOMPARE(tst_qVersion(), qVersion());
#endif
}
void tst_QGlobal::qIsNull()
{
double d = 0.0;
float f = 0.0f;
QVERIFY(::qIsNull(d));
QVERIFY(::qIsNull(f));
d += 0.000000001;
f += 0.0000001f;
QVERIFY(!::qIsNull(d));
QVERIFY(!::qIsNull(f));
d = -0.0;
f = -0.0f;
QVERIFY(::qIsNull(d));
QVERIFY(::qIsNull(f));
}
void tst_QGlobal::for_each()
{
QList<int> list;
list << 0 << 1 << 2 << 3 << 4 << 5;
int counter = 0;
foreach(int i, list) {
QCOMPARE(i, counter++);
}
QCOMPARE(counter, list.size());
// do it again, to make sure we don't have any for-scoping
// problems with older compilers
counter = 0;
foreach(int i, list) {
QCOMPARE(i, counter++);
}
QCOMPARE(counter, list.size());
// check whether we can pass a constructor as container argument
counter = 0;
foreach (int i, QList<int>(list)) {
QCOMPARE(i, counter++);
}
QCOMPARE(counter, list.size());
// check whether we can use a lambda
counter = 0;
foreach (int i, [&](){ return list; }()) {
QCOMPARE(i, counter++);
}
QCOMPARE(counter, list.size());
// Should also work with an existing variable
int local = 0;
counter = 0;
foreach (local, list) {
QCOMPARE(local, counter++);
}
QCOMPARE(counter, list.size());
QCOMPARE(local, counter - 1);
// Test the macro does not mess if/else conditions
counter = 0;
if (true)
foreach (int i, list)
QCOMPARE(i, counter++);
else
QFAIL("If/Else mismatch");
QCOMPARE(counter, list.size());
counter = 0;
if (false)
foreach (int i, list)
if (i) QFAIL("If/Else mismatch");
else QFAIL("If/Else mismatch");
else
foreach (int i, list)
if (false) { }
else QCOMPARE(i, counter++);
QCOMPARE(counter, list.size());
// break and continue
counter = 0;
foreach (int i, list) {
if (i == 0)
continue;
QCOMPARE(i, (counter++) + 1);
if (i == 3)
break;
}
QCOMPARE(counter, 3);
}
void tst_QGlobal::qassert()
{
bool passed = false;
if (false) {
Q_ASSERT(false);
} else {
passed = true;
}
QVERIFY(passed);
passed = false;
if (false) {
Q_ASSERT_X(false, "tst_QGlobal", "qassert");
} else {
passed = true;
}
QVERIFY(passed);
passed = false;
if (false)
Q_ASSERT(false);
else
passed = true;
QVERIFY(passed);
passed = false;
if (false)
Q_ASSERT_X(false, "tst_QGlobal", "qassert");
else
passed = true;
QVERIFY(passed);
}
void tst_QGlobal::qtry()
{
int i = 0;
QT_TRY {
i = 1;
QT_THROW(42);
i = 2;
} QT_CATCH(int) {
QCOMPARE(i, 1);
i = 7;
}
#ifdef QT_NO_EXCEPTIONS
QCOMPARE(i, 2);
#else
QCOMPARE(i, 7);
#endif
// check propper if/else scoping
i = 0;
if (true) {
QT_TRY {
i = 2;
QT_THROW(42);
i = 4;
} QT_CATCH(int) {
QCOMPARE(i, 2);
i = 4;
}
} else {
QCOMPARE(i, 0);
}
QCOMPARE(i, 4);
i = 0;
if (false) {
QT_TRY {
i = 2;
QT_THROW(42);
i = 4;
} QT_CATCH(int) {
QCOMPARE(i, 2);
i = 2;
}
} else {
i = 8;
}
QCOMPARE(i, 8);
i = 0;
if (false) {
i = 42;
} else {
QT_TRY {
i = 2;
QT_THROW(42);
i = 4;
} QT_CATCH(int) {
QCOMPARE(i, 2);
i = 4;
}
}
QCOMPARE(i, 4);
}
void tst_QGlobal::checkptr()
{
int i;
QCOMPARE(q_check_ptr(&i), &i);
const char *c = "hello";
QCOMPARE(q_check_ptr(c), c);
}
// Check Q_STATIC_ASSERT, It should compile
// note that, we are not able to test Q_STATIC_ASSERT(false), to do it manually someone has
// to replace expressions (in the asserts) one by one to false, and check if it breaks build.
class MyTrue
{
public:
MyTrue()
{
Q_STATIC_ASSERT(true);
Q_STATIC_ASSERT(!false);
Q_STATIC_ASSERT_X(true,"");
Q_STATIC_ASSERT_X(!false,"");
}
~MyTrue()
{
Q_STATIC_ASSERT(true);
Q_STATIC_ASSERT(!false);
Q_STATIC_ASSERT_X(true,"");
Q_STATIC_ASSERT_X(!false,"");
}
Q_STATIC_ASSERT(true);
Q_STATIC_ASSERT(!false);
Q_STATIC_ASSERT_X(true,"");
Q_STATIC_ASSERT_X(!false,"");
};
struct MyExpresion
{
void foo()
{
Q_STATIC_ASSERT(sizeof(MyTrue) > 0);
Q_STATIC_ASSERT(sizeof(MyTrue) > 0);
Q_STATIC_ASSERT_X(sizeof(MyTrue) > 0,"");
Q_STATIC_ASSERT_X(sizeof(MyTrue) > 0,"");
}
private:
Q_STATIC_ASSERT(sizeof(MyTrue) > 0);
Q_STATIC_ASSERT(sizeof(MyTrue) > 0);
Q_STATIC_ASSERT_X(sizeof(MyTrue) > 0, "");
Q_STATIC_ASSERT_X(sizeof(MyTrue) > 0, "");
};
struct TypeDef
{
typedef int T;
Q_STATIC_ASSERT(sizeof(T));
Q_STATIC_ASSERT_X(sizeof(T), "");
};
template<typename T1, typename T2>
struct Template
{
static const bool True = true;
typedef typename T1::T DependentType;
Q_STATIC_ASSERT(True);
Q_STATIC_ASSERT(!!True);
Q_STATIC_ASSERT(sizeof(DependentType));
Q_STATIC_ASSERT(!!sizeof(DependentType));
Q_STATIC_ASSERT_X(True, "");
Q_STATIC_ASSERT_X(!!True, "");
Q_STATIC_ASSERT_X(sizeof(DependentType), "");
Q_STATIC_ASSERT_X(!!sizeof(DependentType), "");
};
struct MyTemplate
{
static const bool Value = Template<TypeDef, int>::True;
Q_STATIC_ASSERT(Value);
Q_STATIC_ASSERT(!!Value);
Q_STATIC_ASSERT_X(Value, "");
Q_STATIC_ASSERT_X(!!Value, "");
};
void tst_QGlobal::qstaticassert()
{
// Test multiple Q_STATIC_ASSERT on a single line
Q_STATIC_ASSERT(true); Q_STATIC_ASSERT_X(!false, "");
// Force compilation of these classes
MyTrue tmp1;
MyExpresion tmp2;
MyTemplate tmp3;
Q_UNUSED(tmp1);
Q_UNUSED(tmp2);
Q_UNUSED(tmp3);
QVERIFY(true); // if the test compiles it has passed.
}
static int qConstructorFunctionValue;
static void qConstructorFunctionCtor()
{
qConstructorFunctionValue = 123;
}
Q_CONSTRUCTOR_FUNCTION(qConstructorFunctionCtor);
void tst_QGlobal::qConstructorFunction()
{
QCOMPARE(qConstructorFunctionValue, 123);
}
static int qStartupFunctionValue;
static void myStartupFunc()
{
Q_ASSERT(QCoreApplication::instance());
if (QCoreApplication::instance())
qStartupFunctionValue += 124;
}
Q_COREAPP_STARTUP_FUNCTION(myStartupFunc)
void tst_QGlobal::qCoreAppStartupFunction()
{
QCOMPARE(qStartupFunctionValue, 0);
int argc = 1;
char *argv[] = { const_cast<char*>(QTest::currentAppName()) };
QCoreApplication app(argc, argv);
QCOMPARE(qStartupFunctionValue, 124);
}
void tst_QGlobal::qCoreAppStartupFunctionRestart()
{
qStartupFunctionValue = 0;
qCoreAppStartupFunction();
qStartupFunctionValue = 0;
qCoreAppStartupFunction();
}
struct isEnum_A {
int n_;
};
enum isEnum_B_Byte { isEnum_B_Byte_x = 63 };
enum isEnum_B_Short { isEnum_B_Short_x = 1024 };
enum isEnum_B_Int { isEnum_B_Int_x = 1 << 20 };
union isEnum_C {};
class isEnum_D {
public:
operator int() const;
};
class isEnum_E {
private:
operator int() const;
};
class isEnum_F {
public:
enum AnEnum {};
};
struct Empty {};
template <class T> struct AlignmentInStruct { T dummy; };
typedef int (*fun) ();
typedef int (Empty::*memFun) ();
void tst_QGlobal::integerForSize()
{
// compile-only test:
static_assert(sizeof(QIntegerForSize<1>::Signed) == 1);
static_assert(sizeof(QIntegerForSize<2>::Signed) == 2);
static_assert(sizeof(QIntegerForSize<4>::Signed) == 4);
static_assert(sizeof(QIntegerForSize<8>::Signed) == 8);
static_assert(sizeof(QIntegerForSize<1>::Unsigned) == 1);
static_assert(sizeof(QIntegerForSize<2>::Unsigned) == 2);
static_assert(sizeof(QIntegerForSize<4>::Unsigned) == 4);
static_assert(sizeof(QIntegerForSize<8>::Unsigned) == 8);
}
typedef QPair<const char *, const char *> stringpair;
Q_DECLARE_METATYPE(stringpair)
void tst_QGlobal::buildAbiEndianness()
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
QLatin1String endian("little_endian");
#elif Q_BYTE_ORDER == Q_BIG_ENDIAN
QLatin1String endian("big_endian");
#endif
QVERIFY(QSysInfo::buildAbi().contains(endian));
}
struct Overloaded
{
void foo() {}
void foo(QByteArray) {}
void foo(QByteArray, const QString &) {}
void constFoo() const {}
void constFoo(QByteArray) const {}
void constFoo(QByteArray, const QString &) const {}
void mixedFoo() {}
void mixedFoo(QByteArray) const {}
};
void freeOverloaded() {}
void freeOverloaded(QByteArray) {}
void freeOverloaded(QByteArray, const QString &) {}
void freeOverloadedGet(QByteArray) {}
QByteArray freeOverloadedGet() { return QByteArray(); }
void tst_QGlobal::testqOverload()
{
#ifdef Q_COMPILER_VARIADIC_TEMPLATES
// void returning free overloaded functions
QVERIFY(QOverload<>::of(&freeOverloaded) ==
static_cast<void (*)()>(&freeOverloaded));
QVERIFY(QOverload<QByteArray>::of(&freeOverloaded) ==
static_cast<void (*)(QByteArray)>(&freeOverloaded));
QVERIFY((QOverload<QByteArray, const QString &>::of(&freeOverloaded)) ==
static_cast<void (*)(QByteArray, const QString &)>(&freeOverloaded));
// value returning free overloaded functions
QVERIFY(QOverload<>::of(&freeOverloadedGet) ==
static_cast<QByteArray (*)()>(&freeOverloadedGet));
QVERIFY(QOverload<QByteArray>::of(&freeOverloadedGet) ==
static_cast<void (*)(QByteArray)>(&freeOverloadedGet));
// void returning overloaded member functions
QVERIFY(QOverload<>::of(&Overloaded::foo) ==
static_cast<void (Overloaded::*)()>(&Overloaded::foo));
QVERIFY(QOverload<QByteArray>::of(&Overloaded::foo) ==
static_cast<void (Overloaded::*)(QByteArray)>(&Overloaded::foo));
QVERIFY((QOverload<QByteArray, const QString &>::of(&Overloaded::foo)) ==
static_cast<void (Overloaded::*)(QByteArray, const QString &)>(&Overloaded::foo));
// void returning overloaded const member functions
QVERIFY(QOverload<>::of(&Overloaded::constFoo) ==
static_cast<void (Overloaded::*)() const>(&Overloaded::constFoo));
QVERIFY(QOverload<QByteArray>::of(&Overloaded::constFoo) ==
static_cast<void (Overloaded::*)(QByteArray) const>(&Overloaded::constFoo));
QVERIFY((QOverload<QByteArray, const QString &>::of(&Overloaded::constFoo)) ==
static_cast<void (Overloaded::*)(QByteArray, const QString &) const>(&Overloaded::constFoo));
// void returning overloaded const AND non-const member functions
QVERIFY(QNonConstOverload<>::of(&Overloaded::mixedFoo) ==
static_cast<void (Overloaded::*)()>(&Overloaded::mixedFoo));
QVERIFY(QConstOverload<QByteArray>::of(&Overloaded::mixedFoo) ==
static_cast<void (Overloaded::*)(QByteArray) const>(&Overloaded::mixedFoo));
// void returning free overloaded functions
QVERIFY(qOverload<>(&freeOverloaded) ==
static_cast<void (*)()>(&freeOverloaded));
QVERIFY(qOverload<QByteArray>(&freeOverloaded) ==
static_cast<void (*)(QByteArray)>(&freeOverloaded));
QVERIFY((qOverload<QByteArray, const QString &>(&freeOverloaded) ==
static_cast<void (*)(QByteArray, const QString &)>(&freeOverloaded)));
// value returning free overloaded functions
QVERIFY(qOverload<>(&freeOverloadedGet) ==
static_cast<QByteArray (*)()>(&freeOverloadedGet));
QVERIFY(qOverload<QByteArray>(&freeOverloadedGet) ==
static_cast<void (*)(QByteArray)>(&freeOverloadedGet));
// void returning overloaded member functions
QVERIFY(qOverload<>(&Overloaded::foo) ==
static_cast<void (Overloaded::*)()>(&Overloaded::foo));
QVERIFY(qOverload<QByteArray>(&Overloaded::foo) ==
static_cast<void (Overloaded::*)(QByteArray)>(&Overloaded::foo));
QVERIFY((qOverload<QByteArray, const QString &>(&Overloaded::foo)) ==
static_cast<void (Overloaded::*)(QByteArray, const QString &)>(&Overloaded::foo));
// void returning overloaded const member functions
QVERIFY(qOverload<>(&Overloaded::constFoo) ==
static_cast<void (Overloaded::*)() const>(&Overloaded::constFoo));
QVERIFY(qOverload<QByteArray>(&Overloaded::constFoo) ==
static_cast<void (Overloaded::*)(QByteArray) const>(&Overloaded::constFoo));
QVERIFY((qOverload<QByteArray, const QString &>(&Overloaded::constFoo)) ==
static_cast<void (Overloaded::*)(QByteArray, const QString &) const>(&Overloaded::constFoo));
// void returning overloaded const AND non-const member functions
QVERIFY(qNonConstOverload<>(&Overloaded::mixedFoo) ==
static_cast<void (Overloaded::*)()>(&Overloaded::mixedFoo));
QVERIFY(qConstOverload<QByteArray>(&Overloaded::mixedFoo) ==
static_cast<void (Overloaded::*)(QByteArray) const>(&Overloaded::mixedFoo));
#endif
}
// enforce that types are identical when comparing
template<typename T>
void compare(T a, T b)
{ QCOMPARE(a, b); }
void tst_QGlobal::testqMinMax()
{
// signed types
compare(qMin(float(1), double(-1)), double(-1));
compare(qMin(double(1), float(-1)), double(-1));
compare(qMin(short(1), int(-1)), int(-1));
compare(qMin(short(1), long(-1)), long(-1));
compare(qMin(qint64(1), short(-1)), qint64(-1));
compare(qMax(float(1), double(-1)), double(1));
compare(qMax(short(1), long(-1)), long(1));
compare(qMax(qint64(1), short(-1)), qint64(1));
// unsigned types
compare(qMin(ushort(1), ulong(2)), ulong(1));
compare(qMin(quint64(1), ushort(2)), quint64(1));
compare(qMax(ushort(1), ulong(2)), ulong(2));
compare(qMax(quint64(1), ushort(2)), quint64(2));
}
void tst_QGlobal::qRoundFloats_data()
{
QTest::addColumn<float>("actual");
QTest::addColumn<float>("expected");
QTest::newRow("round half") << 0.5f << 1.0f;
QTest::newRow("round negative half") << -0.5f << -1.0f;
QTest::newRow("round negative") << -1.4f << -1.0f;
QTest::newRow("round largest representable float less than 0.5") << std::nextafter(0.5f, 0.0f) << 0.0f;
}
void tst_QGlobal::qRoundFloats() {
QFETCH(float, actual);
QFETCH(float, expected);
#if !(defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG))
QEXPECT_FAIL("round largest representable float less than 0.5",
"We know qRound fails in this case, but decided that we value simplicity over correctness",
Continue);
#endif
QCOMPARE(qRound(actual), expected);
#if !(defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG))
QEXPECT_FAIL("round largest representable float less than 0.5",
"We know qRound fails in this case, but decided that we value simplicity over correctness",
Continue);
#endif
QCOMPARE(qRound64(actual), expected);
}
void tst_QGlobal::qRoundDoubles_data() {
QTest::addColumn<double>("actual");
QTest::addColumn<double>("expected");
QTest::newRow("round half") << 0.5 << 1.0;
QTest::newRow("round negative half") << -0.5 << -1.0;
QTest::newRow("round negative") << -1.4 << -1.0;
QTest::newRow("round largest representable double less than 0.5") << std::nextafter(0.5, 0.0) << 0.0;
}
void tst_QGlobal::qRoundDoubles() {
QFETCH(double, actual);
QFETCH(double, expected);
#if !(defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG))
QEXPECT_FAIL("round largest representable double less than 0.5",
"We know qRound fails in this case, but decided that we value simplicity over correctness",
Continue);
#endif
QCOMPARE(qRound(actual), expected);
#if !(defined(Q_PROCESSOR_ARM_64) && (__has_builtin(__builtin_round) || defined(Q_CC_GNU)) && !defined(Q_CC_CLANG))
QEXPECT_FAIL("round largest representable double less than 0.5",
"We know qRound fails in this case, but decided that we value simplicity over correctness",
Continue);
#endif
QCOMPARE(qRound64(actual), expected);
}
void tst_QGlobal::PRImacros()
{
// none of these calls must generate a -Wformat warning
{
quintptr p = 123u;
QCOMPARE(QString::asprintf("The value %" PRIuQUINTPTR " is nice", p), "The value 123 is nice");
QCOMPARE(QString::asprintf("The value %" PRIoQUINTPTR " is nice", p), "The value 173 is nice");
QCOMPARE(QString::asprintf("The value %" PRIxQUINTPTR " is nice", p), "The value 7b is nice");
QCOMPARE(QString::asprintf("The value %" PRIXQUINTPTR " is nice", p), "The value 7B is nice");
}
{
qintptr p = 123;
QCOMPARE(QString::asprintf("The value %" PRIdQINTPTR " is nice", p), "The value 123 is nice");
QCOMPARE(QString::asprintf("The value %" PRIiQINTPTR " is nice", p), "The value 123 is nice");
}
{
qptrdiff d = 123;
QCOMPARE(QString::asprintf("The value %" PRIdQPTRDIFF " is nice", d), "The value 123 is nice");
QCOMPARE(QString::asprintf("The value %" PRIiQPTRDIFF " is nice", d), "The value 123 is nice");
}
{
qsizetype s = 123;
QCOMPARE(QString::asprintf("The value %" PRIdQSIZETYPE " is nice", s), "The value 123 is nice");
QCOMPARE(QString::asprintf("The value %" PRIiQSIZETYPE " is nice", s), "The value 123 is nice");
}
}
void tst_QGlobal::testqToUnderlying()
{
enum class E {
E1 = 123,
E2 = 456,
};
static_assert(std::is_same_v<decltype(qToUnderlying(E::E1)), int>);
QCOMPARE(qToUnderlying(E::E1), 123);
QCOMPARE(qToUnderlying(E::E2), 456);
enum EE : unsigned long {
EE1 = 123,
EE2 = 456,
};
static_assert(std::is_same_v<decltype(qToUnderlying(EE1)), unsigned long>);
QCOMPARE(qToUnderlying(EE1), 123UL);
QCOMPARE(qToUnderlying(EE2), 456UL);
}
QTEST_APPLESS_MAIN(tst_QGlobal)
#include "tst_qglobal.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qglobalstatic Test:
#####################################################################
qt_internal_add_test(tst_qglobalstatic
EXCEPTIONS
SOURCES
tst_qglobalstatic.cpp
LIBRARIES
Qt::CorePrivate
Qt::TestPrivate
)

View File

@ -0,0 +1,233 @@
// Copyright (C) 2016 Thiago Macieira <thiago@kde.org>
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QThread>
#include <QTest>
#include <QReadWriteLock>
#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
#include <sys/resource.h>
#endif
#include <QtTest/private/qemulationdetector_p.h>
class tst_QGlobalStatic : public QObject
{
Q_OBJECT
public Q_SLOTS:
void initTestCase();
private Q_SLOTS:
void beforeInitialization();
void api();
void constVolatile();
void exception();
void catchExceptionAndRetry();
void threadStressTest();
void afterDestruction();
};
void tst_QGlobalStatic::initTestCase()
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
// The tests create a lot of threads, which require file descriptors. On systems like
// OS X low defaults such as 256 as the limit for the number of simultaneously
// open files is not sufficient.
struct rlimit numFiles;
if (getrlimit(RLIMIT_NOFILE, &numFiles) == 0 && numFiles.rlim_cur < 1024) {
numFiles.rlim_cur = qMin(rlim_t(1024), numFiles.rlim_max);
setrlimit(RLIMIT_NOFILE, &numFiles);
}
#endif
}
Q_GLOBAL_STATIC_WITH_ARGS(const int, constInt, (42))
Q_GLOBAL_STATIC_WITH_ARGS(volatile int, volatileInt, (-47))
void otherFunction()
{
// never called
constInt();
volatileInt();
}
// do not initialize the following Q_GLOBAL_STATIC
Q_GLOBAL_STATIC(int, checkedBeforeInitialization)
void tst_QGlobalStatic::beforeInitialization()
{
QVERIFY(!checkedBeforeInitialization.exists());
QVERIFY(!checkedBeforeInitialization.isDestroyed());
}
struct Type {
int i;
};
Q_GLOBAL_STATIC(Type, checkedAfterInitialization)
void tst_QGlobalStatic::api()
{
// check the API
QVERIFY((Type *)checkedAfterInitialization);
QVERIFY(checkedAfterInitialization());
*checkedAfterInitialization = Type();
*checkedAfterInitialization() = Type();
checkedAfterInitialization()->i = 47;
checkedAfterInitialization->i = 42;
QCOMPARE(checkedAfterInitialization()->i, 42);
checkedAfterInitialization()->i = 47;
QCOMPARE(checkedAfterInitialization->i, 47);
QVERIFY(checkedAfterInitialization.exists());
QVERIFY(!checkedAfterInitialization.isDestroyed());
}
void tst_QGlobalStatic::constVolatile()
{
QCOMPARE(*constInt(), 42);
QCOMPARE((int)*volatileInt(), -47);
QCOMPARE(*constInt(), 42);
QCOMPARE((int)*volatileInt(), -47);
}
struct ThrowingType
{
static QBasicAtomicInt constructedCount;
static QBasicAtomicInt destructedCount;
ThrowingType()
{
throw 0;
}
ThrowingType(QBasicAtomicInt &throwControl)
{
constructedCount.ref();
if (throwControl.fetchAndAddRelaxed(-1) != 0)
throw 0;
}
~ThrowingType() { destructedCount.ref(); }
};
QBasicAtomicInt ThrowingType::constructedCount = Q_BASIC_ATOMIC_INITIALIZER(0);
QBasicAtomicInt ThrowingType::destructedCount = Q_BASIC_ATOMIC_INITIALIZER(0);
Q_GLOBAL_STATIC(ThrowingType, throwingGS)
void tst_QGlobalStatic::exception()
{
bool exceptionCaught = false;
try {
throwingGS();
} catch (int) {
exceptionCaught = true;
}
QVERIFY(exceptionCaught);
QCOMPARE(QtGlobalStatic::Holder<Q_QGS_throwingGS>::guard.loadRelaxed(), 0);
QVERIFY(!throwingGS.exists());
QVERIFY(!throwingGS.isDestroyed());
}
QBasicAtomicInt exceptionControlVar = Q_BASIC_ATOMIC_INITIALIZER(1);
Q_GLOBAL_STATIC_WITH_ARGS(ThrowingType, exceptionGS, (exceptionControlVar))
void tst_QGlobalStatic::catchExceptionAndRetry()
{
if (exceptionControlVar.loadRelaxed() != 1)
QSKIP("This test cannot be run more than once");
ThrowingType::constructedCount.storeRelaxed(0);
ThrowingType::destructedCount.storeRelaxed(0);
bool exceptionCaught = false;
try {
exceptionGS();
} catch (int) {
exceptionCaught = true;
}
QCOMPARE(ThrowingType::constructedCount.loadRelaxed(), 1);
QVERIFY(exceptionCaught);
exceptionGS();
QCOMPARE(ThrowingType::constructedCount.loadRelaxed(), 2);
}
QBasicAtomicInt threadStressTestControlVar = Q_BASIC_ATOMIC_INITIALIZER(5);
Q_GLOBAL_STATIC_WITH_ARGS(ThrowingType, threadStressTestGS, (threadStressTestControlVar))
void tst_QGlobalStatic::threadStressTest()
{
if (QTestPrivate::isRunningArmOnX86())
QSKIP("Frequently hangs on QEMU, QTBUG-91423");
class ThreadStressTestThread: public QThread
{
public:
QReadWriteLock *lock;
void run() override
{
QReadLocker l(lock);
//usleep(QRandomGenerator::global()->generate(200));
// thundering herd
try {
threadStressTestGS();
} catch (int) {
}
}
};
ThrowingType::constructedCount.storeRelaxed(0);
ThrowingType::destructedCount.storeRelaxed(0);
int expectedConstructionCount = threadStressTestControlVar.loadRelaxed() + 1;
if (expectedConstructionCount <= 0)
QSKIP("This test cannot be run more than once");
#ifdef Q_OS_INTEGRITY
// OPEN_REALTIME_THREADS = 123 on current INTEGRITY environment
// if try to create more, app is halted
const int numThreads = 122;
#else
const int numThreads = 200;
#endif
ThreadStressTestThread threads[numThreads];
QReadWriteLock lock;
lock.lockForWrite();
for (int i = 0; i < numThreads; ++i) {
threads[i].lock = &lock;
threads[i].start();
}
// wait for all threads
// release the herd
lock.unlock();
for (int i = 0; i < numThreads; ++i)
threads[i].wait();
QCOMPARE(ThrowingType::constructedCount.loadAcquire(), expectedConstructionCount);
QCOMPARE(ThrowingType::destructedCount.loadAcquire(), 0);
}
Q_GLOBAL_STATIC(int, checkedAfterDestruction)
void tst_QGlobalStatic::afterDestruction()
{
// this test will not produce results now
// it will simply run some code on destruction (after the global statics have been deleted)
// if that fails, this will cause a crash
// static destruction is LIFO: so we must add our exit-time code before the
// global static is used for the first time
static struct RunAtExit {
~RunAtExit() {
int *ptr = checkedAfterDestruction();
if (ptr)
qFatal("Global static is not null as was expected");
}
} runAtExit;
(void) runAtExit;
*checkedAfterDestruction = 42;
}
QTEST_APPLESS_MAIN(tst_QGlobalStatic);
#include "tst_qglobalstatic.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qhooks Test:
#####################################################################
qt_internal_add_test(tst_qhooks
SOURCES
tst_qhooks.cpp
LIBRARIES
Qt::CorePrivate
)

View File

@ -0,0 +1,122 @@
// Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Volker Krause <volker.krause@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtCore/private/qhooks_p.h>
class tst_QHooks: public QObject
{
Q_OBJECT
private slots:
void cleanup();
void testVersion();
void testAddRemoveObject();
void testChaining();
};
void tst_QHooks::cleanup()
{
qtHookData[QHooks::AddQObject] = 0;
qtHookData[QHooks::RemoveQObject] = 0;
}
void tst_QHooks::testVersion()
{
QVERIFY(qtHookData[QHooks::HookDataVersion] >= 3);
QCOMPARE(qtHookData[QHooks::HookDataSize], (quintptr)QHooks::LastHookIndex);
QCOMPARE(qtHookData[QHooks::QtVersion], (quintptr)QT_VERSION);
}
static int objectCount = 0;
static void objectAddHook(QObject*)
{
++objectCount;
}
static void objectRemoveHook(QObject*)
{
--objectCount;
}
void tst_QHooks::testAddRemoveObject()
{
QCOMPARE(qtHookData[QHooks::AddQObject], (quintptr)0);
QCOMPARE(qtHookData[QHooks::RemoveQObject], (quintptr)0);
qtHookData[QHooks::AddQObject] = (quintptr)&objectAddHook;
qtHookData[QHooks::RemoveQObject] = (quintptr)&objectRemoveHook;
QCOMPARE(objectCount, 0);
QObject *obj = new QObject;
QVERIFY(objectCount > 0);
delete obj;
QCOMPARE(objectCount, 0);
}
static QList<QString> hookOrder;
static QHooks::AddQObjectCallback existingAddHook = 0;
static QHooks::RemoveQObjectCallback existingRemoveHook = 0;
static void firstAddHook(QObject *)
{
hookOrder.append(QLatin1String("firstAddHook"));
}
static void firstRemoveHook(QObject *)
{
hookOrder.append(QLatin1String("firstRemoveHook"));
}
static void secondAddHook(QObject *object)
{
if (existingAddHook)
existingAddHook(object);
hookOrder.append(QLatin1String("secondAddHook"));
}
static void secondRemoveHook(QObject *object)
{
if (existingRemoveHook)
existingRemoveHook(object);
hookOrder.append(QLatin1String("secondRemoveHook"));
}
// Tests that it's possible to "chain" hooks together (i.e. have multiple hooks)
void tst_QHooks::testChaining()
{
QCOMPARE(qtHookData[QHooks::AddQObject], (quintptr)0);
QCOMPARE(qtHookData[QHooks::RemoveQObject], (quintptr)0);
// Set the add and remove hooks (could just skip this and go straight to the next step,
// but it's for illustrative purposes).
qtHookData[QHooks::AddQObject] = (quintptr)&firstAddHook;
qtHookData[QHooks::RemoveQObject] = (quintptr)&firstRemoveHook;
// Store them so that we can call them later.
existingAddHook = reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject]);
existingRemoveHook = reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject]);
// Overide them with hooks that call them first.
qtHookData[QHooks::AddQObject] = (quintptr)&secondAddHook;
qtHookData[QHooks::RemoveQObject] = (quintptr)&secondRemoveHook;
QObject *obj = new QObject;
QCOMPARE(hookOrder.size(), 2);
QCOMPARE(hookOrder.at(0), QLatin1String("firstAddHook"));
QCOMPARE(hookOrder.at(1), QLatin1String("secondAddHook"));
delete obj;
QCOMPARE(hookOrder.size(), 4);
QCOMPARE(hookOrder.at(2), QLatin1String("firstRemoveHook"));
QCOMPARE(hookOrder.at(3), QLatin1String("secondRemoveHook"));
hookOrder.clear();
}
QTEST_APPLESS_MAIN(tst_QHooks)
#include "tst_qhooks.moc"

View File

@ -0,0 +1,11 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qkeycombination Test:
#####################################################################
qt_internal_add_test(tst_qkeycombination
SOURCES
tst_qkeycombination.cpp
)

View File

@ -0,0 +1,292 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QObject>
#include <QTest>
class tst_QKeyCombination : public QObject
{
Q_OBJECT
private slots:
void construction();
void operator_eq();
void operator_or();
};
constexpr int bitwiseOr()
{
return 0;
}
template <typename ...T>
constexpr auto bitwiseOr(T ... args)
{
return (... | ((int)args));
}
void tst_QKeyCombination::construction()
{
{
QKeyCombination combination;
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::CTRL); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ControlModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::ControlModifier, Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::SHIFT); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ShiftModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::ShiftModifier, Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::AltModifier); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::AltModifier, Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::AltModifier | Qt::ControlModifier); // explicit
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier | Qt::ControlModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::AltModifier, Qt::ControlModifier, Qt::Key_unknown));
}
{
QKeyCombination combination = Qt::Key_A; // implicit
QCOMPARE(combination.key(), Qt::Key_A);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_A));
}
{
QKeyCombination combination = Qt::Key_F1; // implicit
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_F1));
}
{
QKeyCombination combination(Qt::SHIFT, Qt::Key_F1);
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ShiftModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::SHIFT, Qt::Key_F1));
}
{
QKeyCombination combination(Qt::SHIFT | Qt::CTRL, Qt::Key_F1);
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ShiftModifier | Qt::ControlModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::SHIFT, Qt::CTRL, Qt::Key_F1));
}
{
QKeyCombination combination(Qt::AltModifier, Qt::Key_F1);
QCOMPARE(combination.key(), Qt::Key_F1);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::AltModifier, Qt::Key_F1));
}
// corner cases
{
QKeyCombination combination = Qt::Key_Alt;
QCOMPARE(combination.key(), Qt::Key_Alt);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_Alt));
}
{
QKeyCombination combination(Qt::ALT, Qt::Key_Alt);
QCOMPARE(combination.key(), Qt::Key_Alt);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::AltModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::ALT, Qt::Key_Alt));
}
{
QKeyCombination combination(Qt::Key_unknown);
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers{});
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::Key_unknown));
}
{
QKeyCombination combination(Qt::CTRL | Qt::SHIFT, Qt::Key_unknown);
QCOMPARE(combination.key(), Qt::Key_unknown);
QCOMPARE(combination.keyboardModifiers(), Qt::KeyboardModifiers(Qt::ControlModifier | Qt::ShiftModifier));
QCOMPARE(combination.toCombined(), bitwiseOr(Qt::CTRL, Qt::SHIFT, Qt::Key_unknown));
}
}
void tst_QKeyCombination::operator_eq()
{
// default
{
QKeyCombination a, b;
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// key only
{
QKeyCombination a;
QKeyCombination b(Qt::Key_X);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::Key_Y);
QKeyCombination b;
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::Key_Y);
QKeyCombination b(Qt::Key_X);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::Key_F1);
QKeyCombination b(Qt::Key_F1);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// modifier only
{
QKeyCombination a;
QKeyCombination b(Qt::CTRL);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b;
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::SHIFT);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::CTRL);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::ControlModifier);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::ControlModifier);
QKeyCombination b(Qt::CTRL);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::ControlModifier);
QKeyCombination b(Qt::ControlModifier);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// key and modifier
{
QKeyCombination a(Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_A);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::CTRL, Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_A);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::SHIFT, Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_A);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::SHIFT, Qt::Key_A);
QKeyCombination b(Qt::SHIFT, Qt::Key_Escape);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::SHIFT, Qt::Key_A);
QKeyCombination b(Qt::ShiftModifier, Qt::Key_A);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
{
QKeyCombination a(Qt::SHIFT | Qt::CTRL, Qt::Key_A);
QKeyCombination b(Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_A);
QVERIFY(a == b);
QVERIFY(!(a != b));
}
// corner cases
{
QKeyCombination a(Qt::CTRL);
QKeyCombination b(Qt::Key_Control);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
{
QKeyCombination a(Qt::ALT);
QKeyCombination b(Qt::Key_Alt);
QVERIFY(a != b);
QVERIFY(!(a == b));
}
}
void tst_QKeyCombination::operator_or()
{
// note tha operator+ between enumerators of the same enumeration
// yields int, so one can't do
// Qt::SHIFT + Qt::CTRL + Qt::Key_A
// but one can do
// Qt::SHIFT | Qt::CTRL | Qt::Key_A
QCOMPARE(Qt::SHIFT | Qt::Key_A, QKeyCombination(Qt::SHIFT, Qt::Key_A));
QCOMPARE(Qt::AltModifier | Qt::Key_F1, QKeyCombination(Qt::AltModifier, Qt::Key_F1));
QCOMPARE(Qt::SHIFT | Qt::ALT | Qt::Key_F1, QKeyCombination(Qt::SHIFT | Qt::ALT, Qt::Key_F1));
QCOMPARE(Qt::ControlModifier | Qt::Key_Escape, QKeyCombination(Qt::ControlModifier, Qt::Key_Escape));
}
QTEST_APPLESS_MAIN(tst_QKeyCombination)
#include "tst_qkeycombination.moc"

View File

@ -0,0 +1,9 @@
[qMessagePattern:backtrace]
# QTBUG-63915
b2qt 64bit
[qMessagePattern:backtrace depth,separator]
# QTBUG-63915
b2qt 64bit
# QTBUG-85364
b2qt cmake

View File

@ -0,0 +1,26 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_executable(qlogging_helper
NO_INSTALL
OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
SOURCES app/main.cpp
DEFINES QT_MESSAGELOGCONTEXT
LIBRARIES Qt::Core)
# Fixes required for the backtrace stack to be correct
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT MINGW)
target_link_options(qlogging_helper PRIVATE -rdynamic)
endif()
set_target_properties(qlogging_helper PROPERTIES CXX_VISIBILITY_PRESET default)
qt_internal_add_test(tst_qlogging SOURCES tst_qlogging.cpp
DEFINES
QT_MESSAGELOGCONTEXT
HELPER_BINARY="${CMAKE_CURRENT_BINARY_DIR}/qlogging_helper"
)
qt_internal_add_test(tst_qmessagelogger SOURCES tst_qmessagelogger.cpp
DEFINES
QT_MESSAGELOGCONTEXT
)

View File

@ -0,0 +1,63 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QCoreApplication>
#include <QLoggingCategory>
#ifdef Q_CC_GNU
#define NEVER_INLINE __attribute__((__noinline__))
#else
#define NEVER_INLINE
#endif
struct T {
T() { qDebug("static constructor"); }
~T() { qDebug("static destructor"); }
} t;
class MyClass : public QObject
{
Q_OBJECT
public slots:
virtual NEVER_INLINE QString mySlot1();
private:
virtual NEVER_INLINE void myFunction(int a);
};
QString MyClass::mySlot1()
{
myFunction(34);
return QString();
}
void MyClass::myFunction(int a)
{
qDebug() << "from_a_function" << a;
}
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
app.setApplicationName("tst_qlogging");
qSetMessagePattern("[%{type}] %{message}");
qDebug("qDebug");
qInfo("qInfo");
qWarning("qWarning");
qCritical("qCritical");
QLoggingCategory cat("category");
qCWarning(cat) << "qDebug with category";
qSetMessagePattern(QString());
qDebug("qDebug2");
MyClass cl;
QMetaObject::invokeMethod(&cl, "mySlot1");
return 0;
}
#include "main.moc"

View File

@ -0,0 +1,988 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2022 Intel Corporation.
// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qdebug.h>
#include <qglobal.h>
#if QT_CONFIG(process)
# include <QtCore/QProcess>
#endif
#include <QtTest/QTest>
#include <QList>
#include <QMap>
class tst_qmessagehandler : public QObject
{
Q_OBJECT
public:
tst_qmessagehandler();
public slots:
void initTestCase();
private slots:
void cleanup();
void defaultHandler();
void installMessageHandler();
#ifdef QT_BUILD_INTERNAL
void cleanupFuncinfo_data();
void cleanupFuncinfo();
void cleanupFuncinfoBad_data();
void cleanupFuncinfoBad();
#endif
void qMessagePattern_data();
void qMessagePattern();
void setMessagePattern();
void formatLogMessage_data();
void formatLogMessage();
private:
QString backtraceHelperPath();
#if QT_CONFIG(process)
QProcessEnvironment m_baseEnvironment;
#endif
};
static QtMsgType s_type;
const char *s_file;
int s_line;
const char *s_function;
static QString s_message;
void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
s_type = type;
s_file = context.file;
s_line = context.line;
s_function = context.function;
s_message = msg;
}
tst_qmessagehandler::tst_qmessagehandler()
{
// ensure it's unset, otherwise we'll have trouble
qputenv("QT_MESSAGE_PATTERN", "");
}
void tst_qmessagehandler::initTestCase()
{
#if QT_CONFIG(process)
m_baseEnvironment = QProcessEnvironment::systemEnvironment();
m_baseEnvironment.remove("QT_MESSAGE_PATTERN");
m_baseEnvironment.insert("QT_FORCE_STDERR_LOGGING", "1");
#endif // QT_CONFIG(process)
}
void tst_qmessagehandler::cleanup()
{
qInstallMessageHandler((QtMessageHandler)0);
s_type = QtFatalMsg;
s_file = 0;
s_line = 0;
s_function = 0;
}
void tst_qmessagehandler::defaultHandler()
{
// check that the default works
QTest::ignoreMessage(QtDebugMsg, "defaultHandler");
qDebug("defaultHandler");
}
void tst_qmessagehandler::installMessageHandler()
{
QtMessageHandler oldHandler = qInstallMessageHandler(customMessageHandler);
qDebug("installMessageHandler"); int line = __LINE__;
QCOMPARE(s_type, QtDebugMsg);
QCOMPARE(s_message, QString::fromLocal8Bit("installMessageHandler"));
QCOMPARE(s_file, __FILE__);
QCOMPARE(s_function, Q_FUNC_INFO);
QCOMPARE(s_line, line);
QtMessageHandler myHandler = qInstallMessageHandler(oldHandler);
QCOMPARE((void*)myHandler, (void*)customMessageHandler);
}
# define ADD(x) QTest::newRow(x) << Q_FUNC_INFO << x;
class TestClass1
{
public:
enum Something { foo };
char c;
void func_void() { ADD("TestClass1::func_void"); }
int func_int() { ADD("TestClass1::func_int"); return 0; }
unsigned func_unsigned() { ADD("TestClass1::func_unsigned"); return 0; }
long func_long() { ADD("TestClass1::func_long"); return 0; }
long long func_ll() { ADD("TestClass1::func_ll"); return 0; }
unsigned long long func_ull() { ADD("TestClass1::func_ull"); return 0; }
char func_char() { ADD("TestClass1::func_char"); return 0; }
signed char func_schar() { ADD("TestClass1::func_schar"); return 0; }
unsigned char func_uchar() { ADD("TestClass1::func_uchar"); return 0; }
char &func_Rchar() { ADD("TestClass1::func_Rchar"); return c; }
char *func_Pchar() { ADD("TestClass1::func_Pchar"); return 0; }
const char *func_KPchar() { ADD("TestClass1::func_KPchar"); return 0; }
const volatile char *func_VKPchar() { ADD("TestClass1::func_VKPchar"); return 0; }
const volatile unsigned long long * func_KVPull() { ADD("TestClass1::func_KVPull"); return 0; }
const void * const volatile *func_KPKVvoid() { ADD("TestClass1::func_KPKVvoid"); return 0; }
QList<int> func_ai() { ADD("TestClass1::func_ai"); return QList<int>(); }
QList<unsigned long long const volatile*> func_aptr() { ADD("TestClass1::func_aptr"); return QList<unsigned long long const volatile*>(); }
QList<Something> func_aenum() { ADD("TestClass1::func_aenum"); return QList<Something>(); }
QList<QList<const void *> > func_aaptr() { ADD("TestClass1::func_aaptr"); return QList<QList<const void *> >(); }
QMap<int, Something> func_ienummap() { ADD("TestClass1::func_ienummap"); return QMap<int, Something>(); }
template<typename T>
T* func_template1() { ADD("TestClass1::func_template1"); return 0; }
template<Something val>
long func_template2() { ADD("TestClass1::func_template2"); return long(val); }
typedef unsigned long long * ( *fptr)();
typedef unsigned long long * (TestClass1::* pmf)();
typedef fptr (TestClass1::* uglypmf)();
fptr func_fptr() { ADD("TestClass1::func_fptr"); return 0; }
pmf func_pmf() { ADD("TestClass1::func_pmf"); return 0; }
uglypmf func_uglypmf(uglypmf = 0) { ADD("TestClass1::func_uglypmf"); return 0; }
QMap<QString, uglypmf> func_uglypmf2() { ADD("TestClass1::func_uglypmf2"); return QMap<QString, uglypmf>(); }
void operator()() { ADD("TestClass1::operator()"); }
int operator<(int) { ADD("TestClass1::operator<"); return 0; }
int operator>(int) { ADD("TestClass1::operator>"); return 0; }
int operator<=(int) { ADD("TestClass1::operator<="); return 0; }
int operator>=(int) { ADD("TestClass1::operator>="); return 0; }
int operator=(int) { ADD("TestClass1::operator="); return 0; }
int operator+(int) { ADD("TestClass1::operator+"); return 0; }
int operator-(int) { ADD("TestClass1::operator-"); return 0; }
int operator*(int) { ADD("TestClass1::operator*"); return 0; }
int operator/(int) { ADD("TestClass1::operator/"); return 0; }
int operator%(int) { ADD("TestClass1::operator%"); return 0; }
int x;
int &operator++() { ADD("TestClass1::operator++"); return x; }
int &operator--() { ADD("TestClass1::operator--"); return x; }
// slightly different to avoid duplicate test rows
#define ADD2(x) QTest::newRow(x ".postfix") << Q_FUNC_INFO << x;
int operator++(int) { ADD2("TestClass1::operator++"); return 0; }
int operator--(int) { ADD2("TestClass1::operator--"); return 0; }
#undef ADD2
int nested_struct()
{
struct Nested { void nested() { ADD("TestClass1::nested_struct"); } };
Nested().nested();
return 0;
}
int nested_struct_const() const
{
struct Nested { void nested() { ADD("TestClass1::nested_struct_const"); } };
Nested().nested();
return 0;
}
#ifdef Q_COMPILER_REF_QUALIFIERS
int lvalue() & { ADD("TestClass1::lvalue"); return 0; }
int const_lvalue() const & { ADD("TestClass1::const_lvalue"); return 0; }
int rvalue() && { ADD("TestClass1::rvalue"); return 0; }
int const_rvalue() const && { ADD("TestClass1::const_rvalue"); return 0; }
#endif
int decltype_param(int x = 0, decltype(x) = 0) { ADD("TestClass1::decltype_param"); return x; }
template<typename T> int decltype_template_param(T x = 0, decltype(x) = 0)
{ ADD("TestClass1::decltype_template_param"); return x; }
template<typename T> void decltype_template_param2(T x, decltype(x + QString()))
{ ADD("TestClass1::decltype_template_param2"); }
auto decltype_return(int x = 0) -> decltype(x)
{ ADD("TestClass1::decltype_return"); return x; }
template <typename T> auto decltype_template_return(T x = 0) -> decltype(x)
{ ADD("TestClass1::decltype_template_return"); return x; }
public:
TestClass1()
{
// instantiate
func_void();
func_int();
func_unsigned();
func_long();
func_ll();
func_ull();
func_char();
func_schar();
func_uchar();
func_Rchar();
func_Pchar();
func_KPchar();
func_VKPchar();
func_KVPull();
func_KPKVvoid();
func_ai();
func_aptr();
func_aenum();
func_aaptr();
func_ienummap();
func_template1<TestClass1>();
func_template2<foo>();
func_fptr();
func_pmf();
func_uglypmf();
func_uglypmf2();
operator()();
operator<(0);
operator>(0);
operator<=(0);
operator>=(0);
operator=(0);
operator+(0);
operator-(0);
operator*(0);
operator/(0);
operator%(0);
operator++();
operator++(0);
operator--();
operator--(0);
nested_struct();
nested_struct_const();
#ifdef Q_COMPILER_REF_QUALIFIERS
lvalue();
const_lvalue();
std::move(*this).rvalue();
std::move(*this).const_rvalue();
#endif
decltype_param();
decltype_template_param(0);
decltype_template_param2(QByteArray(), QString());
decltype_return();
decltype_template_return(0);
}
};
template<typename T> class TestClass2
{
long func_long() { ADD("TestClass2::func_long"); return 0; }
template<typename S>
T* func_template1() { ADD("TestClass2::func_template1"); return 0; }
template<TestClass1::Something val>
long func_template2() { ADD("TestClass2::func_template2"); return long(val); }
public:
TestClass2()
{
func_long();
func_template1<TestClass2>();
func_template2<TestClass1::foo>();
}
};
template<typename T, TestClass1::Something v> class TestClass3
{
long func_long() { ADD("TestClass3::func_long"); return 0; }
template<typename S>
S* func_template1() { ADD("TestClass3::func_template1"); return 0; }
template<TestClass1::Something val>
long func_template2() { ADD("TestClass3::func_template2"); return long(val); }
public:
struct Foo { TestClass3 foo; };
TestClass3()
{
func_long();
func_template1<TestClass2<T> >();
func_template2<TestClass1::foo>();
}
};
class TestClass4
{
TestClass1 c1;
TestClass2<std::map<long, const void *> > func2()
{ ADD("TestClass4::func2"); return TestClass2<std::map<long, const void *> >(); }
TestClass3<std::map<std::list<int>, const void *>, TestClass1::foo>::Foo func3()
{ ADD("TestClass4::func3"); return TestClass3<std::map<std::list<int>, const void *>, TestClass1::foo>::Foo(); }
public:
TestClass4()
{
func2();
func3();
ADD("TestClass4::TestClass4");
}
~TestClass4()
{
ADD("TestClass4::~TestClass4");
}
};
#ifdef QT_BUILD_INTERNAL
void tst_qmessagehandler::cleanupFuncinfo_data()
{
QTest::addColumn<QString>("funcinfo");
QTest::addColumn<QString>("expected");
TestClass4 c4;
QTest::newRow("msvc_01")
<< "void __thiscall TestClass1::func_void(void)"
<< "TestClass1::func_void";
QTest::newRow("gcc_01")
<< "void TestClass1::func_void()"
<< "TestClass1::func_void";
QTest::newRow("msvc_02")
<< "int __thiscall TestClass1::func_int(void)"
<< "TestClass1::func_int";
QTest::newRow("gcc_02")
<< "int TestClass1::func_int()"
<< "TestClass1::func_int";
QTest::newRow("msvc_03")
<< "unsigned int __thiscall TestClass1::func_unsigned(void)"
<< "TestClass1::func_unsigned";
QTest::newRow("gcc_03")
<< "unsigned int TestClass1::func_unsigned()"
<< "TestClass1::func_unsigned";
QTest::newRow("msvc_04")
<< "long __thiscall TestClass1::func_long(void)"
<< "TestClass1::func_long";
QTest::newRow("gcc_04")
<< "long int TestClass1::func_long()"
<< "TestClass1::func_long";
QTest::newRow("msvc_05")
<< "__int64 __thiscall TestClass1::func_ll(void)"
<< "TestClass1::func_ll";
QTest::newRow("gcc_05")
<< "long long int TestClass1::func_ll()"
<< "TestClass1::func_ll";
QTest::newRow("msvc_06")
<< "unsigned __int64 __thiscall TestClass1::func_ull(void)"
<< "TestClass1::func_ull";
QTest::newRow("gcc_06")
<< "long long unsigned int TestClass1::func_ull()"
<< "TestClass1::func_ull";
QTest::newRow("msvc_07")
<< "char __thiscall TestClass1::func_char(void)"
<< "TestClass1::func_char";
QTest::newRow("gcc_07")
<< "char TestClass1::func_char()"
<< "TestClass1::func_char";
QTest::newRow("msvc_08")
<< "signed char __thiscall TestClass1::func_schar(void)"
<< "TestClass1::func_schar";
QTest::newRow("gcc_08")
<< "signed char TestClass1::func_schar()"
<< "TestClass1::func_schar";
QTest::newRow("msvc_09")
<< "unsigned char __thiscall TestClass1::func_uchar(void)"
<< "TestClass1::func_uchar";
QTest::newRow("gcc_09")
<< "unsigned char TestClass1::func_uchar()"
<< "TestClass1::func_uchar";
QTest::newRow("msvc_09a")
<< "char &__thiscall TestClass1::func_Rchar(void)"
<< "TestClass1::func_Rchar";
QTest::newRow("gcc_09a")
<< "char& TestClass1::func_Rchar()"
<< "TestClass1::func_Rchar";
QTest::newRow("clang_09a")
<< "char &TestClass1::func_Rchar()"
<< "TestClass1::func_Rchar";
QTest::newRow("msvc_10")
<< "char *__thiscall TestClass1::func_Pchar(void)"
<< "TestClass1::func_Pchar";
QTest::newRow("gcc_10")
<< "char* TestClass1::func_Pchar()"
<< "TestClass1::func_Pchar";
QTest::newRow("clang_10")
<< "char *TestClass1::func_Pchar()"
<< "TestClass1::func_Pchar";
QTest::newRow("msvc_11")
<< "const char *__thiscall TestClass1::func_KPchar(void)"
<< "TestClass1::func_KPchar";
QTest::newRow("gcc_11")
<< "const char* TestClass1::func_KPchar()"
<< "TestClass1::func_KPchar";
QTest::newRow("msvc_12")
<< "volatile const char *__thiscall TestClass1::func_VKPchar(void)"
<< "TestClass1::func_VKPchar";
QTest::newRow("gcc_12")
<< "const volatile char* TestClass1::func_VKPchar()"
<< "TestClass1::func_VKPchar";
QTest::newRow("msvc_13")
<< "volatile const unsigned __int64 *__thiscall TestClass1::func_KVPull(void)"
<< "TestClass1::func_KVPull";
QTest::newRow("gcc_13")
<< "const volatile long long unsigned int* TestClass1::func_KVPull()"
<< "TestClass1::func_KVPull";
QTest::newRow("msvc_14")
<< "const void *volatile const *__thiscall TestClass1::func_KPKVvoid(void)"
<< "TestClass1::func_KPKVvoid";
QTest::newRow("gcc_14")
<< "const void* const volatile* TestClass1::func_KPKVvoid()"
<< "TestClass1::func_KPKVvoid";
QTest::newRow("msvc_15")
<< "class QList<int> __thiscall TestClass1::func_ai(void)"
<< "TestClass1::func_ai";
QTest::newRow("gcc_15")
<< "QList<int> TestClass1::func_ai()"
<< "TestClass1::func_ai";
QTest::newRow("msvc_16")
<< "class QList<unsigned __int64 const volatile *> __thiscall TestClass1::func_aptr(void)"
<< "TestClass1::func_aptr";
QTest::newRow("gcc_16")
<< "QList<const volatile long long unsigned int*> TestClass1::func_aptr()"
<< "TestClass1::func_aptr";
QTest::newRow("msvc_17")
<< "class QList<enum TestClass1::Something> __thiscall TestClass1::func_aenum(void)"
<< "TestClass1::func_aenum";
QTest::newRow("gcc_17")
<< "QList<TestClass1::Something> TestClass1::func_aenum()"
<< "TestClass1::func_aenum";
QTest::newRow("msvc_18")
<< "class QList<class QList<void const *> > __thiscall TestClass1::func_aaptr(void)"
<< "TestClass1::func_aaptr";
QTest::newRow("gcc_18")
<< "QList<QList<const void*> > TestClass1::func_aaptr()"
<< "TestClass1::func_aaptr";
QTest::newRow("msvc_19")
<< "class QMap<int,enum TestClass1::Something> __thiscall TestClass1::func_ienummap(void)"
<< "TestClass1::func_ienummap";
QTest::newRow("gcc_19")
<< "QMap<int, TestClass1::Something> TestClass1::func_ienummap()"
<< "TestClass1::func_ienummap";
QTest::newRow("msvc_20")
<< "class TestClass1 *__thiscall TestClass1::func_template1<class TestClass1>(void)"
<< "TestClass1::func_template1";
QTest::newRow("gcc_20")
<< "T* TestClass1::func_template1() [with T = TestClass1]"
<< "TestClass1::func_template1";
QTest::newRow("msvc_21")
<< "long __thiscall TestClass1::func_template2<foo>(void)"
<< "TestClass1::func_template2";
QTest::newRow("gcc_21")
<< "long int TestClass1::func_template2() [with TestClass1::Something val = foo]"
<< "TestClass1::func_template2";
QTest::newRow("msvc_22")
<< "unsigned __int64 *(__cdecl *__thiscall TestClass1::func_fptr(void))(void)"
<< "TestClass1::func_fptr";
QTest::newRow("gcc_22")
<< "long long unsigned int* (* TestClass1::func_fptr())()"
<< "TestClass1::func_fptr";
QTest::newRow("msvc_23")
<< "unsigned __int64 *(__thiscall TestClass1::* __thiscall TestClass1::func_pmf(void))(void)"
<< "TestClass1::func_pmf";
QTest::newRow("gcc_23")
<< "long long unsigned int* (TestClass1::* TestClass1::func_pmf())()"
<< "TestClass1::func_pmf";
QTest::newRow("msvc_24")
<< "unsigned __int64 *(__cdecl *(__thiscall TestClass1::* __thiscall TestClass1::func_uglypmf(unsigned __int64 *(__cdecl *(__thiscall TestClass1::* )(void))(void)))(void))(void)"
<< "TestClass1::func_uglypmf";
QTest::newRow("gcc_24")
<< "long long unsigned int* (* (TestClass1::* TestClass1::func_uglypmf(long long unsigned int* (* (TestClass1::*)())()))())()"
<< "TestClass1::func_uglypmf";
QTest::newRow("msvc_25")
<< "class QMap<class QString,unsigned __int64 * (__cdecl*(__thiscall TestClass1::*)(void))(void)> __thiscall TestClass1::func_uglypmf2(void)"
<< "TestClass1::func_uglypmf2";
QTest::newRow("gcc_25")
<< "QMap<QString, long long unsigned int* (* (TestClass1::*)())()> TestClass1::func_uglypmf2()"
<< "TestClass1::func_uglypmf2";
QTest::newRow("msvc_26")
<< "class TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > > __thiscall TestClass4::func2(void)"
<< "TestClass4::func2";
QTest::newRow("gcc_26")
<< "TestClass2<std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > > > TestClass4::func2()"
<< "TestClass4::func2";
QTest::newRow("msvc_27")
<< "long __thiscall TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >::func_long(void)"
<< "TestClass2::func_long";
QTest::newRow("gcc_27")
<< "long int TestClass2<T>::func_long() [with T = std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > >]"
<< "TestClass2::func_long";
QTest::newRow("msvc_28")
<< "class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > *__thiscall TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >::func_template1<class TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >>(void)"
<< "TestClass2::func_template1";
QTest::newRow("gcc_28")
<< "T* TestClass2<T>::func_template1() [with S = TestClass2<std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > > >, T = std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > >]"
<< "TestClass2::func_template1";
QTest::newRow("msvc_29")
<< "long __thiscall TestClass2<class std::map<long,void const *,struct std::less<long>,class std::allocator<struct std::pair<long const ,void const *> > > >::func_template2<foo>(void)"
<< "TestClass2::func_template2";
QTest::newRow("gcc_29")
<< "long int TestClass2<T>::func_template2() [with TestClass1::Something val = foo, T = std::map<long int, const void*, std::less<long int>, std::allocator<std::pair<const long int, const void*> > >]"
<< "TestClass2::func_template2";
QTest::newRow("msvc_30")
<< "struct TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::Foo __thiscall TestClass4::func3(void)"
<< "TestClass4::func3";
QTest::newRow("gcc_30")
<< "TestClass3<std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, foo>::Foo TestClass4::func3()"
<< "TestClass4::func3";
QTest::newRow("msvc_31")
<< "long __thiscall TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::func_long(void)"
<< "TestClass3::func_long";
QTest::newRow("gcc_31")
<< "long int TestClass3<T, v>::func_long() [with T = std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, TestClass1::Something v = foo]"
<< "TestClass3::func_long";
QTest::newRow("msvc_32")
<< "class TestClass2<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > > > *__thiscall TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::func_template1<class TestClass2<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > > >>(void)"
<< "TestClass3::func_template1";
QTest::newRow("gcc_32")
<< "S* TestClass3<T, v>::func_template1() [with S = TestClass2<std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > > >, T = std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, TestClass1::Something v = foo]"
<< "TestClass3::func_template1";
QTest::newRow("msvc_33")
<< "long __thiscall TestClass3<class std::map<class std::list<int,class std::allocator<int> >,void const *,struct std::less<class std::list<int,class std::allocator<int> > >,class std::allocator<struct std::pair<class std::list<int,class std::allocator<int> > const ,void const *> > >,0>::func_template2<foo>(void)"
<< "TestClass3::func_template2";
QTest::newRow("gcc_33")
<< "long int TestClass3<T, v>::func_template2() [with TestClass1::Something val = foo, T = std::map<std::list<int, std::allocator<int> >, const void*, std::less<std::list<int, std::allocator<int> > >, std::allocator<std::pair<const std::list<int, std::allocator<int> >, const void*> > >, TestClass1::Something v = foo]"
<< "TestClass3::func_template2";
QTest::newRow("msvc_34")
<< "__thiscall TestClass4::TestClass4(void)"
<< "TestClass4::TestClass4";
QTest::newRow("gcc_34")
<< "TestClass4::TestClass4()"
<< "TestClass4::TestClass4";
QTest::newRow("msvc_35")
<< "__thiscall TestClass4::~TestClass4(void)"
<< "TestClass4::~TestClass4";
QTest::newRow("gcc_35")
<< "TestClass4::~TestClass4()"
<< "TestClass4::~TestClass4";
QTest::newRow("gcc_36")
<< "void TestClass1::operator()()"
<< "TestClass1::operator()";
QTest::newRow("gcc_37")
<< "long int TestClass1::func_template2() [with TestClass1::Something val = (TestClass1::Something)0u]"
<< "TestClass1::func_template2";
QTest::newRow("gcc_38")
<< "int TestClass1::operator<(int)"
<< "TestClass1::operator<";
QTest::newRow("gcc_39")
<< "int TestClass1::operator>(int)"
<< "TestClass1::operator>";
QTest::newRow("gcc_40")
<< "Polymorphic<void (*)(int)>::~Polymorphic()"
<< "Polymorphic::~Polymorphic";
QTest::newRow("gcc_41")
<< "function<void (int*)>()::S::f()"
<< "function()::S::f";
QTest::newRow("msvc_41")
<< "void `void function<void __cdecl(int *)>(void)'::`2'::S::f(void)"
<< "function(void)'::`2'::S::f";
QTest::newRow("gcc_42")
<< "function<Polymorphic<void (int*)> >()::S::f(Polymorphic<void (int*)>*)"
<< "function()::S::f";
QTest::newRow("msvc_42")
<< "void `void function<Polymorphic<void __cdecl(int *)> >(void)'::`2'::S::f(Polymorphic<void __cdecl(int *)> *)"
<< "function(void)'::`2'::S::f";
QTest::newRow("objc_1")
<< "-[SomeClass someMethod:withArguments:]"
<< "-[SomeClass someMethod:withArguments:]";
QTest::newRow("objc_2")
<< "+[SomeClass withClassMethod:withArguments:]"
<< "+[SomeClass withClassMethod:withArguments:]";
QTest::newRow("objc_3")
<< "-[SomeClass someMethodWithoutArguments]"
<< "-[SomeClass someMethodWithoutArguments]";
QTest::newRow("objc_4")
<< "__31-[SomeClass someMethodSchedulingBlock]_block_invoke"
<< "__31-[SomeClass someMethodSchedulingBlock]_block_invoke";
QTest::newRow("thunk-1")
<< "non-virtual thunk to QFutureWatcherBasePrivate::postCallOutEvent(QFutureCallOutEvent const&)"
<< "QFutureWatcherBasePrivate::postCallOutEvent";
QTest::newRow("thunk-2")
<< "virtual thunk to std::basic_iostream<char, std::char_traits<char> >::~basic_iostream()"
<< "std::basic_iostream::~basic_iostream";
}
#endif
#ifdef QT_BUILD_INTERNAL
QT_BEGIN_NAMESPACE
extern QByteArray qCleanupFuncinfo(QByteArray);
QT_END_NAMESPACE
#endif
#ifdef QT_BUILD_INTERNAL
void tst_qmessagehandler::cleanupFuncinfo()
{
QFETCH(QString, funcinfo);
// qDebug() << funcinfo.toLatin1();
QByteArray result = qCleanupFuncinfo(funcinfo.toLatin1());
QEXPECT_FAIL("TestClass1::nested_struct", "Nested function processing is broken", Continue);
QEXPECT_FAIL("TestClass1::nested_struct_const", "Nested function processing is broken", Continue);
QTEST(QString::fromLatin1(result), "expected");
}
void tst_qmessagehandler::cleanupFuncinfoBad_data()
{
QTest::addColumn<QByteArray>("funcinfo");
auto addBadFrame = [i = 0](const char *symbol) mutable {
QTest::addRow("%d", ++i) << QByteArray(symbol);
};
addBadFrame("typeinfo for QEventLoop");
addBadFrame("typeinfo name for QtPrivate::ResultStoreBase");
addBadFrame("typeinfo name for ._anon_476");
addBadFrame("typeinfo name for std::__1::__function::__base<bool (void*, void*)>");
addBadFrame("vtable for BezierEase");
addBadFrame("vtable for Polymorphic<void ()>");
addBadFrame("vtable for Polymorphic<void (*)(int)>");
addBadFrame("TLS wrapper function for (anonymous namespace)::jitStacks");
addBadFrame("lcCheckIndex()::category");
addBadFrame("guard variable for lcEPDetach()::category");
addBadFrame("guard variable for QImageReader::read(QImage*)::disableNxImageLoading");
addBadFrame("VTT for std::__1::ostrstream");
addBadFrame("qIsRelocatable<(anonymous namespace)::Data>");
addBadFrame("qt_incomplete_metaTypeArray<(anonymous namespace)::qt_meta_stringdata_CLASSQNonContiguousByteDeviceIoDeviceImplENDCLASS_t, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, true> > >");
addBadFrame("f()::i");
}
void tst_qmessagehandler::cleanupFuncinfoBad()
{
QFETCH(QByteArray, funcinfo);
// A corrupted stack trace may find non-sensical symbols that aren't
// functions. The result doesn't matter, so long as we don't crash or hang.
QByteArray result = qCleanupFuncinfo(funcinfo);
qDebug() << "Decode of" << funcinfo << "produced" << result;
}
#endif
void tst_qmessagehandler::qMessagePattern_data()
{
QTest::addColumn<QString>("pattern");
QTest::addColumn<bool>("valid");
QTest::addColumn<QList<QByteArray> >("expected");
// %{file} is tricky because of shadow builds
QTest::newRow("basic") << "%{type} %{appname} %{line} %{function} %{message}" << true << (QList<QByteArray>()
<< "debug 14 T::T static constructor"
// we can't be sure whether the QT_MESSAGE_PATTERN is already destructed
<< "static destructor"
<< "debug tst_qlogging 35 MyClass::myFunction from_a_function 34"
<< "debug tst_qlogging 45 main qDebug"
<< "info tst_qlogging 46 main qInfo"
<< "warning tst_qlogging 47 main qWarning"
<< "critical tst_qlogging 48 main qCritical"
<< "warning tst_qlogging 51 main qDebug with category"
<< "debug tst_qlogging 55 main qDebug2");
QTest::newRow("invalid") << "PREFIX: %{unknown} %{message}" << false << (QList<QByteArray>()
<< "QT_MESSAGE_PATTERN: Unknown placeholder %{unknown}"
<< "PREFIX: qDebug");
// test the if condition
QTest::newRow("ifs") << "[%{if-debug}D%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{if-category}%{category}: %{endif}%{message}"
<< true << (QList<QByteArray>()
<< "[D] static constructor"
// we can't be sure whether the QT_MESSAGE_PATTERN is already destructed
<< "static destructor"
<< "[D] qDebug"
<< "[W] qWarning"
<< "[C] qCritical"
<< "[W] category: qDebug with category"
<< "[D] qDebug2");
// test few errors cases
QTest::newRow("ifs-invalid1") << "PREFIX: %{unknown} %{endif} %{if-warning}"
<< false << (QList<QByteArray>()
<< "QT_MESSAGE_PATTERN: Unknown placeholder %{unknown}"
<< "QT_MESSAGE_PATTERN: %{endif} without an %{if-*}"
<< "QT_MESSAGE_PATTERN: missing %{endif}");
QTest::newRow("ifs-invalid2") << "A %{if-debug}DEBUG%{if-warning}WARNING%{endif} %{message} "
<< false << (QList<QByteArray>()
<< "QT_MESSAGE_PATTERN: %{if-*} cannot be nested"
<< "A DEBUG qDebug "
<< "A qWarning ");
QTest::newRow("pid-tid") << "%{pid}/%{threadid}: %{message}"
<< true << QList<QByteArray>(); // can't match anything, just test validity
QTest::newRow("qthreadptr") << "ThreadId:%{qthreadptr}: %{message}"
<< true << (QList<QByteArray>()
<< "ThreadId:0x");
// This test won't work when midnight is too close... wait a bit
while (QTime::currentTime() > QTime(23, 59, 30))
QTest::qWait(10000);
QTest::newRow("time") << "/%{time yyyy - MM - d}/%{message}"
<< true << (QList<QByteArray>()
<< ('/' + QDateTime::currentDateTime().toString("yyyy - MM - d").toLocal8Bit() + "/qDebug"));
QTest::newRow("time-time") << "/%{time yyyy - MM - d}/%{time dd-MM-yy}/%{message}"
<< true << (QList<QByteArray>()
<< ('/' + QDateTime::currentDateTime().toString("yyyy - MM - d").toLocal8Bit()
+ '/' + QDateTime::currentDateTime().toString("dd-MM-yy").toLocal8Bit()
+ "/qDebug"));
QTest::newRow("skipped-time-shown-time")
<< "/%{if-warning}%{time yyyy - MM - d}%{endif}%{if-debug}%{time dd-MM-yy}%{endif}/%{message}"
<< true << (QList<QByteArray>()
<< ('/' + QDateTime::currentDateTime().toString("dd-MM-yy").toLocal8Bit() + "/qDebug"));
// %{time} should have a padding of 6 so if it takes less than 10 seconds to show
// the first message, there should be 5 spaces
QTest::newRow("time-process") << "<%{time process}>%{message}" << true << (QList<QByteArray>()
<< "< ");
#define BACKTRACE_HELPER_NAME "qlogging_helper"
#ifdef QT_NAMESPACE
#define QT_NAMESPACE_STR QT_STRINGIFY(QT_NAMESPACE::)
#else
#define QT_NAMESPACE_STR ""
#endif
#ifdef __GLIBC__
# if QT_CONFIG(static)
// These test cases don't work with static Qt builds
# elif defined(QT_ASAN_ENABLED)
// These tests produce far more call frames under ASan
# else
# ifndef QT_NO_DEBUG
QList<QByteArray> expectedBacktrace = {
// MyClass::qt_static_metacall is explicitly marked as hidden in the
// Q_OBJECT macro hence the ?helper? frame
"[MyClass::myFunction|MyClass::mySlot1|?" BACKTRACE_HELPER_NAME "?|",
// QMetaObject::invokeMethodImpl calls internal function
// (QMetaMethodPrivate::invokeImpl, at the tims of this writing), which
// will usually show only as ?libQt6Core.so? or equivalent, so we skip
// end of backtrace, actual message
"|" QT_NAMESPACE_STR "QMetaObject::invokeMethodImpl] from_a_function 34"
};
QTest::newRow("backtrace") << "[%{backtrace}] %{message}" << true << expectedBacktrace;
# endif
QTest::newRow("backtrace depth,separator") << "[%{backtrace depth=2 separator=\"\n\"}] %{message}" << true << (QList<QByteArray>()
<< "[MyClass::myFunction\nMyClass::mySlot1] from_a_function 34"
<< "[T::T\n");
# endif // #if !QT_CONFIG(static)
#endif // #ifdef __GLIBC__
}
void tst_qmessagehandler::qMessagePattern()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#else
#ifdef Q_OS_ANDROID
QSKIP("This test crashes on Android");
#endif
QFETCH(QString, pattern);
QFETCH(bool, valid);
QFETCH(QList<QByteArray>, expected);
QProcess process;
const QString appExe(backtraceHelperPath());
//
// test QT_MESSAGE_PATTERN
//
QProcessEnvironment environment = m_baseEnvironment;
environment.insert("QT_MESSAGE_PATTERN", pattern);
process.setProcessEnvironment(environment);
process.start(appExe);
QVERIFY2(process.waitForStarted(), qPrintable(
QString::fromLatin1("Could not start %1: %2").arg(appExe, process.errorString())));
QByteArray pid = QByteArray::number(process.processId());
process.waitForFinished();
QByteArray output = process.readAllStandardError();
// qDebug() << output;
QVERIFY(!output.isEmpty());
QCOMPARE(!output.contains("QT_MESSAGE_PATTERN"), valid);
for (const QByteArray &e : std::as_const(expected)) {
if (!output.contains(e)) {
// use QDebug so we get proper string escaping for the newlines
QString buf;
QDebug(&buf) << "Got:" << output << "; Expected:" << e;
QVERIFY2(output.contains(e), qPrintable(buf));
}
}
if (pattern.startsWith("%{pid}"))
QVERIFY2(output.startsWith(pid), "PID: " + pid + "\noutput:\n" + output);
#endif
}
void tst_qmessagehandler::setMessagePattern()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#else
#ifdef Q_OS_ANDROID
QSKIP("This test crashes on Android");
#endif
//
// test qSetMessagePattern
//
QProcess process;
const QString appExe(backtraceHelperPath());
// make sure there is no QT_MESSAGE_PATTERN in the environment
process.setProcessEnvironment(m_baseEnvironment);
process.start(appExe);
QVERIFY2(process.waitForStarted(), qPrintable(
QString::fromLatin1("Could not start %1: %2").arg(appExe, process.errorString())));
process.waitForFinished();
QByteArray output = process.readAllStandardError();
//qDebug() << output;
QByteArray expected = "static constructor\n"
"[debug] qDebug\n"
"[info] qInfo\n"
"[warning] qWarning\n"
"[critical] qCritical\n"
"[warning] qDebug with category\n";
#ifdef Q_OS_WIN
output.replace("\r\n", "\n");
#endif
QCOMPARE(QString::fromLatin1(output), QString::fromLatin1(expected));
#endif // QT_CONFIG(process)
}
Q_DECLARE_METATYPE(QtMsgType)
void tst_qmessagehandler::formatLogMessage_data()
{
QTest::addColumn<QString>("pattern");
QTest::addColumn<QString>("result");
QTest::addColumn<QtMsgType>("type");
QTest::addColumn<QByteArray>("file");
QTest::addColumn<int>("line");
QTest::addColumn<QByteArray>("function");
QTest::addColumn<QByteArray>("category");
QTest::addColumn<QString>("message");
#define BA QByteArrayLiteral
QTest::newRow("basic") << "%{type} %{file} %{line} %{function} %{message}"
<< "debug main.cpp 1 func msg"
<< QtDebugMsg << BA("main.cpp") << 1 << BA("func") << BA("") << "msg";
// test the if conditions
QString format = "[%{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{if-category}%{category}: %{endif}%{message}";
QTest::newRow("if-debug")
<< format << "[D] msg"
<< QtDebugMsg << BA("") << 0 << BA("func") << QByteArray() << "msg";
QTest::newRow("if_info")
<< format << "[I] msg"
<< QtInfoMsg << BA("") << 0 << BA("func") << QByteArray() << "msg";
QTest::newRow("if_warning")
<< format << "[W] msg"
<< QtWarningMsg << BA("") << 0 << BA("func") << QByteArray() << "msg";
QTest::newRow("if_critical")
<< format << "[C] msg"
<< QtCriticalMsg << BA("") << 0 << BA("func") << QByteArray() << "msg";
QTest::newRow("if_fatal")
<< format << "[F] msg"
<< QtFatalMsg << BA("") << 0 << BA("func") << QByteArray() << "msg";
QTest::newRow("if_cat")
#ifndef Q_OS_ANDROID
<< format << "[F] cat: msg"
#else
<< format << "[F] : msg"
#endif
<< QtFatalMsg << BA("") << 0 << BA("func") << BA("cat") << "msg";
}
void tst_qmessagehandler::formatLogMessage()
{
QFETCH(QString, pattern);
QFETCH(QString, result);
QFETCH(QtMsgType, type);
QFETCH(QByteArray, file);
QFETCH(int, line);
QFETCH(QByteArray, function);
QFETCH(QByteArray, category);
QFETCH(QString, message);
qSetMessagePattern(pattern);
QMessageLogContext ctxt(file, line, function, category.isEmpty() ? 0 : category.data());
QString r = qFormatLogMessage(type, ctxt, message);
QCOMPARE(r, result);
}
QString tst_qmessagehandler::backtraceHelperPath()
{
#ifdef Q_OS_ANDROID
QString appExe(QCoreApplication::applicationDirPath()
+ QLatin1String("/lib" BACKTRACE_HELPER_NAME ".so"));
#elif defined(Q_OS_WEBOS)
QString appExe(QCoreApplication::applicationDirPath()
+ QLatin1String("/" BACKTRACE_HELPER_NAME));
#else
QString appExe(QLatin1String(HELPER_BINARY));
#endif
return appExe;
}
QTEST_MAIN(tst_qmessagehandler)
#include "tst_qlogging.moc"

View File

@ -0,0 +1,334 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qlogging.h>
#include <qloggingcategory.h>
#include <QtTest/QTest>
Q_LOGGING_CATEGORY(debugTestCategory, "debug", QtDebugMsg)
Q_LOGGING_CATEGORY(infoTestCategory, "info", QtInfoMsg)
Q_LOGGING_CATEGORY(warningTestCategory, "warning", QtWarningMsg)
Q_LOGGING_CATEGORY(criticalTestCategory, "critical", QtCriticalMsg)
struct LoggerMessageInfo
{
QtMsgType messageType { QtFatalMsg };
QString message;
const char *file { nullptr };
int line { 0 };
const char *function { nullptr };
const char *category { nullptr };
};
LoggerMessageInfo messageInfo;
static void customMessageHandler(QtMsgType type, const QMessageLogContext &context,
const QString &message)
{
messageInfo.messageType = type;
messageInfo.message = message;
messageInfo.file = context.file;
messageInfo.line = context.line;
messageInfo.function = context.function;
messageInfo.category = context.category;
}
class tst_QMessageLogger : public QObject
{
Q_OBJECT
private slots:
void initTestCase_data();
void init();
void cleanup();
void logMessage();
void logMessageWithLoggingCategory();
void logMessageWithLoggingCategoryDisabled();
void logMessageWithCategoryFunction();
void logMessageWithNoDebug();
private:
void logWithLoggingCategoryHelper(bool messageTypeEnabled);
};
void tst_QMessageLogger::initTestCase_data()
{
QTest::addColumn<QtMsgType>("messageType");
QTest::addColumn<QByteArray>("categoryName");
QTest::addColumn<QByteArray>("messageText");
QTest::addColumn<bool>("useDebugStream");
// not testing QtFatalMsg, as it terminates the application
QTest::newRow("debug") << QtDebugMsg << QByteArray("categoryDebug")
<< QByteArray("debug message") << false;
QTest::newRow("info") << QtInfoMsg << QByteArray("categoryInfo") << QByteArray("info message")
<< false;
QTest::newRow("warning") << QtWarningMsg << QByteArray("categoryWarning")
<< QByteArray("warning message") << false;
QTest::newRow("critical") << QtCriticalMsg << QByteArray("categoryCritical")
<< QByteArray("critical message") << false;
#ifndef QT_NO_DEBUG_STREAM
QTest::newRow("stream debug") << QtDebugMsg << QByteArray("categoryDebug")
<< QByteArray("debug message") << true;
QTest::newRow("stream info") << QtInfoMsg << QByteArray("categoryInfo")
<< QByteArray("info message") << true;
QTest::newRow("stream warning") << QtWarningMsg << QByteArray("categoryWarning")
<< QByteArray("warning message") << true;
QTest::newRow("stream critical") << QtCriticalMsg << QByteArray("categoryCritical")
<< QByteArray("critical message") << true;
#endif
}
void tst_QMessageLogger::init()
{
qInstallMessageHandler(customMessageHandler);
}
void tst_QMessageLogger::cleanup()
{
qInstallMessageHandler((QtMessageHandler)0);
messageInfo.messageType = QtFatalMsg;
messageInfo.message.clear();
messageInfo.file = nullptr;
messageInfo.line = 0;
messageInfo.function = nullptr;
messageInfo.category = nullptr;
}
void tst_QMessageLogger::logMessage()
{
const int line = QT_MESSAGELOG_LINE;
QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC);
QFETCH_GLOBAL(QtMsgType, messageType);
QFETCH_GLOBAL(QByteArray, messageText);
QFETCH_GLOBAL(bool, useDebugStream);
if (useDebugStream) {
#ifndef QT_NO_DEBUG_STREAM
switch (messageType) {
case QtDebugMsg:
logger.debug().noquote() << messageText;
break;
case QtInfoMsg:
logger.info().noquote() << messageText;
break;
case QtWarningMsg:
logger.warning().noquote() << messageText;
break;
case QtCriticalMsg:
logger.critical().noquote() << messageText;
break;
default:
QFAIL("Invalid message type");
break;
}
#else
QSKIP("Qt debug stream disabled");
#endif
} else {
switch (messageType) {
case QtDebugMsg:
logger.debug("%s", messageText.constData());
break;
case QtInfoMsg:
logger.info("%s", messageText.constData());
break;
case QtWarningMsg:
logger.warning("%s", messageText.constData());
break;
case QtCriticalMsg:
logger.critical("%s", messageText.constData());
break;
default:
QFAIL("Invalid message type");
break;
}
}
QCOMPARE(messageInfo.messageType, messageType);
QCOMPARE(messageInfo.message, messageText);
QCOMPARE(messageInfo.file, __FILE__);
QCOMPARE(messageInfo.line, line);
QCOMPARE(messageInfo.function, Q_FUNC_INFO);
}
void tst_QMessageLogger::logMessageWithLoggingCategory()
{
logWithLoggingCategoryHelper(true);
}
void tst_QMessageLogger::logMessageWithLoggingCategoryDisabled()
{
logWithLoggingCategoryHelper(false);
}
void tst_QMessageLogger::logMessageWithCategoryFunction()
{
const int line = QT_MESSAGELOG_LINE;
QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC);
const QLoggingCategory *category = nullptr;
QFETCH_GLOBAL(QtMsgType, messageType);
QFETCH_GLOBAL(QByteArray, messageText);
QFETCH_GLOBAL(bool, useDebugStream);
if (useDebugStream) {
#ifndef QT_NO_DEBUG_STREAM
switch (messageType) {
case QtDebugMsg:
logger.debug(debugTestCategory()).noquote() << messageText;
category = &debugTestCategory();
break;
case QtInfoMsg:
logger.info(infoTestCategory()).noquote() << messageText;
category = &infoTestCategory();
break;
case QtWarningMsg:
logger.warning(warningTestCategory()).noquote() << messageText;
category = &warningTestCategory();
break;
case QtCriticalMsg:
logger.critical(criticalTestCategory()).noquote() << messageText;
category = &criticalTestCategory();
break;
default:
QFAIL("Invalid message type");
break;
}
#else
QSKIP("Qt debug stream disabled");
#endif
} else {
switch (messageType) {
case QtDebugMsg:
logger.debug(debugTestCategory(), "%s", messageText.constData());
category = &debugTestCategory();
break;
case QtInfoMsg:
logger.info(infoTestCategory(), "%s", messageText.constData());
category = &infoTestCategory();
break;
case QtWarningMsg:
logger.warning(warningTestCategory(), "%s", messageText.constData());
category = &warningTestCategory();
break;
case QtCriticalMsg:
logger.critical(criticalTestCategory(), "%s", messageText.constData());
category = &criticalTestCategory();
break;
default:
QFAIL("Invalid message type");
break;
}
}
QCOMPARE(messageInfo.messageType, messageType);
QCOMPARE(messageInfo.message, messageText);
QCOMPARE(messageInfo.file, __FILE__);
QCOMPARE(messageInfo.line, line);
QCOMPARE(messageInfo.function, Q_FUNC_INFO);
QCOMPARE(messageInfo.category, category->categoryName());
}
void tst_QMessageLogger::logMessageWithNoDebug()
{
const int line = QT_MESSAGELOG_LINE;
QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC);
QFETCH_GLOBAL(QByteArray, messageText);
QFETCH_GLOBAL(bool, useDebugStream);
if (useDebugStream) {
#ifndef QT_NO_DEBUG_STREAM
logger.noDebug().noquote() << messageText;
#else
QSKIP("Qt debug stream disabled");
#endif
} else {
logger.noDebug("%s", messageText.constData());
}
// the callback was not called
QVERIFY(messageInfo.messageType == QtFatalMsg);
QVERIFY(messageInfo.message.isEmpty());
QVERIFY(messageInfo.file == nullptr);
QVERIFY(messageInfo.line == 0);
QVERIFY(messageInfo.function == nullptr);
QVERIFY(messageInfo.category == nullptr);
}
void tst_QMessageLogger::logWithLoggingCategoryHelper(bool messageTypeEnabled)
{
QFETCH_GLOBAL(QtMsgType, messageType);
QFETCH_GLOBAL(QByteArray, categoryName);
QLoggingCategory category(categoryName.constData(), messageType);
if (!messageTypeEnabled)
category.setEnabled(messageType, false);
const int line = QT_MESSAGELOG_LINE;
QMessageLogger logger(QT_MESSAGELOG_FILE, line, QT_MESSAGELOG_FUNC);
QFETCH_GLOBAL(QByteArray, messageText);
QFETCH_GLOBAL(bool, useDebugStream);
if (useDebugStream) {
#ifndef QT_NO_DEBUG_STREAM
switch (messageType) {
case QtDebugMsg:
logger.debug(category).noquote() << messageText;
break;
case QtInfoMsg:
logger.info(category).noquote() << messageText;
break;
case QtWarningMsg:
logger.warning(category).noquote() << messageText;
break;
case QtCriticalMsg:
logger.critical(category).noquote() << messageText;
break;
default:
QFAIL("Invalid message type");
break;
}
#else
QSKIP("Qt debug stream disabled");
#endif
} else {
switch (messageType) {
case QtDebugMsg:
logger.debug(category, "%s", messageText.constData());
break;
case QtInfoMsg:
logger.info(category, "%s", messageText.constData());
break;
case QtWarningMsg:
logger.warning(category, "%s", messageText.constData());
break;
case QtCriticalMsg:
logger.critical(category, "%s", messageText.constData());
break;
default:
QFAIL("Invalid message type");
break;
}
}
if (messageTypeEnabled) {
QCOMPARE(messageInfo.messageType, messageType);
QCOMPARE(messageInfo.message, messageText);
QCOMPARE(messageInfo.file, __FILE__);
QCOMPARE(messageInfo.line, line);
QCOMPARE(messageInfo.function, Q_FUNC_INFO);
QCOMPARE(messageInfo.category, categoryName);
} else {
// the callback was not called
QVERIFY(messageInfo.messageType == QtFatalMsg);
QVERIFY(messageInfo.message.isEmpty());
QVERIFY(messageInfo.file == nullptr);
QVERIFY(messageInfo.line == 0);
QVERIFY(messageInfo.function == nullptr);
QVERIFY(messageInfo.category == nullptr);
}
}
QTEST_MAIN(tst_QMessageLogger)
#include "tst_qmessagelogger.moc"

View File

@ -0,0 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_qnativeinterface
SOURCES
tst_qnativeinterface.cpp
LIBRARIES
Qt::CorePrivate
)

View File

@ -0,0 +1,115 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtCore/qnativeinterface.h>
#include <QtCore/private/qnativeinterface_p.h>
class tst_QNativeInterface: public QObject
{
Q_OBJECT
private slots:
void typeInfo() const;
void resolve() const;
void accessor() const;
friend struct PublicClass;
};
struct InterfaceImplementation;
struct PublicClass
{
PublicClass();
QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(PublicClass)
std::unique_ptr<InterfaceImplementation> m_implementation;
friend void tst_QNativeInterface::resolve() const;
};
QT_BEGIN_NAMESPACE
namespace QNativeInterface {
struct Interface
{
QT_DECLARE_NATIVE_INTERFACE(Interface, 10, PublicClass)
virtual int foo() = 0;
};
struct OtherInterface
{
QT_DECLARE_NATIVE_INTERFACE(OtherInterface, 10, PublicClass)
};
}
QT_DEFINE_NATIVE_INTERFACE(Interface);
QT_DEFINE_NATIVE_INTERFACE(OtherInterface);
QT_END_NAMESPACE
struct NotInterface {};
struct AlmostInterface
{
struct TypeInfo {
// Missing required members
};
};
using namespace QNativeInterface;
struct InterfaceImplementation : public Interface
{
int foo() override { return 123; }
};
PublicClass::PublicClass() : m_implementation(new InterfaceImplementation) {}
void* PublicClass::resolveInterface(char const* name, int revision) const
{
auto *implementation = m_implementation.get();
QT_NATIVE_INTERFACE_RETURN_IF(Interface, implementation);
QT_NATIVE_INTERFACE_RETURN_IF(OtherInterface, implementation);
return nullptr;
}
void tst_QNativeInterface::typeInfo() const
{
using namespace QNativeInterface::Private;
QCOMPARE(TypeInfo<Interface>::haveTypeInfo, true);
QCOMPARE(TypeInfo<NotInterface>::haveTypeInfo, false);
QCOMPARE(TypeInfo<AlmostInterface>::haveTypeInfo, false);
QCOMPARE(TypeInfo<Interface>::isCompatibleWith<PublicClass>, true);
QCOMPARE(TypeInfo<Interface>::isCompatibleWith<QObject>, false);
QCOMPARE(TypeInfo<Interface>::isCompatibleWith<int>, false);
QCOMPARE(TypeInfo<Interface>::revision(), 10);
QCOMPARE(TypeInfo<Interface>::name(), "Interface");
}
void tst_QNativeInterface::resolve() const
{
using namespace QNativeInterface::Private;
PublicClass foo;
QVERIFY(foo.resolveInterface("Interface", 10));
QTest::ignoreMessage(QtWarningMsg, "Native interface revision mismatch "
"(requested 5 / available 10) for interface Interface");
QCOMPARE(foo.resolveInterface("Interface", 5), nullptr);
QCOMPARE(foo.resolveInterface("NotInterface", 10), nullptr);
QCOMPARE(foo.resolveInterface("OtherInterface", 10), nullptr);
}
void tst_QNativeInterface::accessor() const
{
PublicClass foo;
QVERIFY(foo.nativeInterface<Interface>());
QCOMPARE(foo.nativeInterface<Interface>()->foo(), 123);
}
QTEST_MAIN(tst_QNativeInterface)
#include "tst_qnativeinterface.moc"

View File

@ -0,0 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qnumeric Test:
#####################################################################
qt_internal_add_test(tst_qnumeric
SOURCES
tst_qnumeric.cpp
LIBRARIES
Qt::CorePrivate
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,751 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtGlobal>
#include "private/qnumeric_p.h"
#include <math.h>
#include <float.h>
namespace {
template <typename F> struct Fuzzy {};
/* Data taken from qglobal.h's implementation of qFuzzyCompare:
* qFuzzyCompare conflates values with fractional difference up to (and
* including) the given scale.
*/
template <> struct Fuzzy<double> { constexpr static double scale = 1e12; };
template <> struct Fuzzy<float> { constexpr static float scale = 1e5f; };
}
class tst_QNumeric: public QObject
{
Q_OBJECT
// Support for floating-point:
template<typename F> inline void fuzzyCompare_data();
template<typename F> inline void fuzzyCompare();
template<typename F> inline void fuzzyIsNull_data();
template<typename F> inline void fuzzyIsNull();
template<typename F> inline void checkNaN(F nan);
template<typename F> inline void rawNaN_data();
template<typename F> inline void rawNaN();
#if QT_CONFIG(signaling_nan)
template<typename F> inline void distinctNaN();
#endif
template<typename F, typename Whole> inline void generalNaN_data();
template<typename F, typename Whole> inline void generalNaN();
template<typename F> inline void infinity();
template<typename F> inline void classifyfp();
template<typename F, typename Count> inline void distance_data();
template<typename F, typename Count> inline void distance();
private slots:
// Floating-point tests:
void fuzzyCompareF_data() { fuzzyCompare_data<float>(); }
void fuzzyCompareF() { fuzzyCompare<float>(); }
void fuzzyCompareD_data() { fuzzyCompare_data<double>(); }
void fuzzyCompareD() { fuzzyCompare<double>(); }
void fuzzyIsNullF_data() { fuzzyIsNull_data<float>(); }
void fuzzyIsNullF() { fuzzyIsNull<float>(); }
void fuzzyIsNullD_data() { fuzzyIsNull_data<double>(); }
void fuzzyIsNullD() { fuzzyIsNull<double>(); }
void rawNaNF_data() { rawNaN_data<float>(); }
void rawNaNF() { rawNaN<float>(); }
void rawNaND_data() { rawNaN_data<double>(); }
void rawNaND() { rawNaN<double>(); }
#if QT_CONFIG(signaling_nan)
void distinctNaNF();
void distinctNaND() { distinctNaN<double>(); }
#endif
void generalNaNd_data() { generalNaN_data<double, quint64>(); }
void generalNaNd() { generalNaN<double, quint64>(); }
void generalNaNf_data() { generalNaN_data<float, quint32>(); }
void generalNaNf() { generalNaN<float, quint32>(); }
void infinityF() { infinity<float>(); }
void infinityD() { infinity<double>(); }
void classifyF() { classifyfp<float>(); }
void classifyD() { classifyfp<double>(); }
void floatDistance_data() { distance_data<float, quint32>(); }
void floatDistance() { distance<float, quint32>(); }
void doubleDistance_data() { distance_data<double, quint64>(); }
void doubleDistance() { distance<double, quint64>(); }
// Whole number tests:
void addOverflow_data();
void addOverflow();
void mulOverflow_data();
void mulOverflow();
void signedOverflow();
};
// Floating-point tests:
template<typename F>
void tst_QNumeric::fuzzyCompare_data()
{
QTest::addColumn<F>("val1");
QTest::addColumn<F>("val2");
QTest::addColumn<bool>("isEqual");
const F zero(0), one(1), ten(10);
const F huge = Fuzzy<F>::scale, tiny = one / huge;
const F deci(.1), giga(1e9), nano(1e-9), big(1e7), small(1e-10);
QTest::newRow("zero") << zero << zero << true;
QTest::newRow("ten") << ten << ten << true;
QTest::newRow("large") << giga << giga << true;
QTest::newRow("small") << small << small << true;
QTest::newRow("10+9*tiny==10") << (ten + 9 * tiny) << ten << true;
QTest::newRow("huge+.9==huge") << (huge + 9 * deci) << huge << true;
QTest::newRow("eps2") << (ten + tiny) << (ten + 2 * tiny) << true;
QTest::newRow("eps9") << (ten + tiny) << (ten + 9 * tiny) << true;
QTest::newRow("0!=1") << zero << one << false;
QTest::newRow("0!=big") << zero << big << false;
QTest::newRow("0!=nano") << zero << nano << false;
QTest::newRow("giga!=nano") << giga << nano << false;
QTest::newRow("small!=nano") << small << nano << false;
QTest::newRow("huge+1.1!=huge") << (huge + 1 + deci) << huge << false;
QTest::newRow("1+1.1*tiny!=1") << (one + tiny * (one + deci)) << one << false;
}
template<typename F>
void tst_QNumeric::fuzzyCompare()
{
QFETCH(F, val1);
QFETCH(F, val2);
QFETCH(bool, isEqual);
QCOMPARE(::qFuzzyCompare(val1, val2), isEqual);
QCOMPARE(::qFuzzyCompare(val2, val1), isEqual);
QCOMPARE(::qFuzzyCompare(-val1, -val2), isEqual);
QCOMPARE(::qFuzzyCompare(-val2, -val1), isEqual);
}
template<typename F>
void tst_QNumeric::fuzzyIsNull_data()
{
QTest::addColumn<F>("value");
QTest::addColumn<bool>("isNull");
using Bounds = std::numeric_limits<F>;
const F one(1), huge = Fuzzy<F>::scale, tiny = one / huge;
QTest::newRow("zero") << F(0) << true;
QTest::newRow("min") << Bounds::min() << true;
QTest::newRow("denorm_min") << Bounds::denorm_min() << true;
QTest::newRow("tiny") << tiny << true;
QTest::newRow("deci") << F(.1) << false;
QTest::newRow("one") << one << false;
QTest::newRow("ten") << F(10) << false;
QTest::newRow("large") << F(1e9) << false;
QTest::newRow("huge") << huge << false;
}
template<typename F>
void tst_QNumeric::fuzzyIsNull()
{
QFETCH(F, value);
QFETCH(bool, isNull);
QCOMPARE(::qFuzzyIsNull(value), isNull);
QCOMPARE(::qFuzzyIsNull(-value), isNull);
}
static void clearFpExceptions()
{
// Call after any functions that exercise floating-point exceptions, such as
// sqrt(-1) or log(0).
#ifdef Q_OS_WIN
_clearfp();
#endif
}
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
// turn -ffast-math off
# pragma GCC optimize "no-fast-math"
#endif
template<typename F>
void tst_QNumeric::checkNaN(F nan)
{
const auto cleanup = qScopeGuard([]() { clearFpExceptions(); });
#define CHECKNAN(value) \
do { \
const F v = (value); \
QCOMPARE(qFpClassify(v), FP_NAN); \
QVERIFY(qIsNaN(v)); \
QVERIFY(!qIsFinite(v)); \
QVERIFY(!qIsInf(v)); \
} while (0)
const F zero(0), one(1), two(2);
QVERIFY(!(zero > nan));
QVERIFY(!(zero < nan));
QVERIFY(!(zero == nan));
QVERIFY(!(nan == nan));
CHECKNAN(nan);
CHECKNAN(nan + one);
CHECKNAN(nan - one);
CHECKNAN(-nan);
CHECKNAN(nan * two);
CHECKNAN(nan / two);
CHECKNAN(one / nan);
CHECKNAN(zero / nan);
CHECKNAN(zero * nan);
CHECKNAN(sqrt(-one));
// When any NaN is expected, any NaN will do:
QCOMPARE(nan, nan);
QCOMPARE(nan, -nan);
QCOMPARE(nan, qQNaN());
#undef CHECKNAN
}
template<typename F>
void tst_QNumeric::rawNaN_data()
{
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404)
QSKIP("Non-conformant fast math mode is enabled, cannot run test");
#endif
QTest::addColumn<F>("nan");
QTest::newRow("quiet") << F(qQNaN());
#if QT_CONFIG(signaling_nan)
QTest::newRow("signaling") << F(qSNaN());
#endif
}
template<typename F>
void tst_QNumeric::rawNaN()
{
QFETCH(F, nan);
#ifdef Q_OS_WASM
# ifdef __asmjs
QEXPECT_FAIL("", "Fastcomp conflates quiet and signaling NaNs", Continue);
# endif // but the modern clang compiler handls it fine.
#endif
checkNaN(nan);
}
#if QT_CONFIG(signaling_nan)
template<typename F>
void tst_QNumeric::distinctNaN()
{
const F qnan = qQNaN();
const F snan = qSNaN();
QVERIFY(memcmp(&qnan, &snan, sizeof(F)) != 0);
}
void tst_QNumeric::distinctNaNF() {
#ifdef Q_CC_MSVC
QEXPECT_FAIL("", "MSVC's float conflates quiet and signaling NaNs", Continue);
#endif
distinctNaN<float>();
}
#endif // signaling_nan
template<typename F, typename Whole>
void tst_QNumeric::generalNaN_data()
{
static_assert(sizeof(F) == sizeof(Whole));
QTest::addColumn<Whole>("whole");
// Every value with every bit of the exponent set is a NaN.
// Sign and mantissa can be anything without interfering with that.
using Bounds = std::numeric_limits<F>;
// Bounds::digits is one more than the number of bits used to encode the mantissa:
const int mantissaBits = Bounds::digits - 1;
// One bit for sign, the rest are mantissa and exponent:
const int exponentBits = sizeof(F) * CHAR_BIT - 1 - mantissaBits;
const Whole exponent = ((Whole(1) << exponentBits) - 1) << mantissaBits;
const Whole sign = Whole(1) << (exponentBits + mantissaBits);
const Whole mantissaTop = Whole(1) << (mantissaBits - 1);
QTest::newRow("lowload") << (exponent | 1);
QTest::newRow("sign-lowload") << (sign | exponent | 1);
QTest::newRow("highload") << (exponent | mantissaTop);
QTest::newRow("sign-highload") << (sign | exponent | mantissaTop);
}
template<typename F, typename Whole>
void tst_QNumeric::generalNaN()
{
static_assert(sizeof(F) == sizeof(Whole));
QFETCH(const Whole, whole);
F nan;
memcpy(&nan, &whole, sizeof(F));
checkNaN(nan);
}
template<typename F>
void tst_QNumeric::infinity()
{
const auto cleanup = qScopeGuard([]() { clearFpExceptions(); });
const F inf = qInf();
const F zero(0), one(1), two(2);
QVERIFY(inf > zero);
QVERIFY(-inf < zero);
QVERIFY(qIsInf(inf));
QCOMPARE(inf, inf);
QCOMPARE(-inf, -inf);
QVERIFY(qIsInf(-inf));
QVERIFY(qIsInf(inf + one));
QVERIFY(qIsInf(inf - one));
QVERIFY(qIsInf(-inf - one));
QVERIFY(qIsInf(-inf + one));
QVERIFY(qIsInf(inf * two));
QVERIFY(qIsInf(-inf * two));
QVERIFY(qIsInf(inf / two));
QVERIFY(qIsInf(-inf / two));
QVERIFY(qFuzzyCompare(one / inf, zero));
QCOMPARE(1.0 / inf, 0.0);
QVERIFY(qFuzzyCompare(one / -inf, zero));
QCOMPARE(one / -inf, zero);
QVERIFY(qIsNaN(zero * inf));
QVERIFY(qIsNaN(zero * -inf));
QCOMPARE(log(zero), -inf);
}
template<typename F>
void tst_QNumeric::classifyfp()
{
using Bounds = std::numeric_limits<F>;
const F huge = Bounds::max();
const F tiny = Bounds::min();
// NaNs already handled, see checkNaN()'s callers.
const F one(1), two(2), inf(qInf());
QCOMPARE(qFpClassify(inf), FP_INFINITE);
QCOMPARE(qFpClassify(-inf), FP_INFINITE);
QCOMPARE(qFpClassify(huge * two), FP_INFINITE);
QCOMPARE(qFpClassify(huge * -two), FP_INFINITE);
QCOMPARE(qFpClassify(one), FP_NORMAL);
QCOMPARE(qFpClassify(huge), FP_NORMAL);
QCOMPARE(qFpClassify(-huge), FP_NORMAL);
QCOMPARE(qFpClassify(tiny), FP_NORMAL);
QCOMPARE(qFpClassify(-tiny), FP_NORMAL);
if (Bounds::has_denorm == std::denorm_present) {
QCOMPARE(qFpClassify(tiny / two), FP_SUBNORMAL);
QCOMPARE(qFpClassify(tiny / -two), FP_SUBNORMAL);
}
}
template<typename F, typename Count>
void tst_QNumeric::distance_data()
{
using Bounds = std::numeric_limits<F>;
const F huge = Bounds::max();
const F tiny = Bounds::min();
QTest::addColumn<F>("from");
QTest::addColumn<F>("stop");
QTest::addColumn<Count>("expectedDistance");
using Bounds = std::numeric_limits<F>;
const int mantissaBits = Bounds::digits - 1;
const int exponentBits = sizeof(F) * CHAR_BIT - 1 - mantissaBits;
// Set to 1 and 0 if denormals are not included:
const Count count_0_to_tiny = Count(1) << mantissaBits;
const Count count_denormals = count_0_to_tiny - 1;
// We need +1 to include the 0:
const Count count_0_to_1
= (Count(1) << mantissaBits) * ((Count(1) << (exponentBits - 1)) - 2)
+ 1 + count_denormals;
const Count count_1_to_2 = Count(1) << mantissaBits;
// We don't need +1 because huge has all bits set in the mantissa. (Thus mantissa
// have not wrapped back to 0, which would be the case for 1 in _0_to_1
const Count count_0_to_huge
= (Count(1) << mantissaBits) * ((Count(1) << exponentBits) - 2)
+ count_denormals;
const F zero(0), half(.5), one(1), sesqui(1.5), two(2);
const F denormal = tiny / two;
QTest::newRow("[0,tiny]") << zero << tiny << count_0_to_tiny;
QTest::newRow("[0,huge]") << zero << huge << count_0_to_huge;
QTest::newRow("[1,1.5]") << one << sesqui << (Count(1) << (mantissaBits - 1));
QTest::newRow("[0,1]") << zero << one << count_0_to_1;
QTest::newRow("[0.5,1]") << half << one << (Count(1) << mantissaBits);
QTest::newRow("[1,2]") << one << two << count_1_to_2;
QTest::newRow("[-1,+1]") << -one << +one << 2 * count_0_to_1;
QTest::newRow("[-1,0]") << -one << zero << count_0_to_1;
QTest::newRow("[-1,huge]") << -one << huge << count_0_to_1 + count_0_to_huge;
QTest::newRow("[-2,-1") << -two << -one << count_1_to_2;
QTest::newRow("[-1,-2") << -one << -two << count_1_to_2;
QTest::newRow("[tiny,huge]") << tiny << huge << count_0_to_huge - count_0_to_tiny;
QTest::newRow("[-huge,huge]") << -huge << huge << (2 * count_0_to_huge);
QTest::newRow("denormal") << zero << denormal << count_0_to_tiny / 2;
}
template<typename F, typename Count>
void tst_QNumeric::distance()
{
QFETCH(F, from);
QFETCH(F, stop);
QFETCH(Count, expectedDistance);
if constexpr (std::numeric_limits<F>::has_denorm != std::denorm_present) {
if (qstrcmp(QTest::currentDataTag(), "denormal") == 0) {
QSKIP("Skipping 'denorm' as this type lacks denormals on this system");
}
}
QCOMPARE(qFloatDistance(from, stop), expectedDistance);
QCOMPARE(qFloatDistance(stop, from), expectedDistance);
}
// Whole number tests:
void tst_QNumeric::addOverflow_data()
{
QTest::addColumn<int>("size");
// for unsigned, all sizes are supported
QTest::newRow("quint8") << 8;
QTest::newRow("quint16") << 16;
QTest::newRow("quint32") << 32;
QTest::newRow("quint64") << 64;
QTest::newRow("ulong") << 48; // it's either 32- or 64-bit, so on average it's 48 :-)
// for signed, we can't guarantee 64-bit
QTest::newRow("qint8") << -8;
QTest::newRow("qint16") << -16;
QTest::newRow("qint32") << -32;
if (sizeof(void *) == sizeof(qint64))
QTest::newRow("qint64") << -64;
}
// Note: in release mode, all the tests may be statically determined and only the calls
// to QTest::toString and QTest::qCompare will remain.
template <typename Int> static void addOverflow_template()
{
#if defined(Q_CC_MSVC) && Q_CC_MSVC < 2000
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling in release mode");
#else
constexpr Int max = std::numeric_limits<Int>::max();
constexpr Int min = std::numeric_limits<Int>::min();
Int r;
#define ADD_COMPARE_NONOVF(v1, v2, expected) \
do { \
QCOMPARE(add_overflow(Int(v1), Int(v2), &r), false); \
QCOMPARE(r, Int(expected)); \
QCOMPARE(add_overflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), false); \
QCOMPARE(r, Int(expected)); \
QCOMPARE(add_overflow<v2>(Int(v1), &r), false); \
QCOMPARE(r, Int(expected)); \
} while (false)
#define ADD_COMPARE_OVF(v1, v2) \
do { \
QCOMPARE(add_overflow(Int(v1), Int(v2), &r), true); \
QCOMPARE(add_overflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), true); \
QCOMPARE(add_overflow<v2>(Int(v1), &r), true); \
} while (false)
#define SUB_COMPARE_NONOVF(v1, v2, expected) \
do { \
QCOMPARE(sub_overflow(Int(v1), Int(v2), &r), false); \
QCOMPARE(r, Int(expected)); \
QCOMPARE(sub_overflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), false); \
QCOMPARE(r, Int(expected)); \
QCOMPARE(sub_overflow<v2>(Int(v1), &r), false); \
QCOMPARE(r, Int(expected)); \
} while (false)
#define SUB_COMPARE_OVF(v1, v2) \
do { \
QCOMPARE(sub_overflow(Int(v1), Int(v2), &r), true); \
QCOMPARE(sub_overflow(Int(v1), (std::integral_constant<Int, Int(v2)>()), &r), true); \
QCOMPARE(sub_overflow<v2>(Int(v1), &r), true); \
} while (false)
// basic values
ADD_COMPARE_NONOVF(0, 0, 0);
ADD_COMPARE_NONOVF(1, 0, 1);
ADD_COMPARE_NONOVF(0, 1, 1);
SUB_COMPARE_NONOVF(0, 0, 0);
SUB_COMPARE_NONOVF(1, 0, 1);
SUB_COMPARE_NONOVF(1, 1, 0);
if (min)
SUB_COMPARE_NONOVF(0, 1, -1);
else
SUB_COMPARE_OVF(0, 1);
// half-way through max
ADD_COMPARE_NONOVF(max/2, max/2, max / 2 * 2);
SUB_COMPARE_NONOVF(max/2, max/2, 0);
ADD_COMPARE_NONOVF(max/2 - 1, max/2 + 1, max / 2 * 2);
if (min)
SUB_COMPARE_NONOVF(max/2 - 1, max/2 + 1, -2);
else
SUB_COMPARE_OVF(max/2 - 1, max/2 + 1);
ADD_COMPARE_NONOVF(max/2 + 1, max/2, max);
SUB_COMPARE_NONOVF(max/2 + 1, max/2, 1);
ADD_COMPARE_NONOVF(max/2, max/2 + 1, max);
if (min)
SUB_COMPARE_NONOVF(max/2, max/2 + 1, -1);
else
SUB_COMPARE_OVF(max/2, max/2 + 1);
ADD_COMPARE_NONOVF(min/2, min/2, min / 2 * 2);
SUB_COMPARE_NONOVF(min/2, min/2, 0);
if (min)
ADD_COMPARE_NONOVF(min/2 - 1, min/2 + 1, min / 2 * 2);
else
ADD_COMPARE_OVF(min/2 - 1, min/2 + 1);
SUB_COMPARE_NONOVF(min/2 - 1, min/2 + 1, -2);
SUB_COMPARE_NONOVF(min/2 + 1, min/2, 1);
if (min)
SUB_COMPARE_NONOVF(min/2, min/2 + 1, -1);
else
SUB_COMPARE_OVF(min/2, min/2 + 1);
// more than half
ADD_COMPARE_NONOVF(max/4 * 3, max/4, max / 4 * 4);
// max
ADD_COMPARE_NONOVF(max, 0, max);
SUB_COMPARE_NONOVF(max, 0, max);
ADD_COMPARE_NONOVF(0, max, max);
if (min)
SUB_COMPARE_NONOVF(0, max, -max);
else
SUB_COMPARE_OVF(0, max);
ADD_COMPARE_NONOVF(min, 0, min);
SUB_COMPARE_NONOVF(min, 0, min);
ADD_COMPARE_NONOVF(0, min, min);
if (min)
SUB_COMPARE_NONOVF(0, min+1, -(min+1));
else
SUB_COMPARE_OVF(0, min+1);
// 64-bit issues
if constexpr (max > std::numeric_limits<uint>::max()) {
ADD_COMPARE_NONOVF(std::numeric_limits<uint>::max(), std::numeric_limits<uint>::max(), 2 * Int(std::numeric_limits<uint>::max()));
SUB_COMPARE_NONOVF(std::numeric_limits<uint>::max(), std::numeric_limits<uint>::max(), 0);
}
if constexpr (min != 0) {
if (qint64(min) < qint64(-std::numeric_limits<uint>::max())) {
ADD_COMPARE_NONOVF(-Int(std::numeric_limits<uint>::max()), -Int(std::numeric_limits<uint>::max()), -2 * Int(std::numeric_limits<uint>::max()));
SUB_COMPARE_NONOVF(-Int(std::numeric_limits<uint>::max()), -Int(std::numeric_limits<uint>::max()), 0);
}
}
// overflows past max
ADD_COMPARE_OVF(max, 1);
ADD_COMPARE_OVF(1, max);
ADD_COMPARE_OVF(max/2 + 1, max/2 + 1);
// overflows past min
if constexpr (min != 0) {
ADD_COMPARE_OVF(-max, -2);
SUB_COMPARE_OVF(-max, 2);
SUB_COMPARE_OVF(-max/2 - 1, max/2 + 2);
SUB_COMPARE_OVF(min, 1);
SUB_COMPARE_OVF(1, min);
SUB_COMPARE_OVF(min/2 - 1, -Int(min/2));
ADD_COMPARE_OVF(min, -1);
ADD_COMPARE_OVF(-1, min);
}
#undef ADD_COMPARE_NONOVF
#undef ADD_COMPARE_OVF
#undef SUB_COMPARE_NONOVF
#undef SUB_COMPARE_OVF
#endif
}
void tst_QNumeric::addOverflow()
{
QFETCH(int, size);
if (size == 8)
addOverflow_template<quint8>();
if (size == 16)
addOverflow_template<quint16>();
if (size == 32)
addOverflow_template<quint32>();
if (size == 48)
addOverflow_template<ulong>(); // not really 48-bit
if (size == 64)
addOverflow_template<quint64>();
if (size == -8)
addOverflow_template<qint8>();
if (size == -16)
addOverflow_template<qint16>();
if (size == -32)
addOverflow_template<qint32>();
if (size == -64)
addOverflow_template<qint64>();
}
void tst_QNumeric::mulOverflow_data()
{
addOverflow_data();
}
// Note: in release mode, all the tests may be statically determined and only the calls
// to QTest::toString and QTest::qCompare will remain.
template <typename Int> static void mulOverflow_template()
{
#if defined(Q_CC_MSVC) && Q_CC_MSVC < 1900
QSKIP("Test disabled, this test generates an Internal Compiler Error compiling");
#else
constexpr Int max = std::numeric_limits<Int>::max();
constexpr Int min = std::numeric_limits<Int>::min();
// for unsigned (even number of significant bits): mid2 = mid1 - 1
// for signed (odd number of significant bits): mid2 = mid1 / 2 - 1
constexpr Int mid1 = Int(Int(1) << (sizeof(Int) * CHAR_BIT / 2));
constexpr Int mid2 = (std::numeric_limits<Int>::digits % 2 ? mid1 / 2 : mid1) - 1;
Int r;
#define MUL_COMPARE_NONOVF(v1, v2, expected) \
do { \
QCOMPARE(mul_overflow(Int(v1), Int(v2), &r), false); \
QCOMPARE(r, Int(expected)); \
QCOMPARE(mul_overflow(Int(v1), (std::integral_constant<Int, v2>()), &r), false); \
QCOMPARE(r, Int(expected)); \
QCOMPARE(mul_overflow<v2>(Int(v1), &r), false); \
QCOMPARE(r, Int(expected)); \
} while (false);
#define MUL_COMPARE_OVF(v1, v2) \
do { \
QCOMPARE(mul_overflow(Int(v1), Int(v2), &r), true); \
QCOMPARE(mul_overflow(Int(v1), (std::integral_constant<Int, v2>()), &r), true); \
QCOMPARE(mul_overflow<v2>(Int(v1), &r), true); \
} while (false);
// basic multiplications
MUL_COMPARE_NONOVF(0, 0, 0);
MUL_COMPARE_NONOVF(1, 0, 0);
MUL_COMPARE_NONOVF(0, 1, 0);
MUL_COMPARE_NONOVF(max, 0, 0);
MUL_COMPARE_NONOVF(0, max, 0);
MUL_COMPARE_NONOVF(min, 0, 0);
MUL_COMPARE_NONOVF(0, min, 0);
if constexpr (min != 0) {
MUL_COMPARE_NONOVF(0, -1, 0);
MUL_COMPARE_NONOVF(1, -1, -1);
MUL_COMPARE_NONOVF(max, -1, -max);
}
MUL_COMPARE_NONOVF(1, 1, 1);
MUL_COMPARE_NONOVF(1, max, max);
MUL_COMPARE_NONOVF(max, 1, max);
MUL_COMPARE_NONOVF(1, min, min);
MUL_COMPARE_NONOVF(min, 1, min);
// almost max
MUL_COMPARE_NONOVF(mid1, mid2, max - mid1 + 1);
MUL_COMPARE_NONOVF(max / 2, 2, max & ~Int(1));
MUL_COMPARE_NONOVF(max / 4, 4, max & ~Int(3));
if constexpr (min != 0) {
MUL_COMPARE_NONOVF(-mid1, mid2, -max + mid1 - 1);
MUL_COMPARE_NONOVF(-max / 2, 2, -max + 1);
MUL_COMPARE_NONOVF(-max / 4, 4, -max + 3);
MUL_COMPARE_NONOVF(-mid1, mid2 + 1, min);
MUL_COMPARE_NONOVF(mid1, -mid2 - 1, min);
}
// overflows
MUL_COMPARE_OVF(max, 2);
MUL_COMPARE_OVF(max / 2, 3);
MUL_COMPARE_OVF(mid1, mid2 + 1);
MUL_COMPARE_OVF(max / 2 + 2, 2);
MUL_COMPARE_OVF(max - max / 2, 2);
MUL_COMPARE_OVF(1ULL << (std::numeric_limits<Int>::digits - 1), 2);
if constexpr (min != 0) {
MUL_COMPARE_OVF(min, -1);
MUL_COMPARE_OVF(min, 2);
MUL_COMPARE_OVF(min / 2, 3);
MUL_COMPARE_OVF(min / 2 - 1, 2);
}
#undef MUL_COMPARE_NONOVF
#undef MUL_COMPARE_OVF
#endif
}
template <typename Int, bool enabled = sizeof(Int) <= sizeof(void*)> struct MulOverflowDispatch;
template <typename Int> struct MulOverflowDispatch<Int, true>
{
void operator()() { mulOverflow_template<Int>(); }
};
template <typename Int> struct MulOverflowDispatch<Int, false>
{
void operator()() { QSKIP("This type is too big for this architecture"); }
};
void tst_QNumeric::mulOverflow()
{
QFETCH(int, size);
if (size == 8)
MulOverflowDispatch<quint8>()();
if (size == 16)
MulOverflowDispatch<quint16>()();
if (size == 32)
MulOverflowDispatch<quint32>()();
if (size == 48)
MulOverflowDispatch<ulong>()(); // not really 48-bit
if (size == 64)
MulOverflowDispatch<quint64>()();
if (size == -8)
MulOverflowDispatch<qint8>()();
if (size == -16)
MulOverflowDispatch<qint16>()();
if (size == -32)
MulOverflowDispatch<qint32>()();
if (size == -64) {
#if QT_POINTER_SIZE == 8 || defined(Q_INTRINSIC_MUL_OVERFLOW64)
MulOverflowDispatch<qint64>()();
#else
QFAIL("128-bit multiplication not supported on this platform");
#endif
}
}
void tst_QNumeric::signedOverflow()
{
const int minInt = std::numeric_limits<int>::min();
const int maxInt = std::numeric_limits<int>::max();
int r;
QCOMPARE(add_overflow(minInt + 1, int(-1), &r), false);
QCOMPARE(add_overflow(minInt, int(-1), &r), true);
QCOMPARE(add_overflow(minInt, minInt, &r), true);
QCOMPARE(add_overflow(maxInt - 1, int(1), &r), false);
QCOMPARE(add_overflow(maxInt, int(1), &r), true);
QCOMPARE(add_overflow(maxInt, maxInt, &r), true);
QCOMPARE(sub_overflow(minInt + 1, int(1), &r), false);
QCOMPARE(sub_overflow(minInt, int(1), &r), true);
QCOMPARE(sub_overflow(minInt, maxInt, &r), true);
QCOMPARE(sub_overflow(maxInt - 1, int(-1), &r), false);
QCOMPARE(sub_overflow(maxInt, int(-1), &r), true);
QCOMPARE(sub_overflow(maxInt, minInt, &r), true);
QCOMPARE(mul_overflow(minInt, int(1), &r), false);
QCOMPARE(mul_overflow(minInt, int(-1), &r), true);
QCOMPARE(mul_overflow(minInt, int(2), &r), true);
QCOMPARE(mul_overflow(minInt, minInt, &r), true);
QCOMPARE(mul_overflow(maxInt, int(1), &r), false);
QCOMPARE(mul_overflow(maxInt, int(-1), &r), false);
QCOMPARE(mul_overflow(maxInt, int(2), &r), true);
QCOMPARE(mul_overflow(maxInt, maxInt, &r), true);
}
QTEST_APPLESS_MAIN(tst_QNumeric)
#include "tst_qnumeric.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qoperatingsystemversion Test:
#####################################################################
qt_internal_add_test(tst_qoperatingsystemversion
SOURCES
tst_qoperatingsystemversion.cpp
)
## Scopes:
#####################################################################

View File

@ -0,0 +1,257 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qoperatingsystemversion.h>
class tst_QOperatingSystemVersion : public QObject
{
Q_OBJECT
private slots:
void construction_data();
void construction();
void globals_data();
void globals();
void anyOf();
void comparison_data();
void comparison();
void comparison2_data();
void comparison2();
void mixedComparison();
};
void tst_QOperatingSystemVersion::construction_data()
{
QTest::addColumn<QOperatingSystemVersion::OSType>("osType");
QTest::addColumn<int>("majorVersion");
QTest::addColumn<int>("minorVersion");
QTest::addColumn<int>("microVersion");
QTest::addColumn<int>("segmentCount");
QTest::newRow("Major only") << QOperatingSystemVersion::OSType::Windows << 1 << -1 << -1 << 1;
QTest::newRow("Major and minor") << QOperatingSystemVersion::OSType::MacOS
<< 1 << 2 << -1 << 2;
QTest::newRow("Major, minor and micro") << QOperatingSystemVersion::OSType::Android
<< 1 << 2 << 3 << 3;
}
void tst_QOperatingSystemVersion::construction()
{
QFETCH(QOperatingSystemVersion::OSType, osType);
QFETCH(int, majorVersion);
QFETCH(int, minorVersion);
QFETCH(int, microVersion);
QFETCH(int, segmentCount);
const QOperatingSystemVersion systemVersion(osType, majorVersion, minorVersion, microVersion);
QCOMPARE(systemVersion.type(), osType);
QCOMPARE(systemVersion.segmentCount(), segmentCount);
QCOMPARE(systemVersion.majorVersion(), majorVersion);
QCOMPARE(systemVersion.minorVersion(), minorVersion);
QCOMPARE(systemVersion.microVersion(), microVersion);
if (osType != QOperatingSystemVersion::OSType::Unknown)
QVERIFY(!systemVersion.name().isEmpty());
}
void tst_QOperatingSystemVersion::globals_data()
{
QTest::addColumn<QOperatingSystemVersion>("osver");
QTest::addColumn<QOperatingSystemVersion::OSType>("osType");
#define ADDROW(os) QTest::newRow(#os) << QOperatingSystemVersion(QOperatingSystemVersion::os)
// legacy ones (global variables)
ADDROW(Windows7) << QOperatingSystemVersion::Windows;
ADDROW(Windows10) << QOperatingSystemVersion::Windows;
ADDROW(OSXMavericks) << QOperatingSystemVersion::MacOS;
ADDROW(MacOSMonterey) << QOperatingSystemVersion::MacOS;
ADDROW(AndroidJellyBean) << QOperatingSystemVersion::Android;
ADDROW(Android11) << QOperatingSystemVersion::Android;
// new ones (static constexpr)
ADDROW(Windows11) << QOperatingSystemVersion::Windows;
ADDROW(Android12) << QOperatingSystemVersion::Android;
#undef ADDROW
}
void tst_QOperatingSystemVersion::globals()
{
QFETCH(QOperatingSystemVersion, osver);
QFETCH(QOperatingSystemVersion::OSType, osType);
QCOMPARE(osver.type(), osType);
QCOMPARE_NE(osver.majorVersion(), 0);
}
void tst_QOperatingSystemVersion::anyOf()
{
std::initializer_list<QOperatingSystemVersion::OSType> typesToCheck = {
QOperatingSystemVersion::OSType::Windows, QOperatingSystemVersion::OSType::Android,
QOperatingSystemVersion::OSType::MacOS, QOperatingSystemVersion::OSType::Unknown
};
{
// type found case
const QOperatingSystemVersion systemVersion(QOperatingSystemVersion::OSType::MacOS, 1);
QCOMPARE(systemVersion.isAnyOfType(typesToCheck), true);
}
{
// type NOT found case
const QOperatingSystemVersion systemVersion(QOperatingSystemVersion::OSType::WatchOS, 1);
QCOMPARE(systemVersion.isAnyOfType(typesToCheck), false);
}
}
void tst_QOperatingSystemVersion::comparison_data()
{
QTest::addColumn<QOperatingSystemVersion::OSType>("lhsType");
QTest::addColumn<int>("lhsMajor");
QTest::addColumn<int>("lhsMinor");
QTest::addColumn<int>("lhsMicro");
QTest::addColumn<QOperatingSystemVersion::OSType>("rhsType");
QTest::addColumn<int>("rhsMajor");
QTest::addColumn<int>("rhsMinor");
QTest::addColumn<int>("rhsMicro");
QTest::addColumn<bool>("lessResult");
QTest::addColumn<bool>("lessEqualResult");
QTest::addColumn<bool>("moreResult");
QTest::addColumn<bool>("moreEqualResult");
QTest::addRow("mismatching types") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< QOperatingSystemVersion::OSType::MacOS << 1 << 2 << 3
<< false << false << false << false;
QTest::addRow("equal versions") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< false << true << false << true;
QTest::addRow("lhs micro less") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 2
<< QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< true << true << false << false;
QTest::addRow("rhs micro less") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 2
<< QOperatingSystemVersion::OSType::Windows << 1 << 2 << 1
<< false << false << true << true;
QTest::addRow("lhs minor less") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< QOperatingSystemVersion::OSType::Windows << 1 << 3 << 3
<< true << true << false << false;
QTest::addRow("rhs minor less") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 2
<< QOperatingSystemVersion::OSType::Windows << 1 << 1 << 3
<< false << false << true << true;
QTest::addRow("lhs major less") << QOperatingSystemVersion::OSType::Windows << 0 << 5 << 6
<< QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< true << true << false << false;
QTest::addRow("rhs major less") << QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< QOperatingSystemVersion::OSType::Windows << 0 << 2 << 3
<< false << false << true << true;
QTest::addRow("different segmentCount")
<< QOperatingSystemVersion::OSType::Windows << 1 << 2 << 3
<< QOperatingSystemVersion::OSType::Windows << 1 << 2 << -1
<< false << true << false << true;
}
void tst_QOperatingSystemVersion::comparison()
{
QFETCH(QOperatingSystemVersion::OSType, lhsType);
QFETCH(int, lhsMajor);
QFETCH(int, lhsMinor);
QFETCH(int, lhsMicro);
const QOperatingSystemVersion lhsSystemInfo(lhsType, lhsMajor, lhsMinor, lhsMicro);
QFETCH(QOperatingSystemVersion::OSType, rhsType);
QFETCH(int, rhsMajor);
QFETCH(int, rhsMinor);
QFETCH(int, rhsMicro);
const QOperatingSystemVersion rhsSystemInfo(rhsType, rhsMajor, rhsMinor, rhsMicro);
QFETCH(bool, lessResult);
QCOMPARE(lhsSystemInfo < rhsSystemInfo, lessResult);
QFETCH(bool, lessEqualResult);
QCOMPARE(lhsSystemInfo <= rhsSystemInfo, lessEqualResult);
QFETCH(bool, moreResult);
QCOMPARE(lhsSystemInfo > rhsSystemInfo, moreResult);
QFETCH(bool, moreEqualResult);
QCOMPARE(lhsSystemInfo >= rhsSystemInfo, moreEqualResult);
}
void tst_QOperatingSystemVersion::comparison2_data()
{
QTest::addColumn<QOperatingSystemVersion>("lhs");
QTest::addColumn<QOperatingSystemVersion>("rhs");
QTest::addColumn<int>("result");
#define ADDROW(os1, os2) \
QTest::newRow(#os1 "-vs-" #os2) << QOperatingSystemVersion(QOperatingSystemVersion::os1) \
<< QOperatingSystemVersion(QOperatingSystemVersion::os2)
// Cross-OS testing: not comparables.
ADDROW(Windows10, MacOSMonterey) << -128;
ADDROW(Windows11, MacOSMonterey) << -128;
ADDROW(MacOSMonterey, Windows10) << -128;
ADDROW(MacOSMonterey, Windows11) << -128;
ADDROW(Windows10, MacOSVentura) << -128;
ADDROW(Windows11, MacOSVentura) << -128;
ADDROW(MacOSVentura, Windows10) << -128;
ADDROW(MacOSVentura, Windows11) << -128;
ADDROW(Windows10, Android10) << -128;
ADDROW(Windows11, Android11) << -128;
// Same-OS tests. This list does not have to be exhaustive.
ADDROW(Windows7, Windows7) << 0;
ADDROW(Windows7, Windows8) << -1;
ADDROW(Windows8, Windows7) << 1;
ADDROW(Windows8, Windows10) << -1;
ADDROW(Windows10, Windows8) << 1;
ADDROW(Windows10, Windows10_21H1) << -1;
ADDROW(Windows10_21H1, Windows10) << 1;
ADDROW(Windows10, Windows11) << -1;
ADDROW(MacOSCatalina, MacOSCatalina) << 0;
ADDROW(MacOSCatalina, MacOSBigSur) << -1;
ADDROW(MacOSBigSur, MacOSCatalina) << 1;
ADDROW(MacOSMonterey, MacOSVentura) << -1;
ADDROW(MacOSVentura, MacOSVentura) << 0;
ADDROW(MacOSVentura, MacOSMonterey) << 1;
#undef ADDROW
}
void tst_QOperatingSystemVersion::comparison2()
{
QFETCH(QOperatingSystemVersion, lhs);
QFETCH(QOperatingSystemVersion, rhs);
QFETCH(int, result);
QEXPECT_FAIL("Windows10-vs-Windows10_21H1", "QTBUG-107907: Unexpected behavior", Abort);
QEXPECT_FAIL("Windows10-vs-Windows11", "QTBUG-107907: Unexpected behavior", Abort);
// value -128 indicates "not comparable"
bool comparable = (result != -128);
QCOMPARE(lhs < rhs, result < 0 && comparable);
QEXPECT_FAIL("Windows10_21H1-vs-Windows10", "QTBUG-107907: Unexpected behavior", Abort);
QCOMPARE(lhs <= rhs, result <= 0 && comparable);
QCOMPARE(lhs > rhs, result > 0 && comparable);
QCOMPARE(lhs >= rhs, result >= 0 && comparable);
}
void tst_QOperatingSystemVersion::mixedComparison()
{
// ==
QVERIFY(QOperatingSystemVersion::Windows10
>= QOperatingSystemVersionBase(QOperatingSystemVersionBase::Windows, 10, 0));
QVERIFY(QOperatingSystemVersion::Windows10
<= QOperatingSystemVersionBase(QOperatingSystemVersionBase::Windows, 10, 0));
}
QTEST_MAIN(tst_QOperatingSystemVersion)
#include "tst_qoperatingsystemversion.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qrandomgenerator Test:
#####################################################################
qt_internal_add_test(tst_qrandomgenerator
SOURCES
tst_qrandomgenerator.cpp
LIBRARIES
Qt::CorePrivate
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qtendian Test:
#####################################################################
qt_internal_add_test(tst_qtendian
SOURCES
tst_qtendian.cpp
LIBRARIES
Qt::CorePrivate
)

View File

@ -0,0 +1,449 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtCore/qendian.h>
#include <QtCore/private/qendian_p.h>
#include <QtCore/qsysinfo.h>
class tst_QtEndian: public QObject
{
Q_OBJECT
public:
enum Signedness {
Unsigned,
Signed
};
Q_ENUM(Signedness);
private slots:
void fromBigEndian();
void fromLittleEndian();
void fromBigEndianRegion_data();
void fromBigEndianRegion();
void fromLittleEndianRegion_data() { fromBigEndianRegion_data(); }
void fromLittleEndianRegion();
void toBigEndian();
void toLittleEndian();
void toBigEndianRegion_data() { fromBigEndianRegion_data(); }
void toBigEndianRegion();
void toLittleEndianRegion_data() { fromBigEndianRegion_data(); }
void toLittleEndianRegion();
void endianIntegers_data();
void endianIntegers();
void endianBitfieldUnions_data();
void endianBitfieldUnions();
};
struct TestData
{
quint64 data64;
quint32 data32;
quint16 data16;
quint8 data8;
float dataFloat;
double dataDouble;
quint8 reserved;
};
template <typename T> T getData(const TestData &d);
template <> quint8 getData(const TestData &d) { return d.data8; }
template <> quint16 getData(const TestData &d) { return d.data16; }
template <> quint32 getData(const TestData &d) { return d.data32; }
template <> quint64 getData(const TestData &d) { return d.data64; }
template <> float getData(const TestData &d) { return d.dataFloat; }
union RawTestData
{
uchar rawData[sizeof(TestData)];
TestData data;
};
template <typename Float>
Float int2Float(typename QIntegerForSizeof<Float>::Unsigned i)
{
Float result = 0;
memcpy(reinterpret_cast<char *>(&result), reinterpret_cast<const char *>(&i), sizeof (Float));
return result;
}
static const TestData inNativeEndian = {
Q_UINT64_C(0x0123456789abcdef),
0x00c0ffee,
0xcafe,
0xcf,
int2Float<float>(0x00c0ffeeU),
int2Float<double>(Q_UINT64_C(0x0123456789abcdef)),
'\0'
};
static const RawTestData inBigEndian = {
"\x01\x23\x45\x67\x89\xab\xcd\xef"
"\x00\xc0\xff\xee"
"\xca\xfe"
"\xcf"
"\x00\xc0\xff\xee"
"\x01\x23\x45\x67\x89\xab\xcd\xef"
};
static const RawTestData inLittleEndian = {
"\xef\xcd\xab\x89\x67\x45\x23\x01"
"\xee\xff\xc0\x00"
"\xfe\xca"
"\xcf"
"\xee\xff\xc0\x00"
"\xef\xcd\xab\x89\x67\x45\x23\x01"
};
#define EXPAND_ENDIAN_TEST(endian) \
do { \
/* Unsigned tests */ \
ENDIAN_TEST(endian, quint, 64); \
ENDIAN_TEST(endian, quint, 32); \
ENDIAN_TEST(endian, quint, 16); \
ENDIAN_TEST(endian, quint, 8); \
\
/* Signed tests */ \
ENDIAN_TEST(endian, qint, 64); \
ENDIAN_TEST(endian, qint, 32); \
ENDIAN_TEST(endian, qint, 16); \
ENDIAN_TEST(endian, qint, 8); \
} while (false) \
/**/
#define ENDIAN_TEST(endian, type, size) \
do { \
QCOMPARE(qFrom ## endian ## Endian( \
(type ## size)(in ## endian ## Endian.data.data ## size)), \
(type ## size)(inNativeEndian.data ## size)); \
QCOMPARE(qFrom ## endian ## Endian<type ## size>( \
in ## endian ## Endian.rawData + offsetof(TestData, data ## size)), \
(type ## size)(inNativeEndian.data ## size)); \
} while (false) \
/**/
void tst_QtEndian::fromBigEndian()
{
EXPAND_ENDIAN_TEST(Big);
}
void tst_QtEndian::fromLittleEndian()
{
EXPAND_ENDIAN_TEST(Little);
}
#undef ENDIAN_TEST
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wmemset-elt-size")
template <typename T>
void transformRegion_template(T (*transformOne)(T), void (*transformRegion)(const void *, qsizetype, void *))
{
enum { Size = 64 };
T source[Size];
T dest[Size];
T expected = transformOne(getData<T>(inNativeEndian));
std::fill_n(source, +Size, getData<T>(inNativeEndian));
memset(dest, 0, sizeof(dest));
auto checkBounds = [&](int from) {
for ( ; from < Size; ++from)
QCOMPARE(dest[from], T(0));
};
transformRegion(source, 1, dest);
QCOMPARE(dest[0], expected);
checkBounds(1);
memset(dest, 0, sizeof(T));
transformRegion(source, 2, dest);
QCOMPARE(dest[0], expected);
QCOMPARE(dest[1], expected);
checkBounds(2);
memset(dest, 0, sizeof(T) * 2);
transformRegion(source, 3, dest);
QCOMPARE(dest[0], expected);
QCOMPARE(dest[1], expected);
QCOMPARE(dest[2], expected);
checkBounds(3);
memset(dest, 0, sizeof(T) * 3);
transformRegion(source, 4, dest);
QCOMPARE(dest[0], expected);
QCOMPARE(dest[1], expected);
QCOMPARE(dest[2], expected);
QCOMPARE(dest[3], expected);
checkBounds(4);
memset(dest, 0, sizeof(T) * 4);
transformRegion(source, 8, dest);
for (int i = 0; i < 8; ++i)
QCOMPARE(dest[i], expected);
checkBounds(8);
memset(dest, 0, sizeof(T) * 8);
transformRegion(source, 16, dest);
for (int i = 0; i < 16; ++i)
QCOMPARE(dest[i], expected);
checkBounds(16);
memset(dest, 0, sizeof(T) * 16);
transformRegion(source, 32, dest);
for (int i = 0; i < 32; ++i)
QCOMPARE(dest[i], expected);
checkBounds(32);
memset(dest, 0, sizeof(T) * 32);
transformRegion(source, 64, dest);
for (int i = 0; i < 64; ++i)
QCOMPARE(dest[i], expected);
// check transforming in-place
memcpy(dest, source, sizeof(dest));
transformRegion(dest, 64, dest);
for (int i = 0; i < 64; ++i)
QCOMPARE(dest[i], expected);
}
QT_WARNING_POP
void tst_QtEndian::fromBigEndianRegion_data()
{
QTest::addColumn<int>("size");
QTest::newRow("1") << 1;
QTest::newRow("2") << 2;
QTest::newRow("4") << 4;
QTest::newRow("8") << 8;
}
void tst_QtEndian::fromBigEndianRegion()
{
QFETCH(int, size);
switch (size) {
case 1: return transformRegion_template<quint8>(qFromBigEndian<quint8>, qFromBigEndian<quint8>);
case 2: return transformRegion_template<quint16>(qFromBigEndian<quint16>, qFromBigEndian<quint16>);
case 4: return transformRegion_template<quint32>(qFromBigEndian<quint32>, qFromBigEndian<quint32>);
case 8: return transformRegion_template<quint64>(qFromBigEndian<quint64>, qFromBigEndian<quint64>);
}
}
void tst_QtEndian::fromLittleEndianRegion()
{
QFETCH(int, size);
switch (size) {
case 1: return transformRegion_template<quint8>(qFromLittleEndian<quint8>, qFromLittleEndian<quint8>);
case 2: return transformRegion_template<quint16>(qFromLittleEndian<quint16>, qFromLittleEndian<quint16>);
case 4: return transformRegion_template<quint32>(qFromLittleEndian<quint32>, qFromLittleEndian<quint32>);
case 8: return transformRegion_template<quint64>(qFromLittleEndian<quint64>, qFromLittleEndian<quint64>);
}
}
#define ENDIAN_TEST(endian, type, size) \
do { \
QCOMPARE(qTo ## endian ## Endian( \
(type ## size)(inNativeEndian.data ## size)), \
(type ## size)(in ## endian ## Endian.data.data ## size)); \
\
RawTestData test; \
qTo ## endian ## Endian( \
(type ## size)(inNativeEndian.data ## size), \
test.rawData + offsetof(TestData, data ## size)); \
QCOMPARE(test.data.data ## size, in ## endian ## Endian.data.data ## size ); \
} while (false) \
/**/
void tst_QtEndian::toBigEndian()
{
EXPAND_ENDIAN_TEST(Big);
}
void tst_QtEndian::toLittleEndian()
{
EXPAND_ENDIAN_TEST(Little);
}
#undef ENDIAN_TEST
void tst_QtEndian::toBigEndianRegion()
{
QFETCH(int, size);
switch (size) {
case 1: return transformRegion_template<quint8>(qToBigEndian<quint8>, qToBigEndian<quint8>);
case 2: return transformRegion_template<quint16>(qToBigEndian<quint16>, qToBigEndian<quint16>);
case 4: return transformRegion_template<quint32>(qToBigEndian<quint32>, qToBigEndian<quint32>);
case 8: return transformRegion_template<quint64>(qToBigEndian<quint64>, qToBigEndian<quint64>);
}
}
void tst_QtEndian::toLittleEndianRegion()
{
QFETCH(int, size);
switch (size) {
case 1: return transformRegion_template<quint8>(qToLittleEndian<quint8>, qToLittleEndian<quint8>);
case 2: return transformRegion_template<quint16>(qToLittleEndian<quint16>, qToLittleEndian<quint16>);
case 4: return transformRegion_template<quint32>(qToLittleEndian<quint32>, qToLittleEndian<quint32>);
case 8: return transformRegion_template<quint64>(qToLittleEndian<quint64>, qToLittleEndian<quint64>);
}
}
void tst_QtEndian::endianIntegers_data()
{
QTest::addColumn<int>("val");
QTest::newRow("-30000") << -30000;
QTest::newRow("-1") << -1;
QTest::newRow("0") << 0;
QTest::newRow("1020") << 1020;
QTest::newRow("16385") << 16385;
}
void tst_QtEndian::endianIntegers()
{
QFETCH(int, val);
qint16 vi16 = val;
qint32 vi32 = val;
qint64 vi64 = val;
quint16 vu16 = val;
quint32 vu32 = val;
quint64 vu64 = val;
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
QCOMPARE(*reinterpret_cast<qint16_be*>(&vi16), vi16);
QCOMPARE(*reinterpret_cast<qint32_be*>(&vi32), vi32);
QCOMPARE(*reinterpret_cast<qint64_be*>(&vi64), vi64);
QCOMPARE(*reinterpret_cast<qint16_le*>(&vi16), qbswap(vi16));
QCOMPARE(*reinterpret_cast<qint32_le*>(&vi32), qbswap(vi32));
QCOMPARE(*reinterpret_cast<qint64_le*>(&vi64), qbswap(vi64));
QCOMPARE(*reinterpret_cast<quint16_be*>(&vu16), vu16);
QCOMPARE(*reinterpret_cast<quint32_be*>(&vu32), vu32);
QCOMPARE(*reinterpret_cast<quint64_be*>(&vu64), vu64);
QCOMPARE(*reinterpret_cast<quint16_le*>(&vu16), qbswap(vu16));
QCOMPARE(*reinterpret_cast<quint32_le*>(&vu32), qbswap(vu32));
QCOMPARE(*reinterpret_cast<quint64_le*>(&vu64), qbswap(vu64));
#else
QCOMPARE(*reinterpret_cast<qint16_be*>(&vi16), qbswap(vi16));
QCOMPARE(*reinterpret_cast<qint32_be*>(&vi32), qbswap(vi32));
QCOMPARE(*reinterpret_cast<qint64_be*>(&vi64), qbswap(vi64));
QCOMPARE(*reinterpret_cast<qint16_le*>(&vi16), vi16);
QCOMPARE(*reinterpret_cast<qint32_le*>(&vi32), vi32);
QCOMPARE(*reinterpret_cast<qint64_le*>(&vi64), vi64);
QCOMPARE(*reinterpret_cast<quint16_be*>(&vu16), qbswap(vu16));
QCOMPARE(*reinterpret_cast<quint32_be*>(&vu32), qbswap(vu32));
QCOMPARE(*reinterpret_cast<quint64_be*>(&vu64), qbswap(vu64));
QCOMPARE(*reinterpret_cast<quint16_le*>(&vu16), vu16);
QCOMPARE(*reinterpret_cast<quint32_le*>(&vu32), vu32);
QCOMPARE(*reinterpret_cast<quint64_le*>(&vu64), vu64);
#endif
}
template<template<typename... Accessors> typename Union, template<int, int, typename> typename Member>
void testBitfieldUnion()
{
using upper = Member<21, 11, uint>;
using lower = Member<10, 11, uint>;
using bottom = Member<0, 10, int>;
using all = Member<0, 32, uint>;
using UnionType = Union<upper, lower, bottom, all>;
UnionType u;
u.template set<upper>(200);
QCOMPARE(u.template get<upper>(), 200U);
u.template set<lower>(1000);
u.template set<bottom>(-8);
QCOMPARE(u.template get<lower>(), 1000U);
QCOMPARE(u.template get<upper>(), 200U);
u.template set<lower>(u.template get<lower>() + u.template get<upper>());
QCOMPARE(u.template get<upper>(), 200U);
QCOMPARE(u.template get<lower>(), 1200U);
u.template set<upper>(65536 + 7);
u.template set<lower>(65535);
QCOMPARE(u.template get<lower>(), 65535U & ((1<<11) - 1));
QCOMPARE(u.template get<upper>(), 7U);
QCOMPARE(u.template get<bottom>(), -8);
UnionType u2(QSpecialIntegerBitfieldZero);
QCOMPARE(u2.data(), 0U);
u2.template set<all>(std::numeric_limits<uint>::max());
QCOMPARE(u2.template get<all>(), std::numeric_limits<uint>::max());
u2.template set<all>(453);
QCOMPARE(u2.template get<all>(), 453U);
u2.template set<all>(0);
QCOMPARE(u2.template get<all>(), 0U);
UnionType u3(42U);
QCOMPARE(u3.data(), 42U);
using BEUintAccessor = QSpecialIntegerAccessor<QBigEndianStorageType<uint>, 21, 11>;
using LEUintAccessor = QSpecialIntegerAccessor<QLittleEndianStorageType<uint>, 21, 11>;
using BEIntAccessor = QSpecialIntegerAccessor<QBigEndianStorageType<int>, 0, 10>;
using LEIntAccessor = QSpecialIntegerAccessor<QLittleEndianStorageType<int>, 0, 10>;
if constexpr (std::is_same_v<BEUintAccessor, upper>) {
QCOMPARE(u.template get<BEUintAccessor>(), 7U);
} else if constexpr (std::is_same_v<LEUintAccessor, upper>) {
QCOMPARE(u.template get<LEUintAccessor>(), 7U);
} else if constexpr (std::is_same_v<BEIntAccessor, bottom>) {
QCOMPARE(u.template get<BEIntAccessor>(), -8);
} else if constexpr (std::is_same_v<LEIntAccessor, bottom>) {
QCOMPARE(u.template get<LEIntAccessor>(), -8);
} else {
QFAIL("none of the manually defined accessors match");
}
}
void tst_QtEndian::endianBitfieldUnions_data()
{
QTest::addColumn<QSysInfo::Endian>("byteOrder");
QTest::addColumn<Signedness>("signedness");
QTest::addRow("little endian unsigned") << QSysInfo::LittleEndian << Unsigned;
QTest::addRow("little endian signed") << QSysInfo::LittleEndian << Signed;
QTest::addRow("big endian unsigned") << QSysInfo::BigEndian << Unsigned;
QTest::addRow("big endian signed") << QSysInfo::BigEndian << Signed;
}
void tst_QtEndian::endianBitfieldUnions()
{
QFETCH(QSysInfo::Endian, byteOrder);
QFETCH(Signedness, signedness);
switch (byteOrder) {
case QSysInfo::LittleEndian:
switch (signedness) {
case Unsigned:
testBitfieldUnion<quint32_le_bitfield_union, quint32_le_bitfield_member>();
return;
case Signed:
testBitfieldUnion<qint32_le_bitfield_union, qint32_le_bitfield_member>();
return;
}
Q_UNREACHABLE_RETURN();
case QSysInfo::BigEndian:
switch (signedness) {
case Unsigned:
testBitfieldUnion<quint32_be_bitfield_union, quint32_be_bitfield_member>();
return;
case Signed:
testBitfieldUnion<qint32_be_bitfield_union, qint32_be_bitfield_member>();
return;
}
Q_UNREACHABLE_RETURN();
}
}
QTEST_MAIN(tst_QtEndian)
#include "tst_qtendian.moc"

View File

@ -0,0 +1 @@
add_subdirectory(function_ref)

View File

@ -0,0 +1,10 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_qxp_function_ref
EXCEPTIONS
SOURCES
tst_qxp_function_ref.cpp
LIBRARIES
Qt::Core
)

View File

@ -0,0 +1,279 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/qxpfunctional.h>
#include <QTest>
#include <type_traits>
// checking dependency q20::remove_cvref_t:
#define CHECK(in, out) \
static_assert(std::is_same_v<q20::remove_cvref_t< in >, out >)
CHECK(int, int);
CHECK(const int, int);
CHECK(int &, int);
CHECK(const int &, int);
CHECK(int &&, int);
CHECK(const int &&, int);
CHECK(int *, int *);
CHECK(const int *, const int *);
CHECK(int[4], int[4]);
CHECK(const int (&)[4], int[4]);
#undef CHECK
template <typename T> constexpr inline bool
is_noexcept_function_ref_helper_v = false;
template <typename R, typename...Args> constexpr inline bool
is_noexcept_function_ref_helper_v<qxp::function_ref<R(Args...) noexcept(true)>> = true;
template <typename R, typename...Args> constexpr inline bool
is_noexcept_function_ref_helper_v<qxp::function_ref<R(Args...) const noexcept(true)>> = true;
template <typename T> constexpr inline bool
is_noexcept_function_ref_v = is_noexcept_function_ref_helper_v<q20::remove_cvref_t<T>>;
class tst_qxp_function_ref : public QObject
{
Q_OBJECT
public:
using QObject::QObject;
private Q_SLOTS:
void basics();
void constOverloads();
void constExpr();
void voidReturning();
void ctad();
};
void tst_qxp_function_ref::basics()
{
static_assert(std::is_trivially_copyable_v<qxp::function_ref<int(int)>>);
static_assert(std::is_trivially_copyable_v<qxp::function_ref<int()>>);
static_assert(std::is_trivially_copyable_v<qxp::function_ref<void()>>);
{
Q_CONSTINIT static int invoked = 0;
auto lambda = [](int i) noexcept { ++invoked; return i; };
const qxp::function_ref<int(int)> f = lambda;
QCOMPARE(invoked, 0);
QCOMPARE(f(42), 42);
QCOMPARE(invoked, 1);
const int fourtyTwo = 42;
const qxp::function_ref<int(int) noexcept> f2 = std::move(lambda);
QCOMPARE(invoked, 1);
QCOMPARE(f2(fourtyTwo), 42);
QCOMPARE(invoked, 2);
int (*fpr)(int) = lambda;
const qxp::function_ref f3 = fpr;
static_assert(!is_noexcept_function_ref_v<decltype(f3)>);
QCOMPARE(invoked, 2);
QCOMPARE(f3(42), 42);
QCOMPARE(invoked, 3);
int (*fpr2)(int) noexcept = lambda;
const qxp::function_ref f4 = fpr2;
static_assert(is_noexcept_function_ref_v<decltype(f4)>);
QCOMPARE(invoked, 3);
QCOMPARE(f4(42), 42);
QCOMPARE(invoked, 4);
}
{
Q_CONSTINIT static int invoked = 0;
auto lambda = [] { ++invoked; return 42; };
const qxp::function_ref<int()> f = lambda;
QCOMPARE(invoked, 0);
QCOMPARE(f(), 42);
QCOMPARE(invoked, 1);
const qxp::function_ref<int()> f2 = std::move(lambda);
QCOMPARE(invoked, 1);
QCOMPARE(f2(), 42);
QCOMPARE(invoked, 2);
int (*fpr)() = lambda;
const qxp::function_ref f3 = fpr;
static_assert(!is_noexcept_function_ref_v<decltype(f3)>);
QCOMPARE(invoked, 2);
QCOMPARE(f3(), 42);
QCOMPARE(invoked, 3);
}
{
Q_CONSTINIT static int invoked = 0;
auto lambda = [] { ++invoked; };
const qxp::function_ref<void()> f = lambda;
QCOMPARE(invoked, 0);
f();
QCOMPARE(invoked, 1);
const qxp::function_ref<void()> f2 = std::move(lambda);
QCOMPARE(invoked, 1);
f2();
QCOMPARE(invoked, 2);
void (*fpr)() = lambda;
const qxp::function_ref f3 = fpr;
QCOMPARE(invoked, 2);
f3();
QCOMPARE(invoked, 3);
}
}
void tst_qxp_function_ref::constOverloads()
{
auto func_c = [](qxp::function_ref<int() const> callable)
{
return callable();
};
auto func_m = [](qxp::function_ref<int() /*mutable*/> callable)
{
return callable();
};
struct S
{
int operator()() { return 1; }
int operator()() const { return 2; }
};
S s;
QCOMPARE(func_c(s), 2);
QCOMPARE(func_m(s), 1);
const S cs;
QCOMPARE(func_c(cs), 2);
#if 0
// this should not compile (and doesn't, but currently fails with an error in the impl,
// not by failing a constructor constaint → spec issue?).
QCOMPARE(func_m(cs), 2);
#endif
}
void tst_qxp_function_ref::constExpr()
{
Q_CONSTINIT static int invoked = 0;
{
Q_CONSTINIT static auto lambda = [] (int i) { ++invoked; return i; };
// the function object constructor is constexpr, so this should be constinit:
Q_CONSTINIT static qxp::function_ref<int(int)> f = lambda;
QCOMPARE(invoked, 0);
QCOMPARE(f(15), 15);
QCOMPARE(invoked, 1);
}
{
constexpr static auto lambda = [] (int i) { ++invoked; return i; };
// the function object constructor is constexpr, so this should be constinit:
Q_CONSTINIT static qxp::function_ref<int(int) const> f = lambda;
QCOMPARE(invoked, 1);
QCOMPARE(f(51), 51);
QCOMPARE(invoked, 2);
#if 0 // ### should this work?:
Q_CONSTINIT static qxp::function_ref<int(int)> f2 = lambda;
QCOMPARE(invoked, 2);
QCOMPARE(f(150), 150);
QCOMPARE(invoked, 3);
#endif
}
}
int i_f_i_nx(int i) noexcept { return i; }
void v_f_i_nx(int) noexcept {}
int i_f_v_nx() noexcept { return 42; }
void v_f_v_nx() noexcept {}
int i_f_i_ex(int i) { return i; }
void v_f_i_ex(int) {}
int i_f_v_ex() { return 42; }
void v_f_v_ex() {}
void tst_qxp_function_ref::voidReturning()
{
// check that "casting" int to void returns works:
using Fi = qxp::function_ref<void(int)>;
using Fv = qxp::function_ref<void()>;
{
Fi fi = i_f_i_nx;
fi(42);
Fv fv = i_f_v_nx;
fv();
}
{
Fi fi = i_f_i_ex;
fi(42);
Fv fv = i_f_v_ex;
fv();
}
// now with lambdas
bool ok = false; // prevent lambdas from decaying to function pointers
{
auto lambda1 = [&](int i) noexcept { return i + int(ok); };
Fi fi = lambda1;
fi(42);
auto lambda2 = [&]() noexcept { return int(ok); };
Fv fv = lambda2;
fv();
}
{
auto lambda1 = [&](int i) { return i + int(ok); };
Fi fi = lambda1;
fi(42);
auto lambda2 = [&]() { return int(ok); };
Fv fv = lambda2;
fv();
}
}
void tst_qxp_function_ref::ctad()
{
#define CHECK(fun, sig) \
do { \
qxp::function_ref f = fun; \
static_assert(std::is_same_v<decltype(f), \
qxp::function_ref<sig>>); \
qxp::function_ref f2 = &fun; \
static_assert(std::is_same_v<decltype(f2), \
qxp::function_ref<sig>>); \
} while (false)
CHECK(i_f_i_nx, int (int) noexcept);
CHECK(v_f_i_nx, void(int) noexcept);
CHECK(i_f_v_nx, int ( ) noexcept);
CHECK(v_f_v_nx, void( ) noexcept);
CHECK(i_f_i_ex, int (int));
CHECK(v_f_i_ex, void(int));
CHECK(i_f_v_ex, int ( ));
CHECK(v_f_v_ex, void( ));
#undef CHECK
#if 0 // no deduction guides for the non-function-pointer case, so no CTAD for lambdas
{
auto lambda = [](int i) -> int { return i; };
qxp::function_ref f = lambda;
static_assert(std::is_same_v<decltype(f),
qxp::function_ref<int(int)>>);
}
#endif
}
QTEST_APPLESS_MAIN(tst_qxp_function_ref);
#include "tst_qxp_function_ref.moc"