tests/auto/qvarlengtharray/tst_qvarlengtharray.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
--- a/tests/auto/qvarlengtharray/tst_qvarlengtharray.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/tests/auto/qvarlengtharray/tst_qvarlengtharray.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -63,6 +63,7 @@
     void oldTests();
     void task214223();
     void QTBUG6718_resize();
+    void QTBUG10978_realloc();
 };
 
 int fooCtor = 0;
@@ -304,5 +305,302 @@
     }
 }
 
+struct MyBase
+{
+    MyBase()
+        : data(this)
+        , isCopy(false)
+    {
+        ++liveCount;
+    }
+
+    MyBase(MyBase const &)
+        : data(this)
+        , isCopy(true)
+    {
+        ++copyCount;
+        ++liveCount;
+    }
+
+    MyBase & operator=(MyBase const &)
+    {
+        if (!isCopy) {
+            isCopy = true;
+            ++copyCount;
+        } else {
+            ++errorCount;
+        }
+
+        return *this;
+    }
+
+    ~MyBase()
+    {
+        if (isCopy) {
+            if (!copyCount)
+                ++errorCount;
+            else
+                --copyCount;
+        }
+
+        if (!liveCount)
+            ++errorCount;
+        else
+            --liveCount;
+    }
+
+    bool hasMoved() const
+    {
+        return this != data;
+    }
+
+protected:
+    MyBase const * const data;
+    bool isCopy;
+
+public:
+    static int errorCount;
+    static int liveCount;
+    static int copyCount;
+};
+
+int MyBase::errorCount = 0;
+int MyBase::liveCount = 0;
+int MyBase::copyCount = 0;
+
+struct MyPrimitive
+    : MyBase
+{
+    MyPrimitive()
+    {
+        ++errorCount;
+    }
+
+    ~MyPrimitive()
+    {
+        ++errorCount;
+    }
+
+    MyPrimitive(MyPrimitive const &other)
+        : MyBase(other)
+    {
+        ++errorCount;
+    }
+};
+
+struct MyMovable
+    : MyBase
+{
+};
+
+struct MyComplex
+    : MyBase
+{
+};
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_TYPEINFO(MyPrimitive, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(MyMovable, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(MyComplex, Q_COMPLEX_TYPE);
+
+QT_END_NAMESPACE
+
+bool QTBUG10978_proceed = true;
+
+template <class T, int PreAlloc>
+int countMoved(QVarLengthArray<T, PreAlloc> const &c)
+{
+    int result = 0;
+    for (int i = 0; i < c.size(); ++i)
+        if (c[i].hasMoved())
+            ++result;
+
+    return result;
+}
+
+template <class T>
+void QTBUG10978_test()
+{
+    QTBUG10978_proceed = false;
+
+    typedef QVarLengthArray<T, 16> Container;
+    enum {
+        isStatic = QTypeInfo<T>::isStatic,
+        isComplex = QTypeInfo<T>::isComplex,
+
+        isPrimitive = !isComplex && !isStatic,
+        isMovable = !isStatic
+    };
+
+    // Constructors
+    Container a;
+    QCOMPARE( MyBase::liveCount, 0 );
+    QCOMPARE( MyBase::copyCount, 0 );
+
+    QVERIFY( a.capacity() >= 16 );
+    QCOMPARE( a.size(), 0 );
+
+    Container b_real(8);
+    Container const &b = b_real;
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 8 );
+    QCOMPARE( MyBase::copyCount, 0 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // Assignment
+    a = b;
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 16 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 8 : 0 );
+    QVERIFY( a.capacity() >= 16 );
+    QCOMPARE( a.size(), 8 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // append
+    a.append(b.data(), b.size());
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 24 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 16 : 0 );
+
+    QVERIFY( a.capacity() >= 16 );
+    QCOMPARE( a.size(), 16 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // removeLast
+    a.removeLast();
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 23 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
+
+    QVERIFY( a.capacity() >= 16 );
+    QCOMPARE( a.size(), 15 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // Movable types
+    const int capacity = a.capacity();
+    if (!isPrimitive)
+        QCOMPARE( countMoved(a), 0 );
+
+    // Reserve, no re-allocation
+    a.reserve(capacity);
+    if (!isPrimitive)
+        QCOMPARE( countMoved(a), 0 );
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 23 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
+
+    QCOMPARE( a.capacity(), capacity );
+    QCOMPARE( a.size(), 15 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // Reserve, force re-allocation
+    a.reserve(capacity * 2);
+    if (!isPrimitive)
+        QCOMPARE( countMoved(a), isMovable ? 15 : 0 );
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 23 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
+
+    QVERIFY( a.capacity() >= capacity * 2 );
+    QCOMPARE( a.size(), 15 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // resize, grow
+    a.resize(40);
+    if (!isPrimitive)
+        QCOMPARE( countMoved(a), isMovable ? 15 : 0 );
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 48 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 15 : 0 );
+
+    QVERIFY( a.capacity() >= a.size() );
+    QCOMPARE( a.size(), 40 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // Copy constructor, allocate
+    {
+        Container c(a);
+        if (!isPrimitive)
+            QCOMPARE( countMoved(c), 0 );
+        QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 88 );
+        QCOMPARE( MyBase::copyCount, isComplex ? 55 : 0 );
+
+        QVERIFY( a.capacity() >= a.size() );
+        QCOMPARE( a.size(), 40 );
+
+        QVERIFY( b.capacity() >= 16 );
+        QCOMPARE( b.size(), 8 );
+
+        QVERIFY( c.capacity() >= 40 );
+        QCOMPARE( c.size(), 40 );
+    }
+
+    // resize, shrink
+    a.resize(10);
+    if (!isPrimitive)
+        QCOMPARE( countMoved(a), isMovable ? 10 : 0 );
+    QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 18 );
+    QCOMPARE( MyBase::copyCount, isComplex ? 10 : 0 );
+
+    QVERIFY( a.capacity() >= a.size() );
+    QCOMPARE( a.size(), 10 );
+
+    QVERIFY( b.capacity() >= 16 );
+    QCOMPARE( b.size(), 8 );
+
+    // Copy constructor, don't allocate
+    {
+        Container c(a);
+        if (!isPrimitive)
+            QCOMPARE( countMoved(c), 0 );
+        QCOMPARE( MyBase::liveCount, isPrimitive ? 0 : 28 );
+        QCOMPARE( MyBase::copyCount, isComplex ? 20 : 0 );
+
+        QVERIFY( a.capacity() >= a.size() );
+        QCOMPARE( a.size(), 10 );
+
+        QVERIFY( b.capacity() >= 16 );
+        QCOMPARE( b.size(), 8 );
+
+        QVERIFY( c.capacity() >= 16 );
+        QCOMPARE( c.size(), 10 );
+    }
+
+    a.clear();
+    QCOMPARE( a.size(), 0 );
+
+    b_real.clear();
+    QCOMPARE( b.size(), 0 );
+
+    QCOMPARE(MyBase::errorCount, 0);
+    QCOMPARE(MyBase::liveCount, 0);
+
+    // All done
+    QTBUG10978_proceed = true;
+}
+
+void tst_QVarLengthArray::QTBUG10978_realloc()
+{
+    QTBUG10978_test<MyBase>();
+    QVERIFY(QTBUG10978_proceed);
+
+    QTBUG10978_test<MyPrimitive>();
+    QVERIFY(QTBUG10978_proceed);
+
+    QTBUG10978_test<MyMovable>();
+    QVERIFY(QTBUG10978_proceed);
+
+    QTBUG10978_test<MyComplex>();
+    QVERIFY(QTBUG10978_proceed);
+}
+
 QTEST_APPLESS_MAIN(tst_QVarLengthArray)
 #include "tst_qvarlengtharray.moc"