1 /*
2 SPDX-FileCopyrightText: 2010 Niko Sams <niko.sams@gmail.com>
3 SPDX-FileCopyrightText: 2011 Milian Wolff <mail@milianw.de>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6 */
7
8 #include "testfile.h"
9
10 #include "testproject.h"
11
12 #include <QTemporaryFile>
13 #include <QElapsedTimer>
14 #include <QTest>
15
16 #include <language/duchain/duchainlock.h>
17 #include <language/duchain/duchain.h>
18 #include <language/backgroundparser/backgroundparser.h>
19 #include <interfaces/icore.h>
20 #include <interfaces/idocumentcontroller.h>
21 #include <interfaces/ilanguagecontroller.h>
22 #include <project/projectmodel.h>
23
24 using namespace KDevelop;
25
26 class KDevelop::TestFilePrivate
27 {
28 public:
TestFilePrivate()29 TestFilePrivate()
30 {
31 }
32
updateReady(const IndexedString & _url,const ReferencedTopDUContext & _topContext)33 void updateReady(const IndexedString& _url, const ReferencedTopDUContext& _topContext)
34 {
35 Q_ASSERT(_url == url);
36 Q_UNUSED(_url);
37 topContext = _topContext;
38 ready = true;
39 }
40
init(const QString & fileName,const QString & contents,TestProject * _project)41 void init(const QString& fileName, const QString& contents, TestProject* _project)
42 {
43 file = fileName;
44
45 setFileContents(contents);
46
47 QFileInfo info(file);
48 Q_ASSERT(info.exists());
49 Q_ASSERT(info.isFile());
50 url = IndexedString(info.absoluteFilePath());
51
52 project = _project;
53 if (project) {
54 fileItem.reset(new ProjectFileItem(_project, Path(file), _project->projectItem()));
55 }
56 }
57
setFileContents(const QString & contents)58 void setFileContents(const QString& contents)
59 {
60 QFile file(this->file);
61 file.open(QIODevice::WriteOnly | QIODevice::Truncate);
62 Q_ASSERT(file.isOpen());
63 Q_ASSERT(file.isWritable());
64 file.write(contents.toUtf8());
65 ready = false;
66 }
67
68 QString file;
69 QString suffix;
70 bool ready = false;
71 ReferencedTopDUContext topContext;
72 IndexedString url;
73 TestProject* project;
74 QScopedPointer<ProjectFileItem> fileItem;
75 bool keepDUChainData = false;
76 };
77
TestFile(const QString & contents,const QString & fileExtension,TestProject * project,const QString & dir)78 TestFile::TestFile(const QString& contents, const QString& fileExtension,
79 TestProject* project, const QString& dir)
80 : d_ptr(new TestFilePrivate())
81 {
82 Q_D(TestFile);
83
84 d->suffix = QLatin1Char('.') + fileExtension;
85
86 QTemporaryFile file((!dir.isEmpty() ? dir : QDir::tempPath()) + QLatin1String("/testfile_XXXXXX") + d->suffix);
87 file.setAutoRemove(false);
88 file.open();
89 Q_ASSERT(file.isOpen());
90
91 d->init(file.fileName(), contents, project);
92 }
93
TestFile(const QString & contents,const QString & fileExtension,const TestFile * base)94 TestFile::TestFile(const QString& contents, const QString& fileExtension, const TestFile* base)
95 : d_ptr(new TestFilePrivate)
96 {
97 Q_D(TestFile);
98
99 QString fileName = base->d_func()->file.mid(0, base->d_func()->file.length() - base->d_func()->suffix.length());
100 d->suffix = QLatin1Char('.') + fileExtension;
101 fileName += d->suffix;
102 d->init(fileName, contents, base->d_func()->project);
103 }
104
TestFile(const QString & contents,const QString & fileExtension,const QString & fileName,KDevelop::TestProject * project,const QString & dir)105 TestFile::TestFile(const QString& contents, const QString& fileExtension, const QString& fileName,
106 KDevelop::TestProject* project, const QString& dir)
107 : d_ptr(new TestFilePrivate)
108 {
109 Q_D(TestFile);
110
111 d->suffix = QLatin1Char('.') + fileExtension;
112 const QString file = (!dir.isEmpty() ? dir : QDir::tempPath())
113 + QLatin1Char('/') + fileName + d->suffix;
114 d->init(file, contents, project);
115 }
116
117
~TestFile()118 TestFile::~TestFile()
119 {
120 Q_D(TestFile);
121
122 if (auto* document = ICore::self()->documentController()->documentForUrl(d->url.toUrl())) {
123 document->close(KDevelop::IDocument::Discard);
124 }
125
126 auto backgroundParser = ICore::self()->languageController()->backgroundParser();
127 backgroundParser->removeDocument(d->url, this);
128 QTRY_VERIFY(!backgroundParser->parseJobForDocument(d->url));
129
130 if (d->topContext && !d->keepDUChainData) {
131 DUChainWriteLocker lock;
132 DUChain::self()->removeDocumentChain(d->topContext.data());
133 }
134 QFile::remove(d->file);
135 }
136
url() const137 IndexedString TestFile::url() const
138 {
139 Q_D(const TestFile);
140
141 return d->url;
142 }
143
parse(TopDUContext::Features features,int priority)144 void TestFile::parse(TopDUContext::Features features, int priority)
145 {
146 Q_D(TestFile);
147
148 d->ready = false;
149 DUChain::self()->updateContextForUrl(d->url, features, this, priority);
150 }
151
parseAndWait(TopDUContext::Features features,int priority,int timeout)152 bool TestFile::parseAndWait(TopDUContext::Features features, int priority, int timeout)
153 {
154 parse(features, priority);
155 return waitForParsed(timeout);
156 }
157
waitForParsed(int timeout)158 bool TestFile::waitForParsed(int timeout)
159 {
160 Q_D(TestFile);
161
162 if (!d->ready) {
163 // optimize: we don't want to wait the usual timeout before parsing documents here
164 ICore::self()->languageController()->backgroundParser()->parseDocuments();
165 }
166 QElapsedTimer t;
167 t.start();
168 while (!d->ready && t.elapsed() < timeout) {
169 QTest::qWait(10);
170 }
171 return d->ready;
172 }
173
isReady() const174 bool TestFile::isReady() const
175 {
176 Q_D(const TestFile);
177
178 return d->ready;
179 }
180
topContext()181 ReferencedTopDUContext TestFile::topContext()
182 {
183 Q_D(TestFile);
184
185 waitForParsed();
186 return d->topContext;
187 }
188
setFileContents(const QString & contents)189 void TestFile::setFileContents(const QString& contents)
190 {
191 Q_D(TestFile);
192
193 d->setFileContents(contents);
194 }
195
fileContents() const196 QString TestFile::fileContents() const
197 {
198 Q_D(const TestFile);
199
200 QFile file(d->file);
201 file.open(QIODevice::ReadOnly);
202 Q_ASSERT(file.isOpen());
203 Q_ASSERT(file.isReadable());
204 return QString::fromUtf8(file.readAll());
205 }
206
setKeepDUChainData(bool keep)207 void TestFile::setKeepDUChainData(bool keep)
208 {
209 Q_D(TestFile);
210
211 d->keepDUChainData = keep;
212 }
213
keepDUChainData() const214 bool TestFile::keepDUChainData() const
215 {
216 Q_D(const TestFile);
217
218 return d->keepDUChainData;
219 }
220
221 #include "moc_testfile.cpp"
222