2013-12-16 16:02:45 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-12-16 16:02:45 +01:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2013-12-16 16:02:45 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** 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-3.0.html.
|
2013-12-16 16:02:45 +01:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "cpptoolstestcase.h"
|
2015-07-07 15:02:14 +02:00
|
|
|
|
|
|
|
|
#include "baseeditordocumentparser.h"
|
|
|
|
|
#include "baseeditordocumentprocessor.h"
|
2021-09-07 11:39:33 +02:00
|
|
|
#include "cppeditorwidget.h"
|
2015-03-05 08:22:48 +01:00
|
|
|
#include "cppmodelmanager.h"
|
2014-12-09 17:09:45 +01:00
|
|
|
#include "cppworkingcopy.h"
|
2021-09-07 11:39:33 +02:00
|
|
|
#include "editordocumenthandle.h"
|
2016-01-12 12:51:33 +01:00
|
|
|
#include "projectinfo.h"
|
2014-12-09 17:09:45 +01:00
|
|
|
|
2013-12-16 16:02:45 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2022-07-27 12:27:41 +02:00
|
|
|
|
|
|
|
|
#include <cplusplus/CppDocument.h>
|
|
|
|
|
|
2019-11-28 11:22:04 +01:00
|
|
|
#include <projectexplorer/buildsystem.h>
|
2015-03-05 08:22:48 +01:00
|
|
|
#include <projectexplorer/project.h>
|
2014-12-09 13:01:44 +01:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
|
#include <projectexplorer/session.h>
|
2022-07-27 12:27:41 +02:00
|
|
|
|
2014-09-26 09:14:03 +02:00
|
|
|
#include <texteditor/texteditor.h>
|
2014-09-19 12:32:43 +02:00
|
|
|
#include <texteditor/codeassist/iassistproposal.h>
|
|
|
|
|
#include <texteditor/codeassist/iassistproposalmodel.h>
|
2021-09-07 11:39:33 +02:00
|
|
|
#include <texteditor/storagesettings.h>
|
2013-12-16 16:02:45 +01:00
|
|
|
|
2015-04-13 17:41:17 +02:00
|
|
|
#include <utils/executeondestruction.h>
|
2013-12-16 16:02:45 +01:00
|
|
|
#include <utils/fileutils.h>
|
2021-05-19 13:22:49 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2022-07-27 12:27:41 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2017-01-19 16:44:22 +01:00
|
|
|
#include <utils/temporarydirectory.h>
|
2013-12-16 16:02:45 +01:00
|
|
|
|
|
|
|
|
#include <QtTest>
|
|
|
|
|
|
2014-12-09 13:01:44 +01:00
|
|
|
using namespace ProjectExplorer;
|
2021-07-16 17:31:41 +02:00
|
|
|
using namespace Utils;
|
2014-12-09 13:01:44 +01:00
|
|
|
|
2021-09-07 13:48:37 +02:00
|
|
|
namespace CppEditor::Internal::Tests {
|
|
|
|
|
|
|
|
|
|
CppTestDocument::CppTestDocument(const QByteArray &fileName, const QByteArray &source,
|
|
|
|
|
char cursorMarker)
|
|
|
|
|
: m_fileName(QString::fromUtf8(fileName))
|
|
|
|
|
, m_source(QString::fromUtf8(source))
|
|
|
|
|
, m_cursorMarker(cursorMarker)
|
|
|
|
|
, m_targetCursorPosition(m_source.indexOf(QLatin1Char('$')))
|
|
|
|
|
, m_selectionStartMarker(QLatin1Char(m_cursorMarker) + QLatin1String("{start}"))
|
|
|
|
|
, m_selectionEndMarker(QLatin1Char(m_cursorMarker) + QLatin1String("{end}"))
|
|
|
|
|
{
|
|
|
|
|
// Try to find selection markers
|
|
|
|
|
const int selectionStartIndex = m_source.indexOf(m_selectionStartMarker);
|
|
|
|
|
const int selectionEndIndex = m_source.indexOf(m_selectionEndMarker);
|
|
|
|
|
const bool bothSelectionMarkersFound = selectionStartIndex != -1 && selectionEndIndex != -1;
|
|
|
|
|
const bool noneSelectionMarkersFounds = selectionStartIndex == -1 && selectionEndIndex == -1;
|
|
|
|
|
QTC_ASSERT(bothSelectionMarkersFound || noneSelectionMarkersFounds, return);
|
|
|
|
|
|
|
|
|
|
if (selectionStartIndex != -1) {
|
|
|
|
|
m_cursorPosition = selectionEndIndex;
|
|
|
|
|
m_anchorPosition = selectionStartIndex;
|
|
|
|
|
|
|
|
|
|
// No selection markers found, so check for simple cursorMarker
|
|
|
|
|
} else {
|
|
|
|
|
m_cursorPosition = m_source.indexOf(QLatin1Char(cursorMarker));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_cursorPosition != -1 || m_targetCursorPosition != -1)
|
|
|
|
|
QVERIFY(m_cursorPosition != m_targetCursorPosition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestDocumentPtr CppTestDocument::create(const QByteArray &source, const QByteArray &fileName)
|
|
|
|
|
{
|
|
|
|
|
const TestDocumentPtr doc(new CppTestDocument(fileName, source));
|
|
|
|
|
doc->removeMarkers();
|
|
|
|
|
return doc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestDocumentPtr CppTestDocument::create(const QByteArray &fileName, const QByteArray &source,
|
|
|
|
|
const QByteArray &expectedSource)
|
|
|
|
|
{
|
|
|
|
|
const TestDocumentPtr doc(new CppTestDocument(fileName, source));
|
|
|
|
|
doc->m_expectedSource = QString::fromUtf8(expectedSource);
|
|
|
|
|
doc->removeMarkers();
|
|
|
|
|
return doc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString CppTestDocument::filePath() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_baseDirectory.isEmpty())
|
|
|
|
|
return QDir::cleanPath(m_baseDirectory + QLatin1Char('/') + m_fileName);
|
|
|
|
|
|
|
|
|
|
if (!QFileInfo(m_fileName).isAbsolute())
|
|
|
|
|
return Utils::TemporaryDirectory::masterDirectoryPath() + '/' + m_fileName;
|
|
|
|
|
|
|
|
|
|
return m_fileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CppTestDocument::writeToDisk() const
|
|
|
|
|
{
|
|
|
|
|
return CppEditor::Tests::TestCase::writeFile(filePath(), m_source.toUtf8());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CppTestDocument::removeMarkers()
|
|
|
|
|
{
|
|
|
|
|
// Remove selection markers
|
|
|
|
|
if (m_anchorPosition != -1) {
|
|
|
|
|
if (m_anchorPosition < m_cursorPosition) {
|
|
|
|
|
m_source.remove(m_anchorPosition, m_selectionStartMarker.size());
|
|
|
|
|
m_cursorPosition -= m_selectionStartMarker.size();
|
|
|
|
|
m_source.remove(m_cursorPosition, m_selectionEndMarker.size());
|
|
|
|
|
} else {
|
|
|
|
|
m_source.remove(m_cursorPosition, m_selectionEndMarker.size());
|
|
|
|
|
m_anchorPosition -= m_selectionEndMarker.size();
|
|
|
|
|
m_source.remove(m_anchorPosition, m_selectionStartMarker.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove simple cursor marker
|
|
|
|
|
} else if (m_cursorPosition != -1 || m_targetCursorPosition != -1) {
|
|
|
|
|
if (m_cursorPosition > m_targetCursorPosition) {
|
|
|
|
|
m_source.remove(m_cursorPosition, 1);
|
|
|
|
|
if (m_targetCursorPosition != -1) {
|
|
|
|
|
m_source.remove(m_targetCursorPosition, 1);
|
|
|
|
|
--m_cursorPosition;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
m_source.remove(m_targetCursorPosition, 1);
|
|
|
|
|
if (m_cursorPosition != -1) {
|
|
|
|
|
m_source.remove(m_cursorPosition, 1);
|
|
|
|
|
--m_targetCursorPosition;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int cursorPositionInExpectedSource
|
|
|
|
|
= m_expectedSource.indexOf(QLatin1Char(m_cursorMarker));
|
|
|
|
|
if (cursorPositionInExpectedSource > -1)
|
|
|
|
|
m_expectedSource.remove(cursorPositionInExpectedSource, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerifyCleanCppModelManager::VerifyCleanCppModelManager()
|
|
|
|
|
{
|
|
|
|
|
QVERIFY(isClean());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VerifyCleanCppModelManager::~VerifyCleanCppModelManager() {
|
|
|
|
|
QVERIFY(isClean());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define RETURN_FALSE_IF_NOT(check) if (!(check)) return false;
|
|
|
|
|
|
|
|
|
|
bool VerifyCleanCppModelManager::isClean(bool testOnlyForCleanedProjects)
|
|
|
|
|
{
|
|
|
|
|
CppModelManager *mm = CppModelManager::instance();
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->projectInfos().isEmpty());
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->headerPaths().isEmpty());
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->definedMacros().isEmpty());
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->projectFiles().isEmpty());
|
|
|
|
|
if (!testOnlyForCleanedProjects) {
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->snapshot().isEmpty());
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->workingCopy().size() == 1);
|
|
|
|
|
RETURN_FALSE_IF_NOT(mm->workingCopy().contains(mm->configurationFileName()));
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef RETURN_FALSE_IF_NOT
|
|
|
|
|
|
|
|
|
|
} // namespace CppEditor::Internal::Tests
|
|
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
namespace CppEditor::Tests {
|
2021-08-18 13:27:26 +02:00
|
|
|
|
2013-12-17 13:54:52 +01:00
|
|
|
static bool closeEditorsWithoutGarbageCollectorInvocation(const QList<Core::IEditor *> &editors)
|
|
|
|
|
{
|
2021-08-18 13:27:26 +02:00
|
|
|
CppModelManager::instance()->enableGarbageCollector(false);
|
2013-12-17 13:54:52 +01:00
|
|
|
const bool closeEditorsSucceeded = Core::EditorManager::closeEditors(editors, false);
|
2021-08-18 13:27:26 +02:00
|
|
|
CppModelManager::instance()->enableGarbageCollector(true);
|
2013-12-17 13:54:52 +01:00
|
|
|
return closeEditorsSucceeded;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-04 14:59:50 +02:00
|
|
|
static bool snapshotContains(const CPlusPlus::Snapshot &snapshot, const QSet<QString> &filePaths)
|
2013-12-16 16:02:45 +01:00
|
|
|
{
|
2021-08-18 13:27:26 +02:00
|
|
|
for (const QString &filePath : filePaths) {
|
2013-12-16 16:02:45 +01:00
|
|
|
if (!snapshot.contains(filePath)) {
|
2021-08-03 21:05:54 +02:00
|
|
|
qWarning() << "Missing file in snapshot:" << qPrintable(filePath);
|
2013-12-16 16:02:45 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestCase::TestCase(bool runGarbageCollector)
|
2014-09-15 00:12:27 +02:00
|
|
|
: m_modelManager(CppModelManager::instance())
|
2013-12-30 19:44:42 +01:00
|
|
|
, m_succeededSoFar(false)
|
2013-12-16 16:02:45 +01:00
|
|
|
, m_runGarbageCollector(runGarbageCollector)
|
|
|
|
|
{
|
|
|
|
|
if (m_runGarbageCollector)
|
|
|
|
|
QVERIFY(garbageCollectGlobalSnapshot());
|
2013-12-30 19:44:42 +01:00
|
|
|
m_succeededSoFar = true;
|
2013-12-16 16:02:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestCase::~TestCase()
|
|
|
|
|
{
|
2013-12-17 13:54:52 +01:00
|
|
|
QVERIFY(closeEditorsWithoutGarbageCollectorInvocation(m_editorsToClose));
|
2013-12-16 16:02:45 +01:00
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
|
|
|
|
|
if (m_runGarbageCollector)
|
|
|
|
|
QVERIFY(garbageCollectGlobalSnapshot());
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-30 19:44:42 +01:00
|
|
|
bool TestCase::succeededSoFar() const
|
|
|
|
|
{
|
|
|
|
|
return m_succeededSoFar;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 11:39:33 +02:00
|
|
|
bool TestCase::openCppEditor(const QString &fileName, TextEditor::BaseTextEditor **editor,
|
|
|
|
|
CppEditorWidget **editorWidget)
|
2014-02-19 11:39:06 -03:00
|
|
|
{
|
2021-11-01 17:02:02 +01:00
|
|
|
if (const auto e = dynamic_cast<TextEditor::BaseTextEditor *>(
|
|
|
|
|
Core::EditorManager::openEditor(FilePath::fromString(fileName)))) {
|
2014-02-19 11:39:06 -03:00
|
|
|
if (editor) {
|
|
|
|
|
*editor = e;
|
2021-09-07 11:39:33 +02:00
|
|
|
TextEditor::StorageSettings s = e->textDocument()->storageSettings();
|
|
|
|
|
s.m_addFinalNewLine = false;
|
|
|
|
|
e->textDocument()->setStorageSettings(s);
|
|
|
|
|
}
|
|
|
|
|
if (editorWidget) {
|
|
|
|
|
if (CppEditorWidget *w = dynamic_cast<CppEditorWidget *>(e->editorWidget())) {
|
|
|
|
|
*editorWidget = w;
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false; // no or wrong widget
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return true; // ok since no widget requested
|
2014-02-19 11:39:06 -03:00
|
|
|
}
|
2021-09-07 11:39:33 +02:00
|
|
|
} else {
|
|
|
|
|
return false; // no or wrong editor
|
2014-02-19 11:39:06 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 16:02:45 +01:00
|
|
|
CPlusPlus::Snapshot TestCase::globalSnapshot()
|
|
|
|
|
{
|
2014-09-15 00:12:27 +02:00
|
|
|
return CppModelManager::instance()->snapshot();
|
2013-12-16 16:02:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestCase::garbageCollectGlobalSnapshot()
|
|
|
|
|
{
|
2014-09-15 00:12:27 +02:00
|
|
|
CppModelManager::instance()->GC();
|
2013-12-16 16:02:45 +01:00
|
|
|
return globalSnapshot().isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-07 15:02:14 +02:00
|
|
|
static bool waitForProcessedEditorDocument_internal(CppEditorDocumentHandle *editorDocument,
|
|
|
|
|
int timeOutInMs)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(editorDocument, return false);
|
|
|
|
|
|
2019-07-05 09:56:23 +02:00
|
|
|
QElapsedTimer timer;
|
2015-07-07 15:02:14 +02:00
|
|
|
timer.start();
|
|
|
|
|
|
|
|
|
|
forever {
|
|
|
|
|
if (!editorDocument->processor()->isParserRunning())
|
|
|
|
|
return true;
|
|
|
|
|
if (timer.elapsed() > timeOutInMs)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
QThread::msleep(20);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestCase::waitForProcessedEditorDocument(const QString &filePath, int timeOutInMs)
|
|
|
|
|
{
|
|
|
|
|
auto *editorDocument = CppModelManager::instance()->cppEditorDocument(filePath);
|
|
|
|
|
return waitForProcessedEditorDocument_internal(editorDocument, timeOutInMs);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 11:39:33 +02:00
|
|
|
CPlusPlus::Document::Ptr TestCase::waitForRehighlightedSemanticDocument(CppEditorWidget *editorWidget)
|
|
|
|
|
{
|
|
|
|
|
while (!editorWidget->isSemanticInfoValid())
|
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
return editorWidget->semanticInfo().doc;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-04 14:59:50 +02:00
|
|
|
bool TestCase::parseFiles(const QSet<QString> &filePaths)
|
2013-12-16 16:02:45 +01:00
|
|
|
{
|
2014-09-15 00:12:27 +02:00
|
|
|
CppModelManager::instance()->updateSourceFiles(filePaths).waitForFinished();
|
2013-12-16 16:02:45 +01:00
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
const CPlusPlus::Snapshot snapshot = globalSnapshot();
|
|
|
|
|
if (snapshot.isEmpty()) {
|
2021-08-03 11:50:13 +02:00
|
|
|
qWarning("After parsing: snapshot is empty.");
|
2013-12-16 16:02:45 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!snapshotContains(snapshot, filePaths)) {
|
2021-08-03 11:50:13 +02:00
|
|
|
qWarning("After parsing: snapshot does not contain all expected files.");
|
2013-12-16 16:02:45 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TestCase::parseFiles(const QString &filePath)
|
|
|
|
|
{
|
2014-09-04 14:59:50 +02:00
|
|
|
return parseFiles(QSet<QString>() << filePath);
|
2013-12-16 16:02:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestCase::closeEditorAtEndOfTestCase(Core::IEditor *editor)
|
|
|
|
|
{
|
|
|
|
|
if (editor && !m_editorsToClose.contains(editor))
|
|
|
|
|
m_editorsToClose.append(editor);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-17 13:54:52 +01:00
|
|
|
bool TestCase::closeEditorWithoutGarbageCollectorInvocation(Core::IEditor *editor)
|
|
|
|
|
{
|
2019-01-18 20:25:30 +01:00
|
|
|
return closeEditorsWithoutGarbageCollectorInvocation({editor});
|
2013-12-17 13:54:52 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 15:05:22 +01:00
|
|
|
CPlusPlus::Document::Ptr TestCase::waitForFileInGlobalSnapshot(const QString &filePath,
|
|
|
|
|
int timeOutInMs)
|
2013-12-16 16:02:45 +01:00
|
|
|
{
|
2015-02-17 15:05:22 +01:00
|
|
|
const auto documents = waitForFilesInGlobalSnapshot(QStringList(filePath), timeOutInMs);
|
|
|
|
|
return documents.isEmpty() ? CPlusPlus::Document::Ptr() : documents.first();
|
2013-12-16 16:02:45 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 15:05:22 +01:00
|
|
|
QList<CPlusPlus::Document::Ptr> TestCase::waitForFilesInGlobalSnapshot(const QStringList &filePaths,
|
|
|
|
|
int timeOutInMs)
|
2013-12-16 16:02:45 +01:00
|
|
|
{
|
2019-07-05 09:56:23 +02:00
|
|
|
QElapsedTimer t;
|
2015-02-17 15:05:22 +01:00
|
|
|
t.start();
|
|
|
|
|
|
2013-12-16 16:02:45 +01:00
|
|
|
QList<CPlusPlus::Document::Ptr> result;
|
2021-08-18 13:27:26 +02:00
|
|
|
for (const QString &filePath : filePaths) {
|
2013-12-16 16:02:45 +01:00
|
|
|
forever {
|
|
|
|
|
if (CPlusPlus::Document::Ptr document = globalSnapshot().document(filePath)) {
|
|
|
|
|
result.append(document);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-02-17 15:05:22 +01:00
|
|
|
if (t.elapsed() > timeOutInMs)
|
|
|
|
|
return QList<CPlusPlus::Document::Ptr>();
|
2013-12-16 16:02:45 +01:00
|
|
|
QCoreApplication::processEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 15:09:08 +01:00
|
|
|
bool TestCase::waitUntilProjectIsFullyOpened(Project *project, int timeOutInMs)
|
2014-12-09 13:01:44 +01:00
|
|
|
{
|
|
|
|
|
if (!project)
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-11-21 15:09:08 +01:00
|
|
|
return QTest::qWaitFor(
|
|
|
|
|
[project]() {
|
2021-05-12 12:04:13 +02:00
|
|
|
return SessionManager::startupBuildSystem()
|
|
|
|
|
&& !SessionManager::startupBuildSystem()->isParsing()
|
2021-05-07 16:10:07 +02:00
|
|
|
&& CppModelManager::instance()->projectInfo(project);
|
2019-11-21 15:09:08 +01:00
|
|
|
},
|
|
|
|
|
timeOutInMs);
|
2014-12-09 13:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-16 16:02:45 +01:00
|
|
|
bool TestCase::writeFile(const QString &filePath, const QByteArray &contents)
|
|
|
|
|
{
|
2021-05-18 09:47:07 +02:00
|
|
|
Utils::FileSaver saver(Utils::FilePath::fromString(filePath));
|
2013-12-16 16:02:45 +01:00
|
|
|
if (!saver.write(contents) || !saver.finalize()) {
|
2021-08-03 21:05:54 +02:00
|
|
|
qWarning() << "Failed to write file to disk:" << qPrintable(filePath);
|
2013-12-16 16:02:45 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-13 17:41:17 +02:00
|
|
|
ProjectOpenerAndCloser::ProjectOpenerAndCloser()
|
2014-12-09 13:01:44 +01:00
|
|
|
{
|
|
|
|
|
QVERIFY(!SessionManager::hasProjects());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProjectOpenerAndCloser::~ProjectOpenerAndCloser()
|
|
|
|
|
{
|
2015-04-13 17:41:17 +02:00
|
|
|
if (m_openProjects.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool hasGcFinished = false;
|
|
|
|
|
QMetaObject::Connection connection;
|
|
|
|
|
Utils::ExecuteOnDestruction disconnect([&]() { QObject::disconnect(connection); });
|
|
|
|
|
connection = QObject::connect(CppModelManager::instance(), &CppModelManager::gcFinished, [&]() {
|
|
|
|
|
hasGcFinished = true;
|
|
|
|
|
});
|
|
|
|
|
|
2022-05-05 15:51:12 +02:00
|
|
|
for (Project *project : qAsConst(m_openProjects))
|
2014-12-09 13:01:44 +01:00
|
|
|
ProjectExplorerPlugin::unloadProject(project);
|
2014-12-09 17:09:45 +01:00
|
|
|
|
2019-07-05 09:56:23 +02:00
|
|
|
QElapsedTimer t;
|
2015-04-13 17:41:17 +02:00
|
|
|
t.start();
|
|
|
|
|
while (!hasGcFinished && t.elapsed() <= 30000)
|
|
|
|
|
QCoreApplication::processEvents();
|
2014-12-09 13:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
2021-08-20 11:21:06 +02:00
|
|
|
ProjectInfo::ConstPtr ProjectOpenerAndCloser::open(const QString &projectFile,
|
2021-05-07 16:10:07 +02:00
|
|
|
bool configureAsExampleProject, Kit *kit)
|
2014-12-09 13:01:44 +01:00
|
|
|
{
|
2021-07-16 17:31:41 +02:00
|
|
|
ProjectExplorerPlugin::OpenProjectResult result =
|
|
|
|
|
ProjectExplorerPlugin::openProject(FilePath::fromString(projectFile));
|
2015-08-20 14:47:02 +02:00
|
|
|
if (!result) {
|
|
|
|
|
qWarning() << result.errorMessage() << result.alreadyOpen();
|
2021-05-07 16:10:07 +02:00
|
|
|
return {};
|
2015-08-20 14:47:02 +02:00
|
|
|
}
|
2014-12-09 13:01:44 +01:00
|
|
|
|
2015-08-20 14:47:02 +02:00
|
|
|
Project *project = result.project();
|
2014-12-09 17:09:45 +01:00
|
|
|
if (configureAsExampleProject)
|
2020-06-16 13:11:10 +02:00
|
|
|
project->configureAsExampleProject(kit);
|
2014-12-09 17:09:45 +01:00
|
|
|
|
2019-11-21 15:09:08 +01:00
|
|
|
if (TestCase::waitUntilProjectIsFullyOpened(project)) {
|
2015-04-13 17:41:17 +02:00
|
|
|
m_openProjects.append(project);
|
2014-12-09 13:01:44 +01:00
|
|
|
return CppModelManager::instance()->projectInfo(project);
|
2015-04-13 17:41:17 +02:00
|
|
|
}
|
2014-12-09 13:01:44 +01:00
|
|
|
|
2021-05-07 16:10:07 +02:00
|
|
|
return {};
|
2014-12-09 13:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-09 18:42:15 +01:00
|
|
|
TemporaryDir::TemporaryDir()
|
2017-01-24 17:29:34 +01:00
|
|
|
: m_temporaryDir("qtcreator-tests-XXXXXX")
|
2014-12-09 13:01:44 +01:00
|
|
|
, m_isValid(m_temporaryDir.isValid())
|
2014-12-09 18:42:15 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString TemporaryDir::createFile(const QByteArray &relativePath, const QByteArray &contents)
|
|
|
|
|
{
|
|
|
|
|
const QString relativePathString = QString::fromUtf8(relativePath);
|
|
|
|
|
if (relativePathString.isEmpty() || QFileInfo(relativePathString).isAbsolute())
|
|
|
|
|
return QString();
|
|
|
|
|
|
2021-07-01 09:58:48 +02:00
|
|
|
const QString filePath = m_temporaryDir.filePath(relativePathString).path();
|
2014-12-09 18:42:15 +01:00
|
|
|
if (!TestCase::writeFile(filePath, contents))
|
|
|
|
|
return QString();
|
|
|
|
|
return filePath;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 11:47:17 +02:00
|
|
|
static bool copyRecursively(const QString &sourceDirPath,
|
|
|
|
|
const QString &targetDirPath,
|
|
|
|
|
QString *error)
|
|
|
|
|
{
|
2021-08-09 08:53:40 +02:00
|
|
|
auto copyHelper = [](const FilePath &sourcePath, const FilePath &targetPath, QString *error) -> bool {
|
|
|
|
|
if (!sourcePath.copyFile(targetPath)) {
|
2015-07-01 11:47:17 +02:00
|
|
|
if (error) {
|
|
|
|
|
*error = QString::fromLatin1("copyRecursively() failed: \"%1\" to \"%2\".")
|
2021-08-09 08:53:40 +02:00
|
|
|
.arg(sourcePath.toUserOutput(), targetPath.toUserOutput());
|
2015-07-01 11:47:17 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copied files from Qt resources are read-only. Make them writable
|
|
|
|
|
// so that their parent directory can be removed without warnings.
|
2021-08-18 13:27:26 +02:00
|
|
|
return targetPath.setPermissions(targetPath.permissions() | QFile::WriteUser);
|
2015-07-01 11:47:17 +02:00
|
|
|
};
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
return Utils::FileUtils::copyRecursively(Utils::FilePath::fromString(sourceDirPath),
|
|
|
|
|
Utils::FilePath::fromString(targetDirPath),
|
2015-07-01 11:47:17 +02:00
|
|
|
error,
|
|
|
|
|
copyHelper);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-09 18:42:15 +01:00
|
|
|
TemporaryCopiedDir::TemporaryCopiedDir(const QString &sourceDirPath)
|
2014-12-09 13:01:44 +01:00
|
|
|
{
|
|
|
|
|
if (!m_isValid)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-07-01 11:47:17 +02:00
|
|
|
if (sourceDirPath.isEmpty())
|
|
|
|
|
return;
|
2014-12-09 13:01:44 +01:00
|
|
|
|
2015-07-01 11:47:17 +02:00
|
|
|
QFileInfo fi(sourceDirPath);
|
|
|
|
|
if (!fi.exists() || !fi.isReadable()) {
|
|
|
|
|
m_isValid = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString errorMessage;
|
|
|
|
|
if (!copyRecursively(sourceDirPath, path(), &errorMessage)) {
|
2021-08-03 21:05:54 +02:00
|
|
|
qWarning() << qPrintable(errorMessage);
|
2015-07-01 11:47:17 +02:00
|
|
|
m_isValid = false;
|
2014-12-09 13:01:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString TemporaryCopiedDir::absolutePath(const QByteArray &relativePath) const
|
|
|
|
|
{
|
2021-07-01 09:58:48 +02:00
|
|
|
return m_temporaryDir.filePath(QString::fromUtf8(relativePath)).path();
|
2014-12-09 13:01:44 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-19 13:22:49 +02:00
|
|
|
int clangdIndexingTimeout()
|
|
|
|
|
{
|
|
|
|
|
const QByteArray timeoutAsByteArray = qgetenv("QTC_CLANGD_INDEXING_TIMEOUT");
|
|
|
|
|
bool isConversionOk = false;
|
|
|
|
|
const int intervalAsInt = timeoutAsByteArray.toInt(&isConversionOk);
|
|
|
|
|
if (!isConversionOk)
|
|
|
|
|
return Utils::HostOsInfo::isWindowsHost() ? 20000 : 10000;
|
|
|
|
|
return intervalAsInt;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 10:58:08 +02:00
|
|
|
} // namespace CppEditor::Tests
|