diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2021-09-08 16:34:19 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-09-10 20:43:28 +0000 |
commit | 9564b103fb1aaa8fe7fb1fb8f8f44ccdfb257138 (patch) | |
tree | 84abdcea5dc0eb0ffc79cab2cc80a74c837efe28 /src/testlib | |
parent | 197f6ab7312551907c0e4ba522a28a9d56cd9acf (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.
Change-Id: Ie295f7cf937ec6abdc4606b6120818551ad285c7
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit b8191f41c65a908d0529d235b0200e6de99c34fb)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src/testlib')
-rw-r--r-- | src/testlib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/testlib/qjunittestlogger.cpp | 40 | ||||
-rw-r--r-- | src/testlib/qjunittestlogger_p.h | 6 | ||||
-rw-r--r-- | src/testlib/qtestcoreelement_p.h | 26 | ||||
-rw-r--r-- | src/testlib/qtestcorelist_p.h | 123 | ||||
-rw-r--r-- | src/testlib/qtestelement.cpp | 9 | ||||
-rw-r--r-- | src/testlib/qtestelement_p.h | 11 | ||||
-rw-r--r-- | src/testlib/qtestelementattribute_p.h | 4 | ||||
-rw-r--r-- | src/testlib/qtestjunitstreamer.cpp | 55 | ||||
-rw-r--r-- | src/testlib/qtestjunitstreamer_p.h | 4 |
10 files changed, 70 insertions, 209 deletions
diff --git a/src/testlib/CMakeLists.txt b/src/testlib/CMakeLists.txt index 488e231347..21643684cc 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; |