mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-27 04:13:05 +00:00
368 lines
12 KiB
C++
368 lines
12 KiB
C++
/* This file is part of KDevelop
|
|
Copyright 2010 Niko Sams <niko.sams@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "reloadtest.h"
|
|
|
|
#include <qtest_kde.h>
|
|
#include <KDebug>
|
|
#include <KTempDir>
|
|
|
|
#include <tests/autotestshell.h>
|
|
#include <tests/testcore.h>
|
|
|
|
#include <interfaces/icore.h>
|
|
#include <interfaces/iprojectcontroller.h>
|
|
#include <interfaces/iproject.h>
|
|
#include <interfaces/ilanguagecontroller.h>
|
|
|
|
#include <project/interfaces/iprojectfilemanager.h>
|
|
#include <project/projectmodel.h>
|
|
#include <language/backgroundparser/backgroundparser.h>
|
|
|
|
QTEST_KDEMAIN(ProjectLoadTest, GUI)
|
|
|
|
Q_DECLARE_METATYPE(KDevelop::IProject*);
|
|
|
|
///FIXME: get rid of this, use temporary dir+file classes!
|
|
void exec(const QString &cmd)
|
|
{
|
|
QProcess proc;
|
|
proc.setProcessChannelMode(QProcess::ForwardedChannels);
|
|
proc.start(cmd);
|
|
proc.waitForFinished();
|
|
Q_ASSERT(proc.exitStatus() == QProcess::NormalExit);
|
|
Q_ASSERT(proc.exitStatus() == 0);
|
|
}
|
|
|
|
void ProjectLoadTest::initTestCase()
|
|
{
|
|
KDevelop::AutoTestShell::init();
|
|
KDevelop::TestCore::initialize();
|
|
KDevelop::ICore::self()->languageController()->backgroundParser()->disableProcessing();
|
|
|
|
qRegisterMetaType<KDevelop::IProject*>("KDevelop::IProject*");
|
|
|
|
foreach(KDevelop::IProject* p, KDevelop::ICore::self()->projectController()->projects()) {
|
|
KDevelop::ICore::self()->projectController()->closeProject(p);
|
|
}
|
|
}
|
|
|
|
void ProjectLoadTest::cleanupTestCase()
|
|
{
|
|
KDevelop::TestCore::shutdown();
|
|
}
|
|
|
|
void ProjectLoadTest::init()
|
|
{
|
|
Q_ASSERT(KDevelop::ICore::self()->projectController()->projects().isEmpty());
|
|
}
|
|
|
|
struct TestProject
|
|
{
|
|
// temp directory of project
|
|
KTempDir* dir;
|
|
// name of the project (random)
|
|
QString name;
|
|
// project file (*.kdev4)
|
|
KUrl file;
|
|
~TestProject() {
|
|
KDevelop::IProject* p = KDevelop::ICore::self()->projectController()->findProjectByName(name);
|
|
if (p) {
|
|
KDevelop::ICore::self()->projectController()->closeProject(p);
|
|
}
|
|
delete dir;
|
|
}
|
|
};
|
|
|
|
TestProject makeProject()
|
|
{
|
|
TestProject ret;
|
|
ret.dir = new KTempDir();
|
|
QFileInfo dir(ret.dir->name().left(ret.dir->name().length() - 1));
|
|
Q_ASSERT(dir.exists());
|
|
ret.name = dir.fileName();
|
|
|
|
QStringList projectFileContents;
|
|
projectFileContents
|
|
<< "[Project]"
|
|
<< QString("Name=") + ret.name
|
|
<< "Manager=KDevGenericManager";
|
|
|
|
KUrl projecturl( dir.absoluteFilePath() + "/simpleproject.kdev4" );
|
|
QFile projectFile(projecturl.toLocalFile());
|
|
projectFile.open(QIODevice::WriteOnly);
|
|
projectFile.write(projectFileContents.join("\n").toAscii());
|
|
projectFile.close();
|
|
ret.file = projecturl;
|
|
|
|
Q_ASSERT(ret.dir->exists());
|
|
Q_ASSERT(projecturl.upUrl().toLocalFile() == ret.dir->name());
|
|
|
|
return ret;
|
|
}
|
|
|
|
void ProjectLoadTest::addRemoveFiles()
|
|
{
|
|
const TestProject p = makeProject();
|
|
|
|
QFile f(p.dir->name()+"/sdf");
|
|
f.open(QIODevice::WriteOnly);
|
|
f.close();
|
|
|
|
KDevelop::ICore::self()->projectController()->openProject(p.file);
|
|
QVERIFY(QTest::kWaitForSignal(KDevelop::ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), 2000));
|
|
KDevelop::IProject* project = KDevelop::ICore::self()->projectController()->projects().first();
|
|
QCOMPARE(project->projectFileUrl(), p.file);
|
|
|
|
//KDirWatch adds/removes the file automatically
|
|
for (int i=0; i<100; ++i) {
|
|
QFile f2(p.dir->name()+"/blub"+QString::number(i));
|
|
f2.open(QIODevice::WriteOnly);
|
|
f2.close();
|
|
}
|
|
for (int i=0; i<50; ++i) {
|
|
QFile f2(p.dir->name()+"/blub"+QString::number(i));
|
|
QVERIFY(f2.exists());
|
|
f2.remove();
|
|
}
|
|
QTest::qWait(500);
|
|
|
|
KUrl url(p.dir->name()+"/blub"+QString::number(50));
|
|
url.cleanPath();
|
|
QCOMPARE(project->filesForUrl(url).count(), 1);
|
|
KDevelop::ProjectFileItem* file = project->filesForUrl(url).first();
|
|
project->projectFileManager()->removeFilesAndFolders(QList<KDevelop::ProjectBaseItem*>() << file ); //message box has to be accepted manually :(
|
|
for (int i=51; i<100; ++i) {
|
|
QFile f2(p.dir->name()+"/blub"+QString::number(i));
|
|
f2.remove();
|
|
}
|
|
|
|
QTest::qWait(2000);
|
|
QCOMPARE(project->fileCount(), 1);
|
|
}
|
|
|
|
void ProjectLoadTest::removeDirRecursive()
|
|
{
|
|
const TestProject p = makeProject();
|
|
|
|
{
|
|
QFile f(p.dir->name()+"/sdf");
|
|
f.open(QIODevice::WriteOnly);
|
|
f.close();
|
|
}
|
|
{
|
|
QDir(p.dir->name()).mkdir("blub");
|
|
for (int i=0; i<10; ++i) {
|
|
QFile f(p.dir->name()+"/blub/file"+QString::number(i));
|
|
f.open(QIODevice::WriteOnly);
|
|
f.close();
|
|
}
|
|
}
|
|
|
|
//close previously opened projects
|
|
QTest::qWait(1000); //wait for projects to load
|
|
foreach ( KDevelop::IProject* p, KDevelop::ICore::self()->projectController()->projects()) {
|
|
KDevelop::ICore::self()->projectController()->closeProject(p);
|
|
QTest::qWait(100);
|
|
}
|
|
QVERIFY(KDevelop::ICore::self()->projectController()->projects().isEmpty());
|
|
|
|
KDevelop::ICore::self()->projectController()->openProject(p.file);
|
|
QVERIFY(QTest::kWaitForSignal(KDevelop::ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), 20000));
|
|
KDevelop::IProject* project = KDevelop::ICore::self()->projectController()->projects().first();
|
|
QCOMPARE(project->projectFileUrl(), p.file);
|
|
|
|
for (int i=0; i<1; ++i) {
|
|
KUrl url(p.dir->name()+"/blub");
|
|
url.cleanPath();
|
|
QCOMPARE(project->foldersForUrl(url).count(), 1);
|
|
|
|
KDevelop::ProjectFolderItem* file = project->foldersForUrl(url).first();
|
|
project->projectFileManager()->removeFilesAndFolders(QList<KDevelop::ProjectBaseItem*>() << file );
|
|
}
|
|
|
|
QTest::qWait(2000);
|
|
QCOMPARE(project->fileCount(), 1);
|
|
}
|
|
|
|
void createFile(const QString& path)
|
|
{
|
|
QFile f(path);
|
|
f.open(QIODevice::WriteOnly);
|
|
f.write(QByteArray::number(qrand()));
|
|
f.write(QByteArray::number(qrand()));
|
|
f.write(QByteArray::number(qrand()));
|
|
f.write(QByteArray::number(qrand()));
|
|
f.close();
|
|
}
|
|
|
|
void _writeRandomStructure(QString path, int files)
|
|
{
|
|
QDir p(path);
|
|
QString name = QString::number(qrand());
|
|
if (qrand() < RAND_MAX / 5) {
|
|
p.mkdir(name);
|
|
path += '/' + name;
|
|
// kDebug() << "wrote path" << path;
|
|
} else {
|
|
createFile(path+'/'+name);
|
|
// kDebug() << "wrote file" << path+"/"+name;
|
|
}
|
|
files--;
|
|
if (files > 0) {
|
|
_writeRandomStructure(path, files);
|
|
}
|
|
}
|
|
|
|
void fillProject(int filesPerDir, int dirs, const TestProject& project, bool wait)
|
|
{
|
|
for(int i=0; i < dirs; ++i) {
|
|
const QString name = "foox" + QString::number(i);
|
|
QDir(project.dir->name()).mkdir(name);
|
|
_writeRandomStructure(project.dir->name() + name, filesPerDir);
|
|
if (wait) {
|
|
QTest::qWait(100);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProjectLoadTest::addLotsOfFiles()
|
|
{
|
|
TestProject p = makeProject();
|
|
|
|
KDevelop::ICore::self()->projectController()->openProject(p.file);
|
|
QVERIFY(QTest::kWaitForSignal(KDevelop::ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), 2000));
|
|
QCOMPARE(KDevelop::ICore::self()->projectController()->projects().size(), 1);
|
|
KDevelop::IProject* project = KDevelop::ICore::self()->projectController()->projects().first();
|
|
QCOMPARE(project->projectFileUrl(), p.file);
|
|
|
|
fillProject(50, 25, p, true);
|
|
|
|
QTest::qWait(2000);
|
|
}
|
|
|
|
void ProjectLoadTest::addMultipleJobs()
|
|
{
|
|
const TestProject p1 = makeProject();
|
|
fillProject(10, 25, p1, false);
|
|
const TestProject p2 = makeProject();
|
|
fillProject(10, 25, p2, false);
|
|
|
|
QSignalSpy spy(KDevelop::ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)));
|
|
KDevelop::ICore::self()->projectController()->openProject(p1.file);
|
|
KDevelop::ICore::self()->projectController()->openProject(p2.file);
|
|
|
|
const int wait = 25;
|
|
const int maxWait = 2000;
|
|
int waited = 0;
|
|
while(waited < maxWait && spy.count() != 2) {
|
|
QTest::qWait(wait);
|
|
waited += wait;
|
|
}
|
|
|
|
QCOMPARE(KDevelop::ICore::self()->projectController()->projects().size(), 2);
|
|
}
|
|
|
|
void ProjectLoadTest::raceJob()
|
|
{
|
|
// our goal here is to try to reproduce https://bugs.kde.org/show_bug.cgi?id=260741
|
|
// my idea is that this can be triggered by the following:
|
|
// - list dir foo/bar containing lots of files
|
|
// - remove dir foo while listjob is still running
|
|
TestProject p = makeProject();
|
|
QDir dir(p.dir->name());
|
|
QVERIFY(dir.mkpath("test/zzzzz"));
|
|
for(int i = 0; i < 1000; ++i) {
|
|
createFile(QString(p.dir->name() + "/test/zzzzz/%1").arg(i));
|
|
createFile(QString(p.dir->name() + "/test/%1").arg(i));
|
|
}
|
|
|
|
KDevelop::ICore::self()->projectController()->openProject(p.file);
|
|
QVERIFY(QTest::kWaitForSignal(KDevelop::ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), 2000));
|
|
|
|
QCOMPARE(KDevelop::ICore::self()->projectController()->projectCount(), 1);
|
|
KDevelop::IProject *project = KDevelop::ICore::self()->projectController()->projectAt(0);
|
|
QCOMPARE(project->projectFileUrl(), p.file);
|
|
KDevelop::ProjectFolderItem* root = project->projectItem();
|
|
QCOMPARE(root->rowCount(), 1);
|
|
KDevelop::ProjectBaseItem* testItem = root->child(0);
|
|
QVERIFY(testItem->folder());
|
|
QCOMPARE(testItem->baseName(), QString("test"));
|
|
QCOMPARE(testItem->rowCount(), 1001);
|
|
KDevelop::ProjectBaseItem* asdfItem = testItem->children().last();
|
|
QVERIFY(asdfItem->folder());
|
|
|
|
// move dir
|
|
dir.rename("test", "test2");
|
|
// move sub dir
|
|
dir.rename("test2/zzzzz", "test2/bla");
|
|
|
|
QTest::qWait(500);
|
|
QCOMPARE(root->rowCount(), 1);
|
|
testItem = root->child(0);
|
|
QVERIFY(testItem->folder());
|
|
QCOMPARE(testItem->baseName(), QString("test2"));
|
|
}
|
|
|
|
void ProjectLoadTest::addDuringImport()
|
|
{
|
|
// our goal here is to try to reproduce an issue in the optimized filesForUrl implementation
|
|
// which requires the project to be associated to the model to function properly
|
|
// to trigger this we create a big project, import it and then call filesForUrl during
|
|
// the import action
|
|
TestProject p = makeProject();
|
|
QDir dir(p.dir->name());
|
|
QVERIFY(dir.mkpath("test/zzzzz"));
|
|
for(int i = 0; i < 1000; ++i) {
|
|
createFile(QString(p.dir->name() + "/test/zzzzz/%1").arg(i));
|
|
createFile(QString(p.dir->name() + "/test/%1").arg(i));
|
|
}
|
|
|
|
QSignalSpy spy(KDevelop::ICore::self()->projectController(), SIGNAL(projectAboutToBeOpened(KDevelop::IProject*)));
|
|
KDevelop::ICore::self()->projectController()->openProject(p.file);
|
|
// not yet ready
|
|
QCOMPARE(KDevelop::ICore::self()->projectController()->projectCount(), 0);
|
|
// but about to be opened
|
|
QCOMPARE(spy.count(), 1);
|
|
KDevelop::IProject* project = spy.value(0).first().value<KDevelop::IProject*>();
|
|
QVERIFY(project);
|
|
QCOMPARE(project->folder(), p.file.upUrl());
|
|
KUrl file(p.file, "test/zzzzz/999");
|
|
QVERIFY(QFile::exists(file.toLocalFile()));
|
|
// this most probably is not yet loaded
|
|
// and this should not crash
|
|
QCOMPARE(project->itemsForUrl(file).size(), 0);
|
|
// now delete that file and don't crash
|
|
QFile::remove(file.toLocalFile());
|
|
// now create another file
|
|
KUrl file2 = file;
|
|
file2.setFileName("999v2");
|
|
createFile(file2.toLocalFile());
|
|
QVERIFY(!project->isReady());
|
|
// now wait for finish
|
|
QVERIFY(QTest::kWaitForSignal(KDevelop::ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), 2000));
|
|
QVERIFY(project->isReady());
|
|
// make sure our file removal + addition was properly tracked
|
|
QCOMPARE(project->filesForUrl(file).size(), 0);
|
|
QCOMPARE(project->filesForUrl(file2).size(), 1);
|
|
|
|
//NOTE: this test is probabably incomplete, I bet there are some race conditions left,
|
|
// esp. when adding a file at a point where the parent folder was already imported
|
|
// or removing a file that was already imported
|
|
}
|