ClangStaticAnalyzer: Tests: Rely on projects telling when they finished parsing

We relied on the CppModelManager to tell us whether a project was reparsed
after a kit change. While this worked, it was not guaranteed that the project
is really finished (and ready for e.g. building) after pushing new ProjectInfos
to the CppModelManager.

Rely on the projects telling when they are finished with parsing. This is more
accurate and future-proof.

The introduced signals in Project and SessionManager are (at the moment)
only for tests.

Change-Id: I1b368ec4585ffa8755eb28fac6d187cce31243ee
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Nikolai Kosjar
2016-10-20 13:18:54 +02:00
parent f952c3ee4a
commit 6e6d5b5309
13 changed files with 68 additions and 17 deletions

View File

@@ -129,6 +129,8 @@ void AppManagerProject::populateProject()
foreach (ProjectExplorer::Target *target, targets()) foreach (ProjectExplorer::Target *target, targets())
targetUpdateDeployableFiles(target, files); targetUpdateDeployableFiles(target, files);
} }
emit parsingFinished();
} }
void AppManagerProject::recursiveScanDirectory(const QDir &dir, QSet<QString> &container) void AppManagerProject::recursiveScanDirectory(const QDir &dir, QSet<QString> &container)

View File

@@ -231,6 +231,8 @@ void AutotoolsProject::makefileParsingFinished()
m_makefileParserThread->deleteLater(); m_makefileParserThread->deleteLater();
m_makefileParserThread = 0; m_makefileParserThread = 0;
emit parsingFinished();
} }
void AutotoolsProject::onFileChanged(const QString &file) void AutotoolsProject::onFileChanged(const QString &file)

View File

@@ -29,7 +29,6 @@
#include "clangstaticanalyzertool.h" #include "clangstaticanalyzertool.h"
#include "clangstaticanalyzerutils.h" #include "clangstaticanalyzerutils.h"
#include <cpptools/cppmodelmanager.h>
#include <cpptools/projectinfo.h> #include <cpptools/projectinfo.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h> #include <projectexplorer/kitmanager.h>
@@ -44,6 +43,7 @@
#include <QSignalSpy> #include <QSignalSpy>
#include <QTimer> #include <QTimer>
#include <QtTest> #include <QtTest>
#include <QVariant>
#include <functional> #include <functional>
@@ -66,6 +66,35 @@ static bool processEventsUntil(const std::function<bool()> condition, int timeOu
} }
} }
class WaitForParsedProjects : public QObject
{
public:
WaitForParsedProjects(ProjectExplorer::SessionManager &sessionManager,
const QStringList &projects)
: m_sessionManager(sessionManager)
, m_projectsToWaitFor(projects)
{
connect(&m_sessionManager, &ProjectExplorer::SessionManager::projectFinishedParsing,
this, &WaitForParsedProjects::onProjectFinishedParsing);
}
void onProjectFinishedParsing(ProjectExplorer::Project *project)
{
m_projectsToWaitFor.removeOne(project->projectFilePath().toString());
}
bool wait()
{
return processEventsUntil([this]() {
return m_projectsToWaitFor.isEmpty();
});
}
private:
ProjectExplorer::SessionManager &m_sessionManager;
QStringList m_projectsToWaitFor;
};
namespace ClangStaticAnalyzer { namespace ClangStaticAnalyzer {
namespace Internal { namespace Internal {
@@ -84,16 +113,14 @@ void ClangStaticAnalyzerPreconfiguredSessionTests::initTestCase()
if (!m_sessionManager.sessions().contains(preconfiguredSessionName)) if (!m_sessionManager.sessions().contains(preconfiguredSessionName))
QSKIP("Manually preconfigured session 'ClangStaticAnalyzerPreconfiguredSession' needed."); QSKIP("Manually preconfigured session 'ClangStaticAnalyzerPreconfiguredSession' needed.");
// Load session if (m_sessionManager.activeSession() == preconfiguredSessionName)
if (m_sessionManager.activeSession() != preconfiguredSessionName) QSKIP("Session must not be already active.");
QVERIFY(m_sessionManager.loadSession(preconfiguredSessionName));
// Wait until all projects are loaded. // Load session
const int sessionManagerProjects = m_sessionManager.projects().size(); const QStringList projects = m_sessionManager.projectsForSessionName(preconfiguredSessionName);
const auto allProjectsLoaded = [sessionManagerProjects]() { WaitForParsedProjects waitForParsedProjects(m_sessionManager, projects);
return CppModelManager::instance()->projectInfos().size() == sessionManagerProjects; QVERIFY(m_sessionManager.loadSession(preconfiguredSessionName));
}; QVERIFY(waitForParsedProjects.wait());
QVERIFY(processEventsUntil(allProjectsLoaded));
} }
void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession() void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession()
@@ -201,15 +228,15 @@ bool ClangStaticAnalyzerPreconfiguredSessionTests::switchToProjectAndTarget(Proj
m_sessionManager.setStartupProject(project); m_sessionManager.setStartupProject(project);
if (target != project->activeTarget()) { if (target != project->activeTarget()) {
QSignalSpy waitUntilProjectUpdated(CppModelManager::instance(), QSignalSpy spyFinishedParsing(ProjectExplorer::SessionManager::instance(),
&CppModelManager::projectPartsUpdated); &ProjectExplorer::SessionManager::projectFinishedParsing);
m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade); m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade);
QTC_ASSERT(spyFinishedParsing.wait(30000), return false);
const bool waitResult = waitUntilProjectUpdated.wait(30000); const QVariant projectArgument = spyFinishedParsing.takeFirst().takeFirst();
if (!waitResult) { QTC_ASSERT(projectArgument.canConvert<ProjectExplorer::Project *>(), return false);
qWarning() << "waitUntilProjectUpdated() failed";
return false; return projectArgument.value<ProjectExplorer::Project *>() == project;
}
} }
return true; return true;

View File

@@ -145,6 +145,8 @@ void CMakeProject::updateProjectData()
emit fileListChanged(); emit fileListChanged();
emit cmakeBc->emitBuildTypeChanged(); emit cmakeBc->emitBuildTypeChanged();
emit parsingFinished();
} }
void CMakeProject::updateQmlJSCodeModel() void CMakeProject::updateQmlJSCodeModel()

View File

@@ -286,6 +286,7 @@ void GenericProject::refresh(RefreshOptions options)
} }
refreshCppCodeModel(); refreshCppCodeModel();
emit parsingFinished();
} }
/** /**

View File

@@ -112,6 +112,8 @@ void NimProject::populateProject()
rootProjectNode()->buildTree(fileNodes); rootProjectNode()->buildTree(fileNodes);
emit fileListChanged(); emit fileListChanged();
emit parsingFinished();
} }
void NimProject::recursiveScanDirectory(const QDir &dir, QSet<QString> &container) void NimProject::recursiveScanDirectory(const QDir &dir, QSet<QString> &container)

View File

@@ -168,6 +168,9 @@ signals:
void projectContextUpdated(); void projectContextUpdated();
void projectLanguagesUpdated(); void projectLanguagesUpdated();
signals: // for tests only
void parsingFinished();
protected: protected:
virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage); virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage);
virtual bool setupTarget(Target *t); virtual bool setupTarget(Target *t);

View File

@@ -1684,6 +1684,9 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con
foundProjectManager = true; foundProjectManager = true;
QString tmp; QString tmp;
if (Project *pro = manager->openProject(filePath, &tmp)) { if (Project *pro = manager->openProject(filePath, &tmp)) {
QObject::connect(pro, &Project::parsingFinished, [pro]() {
emit SessionManager::instance()->projectFinishedParsing(pro);
});
QString restoreError; QString restoreError;
Project::RestoreResult restoreResult = pro->restoreSettings(&restoreError); Project::RestoreResult restoreResult = pro->restoreSettings(&restoreError);
if (restoreResult == Project::RestoreResult::Ok) { if (restoreResult == Project::RestoreResult::Ok) {

View File

@@ -138,6 +138,9 @@ signals:
void aboutToSaveSession(); void aboutToSaveSession();
void dependencyChanged(ProjectExplorer::Project *a, ProjectExplorer::Project *b); void dependencyChanged(ProjectExplorer::Project *a, ProjectExplorer::Project *b);
signals: // for tests only
void projectFinishedParsing(ProjectExplorer::Project *project);
private: private:
static void saveActiveMode(Core::Id mode); static void saveActiveMode(Core::Id mode);
void clearProjectFileCache(); void clearProjectFileCache();

View File

@@ -619,6 +619,8 @@ void PythonProject::refresh()
return new PythonFileNode(FileName::fromString(f), displayName); return new PythonFileNode(FileName::fromString(f), displayName);
}); });
rootProjectNode()->buildTree(fileNodes); rootProjectNode()->buildTree(fileNodes);
emit parsingFinished();
} }
/** /**

View File

@@ -503,6 +503,7 @@ void QbsProject::handleQbsParsingDone(bool success)
if (dataChanged) if (dataChanged)
updateAfterParse(); updateAfterParse();
emit projectParsingDone(success); emit projectParsingDone(success);
emit parsingFinished();
} }
void QbsProject::handleRuleExecutionDone() void QbsProject::handleRuleExecutionDone()

View File

@@ -753,6 +753,7 @@ void QmakeProject::decrementPendingEvaluateFutures()
activeTarget()->updateDefaultDeployConfigurations(); activeTarget()->updateDefaultDeployConfigurations();
updateRunConfigurations(); updateRunConfigurations();
emit proFilesEvaluated(); emit proFilesEvaluated();
emit parsingFinished();
if (debug) if (debug)
qDebug()<<" Setting state to Base"; qDebug()<<" Setting state to Base";
} }

View File

@@ -198,6 +198,8 @@ void QmlProject::refresh(RefreshOptions options)
QmlJS::Dialect::Qml); QmlJS::Dialect::Qml);
modelManager()->updateProjectInfo(projectInfo, this); modelManager()->updateProjectInfo(projectInfo, this);
emit parsingFinished();
} }
QStringList QmlProject::convertToAbsoluteFiles(const QStringList &paths) const QStringList QmlProject::convertToAbsoluteFiles(const QStringList &paths) const