qt5base-lts/tests/auto/qpluginloader/tst_qpluginloader.cpp
Qt by Nokia 38be0d1383 Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:

http://qt.gitorious.org/qt/pages/GitIntroductionWithQt

If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.

Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
2011-04-27 12:05:43 +02:00

407 lines
12 KiB
C++

/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qdir.h>
#include <qpluginloader.h>
#include "theplugin/plugininterface.h"
// Helper macros to let us know if some suffixes are valid
#define bundle_VALID false
#define dylib_VALID false
#define sl_VALID false
#define a_VALID false
#define so_VALID false
#define dll_VALID false
#if defined(Q_OS_DARWIN)
# undef bundle_VALID
# undef dylib_VALID
# undef so_VALID
# define bundle_VALID true
# define dylib_VALID true
# define so_VALID true
# define SUFFIX ".dylib"
# define PREFIX "lib"
#elif defined(Q_OS_HPUX) && !defined(__ia64)
# undef sl_VALID
# define sl_VALID true
# define SUFFIX ".sl"
# define PREFIX "lib"
#elif defined(Q_OS_AIX)
# undef a_VALID
# undef so_VALID
# define a_VALID true
# define so_VALID true
# define SUFFIX ".so"
# define PREFIX "lib"
#elif defined(Q_OS_WIN)
# undef dll_VALID
# define dll_VALID true
# ifdef QT_NO_DEBUG
# define SUFFIX ".dll"
# else
# define SUFFIX "d.dll"
# endif
# define PREFIX ""
#elif defined(Q_OS_SYMBIAN)
# undef dll_VALID
# define dll_VALID true
# define SUFFIX ".dll"
# define PREFIX ""
#else // all other Unix
# undef so_VALID
# define so_VALID true
# define SUFFIX ".so"
# define PREFIX "lib"
#endif
static QString sys_qualifiedLibraryName(const QString &fileName)
{
QString currDir = QDir::currentPath();
return currDir + "/bin/" + PREFIX + fileName + SUFFIX;
}
//TESTED_CLASS=
//TESTED_FILES=
QT_FORWARD_DECLARE_CLASS(QPluginLoader)
class tst_QPluginLoader : public QObject
{
Q_OBJECT
public:
tst_QPluginLoader();
virtual ~tst_QPluginLoader();
private slots:
void errorString();
void loadHints();
void deleteinstanceOnUnload();
void checkingStubsFromDifferentDrives();
void loadDebugObj();
void loadCorruptElf();
void loadGarbage();
};
tst_QPluginLoader::tst_QPluginLoader()
{
}
tst_QPluginLoader::~tst_QPluginLoader()
{
}
//#define SHOW_ERRORS 1
void tst_QPluginLoader::errorString()
{
#if defined(Q_OS_WINCE)
// On WinCE we need an QCoreApplication object for current dir
int argc = 0;
QCoreApplication app(argc,0);
#endif
const QString unknown(QLatin1String("Unknown error"));
{
QPluginLoader loader; // default constructed
bool loaded = loader.load();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(loaded, false);
QCOMPARE(loader.errorString(), unknown);
QObject *obj = loader.instance();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(obj, static_cast<QObject*>(0));
QCOMPARE(loader.errorString(), unknown);
bool unloaded = loader.unload();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(unloaded, false);
QCOMPARE(loader.errorString(), unknown);
}
{
QPluginLoader loader( sys_qualifiedLibraryName("tst_qpluginloaderlib")); //not a plugin
bool loaded = loader.load();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(loaded, false);
QVERIFY(loader.errorString() != unknown);
QObject *obj = loader.instance();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(obj, static_cast<QObject*>(0));
QVERIFY(loader.errorString() != unknown);
bool unloaded = loader.unload();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(unloaded, false);
QVERIFY(loader.errorString() != unknown);
}
{
QPluginLoader loader( sys_qualifiedLibraryName("nosuchfile")); //not a file
bool loaded = loader.load();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(loaded, false);
QVERIFY(loader.errorString() != unknown);
QObject *obj = loader.instance();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(obj, static_cast<QObject*>(0));
QVERIFY(loader.errorString() != unknown);
bool unloaded = loader.unload();
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QCOMPARE(unloaded, false);
QVERIFY(loader.errorString() != unknown);
}
#if !defined Q_OS_WIN && !defined Q_OS_MAC && !defined Q_OS_HPUX && !defined Q_OS_SYMBIAN
{
QPluginLoader loader( sys_qualifiedLibraryName("almostplugin")); //a plugin with unresolved symbols
loader.setLoadHints(QLibrary::ResolveAllSymbolsHint);
QCOMPARE(loader.load(), false);
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QVERIFY(loader.errorString() != unknown);
QCOMPARE(loader.instance(), static_cast<QObject*>(0));
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QVERIFY(loader.errorString() != unknown);
QCOMPARE(loader.unload(), false);
#ifdef SHOW_ERRORS
qDebug() << loader.errorString();
#endif
QVERIFY(loader.errorString() != unknown);
}
#endif
{
QPluginLoader loader( sys_qualifiedLibraryName("theplugin")); //a plugin
QCOMPARE(loader.load(), true);
QCOMPARE(loader.errorString(), unknown);
QVERIFY(loader.instance() != static_cast<QObject*>(0));
QCOMPARE(loader.errorString(), unknown);
// Make sure that plugin really works
PluginInterface* theplugin = qobject_cast<PluginInterface*>(loader.instance());
QString pluginName = theplugin->pluginName();
QCOMPARE(pluginName, QLatin1String("Plugin ok"));
QCOMPARE(loader.unload(), true);
QCOMPARE(loader.errorString(), unknown);
}
}
void tst_QPluginLoader::loadHints()
{
QPluginLoader loader;
QCOMPARE(loader.loadHints(), (QLibrary::LoadHints)0); //Do not crash
loader.setLoadHints(QLibrary::ResolveAllSymbolsHint);
loader.setFileName( sys_qualifiedLibraryName("theplugin")); //a plugin
QCOMPARE(loader.loadHints(), QLibrary::ResolveAllSymbolsHint);
}
void tst_QPluginLoader::deleteinstanceOnUnload()
{
for (int pass = 0; pass < 2; ++pass) {
QPluginLoader loader1;
loader1.setFileName( sys_qualifiedLibraryName("theplugin")); //a plugin
if (pass == 0)
loader1.load(); // not recommended, instance() should do the job.
PluginInterface *instance1 = qobject_cast<PluginInterface*>(loader1.instance());
QVERIFY(instance1);
QCOMPARE(instance1->pluginName(), QLatin1String("Plugin ok"));
QPluginLoader loader2;
loader2.setFileName( sys_qualifiedLibraryName("theplugin")); //a plugin
if (pass == 0)
loader2.load(); // not recommended, instance() should do the job.
PluginInterface *instance2 = qobject_cast<PluginInterface*>(loader2.instance());
QCOMPARE(instance2->pluginName(), QLatin1String("Plugin ok"));
QSignalSpy spy1(loader1.instance(), SIGNAL(destroyed()));
QSignalSpy spy2(loader2.instance(), SIGNAL(destroyed()));
if (pass == 0) {
QCOMPARE(loader2.unload(), false); // refcount not reached 0, not really unloaded
QCOMPARE(spy1.count(), 0);
QCOMPARE(spy2.count(), 0);
}
QCOMPARE(instance1->pluginName(), QLatin1String("Plugin ok"));
QCOMPARE(instance2->pluginName(), QLatin1String("Plugin ok"));
QVERIFY(loader1.unload()); // refcount reached 0, did really unload
QCOMPARE(spy1.count(), 1);
QCOMPARE(spy2.count(), 1);
}
}
void tst_QPluginLoader::checkingStubsFromDifferentDrives()
{
#if defined(Q_OS_SYMBIAN)
// This test needs C-drive + some additional drive (driveForStubs)
const QString driveForStubs("E:/");// != "C:/"
const QString stubDir("system/temp/stubtest/");
const QString stubName("dummyStub.qtplugin");
const QString fullStubFileName(stubDir + stubName);
QDir dir(driveForStubs);
bool test1(false); bool test2(false);
// initial clean up
QFile::remove(driveForStubs + fullStubFileName);
dir.rmdir(driveForStubs + stubDir);
// create a stub dir and do stub drive check
if (!dir.mkpath(stubDir))
QSKIP("Required drive not available for this test", SkipSingle);
{// test without stub, should not be found
QPluginLoader loader("C:/" + fullStubFileName);
test1 = !loader.fileName().length();
}
// create a stub to defined drive
QFile tempFile(driveForStubs + fullStubFileName);
tempFile.open(QIODevice::ReadWrite);
QFileInfo fileInfo(tempFile);
{// now should be found even tried to find from C:
QPluginLoader loader("C:/" + fullStubFileName);
test2 = (loader.fileName() == fileInfo.absoluteFilePath());
}
// clean up
tempFile.close();
if (!QFile::remove(driveForStubs + fullStubFileName))
QWARN("Could not remove stub file");
if (!dir.rmdir(driveForStubs + stubDir))
QWARN("Could not remove stub directory");
// test after cleanup
QVERIFY(test1);
QVERIFY(test2);
#endif//Q_OS_SYMBIAN
}
void tst_QPluginLoader::loadDebugObj()
{
#if defined (__ELF__)
QVERIFY(QFile::exists(SRCDIR "elftest/debugobj.so"));
QPluginLoader lib1(SRCDIR "elftest/debugobj.so");
QCOMPARE(lib1.load(), false);
#endif
}
void tst_QPluginLoader::loadCorruptElf()
{
#if defined (__ELF__)
if (sizeof(void*) == 8) {
QVERIFY(QFile::exists(SRCDIR "elftest/corrupt1.elf64.so"));
QPluginLoader lib1(SRCDIR "elftest/corrupt1.elf64.so");
QCOMPARE(lib1.load(), false);
QVERIFY(lib1.errorString().contains("not an ELF object"));
QPluginLoader lib2(SRCDIR "elftest/corrupt2.elf64.so");
QCOMPARE(lib2.load(), false);
QVERIFY(lib2.errorString().contains("invalid"));
QPluginLoader lib3(SRCDIR "elftest/corrupt3.elf64.so");
QCOMPARE(lib3.load(), false);
QVERIFY(lib3.errorString().contains("invalid"));
} else if (sizeof(void*) == 4) {
QPluginLoader libW(SRCDIR "elftest/corrupt3.elf64.so");
QCOMPARE(libW.load(), false);
QVERIFY(libW.errorString().contains("architecture"));
} else {
QFAIL("Please port QElfParser to this platform or blacklist this test.");
}
#endif
}
void tst_QPluginLoader::loadGarbage()
{
#if defined (Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
for (int i=0; i<5; i++) {
QPluginLoader lib(QString(SRCDIR "elftest/garbage%1.so").arg(i));
QCOMPARE(lib.load(), false);
#ifdef SHOW_ERRORS
qDebug() << lib.errorString();
#endif
}
#endif
}
QTEST_APPLESS_MAIN(tst_QPluginLoader)
#include "tst_qpluginloader.moc"