forked from qt-creator/qt-creator
CppEditor: Tweak test infrastructure
... so we can re-use the "follow symbol" test cases with clangd. Call Creator like this (clangd needs to be version 12 or later): $ QTC_CLANGD=<path to clangd> qtcreator -test 'CppEditor,*Follow*,*Switch*' -test 'ClangCodeModel,*dummy*' During testing, some invalid code in the test cases was uncovered and fixed. Change-Id: I9dc650fdba2a27600e6a550420ee873f6fb31d23 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
#include <cpptools/cppvirtualfunctionassistprovider.h>
|
||||
#include <cpptools/cppvirtualfunctionproposalitem.h>
|
||||
#include <languageclient/languageclientinterface.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projecttree.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <texteditor/basefilefind.h>
|
||||
@@ -513,11 +514,14 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
||||
setLocatorsEnabled(false);
|
||||
setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)"));
|
||||
setCurrentProject(project);
|
||||
connect(this, &Client::workDone, this, [this](const ProgressToken &token) {
|
||||
connect(this, &Client::workDone, this, [this, project](const ProgressToken &token) {
|
||||
const QString * const val = Utils::get_if<QString>(&token);
|
||||
if (val && *val == indexingToken()) {
|
||||
d->isFullyIndexed = true;
|
||||
emit indexingFinished();
|
||||
#ifdef WITH_TESTS
|
||||
emit project->indexingFinished("Indexer.Clangd");
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
@@ -848,6 +852,8 @@ void ClangdClient::followSymbol(
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(clangdLog) << "follow symbol requested" << document->filePath()
|
||||
<< cursor.blockNumber() << cursor.positionInBlock();
|
||||
d->followSymbolData.emplace(this, ++d->nextFollowSymbolId, cursor, editorWidget,
|
||||
DocumentUri::fromFilePath(document->filePath()),
|
||||
std::move(callback), openInSplit);
|
||||
@@ -856,6 +862,7 @@ void ClangdClient::followSymbol(
|
||||
// AST node corresponding to the cursor position, so we can find out whether
|
||||
// we have to look for overrides.
|
||||
const auto gotoDefCallback = [this, id = d->followSymbolData->id](const Utils::Link &link) {
|
||||
qCDebug(clangdLog) << "received go to definition response";
|
||||
if (!link.hasValidTarget()) {
|
||||
d->followSymbolData.reset();
|
||||
return;
|
||||
@@ -872,6 +879,7 @@ void ClangdClient::followSymbol(
|
||||
Range(cursor)));
|
||||
astRequest.setResponseCallback([this, id = d->followSymbolData->id](
|
||||
const AstRequest::Response &response) {
|
||||
qCDebug(clangdLog) << "received ast response";
|
||||
if (!d->followSymbolData || d->followSymbolData->id != id)
|
||||
return;
|
||||
const auto result = response.result();
|
||||
@@ -891,6 +899,8 @@ void ClangdClient::Private::handleGotoDefinitionResult()
|
||||
QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return);
|
||||
QTC_ASSERT(followSymbolData->cursorNode.isValid(), return);
|
||||
|
||||
qCDebug(clangdLog) << "handling go to definition result";
|
||||
|
||||
// No dis-ambiguation necessary. Call back with the link and finish.
|
||||
if (!followSymbolData->cursorNode.isMemberFunctionCall()
|
||||
&& !followSymbolData->cursorNode.isPureVirtualDeclaration()) {
|
||||
|
@@ -49,6 +49,7 @@
|
||||
|
||||
using namespace CPlusPlus;
|
||||
using namespace Core;
|
||||
using namespace CppTools::Tests;
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace ClangCodeModel {
|
||||
@@ -67,20 +68,6 @@ void ClangdTests::initTestCase()
|
||||
settings->setUseClangd(true);
|
||||
}
|
||||
|
||||
template <typename Signal> static bool waitForSignalOrTimeout(
|
||||
const typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal)
|
||||
{
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
timer.setInterval(timeOutInMs());
|
||||
QEventLoop loop;
|
||||
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||
QObject::connect(sender, signal, &loop, &QEventLoop::quit);
|
||||
timer.start();
|
||||
loop.exec();
|
||||
return timer.isActive();
|
||||
}
|
||||
|
||||
// The main point here is to test our access type categorization.
|
||||
// We do not try to stress-test clangd's "Find References" functionality; such tests belong
|
||||
// into LLVM.
|
||||
@@ -110,7 +97,7 @@ void ClangdTests::testFindReferences()
|
||||
ClangdClient *client = modelManagerSupport->clientForProject(openProjectResult.project());
|
||||
if (!client) {
|
||||
QVERIFY(waitForSignalOrTimeout(modelManagerSupport,
|
||||
&ClangModelManagerSupport::createdClient));
|
||||
&ClangModelManagerSupport::createdClient, timeOutInMs()));
|
||||
client = modelManagerSupport->clientForProject(openProjectResult.project());
|
||||
}
|
||||
QVERIFY(client);
|
||||
@@ -119,7 +106,7 @@ void ClangdTests::testFindReferences()
|
||||
// Wait until the client is fully initialized, i.e. it's completed the handshake
|
||||
// with the server.
|
||||
if (!client->reachable())
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::initialized));
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::initialized, timeOutInMs()));
|
||||
QVERIFY(client->reachable());
|
||||
|
||||
// The kind of AST support we need was introduced in LLVM 13.
|
||||
@@ -128,7 +115,7 @@ void ClangdTests::testFindReferences()
|
||||
|
||||
// Wait for index to build.
|
||||
if (!client->isFullyIndexed())
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished));
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::indexingFinished, timeOutInMs()));
|
||||
QVERIFY(client->isFullyIndexed());
|
||||
|
||||
// Open cpp documents.
|
||||
@@ -167,7 +154,7 @@ void ClangdTests::testFindReferences()
|
||||
cursor.setPosition((pos)); \
|
||||
searchResults.clear(); \
|
||||
client->findUsages((doc), cursor, {}); \
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone)); \
|
||||
QVERIFY(waitForSignalOrTimeout(client, &ClangdClient::findUsagesDone, timeOutInMs())); \
|
||||
} while (false)
|
||||
|
||||
#define EXPECT_RESULT(index, lne, col, type) \
|
||||
|
@@ -192,6 +192,10 @@ signals:
|
||||
void autoSaved();
|
||||
void currentEditorAboutToChange(Core::IEditor *editor);
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void linkOpened();
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
static void saveDocument();
|
||||
static void saveDocumentAs();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
add_qtc_plugin(CppEditor
|
||||
DEFINES CPPEDITOR_LIBRARY
|
||||
PLUGIN_DEPENDS Core CppTools ProjectExplorer TextEditor
|
||||
PLUGIN_TEST_DEPENDS QmakeProjectManager
|
||||
PLUGIN_TEST_DEPENDS QbsProjectManager QmakeProjectManager
|
||||
SOURCES
|
||||
cppautocompleter.cpp cppautocompleter.h
|
||||
cppcodemodelinspectordialog.cpp cppcodemodelinspectordialog.h cppcodemodelinspectordialog.ui
|
||||
|
@@ -17,6 +17,7 @@ QtcPlugin {
|
||||
|
||||
pluginTestDepends: [
|
||||
"QmakeProjectManager",
|
||||
"QbsProjectManager",
|
||||
]
|
||||
|
||||
files: [
|
||||
|
@@ -9,4 +9,5 @@ QTC_PLUGIN_DEPENDS += \
|
||||
cpptools \
|
||||
projectexplorer
|
||||
QTC_TEST_DEPENDS += \
|
||||
qbsprojectmanager \
|
||||
qmakeprojectmanager
|
||||
|
@@ -27,6 +27,10 @@
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
namespace ProjectExplorer { class Kit; }
|
||||
#endif
|
||||
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
|
||||
@@ -49,6 +53,10 @@ public:
|
||||
|
||||
CppQuickFixAssistProvider *quickFixProvider() const;
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
ProjectExplorer::Kit *m_testKit = nullptr;
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void outlineSortingChanged(bool sort);
|
||||
void typeHierarchyRequested();
|
||||
@@ -67,6 +75,8 @@ private:
|
||||
QVector<QObject *> createTestObjects() const override;
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
|
||||
// The following tests expect that no projects are loaded on start-up.
|
||||
void test_SwitchMethodDeclarationDefinition_data();
|
||||
void test_SwitchMethodDeclarationDefinition();
|
||||
|
@@ -28,9 +28,12 @@
|
||||
#include "cppeditor.h"
|
||||
#include "cppeditorwidget.h"
|
||||
#include "cppeditordocument.h"
|
||||
#include "cppeditorplugin.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <cpptools/cppcodemodelsettings.h>
|
||||
#include <cpptools/cppsemanticinfo.h>
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <cplusplus/CppDocument.h>
|
||||
|
||||
#include <QDir>
|
||||
@@ -74,12 +77,20 @@ bool TestDocument::hasCursorMarker() const { return m_cursorPosition != -1; }
|
||||
bool TestDocument::hasAnchorMarker() const { return m_anchorPosition != -1; }
|
||||
|
||||
TestCase::TestCase(bool runGarbageCollector)
|
||||
: CppTools::Tests::TestCase(runGarbageCollector)
|
||||
: CppTools::Tests::TestCase(runGarbageCollector),
|
||||
m_prevUseClangd(CppTools::codeModelSettings()->useClangd())
|
||||
{
|
||||
}
|
||||
|
||||
TestCase::~TestCase()
|
||||
{
|
||||
CppTools::codeModelSettings()->setUseClangd(m_prevUseClangd);
|
||||
}
|
||||
|
||||
void TestCase::setUseClangd()
|
||||
{
|
||||
if (CppEditorPlugin::instance()->m_testKit)
|
||||
CppTools::codeModelSettings()->setUseClangd(true);
|
||||
}
|
||||
|
||||
bool TestCase::openCppEditor(const QString &fileName, CppEditor **editor, CppEditorWidget **editorWidget)
|
||||
|
@@ -62,12 +62,17 @@ public:
|
||||
TestCase(bool runGarbageCollector = true);
|
||||
~TestCase();
|
||||
|
||||
void setUseClangd();
|
||||
|
||||
static bool openCppEditor(const QString &fileName,
|
||||
CppEditor **editor,
|
||||
CppEditorWidget **editorWidget = 0);
|
||||
|
||||
static CPlusPlus::Document::Ptr waitForRehighlightedSemanticDocument(
|
||||
CppEditorWidget *editorWidget);
|
||||
|
||||
private:
|
||||
const bool m_prevUseClangd;
|
||||
};
|
||||
|
||||
} // namespace Tests
|
||||
|
@@ -7185,7 +7185,7 @@ void CppEditorPlugin::test_quickfix_ExtractFunction_data()
|
||||
"}\n"
|
||||
"void NS::C::f(NS::C &c)\n"
|
||||
"{\n"
|
||||
" @{start}C *c = &c;@{end}\n"
|
||||
" @{start}C *c2 = &c;@{end}\n"
|
||||
"}\n")
|
||||
<< _("namespace NS {\n"
|
||||
"class C {\n"
|
||||
@@ -7197,7 +7197,7 @@ void CppEditorPlugin::test_quickfix_ExtractFunction_data()
|
||||
"}\n"
|
||||
"inline void NS::C::extracted(NS::C &c)\n"
|
||||
"{\n"
|
||||
" C *c = &c;\n"
|
||||
" C *c2 = &c;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"void NS::C::f(NS::C &c)\n"
|
||||
|
@@ -28,6 +28,8 @@
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortestcase.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QtTest>
|
||||
|
||||
@@ -100,11 +102,18 @@ UseSelectionsTestCase::UseSelectionsTestCase(TestDocument &testFile,
|
||||
|
||||
bool hasTimedOut;
|
||||
const SelectionList selections = waitForUseSelections(&hasTimedOut);
|
||||
QEXPECT_FAIL("non-local use as macro argument - argument expanded 1", "TODO", Abort);
|
||||
const bool clangCodeModel = CppTools::CppModelManager::instance()->isClangCodeModelActive();
|
||||
if (clangCodeModel) {
|
||||
QEXPECT_FAIL("local use as macro argument - argument eaten", "fails with CCM, find out why",
|
||||
Abort);
|
||||
} else {
|
||||
QEXPECT_FAIL("non-local use as macro argument - argument expanded 1", "TODO", Abort);
|
||||
}
|
||||
QVERIFY(!hasTimedOut);
|
||||
// foreach (const Selection &selection, selections)
|
||||
// qDebug() << QTest::toString(selection);
|
||||
QEXPECT_FAIL("non-local use as macro argument - argument expanded 2", "TODO", Abort);
|
||||
if (!clangCodeModel)
|
||||
QEXPECT_FAIL("non-local use as macro argument - argument expanded 2", "TODO", Abort);
|
||||
QCOMPARE(selections, expectedSelections);
|
||||
}
|
||||
|
||||
|
@@ -28,13 +28,18 @@
|
||||
#include "cppeditorplugin.h"
|
||||
#include "cppeditortestcase.h"
|
||||
|
||||
#include <cpptools/cppcodemodelsettings.h>
|
||||
#include <cpptools/cppelementevaluator.h>
|
||||
#include <cpptools/cppfollowsymbolundercursor.h>
|
||||
#include <cpptools/cppvirtualfunctionassistprovider.h>
|
||||
#include <cpptools/cppvirtualfunctionproposalitem.h>
|
||||
#include <cpptools/cpptoolsreuse.h>
|
||||
#include <cpptools/cpptoolstestcase.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
|
||||
#include <texteditor/codeassist/genericproposalmodel.h>
|
||||
#include <texteditor/codeassist/iassistprocessor.h>
|
||||
#include <texteditor/codeassist/iassistproposal.h>
|
||||
@@ -76,6 +81,7 @@ using namespace CPlusPlus;
|
||||
using namespace CppTools;
|
||||
using namespace TextEditor;
|
||||
using namespace Core;
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
class OverrideItem {
|
||||
public:
|
||||
@@ -267,6 +273,8 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
{
|
||||
QVERIFY(succeededSoFar());
|
||||
|
||||
setUseClangd();
|
||||
|
||||
// Check if there are initial and target position markers
|
||||
TestDocumentPtr initialTestFile = testFileWithInitialCursorMarker(testFiles);
|
||||
QVERIFY2(initialTestFile,
|
||||
@@ -275,13 +283,68 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
QVERIFY2(targetTestFile,
|
||||
"No test file with target cursor marker is provided.");
|
||||
|
||||
const QString curTestName = QLatin1String(QTest::currentTestFunction());
|
||||
const QString tag = QLatin1String(QTest::currentDataTag());
|
||||
const bool useClangd = CppTools::codeModelSettings()->useClangd();
|
||||
if (useClangd) {
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall"
|
||||
|| curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall_multipleDocuments") {
|
||||
QSKIP("TODO: Add test infrastructure for this");
|
||||
}
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_QObject_connect"
|
||||
|| curTestName == "test_FollowSymbolUnderCursor_QObject_oldStyleConnect") {
|
||||
QSKIP("TODO: Implement fall-back");
|
||||
}
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_classOperator" && tag == "backward")
|
||||
QSKIP("clangd goes to operator name first");
|
||||
if (tag.toLower().contains("fuzzy"))
|
||||
QSKIP("fuzzy matching is not supposed to work with clangd"); // TODO: Implement fallback as we do with libclang
|
||||
if (tag == "baseClassFunctionIntroducedByUsingDeclaration")
|
||||
QSKIP("clangd points to the using declaration");
|
||||
if (tag == "classDestructor")
|
||||
QSKIP("clangd wants the cursor before the ~ character");
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_classOperator_inOp")
|
||||
QSKIP("clangd goes to operator name first");
|
||||
if (tag == "fromFunctionBody" || tag == "fromReturnType"
|
||||
|| tag == "conversionOperatorDecl2Def") {
|
||||
QSKIP("TODO: explicit decl/def switch not yet supported with clangd");
|
||||
}
|
||||
}
|
||||
|
||||
// Write files to disk
|
||||
CppTools::Tests::TemporaryDir temporaryDir;
|
||||
QVERIFY(temporaryDir.isValid());
|
||||
QString projectFileContent = "CppApplication { files: [";
|
||||
foreach (TestDocumentPtr testFile, testFiles) {
|
||||
QVERIFY(testFile->baseDirectory().isEmpty());
|
||||
testFile->setBaseDirectory(temporaryDir.path());
|
||||
QVERIFY(testFile->writeToDisk());
|
||||
projectFileContent += QString::fromLatin1("\"%1\",").arg(testFile->filePath());
|
||||
}
|
||||
projectFileContent += "]}\n";
|
||||
|
||||
class ProjectCloser {
|
||||
public:
|
||||
void setProject(Project *p) { m_p = p; }
|
||||
~ProjectCloser() { if (m_p) ProjectExplorerPlugin::unloadProject(m_p); }
|
||||
private:
|
||||
Project * m_p = nullptr;
|
||||
} projectCloser;
|
||||
|
||||
if (useClangd) {
|
||||
TestDocument projectFile(projectFileContent.toUtf8(), "project.qbs");
|
||||
projectFile.setBaseDirectory(temporaryDir.path());
|
||||
QVERIFY(projectFile.writeToDisk());
|
||||
const auto openProjectResult = ProjectExplorerPlugin::openProject(projectFile.filePath());
|
||||
QVERIFY2(openProjectResult && openProjectResult.project(),
|
||||
qPrintable(openProjectResult.errorMessage()));
|
||||
projectCloser.setProject(openProjectResult.project());
|
||||
openProjectResult.project()->configureAsExampleProject(
|
||||
CppEditorPlugin::instance()->m_testKit);
|
||||
|
||||
// Wait until project is fully indexed.
|
||||
QVERIFY(CppTools::Tests::waitForSignalOrTimeout(openProjectResult.project(),
|
||||
&Project::indexingFinished, CppTools::Tests::clangdIndexingTimeout()));
|
||||
}
|
||||
|
||||
// Update Code Model
|
||||
@@ -294,7 +357,8 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
foreach (TestDocumentPtr testFile, testFiles) {
|
||||
QVERIFY(openCppEditor(testFile->filePath(), &testFile->m_editor,
|
||||
&testFile->m_editorWidget));
|
||||
closeEditorAtEndOfTestCase(testFile->m_editor);
|
||||
if (!useClangd) // Editors get closed when unloading project.
|
||||
closeEditorAtEndOfTestCase(testFile->m_editor);
|
||||
|
||||
// Wait until the indexer processed the just opened file.
|
||||
// The file is "Full Checked" since it is in the working copy now,
|
||||
@@ -303,13 +367,16 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
const Document::Ptr document = waitForFileInGlobalSnapshot(testFile->filePath());
|
||||
QVERIFY(document);
|
||||
if (document->checkMode() == Document::FullCheck) {
|
||||
if (!document->diagnosticMessages().isEmpty())
|
||||
qDebug() << document->diagnosticMessages().first().text();
|
||||
QVERIFY(document->diagnosticMessages().isEmpty());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Rehighlight
|
||||
waitForRehighlightedSemanticDocument(testFile->m_editorWidget);
|
||||
if (!useClangd)
|
||||
waitForRehighlightedSemanticDocument(testFile->m_editorWidget);
|
||||
}
|
||||
|
||||
// Activate editor of initial test file
|
||||
@@ -329,14 +396,8 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
FollowSymbolInterface &delegate = CppModelManager::instance()->followSymbolInterface();
|
||||
auto* builtinFollowSymbol = dynamic_cast<FollowSymbolUnderCursor *>(&delegate);
|
||||
if (!builtinFollowSymbol) {
|
||||
if (filePaths.size() > 1)
|
||||
QSKIP("Clang FollowSymbol does not currently support multiple files (except cpp+header)");
|
||||
const QString curTestName = QLatin1String(QTest::currentTestFunction());
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_QObject_connect"
|
||||
|| curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall"
|
||||
|| curTestName == "test_FollowSymbolUnderCursor_QTCREATORBUG7903") {
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_QTCREATORBUG7903")
|
||||
QSKIP((curTestName + " is not supported by Clang FollowSymbol").toLatin1());
|
||||
}
|
||||
|
||||
widget->openLinkUnderCursor();
|
||||
break;
|
||||
@@ -358,14 +419,24 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
break;
|
||||
}
|
||||
case SwitchBetweenMethodDeclarationDefinitionAction:
|
||||
CppEditorPlugin::instance()->switchDeclarationDefinition();
|
||||
if (CppTools::codeModelSettings()->useClangd())
|
||||
initialTestFile->m_editorWidget->openLinkUnderCursor();
|
||||
else
|
||||
CppEditorPlugin::instance()->switchDeclarationDefinition();
|
||||
break;
|
||||
default:
|
||||
QFAIL("Unknown test action");
|
||||
break;
|
||||
}
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
if (useClangd) {
|
||||
QEXPECT_FAIL("infiniteLoopLocalTypedef_QTCREATORBUG-11999",
|
||||
"clangd bug: Go to definition does not return", Abort);
|
||||
QVERIFY(CppTools::Tests::waitForSignalOrTimeout(EditorManager::instance(),
|
||||
&EditorManager::linkOpened, 10000));
|
||||
} else {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
// Compare
|
||||
IEditor *currentEditor = EditorManager::currentEditor();
|
||||
@@ -379,8 +450,11 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
// qDebug() << "Expected line:" << expectedLine;
|
||||
// qDebug() << "Expected column:" << expectedColumn;
|
||||
|
||||
QEXPECT_FAIL("globalVarFromEnum", "Contributor works on a fix.", Abort);
|
||||
QEXPECT_FAIL("matchFunctionSignature_Follow_5", "foo(int) resolved as CallAST", Abort);
|
||||
if (!CppTools::codeModelSettings()->useClangd()) {
|
||||
QEXPECT_FAIL("globalVarFromEnum", "Contributor works on a fix.", Abort);
|
||||
QEXPECT_FAIL("matchFunctionSignature_Follow_5", "foo(int) resolved as CallAST", Abort);
|
||||
}
|
||||
|
||||
QCOMPARE(currentTextEditor->currentLine(), expectedLine);
|
||||
QCOMPARE(currentTextEditor->currentColumn(), expectedColumn);
|
||||
|
||||
@@ -421,6 +495,25 @@ Q_DECLARE_METATYPE(QList<CppEditor::Internal::TestDocumentPtr>)
|
||||
namespace CppEditor {
|
||||
namespace Internal {
|
||||
|
||||
void CppEditorPlugin::initTestCase()
|
||||
{
|
||||
const auto settings = CppTools::codeModelSettings();
|
||||
const QString clangdFromEnv = qEnvironmentVariable("QTC_CLANGD");
|
||||
if (clangdFromEnv.isEmpty())
|
||||
return;
|
||||
settings->setClangdFilePath(Utils::FilePath::fromString(clangdFromEnv));
|
||||
const auto clangd = settings->clangdFilePath();
|
||||
if (clangd.isEmpty() || !clangd.exists())
|
||||
return;
|
||||
|
||||
// Find suitable kit.
|
||||
m_testKit = Utils::findOr(KitManager::kits(), nullptr, [](const Kit *k) {
|
||||
return k->isValid();
|
||||
});
|
||||
if (!m_testKit)
|
||||
QSKIP("This test requires at least one kit to be present");
|
||||
}
|
||||
|
||||
void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("header");
|
||||
@@ -576,7 +669,6 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data()
|
||||
"int OtherClass::var;\n"
|
||||
"namespace NS {\n"
|
||||
"int OtherClass::var;\n"
|
||||
"float Test::var;\n"
|
||||
"int Test::$var;\n"
|
||||
"}\n");
|
||||
|
||||
@@ -1276,7 +1368,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data()
|
||||
"int OtherClass::var;\n"
|
||||
"namespace NS {\n"
|
||||
"int OtherClass::var;\n"
|
||||
"float Test::var;\n"
|
||||
"int Test::$var;\n"
|
||||
"}\n", "file.cpp")};
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include <cplusplus/CppDocument.h>
|
||||
#include <utils/executeondestruction.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QtTest>
|
||||
@@ -421,5 +422,15 @@ bool VerifyCleanCppModelManager::isClean(bool testOnlyForCleanedProjects)
|
||||
|
||||
#undef RETURN_FALSE_IF_NOT
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace Tests
|
||||
} // namespace CppTools
|
||||
|
@@ -30,7 +30,9 @@
|
||||
#include <cplusplus/CppDocument.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
namespace CPlusPlus {
|
||||
class Document;
|
||||
@@ -54,6 +56,23 @@ class ProjectInfo;
|
||||
|
||||
namespace Tests {
|
||||
|
||||
int CPPTOOLS_EXPORT clangdIndexingTimeout();
|
||||
|
||||
template <typename Signal> inline bool waitForSignalOrTimeout(
|
||||
const typename QtPrivate::FunctionPointer<Signal>::Object *sender, Signal signal,
|
||||
int timeoutInMs)
|
||||
{
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
timer.setInterval(timeoutInMs);
|
||||
QEventLoop loop;
|
||||
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
||||
QObject::connect(sender, signal, &loop, &QEventLoop::quit);
|
||||
timer.start();
|
||||
loop.exec();
|
||||
return timer.isActive();
|
||||
}
|
||||
|
||||
class CPPTOOLS_EXPORT TestDocument
|
||||
{
|
||||
public:
|
||||
|
@@ -212,6 +212,10 @@ signals:
|
||||
|
||||
void rootProjectDirectoryChanged();
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void indexingFinished(Utils::Id indexer);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage);
|
||||
void createTargetFromMap(const QVariantMap &map, int index);
|
||||
|
@@ -6257,6 +6257,10 @@ void TextEditorWidget::findLinkAt(const QTextCursor &cursor,
|
||||
|
||||
bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit)
|
||||
{
|
||||
#ifdef WITH_TESTS
|
||||
struct Signaller { ~Signaller() { emit EditorManager::instance()->linkOpened(); } } s;
|
||||
#endif
|
||||
|
||||
if (!link.hasValidTarget())
|
||||
return false;
|
||||
|
||||
|
Reference in New Issue
Block a user