mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-04 16:25:27 +08:00
qt 6.5.1 original
This commit is contained in:
23
tests/auto/corelib/global/CMakeLists.txt
Normal file
23
tests/auto/corelib/global/CMakeLists.txt
Normal 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)
|
11
tests/auto/corelib/global/q_func_info/CMakeLists.txt
Normal file
11
tests/auto/corelib/global/q_func_info/CMakeLists.txt
Normal 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
|
||||
)
|
106
tests/auto/corelib/global/q_func_info/tst_q_func_info.cpp
Normal file
106
tests/auto/corelib/global/q_func_info/tst_q_func_info.cpp
Normal 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"
|
14
tests/auto/corelib/global/qcompare/CMakeLists.txt
Normal file
14
tests/auto/corelib/global/qcompare/CMakeLists.txt
Normal 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:
|
||||
#####################################################################
|
98
tests/auto/corelib/global/qcompare/tst_qcompare.cpp
Normal file
98
tests/auto/corelib/global/qcompare/tst_qcompare.cpp
Normal 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"
|
18
tests/auto/corelib/global/qflags/CMakeLists.txt
Normal file
18
tests/auto/corelib/global/qflags/CMakeLists.txt
Normal 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
|
||||
)
|
481
tests/auto/corelib/global/qflags/tst_qflags.cpp
Normal file
481
tests/auto/corelib/global/qflags/tst_qflags.cpp
Normal 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"
|
13
tests/auto/corelib/global/qfloat16/CMakeLists.txt
Normal file
13
tests/auto/corelib/global/qfloat16/CMakeLists.txt
Normal 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
|
||||
)
|
694
tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp
Normal file
694
tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp
Normal 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"
|
11
tests/auto/corelib/global/qgetputenv/CMakeLists.txt
Normal file
11
tests/auto/corelib/global/qgetputenv/CMakeLists.txt
Normal 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
|
||||
)
|
207
tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp
Normal file
207
tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp
Normal 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"
|
15
tests/auto/corelib/global/qglobal/CMakeLists.txt
Normal file
15
tests/auto/corelib/global/qglobal/CMakeLists.txt
Normal 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:
|
||||
#####################################################################
|
92
tests/auto/corelib/global/qglobal/qglobal.c
Normal file
92
tests/auto/corelib/global/qglobal/qglobal.c
Normal 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
|
||||
|
695
tests/auto/corelib/global/qglobal/tst_qglobal.cpp
Normal file
695
tests/auto/corelib/global/qglobal/tst_qglobal.cpp
Normal 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"
|
15
tests/auto/corelib/global/qglobalstatic/CMakeLists.txt
Normal file
15
tests/auto/corelib/global/qglobalstatic/CMakeLists.txt
Normal 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
|
||||
)
|
233
tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp
Normal file
233
tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp
Normal 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"
|
13
tests/auto/corelib/global/qhooks/CMakeLists.txt
Normal file
13
tests/auto/corelib/global/qhooks/CMakeLists.txt
Normal 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
|
||||
)
|
122
tests/auto/corelib/global/qhooks/tst_qhooks.cpp
Normal file
122
tests/auto/corelib/global/qhooks/tst_qhooks.cpp
Normal 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"
|
11
tests/auto/corelib/global/qkeycombination/CMakeLists.txt
Normal file
11
tests/auto/corelib/global/qkeycombination/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
9
tests/auto/corelib/global/qlogging/BLACKLIST
Normal file
9
tests/auto/corelib/global/qlogging/BLACKLIST
Normal file
@ -0,0 +1,9 @@
|
||||
[qMessagePattern:backtrace]
|
||||
# QTBUG-63915
|
||||
b2qt 64bit
|
||||
|
||||
[qMessagePattern:backtrace depth,separator]
|
||||
# QTBUG-63915
|
||||
b2qt 64bit
|
||||
# QTBUG-85364
|
||||
b2qt cmake
|
26
tests/auto/corelib/global/qlogging/CMakeLists.txt
Normal file
26
tests/auto/corelib/global/qlogging/CMakeLists.txt
Normal 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
|
||||
)
|
63
tests/auto/corelib/global/qlogging/app/main.cpp
Normal file
63
tests/auto/corelib/global/qlogging/app/main.cpp
Normal 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"
|
988
tests/auto/corelib/global/qlogging/tst_qlogging.cpp
Normal file
988
tests/auto/corelib/global/qlogging/tst_qlogging.cpp
Normal 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"
|
334
tests/auto/corelib/global/qlogging/tst_qmessagelogger.cpp
Normal file
334
tests/auto/corelib/global/qlogging/tst_qmessagelogger.cpp
Normal 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"
|
@ -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
|
||||
)
|
@ -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"
|
16
tests/auto/corelib/global/qnumeric/CMakeLists.txt
Normal file
16
tests/auto/corelib/global/qnumeric/CMakeLists.txt
Normal 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:
|
||||
#####################################################################
|
751
tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
Normal file
751
tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp
Normal 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"
|
@ -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:
|
||||
#####################################################################
|
@ -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"
|
13
tests/auto/corelib/global/qrandomgenerator/CMakeLists.txt
Normal file
13
tests/auto/corelib/global/qrandomgenerator/CMakeLists.txt
Normal 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
|
||||
)
|
1009
tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp
Normal file
1009
tests/auto/corelib/global/qrandomgenerator/tst_qrandomgenerator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
13
tests/auto/corelib/global/qtendian/CMakeLists.txt
Normal file
13
tests/auto/corelib/global/qtendian/CMakeLists.txt
Normal 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
|
||||
)
|
449
tests/auto/corelib/global/qtendian/tst_qtendian.cpp
Normal file
449
tests/auto/corelib/global/qtendian/tst_qtendian.cpp
Normal 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"
|
1
tests/auto/corelib/global/qxp/CMakeLists.txt
Normal file
1
tests/auto/corelib/global/qxp/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(function_ref)
|
10
tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt
Normal file
10
tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt
Normal 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
|
||||
)
|
@ -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"
|
Reference in New Issue
Block a user