AutoTest: fine tune quick test case specs

and fix multiple inheritance

Change-Id: I031c8518437b7b396f5b17a51d2067e4b3661530
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2019-07-30 13:17:35 +02:00
committed by Christian Stenger
parent c020fb6e3e
commit 6e84529a88
3 changed files with 49 additions and 51 deletions

View File

@@ -190,33 +190,33 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
if (!qmlVisitor.isValid()) if (!qmlVisitor.isValid())
return false; return false;
const QVector<QuickTestCaseSpec> &testFunctions = qmlVisitor.testFunctions(); const QVector<QuickTestCaseSpec> &testCases = qmlVisitor.testCases();
for (const QuickTestCaseSpec &it : testFunctions) { for (const QuickTestCaseSpec &testCase : testCases) {
const QString testCaseName = it.m_caseName; const QString testCaseName = testCase.m_caseName;
const QString functionName = it.m_functionName;
const TestCodeLocationAndType &loc = it.m_functionLocationAndType;
QuickTestParseResult *parseResult = new QuickTestParseResult(id); QuickTestParseResult *parseResult = new QuickTestParseResult(id);
parseResult->proFile = proFile; parseResult->proFile = proFile;
parseResult->itemType = TestTreeItem::TestCase; parseResult->itemType = TestTreeItem::TestCase;
if (!testCaseName.isEmpty()) { if (!testCaseName.isEmpty()) {
parseResult->fileName = it.m_name; parseResult->fileName = testCase.m_locationAndType.m_name;
parseResult->name = testCaseName; parseResult->name = testCaseName;
parseResult->line = it.m_line; parseResult->line = testCase.m_locationAndType.m_line;
parseResult->column = it.m_column; parseResult->column = testCase.m_locationAndType.m_column;
} }
for (auto function : testCase.m_functions) {
QuickTestParseResult *funcResult = new QuickTestParseResult(id); QuickTestParseResult *funcResult = new QuickTestParseResult(id);
funcResult->name = functionName; funcResult->name = function.m_functionName;
funcResult->displayName = functionName; funcResult->displayName = function.m_functionName;
funcResult->itemType = loc.m_type; funcResult->itemType = function.m_locationAndType.m_type;
funcResult->fileName = loc.m_name; funcResult->fileName = function.m_locationAndType.m_name;
funcResult->line = loc.m_line; funcResult->line = function.m_locationAndType.m_line;
funcResult->column = loc.m_column; funcResult->column = function.m_locationAndType.m_column;
funcResult->proFile = proFile; funcResult->proFile = proFile;
parseResult->children.append(funcResult); parseResult->children.append(funcResult);
}
futureInterface.reportResult(TestParseResultPtr(parseResult)); futureInterface.reportResult(TestParseResultPtr(parseResult));
} }

View File

@@ -86,34 +86,29 @@ static bool isDerivedFromTestCase(QmlJS::AST::UiQualifiedId *id, const QmlJS::Do
bool TestQmlVisitor::visit(QmlJS::AST::UiObjectDefinition *ast) bool TestQmlVisitor::visit(QmlJS::AST::UiObjectDefinition *ast)
{ {
const QStringRef name = ast->qualifiedTypeNameId->name; const QStringRef name = ast->qualifiedTypeNameId->name;
m_objectStack.push(name.toString()); m_objectIsTestStack.push(false);
if (name != "TestCase") { if (name != "TestCase") {
m_insideTestCase = false;
if (!isDerivedFromTestCase(ast->qualifiedTypeNameId, m_currentDoc, m_snapshot)) if (!isDerivedFromTestCase(ast->qualifiedTypeNameId, m_currentDoc, m_snapshot))
return true; return true;
} else if (!documentImportsQtTest(m_currentDoc.data())) { } else if (!documentImportsQtTest(m_currentDoc.data())) {
return true; // find nested TestCase items as well return true; // find nested TestCase items as well
} }
m_typeIsTestCase = true; m_objectIsTestStack.top() = true;
m_insideTestCase = true;
const auto sourceLocation = ast->firstSourceLocation(); const auto sourceLocation = ast->firstSourceLocation();
QuickTestCaseSpec currentSpec; QuickTestCaseSpec currentSpec;
currentSpec.m_name = m_currentDoc->fileName(); currentSpec.m_locationAndType.m_name = m_currentDoc->fileName();
currentSpec.m_line = sourceLocation.startLine; currentSpec.m_locationAndType.m_line = sourceLocation.startLine;
currentSpec.m_column = sourceLocation.startColumn - 1; currentSpec.m_locationAndType.m_column = sourceLocation.startColumn - 1;
currentSpec.m_type = TestTreeItem::TestCase; currentSpec.m_locationAndType.m_type = TestTreeItem::TestCase;
m_testCases.push(currentSpec); m_caseParseStack.push(currentSpec);
return true; return true;
} }
void TestQmlVisitor::endVisit(QmlJS::AST::UiObjectDefinition *) void TestQmlVisitor::endVisit(QmlJS::AST::UiObjectDefinition *)
{ {
if (!m_objectStack.isEmpty() && m_objectStack.pop() == "TestCase") { if (!m_objectIsTestStack.isEmpty() && m_objectIsTestStack.pop() && !m_caseParseStack.isEmpty())
if (!m_testCases.isEmpty()) m_testCases << m_caseParseStack.pop();
m_testCases.pop();
m_insideTestCase = !m_objectStack.isEmpty() && m_objectStack.top() == "TestCase";
}
} }
bool TestQmlVisitor::visit(QmlJS::AST::ExpressionStatement *ast) bool TestQmlVisitor::visit(QmlJS::AST::ExpressionStatement *ast)
@@ -124,7 +119,7 @@ bool TestQmlVisitor::visit(QmlJS::AST::ExpressionStatement *ast)
bool TestQmlVisitor::visit(QmlJS::AST::UiScriptBinding *ast) bool TestQmlVisitor::visit(QmlJS::AST::UiScriptBinding *ast)
{ {
if (m_insideTestCase) if (m_objectIsTestStack.top())
m_expectTestCaseName = ast->qualifiedId->name == "name"; m_expectTestCaseName = ast->qualifiedId->name == "name";
return m_expectTestCaseName; return m_expectTestCaseName;
} }
@@ -137,6 +132,9 @@ void TestQmlVisitor::endVisit(QmlJS::AST::UiScriptBinding *)
bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast) bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast)
{ {
if (m_caseParseStack.isEmpty())
return false;
const QStringRef name = ast->name; const QStringRef name = ast->name;
if (name.startsWith("test_") if (name.startsWith("test_")
|| name.startsWith("benchmark_") || name.startsWith("benchmark_")
@@ -154,13 +152,8 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast)
else else
locationAndType.m_type = TestTreeItem::TestFunction; locationAndType.m_type = TestTreeItem::TestFunction;
if (m_testCases.isEmpty()) // invalid qml code m_caseParseStack.top().m_functions.append(
return false; QuickTestFunctionSpec{name.toString(), locationAndType});
QuickTestCaseSpec testCaseWithFunc = m_testCases.top();
testCaseWithFunc.m_functionName = name.toString();
testCaseWithFunc.m_functionLocationAndType = locationAndType;
m_testFunctions.append(testCaseWithFunc);
} }
return false; return false;
} }
@@ -168,8 +161,8 @@ bool TestQmlVisitor::visit(QmlJS::AST::FunctionDeclaration *ast)
bool TestQmlVisitor::visit(QmlJS::AST::StringLiteral *ast) bool TestQmlVisitor::visit(QmlJS::AST::StringLiteral *ast)
{ {
if (m_expectTestCaseName) { if (m_expectTestCaseName) {
QTC_ASSERT(!m_testCases.isEmpty(), return false); QTC_ASSERT(!m_caseParseStack.isEmpty(), return false);
m_testCases.top().m_caseName = ast->value.toString(); m_caseParseStack.top().m_caseName = ast->value.toString();
m_expectTestCaseName = false; m_expectTestCaseName = false;
} }
return false; return false;

View File

@@ -37,12 +37,19 @@
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
class QuickTestCaseSpec : public TestCodeLocationAndType class QuickTestFunctionSpec
{
public:
QString m_functionName;
TestCodeLocationAndType m_locationAndType;
};
class QuickTestCaseSpec
{ {
public: public:
QString m_caseName; QString m_caseName;
QString m_functionName; TestCodeLocationAndType m_locationAndType;
TestCodeLocationAndType m_functionLocationAndType; QVector<QuickTestFunctionSpec> m_functions;
}; };
class TestQmlVisitor : public QmlJS::AST::Visitor class TestQmlVisitor : public QmlJS::AST::Visitor
@@ -58,17 +65,15 @@ public:
bool visit(QmlJS::AST::FunctionDeclaration *ast) override; bool visit(QmlJS::AST::FunctionDeclaration *ast) override;
bool visit(QmlJS::AST::StringLiteral *ast) override; bool visit(QmlJS::AST::StringLiteral *ast) override;
QVector<QuickTestCaseSpec> testFunctions() const { return m_testFunctions; } QVector<QuickTestCaseSpec> testCases() const { return m_testCases; }
bool isValid() const { return m_typeIsTestCase; } bool isValid() const { return !m_testCases.isEmpty(); }
private: private:
QmlJS::Document::Ptr m_currentDoc; QmlJS::Document::Ptr m_currentDoc;
QmlJS::Snapshot m_snapshot; QmlJS::Snapshot m_snapshot;
QStack<QuickTestCaseSpec> m_testCases; QStack<QuickTestCaseSpec> m_caseParseStack;
QVector<QuickTestCaseSpec> m_testFunctions; QVector<QuickTestCaseSpec> m_testCases;
QStack<QString> m_objectStack; QStack<bool> m_objectIsTestStack;
bool m_typeIsTestCase = false;
bool m_insideTestCase = false;
bool m_expectTestCaseName = false; bool m_expectTestCaseName = false;
}; };