mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00
308 lines
10 KiB
C++
308 lines
10 KiB
C++
/* This file is part of the KDE project
|
|
|
|
Copyright 2009 David Faure <faure@kde.org>
|
|
|
|
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 ) version 3 or, at the discretion of KDE e.V.
|
|
( which shall act as a proxy as in section 14 of the GPLv3 ), 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 <kcomponentdata.h>
|
|
#include <kservicegroup.h>
|
|
#include <kmimetype.h>
|
|
#include <qtest_kde.h>
|
|
|
|
#include <kconfig.h>
|
|
#include <kconfiggroup.h>
|
|
#include <kdesktopfile.h>
|
|
#include <ksycoca.h>
|
|
#include <kglobal.h>
|
|
#include <kservicetypetrader.h>
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <kservicetype.h>
|
|
|
|
#include <QtCore/qprocess.h>
|
|
#include <QtCore/qthread.h>
|
|
|
|
// Helper method for all the trader tests
|
|
static bool offerListHasService( const KService::List& offers,
|
|
const QString& entryPath )
|
|
{
|
|
bool found = false;
|
|
KService::List::const_iterator it = offers.begin();
|
|
for ( ; it != offers.end() ; ++it )
|
|
{
|
|
if ( (*it)->entryPath() == entryPath ) {
|
|
if( found ) { // should be there only once
|
|
qWarning( "ERROR: %s was found twice in the list", qPrintable( entryPath ) );
|
|
return false; // make test fail
|
|
}
|
|
found = true;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
class WorkerObject : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
WorkerObject() : QObject() {}
|
|
|
|
public slots:
|
|
void work() {
|
|
kDebug() << QThread::currentThread() << "working...";
|
|
|
|
const KServiceType::List allServiceTypes = KServiceType::allServiceTypes();
|
|
Q_ASSERT(!allServiceTypes.isEmpty());
|
|
|
|
const KMimeType::List allMimeTypes = KMimeType::allMimeTypes();
|
|
Q_ASSERT(!allMimeTypes.isEmpty());
|
|
|
|
const KService::List lst = KService::allServices();
|
|
Q_ASSERT(!lst.isEmpty());
|
|
|
|
for ( KService::List::ConstIterator it = lst.begin();
|
|
it != lst.end(); ++it ) {
|
|
const KService::Ptr service = (*it);
|
|
Q_ASSERT(service->isType(KST_KService));
|
|
const QString name = service->name();
|
|
const QString entryPath = service->entryPath();
|
|
//kDebug() << name << "entryPath=" << entryPath << "menuId=" << service->menuId();
|
|
Q_ASSERT(!name.isEmpty());
|
|
Q_ASSERT(!entryPath.isEmpty());
|
|
|
|
KService::Ptr lookedupService = KService::serviceByDesktopPath( entryPath );
|
|
Q_ASSERT( lookedupService ); // not null
|
|
QCOMPARE( lookedupService->entryPath(), entryPath );
|
|
|
|
if (service->isApplication()) {
|
|
const QString menuId = service->menuId();
|
|
if ( menuId.isEmpty() )
|
|
qWarning( "%s has an empty menuId!", qPrintable( entryPath ) );
|
|
Q_ASSERT( !menuId.isEmpty() );
|
|
lookedupService = KService::serviceByMenuId( menuId );
|
|
Q_ASSERT( lookedupService ); // not null
|
|
QCOMPARE( lookedupService->menuId(), menuId );
|
|
}
|
|
}
|
|
|
|
KService::List offers = KServiceTypeTrader::self()->query("KParts/ReadOnlyPart");
|
|
Q_ASSERT( offers.count() > 0 );
|
|
offers = KServiceTypeTrader::self()->query("KTextEditor/Plugin");
|
|
Q_ASSERT( offerListHasService( offers, "faketextplugin.desktop" ) );
|
|
|
|
offers = KServiceTypeTrader::self()->query("KTextEditor/Plugin", "Library == 'faketextplugin'");
|
|
Q_ASSERT(offers.count() == 1);
|
|
QVERIFY( offerListHasService( offers, "faketextplugin.desktop" ) );
|
|
|
|
KServiceGroup::Ptr root = KServiceGroup::root();
|
|
Q_ASSERT(root);
|
|
}
|
|
};
|
|
|
|
class WorkerThread : public QThread
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
WorkerThread() : QThread() {
|
|
m_stop = false;
|
|
}
|
|
virtual void run() {
|
|
WorkerObject wo;
|
|
while (!m_stop) {
|
|
wo.work();
|
|
}
|
|
}
|
|
virtual void stop() { m_stop = true; }
|
|
private:
|
|
bool m_stop;
|
|
};
|
|
|
|
/**
|
|
* Threads with an event loop will be able to process "database changed" signals.
|
|
* Threads without an event loop (like WorkerThread) cannot, so they will keep using
|
|
* the old data.
|
|
*/
|
|
class EventLoopThread : public WorkerThread
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
virtual void run() {
|
|
// WorkerObject must belong to this thread, this is why we don't
|
|
// have the slot work() in WorkerThread itself. Typical QThread trap!
|
|
WorkerObject wo;
|
|
QTimer timer;
|
|
connect(&timer, SIGNAL(timeout()), &wo, SLOT(work()));
|
|
timer.start(100);
|
|
exec();
|
|
}
|
|
virtual void stop() {
|
|
quit();
|
|
}
|
|
};
|
|
|
|
class KSycocaThreadTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
KSycocaThreadTest() {}
|
|
void launch();
|
|
|
|
private slots:
|
|
// Note that this isn't a QTest based test.
|
|
// All these methods are called manually.
|
|
void cleanupTestCase();
|
|
void testCreateService();
|
|
void testDeleteService() {
|
|
deleteFakeService();
|
|
QTimer::singleShot(1000, this, SLOT(slotFinish()));
|
|
}
|
|
void slotFinish() {
|
|
kDebug() << "Terminating";
|
|
for (int i=0; i<threads.size(); i++) {
|
|
threads[i]->stop();
|
|
}
|
|
for (int i=0; i<threads.size(); i++) {
|
|
threads[i]->wait();
|
|
}
|
|
cleanupTestCase();
|
|
QCoreApplication::instance()->quit();
|
|
}
|
|
|
|
private:
|
|
void createFakeService();
|
|
void deleteFakeService();
|
|
QVector<WorkerThread*> threads;
|
|
};
|
|
|
|
static void runKBuildSycoca()
|
|
{
|
|
QProcess proc;
|
|
const QString kbuildsycoca = KStandardDirs::findExe(KBUILDSYCOCA_EXENAME);
|
|
QVERIFY(!kbuildsycoca.isEmpty());
|
|
QStringList args;
|
|
proc.setProcessChannelMode(QProcess::MergedChannels); // silence kbuildsycoca output
|
|
proc.start(kbuildsycoca, args);
|
|
kDebug() << "waiting for signal";
|
|
QVERIFY(QTest::kWaitForSignal(KSycoca::self(), SIGNAL(databaseChanged(QStringList)), 10000));
|
|
kDebug() << "got signal";
|
|
proc.waitForFinished();
|
|
QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
|
|
}
|
|
|
|
void KSycocaThreadTest::launch()
|
|
{
|
|
// This service is always there. Used in the trader queries from the thread.
|
|
const QString fakeTextPlugin = KStandardDirs::locateLocal("services", "faketextplugin.desktop");
|
|
if (!QFile::exists(fakeTextPlugin)) {
|
|
KDesktopFile file(fakeTextPlugin);
|
|
KConfigGroup group = file.desktopGroup();
|
|
group.writeEntry("Name", "FakeTextPlugin");
|
|
group.writeEntry("Type", "Service");
|
|
group.writeEntry("X-KDE-Library", "faketextplugin");
|
|
group.writeEntry("X-KDE-Protocols", "http,ftp");
|
|
group.writeEntry("ServiceTypes", "KTextEditor/Plugin");
|
|
group.writeEntry("MimeType", "text/plain;");
|
|
file.sync();
|
|
qDebug() << "Created" << fakeTextPlugin << ", running kbuilsycoca";
|
|
runKBuildSycoca();
|
|
// Process the event
|
|
int count = 0;
|
|
while (!KService::serviceByDesktopPath("faketextplugin.desktop")) {
|
|
qApp->processEvents();
|
|
if (++count == 20) {
|
|
qFatal("sycoca doesn't have faketextplugin.desktop");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Start clean
|
|
const QString servPath = KStandardDirs::locateLocal("services", "fakeservice.desktop");
|
|
if (QFile::exists(servPath))
|
|
QFile::remove(servPath);
|
|
if (KService::serviceByDesktopPath("fakeservice.desktop"))
|
|
deleteFakeService();
|
|
threads.resize(5);
|
|
for (int i=0; i<threads.size(); i++) {
|
|
threads[i] = i < 3 ? new WorkerThread : new EventLoopThread;
|
|
threads[i]->start();
|
|
}
|
|
testCreateService();
|
|
}
|
|
|
|
void KSycocaThreadTest::cleanupTestCase()
|
|
{
|
|
const QString fakeTextPlugin = KStandardDirs::locateLocal("services", "faketextplugin.desktop");
|
|
QFile::remove(fakeTextPlugin);
|
|
}
|
|
|
|
void KSycocaThreadTest::testCreateService()
|
|
{
|
|
createFakeService();
|
|
const QString servPath = KStandardDirs::locateLocal("services", "fakeservice.desktop");
|
|
|
|
Q_ASSERT(QFile::exists(servPath));
|
|
kDebug() << "executing kbuildsycoca (1)";
|
|
runKBuildSycoca();
|
|
|
|
QTimer::singleShot(1000, this, SLOT(testDeleteService()));
|
|
}
|
|
|
|
void KSycocaThreadTest::deleteFakeService()
|
|
{
|
|
KService::Ptr fakeService = KService::serviceByDesktopPath("fakeservice.desktop");
|
|
Q_ASSERT(fakeService);
|
|
const QString servPath = KStandardDirs::locateLocal("services", "fakeservice.desktop");
|
|
QFile::remove(servPath);
|
|
|
|
QSignalSpy spy(KSycoca::self(), SIGNAL(databaseChanged(QStringList)));
|
|
Q_ASSERT(spy.isValid());
|
|
|
|
kDebug() << "executing kbuildsycoca (2)";
|
|
runKBuildSycoca();
|
|
Q_ASSERT(spy[0][0].toStringList().contains("services"));
|
|
|
|
Q_ASSERT(fakeService); // the whole point of refcounting is that this KService instance is still valid.
|
|
Q_ASSERT(!QFile::exists(servPath));
|
|
}
|
|
|
|
void KSycocaThreadTest::createFakeService()
|
|
{
|
|
const QString fakeService = KStandardDirs::locateLocal("services", "fakeservice.desktop");
|
|
KDesktopFile file(fakeService);
|
|
KConfigGroup group = file.desktopGroup();
|
|
group.writeEntry("Name", "FakeService");
|
|
group.writeEntry("Type", "Service");
|
|
group.writeEntry("X-KDE-Library", "fakeservice");
|
|
group.writeEntry("X-KDE-Protocols", "http,ftp");
|
|
group.writeEntry("ServiceTypes", "KTextEditor/Plugin");
|
|
group.writeEntry("MimeType", "text/plain;");
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
setenv("KDEHOME", QFile::encodeName(QDir::homePath() + QString::fromLatin1("/.kde-unit-test")), 1);
|
|
setenv("XDG_DATA_HOME", QFile::encodeName(QDir::homePath() + QString::fromLatin1("/.kde-unit-test/xdg/local")), 1);
|
|
QCoreApplication app(argc, argv);
|
|
KComponentData cData("ksycocathreadtest");
|
|
KSycocaThreadTest mainObj;
|
|
mainObj.launch();
|
|
return app.exec();
|
|
}
|
|
|
|
#include "ksycocathreadtest.moc"
|