diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3028d9d5..27258a1c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -93,9 +93,9 @@ set(TEST_LIBRARIES ${ZLIB_LIBRARIES} ) -set(modeltest_SOURCRS modeltest.cpp) -qt4_wrap_cpp(modeltest_SOURCRS modeltest.h) -add_library(modeltest STATIC ${modeltest_SOURCRS}) +set(testsupport_SOURCES modeltest.cpp FailDevice.cpp) +qt4_wrap_cpp(testsupport_SOURCES modeltest.h FailDevice.h) +add_library(testsupport STATIC ${testsupport_SOURCES}) add_unit_test(NAME testgroup SOURCES TestGroup.cpp MOCS TestGroup.h LIBS ${TEST_LIBRARIES}) @@ -110,13 +110,13 @@ add_unit_test(NAME testkeepass2reader SOURCES TestKeePass2Reader.cpp MOCS TestKe LIBS ${TEST_LIBRARIES}) add_unit_test(NAME testkeepass2writer SOURCES TestKeePass2Writer.cpp MOCS TestKeePass2Writer.h - LIBS ${TEST_LIBRARIES}) + LIBS testsupport ${TEST_LIBRARIES}) add_unit_test(NAME testgroupmodel SOURCES TestGroupModel.cpp MOCS TestGroupModel.h - LIBS modeltest ${TEST_LIBRARIES}) + LIBS testsupport ${TEST_LIBRARIES}) add_unit_test(NAME testentrymodel SOURCES TestEntryModel.cpp MOCS TestEntryModel.h - LIBS modeltest ${TEST_LIBRARIES}) + LIBS testsupport ${TEST_LIBRARIES}) add_unit_test(NAME testcryptohash SOURCES TestCryptoHash.cpp MOCS TestCryptoHash.h LIBS ${TEST_LIBRARIES}) @@ -125,7 +125,7 @@ add_unit_test(NAME testsymmetriccipher SOURCES TestSymmetricCipher.cpp MOCS Test LIBS ${TEST_LIBRARIES}) add_unit_test(NAME testhashedblockstream SOURCES TestHashedBlockStream.cpp MOCS TestHashedBlockStream.h - LIBS ${TEST_LIBRARIES}) + LIBS ${TEST_LIBRARIES} testsupport) add_unit_test(NAME testkeepass2randomstream SOURCES TestKeePass2RandomStream.cpp MOCS TestKeePass2RandomStream.h LIBS ${TEST_LIBRARIES}) diff --git a/tests/FailDevice.cpp b/tests/FailDevice.cpp new file mode 100644 index 00000000..5a25db28 --- /dev/null +++ b/tests/FailDevice.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Felix Geyer + * + * 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 or (at your option) + * 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 . + */ + +#include "FailDevice.h" + +FailDevice::FailDevice(int failAfter, QObject* parent) + : QBuffer(parent) + , m_failAfter(failAfter) + , m_readCount(0) + , m_writeCount(0) +{ +} + +bool FailDevice::open(QIODevice::OpenMode openMode) +{ + return QBuffer::open(openMode | QIODevice::Unbuffered); +} + +qint64 FailDevice::readData(char* data, qint64 len) +{ + if (m_readCount >= m_failAfter) { + setErrorString("FAILDEVICE"); + return -1; + } + else { + qint64 result = QBuffer::readData(data, len); + if (result != -1) { + m_readCount += result; + } + + return result; + } +} + +qint64 FailDevice::writeData(const char* data, qint64 len) +{ + if (m_writeCount >= m_failAfter) { + setErrorString("FAILDEVICE"); + return -1; + } + else { + qint64 result = QBuffer::writeData(data, len); + if (result != -1) { + m_writeCount += result; + } + + return result; + } +} diff --git a/tests/FailDevice.h b/tests/FailDevice.h new file mode 100644 index 00000000..f8125932 --- /dev/null +++ b/tests/FailDevice.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 Felix Geyer + * + * 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 or (at your option) + * 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 . + */ + +#ifndef KEEPASSX_FAILDEVICE_H +#define KEEPASSX_FAILDEVICE_H + +#include + +#include "core/Global.h" + +class FailDevice : public QBuffer +{ + Q_OBJECT + +public: + explicit FailDevice(int failAfter, QObject* parent = Q_NULLPTR); + bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE; + +protected: + qint64 readData(char* data, qint64 len) Q_DECL_OVERRIDE; + qint64 writeData(const char* data, qint64 len) Q_DECL_OVERRIDE; + +private: + int m_failAfter; + int m_readCount; + int m_writeCount; +}; + +#endif // KEEPASSX_FAILDEVICE_H diff --git a/tests/TestHashedBlockStream.cpp b/tests/TestHashedBlockStream.cpp index 2a37d0aa..eca63aff 100644 --- a/tests/TestHashedBlockStream.cpp +++ b/tests/TestHashedBlockStream.cpp @@ -21,6 +21,7 @@ #include #include "tests.h" +#include "FailDevice.h" #include "crypto/Crypto.h" #include "streams/HashedBlockStream.h" @@ -71,3 +72,19 @@ void TestHashedBlockStream::testWriteRead() buffer.reset(); buffer.buffer().clear(); } + +void TestHashedBlockStream::testWriteFailure() +{ + FailDevice failDevice(1500); + QVERIFY(failDevice.open(QIODevice::WriteOnly)); + + QByteArray input(2000, 'Z'); + + HashedBlockStream writer(&failDevice, 500); + QVERIFY(writer.open(QIODevice::WriteOnly)); + + QCOMPARE(writer.write(input.left(900)), qint64(900)); + writer.write(input.left(900)); + QVERIFY(!writer.reset()); + QCOMPARE(writer.errorString(), QString("FAILDEVICE")); +} diff --git a/tests/TestHashedBlockStream.h b/tests/TestHashedBlockStream.h index d672664c..96018d88 100644 --- a/tests/TestHashedBlockStream.h +++ b/tests/TestHashedBlockStream.h @@ -27,6 +27,7 @@ class TestHashedBlockStream : public QObject private Q_SLOTS: void initTestCase(); void testWriteRead(); + void testWriteFailure(); }; #endif // KEEPASSX_TESTHASHEDBLOCKSTREAM_H diff --git a/tests/TestKeePass2Writer.cpp b/tests/TestKeePass2Writer.cpp index cf4ab1c5..fd478a87 100644 --- a/tests/TestKeePass2Writer.cpp +++ b/tests/TestKeePass2Writer.cpp @@ -21,12 +21,14 @@ #include #include "tests.h" +#include "FailDevice.h" #include "core/Database.h" #include "core/Group.h" #include "core/Metadata.h" #include "crypto/Crypto.h" #include "format/KeePass2Reader.h" #include "format/KeePass2Writer.h" +#include "format/KeePass2XmlWriter.h" #include "keys/PasswordKey.h" QTEST_GUILESS_MAIN(TestKeePass2Writer) @@ -101,6 +103,30 @@ void TestKeePass2Writer::testNonAsciiPasswords() QCOMPARE(m_dbTest->rootGroup()->entries()[0]->password(), m_dbOrg->rootGroup()->entries()[0]->password()); } +void TestKeePass2Writer::testDeviceFailure() +{ + CompositeKey key; + key.addKey(PasswordKey("test")); + Database* db = new Database(); + db->setKey(key); + // Disable compression so we write a predictable number of bytes. + db->setCompressionAlgo(Database::CompressionNone); + + Entry* entry = new Entry(); + entry->setParent(db->rootGroup()); + QByteArray attachment(4096, 'Z'); + entry->attachments()->set("test", attachment); + + FailDevice failDevice(512); + QVERIFY(failDevice.open(QIODevice::WriteOnly)); + KeePass2Writer writer; + writer.writeDatabase(&failDevice, db); + QVERIFY(writer.hasError()); + QCOMPARE(writer.errorString(), QString("FAILDEVICE")); + + delete db; +} + void TestKeePass2Writer::cleanupTestCase() { delete m_dbOrg; diff --git a/tests/TestKeePass2Writer.h b/tests/TestKeePass2Writer.h index b6a08dc5..eb3f1095 100644 --- a/tests/TestKeePass2Writer.h +++ b/tests/TestKeePass2Writer.h @@ -32,6 +32,7 @@ private Q_SLOTS: void testProtectedAttributes(); void testAttachments(); void testNonAsciiPasswords(); + void testDeviceFailure(); void cleanupTestCase(); private: