File indexing completed on 2024-04-28 04:37:35

0001 /*
0002     SPDX-FileCopyrightText: 2010 Niko Sams <niko.sams@gmail.com>
0003     SPDX-FileCopyrightText: 2011 Milian Wolff <mail@milianw.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "testfile.h"
0009 
0010 #include "testproject.h"
0011 
0012 #include <QTemporaryFile>
0013 #include <QElapsedTimer>
0014 #include <QTest>
0015 
0016 #include <language/duchain/duchainlock.h>
0017 #include <language/duchain/duchain.h>
0018 #include <language/backgroundparser/backgroundparser.h>
0019 #include <interfaces/icore.h>
0020 #include <interfaces/idocumentcontroller.h>
0021 #include <interfaces/ilanguagecontroller.h>
0022 #include <project/projectmodel.h>
0023 
0024 using namespace KDevelop;
0025 
0026 class KDevelop::TestFilePrivate
0027 {
0028 public:
0029     TestFilePrivate()
0030     {
0031     }
0032 
0033     void updateReady(const IndexedString& _url, const ReferencedTopDUContext& _topContext)
0034     {
0035         Q_ASSERT(_url == url);
0036         Q_UNUSED(_url);
0037         topContext = _topContext;
0038         ready = true;
0039     }
0040 
0041     void init(const QString& fileName, const QString& contents, TestProject* _project)
0042     {
0043         file = fileName;
0044 
0045         setFileContents(contents);
0046 
0047         QFileInfo info(file);
0048         Q_ASSERT(info.exists());
0049         Q_ASSERT(info.isFile());
0050         url = IndexedString(info.absoluteFilePath());
0051 
0052         project = _project;
0053         if (project) {
0054             fileItem.reset(new ProjectFileItem(_project, Path(file), _project->projectItem()));
0055         }
0056     }
0057 
0058     void setFileContents(const QString& contents)
0059     {
0060         QFile file(this->file);
0061         file.open(QIODevice::WriteOnly | QIODevice::Truncate);
0062         Q_ASSERT(file.isOpen());
0063         Q_ASSERT(file.isWritable());
0064         file.write(contents.toUtf8());
0065         ready = false;
0066     }
0067 
0068     QString file;
0069     QString suffix;
0070     bool ready = false;
0071     ReferencedTopDUContext topContext;
0072     IndexedString url;
0073     TestProject* project;
0074     QScopedPointer<ProjectFileItem> fileItem;
0075     bool keepDUChainData = false;
0076 };
0077 
0078 TestFile::TestFile(const QString& contents, const QString& fileExtension,
0079                    TestProject* project, const QString& dir)
0080     : d_ptr(new TestFilePrivate())
0081 {
0082     Q_D(TestFile);
0083 
0084     d->suffix = QLatin1Char('.') + fileExtension;
0085 
0086     QTemporaryFile file((!dir.isEmpty() ? dir : QDir::tempPath()) + QLatin1String("/testfile_XXXXXX") + d->suffix);
0087     file.setAutoRemove(false);
0088     file.open();
0089     Q_ASSERT(file.isOpen());
0090 
0091     d->init(file.fileName(), contents, project);
0092 }
0093 
0094 TestFile::TestFile(const QString& contents, const QString& fileExtension, const TestFile* base)
0095     : d_ptr(new TestFilePrivate)
0096 {
0097     Q_D(TestFile);
0098 
0099     QString fileName = base->d_func()->file.mid(0, base->d_func()->file.length() - base->d_func()->suffix.length());
0100     d->suffix = QLatin1Char('.') + fileExtension;
0101     fileName += d->suffix;
0102     d->init(fileName, contents, base->d_func()->project);
0103 }
0104 
0105 TestFile::TestFile(const QString& contents, const QString& fileExtension, const QString& fileName,
0106                    KDevelop::TestProject* project, const QString& dir)
0107     : d_ptr(new TestFilePrivate)
0108 {
0109     Q_D(TestFile);
0110 
0111     d->suffix = QLatin1Char('.') + fileExtension;
0112     const QString file = (!dir.isEmpty() ? dir : QDir::tempPath())
0113                     + QLatin1Char('/') + fileName + d->suffix;
0114     d->init(file, contents, project);
0115 }
0116 
0117 
0118 TestFile::~TestFile()
0119 {
0120     Q_D(TestFile);
0121 
0122     if (auto* document = ICore::self()->documentController()->documentForUrl(d->url.toUrl())) {
0123         document->close(KDevelop::IDocument::Discard);
0124     }
0125 
0126     auto backgroundParser = ICore::self()->languageController()->backgroundParser();
0127     backgroundParser->removeDocument(d->url, this);
0128     QTRY_VERIFY(!backgroundParser->parseJobForDocument(d->url));
0129 
0130     if (d->topContext && !d->keepDUChainData) {
0131         DUChainWriteLocker lock;
0132         DUChain::self()->removeDocumentChain(d->topContext.data());
0133     }
0134     QFile::remove(d->file);
0135 }
0136 
0137 IndexedString TestFile::url() const
0138 {
0139     Q_D(const TestFile);
0140 
0141     return d->url;
0142 }
0143 
0144 void TestFile::parse(TopDUContext::Features features, int priority)
0145 {
0146     Q_D(TestFile);
0147 
0148     d->ready = false;
0149     DUChain::self()->updateContextForUrl(d->url, features, this, priority);
0150 }
0151 
0152 bool TestFile::parseAndWait(TopDUContext::Features features, int priority, int timeout)
0153 {
0154     parse(features, priority);
0155     return waitForParsed(timeout);
0156 }
0157 
0158 bool TestFile::waitForParsed(int timeout)
0159 {
0160     Q_D(TestFile);
0161 
0162     if (!d->ready) {
0163         // optimize: we don't want to wait the usual timeout before parsing documents here
0164         ICore::self()->languageController()->backgroundParser()->parseDocuments();
0165     }
0166     QElapsedTimer t;
0167     t.start();
0168     while (!d->ready && t.elapsed() < timeout) {
0169         QTest::qWait(10);
0170     }
0171     return d->ready;
0172 }
0173 
0174 bool TestFile::isReady() const
0175 {
0176     Q_D(const TestFile);
0177 
0178     return d->ready;
0179 }
0180 
0181 ReferencedTopDUContext TestFile::topContext()
0182 {
0183     Q_D(TestFile);
0184 
0185     waitForParsed();
0186     return d->topContext;
0187 }
0188 
0189 void TestFile::setFileContents(const QString& contents)
0190 {
0191     Q_D(TestFile);
0192 
0193     d->setFileContents(contents);
0194 }
0195 
0196 QString TestFile::fileContents() const
0197 {
0198     Q_D(const TestFile);
0199 
0200     QFile file(d->file);
0201     file.open(QIODevice::ReadOnly);
0202     Q_ASSERT(file.isOpen());
0203     Q_ASSERT(file.isReadable());
0204     return QString::fromUtf8(file.readAll());
0205 }
0206 
0207 void TestFile::setKeepDUChainData(bool keep)
0208 {
0209     Q_D(TestFile);
0210 
0211     d->keepDUChainData = keep;
0212 }
0213 
0214 bool TestFile::keepDUChainData() const
0215 {
0216     Q_D(const TestFile);
0217 
0218     return d->keepDUChainData;
0219 }
0220 
0221 #include "moc_testfile.cpp"