diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2012-04-17 12:58:41 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@nokia.com> | 2012-04-17 12:58:52 +0200 |
commit | 64255ef6502b1144f7b0aa4b2bf62803e0d4788b (patch) | |
tree | 29bf116bfda2ccf61057115690d14f85cc9b085b /tests/auto/corelib/tools | |
parent | 4a9fb41a7947d0bb7a47a9625603a436df288b24 (diff) | |
parent | 7e0beba891cb963a1d535bd45b0be78b43b8d07f (diff) |
Merge remote-tracking branch 'origin/api_changes'
Change-Id: I964b0a6f5c38351fdfafb8a2a128a349ff8c89d1
Diffstat (limited to 'tests/auto/corelib/tools')
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/qarraydata.pro | 5 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/simplevector.h | 378 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp | 1605 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp | 336 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qhash/tst_qhash.cpp | 105 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qlist/tst_qlist.cpp | 172 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qlocale/tst_qlocale.cpp | 2 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qmap/tst_qmap.cpp | 172 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp | 23 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qstring/tst_qstring.cpp | 295 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp | 30 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp | 116 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qvector/tst_qvector.cpp | 94 | ||||
-rw-r--r-- | tests/auto/corelib/tools/tools.pro | 1 |
14 files changed, 3240 insertions, 94 deletions
diff --git a/tests/auto/corelib/tools/qarraydata/qarraydata.pro b/tests/auto/corelib/tools/qarraydata/qarraydata.pro new file mode 100644 index 0000000000..8e368117fa --- /dev/null +++ b/tests/auto/corelib/tools/qarraydata/qarraydata.pro @@ -0,0 +1,5 @@ +TARGET = tst_qarraydata +SOURCES += tst_qarraydata.cpp +HEADERS += simplevector.h +QT = core testlib +CONFIG += testcase parallel_test diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h new file mode 100644 index 0000000000..7e679704c8 --- /dev/null +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QARRAY_TEST_SIMPLE_VECTOR_H +#define QARRAY_TEST_SIMPLE_VECTOR_H + +#include <QtCore/qarraydata.h> +#include <QtCore/qarraydatapointer.h> + +#include <algorithm> + +template <class T> +struct SimpleVector +{ +private: + typedef QTypedArrayData<T> Data; + +public: + typedef T value_type; + typedef typename Data::iterator iterator; + typedef typename Data::const_iterator const_iterator; + + SimpleVector() + { + } + + explicit SimpleVector(size_t n) + : d(Data::allocate(n)) + { + if (n) + d->appendInitialize(n); + } + + SimpleVector(size_t n, const T &t) + : d(Data::allocate(n)) + { + if (n) + d->copyAppend(n, t); + } + + SimpleVector(const T *begin, const T *end) + : d(Data::allocate(end - begin)) + { + if (end - begin) + d->copyAppend(begin, end); + } + + SimpleVector(QArrayDataPointerRef<T> ptr) + : d(ptr) + { + } + + explicit SimpleVector(Data *ptr) + : d(ptr) + { + } + + bool empty() const { return d->size == 0; } + bool isNull() const { return d.isNull(); } + bool isEmpty() const { return this->empty(); } + + bool isStatic() const { return d->ref.isStatic(); } + bool isShared() const { return d->ref.isShared(); } + bool isSharedWith(const SimpleVector &other) const { return d == other.d; } + bool isSharable() const { return d->ref.isSharable(); } + + void setSharable(bool sharable) { d.setSharable(sharable); } + + size_t size() const { return d->size; } + size_t capacity() const { return d->alloc; } + + iterator begin() { detach(); return d->begin(); } + iterator end() { detach(); return d->end(); } + + const_iterator begin() const { return d->begin(); } + const_iterator end() const { return d->end(); } + + 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->capacityReserved) + return; + if (!d->ref.isShared()) { + d->capacityReserved = 1; + return; + } + } + + SimpleVector detached(Data::allocate(qMax(n, size()), + d->detachFlags() | Data::CapacityReserved)); + if (size()) + detached.d->copyAppend(constBegin(), constEnd()); + detached.swap(*this); + } + + void resize(size_t newSize) + { + if (size() == newSize) + return; + + if (d.needsDetach() || newSize > capacity()) { + SimpleVector detached(Data::allocate( + d->detachCapacity(newSize), d->detachFlags())); + 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; + + T *const begin = d->begin(); + if (d.needsDetach() + || capacity() - size() < size_t(last - first)) { + SimpleVector detached(Data::allocate( + d->detachCapacity(size() + (last - first)), + d->detachFlags() | Data::Grow)); + + detached.d->copyAppend(first, last); + detached.d->copyAppend(begin, begin + d->size); + detached.swap(*this); + + return; + } + + d->insert(begin, first, last); + } + + void append(const_iterator first, const_iterator last) + { + if (first == last) + return; + + if (d.needsDetach() + || capacity() - size() < size_t(last - first)) { + SimpleVector detached(Data::allocate( + d->detachCapacity(size() + (last - first)), + d->detachFlags() | Data::Grow)); + + if (d->size) { + const T *const begin = constBegin(); + detached.d->copyAppend(begin, begin + d->size); + } + detached.d->copyAppend(first, last); + detached.swap(*this); + + return; + } + + d->copyAppend(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; + + T *const begin = d->begin(); + T *const where = begin + position; + const T *const end = begin + d->size; + if (d.needsDetach() + || capacity() - size() < size_t(last - first)) { + SimpleVector detached(Data::allocate( + d->detachCapacity(size() + (last - first)), + d->detachFlags() | Data::Grow)); + + if (position) + detached.d->copyAppend(begin, where); + detached.d->copyAppend(first, last); + detached.d->copyAppend(where, end); + detached.swap(*this); + + return; + } + + if ((first >= where && first < end) + || (last > where && last <= end)) { + // Copy overlapping data first and only then shuffle it into place + T *start = d->begin() + position; + T *middle = d->end(); + + d->copyAppend(first, last); + std::rotate(start, middle, d->end()); + + return; + } + + d->insert(where, first, last); + } + + 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, + QArrayData::AllocationOptions options = Data::Default) + { + return SimpleVector(Data::fromRawData(data, size, options)); + } + +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 diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp new file mode 100644 index 0000000000..53217b2222 --- /dev/null +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -0,0 +1,1605 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QString> +#include <QtCore/qarraydata.h> + +#include "simplevector.h" + +struct SharedNullVerifier +{ + SharedNullVerifier() + { + Q_ASSERT(QArrayData::shared_null[0].ref.isStatic()); + Q_ASSERT(QArrayData::shared_null[0].ref.isShared()); + Q_ASSERT(QArrayData::shared_null[0].ref.isSharable()); + } +}; + +// This is meant to verify/ensure that shared_null is not being dynamically +// initialized and stays away from the order-of-static-initialization fiasco. +// +// Of course, if this was to fail, qmake and the build should have crashed and +// burned before we ever got to this point :-) +SharedNullVerifier globalInit; + +class tst_QArrayData : public QObject +{ + Q_OBJECT + +private slots: + void referenceCounting(); + void sharedNullEmpty(); + void staticData(); + void simpleVector(); + void simpleVectorReserve_data(); + void simpleVectorReserve(); + void allocate_data(); + void allocate(); + void alignment_data(); + void alignment(); + void typedData(); + void gccBug43247(); + void arrayOps(); + void arrayOps2(); + void setSharable_data(); + void setSharable(); + void fromRawData(); + void literals(); + void variadicLiterals(); + void rValueReferences(); + void grow(); +}; + +template <class T> const T &const_(const T &t) { return t; } + +void tst_QArrayData::referenceCounting() +{ + { + // Reference counting initialized to 1 (owned) + QArrayData array = { { Q_BASIC_ATOMIC_INITIALIZER(1) }, 0, 0, 0, 0 }; + + QCOMPARE(array.ref.atomic.load(), 1); + + QVERIFY(!array.ref.isStatic()); + QVERIFY(array.ref.isSharable()); + + QVERIFY(array.ref.ref()); + QCOMPARE(array.ref.atomic.load(), 2); + + QVERIFY(array.ref.deref()); + QCOMPARE(array.ref.atomic.load(), 1); + + QVERIFY(array.ref.ref()); + QCOMPARE(array.ref.atomic.load(), 2); + + QVERIFY(array.ref.deref()); + QCOMPARE(array.ref.atomic.load(), 1); + + QVERIFY(!array.ref.deref()); + QCOMPARE(array.ref.atomic.load(), 0); + + // Now would be a good time to free/release allocated data + } + + { + // Reference counting initialized to 0 (non-sharable) + QArrayData array = { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, 0 }; + + QCOMPARE(array.ref.atomic.load(), 0); + + QVERIFY(!array.ref.isStatic()); + QVERIFY(!array.ref.isSharable()); + + QVERIFY(!array.ref.ref()); + // Reference counting fails, data should be copied + QCOMPARE(array.ref.atomic.load(), 0); + + QVERIFY(!array.ref.deref()); + QCOMPARE(array.ref.atomic.load(), 0); + + // Free/release data + } + + { + // Reference counting initialized to -1 (static read-only data) + QArrayData array = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, 0 }; + + QCOMPARE(array.ref.atomic.load(), -1); + + QVERIFY(array.ref.isStatic()); + QVERIFY(array.ref.isSharable()); + + QVERIFY(array.ref.ref()); + QCOMPARE(array.ref.atomic.load(), -1); + + QVERIFY(array.ref.deref()); + QCOMPARE(array.ref.atomic.load(), -1); + } +} + +void tst_QArrayData::sharedNullEmpty() +{ + QArrayData *null = const_cast<QArrayData *>(QArrayData::shared_null); + QArrayData *empty = QArrayData::allocate(1, Q_ALIGNOF(QArrayData), 0); + + QVERIFY(null->ref.isStatic()); + QVERIFY(null->ref.isSharable()); + QVERIFY(null->ref.isShared()); + + QVERIFY(empty->ref.isStatic()); + QVERIFY(empty->ref.isSharable()); + QVERIFY(empty->ref.isShared()); + + QCOMPARE(null->ref.atomic.load(), -1); + QCOMPARE(empty->ref.atomic.load(), -1); + + QVERIFY(null->ref.ref()); + QVERIFY(empty->ref.ref()); + + QCOMPARE(null->ref.atomic.load(), -1); + QCOMPARE(empty->ref.atomic.load(), -1); + + QVERIFY(null->ref.deref()); + QVERIFY(empty->ref.deref()); + + QCOMPARE(null->ref.atomic.load(), -1); + QCOMPARE(empty->ref.atomic.load(), -1); + + QVERIFY(null != empty); + + QCOMPARE(null->size, 0); + QCOMPARE(null->alloc, 0u); + QCOMPARE(null->capacityReserved, 0u); + + QCOMPARE(empty->size, 0); + QCOMPARE(empty->alloc, 0u); + QCOMPARE(empty->capacityReserved, 0u); +} + +void tst_QArrayData::staticData() +{ + QStaticArrayData<char, 10> charArray = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(char, 10), + { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' } + }; + QStaticArrayData<int, 10> intArray = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } + }; + QStaticArrayData<double, 10> doubleArray = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(double, 10), + { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f } + }; + + QCOMPARE(charArray.header.size, 10); + QCOMPARE(intArray.header.size, 10); + QCOMPARE(doubleArray.header.size, 10); + + QCOMPARE(charArray.header.data(), reinterpret_cast<void *>(&charArray.data)); + QCOMPARE(intArray.header.data(), reinterpret_cast<void *>(&intArray.data)); + QCOMPARE(doubleArray.header.data(), reinterpret_cast<void *>(&doubleArray.data)); +} + +void tst_QArrayData::simpleVector() +{ + QArrayData data0 = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, 0 }; + QStaticArrayData<int, 7> data1 = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 7), + { 0, 1, 2, 3, 4, 5, 6 } + }; + + int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + SimpleVector<int> v1; + SimpleVector<int> v2(v1); + SimpleVector<int> v3(static_cast<QTypedArrayData<int> *>(&data0)); + SimpleVector<int> v4(static_cast<QTypedArrayData<int> *>(&data1.header)); + SimpleVector<int> v5(static_cast<QTypedArrayData<int> *>(&data0)); + SimpleVector<int> v6(static_cast<QTypedArrayData<int> *>(&data1.header)); + SimpleVector<int> v7(10, 5); + SimpleVector<int> v8(array, array + sizeof(array)/sizeof(*array)); + + v3 = v1; + v1.swap(v3); + v4.clear(); + + QVERIFY(v1.isNull()); + QVERIFY(v2.isNull()); + QVERIFY(v3.isNull()); + QVERIFY(v4.isNull()); + QVERIFY(!v5.isNull()); + QVERIFY(!v6.isNull()); + QVERIFY(!v7.isNull()); + QVERIFY(!v8.isNull()); + + QVERIFY(v1.isEmpty()); + QVERIFY(v2.isEmpty()); + QVERIFY(v3.isEmpty()); + QVERIFY(v4.isEmpty()); + QVERIFY(v5.isEmpty()); + QVERIFY(!v6.isEmpty()); + QVERIFY(!v7.isEmpty()); + QVERIFY(!v8.isEmpty()); + + QCOMPARE(v1.size(), size_t(0)); + QCOMPARE(v2.size(), size_t(0)); + QCOMPARE(v3.size(), size_t(0)); + QCOMPARE(v4.size(), size_t(0)); + QCOMPARE(v5.size(), size_t(0)); + QCOMPARE(v6.size(), size_t(7)); + QCOMPARE(v7.size(), size_t(10)); + QCOMPARE(v8.size(), size_t(10)); + + QCOMPARE(v1.capacity(), size_t(0)); + QCOMPARE(v2.capacity(), size_t(0)); + QCOMPARE(v3.capacity(), size_t(0)); + QCOMPARE(v4.capacity(), size_t(0)); + QCOMPARE(v5.capacity(), size_t(0)); + // v6.capacity() is unspecified, for now + QVERIFY(v7.capacity() >= size_t(10)); + QVERIFY(v8.capacity() >= size_t(10)); + + QVERIFY(v1.isStatic()); + QVERIFY(v2.isStatic()); + QVERIFY(v3.isStatic()); + QVERIFY(v4.isStatic()); + QVERIFY(v5.isStatic()); + QVERIFY(v6.isStatic()); + QVERIFY(!v7.isStatic()); + QVERIFY(!v8.isStatic()); + + QVERIFY(v1.isShared()); + QVERIFY(v2.isShared()); + QVERIFY(v3.isShared()); + QVERIFY(v4.isShared()); + QVERIFY(v5.isShared()); + QVERIFY(v6.isShared()); + QVERIFY(!v7.isShared()); + QVERIFY((SimpleVector<int>(v7), v7.isShared())); + QVERIFY(!v7.isShared()); + QVERIFY(!v8.isShared()); + + QVERIFY(v1.isSharable()); + QVERIFY(v2.isSharable()); + QVERIFY(v3.isSharable()); + QVERIFY(v4.isSharable()); + QVERIFY(v5.isSharable()); + QVERIFY(v6.isSharable()); + QVERIFY(v7.isSharable()); + QVERIFY(v8.isSharable()); + + QVERIFY(v1.isSharedWith(v2)); + QVERIFY(v1.isSharedWith(v3)); + QVERIFY(v1.isSharedWith(v4)); + QVERIFY(!v1.isSharedWith(v5)); + QVERIFY(!v1.isSharedWith(v6)); + + QCOMPARE((void *)v1.constBegin(), (void *)v1.constEnd()); + QCOMPARE((void *)v4.constBegin(), (void *)v4.constEnd()); + QCOMPARE((void *)(v6.constBegin() + v6.size()), (void *)v6.constEnd()); + QCOMPARE((void *)(v7.constBegin() + v7.size()), (void *)v7.constEnd()); + QCOMPARE((void *)(v8.constBegin() + v8.size()), (void *)v8.constEnd()); + + QVERIFY(v1 == v2); + QVERIFY(v1 == v3); + QVERIFY(v1 == v4); + QVERIFY(v1 == v5); + QVERIFY(!(v1 == v6)); + + QVERIFY(v1 != v6); + QVERIFY(v4 != v6); + QVERIFY(v5 != v6); + QVERIFY(!(v1 != v5)); + + QVERIFY(v1 < v6); + QVERIFY(!(v6 < v1)); + QVERIFY(v6 > v1); + QVERIFY(!(v1 > v6)); + QVERIFY(v1 <= v6); + QVERIFY(!(v6 <= v1)); + QVERIFY(v6 >= v1); + QVERIFY(!(v1 >= v6)); + + { + SimpleVector<int> temp(v6); + + QCOMPARE(const_(v6).front(), 0); + QCOMPARE(const_(v6).back(), 6); + + QVERIFY(temp.isShared()); + QVERIFY(temp.isSharedWith(v6)); + + QCOMPARE(temp.front(), 0); + QCOMPARE(temp.back(), 6); + + // Detached + QVERIFY(!temp.isShared()); + const int *const tempBegin = temp.begin(); + + for (size_t i = 0; i < v6.size(); ++i) { + QCOMPARE(const_(v6)[i], int(i)); + QCOMPARE(const_(v6).at(i), int(i)); + QCOMPARE(&const_(v6)[i], &const_(v6).at(i)); + + QCOMPARE(const_(v8)[i], const_(v6)[i]); + + QCOMPARE(temp[i], int(i)); + QCOMPARE(temp.at(i), int(i)); + QCOMPARE(&temp[i], &temp.at(i)); + } + + // A single detach should do + QCOMPARE(temp.begin(), tempBegin); + } + + { + int count = 0; + Q_FOREACH (int value, v7) { + QCOMPARE(value, 5); + ++count; + } + + QCOMPARE(count, 10); + } + + { + int count = 0; + Q_FOREACH (int value, v8) { + QCOMPARE(value, count); + ++count; + } + + QCOMPARE(count, 10); + } + + v5 = v6; + QVERIFY(v5.isSharedWith(v6)); + QVERIFY(!v1.isSharedWith(v5)); + + v1.swap(v6); + QVERIFY(v6.isNull()); + QVERIFY(v1.isSharedWith(v5)); + + { + using std::swap; + swap(v1, v6); + QVERIFY(v5.isSharedWith(v6)); + QVERIFY(!v1.isSharedWith(v5)); + } + + v1.prepend(array, array + sizeof(array)/sizeof(array[0])); + QCOMPARE(v1.size(), size_t(10)); + QVERIFY(v1 == v8); + + v6 = v1; + QVERIFY(v1.isSharedWith(v6)); + + v1.prepend(array, array + sizeof(array)/sizeof(array[0])); + QVERIFY(!v1.isSharedWith(v6)); + QCOMPARE(v1.size(), size_t(20)); + QCOMPARE(v6.size(), size_t(10)); + + for (int i = 0; i < 20; ++i) + QCOMPARE(v1[i], v6[i % 10]); + + v1.clear(); + + v1.append(array, array + sizeof(array)/sizeof(array[0])); + QCOMPARE(v1.size(), size_t(10)); + QVERIFY(v1 == v8); + + v6 = v1; + QVERIFY(v1.isSharedWith(v6)); + + v1.append(array, array + sizeof(array)/sizeof(array[0])); + QVERIFY(!v1.isSharedWith(v6)); + QCOMPARE(v1.size(), size_t(20)); + QCOMPARE(v6.size(), size_t(10)); + + for (int i = 0; i < 20; ++i) + QCOMPARE(v1[i], v6[i % 10]); + + v1.insert(0, v6.constBegin(), v6.constEnd()); + QCOMPARE(v1.size(), size_t(30)); + + v6 = v1; + QVERIFY(v1.isSharedWith(v6)); + + v1.insert(10, v6.constBegin(), v6.constEnd()); + QVERIFY(!v1.isSharedWith(v6)); + QCOMPARE(v1.size(), size_t(60)); + QCOMPARE(v6.size(), size_t(30)); + + for (int i = 0; i < 30; ++i) + QCOMPARE(v6[i], v8[i % 10]); + + v1.insert(v1.size(), v6.constBegin(), v6.constEnd()); + QCOMPARE(v1.size(), size_t(90)); + + v1.insert(-1, v8.constBegin(), v8.constEnd()); + QCOMPARE(v1.size(), size_t(100)); + + v1.insert(-11, v8.constBegin(), v8.constEnd()); + QCOMPARE(v1.size(), size_t(110)); + + v1.insert(-200, v8.constBegin(), v8.constEnd()); + QCOMPARE(v1.size(), size_t(120)); + + for (int i = 0; i < 120; ++i) + QCOMPARE(v1[i], v8[i % 10]); + + { + v7.setSharable(true); + QVERIFY(v7.isSharable()); + + SimpleVector<int> copy1(v7); + QVERIFY(copy1.isSharedWith(v7)); + + v7.setSharable(false); + QVERIFY(!v7.isSharable()); + + QVERIFY(!copy1.isSharedWith(v7)); + QCOMPARE(v7.size(), copy1.size()); + for (size_t i = 0; i < copy1.size(); ++i) + QCOMPARE(v7[i], copy1[i]); + + SimpleVector<int> clone(v7); + QVERIFY(!clone.isSharedWith(v7)); + QCOMPARE(clone.size(), copy1.size()); + for (size_t i = 0; i < copy1.size(); ++i) + QCOMPARE(clone[i], copy1[i]); + + v7.setSharable(true); + QVERIFY(v7.isSharable()); + + SimpleVector<int> copy2(v7); + QVERIFY(copy2.isSharedWith(v7)); + } + + { + SimpleVector<int> null; + SimpleVector<int> empty(0, 5); + + QVERIFY(null.isSharable()); + QVERIFY(empty.isSharable()); + + null.setSharable(true); + empty.setSharable(true); + + QVERIFY(null.isSharable()); + QVERIFY(empty.isSharable()); + + QVERIFY(null.isEmpty()); + QVERIFY(empty.isEmpty()); + + null.setSharable(false); + empty.setSharable(false); + + QVERIFY(!null.isSharable()); + QVERIFY(!empty.isSharable()); + + QVERIFY(null.isEmpty()); + QVERIFY(empty.isEmpty()); + + null.setSharable(true); + empty.setSharable(true); + + QVERIFY(null.isSharable()); + QVERIFY(empty.isSharable()); + + QVERIFY(null.isEmpty()); + QVERIFY(empty.isEmpty()); + } +} + +Q_DECLARE_METATYPE(SimpleVector<int>) + +void tst_QArrayData::simpleVectorReserve_data() +{ + QTest::addColumn<SimpleVector<int> >("vector"); + QTest::addColumn<size_t>("capacity"); + QTest::addColumn<size_t>("size"); + + QTest::newRow("null") << SimpleVector<int>() << size_t(0) << size_t(0); + QTest::newRow("empty") << SimpleVector<int>(0, 42) << size_t(0) << size_t(0); + QTest::newRow("non-empty") << SimpleVector<int>(5, 42) << size_t(5) << size_t(5); + + static const QStaticArrayData<int, 15> array = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 15), + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } }; + QArrayDataPointerRef<int> p = { + static_cast<QTypedArrayData<int> *>( + const_cast<QArrayData *>(&array.header)) }; + + QTest::newRow("static") << SimpleVector<int>(p) << size_t(0) << size_t(15); + QTest::newRow("raw-data") << SimpleVector<int>::fromRawData(array.data, 15) << size_t(0) << size_t(15); +} + +void tst_QArrayData::simpleVectorReserve() +{ + QFETCH(SimpleVector<int>, vector); + QFETCH(size_t, capacity); + QFETCH(size_t, size); + + QVERIFY(!capacity || capacity >= size); + + QCOMPARE(vector.capacity(), capacity); + QCOMPARE(vector.size(), size); + + const SimpleVector<int> copy(vector); + + vector.reserve(0); + QCOMPARE(vector.capacity(), capacity); + QCOMPARE(vector.size(), size); + + vector.reserve(10); + + // zero-capacity (immutable) resets with detach + if (!capacity) + capacity = size; + + QCOMPARE(vector.capacity(), qMax(size_t(10), capacity)); + QCOMPARE(vector.size(), size); + + vector.reserve(20); + QCOMPARE(vector.capacity(), size_t(20)); + QCOMPARE(vector.size(), size); + + vector.reserve(30); + QCOMPARE(vector.capacity(), size_t(30)); + QCOMPARE(vector.size(), size); + + QVERIFY(vector == copy); +} + +struct Deallocator +{ + Deallocator(size_t objectSize, size_t alignment) + : objectSize(objectSize) + , alignment(alignment) + { + } + + ~Deallocator() + { + Q_FOREACH (QArrayData *data, headers) + QArrayData::deallocate(data, objectSize, alignment); + } + + size_t objectSize; + size_t alignment; + QVector<QArrayData *> headers; +}; + +Q_DECLARE_METATYPE(const QArrayData *) +Q_DECLARE_METATYPE(QArrayData::AllocationOptions) + +void tst_QArrayData::allocate_data() +{ + QTest::addColumn<size_t>("objectSize"); + QTest::addColumn<size_t>("alignment"); + QTest::addColumn<QArrayData::AllocationOptions>("allocateOptions"); + QTest::addColumn<bool>("isCapacityReserved"); + QTest::addColumn<bool>("isSharable"); + QTest::addColumn<const QArrayData *>("commonEmpty"); + + struct { + char const *typeName; + size_t objectSize; + size_t alignment; + } types[] = { + { "char", sizeof(char), Q_ALIGNOF(char) }, + { "short", sizeof(short), Q_ALIGNOF(short) }, + { "void *", sizeof(void *), Q_ALIGNOF(void *) } + }; + + QArrayData *shared_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0); + QArrayData *unsharable_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0, QArrayData::Unsharable); + + QVERIFY(shared_empty); + QVERIFY(unsharable_empty); + + struct { + char const *description; + QArrayData::AllocationOptions allocateOptions; + bool isCapacityReserved; + bool isSharable; + const QArrayData *commonEmpty; + } options[] = { + { "Default", QArrayData::Default, false, true, shared_empty }, + { "Reserved", QArrayData::CapacityReserved, true, true, shared_empty }, + { "Reserved | Unsharable", + QArrayData::CapacityReserved | QArrayData::Unsharable, true, false, + unsharable_empty }, + { "Unsharable", QArrayData::Unsharable, false, false, unsharable_empty }, + { "Grow", QArrayData::Grow, false, true, shared_empty } + }; + + for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); ++i) + for (size_t j = 0; j < sizeof(options)/sizeof(options[0]); ++j) + QTest::newRow(qPrintable( + QLatin1String(types[i].typeName) + + QLatin1String(": ") + + QLatin1String(options[j].description))) + << types[i].objectSize << types[i].alignment + << options[j].allocateOptions << options[j].isCapacityReserved + << options[j].isSharable << options[j].commonEmpty; +} + +void tst_QArrayData::allocate() +{ + QFETCH(size_t, objectSize); + QFETCH(size_t, alignment); + QFETCH(QArrayData::AllocationOptions, allocateOptions); + QFETCH(bool, isCapacityReserved); + QFETCH(bool, isSharable); + QFETCH(const QArrayData *, commonEmpty); + + // Minimum alignment that can be requested is that of QArrayData. + // Typically, this alignment is sizeof(void *) and ensured by malloc. + size_t minAlignment = qMax(alignment, Q_ALIGNOF(QArrayData)); + + // Shared Empty + QCOMPARE(QArrayData::allocate(objectSize, minAlignment, 0, + QArrayData::AllocationOptions(allocateOptions)), commonEmpty); + + Deallocator keeper(objectSize, minAlignment); + keeper.headers.reserve(1024); + + for (int capacity = 1; capacity <= 1024; capacity <<= 1) { + QArrayData *data = QArrayData::allocate(objectSize, minAlignment, + capacity, QArrayData::AllocationOptions(allocateOptions)); + keeper.headers.append(data); + + QCOMPARE(data->size, 0); + if (allocateOptions & QArrayData::Grow) + QVERIFY(data->alloc > uint(capacity)); + else + QCOMPARE(data->alloc, uint(capacity)); + QCOMPARE(data->capacityReserved, uint(isCapacityReserved)); + QCOMPARE(data->ref.isSharable(), isSharable); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(data->data(), 'A', objectSize * capacity); + } +} + +class Unaligned +{ + char dummy[8]; +}; + +void tst_QArrayData::alignment_data() +{ + QTest::addColumn<size_t>("alignment"); + + for (int i = 1; i < 10; ++i) { + size_t alignment = 1u << i; + QTest::newRow(qPrintable(QString::number(alignment))) << alignment; + } +} + +void tst_QArrayData::alignment() +{ + QFETCH(size_t, alignment); + + // Minimum alignment that can be requested is that of QArrayData. + // Typically, this alignment is sizeof(void *) and ensured by malloc. + size_t minAlignment = qMax(alignment, Q_ALIGNOF(QArrayData)); + + Deallocator keeper(sizeof(Unaligned), minAlignment); + keeper.headers.reserve(100); + + for (int i = 0; i < 100; ++i) { + QArrayData *data = QArrayData::allocate(sizeof(Unaligned), + minAlignment, 8, QArrayData::Default); + keeper.headers.append(data); + + QVERIFY(data); + QCOMPARE(data->size, 0); + QVERIFY(data->alloc >= uint(8)); + + // These conditions should hold as long as header and array are + // allocated together + QVERIFY(data->offset >= qptrdiff(sizeof(QArrayData))); + QVERIFY(data->offset <= qptrdiff(sizeof(QArrayData) + + minAlignment - Q_ALIGNOF(QArrayData))); + + // Data is aligned + QCOMPARE(quintptr(data->data()) % alignment, quintptr(0u)); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(data->data(), 'A', sizeof(Unaligned) * 8); + } +} + +void tst_QArrayData::typedData() +{ + QStaticArrayData<int, 10> data = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } + }; + QCOMPARE(data.header.size, 10); + + { + QTypedArrayData<int> *array = + static_cast<QTypedArrayData<int> *>(&data.header); + QCOMPARE(array->data(), data.data); + + int j = 0; + for (QTypedArrayData<int>::iterator iter = array->begin(); + iter != array->end(); ++iter, ++j) + QCOMPARE(iter, data.data + j); + QCOMPARE(j, 10); + } + + { + const QTypedArrayData<int> *array = + static_cast<const QTypedArrayData<int> *>(&data.header); + + QCOMPARE(array->data(), data.data); + + int j = 0; + for (QTypedArrayData<int>::const_iterator iter = array->begin(); + iter != array->end(); ++iter, ++j) + QCOMPARE(iter, data.data + j); + QCOMPARE(j, 10); + } + + { + QTypedArrayData<int> *null = QTypedArrayData<int>::sharedNull(); + QTypedArrayData<int> *empty = QTypedArrayData<int>::allocate(0); + + QVERIFY(null != empty); + + QCOMPARE(null->size, 0); + QCOMPARE(empty->size, 0); + + QCOMPARE(null->begin(), null->end()); + QCOMPARE(empty->begin(), empty->end()); + } + + + { + Deallocator keeper(sizeof(char), + Q_ALIGNOF(QTypedArrayData<char>::AlignmentDummy)); + QArrayData *array = QTypedArrayData<char>::allocate(10); + keeper.headers.append(array); + + QVERIFY(array); + QCOMPARE(array->size, 0); + QCOMPARE(array->alloc, 10u); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(array->data(), 0, 10 * sizeof(char)); + + keeper.headers.clear(); + QTypedArrayData<short>::deallocate(array); + + QVERIFY(true); + } + + { + Deallocator keeper(sizeof(short), + Q_ALIGNOF(QTypedArrayData<short>::AlignmentDummy)); + QArrayData *array = QTypedArrayData<short>::allocate(10); + keeper.headers.append(array); + + QVERIFY(array); + QCOMPARE(array->size, 0); + QCOMPARE(array->alloc, 10u); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(array->data(), 0, 10 * sizeof(short)); + + keeper.headers.clear(); + QTypedArrayData<short>::deallocate(array); + + QVERIFY(true); + } + + { + Deallocator keeper(sizeof(double), + Q_ALIGNOF(QTypedArrayData<double>::AlignmentDummy)); + QArrayData *array = QTypedArrayData<double>::allocate(10); + keeper.headers.append(array); + + QVERIFY(array); + QCOMPARE(array->size, 0); + QCOMPARE(array->alloc, 10u); + + // Check that the allocated array can be used. Best tested with a + // memory checker, such as valgrind, running. + ::memset(array->data(), 0, 10 * sizeof(double)); + + keeper.headers.clear(); + QTypedArrayData<double>::deallocate(array); + + QVERIFY(true); + } +} + +void tst_QArrayData::gccBug43247() +{ + // This test tries to verify QArrayData is not affected by GCC optimizer + // bug #43247. + // Reported on GCC 4.4.3, Linux, affects QVector + + QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (3)"); + QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (4)"); + QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (5)"); + QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (6)"); + QTest::ignoreMessage(QtDebugMsg, "GCC Optimization bug #43247 not triggered (7)"); + + SimpleVector<int> array(10, 0); + // QVector<int> vector(10, 0); + + for (int i = 0; i < 10; ++i) { + if (i >= 3 && i < 8) + qDebug("GCC Optimization bug #43247 not triggered (%i)", i); + + // When access to data is implemented through an array of size 1, this + // line lets the compiler assume i == 0, and the conditional above is + // skipped. + QVERIFY(array.at(i) == 0); + // QVERIFY(vector.at(i) == 0); + } +} + +struct CountedObject +{ + CountedObject() + : id(liveCount++) + , flags(DefaultConstructed) + { + } + + CountedObject(const CountedObject &other) + : id(other.id) + , flags(other.flags == DefaultConstructed + ? ObjectFlags(CopyConstructed | DefaultConstructed) + : CopyConstructed) + { + ++liveCount; + } + + ~CountedObject() + { + --liveCount; + } + + CountedObject &operator=(const CountedObject &other) + { + flags = ObjectFlags(other.flags | CopyAssigned); + id = other.id; + return *this; + } + + struct LeakChecker + { + LeakChecker() + : previousLiveCount(liveCount) + { + } + + ~LeakChecker() + { + QCOMPARE(liveCount, previousLiveCount); + } + + private: + const size_t previousLiveCount; + }; + + enum ObjectFlags { + DefaultConstructed = 1, + CopyConstructed = 2, + CopyAssigned = 4 + }; + + size_t id; // not unique + ObjectFlags flags; + + static size_t liveCount; +}; + +size_t CountedObject::liveCount = 0; + +void tst_QArrayData::arrayOps() +{ + CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker) + + const int intArray[5] = { 80, 101, 100, 114, 111 }; + const QString stringArray[5] = { + QLatin1String("just"), + QLatin1String("for"), + QLatin1String("testing"), + QLatin1String("a"), + QLatin1String("vector") + }; + const CountedObject objArray[5]; + + QVERIFY(!QTypeInfo<int>::isComplex && !QTypeInfo<int>::isStatic); + QVERIFY(QTypeInfo<QString>::isComplex && !QTypeInfo<QString>::isStatic); + QVERIFY(QTypeInfo<CountedObject>::isComplex && QTypeInfo<CountedObject>::isStatic); + + QCOMPARE(CountedObject::liveCount, size_t(5)); + for (size_t i = 0; i < 5; ++i) + QCOMPARE(objArray[i].id, i); + + //////////////////////////////////////////////////////////////////////////// + // copyAppend (I) + SimpleVector<int> vi(intArray, intArray + 5); + SimpleVector<QString> vs(stringArray, stringArray + 5); + SimpleVector<CountedObject> vo(objArray, objArray + 5); + + QCOMPARE(CountedObject::liveCount, size_t(10)); + for (int i = 0; i < 5; ++i) { + QCOMPARE(vi[i], intArray[i]); + QVERIFY(vs[i].isSharedWith(stringArray[i])); + + QCOMPARE(vo[i].id, objArray[i].id); + QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed + | CountedObject::DefaultConstructed); + } + + //////////////////////////////////////////////////////////////////////////// + // destroyAll + vi.clear(); + vs.clear(); + vo.clear(); + + QCOMPARE(CountedObject::liveCount, size_t(5)); + + //////////////////////////////////////////////////////////////////////////// + // copyAppend (II) + int referenceInt = 7; + QString referenceString = QLatin1String("reference"); + CountedObject referenceObject; + + vi = SimpleVector<int>(5, referenceInt); + vs = SimpleVector<QString>(5, referenceString); + vo = SimpleVector<CountedObject>(5, referenceObject); + + QCOMPARE(vi.size(), size_t(5)); + QCOMPARE(vs.size(), size_t(5)); + QCOMPARE(vo.size(), size_t(5)); + + QCOMPARE(CountedObject::liveCount, size_t(11)); + for (int i = 0; i < 5; ++i) { + QCOMPARE(vi[i], referenceInt); + QVERIFY(vs[i].isSharedWith(referenceString)); + + QCOMPARE(vo[i].id, referenceObject.id); + QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed + | CountedObject::DefaultConstructed); + } + + //////////////////////////////////////////////////////////////////////////// + // insert + vi.reserve(30); + vs.reserve(30); + vo.reserve(30); + + QCOMPARE(vi.size(), size_t(5)); + QCOMPARE(vs.size(), size_t(5)); + QCOMPARE(vo.size(), size_t(5)); + + QVERIFY(vi.capacity() >= 30); + QVERIFY(vs.capacity() >= 30); + QVERIFY(vo.capacity() >= 30); + + // Displace as many elements as array is extended by + vi.insert(0, intArray, intArray + 5); + vs.insert(0, stringArray, stringArray + 5); + vo.insert(0, objArray, objArray + 5); + + QCOMPARE(vi.size(), size_t(10)); + QCOMPARE(vs.size(), size_t(10)); + QCOMPARE(vo.size(), size_t(10)); + + // Displace more elements than array is extended by + vi.insert(0, intArray, intArray + 5); + vs.insert(0, stringArray, stringArray + 5); + vo.insert(0, objArray, objArray + 5); + + QCOMPARE(vi.size(), size_t(15)); + QCOMPARE(vs.size(), size_t(15)); + QCOMPARE(vo.size(), size_t(15)); + + // Displace less elements than array is extended by + vi.insert(5, vi.constBegin(), vi.constEnd()); + vs.insert(5, vs.constBegin(), vs.constEnd()); + vo.insert(5, vo.constBegin(), vo.constEnd()); + + QCOMPARE(vi.size(), size_t(30)); + QCOMPARE(vs.size(), size_t(30)); + QCOMPARE(vo.size(), size_t(30)); + + QCOMPARE(CountedObject::liveCount, size_t(36)); + for (int i = 0; i < 5; ++i) { + QCOMPARE(vi[i], intArray[i % 5]); + QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); + + QCOMPARE(vo[i].id, objArray[i % 5].id); + QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed + | CountedObject::CopyAssigned); + } + + for (int i = 5; i < 15; ++i) { + QCOMPARE(vi[i], intArray[i % 5]); + QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); + + QCOMPARE(vo[i].id, objArray[i % 5].id); + QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed + | CountedObject::CopyAssigned); + } + + for (int i = 15; i < 20; ++i) { + QCOMPARE(vi[i], referenceInt); + QVERIFY(vs[i].isSharedWith(referenceString)); + + QCOMPARE(vo[i].id, referenceObject.id); + QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed + | CountedObject::CopyAssigned); + } + + for (int i = 20; i < 25; ++i) { + QCOMPARE(vi[i], intArray[i % 5]); + QVERIFY(vs[i].isSharedWith(stringArray[i % 5])); + + QCOMPARE(vo[i].id, objArray[i % 5].id); + + // Originally inserted as (DefaultConstructed | CopyAssigned), later + // get shuffled into place by std::rotate (SimpleVector::insert, + // overlapping mode). + // Depending on implementation of rotate, final assignment can be: + // - straight from source: DefaultConstructed | CopyAssigned + // - through a temporary: CopyConstructed | CopyAssigned + QCOMPARE(vo[i].flags & CountedObject::CopyAssigned, + int(CountedObject::CopyAssigned)); + } + + for (int i = 25; i < 30; ++i) { + QCOMPARE(vi[i], referenceInt); + QVERIFY(vs[i].isSharedWith(referenceString)); + + QCOMPARE(vo[i].id, referenceObject.id); + QCOMPARE(int(vo[i].flags), CountedObject::CopyConstructed + | CountedObject::CopyAssigned); + } +} + +void tst_QArrayData::arrayOps2() +{ + CountedObject::LeakChecker leakChecker; Q_UNUSED(leakChecker) + + //////////////////////////////////////////////////////////////////////////// + // appendInitialize + SimpleVector<int> vi(5); + SimpleVector<QString> vs(5); + SimpleVector<CountedObject> vo(5); + + QCOMPARE(vi.size(), size_t(5)); + QCOMPARE(vs.size(), size_t(5)); + QCOMPARE(vo.size(), size_t(5)); + + QCOMPARE(CountedObject::liveCount, size_t(5)); + for (size_t i = 0; i < 5; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i); + QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); + } + + //////////////////////////////////////////////////////////////////////////// + // appendInitialize, again + + // These will detach + vi.resize(10); + vs.resize(10); + vo.resize(10); + + QCOMPARE(vi.size(), size_t(10)); + QCOMPARE(vs.size(), size_t(10)); + QCOMPARE(vo.size(), size_t(10)); + + QCOMPARE(CountedObject::liveCount, size_t(10)); + for (size_t i = 0; i < 5; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i); + QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed + | CountedObject::CopyConstructed); + } + + for (size_t i = 5; i < 10; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i + 5); + QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); + } + + //////////////////////////////////////////////////////////////////////////// + // truncate + QVERIFY(!vi.isShared()); + QVERIFY(!vs.isShared()); + QVERIFY(!vo.isShared()); + + // These shouldn't detach + vi.resize(7); + vs.resize(7); + vo.resize(7); + + QCOMPARE(vi.size(), size_t(7)); + QCOMPARE(vs.size(), size_t(7)); + QCOMPARE(vo.size(), size_t(7)); + + QCOMPARE(CountedObject::liveCount, size_t(7)); + for (size_t i = 0; i < 5; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i); + QCOMPARE(int(vo[i].flags), CountedObject::DefaultConstructed + | CountedObject::CopyConstructed); + } + + for (size_t i = 5; i < 7; ++i) { + QCOMPARE(vi[i], 0); + QVERIFY(vs[i].isNull()); + + QCOMPARE(vo[i].id, i + 5); + QCOMPARE(int(vo[i].flags), int(CountedObject::DefaultConstructed)); + } +} + +Q_DECLARE_METATYPE(QArrayDataPointer<int>) + +static inline bool arrayIsFilledWith(const QArrayDataPointer<int> &array, + int fillValue, size_t size) +{ + const int *iter = array->begin(); + const int *const end = array->end(); + + for (size_t i = 0; i < size; ++i, ++iter) + if (*iter != fillValue) + return false; + + if (iter != end) + return false; + + return true; +} + +void tst_QArrayData::setSharable_data() +{ + QTest::addColumn<QArrayDataPointer<int> >("array"); + QTest::addColumn<size_t>("size"); + QTest::addColumn<size_t>("capacity"); + QTest::addColumn<bool>("isCapacityReserved"); + QTest::addColumn<int>("fillValue"); + + QArrayDataPointer<int> null; + QArrayDataPointer<int> empty; empty.clear(); + + static QStaticArrayData<int, 10> staticArrayData = { + Q_STATIC_ARRAY_DATA_HEADER_INITIALIZER(int, 10), + { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 } + }; + + QArrayDataPointer<int> emptyReserved(QTypedArrayData<int>::allocate(5, + QArrayData::CapacityReserved)); + QArrayDataPointer<int> nonEmpty(QTypedArrayData<int>::allocate(5, + QArrayData::Default)); + QArrayDataPointer<int> nonEmptyExtraCapacity( + QTypedArrayData<int>::allocate(10, QArrayData::Default)); + QArrayDataPointer<int> nonEmptyReserved(QTypedArrayData<int>::allocate(15, + QArrayData::CapacityReserved)); + QArrayDataPointer<int> staticArray( + static_cast<QTypedArrayData<int> *>(&staticArrayData.header)); + QArrayDataPointer<int> rawData( + QTypedArrayData<int>::fromRawData(staticArrayData.data, 10)); + + nonEmpty->copyAppend(5, 1); + nonEmptyExtraCapacity->copyAppend(5, 1); + nonEmptyReserved->copyAppend(7, 2); + + QTest::newRow("shared-null") << null << size_t(0) << size_t(0) << false << 0; + QTest::newRow("shared-empty") << empty << size_t(0) << size_t(0) << false << 0; + // unsharable-empty implicitly tested in shared-empty + QTest::newRow("empty-reserved") << emptyReserved << size_t(0) << size_t(5) << true << 0; + QTest::newRow("non-empty") << nonEmpty << size_t(5) << size_t(5) << false << 1; + QTest::newRow("non-empty-extra-capacity") << nonEmptyExtraCapacity << size_t(5) << size_t(10) << false << 1; + QTest::newRow("non-empty-reserved") << nonEmptyReserved << size_t(7) << size_t(15) << true << 2; + QTest::newRow("static-array") << staticArray << size_t(10) << size_t(0) << false << 3; + QTest::newRow("raw-data") << rawData << size_t(10) << size_t(0) << false << 3; +} + +void tst_QArrayData::setSharable() +{ + QFETCH(QArrayDataPointer<int>, array); + QFETCH(size_t, size); + QFETCH(size_t, capacity); + QFETCH(bool, isCapacityReserved); + QFETCH(int, fillValue); + + QVERIFY(array->ref.isShared()); // QTest has a copy + QVERIFY(array->ref.isSharable()); + + QCOMPARE(size_t(array->size), size); + QCOMPARE(size_t(array->alloc), capacity); + QCOMPARE(bool(array->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + // shared-null becomes shared-empty, may otherwise detach + array.setSharable(true); + + QVERIFY(array->ref.isSharable()); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + { + QArrayDataPointer<int> copy(array); + QVERIFY(array->ref.isShared()); + QVERIFY(array->ref.isSharable()); + QCOMPARE(copy.data(), array.data()); + } + + // Unshare, must detach + array.setSharable(false); + + // Immutability (alloc == 0) is lost on detach, as is additional capacity + // if capacityReserved flag is not set. + if ((capacity == 0 && size != 0) + || (!isCapacityReserved && capacity > size)) + capacity = size; + + QVERIFY(!array->ref.isShared()); + QVERIFY(!array->ref.isSharable()); + + QCOMPARE(size_t(array->size), size); + QCOMPARE(size_t(array->alloc), capacity); + QCOMPARE(bool(array->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + { + QArrayDataPointer<int> copy(array); + QVERIFY(!array->ref.isShared()); + QVERIFY(!array->ref.isSharable()); + + // Null/empty is always shared + QCOMPARE(copy->ref.isShared(), !(size || isCapacityReserved)); + QVERIFY(copy->ref.isSharable()); + + QCOMPARE(size_t(copy->size), size); + QCOMPARE(size_t(copy->alloc), capacity); + QCOMPARE(bool(copy->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(copy, fillValue, size)); + } + + // Make sharable, again + array.setSharable(true); + + QCOMPARE(array->ref.isShared(), !(size || isCapacityReserved)); + QVERIFY(array->ref.isSharable()); + + QCOMPARE(size_t(array->size), size); + QCOMPARE(size_t(array->alloc), capacity); + QCOMPARE(bool(array->capacityReserved), isCapacityReserved); + QVERIFY(arrayIsFilledWith(array, fillValue, size)); + + { + QArrayDataPointer<int> copy(array); + QVERIFY(array->ref.isShared()); + QCOMPARE(copy.data(), array.data()); + } + + QCOMPARE(array->ref.isShared(), !(size || isCapacityReserved)); + QVERIFY(array->ref.isSharable()); +} + +void tst_QArrayData::fromRawData() +{ + static const int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + + { + // Default: Immutable, sharable + SimpleVector<int> raw = SimpleVector<int>::fromRawData(array, + sizeof(array)/sizeof(array[0]), QArrayData::Default); + + QCOMPARE(raw.size(), size_t(11)); + QCOMPARE(raw.constBegin(), array); + QCOMPARE((void *)raw.constEnd(), (void *)(array + sizeof(array)/sizeof(array[0]))); + + QVERIFY(!raw.isShared()); + QVERIFY(SimpleVector<int>(raw).isSharedWith(raw)); + QVERIFY(!raw.isShared()); + + // Detach + QCOMPARE(raw.back(), 11); + QVERIFY(raw.constBegin() != array); + } + + { + // Immutable, unsharable + SimpleVector<int> raw = SimpleVector<int>::fromRawData(array, + sizeof(array)/sizeof(array[0]), QArrayData::Unsharable); + + QCOMPARE(raw.size(), size_t(11)); + QCOMPARE(raw.constBegin(), array); + QCOMPARE((void *)raw.constEnd(), (void *)(array + sizeof(array)/sizeof(array[0]))); + + SimpleVector<int> copy(raw); + QVERIFY(!copy.isSharedWith(raw)); + QVERIFY(!raw.isShared()); + + QCOMPARE(copy.size(), size_t(11)); + + for (size_t i = 0; i < 11; ++i) + QCOMPARE(const_(copy)[i], const_(raw)[i]); + + QCOMPARE(raw.size(), size_t(11)); + QCOMPARE(raw.constBegin(), array); + QCOMPARE((void *)raw.constEnd(), (void *)(array + sizeof(array)/sizeof(array[0]))); + + // Detach + QCOMPARE(raw.back(), 11); + QVERIFY(raw.constBegin() != array); + } +} + +void tst_QArrayData::literals() +{ + { + QArrayDataPointer<char> d = Q_ARRAY_LITERAL(char, "ABCDEFGHIJ"); + QCOMPARE(d->size, 10 + 1); + for (int i = 0; i < 10; ++i) + QCOMPARE(d->data()[i], char('A' + i)); + } + + { + // wchar_t is not necessarily 2-bytes + QArrayDataPointer<wchar_t> d = Q_ARRAY_LITERAL(wchar_t, L"ABCDEFGHIJ"); + QCOMPARE(d->size, 10 + 1); + for (int i = 0; i < 10; ++i) + QCOMPARE(d->data()[i], wchar_t('A' + i)); + } + + { + SimpleVector<char> v = Q_ARRAY_LITERAL(char, "ABCDEFGHIJ"); + + QVERIFY(!v.isNull()); + QVERIFY(!v.isEmpty()); + QCOMPARE(v.size(), size_t(11)); + // v.capacity() is unspecified, for now + +#if defined(Q_COMPILER_VARIADIC_MACROS) \ + && (defined(Q_COMPILER_LAMBDA) || defined(Q_CC_GNU)) + QVERIFY(v.isStatic()); +#endif + + QVERIFY(v.isSharable()); + QCOMPARE((void *)(v.constBegin() + v.size()), (void *)v.constEnd()); + + for (int i = 0; i < 10; ++i) + QCOMPARE(const_(v)[i], char('A' + i)); + QCOMPARE(const_(v)[10], char('\0')); + } +} + +void tst_QArrayData::variadicLiterals() +{ +#if defined(Q_COMPILER_VARIADIC_MACROS) \ + && (defined(Q_COMPILER_LAMBDA) || defined(Q_CC_GNU)) + { + QArrayDataPointer<int> d = + Q_ARRAY_LITERAL(int, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + QCOMPARE(d->size, 10); + for (int i = 0; i < 10; ++i) + QCOMPARE(d->data()[i], i); + } + + { + QArrayDataPointer<char> d = Q_ARRAY_LITERAL(char, + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'); + QCOMPARE(d->size, 10); + for (int i = 0; i < 10; ++i) + QCOMPARE(d->data()[i], char('A' + i)); + } + + { + QArrayDataPointer<const char *> d = Q_ARRAY_LITERAL(const char *, + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J"); + QCOMPARE(d->size, 10); + for (int i = 0; i < 10; ++i) { + QCOMPARE(d->data()[i][0], char('A' + i)); + QCOMPARE(d->data()[i][1], '\0'); + } + } + + { + SimpleVector<int> v = Q_ARRAY_LITERAL(int, 0, 1, 2, 3, 4, 5, 6); + + QVERIFY(!v.isNull()); + QVERIFY(!v.isEmpty()); + QCOMPARE(v.size(), size_t(7)); + // v.capacity() is unspecified, for now + + QVERIFY(v.isStatic()); + + QVERIFY(v.isSharable()); + QCOMPARE((void *)(v.constBegin() + v.size()), (void *)v.constEnd()); + + for (int i = 0; i < 7; ++i) + QCOMPARE(const_(v)[i], i); + } +#else + QSKIP("Variadic Q_ARRAY_LITERAL not available in current configuration."); +#endif // defined(Q_COMPILER_VARIADIC_MACROS) +} + +#ifdef Q_COMPILER_RVALUE_REFS +// std::remove_reference is in C++11, but requires library support +template <class T> struct RemoveReference { typedef T Type; }; +template <class T> struct RemoveReference<T &> { typedef T Type; }; + +// single-argument std::move is in C++11, but requires library support +template <class T> +typename RemoveReference<T>::Type &&cxx11Move(T &&t) +{ + return static_cast<typename RemoveReference<T>::Type &&>(t); +} + +struct CompilerHasCxx11ImplicitMoves +{ + static bool value() + { + DetectImplicitMove d(cxx11Move(DetectImplicitMove())); + return d.constructor == DetectConstructor::MoveConstructor; + } + + struct DetectConstructor + { + Q_DECL_CONSTEXPR DetectConstructor() + : constructor(DefaultConstructor) + { + } + + Q_DECL_CONSTEXPR DetectConstructor(const DetectConstructor &) + : constructor(CopyConstructor) + { + } + + Q_DECL_CONSTEXPR DetectConstructor(DetectConstructor &&) + : constructor(MoveConstructor) + { + } + + enum Constructor { + DefaultConstructor, + CopyConstructor, + MoveConstructor + }; + + Constructor constructor; + }; + + struct DetectImplicitMove + : DetectConstructor + { + }; +}; +#endif + +void tst_QArrayData::rValueReferences() +{ +#ifdef Q_COMPILER_RVALUE_REFS + if (!CompilerHasCxx11ImplicitMoves::value()) + QSKIP("Implicit move ctor not supported in current configuration"); + + SimpleVector<int> v1(1, 42); + SimpleVector<int> v2; + + const SimpleVector<int>::const_iterator begin = v1.constBegin(); + + QVERIFY(!v1.isNull()); + QVERIFY(v2.isNull()); + + // move-assign + v2 = cxx11Move(v1); + + QVERIFY(v1.isNull()); + QVERIFY(!v2.isNull()); + QCOMPARE(v2.constBegin(), begin); + + SimpleVector<int> v3(cxx11Move(v2)); + + QVERIFY(v1.isNull()); + QVERIFY(v2.isNull()); + QVERIFY(!v3.isNull()); + QCOMPARE(v3.constBegin(), begin); + + QCOMPARE(v3.size(), size_t(1)); + QCOMPARE(v3.front(), 42); +#else + QSKIP("RValue references are not supported in current configuration"); +#endif +} + +void tst_QArrayData::grow() +{ + SimpleVector<int> vector; + + QCOMPARE(vector.size(), size_t(0)); + + size_t previousCapacity = vector.capacity(); + size_t allocations = 0; + for (size_t i = 1; i <= (1 << 20); ++i) { + int source[1] = { int(i) }; + vector.append(source, source + 1); + QCOMPARE(vector.size(), i); + if (vector.capacity() != previousCapacity) { + previousCapacity = vector.capacity(); + ++allocations; + } + } + QCOMPARE(vector.size(), size_t(1 << 20)); + + // QArrayData::Grow prevents excessive allocations on a growing container + QVERIFY(allocations > 20 / 2); + QVERIFY(allocations < 20 * 2); + + for (size_t i = 0; i < (1 << 20); ++i) + QCOMPARE(const_(vector).at(i), int(i + 1)); +} + +QTEST_APPLESS_MAIN(tst_QArrayData) +#include "tst_qarraydata.moc" diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp index 5e53683abd..267aa71085 100644 --- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp @@ -43,6 +43,7 @@ #include <qbytearray.h> #include <qfile.h> +#include <qhash.h> #include <limits.h> #include <private/qtools_p.h> #if defined(Q_OS_WINCE) @@ -91,8 +92,14 @@ private slots: void chop_data(); void chop(); void prepend(); + void prependExtended_data(); + void prependExtended(); void append(); + void appendExtended_data(); + void appendExtended(); void insert(); + void insertExtended_data(); + void insertExtended(); void remove_data(); void remove(); void replace_data(); @@ -117,6 +124,12 @@ private slots: void toFromHex_data(); void toFromHex(); void toFromPercentEncoding(); + void fromPercentEncoding_data(); + void fromPercentEncoding(); + void toPercentEncoding_data(); + void toPercentEncoding(); + void toPercentEncoding2_data(); + void toPercentEncoding2(); void compare_data(); void compare(); @@ -130,11 +143,103 @@ private slots: void byteRefDetaching() const; void reserve(); + void reserveExtended_data(); + void reserveExtended(); void movablity_data(); void movablity(); void literals(); }; +static const struct StaticByteArrays { + struct Standard { + QByteArrayData data; + const char string[8]; + } standard; + struct NotNullTerminated { + QByteArrayData data; + const char string[8]; + } notNullTerminated; + struct Shifted { + QByteArrayData data; + const char dummy; // added to change offset of string + const char string[8]; + } shifted; + struct ShiftedNotNullTerminated { + QByteArrayData data; + const char dummy; // added to change offset of string + const char string[8]; + } shiftedNotNullTerminated; + +} statics = {{{ Q_REFCOUNT_INITIALIZE_STATIC, /* length = */ 4, 0, 0, sizeof(QByteArrayData) }, "data"} + ,{{ Q_REFCOUNT_INITIALIZE_STATIC, /* length = */ 4, 0, 0, sizeof(QByteArrayData) }, "dataBAD"} + ,{{ Q_REFCOUNT_INITIALIZE_STATIC, /* length = */ 4, 0, 0, sizeof(QByteArrayData) + sizeof(char) }, 0, "data"} + ,{{ Q_REFCOUNT_INITIALIZE_STATIC, /* length = */ 4, 0, 0, sizeof(QByteArrayData) + sizeof(char) }, 0, "dataBAD"} + }; + +static const QByteArrayDataPtr staticStandard = { const_cast<QByteArrayData *>(&statics.standard.data) }; +static const QByteArrayDataPtr staticNotNullTerminated = { const_cast<QByteArrayData *>(&statics.notNullTerminated.data) }; +static const QByteArrayDataPtr staticShifted = { const_cast<QByteArrayData *>(&statics.shifted.data) }; +static const QByteArrayDataPtr staticShiftedNotNullTerminated = { const_cast<QByteArrayData *>(&statics.shiftedNotNullTerminated.data) }; + +template <class T> const T &verifyZeroTermination(const T &t) { return t; } + +QByteArray verifyZeroTermination(const QByteArray &ba) +{ + // This test does some evil stuff, it's all supposed to work. + + QByteArray::DataPtr baDataPtr = const_cast<QByteArray &>(ba).data_ptr(); + + // Skip if isStatic() or fromRawData(), as those offer no guarantees + if (baDataPtr->ref.isStatic() + || baDataPtr->offset != QByteArray().data_ptr()->offset) + return ba; + + int baSize = ba.size(); + char baTerminator = ba.constData()[baSize]; + if ('\0' != baTerminator) + return QString::fromAscii( + "*** Result ('%1') not null-terminated: 0x%2 ***").arg(QString::fromAscii(ba)) + .arg(baTerminator, 2, 16, QChar('0')).toAscii(); + + // Skip mutating checks on shared strings + if (baDataPtr->ref.isShared()) + return ba; + + const char *baData = ba.constData(); + const QByteArray baCopy(baData, baSize); // Deep copy + + const_cast<char *>(baData)[baSize] = 'x'; + if ('x' != ba.constData()[baSize]) { + return QString::fromAscii("*** Failed to replace null-terminator in " + "result ('%1') ***").arg(QString::fromAscii(ba)).toAscii(); + } + if (ba != baCopy) { + return QString::fromAscii( "*** Result ('%1') differs from its copy " + "after null-terminator was replaced ***").arg(QString::fromAscii(ba)).toAscii(); + } + const_cast<char *>(baData)[baSize] = '\0'; // Restore sanity + + return ba; +} + +// Overriding QTest's QCOMPARE, to check QByteArray for null termination +#undef QCOMPARE +#define QCOMPARE(actual, expected) \ + do { \ + if (!QTest::qCompare(verifyZeroTermination(actual), expected, \ + #actual, #expected, __FILE__, __LINE__)) \ + return; \ + } while (0) \ + /**/ +#undef QTEST +#define QTEST(actual, testElement) \ + do { \ + if (!QTest::qTest(verifyZeroTermination(actual), testElement, \ + #actual, #testElement, __FILE__, __LINE__)) \ + return; \ + } while (0) \ + /**/ + tst_QByteArray::tst_QByteArray() { qRegisterMetaType<qulonglong>("qulonglong"); @@ -517,7 +622,7 @@ void tst_QByteArray::fromBase64() void tst_QByteArray::qvsnprintf() { char buf[20]; - qMemSet(buf, 42, sizeof(buf)); + memset(buf, 42, sizeof(buf)); QCOMPARE(::qsnprintf(buf, 10, "%s", "bubu"), 4); QCOMPARE(static_cast<const char *>(buf), "bubu"); @@ -526,12 +631,12 @@ void tst_QByteArray::qvsnprintf() QCOMPARE(buf[5], char(42)); #endif - qMemSet(buf, 42, sizeof(buf)); + memset(buf, 42, sizeof(buf)); QCOMPARE(::qsnprintf(buf, 5, "%s", "bubu"), 4); QCOMPARE(static_cast<const char *>(buf), "bubu"); QCOMPARE(buf[5], char(42)); - qMemSet(buf, 42, sizeof(buf)); + memset(buf, 42, sizeof(buf)); #ifdef Q_OS_WIN // VS 2005 uses the Qt implementation of vsnprintf. # if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE) @@ -556,7 +661,7 @@ void tst_QByteArray::qvsnprintf() QCOMPARE(buf[4], char(42)); #ifndef Q_OS_WIN - qMemSet(buf, 42, sizeof(buf)); + memset(buf, 42, sizeof(buf)); QCOMPARE(::qsnprintf(buf, 10, ""), 0); #endif } @@ -701,6 +806,35 @@ void tst_QByteArray::prepend() QCOMPARE(ba.prepend("\0 ", 2), QByteArray::fromRawData("\0 321foo", 8)); } +void tst_QByteArray::prependExtended_data() +{ + QTest::addColumn<QByteArray>("array"); + QTest::newRow("literal") << QByteArray(QByteArrayLiteral("data")); + QTest::newRow("standard") << QByteArray(staticStandard); + QTest::newRow("shifted") << QByteArray(staticShifted); + QTest::newRow("notNullTerminated") << QByteArray(staticNotNullTerminated); + QTest::newRow("shiftedNotNullTerminated") << QByteArray(staticShiftedNotNullTerminated); + QTest::newRow("non static data") << QByteArray("data"); + QTest::newRow("from raw data") << QByteArray::fromRawData("data", 4); + QTest::newRow("from raw data not terminated") << QByteArray::fromRawData("dataBAD", 4); +} + +void tst_QByteArray::prependExtended() +{ + QFETCH(QByteArray, array); + + QCOMPARE(QByteArray().prepend(array), QByteArray("data")); + QCOMPARE(QByteArray("").prepend(array), QByteArray("data")); + + QCOMPARE(array.prepend((char*)0), QByteArray("data")); + QCOMPARE(array.prepend(QByteArray()), QByteArray("data")); + QCOMPARE(array.prepend("1"), QByteArray("1data")); + QCOMPARE(array.prepend(QByteArray("2")), QByteArray("21data")); + QCOMPARE(array.prepend('3'), QByteArray("321data")); + QCOMPARE(array.prepend("\0 ", 2), QByteArray::fromRawData("\0 321data", 9)); + QCOMPARE(array.size(), 9); +} + void tst_QByteArray::append() { QByteArray ba("foo"); @@ -714,6 +848,28 @@ void tst_QByteArray::append() QCOMPARE(ba.size(), 7); } +void tst_QByteArray::appendExtended_data() +{ + prependExtended_data(); +} + +void tst_QByteArray::appendExtended() +{ + QFETCH(QByteArray, array); + + QCOMPARE(QByteArray().append(array), QByteArray("data")); + QCOMPARE(QByteArray("").append(array), QByteArray("data")); + + QCOMPARE(array.append((char*)0), QByteArray("data")); + QCOMPARE(array.append(QByteArray()), QByteArray("data")); + QCOMPARE(array.append("1"), QByteArray("data1")); + QCOMPARE(array.append(QByteArray("2")), QByteArray("data12")); + QCOMPARE(array.append('3'), QByteArray("data123")); + QCOMPARE(array.append("\0"), QByteArray("data123")); + QCOMPARE(array.append("\0", 1), QByteArray::fromRawData("data123\0", 8)); + QCOMPARE(array.size(), 8); +} + void tst_QByteArray::insert() { QByteArray ba("Meal"); @@ -736,6 +892,18 @@ void tst_QByteArray::insert() QCOMPARE(ba.size(), 5); } +void tst_QByteArray::insertExtended_data() +{ + prependExtended_data(); +} + +void tst_QByteArray::insertExtended() +{ + QFETCH(QByteArray, array); + QCOMPARE(array.insert(1, "i"), QByteArray("diata")); + QCOMPARE(array.size(), 5); +} + void tst_QByteArray::remove_data() { QTest::addColumn<QByteArray>("src"); @@ -1078,18 +1246,25 @@ void tst_QByteArray::toULongLong() // global function defined in qbytearray.cpp void tst_QByteArray::qAllocMore() { - static const int t[] = { - INT_MIN, INT_MIN + 1, -1234567, -66000, -1025, - -3, -1, 0, +1, +3, +1025, +66000, +1234567, INT_MAX - 1, INT_MAX, - INT_MAX/3 - }; - static const int N = sizeof(t)/sizeof(t[0]); - - // make sure qAllocMore() doesn't loop infinitely on any input - for (int i = 0; i < N; ++i) { - for (int j = 0; j < N; ++j) { - ::qAllocMore(t[i], t[j]); - } + using QT_PREPEND_NAMESPACE(qAllocMore); + + // Not very important, but please behave :-) + QVERIFY(qAllocMore(0, 0) >= 0); + + for (int i = 1; i < 1 << 8; i <<= 1) + QVERIFY(qAllocMore(i, 0) >= i); + + for (int i = 1 << 8; i < 1 << 30; i <<= 1) { + const int alloc = qAllocMore(i, 0); + + QVERIFY(alloc >= i); + QCOMPARE(qAllocMore(i - 8, 8), alloc - 8); + QCOMPARE(qAllocMore(i - 16, 16), alloc - 16); + QCOMPARE(qAllocMore(i - 24, 24), alloc - 24); + QCOMPARE(qAllocMore(i - 32, 32), alloc - 32); + + QVERIFY(qAllocMore(i - 1, 0) >= i - 1); + QVERIFY(qAllocMore(i + 1, 0) >= i + 1); } } @@ -1111,7 +1286,7 @@ void tst_QByteArray::appendAfterFromRawData() arr += QByteArray::fromRawData(data, sizeof(data)); data[0] = 'Y'; } - QVERIFY(arr.at(0) == 'X'); + QCOMPARE(arr.at(0), 'X'); } void tst_QByteArray::toFromHex_data() @@ -1231,6 +1406,91 @@ void tst_QByteArray::toFromPercentEncoding() QVERIFY(QByteArray::fromPercentEncoding(QByteArray()).isNull()); } +void tst_QByteArray::fromPercentEncoding_data() +{ + QTest::addColumn<QByteArray>("encodedString"); + QTest::addColumn<QByteArray>("decodedString"); + + QTest::newRow("NormalString") << QByteArray("filename") << QByteArray("filename"); + QTest::newRow("NormalStringEncoded") << QByteArray("file%20name") << QByteArray("file name"); + QTest::newRow("JustEncoded") << QByteArray("%20") << QByteArray(" "); + QTest::newRow("HTTPUrl") << QByteArray("http://qt.nokia.com") << QByteArray("http://qt.nokia.com"); + QTest::newRow("HTTPUrlEncoded") << QByteArray("http://qt%20nokia%20com") << QByteArray("http://qt nokia com"); + QTest::newRow("EmptyString") << QByteArray("") << QByteArray(""); + QTest::newRow("Task27166") << QByteArray("Fran%C3%A7aise") << QByteArray("Française"); +} + +void tst_QByteArray::fromPercentEncoding() +{ + QFETCH(QByteArray, encodedString); + QFETCH(QByteArray, decodedString); + + QCOMPARE(QByteArray::fromPercentEncoding(encodedString), decodedString); +} + +void tst_QByteArray::toPercentEncoding_data() +{ + QTest::addColumn<QByteArray>("decodedString"); + QTest::addColumn<QByteArray>("encodedString"); + + QTest::newRow("NormalString") << QByteArray("filename") << QByteArray("filename"); + QTest::newRow("NormalStringEncoded") << QByteArray("file name") << QByteArray("file%20name"); + QTest::newRow("JustEncoded") << QByteArray(" ") << QByteArray("%20"); + QTest::newRow("HTTPUrl") << QByteArray("http://qt.nokia.com") << QByteArray("http%3A//qt.nokia.com"); + QTest::newRow("HTTPUrlEncoded") << QByteArray("http://qt nokia com") << QByteArray("http%3A//qt%20nokia%20com"); + QTest::newRow("EmptyString") << QByteArray("") << QByteArray(""); + QTest::newRow("Task27166") << QByteArray("Française") << QByteArray("Fran%C3%A7aise"); +} + +void tst_QByteArray::toPercentEncoding() +{ + QFETCH(QByteArray, decodedString); + QFETCH(QByteArray, encodedString); + + QCOMPARE(decodedString.toPercentEncoding("/.").constData(), encodedString.constData()); +} + +void tst_QByteArray::toPercentEncoding2_data() +{ + QTest::addColumn<QByteArray>("original"); + QTest::addColumn<QByteArray>("encoded"); + QTest::addColumn<QByteArray>("excludeInEncoding"); + QTest::addColumn<QByteArray>("includeInEncoding"); + + QTest::newRow("test_01") << QByteArray("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~") + << QByteArray("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_02") << QByteArray("{\t\n\r^\"abc}") + << QByteArray("%7B%09%0A%0D%5E%22abc%7D") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_03") << QByteArray("://?#[]@!$&'()*+,;=") + << QByteArray("%3A%2F%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_04") << QByteArray("://?#[]@!$&'()*+,;=") + << QByteArray("%3A%2F%2F%3F%23%5B%5D%40!$&'()*+,;=") + << QByteArray("!$&'()*+,;=") + << QByteArray(""); + QTest::newRow("test_05") << QByteArray("abcd") + << QByteArray("a%62%63d") + << QByteArray("") + << QByteArray("bc"); +} + +void tst_QByteArray::toPercentEncoding2() +{ + QFETCH(QByteArray, original); + QFETCH(QByteArray, encoded); + QFETCH(QByteArray, excludeInEncoding); + QFETCH(QByteArray, includeInEncoding); + + QByteArray encodedData = original.toPercentEncoding(excludeInEncoding, includeInEncoding); + QCOMPARE(encodedData.constData(), encoded.constData()); + QCOMPARE(original, QByteArray::fromPercentEncoding(encodedData)); +} + void tst_QByteArray::compare_data() { QTest::addColumn<QByteArray>("str1"); @@ -1298,6 +1558,9 @@ void tst_QByteArray::compare() QCOMPARE(str2 <= str1, isGreater || isEqual); QCOMPARE(str2 >= str1, isLess || isEqual); QCOMPARE(str2 != str1, !isEqual); + + if (isEqual) + QVERIFY(qHash(str1) == qHash(str2)); } void tst_QByteArray::compareCharStar_data() @@ -1449,6 +1712,23 @@ void tst_QByteArray::repeated_data() const << QByteArray(("abc")) << QByteArray(("abcabcabcabc")) << 4; + + QTest::newRow("static not null terminated") + << QByteArray(staticNotNullTerminated) + << QByteArray("datadatadatadata") + << 4; + QTest::newRow("static standard") + << QByteArray(staticStandard) + << QByteArray("datadatadatadata") + << 4; + QTest::newRow("static shifted not null terminated") + << QByteArray(staticShiftedNotNullTerminated) + << QByteArray("datadatadatadata") + << 4; + QTest::newRow("static shifted") + << QByteArray(staticShifted) + << QByteArray("datadatadatadata") + << 4; } void tst_QByteArray::byteRefDetaching() const @@ -1501,6 +1781,22 @@ void tst_QByteArray::reserve() nil2.reserve(0); } +void tst_QByteArray::reserveExtended_data() +{ + prependExtended_data(); +} + +void tst_QByteArray::reserveExtended() +{ + QFETCH(QByteArray, array); + array.reserve(1024); + QVERIFY(array.capacity() == 1024); + QCOMPARE(array, QByteArray("data")); + array.squeeze(); + QCOMPARE(array, QByteArray("data")); + QCOMPARE(array.capacity(), array.size()); +} + void tst_QByteArray::movablity_data() { QTest::addColumn<QByteArray>("array"); @@ -1511,6 +1807,8 @@ void tst_QByteArray::movablity_data() QTest::newRow("empty") << QByteArray(""); QTest::newRow("null") << QByteArray(); QTest::newRow("sss") << QByteArray(3, 's'); + + prependExtended_data(); } void tst_QByteArray::movablity() @@ -1587,8 +1885,8 @@ void tst_QByteArray::literals() QVERIFY(str.length() == 4); QVERIFY(str == "abcd"); - QVERIFY(str.data_ptr()->ref == -1); - QVERIFY(str.data_ptr()->offset == 0); + QVERIFY(str.data_ptr()->ref.isStatic()); + QVERIFY(str.data_ptr()->offset == sizeof(QByteArrayData)); const char *s = str.constData(); QByteArray str2 = str; diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 3b5d15dbfc..5bd13b23a3 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -73,6 +73,7 @@ private slots: void noNeedlessRehashes(); void const_shared_null(); + void twoArguments_qHash(); }; struct Foo { @@ -525,14 +526,14 @@ void tst_QHash::key() hash2.insert(3, "two"); QCOMPARE(hash2.key("one"), 1); QCOMPARE(hash2.key("one", def), 1); - QCOMPARE(hash2.key("two"), 2); - QCOMPARE(hash2.key("two", def), 2); + QVERIFY(hash2.key("two") == 2 || hash2.key("two") == 3); + QVERIFY(hash2.key("two", def) == 2 || hash2.key("two", def) == 3); QCOMPARE(hash2.key("three"), 0); QCOMPARE(hash2.key("three", def), def); hash2.insert(-1, "two"); - QCOMPARE(hash2.key("two"), -1); - QCOMPARE(hash2.key("two", def), -1); + QVERIFY(hash2.key("two") == 2 || hash2.key("two") == 3 || hash2.key("two") == -1); + QVERIFY(hash2.key("two", def) == 2 || hash2.key("two", def) == 3 || hash2.key("two", def) == -1); hash2.insert(0, "zero"); QCOMPARE(hash2.key("zero"), 0); @@ -1203,5 +1204,101 @@ void tst_QHash::const_shared_null() QVERIFY(!hash2.isDetached()); } +// This gets set to != 0 in wrong qHash overloads +static int wrongqHashOverload = 0; + +struct OneArgumentQHashStruct1 {}; +bool operator==(const OneArgumentQHashStruct1 &, const OneArgumentQHashStruct1 &) { return false; } +uint qHash(OneArgumentQHashStruct1) { return 0; } + +struct OneArgumentQHashStruct2 {}; +bool operator==(const OneArgumentQHashStruct2 &, const OneArgumentQHashStruct2 &) { return false; } +uint qHash(const OneArgumentQHashStruct2 &) { return 0; } + +struct OneArgumentQHashStruct3 {}; +bool operator==(const OneArgumentQHashStruct3 &, const OneArgumentQHashStruct3 &) { return false; } +uint qHash(OneArgumentQHashStruct3) { return 0; } +uint qHash(OneArgumentQHashStruct3 &, uint) { wrongqHashOverload = 1; return 0; } + +struct OneArgumentQHashStruct4 {}; +bool operator==(const OneArgumentQHashStruct4 &, const OneArgumentQHashStruct4 &) { return false; } +uint qHash(const OneArgumentQHashStruct4 &) { return 0; } +uint qHash(OneArgumentQHashStruct4 &, uint) { wrongqHashOverload = 1; return 0; } + + +struct TwoArgumentsQHashStruct1 {}; +bool operator==(const TwoArgumentsQHashStruct1 &, const TwoArgumentsQHashStruct1 &) { return false; } +uint qHash(const TwoArgumentsQHashStruct1 &) { wrongqHashOverload = 1; return 0; } +uint qHash(const TwoArgumentsQHashStruct1 &, uint) { return 0; } + +struct TwoArgumentsQHashStruct2 {}; +bool operator==(const TwoArgumentsQHashStruct2 &, const TwoArgumentsQHashStruct2 &) { return false; } +uint qHash(TwoArgumentsQHashStruct2) { wrongqHashOverload = 1; return 0; } +uint qHash(const TwoArgumentsQHashStruct2 &, uint) { return 0; } + +struct TwoArgumentsQHashStruct3 {}; +bool operator==(const TwoArgumentsQHashStruct3 &, const TwoArgumentsQHashStruct3 &) { return false; } +uint qHash(const TwoArgumentsQHashStruct3 &) { wrongqHashOverload = 1; return 0; } +uint qHash(TwoArgumentsQHashStruct3, uint) { return 0; } + +struct TwoArgumentsQHashStruct4 {}; +bool operator==(const TwoArgumentsQHashStruct4 &, const TwoArgumentsQHashStruct4 &) { return false; } +uint qHash(TwoArgumentsQHashStruct4) { wrongqHashOverload = 1; return 0; } +uint qHash(TwoArgumentsQHashStruct4, uint) { return 0; } + +/*! + \internal + + Check that QHash picks up the right overload. + The best one, for a type T, is the two-args version of qHash: + either uint qHash(T, uint) or uint qHash(const T &, uint). + + If neither of these exists, then one between + uint qHash(T) or uint qHash(const T &) must exist + (and it gets selected instead). +*/ +void tst_QHash::twoArguments_qHash() +{ + QHash<OneArgumentQHashStruct1, int> oneArgHash1; + OneArgumentQHashStruct1 oneArgObject1; + oneArgHash1[oneArgObject1] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<OneArgumentQHashStruct2, int> oneArgHash2; + OneArgumentQHashStruct2 oneArgObject2; + oneArgHash2[oneArgObject2] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<OneArgumentQHashStruct3, int> oneArgHash3; + OneArgumentQHashStruct3 oneArgObject3; + oneArgHash3[oneArgObject3] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<OneArgumentQHashStruct4, int> oneArgHash4; + OneArgumentQHashStruct4 oneArgObject4; + oneArgHash4[oneArgObject4] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct1, int> twoArgsHash1; + TwoArgumentsQHashStruct1 twoArgsObject1; + twoArgsHash1[twoArgsObject1] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct2, int> twoArgsHash2; + TwoArgumentsQHashStruct2 twoArgsObject2; + twoArgsHash2[twoArgsObject2] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct3, int> twoArgsHash3; + TwoArgumentsQHashStruct3 twoArgsObject3; + twoArgsHash3[twoArgsObject3] = 1; + QCOMPARE(wrongqHashOverload, 0); + + QHash<TwoArgumentsQHashStruct4, int> twoArgsHash4; + TwoArgumentsQHashStruct4 twoArgsObject4; + twoArgsHash4[twoArgsObject4] = 1; + QCOMPARE(wrongqHashOverload, 0); +} + QTEST_APPLESS_MAIN(tst_QHash) #include "tst_qhash.moc" diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index 934130d3ee..c883c1c5f6 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -48,6 +48,9 @@ class tst_QList : public QObject Q_OBJECT private slots: + void init(); + void cleanup(); + void length() const; void lengthSignature() const; void append() const; @@ -84,8 +87,100 @@ private slots: void initializeList() const; void const_shared_null() const; + void setSharable1_data() const; + void setSharable1() const; + void setSharable2_data() const; + void setSharable2() const; + +private: + int dummyForGuard; +}; + +struct Complex +{ + Complex(int val) + : value(val) + , checkSum(this) + { + ++liveCount; + } + + Complex(Complex const &other) + : value(other.value) + , checkSum(this) + { + ++liveCount; + } + + Complex &operator=(Complex const &other) + { + check(); other.check(); + + value = other.value; + return *this; + } + + ~Complex() + { + --liveCount; + check(); + } + + operator int() const { return value; } + + bool operator==(Complex const &other) const + { + check(); other.check(); + return value == other.value; + } + + bool check() const + { + if (this != checkSum) { + ++errorCount; + return false; + } + return true; + } + + struct Guard + { + Guard() : initialLiveCount(liveCount) {} + ~Guard() { if (liveCount != initialLiveCount) ++errorCount; } + + private: + Q_DISABLE_COPY(Guard); + int initialLiveCount; + }; + + static void resetErrors() { errorCount = 0; } + static int errors() { return errorCount; } + +private: + static int errorCount; + static int liveCount; + + int value; + void *checkSum; }; +int Complex::errorCount = 0; +int Complex::liveCount = 0; + +void tst_QList::init() +{ + Complex::resetErrors(); + new (&dummyForGuard) Complex::Guard(); +} + +void tst_QList::cleanup() +{ + QCOMPARE(Complex::errors(), 0); + + reinterpret_cast<Complex::Guard *>(&dummyForGuard)->~Guard(); + QCOMPARE(Complex::errors(), 0); +} + void tst_QList::length() const { /* Empty list. */ @@ -690,5 +785,82 @@ void tst_QList::const_shared_null() const QVERIFY(!list2.isDetached()); } +Q_DECLARE_METATYPE(QList<int>); +Q_DECLARE_METATYPE(QList<Complex>); + +template <class T> +void generateSetSharableData() +{ + QTest::addColumn<QList<T> >("list"); + QTest::addColumn<int>("size"); + + QTest::newRow("null") << QList<T>() << 0; + QTest::newRow("non-empty") << (QList<T>() << T(0) << T(1) << T(2) << T(3) << T(4)) << 5; +} + +template <class T> +void runSetSharableTest() +{ + QFETCH(QList<T>, list); + QFETCH(int, size); + + QVERIFY(!list.isDetached()); // Shared with QTest + + list.setSharable(true); + + QCOMPARE(list.size(), size); + + { + QList<T> copy(list); + QVERIFY(!copy.isDetached()); + QVERIFY(copy.isSharedWith(list)); + } + + list.setSharable(false); + QVERIFY(list.isDetached() || list.isSharedWith(QList<T>())); + + { + QList<T> copy(list); + + QVERIFY(copy.isDetached() || copy.isSharedWith(QList<T>())); + QCOMPARE(copy.size(), size); + QCOMPARE(copy, list); + } + + list.setSharable(true); + + { + QList<T> copy(list); + + QVERIFY(!copy.isDetached()); + QVERIFY(copy.isSharedWith(list)); + } + + for (int i = 0; i < list.size(); ++i) + QCOMPARE(int(list[i]), i); + + QCOMPARE(list.size(), size); +} + +void tst_QList::setSharable1_data() const +{ + generateSetSharableData<int>(); +} + +void tst_QList::setSharable2_data() const +{ + generateSetSharableData<Complex>(); +} + +void tst_QList::setSharable1() const +{ + runSetSharableTest<int>(); +} + +void tst_QList::setSharable2() const +{ + runSetSharableTest<Complex>(); +} + QTEST_APPLESS_MAIN(tst_QList) #include "tst_qlist.moc" diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index f9de2f0c05..7e12e42107 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -1751,7 +1751,7 @@ void tst_QLocale::dayName_data() QTest::newRow("C narrow") << QString("C") << QString("7") << 7 << QLocale::NarrowFormat; QTest::newRow("ru_RU long") << QString("ru_RU") << QString::fromUtf8("\320\262\320\276\321\201\320\272\321\200\320\265\321\201\320\265\320\275\321\214\320\265") << 7 << QLocale::LongFormat; - QTest::newRow("ru_RU short") << QString("ru_RU") << QString::fromUtf8("\320\222\321\201") << 7 << QLocale::ShortFormat; + QTest::newRow("ru_RU short") << QString("ru_RU") << QString::fromUtf8("\320\262\321\201") << 7 << QLocale::ShortFormat; QTest::newRow("ru_RU narrow") << QString("ru_RU") << QString::fromUtf8("\320\222") << 7 << QLocale::NarrowFormat; } diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index 7d0ef7d7e4..a28ea94aa5 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -41,10 +41,10 @@ #define QT_STRICT_ITERATORS +#include <qmap.h> #include <QtTest/QtTest> #include <QDebug> -#include <qmap.h> class tst_QMap : public QObject { @@ -74,6 +74,11 @@ private slots: void qmultimap_specific(); void const_shared_null(); + + void equal_range(); + void setSharable(); + + void insert(); }; typedef QMap<QString, QString> StringMap; @@ -105,6 +110,11 @@ int MyClass::count = 0; typedef QMap<QString, MyClass> MyMap; +QDebug operator << (QDebug d, const MyClass &c) { + d << c.str; + return d; +} + void tst_QMap::init() { MyClass::count = 0; @@ -152,6 +162,7 @@ void tst_QMap::count() map.insert( "Paul", MyClass("Tvete 6") ); QCOMPARE( map.count(), 9 ); + QCOMPARE( map.count("Paul"), 1 ); #ifndef Q_CC_SUN QCOMPARE( MyClass::count, 9 ); #endif @@ -519,6 +530,7 @@ void tst_QMap::find() for(i = 3; i < 10; ++i) { compareString = testString.arg(i); map1.insertMulti(4, compareString); + QCOMPARE(map1.count(4), i - 2); } QMap<int, QString>::const_iterator it=map1.constFind(4); @@ -588,6 +600,33 @@ void tst_QMap::lowerUpperBound() QCOMPARE(map1.lowerBound(2).key(), 5); // returns iterator to (5, "five") QCOMPARE(map1.lowerBound(10).key(), 10); // returns iterator to (10, "ten") QVERIFY(map1.lowerBound(999) == map1.end()); // returns end() + + map1.insert(3, "three"); + map1.insert(7, "seven"); + map1.insertMulti(7, "seven_2"); + + QCOMPARE(map1.upperBound(0).key(), 1); + QCOMPARE(map1.upperBound(1).key(), 3); + QCOMPARE(map1.upperBound(2).key(), 3); + QCOMPARE(map1.upperBound(3).key(), 5); + QCOMPARE(map1.upperBound(7).key(), 10); + QVERIFY(map1.upperBound(10) == map1.end()); + QVERIFY(map1.upperBound(999) == map1.end()); + + QCOMPARE(map1.lowerBound(0).key(), 1); + QCOMPARE(map1.lowerBound(1).key(), 1); + QCOMPARE(map1.lowerBound(2).key(), 3); + QCOMPARE(map1.lowerBound(3).key(), 3); + QCOMPARE(map1.lowerBound(4).key(), 5); + QCOMPARE(map1.lowerBound(5).key(), 5); + QCOMPARE(map1.lowerBound(6).key(), 7); + QCOMPARE(map1.lowerBound(7).key(), 7); + QCOMPARE(map1.lowerBound(6).value(), QString("seven_2")); + QCOMPARE(map1.lowerBound(7).value(), QString("seven_2")); + QCOMPARE((++map1.lowerBound(6)).value(), QString("seven")); + QCOMPARE((++map1.lowerBound(7)).value(), QString("seven")); + QCOMPARE(map1.lowerBound(10).key(), 10); + QVERIFY(map1.lowerBound(999) == map1.end()); } void tst_QMap::mergeCompare() @@ -655,8 +694,9 @@ void tst_QMap::iterators() stlIt--; QVERIFY(stlIt.value() == "Teststring 3"); - for(stlIt = map.begin(), i = 1; stlIt != map.end(), i < 100; ++stlIt, ++i) + for(stlIt = map.begin(), i = 1; stlIt != map.end(); ++stlIt, ++i) QVERIFY(stlIt.value() == testString.arg(i)); + QCOMPARE(i, 100); //STL-Style const-iterators @@ -675,8 +715,9 @@ void tst_QMap::iterators() cstlIt--; QVERIFY(cstlIt.value() == "Teststring 3"); - for(cstlIt = map.constBegin(), i = 1; cstlIt != map.constEnd(), i < 100; ++cstlIt, ++i) + for(cstlIt = map.constBegin(), i = 1; cstlIt != map.constEnd(); ++cstlIt, ++i) QVERIFY(cstlIt.value() == testString.arg(i)); + QCOMPARE(i, 100); //Java-Style iterators @@ -846,10 +887,129 @@ void tst_QMap::const_shared_null() QMap<int, QString> map2; map2.setSharable(true); QVERIFY(!map2.isDetached()); +} + +void tst_QMap::equal_range() +{ + QMap<int, QString> map; + + QPair<QMap<int, QString>::iterator, QMap<int, QString>::iterator> result = map.equal_range(0); + QCOMPARE(result.first, map.end()); + QCOMPARE(result.second, map.end()); + + map.insert(1, "one"); + + result = map.equal_range(0); + QCOMPARE(result.first, map.find(1)); + QCOMPARE(result.second, map.find(1)); - QMap<int, QString> map3; - map3.setInsertInOrder(true); - map3.setInsertInOrder(false); + result = map.equal_range(1); + QCOMPARE(result.first, map.find(1)); + QCOMPARE(result.second, map.end()); + + result = map.equal_range(2); + QCOMPARE(result.first, map.end()); + QCOMPARE(result.second, map.end()); + + for (int i = -10; i < 10; i += 2) + map.insert(i, QString("%1").arg(i)); + + result = map.equal_range(0); + QCOMPARE(result.first, map.find(0)); + QCOMPARE(result.second, map.find(1)); + + result = map.equal_range(1); + QCOMPARE(result.first, map.find(1)); + QCOMPARE(result.second, map.find(2)); + + result = map.equal_range(2); + QCOMPARE(result.first, map.find(2)); + QCOMPARE(result.second, map.find(4)); + + map.insertMulti(1, "another one"); + result = map.equal_range(1); + QCOMPARE(result.first, map.find(1)); + QCOMPARE(result.second, map.find(2)); + + QCOMPARE(map.count(1), 2); +} + +template <class T> +const T &const_(const T &t) +{ + return t; +} + +void tst_QMap::setSharable() +{ + QMap<int, QString> map; + + map.insert(1, "um"); + map.insert(2, "dois"); + map.insert(4, "quatro"); + map.insert(5, "cinco"); + + map.setSharable(true); + QCOMPARE(map.size(), 4); + QCOMPARE(const_(map)[4], QString("quatro")); + + { + QMap<int, QString> copy(map); + + QVERIFY(!map.isDetached()); + QVERIFY(copy.isSharedWith(map)); + } + + map.setSharable(false); + QVERIFY(map.isDetached()); + QCOMPARE(map.size(), 4); + QCOMPARE(const_(map)[4], QString("quatro")); + + { + QMap<int, QString> copy(map); + + QVERIFY(map.isDetached()); + QVERIFY(copy.isDetached()); + + QCOMPARE(copy.size(), 4); + QCOMPARE(const_(copy)[4], QString("quatro")); + + QCOMPARE(map, copy); + } + + map.setSharable(true); + QCOMPARE(map.size(), 4); + QCOMPARE(const_(map)[4], QString("quatro")); + + { + QMap<int, QString> copy(map); + + QVERIFY(!map.isDetached()); + QVERIFY(copy.isSharedWith(map)); + } +} + +void tst_QMap::insert() +{ + QMap<QString, float> map; + map.insert("cs/key1", 1); + map.insert("cs/key2", 2); + map.insert("cs/key1", 3); + QCOMPARE(map.count(), 2); + + QMap<int, int> intMap; + for (int i = 0; i < 1000; ++i) { + intMap.insert(i, i); + } + + QCOMPARE(intMap.size(), 1000); + + for (int i = 0; i < 1000; ++i) { + QCOMPARE(intMap.value(i), i); + intMap.insert(i, -1); + QCOMPARE(intMap.size(), 1000); + QCOMPARE(intMap.value(i), -1); + } } QTEST_APPLESS_MAIN(tst_QMap) diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp index 5b697a3509..bb9be1d65f 100644 --- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp @@ -114,15 +114,19 @@ public: } }; -template <typename Base> -class RefCountHack: public Base +template<typename T> static inline +QtSharedPointer::ExternalRefCountData *refCountData(const QtSharedPointer::ExternalRefCount<T> &b) { -public: - using Base::d; -}; -template<typename Base> static inline -QtSharedPointer::ExternalRefCountData *refCountData(const Base &b) -{ return static_cast<const RefCountHack<Base> *>(&b)->d; } + // access d-pointer: + struct Dummy { + void* value; + QtSharedPointer::ExternalRefCountData* data; + }; + // sanity checks: + Q_STATIC_ASSERT(sizeof(QtSharedPointer::ExternalRefCount<T>) == sizeof(Dummy)); + Q_ASSERT(static_cast<const Dummy*>(static_cast<const void*>(&b))->value == b.data()); + return static_cast<const Dummy*>(static_cast<const void*>(&b))->data; +} class Data { @@ -1619,7 +1623,8 @@ void hashAndMapTest() QVERIFY(it != c.end()); QCOMPARE(it.key(), k1); ++it; - QVERIFY(it == c.end()); + if (Ordered) + QVERIFY(it == c.end()); } void tst_QSharedPointer::map() diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 4eabd61025..1905c9c049 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -41,6 +41,7 @@ #include <QtTest/QtTest> #include <qregexp.h> +#include <qregularexpression.h> #include <qtextcodec.h> #include <qtextstream.h> #include <qstringlist.h> @@ -50,6 +51,7 @@ #include <qlocale.h> #include <locale.h> +#include <qhash.h> Q_DECLARE_METATYPE(qlonglong) @@ -194,6 +196,7 @@ private slots: void localeAwareCompare(); void split_data(); void split(); + void split_regexp_data(); void split_regexp(); void fromUtf16_data(); void fromUtf16(); @@ -227,6 +230,65 @@ private slots: void assignQLatin1String(); }; +template <class T> const T &verifyZeroTermination(const T &t) { return t; } + +QString verifyZeroTermination(const QString &str) +{ + // This test does some evil stuff, it's all supposed to work. + + QString::DataPtr strDataPtr = const_cast<QString &>(str).data_ptr(); + + // Skip if isStatic() or fromRawData(), as those offer no guarantees + if (strDataPtr->ref.isStatic() + || strDataPtr->offset != QString().data_ptr()->offset) + return str; + + int strSize = str.size(); + QChar strTerminator = str.constData()[strSize]; + if (QChar('\0') != strTerminator) + return QString::fromAscii( + "*** Result ('%1') not null-terminated: 0x%2 ***").arg(str) + .arg(strTerminator.unicode(), 4, 16, QChar('0')); + + // Skip mutating checks on shared strings + if (strDataPtr->ref.isShared()) + return str; + + const QChar *strData = str.constData(); + const QString strCopy(strData, strSize); // Deep copy + + const_cast<QChar *>(strData)[strSize] = QChar('x'); + if (QChar('x') != str.constData()[strSize]) { + return QString::fromAscii("*** Failed to replace null-terminator in " + "result ('%1') ***").arg(str); + } + if (str != strCopy) { + return QString::fromAscii( "*** Result ('%1') differs from its copy " + "after null-terminator was replaced ***").arg(str); + } + const_cast<QChar *>(strData)[strSize] = QChar('\0'); // Restore sanity + + return str; +} + +// Overriding QTest's QCOMPARE, to check QString for null termination +#undef QCOMPARE +#define QCOMPARE(actual, expected) \ + do { \ + if (!QTest::qCompare(verifyZeroTermination(actual), expected, \ + #actual, #expected, __FILE__, __LINE__)) \ + return; \ + } while (0) \ + /**/ +#undef QTEST +#define QTEST(actual, testElement) \ + do { \ + if (!QTest::qTest(verifyZeroTermination(actual), testElement, \ + #actual, #testElement, __FILE__, __LINE__)) \ + return; \ + } while (0) \ + /**/ + typedef QList<int> IntList; Q_DECLARE_METATYPE(QList<QVariant>) @@ -823,7 +885,6 @@ void tst_QString::constructorQByteArray() void tst_QString::STL() { -#ifndef QT_NO_STL #ifndef QT_NO_CAST_TO_ASCII QString qt( "QString" ); @@ -867,9 +928,6 @@ void tst_QString::STL() QCOMPARE(s, QString::fromLatin1("hello")); QCOMPARE(stlStr, s.toStdWString()); -#else - QSKIP( "Not tested without STL support"); -#endif } void tst_QString::truncate() @@ -1089,6 +1147,17 @@ void tst_QString::indexOf() QCOMPARE( rx2.matchedLength(), -1 ); } + { + QRegularExpression::PatternOptions options = QRegularExpression::NoPatternOption; + if (!bcs) + options |= QRegularExpression::CaseInsensitiveOption; + + QRegularExpression re(QRegularExpression::escape(needle), options); + QEXPECT_FAIL("data58", "QRegularExpression does not support case folding", Continue); + QEXPECT_FAIL("data59", "QRegularExpression does not support case folding", Continue); + QCOMPARE( haystack.indexOf(re, startpos), resultpos ); + } + if (cs == Qt::CaseSensitive) { QCOMPARE( haystack.indexOf(needle, startpos), resultpos ); QCOMPARE( haystack.indexOf(ref, startpos), resultpos ); @@ -1276,6 +1345,15 @@ void tst_QString::lastIndexOf() QCOMPARE(rx1.matchedLength(), -1); QCOMPARE(rx2.matchedLength(), -1); } + + { + QRegularExpression::PatternOptions options = QRegularExpression::NoPatternOption; + if (!caseSensitive) + options |= QRegularExpression::CaseInsensitiveOption; + + QRegularExpression re(QRegularExpression::escape(needle), options); + QCOMPARE(haystack.lastIndexOf(re, from), expected); + } } if (cs == Qt::CaseSensitive) { @@ -1311,6 +1389,9 @@ void tst_QString::count() QCOMPARE(a.count( "", Qt::CaseInsensitive), 16); QCOMPARE(a.count(QRegExp("[FG][HI]")),1); QCOMPARE(a.count(QRegExp("[G][HE]")),2); + QCOMPARE(a.count(QRegularExpression("[FG][HI]")), 1); + QCOMPARE(a.count(QRegularExpression("[G][HE]")), 2); + CREATE_REF(QLatin1String("FG")); QCOMPARE(a.count(ref),2); @@ -1336,6 +1417,8 @@ void tst_QString::contains() QVERIFY(a.contains( "", Qt::CaseInsensitive)); QVERIFY(a.contains(QRegExp("[FG][HI]"))); QVERIFY(a.contains(QRegExp("[G][HE]"))); + QVERIFY(a.contains(QRegularExpression("[FG][HI]"))); + QVERIFY(a.contains(QRegularExpression("[G][HE]"))); CREATE_REF(QLatin1String("FG")); QVERIFY(a.contains(ref)); @@ -1430,16 +1513,69 @@ void tst_QString::mid() QVERIFY(a.mid(9999).isNull()); QVERIFY(a.mid(9999,1).isNull()); + QCOMPARE(a.mid(-1, 6), a.mid(0, 5)); + QVERIFY(a.mid(-100, 6).isEmpty()); + QVERIFY(a.mid(INT_MIN, 0).isEmpty()); + QCOMPARE(a.mid(INT_MIN, -1), a); + QVERIFY(a.mid(INT_MIN, INT_MAX).isNull()); + QVERIFY(a.mid(INT_MIN + 1, INT_MAX).isEmpty()); + QCOMPARE(a.mid(INT_MIN + 2, INT_MAX), a.left(1)); + QCOMPARE(a.mid(INT_MIN + a.size() + 1, INT_MAX), a); + QVERIFY(a.mid(INT_MAX).isNull()); + QVERIFY(a.mid(INT_MAX, INT_MAX).isNull()); + QCOMPARE(a.mid(-5, INT_MAX), a); + QCOMPARE(a.mid(-1, INT_MAX), a); + QCOMPARE(a.mid(0, INT_MAX), a); + QCOMPARE(a.mid(1, INT_MAX), QString("BCDEFGHIEfGEFG")); + QCOMPARE(a.mid(5, INT_MAX), QString("FGHIEfGEFG")); + QVERIFY(a.mid(20, INT_MAX).isNull()); + QCOMPARE(a.mid(-1, -1), a); + QString n; QVERIFY(n.mid(3,3).isNull()); QVERIFY(n.mid(0,0).isNull()); QVERIFY(n.mid(9999,0).isNull()); QVERIFY(n.mid(9999,1).isNull()); + QVERIFY(n.mid(-1, 6).isNull()); + QVERIFY(n.mid(-100, 6).isNull()); + QVERIFY(n.mid(INT_MIN, 0).isNull()); + QVERIFY(n.mid(INT_MIN, -1).isNull()); + QVERIFY(n.mid(INT_MIN, INT_MAX).isNull()); + QVERIFY(n.mid(INT_MIN + 1, INT_MAX).isNull()); + QVERIFY(n.mid(INT_MIN + 2, INT_MAX).isNull()); + QVERIFY(n.mid(INT_MIN + n.size() + 1, INT_MAX).isNull()); + QVERIFY(n.mid(INT_MAX).isNull()); + QVERIFY(n.mid(INT_MAX, INT_MAX).isNull()); + QVERIFY(n.mid(-5, INT_MAX).isNull()); + QVERIFY(n.mid(-1, INT_MAX).isNull()); + QVERIFY(n.mid(0, INT_MAX).isNull()); + QVERIFY(n.mid(1, INT_MAX).isNull()); + QVERIFY(n.mid(5, INT_MAX).isNull()); + QVERIFY(n.mid(20, INT_MAX).isNull()); + QVERIFY(n.mid(-1, -1).isNull()); + QString x = "Nine pineapples"; QCOMPARE(x.mid(5, 4), QString("pine")); QCOMPARE(x.mid(5), QString("pineapples")); + QCOMPARE(x.mid(-1, 6), x.mid(0, 5)); + QVERIFY(x.mid(-100, 6).isEmpty()); + QVERIFY(x.mid(INT_MIN, 0).isEmpty()); + QCOMPARE(x.mid(INT_MIN, -1), x); + QVERIFY(x.mid(INT_MIN, INT_MAX).isNull()); + QVERIFY(x.mid(INT_MIN + 1, INT_MAX).isEmpty()); + QCOMPARE(x.mid(INT_MIN + 2, INT_MAX), x.left(1)); + QCOMPARE(x.mid(INT_MIN + x.size() + 1, INT_MAX), x); + QVERIFY(x.mid(INT_MAX).isNull()); + QVERIFY(x.mid(INT_MAX, INT_MAX).isNull()); + QCOMPARE(x.mid(-5, INT_MAX), x); + QCOMPARE(x.mid(-1, INT_MAX), x); + QCOMPARE(x.mid(0, INT_MAX), x); + QCOMPARE(x.mid(1, INT_MAX), QString("ine pineapples")); + QCOMPARE(x.mid(5, INT_MAX), QString("pineapples")); + QVERIFY(x.mid(20, INT_MAX).isNull()); + QCOMPARE(x.mid(-1, -1), x); } void tst_QString::midRef() @@ -1456,16 +1592,69 @@ void tst_QString::midRef() QVERIFY(a.midRef(9999).toString().isEmpty()); QVERIFY(a.midRef(9999,1).toString().isEmpty()); + QCOMPARE(a.midRef(-1, 6), a.midRef(0, 5)); + QVERIFY(a.midRef(-100, 6).isEmpty()); + QVERIFY(a.midRef(INT_MIN, 0).isEmpty()); + QCOMPARE(a.midRef(INT_MIN, -1).toString(), a); + QVERIFY(a.midRef(INT_MIN, INT_MAX).isNull()); + QVERIFY(a.midRef(INT_MIN + 1, INT_MAX).isEmpty()); + QCOMPARE(a.midRef(INT_MIN + 2, INT_MAX), a.leftRef(1)); + QCOMPARE(a.midRef(INT_MIN + a.size() + 1, INT_MAX).toString(), a); + QVERIFY(a.midRef(INT_MAX).isNull()); + QVERIFY(a.midRef(INT_MAX, INT_MAX).isNull()); + QCOMPARE(a.midRef(-5, INT_MAX).toString(), a); + QCOMPARE(a.midRef(-1, INT_MAX).toString(), a); + QCOMPARE(a.midRef(0, INT_MAX).toString(), a); + QCOMPARE(a.midRef(1, INT_MAX).toString(), QString("BCDEFGHIEfGEFG")); + QCOMPARE(a.midRef(5, INT_MAX).toString(), QString("FGHIEfGEFG")); + QVERIFY(a.midRef(20, INT_MAX).isNull()); + QCOMPARE(a.midRef(-1, -1).toString(), a); + QString n; QVERIFY(n.midRef(3,3).toString().isEmpty()); QVERIFY(n.midRef(0,0).toString().isEmpty()); QVERIFY(n.midRef(9999,0).toString().isEmpty()); QVERIFY(n.midRef(9999,1).toString().isEmpty()); + QVERIFY(n.midRef(-1, 6).isNull()); + QVERIFY(n.midRef(-100, 6).isNull()); + QVERIFY(n.midRef(INT_MIN, 0).isNull()); + QVERIFY(n.midRef(INT_MIN, -1).isNull()); + QVERIFY(n.midRef(INT_MIN, INT_MAX).isNull()); + QVERIFY(n.midRef(INT_MIN + 1, INT_MAX).isNull()); + QVERIFY(n.midRef(INT_MIN + 2, INT_MAX).isNull()); + QVERIFY(n.midRef(INT_MIN + n.size() + 1, INT_MAX).isNull()); + QVERIFY(n.midRef(INT_MAX).isNull()); + QVERIFY(n.midRef(INT_MAX, INT_MAX).isNull()); + QVERIFY(n.midRef(-5, INT_MAX).isNull()); + QVERIFY(n.midRef(-1, INT_MAX).isNull()); + QVERIFY(n.midRef(0, INT_MAX).isNull()); + QVERIFY(n.midRef(1, INT_MAX).isNull()); + QVERIFY(n.midRef(5, INT_MAX).isNull()); + QVERIFY(n.midRef(20, INT_MAX).isNull()); + QVERIFY(n.midRef(-1, -1).isNull()); + QString x = "Nine pineapples"; QCOMPARE(x.midRef(5, 4).toString(), QString("pine")); QCOMPARE(x.midRef(5).toString(), QString("pineapples")); + QCOMPARE(x.midRef(-1, 6), x.midRef(0, 5)); + QVERIFY(x.midRef(-100, 6).isEmpty()); + QVERIFY(x.midRef(INT_MIN, 0).isEmpty()); + QCOMPARE(x.midRef(INT_MIN, -1).toString(), x); + QVERIFY(x.midRef(INT_MIN, INT_MAX).isNull()); + QVERIFY(x.midRef(INT_MIN + 1, INT_MAX).isEmpty()); + QCOMPARE(x.midRef(INT_MIN + 2, INT_MAX), x.leftRef(1)); + QCOMPARE(x.midRef(INT_MIN + x.size() + 1, INT_MAX).toString(), x); + QVERIFY(x.midRef(INT_MAX).isNull()); + QVERIFY(x.midRef(INT_MAX, INT_MAX).isNull()); + QCOMPARE(x.midRef(-5, INT_MAX).toString(), x); + QCOMPARE(x.midRef(-1, INT_MAX).toString(), x); + QCOMPARE(x.midRef(0, INT_MAX).toString(), x); + QCOMPARE(x.midRef(1, INT_MAX).toString(), QString("ine pineapples")); + QCOMPARE(x.midRef(5, INT_MAX).toString(), QString("pineapples")); + QVERIFY(x.midRef(20, INT_MAX).isNull()); + QCOMPARE(x.midRef(-1, -1).toString(), x); } void tst_QString::stringRef() @@ -2075,6 +2264,9 @@ void tst_QString::replace_regexp() QString s2 = string; s2.replace( QRegExp(regexp), after ); QTEST( s2, "result" ); + s2 = string; + s2.replace( QRegularExpression(regexp), after ); + QTEST( s2, "result" ); } void tst_QString::remove_uint_uint() @@ -2139,8 +2331,13 @@ void tst_QString::remove_regexp() QFETCH( QString, after ); if ( after.length() == 0 ) { - string.remove( QRegExp(regexp) ); - QTEST( string, "result" ); + QString s2 = string; + s2.remove( QRegExp(regexp) ); + QTEST( s2, "result" ); + + s2 = string; + s2.remove( QRegularExpression(regexp) ); + QTEST( s2, "result" ); } else { QCOMPARE( 0, 0 ); // shut QtTest } @@ -3168,7 +3365,6 @@ void tst_QString::fromStdString() #ifdef Q_CC_HPACC QSKIP("This test crashes on HP-UX with aCC"); #endif -#if !defined(QT_NO_STL) std::string stroustrup = "foo"; QString eng = QString::fromStdString( stroustrup ); QCOMPARE( eng, QString("foo") ); @@ -3176,7 +3372,6 @@ void tst_QString::fromStdString() std::string stdnull( cnull, sizeof(cnull)-1 ); QString qtnull = QString::fromStdString( stdnull ); QCOMPARE( qtnull.size(), int(stdnull.size()) ); -#endif } void tst_QString::toStdString() @@ -3184,7 +3379,6 @@ void tst_QString::toStdString() #ifdef Q_CC_HPACC QSKIP("This test crashes on HP-UX with aCC"); #endif -#if !defined(QT_NO_STL) QString nord = "foo"; std::string stroustrup1 = nord.toStdString(); QVERIFY( qstrcmp(stroustrup1.c_str(), "foo") == 0 ); @@ -3198,7 +3392,6 @@ void tst_QString::toStdString() QString qtnull( qcnull, sizeof(qcnull)/sizeof(QChar) ); std::string stdnull = qtnull.toStdString(); QCOMPARE( int(stdnull.size()), qtnull.size() ); -#endif } void tst_QString::utf8() @@ -3881,8 +4074,12 @@ void tst_QString::section() QFETCH( bool, regexp ); if (regexp) { QCOMPARE( wholeString.section( QRegExp(sep), start, end, QString::SectionFlag(flags) ), sectionString ); + QCOMPARE( wholeString.section( QRegularExpression(sep), start, end, QString::SectionFlag(flags) ), sectionString ); } else { QCOMPARE( wholeString.section( sep, start, end, QString::SectionFlag(flags) ), sectionString ); + QCOMPARE( wholeString.section( QRegExp(QRegExp::escape(sep)), start, end, QString::SectionFlag(flags) ), sectionString ); + QCOMPARE( wholeString.section( QRegularExpression(QRegularExpression::escape(sep)), start, end, QString::SectionFlag(flags) ), sectionString ); + } } @@ -4403,6 +4600,7 @@ void tst_QString::split() QFETCH(QStringList, result); QRegExp rx = QRegExp(QRegExp::escape(sep)); + QRegularExpression re(QRegularExpression::escape(sep)); QStringList list; @@ -4410,6 +4608,8 @@ void tst_QString::split() QVERIFY(list == result); list = str.split(rx); QVERIFY(list == result); + list = str.split(re); + QVERIFY(list == result); if (sep.size() == 1) { list = str.split(sep.at(0)); QVERIFY(list == result); @@ -4419,6 +4619,8 @@ void tst_QString::split() QVERIFY(list == result); list = str.split(rx, QString::KeepEmptyParts); QVERIFY(list == result); + list = str.split(re, QString::KeepEmptyParts); + QVERIFY(list == result); if (sep.size() == 1) { list = str.split(sep.at(0), QString::KeepEmptyParts); QVERIFY(list == result); @@ -4429,39 +4631,51 @@ void tst_QString::split() QVERIFY(list == result); list = str.split(rx, QString::SkipEmptyParts); QVERIFY(list == result); + list = str.split(re, QString::SkipEmptyParts); + QVERIFY(list == result); if (sep.size() == 1) { list = str.split(sep.at(0), QString::SkipEmptyParts); QVERIFY(list == result); } } +void tst_QString::split_regexp_data() +{ + QTest::addColumn<QString>("string"); + QTest::addColumn<QString>("pattern"); + QTest::addColumn<QStringList>("result"); + + QTest::newRow("data01") << "Some text\n\twith strange whitespace." + << "\\s+" + << (QStringList() << "Some" << "text" << "with" << "strange" << "whitespace." ); + + QTest::newRow("data02") << "This time, a normal English sentence." + << "\\W+" + << (QStringList() << "This" << "time" << "a" << "normal" << "English" << "sentence" << ""); + + QTest::newRow("data03") << "Now: this sentence fragment." + << "\\b" + << (QStringList() << "" << "Now" << ": " << "this" << " " << "sentence" << " " << "fragment" << "."); +} + void tst_QString::split_regexp() { - QString str1 = "Some text\n\twith strange whitespace."; - QStringList list1 = str1.split(QRegExp("\\s+")); - QStringList result1; - result1 << "Some" << "text" << "with" << "strange" << "whitespace."; - QVERIFY(list1 == result1); - list1 = str1.split(QRegExp("\\s"), QString::SkipEmptyParts); - QVERIFY(list1 == result1); - - QString str2 = "This time, a normal English sentence."; - QStringList list2 = str2.split(QRegExp("\\W+")); - QStringList result2; - result2 << "This" << "time" << "a" << "normal" << "English" << "sentence" << ""; - QVERIFY(list2 == result2); - list2 = str2.split(QRegExp("\\W"), QString::SkipEmptyParts); - result2.removeAll(QString()); - QVERIFY(list2 == result2); - - QString str3 = "Now: this sentence fragment."; - QStringList list3 = str3.split(QRegExp("\\b")); - QStringList result3; - result3 << "" << "Now" << ": " << "this" << " " << "sentence" << " " << "fragment" << "."; - QVERIFY(list3 == result3); - list3 = str3.split(QRegExp("\\b"), QString::SkipEmptyParts); - result3.removeAll(QString()); - QVERIFY(list3 == result3); + QFETCH(QString, string); + QFETCH(QString, pattern); + QFETCH(QStringList, result); + + QStringList list; + list = string.split(QRegExp(pattern)); + QCOMPARE(list, result); + list = string.split(QRegularExpression(pattern)); + QCOMPARE(list, result); + + result.removeAll(QString()); + + list = string.split(QRegExp(pattern), QString::SkipEmptyParts); + QCOMPARE(list, result); + list = string.split(QRegularExpression(pattern), QString::SkipEmptyParts); + QCOMPARE(list, result); } void tst_QString::fromUtf16_data() @@ -4717,6 +4931,13 @@ void tst_QString::compare() QCOMPARE(sign(QStringRef::compare(r1, r2, Qt::CaseSensitive)), csr); QCOMPARE(sign(QStringRef::compare(r1, r2, Qt::CaseInsensitive)), cir); + if (csr == 0) { + QVERIFY(qHash(s1) == qHash(s2)); + QVERIFY(qHash(s1) == qHash(r2)); + QVERIFY(qHash(r1) == qHash(s2)); + QVERIFY(qHash(r1) == qHash(r2)); + } + if (!cir) { QCOMPARE(s1.toCaseFolded(), s2.toCaseFolded()); } @@ -5065,8 +5286,8 @@ void tst_QString::literals() QVERIFY(str.length() == 4); QVERIFY(str == QLatin1String("abcd")); - QVERIFY(str.data_ptr()->ref == -1); - QVERIFY(str.data_ptr()->offset == 0); + QVERIFY(str.data_ptr()->ref.isStatic()); + QVERIFY(str.data_ptr()->offset == sizeof(QStringData)); const QChar *s = str.constData(); QString str2 = str; diff --git a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp b/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp index 556b9ac16a..862789cc73 100644 --- a/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/corelib/tools/qstringbuilder/qstringbuilder1/stringbuilder.cpp @@ -107,6 +107,21 @@ void runScenario() QCOMPARE(r, r3); #endif + { + static const QStaticStringData<12> literalData = { + Q_STATIC_STRING_DATA_HEADER_INITIALIZER(12), + { 's', 'o', 'm', 'e', ' ', 'l', 'i', 't', 'e', 'r', 'a', 'l' } + }; + static QStringDataPtr literal = { literalData.data_ptr() }; + + r = literal; + QCOMPARE(r, string); + r = r Q literal; + QCOMPARE(r, r2); + r = literal Q literal; + QCOMPARE(r, r2); + } + #ifndef QT_NO_CAST_FROM_ASCII r = string P LITERAL; QCOMPARE(r, r2); @@ -211,6 +226,21 @@ void runScenario() QCOMPARE(r, ba); } + { + static const QStaticByteArrayData<12> literalData = { + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER(12), + { 's', 'o', 'm', 'e', ' ', 'l', 'i', 't', 'e', 'r', 'a', 'l' } + }; + static QByteArrayDataPtr literal = { literalData.data_ptr() }; + + QByteArray ba = literal; + QCOMPARE(ba, QByteArray(LITERAL)); + ba = ba Q literal; + QCOMPARE(ba, QByteArray(LITERAL LITERAL)); + ba = literal Q literal; + QCOMPARE(ba, QByteArray(LITERAL LITERAL)); + } + //operator QString += { QString str = QString::fromUtf8(UTF8_LITERAL); diff --git a/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp b/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp index 6066f7c8e0..16a329f1dd 100644 --- a/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp +++ b/tests/auto/corelib/tools/qstringlist/tst_qstringlist.cpp @@ -41,12 +41,16 @@ #include <QtTest/QtTest> #include <qregexp.h> +#include <qregularexpression.h> #include <qstringlist.h> +#include <locale.h> + class tst_QStringList : public QObject { Q_OBJECT private slots: + void sort(); void filter(); void replaceInStrings(); void removeDuplicates(); @@ -72,18 +76,37 @@ void tst_QStringList::indexOf_regExp() { QStringList list; list << "harald" << "trond" << "vohi" << "harald"; + { + QRegExp re(".*o.*"); + + QCOMPARE(list.indexOf(re), 1); + QCOMPARE(list.indexOf(re, 2), 2); + QCOMPARE(list.indexOf(re, 3), -1); + + QCOMPARE(list.indexOf(QRegExp(".*x.*")), -1); + QCOMPARE(list.indexOf(re, -1), -1); + QCOMPARE(list.indexOf(re, -3), 1); + QCOMPARE(list.indexOf(re, -9999), 1); + QCOMPARE(list.indexOf(re, 9999), -1); - QRegExp re(".*o.*"); + QCOMPARE(list.indexOf(QRegExp("[aeiou]")), -1); + } - QCOMPARE(list.indexOf(re), 1); - QCOMPARE(list.indexOf(re, 2), 2); - QCOMPARE(list.indexOf(re, 3), -1); + { + QRegularExpression re(".*o.*"); - QCOMPARE(list.indexOf(QRegExp(".*x.*")), -1); - QCOMPARE(list.indexOf(re, -1), -1); - QCOMPARE(list.indexOf(re, -3), 1); - QCOMPARE(list.indexOf(re, -9999), 1); - QCOMPARE(list.indexOf(re, 9999), -1); + QCOMPARE(list.indexOf(re), 1); + QCOMPARE(list.indexOf(re, 2), 2); + QCOMPARE(list.indexOf(re, 3), -1); + + QCOMPARE(list.indexOf(QRegularExpression(".*x.*")), -1); + QCOMPARE(list.indexOf(re, -1), -1); + QCOMPARE(list.indexOf(re, -3), 1); + QCOMPARE(list.indexOf(re, -9999), 1); + QCOMPARE(list.indexOf(re, 9999), -1); + + QCOMPARE(list.indexOf(QRegularExpression("[aeiou]")), -1); + } } void tst_QStringList::lastIndexOf_regExp() @@ -91,17 +114,39 @@ void tst_QStringList::lastIndexOf_regExp() QStringList list; list << "harald" << "trond" << "vohi" << "harald"; - QRegExp re(".*o.*"); + { + QRegExp re(".*o.*"); + + QCOMPARE(list.lastIndexOf(re), 2); + QCOMPARE(list.lastIndexOf(re, 2), 2); + QCOMPARE(list.lastIndexOf(re, 1), 1); + + QCOMPARE(list.lastIndexOf(QRegExp(".*x.*")), -1); + QCOMPARE(list.lastIndexOf(re, -1), 2); + QCOMPARE(list.lastIndexOf(re, -3), 1); + QCOMPARE(list.lastIndexOf(re, -9999), -1); + QCOMPARE(list.lastIndexOf(re, 9999), 2); + + QCOMPARE(list.lastIndexOf(QRegExp("[aeiou]")), -1); + } + + { + QRegularExpression re(".*o.*"); + + QCOMPARE(list.lastIndexOf(re), 2); + QCOMPARE(list.lastIndexOf(re, 2), 2); + QCOMPARE(list.lastIndexOf(re, 1), 1); + + QCOMPARE(list.lastIndexOf(QRegularExpression(".*x.*")), -1); + QCOMPARE(list.lastIndexOf(re, -1), 2); + QCOMPARE(list.lastIndexOf(re, -3), 1); + QCOMPARE(list.lastIndexOf(re, -9999), -1); + QCOMPARE(list.lastIndexOf(re, 9999), 2); + + QCOMPARE(list.lastIndexOf(QRegularExpression("[aeiou]")), -1); + } - QCOMPARE(list.lastIndexOf(re), 2); - QCOMPARE(list.lastIndexOf(re, 2), 2); - QCOMPARE(list.lastIndexOf(re, 1), 1); - QCOMPARE(list.lastIndexOf(QRegExp(".*x.*")), -1); - QCOMPARE(list.lastIndexOf(re, -1), 2); - QCOMPARE(list.lastIndexOf(re, -3), 1); - QCOMPARE(list.lastIndexOf(re, -9999), -1); - QCOMPARE(list.lastIndexOf(re, 9999), 2); } void tst_QStringList::indexOf() @@ -149,6 +194,29 @@ void tst_QStringList::filter() list3 = list3.filter( QRegExp("[i]ll") ); list4 << "Bill Gates" << "Bill Clinton"; QCOMPARE( list3, list4 ); + + QStringList list5, list6; + list5 << "Bill Gates" << "Joe Blow" << "Bill Clinton"; + list5 = list5.filter( QRegularExpression("[i]ll") ); + list6 << "Bill Gates" << "Bill Clinton"; + QCOMPARE( list5, list6 ); +} + +void tst_QStringList::sort() +{ + QStringList list1, list2; + list1 << "alpha" << "beta" << "BETA" << "gamma" << "Gamma" << "gAmma" << "epsilon"; + list1.sort(); + list2 << "BETA" << "Gamma" << "alpha" << "beta" << "epsilon" << "gAmma" << "gamma"; + QCOMPARE( list1, list2 ); + + char *current_locale = setlocale(LC_ALL, "C"); + QStringList list3, list4; + list3 << "alpha" << "beta" << "BETA" << "gamma" << "Gamma" << "gAmma" << "epsilon"; + list3.sort(Qt::CaseInsensitive); + list4 << "alpha" << "beta" << "BETA" << "epsilon" << "Gamma" << "gAmma" << "gamma"; + QCOMPARE( list3, list4 ); + setlocale(LC_ALL, current_locale); } void tst_QStringList::replaceInStrings() @@ -170,6 +238,18 @@ void tst_QStringList::replaceInStrings() list6 << "Bill Clinton" << "Bill Gates"; list5.replaceInStrings( QRegExp("^(.*), (.*)$"), "\\2 \\1" ); QCOMPARE( list5, list6 ); + + QStringList list7, list8; + list7 << "alpha" << "beta" << "gamma" << "epsilon"; + list7.replaceInStrings( QRegularExpression("^a"), "o" ); + list8 << "olpha" << "beta" << "gamma" << "epsilon"; + QCOMPARE( list7, list8 ); + + QStringList list9, list10; + list9 << "Bill Clinton" << "Gates, Bill"; + list10 << "Bill Clinton" << "Bill Gates"; + list9.replaceInStrings( QRegularExpression("^(.*), (.*)$"), "\\2 \\1" ); + QCOMPARE( list9, list10 ); } void tst_QStringList::contains() diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp index c79aee4187..67ca547736 100644 --- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp +++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp @@ -85,6 +85,8 @@ private slots: void initializeList(); void const_shared_null(); + void setSharable_data(); + void setSharable(); }; void tst_QVector::constructors() const @@ -946,5 +948,97 @@ void tst_QVector::const_shared_null() QVERIFY(!v2.isDetached()); } +Q_DECLARE_METATYPE(QVector<int>); + +void tst_QVector::setSharable_data() +{ + QTest::addColumn<QVector<int> >("vector"); + QTest::addColumn<int>("size"); + QTest::addColumn<int>("capacity"); + QTest::addColumn<bool>("isCapacityReserved"); + + QVector<int> null; + QVector<int> empty(0, 5); + QVector<int> emptyReserved; + QVector<int> nonEmpty; + QVector<int> nonEmptyReserved; + + emptyReserved.reserve(10); + nonEmptyReserved.reserve(15); + + nonEmpty << 0 << 1 << 2 << 3 << 4; + nonEmptyReserved << 0 << 1 << 2 << 3 << 4 << 5 << 6; + + QVERIFY(emptyReserved.capacity() >= 10); + QVERIFY(nonEmptyReserved.capacity() >= 15); + + QTest::newRow("null") << null << 0 << 0 << false; + QTest::newRow("empty") << empty << 0 << 0 << false; + QTest::newRow("empty, Reserved") << emptyReserved << 0 << 10 << true; + QTest::newRow("non-empty") << nonEmpty << 5 << 0 << false; + QTest::newRow("non-empty, Reserved") << nonEmptyReserved << 7 << 15 << true; +} + +void tst_QVector::setSharable() +{ + QFETCH(QVector<int>, vector); + QFETCH(int, size); + QFETCH(int, capacity); + QFETCH(bool, isCapacityReserved); + + QVERIFY(!vector.isDetached()); // Shared with QTest + + vector.setSharable(true); + + QCOMPARE(vector.size(), size); + if (isCapacityReserved) + QVERIFY2(vector.capacity() >= capacity, + qPrintable(QString("Capacity is %1, expected at least %2.") + .arg(vector.capacity()) + .arg(capacity))); + + { + QVector<int> copy(vector); + + QVERIFY(!copy.isDetached()); + QVERIFY(copy.isSharedWith(vector)); + } + + vector.setSharable(false); + QVERIFY(vector.isDetached() || vector.isSharedWith(QVector<int>())); + + { + QVector<int> copy(vector); + + QVERIFY(copy.isDetached() || copy.isSharedWith(QVector<int>())); + QCOMPARE(copy.size(), size); + if (isCapacityReserved) + QVERIFY2(copy.capacity() >= capacity, + qPrintable(QString("Capacity is %1, expected at least %2.") + .arg(vector.capacity()) + .arg(capacity))); + QCOMPARE(copy, vector); + } + + vector.setSharable(true); + + { + QVector<int> copy(vector); + + QVERIFY(!copy.isDetached()); + QVERIFY(copy.isSharedWith(vector)); + } + + for (int i = 0; i < vector.size(); ++i) + QCOMPARE(vector[i], i); + + QCOMPARE(vector.size(), size); + if (isCapacityReserved) + QVERIFY2(vector.capacity() >= capacity, + qPrintable(QString("Capacity is %1, expected at least %2.") + .arg(vector.capacity()) + .arg(capacity))); +} + QTEST_APPLESS_MAIN(tst_QVector) #include "tst_qvector.moc" diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro index d8961559e5..38225e12f7 100644 --- a/tests/auto/corelib/tools/tools.pro +++ b/tests/auto/corelib/tools/tools.pro @@ -1,6 +1,7 @@ TEMPLATE=subdirs SUBDIRS=\ qalgorithms \ + qarraydata \ qbitarray \ qbytearray \ qbytearraymatcher \ |