1 /*
2     SPDX-FileCopyrightText: 2017 Kevin Funk <kfunk@kde.org>
3 
4     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6 
7 #include "test_refactoring.h"
8 
9 #include <tests/testcore.h>
10 #include <tests/autotestshell.h>
11 #include <tests/testfile.h>
12 #include <tests/testproject.h>
13 #include <interfaces/ilanguagecontroller.h>
14 
15 #include "codegen/clangrefactoring.h"
16 
17 #include <language/duchain/duchainlock.h>
18 #include <language/duchain/declaration.h>
19 #include <language/interfaces/ilanguagesupport.h>
20 
21 #include <QTemporaryDir>
22 #include <QLoggingCategory>
23 #include <QTest>
24 
25 QTEST_MAIN(TestRefactoring)
26 
27 using namespace KDevelop;
28 
29 TestRefactoring::~TestRefactoring() = default;
30 
initTestCase()31 void TestRefactoring::initTestCase()
32 {
33     QLoggingCategory::setFilterRules(QStringLiteral("*.debug=false\ndefault.debug=true\nkdevelop.plugins.clang.debug=true\n"));
34 
35     QVERIFY(qputenv("KDEV_CLANG_DISPLAY_DIAGS", "1"));
36 
37     AutoTestShell::init({QStringLiteral("kdevclangsupport")});
38 
39     auto core = TestCore::initialize();
40     delete core->projectController();
41     m_projectController = new TestProjectController(core);
42     core->setProjectController(m_projectController);
43 }
44 
cleanupTestCase()45 void TestRefactoring::cleanupTestCase()
46 {
47     TestCore::shutdown();
48 }
49 
testClassRename()50 void TestRefactoring::testClassRename()
51 {
52     const QString codeBefore(QStringLiteral(R"(
53 class Foo {
54 public:
55     Foo();
56     ~Foo();
57 };
58 Foo::Foo() {
59 }
60 Foo::~Foo() {
61 }
62     )"));
63 
64     const QString codeAfter(QStringLiteral(R"(
65 class FooNew {
66 public:
67     FooNew();
68     ~FooNew();
69 };
70 FooNew::FooNew() {
71 }
72 FooNew::~FooNew() {
73 }
74     )"));
75 
76     QTemporaryDir dir;
77     auto project = new TestProject(Path(dir.path()), this);
78     m_projectController->addProject(project);
79 
80     TestFile file(codeBefore, QStringLiteral("cpp"), project, dir.path());
81     QVERIFY(file.parseAndWait(TopDUContext::AllDeclarationsContextsAndUses));
82 
83     DUChainReadLocker lock;
84 
85     auto top = file.topContext();
86     QVERIFY(top);
87 
88     auto declaration = top->localDeclarations().first();
89     QVERIFY(declaration);
90 
91     const QString originalName = declaration->identifier().identifier().str();
92     const QString newName = QStringLiteral("FooNew");
93 
94     QSharedPointer<BasicRefactoringCollector> collector(new BasicRefactoringCollector(declaration));
95 
96     // TODO: Do this without GUI?
97     UsesWidget uses(declaration, collector);
98     lock.unlock();
99 
100     for (int i = 0; i < 30000; i += 1000) {
101         if (collector->isReady()) {
102             break;
103         }
104         QTest::qWait(1000);
105     }
106     QVERIFY(collector->isReady());
107 
108     BasicRefactoring::NameAndCollector nameAndCollector{newName, collector};
109 
110     auto languages = ICore::self()->languageController()->languagesForUrl(file.url().toUrl());
111     QVERIFY(!languages.isEmpty());
112     auto clangLanguageSupport = languages.first();
113     QVERIFY(clangLanguageSupport);
114     auto clangRefactoring = qobject_cast<ClangRefactoring*>(clangLanguageSupport->refactoring());
115     QVERIFY(clangRefactoring);
116 
117     clangRefactoring->renameCollectedDeclarations(nameAndCollector.collector.data(), newName, originalName);
118     QCOMPARE(file.fileContents(), codeAfter);
119 
120     m_projectController->closeAllProjects();
121 }
122 
123