[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [KSecretService] ed2129f: Start a test for the ksecret file format
From: Michael Leupold <lemma () confuego ! org>
Date: 2010-11-09 19:14:29
Message-ID: 20101109191429.678BDA60E9 () git ! kde ! org
[Download RAW message or body]
A backend/tests/ksecrettest.h [License: GPL(v2)]
A backend/tests/ksecrettest.cpp [License: GPL(v2)]
commit ed2129fb8c146c2405e63186c1e2cc428ef5c9f9
Author: Michael Leupold <lemma@confuego.org>
Date: Sat Sep 18 14:10:46 2010 +0000
Start a test for the ksecret file format backend for ksecretservice. In the \
process of creating it, fix some bugs and start integrating the UI.
svn path=/trunk/playground/base/ksecretservice/; revision=1176746
diff --git a/backend/backendmaster.cpp b/backend/backendmaster.cpp
index e0a7435..90f6905 100644
--- a/backend/backendmaster.cpp
+++ b/backend/backendmaster.cpp
@@ -25,8 +25,10 @@
#include "ui/abstractuimanager.h"
#include <QtCore/QEventLoop>
+#include <QtCore/QCoreApplication>
K_GLOBAL_STATIC(BackendMaster, s_backendMaster)
+bool BackendMaster::s_initialized = false;
BackendMaster::BackendMaster()
: m_uiManager(0)
@@ -35,11 +37,16 @@ BackendMaster::BackendMaster()
BackendMaster::~BackendMaster()
{
+ qRemovePostRoutine(s_backendMaster.destroy);
delete m_uiManager;
}
BackendMaster *BackendMaster::instance()
{
+ if (!s_initialized) {
+ s_initialized = true;
+ qAddPostRoutine(s_backendMaster.destroy);
+ }
return s_backendMaster;
}
diff --git a/backend/backendmaster.h b/backend/backendmaster.h
index 3d8dfbb..92bca84 100644
--- a/backend/backendmaster.h
+++ b/backend/backendmaster.h
@@ -160,6 +160,7 @@ private:
QList<BackendCollectionManager*> m_collectionManagers;
AbstractUiManager *m_uiManager;
+ static bool s_initialized;
};
#endif
diff --git a/backend/ksecret/FORMAT b/backend/ksecret/FORMAT
index 0dbddce..855f0b8 100644
--- a/backend/ksecret/FORMAT
+++ b/backend/ksecret/FORMAT
@@ -127,6 +127,9 @@ part-symkey = key-type enc-symkey
key-type = UINT ;; method for encrypting the \
key
enc-symkey = BYTEARRAY ;; the encrypted symmetric \
master key +
+ init-vector = BYTEARRAY ;; initialization vector used \
or empty + ;; if unneeded
Encrypted parts
diff --git a/backend/ksecret/ksecretcollection.cpp \
b/backend/ksecret/ksecretcollection.cpp index d29caef..f1e6b95 100644
--- a/backend/ksecret/ksecretcollection.cpp
+++ b/backend/ksecret/ksecretcollection.cpp
@@ -45,8 +45,22 @@ static const QString genericSavingErrorMessage()
"There was an error writing the ksecret file.");
}
-KSecretCollection *KSecretCollection::create(const QString &id, \
BackendCollectionManager *parent,
- QString &errorMessage)
+// create a symmetric encryption key from a user-supplied password using
+// PBKDF2.
+// Returns a zero-length key if creating the key failed.
+static QCA::SymmetricKey createKeyFromPassword(const QCA::SecureArray &password,
+ int keyLength)
+{
+ if (!QCA::isSupported("sha1")) {
+ return QCA::SymmetricKey();
+ }
+
+ QCA::PBKDF2 deriv("sha1");
+ return deriv.makeKey(password, QCA::InitializationVector(), keyLength, 10000);
+}
+
+KSecretCollection *KSecretCollection::create(const QString &id, const \
QCA::SecureArray &password, + \
BackendCollectionManager *parent, QString &errorMessage) {
KSecretCollection *coll = new KSecretCollection(parent);
coll->m_id = id;
@@ -62,24 +76,28 @@ KSecretCollection *KSecretCollection::create(const QString &id, \
BackendCollectio // create a new symmetric key
// TODO: is minimum() right in all cases?
coll->m_symmetricKey = new \
QCA::SymmetricKey(coll->m_cipher->keyLength().minimum()); + QCA::Cipher *keyCipher \
= coll->m_cipher; + int keyLength = keyCipher->keyLength().minimum();
+ QCA::SymmetricKey keyUnlockKey = createKeyFromPassword(password, keyLength);
+ if (keyUnlockKey.isEmpty()) {
+ delete coll;
+ return 0;
+ }
- // FIXME: this is bogus. Actually the unlocking method needs to be chosen.
- // here we just use a bogus key to encrypt the symmetric key using
- // blowfish.
- QCA::SymmetricKey *keyUnlockKey = new \
QCA::SymmetricKey(QByteArray("12345678901234567890")); + QCA::InitializationVector \
iv = QCA::InitializationVector(keyLength); EncryptedKey *key = new EncryptedKey;
- key->m_type = KSecretFile::KeyBogus;
- QCA::Cipher keyCipher("blowfish", QCA::Cipher::CBC);
- keyCipher.setup(QCA::Encode, *keyUnlockKey);
- key->m_key.append(keyCipher.update(*coll->m_symmetricKey).toByteArray());
- key->m_key.append(keyCipher.final().toByteArray());
+ key->m_type = KSecretFile::KeyPassword;
+ key->m_iv = iv.toByteArray();
+ keyCipher->setup(QCA::Encode, keyUnlockKey, iv);
+ key->m_key.append(keyCipher->update(*coll->m_symmetricKey).toByteArray());
+ key->m_key.append(keyCipher->final().toByteArray());
coll->m_encryptedSymKeys.append(key);
return coll;
}
KSecretCollection::KSecretCollection(BackendCollectionManager *parent)
: BackendCollection(parent), m_hash(0), m_cipher(0),
- m_symmetricKey(0)
+ m_symmetricKey(0), m_mac(0)
{
}
@@ -113,6 +131,7 @@ BackendReturn<void> KSecretCollection::setLabel(const QString \
&label) }
m_label = label;
+ emit collectionChanged(this);
return NoError;
}
@@ -129,7 +148,7 @@ QDateTime KSecretCollection::modified() const
bool KSecretCollection::isLocked() const
{
// a collection is unlocked if m_cipher is initialized
- return (m_symmetricKey != 0);
+ return (m_symmetricKey == 0);
}
BackendReturn<QList<BackendItem*> > KSecretCollection::items() const
@@ -178,7 +197,10 @@ LockCollectionJob *KSecretCollection::createLockJob()
return new KSecretLockCollectionJob(this);
}
-
+DeleteCollectionJob *KSecretCollection::createDeleteJob()
+{
+ return new KSecretDeleteCollectionJob(this);
+}
BackendReturn<bool> KSecretCollection::deleteCollection()
{
@@ -389,6 +411,12 @@ BackendReturn<bool> KSecretCollection::lock()
// FIXME: it.value()->removeSecrets();
}
+ // remove symmetric key
+ delete m_symmetricKey;
+ m_symmetricKey = 0;
+
+ emit collectionChanged(this);
+
return true;
}
}
@@ -399,13 +427,13 @@ bool KSecretCollection::setupAlgorithms(QString &errorMessage)
switch (m_algoHash) {
case KSecretFile::SHA256:
- if (!QCA::isSupported("sha256") || !QCA::isSupported("hmac(sha256))")) {
+ if (!QCA::isSupported("sha256") || !QCA::isSupported("hmac(sha256)")) {
errorMessage = i18nc("Error message: unsupported hashing algorithm SHA256 \
used",
"The hashing algorithm SHA256 is not supported by your \
installation."); return false;
}
m_hash = new QCA::Hash("sha256");
- m_mac = new QCA::MessageAuthenticationCode("hmac(sha256))", \
QCA::SymmetricKey()); + m_mac = new \
QCA::MessageAuthenticationCode("hmac(sha256)", QCA::SymmetricKey()); break;
default:
@@ -417,12 +445,12 @@ bool KSecretCollection::setupAlgorithms(QString &errorMessage)
switch (m_algoCipher) {
case KSecretFile::AES256:
- if (!QCA::isSupported("aes256")) {
+ if (!QCA::isSupported("aes256-cbc-pkcs7")) {
errorMessage = i18nc("Error message: unsupported encryption algorithm \
AES256 used",
"The encryption algorithm AES256 is not suppored by \
your installation."); return false;
}
- m_cipher = new QCA::Cipher("aes256", QCA::Cipher::CBC);
+ m_cipher = new QCA::Cipher("aes256", QCA::Cipher::CBC, QCA::Cipher::PKCS7);
break;
default:
@@ -819,7 +847,18 @@ bool KSecretCollection::serialize(QString &errorMessage) const
return false;
}
- if (!serializeHeader(file) || !serializeParts(file)) {
+ if (!serializeHeader(file)) {
+ errorMessage = genericSavingErrorMessage();
+ return false;
+ }
+
+ // collection properties
+ if (!file.writeString(m_id) || !file.writeString(m_label) ||
+ !file.writeDatetime(m_created) || !file.writeDatetime(m_modified)) {
+ return false;
+ }
+
+ if (!serializeParts(file)) {
errorMessage = genericSavingErrorMessage();
return false;
}
@@ -864,15 +903,6 @@ bool KSecretCollection::serializeParts(KSecretFile &file) const
return false;
}
- // collection properties part
- filePartEntries[curFilePartEntry].m_type = KSecretFile::PartCollProps;
- filePartEntries[curFilePartEntry].m_position = (quint32)file.pos();
- if (!file.writeString(m_id) || !file.writeString(m_label) ||
- !file.writeDatetime(m_created) || !file.writeDatetime(m_modified)) {
- return false;
- }
- curFilePartEntry++;
-
// config part
if (!serializeConfigPart(file, filePartEntries[curFilePartEntry])) {
return false;
@@ -914,7 +944,8 @@ bool KSecretCollection::serializeParts(KSecretFile &file) const
Q_FOREACH(EncryptedKey *key, m_encryptedSymKeys) {
filePartEntries[curFilePartEntry].m_type = KSecretFile::PartSymKey;
filePartEntries[curFilePartEntry].m_position = (quint32)file.pos();
- if (!file.writeUint(key->m_type) || !file.writeBytearray(key->m_key)) {
+ if (!file.writeUint(key->m_type) || !file.writeBytearray(key->m_key) ||
+ !file.writeBytearray(key->m_iv)) {
return false;
}
filePartEntries[curFilePartEntry].m_length =
diff --git a/backend/ksecret/ksecretcollection.h \
b/backend/ksecret/ksecretcollection.h index bfe94db..5548b12 100644
--- a/backend/ksecret/ksecretcollection.h
+++ b/backend/ksecret/ksecretcollection.h
@@ -51,6 +51,7 @@ struct EncryptedKey
{
quint32 m_type;
QByteArray m_key;
+ QByteArray m_iv;
};
/**
@@ -84,12 +85,13 @@ public:
* Create a new collection.
*
* @param id id for the new collection
+ * @param password password to use for encrypting the collection
* @param parent parent collection manager
* @param errorMessage set in case of an error
* @return the new collection or 0 in case of an error
*/
- static KSecretCollection *create(const QString &id, BackendCollectionManager \
*parent,
- QString &errorMessage);
+ static KSecretCollection *create(const QString &id, const QCA::SecureArray \
&password, + BackendCollectionManager *parent, \
QString &errorMessage);
/**
* Destructor
@@ -272,7 +274,7 @@ protected:
* @remarks this is used by KSecretDeleteCollectionJob
*/
BackendReturn<bool> deleteCollection();
-
+
private:
friend class KSecretUnlockCollectionJob;
friend class KSecretLockCollectionJob;
diff --git a/backend/ksecret/ksecretcollectionmanager.cpp \
b/backend/ksecret/ksecretcollectionmanager.cpp index 6b56d40..d2a5ef9 100644
--- a/backend/ksecret/ksecretcollectionmanager.cpp
+++ b/backend/ksecret/ksecretcollectionmanager.cpp
@@ -40,6 +40,15 @@ KSecretCollectionManager::~KSecretCollectionManager()
// TODO: cleanup?
}
+CreateCollectionJob *KSecretCollectionManager::createCreateCollectionJob(const \
QString &label, + \
bool locked) +{
+ KSecretCreateCollectionJob *job = new KSecretCreateCollectionJob(label, locked, \
this); + connect(job, SIGNAL(result(QueuedJob*)),
+ SLOT(createCollectionJobResult(QueuedJob*)));
+ return job;
+}
+
void KSecretCollectionManager::addCollection(KSecretCollection *collection)
{
m_collections.insert(collection->path(), collection);
@@ -75,6 +84,8 @@ void KSecretCollectionManager::createCollectionJobResult(QueuedJob \
*job)
connect(ccj->collection(), SIGNAL(collectionDeleted(BackendCollection*)),
SIGNAL(collectionDeleted(BackendCollection*)));
+ connect(ccj->collection(), SIGNAL(collectionChanged(BackendCollection*)),
+ SIGNAL(collectionChanged(BackendCollection*)));
emit collectionCreated(ccj->collection());
}
diff --git a/backend/ksecret/ksecretfile.cpp b/backend/ksecret/ksecretfile.cpp
index 7f0e76c..8ebad21 100644
--- a/backend/ksecret/ksecretfile.cpp
+++ b/backend/ksecret/ksecretfile.cpp
@@ -37,7 +37,6 @@ KSecretFile::KSecretFile(QIODevice *device, OpenMode mode)
KSecretFile::~KSecretFile()
{
m_device->close();
- delete m_device;
}
void KSecretFile::close()
@@ -84,7 +83,7 @@ bool KSecretFile::writeMagic()
return false;
}
- if (m_device->write(KSECRET_MAGIC) != KSECRET_MAGIC_LEN) {
+ if (m_device->write(KSECRET_MAGIC, KSECRET_MAGIC_LEN) != KSECRET_MAGIC_LEN) {
m_valid = false;
}
return m_valid;
diff --git a/backend/ksecret/ksecretjobs.cpp b/backend/ksecret/ksecretjobs.cpp
index 9c81fb0..7f365aa 100644
--- a/backend/ksecret/ksecretjobs.cpp
+++ b/backend/ksecret/ksecretjobs.cpp
@@ -20,9 +20,12 @@
#include "ksecretjobs.h"
+#include <backend/backendmaster.h>
+#include <ui/abstractuimanager.h>
#include <secrettool.h>
#include <QtCore/QTimer>
+#include <klocalizedstring.h>
KSecretCreateCollectionJob::KSecretCreateCollectionJob(const QString &label, bool \
locked,
KSecretCollectionManager \
*manager) @@ -44,10 +47,36 @@ void KSecretCreateCollectionJob::exec()
void KSecretCreateCollectionJob::start()
{
+ // start a job for getting a new password for the collection from the user.
+ AbstractUiManager *uiManager = BackendMaster::instance()->uiManager();
+ AbstractNewPasswordJob *subJob = uiManager->createNewPasswordJob(label());
+ connect(subJob, SIGNAL(result(QueuedJob*)),
+ SLOT(newPasswordJobResult(QueuedJob*)));
+ subJob->enqueue();
+}
+
+void KSecretCreateCollectionJob::newPasswordJobResult(QueuedJob *job)
+{
+ AbstractNewPasswordJob *npj = qobject_cast<AbstractNewPasswordJob*>(job);
+ Q_ASSERT(npj);
+
+ if (npj->cancelled()) {
+ setCollection(0);
+ setError(ErrorOther, i18n("Creating the collection was cancelled by the \
uesr.")); + emitResult();
+ return;
+ }
+
// TODO: collection needs authentication methods, filenames, ...
QString errorMessage;
- KSecretCollection *coll = KSecretCollection::create(createId(), manager(),
- errorMessage);
+ KSecretCollection *coll = KSecretCollection::create(createId(), npj->password(),
+ manager(), errorMessage);
+ if (!coll) {
+ setCollection(0);
+ setError(ErrorOther, errorMessage);
+ emitResult();
+ return;
+ }
coll->setLabel(label());
// NOTE: coll has to be added to m_collections before serializing it for the
@@ -152,8 +181,8 @@ void KSecretLockCollectionJob::exec()
setResult(false);
} else {
setResult(true);
- emitResult();
}
+ emitResult();
}
KSecretDeleteCollectionJob::KSecretDeleteCollectionJob(KSecretCollection \
*collection)
diff --git a/backend/ksecret/ksecretjobs.h b/backend/ksecret/ksecretjobs.h
index c418d9f..8bcaa84 100644
--- a/backend/ksecret/ksecretjobs.h
+++ b/backend/ksecret/ksecretjobs.h
@@ -24,7 +24,9 @@
#include "ksecretcollectionmanager.h"
#include "ksecretcollection.h"
#include "ksecretitem.h"
-#include "../backendjob.h"
+
+#include <backend/backendjob.h>
+#include <ui/abstractuijobs.h>
#include <QtCore/QPointer>
@@ -41,6 +43,9 @@ public:
virtual bool isImmediate() const;
virtual void exec();
virtual void start();
+
+private Q_SLOTS:
+ void newPasswordJobResult(QueuedJob *job);
private:
KSecretCollectionManager *m_manager;
diff --git a/backend/tests/CMakeLists.txt b/backend/tests/CMakeLists.txt
index d37fd1d..03f75e9 100644
--- a/backend/tests/CMakeLists.txt
+++ b/backend/tests/CMakeLists.txt
@@ -10,6 +10,16 @@ TARGET_LINK_LIBRARIES (ksecretservice_backend_test
ADD_TEST (BackendItemCollectionHandlingTest ksecretservice_backend_test)
+KDE4_ADD_EXECUTABLE (ksecretservice_ksecret_test ksecrettest.cpp)
+TARGET_LINK_LIBRARIES (ksecretservice_ksecret_test
+ ksecretservicebackend
+ ksecretservicelib
+ ksecretserviceui
+ ${QT_QTTEST_LIBRARIES}
+)
+
+ADD_TEST (KSecretTest ksecretservice_ksecret_test)
+
KDE4_ADD_EXECUTABLE (securebuffer_test securebuffertest.cpp)
TARGET_LINK_LIBRARIES (securebuffer_test ksecretservicebackend \
${QT_QTTEST_LIBRARIES})
diff --git a/backend/tests/ksecrettest.cpp b/backend/tests/ksecrettest.cpp
new file mode 100644
index 0000000..d79b6d2
--- /dev/null
+++ b/backend/tests/ksecrettest.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2010, Dario Freddi <dario.freddi@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ksecrettest.h"
+#include <backendmaster.h>
+#include <ksecret/ksecretcollectionmanager.h>
+#include <backendcollection.h>
+#include <backenditem.h>
+#include <ui/nouimanager.h>
+
+Q_DECLARE_METATYPE(BackendCollection*)
+Q_DECLARE_METATYPE(BackendItem*)
+
+void KSecretTest::initTestCase()
+{
+ qRegisterMetaType<BackendCollection*>();
+ qRegisterMetaType<BackendItem*>();
+ QCA::init();
+ BackendMaster *master = BackendMaster::instance();
+ master->setUiManager(new NoUiManager);
+ m_manager = new KSecretCollectionManager("/tmp", master);
+ master->addManager(m_manager);
+}
+
+void KSecretTest::testCreateCollectionAsync()
+{
+ CreateCollectionJob *createColl = m_manager->createCreateCollectionJob("test", \
false); + QSignalSpy managerSpy(m_manager, \
SIGNAL(collectionCreated(BackendCollection*))); + QSignalSpy \
masterSpy(BackendMaster::instance(), SIGNAL(collectionCreated(BackendCollection*))); \
+ QTestEventLoop loop; + QVERIFY(loop.connect(createColl, \
SIGNAL(result(QueuedJob*)), SLOT(exitLoop()))); + createColl->enqueue();
+ if (!createColl->isFinished()) {
+ loop.enterLoop(5);
+ }
+
+ QVERIFY(createColl->isFinished());
+ QCOMPARE(createColl->error(), NoError);
+ QVERIFY(!createColl->isDismissed());
+ QVERIFY(createColl->collection() != 0);
+
+ // Verify signals
+ QCOMPARE(managerSpy.count(), 1);
+ QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>(), \
createColl->collection()); + QCOMPARE(masterSpy.count(), 1);
+ QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), \
createColl->collection()); +
+ // Check the collection is present and alive
+ BackendMaster *master = BackendMaster::instance();
+ QCOMPARE(master->collections().size(), 1);
+ QCOMPARE(master->collections().first(), createColl->collection());
+ QCOMPARE(master->collections().first()->label().value(), QLatin1String("test"));
+
+ // TODO: check collection attributes (eg. timestamps)
+
+ // TODO: check if the collection has been written to disk
+
+ // remember the collection
+ m_collection = createColl->collection();
+}
+
+void KSecretTest::testLockCollectionAsync()
+{
+ LockCollectionJob *lockColl = m_collection->createLockJob();
+ BackendMaster *master = BackendMaster::instance();
+ QSignalSpy masterSpy(master, SIGNAL(collectionChanged(BackendCollection*)));
+ QSignalSpy managerSpy(m_manager, SIGNAL(collectionChanged(BackendCollection*)));
+ QSignalSpy collSpy(m_collection, SIGNAL(collectionChanged(BackendCollection*)));
+ QTestEventLoop loop;
+ QVERIFY(loop.connect(lockColl, SIGNAL(result(QueuedJob*)), SLOT(exitLoop())));
+ lockColl->enqueue();
+ if (!lockColl->isFinished()) {
+ loop.enterLoop(5);
+ }
+
+ QVERIFY(lockColl->isFinished());
+ QCOMPARE(lockColl->error(), NoError);
+ QVERIFY(!lockColl->isDismissed());
+ QVERIFY(lockColl->result());
+ QVERIFY(m_collection->isLocked());
+
+ // Verify signals
+ QCOMPARE(managerSpy.count(), 1);
+ QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>(), m_collection);
+ QCOMPARE(masterSpy.count(), 1);
+ QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), m_collection);
+ QCOMPARE(collSpy.count(), 1);
+ QCOMPARE(collSpy.takeFirst().at(0).value<BackendCollection*>(), m_collection);
+}
+
+void KSecretTest::testUnlockCollectionAsync()
+{
+}
+
+void KSecretTest::testCreateItemAsync()
+{
+}
+
+void KSecretTest::testReplaceItemAsync()
+{
+}
+
+void KSecretTest::testDoNotReplaceItemAsync()
+{
+}
+
+void KSecretTest::testDeleteItemAsync()
+{
+}
+
+void KSecretTest::testDeleteCollectionAsync()
+{
+}
+
+void KSecretTest::cleanupTestCase()
+{
+}
+
+QTEST_MAIN(KSecretTest)
+#include "ksecrettest.moc"
diff --git a/backend/tests/ksecrettest.h b/backend/tests/ksecrettest.h
new file mode 100644
index 0000000..0ea2a63
--- /dev/null
+++ b/backend/tests/ksecrettest.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010, Dario Freddi <dario.freddi@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KSECRETTEST_H
+#define KSECRETTEST_H
+
+#include <QtTest>
+
+class BackendCollectionManager;
+class BackendCollection;
+
+class KSecretTest : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase();
+
+ void testCreateCollectionAsync();
+ void testLockCollectionAsync();
+ void testUnlockCollectionAsync();
+ void testCreateItemAsync();
+ void testReplaceItemAsync();
+ void testDoNotReplaceItemAsync();
+ void testDeleteItemAsync();
+ void testDeleteCollectionAsync();
+
+ void cleanupTestCase();
+
+private:
+ BackendCollectionManager *m_manager;
+ BackendCollection *m_collection;
+};
+
+#endif
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic