summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-09-08 16:34:19 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-09-10 22:19:45 +0200
commitb8191f41c65a908d0529d235b0200e6de99c34fb (patch)
tree59d750687ba5896cd4638780bb32193a5f563961
parent4e0082a9cacfdfd0c43e6105274bc0d41dd18801 (diff)
testlib: Replace custom QTestCoreList with std::vector
The custom linked list implementation was implemented using recursion, and as a result didn't handle long lists of test cases, exhausting the stack on e.g. Windows where the default stack is only 1MB. This was the case with e.g. the tst_QChar test that produces 20K test cases. Replacing with a std::vector should do nicely for our use-case. No attempt has been made at further reducing the complexity of QTestElement/QTestCoreElement/QTestElementAttribute. Pick-to: 6.2 Change-Id: Ie295f7cf937ec6abdc4606b6120818551ad285c7 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/testlib/CMakeLists.txt1
-rw-r--r--src/testlib/qjunittestlogger.cpp40
-rw-r--r--src/testlib/qjunittestlogger_p.h6
-rw-r--r--src/testlib/qtestcoreelement_p.h26
-rw-r--r--src/testlib/qtestcorelist_p.h123
-rw-r--r--src/testlib/qtestelement.cpp9
-rw-r--r--src/testlib/qtestelement_p.h11
-rw-r--r--src/testlib/qtestelementattribute_p.h4
-rw-r--r--src/testlib/qtestjunitstreamer.cpp55
-rw-r--r--src/testlib/qtestjunitstreamer_p.h4
10 files changed, 70 insertions, 209 deletions
diff --git a/src/testlib/CMakeLists.txt b/src/testlib/CMakeLists.txt
index 3e90d67797..2b7aaad4da 100644
--- a/src/testlib/CMakeLists.txt
+++ b/src/testlib/CMakeLists.txt
@@ -39,7 +39,6 @@ qt_internal_add_module(Test
qtestblacklist.cpp qtestblacklist_p.h
qtestcase.cpp qtestcase.h
qtestcoreelement_p.h
- qtestcorelist_p.h
qtestdata.cpp qtestdata.h
qtestelement.cpp qtestelement_p.h
qtestelementattribute.cpp qtestelementattribute_p.h
diff --git a/src/testlib/qjunittestlogger.cpp b/src/testlib/qjunittestlogger.cpp
index 4b5de7b7c0..bc9d8f4df3 100644
--- a/src/testlib/qjunittestlogger.cpp
+++ b/src/testlib/qjunittestlogger.cpp
@@ -105,19 +105,19 @@ void QJUnitTestLogger::startLogging()
property = new QTestElement(QTest::LET_Property);
property->addAttribute(QTest::AI_Name, "QTestVersion");
property->addAttribute(QTest::AI_PropertyValue, QTEST_VERSION_STR);
- properties->addLogElement(property);
+ properties->addChild(property);
property = new QTestElement(QTest::LET_Property);
property->addAttribute(QTest::AI_Name, "QtVersion");
property->addAttribute(QTest::AI_PropertyValue, qVersion());
- properties->addLogElement(property);
+ properties->addChild(property);
property = new QTestElement(QTest::LET_Property);
property->addAttribute(QTest::AI_Name, "QtBuild");
property->addAttribute(QTest::AI_PropertyValue, QLibraryInfo::build());
- properties->addLogElement(property);
+ properties->addChild(property);
- currentTestSuite->addLogElement(properties);
+ currentTestSuite->addChild(properties);
elapsedTestcaseTime.start();
}
@@ -141,14 +141,9 @@ void QJUnitTestLogger::stopLogging()
currentTestSuite->addAttribute(QTest::AI_Time,
toSecondsFormat(QTestLog::msecsTotalTime()).constData());
- currentTestSuite->addLogElement(listOfTestcases);
-
- // For correct indenting, make sure every testcase knows its parent
- QTestElement *testcase = listOfTestcases;
- while (testcase) {
- testcase->setParent(currentTestSuite);
- testcase = testcase->nextElement();
- }
+ for (auto *testCase : listOfTestcases)
+ currentTestSuite->addChild(testCase);
+ listOfTestcases.clear();
logFormatter->output(currentTestSuite);
@@ -168,7 +163,7 @@ void QJUnitTestLogger::enterTestCase(const char *name)
currentTestCase = new QTestElement(QTest::LET_TestCase);
currentTestCase->addAttribute(QTest::AI_Name, name);
currentTestCase->addAttribute(QTest::AI_Classname, QTestResult::currentTestObjectName());
- currentTestCase->addToList(&listOfTestcases);
+ listOfTestcases.push_back(currentTestCase);
Q_ASSERT(!systemOutputElement && !systemErrorElement);
systemOutputElement = new QTestElement(QTest::LET_SystemOutput);
@@ -212,13 +207,13 @@ void QJUnitTestLogger::leaveTestCase()
currentTestCase->addAttribute(QTest::AI_Time,
toSecondsFormat(elapsedTestCaseSeconds()).constData());
- if (systemOutputElement->childElements())
- currentTestCase->addLogElement(systemOutputElement);
+ if (!systemOutputElement->childElements().empty())
+ currentTestCase->addChild(systemOutputElement);
else
delete systemOutputElement;
- if (systemErrorElement->childElements())
- currentTestCase->addLogElement(systemErrorElement);
+ if (!systemErrorElement->childElements().empty())
+ currentTestCase->addChild(systemErrorElement);
else
delete systemErrorElement;
@@ -252,8 +247,7 @@ void QJUnitTestLogger::addFailure(QTest::LogElementType elementType,
if (elementType == QTest::LET_Failure) {
// Make sure we're not adding failure when we already have error,
// or adding additional failures when we already have a failure.
- for (auto *childElement = currentTestCase->childElements();
- childElement; childElement = childElement->nextElement()) {
+ for (auto *childElement : currentTestCase->childElements()) {
if (childElement->elementType() == QTest::LET_Error ||
childElement->elementType() == QTest::LET_Failure)
return;
@@ -272,10 +266,10 @@ void QJUnitTestLogger::addFailure(QTest::LogElementType elementType,
if (!details.isEmpty()) {
auto textNode = new QTestElement(QTest::LET_Text);
textNode->addAttribute(QTest::AI_Value, details.toUtf8().constData());
- failureElement->addLogElement(textNode);
+ failureElement->addChild(textNode);
}
- currentTestCase->addLogElement(failureElement);
+ currentTestCase->addChild(failureElement);
switch (elementType) {
case QTest::LET_Failure: ++failureCounter; break;
@@ -292,7 +286,7 @@ void QJUnitTestLogger::addMessage(MessageTypes type, const QString &message, con
if (type == QAbstractTestLogger::Skip) {
auto skippedElement = new QTestElement(QTest::LET_Skipped);
skippedElement->addAttribute(QTest::AI_Message, message.toUtf8().constData());
- currentTestCase->addLogElement(skippedElement);
+ currentTestCase->addChild(skippedElement);
return;
} else if (type == QAbstractTestLogger::QFatal) {
addFailure(QTest::LET_Error, "qfatal", message);
@@ -316,7 +310,7 @@ void QJUnitTestLogger::addMessage(MessageTypes type, const QString &message, con
auto textNode = new QTestElement(QTest::LET_Text);
textNode->addAttribute(QTest::AI_Value, message.toUtf8().constData());
- systemLogElement->addLogElement(textNode);
+ systemLogElement->addChild(textNode);
}
QT_END_NAMESPACE
diff --git a/src/testlib/qjunittestlogger_p.h b/src/testlib/qjunittestlogger_p.h
index 91d2774144..abed9b1b44 100644
--- a/src/testlib/qjunittestlogger_p.h
+++ b/src/testlib/qjunittestlogger_p.h
@@ -51,9 +51,13 @@
// We mean it.
//
+#include <QtTest/qttestglobal.h>
+
#include <QtTest/private/qabstracttestlogger_p.h>
#include <QtTest/private/qtestelementattribute_p.h>
+#include <vector>
+
QT_BEGIN_NAMESPACE
class QTestJUnitStreamer;
@@ -88,7 +92,7 @@ class QJUnitTestLogger : public QAbstractTestLogger
const char *failureType, const QString &failureDescription);
QTestElement *currentTestSuite = nullptr;
- QTestElement *listOfTestcases = nullptr;
+ std::vector<QTestElement*> listOfTestcases;
QTestElement *currentTestCase = nullptr;
QTestElement *systemOutputElement = nullptr;
QTestElement *systemErrorElement = nullptr;
diff --git a/src/testlib/qtestcoreelement_p.h b/src/testlib/qtestcoreelement_p.h
index 362a503126..a6a09aab52 100644
--- a/src/testlib/qtestcoreelement_p.h
+++ b/src/testlib/qtestcoreelement_p.h
@@ -51,21 +51,23 @@
// We mean it.
//
-#include <QtTest/private/qtestcorelist_p.h>
+#include <QtTest/qttestglobal.h>
#include <QtTest/private/qtestelementattribute_p.h>
+#include <vector>
+
QT_BEGIN_NAMESPACE
template <class ElementType>
-class QTestCoreElement: public QTestCoreList<ElementType>
+class QTestCoreElement
{
public:
QTestCoreElement( int type = -1 );
virtual ~QTestCoreElement();
void addAttribute(const QTest::AttributeIndex index, const char *value);
- QTestElementAttribute *attributes() const;
+ const std::vector<QTestElementAttribute*> &attributes() const;
const char *attributeValue(QTest::AttributeIndex index) const;
const char *attributeName(QTest::AttributeIndex index) const;
const QTestElementAttribute *attribute(QTest::AttributeIndex index) const;
@@ -74,7 +76,7 @@ class QTestCoreElement: public QTestCoreList<ElementType>
QTest::LogElementType elementType() const;
private:
- QTestElementAttribute *listOfAttributes = nullptr;
+ std::vector<QTestElementAttribute*> listOfAttributes;
QTest::LogElementType type;
};
@@ -87,7 +89,8 @@ QTestCoreElement<ElementType>::QTestCoreElement(int t)
template<class ElementType>
QTestCoreElement<ElementType>::~QTestCoreElement()
{
- delete listOfAttributes;
+ for (auto *attribute : listOfAttributes)
+ delete attribute;
}
template <class ElementType>
@@ -98,11 +101,11 @@ void QTestCoreElement<ElementType>::addAttribute(const QTest::AttributeIndex att
QTestElementAttribute *testAttribute = new QTestElementAttribute;
testAttribute->setPair(attributeIndex, value);
- testAttribute->addToList(&listOfAttributes);
+ listOfAttributes.push_back(testAttribute);
}
template <class ElementType>
-QTestElementAttribute *QTestCoreElement<ElementType>::attributes() const
+const std::vector<QTestElementAttribute*> &QTestCoreElement<ElementType>::attributes() const
{
return listOfAttributes;
}
@@ -159,12 +162,9 @@ QTest::LogElementType QTestCoreElement<ElementType>::elementType() const
template <class ElementType>
const QTestElementAttribute *QTestCoreElement<ElementType>::attribute(QTest::AttributeIndex index) const
{
- QTestElementAttribute *iterator = listOfAttributes;
- while (iterator) {
- if (iterator->index() == index)
- return iterator;
-
- iterator = iterator->nextElement();
+ for (auto *attribute : listOfAttributes) {
+ if (attribute->index() == index)
+ return attribute;
}
return nullptr;
diff --git a/src/testlib/qtestcorelist_p.h b/src/testlib/qtestcorelist_p.h
deleted file mode 100644
index daeb293644..0000000000
--- a/src/testlib/qtestcorelist_p.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtTest module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QTESTCORELIST_P_H
-#define QTESTCORELIST_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-
-template <class T>
-class QTestCoreList
-{
- public:
- QTestCoreList();
- virtual ~QTestCoreList();
-
- void addToList(T **list);
- T *nextElement();
- T *previousElement();
- private:
- T *next;
- T *prev;
-};
-
-template <class T>
-QTestCoreList<T>::QTestCoreList()
- : next(nullptr)
- , prev(nullptr)
-{
-}
-
-template <class T>
-QTestCoreList<T>::~QTestCoreList()
-{
- if (prev) {
- prev->next = nullptr;
- }
- delete prev;
-
- if (next) {
- next->prev = nullptr;
- }
- delete next;
-}
-
-template <class T>
-void QTestCoreList<T>::addToList(T **list)
-{
- if (next)
- next->addToList(list);
- else {
- next = *list;
- if (next)
- next->prev = static_cast<T*>(this);
- }
-
- *list = static_cast<T*>(this);
-}
-
-template <class T>
-T *QTestCoreList<T>::nextElement()
-{
- return next;
-}
-
-template <class T>
-T *QTestCoreList<T>::previousElement()
-{
- return prev;
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/testlib/qtestelement.cpp b/src/testlib/qtestelement.cpp
index b468295917..e89accd82c 100644
--- a/src/testlib/qtestelement.cpp
+++ b/src/testlib/qtestelement.cpp
@@ -48,16 +48,17 @@ QTestElement::QTestElement(int type)
QTestElement::~QTestElement()
{
- delete listOfChildren;
+ for (auto *child : listOfChildren)
+ delete child;
}
-bool QTestElement::addLogElement(QTestElement *element)
+bool QTestElement::addChild(QTestElement *element)
{
if (!element)
return false;
if (element->elementType() != QTest::LET_Undefined) {
- element->addToList(&listOfChildren);
+ listOfChildren.push_back(element);
element->setParent(this);
return true;
}
@@ -65,7 +66,7 @@ bool QTestElement::addLogElement(QTestElement *element)
return false;
}
-QTestElement *QTestElement::childElements() const
+const std::vector<QTestElement*> &QTestElement::childElements() const
{
return listOfChildren;
}
diff --git a/src/testlib/qtestelement_p.h b/src/testlib/qtestelement_p.h
index a6b2791a42..fe7bde68a0 100644
--- a/src/testlib/qtestelement_p.h
+++ b/src/testlib/qtestelement_p.h
@@ -51,26 +51,27 @@
// We mean it.
//
+#include <QtTest/qttestglobal.h>
#include <QtTest/private/qtestcoreelement_p.h>
QT_BEGIN_NAMESPACE
-class QTestElement: public QTestCoreElement<QTestElement>
+class QTestElement : public QTestCoreElement<QTestElement>
{
public:
QTestElement(int type = -1);
~QTestElement();
- bool addLogElement(QTestElement *element);
- QTestElement *childElements() const;
+ bool addChild(QTestElement *element);
+ const std::vector<QTestElement*> &childElements() const;
const QTestElement *parentElement() const;
void setParent(const QTestElement *p);
private:
- QTestElement *listOfChildren = nullptr;
- const QTestElement * parent = nullptr;
+ std::vector<QTestElement*> listOfChildren;
+ const QTestElement *parent = nullptr;
};
diff --git a/src/testlib/qtestelementattribute_p.h b/src/testlib/qtestelementattribute_p.h
index 70083f3ad5..6212e7b18a 100644
--- a/src/testlib/qtestelementattribute_p.h
+++ b/src/testlib/qtestelementattribute_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <QtTest/private/qtestcorelist_p.h>
+#include <QtTest/qttestglobal.h>
QT_BEGIN_NAMESPACE
@@ -92,7 +92,7 @@ namespace QTest {
};
}
-class QTestElementAttribute: public QTestCoreList<QTestElementAttribute>
+class QTestElementAttribute
{
public:
QTestElementAttribute();
diff --git a/src/testlib/qtestjunitstreamer.cpp b/src/testlib/qtestjunitstreamer.cpp
index d8c73505db..72ab7d1534 100644
--- a/src/testlib/qtestjunitstreamer.cpp
+++ b/src/testlib/qtestjunitstreamer.cpp
@@ -95,7 +95,7 @@ void QTestJUnitStreamer::formatEnd(const QTestElement *element, QTestCharBuffer
if (!element || !formatted )
return;
- if (!element->childElements()) {
+ if (element->childElements().empty()) {
formatted->data()[0] = '\0';
return;
}
@@ -135,7 +135,7 @@ void QTestJUnitStreamer::formatAfterAttributes(const QTestElement *element, QTes
return;
}
- if (!element->childElements())
+ if (element->childElements().empty())
QTest::qt_asprintf(formatted, "/>\n");
else
QTest::qt_asprintf(formatted, ">\n");
@@ -145,54 +145,39 @@ void QTestJUnitStreamer::output(QTestElement *element) const
{
QTEST_ASSERT(element);
- outputString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
- outputElements(element);
-}
+ if (!element->parentElement())
+ outputString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
-void QTestJUnitStreamer::outputElements(QTestElement *element, bool) const
-{
QTestCharBuffer buf;
- bool hasChildren;
-
- // Elements are in reverse order of occurrence, so
- // start from the end and work our way backwards.
- while (element && element->nextElement())
- element = element->nextElement();
- while (element) {
- hasChildren = element->childElements();
+ formatStart(element, &buf);
+ outputString(buf.data());
- formatStart(element, &buf);
- outputString(buf.data());
-
- outputElementAttributes(element, element->attributes());
+ outputElementAttributes(element, element->attributes());
- formatAfterAttributes(element, &buf);
- outputString(buf.data());
+ formatAfterAttributes(element, &buf);
+ outputString(buf.data());
- if (hasChildren)
- outputElements(element->childElements(), true);
+ if (!element->childElements().empty())
+ outputElements(element->childElements());
- formatEnd(element, &buf);
- outputString(buf.data());
+ formatEnd(element, &buf);
+ outputString(buf.data());
+}
- element = element->previousElement();
- }
+void QTestJUnitStreamer::outputElements(const std::vector<QTestElement*> &elements) const
+{
+ for (auto *element : elements)
+ output(element);
}
-void QTestJUnitStreamer::outputElementAttributes(const QTestElement* element, QTestElementAttribute *attribute) const
+void QTestJUnitStreamer::outputElementAttributes(const QTestElement* element, const std::vector<QTestElementAttribute*> &attributes) const
{
QTestCharBuffer buf;
- // Attributes are in reverse order of occurrence, so
- // start from the end and work our way backwards.
- while (attribute && attribute->nextElement())
- attribute = attribute->nextElement();
-
- while (attribute) {
+ for (auto *attribute : attributes) {
formatAttributes(element, attribute, &buf);
outputString(buf.data());
- attribute = attribute->previousElement();
}
}
diff --git a/src/testlib/qtestjunitstreamer_p.h b/src/testlib/qtestjunitstreamer_p.h
index 7d91e2b66c..7fe9c5cc5c 100644
--- a/src/testlib/qtestjunitstreamer_p.h
+++ b/src/testlib/qtestjunitstreamer_p.h
@@ -72,8 +72,8 @@ class QTestJUnitStreamer
void formatAfterAttributes(const QTestElement *element, QTestCharBuffer *formatted) const;
void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, QTestCharBuffer *formatted) const;
void output(QTestElement *element) const;
- void outputElements(QTestElement *element, bool isChildElement = false) const;
- void outputElementAttributes(const QTestElement *element, QTestElementAttribute *attribute) const;
+ void outputElements(const std::vector<QTestElement*> &) const;
+ void outputElementAttributes(const QTestElement *element, const std::vector<QTestElementAttribute*> &attributes) const;
void outputString(const char *msg) const;