qt 6.5.1 original

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

View File

@ -0,0 +1,55 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qatomicscopedvaluerollback)
if(NOT INTEGRITY)
add_subdirectory(collections)
endif()
add_subdirectory(containerapisymmetry)
add_subdirectory(qalgorithms)
add_subdirectory(qarraydata)
add_subdirectory(qbitarray)
add_subdirectory(qcache)
add_subdirectory(qcommandlineparser)
add_subdirectory(qcontiguouscache)
add_subdirectory(qcryptographichash)
add_subdirectory(qduplicatetracker)
add_subdirectory(qeasingcurve)
add_subdirectory(qexplicitlyshareddatapointer)
add_subdirectory(qflatmap)
if(QT_FEATURE_private_tests)
add_subdirectory(qfreelist)
endif()
add_subdirectory(qhash)
add_subdirectory(qhashfunctions)
add_subdirectory(qhashseed)
add_subdirectory(qline)
add_subdirectory(qlist)
add_subdirectory(qmakearray)
add_subdirectory(qmap)
add_subdirectory(qmargins)
add_subdirectory(qmessageauthenticationcode)
if(NOT INTEGRITY)
add_subdirectory(qoffsetstringarray)
endif()
add_subdirectory(qpair)
add_subdirectory(qpoint)
add_subdirectory(qpointf)
add_subdirectory(qqueue)
add_subdirectory(qrect)
add_subdirectory(qringbuffer)
add_subdirectory(qscopedpointer)
add_subdirectory(qscopedvaluerollback)
add_subdirectory(qscopeguard)
add_subdirectory(qtaggedpointer)
add_subdirectory(qset)
add_subdirectory(qsharedpointer)
add_subdirectory(qsize)
add_subdirectory(qsizef)
add_subdirectory(qstl)
add_subdirectory(qvarlengtharray)
add_subdirectory(qversionnumber)
add_subdirectory(qtimeline)
if(APPLE)
add_subdirectory(qmacautoreleasepool)
endif()

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,378 @@
// 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 "../../../../../src/corelib/tools/qalgorithms.h"
#include <QTest>
QT_WARNING_DISABLE_DEPRECATED
#include <iostream>
#include <iomanip>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <qalgorithms.h>
#include <QList>
#include <QRandomGenerator>
#include <QString>
#include <QStringList>
#define Q_TEST_PERFORMANCE 0
using namespace std;
class tst_QAlgorithms : public QObject
{
Q_OBJECT
private slots:
void swap();
void swap2();
void convenienceAPI();
void popCount08_data() { popCount_data_impl(sizeof(quint8 )); }
void popCount16_data() { popCount_data_impl(sizeof(quint16)); }
void popCount32_data() { popCount_data_impl(sizeof(quint32)); }
void popCount64_data() { popCount_data_impl(sizeof(quint64)); }
void popCount08() { popCount_impl<quint8 >(); }
void popCount16() { popCount_impl<quint16>(); }
void popCount32() { popCount_impl<quint32>(); }
void popCount64() { popCount_impl<quint64>(); }
void countTrailing08_data() { countTrailing_data_impl(sizeof(quint8 )); }
void countTrailing16_data() { countTrailing_data_impl(sizeof(quint16)); }
void countTrailing32_data() { countTrailing_data_impl(sizeof(quint32)); }
void countTrailing64_data() { countTrailing_data_impl(sizeof(quint64)); }
void countTrailing08() { countTrailing_impl<quint8 >(); }
void countTrailing16() { countTrailing_impl<quint16>(); }
void countTrailing32() { countTrailing_impl<quint32>(); }
void countTrailing64() { countTrailing_impl<quint64>(); }
void countLeading08_data() { countLeading_data_impl(sizeof(quint8 )); }
void countLeading16_data() { countLeading_data_impl(sizeof(quint16)); }
void countLeading32_data() { countLeading_data_impl(sizeof(quint32)); }
void countLeading64_data() { countLeading_data_impl(sizeof(quint64)); }
void countLeading08() { countLeading_impl<quint8 >(); }
void countLeading16() { countLeading_impl<quint16>(); }
void countLeading32() { countLeading_impl<quint32>(); }
void countLeading64() { countLeading_impl<quint64>(); }
private:
void popCount_data_impl(size_t sizeof_T_Int);
template <typename T_Int>
void popCount_impl();
void countTrailing_data_impl(size_t sizeof_T_Int);
template <typename T_Int>
void countTrailing_impl();
void countLeading_data_impl(size_t sizeof_T_Int);
template <typename T_Int>
void countLeading_impl();
};
template <typename T> struct PrintIfFailed
{
T value;
PrintIfFailed(T v) : value(v) {}
~PrintIfFailed()
{
if (!QTest::currentTestFailed())
return;
qWarning() << "Original value was" << Qt::hex << Qt::showbase << T(value);
}
};
void tst_QAlgorithms::swap()
{
{
int a = 1, b = 2;
qSwap(a, b);
QVERIFY(a == 2);
QVERIFY(b == 1);
qSwap(a, a);
QVERIFY(a == 2);
QVERIFY(b == 1);
qSwap(b, b);
QVERIFY(a == 2);
QVERIFY(b == 1);
qSwap(a, b);
QVERIFY(a == 1);
QVERIFY(b == 2);
qSwap(b, a);
QVERIFY(a == 2);
QVERIFY(b == 1);
}
{
double a = 1.0, b = 2.0;
qSwap(a, b);
QVERIFY(a == 2.0);
QVERIFY(b == 1.0);
qSwap(a, a);
QVERIFY(a == 2.0);
QVERIFY(b == 1.0);
qSwap(b, b);
QVERIFY(a == 2.0);
QVERIFY(b == 1.0);
qSwap(a, b);
QVERIFY(a == 1.0);
QVERIFY(b == 2.0);
qSwap(b, a);
QVERIFY(a == 2.0);
QVERIFY(b == 1.0);
}
{
QString a = "1", b = "2";
qSwap(a, b);
QCOMPARE(a, QLatin1String("2"));
QCOMPARE(b, QLatin1String("1"));
qSwap(a, a);
QCOMPARE(a, QLatin1String("2"));
QCOMPARE(b, QLatin1String("1"));
qSwap(b, b);
QCOMPARE(a, QLatin1String("2"));
QCOMPARE(b, QLatin1String("1"));
qSwap(a, b);
QCOMPARE(a, QLatin1String("1"));
QCOMPARE(b, QLatin1String("2"));
qSwap(b, a);
QCOMPARE(a, QLatin1String("2"));
QCOMPARE(b, QLatin1String("1"));
}
{
void *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
const void *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
QString *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
const QString *a = nullptr, *b = nullptr;
qSwap(a, b);
}
{
QString **a = nullptr, **b = nullptr;
qSwap(a, b);
}
{
const QString **a = nullptr, **b = nullptr;
qSwap(a, b);
}
{
QString * const *a = nullptr, * const *b = nullptr;
qSwap(a, b);
}
{
const QString * const *a = nullptr, * const *b = nullptr;
qSwap(a, b);
}
}
namespace SwapTest {
struct ST { int i; int j; };
void swap(ST &a, ST &b) {
a.i = b.j;
b.i = a.j;
}
}
void tst_QAlgorithms::swap2()
{
{
#ifndef QT_NO_SQL
//check the namespace lookup works correctly
SwapTest::ST a = { 45, 65 };
SwapTest::ST b = { 48, 68 };
qSwap(a, b);
QCOMPARE(a.i, 68);
QCOMPARE(b.i, 65);
#endif
}
}
void tst_QAlgorithms::convenienceAPI()
{
// Compile-test for QAlgorithm convenience functions.
QList<int *> pointerList;
qDeleteAll(pointerList);
qDeleteAll(pointerList.begin(), pointerList.end());
}
// alternative implementation of qPopulationCount for comparison:
static constexpr const uint bitsSetInNibble[] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4,
};
static_assert(sizeof bitsSetInNibble / sizeof *bitsSetInNibble == 16);
static constexpr uint bitsSetInByte(quint8 byte)
{
return bitsSetInNibble[byte & 0xF] + bitsSetInNibble[byte >> 4];
}
static constexpr uint bitsSetInShort(quint16 word)
{
return bitsSetInByte(word & 0xFF) + bitsSetInByte(word >> 8);
}
static constexpr uint bitsSetInInt(quint32 word)
{
return bitsSetInShort(word & 0xFFFF) + bitsSetInShort(word >> 16);
}
static constexpr uint bitsSetInInt64(quint64 word)
{
return bitsSetInInt(word & 0xFFFFFFFF) + bitsSetInInt(word >> 32);
}
void tst_QAlgorithms::popCount_data_impl(size_t sizeof_T_Int)
{
using namespace QTest;
addColumn<quint64>("input");
addColumn<uint>("expected");
for (uint i = 0; i < UCHAR_MAX; ++i) {
const uchar byte = static_cast<uchar>(i);
const uint bits = bitsSetInByte(byte);
const quint64 value = static_cast<quint64>(byte);
const quint64 input = value << ((i % sizeof_T_Int) * 8U);
QTest::addRow("%u-bits", i) << input << bits;
}
// and some random ones:
if (sizeof_T_Int >= 8) {
for (size_t i = 0; i < 1000; ++i) {
const quint64 input = QRandomGenerator::global()->generate64();
QTest::addRow("random-%zu", i) << input << bitsSetInInt64(input);
}
} else if (sizeof_T_Int >= 2) {
for (size_t i = 0; i < 1000 ; ++i) {
const quint32 input = QRandomGenerator::global()->generate();
if (sizeof_T_Int >= 4) {
QTest::addRow("random-%zu", i) << quint64(input) << bitsSetInInt(input);
} else {
QTest::addRow("random-%zu", i)
<< quint64(input & 0xFFFF) << bitsSetInShort(input & 0xFFFF);
}
}
}
}
template <typename T_Int>
void tst_QAlgorithms::popCount_impl()
{
QFETCH(quint64, input);
QFETCH(uint, expected);
const T_Int value = static_cast<T_Int>(input);
PrintIfFailed pf(value);
QCOMPARE(qPopulationCount(value), expected);
}
// Number of test-cases per offset into each size (arbitrary):
static constexpr int casesPerOffset = 3;
void tst_QAlgorithms::countTrailing_data_impl(size_t sizeof_T_Int)
{
using namespace QTest;
addColumn<quint64>("input");
addColumn<uint>("expected");
addRow("0") << Q_UINT64_C(0) << uint(sizeof_T_Int*8);
for (uint i = 0; i < sizeof_T_Int*8; ++i) {
const quint64 input = Q_UINT64_C(1) << i;
addRow("bit-%u", i) << input << i;
}
quint64 type_mask;
if (sizeof_T_Int>=8)
type_mask = ~Q_UINT64_C(0);
else
type_mask = (Q_UINT64_C(1) << (sizeof_T_Int*8))-1;
// and some random ones:
for (uint i = 0; i < sizeof_T_Int*8; ++i) {
const quint64 b = Q_UINT64_C(1) << i;
const quint64 mask = ((~(b - 1)) ^ b) & type_mask;
for (uint j = 0; j < sizeof_T_Int * casesPerOffset; ++j) {
const quint64 r = QRandomGenerator::global()->generate64();
const quint64 input = (r&mask) | b;
addRow("%u-bits-random-%u", i, j) << input << i;
}
}
}
template <typename T_Int>
void tst_QAlgorithms::countTrailing_impl()
{
QFETCH(quint64, input);
QFETCH(uint, expected);
const T_Int value = static_cast<T_Int>(input);
PrintIfFailed pf(value);
QCOMPARE(qCountTrailingZeroBits(value), expected);
}
void tst_QAlgorithms::countLeading_data_impl(size_t sizeof_T_Int)
{
using namespace QTest;
addColumn<quint64>("input");
addColumn<uint>("expected");
addRow("0") << Q_UINT64_C(0) << uint(sizeof_T_Int*8);
for (uint i = 0; i < sizeof_T_Int*8; ++i) {
const quint64 input = Q_UINT64_C(1) << i;
addRow("bit-%u", i) << input << uint(sizeof_T_Int*8-i-1);
}
// and some random ones:
for (uint i = 0; i < sizeof_T_Int*8; ++i) {
const quint64 b = Q_UINT64_C(1) << i;
const quint64 mask = b - 1;
for (uint j = 0; j < sizeof_T_Int * casesPerOffset; ++j) {
const quint64 r = QRandomGenerator::global()->generate64();
const quint64 input = (r&mask) | b;
addRow("%u-bits-random-%u", i, j) << input << uint(sizeof_T_Int*8-i-1);
}
}
}
template <typename T_Int>
void tst_QAlgorithms::countLeading_impl()
{
QFETCH(quint64, input);
QFETCH(uint, expected);
const T_Int value = static_cast<T_Int>(input);
PrintIfFailed pf(value);
QCOMPARE(qCountLeadingZeroBits(value), expected);
}
QTEST_APPLESS_MAIN(tst_QAlgorithms)
#include "tst_qalgorithms.moc"

View File

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

View File

@ -0,0 +1,313 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QARRAY_TEST_SIMPLE_VECTOR_H
#define QARRAY_TEST_SIMPLE_VECTOR_H
#include <QtCore/qarraydata.h>
#include <QtCore/qarraydatapointer.h>
#include <QtCore/qvarlengtharray.h>
#include <algorithm>
template <class T>
struct SimpleVector
{
private:
typedef QTypedArrayData<T> Data;
typedef QArrayDataPointer<T> DataPointer;
public:
typedef T value_type;
typedef T *iterator;
typedef const T *const_iterator;
SimpleVector()
{
}
explicit SimpleVector(size_t n, bool capacityReserved = false)
: d(Data::allocate(n))
{
if (n)
d->appendInitialize(n);
if (capacityReserved)
d.setFlag(QArrayData::CapacityReserved);
}
SimpleVector(size_t n, const T &t, bool capacityReserved = false)
: d(Data::allocate(n))
{
if (n)
d->copyAppend(n, t);
if (capacityReserved)
d.setFlag(QArrayData::CapacityReserved);
}
SimpleVector(const T *begin, const T *end, bool capacityReserved = false)
: d(Data::allocate(end - begin))
{
if (end - begin)
d->copyAppend(begin, end);
if (capacityReserved)
d.setFlag(QArrayData::CapacityReserved);
}
SimpleVector(Data *header, T *data, size_t len = 0)
: d(header, data, len)
{
}
explicit SimpleVector(QPair<Data*, T*> ptr, size_t len = 0)
: d(ptr, len)
{
}
SimpleVector(const QArrayDataPointer<T> &other)
: d(other)
{
}
bool empty() const { return d.size == 0; }
bool isNull() const { return d.isNull(); }
bool isEmpty() const { return this->empty(); }
bool isStatic() const { return !d.isMutable(); }
bool isShared() const { return d->isShared(); }
bool isSharedWith(const SimpleVector &other) const { return d == other.d; }
size_t size() const { return d.size; }
size_t capacity() const { return d->constAllocatedCapacity(); }
iterator begin() { detach(); return d->begin(); }
iterator end() { detach(); return d->end(); }
const_iterator begin() const { return d->constBegin(); }
const_iterator end() const { return d->constEnd(); }
const_iterator constBegin() const { return begin(); }
const_iterator constEnd() const { return end(); }
T &operator[](size_t i) { Q_ASSERT(i < size_t(d->size)); detach(); return begin()[i]; }
T &at(size_t i) { Q_ASSERT(i < size_t(d->size)); detach(); return begin()[i]; }
const T &operator[](size_t i) const { Q_ASSERT(i < size_t(d->size)); return begin()[i]; }
const T &at(size_t i) const { Q_ASSERT(i < size_t(d->size)); return begin()[i]; }
T &front()
{
Q_ASSERT(!isEmpty());
detach();
return *begin();
}
T &back()
{
Q_ASSERT(!isEmpty());
detach();
return *(end() - 1);
}
const T &front() const
{
Q_ASSERT(!isEmpty());
return *begin();
}
const T &back() const
{
Q_ASSERT(!isEmpty());
return *(end() - 1);
}
void reserve(size_t n)
{
if (n == 0)
return;
if (n <= capacity()) {
if (d->flags() & Data::CapacityReserved)
return;
if (!d->isShared()) {
d.setFlag(Data::CapacityReserved);
return;
}
}
SimpleVector detached(Data::allocate(qMax(n, size())));
if (size()) {
detached.d->copyAppend(constBegin(), constEnd());
detached.d->setFlag(QArrayData::CapacityReserved);
}
detached.swap(*this);
}
void resize(size_t newSize)
{
if (size() == newSize)
return;
if (d->needsDetach() || newSize > capacity()) {
SimpleVector detached(Data::allocate(d->detachCapacity(newSize)));
if (newSize) {
if (newSize < size()) {
const T *const begin = constBegin();
detached.d->copyAppend(begin, begin + newSize);
} else {
if (size()) {
const T *const begin = constBegin();
detached.d->copyAppend(begin, begin + size());
}
detached.d->appendInitialize(newSize);
}
}
detached.swap(*this);
return;
}
if (newSize > size())
d->appendInitialize(newSize);
else
d->truncate(newSize);
}
void prepend(const_iterator first, const_iterator last)
{
if (!d->size) {
append(first, last);
return;
}
if (first == last)
return;
d->insert(0, first, last - first);
}
void append(const_iterator first, const_iterator last) { d->growAppend(first, last); }
void insert(int position, const_iterator first, const_iterator last)
{
if (position < 0)
position += d->size + 1;
if (position <= 0) {
prepend(first, last);
return;
}
if (size_t(position) >= size()) {
append(first, last);
return;
}
if (first == last)
return;
if (first >= d.begin() && first <= d.end()) {
QVarLengthArray<T> copy(first, last);
insert(position, copy.begin(), copy.end());
return;
}
d->insert(position, first, last - first);
}
void erase(iterator first, iterator last)
{
if (first == last)
return;
const T *const begin = d->begin();
const T *const end = begin + d->size;
if (d->needsDetach()) {
SimpleVector detached(Data::allocate(d->detachCapacity(size() - (last - first))));
if (first != begin)
detached.d->copyAppend(begin, first);
detached.d->copyAppend(last, end);
detached.swap(*this);
return;
}
if (last == end)
d->truncate(end - first);
else
d->erase(first, last - first);
}
void swap(SimpleVector &other)
{
qSwap(d, other.d);
}
void clear()
{
d.clear();
}
void detach()
{
d.detach();
}
static SimpleVector fromRawData(const T *data, size_t size)
{
return SimpleVector(QArrayDataPointer<T>::fromRawData(data, size));
}
private:
QArrayDataPointer<T> d;
};
template <class T>
bool operator==(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
if (lhs.isSharedWith(rhs))
return true;
if (lhs.size() != rhs.size())
return false;
return std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template <class T>
bool operator!=(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return !(lhs == rhs);
}
template <class T>
bool operator<(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <class T>
bool operator>(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return rhs < lhs;
}
template <class T>
bool operator<=(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return !(rhs < lhs);
}
template <class T>
bool operator>=(const SimpleVector<T> &lhs, const SimpleVector<T> &rhs)
{
return !(lhs < rhs);
}
namespace std {
template <class T>
void swap(SimpleVector<T> &v1, SimpleVector<T> &v2)
{
v1.swap(v2);
}
}
#endif // include guard

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,157 @@
// 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/private/qatomicscopedvaluerollback_p.h>
#include <QTest>
class tst_QAtomicScopedValueRollback : public QObject
{
Q_OBJECT
private Q_SLOTS:
void leavingScope();
void leavingScopeAfterCommit();
void rollbackToPreviousCommit();
void exceptions();
void earlyExitScope();
private:
void earlyExitScope_helper(int exitpoint, std::atomic<int> &member);
};
void tst_QAtomicScopedValueRollback::leavingScope()
{
QAtomicInt i = 0;
QBasicAtomicInteger<bool> b = false;
std::atomic<bool> b2 = false;
//test rollback on going out of scope
{
QAtomicScopedValueRollback ri(i);
QAtomicScopedValueRollback rb(b);
QAtomicScopedValueRollback rb2(b2, true);
QCOMPARE(b.loadRelaxed(), false);
QCOMPARE(b2, true);
QCOMPARE(i.loadRelaxed(), 0);
b.storeRelaxed(true);
i.storeRelaxed(1);
QCOMPARE(b.loadRelaxed(), true);
QCOMPARE(i.loadRelaxed(), 1);
}
QCOMPARE(b.loadRelaxed(), false);
QCOMPARE(b2, false);
QCOMPARE(i.loadRelaxed(), 0);
}
void tst_QAtomicScopedValueRollback::leavingScopeAfterCommit()
{
std::atomic<int> i = 0;
QAtomicInteger<bool> b = false;
//test rollback on going out of scope
{
QAtomicScopedValueRollback ri(i);
QAtomicScopedValueRollback rb(b);
QCOMPARE(b.loadRelaxed(), false);
QCOMPARE(i, 0);
b.storeRelaxed(true);
i = 1;
QCOMPARE(b.loadRelaxed(), true);
QCOMPARE(i, 1);
ri.commit();
rb.commit();
}
QCOMPARE(b.loadRelaxed(), true);
QCOMPARE(i, 1);
}
void tst_QAtomicScopedValueRollback::rollbackToPreviousCommit()
{
QBasicAtomicInt i = 0;
{
QAtomicScopedValueRollback ri(i);
i++;
ri.commit();
i++;
}
QCOMPARE(i.loadRelaxed(), 1);
{
QAtomicScopedValueRollback ri1(i);
i++;
ri1.commit();
i++;
ri1.commit();
i++;
}
QCOMPARE(i.loadRelaxed(), 3);
}
void tst_QAtomicScopedValueRollback::exceptions()
{
std::atomic<bool> b = false;
bool caught = false;
QT_TRY
{
QAtomicScopedValueRollback rb(b);
b = true;
QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop
rb.commit(); //if Qt compiled without exceptions, true is committed
}
QT_CATCH(...)
{
caught = true;
}
QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise
}
void tst_QAtomicScopedValueRollback::earlyExitScope()
{
QAtomicInt ai = 0;
std::atomic<int> aj = 0;
while (true) {
QAtomicScopedValueRollback ri(ai);
++ai;
aj = ai.loadRelaxed();
if (ai.loadRelaxed() > 8) break;
ri.commit();
}
QCOMPARE(ai.loadRelaxed(), 8);
QCOMPARE(aj.load(), 9);
for (int i = 0; i < 5; ++i) {
aj = 1;
earlyExitScope_helper(i, aj);
QCOMPARE(aj.load(), 1 << i);
}
}
static void operator*=(std::atomic<int> &lhs, int rhs)
{
int expected = lhs.load();
while (!lhs.compare_exchange_weak(expected, expected * rhs))
;
}
void tst_QAtomicScopedValueRollback::earlyExitScope_helper(int exitpoint, std::atomic<int>& member)
{
QAtomicScopedValueRollback r(member);
member *= 2;
if (exitpoint == 0)
return;
r.commit();
member *= 2;
if (exitpoint == 1)
return;
r.commit();
member *= 2;
if (exitpoint == 2)
return;
r.commit();
member *= 2;
if (exitpoint == 3)
return;
r.commit();
}
QTEST_MAIN(tst_QAtomicScopedValueRollback)
#include "tst_qatomicscopedvaluerollback.moc"

View File

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

View File

@ -0,0 +1,739 @@
// 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 <QtCore/QBuffer>
#include <QtCore/QDataStream>
#include "qbitarray.h"
/**
* Helper function to initialize a bitarray from a string
*/
static QBitArray QStringToQBitArray(const QString &str)
{
QBitArray ba;
ba.resize(str.size());
int i;
QChar tru('1');
for (i = 0; i < str.size(); i++)
{
if (str.at(i) == tru)
{
ba.setBit(i, true);
}
}
return ba;
}
class tst_QBitArray : public QObject
{
Q_OBJECT
private slots:
void size_data();
void size();
void countBits_data();
void countBits();
void countBits2();
void isEmpty();
void swap();
void fill();
void toggleBit_data();
void toggleBit();
// operator &=
void operator_andeq_data();
void operator_andeq();
// operator |=
void operator_oreq_data();
void operator_oreq();
// operator ^=
void operator_xoreq_data();
void operator_xoreq();
// operator ~
void operator_neg_data();
void operator_neg();
void datastream_data();
void datastream();
void invertOnNull() const;
void operator_noteq_data();
void operator_noteq();
void resize();
void fromBits_data();
void fromBits();
void toUInt32_data();
void toUInt32();
};
void tst_QBitArray::size_data()
{
//create the testtable instance and define the elements
QTest::addColumn<int>("count");
QTest::addColumn<QString>("res");
//next we fill it with data
QTest::newRow( "data0" ) << 1 << QString("1");
QTest::newRow( "data1" ) << 2 << QString("11");
QTest::newRow( "data2" ) << 3 << QString("111");
QTest::newRow( "data3" ) << 9 << QString("111111111");
QTest::newRow( "data4" ) << 10 << QString("1111111111");
QTest::newRow( "data5" ) << 17 << QString("11111111111111111");
QTest::newRow( "data6" ) << 18 << QString("111111111111111111");
QTest::newRow( "data7" ) << 19 << QString("1111111111111111111");
QTest::newRow( "data8" ) << 20 << QString("11111111111111111111");
QTest::newRow( "data9" ) << 21 << QString("111111111111111111111");
QTest::newRow( "data10" ) << 22 << QString("1111111111111111111111");
QTest::newRow( "data11" ) << 23 << QString("11111111111111111111111");
QTest::newRow( "data12" ) << 24 << QString("111111111111111111111111");
QTest::newRow( "data13" ) << 25 << QString("1111111111111111111111111");
QTest::newRow( "data14" ) << 32 << QString("11111111111111111111111111111111");
}
void tst_QBitArray::size()
{
QFETCH(int,count);
QString S;
QBitArray a(count);
a.fill(1);
int len = a.size();
for (int j=0; j<len; j++) {
bool b = a[j];
if (b)
S+= QLatin1Char('1');
else
S+= QLatin1Char('0');
}
QTEST(S,"res");
}
void tst_QBitArray::countBits_data()
{
QTest::addColumn<QString>("bitField");
QTest::addColumn<int>("numBits");
QTest::addColumn<int>("onBits");
QTest::newRow("empty") << QString() << 0 << 0;
QTest::newRow("1") << QString("1") << 1 << 1;
QTest::newRow("101") << QString("101") << 3 << 2;
QTest::newRow("101100001") << QString("101100001") << 9 << 4;
QTest::newRow("101100001101100001") << QString("101100001101100001") << 18 << 8;
QTest::newRow("101100001101100001101100001101100001") << QString("101100001101100001101100001101100001") << 36 << 16;
QTest::newRow("00000000000000000000000000000000000") << QString("00000000000000000000000000000000000") << 35 << 0;
QTest::newRow("11111111111111111111111111111111111") << QString("11111111111111111111111111111111111") << 35 << 35;
QTest::newRow("11111111111111111111111111111111") << QString("11111111111111111111111111111111") << 32 << 32;
QTest::newRow("11111111111111111111111111111111111111111111111111111111")
<< QString("11111111111111111111111111111111111111111111111111111111") << 56 << 56;
QTest::newRow("00000000000000000000000000000000") << QString("00000000000000000000000000000000") << 32 << 0;
QTest::newRow("00000000000000000000000000000000000000000000000000000000")
<< QString("00000000000000000000000000000000000000000000000000000000") << 56 << 0;
}
void tst_QBitArray::countBits()
{
QFETCH(QString, bitField);
QFETCH(int, numBits);
QFETCH(int, onBits);
QBitArray bits(bitField.size());
for (int i = 0; i < bitField.size(); ++i) {
if (bitField.at(i) == QLatin1Char('1'))
bits.setBit(i);
}
QCOMPARE(bits.size(), numBits);
// NOLINTNEXTLINE(qt-port-to-std-compatible-api): We want to test count() and size()
QCOMPARE(bits.count(), numBits);
QCOMPARE(bits.count(true), onBits);
QCOMPARE(bits.count(false), numBits - onBits);
}
void tst_QBitArray::countBits2()
{
QBitArray bitArray;
for (int i = 0; i < 4017; ++i) {
bitArray.resize(i);
bitArray.fill(true);
QCOMPARE(bitArray.count(true), i);
QCOMPARE(bitArray.count(false), 0);
bitArray.fill(false);
QCOMPARE(bitArray.count(true), 0);
QCOMPARE(bitArray.count(false), i);
}
}
void tst_QBitArray::isEmpty()
{
QBitArray a1;
QVERIFY(a1.isEmpty());
QVERIFY(a1.isNull());
QVERIFY(a1.size() == 0);
QBitArray a2(0, true);
QVERIFY(a2.isEmpty());
QVERIFY(!a2.isNull());
QVERIFY(a2.size() == 0);
QBitArray a3(1, true);
QVERIFY(!a3.isEmpty());
QVERIFY(!a3.isNull());
QVERIFY(a3.size() == 1);
a1.resize(0);
QVERIFY(a1.isEmpty());
QVERIFY(!a1.isNull());
QVERIFY(a1.size() == 0);
a2.resize(0);
QVERIFY(a2.isEmpty());
QVERIFY(!a2.isNull());
QVERIFY(a2.size() == 0);
a1.resize(1);
QVERIFY(!a1.isEmpty());
QVERIFY(!a1.isNull());
QVERIFY(a1.size() == 1);
a1.resize(2);
QVERIFY(!a1.isEmpty());
QVERIFY(!a1.isNull());
QVERIFY(a1.size() == 2);
}
void tst_QBitArray::swap()
{
QBitArray b1 = QStringToQBitArray("1"), b2 = QStringToQBitArray("10");
b1.swap(b2);
QCOMPARE(b1,QStringToQBitArray("10"));
QCOMPARE(b2,QStringToQBitArray("1"));
}
void tst_QBitArray::fill()
{
int N = 64;
int M = 17;
QBitArray a(N, false);
int i, j;
for (i = 0; i < N-M; ++i) {
a.fill(true, i, i + M);
for (j = 0; j < N; ++j) {
if (j >= i && j < i + M) {
QVERIFY(a.at(j));
} else {
QVERIFY(!a.at(j));
}
}
a.fill(false, i, i + M);
}
for (i = 0; i < N; ++i)
a.fill(i % 2 == 0, i, i + 1);
for (i = 0; i < N; ++i) {
QVERIFY(a.at(i) == (i % 2 == 0));
}
}
void tst_QBitArray::toggleBit_data()
{
QTest::addColumn<int>("index");
QTest::addColumn<QBitArray>("input");
QTest::addColumn<QBitArray>("res");
// 8 bits, toggle first bit
QTest::newRow( "data0" ) << 0 << QStringToQBitArray(QString("11111111")) << QStringToQBitArray(QString("01111111"));
// 8 bits
QTest::newRow( "data1" ) << 1 << QStringToQBitArray(QString("11111111")) << QStringToQBitArray(QString("10111111"));
// 11 bits, toggle last bit
QTest::newRow( "data2" ) << 10 << QStringToQBitArray(QString("11111111111")) << QStringToQBitArray(QString("11111111110"));
}
void tst_QBitArray::toggleBit()
{
QFETCH(int,index);
QFETCH(QBitArray, input);
QFETCH(QBitArray, res);
input.toggleBit(index);
QCOMPARE(input, res);
}
void tst_QBitArray::operator_andeq_data()
{
QTest::addColumn<QBitArray>("input1");
QTest::addColumn<QBitArray>("input2");
QTest::addColumn<QBitArray>("res");
QTest::newRow( "data0" ) << QStringToQBitArray(QString("11111111"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("00101100"));
QTest::newRow( "data1" ) << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("00001000"));
QTest::newRow( "data2" ) << QStringToQBitArray(QString("11011011111"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("00001000000"));
QTest::newRow( "data3" ) << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString("00001000000"));
QTest::newRow( "data4" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString("00000000000"));
QTest::newRow( "data5" ) << QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00000000000"));
QTest::newRow( "data6" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString())
<< QStringToQBitArray(QString());
}
void tst_QBitArray::operator_andeq()
{
QFETCH(QBitArray, input1);
QFETCH(QBitArray, input2);
QFETCH(QBitArray, res);
input1&=input2;
QCOMPARE(input1, res);
}
void tst_QBitArray::operator_oreq_data()
{
QTest::addColumn<QBitArray>("input1");
QTest::addColumn<QBitArray>("input2");
QTest::addColumn<QBitArray>("res");
QTest::newRow( "data0" ) << QStringToQBitArray(QString("11111111"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("11111111"));
QTest::newRow( "data1" ) << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("11111111"));
QTest::newRow( "data2" ) << QStringToQBitArray(QString("01000010"))
<< QStringToQBitArray(QString("10100001"))
<< QStringToQBitArray(QString("11100011"));
QTest::newRow( "data3" ) << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("00101100000"))
<< QStringToQBitArray(QString("11111111000"));
QTest::newRow( "data4" ) << QStringToQBitArray(QString("11011011111"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("11111111111"));
QTest::newRow( "data5" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString("00101100111"));
QTest::newRow( "data6" ) << QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00101100111"));
QTest::newRow( "data7" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString())
<< QStringToQBitArray(QString());
}
void tst_QBitArray::operator_oreq()
{
QFETCH(QBitArray, input1);
QFETCH(QBitArray, input2);
QFETCH(QBitArray, res);
input1|=input2;
QCOMPARE(input1, res);
}
void tst_QBitArray::operator_xoreq_data()
{
QTest::addColumn<QBitArray>("input1");
QTest::addColumn<QBitArray>("input2");
QTest::addColumn<QBitArray>("res");
QTest::newRow( "data0" ) << QStringToQBitArray(QString("11111111"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("11010011"));
QTest::newRow( "data1" ) << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("11110111"));
QTest::newRow( "data2" ) << QStringToQBitArray(QString("01000010"))
<< QStringToQBitArray(QString("10100001"))
<< QStringToQBitArray(QString("11100011"));
QTest::newRow( "data3" ) << QStringToQBitArray(QString("01000010"))
<< QStringToQBitArray(QString("10100001101"))
<< QStringToQBitArray(QString("11100011101"));
QTest::newRow( "data4" ) << QStringToQBitArray(QString("01000010111"))
<< QStringToQBitArray(QString("101000011"))
<< QStringToQBitArray(QString("11100011011"));
QTest::newRow( "data5" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString("00101100111"));
QTest::newRow( "data6" ) << QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00101100111"));
QTest::newRow( "data7" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString())
<< QStringToQBitArray(QString());
}
void tst_QBitArray::operator_xoreq()
{
QFETCH(QBitArray, input1);
QFETCH(QBitArray, input2);
QFETCH(QBitArray, res);
input1^=input2;
QCOMPARE(input1, res);
}
void tst_QBitArray::operator_neg_data()
{
QTest::addColumn<QBitArray>("input");
QTest::addColumn<QBitArray>("res");
QTest::newRow( "data0" ) << QStringToQBitArray(QString("11111111"))
<< QStringToQBitArray(QString("00000000"));
QTest::newRow( "data1" ) << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("00100100"));
QTest::newRow( "data2" ) << QStringToQBitArray(QString("00000000"))
<< QStringToQBitArray(QString("11111111"));
QTest::newRow( "data3" ) << QStringToQBitArray(QString())
<< QStringToQBitArray(QString());
QTest::newRow( "data4" ) << QStringToQBitArray("1")
<< QStringToQBitArray("0");
QTest::newRow( "data5" ) << QStringToQBitArray("0")
<< QStringToQBitArray("1");
QTest::newRow( "data6" ) << QStringToQBitArray("01")
<< QStringToQBitArray("10");
QTest::newRow( "data7" ) << QStringToQBitArray("1110101")
<< QStringToQBitArray("0001010");
QTest::newRow( "data8" ) << QStringToQBitArray("01110101")
<< QStringToQBitArray("10001010");
QTest::newRow( "data9" ) << QStringToQBitArray("011101010")
<< QStringToQBitArray("100010101");
QTest::newRow( "data10" ) << QStringToQBitArray("0111010101111010")
<< QStringToQBitArray("1000101010000101");
}
void tst_QBitArray::operator_neg()
{
QFETCH(QBitArray, input);
QFETCH(QBitArray, res);
input = ~input;
QCOMPARE(input, res);
}
void tst_QBitArray::datastream_data()
{
QTest::addColumn<QString>("bitField");
QTest::addColumn<int>("numBits");
QTest::addColumn<int>("onBits");
QTest::newRow("empty") << QString() << 0 << 0;
QTest::newRow("1") << QString("1") << 1 << 1;
QTest::newRow("101") << QString("101") << 3 << 2;
QTest::newRow("101100001") << QString("101100001") << 9 << 4;
QTest::newRow("101100001101100001") << QString("101100001101100001") << 18 << 8;
QTest::newRow("101100001101100001101100001101100001") << QString("101100001101100001101100001101100001") << 36 << 16;
QTest::newRow("00000000000000000000000000000000000") << QString("00000000000000000000000000000000000") << 35 << 0;
QTest::newRow("11111111111111111111111111111111111") << QString("11111111111111111111111111111111111") << 35 << 35;
QTest::newRow("11111111111111111111111111111111") << QString("11111111111111111111111111111111") << 32 << 32;
QTest::newRow("11111111111111111111111111111111111111111111111111111111")
<< QString("11111111111111111111111111111111111111111111111111111111") << 56 << 56;
QTest::newRow("00000000000000000000000000000000") << QString("00000000000000000000000000000000") << 32 << 0;
QTest::newRow("00000000000000000000000000000000000000000000000000000000")
<< QString("00000000000000000000000000000000000000000000000000000000") << 56 << 0;
}
void tst_QBitArray::datastream()
{
QFETCH(QString, bitField);
QFETCH(int, numBits);
QFETCH(int, onBits);
QBuffer buffer;
QVERIFY(buffer.open(QBuffer::ReadWrite));
QDataStream stream(&buffer);
QBitArray bits(bitField.size());
for (int i = 0; i < bitField.size(); ++i) {
if (bitField.at(i) == QLatin1Char('1'))
bits.setBit(i);
}
QCOMPARE(bits.size(), numBits);
QCOMPARE(bits.count(true), onBits);
QCOMPARE(bits.count(false), numBits - onBits);
stream << bits << bits << bits;
buffer.close();
QCOMPARE(stream.status(), QDataStream::Ok);
QVERIFY(buffer.open(QBuffer::ReadWrite));
QDataStream stream2(&buffer);
QBitArray array1, array2, array3;
stream2 >> array1 >> array2 >> array3;
QCOMPARE(array1.size(), numBits);
QCOMPARE(array1.count(true), onBits);
QCOMPARE(array1.count(false), numBits - onBits);
QCOMPARE(array1, bits);
QCOMPARE(array2, bits);
QCOMPARE(array3, bits);
}
void tst_QBitArray::invertOnNull() const
{
QBitArray a;
QCOMPARE(a = ~a, QBitArray());
}
void tst_QBitArray::operator_noteq_data()
{
QTest::addColumn<QBitArray>("input1");
QTest::addColumn<QBitArray>("input2");
QTest::addColumn<bool>("res");
QTest::newRow("data0") << QStringToQBitArray(QString("11111111"))
<< QStringToQBitArray(QString("00101100"))
<< true;
QTest::newRow("data1") << QStringToQBitArray(QString("11011011"))
<< QStringToQBitArray(QString("11011011"))
<< false;
QTest::newRow("data2") << QStringToQBitArray(QString())
<< QStringToQBitArray(QString("00101100111"))
<< true;
QTest::newRow("data3") << QStringToQBitArray(QString())
<< QStringToQBitArray(QString())
<< false;
QTest::newRow("data4") << QStringToQBitArray(QString("00101100"))
<< QStringToQBitArray(QString("11111111"))
<< true;
QTest::newRow("data5") << QStringToQBitArray(QString("00101100111"))
<< QStringToQBitArray(QString())
<< true;
}
void tst_QBitArray::operator_noteq()
{
QFETCH(QBitArray, input1);
QFETCH(QBitArray, input2);
QFETCH(bool, res);
bool b = input1 != input2;
QCOMPARE(b, res);
}
void tst_QBitArray::resize()
{
// -- check that a resize handles the bits correctly
QBitArray a = QStringToQBitArray(QString("11"));
a.resize(10);
QVERIFY(a.size() == 10);
QCOMPARE( a, QStringToQBitArray(QString("1100000000")) );
a.setBit(9);
a.resize(9);
// now the bit in a should have been gone:
QCOMPARE( a, QStringToQBitArray(QString("110000000")) );
// grow the array back and check the new bit
a.resize(10);
QCOMPARE( a, QStringToQBitArray(QString("1100000000")) );
// other test with and
a.resize(9);
QBitArray b = QStringToQBitArray(QString("1111111111"));
b &= a;
QCOMPARE( b, QStringToQBitArray(QString("1100000000")) );
}
void tst_QBitArray::fromBits_data()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<int>("size");
QTest::addColumn<QBitArray>("expected");
QTest::newRow("empty") << QByteArray() << 0 << QBitArray();
auto add = [](const QByteArray &tag, const char *data) {
QTest::newRow(tag) << QByteArray(data, (tag.size() + 7) / 8) << tag.size()
<< QStringToQBitArray(tag);
};
// "0" to "0000000000000000"
for (int i = 1; i < 16; ++i) {
char zero[2] = { 0, 0 };
QByteArray pattern(i, '0');
add(pattern, zero);
}
// "1" to "1111111111111111"
for (int i = 1; i < 16; ++i) {
char one[2] = { '\xff', '\xff' };
QByteArray pattern(i, '1');
add(pattern, one);
}
// trailing 0 and 1
char zero = 1;
char one = 0;
QByteArray pzero = "1";
QByteArray pone = "0";
for (int i = 2; i < 8; ++i) {
zero <<= 1;
pzero.prepend('0');
add(pzero, &zero);
one = (one << 1) | 1;
pone.prepend('1');
add(pone, &one);
}
}
void tst_QBitArray::fromBits()
{
QFETCH(QByteArray, data);
QFETCH(int, size);
QFETCH(QBitArray, expected);
QBitArray fromBits = QBitArray::fromBits(data, size);
QCOMPARE(fromBits, expected);
QCOMPARE(QBitArray::fromBits(fromBits.bits(), fromBits.size()), expected);
}
void tst_QBitArray::toUInt32_data()
{
QTest::addColumn<QBitArray>("data");
QTest::addColumn<int>("endianness");
QTest::addColumn<bool>("check");
QTest::addColumn<quint32>("result");
QTest::newRow("ctor") << QBitArray()
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(0);
QTest::newRow("empty") << QBitArray(0)
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(0);
QTest::newRow("LittleEndian4") << QStringToQBitArray(QString("0111"))
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(14);
QTest::newRow("BigEndian4") << QStringToQBitArray(QString("0111"))
<< static_cast<int>(QSysInfo::Endian::BigEndian)
<< true
<< quint32(7);
QTest::newRow("LittleEndian8") << QStringToQBitArray(QString("01111111"))
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(254);
QTest::newRow("BigEndian8") << QStringToQBitArray(QString("01111111"))
<< static_cast<int>(QSysInfo::Endian::BigEndian)
<< true
<< quint32(127);
QTest::newRow("LittleEndian16") << QStringToQBitArray(QString("0111111111111111"))
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(65534);
QTest::newRow("BigEndian16") << QStringToQBitArray(QString("0111111111111111"))
<< static_cast<int>(QSysInfo::Endian::BigEndian)
<< true
<< quint32(32767);
QTest::newRow("LittleEndian31") << QBitArray(31, true)
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(2147483647);
QTest::newRow("BigEndian31") << QBitArray(31, true)
<< static_cast<int>(QSysInfo::Endian::BigEndian)
<< true
<< quint32(2147483647);
QTest::newRow("LittleEndian32") << QBitArray(32, true)
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< true
<< quint32(4294967295);
QTest::newRow("BigEndian32") << QBitArray(32, true)
<< static_cast<int>(QSysInfo::Endian::BigEndian)
<< true
<< quint32(4294967295);
QTest::newRow("LittleEndian33") << QBitArray(33, true)
<< static_cast<int>(QSysInfo::Endian::LittleEndian)
<< false
<< quint32(0);
QTest::newRow("BigEndian33") << QBitArray(33, true)
<< static_cast<int>(QSysInfo::Endian::BigEndian)
<< false
<< quint32(0);
}
void tst_QBitArray::toUInt32()
{
QFETCH(QBitArray, data);
QFETCH(int, endianness);
QFETCH(bool, check);
QFETCH(quint32, result);
bool ok = false;
QCOMPARE(data.toUInt32(static_cast<QSysInfo::Endian>(endianness), &ok), result);
QCOMPARE(ok, check);
}
QTEST_APPLESS_MAIN(tst_QBitArray)
#include "tst_qbitarray.moc"

View File

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

View File

@ -0,0 +1,508 @@
// 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 <qcache.h>
class tst_QCache : public QObject
{
Q_OBJECT
public slots:
void initTestCase();
void cleanupTestCase();
private slots:
void empty();
void maxCost();
void setMaxCost();
void totalCost();
void clear();
void insert();
void contains();
void operator_bracket_bracket();
void remove();
void take();
void axioms_on_key_type();
void largeCache();
void internalChainOrderAfterEntryUpdate();
void emplaceLowerCost();
void trimWithMovingAcrossSpans();
};
struct Foo {
static int count;
Foo():c(count) { ++count; }
Foo(const Foo& o):c(o.c) { ++count; }
~Foo() { --count; }
int c;
int data[8];
};
int Foo::count = 0;
void tst_QCache::initTestCase()
{
Foo::count = 0;
}
void tst_QCache::cleanupTestCase()
{
// always check for memory leaks
QCOMPARE(Foo::count, 0);
}
void tst_QCache::empty()
{
QCache<int, int> cache;
QCOMPARE(cache.size(), 0);
QCOMPARE(cache.count(), 0);
QVERIFY(cache.isEmpty());
QVERIFY(!cache.contains(1));
QCOMPARE(cache.keys().size(), 0);
QCOMPARE(cache.take(1), nullptr);
QVERIFY(!cache.remove(1));
QCOMPARE(cache.object(1), nullptr);
QCOMPARE(cache[1], nullptr);
QCOMPARE(cache.totalCost(), 0);
}
void tst_QCache::maxCost()
{
QCache<QString, int> cache1, cache2(100), cache3(200), cache4(-50);
QCOMPARE(cache1.maxCost(), 100);
QCOMPARE(cache2.maxCost(), 100);
QCOMPARE(cache3.maxCost(), 200);
QCOMPARE(cache4.maxCost(), -50); // 0 would also make sense
cache1.setMaxCost(101);
QCOMPARE(cache1.maxCost(), 101);
cache1.insert("one", new int(1), 1);
cache1.insert("two", new int(2), 1);
QCOMPARE(cache1.totalCost(), 2);
QCOMPARE(cache1.size(), 2);
QCOMPARE(cache1.maxCost(), 101);
cache1.insert("three", new int(3), 98);
QCOMPARE(cache1.totalCost(), 100);
QCOMPARE(cache1.size(), 3);
QCOMPARE(cache1.maxCost(), 101);
cache1.insert("four", new int(4), 1);
QCOMPARE(cache1.totalCost(), 101);
QCOMPARE(cache1.size(), 4);
QCOMPARE(cache1.maxCost(), 101);
cache1.insert("five", new int(4), 1);
QVERIFY(cache1.totalCost() <= 101);
QVERIFY(cache1.size() == 4);
QCOMPARE(cache1.maxCost(), 101);
cache1.setMaxCost(-1);
QCOMPARE(cache1.totalCost(), 0);
QCOMPARE(cache1.maxCost(), -1);
cache2.setMaxCost(202);
QCOMPARE(cache2.maxCost(), 202);
cache3.setMaxCost(-50);
QCOMPARE(cache3.maxCost(), -50);
}
void tst_QCache::setMaxCost()
{
QCache<int, Foo> cache;
cache.setMaxCost(2);
cache.insert(1, new Foo);
cache.insert(2, new Foo);
QCOMPARE(cache.totalCost(), 2);
QCOMPARE(Foo::count, 2);
cache.insert(3, new Foo);
QCOMPARE(cache.totalCost(), 2);
QCOMPARE(Foo::count, 2);
cache.setMaxCost(3);
QCOMPARE(cache.totalCost(), 2);
QCOMPARE(Foo::count, 2);
cache.setMaxCost(2);
QCOMPARE(cache.totalCost(), 2);
QCOMPARE(Foo::count, 2);
cache.setMaxCost(1);
QCOMPARE(cache.totalCost(), 1);
QCOMPARE(Foo::count, 1);
cache.setMaxCost(0);
QCOMPARE(cache.totalCost(), 0);
QCOMPARE(Foo::count, 0);
cache.setMaxCost(-1);
QCOMPARE(cache.totalCost(), 0);
QCOMPARE(Foo::count, 0);
}
void tst_QCache::totalCost()
{
QCache<QString, int> cache;
QCOMPARE(cache.totalCost(), 0);
cache.insert("one", new int(1), 0);
QCOMPARE(cache.totalCost(), 0);
cache.insert("two", new int(2), 1);
QCOMPARE(cache.totalCost(), 1);
cache.insert("three", new int(3), 2);
QCOMPARE(cache.totalCost(), 3);
cache.insert("four", new int(4), 10000);
QCOMPARE(cache.totalCost(), 3);
QVERIFY(!cache.contains("four"));
cache.insert("five", new int(5), -5);
QCOMPARE(cache.totalCost(), -2);
cache.insert("six", new int(6), 101);
QCOMPARE(cache.totalCost(), -2);
cache.insert("seven", new int(7), 100);
QCOMPARE(cache.totalCost(), 98);
QCOMPARE(cache.size(), 5);
cache.insert("eight", new int(8), 2);
QCOMPARE(cache.totalCost(), 100);
QCOMPARE(cache.size(), 6);
}
void tst_QCache::clear()
{
{
QCache<QString, Foo> cache(200);
QCOMPARE(cache.totalCost(), 0);
for (int i = -3; i < 9; ++i)
cache.insert(QString::number(i), new Foo, i);
QCOMPARE(cache.totalCost(), 30);
QCOMPARE(cache.size(), 12);
QVERIFY(!cache.isEmpty());
cache.setMaxCost(300);
for (int j = 0; j < 3; ++j) {
cache.clear();
QCOMPARE(cache.totalCost(), 0);
QCOMPARE(cache.size(), 0);
QVERIFY(cache.isEmpty());
QCOMPARE(Foo::count, 0);
QCOMPARE(cache.maxCost(), 300);
}
cache.insert("10", new Foo, 10);
QCOMPARE(cache.size(), 1);
cache.setMaxCost(9);
QCOMPARE(cache.size(), 0);
cache.insert("11", new Foo, 9);
QCOMPARE(cache.size(), 1);
QCOMPARE(Foo::count, 1);
}
QCOMPARE(Foo::count, 0);
}
void tst_QCache::insert()
{
QCache<QString, Foo> cache;
Foo *f1 = new Foo;
cache.insert("one", f1, 1);
QVERIFY(cache.contains("one"));
Foo *f2 = new Foo;
cache.insert("two", f2, 2);
QVERIFY(cache.contains("two"));
QCOMPARE(cache.size(), 2);
Foo *f3 = new Foo;
cache.insert("two", f3, 2);
QVERIFY(cache.contains("two"));
QCOMPARE(cache.size(), 2);
QVERIFY(cache["two"] == f3);
QCOMPARE(Foo::count, 2);
/*
If the new item is too big, any item with the same name in
the cache must still be removed, otherwise the application
might get bad results.
*/
Foo *f4 = new Foo;
cache.insert("two", f4, 10000);
QVERIFY(!cache.contains("two"));
QCOMPARE(cache.size(), 1);
QCOMPARE(Foo::count, 1);
}
void tst_QCache::contains()
{
QCache<int, int> cache;
QVERIFY(!cache.contains(0));
QVERIFY(!cache.contains(1));
cache.insert(1, new int(1), 1);
QVERIFY(!cache.contains(0));
QVERIFY(cache.contains(1));
cache.remove(0);
cache.remove(1);
QVERIFY(!cache.contains(0));
QVERIFY(!cache.contains(1));
cache.insert(1, new int(1), 1);
QVERIFY(!cache.contains(0));
QVERIFY(cache.contains(1));
cache.clear();
QVERIFY(!cache.contains(0));
QVERIFY(!cache.contains(1));
}
void tst_QCache::operator_bracket_bracket()
{
QCache<int, int> cache;
cache.insert(1, new int(2));
QVERIFY(cache[0] == 0);
QVERIFY(cache[1] != 0);
QCOMPARE(*cache[1], 2);
cache.insert(1, new int(4));
QVERIFY(cache[1] != 0);
QCOMPARE(*cache[1], 4);
// check that operator[] doesn't remove the item
QVERIFY(cache[1] != 0);
QCOMPARE(*cache[1], 4);
cache.remove(1);
QVERIFY(cache[1] == 0);
}
void tst_QCache::remove()
{
QCache<QString, Foo> cache;
cache.remove(QString());
cache.remove("alpha");
QVERIFY(cache.isEmpty());
cache.insert("alpha", new Foo, 10);
QCOMPARE(cache.size(), 1);
cache.insert("beta", new Foo, 20);
QCOMPARE(cache.size(), 2);
for (int i = 0; i < 10; ++i) {
cache.remove("alpha");
QCOMPARE(cache.size(), 1);
QCOMPARE(cache.totalCost(), 20);
}
cache.setMaxCost(1);
QCOMPARE(cache.size(), 0);
cache.remove("beta");
QCOMPARE(cache.size(), 0);
}
void tst_QCache::take()
{
QCache<QString, Foo> cache;
QCOMPARE(cache.take(QString()), (Foo*)0);
QCOMPARE(cache.take("alpha"), (Foo*)0);
QVERIFY(cache.isEmpty());
Foo *f1 = new Foo;
cache.insert("alpha", f1, 10);
QCOMPARE(cache.size(), 1);
QVERIFY(cache["alpha"] == f1);
cache.insert("beta", new Foo, 20);
QCOMPARE(cache.size(), 2);
QCOMPARE(cache.take("alpha"), f1);
QCOMPARE(cache.size(), 1);
QCOMPARE(cache.totalCost(), 20);
QCOMPARE(Foo::count, 2);
delete f1;
QCOMPARE(Foo::count, 1);
QCOMPARE(cache.take("alpha"), (Foo*)0);
QCOMPARE(Foo::count, 1);
QCOMPARE(cache.size(), 1);
QCOMPARE(cache.totalCost(), 20);
cache.setMaxCost(1);
QCOMPARE(cache.size(), 0);
QCOMPARE(cache.take("beta"), (Foo*)0);
QCOMPARE(cache.size(), 0);
}
struct KeyType
{
int foo;
KeyType(int x) : foo(x) {}
constexpr KeyType(const KeyType &o) noexcept : foo(o.foo) {}
private:
KeyType &operator=(const KeyType &);
};
struct ValueType
{
int foo;
ValueType(int x) : foo(x) {}
private:
ValueType(const ValueType &);
ValueType &operator=(const ValueType &);
};
bool operator==(const KeyType &key1, const KeyType &key2)
{
return key1.foo == key2.foo;
}
size_t qHash(const KeyType &key)
{
return qHash(key.foo);
}
void tst_QCache::axioms_on_key_type()
{
QCache<KeyType, ValueType> foo;
foo.setMaxCost(1);
foo.clear();
foo.insert(KeyType(123), new ValueType(123));
foo.object(KeyType(123));
foo.contains(KeyType(456));
foo[KeyType(456)];
foo.remove(KeyType(456));
foo.remove(KeyType(123));
foo.take(KeyType(789));
// If this fails, contact the maintaner
QVERIFY(sizeof(QHash<int, int>) == sizeof(void *));
}
void tst_QCache::largeCache()
{
QCache<int, int> cache;
cache.setMaxCost(500);
for (int i = 0; i < 1000; ++i) {
for (int j = 0; j < qMax(0, i - 500); ++j)
QVERIFY(!cache.contains(j));
for (int j = qMax(0, i - 500); j < i; ++j)
QVERIFY(cache.contains(j));
cache.insert(i, new int);
}
cache.clear();
QVERIFY(cache.size() == 0);
}
// The internal chain could lose track of some objects.
// Make sure it doesn't happen again.
void tst_QCache::internalChainOrderAfterEntryUpdate()
{
QCache<QString, int> cache;
cache.setMaxCost(20);
cache.insert(QString::number(1), new int, 1);
cache.insert(QString::number(2), new int, 1);
cache.insert(QString::number(1), new int, 1);
// If the chain is still 'in order' then setting maxCost == 0 should
// a. not crash, and
// b. remove all the elements in the QHash
cache.setMaxCost(0);
QCOMPARE(cache.size(), 0);
}
void tst_QCache::emplaceLowerCost()
{
QCache<QString, int> cache;
cache.setMaxCost(5);
cache.insert("a", new int, 3); // insert high cost
cache.insert("a", new int, 1); // and then exchange it with a lower-cost object
QCOMPARE(cache.totalCost(), 1);
cache.remove("a"); // then remove the object
// The cache should now have a cost == 0 and be empty.
QCOMPARE(cache.totalCost(), 0);
QVERIFY(cache.isEmpty());
}
struct TrivialHashType {
int i = -1;
size_t hash = 0;
TrivialHashType(int i, size_t hash) : i(i), hash(hash) {}
TrivialHashType(const TrivialHashType &o) noexcept = default;
TrivialHashType &operator=(const TrivialHashType &o) noexcept = default;
TrivialHashType(TrivialHashType &&o) noexcept : i(o.i), hash(o.hash) {
o.i = -1;
o.hash = 0;
}
TrivialHashType &operator=(TrivialHashType &&o) noexcept {
i = o.i;
hash = o.hash;
o.i = -1;
o.hash = 0;
return *this;
}
friend bool operator==(const TrivialHashType &lhs, const TrivialHashType &rhs)
{
return lhs.i == rhs.i;
}
};
quint64 qHash(TrivialHashType t, size_t seed = 0)
{
Q_UNUSED(seed);
return t.hash;
}
// During trim(), if the Node we have a pointer to in the function is moved
// to another span in the hash table, our pointer would end up pointing to
// garbage memory. Test that this no longer happens
void tst_QCache::trimWithMovingAcrossSpans()
{
qsizetype numBuckets = [](){
QHash<int, int> h;
h.reserve(1);
// Beholden to QHash internals:
return h.capacity() << 1;
}();
QCache<TrivialHashType, int> cache;
cache.setMaxCost(1000);
auto lastBucketInSpan = size_t(numBuckets - 1);
// If this fails then the test is no longer valid
QCOMPARE(QHashPrivate::GrowthPolicy::bucketForHash(numBuckets, lastBucketInSpan),
lastBucketInSpan);
// Pad some space so we have two spans:
for (int i = 2; i < numBuckets; ++i)
cache.insert({i, 0}, nullptr);
// These two are vying for the last bucket in the first span,
// when '0' is deleted, '1' is moved across the span boundary,
// invalidating any pointer to its Node.
cache.insert({0, lastBucketInSpan}, nullptr);
cache.insert({1, lastBucketInSpan}, nullptr);
QCOMPARE(cache.size(), numBuckets);
cache.setMaxCost(0);
QCOMPARE(cache.size(), 0);
}
QTEST_APPLESS_MAIN(tst_QCache)
#include "tst_qcache.moc"

View File

@ -0,0 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qcommandlineparser Test:
#####################################################################
qt_internal_add_test(tst_qcommandlineparser
SOURCES
tst_qcommandlineparser.cpp
)
add_subdirectory(testhelper)
if(QT_FEATURE_process AND NOT ANDROID)
add_dependencies(tst_qcommandlineparser qcommandlineparser_test_helper)
endif()

View File

@ -0,0 +1,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## qcommandlineparser_test_helper Binary:
#####################################################################
qt_internal_add_executable(qcommandlineparser_test_helper
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
SOURCES
qcommandlineparser_test_helper.cpp
)

View File

@ -0,0 +1,86 @@
// Copyright (C) 2013 David Faure <faure@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QDebug>
#include <QCoreApplication>
#include <QCommandLineParser>
#include <stdio.h>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
app.setApplicationVersion("1.0");
// Test for QCoreApplication::arguments()
const QStringList incomingArgs = QCoreApplication::arguments();
for (int i = 0; i < argc; ++i) {
if (incomingArgs.at(i) != QLatin1String(argv[i]))
qDebug() << "ERROR: arguments[" << i << "] was" << incomingArgs.at(i) << "expected" << argv[i];
}
QCommandLineParser parser;
parser.setApplicationDescription("Test helper");
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("parsingMode", "The parsing mode to test.");
parser.addPositionalArgument("command", "The command to execute.");
parser.addOption(QCommandLineOption("load", "Load file from URL.", "url"));
parser.addOption(QCommandLineOption(QStringList() << "o" << "output", "Set output file.", "file"));
parser.addOption(QCommandLineOption("D", "Define macro.", "key=value"));
parser.addOption(QCommandLineOption("long-option"));
// An option with a longer description, to test wrapping
QCommandLineOption noImplicitIncludesOption(QStringList() << QStringLiteral("n") << QStringLiteral("no-implicit-includes"));
noImplicitIncludesOption.setDescription(QStringLiteral("Disable magic generation of implicit #include-directives."));
parser.addOption(noImplicitIncludesOption);
QCommandLineOption newlineOption(QStringList() << QStringLiteral("newline"));
newlineOption.setDescription(QString::fromLatin1("This is an option with a rather long\n"
"description using explicit newline characters "
"(but testing automatic wrapping too). In addition, "
"here, we test breaking after a comma. Testing -option. "
"Long URL: http://qt-project.org/wiki/How_to_create_a_library_with_Qt_and_use_it_in_an_application "
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"));
parser.addOption(newlineOption);
// A hidden option
QCommandLineOption hiddenOption(QStringList() << QStringLiteral("hidden"));
hiddenOption.setDescription(QStringLiteral("THIS SHOULD NEVER APPEAR"));
hiddenOption.setFlags(QCommandLineOption::HiddenFromHelp);
parser.addOption(hiddenOption);
// This program supports different options depending on the "command" (first argument).
// Call parse() to find out the positional arguments.
parser.parse(QCoreApplication::arguments());
QStringList args = parser.positionalArguments();
if (args.isEmpty())
parser.showHelp(1);
parser.setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode(args.takeFirst().toInt()));
const QString command = args.isEmpty() ? QString() : args.first();
if (command == "resize") {
parser.clearPositionalArguments();
parser.addPositionalArgument("resize", "Resize the object to a new size.", "resize [resize_options]");
parser.addOption(QCommandLineOption("size", "New size.", "size"));
parser.process(app);
const QString size = parser.value("size");
printf("Resizing %s to %s and saving to %s\n", qPrintable(parser.value("load")), qPrintable(size), qPrintable(parser.value("o")));
} else if (command == "long") {
// A very long option (QTBUG-79926)
QCommandLineOption longOption(QStringList{QStringLiteral("looooooooooooong-option"), QStringLiteral("looooong-opt-alias")});
longOption.setDescription(QStringLiteral("Short description"));
longOption.setValueName(QStringLiteral("looooooooooooong-value-name"));
parser.addOption(longOption);
parser.process(app);
} else {
// Call process again, to handle unknown options this time.
parser.process(app);
}
printf("Positional arguments: %s\n", qPrintable(parser.positionalArguments().join(",")));
printf("Macros: %s\n", qPrintable(parser.values("D").join(",")));
return 0;
}

View File

@ -0,0 +1,780 @@
// Copyright (C) 2021 David Faure <faure@kde.org>
// 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>
#if QT_CONFIG(process)
#include <QProcess>
#endif
#include <QtCore/QCommandLineParser>
Q_DECLARE_METATYPE(char**)
Q_DECLARE_METATYPE(QCommandLineParser::OptionsAfterPositionalArgumentsMode)
class tst_QCommandLineParser : public QObject
{
Q_OBJECT
public slots:
void initTestCase();
private slots:
void parsingModes_data();
// In-process tests
void testInvalidOptions();
void testDuplicateOption();
void testPositionalArguments();
void testBooleanOption_data();
void testBooleanOption();
void testOptionsAndPositional_data();
void testOptionsAndPositional();
void testMultipleNames_data();
void testMultipleNames();
void testSingleValueOption_data();
void testSingleValueOption();
void testValueNotSet();
void testMultipleValuesOption();
void testUnknownOptionErrorHandling_data();
void testUnknownOptionErrorHandling();
void testDoubleDash_data();
void testDoubleDash();
void testDefaultValue();
void testProcessNotCalled();
void testEmptyArgsList();
void testNoApplication();
void testMissingOptionValue();
void testStdinArgument_data();
void testStdinArgument();
void testSingleDashWordOptionModes_data();
void testSingleDashWordOptionModes();
void testCpp11StyleInitialization();
// QProcess-based tests using qcommandlineparser_test_helper
void testVersionOption();
void testHelpOption_data();
void testHelpOption();
void testQuoteEscaping();
void testUnknownOption();
void testHelpAll_data();
void testHelpAll();
void testVeryLongOptionNames();
};
static char *empty_argv[] = { 0 };
static int empty_argc = 1;
void tst_QCommandLineParser::initTestCase()
{
Q_ASSERT(!empty_argv[0]);
empty_argv[0] = const_cast<char*>(QTest::currentAppName());
}
Q_DECLARE_METATYPE(QCommandLineParser::SingleDashWordOptionMode)
void tst_QCommandLineParser::parsingModes_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions;
QTest::newRow("implicitlylong") << QCommandLineParser::ParseAsLongOptions;
}
void tst_QCommandLineParser::testInvalidOptions()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QTest::ignoreMessage(QtWarningMsg, "QCommandLineOption: Option names cannot start with a '-'");
QVERIFY(!parser.addOption(QCommandLineOption(QStringLiteral("-v"), QStringLiteral("Displays version information."))));
}
void tst_QCommandLineParser::testDuplicateOption()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("h"), QStringLiteral("Hostname."), QStringLiteral("hostname"))));
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: already having an option named \"h\"");
parser.addHelpOption();
}
void tst_QCommandLineParser::testPositionalArguments()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "file.txt"));
QCOMPARE(parser.positionalArguments(), QStringList() << QStringLiteral("file.txt"));
}
void tst_QCommandLineParser::testBooleanOption_data()
{
QTest::addColumn<QStringList>("args");
QTest::addColumn<QStringList>("expectedOptionNames");
QTest::addColumn<bool>("expectedIsSet");
QTest::newRow("set") << (QStringList() << "tst_qcommandlineparser" << "-b") << (QStringList() << "b") << true;
QTest::newRow("unset") << (QStringList() << "tst_qcommandlineparser") << QStringList() << false;
}
void tst_QCommandLineParser::testBooleanOption()
{
QFETCH(QStringList, args);
QFETCH(QStringList, expectedOptionNames);
QFETCH(bool, expectedIsSet);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("b"))));
QVERIFY(parser.parse(args));
QCOMPARE(parser.optionNames(), expectedOptionNames);
QCOMPARE(parser.isSet("b"), expectedIsSet);
QCOMPARE(parser.values("b"), QStringList());
QCOMPARE(parser.positionalArguments(), QStringList());
// Should warn on typos
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not defined: \"c\"");
QVERIFY(!parser.isSet("c"));
}
void tst_QCommandLineParser::testOptionsAndPositional_data()
{
QTest::addColumn<QStringList>("args");
QTest::addColumn<QStringList>("expectedOptionNames");
QTest::addColumn<bool>("expectedIsSet");
QTest::addColumn<QStringList>("expectedPositionalArguments");
QTest::addColumn<QCommandLineParser::OptionsAfterPositionalArgumentsMode>("parsingMode");
const QStringList arg = QStringList() << "arg";
QTest::newRow("before_positional_default") << (QStringList() << "tst_qcommandlineparser" << "-b" << "arg") << (QStringList() << "b") << true << arg << QCommandLineParser::ParseAsOptions;
QTest::newRow("after_positional_default") << (QStringList() << "tst_qcommandlineparser" << "arg" << "-b") << (QStringList() << "b") << true << arg << QCommandLineParser::ParseAsOptions;
QTest::newRow("before_positional_parseAsArg") << (QStringList() << "tst_qcommandlineparser" << "-b" << "arg") << (QStringList() << "b") << true << arg << QCommandLineParser::ParseAsPositionalArguments;
QTest::newRow("after_positional_parseAsArg") << (QStringList() << "tst_qcommandlineparser" << "arg" << "-b") << (QStringList()) << false << (QStringList() << "arg" << "-b") << QCommandLineParser::ParseAsPositionalArguments;
}
void tst_QCommandLineParser::testOptionsAndPositional()
{
QFETCH(QStringList, args);
QFETCH(QStringList, expectedOptionNames);
QFETCH(bool, expectedIsSet);
QFETCH(QStringList, expectedPositionalArguments);
QFETCH(QCommandLineParser::OptionsAfterPositionalArgumentsMode, parsingMode);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
parser.setOptionsAfterPositionalArgumentsMode(parsingMode);
QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("b"), QStringLiteral("a boolean option"))));
QVERIFY(parser.parse(args));
QCOMPARE(parser.optionNames(), expectedOptionNames);
QCOMPARE(parser.isSet("b"), expectedIsSet);
QCOMPARE(parser.values("b"), QStringList());
QCOMPARE(parser.positionalArguments(), expectedPositionalArguments);
}
void tst_QCommandLineParser::testMultipleNames_data()
{
QTest::addColumn<QStringList>("args");
QTest::addColumn<QStringList>("expectedOptionNames");
QTest::newRow("short") << (QStringList() << "tst_qcommandlineparser" << "-v") << (QStringList() << "v");
QTest::newRow("long") << (QStringList() << "tst_qcommandlineparser" << "--version") << (QStringList() << "version");
QTest::newRow("not_set") << (QStringList() << "tst_qcommandlineparser") << QStringList();
}
void tst_QCommandLineParser::testMultipleNames()
{
QFETCH(QStringList, args);
QFETCH(QStringList, expectedOptionNames);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineOption option(QStringList() << "v" << "version", QStringLiteral("Show version information"));
QCOMPARE(option.names(), QStringList() << "v" << "version");
QCommandLineParser parser;
QVERIFY(parser.addOption(option));
QVERIFY(parser.parse(args));
QCOMPARE(parser.optionNames(), expectedOptionNames);
const bool expectedIsSet = !expectedOptionNames.isEmpty();
QCOMPARE(parser.isSet("v"), expectedIsSet);
QCOMPARE(parser.isSet("version"), expectedIsSet);
}
void tst_QCommandLineParser::testSingleValueOption_data()
{
QTest::addColumn<QStringList>("args");
QTest::addColumn<QStringList>("defaults");
QTest::addColumn<bool>("expectedIsSet");
QTest::newRow("short") << (QStringList() << "tst" << "-s" << "oxygen") << QStringList() << true;
QTest::newRow("long") << (QStringList() << "tst" << "--style" << "oxygen") << QStringList() << true;
QTest::newRow("longequal") << (QStringList() << "tst" << "--style=oxygen") << QStringList() << true;
QTest::newRow("default") << (QStringList() << "tst") << (QStringList() << "oxygen") << false;
}
void tst_QCommandLineParser::testSingleValueOption()
{
QFETCH(QStringList, args);
QFETCH(QStringList, defaults);
QFETCH(bool, expectedIsSet);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QCommandLineOption option(QStringList() << "s" << "style", QStringLiteral("style name"), "styleName");
option.setDefaultValues(defaults);
QVERIFY(parser.addOption(option));
for (int mode = 0; mode < 2; ++mode) {
parser.setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode(mode));
QVERIFY(parser.parse(args));
QCOMPARE(parser.isSet("s"), expectedIsSet);
QCOMPARE(parser.isSet("style"), expectedIsSet);
QCOMPARE(parser.isSet(option), expectedIsSet);
QCOMPARE(parser.value("s"), QString("oxygen"));
QCOMPARE(parser.value("style"), QString("oxygen"));
QCOMPARE(parser.values("s"), QStringList() << "oxygen");
QCOMPARE(parser.values("style"), QStringList() << "oxygen");
QCOMPARE(parser.values(option), QStringList() << "oxygen");
QCOMPARE(parser.positionalArguments(), QStringList());
}
// Should warn on typos
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: option not defined: \"c\"");
QVERIFY(parser.values("c").isEmpty());
}
void tst_QCommandLineParser::testValueNotSet()
{
QCoreApplication app(empty_argc, empty_argv);
// Not set, no default value
QCommandLineParser parser;
QCommandLineOption option(QStringList() << "s" << "style", QStringLiteral("style name"));
option.setValueName("styleName");
QVERIFY(parser.addOption(option));
QVERIFY(parser.parse(QStringList() << "tst"));
QCOMPARE(parser.optionNames(), QStringList());
QVERIFY(!parser.isSet("s"));
QVERIFY(!parser.isSet("style"));
QCOMPARE(parser.value("s"), QString());
QCOMPARE(parser.value("style"), QString());
QCOMPARE(parser.values("s"), QStringList());
QCOMPARE(parser.values("style"), QStringList());
}
void tst_QCommandLineParser::testMultipleValuesOption()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineOption option(QStringLiteral("param"), QStringLiteral("Pass parameter to the backend."));
option.setValueName("key=value");
QCommandLineParser parser;
QVERIFY(parser.addOption(option));
{
QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1"));
QVERIFY(parser.isSet("param"));
QCOMPARE(parser.values("param"), QStringList() << "key1=value1");
QCOMPARE(parser.value("param"), QString("key1=value1"));
}
{
QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1" << "--param" << "key2=value2"));
QVERIFY(parser.isSet("param"));
QCOMPARE(parser.values("param"), QStringList() << "key1=value1" << "key2=value2");
QCOMPARE(parser.value("param"), QString("key2=value2"));
}
QString expected =
"Usage: tst_qcommandlineparser [options]\n"
"\n"
"Options:\n"
" --param <key=value> Pass parameter to the backend.\n";
const QString exeName = QCoreApplication::instance()->arguments().first(); // e.g. debug\tst_qcommandlineparser.exe on Windows
expected.replace(QStringLiteral("tst_qcommandlineparser"), exeName);
QCOMPARE(parser.helpText(), expected);
}
void tst_QCommandLineParser::testUnknownOptionErrorHandling_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::addColumn<QStringList>("args");
QTest::addColumn<QStringList>("expectedUnknownOptionNames");
QTest::addColumn<QString>("expectedErrorText");
const QStringList args_hello = QStringList() << "tst_qcommandlineparser" << "--hello";
const QString error_hello("Unknown option 'hello'.");
QTest::newRow("unknown_name_collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << args_hello << QStringList("hello") << error_hello;
QTest::newRow("unknown_name_long") << QCommandLineParser::ParseAsLongOptions << args_hello << QStringList("hello") << error_hello;
const QStringList args_value = QStringList() << "tst_qcommandlineparser" << "-b=1";
QTest::newRow("bool_with_value_collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << args_value << QStringList() << QString("Unexpected value after '-b'.");
QTest::newRow("bool_with_value_long") << QCommandLineParser::ParseAsLongOptions << args_value << QStringList() << QString("Unexpected value after '-b'.");
const QStringList args_dash_long = QStringList() << "tst_qcommandlineparser" << "-bool";
const QString error_bool("Unknown options: o, o, l.");
QTest::newRow("unknown_name_long_collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << args_dash_long << (QStringList() << "o" << "o" << "l") << error_bool;
}
void tst_QCommandLineParser::testUnknownOptionErrorHandling()
{
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QFETCH(QStringList, args);
QFETCH(QStringList, expectedUnknownOptionNames);
QFETCH(QString, expectedErrorText);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
parser.setSingleDashWordOptionMode(parsingMode);
QVERIFY(parser.addOption(QCommandLineOption(QStringList() << "b" << "bool", QStringLiteral("a boolean option"))));
QCOMPARE(parser.parse(args), expectedErrorText.isEmpty());
QCOMPARE(parser.unknownOptionNames(), expectedUnknownOptionNames);
QCOMPARE(parser.errorText(), expectedErrorText);
}
void tst_QCommandLineParser::testDoubleDash_data()
{
parsingModes_data();
}
void tst_QCommandLineParser::testDoubleDash()
{
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QVERIFY(parser.addOption(QCommandLineOption(QStringList() << "o" << "output", QStringLiteral("Output file"), QStringLiteral("filename"))));
parser.setSingleDashWordOptionMode(parsingMode);
QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--output" << "foo"));
QCOMPARE(parser.value("output"), QString("foo"));
QCOMPARE(parser.positionalArguments(), QStringList());
QCOMPARE(parser.unknownOptionNames(), QStringList());
QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--" << "--output" << "bar" << "-b" << "bleh"));
QCOMPARE(parser.value("output"), QString());
QCOMPARE(parser.positionalArguments(), QStringList() << "--output" << "bar" << "-b" << "bleh");
QCOMPARE(parser.unknownOptionNames(), QStringList());
}
void tst_QCommandLineParser::testDefaultValue()
{
QCommandLineOption opt(QStringLiteral("name"), QStringLiteral("desc"),
QStringLiteral("valueName"), QStringLiteral("default"));
QCOMPARE(opt.defaultValues(), QStringList(QStringLiteral("default")));
opt.setDefaultValue(QStringLiteral(""));
QCOMPARE(opt.defaultValues(), QStringList());
opt.setDefaultValue(QStringLiteral("default"));
QCOMPARE(opt.defaultValues(), QStringList(QStringLiteral("default")));
}
void tst_QCommandLineParser::testProcessNotCalled()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("b"), QStringLiteral("a boolean option"))));
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: call process() or parse() before isSet");
QVERIFY(!parser.isSet("b"));
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: call process() or parse() before values");
QCOMPARE(parser.values("b"), QStringList());
}
void tst_QCommandLineParser::testEmptyArgsList()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QTest::ignoreMessage(QtWarningMsg, "QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
QVERIFY(!parser.parse(QStringList())); // invalid call, argv[0] is missing
}
void tst_QCommandLineParser::testNoApplication()
{
QCommandLineOption option(QStringLiteral("param"), QStringLiteral("Pass parameter to the backend."));
option.setValueName("key=value");
QCommandLineParser parser;
QVERIFY(parser.addOption(option));
{
QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1"));
QVERIFY(parser.isSet("param"));
QCOMPARE(parser.values("param"), QStringList() << "key1=value1");
QCOMPARE(parser.value("param"), QString("key1=value1"));
}
{
QVERIFY(parser.parse(QStringList() << "tst" << "--param" << "key1=value1" << "--param" << "key2=value2"));
QVERIFY(parser.isSet("param"));
QCOMPARE(parser.values("param"), QStringList() << "key1=value1" << "key2=value2");
QCOMPARE(parser.value("param"), QString("key2=value2"));
}
const QString expected =
"Usage: <executable_name> [options]\n"
"\n"
"Options:\n"
" --param <key=value> Pass parameter to the backend.\n";
QCOMPARE(parser.helpText(), expected);
}
void tst_QCommandLineParser::testMissingOptionValue()
{
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("option"), QStringLiteral("An option"), "value")));
QVERIFY(!parser.parse(QStringList() << "argv0" << "--option")); // the user forgot to pass a value for --option
QCOMPARE(parser.value("option"), QString());
QCOMPARE(parser.errorText(), QString("Missing value after '--option'."));
}
void tst_QCommandLineParser::testStdinArgument_data()
{
parsingModes_data();
}
void tst_QCommandLineParser::testStdinArgument()
{
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
parser.setSingleDashWordOptionMode(parsingMode);
QVERIFY(parser.addOption(QCommandLineOption(QStringList() << "i" << "input", QStringLiteral("Input file."), QStringLiteral("filename"))));
QVERIFY(parser.addOption(QCommandLineOption("b", QStringLiteral("Boolean option."))));
QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--input" << "-"));
QCOMPARE(parser.value("input"), QString("-"));
QCOMPARE(parser.positionalArguments(), QStringList());
QCOMPARE(parser.unknownOptionNames(), QStringList());
QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "--input" << "-" << "-b" << "arg"));
QCOMPARE(parser.value("input"), QString("-"));
QVERIFY(parser.isSet("b"));
QCOMPARE(parser.positionalArguments(), QStringList() << "arg");
QCOMPARE(parser.unknownOptionNames(), QStringList());
QVERIFY(parser.parse(QStringList() << "tst_qcommandlineparser" << "-"));
QCOMPARE(parser.value("input"), QString());
QVERIFY(!parser.isSet("b"));
QCOMPARE(parser.positionalArguments(), QStringList() << "-");
QCOMPARE(parser.unknownOptionNames(), QStringList());
}
void tst_QCommandLineParser::testSingleDashWordOptionModes_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::addColumn<QStringList>("commandLine");
QTest::addColumn<QStringList>("expectedOptionNames");
QTest::addColumn<QStringList>("expectedOptionValues");
QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-abc" << "val")
<< (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val");
QTest::newRow("collapsed_with_equalsign_value") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-abc=val")
<< (QStringList() << "a" << "b" << "c") << (QStringList() << QString() << QString() << "val");
QTest::newRow("collapsed_explicit_longoption") << QCommandLineParser::ParseAsCompactedShortOptions << QStringList("--nn")
<< QStringList("nn") << QStringList();
QTest::newRow("collapsed_longoption_value") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "--abc" << "val")
<< QStringList("abc") << QStringList("val");
QTest::newRow("compiler") << QCommandLineParser::ParseAsCompactedShortOptions << QStringList("-cab")
<< QStringList("c") << QStringList("ab");
QTest::newRow("compiler_with_space") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-c" << "val")
<< QStringList("c") << QStringList("val");
QTest::newRow("implicitlylong") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-abc" << "val")
<< QStringList("abc") << QStringList("val");
QTest::newRow("implicitlylong_equal") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-abc=val")
<< QStringList("abc") << QStringList("val");
QTest::newRow("implicitlylong_longoption") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "--nn")
<< QStringList("nn") << QStringList();
QTest::newRow("implicitlylong_longoption_value") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "--abc" << "val")
<< QStringList("abc") << QStringList("val");
QTest::newRow("implicitlylong_with_space") << QCommandLineParser::ParseAsCompactedShortOptions << (QStringList() << "-c" << "val")
<< QStringList("c") << QStringList("val");
QTest::newRow("forceshort_detached") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-I" << "45")
<< QStringList("I") << QStringList("45");
QTest::newRow("forceshort_attached") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-I46")
<< QStringList("I") << QStringList("46");
QTest::newRow("forceshort_mixed") << QCommandLineParser::ParseAsLongOptions << (QStringList() << "-I45" << "-nn")
<< (QStringList() << "I" << "nn") << QStringList("45");
}
void tst_QCommandLineParser::testSingleDashWordOptionModes()
{
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QFETCH(QStringList, commandLine);
QFETCH(QStringList, expectedOptionNames);
QFETCH(QStringList, expectedOptionValues);
commandLine.prepend("tst_QCommandLineParser");
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
parser.setSingleDashWordOptionMode(parsingMode);
QVERIFY(parser.addOption(QCommandLineOption("a", QStringLiteral("a option."))));
QVERIFY(parser.addOption(QCommandLineOption("b", QStringLiteral("b option."))));
QVERIFY(parser.addOption(QCommandLineOption(QStringList() << "c" << "abc", QStringLiteral("c option."), QStringLiteral("value"))));
QVERIFY(parser.addOption(QCommandLineOption("nn", QStringLiteral("nn option."))));
QCommandLineOption forceShort(QStringLiteral("I"), QStringLiteral("always short option"),
QStringLiteral("path"), QStringLiteral("default"));
forceShort.setFlags(QCommandLineOption::ShortOptionStyle);
QVERIFY(parser.addOption(forceShort));
QVERIFY(parser.parse(commandLine));
QCOMPARE(parser.optionNames(), expectedOptionNames);
for (int i = 0; i < expectedOptionValues.size(); ++i)
QCOMPARE(parser.value(parser.optionNames().at(i)), expectedOptionValues.at(i));
QCOMPARE(parser.unknownOptionNames(), QStringList());
}
void tst_QCommandLineParser::testCpp11StyleInitialization()
{
#if defined(Q_COMPILER_UNIFORM_INIT)
QCoreApplication app(empty_argc, empty_argv);
QCommandLineParser parser;
// primarily check that this compiles:
QVERIFY(parser.addOptions({
{ "a", "The A option." },
{ { "v", "verbose" }, "The verbose option." },
{ { "i", "infile" }, "The input file.", "value" },
}));
// but do a very basic functionality test, too:
QVERIFY(parser.parse({"tst_QCommandLineParser", "-a", "-vvv", "--infile=in.txt"}));
QCOMPARE(parser.optionNames(), (QStringList{"a", "v", "v", "v", "infile"}));
QCOMPARE(parser.value("infile"), QString("in.txt"));
#else
QSKIP("This test requires C++11 uniform initialization support in the compiler.");
#endif
}
void tst_QCommandLineParser::testVersionOption()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "--version");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QString output = process.readAll();
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
QCOMPARE(output, QString("qcommandlineparser_test_helper 1.0\n"));
#endif // QT_CONFIG(process)
}
static const char expectedOptionsHelp[] =
"Options:\n"
" -h, --help Displays help on commandline options.\n"
" --help-all Displays help including Qt specific options.\n"
" -v, --version Displays version information.\n"
" --load <url> Load file from URL.\n"
" -o, --output <file> Set output file.\n"
" -D <key=value> Define macro.\n"
" --long-option\n"
" -n, --no-implicit-includes Disable magic generation of implicit\n"
" #include-directives.\n"
" --newline This is an option with a rather long\n"
" description using explicit newline characters (but\n"
" testing automatic wrapping too). In addition,\n"
" here, we test breaking after a comma. Testing\n"
" -option. Long URL:\n"
" http://qt-project.org/wiki/How_to_create_a_library\n"
" _with_Qt_and_use_it_in_an_application\n"
" abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx\n"
" yzabcdefghijklmnopqrstuvwxyz\n";
void tst_QCommandLineParser::testHelpOption_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::addColumn<QString>("expectedHelpOutput");
QString expectedOutput = QString::fromLatin1(
"Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n"
"Test helper\n"
"\n")
+ QString::fromLatin1(expectedOptionsHelp) +
QString::fromLatin1(
"\n"
"Arguments:\n"
" parsingMode The parsing mode to test.\n"
" command The command to execute.\n");
#ifdef Q_OS_WIN
expectedOutput.replace(" -h, --help Displays help on commandline options.\n",
" -?, -h, --help Displays help on commandline options.\n");
expectedOutput.replace("testhelper/", "testhelper\\");
#endif
QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << expectedOutput;
QTest::newRow("long") << QCommandLineParser::ParseAsLongOptions << expectedOutput;
}
void tst_QCommandLineParser::testHelpOption()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QFETCH(QString, expectedHelpOutput);
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
process.start("testhelper/qcommandlineparser_test_helper", QStringList() << QString::number(parsingMode) << "--help");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QString output = process.readAll();
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
QCOMPARE(output.split('\n'), expectedHelpOutput.split('\n')); // easier to debug than the next line, on failure
QCOMPARE(output, expectedHelpOutput);
process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "resize" << "--help");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
output = process.readAll();
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
QByteArray expectedResizeHelp = QByteArrayLiteral(
"Usage: testhelper/qcommandlineparser_test_helper [options] resize [resize_options]\n"
"Test helper\n"
"\n")
+ expectedOptionsHelp +
" --size <size> New size.\n"
"\n"
"Arguments:\n"
" resize Resize the object to a new size.\n";
#ifdef Q_OS_WIN
expectedResizeHelp.replace(" -h, --help Displays help on commandline options.\n",
" -?, -h, --help Displays help on commandline options.\n");
expectedResizeHelp.replace("testhelper/", "testhelper\\");
#endif
QCOMPARE(output, QString(expectedResizeHelp));
#endif // QT_CONFIG(process)
}
void tst_QCommandLineParser::testQuoteEscaping()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
process.start("testhelper/qcommandlineparser_test_helper", QStringList() <<
QString::number(QCommandLineParser::ParseAsCompactedShortOptions) <<
"\\\\server\\path" <<
"-DKEY1=\"VALUE1\""
"-DQTBUG-15379=C:\\path\\'file.ext" <<
"-DQTBUG-30628=C:\\temp\\'file'.ext");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QString output = process.readAll();
QVERIFY2(!output.contains("ERROR"), qPrintable(output));
QVERIFY2(output.contains("\\\\server\\path"), qPrintable(output));
QVERIFY2(output.contains("KEY1=\"VALUE1\""), qPrintable(output));
QVERIFY2(output.contains("QTBUG-15379=C:\\path\\'file.ext"), qPrintable(output));
QVERIFY2(output.contains("QTBUG-30628=C:\\temp\\'file'.ext"), qPrintable(output));
#endif // QT_CONFIG(process)
}
void tst_QCommandLineParser::testUnknownOption()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
process.start("testhelper/qcommandlineparser_test_helper", QStringList() <<
QString::number(QCommandLineParser::ParseAsLongOptions) <<
"-unknown-option");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
process.setReadChannel(QProcess::StandardError);
QString output = process.readAll();
QVERIFY2(output.contains("qcommandlineparser_test_helper"), qPrintable(output)); // separate in case of .exe extension
QVERIFY2(output.contains(": Unknown option 'unknown-option'"), qPrintable(output));
#endif // QT_CONFIG(process)
}
void tst_QCommandLineParser::testHelpAll_data()
{
QTest::addColumn<QCommandLineParser::SingleDashWordOptionMode>("parsingMode");
QTest::addColumn<QString>("expectedHelpOutput");
QString expectedOutput = QString::fromLatin1(
"Usage: testhelper/qcommandlineparser_test_helper [options] parsingMode command\n"
"Test helper\n"
"\n")
+ QString::fromLatin1(expectedOptionsHelp) +
QString::fromLatin1(
" --qmljsdebugger <value> Activates the QML/JS debugger with a specified\n"
" port. The value must be of format\n"
" port:1234[,block]. \"block\" makes the application\n"
" wait for a connection.\n"
"\n"
"Arguments:\n"
" parsingMode The parsing mode to test.\n"
" command The command to execute.\n");
#ifdef Q_OS_WIN
expectedOutput.replace(" -h, --help Displays help on commandline options.\n",
" -?, -h, --help Displays help on commandline options.\n");
expectedOutput.replace("testhelper/", "testhelper\\");
#endif
QTest::newRow("collapsed") << QCommandLineParser::ParseAsCompactedShortOptions << expectedOutput;
QTest::newRow("long") << QCommandLineParser::ParseAsLongOptions << expectedOutput;
}
void tst_QCommandLineParser::testHelpAll()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#else
#ifdef Q_OS_ANDROID
QSKIP("Deploying executable applications to file system on Android not supported.");
#endif
QFETCH(QCommandLineParser::SingleDashWordOptionMode, parsingMode);
QFETCH(QString, expectedHelpOutput);
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
process.start("testhelper/qcommandlineparser_test_helper", QStringList() << QString::number(parsingMode) << "--help-all");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QString output = process.readAll();
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
QCOMPARE(output.split('\n'), expectedHelpOutput.split('\n')); // easier to debug than the next line, on failure
QCOMPARE(output, expectedHelpOutput);
#endif // QT_CONFIG(process)
}
void tst_QCommandLineParser::testVeryLongOptionNames()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#elif defined(Q_OS_ANDROID)
QSKIP("Deploying executable applications to file system on Android not supported.");
#else
QCoreApplication app(empty_argc, empty_argv);
QProcess process;
process.start("testhelper/qcommandlineparser_test_helper", QStringList() << "0" << "long" << "--help");
QVERIFY(process.waitForFinished(5000));
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QString output = process.readAll();
#ifdef Q_OS_WIN
output.replace(QStringLiteral("\r\n"), QStringLiteral("\n"));
#endif
const QStringList lines = output.split('\n');
const int last = lines.size() - 1;
// Let's not compare everything, just the final parts.
QCOMPARE(lines.at(last - 7), " cdefghijklmnopqrstuvwxyz");
QCOMPARE(lines.at(last - 6), " --looooooooooooong-option, --looooong-opt-alias <l Short description");
QCOMPARE(lines.at(last - 5), " ooooooooooooong-value-name>");
QCOMPARE(lines.at(last - 4), "");
QCOMPARE(lines.at(last - 3), "Arguments:");
QCOMPARE(lines.at(last - 2), " parsingMode The parsing mode to test.");
QCOMPARE(lines.at(last - 1), " command The command to execute.");
#endif // QT_CONFIG(process)
}
QTEST_APPLESS_MAIN(tst_QCommandLineParser)
#include "tst_qcommandlineparser.moc"

View File

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

View File

@ -0,0 +1,367 @@
// 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 <QObject>
#include <QTest>
#include <QCache>
#include <QContiguousCache>
#include <QDebug>
#include <stdio.h>
class tst_QContiguousCache : public QObject
{
Q_OBJECT
private slots:
void assignment();
void empty();
void swap();
void append_data();
void append();
void prepend_data();
void prepend();
void complexType();
void operatorAt();
void setCapacity();
void zeroCapacity();
void modifyZeroCapacityCache();
};
QTEST_MAIN(tst_QContiguousCache)
void tst_QContiguousCache::assignment()
{
// compile-only test: QTBUG-45783
QContiguousCache<int> cc1, cc2;
// copy:
cc1 = cc2;
// move:
cc1 = std::move(cc2);
}
void tst_QContiguousCache::empty()
{
QContiguousCache<int> c(10);
QCOMPARE(c.capacity(), 10);
QCOMPARE(c.size(), 0);
// NOLINTNEXTLINE(qt-port-to-std-compatible-api): Test both size() and count()
QCOMPARE(c.count(), 0);
QVERIFY(c.isEmpty());
c.append(1);
// NOLINTNEXTLINE(qt-port-to-std-compatible-api): Test both size() and count()
QCOMPARE(c.count(), 1);
QCOMPARE(c.size(), 1);
QVERIFY(!c.isEmpty());
c.clear();
QCOMPARE(c.capacity(), 10);
QCOMPARE(c.size(), 0);
QVERIFY(c.isEmpty());
c.prepend(1);
QCOMPARE(c.size(), 1);
QVERIFY(!c.isEmpty());
c.clear();
QCOMPARE(c.size(), 0);
QVERIFY(c.isEmpty());
QCOMPARE(c.capacity(), 10);
}
void tst_QContiguousCache::swap()
{
QContiguousCache<int> c1(10), c2(100);
c1.append(1);
c1.swap(c2);
QCOMPARE(c1.capacity(), 100);
QCOMPARE(c1.size(), 0 );
QCOMPARE(c2.capacity(), 10 );
QCOMPARE(c2.size(), 1 );
}
void tst_QContiguousCache::append_data()
{
QTest::addColumn<qsizetype>("start");
QTest::addColumn<qsizetype>("count");
QTest::addColumn<qsizetype>("cacheSize");
QTest::addColumn<bool>("invalidIndexes");
QTest::newRow("0+30[10]") << qsizetype(0) << qsizetype(30) << qsizetype(10) << false;
QTest::newRow("300+30[10]") << qsizetype(300) << qsizetype(30) << qsizetype(10) << false;
QTest::newRow("MAX-10+30[10]") << std::numeric_limits<qsizetype>::max()-10 << qsizetype(30) << qsizetype(10) << true;
}
void tst_QContiguousCache::append()
{
QFETCH(qsizetype, start);
QFETCH(qsizetype, count);
QFETCH(qsizetype, cacheSize);
QFETCH(bool, invalidIndexes);
qsizetype i, j;
QContiguousCache<qsizetype> c(cacheSize);
i = 1;
QCOMPARE(c.available(), cacheSize);
if (start == 0)
c.append(i++);
else
c.insert(start, i++);
while (i < count) {
c.append(i);
QCOMPARE(c.available(), qMax(qsizetype(0), cacheSize - i));
QCOMPARE(c.first(), qMax(qsizetype(1), i-cacheSize+1));
QCOMPARE(c.last(), i);
QCOMPARE(c.size(), qMin(i, cacheSize));
QCOMPARE(c.isFull(), i >= cacheSize);
i++;
}
QCOMPARE(c.areIndexesValid(), !invalidIndexes);
if (invalidIndexes)
c.normalizeIndexes();
QVERIFY(c.areIndexesValid());
// test taking from end until empty.
for (j = 0; j < cacheSize; j++, i--) {
QCOMPARE(c.takeLast(), i-1);
QCOMPARE(c.size(), cacheSize-j-1);
QCOMPARE(c.available(), j+1);
QVERIFY(!c.isFull());
QCOMPARE(c.isEmpty(), j==cacheSize-1);
}
}
void tst_QContiguousCache::prepend_data()
{
QTest::addColumn<int>("start");
QTest::addColumn<int>("count");
QTest::addColumn<int>("cacheSize");
QTest::addColumn<bool>("invalidIndexes");
QTest::newRow("30-30[10]") << 30 << 30 << 10 << false;
QTest::newRow("300-30[10]") << 300 << 30 << 10 << false;
QTest::newRow("10-30[10]") << 10 << 30 << 10 << true;
}
void tst_QContiguousCache::prepend()
{
QFETCH(int, start);
QFETCH(int, count);
QFETCH(int, cacheSize);
QFETCH(bool, invalidIndexes);
int i, j;
QContiguousCache<int> c(cacheSize);
i = 1;
QCOMPARE(c.available(), cacheSize);
c.insert(start, i++);
while(i < count) {
c.prepend(i);
QCOMPARE(c.available(), qMax(0, cacheSize - i));
QCOMPARE(c.last(), qMax(1, i-cacheSize+1));
QCOMPARE(c.first(), i);
QCOMPARE(c.size(), qMin(i, cacheSize));
QCOMPARE(c.isFull(), i >= cacheSize);
i++;
}
QCOMPARE(c.areIndexesValid(), !invalidIndexes);
if (invalidIndexes)
c.normalizeIndexes();
QVERIFY(c.areIndexesValid());
// test taking from start until empty.
for (j = 0; j < cacheSize; j++, i--) {
QCOMPARE(c.takeFirst(), i-1);
QCOMPARE(c.size(), cacheSize-j-1);
QCOMPARE(c.available(), j+1);
QVERIFY(!c.isFull());
QCOMPARE(c.isEmpty(), j==cacheSize-1);
}
}
struct RefCountingClassData
{
QBasicAtomicInt ref;
static RefCountingClassData shared_null;
};
RefCountingClassData RefCountingClassData::shared_null = {
Q_BASIC_ATOMIC_INITIALIZER(1)
};
class RefCountingClass
{
public:
RefCountingClass() : d(&RefCountingClassData::shared_null) { d->ref.ref(); }
RefCountingClass(const RefCountingClass &other)
{
d = other.d;
d->ref.ref();
}
~RefCountingClass()
{
if (!d->ref.deref())
delete d;
}
RefCountingClass &operator=(const RefCountingClass &other)
{
if (!d->ref.deref())
delete d;
d = other.d;
d->ref.ref();
return *this;
}
int refCount() const { return d->ref.loadRelaxed(); }
private:
RefCountingClassData *d;
};
void tst_QContiguousCache::complexType()
{
RefCountingClass original;
QContiguousCache<RefCountingClass> contiguousCache(10);
contiguousCache.append(original);
QCOMPARE(original.refCount(), 3);
contiguousCache.removeFirst();
QCOMPARE(original.refCount(), 2); // shared null, 'original'.
contiguousCache.append(original);
QCOMPARE(original.refCount(), 3);
contiguousCache.clear();
QCOMPARE(original.refCount(), 2);
for(int i = 0; i < 100; ++i)
contiguousCache.insert(i, original);
QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache.
contiguousCache.clear();
QCOMPARE(original.refCount(), 2);
for (int i = 0; i < 100; i++)
contiguousCache.append(original);
QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache.
contiguousCache.clear();
QCOMPARE(original.refCount(), 2);
for (int i = 0; i < 100; i++)
contiguousCache.prepend(original);
QCOMPARE(original.refCount(), 12); // shared null, 'original', + 10 in contiguousCache.
contiguousCache.clear();
QCOMPARE(original.refCount(), 2);
for (int i = 0; i < 100; i++)
contiguousCache.append(original);
contiguousCache.takeLast();
QCOMPARE(original.refCount(), 11);
contiguousCache.takeFirst();
QCOMPARE(original.refCount(), 10);
}
void tst_QContiguousCache::operatorAt()
{
RefCountingClass original;
QContiguousCache<RefCountingClass> contiguousCache(10);
for (int i = 25; i < 35; ++i)
contiguousCache[i] = original;
QCOMPARE(original.refCount(), 12); // shared null, orig, items in cache
// verify const access does not copy items.
const QContiguousCache<RefCountingClass> copy(contiguousCache);
for (int i = 25; i < 35; ++i)
QCOMPARE(copy[i].refCount(), 12);
// verify modifying the original increments ref count (e.g. does a detach)
contiguousCache[25] = original;
QCOMPARE(original.refCount(), 22);
}
void tst_QContiguousCache::setCapacity()
{
int i;
QContiguousCache<int> contiguousCache(100);
for (i = 280; i < 310; ++i)
contiguousCache.insert(i, i);
QCOMPARE(contiguousCache.capacity(), 100);
QCOMPARE(contiguousCache.size(), 30);
QCOMPARE(contiguousCache.firstIndex(), 280);
QCOMPARE(contiguousCache.lastIndex(), 309);
for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) {
QVERIFY(contiguousCache.containsIndex(i));
QCOMPARE(contiguousCache.at(i), i);
}
contiguousCache.setCapacity(150);
QCOMPARE(contiguousCache.capacity(), 150);
QCOMPARE(contiguousCache.size(), 30);
QCOMPARE(contiguousCache.firstIndex(), 280);
QCOMPARE(contiguousCache.lastIndex(), 309);
for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) {
QVERIFY(contiguousCache.containsIndex(i));
QCOMPARE(contiguousCache.at(i), i);
}
contiguousCache.setCapacity(20);
QCOMPARE(contiguousCache.capacity(), 20);
QCOMPARE(contiguousCache.size(), 20);
QCOMPARE(contiguousCache.firstIndex(), 290);
QCOMPARE(contiguousCache.lastIndex(), 309);
for (i = contiguousCache.firstIndex(); i <= contiguousCache.lastIndex(); ++i) {
QVERIFY(contiguousCache.containsIndex(i));
QCOMPARE(contiguousCache.at(i), i);
}
}
void tst_QContiguousCache::zeroCapacity()
{
QContiguousCache<int> contiguousCache;
QCOMPARE(contiguousCache.capacity(),0);
contiguousCache.setCapacity(10);
QCOMPARE(contiguousCache.capacity(),10);
contiguousCache.setCapacity(0);
QCOMPARE(contiguousCache.capacity(),0);
}
void tst_QContiguousCache::modifyZeroCapacityCache()
{
{
QContiguousCache<int> contiguousCache;
contiguousCache.insert(0, 42);
}
{
QContiguousCache<int> contiguousCache;
contiguousCache.insert(1, 42);
}
{
QContiguousCache<int> contiguousCache;
contiguousCache.append(42);
}
{
QContiguousCache<int> contiguousCache;
contiguousCache.prepend(42);
}
}
#include "tst_qcontiguouscache.moc"

View File

@ -0,0 +1,22 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qcryptographichash Test:
#####################################################################
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
data/*)
list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qcryptographichash
SOURCES
tst_qcryptographichash.cpp
TESTDATA ${test_data}
)
if(QT_FEATURE_sanitize_address)
set_property(TEST tst_qcryptographichash APPEND PROPERTY ENVIRONMENT "QTEST_FUNCTION_TIMEOUT=900000")
endif()

View File

@ -0,0 +1,590 @@
// 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 <QtCore/QCoreApplication>
#include <QTest>
#include <QScopeGuard>
#include <QCryptographicHash>
#include <QtCore/QMetaEnum>
#if QT_CONFIG(cxx11_future)
# include <thread>
#endif
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
class tst_QCryptographicHash : public QObject
{
Q_OBJECT
private slots:
void repeated_result_data();
void repeated_result();
void intermediary_result_data();
void intermediary_result();
void sha1();
void sha3_data();
void sha3();
void blake2_data();
void blake2();
void files_data();
void files();
void hashLength_data();
void hashLength();
void addDataAcceptsNullByteArrayView_data() { hashLength_data(); }
void addDataAcceptsNullByteArrayView();
void move();
void swap();
// keep last
void moreThan4GiBOfData_data();
void moreThan4GiBOfData();
void keccakBufferOverflow();
private:
void ensureLargeData();
std::vector<char> large;
};
void tst_QCryptographicHash::repeated_result_data()
{
intermediary_result_data();
}
void tst_QCryptographicHash::repeated_result()
{
QFETCH(int, algo);
QCryptographicHash::Algorithm _algo = QCryptographicHash::Algorithm(algo);
QCryptographicHash hash(_algo);
QCOMPARE_EQ(hash.algorithm(), _algo);
QFETCH(QByteArray, first);
hash.addData(first);
QFETCH(QByteArray, hash_first);
QByteArrayView result = hash.resultView();
QCOMPARE(result, hash_first);
QCOMPARE(result, hash.resultView());
QCOMPARE(result, hash.result());
hash.reset();
hash.addData(first);
result = hash.resultView();
QCOMPARE(result, hash_first);
QCOMPARE(result, hash.result());
QCOMPARE(result, hash.resultView());
}
void tst_QCryptographicHash::intermediary_result_data()
{
QTest::addColumn<int>("algo");
QTest::addColumn<QByteArray>("first");
QTest::addColumn<QByteArray>("second");
QTest::addColumn<QByteArray>("hash_first");
QTest::addColumn<QByteArray>("hash_firstsecond");
QTest::newRow("md4") << int(QCryptographicHash::Md4)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("A448017AAF21D8525FC10AE87AA6729D")
<< QByteArray::fromHex("03E5E436DAFAF3B9B3589DB83C417C6B");
QTest::newRow("md5") << int(QCryptographicHash::Md5)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("900150983CD24FB0D6963F7D28E17F72")
<< QByteArray::fromHex("440AC85892CA43AD26D44C7AD9D47D3E");
QTest::newRow("sha1") << int(QCryptographicHash::Sha1)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("A9993E364706816ABA3E25717850C26C9CD0D89D")
<< QByteArray::fromHex("F8C1D87006FBF7E5CC4B026C3138BC046883DC71");
QTest::newRow("sha224") << int(QCryptographicHash::Sha224)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7")
<< QByteArray::fromHex("7C9C91FC479626AA1A525301084DEB96716131D146A2DB61B533F4C9");
QTest::newRow("sha256") << int(QCryptographicHash::Sha256)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD")
<< QByteArray::fromHex("BBB59DA3AF939F7AF5F360F2CEB80A496E3BAE1CD87DDE426DB0AE40677E1C2C");
QTest::newRow("sha384") << int(QCryptographicHash::Sha384)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7")
<< QByteArray::fromHex("CAF33A735C9535CE7F5D24FB5B3A4834F0E9316664AD15A9E8221679D4A3B4FB7E962404BA0C10C1D43AB49D03A08B8D");
QTest::newRow("sha512") << int(QCryptographicHash::Sha512)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F")
<< QByteArray::fromHex("F3C41E7B63EE869596FC28BAD64120612C520F65928AB4D126C72C6998B551B8FF1CEDDFED4373E6717554DC89D1EEE6F0AB22FD3675E561ABA9AE26A3EEC53B");
QTest::newRow("sha3_224_empty_abc")
<< int(QCryptographicHash::Sha3_224)
<< QByteArray("") << QByteArray("abc")
<< QByteArray::fromHex("6B4E03423667DBB73B6E15454F0EB1ABD4597F9A1B078E3F5B5A6BC7")
<< QByteArray::fromHex("E642824C3F8CF24AD09234EE7D3C766FC9A3A5168D0C94AD73B46FDF");
QTest::newRow("sha3_256_empty_abc")
<< int(QCryptographicHash::Sha3_256)
<< QByteArray("") << QByteArray("abc")
<< QByteArray::fromHex("A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A")
<< QByteArray::fromHex("3A985DA74FE225B2045C172D6BD390BD855F086E3E9D525B46BFE24511431532");
QTest::newRow("sha3_384_empty_abc")
<< int(QCryptographicHash::Sha3_384)
<< QByteArray("") << QByteArray("abc")
<< QByteArray::fromHex("0C63A75B845E4F7D01107D852E4C2485C51A50AAAA94FC61995E71BBEE983A2AC3713831264ADB47FB6BD1E058D5F004")
<< QByteArray::fromHex("EC01498288516FC926459F58E2C6AD8DF9B473CB0FC08C2596DA7CF0E49BE4B298D88CEA927AC7F539F1EDF228376D25");
QTest::newRow("sha3_512_empty_abc")
<< int(QCryptographicHash::Sha3_512)
<< QByteArray("") << QByteArray("abc")
<< QByteArray::fromHex("A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26")
<< QByteArray::fromHex("B751850B1A57168A5693CD924B6B096E08F621827444F70D884F5D0240D2712E10E116E9192AF3C91A7EC57647E3934057340B4CF408D5A56592F8274EEC53F0");
QTest::newRow("sha3_224_abc_abc")
<< int(QCryptographicHash::Sha3_224)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("E642824C3F8CF24AD09234EE7D3C766FC9A3A5168D0C94AD73B46FDF")
<< QByteArray::fromHex("58F426458091E16FBC61DDCB8F2D2A6F30F729CAFA3C289A4EB2BCF8");
QTest::newRow("sha3_256_abc_abc")
<< int(QCryptographicHash::Sha3_256)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("3A985DA74FE225B2045C172D6BD390BD855F086E3E9D525B46BFE24511431532")
<< QByteArray::fromHex("6C0872716337DE1EE664C1E37F64ADE109448F02681C63A912BC230FDEFC0058");
QTest::newRow("sha3_384_abc_abc")
<< int(QCryptographicHash::Sha3_384)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("EC01498288516FC926459F58E2C6AD8DF9B473CB0FC08C2596DA7CF0E49BE4B298D88CEA927AC7F539F1EDF228376D25")
<< QByteArray::fromHex("34FA93E11E467D610524EC91CEDC848EE1395BCF8F4F987455478E63DB0BCE47194D33D1251A3CC32BBB18D8726040D0");
QTest::newRow("sha3_512_abc_abc")
<< int(QCryptographicHash::Sha3_512)
<< QByteArray("abc") << QByteArray("abc")
<< QByteArray::fromHex("B751850B1A57168A5693CD924B6B096E08F621827444F70D884F5D0240D2712E10E116E9192AF3C91A7EC57647E3934057340B4CF408D5A56592F8274EEC53F0")
<< QByteArray::fromHex("BB582DA40D15399ACF62AFCBBD6CFC9EE1DD5129B1EF9935DD3B21668F1A73D7841018BE3B13F281C3A8E9DA7EDB60F57B9F9F1C04033DF4CE3654B7B2ADB310");
}
void tst_QCryptographicHash::intermediary_result()
{
QFETCH(int, algo);
QCryptographicHash::Algorithm _algo = QCryptographicHash::Algorithm(algo);
QCryptographicHash hash(_algo);
QFETCH(QByteArray, first);
hash.addData(first);
QFETCH(QByteArray, hash_first);
QCOMPARE(hash.resultView(), hash_first);
// don't reset
QFETCH(QByteArray, second);
QFETCH(QByteArray, hash_firstsecond);
hash.addData(second);
QCOMPARE(hash.resultView(), hash_firstsecond);
hash.reset();
}
void tst_QCryptographicHash::sha1()
{
// SHA1("abc") =
// A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
QCOMPARE(QCryptographicHash::hash("abc", QCryptographicHash::Sha1).toHex().toUpper(),
QByteArray("A9993E364706816ABA3E25717850C26C9CD0D89D"));
// SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
// 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
QCOMPARE(QCryptographicHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
QCryptographicHash::Sha1).toHex().toUpper(),
QByteArray("84983E441C3BD26EBAAE4AA1F95129E5E54670F1"));
// SHA1(A million repetitions of "a") =
// 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
QCOMPARE(QCryptographicHash::hash(QByteArray(1'000'000, 'a'), QCryptographicHash::Sha1).toHex().toUpper(),
QByteArray("34AA973CD4C4DAA4F61EEB2BDBAD27316534016F"));
}
void tst_QCryptographicHash::sha3_data()
{
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
QTest::addColumn<QByteArray>("data");
QTest::addColumn<QByteArray>("expectedResult");
#define ROW(Tag, Algorithm, Input, Result) \
QTest::newRow(Tag) << Algorithm << QByteArrayLiteral(Input) << QByteArray::fromHex(Result)
ROW("sha3_224_pangram",
QCryptographicHash::Sha3_224,
"The quick brown fox jumps over the lazy dog",
"d15dadceaa4d5d7bb3b48f446421d542e08ad8887305e28d58335795");
ROW("sha3_224_pangram_dot",
QCryptographicHash::Sha3_224,
"The quick brown fox jumps over the lazy dog.",
"2d0708903833afabdd232a20201176e8b58c5be8a6fe74265ac54db0");
ROW("sha3_256_pangram",
QCryptographicHash::Sha3_256,
"The quick brown fox jumps over the lazy dog",
"69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04");
ROW("sha3_256_pangram_dot",
QCryptographicHash::Sha3_256,
"The quick brown fox jumps over the lazy dog.",
"a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d");
ROW("sha3_384_pangram",
QCryptographicHash::Sha3_384,
"The quick brown fox jumps over the lazy dog",
"7063465e08a93bce31cd89d2e3ca8f602498696e253592ed26f07bf7e703cf328581e1471a7ba7ab119b1a9ebdf8be41");
ROW("sha3_384_pangram_dot",
QCryptographicHash::Sha3_384,
"The quick brown fox jumps over the lazy dog.",
"1a34d81695b622df178bc74df7124fe12fac0f64ba5250b78b99c1273d4b080168e10652894ecad5f1f4d5b965437fb9");
ROW("sha3_512_pangram",
QCryptographicHash::Sha3_512,
"The quick brown fox jumps over the lazy dog",
"01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450");
ROW("sha3_512_pangram_dot",
QCryptographicHash::Sha3_512,
"The quick brown fox jumps over the lazy dog.",
"18f4f4bd419603f95538837003d9d254c26c23765565162247483f65c50303597bc9ce4d289f21d1c2f1f458828e33dc442100331b35e7eb031b5d38ba6460f8");
#undef ROW
}
void tst_QCryptographicHash::sha3()
{
QFETCH(QCryptographicHash::Algorithm, algorithm);
QFETCH(QByteArray, data);
QFETCH(QByteArray, expectedResult);
const auto result = QCryptographicHash::hash(data, algorithm);
QCOMPARE(result, expectedResult);
}
void tst_QCryptographicHash::blake2_data()
{
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
QTest::addColumn<QByteArray>("data");
QTest::addColumn<QByteArray>("expectedResult");
#define ROW(Tag, Algorithm, Input, Result) \
QTest::newRow(Tag) << Algorithm << QByteArrayLiteral(Input) << QByteArray::fromHex(Result)
// BLAKE2b
ROW("blake2b_160_pangram",
QCryptographicHash::Blake2b_160,
"The quick brown fox jumps over the lazy dog",
"3c523ed102ab45a37d54f5610d5a983162fde84f");
ROW("blake2b_160_pangram_dot",
QCryptographicHash::Blake2b_160,
"The quick brown fox jumps over the lazy dog.",
"d0c8bb0bdd830296d1d4f4348176699ccccc16bb");
ROW("blake2b_256_pangram",
QCryptographicHash::Blake2b_256,
"The quick brown fox jumps over the lazy dog",
"01718cec35cd3d796dd00020e0bfecb473ad23457d063b75eff29c0ffa2e58a9");
ROW("blake2b_256_pangram_dot",
QCryptographicHash::Blake2b_256,
"The quick brown fox jumps over the lazy dog.",
"69d7d3b0afba81826d27024c17f7f183659ed0812cf27b382eaef9fdc29b5712");
ROW("blake2b_384_pangram",
QCryptographicHash::Blake2b_384,
"The quick brown fox jumps over the lazy dog",
"b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d");
ROW("blake2b_384_pangram_dot",
QCryptographicHash::Blake2b_384,
"The quick brown fox jumps over the lazy dog.",
"16d65de1a3caf1c26247234c39af636284c7e19ca448c0de788272081410778852c94d9cef6b939968d4f872c7f78337");
ROW("blake2b_512_pangram",
QCryptographicHash::Blake2b_512,
"The quick brown fox jumps over the lazy dog",
"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918");
ROW("blake2b_512_pangram_dot",
QCryptographicHash::Blake2b_512,
"The quick brown fox jumps over the lazy dog.",
"87af9dc4afe5651b7aa89124b905fd214bf17c79af58610db86a0fb1e0194622a4e9d8e395b352223a8183b0d421c0994b98286cbf8c68a495902e0fe6e2bda2");
// BLAKE2s
ROW("blake2s_128_pangram",
QCryptographicHash::Blake2s_128,
"The quick brown fox jumps over the lazy dog",
"96fd07258925748a0d2fb1c8a1167a73");
ROW("blake2s_128_pangram_dot",
QCryptographicHash::Blake2s_128,
"The quick brown fox jumps over the lazy dog.",
"1f298f2e1f9c2490e506c2308f64e7c0");
ROW("blake2s_160_pangram",
QCryptographicHash::Blake2s_160,
"The quick brown fox jumps over the lazy dog",
"5a604fec9713c369e84b0ed68daed7d7504ef240");
ROW("blake2s_160_pangram_dot",
QCryptographicHash::Blake2s_160,
"The quick brown fox jumps over the lazy dog.",
"cd4a863226463aac852662d16275d399966e3ffe");
ROW("blake2s_224_pangram",
QCryptographicHash::Blake2s_224,
"The quick brown fox jumps over the lazy dog",
"e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912");
ROW("blake2s_224_pangram_dot",
QCryptographicHash::Blake2s_224,
"The quick brown fox jumps over the lazy dog.",
"fd1557500ef49f308882969507acd18a13e155c26f8fcd82f9bf2ff7");
ROW("blake2s_256_pangram",
QCryptographicHash::Blake2s_256,
"The quick brown fox jumps over the lazy dog",
"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812");
ROW("blake2s_256_pangram_dot",
QCryptographicHash::Blake2s_256,
"The quick brown fox jumps over the lazy dog.",
"95bca6e1b761dca1323505cc629949a0e03edf11633cc7935bd8b56f393afcf2");
#undef ROW
}
void tst_QCryptographicHash::blake2()
{
QFETCH(QCryptographicHash::Algorithm, algorithm);
QFETCH(QByteArray, data);
QFETCH(QByteArray, expectedResult);
const auto result = QCryptographicHash::hash(data, algorithm);
QCOMPARE(result, expectedResult);
}
void tst_QCryptographicHash::files_data() {
QTest::addColumn<QString>("filename");
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
QTest::addColumn<QByteArray>("md5sum");
QTest::newRow("data1") << QString::fromLatin1("data/2c1517dad3678f03917f15849b052fd5.md5") << QCryptographicHash::Md5 << QByteArray("2c1517dad3678f03917f15849b052fd5");
QTest::newRow("data2") << QString::fromLatin1("data/d41d8cd98f00b204e9800998ecf8427e.md5") << QCryptographicHash::Md5 << QByteArray("d41d8cd98f00b204e9800998ecf8427e");
}
void tst_QCryptographicHash::files()
{
QFETCH(QString, filename);
QFETCH(QCryptographicHash::Algorithm, algorithm);
QFETCH(QByteArray, md5sum);
{
QString testData = QFINDTESTDATA(filename);
QVERIFY2(!testData.isEmpty(), qPrintable(QString("Cannot find test data: %1").arg(filename)));
QFile f(testData);
QCryptographicHash hash(algorithm);
QVERIFY(! hash.addData(&f)); // file is not open for reading;
if (f.open(QIODevice::ReadOnly)) {
QVERIFY(hash.addData(&f));
QCOMPARE(hash.result().toHex(),md5sum);
} else {
QFAIL("Failed to open file for testing. should not happen");
}
}
}
void tst_QCryptographicHash::hashLength_data()
{
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
auto metaEnum = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
for (int i = 0, value = metaEnum.value(i); value != -1; value = metaEnum.value(++i)) {
auto algorithm = QCryptographicHash::Algorithm(value);
QTest::addRow("%s", metaEnum.key(i)) << algorithm;
}
}
void tst_QCryptographicHash::hashLength()
{
QFETCH(const QCryptographicHash::Algorithm, algorithm);
qsizetype expectedSize;
if (algorithm == QCryptographicHash::NumAlgorithms) {
// It's UB to call ::hash() with NumAlgorithms, but hashLength() is
// fine and returns 0 for invalid values:
expectedSize = 0;
} else {
expectedSize = QCryptographicHash::hash("test", algorithm).size();
}
QCOMPARE(QCryptographicHash::hashLength(algorithm), expectedSize);
}
void tst_QCryptographicHash::addDataAcceptsNullByteArrayView()
{
QFETCH(const QCryptographicHash::Algorithm, algorithm);
if (!QCryptographicHash::supportsAlgorithm(algorithm))
QSKIP("QCryptographicHash doesn't support this algorithm");
QCryptographicHash hash1(algorithm);
hash1.addData("meep");
hash1.addData(QByteArrayView{}); // after other data
QCryptographicHash hash2(algorithm);
hash2.addData(QByteArrayView{}); // before any other data
hash2.addData("meep");
const auto expected = QCryptographicHash::hash("meep", algorithm);
QCOMPARE(hash1.resultView(), expected);
QCOMPARE(hash2.resultView(), expected);
}
void tst_QCryptographicHash::move()
{
QCryptographicHash hash1(QCryptographicHash::Sha1);
hash1.addData("a");
// move constructor
auto hash2(std::move(hash1));
hash2.addData("b");
// move assign operator
QCryptographicHash hash3(QCryptographicHash::Sha256);
hash3.addData("no effect on the end result");
hash3 = std::move(hash2);
hash3.addData("c");
QCOMPARE(hash3.resultView(), QByteArray::fromHex("A9993E364706816ABA3E25717850C26C9CD0D89D"));
}
void tst_QCryptographicHash::swap()
{
QCryptographicHash hash1(QCryptographicHash::Sha1);
QCryptographicHash hash2(QCryptographicHash::Sha256);
hash1.addData("da");
hash2.addData("te");
hash1.swap(hash2);
hash2.addData("ta");
hash1.addData("st");
QCOMPARE(hash2.result(), QCryptographicHash::hash("data", QCryptographicHash::Sha1));
QCOMPARE(hash1.result(), QCryptographicHash::hash("test", QCryptographicHash::Sha256));
}
void tst_QCryptographicHash::ensureLargeData()
{
#if QT_POINTER_SIZE > 4
QElapsedTimer timer;
timer.start();
const size_t GiB = 1024 * 1024 * 1024;
if (large.size() == 4 * GiB + 1)
return;
try {
large.resize(4 * GiB + 1, '\0');
} catch (const std::bad_alloc &) {
QSKIP("Could not allocate 4GiB plus one byte of RAM.");
}
QCOMPARE(large.size(), 4 * GiB + 1);
large.back() = '\1';
qDebug("created dataset in %lld ms", timer.elapsed());
#endif
}
void tst_QCryptographicHash::moreThan4GiBOfData_data()
{
#if QT_POINTER_SIZE > 4
if (ensureLargeData(); large.empty())
return;
QTest::addColumn<QCryptographicHash::Algorithm>("algorithm");
auto me = QMetaEnum::fromType<QCryptographicHash::Algorithm>();
auto row = [me] (QCryptographicHash::Algorithm algo) {
QTest::addRow("%s", me.valueToKey(int(algo))) << algo;
};
// these are reasonably fast (O(secs))
row(QCryptographicHash::Md4);
row(QCryptographicHash::Md5);
row(QCryptographicHash::Sha1);
if (!qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci")) {
// This is important but so slow (O(minute)) that, on CI, it tends to time out.
// Retain it for manual runs, all the same, as most dev machines will be fast enough.
row(QCryptographicHash::Sha512);
}
// the rest is just too slow
#else
QSKIP("This test is 64-bit only.");
#endif
}
void tst_QCryptographicHash::moreThan4GiBOfData()
{
QFETCH(const QCryptographicHash::Algorithm, algorithm);
# if QT_CONFIG(cxx11_future)
using MaybeThread = std::thread;
# else
struct MaybeThread {
std::function<void()> func;
void join() { func(); }
};
# endif
QElapsedTimer timer;
timer.start();
const auto sg = qScopeGuard([&] {
qDebug() << algorithm << "test finished in" << timer.restart() << "ms";
});
const auto view = QByteArrayView{large};
const auto first = view.first(view.size() / 2);
const auto last = view.sliced(view.size() / 2);
QByteArray single;
QByteArray chunked;
auto t = MaybeThread{[&] {
QCryptographicHash h(algorithm);
h.addData(view);
single = h.result();
}};
{
QCryptographicHash h(algorithm);
h.addData(first);
h.addData(last);
chunked = h.result();
}
t.join();
QCOMPARE(single, chunked);
}
void tst_QCryptographicHash::keccakBufferOverflow()
{
#if QT_POINTER_SIZE == 4
QSKIP("This is a 64-bit-only test");
#else
if (ensureLargeData(); large.empty())
return;
QElapsedTimer timer;
timer.start();
const auto sg = qScopeGuard([&] {
qDebug() << "test finished in" << timer.restart() << "ms";
});
constexpr qsizetype magic = INT_MAX/4;
QCOMPARE_GE(large.size(), size_t(magic + 1));
QCryptographicHash hash(QCryptographicHash::Algorithm::Keccak_224);
const auto first = QByteArrayView{large}.first(1);
const auto second = QByteArrayView{large}.sliced(1, magic);
hash.addData(first);
hash.addData(second);
(void)hash.resultView();
QVERIFY(true); // didn't crash
#endif
}
QTEST_MAIN(tst_QCryptographicHash)
#include "tst_qcryptographichash.moc"

View File

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

View File

@ -0,0 +1,207 @@
// 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 <QtTest/QtTest>
#include <QtCore/private/qduplicatetracker_p.h>
#include <QObject>
#include <utility>
class tst_QDuplicateTracker : public QObject
{
Q_OBJECT
private slots:
void hasSeen();
void clear();
void appendTo();
void appendTo_special();
};
void tst_QDuplicateTracker::hasSeen()
{
{
QDuplicateTracker<int, 2> tracker;
QVERIFY(!tracker.hasSeen(0));
QVERIFY(tracker.hasSeen(0));
QVERIFY(!tracker.hasSeen(1));
QVERIFY(tracker.hasSeen(1));
// past the prealloc amount
QVERIFY(!tracker.hasSeen(2));
QVERIFY(tracker.hasSeen(2));
}
{
QDuplicateTracker<QString, 2> tracker;
QString string1("string1");
QString string2("string2");
QString string2_2("string2");
QString string3("string3");
// Move when seen
QVERIFY(!tracker.hasSeen(string1));
QVERIFY(tracker.hasSeen(std::move(string1)));
// Move when unseen
QVERIFY(!tracker.hasSeen(std::move(string2)));
QVERIFY(tracker.hasSeen(string2_2));
// Past the prealloc amount
QVERIFY(!tracker.hasSeen(string3));
QVERIFY(tracker.hasSeen(string3));
}
}
void tst_QDuplicateTracker::clear()
{
QDuplicateTracker<int, 2> tracker;
QVERIFY(!tracker.hasSeen(0));
QVERIFY(tracker.hasSeen(0));
QVERIFY(!tracker.hasSeen(1));
QVERIFY(tracker.hasSeen(1));
tracker.clear();
QVERIFY(!tracker.hasSeen(0));
QVERIFY(tracker.hasSeen(0));
QVERIFY(!tracker.hasSeen(1));
QVERIFY(tracker.hasSeen(1));
}
void tst_QDuplicateTracker::appendTo()
{
QDuplicateTracker<int, 2> tracker;
QVERIFY(!tracker.hasSeen(0));
QVERIFY(!tracker.hasSeen(1));
QList<int> a;
a.append(-1);
tracker.appendTo(a);
std::sort(a.begin(), a.end());
QCOMPARE(a, QList<int>({ -1, 0, 1 }));
QList<int> b;
tracker.appendTo(b);
std::sort(b.begin(), b.end());
QCOMPARE(b, QList<int>({ 0, 1 }));
QVERIFY(!tracker.hasSeen(2));
QList<int> c;
std::move(tracker).appendTo(c);
std::sort(c.begin(), c.end());
QCOMPARE(c, QList<int>({ 0, 1, 2 }));
if (QDuplicateTracker<int, 2>::uses_pmr) {
// the following is only true if we use the std container
QVERIFY(!tracker.hasSeen(0));
QVERIFY(!tracker.hasSeen(1));
QVERIFY(!tracker.hasSeen(2));
}
}
struct ConstructionCounted
{
ConstructionCounted(int i) : i(i) { }
ConstructionCounted(ConstructionCounted &&other) noexcept
: i(other.i), copies(other.copies), moves(other.moves + 1)
{
// set to some easily noticeable values
other.i = -64;
other.copies = -64;
other.moves = -64;
}
ConstructionCounted &operator=(ConstructionCounted &&other) noexcept
{
ConstructionCounted moved = std::move(other);
swap(moved);
// set to some easily noticeable values
other.i = -64;
other.copies = -64;
other.moves = -64;
return *this;
}
ConstructionCounted(const ConstructionCounted &other) noexcept
: i(other.i), copies(other.copies + 1), moves(other.moves)
{
}
ConstructionCounted &operator=(const ConstructionCounted &other) noexcept
{
ConstructionCounted copy = other;
swap(copy);
return *this;
}
~ConstructionCounted() = default;
friend bool operator==(const ConstructionCounted &lhs, const ConstructionCounted &rhs)
{
return lhs.i == rhs.i;
}
QString toString() { return QString::number(i); }
void swap(ConstructionCounted &other)
{
std::swap(copies, other.copies);
std::swap(i, other.i);
std::swap(moves, other.moves);
}
int i;
int copies = 0;
int moves = 0;
};
// for std::unordered_set
namespace std {
template<>
struct hash<ConstructionCounted>
{
std::size_t operator()(const ConstructionCounted &c) const noexcept { return c.i; }
};
}
// for QSet
size_t qHash(const ConstructionCounted &c, std::size_t seed = 0)
{
return qHash(c.i, seed);
}
void tst_QDuplicateTracker::appendTo_special()
{
QDuplicateTracker<ConstructionCounted> tracker(3);
QVERIFY(!tracker.hasSeen(1));
QVERIFY(!tracker.hasSeen(2));
QVERIFY(!tracker.hasSeen(3));
QVERIFY(tracker.hasSeen(1));
QVERIFY(tracker.hasSeen(2));
QVERIFY(tracker.hasSeen(3));
{
QList<ConstructionCounted> a;
a.reserve(3);
tracker.appendTo(a);
for (const auto &counter : a) {
QCOMPARE(counter.moves, 1);
QCOMPARE(counter.copies, 1);
}
}
QVERIFY(tracker.hasSeen(1));
QVERIFY(tracker.hasSeen(2));
QVERIFY(tracker.hasSeen(3));
{
QList<ConstructionCounted> a;
a.reserve(3);
std::move(tracker).appendTo(a);
if (QDuplicateTracker<ConstructionCounted>::uses_pmr) {
// the following is only true if we use the std container
for (const auto &counter : a) {
QCOMPARE(counter.moves, 2);
QCOMPARE(counter.copies, 0);
}
QVERIFY(!tracker.hasSeen(1));
QVERIFY(!tracker.hasSeen(2));
QVERIFY(!tracker.hasSeen(3));
}
}
}
QTEST_MAIN(tst_QDuplicateTracker)
#include "tst_qduplicatetracker.moc"

View File

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

View File

@ -0,0 +1,897 @@
// 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 <qeasingcurve.h>
#include <utility> // for std::move()
class tst_QEasingCurve : public QObject
{
Q_OBJECT
private slots:
void type();
void propertyDefaults();
void valueForProgress_data();
void valueForProgress();
void setCustomType();
void operators();
void properties();
void metaTypes();
void propertyOrderIsNotImportant();
void bezierSpline_data();
void bezierSpline();
void tcbSpline_data();
void tcbSpline();
void testCbrtDouble();
void testCbrtFloat();
void cpp11();
void quadraticEquation();
void streamInOut_data();
void streamInOut();
};
void tst_QEasingCurve::type()
{
{
QEasingCurve curve(QEasingCurve::Linear);
QCOMPARE(curve.period(), 0.3);
QCOMPARE(curve.amplitude(), 1.0);
curve.setPeriod(5);
curve.setAmplitude(3);
QCOMPARE(curve.period(), 5.0);
QCOMPARE(curve.amplitude(), 3.0);
curve.setType(QEasingCurve::InElastic);
QCOMPARE(curve.period(), 5.0);
QCOMPARE(curve.amplitude(), 3.0);
}
{
QEasingCurve curve(QEasingCurve::InElastic);
QCOMPARE(curve.period(), 0.3);
QCOMPARE(curve.amplitude(), 1.0);
curve.setAmplitude(2);
QCOMPARE(curve.type(), QEasingCurve::InElastic);
curve.setType(QEasingCurve::Linear);
}
{
// check bounaries
QEasingCurve curve(QEasingCurve::InCubic);
QTest::ignoreMessage(QtWarningMsg, "QEasingCurve: Invalid curve type 9999");
curve.setType((QEasingCurve::Type)9999);
QCOMPARE(curve.type(), QEasingCurve::InCubic);
QTest::ignoreMessage(QtWarningMsg, "QEasingCurve: Invalid curve type -9999");
curve.setType((QEasingCurve::Type)-9999);
QCOMPARE(curve.type(), QEasingCurve::InCubic);
QTest::ignoreMessage(QtWarningMsg, QString::fromLatin1("QEasingCurve: Invalid curve type %1")
.arg(QEasingCurve::NCurveTypes).toLatin1().constData());
curve.setType(QEasingCurve::NCurveTypes);
QCOMPARE(curve.type(), QEasingCurve::InCubic);
QTest::ignoreMessage(QtWarningMsg, QString::fromLatin1("QEasingCurve: Invalid curve type %1")
.arg(QEasingCurve::Custom).toLatin1().constData());
curve.setType(QEasingCurve::Custom);
QCOMPARE(curve.type(), QEasingCurve::InCubic);
QTest::ignoreMessage(QtWarningMsg, QString::fromLatin1("QEasingCurve: Invalid curve type %1")
.arg(-1).toLatin1().constData());
curve.setType((QEasingCurve::Type)-1);
QCOMPARE(curve.type(), QEasingCurve::InCubic);
curve.setType(QEasingCurve::Linear);
QCOMPARE(curve.type(), QEasingCurve::Linear);
curve.setType(QEasingCurve::CosineCurve);
QCOMPARE(curve.type(), QEasingCurve::CosineCurve);
}
}
void tst_QEasingCurve::propertyDefaults()
{
{
// checks if the defaults are correct, but also demonstrates a weakness with the API.
QEasingCurve curve(QEasingCurve::InElastic);
QCOMPARE(curve.period(), 0.3);
QCOMPARE(curve.amplitude(), 1.0);
QCOMPARE(curve.overshoot(), qreal(1.70158));
curve.setType(QEasingCurve::InBounce);
QCOMPARE(curve.period(), 0.3);
QCOMPARE(curve.amplitude(), 1.0);
QCOMPARE(curve.overshoot(), qreal(1.70158));
curve.setType(QEasingCurve::Linear);
QCOMPARE(curve.period(), 0.3);
QCOMPARE(curve.amplitude(), 1.0);
QCOMPARE(curve.overshoot(), qreal(1.70158));
curve.setType(QEasingCurve::InElastic);
QCOMPARE(curve.period(), 0.3);
QCOMPARE(curve.amplitude(), 1.0);
QCOMPARE(curve.overshoot(), qreal(1.70158));
curve.setPeriod(0.4);
curve.setAmplitude(0.6);
curve.setOvershoot(1.0);
curve.setType(QEasingCurve::Linear);
QCOMPARE(curve.period(), 0.4);
QCOMPARE(curve.amplitude(), 0.6);
QCOMPARE(curve.overshoot(), 1.0);
curve.setType(QEasingCurve::InElastic);
QCOMPARE(curve.period(), 0.4);
QCOMPARE(curve.amplitude(), 0.6);
QCOMPARE(curve.overshoot(), 1.0);
}
}
typedef QList<int> IntList;
typedef QList<qreal> RealList;
void tst_QEasingCurve::valueForProgress_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<IntList>("at");
QTest::addColumn<RealList>("expected");
// automatically generated.
// note that values are scaled from range [0,1] to range [0, 100] in order to store them as
// integer values and avoid fp inaccuracies
QTest::newRow("Linear") << int(QEasingCurve::Linear)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1000 << 0.2000 << 0.3000 << 0.4000 << 0.5000 << 0.6000 << 0.7000 << 0.8000 << 0.9000 << 1.0000);
QTest::newRow("InQuad") << int(QEasingCurve::InQuad)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0100 << 0.0400 << 0.0900 << 0.1600 << 0.2500 << 0.3600 << 0.4900 << 0.6400 << 0.8100 << 1.0000);
QTest::newRow("OutQuad") << int(QEasingCurve::OutQuad)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1900 << 0.3600 << 0.5100 << 0.6400 << 0.7500 << 0.8400 << 0.9100 << 0.9600 << 0.9900 << 1.0000);
QTest::newRow("InOutQuad") << int(QEasingCurve::InOutQuad)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0200 << 0.0800 << 0.1800 << 0.3200 << 0.5000 << 0.6800 << 0.8200 << 0.9200 << 0.9800 << 1.0000);
QTest::newRow("OutInQuad") << int(QEasingCurve::OutInQuad)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1800 << 0.3200 << 0.4200 << 0.4800 << 0.5000 << 0.5200 << 0.5800 << 0.6800 << 0.8200 << 1.0000);
QTest::newRow("InCubic") << int(QEasingCurve::InCubic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0010 << 0.0080 << 0.0270 << 0.0640 << 0.1250 << 0.2160 << 0.3430 << 0.5120 << 0.7290 << 1.0000);
QTest::newRow("OutCubic") << int(QEasingCurve::OutCubic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.2710 << 0.4880 << 0.6570 << 0.7840 << 0.8750 << 0.9360 << 0.9730 << 0.9920 << 0.9990 << 1.0000);
QTest::newRow("InOutCubic") << int(QEasingCurve::InOutCubic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0040 << 0.0320 << 0.1080 << 0.2560 << 0.5000 << 0.7440 << 0.8920 << 0.9680 << 0.9960 << 1.0000);
QTest::newRow("OutInCubic") << int(QEasingCurve::OutInCubic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.2440 << 0.3920 << 0.4680 << 0.4960 << 0.5000 << 0.5040 << 0.5320 << 0.6080 << 0.7560 << 1.0000);
QTest::newRow("InQuart") << int(QEasingCurve::InQuart)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0001 << 0.0016 << 0.0081 << 0.0256 << 0.0625 << 0.1296 << 0.2401 << 0.4096 << 0.6561 << 1.0000);
QTest::newRow("OutQuart") << int(QEasingCurve::OutQuart)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.3439 << 0.5904 << 0.7599 << 0.8704 << 0.9375 << 0.9744 << 0.9919 << 0.9984 << 0.9999 << 1.0000);
QTest::newRow("InOutQuart") << int(QEasingCurve::InOutQuart)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0008 << 0.0128 << 0.0648 << 0.2048 << 0.5000 << 0.7952 << 0.9352 << 0.9872 << 0.9992 << 1.0000);
QTest::newRow("OutInQuart") << int(QEasingCurve::OutInQuart)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.2952 << 0.4352 << 0.4872 << 0.4992 << 0.5000 << 0.5008 << 0.5128 << 0.5648 << 0.7048 << 1.0000);
QTest::newRow("InQuint") << int(QEasingCurve::InQuint)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0000 << 0.0003 << 0.0024 << 0.0102 << 0.0313 << 0.0778 << 0.1681 << 0.3277 << 0.5905 << 1.0000);
QTest::newRow("OutQuint") << int(QEasingCurve::OutQuint)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.4095 << 0.6723 << 0.8319 << 0.9222 << 0.9688 << 0.9898 << 0.9976 << 0.9997 << 1.0000 << 1.0000);
QTest::newRow("InOutQuint") << int(QEasingCurve::InOutQuint)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0002 << 0.0051 << 0.0389 << 0.1638 << 0.5000 << 0.8362 << 0.9611 << 0.9949 << 0.9998 << 1.0000);
QTest::newRow("OutInQuint") << int(QEasingCurve::OutInQuint)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.3362 << 0.4611 << 0.4949 << 0.4998 << 0.5000 << 0.5002 << 0.5051 << 0.5389 << 0.6638 << 1.0000);
QTest::newRow("InSine") << int(QEasingCurve::InSine)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0123 << 0.0489 << 0.1090 << 0.1910 << 0.2929 << 0.4122 << 0.5460 << 0.6910 << 0.8436 << 1.0000);
QTest::newRow("OutSine") << int(QEasingCurve::OutSine)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1564 << 0.3090 << 0.4540 << 0.5878 << 0.7071 << 0.8090 << 0.8910 << 0.9511 << 0.9877 << 1.0000);
QTest::newRow("InOutSine") << int(QEasingCurve::InOutSine)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0245 << 0.0955 << 0.2061 << 0.3455 << 0.5000 << 0.6545 << 0.7939 << 0.9045 << 0.9755 << 1.0000);
QTest::newRow("OutInSine") << int(QEasingCurve::OutInSine)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1545 << 0.2939 << 0.4045 << 0.4755 << 0.5000 << 0.5245 << 0.5955 << 0.7061 << 0.8455 << 1.0000);
QTest::newRow("InExpo") << int(QEasingCurve::InExpo)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0010 << 0.0029 << 0.0068 << 0.0146 << 0.0303 << 0.0615 << 0.1240 << 0.2490 << 0.4990 << 1.0000);
QTest::newRow("OutExpo") << int(QEasingCurve::OutExpo)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.5005 << 0.7507 << 0.8759 << 0.9384 << 0.9697 << 0.9854 << 0.9932 << 0.9971 << 0.9990 << 1.0000);
QTest::newRow("InOutExpo") << int(QEasingCurve::InOutExpo)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0015 << 0.0073 << 0.0308 << 0.1245 << 0.5003 << 0.8754 << 0.9692 << 0.9927 << 0.9985 << 1.0000);
QTest::newRow("OutInExpo") << int(QEasingCurve::OutInExpo)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.3754 << 0.4692 << 0.4927 << 0.4985 << 0.5000 << 0.5015 << 0.5073 << 0.5308 << 0.6245 << 1.0000);
QTest::newRow("InCirc") << int(QEasingCurve::InCirc)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0050 << 0.0202 << 0.0461 << 0.0835 << 0.1340 << 0.2000 << 0.2859 << 0.4000 << 0.5641 << 1.0000);
QTest::newRow("OutCirc") << int(QEasingCurve::OutCirc)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.4359 << 0.6000 << 0.7141 << 0.8000 << 0.8660 << 0.9165 << 0.9539 << 0.9798 << 0.9950 << 1.0000);
QTest::newRow("InOutCirc") << int(QEasingCurve::InOutCirc)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0101 << 0.0417 << 0.1000 << 0.2000 << 0.5000 << 0.8000 << 0.9000 << 0.9583 << 0.9899 << 1.0000);
QTest::newRow("OutInCirc") << int(QEasingCurve::OutInCirc)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.3000 << 0.4000 << 0.4583 << 0.4899 << 0.5000 << 0.5101 << 0.5417 << 0.6000 << 0.7000 << 1.0000);
QTest::newRow("InElastic") << int(QEasingCurve::InElastic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0020 << -0.0020 << -0.0039 << 0.0156 << -0.0156 << -0.0313 << 0.1250 << -0.1250 << -0.2500 << 1.0000);
QTest::newRow("OutElastic") << int(QEasingCurve::OutElastic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 1.2500 << 1.1250 << 0.8750 << 1.0313 << 1.0156 << 0.9844 << 1.0039 << 1.0020 << 0.9980 << 1.0000);
QTest::newRow("InOutElastic") << int(QEasingCurve::InOutElastic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << -0.0010 << 0.0078 << -0.0156 << -0.0625 << 0.5000 << 1.0625 << 1.0156 << 0.9922 << 1.0010 << 1.0000);
QTest::newRow("OutInElastic") << int(QEasingCurve::OutInElastic)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.3750 << 0.5625 << 0.4922 << 0.4980 << 0.5000 << 0.4961 << 0.5078 << 0.5313 << 0.2500 << 1.0000);
QTest::newRow("InBack") << int(QEasingCurve::InBack)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << -0.0143 << -0.0465 << -0.0802 << -0.0994 << -0.0877 << -0.0290 << 0.0929 << 0.2942 << 0.5912 << 1.0000);
QTest::newRow("OutBack") << int(QEasingCurve::OutBack)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.4088 << 0.7058 << 0.9071 << 1.0290 << 1.0877 << 1.0994 << 1.0802 << 1.0465 << 1.0143 << 1.0000);
QTest::newRow("InOutBack") << int(QEasingCurve::InOutBack)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << -0.0375 << -0.0926 << -0.0788 << 0.0899 << 0.5000 << 0.9101 << 1.0788 << 1.0926 << 1.0375 << 1.0000);
QTest::newRow("OutInBack") << int(QEasingCurve::OutInBack)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.3529 << 0.5145 << 0.5497 << 0.5232 << 0.5000 << 0.4768 << 0.4503 << 0.4855 << 0.6471 << 1.0000);
QTest::newRow("InBounce") << int(QEasingCurve::InBounce)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0119 << 0.0600 << 0.0694 << 0.2275 << 0.2344 << 0.0900 << 0.3194 << 0.6975 << 0.9244 << 1.0000);
QTest::newRow("OutBounce") << int(QEasingCurve::OutBounce)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0756 << 0.3025 << 0.6806 << 0.9100 << 0.7656 << 0.7725 << 0.9306 << 0.9400 << 0.9881 << 1.0000);
QTest::newRow("InOutBounce") << int(QEasingCurve::InOutBounce)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0300 << 0.1138 << 0.0450 << 0.3488 << 0.5000 << 0.6512 << 0.9550 << 0.8863 << 0.9700 << 1.0000);
QTest::newRow("OutInBounce") << int(QEasingCurve::OutInBounce)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1513 << 0.4100 << 0.2725 << 0.4400 << 0.5000 << 0.5600 << 0.7275 << 0.5900 << 0.8488 << 1.0000);
QTest::newRow("InCurve") << int(QEasingCurve::InCurve)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0245 << 0.1059 << 0.2343 << 0.3727 << 0.5000 << 0.6055 << 0.7000 << 0.8000 << 0.9000 << 1.0000);
QTest::newRow("OutCurve") << int(QEasingCurve::OutCurve)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.1000 << 0.2000 << 0.3000 << 0.3945 << 0.5000 << 0.6273 << 0.7657 << 0.8941 << 0.9755 << 1.0000);
QTest::newRow("SineCurve") << int(QEasingCurve::SineCurve)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.0000 << 0.0955 << 0.3455 << 0.6545 << 0.9045 << 1.0000 << 0.9045 << 0.6545 << 0.3455 << 0.0955 << 0.0000);
QTest::newRow("CosineCurve") << int(QEasingCurve::CosineCurve)
<< (IntList() << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100)
<< (RealList() << 0.5000 << 0.7939 << 0.9755 << 0.9755 << 0.7939 << 0.5000 << 0.2061 << 0.0245 << 0.0245 << 0.2061 << 0.5000);
}
/*
"fixedpoint" number that is scaled up by 10000.
This is to work around two bugs (precision and rounding error) in QString::setNum().
It does not trim off trailing zeros. This is good, just to emphasize the precision.
*/
QString fixedToString(int value)
{
QString str;
if (value < 0) {
str+= QLatin1Char('-');
value = -value;
}
QString digitArg(QLatin1String("%1."));
for (int i = 10000; i >= 1; i/=10) {
int digit = value/i;
value -= digit*i;
str.append(digitArg.arg(digit));
digitArg = QLatin1String("%1");
}
return str;
}
void tst_QEasingCurve::valueForProgress()
{
#if 0
// used to generate data tables...
QFile out;
out.open(stdout, QIODevice::WriteOnly);
for (int c = QEasingCurve::Linear; c < QEasingCurve::NCurveTypes - 1; ++c) {
QEasingCurve curve((QEasingCurve::Type)c);
QMetaObject mo = QEasingCurve::staticMetaObject;
QString strCurve = QLatin1String(mo.enumerator(mo.indexOfEnumerator("Type")).key(c));
QString strInputs;
QString strOutputs;
for (int t = 0; t <= 100; t+= 10) {
qreal ease = curve.valueForProgress(t/qreal(100));
strInputs += QString::fromLatin1(" << %1").arg(t);
strOutputs += " << " + fixedToString(qRound(ease*10000));
}
QString str = QString::fromLatin1(" QTest::newRow(\"%1\") << int(QEasingCurve::%2)\n"
" << (IntList() %3)\n"
" << (RealList()%4);\n\n")
.arg(strCurve)
.arg(strCurve)
.arg(strInputs)
.arg(strOutputs);
out.write(str.toLatin1().constData());
}
out.close();
exit(1);
#else
QFETCH(int, type);
QFETCH(IntList, at);
QFETCH(RealList, expected);
QEasingCurve curve((QEasingCurve::Type)type);
// in theory the baseline should't have an error of more than 0.00005 due to how its rounded,
// but due to FP imprecision, we have to adjust the error a bit more.
const qreal errorBound = 0.00006;
for (int i = 0; i < at.size(); ++i) {
const qreal ex = expected.at(i);
const qreal error = qAbs(ex - curve.valueForProgress(at.at(i)/qreal(100)));
QVERIFY(error <= errorBound);
}
if (type != QEasingCurve::SineCurve && type != QEasingCurve::CosineCurve) {
QVERIFY( !(curve.valueForProgress(0) > 0) );
QVERIFY( !(curve.valueForProgress(1) < 1) );
}
#endif
}
static qreal discreteEase(qreal progress)
{
return qFloor(progress * 10) / qreal(10.0);
}
void tst_QEasingCurve::setCustomType()
{
QEasingCurve curve;
curve.setCustomType(&discreteEase);
QCOMPARE(curve.type(), QEasingCurve::Custom);
QCOMPARE(curve.valueForProgress(0.0), 0.0);
QCOMPARE(curve.valueForProgress(0.05), 0.0);
QCOMPARE(curve.valueForProgress(0.10), 0.1);
QCOMPARE(curve.valueForProgress(0.15), 0.1);
QCOMPARE(curve.valueForProgress(0.20), 0.2);
QCOMPARE(curve.valueForProgress(0.25), 0.2);
// QTBUG-69947, MinGW 7.3, 8.1 x86 returns 0.2
#if defined(Q_CC_MINGW)
#if !defined(__GNUC__) || defined(__MINGW64__)
QCOMPARE(curve.valueForProgress(0.30), 0.3);
#endif
#endif
QCOMPARE(curve.valueForProgress(0.35), 0.3);
QCOMPARE(curve.valueForProgress(0.999999), 0.9);
curve.setType(QEasingCurve::Linear);
QCOMPARE(curve.type(), QEasingCurve::Linear);
QCOMPARE(curve.valueForProgress(0.0), 0.0);
QCOMPARE(curve.valueForProgress(0.1), 0.1);
QCOMPARE(curve.valueForProgress(0.5), 0.5);
QCOMPARE(curve.valueForProgress(0.99), 0.99);
}
void tst_QEasingCurve::operators()
{
{ // member-swap()
QEasingCurve ec1, ec2;
ec2.setCustomType(&discreteEase);
ec1.swap(ec2);
QCOMPARE(ec1.type(), QEasingCurve::Custom);
}
// operator=
QEasingCurve curve;
QEasingCurve curve2;
curve.setCustomType(&discreteEase);
curve2 = curve;
QCOMPARE(curve2.type(), QEasingCurve::Custom);
QCOMPARE(curve2.valueForProgress(0.0), 0.0);
QCOMPARE(curve2.valueForProgress(0.05), 0.0);
QCOMPARE(curve2.valueForProgress(0.15), 0.1);
QCOMPARE(curve2.valueForProgress(0.25), 0.2);
QCOMPARE(curve2.valueForProgress(0.35), 0.3);
QCOMPARE(curve2.valueForProgress(0.999999), 0.9);
// operator==
curve.setType(QEasingCurve::InBack);
curve2 = curve;
curve2.setOvershoot(qreal(1.70158));
QCOMPARE(curve.overshoot(), curve2.overshoot());
QVERIFY(curve2 == curve);
curve.setOvershoot(3.0);
QVERIFY(curve2 != curve);
curve2.setOvershoot(3.0);
QVERIFY(curve2 == curve);
curve2.setType(QEasingCurve::Linear);
QCOMPARE(curve.overshoot(), curve2.overshoot());
QVERIFY(curve2 != curve);
curve2.setType(QEasingCurve::InBack);
QCOMPARE(curve.overshoot(), curve2.overshoot());
QVERIFY(curve2 == curve);
QEasingCurve curve3;
QEasingCurve curve4;
curve4.setAmplitude(curve4.amplitude());
QEasingCurve curve5;
curve5.setAmplitude(0.12345);
QVERIFY(curve3 == curve4); // default value and not assigned
QVERIFY(curve3 != curve5); // unassinged and other value
QVERIFY(curve4 != curve5);
}
class tst_QEasingProperties : public QObject
{
Q_OBJECT
Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing)
public:
tst_QEasingProperties(QObject *parent = nullptr) : QObject(parent) {}
QEasingCurve easing() const { return e; }
void setEasing(const QEasingCurve& value) { e = value; }
private:
QEasingCurve e;
};
// Test getting and setting easing properties via the metaobject system.
void tst_QEasingCurve::properties()
{
tst_QEasingProperties obj;
QEasingCurve inOutBack(QEasingCurve::InOutBack);
qreal overshoot = 1.5;
inOutBack.setOvershoot(overshoot);
qreal amplitude = inOutBack.amplitude();
qreal period = inOutBack.period();
obj.setEasing(inOutBack);
QEasingCurve easing = qvariant_cast<QEasingCurve>(obj.property("easing"));
QCOMPARE(easing.type(), QEasingCurve::InOutBack);
QCOMPARE(easing.overshoot(), overshoot);
QCOMPARE(easing.amplitude(), amplitude);
QCOMPARE(easing.period(), period);
QEasingCurve linear(QEasingCurve::Linear);
overshoot = linear.overshoot();
amplitude = linear.amplitude();
period = linear.period();
obj.setProperty("easing",
QVariant::fromValue(QEasingCurve(QEasingCurve::Linear)));
easing = qvariant_cast<QEasingCurve>(obj.property("easing"));
QCOMPARE(easing.type(), QEasingCurve::Linear);
QCOMPARE(easing.overshoot(), overshoot);
QCOMPARE(easing.amplitude(), amplitude);
QCOMPARE(easing.period(), period);
}
void tst_QEasingCurve::metaTypes()
{
QVERIFY(QMetaType::fromName("QEasingCurve").id() == QMetaType::QEasingCurve);
QCOMPARE(QByteArray(QMetaType(QMetaType::QEasingCurve).name()), QByteArray("QEasingCurve"));
QVERIFY(QMetaType::isRegistered(QMetaType::QEasingCurve));
QVERIFY(qMetaTypeId<QEasingCurve>() == QMetaType::QEasingCurve);
}
/*
Test to ensure that regardless of what order properties are set, they should produce the same
behavior.
*/
void tst_QEasingCurve::propertyOrderIsNotImportant()
{
QEasingCurve c1;
c1.setPeriod(1);
c1.setType(QEasingCurve::OutSine);
QVERIFY(c1.valueForProgress(0.75) > 0.9);
QEasingCurve c2;
c2.setType(QEasingCurve::OutSine);
c2.setPeriod(1);
QCOMPARE(c1.valueForProgress(0.75), c2.valueForProgress(0.75));
}
void tst_QEasingCurve::bezierSpline_data()
{
QTest::addColumn<QString>("definition");
QTest::addColumn<IntList>("at");
QTest::addColumn<RealList>("expected");
QTest::newRow("EasingCurve") << QString::fromLatin1("0.2,0 0.6,0.09 0.7,1.0 0.7,0.97 0.74,0.96 0.74,0.95 0.81,0.97 0.9,0.97 1,1")
<< (IntList() << 0 << 70 << 74 << 100)
<< (RealList() << 0.0000 << 1.0000 << 0.9500 << 1.0000);
//This curve is likely to be numerical instable
QTest::newRow("NastyCurve") << QString::fromLatin1("0.2,0.2 0.126667,0.646667 0.2,0.8 0.624,0.984 0.930667,0.946667 1,1")
<< (IntList() << 0 << 20 << 30 << 50 << 75 << 100)
<< (RealList() << 0.0000 << 0.8000 << 0.8402 << 0.9029 << 0.9515 << 1.0000);
QTest::newRow("ComplexCurve") << QString::fromLatin1("0,0.47174849 0.17393079,0.35634291 0.18950309,0.47179766 0.2487779,0.91126755 "
"0.27029205,-0.11275513 0.33421971,0.12062718 0.41170105,-0.10157488 0.4140625,0.16796875 "
"0.4140625,0.16796875 0.4140625,0.16796875 0.59658877,0.36978503 0.67931151,0.89255893 0.711253,0.44658283 "
"0.88203125,0.43671875 0.88203125,0.43671875 0.86087213,0.78786873 0.99609375,0.4921875 1,1")
<< (IntList() << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100)
<< (RealList() << 0.0000 << 0.4134 << 0.5367 << 0.1107 << 0.0505 << 0.7299 << 0.3030 << 0.4886 << 1.0000);
}
static inline void setupBezierSpline(QEasingCurve *easingCurve, const QString &string)
{
QStringList pointStr = string.split(QLatin1Char(' '));
QList<QPointF> points;
foreach (const QString &str, pointStr) {
QStringList coordStr = str.split(QLatin1Char(','));
QPointF point(coordStr.first().toDouble(), coordStr.last().toDouble());
points.append(point);
}
QVERIFY(points.size() % 3 == 0);
for (int i = 0; i < points.size() / 3; i++) {
QPointF c1 = points.at(i * 3);
QPointF c2 = points.at(i * 3 + 1);
QPointF p1 = points.at(i * 3 + 2);
easingCurve->addCubicBezierSegment(c1, c2, p1);
}
}
void tst_QEasingCurve::bezierSpline()
{
QFETCH(QString, definition);
QFETCH(IntList, at);
QFETCH(RealList, expected);
QEasingCurve bezierEasingCurve(QEasingCurve::BezierSpline);
setupBezierSpline(&bezierEasingCurve, definition);
const qreal errorBound = 0.002;
for (int i = 0; i < at.size(); ++i) {
const qreal ex = expected.at(i);
const qreal value = bezierEasingCurve.valueForProgress(at.at(i)/qreal(100));
const qreal error = qAbs(ex - value);
if (error > errorBound)
QCOMPARE(value, ex);
QVERIFY(error <= errorBound);
}
QVERIFY( !(bezierEasingCurve.valueForProgress(0) > 0) );
QVERIFY( !(bezierEasingCurve.valueForProgress(1) < 1) );
}
void tst_QEasingCurve::tcbSpline_data()
{
QTest::addColumn<QString>("definition");
QTest::addColumn<IntList>("at");
QTest::addColumn<RealList>("expected");
QTest::newRow("NegativeCurved") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.0,1,0.0 1.0,1.0,0.0,0.0,0")
<< (IntList() << 0 << 66 << 73 << 100)
<< (RealList() << 0.0000 << 0.9736 << 0.9774 << 1.0000);
//This curve is likely to be numerical instable
QTest::newRow("Corner") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.0,-1,0.0 1.0,1.0,0.0,0.0,0")
<< (IntList() << 0 << 20 << 30 << 50 << 75 << 100)
<< (RealList() << 0.0000 << 0.3999 << 0.5996 << 0.8334 << 0.9166 << 1.0000);
QTest::newRow("RoundCurve") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.0,0,0.0 1.0,1.0,0.0,0.0,0")
<< (IntList() << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100)
<< (RealList() << 0.0000 << 0.3478 << 0.4663 << 0.6664 << 0.8000 << 0.9399 << 0.8746 << 0.9567 << 1.0000);
QTest::newRow("Bias") << QString::fromLatin1("0.0,0.0,0,0,0 0.4,0.8,0.1,0,1.0 1.0,1.0,0.0,0.0,0")
<< (IntList() << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100)
<< (RealList() << 0.0000 << 0.2999 << 0.3998 << 0.5997 << 0.8000 << 0.9676 << 0.9136 << 0.9725 << 1.0000);
}
static inline void setupTCBSpline(QEasingCurve *easingCurve, const QString &string)
{
QStringList pointStr = string.split(QLatin1Char(' '));
foreach (const QString &str, pointStr) {
QStringList coordStr = str.split(QLatin1Char(','));
Q_ASSERT(coordStr.size() == 5);
QPointF point(coordStr.first().toDouble(), coordStr.at(1).toDouble());
qreal t = coordStr.at(2).toDouble();
qreal c = coordStr.at(3).toDouble();
qreal b = coordStr.at(4).toDouble();
easingCurve->addTCBSegment(point, t, c ,b);
}
}
void tst_QEasingCurve::tcbSpline()
{
QFETCH(QString, definition);
QFETCH(IntList, at);
QFETCH(RealList, expected);
QEasingCurve tcbEasingCurve(QEasingCurve::TCBSpline);
setupTCBSpline(&tcbEasingCurve, definition);
const qreal errorBound = 0.002;
for (int i = 0; i < at.size(); ++i) {
const qreal ex = expected.at(i);
const qreal value = tcbEasingCurve.valueForProgress(at.at(i)/qreal(100));
const qreal error = qAbs(ex - value);
if (error > errorBound)
QCOMPARE(value, ex);
QVERIFY(error <= errorBound);
}
QVERIFY( !(tcbEasingCurve.valueForProgress(0) > 0) );
QVERIFY( !(tcbEasingCurve.valueForProgress(1) < 1) );
}
/*This is single precision code for a cubic root used inside the spline easing curve.
This code is tested here explicitly. See: qeasingcurve.cpp */
float static inline _fast_cbrt(float x)
{
union {
float f;
quint32 i;
} ux;
const unsigned int B1 = 709921077;
ux.f = x;
ux.i = (ux.i / 3 + B1);
return ux.f;
}
/*This is double precision code for a cubic root used inside the spline easing curve.
This code is tested here explicitly. See: qeasingcurve.cpp */
double static inline _fast_cbrt(double d)
{
union {
double d;
quint32 pt[2];
} ut, ux;
const unsigned int B1 = 715094163;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
const int h0 = 1;
#else
const int h0 = 0;
#endif
ut.d = 0.0;
ux.d = d;
quint32 hx = ux.pt[h0]; //high word of d
ut.pt[h0] = hx/3 + B1;
return ut.d;
}
void tst_QEasingCurve::testCbrtDouble()
{
const double errorBound = 0.0001;
for (int i = 0; i < 100000; i++) {
double d = double(i) / 1000.0;
double t = _fast_cbrt(d);
const double t_cubic = t * t * t;
const double f = t_cubic + t_cubic + d;
if (f != 0.0)
t = t * (t_cubic + d + d) / f;
double expected = std::pow(d, 1.0/3.0);
const qreal error = qAbs(expected - t);
if (!(error < errorBound)) {
qWarning() << d;
qWarning() << error;
}
QVERIFY(error < errorBound);
}
}
void tst_QEasingCurve::testCbrtFloat()
{
const float errorBound = 0.0005f;
for (int i = 0; i < 100000; i++) {
float f = float(i) / 1000.0f;
float t = _fast_cbrt(f);
const float t_cubic = t * t * t;
const float fac = t_cubic + t_cubic + f;
if (fac != 0.0f)
t = t * (t_cubic + f + f) / fac;
float expected = std::pow(f, float(1.0/3.0));
const qreal error = qAbs(expected - t);
if (!(error < errorBound)) {
qWarning() << f;
qWarning() << error;
}
QVERIFY(error < errorBound);
}
}
void tst_QEasingCurve::cpp11()
{
{
QEasingCurve ec( QEasingCurve::InOutBack );
QEasingCurve copy = std::move(ec); // move ctor
QCOMPARE( copy.type(), QEasingCurve::InOutBack );
QVERIFY( *reinterpret_cast<void**>(&ec) == 0 );
}
{
QEasingCurve ec( QEasingCurve::InOutBack );
QEasingCurve copy;
const QEasingCurve::Type type = copy.type();
copy = std::move(ec); // move assignment op
QCOMPARE( copy.type(), QEasingCurve::InOutBack );
QCOMPARE( ec.type(), type );
}
}
void tst_QEasingCurve::quadraticEquation() {
// We find the value for a given time by solving a cubic equation.
// ax^3 + bx^2 + cx + d = 0
// However, the solver also needs to take care of cases where a = 0,
// b = 0 or c = 0, and the equation becomes quadratic, linear or invalid.
// A naive cubic solver might divide by zero and return nan, even
// when the solution is a real number.
// This test should triggers those cases.
{
// If the control points are spaced 1/3 apart of the distance of the
// start- and endpoint, the equation becomes linear.
QEasingCurve test(QEasingCurve::BezierSpline);
const qreal p1 = 1.0 / 3.0;
const qreal p2 = 1.0 - 1.0 / 3.0;
const qreal p3 = 1.0;
test.addCubicBezierSegment(QPointF(p1, 0.0), QPointF(p2, 1.0), QPointF(p3, 1.0));
QVERIFY(qAbs(test.valueForProgress(0.25) - 0.15625) < 1e-6);
QVERIFY(qAbs(test.valueForProgress(0.5) - 0.5) < 1e-6);
QVERIFY(qAbs(test.valueForProgress(0.75) - 0.84375) < 1e-6);
}
{
// If both the start point and the first control point
// are placed a 0.0, and the second control point is
// placed at 1/3, we get a case where a = 0 and b != 0
// i.e. a quadratic equation.
QEasingCurve test(QEasingCurve::BezierSpline);
const qreal p1 = 0.0;
const qreal p2 = 1.0 / 3.0;
const qreal p3 = 1.0;
test.addCubicBezierSegment(QPointF(p1, 0.0), QPointF(p2, 1.0), QPointF(p3, 1.0));
QVERIFY(qAbs(test.valueForProgress(0.25) - 0.5) < 1e-6);
QVERIFY(qAbs(test.valueForProgress(0.5) - 0.792893) < 1e-6);
QVERIFY(qAbs(test.valueForProgress(0.75) - 0.950962) < 1e-6);
}
{
// If both the start point and the first control point
// are placed a 0.0, and the second control point is
// placed close to 1/3, we get a case where a = ~0 and b != 0.
// It's not truly a quadratic equation, but should be treated
// as one, because it causes some cubic solvers to fail.
QEasingCurve test(QEasingCurve::BezierSpline);
const qreal p1 = 0.0;
const qreal p2 = 1.0 / 3.0 + 1e-6;
const qreal p3 = 1.0;
test.addCubicBezierSegment(QPointF(p1, 0.0), QPointF(p2, 1.0), QPointF(p3, 1.0));
QVERIFY(qAbs(test.valueForProgress(0.25) - 0.499999) < 1e-6);
QVERIFY(qAbs(test.valueForProgress(0.5) - 0.792892) < 1e-6);
QVERIFY(qAbs(test.valueForProgress(0.75) - 0.950961) < 1e-6);
}
{
// A bad case, where the segment is of zero length.
// However, it might still happen in user code,
// and we should return a sensible answer.
QEasingCurve test(QEasingCurve::BezierSpline);
const qreal p0 = 0.0;
const qreal p1 = p0;
const qreal p2 = p0;
const qreal p3 = p0;
test.addCubicBezierSegment(QPointF(p1, 0.0), QPointF(p2, 1.0), QPointF(p3, 1.0));
test.addCubicBezierSegment(QPointF(p3, 1.0), QPointF(1.0, 1.0), QPointF(1.0, 1.0));
QCOMPARE(test.valueForProgress(0.0), 0.0);
}
}
void tst_QEasingCurve::streamInOut_data()
{
QTest::addColumn<int>("version");
QTest::addColumn<bool>("equality");
QTest::newRow("5.11") << int(QDataStream::Qt_5_11) << false;
QTest::newRow("5.13") << int(QDataStream::Qt_5_13) << true;
}
void tst_QEasingCurve::streamInOut()
{
QFETCH(int, version);
QFETCH(bool, equality);
QEasingCurve orig;
orig.addCubicBezierSegment(QPointF(0.43, 0.0025), QPointF(0.38, 0.51), QPointF(0.57, 0.99));
QEasingCurve copy;
QByteArray data;
QDataStream dsw(&data,QIODevice::WriteOnly);
QDataStream dsr(&data,QIODevice::ReadOnly);
dsw.setVersion(version);
dsr.setVersion(version);
dsw << orig;
dsr >> copy;
QCOMPARE(copy == orig, equality);
}
QTEST_MAIN(tst_QEasingCurve)
#include "tst_qeasingcurve.moc"

View File

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

View File

@ -0,0 +1,226 @@
// 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 <QtCore/QSharedData>
/*!
\class tst_QExplicitlySharedDataPointer
\internal
\since 4.4
\brief Tests class QExplicitlySharedDataPointer.
*/
class tst_QExplicitlySharedDataPointer : public QObject
{
Q_OBJECT
private Q_SLOTS:
void pointerOperatorOnConst() const;
void pointerOperatorOnMutable() const;
void copyConstructor() const;
void clone() const;
void data() const;
void reset() const;
void swap() const;
};
class MyClass : public QSharedData
{
public:
void mutating()
{
}
void notMutating() const
{
}
MyClass &operator=(const MyClass &)
{
return *this;
}
};
class Base : public QSharedData
{
public:
virtual ~Base() { }
virtual Base *clone() { return new Base(*this); }
virtual bool isBase() const { return true; }
};
class Derived : public Base
{
public:
virtual Base *clone() override { return new Derived(*this); }
virtual bool isBase() const override { return false; }
};
QT_BEGIN_NAMESPACE
template<> Base *QExplicitlySharedDataPointer<Base>::clone()
{
return d->clone();
}
QT_END_NAMESPACE
void tst_QExplicitlySharedDataPointer::pointerOperatorOnConst() const
{
/* Pointer itself is const. */
{
const QExplicitlySharedDataPointer<const MyClass> pointer(new MyClass());
pointer->notMutating();
}
/* Pointer itself is mutable. */
{
QExplicitlySharedDataPointer<const MyClass> pointer(new MyClass());
pointer->notMutating();
}
}
void tst_QExplicitlySharedDataPointer::pointerOperatorOnMutable() const
{
/* Pointer itself is const. */
{
const QExplicitlySharedDataPointer<MyClass> pointer(new MyClass());
pointer->notMutating();
pointer->mutating();
*pointer = MyClass();
}
/* Pointer itself is mutable. */
{
const QExplicitlySharedDataPointer<MyClass> pointer(new MyClass());
pointer->notMutating();
pointer->mutating();
*pointer = MyClass();
}
}
void tst_QExplicitlySharedDataPointer::copyConstructor() const
{
const QExplicitlySharedDataPointer<const MyClass> pointer(new MyClass());
const QExplicitlySharedDataPointer<const MyClass> copy(pointer);
}
void tst_QExplicitlySharedDataPointer::clone() const
{
/* holding a base element */
{
QExplicitlySharedDataPointer<Base> pointer(new Base);
QVERIFY(pointer->isBase());
QExplicitlySharedDataPointer<Base> copy(pointer);
pointer.detach();
QVERIFY(pointer->isBase());
}
/* holding a derived element */
{
QExplicitlySharedDataPointer<Base> pointer(new Derived);
QVERIFY(!pointer->isBase());
QExplicitlySharedDataPointer<Base> copy(pointer);
pointer.detach();
QVERIFY(!pointer->isBase());
}
}
void tst_QExplicitlySharedDataPointer::data() const
{
/* Check default value. */
{
QExplicitlySharedDataPointer<const MyClass> pointer;
QCOMPARE(pointer.data(), static_cast<const MyClass *>(0));
QVERIFY(pointer == nullptr);
QVERIFY(nullptr == pointer);
}
/* On const pointer. Must not mutate the pointer. */
{
const QExplicitlySharedDataPointer<const MyClass> pointer(new MyClass());
pointer.data();
/* Check that this cast is possible. */
Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
QVERIFY(! (pointer == nullptr));
QVERIFY(! (nullptr == pointer));
}
/* On mutatable pointer. Must not mutate the pointer. */
{
QExplicitlySharedDataPointer<const MyClass> pointer(new MyClass());
pointer.data();
/* Check that this cast is possible. */
Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
}
/* Must not mutate the pointer. */
{
const QExplicitlySharedDataPointer<MyClass> pointer(new MyClass());
pointer.data();
/* Check that these casts are possible. */
Q_UNUSED(static_cast<MyClass *>(pointer.data()));
Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
}
/* Must not mutate the pointer. */
{
QExplicitlySharedDataPointer<MyClass> pointer(new MyClass());
pointer.data();
/* Check that these casts are possible. */
Q_UNUSED(static_cast<MyClass *>(pointer.data()));
Q_UNUSED(static_cast<const MyClass *>(pointer.data()));
}
}
void tst_QExplicitlySharedDataPointer::reset() const
{
/* Do reset on a single ref count. */
{
QExplicitlySharedDataPointer<MyClass> pointer(new MyClass());
QVERIFY(pointer.data() != 0);
pointer.reset();
QCOMPARE(pointer.data(), static_cast<MyClass *>(0));
}
/* Do reset on a default constructed object. */
{
QExplicitlySharedDataPointer<MyClass> pointer;
QCOMPARE(pointer.data(), static_cast<MyClass *>(0));
pointer.reset();
QCOMPARE(pointer.data(), static_cast<MyClass *>(0));
}
}
void tst_QExplicitlySharedDataPointer::swap() const
{
QExplicitlySharedDataPointer<MyClass> p1(0), p2(new MyClass());
QVERIFY(!p1.data());
QVERIFY(p2.data());
p1.swap(p2);
QVERIFY(p1.data());
QVERIFY(!p2.data());
p1.swap(p2);
QVERIFY(!p1.data());
QVERIFY(p2.data());
qSwap(p1, p2);
QVERIFY(p1.data());
QVERIFY(!p2.data());
}
QTEST_MAIN(tst_QExplicitlySharedDataPointer)
#include "tst_qexplicitlyshareddatapointer.moc"
// vim: et:ts=4:sw=4:sts=4

View File

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

View File

@ -0,0 +1,732 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#define QT_USE_QSTRINGBUILDER
#define QFLATMAP_ENABLE_STL_COMPATIBLE_INSERT
#include <QTest>
#include <private/qflatmap_p.h>
#include <qbytearray.h>
#include <qstring.h>
#include <qstringview.h>
#include <qvarlengtharray.h>
#include <algorithm>
#include <list>
#include <tuple>
static constexpr bool is_even(int n) { return n % 2 == 0; }
static constexpr bool is_empty(QAnyStringView v) { return v.isEmpty(); }
namespace {
template <typename P>
constexpr inline bool is_pair_impl_v = false;
template <typename T, typename S>
constexpr inline bool is_pair_impl_v<std::pair<T,S>> = true;
template <typename P>
constexpr inline bool is_pair_v = is_pair_impl_v<std::decay_t<P>>;
template <typename P>
using if_pair = std::enable_if_t<is_pair_v<P>, bool>;
}
class tst_QFlatMap : public QObject
{
Q_OBJECT
private slots:
void constructing();
void constAccess();
void insertion();
void insertRValuesAndLValues();
void removal();
void extraction();
void iterators();
void remove_if_pair() { remove_if_impl([](const auto &p) -> if_pair<decltype(p)> { return is_even(p.first) && is_empty(p.second); }); }
void remove_if_key_value() { remove_if_impl([](const auto &k, const auto &v) { return is_even(k) && is_empty(v); }); }
void remove_if_key() { remove_if_impl([](int k) { return is_even(k); }, true); }
void statefulComparator();
void transparency_using();
void transparency_struct();
void try_emplace_and_insert_or_assign();
void viewIterators();
void varLengthArray();
private:
template <typename Compare>
void transparency_impl();
template <typename Predicate>
void remove_if_impl(Predicate p, bool removeNonEmptyValues = false);
};
void tst_QFlatMap::constructing()
{
using Map = QFlatMap<int, QByteArray>;
Map fmDefault;
QVERIFY(fmDefault.isEmpty());
QCOMPARE(fmDefault.size(), Map::size_type(0));
QCOMPARE(fmDefault.size(), fmDefault.count());
auto key_compare = fmDefault.key_comp();
auto selfbuilt_value_compare
= [&key_compare](const Map::value_type &a, const Map::value_type &b)
{
return key_compare(a.first, b.first);
};
auto value_compare = fmDefault.value_comp();
Map::key_container_type kv = { 6, 2, 1 };
Map::mapped_container_type mv = { "foo", "bar", "baz" };
Map fmCopy{kv, mv};
QCOMPARE(fmCopy.size(), Map::size_type(3));
QVERIFY(std::is_sorted(fmCopy.begin(), fmCopy.end(), selfbuilt_value_compare));
QVERIFY(std::is_sorted(fmCopy.begin(), fmCopy.end(), value_compare));
Map fmMove{
Map::key_container_type{ 6, 2, 1 },
Map::mapped_container_type{ "foo", "bar", "baz" }
};
QCOMPARE(fmMove.size(), Map::size_type(3));
QVERIFY(std::is_sorted(fmMove.begin(), fmMove.end(), value_compare));
auto fmInitList = Map{ { 1, 2 }, { "foo", "bar" } };
QVERIFY(std::is_sorted(fmInitList.begin(), fmInitList.end(), value_compare));
auto fmRange = Map(fmCopy.begin(), fmCopy.end());
QVERIFY(std::is_sorted(fmRange.begin(), fmRange.end(), value_compare));
kv.clear();
mv.clear();
std::vector<Map::value_type> sv;
for (auto it = fmRange.begin(); it != fmRange.end(); ++it) {
kv.push_back(it->first);
mv.push_back(it->second);
sv.push_back(*it);
}
auto fmFromSortedVectorCopy = Map(Qt::OrderedUniqueRange, kv, mv);
auto fmFromSortedVectorMove = Map(Qt::OrderedUniqueRange, Map::key_container_type(kv),
Map::mapped_container_type(mv));
auto fmFromSortedInitList = Map(Qt::OrderedUniqueRange, { { 1, "foo" }, { 2, "bar" } });
auto fmFromSortedRange = Map(Qt::OrderedUniqueRange, sv.begin(), sv.end());
}
void tst_QFlatMap::constAccess()
{
using Map = QFlatMap<QByteArray, QByteArray>;
const Map m{ { { "foo", "FOO" }, { "bar", "BAR" } } };
const std::vector<Map::value_type> v{ { "foo", "FOO" }, { "bar", "BAR" } };
QCOMPARE(m.value("foo").data(), "FOO");
QCOMPARE(m.value("bar").data(), "BAR");
QCOMPARE(m.value("nix"), QByteArray());
QCOMPARE(m.value("nix", "NIX").data(), "NIX");
QCOMPARE(m["foo"].data(), "FOO");
QCOMPARE(m["bar"].data(), "BAR");
QCOMPARE(m["nix"], QByteArray());
QVERIFY(m.contains("foo"));
QVERIFY(!m.contains("nix"));
}
void tst_QFlatMap::insertion()
{
using Map = QFlatMap<QByteArray, QByteArray>;
Map m;
QByteArray foo = "foo";
m[foo] = foo.toUpper();
m["bar"] = "BAR";
m["baz"] = "BAZ";
QVERIFY(m.insert("oof", "eek").second);
QVERIFY(!m.insert("oof", "OOF").second);
const std::vector<Map::value_type> container = { { "bla", "BLA" }, { "blubb", "BLUBB" } };
m.insert(container.begin(), container.end());
QCOMPARE(m.value("foo").data(), "FOO");
QCOMPARE(m.value("bar").data(), "BAR");
QCOMPARE(m.value("baz").data(), "BAZ");
QCOMPARE(m.value("oof").data(), "eek");
QCOMPARE(m.value("bla").data(), "BLA");
QCOMPARE(m.value("blubb").data(), "BLUBB");
Map::value_type a1[] = { { "narf", "NARF" },
{ "zort", "ZORT" },
{ "troz", "TROZ" } };
Map::value_type a2[] = { { "gnampf", "GNAMPF" },
{ "narf", "NARFFFF" },
{ "narf", "NARFFFFF" },
{ "narf", "NARFFFFFF" } };
m.insert(std::begin(a1), std::end(a1));
m.insert(Qt::OrderedUniqueRange, std::begin(a2), std::end(a2));
QCOMPARE(m.size(), 10);
QCOMPARE(m.value("narf").data(), "NARF");
QCOMPARE(m.value("gnampf").data(), "GNAMPF");
}
void tst_QFlatMap::insertRValuesAndLValues()
{
using Map = QFlatMap<QByteArray, QByteArray>;
const QByteArray foo = QByteArrayLiteral("foo");
const QByteArray bar = QByteArrayLiteral("bar");
auto rvalue = [](const QByteArray &ba) { return ba; };
#define lvalue(x) x
{
Map m;
QVERIFY( m.insert(lvalue(foo), lvalue(bar)).second);
QVERIFY(!m.insert(lvalue(foo), lvalue(bar)).second);
}
{
Map m;
QVERIFY( m.insert(lvalue(foo), rvalue(bar)).second);
QVERIFY(!m.insert(lvalue(foo), rvalue(bar)).second);
}
{
Map m;
QVERIFY( m.insert(rvalue(foo), lvalue(bar)).second);
QVERIFY(!m.insert(rvalue(foo), lvalue(bar)).second);
}
{
Map m;
QVERIFY( m.insert(rvalue(foo), rvalue(bar)).second);
QVERIFY(!m.insert(rvalue(foo), rvalue(bar)).second);
}
#undef lvalue
}
void tst_QFlatMap::extraction()
{
using Map = QFlatMap<int, QByteArray>;
Map::key_container_type expectedKeys = { 1, 2, 3 };
Map::mapped_container_type expectedValues = { "een", "twee", "dree" };
Map m(Qt::OrderedUniqueRange, expectedKeys, expectedValues);
auto keys = m.keys();
auto values = m.values();
QCOMPARE(keys, expectedKeys);
QCOMPARE(values, expectedValues);
Map::containers c = std::move(m).extract();
QCOMPARE(c.keys, expectedKeys);
QCOMPARE(c.values, expectedValues);
}
void tst_QFlatMap::iterators()
{
using Map = QFlatMap<int, QByteArray>;
auto m = Map{ Qt::OrderedUniqueRange, { { 1, "foo" }, { 2, "bar" }, { 3, "baz" } } };
{
// forward / backward
Map::iterator a = m.begin();
QVERIFY(a != m.end());
QCOMPARE(a.key(), 1);
QCOMPARE(a.value(), "foo");
++a;
QCOMPARE(a.key(), 2);
QCOMPARE(a.value(), "bar");
Map::iterator b = a++;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(2, "bar"));
QCOMPARE(++a, m.end());
--a;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
a.value() = "buzz";
b = a--;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(3, "buzz"));
b.value() = "baz";
// random access
a = m.begin();
a += 2;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
a = m.begin() + 1;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
a = 1 + m.begin();
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
a = m.end() - 1;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
b = m.end();
b -= 1;
QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(3, "baz"));
QCOMPARE(m.end() - m.begin(), m.size());
// comparison
a = m.begin() + m.size() - 1;
b = m.end() - 1;
QVERIFY(a == b);
a = m.begin();
b = m.end();
QVERIFY(a < b);
QVERIFY(a <= b);
QVERIFY(b > a);
QVERIFY(b >= a);
a = b;
QVERIFY(!(a < b));
QVERIFY(a <= b);
QVERIFY(!(b > a));
QVERIFY(b >= a);
// de-referencing
a = m.begin();
auto ref0 = *a;
QCOMPARE(ref0.first, 1);
QCOMPARE(ref0.second, "foo");
auto ref1 = a[1];
QCOMPARE(ref1.first, 2);
QCOMPARE(ref1.second, "bar");
}
{
// forward / backward
Map::const_iterator a = m.cbegin();
QVERIFY(a != m.cend());
QCOMPARE(a.key(), 1);
QCOMPARE(a.value(), "foo");
++a;
QCOMPARE(a.key(), 2);
QCOMPARE(a.value(), "bar");
Map::const_iterator b = a++;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(2, "bar"));
QCOMPARE(++a, m.cend());
--a;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
b = a--;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
// random access
a = m.cbegin();
a += 2;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
a = m.cbegin() + 1;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
a = 1 + m.cbegin();
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(2, "bar"));
a = m.cend() - 1;
QCOMPARE(std::tie(a.key(), a.value()), std::make_tuple(3, "baz"));
b = m.cend();
b -= 1;
QCOMPARE(std::tie(b.key(), b.value()), std::make_tuple(3, "baz"));
QCOMPARE(m.cend() - m.cbegin(), m.size());
// comparison
a = m.cbegin() + m.size() - 1;
b = m.cend() - 1;
QVERIFY(a == b);
a = m.cbegin();
b = m.cend();
QVERIFY(a < b);
QVERIFY(a <= b);
QVERIFY(b > a);
QVERIFY(b >= a);
a = b;
QVERIFY(!(a < b));
QVERIFY(a <= b);
QVERIFY(!(b > a));
QVERIFY(b >= a);
// de-referencing
a = m.cbegin();
auto ref0 = *a;
QCOMPARE(ref0.first, 1);
QCOMPARE(ref0.second, "foo");
auto ref1 = a[1];
QCOMPARE(ref1.first, 2);
QCOMPARE(ref1.second, "bar");
}
{
Map::iterator it = m.begin();
Map::const_iterator cit = it;
Q_UNUSED(it);
Q_UNUSED(cit);
}
{
std::list<Map::value_type> revlst;
std::copy(m.begin(), m.end(), std::front_inserter(revlst));
std::vector<Map::value_type> v0;
std::copy(revlst.begin(), revlst.end(), std::back_inserter(v0));
std::vector<Map::value_type> v1;
std::copy(m.rbegin(), m.rend(), std::back_inserter(v1));
const Map cm = m;
std::vector<Map::value_type> v2;
std::copy(cm.rbegin(), cm.rend(), std::back_inserter(v2));
std::vector<Map::value_type> v3;
std::copy(m.crbegin(), m.crend(), std::back_inserter(v3));
QCOMPARE(v0, v1);
QCOMPARE(v1, v2);
QCOMPARE(v2, v3);
}
}
template <typename Pred>
void tst_QFlatMap::remove_if_impl(Pred p, bool removeNonEmptyValues)
{
// empty stays empty:
{
QFlatMap<int, QString> m;
QCOMPARE(m.remove_if(p), 0);
QVERIFY(m.isEmpty());
}
// a matching element is removed:
{
{
QFlatMap<int, QString> m;
m.insert_or_assign(0, "");
QCOMPARE(m.remove_if(p), 1);
QVERIFY(m.isEmpty());
}
if (removeNonEmptyValues) {
QFlatMap<int, QString> m;
m.insert_or_assign(0, "x");
QCOMPARE(m.remove_if(p), 1);
QVERIFY(m.isEmpty());
}
}
// a non-matching element is not removed:
{
{
QFlatMap<int, QString> m;
m.insert_or_assign(1, "");
QCOMPARE(m.remove_if(p), 0);
QVERIFY(m.contains(1));
QVERIFY(m[1].isEmpty());
}
if (removeNonEmptyValues) {
QFlatMap<int, QString> m;
m.insert_or_assign(1, "x");
QCOMPARE(m.remove_if(p), 0);
QVERIFY(m.contains(1));
QCOMPARE(m[1], "x");
}
}
// of matching and non-matching elements, only matching ones are removed:
{
{
QFlatMap<int, QString> m;
m.insert_or_assign(0, "");
m.insert_or_assign(1, "");
const auto copy = m;
QCOMPARE(m.remove_if(p), 1);
QCOMPARE(copy.size(), 2);
QCOMPARE(copy[0], "");
QCOMPARE(copy[1], "");
QCOMPARE(m.size(), 1);
QVERIFY(m.contains(1));
QVERIFY(m[1].isEmpty());
}
{
QFlatMap<int, QString> m;
m.insert_or_assign(1, "");
m.insert_or_assign(2, "");
QCOMPARE(m.remove_if(p), 1);
QCOMPARE(m.size(), 1);
QVERIFY(m.contains(1));
QVERIFY(m[1].isEmpty());
}
}
}
void tst_QFlatMap::removal()
{
using Map = QFlatMap<int, QByteArray>;
Map m({ { 2, "bar" }, { 3, "baz" }, { 1, "foo" } });
QCOMPARE(m.value(2).data(), "bar");
QCOMPARE(m.take(2).data(), "bar");
QVERIFY(!m.contains(2));
QCOMPARE(m.size(), Map::size_type(2));
QVERIFY(m.remove(1));
QVERIFY(!m.contains(1));
QVERIFY(!m.remove(1));
QCOMPARE(m.size(), Map::size_type(1));
m.clear();
QVERIFY(m.isEmpty());
QVERIFY(m.empty());
m[1] = "een";
m[2] = "twee";
m[3] = "dree";
auto it = m.lower_bound(1);
QCOMPARE(it.key(), 1);
it = m.erase(it);
QCOMPARE(it.key(), 2);
QVERIFY(!m.contains(1));
}
void tst_QFlatMap::statefulComparator()
{
struct CountingCompare {
mutable int count = 0;
bool operator()(const QString &lhs, const QString &rhs) const
{
++count;
return lhs < rhs;
}
};
using Map = QFlatMap<QString, QString, CountingCompare>;
auto m1 = Map{ { "en", "een"}, { "to", "twee" }, { "tre", "dree" } };
QVERIFY(m1.key_comp().count > 0);
auto m2 = Map(m1.key_comp());
QCOMPARE(m2.key_comp().count, m1.key_comp().count);
m2.insert(m1.begin(), m1.end());
QVERIFY(m2.key_comp().count > m1.key_comp().count);
}
void tst_QFlatMap::transparency_using()
{
struct StringViewCompare
{
using is_transparent [[maybe_unused]] = void;
bool operator()(QAnyStringView lhs, QAnyStringView rhs) const
{
return lhs < rhs;
}
};
transparency_impl<StringViewCompare>();
}
void tst_QFlatMap::transparency_struct()
{
struct StringViewCompare
{
struct is_transparent {};
bool operator()(QAnyStringView lhs, QAnyStringView rhs) const
{
return lhs < rhs;
}
};
transparency_impl<StringViewCompare>();
}
template <typename StringViewCompare>
void tst_QFlatMap::transparency_impl()
{
using Map = QFlatMap<QString, QString, StringViewCompare>;
auto m = Map{ { "one", "een" }, { "two", "twee" }, { "three", "dree" } };
const QString numbers = "one two three";
const QStringView sv1{numbers.constData(), 3};
const QStringView sv2{numbers.constData() + 4, 3};
const QStringView sv3{numbers.constData() + 8, 5};
QCOMPARE(m.lower_bound(sv1).value(), "een");
QCOMPARE(m.value(sv1), "een");
QCOMPARE(m.lower_bound(sv2).value(), "twee");
QCOMPARE(m.value(sv2), "twee");
QCOMPARE(m.lower_bound(sv3).value(), "dree");
QCOMPARE(m.value(sv3), "dree");
QVERIFY(m.contains(sv2));
auto twee = m.take(sv2);
static_assert(std::is_same_v<decltype(twee), QString>);
QCOMPARE(twee, "twee");
QVERIFY(!m.contains(sv2));
QVERIFY(m.contains(QLatin1String("one")));
QVERIFY(m.remove(QAnyStringView(u8"one")));
QVERIFY(!m.contains(QLatin1String("one")));
}
void tst_QFlatMap::try_emplace_and_insert_or_assign()
{
using Map = QFlatMap<QByteArray, QByteArray>;
const QByteArray foo = QByteArrayLiteral("foo");
const qsizetype qqq_1 = 3;
const char qqq_2 = 'q';
const QByteArray qqq = QByteArray(qqq_1, qqq_2);
auto sb = [] (const auto &str) { return str % ""; };
auto rvalue = [](const auto &x) { return x; };
#define lvalue(x) x
#define CHECKS() \
do { \
QVERIFY(!m.try_emplace(rvalue(foo), lvalue(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
QVERIFY(!m.try_emplace(lvalue(foo), lvalue(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
QVERIFY(!m.try_emplace(lvalue(foo), sb(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
QVERIFY(!m.try_emplace(rvalue(foo), sb(foo)).second); \
QCOMPARE(m.value(foo), qqq); \
} while (0) \
/* end */
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), lvalue(qqq)).second);
CHECKS();
QVERIFY(!m.insert_or_assign(lvalue(foo), lvalue(foo)).second);
QCOMPARE(m.value(foo), foo);
}
{
Map m;
QVERIFY(m.insert_or_assign(lvalue(foo), lvalue(qqq)).second);
CHECKS();
QVERIFY(!m.try_emplace(lvalue(foo), lvalue(foo)).second);
QCOMPARE(m.value(foo), qqq);
}
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), rvalue(qqq)).second);
CHECKS();
QVERIFY(!m.insert_or_assign(lvalue(foo), rvalue(foo)).second);
QCOMPARE(m.value(foo), foo);
}
{
Map m;
QVERIFY(m.insert_or_assign(lvalue(foo), rvalue(qqq)).second);
CHECKS();
QVERIFY(!m.try_emplace(lvalue(foo), rvalue(foo)).second);
QCOMPARE(m.value(foo), qqq);
}
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), qqq_1, qqq_2).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(lvalue(foo), sb(qqq)).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
QVERIFY(!m.insert_or_assign(lvalue(foo), sb(foo)).second);
QCOMPARE(m.value(foo), foo);
}
{
Map m;
QVERIFY(m.insert_or_assign(lvalue(foo), sb(qqq)).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
QVERIFY(!m.try_emplace(lvalue(foo), sb(foo)).second);
QCOMPARE(m.value(foo), qqq);
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), lvalue(qqq)).second);
CHECKS();
QVERIFY(!m.insert_or_assign(rvalue(foo), lvalue(foo)).second);
QCOMPARE(m.value(foo), foo);
}
{
Map m;
QVERIFY(m.insert_or_assign(rvalue(foo), lvalue(qqq)).second);
CHECKS();
QVERIFY(!m.try_emplace(rvalue(foo), lvalue(foo)).second);
QCOMPARE(m.value(foo), qqq);
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), rvalue(qqq)).second);
CHECKS();
QVERIFY(!m.insert_or_assign(rvalue(foo), rvalue(foo)).second);
QCOMPARE(m.value(foo), foo);
}
{
Map m;
QVERIFY(m.insert_or_assign(rvalue(foo), rvalue(qqq)).second);
CHECKS();
QVERIFY(!m.try_emplace(rvalue(foo), rvalue(foo)).second);
QCOMPARE(m.value(foo), qqq);
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), qqq_1, qqq_2).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
}
{
Map m;
QVERIFY(m.try_emplace(rvalue(foo), sb(qqq)).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
QVERIFY(!m.insert_or_assign(rvalue(foo), sb(foo)).second);
QCOMPARE(m.value(foo), foo);
}
{
Map m;
QVERIFY(m.insert_or_assign(rvalue(foo), sb(qqq)).second);
QCOMPARE(m.value(foo), qqq);
CHECKS();
QVERIFY(!m.try_emplace(rvalue(foo), sb(foo)).second);
QCOMPARE(m.value(foo), qqq);
}
#undef CHECKS
#undef lvalue
}
void tst_QFlatMap::viewIterators()
{
using Map = QFlatMap<QByteArray, QByteArray>;
Map m({ { "yksi", "een"}, { "kaksi", "twee" }, { "kolme", "dree" } });
{
std::vector<QByteArray> keys;
std::transform(m.begin(), m.end(), std::back_inserter(keys),
[](const Map::value_type &v)
{
return v.first;
});
auto it = keys.begin();
QCOMPARE(*it, "kaksi");
QCOMPARE(it->size(), 5);
++it;
QCOMPARE(*it, "kolme");
it++;
QCOMPARE(*it, "yksi");
++it;
QCOMPARE(it, keys.end());
--it;
QCOMPARE(*it, "yksi");
it--;
QCOMPARE(*it, "kolme");
}
{
std::vector<QByteArray> values;
std::transform(m.begin(), m.end(), std::back_inserter(values),
[](const Map::value_type &v)
{
return v.second;
});
auto it = values.begin();
QCOMPARE(*it, "twee");
QCOMPARE(it->size(), 4);
++it;
QCOMPARE(*it, "dree");
it++;
QCOMPARE(*it, "een");
++it;
QCOMPARE(it, values.end());
--it;
QCOMPARE(*it, "een");
it--;
QCOMPARE(*it, "dree");
}
}
void tst_QFlatMap::varLengthArray()
{
using Map = QVarLengthFlatMap<int, QByteArray, 1024>;
Map m(Qt::OrderedUniqueRange, { { 2, "twee" } });
m.insert_or_assign(1, "een");
m.remove(1);
QVERIFY(!m.isEmpty());
m.remove(2);
QVERIFY(m.isEmpty());
}
QTEST_APPLESS_MAIN(tst_QFlatMap)
#include "tst_qflatmap.moc"

View File

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

View File

@ -0,0 +1,138 @@
// 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 <QtCore/QCoreApplication>
#include <QtCore/QElapsedTimer>
#include <QtCore/QList>
#include <QtCore/QThread>
#include <private/qfreelist_p.h>
#include <QTest>
class tst_QFreeList : public QObject
{
Q_OBJECT
private slots:
void basicTest();
void customized();
void threadedTest();
};
void tst_QFreeList::basicTest()
{
{
QFreeList<void> voidFreeList;
int zero = voidFreeList.next();
int one = voidFreeList.next();
int two = voidFreeList.next();
QCOMPARE(zero, 0);
QCOMPARE(one, 1);
QCOMPARE(two, 2);
voidFreeList[zero];
voidFreeList[one];
voidFreeList[two];
voidFreeList.at(zero);
voidFreeList.at(one);
voidFreeList.at(two);
voidFreeList.release(one);
int next = voidFreeList.next();
QCOMPARE(next, 1);
voidFreeList[next];
voidFreeList.at(next);
}
{
QFreeList<int> intFreeList;
int zero = intFreeList.next();
int one = intFreeList.next();
int two = intFreeList.next();
QCOMPARE(zero, 0);
QCOMPARE(one, 1);
QCOMPARE(two, 2);
intFreeList[zero] = zero;
intFreeList[one] = one;
intFreeList[two] = two;
QCOMPARE(intFreeList.at(zero), zero);
QCOMPARE(intFreeList.at(one), one);
QCOMPARE(intFreeList.at(two), two);
intFreeList.release(one);
int next = intFreeList.next();
QCOMPARE(next, 1);
QCOMPARE(intFreeList.at(next), one);
intFreeList[next] = -one;
QCOMPARE(intFreeList.at(next), -one);
}
}
struct CustomFreeListConstants : public QFreeListDefaultConstants
{
enum {
InitialNextValue = 50,
BlockCount = 10
};
static const int Sizes[10];
};
const int CustomFreeListConstants::Sizes[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16777216 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 };
void tst_QFreeList::customized()
{
QFreeList<void, CustomFreeListConstants> customFreeList;
int next = customFreeList.next();
QCOMPARE(next, int(CustomFreeListConstants::InitialNextValue));
customFreeList[next];
customFreeList.at(next);
customFreeList.release(next);
}
enum { TimeLimit = 3000 };
class FreeListThread : public QThread
{
static QFreeList<void> freelist;
public:
inline FreeListThread() : QThread() { }
inline void run() override
{
QElapsedTimer t;
t.start();
QList<int> needToRelease;
do {
int i = freelist.next();
int j = freelist.next();
int k = freelist.next();
int l = freelist.next();
freelist.release(k);
int n = freelist.next();
int m = freelist.next();
freelist.release(l);
freelist.release(m);
freelist.release(n);
freelist.release(j);
// freelist.release(i);
needToRelease << i;
} while (t.elapsed() < TimeLimit);
foreach (int x, needToRelease)
freelist.release(x);
}
};
QFreeList<void> FreeListThread::freelist;
void tst_QFreeList::threadedTest()
{
const int ThreadCount = QThread::idealThreadCount();
FreeListThread *threads = new FreeListThread[ThreadCount];
for (int i = 0; i < ThreadCount; ++i)
threads[i].start();
for (int i = 0; i < ThreadCount; ++i)
threads[i].wait();
delete [] threads;
}
QTEST_MAIN(tst_QFreeList)
#include "tst_qfreelist.moc"

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,409 @@
// 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 <QVarLengthArray>
#include <qhash.h>
#include <iterator>
#include <sstream>
#include <algorithm>
#include <unordered_set>
class tst_QHashFunctions : public QObject
{
Q_OBJECT
public:
enum {
// random value
RandomSeed = 1045982819
};
uint seed;
template <typename T1, typename T2> void stdPair_template(const T1 &t1, const T2 &t2);
public slots:
void initTestCase();
void init();
private Q_SLOTS:
void consistent();
void qhash();
void qhash_of_empty_and_null_qstring();
void qhash_of_empty_and_null_qbytearray();
void qhash_of_zero_floating_points();
void qthash_data();
void qthash();
void range();
void rangeCommutative();
void stdHash();
void stdPair_int_int() { stdPair_template(1, 2); }
void stdPair_ulong_llong() { stdPair_template(1UL, -2LL); }
void stdPair_ullong_long() { stdPair_template(1ULL, -2L); }
void stdPair_string_int() { stdPair_template(QString("Hello"), 2); }
void stdPair_int_string() { stdPair_template(1, QString("Hello")); }
void stdPair_bytearray_string() { stdPair_template(QByteArray("Hello"), QString("World")); }
void stdPair_string_bytearray() { stdPair_template(QString("Hello"), QByteArray("World")); }
void stdPair_int_pairIntInt() { stdPair_template(1, std::make_pair(2, 3)); }
void stdPair_2x_pairIntInt() { stdPair_template(std::make_pair(1, 2), std::make_pair(2, 3)); }
void stdPair_string_pairIntInt() { stdPair_template(QString("Hello"), std::make_pair(42, -47)); } // QTBUG-92910
void stdPair_int_pairIntPairIntInt() { stdPair_template(1, std::make_pair(2, std::make_pair(3, 4))); }
void enum_int_consistent_hash_qtbug108032();
#if QT_DEPRECATED_SINCE(6, 6)
void setGlobalQHashSeed();
#endif
};
void tst_QHashFunctions::consistent()
{
// QString-like
const QString s = QStringLiteral("abcdefghijklmnopqrstuvxyz").repeated(16);
QCOMPARE(qHash(s), qHash(QStringView(s)));
}
void tst_QHashFunctions::initTestCase()
{
static_assert(int(RandomSeed) > 0);
QTest::addColumn<uint>("seedValue");
QTest::newRow("zero-seed") << 0U;
QTest::newRow("non-zero-seed") << uint(RandomSeed);
}
void tst_QHashFunctions::init()
{
QFETCH_GLOBAL(uint, seedValue);
seed = seedValue;
}
void tst_QHashFunctions::qhash()
{
{
QBitArray a1;
QBitArray a2;
a1.resize(1);
a1.setBit(0, true);
a2.resize(1);
a2.setBit(0, false);
size_t h1 = qHash(a1, seed);
size_t h2 = qHash(a2, seed);
QVERIFY(h1 != h2); // not guaranteed
a2.setBit(0, true);
QVERIFY(h1 == qHash(a2, seed));
a1.fill(true, 8);
a1.resize(7);
h1 = qHash(a1, seed);
a2.fill(true, 7);
h2 = qHash(a2, seed);
QVERIFY(h1 == h2);
a2.setBit(0, false);
size_t h3 = qHash(a2, seed);
QVERIFY(h2 != h3); // not guaranteed
a2.setBit(0, true);
QVERIFY(h2 == qHash(a2, seed));
a2.setBit(6, false);
size_t h4 = qHash(a2, seed);
QVERIFY(h2 != h4); // not guaranteed
a2.setBit(6, true);
QVERIFY(h2 == qHash(a2, seed));
QVERIFY(h3 != h4); // not guaranteed
}
{
QPair<int, int> p12(1, 2);
QPair<int, int> p21(2, 1);
QVERIFY(qHash(p12, seed) == qHash(p12, seed));
QVERIFY(qHash(p21, seed) == qHash(p21, seed));
QVERIFY(qHash(p12, seed) != qHash(p21, seed)); // not guaranteed
QPair<int, int> pA(0x12345678, 0x12345678);
QPair<int, int> pB(0x12345675, 0x12345675);
QVERIFY(qHash(pA, seed) != qHash(pB, seed)); // not guaranteed
}
{
std::pair<int, int> p12(1, 2);
std::pair<int, int> p21(2, 1);
using QT_PREPEND_NAMESPACE(qHash);
QVERIFY(qHash(p12, seed) == qHash(p12, seed));
QVERIFY(qHash(p21, seed) == qHash(p21, seed));
QVERIFY(qHash(p12, seed) != qHash(p21, seed)); // not guaranteed
std::pair<int, int> pA(0x12345678, 0x12345678);
std::pair<int, int> pB(0x12345675, 0x12345675);
QVERIFY(qHash(pA, seed) != qHash(pB, seed)); // not guaranteed
}
}
void tst_QHashFunctions::qhash_of_empty_and_null_qstring()
{
QString null, empty("");
QCOMPARE(null, empty);
QCOMPARE(qHash(null, seed), qHash(empty, seed));
QStringView nullView, emptyView(empty);
QCOMPARE(nullView, emptyView);
QCOMPARE(qHash(nullView, seed), qHash(emptyView, seed));
}
void tst_QHashFunctions::qhash_of_empty_and_null_qbytearray()
{
QByteArray null, empty("");
QCOMPARE(null, empty);
QCOMPARE(qHash(null, seed), qHash(empty, seed));
}
void tst_QHashFunctions::qhash_of_zero_floating_points()
{
QCOMPARE(qHash(-0.0f, seed), qHash(0.0f, seed));
QCOMPARE(qHash(-0.0 , seed), qHash(0.0 , seed));
#ifndef Q_OS_DARWIN
QCOMPARE(qHash(-0.0L, seed), qHash(0.0L, seed));
#endif
}
void tst_QHashFunctions::qthash_data()
{
QTest::addColumn<QString>("key");
QTest::addColumn<uint>("hash");
QTest::newRow("null") << QString() << 0u;
QTest::newRow("empty") << QStringLiteral("") << 0u;
QTest::newRow("abcdef") << QStringLiteral("abcdef") << 108567222u;
QTest::newRow("tqbfjotld") << QStringLiteral("The quick brown fox jumps over the lazy dog") << 140865879u;
QTest::newRow("42") << QStringLiteral("42") << 882u;
}
void tst_QHashFunctions::qthash()
{
QFETCH(QString, key);
const uint result = qt_hash(key);
QTEST(result, "hash");
}
namespace SomeNamespace {
struct Hashable { int i; };
inline size_t qHash(Hashable h, size_t seed = 0)
{ return QT_PREPEND_NAMESPACE(qHash)(h.i, seed); }
struct AdlHashable {
int i;
private:
friend size_t qHash(AdlHashable h, size_t seed = 0)
{ return QT_PREPEND_NAMESPACE(qHash)(h.i, seed); }
};
}
void tst_QHashFunctions::range()
{
static const int ints[] = {0, 1, 2, 3, 4, 5};
static const size_t numInts = sizeof ints / sizeof *ints;
// empty range just gives the seed:
QCOMPARE(qHashRange(ints, ints, seed), seed);
// verify that order matters (test not guaranteed):
QVERIFY(qHashRange(ints, ints + numInts, seed) !=
qHashRange(std::reverse_iterator<const int*>(ints + numInts), std::reverse_iterator<const int*>(ints), seed));
{
// verify that the input iterator category suffices:
std::stringstream sstream;
static_assert((std::is_same<std::input_iterator_tag, std::istream_iterator<int>::iterator_category>::value));
std::copy(ints, ints + numInts, std::ostream_iterator<int>(sstream, " "));
sstream.seekg(0);
std::istream_iterator<int> it(sstream), end;
QCOMPARE(qHashRange(ints, ints + numInts, seed), qHashRange(it, end, seed));
}
{
SomeNamespace::Hashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
// compile check: is qHash() found using ADL?
[[maybe_unused]] auto r = qHashRange(std::begin(hashables), std::end(hashables), seed);
}
{
SomeNamespace::AdlHashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
// compile check: is qHash() found as a hidden friend?
[[maybe_unused]] auto r = qHashRange(std::begin(hashables), std::end(hashables), seed);
}
}
void tst_QHashFunctions::rangeCommutative()
{
int ints[] = {0, 1, 2, 3, 4, 5};
static const size_t numInts = sizeof ints / sizeof *ints;
// empty range just gives the seed:
QCOMPARE(qHashRangeCommutative(ints, ints, seed), seed);
// verify that order doesn't matter (test not guaranteed):
QCOMPARE(qHashRangeCommutative(ints, ints + numInts, seed),
qHashRangeCommutative(std::reverse_iterator<int*>(ints + numInts), std::reverse_iterator<int*>(ints), seed));
{
// verify that the input iterator category suffices:
std::stringstream sstream;
std::copy(ints, ints + numInts, std::ostream_iterator<int>(sstream, " "));
sstream.seekg(0);
std::istream_iterator<int> it(sstream), end;
QCOMPARE(qHashRangeCommutative(ints, ints + numInts, seed), qHashRangeCommutative(it, end, seed));
}
{
SomeNamespace::Hashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
// compile check: is qHash() found using ADL?
[[maybe_unused]] auto r = qHashRangeCommutative(std::begin(hashables), std::end(hashables), seed);
}
{
SomeNamespace::AdlHashable hashables[] = {{0}, {1}, {2}, {3}, {4}, {5}};
// compile check: is qHash() found as a hidden friend?
[[maybe_unused]] auto r = qHashRangeCommutative(std::begin(hashables), std::end(hashables), seed);
}
}
// QVarLengthArray these days has a qHash() as a hidden friend.
// This checks that QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH can deal with that:
QT_BEGIN_NAMESPACE
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QVarLengthArray<QVector<int>>)
QT_END_NAMESPACE
void tst_QHashFunctions::stdHash()
{
{
std::unordered_set<QVarLengthArray<QVector<int>>> s = {
{
{0, 1, 2},
{42, 43, 44},
{},
}, {
{11, 12, 13},
{},
},
};
QCOMPARE(s.size(), 2UL);
s.insert({
{11, 12, 13},
{},
});
QCOMPARE(s.size(), 2UL);
}
{
std::unordered_set<QString> s = {QStringLiteral("Hello"), QStringLiteral("World")};
QCOMPARE(s.size(), 2UL);
s.insert(QStringLiteral("Hello"));
QCOMPARE(s.size(), 2UL);
}
{
std::unordered_set<QStringView> s = {QStringLiteral("Hello"), QStringLiteral("World")};
QCOMPARE(s.size(), 2UL);
s.insert(QStringLiteral("Hello"));
QCOMPARE(s.size(), 2UL);
}
{
std::unordered_set<QLatin1String> s = {QLatin1String("Hello"), QLatin1String("World")};
QCOMPARE(s.size(), 2UL);
s.insert(QLatin1String("Hello"));
QCOMPARE(s.size(), 2UL);
}
{
std::unordered_set<QByteArray> s = {QByteArrayLiteral("Hello"), QByteArrayLiteral("World")};
QCOMPARE(s.size(), 2UL);
s.insert(QByteArray("Hello"));
QCOMPARE(s.size(), 2UL);
}
{
std::unordered_set<QChar> s = {u'H', u'W'};
QCOMPARE(s.size(), 2UL);
s.insert(u'H');
QCOMPARE(s.size(), 2UL);
}
}
template <typename T1, typename T2>
void tst_QHashFunctions::stdPair_template(const T1 &t1, const T2 &t2)
{
std::pair<T1, T2> dpair{};
std::pair<T1, T2> vpair{t1, t2};
size_t seed = QHashSeed::globalSeed();
// confirm proper working of the pair and of the underlying types
QVERIFY(t1 == t1);
QVERIFY(t2 == t2);
QCOMPARE(qHash(t1), qHash(t1));
QCOMPARE(qHash(t2), qHash(t2));
QCOMPARE(qHash(t1, seed), qHash(t1, seed));
QCOMPARE(qHash(t2, seed), qHash(t2, seed));
QVERIFY(dpair == dpair);
QVERIFY(vpair == vpair);
// therefore their hashes should be equal
QCOMPARE(qHash(dpair), qHash(dpair));
QCOMPARE(qHash(dpair, seed), qHash(dpair, seed));
QCOMPARE(qHash(vpair), qHash(vpair));
QCOMPARE(qHash(vpair, seed), qHash(vpair, seed));
}
void tst_QHashFunctions::enum_int_consistent_hash_qtbug108032()
{
enum E { E1, E2, E3 };
static_assert(QHashPrivate::HasQHashSingleArgOverload<E>);
QCOMPARE(qHash(E1, seed), qHash(int(E1), seed));
QCOMPARE(qHash(E2, seed), qHash(int(E2), seed));
QCOMPARE(qHash(E3, seed), qHash(int(E3), seed));
}
#if QT_DEPRECATED_SINCE(6, 6)
void tst_QHashFunctions::setGlobalQHashSeed()
{
QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
// Setter works as advertised
qSetGlobalQHashSeed(0);
QCOMPARE(qGlobalQHashSeed(), 0);
// Creating a new QHash doesn't reset the seed
QHash<QString, int> someHash;
someHash.insert("foo", 42);
QCOMPARE(qGlobalQHashSeed(), 0);
// Reset works as advertised
qSetGlobalQHashSeed(-1);
QVERIFY(qGlobalQHashSeed() > 0);
QT_WARNING_POP
}
#endif // QT_DEPRECATED_SINCE(6, 6)
QTEST_APPLESS_MAIN(tst_QHashFunctions)
#include "tst_qhashfunctions.moc"

View File

@ -0,0 +1,17 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qhashseed Test:
#####################################################################
qt_internal_add_test(tst_qhashseed
SOURCES
tst_qhashseed.cpp
)
qt_internal_add_executable(tst_qhashseed_helper
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
SOURCES
tst_qhashseed_helper.cpp
)

View File

@ -0,0 +1,186 @@
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qhashfunctions.h>
#if QT_CONFIG(process)
#include <qprocess.h>
#endif
class tst_QHashSeed : public QObject
{
Q_OBJECT
public:
static void initMain();
private Q_SLOTS:
void initTestCase();
void environmentVariable_data();
void environmentVariable();
void deterministicSeed();
void reseeding();
void quality();
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
void compatibilityApi();
void deterministicSeed_compat();
#endif
};
void tst_QHashSeed::initMain()
{
qunsetenv("QT_HASH_SEED");
}
void tst_QHashSeed::initTestCase()
{
// in case the qunsetenv above didn't work
if (qEnvironmentVariableIsSet("QT_HASH_SEED"))
QSKIP("QT_HASH_SEED environment variable is set, please don't do that");
}
void tst_QHashSeed::environmentVariable_data()
{
#ifdef Q_OS_ANDROID
QSKIP("This test needs a helper binary, so is excluded from this platform.");
#endif
QTest::addColumn<QByteArray>("envVar");
QTest::addColumn<bool>("isZero");
QTest::newRow("unset-environment") << QByteArray() << false;
QTest::newRow("empty-environment") << QByteArray("") << false;
QTest::newRow("zero-seed") << QByteArray("0") << true;
}
void tst_QHashSeed::environmentVariable()
{
#if QT_CONFIG(process)
QFETCH(QByteArray, envVar);
QFETCH(bool, isZero);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
if (envVar.isNull())
env.remove("QT_HASH_SEED");
else
env.insert("QT_HASH_SEED", envVar);
QProcess helper;
helper.setProcessEnvironment(env);
helper.setProgram("./tst_qhashseed_helper");
helper.start();
QVERIFY2(helper.waitForStarted(5000), qPrintable(helper.errorString()));
QVERIFY2(helper.waitForFinished(5000), qPrintable(helper.errorString()));
QCOMPARE(helper.exitStatus(), 0);
QByteArray line1 = helper.readLine().trimmed();
QByteArray line2 = helper.readLine().trimmed();
QCOMPARE(line2, line1);
QCOMPARE(line1 == "0", isZero);
#endif
}
void tst_QHashSeed::deterministicSeed()
{
QHashSeed::setDeterministicGlobalSeed();
QCOMPARE(size_t(QHashSeed::globalSeed()), size_t(0));
// now reset
QHashSeed::resetRandomGlobalSeed();
QVERIFY(QHashSeed::globalSeed() != 0);
}
void tst_QHashSeed::reseeding()
{
constexpr int Iterations = 4;
size_t seeds[Iterations];
for (int i = 0; i < Iterations; ++i) {
seeds[i] = QHashSeed::globalSeed();
QHashSeed::resetRandomGlobalSeed();
}
// verify that they are all different
QString fmt = QStringLiteral("seeds[%1] = 0x%3, seeds[%2] = 0x%4");
for (int i = 0; i < Iterations; ++i) {
for (int j = i + 1; j < Iterations; ++j) {
QVERIFY2(seeds[i] != seeds[j],
qPrintable(fmt.arg(i).arg(j).arg(seeds[i], 16).arg(seeds[j], 16)));
}
}
}
void tst_QHashSeed::quality()
{
// this "bad seed" is used internally in qhash.cpp and should never leak!
constexpr size_t BadSeed = size_t(Q_UINT64_C(0x5555'5555'5555'5555));
constexpr int Iterations = 24; // nicely divisible by 3
int oneThird = 0;
int badSeeds = 0;
int seedsToMinus1 = 0;
size_t ored = 0;
for (int i = 0; i < Iterations; ++i) {
size_t seed = QHashSeed::globalSeed();
ored |= seed;
int bits = qPopulationCount(quintptr(seed));
QVERIFY2(bits > 0, QByteArray::number(bits)); // mandatory
if (bits >= std::numeric_limits<size_t>::digits / 3)
++oneThird;
if (seed == BadSeed)
++badSeeds;
if (ored != size_t(-1))
++seedsToMinus1;
QHashSeed::resetRandomGlobalSeed();
}
// report out
qInfo() << "Number of seeds until all bits became set:" << seedsToMinus1 << '/' << Iterations;
qInfo() << "Number of seeds with at least one third of the bits set:"
<< oneThird << '/' << Iterations;
// we must have set all bits after all the iterations
QCOMPARE(ored, size_t(-1));
// at least one third of the seeds must have one third of all the bits set
QVERIFY(oneThird > (Iterations/3));
// at most one seed can be the bad seed, if 32-bit, none on 64-bit
if (std::numeric_limits<size_t>::digits > 32)
QCOMPARE(badSeeds, 0);
else
QVERIFY2(badSeeds <= 1, "badSeeds = " + QByteArray::number(badSeeds));
// we must have taken at most two thirds of the iterations to have set each
// bit at least once
QVERIFY2(seedsToMinus1 < 2*Iterations/3,
"seedsToMinus1 = " + QByteArray::number(seedsToMinus1));
}
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
QT_WARNING_DISABLE_DEPRECATED
void tst_QHashSeed::compatibilityApi()
{
int oldSeed = qGlobalQHashSeed();
size_t newSeed = QHashSeed::globalSeed();
QCOMPARE(size_t(oldSeed), newSeed & size_t(INT_MAX));
}
void tst_QHashSeed::deterministicSeed_compat()
{
// same as above, but using the compat API
qSetGlobalQHashSeed(0);
QCOMPARE(size_t(QHashSeed::globalSeed()), size_t(0));
QCOMPARE(qGlobalQHashSeed(), 0);
// now reset
qSetGlobalQHashSeed(-1);
QVERIFY(QHashSeed::globalSeed() != 0);
QVERIFY(qGlobalQHashSeed() != 0);
QVERIFY(qGlobalQHashSeed() != -1); // possible, but extremely unlikely
}
#endif // Qt 7
QTEST_MAIN(tst_QHashSeed)
#include "tst_qhashseed.moc"

View File

@ -0,0 +1,14 @@
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qhashfunctions.h>
#include <stdio.h>
int main()
{
// appless:
QHashSeed seed1 = QHashSeed::globalSeed();
QHashSeed seed2 = QHashSeed::globalSeed();
printf("%zu\n%zu\n", size_t(seed1), size_t(seed2));
return 0;
}

View File

@ -0,0 +1,19 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qline Test:
#####################################################################
qt_internal_add_test(tst_qline
SOURCES
tst_qline.cpp
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qline CONDITION UNIX AND NOT APPLE AND NOT HAIKU AND NOT INTEGRITY AND NOT VXWORKS
LIBRARIES
m
)

View File

@ -0,0 +1,516 @@
// 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 <QTest>
#include <qline.h>
#include <qmath.h>
#include <array>
class tst_QLine : public QObject
{
Q_OBJECT
private slots:
void testIntersection();
void testIntersection_data();
void testLength();
void testLength_data();
void testCenter();
void testCenter_data();
void testCenterF();
void testCenterF_data();
void testNormalVector();
void testNormalVector_data();
void testAngle2();
void testAngle2_data();
void testAngle3();
void testAngleTo();
void testAngleTo_data();
void testSet();
void toLineF_data();
void toLineF();
};
const qreal epsilon = sizeof(qreal) == sizeof(double) ? 1e-8 : 1e-4;
void tst_QLine::testSet()
{
{
QLine l;
l.setP1(QPoint(1, 2));
l.setP2(QPoint(3, 4));
QCOMPARE(l.x1(), 1);
QCOMPARE(l.y1(), 2);
QCOMPARE(l.x2(), 3);
QCOMPARE(l.y2(), 4);
l.setPoints(QPoint(5, 6), QPoint(7, 8));
QCOMPARE(l.x1(), 5);
QCOMPARE(l.y1(), 6);
QCOMPARE(l.x2(), 7);
QCOMPARE(l.y2(), 8);
l.setLine(9, 10, 11, 12);
QCOMPARE(l.x1(), 9);
QCOMPARE(l.y1(), 10);
QCOMPARE(l.x2(), 11);
QCOMPARE(l.y2(), 12);
}
{
QLineF l;
l.setP1(QPointF(1, 2));
l.setP2(QPointF(3, 4));
QCOMPARE(l.x1(), 1.0);
QCOMPARE(l.y1(), 2.0);
QCOMPARE(l.x2(), 3.0);
QCOMPARE(l.y2(), 4.0);
l.setPoints(QPointF(5, 6), QPointF(7, 8));
QCOMPARE(l.x1(), 5.0);
QCOMPARE(l.y1(), 6.0);
QCOMPARE(l.x2(), 7.0);
QCOMPARE(l.y2(), 8.0);
l.setLine(9.0, 10.0, 11.0, 12.0);
QCOMPARE(l.x1(), 9.0);
QCOMPARE(l.y1(), 10.0);
QCOMPARE(l.x2(), 11.0);
QCOMPARE(l.y2(), 12.0);
}
}
void tst_QLine::testIntersection_data()
{
QTest::addColumn<double>("xa1");
QTest::addColumn<double>("ya1");
QTest::addColumn<double>("xa2");
QTest::addColumn<double>("ya2");
QTest::addColumn<double>("xb1");
QTest::addColumn<double>("yb1");
QTest::addColumn<double>("xb2");
QTest::addColumn<double>("yb2");
QTest::addColumn<int>("type");
QTest::addColumn<double>("ix");
QTest::addColumn<double>("iy");
QTest::newRow("parallel") << 1.0 << 1.0 << 3.0 << 4.0
<< 5.0 << 6.0 << 7.0 << 9.0
<< int(QLineF::NoIntersection) << 0.0 << 0.0;
QTest::newRow("unbounded") << 1.0 << 1.0 << 5.0 << 5.0
<< 0.0 << 4.0 << 3.0 << 4.0
<< int(QLineF::UnboundedIntersection) << 4.0 << 4.0;
QTest::newRow("bounded") << 1.0 << 1.0 << 5.0 << 5.0
<< 0.0 << 4.0 << 5.0 << 4.0
<< int(QLineF::BoundedIntersection) << 4.0 << 4.0;
QTest::newRow("almost vertical") << 0.0 << 10.0 << 20.0000000000001 << 10.0
<< 10.0 << 0.0 << 10.0 << 20.0
<< int(QLineF::BoundedIntersection) << 10.0 << 10.0;
QTest::newRow("almost horizontal") << 0.0 << 10.0 << 20.0 << 10.0
<< 10.0000000000001 << 0.0 << 10.0 << 20.0
<< int(QLineF::BoundedIntersection) << 10.0 << 10.0;
QTest::newRow("long vertical") << 100.1599256468623
<< 100.7861905065196
<< 100.1599256468604
<< -9999.78619050651
<< 10.0 << 50.0 << 190.0 << 50.0
<< int(QLineF::BoundedIntersection)
<< 100.1599256468622
<< 50.0;
for (int i = 0; i < 1000; ++i) {
QLineF a = QLineF::fromPolar(50, i);
a.setP1(-a.p2());
QLineF b = QLineF::fromPolar(50, i * 0.997 + 90);
b.setP1(-b.p2());
// make the qFuzzyCompare be a bit more lenient
a = a.translated(1, 1);
b = b.translated(1, 1);
QTest::newRow(("rotation-" + QByteArray::number(i)).constData())
<< (double)a.x1() << (double)a.y1() << (double)a.x2() << (double)a.y2()
<< (double)b.x1() << (double)b.y1() << (double)b.x2() << (double)b.y2()
<< int(QLineF::BoundedIntersection)
<< 1.0
<< 1.0;
}
}
void tst_QLine::testIntersection()
{
QFETCH(double, xa1);
QFETCH(double, ya1);
QFETCH(double, xa2);
QFETCH(double, ya2);
QFETCH(double, xb1);
QFETCH(double, yb1);
QFETCH(double, xb2);
QFETCH(double, yb2);
QFETCH(int, type);
QFETCH(double, ix);
QFETCH(double, iy);
QLineF a(xa1, ya1, xa2, ya2);
QLineF b(xb1, yb1, xb2, yb2);
QPointF ip;
QLineF::IntersectionType itype = a.intersects(b, &ip);
QCOMPARE(int(itype), type);
if (type != QLineF::NoIntersection) {
QVERIFY(qAbs(ip.x() - ix) < epsilon);
QVERIFY(qAbs(ip.y() - iy) < epsilon);
}
}
void tst_QLine::testLength_data()
{
QTest::addColumn<double>("x1");
QTest::addColumn<double>("y1");
QTest::addColumn<double>("x2");
QTest::addColumn<double>("y2");
QTest::addColumn<double>("length");
QTest::addColumn<double>("lengthToSet");
QTest::addColumn<double>("vx");
QTest::addColumn<double>("vy");
// Test name: [dx,dy]->|lenToSet| (x1,x2)
// with the last part omitted if (0,0)
QTest::newRow("[1,0]->|2|") << 0.0 << 0.0 << 1.0 << 0.0 << 1.0 << 2.0 << 2.0 << 0.0;
QTest::newRow("[0,1]->|2|") << 0.0 << 0.0 << 0.0 << 1.0 << 1.0 << 2.0 << 0.0 << 2.0;
QTest::newRow("[-1,0]->|2|") << 0.0 << 0.0 << -1.0 << 0.0 << 1.0 << 2.0 << -2.0 << 0.0;
QTest::newRow("[0,-1]->|2|") << 0.0 << 0.0 << 0.0 << -1.0 << 1.0 << 2.0 << 0.0 << -2.0;
QTest::newRow("[1,1]->->|1|") << 0.0 << 0.0 << 1.0 << 1.0
<< M_SQRT2 << 1.0 << M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[-1,1]->|1|") << 0.0 << 0.0 << -1.0 << 1.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[1,-1]->|1|") << 0.0 << 0.0 << 1.0 << -1.0
<< M_SQRT2 << 1.0 << M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[-1,-1]->|1|") << 0.0 << 0.0 << -1.0 << -1.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[1,0]->|2| (2,2)") << 2.0 << 2.0 << 3.0 << 2.0 << 1.0 << 2.0 << 2.0 << 0.0;
QTest::newRow("[0,1]->|2| (2,2)") << 2.0 << 2.0 << 2.0 << 3.0 << 1.0 << 2.0 << 0.0 << 2.0;
QTest::newRow("[-1,0]->|2| (2,2)") << 2.0 << 2.0 << 1.0 << 2.0 << 1.0 << 2.0 << -2.0 << 0.0;
QTest::newRow("[0,-1]->|2| (2,2)") << 2.0 << 2.0 << 2.0 << 1.0 << 1.0 << 2.0 << 0.0 << -2.0;
QTest::newRow("[1,1]->|1| (2,2)") << 2.0 << 2.0 << 3.0 << 3.0
<< M_SQRT2 << 1.0 << M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[-1,1]->|1| (2,2)") << 2.0 << 2.0 << 1.0 << 3.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[1,-1]->|1| (2,2)") << 2.0 << 2.0 << 3.0 << 1.0
<< M_SQRT2 << 1.0 << M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[-1,-1]->|1| (2,2)") << 2.0 << 2.0 << 1.0 << 1.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << -M_SQRT1_2;
const double small = qSqrt(std::numeric_limits<qreal>::denorm_min()) / 8;
QTest::newRow("[small,small]->|2| (-small/2,-small/2)")
<< -(small * .5) << -(small * .5) << (small * .5) << (small * .5)
<< (small * M_SQRT2) << (2 * M_SQRT2) << 2.0 << 2.0;
const double tiny = std::numeric_limits<qreal>::min() / 2;
QTest::newRow("[tiny,tiny]->|2| (-tiny/2,-tiny/2)")
<< -(tiny * .5) << -(tiny * .5) << (tiny * .5) << (tiny * .5)
<< (tiny * M_SQRT2) << (2 * M_SQRT2) << 2.0 << 2.0;
QTest::newRow("[1+3e-13,1+4e-13]|1895| (1, 1)")
<< 1.0 << 1.0 << (1 + 3e-13) << (1 + 4e-13)
<< 5e-13 << 1895.0 << 1137.0 << 1516.0;
QTest::newRow("[4e-323,5e-324]|1892|") // Unavoidable underflow: denormals
<< 0.0 << 0.0 << 4e-323 << 5e-324
<< 4e-323 << 1892.0 << 4e-323 << 5e-324; // vx, vy values ignored
}
void tst_QLine::testLength()
{
QFETCH(double, x1);
QFETCH(double, y1);
QFETCH(double, x2);
QFETCH(double, y2);
QFETCH(double, length);
QFETCH(double, lengthToSet);
QFETCH(double, vx);
QFETCH(double, vy);
QLineF l(x1, y1, x2, y2);
QCOMPARE(l.length(), qreal(length));
l.setLength(lengthToSet);
if constexpr (std::numeric_limits<double>::has_denorm != std::denorm_present) {
if (qstrcmp(QTest::currentDataTag(), "[tiny,tiny]->|2| (-tiny/2,-tiny/2)") == 0
|| qstrcmp(QTest::currentDataTag(), "[4e-323,5e-324]|1892|") == 0) {
QSKIP("Skipping 'denorm' as this type lacks denormals on this system");
}
}
// Scaling tiny values up to big can be imprecise: don't try to test vx, vy
if (length > 0 && qFuzzyIsNull(length)) {
QVERIFY(l.length() > lengthToSet / 2 && l.length() < lengthToSet * 2);
} else {
QCOMPARE(l.length(), length > 0 ? qreal(lengthToSet) : qreal(length));
QCOMPARE(l.dx(), qreal(vx));
QCOMPARE(l.dy(), qreal(vy));
}
}
void tst_QLine::testCenter()
{
QFETCH(int, x1);
QFETCH(int, y1);
QFETCH(int, x2);
QFETCH(int, y2);
QFETCH(int, centerX);
QFETCH(int, centerY);
const QPoint c = QLine(x1, y1, x2, y2).center();
QCOMPARE(centerX, c.x());
QCOMPARE(centerY, c.y());
}
void tst_QLine::testCenter_data()
{
QTest::addColumn<int>("x1");
QTest::addColumn<int>("y1");
QTest::addColumn<int>("x2");
QTest::addColumn<int>("y2");
QTest::addColumn<int>("centerX");
QTest::addColumn<int>("centerY");
QTest::newRow("[0, 0]") << 0 << 0 << 0 << 0 << 0 << 0;
QTest::newRow("top") << 0 << 0 << 2 << 0 << 1 << 0;
QTest::newRow("right") << 0 << 0 << 0 << 2 << 0 << 1;
QTest::newRow("bottom") << 0 << 0 << -2 << 0 << -1 << 0;
QTest::newRow("left") << 0 << 0 << 0 << -2 << 0 << -1;
QTest::newRow("precision+") << 0 << 0 << 1 << 1 << 0 << 0;
QTest::newRow("precision-") << -1 << -1 << 0 << 0 << 0 << 0;
const int max = std::numeric_limits<int>::max();
const int min = std::numeric_limits<int>::min();
QTest::newRow("max") << max << max << max << max << max << max;
QTest::newRow("min") << min << min << min << min << min << min;
QTest::newRow("minmax") << min << min << max << max << 0 << 0;
}
void tst_QLine::testCenterF()
{
QFETCH(double, x1);
QFETCH(double, y1);
QFETCH(double, x2);
QFETCH(double, y2);
QFETCH(double, centerX);
QFETCH(double, centerY);
const QPointF c = QLineF(x1, y1, x2, y2).center();
QCOMPARE(centerX, c.x());
QCOMPARE(centerY, c.y());
}
void tst_QLine::testCenterF_data()
{
QTest::addColumn<double>("x1");
QTest::addColumn<double>("y1");
QTest::addColumn<double>("x2");
QTest::addColumn<double>("y2");
QTest::addColumn<double>("centerX");
QTest::addColumn<double>("centerY");
QTest::newRow("[0, 0]") << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
QTest::newRow("top") << 0.0 << 0.0 << 1.0 << 0.0 << 0.5 << 0.0;
QTest::newRow("right") << 0.0 << 0.0 << 0.0 << 1.0 << 0.0 << 0.5;
QTest::newRow("bottom") << 0.0 << 0.0 << -1.0 << 0.0 << -0.5 << 0.0;
QTest::newRow("left") << 0.0 << 0.0 << 0.0 << -1.0 << 0.0 << -0.5;
const double max = std::numeric_limits<qreal>::max();
QTest::newRow("max") << max << max << max << max << max << max;
}
void tst_QLine::testNormalVector_data()
{
QTest::addColumn<double>("x1");
QTest::addColumn<double>("y1");
QTest::addColumn<double>("x2");
QTest::addColumn<double>("y2");
QTest::addColumn<double>("nvx");
QTest::addColumn<double>("nvy");
QTest::newRow("[1, 0]") << 0.0 << 0.0 << 1.0 << 0.0 << 0.0 << -1.0;
QTest::newRow("[-1, 0]") << 0.0 << 0.0 << -1.0 << 0.0 << 0.0 << 1.0;
QTest::newRow("[0, 1]") << 0.0 << 0.0 << 0.0 << 1.0 << 1.0 << 0.0;
QTest::newRow("[0, -1]") << 0.0 << 0.0 << 0.0 << -1.0 << -1.0 << 0.0;
QTest::newRow("[2, 3]") << 2.0 << 3.0 << 4.0 << 6.0 << 3.0 << -2.0;
}
void tst_QLine::testNormalVector()
{
QFETCH(double, x1);
QFETCH(double, y1);
QFETCH(double, x2);
QFETCH(double, y2);
QFETCH(double, nvx);
QFETCH(double, nvy);
QLineF l(x1, y1, x2, y2);
QLineF n = l.normalVector();
QCOMPARE(l.x1(), n.x1());
QCOMPARE(l.y1(), n.y1());
QCOMPARE(n.dx(), qreal(nvx));
QCOMPARE(n.dy(), qreal(nvy));
}
void tst_QLine::testAngle2_data()
{
QTest::addColumn<qreal>("x1");
QTest::addColumn<qreal>("y1");
QTest::addColumn<qreal>("x2");
QTest::addColumn<qreal>("y2");
QTest::addColumn<qreal>("angle");
QTest::newRow("right") << qreal(0.0) << qreal(0.0) << qreal(10.0) << qreal(0.0) << qreal(0.0);
QTest::newRow("left") << qreal(0.0) << qreal(0.0) << qreal(-10.0) << qreal(0.0) << qreal(180.0);
QTest::newRow("up") << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(-10.0) << qreal(90.0);
QTest::newRow("down") << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(10.0) << qreal(270.0);
QTest::newRow("diag a") << qreal(0.0) << qreal(0.0) << qreal(10.0) << qreal(-10.0) << qreal(45.0);
QTest::newRow("diag b") << qreal(0.0) << qreal(0.0) << qreal(-10.0) << qreal(-10.0) << qreal(135.0);
QTest::newRow("diag c") << qreal(0.0) << qreal(0.0) << qreal(-10.0) << qreal(10.0) << qreal(225.0);
QTest::newRow("diag d") << qreal(0.0) << qreal(0.0) << qreal(10.0) << qreal(10.0) << qreal(315.0);
}
void tst_QLine::testAngle2()
{
QFETCH(qreal, x1);
QFETCH(qreal, y1);
QFETCH(qreal, x2);
QFETCH(qreal, y2);
QFETCH(qreal, angle);
QLineF line(x1, y1, x2, y2);
QCOMPARE(line.angle(), angle);
QLineF polar = QLineF::fromPolar(line.length(), angle);
QVERIFY(qAbs(line.x1() - polar.x1()) < epsilon);
QVERIFY(qAbs(line.y1() - polar.y1()) < epsilon);
QVERIFY(qAbs(line.x2() - polar.x2()) < epsilon);
QVERIFY(qAbs(line.y2() - polar.y2()) < epsilon);
}
void tst_QLine::testAngle3()
{
for (int i = -720; i <= 720; ++i) {
QLineF line(0, 0, 100, 0);
line.setAngle(i);
const int expected = (i + 720) % 360;
QVERIFY2(qAbs(line.angle() - qreal(expected)) < epsilon, qPrintable(QString::fromLatin1("value: %1").arg(i)));
QCOMPARE(line.length(), qreal(100.0));
QCOMPARE(QLineF::fromPolar(100.0, i), line);
}
}
void tst_QLine::testAngleTo()
{
QFETCH(qreal, xa1);
QFETCH(qreal, ya1);
QFETCH(qreal, xa2);
QFETCH(qreal, ya2);
QFETCH(qreal, xb1);
QFETCH(qreal, yb1);
QFETCH(qreal, xb2);
QFETCH(qreal, yb2);
QFETCH(qreal, angle);
QLineF a(xa1, ya1, xa2, ya2);
QLineF b(xb1, yb1, xb2, yb2);
const qreal resultAngle = a.angleTo(b);
QVERIFY(qAbs(resultAngle - angle) < epsilon);
a.translate(b.p1() - a.p1());
a.setAngle(a.angle() + resultAngle);
a.setLength(b.length());
QCOMPARE(a, b);
}
void tst_QLine::testAngleTo_data()
{
QTest::addColumn<qreal>("xa1");
QTest::addColumn<qreal>("ya1");
QTest::addColumn<qreal>("xa2");
QTest::addColumn<qreal>("ya2");
QTest::addColumn<qreal>("xb1");
QTest::addColumn<qreal>("yb1");
QTest::addColumn<qreal>("xb2");
QTest::addColumn<qreal>("yb2");
QTest::addColumn<qreal>("angle");
QTest::newRow("parallel") << qreal(1.0) << qreal(1.0) << qreal(3.0) << qreal(4.0)
<< qreal(5.0) << qreal(6.0) << qreal(7.0) << qreal(9.0)
<< qreal(0.0);
QTest::newRow("[4,4]-[4,0]") << qreal(1.0) << qreal(1.0) << qreal(5.0) << qreal(5.0)
<< qreal(0.0) << qreal(4.0) << qreal(3.0) << qreal(4.0)
<< qreal(45.0);
QTest::newRow("[4,4]-[-4,0]") << qreal(1.0) << qreal(1.0) << qreal(5.0) << qreal(5.0)
<< qreal(3.0) << qreal(4.0) << qreal(0.0) << qreal(4.0)
<< qreal(225.0);
for (int i = 0; i < 360; ++i) {
const QLineF l = QLineF::fromPolar(1, i);
QTest::newRow(("angle:" + QByteArray::number(i)).constData())
<< qreal(0.0) << qreal(0.0) << qreal(1.0) << qreal(0.0)
<< qreal(0.0) << qreal(0.0) << l.p2().x() << l.p2().y()
<< qreal(i);
}
}
void tst_QLine::toLineF_data()
{
QTest::addColumn<QLine>("input");
QTest::addColumn<QLineF>("result");
auto row = [](int x1, int y1, int x2, int y2) {
QTest::addRow("((%d, %d)->(%d, %d))", x1, y1, x2, y2)
<< QLine(x1, y1, x2, y2) << QLineF(x1, y1, x2, y2);
};
constexpr std::array samples = {-1, 0, 1};
for (int x1 : samples) {
for (int y1 : samples) {
for (int x2 : samples) {
for (int y2 : samples) {
row(x1, y1, x2, y2);
}
}
}
}
}
void tst_QLine::toLineF()
{
QFETCH(const QLine, input);
QFETCH(const QLineF, result);
QCOMPARE(input.toLineF(), result);
}
QTEST_MAIN(tst_QLine)
#include "tst_qline.moc"

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qmacautoreleasepool Test:
#####################################################################
qt_internal_add_test(tst_qmacautoreleasepool
SOURCES
tst_qmacautoreleasepool.mm
LIBRARIES
Qt::CorePrivate
${FWFoundation}
)

View File

@ -0,0 +1,88 @@
// Copyright (C) 2017 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/private/qcore_mac_p.h>
#include <Foundation/Foundation.h>
class tst_QMacAutoreleasePool : public QObject
{
Q_OBJECT
private slots:
void noPool();
void rootLevelPool();
void stackAllocatedPool();
void heapAllocatedPool();
};
static id lastDeallocedObject = nil;
@interface DeallocTracker : NSObject @end
@implementation DeallocTracker
-(void)dealloc
{
lastDeallocedObject = self;
[super dealloc];
}
@end
void tst_QMacAutoreleasePool::noPool()
{
// No pool, will not be released, but should not crash
[[[DeallocTracker alloc] init] autorelease];
}
void tst_QMacAutoreleasePool::rootLevelPool()
{
// The root level case, no NSAutoreleasePool since we're not in the main
// runloop, and objects autoreleased as part of main.
NSObject *allocedObject = nil;
{
QMacAutoReleasePool qtPool;
allocedObject = [[[DeallocTracker alloc] init] autorelease];
}
QCOMPARE(lastDeallocedObject, allocedObject);
}
void tst_QMacAutoreleasePool::stackAllocatedPool()
{
// The normal case, other pools surrounding our pool, draining
// our pool before any other pool.
NSObject *allocedObject = nil;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{
QMacAutoReleasePool qtPool;
allocedObject = [[[DeallocTracker alloc] init] autorelease];
}
QCOMPARE(lastDeallocedObject, allocedObject);
[pool drain];
}
void tst_QMacAutoreleasePool::heapAllocatedPool()
{
// The special case, a pool allocated on the heap, or as a member of a
// heap allocated object. This is not a supported use of QMacAutoReleasePool,
// and will result in warnings if the pool is prematurely drained.
NSObject *allocedObject = nil;
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QMacAutoReleasePool *qtPool = nullptr;
{
qtPool = new QMacAutoReleasePool;
allocedObject = [[[DeallocTracker alloc] init] autorelease];
}
[pool drain];
delete qtPool;
}
QCOMPARE(lastDeallocedObject, allocedObject);
}
QTEST_APPLESS_MAIN(tst_QMacAutoreleasePool)
#include "tst_qmacautoreleasepool.moc"

View File

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

View File

@ -0,0 +1,78 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <private/qmakearray_p.h>
class tst_QMakeArray : public QObject
{
Q_OBJECT
private slots:
void quicksort();
};
struct Pair {
unsigned int key;
unsigned int val;
constexpr bool operator <=(const Pair &that) const noexcept
{
return key <= that.key;
}
constexpr bool operator<(const Pair &that) const noexcept
{
return key < that.key;
}
constexpr bool operator==(const Pair &that) const noexcept
{
return key == that.key;
}
};
template<std::size_t Key, std::size_t Val>
struct PairQuickSortElem
{
using Type = Pair;
static constexpr Type data() noexcept { return Type{Key, Val}; }
};
void tst_QMakeArray::quicksort()
{
constexpr const auto sorted_array = qMakeArray(
QSortedData<
PairQuickSortElem<10, 0>,
PairQuickSortElem<5, 0>,
PairQuickSortElem<7, 0>,
PairQuickSortElem<1, 0>,
PairQuickSortElem<8, 0>,
PairQuickSortElem<6, 0>,
PairQuickSortElem<4, 0>,
PairQuickSortElem<3, 0>,
PairQuickSortElem<1, 0>,
PairQuickSortElem<2, 0>,
PairQuickSortElem<10, 0>,
PairQuickSortElem<5, 0>
>::Data{});
static_assert(sorted_array.size() == 12, "sorted_array.size() != 12");
QCOMPARE(sorted_array[0].key, 1u);
QCOMPARE(sorted_array[1].key, 1u);
QCOMPARE(sorted_array[2].key, 2u);
QCOMPARE(sorted_array[3].key, 3u);
QCOMPARE(sorted_array[4].key, 4u);
QCOMPARE(sorted_array[5].key, 5u);
QCOMPARE(sorted_array[6].key, 5u);
QCOMPARE(sorted_array[7].key, 6u);
QCOMPARE(sorted_array[8].key, 7u);
QCOMPARE(sorted_array[9].key, 8u);
QCOMPARE(sorted_array[10].key, 10u);
QCOMPARE(sorted_array[11].key, 10u);
}
QTEST_APPLESS_MAIN(tst_QMakeArray)
#include "tst_qmakearray.moc"

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,352 @@
// 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 <QTest>
#include <qmargins.h>
#include <array>
Q_DECLARE_METATYPE(QMargins)
class tst_QMargins : public QObject
{
Q_OBJECT
private slots:
void getSetCheck();
#ifndef QT_NO_DATASTREAM
void dataStreamCheck();
#endif
void operators();
#ifndef QT_NO_DEBUG_STREAM
void debugStreamCheck();
#endif
void getSetCheckF();
#ifndef QT_NO_DATASTREAM
void dataStreamCheckF();
#endif
void operatorsF();
#ifndef QT_NO_DEBUG_STREAM
void debugStreamCheckF();
#endif
void structuredBinding();
void toMarginsF_data();
void toMarginsF();
};
// Testing get/set functions
void tst_QMargins::getSetCheck()
{
QMargins margins;
// int QMargins::width()
// void QMargins::setWidth(int)
margins.setLeft(0);
QCOMPARE(0, margins.left());
margins.setTop(INT_MIN);
QCOMPARE(INT_MIN, margins.top());
margins.setBottom(INT_MAX);
QCOMPARE(INT_MAX, margins.bottom());
margins.setRight(INT_MAX);
QCOMPARE(INT_MAX, margins.right());
margins = QMargins();
QVERIFY(margins.isNull());
margins.setLeft(5);
margins.setRight(5);
QVERIFY(!margins.isNull());
QCOMPARE(margins, QMargins(5, 0, 5, 0));
}
void tst_QMargins::operators()
{
const QMargins m1(12, 14, 16, 18);
const QMargins m2(2, 3, 4, 5);
const QMargins added = m1 + m2;
QCOMPARE(added, QMargins(14, 17, 20, 23));
QMargins a = m1;
a += m2;
QCOMPARE(a, added);
const QMargins subtracted = m1 - m2;
QCOMPARE(subtracted, QMargins(10, 11, 12, 13));
a = m1;
a -= m2;
QCOMPARE(a, subtracted);
QMargins h = m1;
h += 2;
QCOMPARE(h, QMargins(14, 16, 18, 20));
h -= 2;
QCOMPARE(h, m1);
const QMargins doubled = m1 * 2;
QCOMPARE(doubled, QMargins(24, 28, 32, 36));
QCOMPARE(2 * m1, doubled);
QCOMPARE(qreal(2) * m1, doubled);
QCOMPARE(m1 * qreal(2), doubled);
a = m1;
a *= 2;
QCOMPARE(a, doubled);
a = m1;
a *= qreal(2);
QCOMPARE(a, doubled);
const QMargins halved = m1 / 2;
QCOMPARE(halved, QMargins(6, 7, 8, 9));
a = m1;
a /= 2;
QCOMPARE(a, halved);
a = m1;
a /= qreal(2);
QCOMPARE(a, halved);
QCOMPARE(m1 + (-m1), QMargins());
QMargins m3 = QMargins(10, 11, 12, 13);
QCOMPARE(m3 + 1, QMargins(11, 12, 13, 14));
QCOMPARE(1 + m3, QMargins(11, 12, 13, 14));
QCOMPARE(m3 - 1, QMargins(9, 10, 11, 12));
QCOMPARE(+m3, QMargins(10, 11, 12, 13));
QCOMPARE(-m3, QMargins(-10, -11, -12, -13));
}
#ifndef QT_NO_DEBUG_STREAM
// Testing QDebug operators
void tst_QMargins::debugStreamCheck()
{
QMargins m(10, 11, 12, 13);
const QString expected = "QMargins(10, 11, 12, 13)";
QString result;
QDebug(&result).nospace() << m;
QCOMPARE(result, expected);
}
#endif
#ifndef QT_NO_DATASTREAM
// Testing QDataStream operators
void tst_QMargins::dataStreamCheck()
{
QByteArray buffer;
// stream out
{
QMargins marginsOut(0,INT_MIN,INT_MAX,6852);
QDataStream streamOut(&buffer, QIODevice::WriteOnly);
streamOut << marginsOut;
}
// stream in & compare
{
QMargins marginsIn;
QDataStream streamIn(&buffer, QIODevice::ReadOnly);
streamIn >> marginsIn;
QCOMPARE(marginsIn.left(), 0);
QCOMPARE(marginsIn.top(), INT_MIN);
QCOMPARE(marginsIn.right(), INT_MAX);
QCOMPARE(marginsIn.bottom(), 6852);
}
}
#endif
// Testing get/set functions
void tst_QMargins::getSetCheckF()
{
QMarginsF margins;
// int QMarginsF::width()
// void QMarginsF::setWidth(int)
margins.setLeft(1.1);
QCOMPARE(1.1, margins.left());
margins.setTop(2.2);
QCOMPARE(2.2, margins.top());
margins.setBottom(3.3);
QCOMPARE(3.3, margins.bottom());
margins.setRight(4.4);
QCOMPARE(4.4, margins.right());
margins = QMarginsF();
QVERIFY(margins.isNull());
margins.setLeft(5.5);
margins.setRight(5.5);
QVERIFY(!margins.isNull());
QCOMPARE(margins, QMarginsF(5.5, 0.0, 5.5, 0.0));
}
void tst_QMargins::operatorsF()
{
const QMarginsF m1(12.1, 14.1, 16.1, 18.1);
const QMarginsF m2(2.1, 3.1, 4.1, 5.1);
const QMarginsF added = m1 + m2;
QCOMPARE(added, QMarginsF(14.2, 17.2, 20.2, 23.2));
QMarginsF a = m1;
a += m2;
QCOMPARE(a, added);
const QMarginsF subtracted = m1 - m2;
QCOMPARE(subtracted, QMarginsF(10.0, 11.0, 12.0, 13.0));
a = m1;
a -= m2;
QCOMPARE(a, subtracted);
QMarginsF h = m1;
h += 2.1;
QCOMPARE(h, QMarginsF(14.2, 16.2, 18.2, 20.2));
h -= 2.1;
QCOMPARE(h, m1);
const QMarginsF doubled = m1 * 2.0;
QCOMPARE(doubled, QMarginsF(24.2, 28.2, 32.2, 36.2));
QCOMPARE(2.0 * m1, doubled);
QCOMPARE(m1 * 2.0, doubled);
a = m1;
a *= 2.0;
QCOMPARE(a, doubled);
const QMarginsF halved = m1 / 2.0;
QCOMPARE(halved, QMarginsF(6.05, 7.05, 8.05, 9.05));
a = m1;
a /= 2.0;
QCOMPARE(a, halved);
QCOMPARE(m1 + (-m1), QMarginsF());
QMarginsF m3 = QMarginsF(10.3, 11.4, 12.5, 13.6);
QCOMPARE(m3 + 1.1, QMarginsF(11.4, 12.5, 13.6, 14.7));
QCOMPARE(1.1 + m3, QMarginsF(11.4, 12.5, 13.6, 14.7));
QCOMPARE(m3 - 1.1, QMarginsF(9.2, 10.3, 11.4, 12.5));
QCOMPARE(+m3, QMarginsF(10.3, 11.4, 12.5, 13.6));
QCOMPARE(-m3, QMarginsF(-10.3, -11.4, -12.5, -13.6));
}
#ifndef QT_NO_DATASTREAM
// Testing QDataStream operators
void tst_QMargins::dataStreamCheckF()
{
QByteArray buffer;
// stream out
{
QMarginsF marginsOut(1.1, 2.2, 3.3, 4.4);
QDataStream streamOut(&buffer, QIODevice::WriteOnly);
streamOut << marginsOut;
}
// stream in & compare
{
QMarginsF marginsIn;
QDataStream streamIn(&buffer, QIODevice::ReadOnly);
streamIn >> marginsIn;
QCOMPARE(marginsIn.left(), 1.1);
QCOMPARE(marginsIn.top(), 2.2);
QCOMPARE(marginsIn.right(), 3.3);
QCOMPARE(marginsIn.bottom(), 4.4);
}
}
#endif
#ifndef QT_NO_DEBUG_STREAM
// Testing QDebug operators
void tst_QMargins::debugStreamCheckF()
{
QMarginsF m(10.1, 11.2, 12.3, 13.4);
const QString expected = "QMarginsF(10.1, 11.2, 12.3, 13.4)";
QString result;
QDebug(&result).nospace() << m;
QCOMPARE(result, expected);
}
#endif
void tst_QMargins::structuredBinding()
{
{
QMargins m(1, 2, 3, 4);
auto [left, top, right, bottom] = m;
QCOMPARE(left, 1);
QCOMPARE(top, 2);
QCOMPARE(right, 3);
QCOMPARE(bottom, 4);
}
{
QMargins m(1, 2, 3, 4);
auto &[left, top, right, bottom] = m;
QCOMPARE(left, 1);
QCOMPARE(top, 2);
QCOMPARE(right, 3);
QCOMPARE(bottom, 4);
left = 10;
top = 20;
right = 30;
bottom = 40;
QCOMPARE(m.left(), 10);
QCOMPARE(m.top(), 20);
QCOMPARE(m.right(), 30);
QCOMPARE(m.bottom(), 40);
}
{
QMarginsF m(1.0, 2.0, 3.0, 4.0);
auto [left, top, right, bottom] = m;
QCOMPARE(left, 1.0);
QCOMPARE(top, 2.0);
QCOMPARE(right, 3.0);
QCOMPARE(bottom, 4.0);
}
{
QMarginsF m(1.0, 2.0, 3.0, 4.0);
auto &[left, top, right, bottom] = m;
QCOMPARE(left, 1.0);
QCOMPARE(top, 2.0);
QCOMPARE(right, 3.0);
QCOMPARE(bottom, 4.0);
left = 10.0;
top = 20.0;
right = 30.0;
bottom = 40.0;
QCOMPARE(m.left(), 10.0);
QCOMPARE(m.top(), 20.0);
QCOMPARE(m.right(), 30.0);
QCOMPARE(m.bottom(), 40.0);
}
}
void tst_QMargins::toMarginsF_data()
{
QTest::addColumn<QMargins>("input");
QTest::addColumn<QMarginsF>("result");
auto row = [](int x1, int y1, int x2, int y2) {
QTest::addRow("(%d, %d, %d, %d)", x1, y1, x2, y2)
<< QMargins(x1, y1, x2, y2) << QMarginsF(x1, y1, x2, y2);
};
constexpr std::array samples = {-1, 0, 1};
for (int x1 : samples) {
for (int y1 : samples) {
for (int x2 : samples) {
for (int y2 : samples) {
row(x1, y1, x2, y2);
}
}
}
}
}
void tst_QMargins::toMarginsF()
{
QFETCH(const QMargins, input);
QFETCH(const QMarginsF, result);
QCOMPARE(input.toMarginsF(), result);
}
QTEST_APPLESS_MAIN(tst_QMargins)
#include "tst_qmargins.moc"

View File

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

View File

@ -0,0 +1,221 @@
// Copyright (C) 2013 Ruslan Nigmatullin <euroelessar@yandex.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QCoreApplication>
#include <QTest>
#include <QCryptographicHash>
#include <QMessageAuthenticationCode>
#include <QBuffer>
class tst_QMessageAuthenticationCode : public QObject
{
Q_OBJECT
private slots:
void repeated_setKey_data();
void repeated_setKey();
void result_data();
void result();
void result_incremental_data();
void result_incremental();
void addData_overloads_data();
void addData_overloads();
};
Q_DECLARE_METATYPE(QCryptographicHash::Algorithm)
void tst_QMessageAuthenticationCode::repeated_setKey_data()
{
using A = QCryptographicHash::Algorithm;
QTest::addColumn<A>("algo");
const auto me = QMetaEnum::fromType<A>();
for (int i = 0, value; (value = me.value(i)) != -1; ++i)
QTest::addRow("%s", me.key(i)) << A(value);
}
void tst_QMessageAuthenticationCode::repeated_setKey()
{
QFETCH(const QCryptographicHash::Algorithm, algo);
if (!QCryptographicHash::supportsAlgorithm(algo))
QSKIP("QCryptographicHash doesn't support this algorithm");
// GIVEN: two long keys, so we're sure the key needs to be hashed in order
// to fit into the hash algorithm's block
static const QByteArray key1(1024, 'a');
static const QByteArray key2(2048, 'b');
// WHEN: processing the same message
QMessageAuthenticationCode macX(algo);
QMessageAuthenticationCode mac1(algo, key1);
QMessageAuthenticationCode mac2(algo, key2);
const auto check = [](QMessageAuthenticationCode &mac) {
mac.addData("This is nonsense, ignore it, please.");
return mac.result();
};
macX.setKey(key1);
QCOMPARE(check(macX), check(mac1));
// THEN: the result does not depend on whether a new QMAC instance was used
// or an old one re-used (iow: setKey() reset()s)
macX.setKey(key2);
QCOMPARE(check(macX), check(mac2));
}
void tst_QMessageAuthenticationCode::result_data()
{
QTest::addColumn<QCryptographicHash::Algorithm>("algo");
QTest::addColumn<QByteArray>("key");
QTest::addColumn<QByteArray>("message");
QTest::addColumn<QByteArray>("code");
// Empty values
QTest::newRow("md5-empty") << QCryptographicHash::Md5
<< QByteArray()
<< QByteArray()
<< QByteArray::fromHex("74e6f7298a9c2d168935f58c001bad88");
QTest::newRow("sha1-empty") << QCryptographicHash::Sha1
<< QByteArray()
<< QByteArray()
<< QByteArray::fromHex("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d");
QTest::newRow("sha256-empty") << QCryptographicHash::Sha256
<< QByteArray()
<< QByteArray()
<< QByteArray::fromHex("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad");
QTest::newRow("sha384-empty") << QCryptographicHash::Sha384 << QByteArray() << QByteArray()
<< QByteArray::fromHex(
"6c1f2ee938fad2e24bd91298474382ca218c75db3d83e114b3d43"
"67776d14d3551289e75e8209cd4b792302840234adc");
QTest::newRow("sha512-empty")
<< QCryptographicHash::Sha512 << QByteArray() << QByteArray()
<< QByteArray::fromHex(
"b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b"
"327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47");
// Some not-empty
QTest::newRow("md5") << QCryptographicHash::Md5
<< QByteArray("key")
<< QByteArray("The quick brown fox jumps over the lazy dog")
<< QByteArray::fromHex("80070713463e7749b90c2dc24911e275");
QTest::newRow("sha1") << QCryptographicHash::Sha1
<< QByteArray("key")
<< QByteArray("The quick brown fox jumps over the lazy dog")
<< QByteArray::fromHex("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9");
QTest::newRow("sha256") << QCryptographicHash::Sha256
<< QByteArray("key")
<< QByteArray("The quick brown fox jumps over the lazy dog")
<< QByteArray::fromHex("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8");
QTest::newRow("sha384") << QCryptographicHash::Sha384 << QByteArray("key")
<< QByteArray("The quick brown fox jumps over the lazy dog")
<< QByteArray::fromHex(
"d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1ae"
"50700582a96cf35e1e554995fe4e03381c237");
QTest::newRow("sha512")
<< QCryptographicHash::Sha512 << QByteArray("key")
<< QByteArray("The quick brown fox jumps over the lazy dog")
<< QByteArray::fromHex(
"b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f"
"7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a");
// Some from rfc-2104
QTest::newRow("rfc-md5-1") << QCryptographicHash::Md5
<< QByteArray::fromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
<< QByteArray("Hi There")
<< QByteArray::fromHex("9294727a3638bb1c13f48ef8158bfc9d");
QTest::newRow("rfc-md5-2") << QCryptographicHash::Md5
<< QByteArray("Jefe")
<< QByteArray("what do ya want for nothing?")
<< QByteArray::fromHex("750c783e6ab0b503eaa86e310a5db738");
QTest::newRow("rfc-md5-3") << QCryptographicHash::Md5
<< QByteArray::fromHex("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
<< QByteArray(50, char(0xdd))
<< QByteArray::fromHex("56be34521d144c88dbb8c733f0e8b3f6");
}
void tst_QMessageAuthenticationCode::result()
{
QFETCH(QCryptographicHash::Algorithm, algo);
QFETCH(QByteArray, key);
QFETCH(QByteArray, message);
QFETCH(QByteArray, code);
QMessageAuthenticationCode mac(algo, key);
mac.addData(message);
QByteArray result = mac.result();
QCOMPARE(result, code);
result = QMessageAuthenticationCode::hash(message, key, algo);
QCOMPARE(result, code);
}
void tst_QMessageAuthenticationCode::result_incremental_data()
{
result_data();
}
void tst_QMessageAuthenticationCode::result_incremental()
{
QFETCH(QCryptographicHash::Algorithm, algo);
QFETCH(QByteArray, key);
QFETCH(QByteArray, message);
QFETCH(QByteArray, code);
int index = message.size() / 2;
QByteArray leftPart(message.mid(0, index));
QByteArray rightPart(message.mid(index));
QCOMPARE(leftPart + rightPart, message);
QMessageAuthenticationCode mac(algo, key);
mac.addData(leftPart);
mac.addData(rightPart);
QByteArray result = mac.result();
QCOMPARE(result, code);
}
void tst_QMessageAuthenticationCode::addData_overloads_data()
{
result_data();
}
void tst_QMessageAuthenticationCode::addData_overloads()
{
QFETCH(QCryptographicHash::Algorithm, algo);
QFETCH(QByteArray, key);
QFETCH(QByteArray, message);
QFETCH(QByteArray, code);
// overload using const char* and length
{
QMessageAuthenticationCode mac(algo);
mac.setKey(key);
mac.addData(message.constData(), message.size());
QByteArray result = mac.result();
QCOMPARE(result, code);
}
// overload using QIODevice
{
QBuffer buffer(&message);
buffer.open(QIODevice::ReadOnly);
QMessageAuthenticationCode mac(algo);
mac.setKey(key);
QVERIFY(mac.addData(&buffer));
QByteArray result = mac.result();
buffer.close();
QCOMPARE(result, code);
}
}
QTEST_MAIN(tst_QMessageAuthenticationCode)
#include "tst_qmessageauthenticationcode.moc"

View File

@ -0,0 +1,20 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qoffsetstringarray Test:
#####################################################################
qt_internal_add_test(tst_qoffsetstringarray
SOURCES
tst_qoffsetstringarray.cpp
LIBRARIES
Qt::CorePrivate
)
if (CLANG)
target_compile_options(tst_qoffsetstringarray
PUBLIC -fbracket-depth=512)
elseif (GCC)
# fconstexpr-depth= defaults to 512
endif()

View File

@ -0,0 +1,105 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <private/qoffsetstringarray_p.h>
class tst_QOffsetStringArray : public QObject
{
Q_OBJECT
private slots:
void init();
void access();
void contains();
};
constexpr const auto messages = qOffsetStringArray(
"level - 0",
"level - 1",
"level - 2",
"level - 3",
"level - 4"
);
constexpr const auto messages257 = qOffsetStringArray(
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "end"
);
constexpr const auto messagesBigOffsets = qOffsetStringArray(
" 10 20 30 40 50 60 70 80 90",
" 10 20 30 40 50 60 70 80 90",
" 10 20 30 40 50 60 70 80 90",
" 10 20 30 40 50 60 70 80 90"
);
void tst_QOffsetStringArray::init()
{
static_assert(messages.m_string.size() == 50);
static_assert(messages.m_offsets.size() == 6);
static_assert(std::is_same_v<decltype(messages.m_offsets)::value_type, quint8>);
static_assert(messages257.m_offsets.size() == 258);
static_assert(messages257.m_string.size() == 260);
static_assert(std::is_same_v<decltype(messages257.m_offsets)::value_type, quint16>);
static_assert(messagesBigOffsets.m_offsets.size() == 5);
static_assert(messagesBigOffsets.m_string.size() == 364);
static_assert(std::is_same_v<decltype(messagesBigOffsets.m_offsets)::value_type, quint16>);
}
void tst_QOffsetStringArray::access()
{
QCOMPARE(messages[0], "level - 0");
QCOMPARE(messages[1], "level - 1");
QCOMPARE(messages[2], "level - 2");
QCOMPARE(messages[3], "level - 3");
QCOMPARE(messages[4], "level - 4");
// out of bounds returns empty strings:
QCOMPARE(messages[5], "");
QCOMPARE(messages[6], "");
}
void tst_QOffsetStringArray::contains()
{
QVERIFY(!messages.contains(""));
QVERIFY( messages.contains("level - 0"));
std::string l2 = "level - 2"; // make sure we don't compare pointer values
QVERIFY( messages.contains(l2));
QByteArray L4 = "Level - 4";
QVERIFY( messages.contains(L4, Qt::CaseInsensitive));
QVERIFY(!messages.contains(L4, Qt::CaseSensitive));
}
QTEST_APPLESS_MAIN(tst_QOffsetStringArray)
#include "tst_qoffsetstringarray.moc"

View File

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

View File

@ -0,0 +1,257 @@
// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QPair>
#include <QSize>
class tst_QPair : public QObject
{
Q_OBJECT
private Q_SLOTS:
void pairOfReferences();
void structuredBindings();
void testConstexpr();
void testConversions();
void taskQTBUG_48780_pairContainingCArray();
void testDeductionRules();
};
class C { C() {} ~C() {} Q_DECL_UNUSED_MEMBER char _[4]; };
class M { M() {} Q_DECL_UNUSED_MEMBER char _[4]; };
class P { Q_DECL_UNUSED_MEMBER char _[4]; };
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(M, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(P, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
// avoid the comma:
typedef QPair<C,C> QPairCC;
typedef QPair<C,M> QPairCM;
typedef QPair<C,P> QPairCP;
typedef QPair<M,C> QPairMC;
typedef QPair<M,M> QPairMM;
typedef QPair<M,P> QPairMP;
typedef QPair<P,C> QPairPC;
typedef QPair<P,M> QPairPM;
typedef QPair<P,P> QPairPP;
static_assert( QTypeInfo<QPairCC>::isComplex);
static_assert( !QTypeInfo<QPairCC>::isRelocatable );
static_assert( QTypeInfo<QPairCM>::isComplex);
static_assert( !QTypeInfo<QPairCM>::isRelocatable );
static_assert( QTypeInfo<QPairCP>::isComplex);
static_assert( !QTypeInfo<QPairCP>::isRelocatable );
static_assert( QTypeInfo<QPairMC>::isComplex);
static_assert( !QTypeInfo<QPairMC>::isRelocatable );
static_assert( QTypeInfo<QPairMM>::isComplex);
static_assert( QTypeInfo<QPairMM>::isRelocatable );
static_assert( QTypeInfo<QPairMP>::isComplex);
static_assert( QTypeInfo<QPairMP>::isRelocatable );
static_assert( QTypeInfo<QPairPC>::isComplex);
static_assert( !QTypeInfo<QPairPC>::isRelocatable );
static_assert( QTypeInfo<QPairPM>::isComplex);
static_assert( QTypeInfo<QPairPM>::isRelocatable );
static_assert(!QTypeInfo<QPairPP>::isComplex);
static_assert( QTypeInfo<QPairPP>::isRelocatable );
static_assert(!QTypeInfo<QPairPP>::isPointer);
void tst_QPair::pairOfReferences()
{
int i = 0;
QString s;
QPair<int&, QString&> p(i, s);
p.first = 1;
QCOMPARE(i, 1);
i = 2;
QCOMPARE(p.first, 2);
p.second = QLatin1String("Hello");
QCOMPARE(s, QLatin1String("Hello"));
s = QLatin1String("olleH");
QCOMPARE(p.second, QLatin1String("olleH"));
QPair<int&, QString&> q = p;
q.first = 3;
QCOMPARE(i, 3);
QCOMPARE(p.first, 3);
q.second = QLatin1String("World");
QCOMPARE(s, QLatin1String("World"));
QCOMPARE(p.second, QLatin1String("World"));
}
void tst_QPair::structuredBindings()
{
using PV = QPair<int, QString>;
using PR = QPair<int&, const QString&>;
{
PV pv = {42, "Hello"};
PR pr = {pv.first, pv.second};
auto [fv, sv] = pv;
fv = 24;
sv = "World";
QCOMPARE(fv, 24);
QCOMPARE(sv, "World");
QCOMPARE(pv.first, 42);
QCOMPARE(pv.second, "Hello");
auto [fr, sr] = pr;
fr = 2424;
// sr = "World"; // const
QCOMPARE(fr, 2424);
QCOMPARE(pv.first, 2424);
}
{
PV pv = {42, "Hello"};
PR pr = {pv.first, pv.second};
auto& [fv, sv] = pv;
fv = 24;
sv = "World";
QCOMPARE(fv, 24);
QCOMPARE(sv, "World");
QCOMPARE(pv.first, 24);
QCOMPARE(pv.second, "World");
auto& [fr, sr] = pr;
fr = 4242;
//sr = "2World"; // const
QCOMPARE(fr, 4242);
QCOMPARE(pr.first, 4242);
QCOMPARE(pv.first, 4242);
}
}
void tst_QPair::testConstexpr()
{
constexpr QPair<int, double> pID = qMakePair(0, 0.0);
Q_UNUSED(pID);
constexpr QPair<double, double> pDD = qMakePair(0.0, 0.0);
constexpr QPair<double, double> pDD2 = qMakePair(0, 0.0); // involes (rvalue) conversion ctor
constexpr bool equal = pDD2 == pDD;
QVERIFY(equal);
constexpr QPair<QSize, int> pSI = qMakePair(QSize(4, 5), 6);
Q_UNUSED(pSI);
}
void tst_QPair::testConversions()
{
// construction from lvalue:
{
const QPair<int, double> rhs(42, 4.5);
const QPair<int, int> pii = rhs;
QCOMPARE(pii.first, 42);
QCOMPARE(pii.second, 4);
const QPair<int, float> pif = rhs;
QCOMPARE(pif.first, 42);
QCOMPARE(pif.second, 4.5f);
}
// assignment from lvalue:
{
const QPair<int, double> rhs(42, 4.5);
QPair<int, int> pii;
pii = rhs;
QCOMPARE(pii.first, 42);
QCOMPARE(pii.second, 4);
QPair<int, float> pif;
pif = rhs;
QCOMPARE(pif.first, 42);
QCOMPARE(pif.second, 4.5f);
}
// construction from rvalue:
{
#define rhs qMakePair(42, 4.5)
const QPair<int, int> pii = rhs;
QCOMPARE(pii.first, 42);
QCOMPARE(pii.second, 4);
const QPair<int, float> pif = rhs;
QCOMPARE(pif.first, 42);
QCOMPARE(pif.second, 4.5f);
#undef rhs
}
// assignment from rvalue:
{
#define rhs qMakePair(42, 4.5)
QPair<int, int> pii;
pii = rhs;
QCOMPARE(pii.first, 42);
QCOMPARE(pii.second, 4);
QPair<int, float> pif;
pif = rhs;
QCOMPARE(pif.first, 42);
QCOMPARE(pif.second, 4.5f);
#undef rhs
}
}
void tst_QPair::taskQTBUG_48780_pairContainingCArray()
{
// compile-only:
QPair<int[2], int> pair;
pair.first[0] = 0;
pair.first[1] = 1;
pair.second = 2;
Q_UNUSED(pair);
}
void tst_QPair::testDeductionRules()
{
#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201907L
QPair p1{1, 2};
static_assert(std::is_same<decltype(p1)::first_type, decltype(1)>::value);
static_assert(std::is_same<decltype(p1)::second_type, decltype(2)>::value);
QCOMPARE(p1.first, 1);
QCOMPARE(p1.second, 2);
QPair p2{QString("string"), 2};
static_assert(std::is_same<decltype(p2)::first_type, QString>::value);
static_assert(std::is_same<decltype(p2)::second_type, decltype(2)>::value);
QCOMPARE(p2.first, "string");
QCOMPARE(p2.second, 2);
QPair p3(p2);
static_assert(std::is_same<decltype(p3)::first_type, decltype(p2)::first_type>::value);
static_assert(std::is_same<decltype(p3)::second_type, decltype(p2)::second_type>::value);
QCOMPARE(p3.first, "string");
QCOMPARE(p3.second, 2);
#else
QSKIP("Unsupported (requires C++20's CTAD for aliases)");
#endif
}
QTEST_APPLESS_MAIN(tst_QPair)
#include "tst_qpair.moc"

View File

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

View File

@ -0,0 +1,449 @@
// 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 <QTest>
#include <QBuffer>
#include <qpoint.h>
#include <array>
class tst_QPoint : public QObject
{
Q_OBJECT
private slots:
void isNull();
void manhattanLength_data();
void manhattanLength();
void getSet_data();
void getSet();
void transposed();
void toPointF_data();
void toPointF();
void rx();
void ry();
void operator_add_data();
void operator_add();
void operator_subtract_data();
void operator_subtract();
void operator_multiply_data();
void operator_multiply();
void operator_divide_data();
void operator_divide();
void dotProduct_data();
void dotProduct();
void operator_unary_plus_data();
void operator_unary_plus();
void operator_unary_minus_data();
void operator_unary_minus();
void operator_eq_data();
void operator_eq();
#ifndef QT_NO_DATASTREAM
void stream_data();
void stream();
#endif
void structuredBinding();
};
void tst_QPoint::isNull()
{
QPoint point(0, 0);
QVERIFY(point.isNull());
++point.rx();
QVERIFY(!point.isNull());
point.rx() -= 2;
QVERIFY(!point.isNull());
}
void tst_QPoint::manhattanLength_data()
{
QTest::addColumn<QPoint>("point");
QTest::addColumn<int>("expected");
QTest::newRow("(0, 0)") << QPoint(0, 0) << 0;
QTest::newRow("(10, 0)") << QPoint(10, 0) << 10;
QTest::newRow("(0, 10)") << QPoint(0, 10) << 10;
QTest::newRow("(10, 20)") << QPoint(10, 20) << 30;
QTest::newRow("(-10, -20)") << QPoint(-10, -20) << 30;
}
void tst_QPoint::manhattanLength()
{
QFETCH(QPoint, point);
QFETCH(int, expected);
QCOMPARE(point.manhattanLength(), expected);
}
void tst_QPoint::getSet_data()
{
QTest::addColumn<int>("i");
QTest::newRow("0") << 0;
QTest::newRow("INT_MIN") << INT_MIN;
QTest::newRow("INT_MAX") << INT_MAX;
}
void tst_QPoint::getSet()
{
QFETCH(int, i);
QPoint point;
point.setX(i);
QCOMPARE(point.x(), i);
point.setY(i);
QCOMPARE(point.y(), i);
}
void tst_QPoint::toPointF_data()
{
QTest::addColumn<QPoint>("input");
QTest::addColumn<QPointF>("result");
auto row = [](int x, int y) {
QTest::addRow("(%d, %d)", x, y) << QPoint(x, y) << QPointF(x, y);
};
constexpr std::array samples = {-1, 0, 1};
for (int x : samples) {
for (int y : samples) {
row(x, y);
}
}
}
void tst_QPoint::toPointF()
{
QFETCH(const QPoint, input);
QFETCH(const QPointF, result);
QCOMPARE(input.toPointF(), result);
}
void tst_QPoint::transposed()
{
QCOMPARE(QPoint(1, 2).transposed(), QPoint(2, 1));
}
void tst_QPoint::rx()
{
const QPoint originalPoint(-1, 0);
QPoint point(originalPoint);
++point.rx();
QCOMPARE(point.x(), originalPoint.x() + 1);
}
void tst_QPoint::ry()
{
const QPoint originalPoint(0, -1);
QPoint point(originalPoint);
++point.ry();
QCOMPARE(point.y(), originalPoint.y() + 1);
}
void tst_QPoint::operator_add_data()
{
QTest::addColumn<QPoint>("point1");
QTest::addColumn<QPoint>("point2");
QTest::addColumn<QPoint>("expected");
QTest::newRow("(0, 0) + (0, 0)") << QPoint(0, 0) << QPoint(0, 0) << QPoint(0, 0);
QTest::newRow("(0, 9) + (1, 0)") << QPoint(0, 9) << QPoint(1, 0) << QPoint(1, 9);
QTest::newRow("(INT_MIN, 0) + (1, 0)") << QPoint(INT_MIN, 0) << QPoint(1, 0) << QPoint(INT_MIN + 1, 0);
QTest::newRow("(INT_MAX, 0) + (-1, 0)") << QPoint(INT_MAX, 0) << QPoint(-1, 0) << QPoint(INT_MAX - 1, 0);
}
void tst_QPoint::operator_add()
{
QFETCH(QPoint, point1);
QFETCH(QPoint, point2);
QFETCH(QPoint, expected);
QCOMPARE(point1 + point2, expected);
point1 += point2;
QCOMPARE(point1, expected);
}
void tst_QPoint::operator_subtract_data()
{
QTest::addColumn<QPoint>("point1");
QTest::addColumn<QPoint>("point2");
QTest::addColumn<QPoint>("expected");
QTest::newRow("(0, 0) - (0, 0)") << QPoint(0, 0) << QPoint(0, 0) << QPoint(0, 0);
QTest::newRow("(0, 9) - (1, 0)") << QPoint(0, 9) << QPoint(1, 0) << QPoint(-1, 9);
QTest::newRow("(INT_MAX, 0) - (1, 0)") << QPoint(INT_MAX, 0) << QPoint(1, 0) << QPoint(INT_MAX - 1, 0);
QTest::newRow("(INT_MIN, 0) - (-1, 0)") << QPoint(INT_MIN, 0) << QPoint(-1, 0) << QPoint(INT_MIN - -1, 0);
}
void tst_QPoint::operator_subtract()
{
QFETCH(QPoint, point1);
QFETCH(QPoint, point2);
QFETCH(QPoint, expected);
QCOMPARE(point1 - point2, expected);
point1 -= point2;
QCOMPARE(point1, expected);
}
enum PrimitiveType { Int, Float, Double };
Q_DECLARE_METATYPE(PrimitiveType)
void tst_QPoint::operator_multiply_data()
{
QTest::addColumn<QPoint>("point");
QTest::addColumn<double>("factorAsDouble");
QTest::addColumn<PrimitiveType>("type");
QTest::addColumn<QPoint>("expected");
QTest::newRow("(0, 0) * 0.0") << QPoint(0, 0) << 0.0 << Double << QPoint(0, 0);
QTest::newRow("(INT_MIN, 1) * 0.5") << QPoint(INT_MIN, 1) << 0.5 << Double << QPoint(qRound(INT_MIN * 0.5), 1);
QTest::newRow("(INT_MAX, 2) * 0.5") << QPoint(INT_MAX, 2) << 0.5 << Double << QPoint(qRound(INT_MAX * 0.5), 1);
QTest::newRow("(0, 0) * 0") << QPoint(0, 0) << 0.0 << Int << QPoint(0, 0);
QTest::newRow("(INT_MIN + 1, 0) * -1") << QPoint(INT_MIN + 1, 0) << -1.0 << Int << QPoint((INT_MIN + 1) * -1, 0);
QTest::newRow("(INT_MAX, 0) * -1") << QPoint(INT_MAX, 0) << -1.0 << Int << QPoint(INT_MAX * -1, 0);
QTest::newRow("(0, 0) * 0.0f") << QPoint(0, 0) << 0.0 << Float << QPoint(0, 0);
QTest::newRow("(INT_MIN, 0) * -0.5f") << QPoint(INT_MIN, 0) << -0.5 << Float << QPoint(qRound(INT_MIN * -0.5f), 0);
}
template<typename T>
void multiplyTest(QPoint point, double factor, const QPoint &expected)
{
T factorAsT = static_cast<T>(factor);
QCOMPARE(point * factorAsT, expected);
// Test with reversed argument version.
QCOMPARE(factorAsT * point, expected);
point *= factorAsT;
QCOMPARE(point, expected);
}
void tst_QPoint::operator_multiply()
{
QFETCH(QPoint, point);
QFETCH(double, factorAsDouble);
QFETCH(PrimitiveType, type);
QFETCH(QPoint, expected);
if (type == Int)
multiplyTest<int>(point, factorAsDouble, expected);
else if (type == Float)
multiplyTest<float>(point, factorAsDouble, expected);
else if (type == Double)
multiplyTest<double>(point, factorAsDouble, expected);
}
void tst_QPoint::operator_divide_data()
{
QTest::addColumn<QPoint>("point");
QTest::addColumn<qreal>("divisor");
QTest::addColumn<QPoint>("expected");
QTest::newRow("(0, 0) / 1") << QPoint(0, 0) << qreal(1) << QPoint(0, 0);
QTest::newRow("(0, 9) / 2") << QPoint(0, 9) << qreal(2) << QPoint(0, 5);
QTest::newRow("(INT_MAX, 0) / 2") << QPoint(INT_MAX, 0) << qreal(2) << QPoint(qRound(INT_MAX / qreal(2)), 0);
QTest::newRow("(INT_MIN, 0) / -1.5") << QPoint(INT_MIN, 0) << qreal(-1.5) << QPoint(qRound(INT_MIN / qreal(-1.5)), 0);
}
void tst_QPoint::operator_divide()
{
QFETCH(QPoint, point);
QFETCH(qreal, divisor);
QFETCH(QPoint, expected);
QCOMPARE(point / divisor, expected);
point /= divisor;
QCOMPARE(point, expected);
}
void tst_QPoint::dotProduct_data()
{
QTest::addColumn<QPoint>("point1");
QTest::addColumn<QPoint>("point2");
QTest::addColumn<int>("expected");
QTest::newRow("(0, 0) dot (0, 0)") << QPoint(0, 0) << QPoint(0, 0)<< 0;
QTest::newRow("(10, 0) dot (0, 10)") << QPoint(10, 0) << QPoint(0, 10) << 0;
QTest::newRow("(0, 10) dot (10, 0)") << QPoint(0, 10) << QPoint(10, 0) << 0;
QTest::newRow("(10, 20) dot (-10, -20)") << QPoint(10, 20) << QPoint(-10, -20) << -500;
QTest::newRow("(-10, -20) dot (10, 20)") << QPoint(-10, -20) << QPoint(10, 20) << -500;
}
void tst_QPoint::dotProduct()
{
QFETCH(QPoint, point1);
QFETCH(QPoint, point2);
QFETCH(int, expected);
QCOMPARE(QPoint::dotProduct(point1, point2), expected);
}
void tst_QPoint::operator_unary_plus_data()
{
operator_unary_minus_data();
}
void tst_QPoint::operator_unary_plus()
{
QFETCH(QPoint, point);
// Should be a NOOP.
QCOMPARE(+point, point);
}
void tst_QPoint::operator_unary_minus_data()
{
QTest::addColumn<QPoint>("point");
QTest::addColumn<QPoint>("expected");
QTest::newRow("-(0, 0)") << QPoint(0, 0) << QPoint(0, 0);
QTest::newRow("-(-1, 0)") << QPoint(-1, 0) << QPoint(1, 0);
QTest::newRow("-(0, -1)") << QPoint(0, -1) << QPoint(0, 1);
QTest::newRow("-(-INT_MAX, INT_MAX)") << QPoint(-INT_MAX, INT_MAX) << QPoint(INT_MAX, -INT_MAX);
}
void tst_QPoint::operator_unary_minus()
{
QFETCH(QPoint, point);
QFETCH(QPoint, expected);
QCOMPARE(-point, expected);
}
void tst_QPoint::operator_eq_data()
{
QTest::addColumn<QPoint>("point1");
QTest::addColumn<QPoint>("point2");
QTest::addColumn<bool>("expectEqual");
QTest::newRow("(0, 0) == (0, 0)") << QPoint(0, 0) << QPoint(0, 0) << true;
QTest::newRow("(-1, 0) == (-1, 0)") << QPoint(-1, 0) << QPoint(-1, 0) << true;
QTest::newRow("(-1, 0) != (0, 0)") << QPoint(-1, 0) << QPoint(0, 0) << false;
QTest::newRow("(-1, 0) != (0, -1)") << QPoint(-1, 0) << QPoint(0, -1) << false;
QTest::newRow("(1, 99999) != (-1, 99999)") << QPoint(1, 99999) << QPoint(-1, 99999) << false;
QTest::newRow("(INT_MIN, INT_MIN) == (INT_MIN, INT_MIN)") << QPoint(INT_MIN, INT_MIN) << QPoint(INT_MIN, INT_MIN) << true;
QTest::newRow("(INT_MAX, INT_MAX) == (INT_MAX, INT_MAX)") << QPoint(INT_MAX, INT_MAX) << QPoint(INT_MAX, INT_MAX) << true;
}
void tst_QPoint::operator_eq()
{
QFETCH(QPoint, point1);
QFETCH(QPoint, point2);
QFETCH(bool, expectEqual);
bool equal = point1 == point2;
QCOMPARE(equal, expectEqual);
bool notEqual = point1 != point2;
QCOMPARE(notEqual, !expectEqual);
if (equal)
QCOMPARE(qHash(point1), qHash(point2));
}
#ifndef QT_NO_DATASTREAM
void tst_QPoint::stream_data()
{
QTest::addColumn<QPoint>("point");
QTest::newRow("(0, 0)") << QPoint(0, 0);
QTest::newRow("(-1, 1)") << QPoint(-1, 1);
QTest::newRow("(1, -1)") << QPoint(1, -1);
QTest::newRow("(INT_MIN, INT_MAX)") << QPoint(INT_MIN, INT_MAX);
}
void tst_QPoint::stream()
{
QFETCH(QPoint, point);
QBuffer tmp;
QVERIFY(tmp.open(QBuffer::ReadWrite));
QDataStream stream(&tmp);
// Ensure that stream returned is the same stream we inserted into.
QDataStream &insertionStreamRef(stream << point);
QVERIFY(&insertionStreamRef == &stream);
tmp.seek(0);
QPoint pointFromStream;
QDataStream &extractionStreamRef(stream >> pointFromStream);
QVERIFY(&extractionStreamRef == &stream);
QCOMPARE(pointFromStream, point);
}
#endif
void tst_QPoint::structuredBinding()
{
{
QPoint p(1, 2);
auto [x, y] = p;
QCOMPARE(x, 1);
QCOMPARE(y, 2);
p.setX(42);
QCOMPARE(x, 1);
QCOMPARE(y, 2);
p.setY(-123);
QCOMPARE(x, 1);
QCOMPARE(y, 2);
}
{
QPoint p(1, 2);
auto &[x, y] = p;
QCOMPARE(x, 1);
QCOMPARE(y, 2);
x = 42;
QCOMPARE(x, 42);
QCOMPARE(p.x(), 42);
QCOMPARE(p.rx(), 42);
QCOMPARE(y, 2);
QCOMPARE(p.y(), 2);
QCOMPARE(p.ry(), 2);
y = -123;
QCOMPARE(x, 42);
QCOMPARE(p.x(), 42);
QCOMPARE(p.rx(), 42);
QCOMPARE(y, -123);
QCOMPARE(p.y(), -123);
QCOMPARE(p.ry(), -123);
p.setX(0);
QCOMPARE(x, 0);
QCOMPARE(p.x(), 0);
QCOMPARE(p.rx(), 0);
QCOMPARE(y, -123);
QCOMPARE(p.y(), -123);
QCOMPARE(p.ry(), -123);
p.ry() = 10;
QCOMPARE(x, 0);
QCOMPARE(p.x(), 0);
QCOMPARE(p.rx(), 0);
QCOMPARE(y, 10);
QCOMPARE(p.y(), 10);
QCOMPARE(p.ry(), 10);
}
}
QTEST_MAIN(tst_QPoint)
#include "tst_qpoint.moc"

View File

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

View File

@ -0,0 +1,502 @@
// 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 <QBuffer>
#include <qpoint.h>
class tst_QPointF : public QObject
{
Q_OBJECT
public:
tst_QPointF();
private slots:
void isNull();
void manhattanLength_data();
void manhattanLength();
void getSet_data();
void getSet();
void transposed();
void rx();
void ry();
void operator_add_data();
void operator_add();
void operator_subtract_data();
void operator_subtract();
void operator_multiply_data();
void operator_multiply();
void operator_divide_data();
void operator_divide();
void division();
void dotProduct_data();
void dotProduct();
void operator_unary_plus_data();
void operator_unary_plus();
void operator_unary_minus_data();
void operator_unary_minus();
void operator_eq_data();
void operator_eq();
void toPoint_data();
void toPoint();
void compare();
#ifndef QT_NO_DATASTREAM
void stream_data();
void stream();
#endif
void structuredBinding();
private:
const qreal QREAL_MIN;
const qreal QREAL_MAX;
};
tst_QPointF::tst_QPointF()
: QREAL_MIN(std::numeric_limits<qreal>::min()),
QREAL_MAX(std::numeric_limits<qreal>::max())
{
}
void tst_QPointF::isNull()
{
QPointF point(0, 0);
QVERIFY(point.isNull());
++point.rx();
QVERIFY(!point.isNull());
point.rx() -= 2;
QVERIFY(!point.isNull());
QPointF nullNegativeZero(qreal(-0.0), qreal(-0.0));
QCOMPARE(nullNegativeZero.x(), (qreal)-0.0f);
QCOMPARE(nullNegativeZero.y(), (qreal)-0.0f);
QVERIFY(nullNegativeZero.isNull());
}
void tst_QPointF::manhattanLength_data()
{
QTest::addColumn<QPointF>("point");
QTest::addColumn<qreal>("expected");
QTest::newRow("(0, 0)") << QPointF(0, 0) << qreal(0);
QTest::newRow("(10, 0)") << QPointF(10, 0) << qreal(10);
QTest::newRow("(0, 10)") << QPointF(0, 10) << qreal(10);
QTest::newRow("(10, 20)") << QPointF(10, 20) << qreal(30);
QTest::newRow("(10.1, 20.2)") << QPointF(10.1, 20.2) << qreal(30.3);
QTest::newRow("(-10.1, -20.2)") << QPointF(-10.1, -20.2) << qreal(30.3);
}
void tst_QPointF::manhattanLength()
{
QFETCH(QPointF, point);
QFETCH(qreal, expected);
QCOMPARE(point.manhattanLength(), expected);
}
void tst_QPointF::getSet_data()
{
QTest::addColumn<qreal>("r");
QTest::newRow("0") << qreal(0);
QTest::newRow("-1") << qreal(-1);
QTest::newRow("1") << qreal(1);
QTest::newRow("QREAL_MAX") << qreal(QREAL_MAX);
QTest::newRow("QREAL_MIN") << qreal(QREAL_MIN);
}
void tst_QPointF::getSet()
{
QFETCH(qreal, r);
QPointF point;
point.setX(r);
QCOMPARE(point.x(), r);
point.setY(r);
QCOMPARE(point.y(), r);
}
void tst_QPointF::transposed()
{
QCOMPARE(QPointF(1, 2).transposed(), QPointF(2, 1));
}
void tst_QPointF::rx()
{
const QPointF originalPoint(-1, 0);
QPointF point(originalPoint);
++point.rx();
QCOMPARE(point.x(), originalPoint.x() + 1);
}
void tst_QPointF::ry()
{
const QPointF originalPoint(0, -1);
QPointF point(originalPoint);
++point.ry();
QCOMPARE(point.y(), originalPoint.y() + 1);
}
void tst_QPointF::operator_add_data()
{
QTest::addColumn<QPointF>("point1");
QTest::addColumn<QPointF>("point2");
QTest::addColumn<QPointF>("expected");
QTest::newRow("(0, 0) + (0, 0)") << QPointF(0, 0) << QPointF(0, 0) << QPointF(0, 0);
QTest::newRow("(0, 9) + (1, 0)") << QPointF(0, 9) << QPointF(1, 0) << QPointF(1, 9);
QTest::newRow("(QREAL_MIN, 0) + (1, 0)") << QPointF(QREAL_MIN, 0) << QPointF(1, 0) << QPointF(QREAL_MIN + 1, 0);
QTest::newRow("(QREAL_MAX, 0) + (-1, 0)") << QPointF(QREAL_MAX, 0) << QPointF(-1, 0) << QPointF(QREAL_MAX - 1, 0);
}
void tst_QPointF::operator_add()
{
QFETCH(QPointF, point1);
QFETCH(QPointF, point2);
QFETCH(QPointF, expected);
QCOMPARE(point1 + point2, expected);
point1 += point2;
QCOMPARE(point1, expected);
}
void tst_QPointF::operator_subtract_data()
{
QTest::addColumn<QPointF>("point1");
QTest::addColumn<QPointF>("point2");
QTest::addColumn<QPointF>("expected");
QTest::newRow("(0, 0) - (0, 0)") << QPointF(0, 0) << QPointF(0, 0) << QPointF(0, 0);
QTest::newRow("(0, 9) - (1, 0)") << QPointF(0, 9) << QPointF(1, 0) << QPointF(-1, 9);
QTest::newRow("(QREAL_MAX, 0) - (1, 0)") << QPointF(QREAL_MAX, 0) << QPointF(1, 0) << QPointF(QREAL_MAX - 1, 0);
QTest::newRow("(QREAL_MIN, 0) - (-1, 0)") << QPointF(QREAL_MIN, 0) << QPointF(-1, 0) << QPointF(QREAL_MIN - -1, 0);
}
void tst_QPointF::operator_subtract()
{
QFETCH(QPointF, point1);
QFETCH(QPointF, point2);
QFETCH(QPointF, expected);
QCOMPARE(point1 - point2, expected);
point1 -= point2;
QCOMPARE(point1, expected);
}
void tst_QPointF::operator_multiply_data()
{
QTest::addColumn<QPointF>("point");
QTest::addColumn<qreal>("factor");
QTest::addColumn<QPointF>("expected");
QTest::newRow("(0, 0) * 0.0") << QPointF(0, 0) << qreal(0) << QPointF(0, 0);
QTest::newRow("(QREAL_MIN, 1) * 0.5") << QPointF(QREAL_MIN, 1) << qreal(0.5) << QPointF(QREAL_MIN * 0.5, 0.5);
QTest::newRow("(QREAL_MAX, 2) * 0.5") << QPointF(QREAL_MAX, 2) << qreal(0.5) << QPointF(QREAL_MAX * 0.5, 1);
}
void tst_QPointF::operator_multiply()
{
QFETCH(QPointF, point);
QFETCH(qreal, factor);
QFETCH(QPointF, expected);
QCOMPARE(point * factor, expected);
// Test with reversed argument version.
QCOMPARE(factor * point, expected);
point *= factor;
QCOMPARE(point, expected);
}
void tst_QPointF::operator_divide_data()
{
QTest::addColumn<QPointF>("point");
QTest::addColumn<qreal>("divisor");
QTest::addColumn<QPointF>("expected");
QTest::newRow("(0, 0) / 1") << QPointF(0, 0) << qreal(1) << QPointF(0, 0);
QTest::newRow("(0, 9) / 2") << QPointF(0, 9) << qreal(2) << QPointF(0, 4.5);
QTest::newRow("(QREAL_MAX, 0) / 2") << QPointF(QREAL_MAX, 0) << qreal(2) << QPointF(QREAL_MAX / qreal(2), 0);
QTest::newRow("(QREAL_MIN, 0) / -1.5") << QPointF(QREAL_MIN, 0) << qreal(-1.5) << QPointF(QREAL_MIN / qreal(-1.5), 0);
}
void tst_QPointF::operator_divide()
{
QFETCH(QPointF, point);
QFETCH(qreal, divisor);
QFETCH(QPointF, expected);
QCOMPARE(point / divisor, expected);
point /= divisor;
QCOMPARE(point, expected);
}
static inline qreal dot(const QPointF &a, const QPointF &b)
{
return a.x() * b.x() + a.y() * b.y();
}
void tst_QPointF::division()
{
{
QPointF p(1e-14, 1e-14);
p = p / std::sqrt(dot(p, p));
QCOMPARE(dot(p, p), qreal(1.0));
}
{
QPointF p(1e-14, 1e-14);
p /= std::sqrt(dot(p, p));
QCOMPARE(dot(p, p), qreal(1.0));
}
}
void tst_QPointF::dotProduct_data()
{
QTest::addColumn<QPointF>("point1");
QTest::addColumn<QPointF>("point2");
QTest::addColumn<qreal>("expected");
QTest::newRow("(0, 0) dot (0, 0)") << QPointF(0, 0) << QPointF(0, 0) << qreal(0);
QTest::newRow("(10, 0) dot (0, 10)") << QPointF(10, 0) << QPointF(0, 10)<< qreal(0);
QTest::newRow("(0, 10) dot (10, 0)") << QPointF(0, 10) << QPointF(10, 0) << qreal(0);
QTest::newRow("(10, 20) dot (-10, -20)") << QPointF(10, 20) << QPointF(-10, -20) << qreal(-500);
QTest::newRow("(10.1, 20.2) dot (-10.1, -20.2)") << QPointF(10.1, 20.2) << QPointF(-10.1, -20.2) << qreal(-510.05);
QTest::newRow("(-10.1, -20.2) dot (10.1, 20.2)") << QPointF(-10.1, -20.2) << QPointF(10.1, 20.2) << qreal(-510.05);
}
void tst_QPointF::dotProduct()
{
QFETCH(QPointF, point1);
QFETCH(QPointF, point2);
QFETCH(qreal, expected);
QCOMPARE(QPointF::dotProduct(point1, point2), expected);
}
void tst_QPointF::operator_unary_plus_data()
{
operator_unary_minus_data();
}
void tst_QPointF::operator_unary_plus()
{
QFETCH(QPointF, point);
// Should be a NOOP.
QCOMPARE(+point, point);
}
void tst_QPointF::operator_unary_minus_data()
{
QTest::addColumn<QPointF>("point");
QTest::addColumn<QPointF>("expected");
QTest::newRow("-(0, 0)") << QPointF(0, 0) << QPointF(0, 0);
QTest::newRow("-(-1, 0)") << QPointF(-1, 0) << QPointF(1, 0);
QTest::newRow("-(0, -1)") << QPointF(0, -1) << QPointF(0, 1);
QTest::newRow("-(1.2345, 0)") << QPointF(1.2345, 0) << QPointF(-1.2345, 0);
QTest::newRow("-(-QREAL_MAX, QREAL_MAX)")
<< QPointF(-QREAL_MAX, QREAL_MAX) << QPointF(QREAL_MAX, -QREAL_MAX);
}
void tst_QPointF::operator_unary_minus()
{
QFETCH(QPointF, point);
QFETCH(QPointF, expected);
QCOMPARE(-point, expected);
}
void tst_QPointF::operator_eq_data()
{
QTest::addColumn<QPointF>("point1");
QTest::addColumn<QPointF>("point2");
QTest::addColumn<bool>("expectEqual");
QTest::newRow("(0, 0) == (0, 0)") << QPointF(0, 0) << QPointF(0, 0) << true;
QTest::newRow("(-1, 0) == (-1, 0)") << QPointF(-1, 0) << QPointF(-1, 0) << true;
QTest::newRow("(-1, 0) != (0, 0)") << QPointF(-1, 0) << QPointF(0, 0) << false;
QTest::newRow("(-1, 0) != (0, -1)") << QPointF(-1, 0) << QPointF(0, -1) << false;
QTest::newRow("(-1.125, 0.25) == (-1.125, 0.25)") << QPointF(-1.125, 0.25) << QPointF(-1.125, 0.25) << true;
QTest::newRow("(QREAL_MIN, QREAL_MIN) == (QREAL_MIN, QREAL_MIN)")
<< QPointF(QREAL_MIN, QREAL_MIN) << QPointF(QREAL_MIN, QREAL_MIN) << true;
QTest::newRow("(QREAL_MAX, QREAL_MAX) == (QREAL_MAX, QREAL_MAX)")
<< QPointF(QREAL_MAX, QREAL_MAX) << QPointF(QREAL_MAX, QREAL_MAX) << true;
}
void tst_QPointF::operator_eq()
{
QFETCH(QPointF, point1);
QFETCH(QPointF, point2);
QFETCH(bool, expectEqual);
bool equal = point1 == point2;
QCOMPARE(equal, expectEqual);
bool notEqual = point1 != point2;
QCOMPARE(notEqual, !expectEqual);
}
void tst_QPointF::toPoint_data()
{
QTest::addColumn<QPointF>("pointf");
QTest::addColumn<QPoint>("expected");
QTest::newRow("(0.0, 0.0) ==> (0, 0)") << QPointF(0, 0) << QPoint(0, 0);
QTest::newRow("(0.5, 0.5) ==> (1, 1)") << QPointF(0.5, 0.5) << QPoint(1, 1);
QTest::newRow("(-0.5, -0.5) ==> (-1, -1)") << QPointF(-0.5, -0.5) << QPoint(-1, -1);
}
void tst_QPointF::toPoint()
{
QFETCH(QPointF, pointf);
QFETCH(QPoint, expected);
QCOMPARE(pointf.toPoint(), expected);
}
#ifndef QT_NO_DATASTREAM
void tst_QPointF::stream_data()
{
QTest::addColumn<QPointF>("point");
QTest::newRow("(0, 0.5)") << QPointF(0, 0.5);
QTest::newRow("(-1, 1)") << QPointF(-1, 1);
QTest::newRow("(1, -1)") << QPointF(1, -1);
QTest::newRow("(INT_MIN, INT_MAX)") << QPointF(INT_MIN, INT_MAX);
}
void tst_QPointF::stream()
{
QFETCH(QPointF, point);
QBuffer tmp;
QVERIFY(tmp.open(QBuffer::ReadWrite));
QDataStream stream(&tmp);
// Ensure that stream returned is the same stream we inserted into.
QDataStream& insertionStreamRef(stream << point);
QVERIFY(&insertionStreamRef == &stream);
tmp.seek(0);
QPointF pointFromStream;
QDataStream& extractionStreamRef(stream >> pointFromStream);
QVERIFY(&extractionStreamRef == &stream);
QCOMPARE(pointFromStream, point);
}
#endif
void tst_QPointF::compare()
{
// First test we can scale and maintain difference.
QPointF p1(2.0, 2.0);
QPointF p2(3.0, 3.0);
QVERIFY(p1 != p2);
p1 /= 1e5;
p2 /= 1e5;
QVERIFY(!(p1 == p2));
p1 /= 1e5;
p2 /= 1e5;
QVERIFY(p1 != p2);
p1 /= 1e5;
p2 /= 1e5;
QVERIFY(!(p1 == p2));
p1 /= 2;
p2 /= 3;
QVERIFY(p1 == p2);
// Test we can compare with zero after inexact math
QPointF p3(3.0, 3.0);
p3 *= 0.1;
p3 /= 3;
p3 -= QPointF(0.1, 0.1);
QVERIFY(p3 == QPointF());
// Test we can compare one dimension with hard zero
QVERIFY(QPointF(1.9543e-14, -32.0) == QPointF(0.0, -32.0));
}
void tst_QPointF::structuredBinding()
{
{
QPointF p(1.5, 2.25);
auto [x, y] = p;
QCOMPARE(x, 1.5);
QCOMPARE(y, 2.25);
p.setX(42);
QCOMPARE(x, 1.5);
QCOMPARE(y, 2.25);
p.setY(-123);
QCOMPARE(x, 1.5);
QCOMPARE(y, 2.25);
}
{
QPointF p(1.5, 2.25);
auto &[x, y] = p;
QCOMPARE(x, 1.5);
QCOMPARE(y, 2.25);
x = 42.0;
QCOMPARE(x, 42.0);
QCOMPARE(p.x(), 42.0);
QCOMPARE(p.rx(), 42.0);
QCOMPARE(y, 2.25);
QCOMPARE(p.y(), 2.25);
QCOMPARE(p.ry(), 2.25);
y = -123.5;
QCOMPARE(x, 42.0);
QCOMPARE(p.x(), 42.0);
QCOMPARE(p.rx(), 42.0);
QCOMPARE(y, -123.5);
QCOMPARE(p.y(), -123.5);
QCOMPARE(p.ry(), -123.5);
p.setX(0.0);
QCOMPARE(x, 0.0);
QCOMPARE(p.x(), 0.0);
QCOMPARE(p.rx(), 0.0);
QCOMPARE(y, -123.5);
QCOMPARE(p.y(), -123.5);
QCOMPARE(p.ry(), -123.5);
p.ry() = 10.5;
QCOMPARE(x, 0.0);
QCOMPARE(p.x(), 0.0);
QCOMPARE(p.rx(), 0.0);
QCOMPARE(y, 10.5);
QCOMPARE(p.y(), 10.5);
QCOMPARE(p.ry(), 10.5);
}
}
QTEST_MAIN(tst_QPointF)
#include "tst_qpointf.moc"

View File

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

View File

@ -0,0 +1,62 @@
// 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 <qqueue.h>
class tst_QQueue : public QObject
{
Q_OBJECT
private slots:
void enqueue_dequeue_data();
void enqueue_dequeue();
};
void tst_QQueue::enqueue_dequeue_data()
{
QTest::addColumn<int>("num_items");
QTest::newRow("1") << 11;
QTest::newRow("2") << 211;
QTest::newRow("3") << 1024 + 211;
}
void tst_QQueue::enqueue_dequeue()
{
QFETCH(int, num_items);
int *values = new int[num_items];
QQueue<int> queue_v;
QQueue<int*> queue_p;
QVERIFY(queue_v.empty());
QVERIFY(queue_p.empty());
for (int i = 0; i < num_items; i++ ) {
values[i] = i;
queue_p.enqueue(values + i);
queue_v.enqueue(values[i]);
}
QVERIFY(!queue_p.empty());
QVERIFY(!queue_v.empty());
for (int i = 0; i < num_items; i++ ) {
int v, *p;
v = queue_v.head();
p = queue_p.head();
QCOMPARE(*p, v);
QCOMPARE(v, i);
v = queue_v.dequeue();
p = queue_p.dequeue();
QCOMPARE(*p, v);
QCOMPARE(v, values[i]);
}
QVERIFY(queue_v.empty());
QVERIFY(queue_p.empty());
delete[] values;
}
QTEST_APPLESS_MAIN(tst_QQueue)
#include "tst_qqueue.moc"

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,408 @@
// 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 <QBuffer>
#include <QVarLengthArray>
#include <private/qringbuffer_p.h>
#include <qlist.h>
class tst_QRingBuffer : public QObject
{
Q_OBJECT
private slots:
void constructing();
void usingInVector();
void usingInVarLengthArray();
void readPointerAtPositionWriteRead();
void readPointerAtPositionEmptyRead();
void readPointerAtPositionWithHead();
void readPointerAtPositionReadTooMuch();
void sizeWhenReservedAndChopped();
void sizeWhenReserved();
void free();
void reserveAndRead();
void reserveAndReadInPacketMode();
void reserveFrontAndRead();
void chop();
void readPointerValidity();
void ungetChar();
void indexOf();
void appendAndRead();
void peek();
void readLine();
};
void tst_QRingBuffer::constructing()
{
QRingBuffer ringBuffer;
const int chunkSize = ringBuffer.chunkSize();
ringBuffer.setChunkSize(0);
QCOMPARE(ringBuffer.chunkSize(), Q_INT64_C(0));
ringBuffer.setChunkSize(chunkSize);
QCOMPARE(ringBuffer.chunkSize(), chunkSize);
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
QVERIFY(ringBuffer.isEmpty());
QCOMPARE(ringBuffer.nextDataBlockSize(), Q_INT64_C(0));
QVERIFY(ringBuffer.readPointer() == nullptr);
QCOMPARE(ringBuffer.skip(5), Q_INT64_C(0));
QCOMPARE(ringBuffer.read(), QByteArray());
QCOMPARE(ringBuffer.getChar(), -1);
QVERIFY(!ringBuffer.canReadLine());
char buf[5];
QCOMPARE(ringBuffer.peek(buf, sizeof(buf)), Q_INT64_C(0));
}
void tst_QRingBuffer::usingInVector()
{
QRingBuffer ringBuffer;
std::vector<QRingBuffer> buffers;
ringBuffer.reserve(5);
buffers.push_back(std::move(ringBuffer));
QCOMPARE(buffers[0].size(), Q_INT64_C(5));
}
void tst_QRingBuffer::usingInVarLengthArray()
{
QRingBuffer ringBuffer;
QVarLengthArray<QRingBuffer, 42> buffers;
ringBuffer.reserve(5);
buffers.push_back(std::move(ringBuffer));
QCOMPARE(buffers[0].size(), Q_INT64_C(5));
}
void tst_QRingBuffer::sizeWhenReserved()
{
QRingBuffer ringBuffer;
ringBuffer.reserve(5);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5));
}
void tst_QRingBuffer::sizeWhenReservedAndChopped()
{
QRingBuffer ringBuffer;
ringBuffer.reserve(31337);
ringBuffer.chop(31337);
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
}
void tst_QRingBuffer::readPointerAtPositionReadTooMuch()
{
QRingBuffer ringBuffer;
qint64 length;
const char *buf = ringBuffer.readPointerAtPosition(42, length);
QVERIFY(buf == 0);
QCOMPARE(length, Q_INT64_C(0));
}
void tst_QRingBuffer::readPointerAtPositionWithHead()
{
QRingBuffer ringBuffer;
char *buf = ringBuffer.reserve(4);
memcpy (buf, "0123", 4);
ringBuffer.free(2);
// ringBuffer should have stayed the same except
// its head it had moved to position 2
qint64 length;
const char* buf2 = ringBuffer.readPointerAtPosition(0, length);
QCOMPARE(length, Q_INT64_C(2));
QCOMPARE(*buf2, '2');
QCOMPARE(*(buf2 + 1), '3');
// advance 2 more, ringBuffer should be empty then
ringBuffer.free(2);
buf2 = ringBuffer.readPointerAtPosition(0, length);
QCOMPARE(length, Q_INT64_C(0));
QVERIFY(buf2 == 0);
// check buffer with 2 blocks
memcpy(ringBuffer.reserve(4), "0123", 4);
ringBuffer.append(QByteArray("45678", 5));
ringBuffer.free(3);
buf2 = ringBuffer.readPointerAtPosition(Q_INT64_C(1), length);
QCOMPARE(length, Q_INT64_C(5));
}
void tst_QRingBuffer::readPointerAtPositionEmptyRead()
{
QRingBuffer ringBuffer;
qint64 length;
const char *buf = ringBuffer.readPointerAtPosition(0, length);
QVERIFY(buf == 0);
QCOMPARE(length, Q_INT64_C(0));
}
void tst_QRingBuffer::readPointerAtPositionWriteRead()
{
//create some data
QBuffer inData;
inData.open(QIODevice::ReadWrite);
inData.putChar(0x42);
inData.putChar(0x23);
inData.write("Qt rocks!");
for (int i = 0; i < 5000; i++)
inData.write("Number " + QByteArray::number(i));
inData.reset();
QVERIFY(inData.size() > 0);
//put the inData in the QRingBuffer
QRingBuffer ringBuffer;
qint64 remaining = inData.size();
while (remaining > 0) {
// write in chunks of 50 bytes
// this ensures there will be multiple QByteArrays inside the QRingBuffer
// since QRingBuffer is then only using individual arrays of around 4000 bytes
qint64 thisWrite = qMin(remaining, Q_INT64_C(50));
char *pos = ringBuffer.reserve(thisWrite);
inData.read(pos, thisWrite);
remaining -= thisWrite;
}
// was data put into it?
QVERIFY(ringBuffer.size() > 0);
QCOMPARE(ringBuffer.size(), inData.size());
//read from the QRingBuffer in loop, put back into another QBuffer
QBuffer outData;
outData.open(QIODevice::ReadWrite);
remaining = ringBuffer.size();
while (remaining > 0) {
qint64 thisRead;
// always try to read as much as possible
const char *buf = ringBuffer.readPointerAtPosition(ringBuffer.size() - remaining, thisRead);
outData.write(buf, thisRead);
remaining -= thisRead;
}
outData.reset();
QVERIFY(outData.size() > 0);
// was the data read from the QRingBuffer the same as the one written into it?
QCOMPARE(outData.size(), inData.size());
QVERIFY(outData.buffer().startsWith(inData.buffer()));
}
void tst_QRingBuffer::free()
{
QRingBuffer ringBuffer;
// make three byte arrays with different sizes
ringBuffer.reserve(4096);
ringBuffer.reserve(2048);
ringBuffer.append(QByteArray("01234", 5));
ringBuffer.free(1);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4095) + 2048 + 5);
ringBuffer.free(4096);
QCOMPARE(ringBuffer.size(), Q_INT64_C(2047) + 5);
ringBuffer.free(48);
ringBuffer.free(2000);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4));
QVERIFY(memcmp(ringBuffer.readPointer(), "1234", 4) == 0);
}
void tst_QRingBuffer::reserveAndRead()
{
QRingBuffer ringBuffer;
// fill buffer with an arithmetic progression
for (int i = 1; i < 256; ++i) {
QByteArray ba(i, char(i));
char *ringPos = ringBuffer.reserve(i);
QVERIFY(ringPos);
memcpy(ringPos, ba.constData(), i);
}
// readback and check stored data
for (int i = 1; i < 256; ++i) {
QByteArray ba;
ba.resize(i);
qint64 thisRead = ringBuffer.read(ba.data(), i);
QCOMPARE(thisRead, qint64(i));
QCOMPARE(ba.count(char(i)), i);
}
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
}
void tst_QRingBuffer::reserveAndReadInPacketMode()
{
QRingBuffer ringBuffer(0);
// try to allocate 255 buffers
for (int i = 1; i < 256; ++i) {
char *ringPos = ringBuffer.reserve(i);
QVERIFY(ringPos);
}
// count and check the size of stored buffers
int buffersCount = 0;
while (!ringBuffer.isEmpty()) {
QByteArray ba = ringBuffer.read();
++buffersCount;
QCOMPARE(ba.size(), buffersCount);
}
QCOMPARE(buffersCount, 255);
}
void tst_QRingBuffer::reserveFrontAndRead()
{
QRingBuffer ringBuffer;
// fill buffer with an arithmetic progression
for (int i = 1; i < 256; ++i) {
QByteArray ba(i, char(i));
char *ringPos = ringBuffer.reserveFront(i);
QVERIFY(ringPos);
memcpy(ringPos, ba.constData(), i);
}
// readback and check stored data
for (int i = 255; i > 0; --i) {
QByteArray ba;
ba.resize(i);
qint64 thisRead = ringBuffer.read(ba.data(), i);
QCOMPARE(thisRead, qint64(i));
QCOMPARE(ba.count(char(i)), i);
}
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
}
void tst_QRingBuffer::chop()
{
QRingBuffer ringBuffer;
// make three byte arrays with different sizes
ringBuffer.append(QByteArray("01234", 5));
ringBuffer.reserve(2048);
ringBuffer.reserve(4096);
ringBuffer.chop(1);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5) + 2048 + 4095);
ringBuffer.chop(4096);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5) + 2047);
ringBuffer.chop(48);
ringBuffer.chop(2000);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4));
QVERIFY(memcmp(ringBuffer.readPointer(), "0123", 4) == 0);
}
void tst_QRingBuffer::readPointerValidity()
{
QRingBuffer ringBuffer(16);
QByteArray ba("Hello world!");
ringBuffer.append(ba);
const char *ptr = ringBuffer.readPointer();
ba.clear();
ringBuffer.reserve(32);
QVERIFY(ptr == ringBuffer.readPointer());
ringBuffer.reserveFront(32);
qint64 dummy;
QVERIFY(ptr == ringBuffer.readPointerAtPosition(32, dummy));
}
void tst_QRingBuffer::ungetChar()
{
QRingBuffer ringBuffer(16);
for (int i = 1; i < 32; ++i)
ringBuffer.putChar(char(i));
for (int i = 1; i < 31; ++i) {
int c = ringBuffer.getChar();
QCOMPARE(c, 1);
ringBuffer.getChar();
ringBuffer.ungetChar(char(c)); // unget first char
}
QCOMPARE(ringBuffer.size(), Q_INT64_C(1));
}
void tst_QRingBuffer::indexOf()
{
QRingBuffer ringBuffer(16);
for (int i = 1; i < 256; ++i)
ringBuffer.putChar(char(i));
for (int i = 1; i < 256; ++i) {
qint64 index = ringBuffer.indexOf(char(i));
QCOMPARE(index, qint64(i - 1));
QCOMPARE(ringBuffer.indexOf(char(i), i, i >> 1), index);
QCOMPARE(ringBuffer.indexOf(char(i), 256, i), Q_INT64_C(-1));
QCOMPARE(ringBuffer.indexOf(char(i), i - 1), -1); // test for absent char
}
}
void tst_QRingBuffer::appendAndRead()
{
QRingBuffer ringBuffer;
QByteArray ba1("Hello world!");
QByteArray ba2("Test string.");
QByteArray ba3("0123456789");
ringBuffer.append(ba1);
ringBuffer.append(ba2);
ringBuffer.append(ba3);
QCOMPARE(ringBuffer.read(), ba1);
QCOMPARE(ringBuffer.read(), ba2);
QCOMPARE(ringBuffer.read(), ba3);
}
void tst_QRingBuffer::peek()
{
QRingBuffer ringBuffer;
QByteArray testBuffer;
// fill buffer with an arithmetic progression
for (int i = 1; i < 256; ++i) {
char *ringPos = ringBuffer.reserve(i);
QVERIFY(ringPos);
memset(ringPos, i, i);
testBuffer.append(ringPos, i);
}
// check stored data
QByteArray resultBuffer;
int peekPosition = testBuffer.size();
for (int i = 1; i < 256; ++i) {
QByteArray ba(i, 0);
peekPosition -= i;
qint64 thisPeek = ringBuffer.peek(ba.data(), i, peekPosition);
QCOMPARE(thisPeek, qint64(i));
resultBuffer.prepend(ba);
}
QCOMPARE(resultBuffer, testBuffer);
}
void tst_QRingBuffer::readLine()
{
QRingBuffer ringBuffer;
QByteArray ba1("Hello world!\n", 13);
QByteArray ba2("\n", 1);
QByteArray ba3("Test string.", 12);
QByteArray ba4("0123456789", 10);
ringBuffer.append(ba1);
ringBuffer.append(ba2);
ringBuffer.append(ba3 + ba4 + ba2);
char stringBuf[102];
stringBuf[101] = 0; // non-crash terminator
QCOMPARE(ringBuffer.readLine(stringBuf, sizeof(stringBuf) - 2), qint64(ba1.size()));
QCOMPARE(QByteArray(stringBuf, int(strlen(stringBuf))), ba1);
// check first empty string reading
stringBuf[0] = char(0xFF);
QCOMPARE(ringBuffer.readLine(stringBuf, int(sizeof(stringBuf)) - 2), qint64(ba2.size()));
QCOMPARE(stringBuf[0], ba2.at(0));
QCOMPARE(ringBuffer.readLine(stringBuf, int(sizeof(stringBuf)) - 2),
qint64(ba3.size() + ba4.size() + ba2.size()));
QCOMPARE(QByteArray(stringBuf, int(strlen(stringBuf))), ba3 + ba4 + ba2);
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
}
QTEST_APPLESS_MAIN(tst_QRingBuffer)
#include "tst_qringbuffer.moc"

View File

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

View File

@ -0,0 +1,467 @@
// 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 <QtCore/QScopedPointer>
/*!
\class tst_QScopedPointer
\internal
\since 4.6
\brief Tests class QScopedPointer.
*/
class tst_QScopedPointer : public QObject
{
Q_OBJECT
private Q_SLOTS:
void defaultConstructor();
void dataOnDefaultConstructed();
void useSubClassInConstructor();
void dataOnValue();
void dataSignature();
void reset();
void dereferenceOperator();
void dereferenceOperatorSignature();
void pointerOperator();
void pointerOperatorSignature();
void negationOperator();
void negationOperatorSignature();
void operatorBool();
void operatorBoolSignature();
void isNull();
void isNullSignature();
void objectSize();
void comparison();
void array();
// TODO instanciate on const object
// Tests for deprecated APIs
#if QT_DEPRECATED_SINCE(6, 1)
void deprecatedTake();
#endif // QT_DEPRECATED_SINCE(6, 1)
};
void tst_QScopedPointer::defaultConstructor()
{
/* Check that the members, one, is correctly initialized. */
QScopedPointer<int> p;
QCOMPARE(p.data(), static_cast<int *>(0));
QCOMPARE(p.get(), static_cast<int *>(0));
}
void tst_QScopedPointer::dataOnDefaultConstructed()
{
QScopedPointer<int> p;
QCOMPARE(p.data(), static_cast<int *>(0));
QCOMPARE(p.get(), static_cast<int *>(0));
}
class MyClass
{
};
class MySubClass : public MyClass
{
};
void tst_QScopedPointer::useSubClassInConstructor()
{
/* Use a syntax which users typically would do. */
QScopedPointer<MyClass> p(new MySubClass());
}
void tst_QScopedPointer::dataOnValue()
{
int *const rawPointer = new int(5);
QScopedPointer<int> p(rawPointer);
QCOMPARE(p.data(), rawPointer);
}
void tst_QScopedPointer::dataSignature()
{
const QScopedPointer<int> p;
/* data() should be const. */
p.data();
}
void tst_QScopedPointer::reset()
{
/* Call reset() on a default constructed value. */
{
QScopedPointer<int> p;
p.reset();
QCOMPARE(p.data(), static_cast<int *>(0));
QCOMPARE(p.get(), static_cast<int *>(0));
}
/* Call reset() on an active value. */
{
QScopedPointer<int> p(new int(3));
p.reset();
QCOMPARE(p.data(), static_cast<int *>(0));
QCOMPARE(p.get(), static_cast<int *>(0));
}
/* Call reset() with a value, on an active value. */
{
QScopedPointer<int> p(new int(3));
int *const value = new int(9);
p.reset(value);
QCOMPARE(*p.data(), 9);
QCOMPARE(*p.get(), 9);
}
/* Call reset() with a value, on default constructed value. */
{
QScopedPointer<int> p;
int *const value = new int(9);
p.reset(value);
QCOMPARE(*p.data(), 9);
QCOMPARE(*p.get(), 9);
}
}
class AbstractClass
{
public:
virtual ~AbstractClass()
{
}
virtual int member() const = 0;
};
class SubClass : public AbstractClass
{
public:
virtual int member() const override
{
return 5;
}
};
void tst_QScopedPointer::dereferenceOperator()
{
/* Dereference a basic value. */
{
QScopedPointer<int> p(new int(5));
const int value2 = *p;
QCOMPARE(value2, 5);
}
/* Dereference a pointer to an abstract class. This verifies
* that the operator returns a reference, when compiling
* with MSVC 2005. */
{
QScopedPointer<AbstractClass> p(new SubClass());
QCOMPARE((*p).member(), 5);
}
}
void tst_QScopedPointer::dereferenceOperatorSignature()
{
/* The operator should be const. */
{
const QScopedPointer<int> p(new int(5));
*p;
}
/* A reference should be returned, not a value. */
{
const QScopedPointer<int> p(new int(5));
Q_UNUSED(static_cast<int &>(*p));
}
/* Instantiated on a const object, the returned object is a const reference. */
{
const QScopedPointer<const int> p(new int(5));
Q_UNUSED(static_cast<const int &>(*p));
}
}
class AnyForm
{
public:
int value;
};
void tst_QScopedPointer::pointerOperator()
{
QScopedPointer<AnyForm> p(new AnyForm());
p->value = 5;
QCOMPARE(p->value, 5);
}
void tst_QScopedPointer::pointerOperatorSignature()
{
/* The operator should be const. */
const QScopedPointer<AnyForm> p(new AnyForm);
p->value = 5;
QVERIFY(p->value);
}
void tst_QScopedPointer::negationOperator()
{
/* Invoke on default constructed value. */
{
QScopedPointer<int> p;
QVERIFY(!p);
}
/* Invoke on a value. */
{
QScopedPointer<int> p(new int(2));
QCOMPARE(!p, false);
}
}
void tst_QScopedPointer::negationOperatorSignature()
{
/* The signature should be const. */
const QScopedPointer<int> p;
!p;
/* The return value should be bool. */
Q_UNUSED(static_cast<bool>(!p));
}
void tst_QScopedPointer::operatorBool()
{
/* Invoke on default constructed value. */
{
QScopedPointer<int> p;
QCOMPARE(bool(p), false);
}
/* Invoke on active value. */
{
QScopedPointer<int> p(new int(3));
QVERIFY(p);
}
}
void tst_QScopedPointer::operatorBoolSignature()
{
/* The signature should be const and return bool. */
const QScopedPointer<int> p;
(void)static_cast<bool>(p);
}
void tst_QScopedPointer::isNull()
{
/* Invoke on default constructed value. */
{
QScopedPointer<int> p;
QVERIFY(p.isNull());
QVERIFY(p == nullptr);
QVERIFY(nullptr == p);
}
/* Invoke on a set value. */
{
QScopedPointer<int> p(new int(69));
QVERIFY(!p.isNull());
QVERIFY(p != nullptr);
QVERIFY(nullptr != p);
}
}
void tst_QScopedPointer::isNullSignature()
{
const QScopedPointer<int> p(new int(69));
/* The signature should be const and return bool. */
Q_UNUSED(static_cast<bool>(p.isNull()));
}
void tst_QScopedPointer::objectSize()
{
/* The size of QScopedPointer should be the same as one pointer. */
QCOMPARE(sizeof(QScopedPointer<int>), sizeof(void *));
}
struct RefCounted
{
RefCounted()
: ref(0)
{
instanceCount.ref();
}
RefCounted(RefCounted const &)
: ref(0)
{
instanceCount.ref();
}
~RefCounted()
{
QVERIFY( ref.loadRelaxed() == 0 );
instanceCount.deref();
}
RefCounted &operator=(RefCounted const &)
{
return *this;
}
QAtomicInt ref;
static QAtomicInt instanceCount;
};
QAtomicInt RefCounted::instanceCount = 0;
template <class A1, class A2, class B>
void scopedPointerComparisonTest(const A1 &a1, const A2 &a2, const B &b)
{
// test equality on equal pointers
QVERIFY(a1 == a2);
QVERIFY(a2 == a1);
// test inequality on equal pointers
QVERIFY(!(a1 != a2));
QVERIFY(!(a2 != a1));
// test equality on unequal pointers
QVERIFY(!(a1 == b));
QVERIFY(!(a2 == b));
QVERIFY(!(b == a1));
QVERIFY(!(b == a2));
// test inequality on unequal pointers
QVERIFY(b != a1);
QVERIFY(b != a2);
QVERIFY(a1 != b);
QVERIFY(a2 != b);
}
// tst_QScopedPointer::comparison creates two QScopedPointers referring to the
// same memory. This will lead to double-deletion error during cleanup if we
// use a default QScopedPointer{Array}Deleter. This DummyDeleter does nothing,
// so we can safely reference the same memory from multiple QScopedPointer
// instances, and manage the memory manually.
// That is fine for the comparison() test, because its goal is to check the
// object's (in)equality, not the memory management
struct DummyDeleter
{
static inline void cleanup(RefCounted *) noexcept {}
void operator()(RefCounted *pointer) const noexcept
{
cleanup(pointer);
}
};
void tst_QScopedPointer::comparison()
{
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
{
auto a = std::make_unique<RefCounted>();
auto b = std::make_unique<RefCounted>();
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
QScopedPointer<RefCounted, DummyDeleter> pa1(a.get());
QScopedPointer<RefCounted, DummyDeleter> pa2(a.get());
QScopedPointer<RefCounted, DummyDeleter> pb(b.get());
scopedPointerComparisonTest(pa1, pa1, pb);
scopedPointerComparisonTest(pa2, pa2, pb);
scopedPointerComparisonTest(pa1, pa2, pb);
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
}
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
{
auto a = std::make_unique<RefCounted[]>(42);
auto b = std::make_unique<RefCounted[]>(43);
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 );
QScopedArrayPointer<RefCounted, DummyDeleter> pa1(a.get());
QScopedArrayPointer<RefCounted, DummyDeleter> pa2(a.get());
QScopedArrayPointer<RefCounted, DummyDeleter> pb(b.get());
scopedPointerComparisonTest(pa1, pa2, pb);
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 85 );
}
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
{
RefCounted *a = new RefCounted;
RefCounted *b = new RefCounted;
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
QSharedDataPointer<RefCounted> pa1(a);
QSharedDataPointer<RefCounted> pa2(a);
QSharedDataPointer<RefCounted> pb(b);
QCOMPARE( a->ref.loadRelaxed(), 2 );
QCOMPARE( b->ref.loadRelaxed(), 1 );
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
scopedPointerComparisonTest(pa1, pa2, pb);
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 2 );
}
QCOMPARE( RefCounted::instanceCount.loadRelaxed(), 0 );
}
void tst_QScopedPointer::array()
{
int instCount = RefCounted::instanceCount.loadRelaxed();
{
QScopedArrayPointer<RefCounted> array;
array.reset(new RefCounted[42]);
QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed());
}
QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
{
QScopedArrayPointer<RefCounted> array(new RefCounted[42]);
QCOMPARE(instCount + 42, RefCounted::instanceCount.loadRelaxed());
array.reset(new RefCounted[28]);
QCOMPARE(instCount + 28, RefCounted::instanceCount.loadRelaxed());
array.reset(0);
QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
}
QCOMPARE(instCount, RefCounted::instanceCount.loadRelaxed());
}
#if QT_DEPRECATED_SINCE(6, 1)
void tst_QScopedPointer::deprecatedTake()
{
RefCounted *a = new RefCounted;
QScopedPointer<RefCounted> pa1(a);
QScopedPointer<RefCounted> pa2(a);
QCOMPARE(RefCounted::instanceCount.loadRelaxed(), 1);
QT_IGNORE_DEPRECATIONS(pa2.take();)
// check that pa2 holds nullptr, but the memory was not released
QVERIFY(pa2.isNull());
QCOMPARE(RefCounted::instanceCount.loadRelaxed(), 1);
}
#endif // QT_DEPRECATED_SINCE(6, 1)
QTEST_MAIN(tst_QScopedPointer)
#include "tst_qscopedpointer.moc"

View File

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

View File

@ -0,0 +1,182 @@
// 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 <QtCore/QScopedValueRollback>
/*!
\class tst_QScopedValueRollback
\internal
\since 4.8
\brief Tests class QScopedValueRollback.
*/
class tst_QScopedValueRollback : public QObject
{
Q_OBJECT
private Q_SLOTS:
void leavingScope();
void leavingScopeAfterCommit();
void rollbackToPreviousCommit();
void exceptions();
void earlyExitScope();
void moveOnly();
private:
void earlyExitScope_helper(int exitpoint, int &member);
};
void tst_QScopedValueRollback::leavingScope()
{
int i = 0;
bool b = false;
bool b2 = false;
QString s("This is useful");
//test rollback on going out of scope
{
QScopedValueRollback<int> ri(i);
QScopedValueRollback<bool> rb(b);
QScopedValueRollback<bool> rb2(b2, true);
QScopedValueRollback<QString> rs(s);
QCOMPARE(b, false);
QCOMPARE(b2, true);
QCOMPARE(i, 0);
QCOMPARE(s, QString("This is useful"));
b = true;
i = 1;
s = "Useless";
QCOMPARE(b, true);
QCOMPARE(i, 1);
QCOMPARE(s, QString("Useless"));
}
QCOMPARE(b, false);
QCOMPARE(b2, false);
QCOMPARE(i, 0);
QCOMPARE(s, QString("This is useful"));
}
void tst_QScopedValueRollback::leavingScopeAfterCommit()
{
int i = 0;
bool b = false;
QString s("This is useful");
//test rollback on going out of scope
{
QScopedValueRollback<int> ri(i);
QScopedValueRollback<bool> rb(b);
QScopedValueRollback<QString> rs(s);
QCOMPARE(b, false);
QCOMPARE(i, 0);
QCOMPARE(s, QString("This is useful"));
b = true;
i = 1;
s = "Useless";
QCOMPARE(b, true);
QCOMPARE(i, 1);
QCOMPARE(s, QString("Useless"));
ri.commit();
rb.commit();
rs.commit();
}
QCOMPARE(b, true);
QCOMPARE(i, 1);
QCOMPARE(s, QString("Useless"));
}
void tst_QScopedValueRollback::rollbackToPreviousCommit()
{
int i=0;
{
QScopedValueRollback<int> ri(i);
i++;
ri.commit();
i++;
}
QCOMPARE(i,1);
{
QScopedValueRollback<int> ri1(i);
i++;
ri1.commit();
i++;
ri1.commit();
i++;
}
QCOMPARE(i,3);
}
void tst_QScopedValueRollback::exceptions()
{
bool b = false;
bool caught = false;
QT_TRY
{
QScopedValueRollback<bool> rb(b);
b = true;
QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop
rb.commit(); //if Qt compiled without exceptions, true is committed
}
QT_CATCH(...)
{
caught = true;
}
QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise
}
void tst_QScopedValueRollback::earlyExitScope()
{
int i=0;
int j=0;
while (true) {
QScopedValueRollback<int> ri(i);
i++;
j=i;
if (i>8) break;
ri.commit();
}
QCOMPARE(i,8);
QCOMPARE(j,9);
for (i = 0; i < 5; i++) {
j=1;
earlyExitScope_helper(i,j);
QCOMPARE(j, 1<<i);
}
}
void tst_QScopedValueRollback::earlyExitScope_helper(int exitpoint, int& member)
{
QScopedValueRollback<int> r(member);
member *= 2;
if (exitpoint == 0)
return;
r.commit();
member *= 2;
if (exitpoint == 1)
return;
r.commit();
member *= 2;
if (exitpoint == 2)
return;
r.commit();
member *= 2;
if (exitpoint == 3)
return;
r.commit();
}
void tst_QScopedValueRollback::moveOnly()
{
std::unique_ptr<int> uniquePtr;
std::unique_ptr<int> newVal(new int(5));
QVERIFY(!uniquePtr);
{
QScopedValueRollback<std::unique_ptr<int>> r(uniquePtr, std::move(newVal));
QVERIFY(uniquePtr);
}
QVERIFY(!uniquePtr);
}
QTEST_MAIN(tst_QScopedValueRollback)
#include "tst_qscopedvaluerollback.moc"

View File

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

View File

@ -0,0 +1,155 @@
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sérgio Martins <sergio.martins@kdab.com>
// 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 <QtCore/QScopeGuard>
/*!
\class tst_QScopeGuard
\internal
\since 5.11
\brief Tests class QScopeGuard and function qScopeGuard
*/
class tst_QScopeGuard : public QObject
{
Q_OBJECT
private Q_SLOTS:
void construction();
void constructionFromLvalue();
void constructionFromRvalue();
void leavingScope();
void exceptions();
};
void func()
{
}
int intFunc()
{
return 0;
}
[[nodiscard]] int noDiscardFunc()
{
return 0;
}
struct Callable
{
Callable() { }
Callable(const Callable &other)
{
Q_UNUSED(other);
++copied;
}
Callable(Callable &&other)
{
Q_UNUSED(other);
++moved;
}
void operator()() { }
static int copied;
static int moved;
static void resetCounts()
{
copied = 0;
moved = 0;
}
};
int Callable::copied = 0;
int Callable::moved = 0;
static int s_globalState = 0;
void tst_QScopeGuard::construction()
{
QScopeGuard fromLambda([] { });
QScopeGuard fromFunction(func);
QScopeGuard fromFunctionPointer(&func);
QScopeGuard fromNonVoidFunction(intFunc);
QScopeGuard fromNoDiscardFunction(noDiscardFunc);
#ifndef __apple_build_version__
QScopeGuard fromStdFunction{std::function<void()>(func)};
std::function<void()> stdFunction(func);
QScopeGuard fromNamedStdFunction(stdFunction);
#endif
}
void tst_QScopeGuard::constructionFromLvalue()
{
Callable::resetCounts();
{
Callable callable;
QScopeGuard guard(callable);
}
QCOMPARE(Callable::copied, 1);
QCOMPARE(Callable::moved, 0);
Callable::resetCounts();
{
Callable callable;
auto guard = qScopeGuard(callable);
}
QCOMPARE(Callable::copied, 1);
QCOMPARE(Callable::moved, 0);
}
void tst_QScopeGuard::constructionFromRvalue()
{
Callable::resetCounts();
{
Callable callable;
QScopeGuard guard(std::move(callable));
}
QCOMPARE(Callable::copied, 0);
QCOMPARE(Callable::moved, 1);
Callable::resetCounts();
{
Callable callable;
auto guard = qScopeGuard(std::move(callable));
}
QCOMPARE(Callable::copied, 0);
QCOMPARE(Callable::moved, 1);
}
void tst_QScopeGuard::leavingScope()
{
auto cleanup = qScopeGuard([] { s_globalState++; QCOMPARE(s_globalState, 3); });
QCOMPARE(s_globalState, 0);
{
auto cleanup = qScopeGuard([] { s_globalState++; });
QCOMPARE(s_globalState, 0);
}
QCOMPARE(s_globalState, 1);
s_globalState++;
}
void tst_QScopeGuard::exceptions()
{
s_globalState = 0;
bool caught = false;
QT_TRY
{
auto cleanup = qScopeGuard([] { s_globalState++; });
QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop
s_globalState = 100;
}
QT_CATCH(...)
{
caught = true;
QCOMPARE(s_globalState, 1);
}
QVERIFY((caught && s_globalState == 1) || (!caught && s_globalState == 101));
}
QTEST_MAIN(tst_QScopeGuard)
#include "tst_qscopeguard.moc"

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,717 @@
// 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 "externaltests.h"
#include <QtCore/QTemporaryFile>
#include <QtCore/QTemporaryDir>
#if QT_CONFIG(process)
# include <QtCore/QProcess>
#endif
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QLibraryInfo>
#include <QtCore/QThread>
#ifndef DEFAULT_MAKESPEC
# error DEFAULT_MAKESPEC not defined
#endif
#ifdef Q_OS_UNIX
# include <fcntl.h>
# include <unistd.h>
#endif
enum {
QMakeTimeout = 300000, // 5 minutes
CompileTimeout = 600000, // 10 minutes
RunTimeout = 300000 // 5 minutes
};
static QString makespec()
{
static const char default_makespec[] = DEFAULT_MAKESPEC;
if (default_makespec[0] == '/')
return QString::fromLatin1(default_makespec);
const char *p;
for (p = default_makespec + sizeof(default_makespec) - 1; p >= default_makespec; --p)
if (*p == '/' || *p == '\\')
break;
return QString::fromLatin1(p + 1);
}
QT_BEGIN_NAMESPACE
namespace QTest {
#if QT_CONFIG(process)
static void ensureStopped(QProcess &process)
{
if (process.state() == QProcess::Running) {
process.terminate();
QThread::msleep(20);
if (process.state() == QProcess::Running)
process.kill();
}
}
# ifdef Q_OS_UNIX
class QExternalProcess: public QProcess
{
public:
QExternalProcess()
{
setChildProcessModifier([this]() {
// run in user code
if (processChannelMode() == ForwardedChannels) {
// reopen /dev/tty into stdin
int fd = ::open("/dev/tty", O_RDONLY);
if (fd == -1)
return;
::dup2(fd, 0);
::close(fd);
}
});
}
};
# else
using QExternalProcess = QProcess;
# endif
#endif // QT_CONFIG(process)
class QExternalTestPrivate
{
public:
QExternalTestPrivate()
: qtModules(QExternalTest::QtCore | QExternalTest::QtGui | QExternalTest::QtTest),
appType(QExternalTest::AutoApplication),
temporaryDir(0), exitCode(-1)
{
}
~QExternalTestPrivate()
{
clear();
}
enum Target { Compile, Link, Run };
QList<QByteArray> qmakeLines;
QStringList extraProgramSources;
QByteArray programHeader;
QExternalTest::QtModules qtModules;
QExternalTest::ApplicationType appType;
QString temporaryDirPath;
QTemporaryDir *temporaryDir;
QByteArray sourceCode;
QByteArray std_out;
QByteArray std_err;
int exitCode;
QExternalTest::Stage failedStage;
void clear();
bool tryCompile(const QByteArray &body);
bool tryLink(const QByteArray &body);
bool tryRun(const QByteArray &body);
private:
void removeTemporaryDirectory();
bool createTemporaryDirectory();
bool prepareSourceCode(const QByteArray &body);
bool createProjectFile();
bool runQmake();
bool runMake(Target target, int timeout);
bool commonSetup(const QByteArray &body);
};
QExternalTest::QExternalTest()
: d(new QExternalTestPrivate)
{
}
QExternalTest::~QExternalTest()
{
delete d;
}
QList<QByteArray> QExternalTest::qmakeSettings() const
{
return d->qmakeLines;
}
void QExternalTest::setQmakeSettings(const QList<QByteArray> &settings)
{
d->qmakeLines = settings;
}
QExternalTest::QtModules QExternalTest::qtModules() const
{
return d->qtModules;
}
void QExternalTest::setQtModules(QtModules modules)
{
d->qtModules = modules;
}
QExternalTest::ApplicationType QExternalTest::applicationType() const
{
return d->appType;
}
void QExternalTest::setApplicationType(ApplicationType type)
{
d->appType = type;
}
QStringList QExternalTest::extraProgramSources() const
{
return d->extraProgramSources;
}
void QExternalTest::setExtraProgramSources(const QStringList &extra)
{
d->extraProgramSources = extra;
}
QByteArray QExternalTest::programHeader() const
{
return d->programHeader;
}
void QExternalTest::setProgramHeader(const QByteArray &header)
{
d->programHeader = header;
}
bool QExternalTest::tryCompile(const QByteArray &body)
{
return d->tryCompile(body) && d->exitCode == 0;
}
bool QExternalTest::tryLink(const QByteArray &body)
{
return d->tryLink(body) && d->exitCode == 0;
}
bool QExternalTest::tryRun(const QByteArray &body)
{
return d->tryRun(body) && d->exitCode == 0;
}
bool QExternalTest::tryCompileFail(const QByteArray &body)
{
return d->tryCompile(body) && d->exitCode != 0;
}
bool QExternalTest::tryLinkFail(const QByteArray &body)
{
return d->tryLink(body) && d->exitCode != 0;
}
bool QExternalTest::tryRunFail(const QByteArray &body)
{
return d->tryRun(body) && d->exitCode != 0;
}
QExternalTest::Stage QExternalTest::failedStage() const
{
return d->failedStage;
}
int QExternalTest::exitCode() const
{
return d->exitCode;
}
QByteArray QExternalTest::fullProgramSource() const
{
return d->sourceCode;
}
QByteArray QExternalTest::standardOutput() const
{
return d->std_out;
}
QByteArray QExternalTest::standardError() const
{
return d->std_err;
}
QString QExternalTest::errorReport() const
{
const char *stage = 0;
switch (d->failedStage) {
case FileStage:
stage = "creating files";
break;
case QmakeStage:
stage = "executing qmake";
break;
case CompilationStage:
stage = "during compilation";
break;
case LinkStage:
stage = "during linking";
break;
case RunStage:
stage = "executing program";
break;
}
QString report = QString::fromLatin1(
"External test failed %1 with exit code %4\n"
"==== standard error: ====\n"
"%2\n"
"==== standard output: ====\n"
"%3\n"
"==== ====\n");
return report.arg(QString::fromLatin1(stage),
QString::fromLocal8Bit(d->std_err),
QString::fromLocal8Bit(d->std_out))
.arg(d->exitCode);
}
// actual execution code
void QExternalTestPrivate::clear()
{
delete temporaryDir;
temporaryDir = 0;
sourceCode.clear();
std_out.clear();
std_err.clear();
exitCode = -1;
failedStage = QExternalTest::FileStage;
}
bool QExternalTestPrivate::prepareSourceCode(const QByteArray &body)
{
sourceCode.clear();
sourceCode.reserve(8192);
sourceCode += programHeader;
// Add Qt header includes
if (qtModules & QExternalTest::QtCore)
sourceCode += "#include <QtCore/QtCore>\n";
if (qtModules & QExternalTest::QtGui)
sourceCode += "#include <QtGui/QtGui>\n";
if (qtModules & QExternalTest::QtNetwork)
sourceCode += "#include <QtNetwork/QtNetwork>\n";
if (qtModules & QExternalTest::QtXml)
sourceCode += "#include <QtXml/QtXml>\n";
if (qtModules & QExternalTest::QtXmlPatterns)
sourceCode += "#include <QtXmlPatterns/QtXmlPatterns>\n";
if (qtModules & QExternalTest::QtOpenGL)
sourceCode += "#include <QtOpenGL/QtOpenGL>\n";
if (qtModules & QExternalTest::QtSql)
sourceCode += "#include <QtSql/QtSql>\n";
if (qtModules & QExternalTest::QtSvg)
sourceCode += "#include <QtSvg/QtSvg>\n";
if (qtModules & QExternalTest::QtScript)
sourceCode += "#include <QtScript/QtScript>\n";
if (qtModules & QExternalTest::QtTest)
sourceCode += "#include <QTest>\n";
if (qtModules & QExternalTest::QtDBus)
sourceCode += "#include <QtDBus/QtDBus>\n";
if (qtModules & QExternalTest::QtWebKit)
sourceCode += "#include <QtWebKit/QtWebKit>\n";
if (qtModules & QExternalTest::Phonon)
sourceCode += "#include <Phonon/Phonon>\n";
sourceCode +=
"#include <stdlib.h>\n"
"#include <stddef.h>\n";
sourceCode +=
"\n"
"void q_external_test_user_code()\n"
"{\n"
"#include \"user_code.cpp\"\n"
"}\n"
"\n"
"#ifdef Q_OS_WIN\n"
"#include <qt_windows.h>\n"
"#if defined(Q_CC_MSVC)\n"
"#include <crtdbg.h>\n"
"#endif\n"
"static void q_test_setup()\n"
"{\n"
" SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n"
"}\n"
"static int __cdecl CrtDbgHook(int /*reportType*/, char * /*message*/, int * /*returnValue*/)\n"
"{\n"
" return TRUE;\n"
"}\n"
"#else\n"
"static void q_test_setup() { }\n"
"#endif\n"
"int main(int argc, char **argv)\n"
"{\n"
"#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)\n"
" _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, CrtDbgHook);\n"
"#endif\n";
switch (appType) {
applicationless:
case QExternalTest::Applicationless:
sourceCode +=
" (void)argc; (void)argv;\n";
break;
coreapplication:
case QExternalTest::QCoreApplication:
sourceCode +=
" QCoreApplication app(argc, argv);\n";
break;
guiapplication:
case QExternalTest::QGuiApplication:
sourceCode +=
" QGuiApplication app(argc, argv);\n";
break;
widgetsapplication:
case QExternalTest::QApplication:
sourceCode +=
" QApplication app(argc, argv);\n";
break;
case QExternalTest::AutoApplication:
if (qtModules & QExternalTest::QtWidgets)
goto widgetsapplication;
if (qtModules & QExternalTest::QtGui)
goto guiapplication;
if (qtModules == 0)
goto applicationless;
goto coreapplication;
}
sourceCode +=
" q_test_setup();\n"
" q_external_test_user_code();\n"
" return 0;\n"
"}\n";
QFile sourceFile(temporaryDirPath + QLatin1String("/project.cpp"));
if (!sourceFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
std_err = sourceFile.errorString().toLocal8Bit();
return false;
}
sourceFile.write(sourceCode);
sourceFile.close();
sourceFile.setFileName(temporaryDirPath + QLatin1String("/user_code.cpp"));
if (!sourceFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
std_err = sourceFile.errorString().toLocal8Bit();
return false;
}
sourceFile.write(body);
return true;
}
bool QExternalTestPrivate::createTemporaryDirectory()
{
delete temporaryDir;
temporaryDir = new QTemporaryDir;
if (temporaryDir->isValid()) {
temporaryDirPath = temporaryDir->path();
return true;
} else {
delete temporaryDir;
temporaryDir = 0;
return false;
}
}
bool QExternalTestPrivate::createProjectFile()
{
if (temporaryDirPath.isEmpty())
qWarning() << "Temporary directory is expected to be non-empty";
QFile projectFile(temporaryDirPath + QLatin1String("/project.pro"));
if (!projectFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
std_err = projectFile.errorString().toLocal8Bit();
return false;
}
projectFile.write(
"TEMPLATE = app\n"
"\n"
"TARGET = externaltest\n"
"CONFIG -= debug_and_release\n"
"CONFIG += cmdline\n"
"DESTDIR = .\n"
"OBJECTS_DIR = .\n"
"UI_DIR = .\n"
"MOC_DIR = .\n"
"RCC_DIR = .\n"
"HEADERS +=\n"
"SOURCES += project.cpp\n"
"QT -= core gui\n"
"INCLUDEPATH += . ");
QString workingDir = QDir::currentPath();
if (extraProgramSources.count() > 0)
workingDir = QFileInfo(extraProgramSources.first()).absolutePath();
projectFile.write(QFile::encodeName(workingDir));
#ifndef QT_NO_DEBUG
projectFile.write("\nCONFIG += debug\n");
#else
projectFile.write("\nCONFIG += release\n");
#endif
QByteArray extraSources = QFile::encodeName(extraProgramSources.join(' '));
if (!extraSources.isEmpty()) {
projectFile.write("SOURCES += ");
projectFile.write(extraSources);
projectFile.putChar('\n');
}
// Add Qt modules
if (qtModules & QExternalTest::QtCore)
projectFile.write("QT += core\n");
if (qtModules & QExternalTest::QtGui)
projectFile.write("QT += gui\n");
if (qtModules & QExternalTest::QtNetwork)
projectFile.write("QT += network\n");
if (qtModules & QExternalTest::QtXml)
projectFile.write("QT += xml\n");
if (qtModules & QExternalTest::QtXmlPatterns)
projectFile.write("QT += xmlpatterns\n");
if (qtModules & QExternalTest::QtOpenGL)
projectFile.write("QT += opengl\n");
if (qtModules & QExternalTest::QtSql)
projectFile.write("QT += sql\n");
if (qtModules & QExternalTest::QtSvg)
projectFile.write("QT += svg\n");
if (qtModules & QExternalTest::QtScript)
projectFile.write("QT += script\n");
if (qtModules & QExternalTest::QtTest)
projectFile.write("QT += testlib\n");
if (qtModules & QExternalTest::QtDBus)
projectFile.write("QT += dbus\n");
if (qtModules & QExternalTest::QtWebKit)
projectFile.write("QT += webkit\n");
if (qtModules & QExternalTest::Phonon)
projectFile.write("QT += phonon\n");
projectFile.write("\n### User-specified settings start ###\n");
foreach (QByteArray line, qmakeLines) {
projectFile.write(line);
projectFile.write("\n");
}
projectFile.write("\n### User-specified settings end ###\n");
// Use qmake to just compile:
projectFile.write(
"\n"
"test_compile.depends += $(OBJECTS)\n"
"QMAKE_EXTRA_TARGETS += test_compile\n");
// Use qmake to run the app too:
projectFile.write(
"\n"
"unix:test_run.commands = ./$(QMAKE_TARGET)\n"
"else:test_run.commands = $(QMAKE_TARGET)\n"
"embedded:test_run.commands += -qws\n"
"QMAKE_EXTRA_TARGETS += test_run\n");
// Use qmake to debug:
projectFile.write(
"\n"
"*-g++* {\n"
" unix:test_debug.commands = gdb --args ./$(QMAKE_TARGET)\n"
" else:test_debug.commands = gdb --args $(QMAKE_TARGET)\n"
" embedded:test_debug.commands += -qws\n"
" QMAKE_EXTRA_TARGETS += test_debug\n"
"}\n");
// Also use qmake to run the app with valgrind:
projectFile.write(
"\n"
"unix:test_valgrind.commands = valgrind ./$(QMAKE_TARGET)\n"
"else:test_valgrind.commands = valgrind $(QMAKE_TARGET)\n"
"embedded:test_valgrind.commands += -qws\n"
"QMAKE_EXTRA_TARGETS += test_valgrind\n");
return true;
}
bool QExternalTestPrivate::runQmake()
{
#if QT_CONFIG(process)
if (temporaryDirPath.isEmpty())
qWarning() << "Temporary directory is expected to be non-empty";
if (!createProjectFile())
return false;
failedStage = QExternalTest::QmakeStage;
QProcess qmake;
QStringList args;
args << QLatin1String("-makefile")
<< QLatin1String("-spec")
<< makespec()
<< QLatin1String("project.pro");
qmake.setWorkingDirectory(temporaryDirPath);
QString cmd = QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qmake";
#ifdef Q_OS_WIN
cmd.append(".exe");
#endif
if (!QFile::exists(cmd)) {
cmd = "qmake";
qWarning("qmake from build not found, fallback to PATH's qmake");
}
qmake.start(cmd, args);
std_out += "### --- stdout from qmake --- ###\n";
std_err += "### --- stderr from qmake --- ###\n";
bool ok = qmake.waitForStarted();
if (!ok) {
exitCode = 255;
std_err += "qmake: ";
std_err += qmake.errorString().toLocal8Bit();
} else {
ok = qmake.waitForFinished(QMakeTimeout);
exitCode = qmake.exitCode();
if (!ok)
QTest::ensureStopped(qmake);
std_out += qmake.readAllStandardOutput();
std_err += qmake.readAllStandardError();
}
return ok && exitCode == 0;
#else // QT_CONFIG(process)
return false;
#endif // QT_CONFIG(process)
}
bool QExternalTestPrivate::runMake(Target target, int timeout)
{
#if !QT_CONFIG(process)
return false;
#else
if (temporaryDirPath.isEmpty())
qWarning() << "Temporary directory is expected to be non-empty";
QExternalProcess make;
make.setWorkingDirectory(temporaryDirPath);
QStringList environment = QProcess::systemEnvironment();
environment += QLatin1String("LC_ALL=C");
make.setEnvironment(environment);
QStringList args;
QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels;
if (target == Compile) {
args << QLatin1String("test_compile");
} else if (target == Run) {
QByteArray run = qgetenv("QTEST_EXTERNAL_RUN");
if (run == "valgrind")
args << QLatin1String("test_valgrind");
else if (run == "debug")
args << QLatin1String("test_debug");
else
args << QLatin1String("test_run");
if (!run.isEmpty())
channelMode = QProcess::ForwardedChannels;
}
make.setProcessChannelMode(channelMode);
static const char makes[] =
"jom.exe\0" //preferred for visual c++ or mingw
"nmake.exe\0" //for visual c++
"mingw32-make.exe\0" //for mingw
"gmake\0"
"make\0";
for (const char *p = makes; *p; p += strlen(p) + 1) {
make.start(QLatin1String(p), args);
if (make.waitForStarted())
break;
}
if (make.state() != QProcess::Running) {
exitCode = 255;
std_err += "make: ";
std_err += make.errorString().toLocal8Bit();
return false;
}
make.closeWriteChannel();
bool ok = make.waitForFinished(channelMode == QProcess::ForwardedChannels ? -1 : timeout);
if (!ok)
QTest::ensureStopped(make);
exitCode = make.exitCode();
std_out += make.readAllStandardOutput();
std_err += make.readAllStandardError();
return ok;
#endif // QT_CONFIG(process)
}
bool QExternalTestPrivate::commonSetup(const QByteArray &body)
{
clear();
if (!createTemporaryDirectory())
return false;
if (!createProjectFile())
return false;
if (!prepareSourceCode(body))
return false;
if (!runQmake())
return false;
return true;
}
bool QExternalTestPrivate::tryCompile(const QByteArray &body)
{
if (!commonSetup(body))
return false;
// compile
failedStage = QExternalTest::CompilationStage;
std_out += "\n### --- stdout from make (compilation) --- ###\n";
std_err += "\n### --- stderr from make (compilation) --- ###\n";
return runMake(Compile, CompileTimeout);
}
bool QExternalTestPrivate::tryLink(const QByteArray &body)
{
if (!tryCompile(body) || exitCode != 0)
return false;
// link
failedStage = QExternalTest::LinkStage;
std_out += "\n### --- stdout from make (linking) --- ###\n";
std_err += "\n### --- stderr from make (linking) --- ###\n";
return runMake(Link, CompileTimeout);
}
bool QExternalTestPrivate::tryRun(const QByteArray &body)
{
if (!tryLink(body) || exitCode != 0)
return false;
// run
failedStage = QExternalTest::RunStage;
std_out += "\n### --- stdout from process --- ###\n";
std_err += "\n### --- stderr from process --- ###\n";
return runMake(Run, RunTimeout);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,94 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTEST_EXTERNAL_TESTS_H
#define QTEST_EXTERNAL_TESTS_H
#include <QList>
#include <QByteArray>
#include <QStringList>
QT_BEGIN_NAMESPACE
namespace QTest {
class QExternalTestPrivate;
class QExternalTest
{
public:
QExternalTest();
~QExternalTest();
enum Stage {
FileStage,
QmakeStage,
CompilationStage,
LinkStage,
RunStage
};
enum QtModule {
QtCore = 0x0001,
QtGui = 0x0002,
QtNetwork = 0x0004,
QtXml = 0x0008,
QtXmlPatterns=0x0010,
QtOpenGL = 0x0020,
QtSql = 0x0040,
QtSvg = 0x0080,
QtScript = 0x0100,
QtTest = 0x0200,
QtDBus = 0x0400,
QtWebKit = 0x0800,
QtWidgets = 0x1000,
Phonon = 0x2000 // odd man out
};
Q_DECLARE_FLAGS(QtModules, QtModule)
enum ApplicationType {
AutoApplication,
Applicationless,
QCoreApplication,
QGuiApplication,
QApplication
};
QList<QByteArray> qmakeSettings() const;
void setQmakeSettings(const QList<QByteArray> &settings);
QtModules qtModules() const;
void setQtModules(QtModules modules);
ApplicationType applicationType() const;
void setApplicationType(ApplicationType type);
QStringList extraProgramSources() const;
void setExtraProgramSources(const QStringList &list);
QByteArray programHeader() const;
void setProgramHeader(const QByteArray &header);
// execution:
bool tryCompile(const QByteArray &body);
bool tryLink(const QByteArray &body);
bool tryRun(const QByteArray &body);
bool tryCompileFail(const QByteArray &body);
bool tryLinkFail(const QByteArray &body);
bool tryRunFail(const QByteArray &body);
Stage failedStage() const;
int exitCode() const;
QByteArray fullProgramSource() const;
QByteArray standardOutput() const;
QByteArray standardError() const;
QString errorReport() const;
private:
QExternalTestPrivate * const d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QExternalTest::QtModules)
}
QT_END_NAMESPACE
#endif

View File

@ -0,0 +1,23 @@
// 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 "forwarddeclared.h"
#include "qsharedpointer.h"
class ForwardDeclared
{
public:
~ForwardDeclared();
};
QSharedPointer<ForwardDeclared> *forwardPointer()
{
return new QSharedPointer<ForwardDeclared>(new ForwardDeclared);
}
int forwardDeclaredDestructorRunCount;
ForwardDeclared::~ForwardDeclared()
{
++forwardDeclaredDestructorRunCount;
}

View File

@ -0,0 +1,22 @@
// 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
#ifndef FORWARDDECLARED_H
#define FORWARDDECLARED_H
extern int forwardDeclaredDestructorRunCount;
class ForwardDeclared;
#ifdef QT_NAMESPACE
namespace QT_NAMESPACE {
#endif
template <typename T> class QSharedPointer;
#ifdef QT_NAMESPACE
}
using namespace QT_NAMESPACE;
#endif
QSharedPointer<ForwardDeclared> *forwardPointer();
#endif // FORWARDDECLARED_H

View File

@ -0,0 +1,78 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
/*
* This file exists because tst_qsharedpointer.cpp is compiled with
* QT_SHAREDPOINTER_TRACK_POINTERS. That changes some behavior.
*
* Note that most of these tests may yield false-positives in debug mode, but
* they should not yield false negatives. That is, they may report PASS when
* they are failing, but they should not produce FAILs.
*
* The reason for that is because of C++'s One Definition Rule: the macro
* changes some functions and, in debug mode, they will not be inlined. At link
* time, the two functions would be merged.
*/
#include <qsharedpointer.h>
#include <QTest>
#include "nontracked.h"
// We can't name our classes Data and DerivedData: those are in tst_qsharedpointer.cpp
namespace NonTracked {
class Data
{
public:
static int destructorCounter;
static int generationCounter;
int generation;
Data() : generation(++generationCounter)
{ }
virtual ~Data()
{
if (generation <= 0)
qFatal("tst_qsharedpointer: Double deletion!");
generation = 0;
++destructorCounter;
}
};
int Data::generationCounter = 0;
int Data::destructorCounter = 0;
class DerivedData: public Data
{
public:
static int derivedDestructorCounter;
int moreData;
DerivedData() : moreData(0) { }
~DerivedData() { ++derivedDestructorCounter; }
};
int DerivedData::derivedDestructorCounter = 0;
#ifndef QTEST_NO_RTTI
void dynamicCastFailureNoLeak()
{
Data::destructorCounter = DerivedData::derivedDestructorCounter = 0;
// see QTBUG-28924
QSharedPointer<Data> a(new Data);
QSharedPointer<DerivedData> b = a.dynamicCast<DerivedData>();
QVERIFY(!a.isNull());
QVERIFY(b.isNull());
a.clear();
b.clear();
QVERIFY(a.isNull());
// verify that the destructors were called
QCOMPARE(Data::destructorCounter, 1);
QCOMPARE(DerivedData::derivedDestructorCounter, 0);
}
#endif
} // namespace NonTracked

View File

@ -0,0 +1,11 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef NONTRACKED_H
#define NONTRACKED_H
namespace NonTracked {
void dynamicCastFailureNoLeak();
}
#endif // NONTRACKED_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
# undef QT_SHAREDPOINTER_TRACK_POINTERS
#endif
#include <QtCore/qsharedpointer.h>
#include "wrapper.h"
Wrapper::Wrapper(const QSharedPointer<int> &value)
: ptr(value)
{
}
Wrapper::~Wrapper()
{
}
Wrapper Wrapper::create()
{
return Wrapper(QSharedPointer<int>(new int(-47)));
}

View File

@ -0,0 +1,20 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef WRAPPER_H
#define WRAPPER_H
QT_BEGIN_NAMESPACE
template <class T> class QSharedPointer;
QT_END_NAMESPACE
class Wrapper
{
public:
QSharedPointer<int> ptr;
Wrapper(const QSharedPointer<int> &);
~Wrapper();
static Wrapper create();
};
#endif // WRAPPER_H

View File

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

View File

@ -0,0 +1,281 @@
// 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 <QTest>
#include <qsize.h>
#include <array>
Q_DECLARE_METATYPE(QMargins)
class tst_QSize : public QObject
{
Q_OBJECT
private slots:
void getSetCheck();
void scale();
void expandedTo();
void expandedTo_data();
void boundedTo_data();
void boundedTo();
void grownOrShrunkBy_data();
void grownOrShrunkBy();
void toSizeF_data();
void toSizeF();
void transpose_data();
void transpose();
void structuredBinding();
};
// Testing get/set functions
void tst_QSize::getSetCheck()
{
QSize obj1;
// int QSize::width()
// void QSize::setWidth(int)
obj1.setWidth(0);
QCOMPARE(0, obj1.width());
obj1.setWidth(INT_MIN);
QCOMPARE(INT_MIN, obj1.width());
obj1.setWidth(INT_MAX);
QCOMPARE(INT_MAX, obj1.width());
// int QSize::height()
// void QSize::setHeight(int)
obj1.setHeight(0);
QCOMPARE(0, obj1.height());
obj1.setHeight(INT_MIN);
QCOMPARE(INT_MIN, obj1.height());
obj1.setHeight(INT_MAX);
QCOMPARE(INT_MAX, obj1.height());
QSizeF obj2;
// qreal QSizeF::width()
// void QSizeF::setWidth(qreal)
obj2.setWidth(0.0);
QCOMPARE(0.0, obj2.width());
obj2.setWidth(1.1);
QCOMPARE(1.1, obj2.width());
// qreal QSizeF::height()
// void QSizeF::setHeight(qreal)
obj2.setHeight(0.0);
QCOMPARE(0.0, obj2.height());
obj2.setHeight(1.1);
QCOMPARE(1.1, obj2.height());
}
void tst_QSize::scale()
{
QSize t1( 10, 12 );
t1.scale( 60, 60, Qt::IgnoreAspectRatio );
QCOMPARE( t1, QSize(60, 60) );
QSize t2( 10, 12 );
t2.scale( 60, 60, Qt::KeepAspectRatio );
QCOMPARE( t2, QSize(50, 60) );
QSize t3( 10, 12 );
t3.scale( 60, 60, Qt::KeepAspectRatioByExpanding );
QCOMPARE( t3, QSize(60, 72) );
QSize t4( 12, 10 );
t4.scale( 60, 60, Qt::KeepAspectRatio );
QCOMPARE( t4, QSize(60, 50) );
QSize t5( 12, 10 );
t5.scale( 60, 60, Qt::KeepAspectRatioByExpanding );
QCOMPARE( t5, QSize(72, 60) );
// test potential int overflow
QSize t6(88473, 88473);
t6.scale(141817, 141817, Qt::KeepAspectRatio);
QCOMPARE(t6, QSize(141817, 141817));
QSize t7(800, 600);
t7.scale(400, INT_MAX, Qt::KeepAspectRatio);
QCOMPARE(t7, QSize(400, 300));
QSize t8(800, 600);
t8.scale(INT_MAX, 150, Qt::KeepAspectRatio);
QCOMPARE(t8, QSize(200, 150));
QSize t9(600, 800);
t9.scale(300, INT_MAX, Qt::KeepAspectRatio);
QCOMPARE(t9, QSize(300, 400));
QSize t10(600, 800);
t10.scale(INT_MAX, 200, Qt::KeepAspectRatio);
QCOMPARE(t10, QSize(150, 200));
QSize t11(0, 0);
t11.scale(240, 200, Qt::IgnoreAspectRatio);
QCOMPARE(t11, QSize(240, 200));
QSize t12(0, 0);
t12.scale(240, 200, Qt::KeepAspectRatio);
QCOMPARE(t12, QSize(240, 200));
QSize t13(0, 0);
t13.scale(240, 200, Qt::KeepAspectRatioByExpanding);
QCOMPARE(t13, QSize(240, 200));
}
void tst_QSize::expandedTo_data()
{
QTest::addColumn<QSize>("input1");
QTest::addColumn<QSize>("input2");
QTest::addColumn<QSize>("expected");
QTest::newRow("data0") << QSize(10,12) << QSize(6,4) << QSize(10,12);
QTest::newRow("data1") << QSize(0,0) << QSize(6,4) << QSize(6,4);
// This should pick the highest of w,h components independently of each other,
// thus the results don't have to be equal to neither input1 nor input2.
QTest::newRow("data3") << QSize(6,4) << QSize(4,6) << QSize(6,6);
}
void tst_QSize::expandedTo()
{
QFETCH( QSize, input1);
QFETCH( QSize, input2);
QFETCH( QSize, expected);
QCOMPARE( input1.expandedTo(input2), expected);
}
void tst_QSize::boundedTo_data()
{
QTest::addColumn<QSize>("input1");
QTest::addColumn<QSize>("input2");
QTest::addColumn<QSize>("expected");
QTest::newRow("data0") << QSize(10,12) << QSize(6,4) << QSize(6,4);
QTest::newRow("data1") << QSize(0,0) << QSize(6,4) << QSize(0,0);
// This should pick the lowest of w,h components independently of each other,
// thus the results don't have to be equal to neither input1 nor input2.
QTest::newRow("data3") << QSize(6,4) << QSize(4,6) << QSize(4,4);
}
void tst_QSize::boundedTo()
{
QFETCH( QSize, input1);
QFETCH( QSize, input2);
QFETCH( QSize, expected);
QCOMPARE( input1.boundedTo(input2), expected);
}
void tst_QSize::grownOrShrunkBy_data()
{
QTest::addColumn<QSize>("input");
QTest::addColumn<QMargins>("margins");
QTest::addColumn<QSize>("grown");
QTest::addColumn<QSize>("shrunk");
auto row = [](QSize i, QMargins m, QSize g, QSize s) {
QTest::addRow("{%d,%d}/{%d,%d,%d,%d}", i.width(), i.height(),
m.left(), m.top(), m.right(), m.bottom())
<< i << m << g << s;
};
const QSize zero = {0, 0};
const QSize some = {100, 200};
const QMargins zeroMargins = {};
const QMargins negative = {-1, -2, -3, -4};
const QMargins positive = { 1, 2, 3, 4};
row(zero, zeroMargins, zero, zero);
row(zero, negative, {-4, -6}, { 4, 6});
row(zero, positive, { 4, 6}, {-4, -6});
row(some, zeroMargins, some, some);
row(some, negative, { 96, 194}, {104, 206});
row(some, positive, {104, 206}, { 96, 194});
}
void tst_QSize::grownOrShrunkBy()
{
QFETCH(const QSize, input);
QFETCH(const QMargins, margins);
QFETCH(const QSize, grown);
QFETCH(const QSize, shrunk);
QCOMPARE(input.grownBy(margins), grown);
QCOMPARE(input.shrunkBy(margins), shrunk);
QCOMPARE(grown.shrunkBy(margins), input);
QCOMPARE(shrunk.grownBy(margins), input);
}
void tst_QSize::toSizeF_data()
{
QTest::addColumn<QSize>("input");
QTest::addColumn<QSizeF>("result");
auto row = [](int w, int h) {
QTest::addRow("(%d, %d)", w, h) << QSize(w, h) << QSizeF(w, h);
};
constexpr std::array samples = {-1, 0, 1};
for (int w : samples) {
for (int h : samples) {
row(w, h);
}
}
}
void tst_QSize::toSizeF()
{
QFETCH(const QSize, input);
QFETCH(const QSizeF, result);
QCOMPARE(input.toSizeF(), result);
}
void tst_QSize::transpose_data()
{
QTest::addColumn<QSize>("input1");
QTest::addColumn<QSize>("expected");
QTest::newRow("data0") << QSize(10,12) << QSize(12,10);
QTest::newRow("data1") << QSize(0,0) << QSize(0,0);
QTest::newRow("data3") << QSize(6,4) << QSize(4,6);
}
void tst_QSize::transpose()
{
QFETCH( QSize, input1);
QFETCH( QSize, expected);
// transpose() works only inplace and does not return anything, so we must do the operation itself before the compare.
input1.transpose();
QCOMPARE(input1 , expected);
}
void tst_QSize::structuredBinding()
{
{
QSize size(10, 20);
auto [width, height] = size;
QCOMPARE(width, 10);
QCOMPARE(height, 20);
}
{
QSize size(30, 40);
auto &[width, height] = size;
QCOMPARE(width, 30);
QCOMPARE(height, 40);
width = 100;
height = 200;
QCOMPARE(size.width(), 100);
QCOMPARE(size.height(), 200);
}
}
QTEST_APPLESS_MAIN(tst_QSize)
#include "tst_qsize.moc"

View File

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

View File

@ -0,0 +1,216 @@
// 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 <qsize.h>
Q_DECLARE_METATYPE(QMarginsF)
class tst_QSizeF : public QObject
{
Q_OBJECT
private slots:
void isNull_data();
void isNull();
void scale();
void expandedTo();
void expandedTo_data();
void boundedTo_data();
void boundedTo();
void grownOrShrunkBy_data();
void grownOrShrunkBy();
void transpose_data();
void transpose();
void structuredBinding();
};
void tst_QSizeF::isNull_data()
{
QTest::addColumn<qreal>("width");
QTest::addColumn<qreal>("height");
QTest::addColumn<bool>("isNull");
QTest::newRow("0, 0") << qreal(0.0) << qreal(0.0) << true;
QTest::newRow("-0, -0") << qreal(-0.0) << qreal(-0.0) << true;
QTest::newRow("0, -0") << qreal(0) << qreal(-0.0) << true;
QTest::newRow("-0, 0") << qreal(-0.0) << qreal(0) << true;
QTest::newRow("-0.1, 0") << qreal(-0.1) << qreal(0) << false;
QTest::newRow("0, -0.1") << qreal(0) << qreal(-0.1) << false;
QTest::newRow("0.1, 0") << qreal(0.1) << qreal(0) << false;
QTest::newRow("0, 0.1") << qreal(0) << qreal(0.1) << false;
}
void tst_QSizeF::isNull()
{
QFETCH(qreal, width);
QFETCH(qreal, height);
QFETCH(bool, isNull);
QSizeF size(width, height);
QCOMPARE(size.width(), width);
QCOMPARE(size.height(), height);
QCOMPARE(size.isNull(), isNull);
}
void tst_QSizeF::scale() {
QSizeF t1(10.4, 12.8);
t1.scale(60.6, 60.6, Qt::IgnoreAspectRatio);
QCOMPARE(t1, QSizeF(60.6, 60.6));
QSizeF t2(10.4, 12.8);
t2.scale(43.52, 43.52, Qt::KeepAspectRatio);
QCOMPARE(t2, QSizeF(35.36, 43.52));
QSizeF t3(9.6, 12.48);
t3.scale(31.68, 31.68, Qt::KeepAspectRatioByExpanding);
QCOMPARE(t3, QSizeF(31.68, 41.184));
QSizeF t4(12.8, 10.4);
t4.scale(43.52, 43.52, Qt::KeepAspectRatio);
QCOMPARE(t4, QSizeF(43.52, 35.36));
QSizeF t5(12.48, 9.6);
t5.scale(31.68, 31.68, Qt::KeepAspectRatioByExpanding);
QCOMPARE(t5, QSizeF(41.184, 31.68));
QSizeF t6(0.0, 0.0);
t6.scale(200, 240, Qt::IgnoreAspectRatio);
QCOMPARE(t6, QSizeF(200, 240));
QSizeF t7(0.0, 0.0);
t7.scale(200, 240, Qt::KeepAspectRatio);
QCOMPARE(t7, QSizeF(200, 240));
QSizeF t8(0.0, 0.0);
t8.scale(200, 240, Qt::KeepAspectRatioByExpanding);
QCOMPARE(t8, QSizeF(200, 240));
}
void tst_QSizeF::expandedTo_data() {
QTest::addColumn<QSizeF>("input1");
QTest::addColumn<QSizeF>("input2");
QTest::addColumn<QSizeF>("expected");
QTest::newRow("data0") << QSizeF(10.4, 12.8) << QSizeF(6.6, 4.4) << QSizeF(10.4, 12.8);
QTest::newRow("data1") << QSizeF(0.0, 0.0) << QSizeF(6.6, 4.4) << QSizeF(6.6, 4.4);
// This should pick the highest of w,h components independently of each other,
// thus the result don't have to be equal to neither input1 nor input2.
QTest::newRow("data3") << QSizeF(6.6, 4.4) << QSizeF(4.4, 6.6) << QSizeF(6.6, 6.6);
}
void tst_QSizeF::expandedTo() {
QFETCH( QSizeF, input1);
QFETCH( QSizeF, input2);
QFETCH( QSizeF, expected);
QCOMPARE( input1.expandedTo(input2), expected);
}
void tst_QSizeF::boundedTo_data() {
QTest::addColumn<QSizeF>("input1");
QTest::addColumn<QSizeF>("input2");
QTest::addColumn<QSizeF>("expected");
QTest::newRow("data0") << QSizeF(10.4, 12.8) << QSizeF(6.6, 4.4) << QSizeF(6.6, 4.4);
QTest::newRow("data1") << QSizeF(0.0, 0.0) << QSizeF(6.6, 4.4) << QSizeF(0.0, 0.0);
// This should pick the lowest of w,h components independently of each other,
// thus the result don't have to be equal to neither input1 nor input2.
QTest::newRow("data3") << QSizeF(6.6, 4.4) << QSizeF(4.4, 6.6) << QSizeF(4.4, 4.4);
}
void tst_QSizeF::boundedTo() {
QFETCH( QSizeF, input1);
QFETCH( QSizeF, input2);
QFETCH( QSizeF, expected);
QCOMPARE( input1.boundedTo(input2), expected);
}
void tst_QSizeF::grownOrShrunkBy_data()
{
QTest::addColumn<QSizeF>("input");
QTest::addColumn<QMarginsF>("margins");
QTest::addColumn<QSizeF>("grown");
QTest::addColumn<QSizeF>("shrunk");
auto row = [](QSizeF i, QMarginsF m, QSizeF g, QSizeF s) {
QTest::addRow("{%g,%g}/{%g,%g,%g,%g}", i.width(), i.height(),
m.left(), m.top(), m.right(), m.bottom())
<< i << m << g << s;
};
const QSizeF zero = {0, 0};
const QSizeF some = {100, 200};
const QMarginsF zeroMargins = {};
const QMarginsF negative = {-1, -2, -3, -4};
const QMarginsF positive = { 1, 2, 3, 4};
row(zero, zeroMargins, zero, zero);
row(zero, negative, {-4, -6}, { 4, 6});
row(zero, positive, { 4, 6}, {-4, -6});
row(some, zeroMargins, some, some);
row(some, negative, { 96, 194}, {104, 206});
row(some, positive, {104, 206}, { 96, 194});
}
void tst_QSizeF::grownOrShrunkBy()
{
QFETCH(const QSizeF, input);
QFETCH(const QMarginsF, margins);
QFETCH(const QSizeF, grown);
QFETCH(const QSizeF, shrunk);
QCOMPARE(input.grownBy(margins), grown);
QCOMPARE(input.shrunkBy(margins), shrunk);
QCOMPARE(grown.shrunkBy(margins), input);
QCOMPARE(shrunk.grownBy(margins), input);
}
void tst_QSizeF::transpose_data() {
QTest::addColumn<QSizeF>("input1");
QTest::addColumn<QSizeF>("expected");
QTest::newRow("data0") << QSizeF(10.4, 12.8) << QSizeF(12.8, 10.4);
QTest::newRow("data1") << QSizeF(0.0, 0.0) << QSizeF(0.0, 0.0);
QTest::newRow("data3") << QSizeF(6.6, 4.4) << QSizeF(4.4, 6.6);
}
void tst_QSizeF::transpose() {
QFETCH( QSizeF, input1);
QFETCH( QSizeF, expected);
// transpose() works only inplace and does not return anything, so we must do the operation itself before the compare.
input1.transpose();
QCOMPARE(input1 , expected);
}
void tst_QSizeF::structuredBinding()
{
{
QSizeF size(10.0, 20.0);
auto [width, height] = size;
QCOMPARE(width, 10.0);
QCOMPARE(height, 20.0);
}
{
QSizeF size(30.0, 40.0);
auto &[width, height] = size;
QCOMPARE(width, 30.0);
QCOMPARE(height, 40.0);
width = 100.0;
height = 200.0;
QCOMPARE(size.width(), 100.0);
QCOMPARE(size.height(), 200.0);
}
}
QTEST_APPLESS_MAIN(tst_QSizeF)
#include "tst_qsizef.moc"

View File

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

View File

@ -0,0 +1,60 @@
// 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 <qstring.h>
#include <ostream>
#include <sstream>
class tst_QStl: public QObject
{
Q_OBJECT
private slots:
void streaming_data();
void streaming();
void concatenate();
};
static inline std::ostream &operator<<(std::ostream &out, const QString &string)
{
out << string.toLocal8Bit().constData();
return out;
}
void tst_QStl::streaming_data()
{
QTest::addColumn<QString>("str");
QTest::newRow("hello") << "hello";
QTest::newRow("empty") << "";
}
void tst_QStl::streaming()
{
QFETCH(QString, str);
std::ostringstream buf;
buf << str;
std::string result = buf.str();
QCOMPARE(QString::fromLatin1(result.data()), str);
}
void tst_QStl::concatenate()
{
std::ostringstream buf;
buf << QLatin1String("Hello ") << QLatin1String("World");
QCOMPARE(QString::fromLatin1(buf.str().data()), QString("Hello World"));
}
QTEST_APPLESS_MAIN(tst_QStl)
#include "tst_qstl.moc"

View File

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

View File

@ -0,0 +1,478 @@
// 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 <QtCore/qtaggedpointer.h>
class tst_QTaggedPointer : public QObject
{
Q_OBJECT
private Q_SLOTS:
void constExpr();
void construction();
void assignment();
void dereferenceOperator();
void pointerOperator();
void negationOperator();
void operatorBool();
void comparison();
void tag();
void objectMember();
void customTagType();
void taggedLinkedList();
};
void tst_QTaggedPointer::constExpr()
{
{
constexpr QTaggedPointer<int> p;
Q_UNUSED(p);
}
{
enum Foo : uint {};
constexpr QTaggedPointer<int, Foo> p;
Q_UNUSED(p);
}
{
enum Foo : int {};
constexpr QTaggedPointer<int, Foo> p;
Q_UNUSED(p);
}
{
constexpr QTaggedPointer<int> p = nullptr;
Q_UNUSED(p);
}
{
enum Foo : uint {};
constexpr QTaggedPointer<int, Foo> p = nullptr;
Q_UNUSED(p);
}
{
enum Foo : int {};
constexpr QTaggedPointer<int, Foo> p = nullptr;
Q_UNUSED(p);
}
}
void tst_QTaggedPointer::construction()
{
{
QTaggedPointer<int> p;
QCOMPARE(p.data(), nullptr);
QVERIFY(!p.tag());
}
{
QTaggedPointer<int> p(nullptr, 0x1);
QCOMPARE(p.data(), nullptr);
QCOMPARE(p.tag(), quintptr(0x1));
}
{
QScopedPointer<int> rawPointer(new int(5));
QTaggedPointer<int> p(rawPointer.data());
QCOMPARE(p.data(), rawPointer.data());
QVERIFY(!p.tag());
}
{
QScopedPointer<int> rawPointer(new int(5));
QTaggedPointer<int> p(rawPointer.data(), 0x1);
QCOMPARE(p.data(), rawPointer.data());
QCOMPARE(p.tag(), quintptr(0x1));
}
}
void tst_QTaggedPointer::assignment()
{
QScopedPointer<int> rawPointer(new int(5));
QTaggedPointer<int> p(rawPointer.data(), 0x1);
QTaggedPointer<int> p2(rawPointer.data(), 0x2);
QCOMPARE(p.data(), rawPointer.data());
QCOMPARE(p.tag(), quintptr(0x1));
QCOMPARE(p2.data(), rawPointer.data());
QCOMPARE(p2.tag(), quintptr(0x2));
p = nullptr;
QCOMPARE(p.data(), nullptr);
QCOMPARE(p.tag(), quintptr(0x1));
p = rawPointer.data();
QCOMPARE(p.data(), rawPointer.data());
QCOMPARE(p.tag(), quintptr(0x1));
p = {};
QCOMPARE(p.data(), nullptr);
QCOMPARE(p.tag(), quintptr(0x0));
p = p2;
QCOMPARE(p.data(), rawPointer.data());
QCOMPARE(p.tag(), quintptr(0x2));
p = nullptr;
QCOMPARE(p.data(), nullptr);
QCOMPARE(p.tag(), quintptr(0x2));
p = {};
QCOMPARE(p.data(), nullptr);
QCOMPARE(p.tag(), quintptr(0x0));
p = rawPointer.data();
QCOMPARE(p.data(), rawPointer.data());
QCOMPARE(p.tag(), quintptr(0x0));
}
class AbstractClass
{
public:
virtual ~AbstractClass() {}
virtual int member() const = 0;
};
class SubClass : public AbstractClass
{
public:
int member() const override { return 5; }
};
void tst_QTaggedPointer::dereferenceOperator()
{
/* Dereference a basic value. */
{
QScopedPointer<int> rawPointer(new int(5));
QTaggedPointer<int> p(rawPointer.data());
const int value = *p;
QCOMPARE(value, 5);
}
/* Dereference a basic value with tag. */
{
QScopedPointer<int> rawPointer(new int(5));
QTaggedPointer<int> p(rawPointer.data(), 0x1);
const int value = *p;
QCOMPARE(value, 5);
}
/* Dereference a pointer to an abstract class. This verifies
* that the operator returns a reference, when compiling
* with MSVC 2005. */
{
QScopedPointer<SubClass> ptr(new SubClass());
QTaggedPointer<AbstractClass> p(ptr.data());
QCOMPARE((*p).member(), 5);
}
/* The operator should be const. */
{
QScopedPointer<int> rawPointer(new int(5));
const QTaggedPointer<int> p(rawPointer.data());
*p;
}
/* A reference should be returned, not a value. */
{
QScopedPointer<int> rawPointer(new int(5));
const QTaggedPointer<int> p(rawPointer.data());
Q_UNUSED(static_cast<int &>(*p));
}
/* Instantiated on a const object, the returned object is a const reference. */
{
QScopedPointer<int> rawPointer(new int(5));
const QTaggedPointer<const int> p(rawPointer.data());
Q_UNUSED(static_cast<const int &>(*p));
}
}
class Value
{
public:
int value;
};
void tst_QTaggedPointer::pointerOperator()
{
{
QScopedPointer<Value> valuePtr(new Value{5});
QTaggedPointer<Value> p(valuePtr.data());
QCOMPARE(p->value, 5);
}
{
QScopedPointer<Value> valuePtr(new Value{5});
QTaggedPointer<Value> p(valuePtr.data(), 0x1);
QCOMPARE(p->value, 5);
}
/* The operator should be const. */
{
QScopedPointer<Value> valuePtr(new Value{5});
const QTaggedPointer<Value> p(valuePtr.data());
QVERIFY(p->value);
}
}
void tst_QTaggedPointer::negationOperator()
{
/* Invoke on default constructed value. */
{
QTaggedPointer<int> p;
QVERIFY(!p);
}
/* Invoke on nullptr value with tag. */
{
QTaggedPointer<int> p(nullptr, 0x1);
QVERIFY(!p);
}
/* Invoke on a value. */
{
QScopedPointer<int> rawPointer(new int(2));
QTaggedPointer<int> p(rawPointer.data());
QCOMPARE(!p, false);
}
/* Invoke on a value with tag. */
{
QScopedPointer<int> rawPointer(new int(2));
QTaggedPointer<int> p(rawPointer.data(), 0x1);
QCOMPARE(!p, false);
}
/* The signature should be const. */
{
const QTaggedPointer<int> p;
!p;
}
/* The return value should be bool. */
{
const QTaggedPointer<int> p;
Q_UNUSED(static_cast<bool>(!p));
}
}
void tst_QTaggedPointer::operatorBool()
{
/* Invoke on default constructed value. */
{
QTaggedPointer<int> p;
QCOMPARE(bool(p), false);
}
/* Invoke on nullptr value with tag. */
{
QTaggedPointer<int> p(nullptr, 0x1);
QCOMPARE(bool(p), false);
}
/* Invoke on active value. */
{
QScopedPointer<int> rawPointer(new int(3));
QTaggedPointer<int> p(rawPointer.data());
QVERIFY(p);
}
/* Invoke on active value with tag. */
{
QScopedPointer<int> rawPointer(new int(3));
QTaggedPointer<int> p(rawPointer.data(), 0x1);
QVERIFY(p);
}
/* The signature should be const and return bool. */
{
const QTaggedPointer<int> p;
(void)static_cast<bool>(p);
}
}
template <class A1, class A2, class B>
void comparisonTest(const A1 &a1, const A2 &a2, const B &b)
{
// test equality on equal pointers
QVERIFY(a1 == a2);
QVERIFY(a2 == a1);
// test inequality on equal pointers
QVERIFY(!(a1 != a2));
QVERIFY(!(a2 != a1));
// test equality on unequal pointers
QVERIFY(!(a1 == b));
QVERIFY(!(a2 == b));
QVERIFY(!(b == a1));
QVERIFY(!(b == a2));
// test inequality on unequal pointers
QVERIFY(b != a1);
QVERIFY(b != a2);
QVERIFY(a1 != b);
QVERIFY(a2 != b);
}
void tst_QTaggedPointer::comparison()
{
QScopedPointer<int> a(new int(5));
{
QTaggedPointer<int> a1(a.data());
QTaggedPointer<int> a2(a.data());
QScopedPointer<int> rawPointer(new int(6));
QTaggedPointer<int> b(rawPointer.data());
comparisonTest(a1, a1, b);
comparisonTest(a2, a2, b);
comparisonTest(a1, a2, b);
}
{
QTaggedPointer<int> a1(a.data(), 0x1);
QTaggedPointer<int> a2(a.data(), 0x1);
QScopedPointer<int> rawPointer(new int(6));
QTaggedPointer<int> b(rawPointer.data(), 0x1);
comparisonTest(a1, a1, b);
comparisonTest(a2, a2, b);
comparisonTest(a1, a2, b);
}
{
QTaggedPointer<int> a1(a.data(), 0x1);
QTaggedPointer<int> a2(a.data(), 0x2);
QScopedPointer<int> rawPointer(new int(6));
QTaggedPointer<int> b(rawPointer.data(), 0x2);
comparisonTest(a1, a1, b);
comparisonTest(a2, a2, b);
comparisonTest(a1, a2, b);
}
{
QTaggedPointer<int> p;
QVERIFY(p.isNull());
QVERIFY(p == nullptr);
QVERIFY(nullptr == p);
}
{
QTaggedPointer<int> p(nullptr, 0x1);
QVERIFY(p.isNull());
QVERIFY(p == nullptr);
QVERIFY(nullptr == p);
}
{
QScopedPointer<int> rawPointer(new int(42));
QTaggedPointer<int> p(rawPointer.data());
QVERIFY(!p.isNull());
QVERIFY(p != nullptr);
QVERIFY(nullptr != p);
}
{
QScopedPointer<int> rawPointer(new int(42));
QTaggedPointer<int> p(rawPointer.data(), 0x1);
QVERIFY(!p.isNull());
QVERIFY(p != nullptr);
QVERIFY(nullptr != p);
}
}
void tst_QTaggedPointer::tag()
{
QScopedPointer<int> rawPointer(new int(3));
QTaggedPointer<int> p(rawPointer.data());
QCOMPARE(*p.data(), 3);
QVERIFY(!p.tag());
p.setTag(0x1);
QCOMPARE(p.tag(), 0x1);
p.setTag(0x2);
QCOMPARE(p.tag(), 0x2);
}
struct Foo
{
Foo() : p(nullptr) {}
Foo(const Foo &other) : p(other.p) {}
Foo &operator=(const Foo &other) {
p = other.p;
return *this;
}
QTaggedPointer<int> p;
};
void tst_QTaggedPointer::objectMember()
{
QScopedPointer<int> rawPointer(new int(42));
Foo f;
f.p = QTaggedPointer<int>(rawPointer.data(), 0x1);
Foo f2(f);
QCOMPARE(f2.p.data(), f.p.data());
QCOMPARE(f2.p.tag(), f.p.tag());
Foo f3 = f;
QCOMPARE(f3.p.data(), f.p.data());
QCOMPARE(f3.p.tag(), f.p.tag());
}
class Bar
{
Q_GADGET
public:
enum Tag {
NoTag = 0,
FirstTag = 1,
SecondTag = 2
};
Q_DECLARE_FLAGS(Tags, Tag)
Q_FLAG(Tags)
int value;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Bar::Tags)
void tst_QTaggedPointer::customTagType()
{
QScopedPointer<Bar> barPtr(new Bar{5});
typedef QTaggedPointer<Bar, Bar::Tags> TaggedBar;
TaggedBar p(barPtr.data());
QCOMPARE(p->value, 5);
QVERIFY(TaggedBar::maximumTag());
QVERIFY(!p.tag());
QCOMPARE(p.tag(), Bar::NoTag);
p.setTag(Bar::FirstTag | Bar::SecondTag);
QCOMPARE(p->value, 5);
QCOMPARE(p.tag(), Bar::FirstTag | Bar::SecondTag);
}
// Compile-only test to ensure it's possible to use tagged pointers
// with incomplete types.
struct LinkedListItem
{
enum Tag {
NoTag = 0,
FirstTag = 1
};
Q_DECLARE_FLAGS(Tags, Tag)
QTaggedPointer<LinkedListItem, Tag> next;
~LinkedListItem()
{
delete next.data();
}
};
Q_DECLARE_OPERATORS_FOR_FLAGS(LinkedListItem::Tags)
void tst_QTaggedPointer::taggedLinkedList()
{
QScopedPointer<LinkedListItem> lli(new LinkedListItem);
lli->next = QTaggedPointer<LinkedListItem, LinkedListItem::Tag>(new LinkedListItem);
lli->next.setTag(LinkedListItem::FirstTag);
}
QTEST_MAIN(tst_QTaggedPointer)
#include "tst_qtaggedpointer.moc"

View File

@ -0,0 +1,6 @@
[interpolation]
windows
osx
[frameRate]
macos

View File

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

View File

@ -0,0 +1,914 @@
// 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 <QtTest/private/qpropertytesthelper_p.h>
#include <QSignalSpy>
#include <qtimeline.h>
class tst_QTimeLine : public QObject
{
Q_OBJECT
private slots:
void range();
void currentTime();
void bindableCurrentTime();
void duration();
void bindableDuration();
void frameRate();
void bindableUpdateInterval();
void value();
void currentFrame();
void loopCount();
void bindableLoopCount();
void interpolation();
void reverse_data();
void reverse();
void toggleDirection();
void bindableDirection();
void frameChanged();
void stopped();
void finished();
void isRunning();
void multipleTimeLines();
void sineCurve();
void cosineCurve();
void outOfRange();
void stateInFinishedSignal();
void resume();
void restart();
void setPaused();
void automatedBindableTests();
protected slots:
void finishedSlot();
protected:
QTimeLine::State state;
QTimeLine * view;
};
void tst_QTimeLine::range()
{
QTimeLine timeLine(200);
QCOMPARE(timeLine.startFrame(), 0);
QCOMPARE(timeLine.endFrame(), 0);
timeLine.setFrameRange(0, 1);
QCOMPARE(timeLine.startFrame(), 0);
QCOMPARE(timeLine.endFrame(), 1);
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.startFrame(), 10);
QCOMPARE(timeLine.endFrame(), 20);
timeLine.setStartFrame(6);
QCOMPARE(timeLine.startFrame(), 6);
timeLine.setEndFrame(16);
QCOMPARE(timeLine.endFrame(), 16);
// Verify that you can change the range in the timeLine
timeLine.setFrameRange(1000, 2000);
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start(); // make sure that the logic works for a running timeline
QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
timeLine.setCurrentTime(timeLine.duration()/2);
int oldValue = timeLine.currentFrame();
timeLine.setFrameRange(0, 500);
QVERIFY(timeLine.currentFrame() < oldValue);
timeLine.setEndFrame(10000);
timeLine.setStartFrame(5000);
QVERIFY(timeLine.currentFrame() > oldValue);
timeLine.setFrameRange(0, 500);
QTRY_VERIFY(spy.size() > 1);
QVERIFY(timeLine.currentFrame() < oldValue);
}
void tst_QTimeLine::currentTime()
{
QTimeLine timeLine(2000);
timeLine.setUpdateInterval((timeLine.duration()/2) / 33);
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.currentTime(), 0);
timeLine.start();
QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(timeLine.currentTime() > timeLine.duration()/2 - timeLine.duration()/4);
QVERIFY(timeLine.currentTime() < timeLine.duration()/2 + timeLine.duration()/4);
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentTime(), timeLine.duration());
QSignalSpy spy(&timeLine, &QTimeLine::valueChanged);
QVERIFY(spy.isValid());
spy.clear();
timeLine.setCurrentTime(timeLine.duration()/2);
timeLine.setCurrentTime(timeLine.duration()/2);
QCOMPARE(spy.size(), 1);
spy.clear();
QCOMPARE(timeLine.currentTime(), timeLine.duration()/2);
timeLine.resume();
// Let it update on its own
QCOMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(timeLine.currentTime() > timeLine.duration()/2);
QVERIFY(timeLine.currentTime() < timeLine.duration());
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentTime(), timeLine.duration());
// Reverse should decrease the currentTime
timeLine.setCurrentTime(timeLine.duration()/2);
timeLine.start();
// Let it update on its own
int currentTime = timeLine.currentTime();
QTRY_VERIFY(timeLine.currentTime() > currentTime);
QCOMPARE(timeLine.state(), QTimeLine::Running);
currentTime = timeLine.currentTime();
timeLine.setDirection(QTimeLine::Backward);
QTRY_VERIFY(timeLine.currentTime() < currentTime);
timeLine.stop();
}
void tst_QTimeLine::bindableCurrentTime()
{
QTimeLine timeLine(2000);
QProperty<int> currentTimeObserver([&]() { return timeLine.currentTime(); });
timeLine.setUpdateInterval((timeLine.duration() / 2) / 33);
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.currentTime(), 0);
QCOMPARE(currentTimeObserver.value(), 0);
QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
timeLine.start();
QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
QTRY_VERIFY(timeLine.currentTime() > timeLine.duration() / 2 - timeLine.duration() / 4);
QVERIFY(timeLine.currentTime() < timeLine.duration() / 2 + timeLine.duration() / 4);
QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentTime(), timeLine.duration());
QCOMPARE(currentTimeObserver.value(), timeLine.currentTime());
QSignalSpy spy(&timeLine, &QTimeLine::valueChanged);
QVERIFY(spy.isValid());
spy.clear();
QProperty<int> referenceCurrentTime(timeLine.duration() / 2);
timeLine.bindableCurrentTime().setBinding([&]() { return referenceCurrentTime.value(); });
QCOMPARE(spy.size(), 1);
// setting it a second time to check that valueChanged() is emitted only once
referenceCurrentTime = timeLine.duration() / 2;
QCOMPARE(spy.size(), 1);
spy.clear();
QCOMPARE(timeLine.currentTime(), timeLine.duration() / 2);
QCOMPARE(currentTimeObserver.value(), timeLine.duration() / 2);
timeLine.resume();
// Let it update on its own
QCOMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(currentTimeObserver.value() > timeLine.duration() / 2);
QVERIFY(currentTimeObserver.value() < timeLine.duration());
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(currentTimeObserver.value(), timeLine.duration());
// the resume above should have broken the connection to referenceCurrentTime, check that:
spy.clear();
referenceCurrentTime = 0;
QCOMPARE(currentTimeObserver.value(), timeLine.duration());
QCOMPARE(spy.size(), 0);
}
void tst_QTimeLine::duration()
{
QTimeLine timeLine(200);
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.duration(), 200);
timeLine.setDuration(1000);
QCOMPARE(timeLine.duration(), 1000);
timeLine.start();
QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(timeLine.currentTime() > 0);
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentTime(), 1000);
// The duration shouldn't change
QCOMPARE(timeLine.duration(), 1000);
}
void tst_QTimeLine::bindableDuration()
{
QTimeLine timeLine(200);
QProperty<int> durationObserver;
durationObserver.setBinding([&]() { return timeLine.duration(); });
QCOMPARE(durationObserver.value(), timeLine.duration());
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.duration(), 200);
QProperty<int> referenceDuration(500);
timeLine.bindableDuration().setBinding([&]() { return referenceDuration.value(); });
QCOMPARE(durationObserver.value(), referenceDuration.value());
QCOMPARE(timeLine.duration(), 500);
timeLine.start();
QTRY_COMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(timeLine.currentTime() > 0);
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentTime(), 500);
// The duration shouldn't change
QCOMPARE(timeLine.duration(), 500);
referenceDuration = 30;
QCOMPARE(timeLine.duration(), 30);
QCOMPARE(durationObserver.value(), 30);
}
void tst_QTimeLine::frameRate()
{
QTimeLine timeLine;
timeLine.setFrameRange(100, 2000);
QCOMPARE(timeLine.updateInterval(), 1000 / 25);
timeLine.setUpdateInterval(1000 / 60);
QCOMPARE(timeLine.updateInterval(), 1000 / 60);
// Default speed
timeLine.setUpdateInterval(1000 / 33);
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
int slowCount = spy.size();
// Faster!!
timeLine.setUpdateInterval(1000 / 100);
spy.clear();
timeLine.setCurrentTime(0);
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
QVERIFY2(slowCount < spy.size(), QByteArray::number(spy.size()));
}
void tst_QTimeLine::bindableUpdateInterval()
{
QTimeLine timeLine;
timeLine.setFrameRange(100, 2000);
QProperty<int> updateIntervalObserver;
updateIntervalObserver.setBinding([&]() { return timeLine.updateInterval(); });
QCOMPARE(updateIntervalObserver.value(), 1000 / 25);
QProperty<int> updateIntervalReference(1000 / 60);
timeLine.bindableUpdateInterval().setBinding([&]() { return updateIntervalReference.value(); });
updateIntervalReference = 1000 / 60;
QCOMPARE(updateIntervalObserver.value(), 1000 / 60);
// Default speed
updateIntervalReference = 1000 / 33;
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTest::qWait(timeLine.duration() * 2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
int slowCount = spy.size();
// Faster!!
updateIntervalReference = 1000 / 100;
spy.clear();
timeLine.setCurrentTime(0);
timeLine.start();
QTest::qWait(timeLine.duration() * 2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
QVERIFY2(slowCount < spy.size(), QByteArray::number(spy.size()));
}
void tst_QTimeLine::value()
{
QTimeLine timeLine(4500); // Should be at least 5% under 5000ms
QCOMPARE(timeLine.currentValue(), 0.0);
// Default speed
QSignalSpy spy(&timeLine, &QTimeLine::valueChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTRY_VERIFY(timeLine.currentValue() > 0);
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentValue(), 1.0);
QVERIFY(spy.size() > 0);
// Reverse should decrease the value
timeLine.setCurrentTime(100);
timeLine.start();
// Let it update on its own
QCOMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(timeLine.currentValue());
qreal value = timeLine.currentValue();
timeLine.setDirection(QTimeLine::Backward);
QTRY_VERIFY(timeLine.currentValue() < value);
timeLine.stop();
}
void tst_QTimeLine::currentFrame()
{
QTimeLine timeLine(2000);
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.currentFrame(), 10);
// Default speed
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTRY_VERIFY(timeLine.currentFrame() > 10);
QTRY_COMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(timeLine.currentFrame(), 20);
// Reverse should decrease the value
timeLine.setCurrentTime(timeLine.duration()/2);
timeLine.start();
// Let it update on its own
QCOMPARE(timeLine.state(), QTimeLine::Running);
QTRY_VERIFY(timeLine.currentTime() > timeLine.duration()/2); // wait for continuation
int value = timeLine.currentFrame();
timeLine.setDirection(QTimeLine::Backward);
QTRY_VERIFY(timeLine.currentFrame() < value);
timeLine.stop();
}
void tst_QTimeLine::loopCount()
{
QTimeLine timeLine(200);
QCOMPARE(timeLine.loopCount(), 1);
timeLine.setFrameRange(10, 20);
QCOMPARE(timeLine.loopCount(), 1);
timeLine.setLoopCount(0);
QCOMPARE(timeLine.loopCount(), 0);
// Default speed endless looping
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTest::qWait(timeLine.duration());
QCOMPARE(timeLine.state(), QTimeLine::Running);
//QCOMPARE(timeLine.currentFrame(), 20);
QTest::qWait(timeLine.duration()*6);
QCOMPARE(timeLine.state(), QTimeLine::Running);
QVERIFY(timeLine.currentTime() >= 0);
QVERIFY(timeLine.currentFrame() >= 10);
QVERIFY(timeLine.currentFrame() <= 20);
QCOMPARE(timeLine.state(), QTimeLine::Running);
timeLine.stop();
timeLine.setDuration(2500); // some platforms have a very low resolution timer
timeLine.setFrameRange(0, 2);
timeLine.setLoopCount(4);
QSignalSpy finishedSpy(&timeLine, &QTimeLine::finished);
QSignalSpy frameChangedSpy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(finishedSpy.isValid());
QVERIFY(frameChangedSpy.isValid());
QEventLoop loop;
connect(&timeLine, SIGNAL(finished()), &loop, SLOT(quit()));
for(int i=0;i<2;i++) {
timeLine.start();
// we clear the list after the start so we don't catch
// a frameChanged signal for the frame 0 at the beginning
finishedSpy.clear();
frameChangedSpy.clear();
loop.exec();
QCOMPARE(finishedSpy.size(), 1);
QCOMPARE(frameChangedSpy.size(), 11);
for (int i = 0; i < 11; ++i)
QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), (i+1) % 3);
}
timeLine.setDirection(QTimeLine::Backward);
timeLine.start();
loop.exec();
QCOMPARE(finishedSpy.size(), 2);
QCOMPARE(frameChangedSpy.size(), 22);
for (int i = 11; i < 22; ++i) {
QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), 2 - (i+2) % 3);
}
}
void tst_QTimeLine::bindableLoopCount()
{
QTimeLine timeLine(200);
QProperty<int> referenceLoopCount(1);
timeLine.bindableLoopCount().setBinding([&]() { return referenceLoopCount.value(); });
QProperty<int> loopCountObserver([&]() { return timeLine.loopCount(); });
QCOMPARE(referenceLoopCount.value(), 1);
QCOMPARE(timeLine.loopCount(), 1);
QCOMPARE(loopCountObserver.value(), 1);
timeLine.setFrameRange(10, 20);
QCOMPARE(referenceLoopCount.value(), 1);
QCOMPARE(timeLine.loopCount(), 1);
QCOMPARE(loopCountObserver.value(), 1);
referenceLoopCount = 0;
QCOMPARE(referenceLoopCount.value(), 0);
QCOMPARE(timeLine.loopCount(), 0);
QCOMPARE(loopCountObserver.value(), 0);
// Default speed endless looping
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTest::qWait(timeLine.duration());
QCOMPARE(timeLine.state(), QTimeLine::Running);
// QCOMPARE(timeLine.currentFrame(), 20);
QTest::qWait(timeLine.duration() * 6);
QCOMPARE(timeLine.state(), QTimeLine::Running);
QVERIFY(timeLine.currentTime() >= 0);
QVERIFY(timeLine.currentFrame() >= 10);
QVERIFY(timeLine.currentFrame() <= 20);
QCOMPARE(timeLine.state(), QTimeLine::Running);
timeLine.stop();
timeLine.setDuration(2500); // some platforms have a very low resolution timer
timeLine.setFrameRange(0, 2);
referenceLoopCount = 4;
QSignalSpy finishedSpy(&timeLine, &QTimeLine::finished);
QSignalSpy frameChangedSpy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(finishedSpy.isValid());
QVERIFY(frameChangedSpy.isValid());
QEventLoop loop;
connect(&timeLine, SIGNAL(finished()), &loop, SLOT(quit()));
for (int i = 0; i < 2; i++) {
timeLine.start();
// we clear the list after the start so we don't catch
// a frameChanged signal for the frame 0 at the beginning
finishedSpy.clear();
frameChangedSpy.clear();
loop.exec();
QCOMPARE(finishedSpy.size(), 1);
QCOMPARE(frameChangedSpy.size(), 11);
for (int i = 0; i < 11; ++i)
QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), (i + 1) % 3);
}
timeLine.setDirection(QTimeLine::Backward);
timeLine.start();
loop.exec();
QCOMPARE(finishedSpy.size(), 2);
QCOMPARE(frameChangedSpy.size(), 22);
for (int i = 11; i < 22; ++i)
QCOMPARE(frameChangedSpy.at(i).at(0).toInt(), 2 - (i + 2) % 3);
}
void tst_QTimeLine::interpolation()
{
// also tests bindableEasingCurve
QTimeLine timeLine(400);
QProperty<QEasingCurve> easingCurveObserver([&]() { return timeLine.easingCurve(); });
QCOMPARE(timeLine.easingCurve(), QEasingCurve::InOutSine);
QCOMPARE(easingCurveObserver.value(), QEasingCurve::InOutSine);
timeLine.setFrameRange(100, 200);
QProperty<QEasingCurve> referenceEasingCurve(QEasingCurve::Linear);
timeLine.bindableEasingCurve().setBinding([&]() { return referenceEasingCurve.value(); });
QCOMPARE(timeLine.easingCurve(), QEasingCurve::Linear);
QCOMPARE(easingCurveObserver.value(), QEasingCurve::Linear);
// smooth
referenceEasingCurve = QEasingCurve::InOutSine;
QCOMPARE(timeLine.easingCurve(), QEasingCurve::InOutSine);
QCOMPARE(easingCurveObserver.value(), QEasingCurve::InOutSine);
timeLine.start();
QTest::qWait(100);
QCOMPARE(timeLine.state(), QTimeLine::Running);
int firstValue = timeLine.currentFrame();
QTest::qWait(200);
int endValue = timeLine.currentFrame();
timeLine.stop();
timeLine.setCurrentTime(0);
// linear
referenceEasingCurve = QEasingCurve::Linear;
QCOMPARE(timeLine.easingCurve(), QEasingCurve::Linear);
QCOMPARE(easingCurveObserver.value(), QEasingCurve::Linear);
timeLine.start();
QTest::qWait(100);
QCOMPARE(timeLine.state(), QTimeLine::Running);
// Smooth accellerates slowly so in the beginning so it is farther behind
if (firstValue >= timeLine.currentFrame())
QEXPECT_FAIL("", "QTBUG-24796: QTimeLine exhibits inconsistent timing behaviour", Abort);
QVERIFY(firstValue < timeLine.currentFrame());
QTest::qWait(200);
QVERIFY(endValue > timeLine.currentFrame());
timeLine.stop();
}
void tst_QTimeLine::reverse_data()
{
QTest::addColumn<int>("duration");
QTest::addColumn<int>("start");
QTest::addColumn<int>("end");
QTest::addColumn<int>("direction");
QTest::addColumn<int>("direction2");
QTest::addColumn<int>("direction3");
QTest::addColumn<int>("startTime");
QTest::addColumn<int>("currentFrame");
QTest::addColumn<qreal>("currentValue");
QTest::addColumn<int>("wait");
QTest::addColumn<int>("state");
QTest::addColumn<int>("wait2");
QTest::newRow("start at end") << 200 << 1000 << 2000 << (int)QTimeLine::Backward << (int)QTimeLine::Forward << (int)QTimeLine::Backward << 200 << 2000 << qreal(1.0) << 40 << (int)QTimeLine::Running << 140;
QTest::newRow("start at half") << 200 << 1000 << 2000 << (int)QTimeLine::Backward << (int)QTimeLine::Forward << (int)QTimeLine::Backward << 100 << 1500 << qreal(0.5) << 40 << (int)QTimeLine::Running << 140;
QTest::newRow("start at quarter") << 200 << 1000 << 2000 << (int)QTimeLine::Backward << (int)QTimeLine::Forward << (int)QTimeLine::Backward << 50 << 1250 << qreal(0.25) << 40 << (int)QTimeLine::Running << 140;
}
void tst_QTimeLine::reverse()
{
QFETCH(int, duration);
QFETCH(int, start);
QFETCH(int, end);
QFETCH(int, direction);
QFETCH(int, direction2);
QFETCH(int, direction3);
QFETCH(int, startTime);
QFETCH(int, currentFrame);
QFETCH(qreal, currentValue);
QFETCH(int, wait);
QFETCH(int, state);
QFETCH(int, wait2);
QTimeLine timeLine(duration);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setFrameRange(start, end);
timeLine.setDirection((QTimeLine::Direction)direction);
timeLine.setDirection((QTimeLine::Direction)direction2);
timeLine.setDirection((QTimeLine::Direction)direction3);
QCOMPARE(timeLine.direction(), ((QTimeLine::Direction)direction));
timeLine.setCurrentTime(startTime);
timeLine.setDirection((QTimeLine::Direction)direction);
timeLine.setDirection((QTimeLine::Direction)direction2);
timeLine.setDirection((QTimeLine::Direction)direction3);
QCOMPARE(timeLine.currentFrame(), currentFrame);
QCOMPARE(timeLine.currentValue(), currentValue);
timeLine.start();
QTest::qWait(wait);
QCOMPARE(timeLine.state(), (QTimeLine::State)state);
int firstValue = timeLine.currentFrame();
timeLine.setDirection((QTimeLine::Direction)direction2);
timeLine.setDirection((QTimeLine::Direction)direction3);
timeLine.setDirection((QTimeLine::Direction)direction2);
timeLine.setDirection((QTimeLine::Direction)direction3);
QTest::qWait(wait2);
int endValue = timeLine.currentFrame();
QVERIFY(endValue < firstValue);
}
void tst_QTimeLine::toggleDirection()
{
QTimeLine timeLine;
QCOMPARE(timeLine.direction(), QTimeLine::Forward);
timeLine.toggleDirection();
QCOMPARE(timeLine.direction(), QTimeLine::Backward);
timeLine.toggleDirection();
QCOMPARE(timeLine.direction(), QTimeLine::Forward);
}
void tst_QTimeLine::bindableDirection()
{
// Note: enum values are cast to int so that QCOMPARE will show
// the values if they don't match.
QTimeLine timeLine;
QProperty<QTimeLine::Direction> directionObserver([&]() { return timeLine.direction(); });
QProperty<QTimeLine::Direction> referenceDirection(QTimeLine::Forward);
timeLine.bindableDirection().setBinding([&]() { return referenceDirection.value(); });
QCOMPARE(referenceDirection.value(), QTimeLine::Forward);
QCOMPARE(timeLine.direction(), QTimeLine::Forward);
QCOMPARE(directionObserver.value(), QTimeLine::Forward);
referenceDirection = QTimeLine::Backward;
QCOMPARE(referenceDirection.value(), QTimeLine::Backward);
QCOMPARE(timeLine.direction(), QTimeLine::Backward);
QCOMPARE(directionObserver.value(), QTimeLine::Backward);
referenceDirection = QTimeLine::Forward;
QCOMPARE(referenceDirection.value(), QTimeLine::Forward);
QCOMPARE(timeLine.direction(), QTimeLine::Forward);
QCOMPARE(directionObserver.value(), QTimeLine::Forward);
}
void tst_QTimeLine::frameChanged()
{
QTimeLine timeLine;
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setFrameRange(0,9);
timeLine.setUpdateInterval(800);
QSignalSpy spy(&timeLine, &QTimeLine::frameChanged);
QVERIFY(spy.isValid());
// Test what happens when duration expires before all frames are emitted.
timeLine.start();
QTest::qWait(timeLine.duration()/2);
QCOMPARE(timeLine.state(), QTimeLine::Running);
QCOMPARE(spy.size(), 0);
QTest::qWait(timeLine.duration());
if (timeLine.state() != QTimeLine::NotRunning)
QEXPECT_FAIL("", "QTBUG-24796: QTimeLine runs slower than it should", Abort);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
if (spy.size() != 1)
QEXPECT_FAIL("", "QTBUG-24796: QTimeLine runs slower than it should", Abort);
QCOMPARE(spy.size(), 1);
// Test what happens when the frames are all emitted well before duration expires.
timeLine.setUpdateInterval(5);
spy.clear();
timeLine.setCurrentTime(0);
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(spy.size(), 10);
}
void tst_QTimeLine::stopped()
{
QTimeLine timeLine;
timeLine.setFrameRange(0, 9);
qRegisterMetaType<QTimeLine::State>("QTimeLine::State");
QSignalSpy spy(&timeLine, &QTimeLine::stateChanged);
QVERIFY(spy.isValid());
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
QCOMPARE(spy.size(), 2);
spy.clear();
timeLine.start();
timeLine.stop();
QCOMPARE(spy.size(), 2);
timeLine.setDirection(QTimeLine::Backward);
QCOMPARE(timeLine.loopCount(), 1);
}
void tst_QTimeLine::finished()
{
QTimeLine timeLine;
timeLine.setFrameRange(0,9);
QSignalSpy spy(&timeLine, &QTimeLine::finished);
QVERIFY(spy.isValid());
timeLine.start();
QTRY_COMPARE(spy.size(), 1);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
spy.clear();
timeLine.start();
timeLine.stop();
QCOMPARE(spy.size(), 0);
}
void tst_QTimeLine::isRunning()
{
QTimeLine timeLine;
timeLine.setFrameRange(0,9);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
timeLine.start();
QCOMPARE(timeLine.state(), QTimeLine::Running);
timeLine.stop();
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
timeLine.start();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
}
void tst_QTimeLine::multipleTimeLines()
{
// Stopping a timer shouldn't affect the other timers
QTimeLine timeLine(200);
timeLine.setFrameRange(0,99);
QSignalSpy spy(&timeLine, &QTimeLine::finished);
QVERIFY(spy.isValid());
QTimeLine timeLineKiller;
timeLineKiller.setFrameRange(0,99);
timeLineKiller.start();
timeLine.start();
timeLineKiller.stop();
QTest::qWait(timeLine.duration()*2);
QCOMPARE(spy.size(), 1);
}
void tst_QTimeLine::sineCurve()
{
QTimeLine timeLine(1000);
timeLine.setEasingCurve(QEasingCurve::SineCurve);
QCOMPARE(timeLine.valueForTime(0), qreal(0));
QCOMPARE(timeLine.valueForTime(250), qreal(0.5));
QCOMPARE(timeLine.valueForTime(500), qreal(1));
QCOMPARE(timeLine.valueForTime(750), qreal(0.5));
QCOMPARE(timeLine.valueForTime(1000), qreal(0));
}
void tst_QTimeLine::cosineCurve()
{
QTimeLine timeLine(1000);
timeLine.setEasingCurve(QEasingCurve::CosineCurve);
QCOMPARE(timeLine.valueForTime(0), qreal(0.5));
QCOMPARE(timeLine.valueForTime(250), qreal(1));
QCOMPARE(timeLine.valueForTime(500), qreal(0.5));
QCOMPARE(timeLine.valueForTime(750), qreal(0));
QCOMPARE(timeLine.valueForTime(1000), qreal(0.5));
}
void tst_QTimeLine::outOfRange()
{
QTimeLine timeLine(1000);
QCOMPARE(timeLine.valueForTime(-100), qreal(0));
QCOMPARE(timeLine.valueForTime(2000), qreal(1));
timeLine.setEasingCurve(QEasingCurve::SineCurve);
QCOMPARE(timeLine.valueForTime(2000), qreal(0));
}
void tst_QTimeLine::stateInFinishedSignal()
{
QTimeLine timeLine(50);
connect(&timeLine, SIGNAL(finished()), this, SLOT(finishedSlot()));
state = QTimeLine::State(-1);
timeLine.start();
QTest::qWait(250);
QCOMPARE(state, QTimeLine::NotRunning);
}
void tst_QTimeLine::finishedSlot()
{
QTimeLine *timeLine = qobject_cast<QTimeLine *>(sender());
if (timeLine)
state = timeLine->state();
}
void tst_QTimeLine::resume()
{
QTimeLine timeLine(1000);
{
QCOMPARE(timeLine.currentTime(), 0);
timeLine.start();
QTRY_VERIFY(timeLine.currentTime() > 0);
timeLine.stop();
int oldCurrentTime = timeLine.currentTime();
QVERIFY(oldCurrentTime > 0);
QVERIFY(oldCurrentTime < 1000);
timeLine.resume();
QTRY_VERIFY(timeLine.currentTime() > oldCurrentTime);
timeLine.stop();
int currentTime = timeLine.currentTime();
QVERIFY(currentTime < 1000);
}
timeLine.setDirection(QTimeLine::Backward);
{
timeLine.setCurrentTime(1000);
QCOMPARE(timeLine.currentTime(), 1000);
timeLine.start();
QTRY_VERIFY(timeLine.currentTime() < 1000);
timeLine.stop();
int oldCurrentTime = timeLine.currentTime();
QVERIFY(oldCurrentTime < 1000);
QVERIFY(oldCurrentTime > 0);
timeLine.resume();
QTRY_VERIFY(timeLine.currentTime() < oldCurrentTime);
timeLine.stop();
int currentTime = timeLine.currentTime();
QVERIFY(currentTime < oldCurrentTime);
QVERIFY(currentTime > 0);
}
}
void tst_QTimeLine::restart()
{
QTimeLine timeLine(100);
timeLine.setFrameRange(0,9);
timeLine.start();
QTRY_COMPARE(timeLine.currentFrame(), timeLine.endFrame());
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
// A restart with the same duration
timeLine.start();
QCOMPARE(timeLine.state(), QTimeLine::Running);
QCOMPARE(timeLine.currentFrame(), timeLine.startFrame());
QCOMPARE(timeLine.currentTime(), 0);
QTRY_COMPARE(timeLine.currentFrame(), timeLine.endFrame());
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
// Set a smaller duration and restart
timeLine.setDuration(50);
timeLine.start();
QCOMPARE(timeLine.state(), QTimeLine::Running);
QCOMPARE(timeLine.currentFrame(), timeLine.startFrame());
QCOMPARE(timeLine.currentTime(), 0);
QTRY_COMPARE(timeLine.currentFrame(), timeLine.endFrame());
QCOMPARE(timeLine.state(), QTimeLine::NotRunning);
// Set a longer duration and restart
timeLine.setDuration(150);
timeLine.start();
QCOMPARE(timeLine.state(), QTimeLine::Running);
QCOMPARE(timeLine.currentFrame(), timeLine.startFrame());
QCOMPARE(timeLine.currentTime(), 0);
}
void tst_QTimeLine::setPaused()
{
const int EndTime = 10000;
QTimeLine timeLine(EndTime);
{
QCOMPARE(timeLine.currentTime(), 0);
timeLine.start();
QTRY_VERIFY(timeLine.currentTime() != 0); // wait for start
timeLine.setPaused(true);
int oldCurrentTime = timeLine.currentTime();
QVERIFY(oldCurrentTime > 0);
QVERIFY(oldCurrentTime < EndTime);
QTest::qWait(1000);
timeLine.setPaused(false);
QTRY_VERIFY(timeLine.currentTime() > oldCurrentTime);
QVERIFY(timeLine.currentTime() > 0);
QVERIFY(timeLine.currentTime() < EndTime);
timeLine.stop();
}
}
void tst_QTimeLine::automatedBindableTests()
{
QTimeLine timeLine(200);
QTestPrivate::testReadWritePropertyBasics(timeLine, 1000, 2000, "duration");
if (QTest::currentTestFailed()) {
qDebug() << "Failed property test for duration";
return;
}
QTestPrivate::testReadWritePropertyBasics(timeLine, 10, 20, "updateInterval");
if (QTest::currentTestFailed()) {
qDebug() << "Failed property test for updateInterval";
return;
}
QTestPrivate::testReadWritePropertyBasics(timeLine, 10, 20, "currentTime");
if (QTest::currentTestFailed()) {
qDebug() << "Failed property test for currentTime";
return;
}
QTestPrivate::testReadWritePropertyBasics(timeLine, QTimeLine::Forward, QTimeLine::Backward,
"direction");
if (QTest::currentTestFailed()) {
qDebug() << "Failed property test for direction";
return;
}
QTestPrivate::testReadWritePropertyBasics(timeLine, 4, 5, "loopCount");
if (QTest::currentTestFailed()) {
qDebug() << "Failed property test for loopCount";
return;
}
QTestPrivate::testReadWritePropertyBasics<QTimeLine, QEasingCurve>(
timeLine, QEasingCurve::InQuad, QEasingCurve::OutQuad, "easingCurve");
if (QTest::currentTestFailed()) {
qDebug() << "Failed property test for easingCurve";
return;
}
}
QTEST_MAIN(tst_QTimeLine)
#include "tst_qtimeline.moc"

Some files were not shown because too many files have changed in this diff Show More