Fix QMarginsF::operator==() for zero margins

The (in)equality operators for QMarginsF are documented to use fuzzy
comparison. However, the implementation unconditionally used
qFuzzyCompare which is incorrect for the case of 0 margins.
Update the implementation to use a combination of qFuzzyIsNull and
qFuzzyCompare, like it's done for QPointF.

[ChangeLog][QtCore][QMarginsF] Fixed a bug when equality comparison
returned incorrect results if one of the margins was zero.

Task-number: QTBUG-120308
Change-Id: I6e785fe8b523f6aa5f5317fb75877fdbf4e086c2
Reviewed-by: Tatiana Borisova <tatiana.borisova@qt.io>
This commit is contained in:
Ivan Solovev 2024-04-19 17:49:03 +02:00
parent 9d4e1b9f8d
commit 8a54d25a46
3 changed files with 59 additions and 4 deletions

View File

@ -304,18 +304,25 @@ private:
qreal m_right;
qreal m_bottom;
QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
friend constexpr inline bool operator==(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
return qFuzzyCompare(lhs.left(), rhs.left())
&& qFuzzyCompare(lhs.top(), rhs.top())
&& qFuzzyCompare(lhs.right(), rhs.right())
&& qFuzzyCompare(lhs.bottom(), rhs.bottom());
return ((!lhs.m_left || !rhs.m_left) ? qFuzzyIsNull(lhs.m_left - rhs.m_left)
: qFuzzyCompare(lhs.m_left, rhs.m_left))
&& ((!lhs.m_top || !rhs.m_top) ? qFuzzyIsNull(lhs.m_top - rhs.m_top)
: qFuzzyCompare(lhs.m_top, rhs.m_top))
&& ((!lhs.m_right || !rhs.m_right) ? qFuzzyIsNull(lhs.m_right - rhs.m_right)
: qFuzzyCompare(lhs.m_right, rhs.m_right))
&& ((!lhs.m_bottom || !rhs.m_bottom) ? qFuzzyIsNull(lhs.m_bottom - rhs.m_bottom)
: qFuzzyCompare(lhs.m_bottom, rhs.m_bottom));
}
friend constexpr inline bool operator!=(const QMarginsF &lhs, const QMarginsF &rhs) noexcept
{
return !(lhs == rhs);
}
QT_WARNING_POP
template <std::size_t I,
typename M,

View File

@ -14,4 +14,6 @@ endif()
qt_internal_add_test(tst_qmargins
SOURCES
tst_qmargins.cpp
LIBRARIES
Qt::TestPrivate
)

View File

@ -32,15 +32,21 @@ CHECK(const &&);
#include <QTest>
#include <qmargins.h>
#include <private/qcomparisontesthelper_p.h>
#include <array>
Q_DECLARE_METATYPE(QMargins)
constexpr static qreal qreal_min = std::numeric_limits<qreal>::min();
class tst_QMargins : public QObject
{
Q_OBJECT
private slots:
void comparison_data();
void comparison();
void getSetCheck();
#ifndef QT_NO_DATASTREAM
void dataStreamCheck();
@ -65,6 +71,46 @@ private slots:
void toMarginsF();
};
void tst_QMargins::comparison_data()
{
QTest::addColumn<QMarginsF>("lhs");
QTest::addColumn<QMarginsF>("rhs");
QTest::addColumn<bool>("result");
QTest::addColumn<bool>("floatResult");
QTest::addColumn<bool>("mixedResult");
auto row = [](const QMarginsF &lhs, const QMarginsF &rhs, bool res, bool fRes, bool mRes) {
QString str;
QDebug dbg(&str);
dbg.nospace() << "(" << lhs.left() << ", " << lhs.top() << ", " << lhs.right() << ", "
<< lhs.bottom() << ") vs (" << rhs.left() << ", " << rhs.top() << ", "
<< rhs.right() << ", " << rhs.bottom() << ")";
QTest::addRow("%s", str.toLatin1().constData()) << lhs << rhs << res << fRes << mRes;
};
row(QMarginsF(0.0, 0.0, 0.0, 0.0), QMarginsF(0.0, 0.0, 0.0, 0.0), true, true, true);
row(QMarginsF(qreal_min, -qreal_min, -qreal_min, qreal_min), QMarginsF(0.0, 0.0, 0.0, 0.0), true, true, true);
row(QMarginsF(1.0, 2.0, 3.0, 4.0), QMarginsF(1.1, 2.1, 2.9, 3.9), true, false, true);
row(QMarginsF(1.5, 2.5, 3.0, 4.0), QMarginsF(1.1, 2.1, 2.9, 3.9), false, false, false);
}
void tst_QMargins::comparison()
{
QFETCH(const QMarginsF, lhs);
QFETCH(const QMarginsF, rhs);
QFETCH(const bool, result);
QFETCH(const bool, floatResult);
QFETCH(const bool, mixedResult);
QT_TEST_EQUALITY_OPS(lhs, rhs, floatResult);
const QMargins lhsInt = lhs.toMargins();
const QMargins rhsInt = rhs.toMargins();
QT_TEST_EQUALITY_OPS(lhsInt, rhsInt, result);
QT_TEST_EQUALITY_OPS(lhs, rhsInt, mixedResult);
}
// Testing get/set functions
void tst_QMargins::getSetCheck()
{