forked from qt-creator/qt-creator
AutoTest: Handle re-implemented test functions appropriate
If a derived test case implements the same private slot as one of its base classes one of these information got lost as both were using the same key to store the information at. Additionally take care of what is possible and sensible when using QtTest and deriving test cases from others. Task-number: QTCREATORBUG-17522 Change-Id: I0d2a47c820d5eb002f8bdd851a07a4774e9838f0 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
#include "../autotest_utils.h"
|
#include "../autotest_utils.h"
|
||||||
|
|
||||||
#include <cplusplus/TypeOfExpression.h>
|
#include <cplusplus/TypeOfExpression.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -175,24 +176,67 @@ static QMap<QString, QtTestCodeLocationList> checkForDataTags(const QString &fil
|
|||||||
return visitor.dataTags();
|
return visitor.dataTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QMap<QString, QtTestCodeLocationAndType> baseClassTestFunctions(const QSet<QString> &bases,
|
/*!
|
||||||
const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot)
|
* \brief Checks whether \a testFunctions (keys are full qualified names) contains already the
|
||||||
|
* given \a function (unqualified name).
|
||||||
|
*
|
||||||
|
* \return true if this function is already contained, false otherwise
|
||||||
|
*/
|
||||||
|
static bool containsFunction(const QMap<QString, QtTestCodeLocationAndType> &testFunctions,
|
||||||
|
const QString &function)
|
||||||
{
|
{
|
||||||
QMap<QString, QtTestCodeLocationAndType> testFunctions;
|
const QString search = "::" + function;
|
||||||
for (const QString &baseClassName : bases) {
|
return Utils::anyOf(testFunctions.keys(), [&search] (const QString &key) {
|
||||||
TestVisitor baseVisitor(baseClassName, snapshot);
|
return key.endsWith(search);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mergeTestFunctions(QMap<QString, QtTestCodeLocationAndType> &testFunctions,
|
||||||
|
const QMap<QString, QtTestCodeLocationAndType> &inheritedFunctions)
|
||||||
|
{
|
||||||
|
static const QString dataSuffix("_data");
|
||||||
|
// take over only inherited test functions that have not been re-implemented
|
||||||
|
QMap<QString, QtTestCodeLocationAndType>::ConstIterator it = inheritedFunctions.begin();
|
||||||
|
QMap<QString, QtTestCodeLocationAndType>::ConstIterator end = inheritedFunctions.end();
|
||||||
|
for ( ; it != end; ++it) {
|
||||||
|
const QString functionName = it.key();
|
||||||
|
const QString &shortName = functionName.mid(functionName.lastIndexOf(':') + 1);
|
||||||
|
if (shortName.endsWith(dataSuffix)) {
|
||||||
|
const QString &correspondingFunc = functionName.left(functionName.size()
|
||||||
|
- dataSuffix.size());
|
||||||
|
// inherited test data functions only if we're inheriting the corresponding test
|
||||||
|
// function as well (and the inherited test function is not omitted)
|
||||||
|
if (inheritedFunctions.contains(correspondingFunc)) {
|
||||||
|
if (!testFunctions.contains(correspondingFunc))
|
||||||
|
continue;
|
||||||
|
testFunctions.insert(functionName, it.value());
|
||||||
|
}
|
||||||
|
} else if (!containsFunction(testFunctions, shortName)) {
|
||||||
|
// normal test functions only if not re-implemented
|
||||||
|
testFunctions.insert(functionName, it.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fetchAndMergeBaseTestFunctions(const QSet<QString> &baseClasses,
|
||||||
|
QMap<QString, QtTestCodeLocationAndType> &testFunctions,
|
||||||
|
const CPlusPlus::Document::Ptr &doc,
|
||||||
|
const CPlusPlus::Snapshot &snapshot)
|
||||||
|
{
|
||||||
|
QList<QString> bases = baseClasses.toList();
|
||||||
|
while (!bases.empty()) {
|
||||||
|
const QString base = bases.takeFirst();
|
||||||
|
TestVisitor baseVisitor(base, snapshot);
|
||||||
baseVisitor.setInheritedMode(true);
|
baseVisitor.setInheritedMode(true);
|
||||||
CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, snapshot, baseClassName);
|
CPlusPlus::Document::Ptr declaringDoc = declaringDocument(doc, snapshot, base);
|
||||||
if (declaringDoc.isNull())
|
if (declaringDoc.isNull())
|
||||||
continue;
|
continue;
|
||||||
baseVisitor.accept(declaringDoc->globalNamespace());
|
baseVisitor.accept(declaringDoc->globalNamespace());
|
||||||
if (baseVisitor.resultValid())
|
if (!baseVisitor.resultValid())
|
||||||
testFunctions.unite(baseVisitor.privateSlots());
|
continue;
|
||||||
const QSet<QString> currentBaseBases = baseVisitor.baseClasses();
|
bases.append(baseVisitor.baseClasses().toList());
|
||||||
// recursively check base classes
|
mergeTestFunctions(testFunctions, baseVisitor.privateSlots());
|
||||||
testFunctions.unite(baseClassTestFunctions(currentBaseBases, doc, snapshot));
|
|
||||||
}
|
}
|
||||||
return testFunctions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QtTestCodeLocationList tagLocationsFor(const QtTestParseResult *func,
|
static QtTestCodeLocationList tagLocationsFor(const QtTestParseResult *func,
|
||||||
@@ -239,8 +283,11 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
QMap<QString, QtTestCodeLocationAndType> testFunctions = visitor.privateSlots();
|
QMap<QString, QtTestCodeLocationAndType> testFunctions = visitor.privateSlots();
|
||||||
// gather appropriate information of base classes as well
|
// gather appropriate information of base classes as well and merge into already found
|
||||||
testFunctions.unite(baseClassTestFunctions(visitor.baseClasses(), declaringDoc, snapshot));
|
// functions - but only as far as QtTest can handle this appropriate
|
||||||
|
fetchAndMergeBaseTestFunctions(
|
||||||
|
visitor.baseClasses(), testFunctions, declaringDoc, snapshot);
|
||||||
|
|
||||||
const QSet<QString> &files = filesWithDataFunctionDefinitions(testFunctions);
|
const QSet<QString> &files = filesWithDataFunctionDefinitions(testFunctions);
|
||||||
|
|
||||||
// TODO: change to QHash<>
|
// TODO: change to QHash<>
|
||||||
@@ -263,10 +310,12 @@ static bool handleQtTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
|||||||
const QMap<QString, QtTestCodeLocationAndType>::ConstIterator end = testFunctions.end();
|
const QMap<QString, QtTestCodeLocationAndType>::ConstIterator end = testFunctions.end();
|
||||||
for ( ; it != end; ++it) {
|
for ( ; it != end; ++it) {
|
||||||
const QtTestCodeLocationAndType &location = it.value();
|
const QtTestCodeLocationAndType &location = it.value();
|
||||||
|
QString functionName = it.key();
|
||||||
|
functionName = functionName.mid(functionName.lastIndexOf(':') + 1);
|
||||||
QtTestParseResult *func = new QtTestParseResult(id);
|
QtTestParseResult *func = new QtTestParseResult(id);
|
||||||
func->itemType = location.m_type;
|
func->itemType = location.m_type;
|
||||||
func->name = testCaseName + "::" + it.key();
|
func->name = testCaseName + "::" + functionName;
|
||||||
func->displayName = it.key();
|
func->displayName = functionName;
|
||||||
func->fileName = location.m_name;
|
func->fileName = location.m_name;
|
||||||
func->line = location.m_line;
|
func->line = location.m_line;
|
||||||
func->column = location.m_column;
|
func->column = location.m_column;
|
||||||
|
@@ -84,7 +84,7 @@ bool TestVisitor::visit(CPlusPlus::Class *symbol)
|
|||||||
else
|
else
|
||||||
locationAndType.m_type = TestTreeItem::TestFunctionOrSet;
|
locationAndType.m_type = TestTreeItem::TestFunctionOrSet;
|
||||||
locationAndType.m_inherited = m_inherited;
|
locationAndType.m_inherited = m_inherited;
|
||||||
m_privSlots.insert(name, locationAndType);
|
m_privSlots.insert(className + "::" + name, locationAndType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned counter = 0, end = symbol->baseClassCount(); counter < end; ++counter) {
|
for (unsigned counter = 0, end = symbol->baseClassCount(); counter < end; ++counter) {
|
||||||
|
Reference in New Issue
Block a user