Merge branch 'develop'

Conflicts:
	CMakeLists.txt
	cmake/CLangFormat.cmake
	snapcraft.yaml
	src/CMakeLists.txt
	src/core/Database.cpp
	src/core/Database.h
	src/core/Tools.cpp
	src/crypto/CryptoHash.h
	src/crypto/ssh/ASN1Key.h
	src/crypto/ssh/OpenSSHKey.cpp
	src/format/Kdbx4Reader.cpp
	src/gui/DatabaseTabWidget.cpp
	src/gui/DatabaseTabWidget.h
	src/gui/DatabaseWidget.cpp
	src/gui/DatabaseWidget.h
	src/gui/DetailsWidget.cpp
	src/gui/DetailsWidget.ui
	src/gui/EditWidgetProperties.cpp
	src/gui/EntryPreviewWidget.cpp
	src/gui/EntryPreviewWidget.ui
	src/gui/FileDialog.cpp
	src/gui/dbsettings/DatabaseSettingsDialog.cpp
	src/gui/dbsettings/DatabaseSettingsDialog.h
	src/gui/group/EditGroupWidget.cpp
	src/gui/group/EditGroupWidget.h
	src/sshagent/ASN1Key.h
	src/sshagent/OpenSSHKey.cpp
	src/sshagent/SSHAgent.cpp
	tests/CMakeLists.txt
This commit is contained in:
Jonathan White
2018-12-18 22:28:56 -05:00
421 changed files with 18208 additions and 12907 deletions

View File

@@ -1,3 +1,4 @@
# Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
# Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
#
# This program is free software: you can redistribute it and/or modify
@@ -13,7 +14,11 @@
# 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_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR}/../src)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/../src)
add_definitions(-DQT_TEST_LIB)
@@ -21,99 +26,98 @@ set(KEEPASSX_TEST_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data)
configure_file(config-keepassx-tests.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepassx-tests.h)
macro(parse_arguments prefix arg_names option_names)
set(DEFAULT_ARGS)
foreach(arg_name ${arg_names})
set(${prefix}_${arg_name})
endforeach(arg_name)
foreach(option ${option_names})
set(${prefix}_${option} FALSE)
endforeach(option)
set(DEFAULT_ARGS)
foreach(arg_name ${arg_names})
set(${prefix}_${arg_name})
endforeach(arg_name)
foreach(option ${option_names})
set(${prefix}_${option} FALSE)
endforeach(option)
set(current_arg_name DEFAULT_ARGS)
set(current_arg_list)
foreach(arg ${ARGN})
set(larg_names ${arg_names})
list(FIND larg_names "${arg}" is_arg_name)
if(is_arg_name GREATER -1)
set(${prefix}_${current_arg_name} ${current_arg_list})
set(current_arg_name ${arg})
set(current_arg_list)
else()
set(loption_names ${option_names})
list(FIND loption_names "${arg}" is_option)
if(is_option GREATER -1)
set(${prefix}_${arg} TRUE)
else(is_option GREATER -1)
set(current_arg_list ${current_arg_list} ${arg})
endif()
endif()
endforeach(arg)
set(${prefix}_${current_arg_name} ${current_arg_list})
set(current_arg_name DEFAULT_ARGS)
set(current_arg_list)
foreach(arg ${ARGN})
set(larg_names ${arg_names})
list(FIND larg_names "${arg}" is_arg_name)
if(is_arg_name GREATER -1)
set(${prefix}_${current_arg_name} ${current_arg_list})
set(current_arg_name ${arg})
set(current_arg_list)
else()
set(loption_names ${option_names})
list(FIND loption_names "${arg}" is_option)
if(is_option GREATER -1)
set(${prefix}_${arg} TRUE)
else(is_option GREATER -1)
set(current_arg_list ${current_arg_list} ${arg})
endif()
endif()
endforeach(arg)
set(${prefix}_${current_arg_name} ${current_arg_list})
endmacro(parse_arguments)
macro(add_unit_test)
parse_arguments(TEST "NAME;SOURCES;LIBS" "" ${ARGN})
set(_test_NAME ${TEST_NAME})
set(_srcList ${TEST_SOURCES})
add_executable(${_test_NAME} ${_srcList})
target_link_libraries(${_test_NAME} ${TEST_LIBS})
parse_arguments(TEST "NAME;SOURCES;LIBS" "" ${ARGN})
set(_test_NAME ${TEST_NAME})
set(_srcList ${TEST_SOURCES})
add_executable(${_test_NAME} ${_srcList})
target_link_libraries(${_test_NAME} ${TEST_LIBS})
if(NOT TEST_OUTPUT)
set(TEST_OUTPUT plaintext)
endif(NOT TEST_OUTPUT)
set(TEST_OUTPUT ${TEST_OUTPUT} CACHE STRING "The output to generate when running the QTest unit tests")
if(NOT TEST_OUTPUT)
set(TEST_OUTPUT plaintext)
endif(NOT TEST_OUTPUT)
set(TEST_OUTPUT ${TEST_OUTPUT} CACHE STRING "The output to generate when running the QTest unit tests")
if(KDE4_TEST_OUTPUT STREQUAL "xml")
add_test(${_test_NAME} ${_test_NAME} -xml -o ${_test_NAME}.tml)
else(KDE4_TEST_OUTPUT STREQUAL "xml")
add_test(${_test_NAME} ${_test_NAME})
endif(KDE4_TEST_OUTPUT STREQUAL "xml")
if(KDE4_TEST_OUTPUT STREQUAL "xml")
add_test(${_test_NAME} ${_test_NAME} -xml -o ${_test_NAME}.tml)
else(KDE4_TEST_OUTPUT STREQUAL "xml")
add_test(${_test_NAME} ${_test_NAME})
endif(KDE4_TEST_OUTPUT STREQUAL "xml")
if(NOT MSVC_IDE) #not needed for the ide
# if the tests are EXCLUDE_FROM_ALL, add a target "buildtests" to build all tests
if(NOT WITH_TESTS)
get_directory_property(_buildtestsAdded BUILDTESTS_ADDED)
if(NOT _buildtestsAdded)
add_custom_target(buildtests)
set_directory_properties(PROPERTIES BUILDTESTS_ADDED TRUE)
endif()
add_dependencies(buildtests ${_test_NAME})
if(NOT MSVC_IDE) #not needed for the ide
# if the tests are EXCLUDE_FROM_ALL, add a target "buildtests" to build all tests
if(NOT WITH_TESTS)
get_directory_property(_buildtestsAdded BUILDTESTS_ADDED)
if(NOT _buildtestsAdded)
add_custom_target(buildtests)
set_directory_properties(PROPERTIES BUILDTESTS_ADDED TRUE)
endif()
add_dependencies(buildtests ${_test_NAME})
endif()
endif()
endif()
endmacro(add_unit_test)
set(TEST_LIBRARIES
keepassx_core
${keepasshttp_LIB}
${autotype_LIB}
Qt5::Core
Qt5::Concurrent
Qt5::Widgets
Qt5::Test
${GCRYPT_LIBRARIES}
${GPGERROR_LIBRARIES}
${ZLIB_LIBRARIES}
)
keepassx_core
${keepasshttp_LIB}
${autotype_LIB}
Qt5::Core
Qt5::Concurrent
Qt5::Widgets
Qt5::Test
${GCRYPT_LIBRARIES}
${GPGERROR_LIBRARIES}
${ZLIB_LIBRARIES})
set(testsupport_SOURCES TestGlobal.h modeltest.cpp FailDevice.cpp stub/TestClock.cpp stub/TestRandom.cpp)
set(testsupport_SOURCES TestGlobal.h modeltest.cpp FailDevice.cpp mock/MockClock.cpp util/TemporaryFile.cpp stub/TestRandom.cpp)
add_library(testsupport STATIC ${testsupport_SOURCES})
target_link_libraries(testsupport Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Test)
if(YUBIKEY_FOUND)
set(TEST_LIBRARIES ${TEST_LIBRARIES} ${YUBIKEY_LIBRARIES})
set(TEST_LIBRARIES ${TEST_LIBRARIES} ${YUBIKEY_LIBRARIES})
endif()
add_unit_test(NAME testgroup SOURCES TestGroup.cpp
LIBS testsupport ${TEST_LIBRARIES})
LIBS testsupport ${TEST_LIBRARIES})
add_unit_test(NAME testkdbx2 SOURCES TestKdbx2.cpp
LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testkdbx3 SOURCES TestKeePass2Format.cpp FailDevice.cpp TestKdbx3.cpp
LIBS testsupport ${TEST_LIBRARIES})
LIBS testsupport ${TEST_LIBRARIES})
add_unit_test(NAME testkdbx4 SOURCES TestKeePass2Format.cpp FailDevice.cpp mock/MockChallengeResponseKey.cpp TestKdbx4.cpp
LIBS testsupport ${TEST_LIBRARIES})
LIBS testsupport ${TEST_LIBRARIES})
add_unit_test(NAME testkeys SOURCES TestKeys.cpp mock/MockChallengeResponseKey.cpp
LIBS ${TEST_LIBRARIES})
@@ -132,7 +136,7 @@ add_unit_test(NAME testsymmetriccipher SOURCES TestSymmetricCipher.cpp
if(WITH_XC_KEESHARE)
add_unit_test(NAME testsignature SOURCES TestSignature.cpp
LIBS ${TEST_LIBRARIES})
LIBS ${TEST_LIBRARIES})
endif()
add_unit_test(NAME testhashedblockstream SOURCES TestHashedBlockStream.cpp
@@ -142,7 +146,7 @@ add_unit_test(NAME testkeepass2randomstream SOURCES TestKeePass2RandomStream.cpp
LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testmodified SOURCES TestModified.cpp
LIBS testsupport ${TEST_LIBRARIES})
LIBS testsupport ${TEST_LIBRARIES})
add_unit_test(NAME testdeletedobjects SOURCES TestDeletedObjects.cpp
LIBS ${TEST_LIBRARIES})
@@ -154,21 +158,24 @@ add_unit_test(NAME testwildcardmatcher SOURCES TestWildcardMatcher.cpp
LIBS ${TEST_LIBRARIES})
if(WITH_XC_AUTOTYPE)
add_unit_test(NAME testautotype SOURCES TestAutoType.cpp
LIBS ${TEST_LIBRARIES})
set_target_properties(testautotype PROPERTIES ENABLE_EXPORTS ON)
add_unit_test(NAME testautotype SOURCES TestAutoType.cpp
LIBS ${TEST_LIBRARIES})
set_target_properties(testautotype PROPERTIES ENABLE_EXPORTS ON)
endif()
if(WITH_XC_CRYPTO_SSH)
add_unit_test(NAME testopensshkey SOURCES TestOpenSSHKey.cpp
LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testopensshkey SOURCES TestOpenSSHKey.cpp
LIBS ${TEST_LIBRARIES})
endif()
add_unit_test(NAME testentry SOURCES TestEntry.cpp
LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testmerge SOURCES TestMerge.cpp
LIBS testsupport ${TEST_LIBRARIES})
LIBS testsupport ${TEST_LIBRARIES})
add_unit_test(NAME testpasswordgenerator SOURCES TestPasswordGenerator.cpp
LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testtotp SOURCES TestTotp.cpp
LIBS ${TEST_LIBRARIES})
@@ -203,6 +210,11 @@ add_unit_test(NAME testdatabase SOURCES TestDatabase.cpp
add_unit_test(NAME testtools SOURCES TestTools.cpp
LIBS ${TEST_LIBRARIES})
if(WITH_GUI_TESTS)
add_subdirectory(gui)
# CLI clip tests need X environment on Linux
add_unit_test(NAME testcli SOURCES TestCli.cpp
LIBS testsupport cli ${TEST_LIBRARIES})
add_subdirectory(gui)
endif(WITH_GUI_TESTS)

View File

@@ -57,7 +57,7 @@ void TestAutoType::init()
config()->set("AutoTypeEntryTitleMatch", false);
m_test->clearActions();
m_db = new Database();
m_db = QSharedPointer<Database>::create();
m_dbList.clear();
m_dbList.append(m_db);
m_group = new Group();
@@ -126,7 +126,6 @@ void TestAutoType::init()
void TestAutoType::cleanup()
{
delete m_db;
}
void TestAutoType::testInternal()

View File

@@ -20,6 +20,7 @@
#define KEEPASSX_TESTAUTOTYPE_H
#include <QObject>
#include <QSharedPointer>
class AutoType;
class AutoTypePlatformInterface;
@@ -53,8 +54,8 @@ private:
AutoTypePlatformInterface* m_platform;
AutoTypeTestInterface* m_test;
AutoType* m_autoType;
Database* m_db;
QList<Database*> m_dbList;
QSharedPointer<Database> m_db;
QList<QSharedPointer<Database>> m_dbList;
Group* m_group;
Entry* m_entry1;
Entry* m_entry2;

1019
tests/TestCli.cpp Normal file

File diff suppressed because it is too large Load Diff

73
tests/TestCli.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_TESTCLI_H
#define KEEPASSXC_TESTCLI_H
#include "core/Database.h"
#include "util/TemporaryFile.h"
#include <QFile>
#include <QScopedPointer>
#include <QTemporaryFile>
#include <QTest>
#include <QTextStream>
class TestCli : public QObject
{
Q_OBJECT
private:
QSharedPointer<Database> readTestDatabase() const;
private slots:
void initTestCase();
void init();
void cleanup();
void cleanupTestCase();
void testCommand();
void testAdd();
void testClip();
void testDiceware();
void testEdit();
void testEstimate_data();
void testEstimate();
void testExtract();
void testGenerate_data();
void testGenerate();
void testList();
void testLocate();
void testMerge();
void testRemove();
void testRemoveQuiet();
void testShow();
private:
QByteArray m_dbData;
QByteArray m_dbData2;
QScopedPointer<TemporaryFile> m_dbFile;
QScopedPointer<TemporaryFile> m_dbFile2;
QScopedPointer<TemporaryFile> m_stdoutFile;
QScopedPointer<TemporaryFile> m_stderrFile;
QScopedPointer<TemporaryFile> m_stdinFile;
FILE* m_stdoutHandle = stdout;
FILE* m_stderrHandle = stderr;
FILE* m_stdinHandle = stdin;
};
#endif // KEEPASSXC_TESTCLI_H

View File

@@ -50,8 +50,9 @@ void TestCryptoHash::test()
"8d2877eec2f63b931bd47417a81a538327af927da3e"));
QByteArray result3 = CryptoHash::hash(source2, CryptoHash::Sha512);
QCOMPARE(result3, QByteArray::fromHex("0d41b612584ed39ff72944c29494573e40f4bb95283455fae2e0be1e3565aa9f48057d59e6ff"
"d777970e282871c25a549a2763e5b724794f312c97021c42f91d"));
QCOMPARE(result3,
QByteArray::fromHex("0d41b612584ed39ff72944c29494573e40f4bb95283455fae2e0be1e3565aa9f48057d59e6ff"
"d777970e282871c25a549a2763e5b724794f312c97021c42f91d"));
CryptoHash cryptoHash4(CryptoHash::Sha512);
cryptoHash4.addData(QString("KeePa").toLatin1());

View File

@@ -31,8 +31,8 @@ const QString TestCsvExporter::ExpectedHeaderLine =
void TestCsvExporter::init()
{
m_db = new Database();
m_csvExporter = new CsvExporter();
m_db = QSharedPointer<Database>::create();
m_csvExporter = QSharedPointer<CsvExporter>::create();
}
void TestCsvExporter::initTestCase()
@@ -42,17 +42,15 @@ void TestCsvExporter::initTestCase()
void TestCsvExporter::cleanup()
{
delete m_db;
delete m_csvExporter;
}
void TestCsvExporter::testExport()
{
Group* groupRoot = m_db->rootGroup();
Group* group = new Group();
auto* group = new Group();
group->setName("Test Group Name");
group->setParent(groupRoot);
Entry* entry = new Entry();
auto* entry = new Entry();
entry->setGroup(group);
entry->setTitle("Test Entry Title");
entry->setUsername("Test Username");
@@ -64,9 +62,10 @@ void TestCsvExporter::testExport()
QVERIFY(buffer.open(QIODevice::ReadWrite));
m_csvExporter->exportDatabase(&buffer, m_db);
QString expectedResult =
QString().append(ExpectedHeaderLine).append("\"Test Group Name\",\"Test Entry Title\",\"Test Username\",\"Test "
"Password\",\"http://test.url\",\"Test Notes\"\n");
QString expectedResult = QString()
.append(ExpectedHeaderLine)
.append("\"Root/Test Group Name\",\"Test Entry Title\",\"Test Username\",\"Test "
"Password\",\"http://test.url\",\"Test Notes\"\n");
QCOMPARE(QString::fromUtf8(buffer.buffer().constData()), expectedResult);
}
@@ -83,13 +82,13 @@ void TestCsvExporter::testEmptyDatabase()
void TestCsvExporter::testNestedGroups()
{
Group* groupRoot = m_db->rootGroup();
Group* group = new Group();
auto* group = new Group();
group->setName("Test Group Name");
group->setParent(groupRoot);
Group* childGroup = new Group();
auto* childGroup = new Group();
childGroup->setName("Test Sub Group Name");
childGroup->setParent(group);
Entry* entry = new Entry();
auto* entry = new Entry();
entry->setGroup(childGroup);
entry->setTitle("Test Entry Title");
@@ -100,5 +99,5 @@ void TestCsvExporter::testNestedGroups()
QCOMPARE(QString::fromUtf8(buffer.buffer().constData()),
QString()
.append(ExpectedHeaderLine)
.append("\"Test Group Name/Test Sub Group Name\",\"Test Entry Title\",\"\",\"\",\"\",\"\"\n"));
.append("\"Root/Test Group Name/Test Sub Group Name\",\"Test Entry Title\",\"\",\"\",\"\",\"\"\n"));
}

View File

@@ -20,6 +20,7 @@
#define KEEPASSX_TESTCSVEXPORTER_H
#include <QObject>
#include <QSharedPointer>
class Database;
class CsvExporter;
@@ -40,8 +41,8 @@ private slots:
void testNestedGroups();
private:
Database* m_db;
CsvExporter* m_csvExporter;
QSharedPointer<Database> m_db;
QSharedPointer<CsvExporter> m_csvExporter;
};
#endif // KEEPASSX_TESTCSVEXPORTER_H

View File

@@ -40,14 +40,18 @@ void TestDatabase::testEmptyRecycleBinOnDisabled()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinDisabled.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("123"));
QScopedPointer<Database> db(Database::openDatabaseFile(filename, key));
QVERIFY(db);
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
// Explicitly mark DB as read-write in case it was opened from a read-only drive.
// Prevents assertion failures on CI systems when the data dir is not writable
db->setReadOnly(false);
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
db->emptyRecycleBin();
// The database must be unmodified in this test after emptying the recycle bin.
QCOMPARE(spyModified.count(), 0);
QTRY_COMPARE(spyModified.count(), 0);
}
void TestDatabase::testEmptyRecycleBinOnNotCreated()
@@ -55,14 +59,15 @@ void TestDatabase::testEmptyRecycleBinOnNotCreated()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinNotYetCreated.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("123"));
QScopedPointer<Database> db(Database::openDatabaseFile(filename, key));
QVERIFY(db);
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
db->setReadOnly(false);
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
db->emptyRecycleBin();
// The database must be unmodified in this test after emptying the recycle bin.
QCOMPARE(spyModified.count(), 0);
QTRY_COMPARE(spyModified.count(), 0);
}
void TestDatabase::testEmptyRecycleBinOnEmpty()
@@ -70,14 +75,15 @@ void TestDatabase::testEmptyRecycleBinOnEmpty()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinEmpty.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("123"));
QScopedPointer<Database> db(Database::openDatabaseFile(filename, key));
QVERIFY(db);
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
db->setReadOnly(false);
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
db->emptyRecycleBin();
// The database must be unmodified in this test after emptying the recycle bin.
QCOMPARE(spyModified.count(), 0);
QTRY_COMPARE(spyModified.count(), 0);
}
void TestDatabase::testEmptyRecycleBinWithHierarchicalData()
@@ -85,8 +91,9 @@ void TestDatabase::testEmptyRecycleBinWithHierarchicalData()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinWithData.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("123"));
QScopedPointer<Database> db(Database::openDatabaseFile(filename, key));
QVERIFY(db);
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
db->setReadOnly(false);
QFile originalFile(filename);
qint64 initialSize = originalFile.size();
@@ -97,6 +104,8 @@ void TestDatabase::testEmptyRecycleBinWithHierarchicalData()
QVERIFY(db->metadata()->recycleBin()->children().empty());
QTemporaryFile afterCleanup;
afterCleanup.open();
KeePass2Writer writer;
writer.writeDatabase(&afterCleanup, db.data());
QVERIFY(afterCleanup.size() < initialSize);

View File

@@ -30,7 +30,7 @@ void TestDeletedObjects::initTestCase()
QVERIFY(Crypto::init());
}
void TestDeletedObjects::createAndDelete(Database* db, int delObjectsSize)
void TestDeletedObjects::createAndDelete(QSharedPointer<Database> db, int delObjectsSize)
{
QCOMPARE(db->deletedObjects().size(), delObjectsSize);
Group* root = db->rootGroup();
@@ -89,32 +89,27 @@ void TestDeletedObjects::testDeletedObjectsFromFile()
KdbxXmlReader reader(KeePass2::FILE_VERSION_3_1);
reader.setStrictMode(true);
QString xmlFile = QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml");
Database* db = reader.readDatabase(xmlFile);
auto db = reader.readDatabase(xmlFile);
createAndDelete(db, 2);
delete db;
}
void TestDeletedObjects::testDeletedObjectsFromNewDb()
{
Database* db = new Database();
auto db = QSharedPointer<Database>::create();
createAndDelete(db, 0);
delete db;
}
void TestDeletedObjects::testDatabaseChange()
{
Database* db = new Database();
auto db = QSharedPointer<Database>::create();
Group* root = db->rootGroup();
int delObjectsSize = 0;
Database* db2 = new Database();
auto db2 = QSharedPointer<Database>::create();
Group* root2 = db2->rootGroup();
int delObjectsSize2 = 0;
Entry* e = new Entry();
auto* e = new Entry();
e->setGroup(root);
QCOMPARE(db->deletedObjects().size(), delObjectsSize);
@@ -130,11 +125,11 @@ void TestDeletedObjects::testDatabaseChange()
QCOMPARE(db->deletedObjects().size(), delObjectsSize);
QCOMPARE(db2->deletedObjects().size(), ++delObjectsSize2);
Group* g1 = new Group();
auto* g1 = new Group();
g1->setParent(root);
QUuid g1Uuid = QUuid::createUuid();
g1->setUuid(g1Uuid);
Entry* e1 = new Entry();
auto* e1 = new Entry();
e1->setGroup(g1);
QUuid e1Uuid = QUuid::createUuid();
e1->setUuid(e1Uuid);
@@ -146,8 +141,8 @@ void TestDeletedObjects::testDatabaseChange()
QCOMPARE(db->deletedObjects().at(delObjectsSize - 2).uuid, e1Uuid);
QCOMPARE(db->deletedObjects().at(delObjectsSize - 1).uuid, g1Uuid);
Group* group = new Group();
Entry* entry = new Entry();
auto* group = new Group();
auto* entry = new Entry();
entry->setGroup(group);
entry->setGroup(root);
@@ -155,6 +150,4 @@ void TestDeletedObjects::testDatabaseChange()
QCOMPARE(db2->deletedObjects().size(), delObjectsSize2);
delete group;
delete db;
delete db2;
}

View File

@@ -27,7 +27,7 @@ class TestDeletedObjects : public QObject
Q_OBJECT
private:
void createAndDelete(Database* db, int delObjectsSize);
void createAndDelete(QSharedPointer<Database> db, int delObjectsSize);
private slots:
void initTestCase();

View File

@@ -343,8 +343,7 @@ void TestEntry::testResolveReferencePlaceholders()
tstEntry->setGroup(root);
tstEntry->setUuid(QUuid::createUuid());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())),
entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())), entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), entry1->title());
@@ -354,8 +353,7 @@ void TestEntry::testResolveReferencePlaceholders()
QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))),
entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())),
entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())), entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())),
entry1->username());
@@ -364,8 +362,7 @@ void TestEntry::testResolveReferencePlaceholders()
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), entry1->url());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), entry1->notes());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuidToHex())),
entry2->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuidToHex())), entry2->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), entry2->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry2->username())), entry2->title());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry2->password())), entry2->title());
@@ -383,23 +380,38 @@ void TestEntry::testResolveReferencePlaceholders()
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry2->url())), entry2->url());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry2->notes())), entry2->notes());
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeTitle"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeUsername"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributePassword"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeUrl"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeNotes"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex())),
entry3->attributes()->value("AttributeTitle"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex())),
entry3->attributes()->value("AttributeUsername"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex())),
entry3->attributes()->value("AttributePassword"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex())),
entry3->attributes()->value("AttributeUrl"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex())),
entry3->attributes()->value("AttributeNotes"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeTitle"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeUsername"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributePassword"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeUrl"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeNotes"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex().toUpper())),
entry3->attributes()->value("AttributeTitle"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex().toUpper())),
entry3->attributes()->value("AttributeUsername"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex().toUpper())),
entry3->attributes()->value("AttributePassword"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex().toUpper())),
entry3->attributes()->value("AttributeUrl"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex().toUpper())),
entry3->attributes()->value("AttributeNotes"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:t@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeTitle"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:u@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeUsername"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:p@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributePassword"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:a@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeUrl"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:n@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeNotes"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:t@i:%1}").arg(entry3->uuidToHex().toLower())),
entry3->attributes()->value("AttributeTitle"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:u@i:%1}").arg(entry3->uuidToHex().toLower())),
entry3->attributes()->value("AttributeUsername"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:p@i:%1}").arg(entry3->uuidToHex().toLower())),
entry3->attributes()->value("AttributePassword"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:a@i:%1}").arg(entry3->uuidToHex().toLower())),
entry3->attributes()->value("AttributeUrl"));
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:n@i:%1}").arg(entry3->uuidToHex().toLower())),
entry3->attributes()->value("AttributeNotes"));
}
void TestEntry::testResolveNonIdPlaceholdersToUuid()
@@ -466,8 +478,7 @@ void TestEntry::testResolveNonIdPlaceholdersToUuid()
newEntry->setGroup(root);
newEntry->setNotes(newEntryNotesRaw);
const QString newEntryNotesResolved =
newEntry->resolveMultiplePlaceholders(newEntry->notes());
const QString newEntryNotesResolved = newEntry->resolveMultiplePlaceholders(newEntry->notes());
QCOMPARE(newEntryNotesResolved, referencedEntry->uuidToHex());
}
}

View File

@@ -307,7 +307,7 @@ void TestEntryModel::testProxyModel()
QList<Entry*> entryList;
entryList << entry;
modelSource->setEntryList(entryList);
modelSource->setEntries(entryList);
/**
* @author Fonic <https://github.com/fonic>
@@ -346,7 +346,7 @@ void TestEntryModel::testDatabaseDelete()
Entry* entry2 = new Entry();
entry2->setGroup(db2->rootGroup());
model->setEntryList(QList<Entry*>() << entry1 << entry2);
model->setEntries(QList<Entry*>() << entry1 << entry2);
QCOMPARE(model->rowCount(), 2);

View File

@@ -20,25 +20,34 @@
QTEST_GUILESS_MAIN(TestEntrySearcher)
void TestEntrySearcher::initTestCase()
void TestEntrySearcher::init()
{
m_groupRoot = new Group();
m_rootGroup = new Group();
}
void TestEntrySearcher::cleanupTestCase()
void TestEntrySearcher::cleanup()
{
delete m_groupRoot;
delete m_rootGroup;
}
void TestEntrySearcher::testSearch()
{
/**
* Root
* - group1 (search disabled)
* - group11
* - group2
* - group21
* - group211
* - group2111
*/
Group* group1 = new Group();
Group* group2 = new Group();
Group* group3 = new Group();
group1->setParent(m_groupRoot);
group2->setParent(m_groupRoot);
group3->setParent(m_groupRoot);
group1->setParent(m_rootGroup);
group2->setParent(m_rootGroup);
group3->setParent(m_rootGroup);
Group* group11 = new Group();
@@ -53,50 +62,74 @@ void TestEntrySearcher::testSearch()
group2111->setParent(group211);
group1->setSearchingEnabled(Group::Disable);
group11->setSearchingEnabled(Group::Enable);
Entry* eRoot = new Entry();
eRoot->setNotes("test search term test");
eRoot->setGroup(m_groupRoot);
eRoot->setTitle("test search term test");
eRoot->setGroup(m_rootGroup);
Entry* eRoot2 = new Entry();
eRoot2->setNotes("test term test");
eRoot2->setGroup(m_groupRoot);
eRoot2->setGroup(m_rootGroup);
// Searching is disabled for these
Entry* e1 = new Entry();
e1->setNotes("test search term test");
e1->setUsername("test search term test");
e1->setGroup(group1);
Entry* e11 = new Entry();
e11->setNotes("test search term test");
e11->setGroup(group11);
// End searching disabled
Entry* e2111 = new Entry();
e2111->setNotes("test search term test");
e2111->setTitle("test search term test");
e2111->setGroup(group2111);
Entry* e2111b = new Entry();
e2111b->setNotes("test search test");
e2111b->setUsername("user123");
e2111b->setPassword("testpass");
e2111b->setGroup(group2111);
Entry* e3 = new Entry();
e3->setNotes("test search term test");
e3->setUrl("test search term test");
e3->setGroup(group3);
Entry* e3b = new Entry();
e3b->setNotes("test search test");
e3b->setTitle("test search test");
e3b->setUsername("test@email.com");
e3b->setPassword("realpass");
e3b->setGroup(group3);
m_searchResult = m_entrySearcher.search("search term", m_groupRoot, Qt::CaseInsensitive);
// Simple search term testing
m_searchResult = m_entrySearcher.search("search", m_rootGroup);
QCOMPARE(m_searchResult.count(), 5);
m_searchResult = m_entrySearcher.search("search term", m_rootGroup);
QCOMPARE(m_searchResult.count(), 3);
m_searchResult = m_entrySearcher.search("search term", group211, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("search term", group211);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search("search term", group11, Qt::CaseInsensitive);
// Test advanced search terms
m_searchResult = m_entrySearcher.search("password:testpass", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search("search term", group1, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("!user:email.com", m_rootGroup);
QCOMPARE(m_searchResult.count(), 5);
m_searchResult = m_entrySearcher.search("*user:\".*@.*\\.com\"", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search("+user:email", m_rootGroup);
QCOMPARE(m_searchResult.count(), 0);
// Terms are logical AND together
m_searchResult = m_entrySearcher.search("password:pass user:user", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
// Parent group has search disabled
m_searchResult = m_entrySearcher.search("search term", group11);
QCOMPARE(m_searchResult.count(), 0);
}
@@ -105,38 +138,74 @@ void TestEntrySearcher::testAndConcatenationInSearch()
Entry* entry = new Entry();
entry->setNotes("abc def ghi");
entry->setTitle("jkl");
entry->setGroup(m_groupRoot);
entry->setGroup(m_rootGroup);
m_searchResult = m_entrySearcher.search("", m_groupRoot, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search("def", m_groupRoot, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("def", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search(" abc ghi ", m_groupRoot, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search(" abc ghi ", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search("ghi ef", m_groupRoot, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("ghi ef", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
m_searchResult = m_entrySearcher.search("abc ef xyz", m_groupRoot, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("abc ef xyz", m_rootGroup);
QCOMPARE(m_searchResult.count(), 0);
m_searchResult = m_entrySearcher.search("abc kl", m_groupRoot, Qt::CaseInsensitive);
m_searchResult = m_entrySearcher.search("abc kl", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
}
void TestEntrySearcher::testAllAttributesAreSearched()
{
Entry* entry = new Entry();
entry->setGroup(m_groupRoot);
entry->setGroup(m_rootGroup);
entry->setTitle("testTitle");
entry->setUsername("testUsername");
entry->setUrl("testUrl");
entry->setNotes("testNote");
m_searchResult =
m_entrySearcher.search("testTitle testUsername testUrl testNote", m_groupRoot, Qt::CaseInsensitive);
// Default is to AND all terms together
m_searchResult = m_entrySearcher.search("testTitle testUsername testUrl testNote", m_rootGroup);
QCOMPARE(m_searchResult.count(), 1);
}
void TestEntrySearcher::testSearchTermParser()
{
// Test standard search terms
auto terms = m_entrySearcher.parseSearchTerms("-test \"quoted \\\"string\\\"\" user:user pass:\"test me\" noquote ");
QCOMPARE(terms.length(), 5);
QCOMPARE(terms[0]->field, EntrySearcher::Field::Undefined);
QCOMPARE(terms[0]->word, QString("test"));
QCOMPARE(terms[0]->exclude, true);
QCOMPARE(terms[1]->field, EntrySearcher::Field::Undefined);
QCOMPARE(terms[1]->word, QString("quoted \\\"string\\\""));
QCOMPARE(terms[1]->exclude, false);
QCOMPARE(terms[2]->field, EntrySearcher::Field::Username);
QCOMPARE(terms[2]->word, QString("user"));
QCOMPARE(terms[3]->field, EntrySearcher::Field::Password);
QCOMPARE(terms[3]->word, QString("test me"));
QCOMPARE(terms[4]->field, EntrySearcher::Field::Undefined);
QCOMPARE(terms[4]->word, QString("noquote"));
// Test wildcard and regex search terms
terms = m_entrySearcher.parseSearchTerms("+url:*.google.com *user:\\d+\\w{2}");
QCOMPARE(terms.length(), 2);
QCOMPARE(terms[0]->field, EntrySearcher::Field::Url);
QCOMPARE(terms[0]->regex.pattern(), QString("^.*\\.google\\.com$"));
QCOMPARE(terms[1]->field, EntrySearcher::Field::Username);
QCOMPARE(terms[1]->regex.pattern(), QString("\\d+\\w{2}"));
}

View File

@@ -28,15 +28,16 @@ class TestEntrySearcher : public QObject
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testAndConcatenationInSearch();
void testSearch();
void testAllAttributesAreSearched();
void testSearchTermParser();
private:
Group* m_groupRoot;
Group* m_rootGroup;
EntrySearcher m_entrySearcher;
QList<Entry*> m_searchResult;
};

View File

@@ -25,7 +25,7 @@
namespace QTest
{
template <> inline char* toString(const Group::TriState& triState)
{
QString value;

View File

@@ -18,7 +18,7 @@
#include "TestGroup.h"
#include "TestGlobal.h"
#include "stub/TestClock.h"
#include "mock/MockClock.h"
#include <QSignalSpy>
@@ -29,7 +29,7 @@ QTEST_GUILESS_MAIN(TestGroup)
namespace
{
TestClock* m_clock = nullptr;
MockClock* m_clock = nullptr;
}
void TestGroup::initTestCase()
@@ -42,13 +42,13 @@ void TestGroup::initTestCase()
void TestGroup::init()
{
Q_ASSERT(m_clock == nullptr);
m_clock = new TestClock(2010, 5, 5, 10, 30, 10);
TestClock::setup(m_clock);
m_clock = new MockClock(2010, 5, 5, 10, 30, 10);
MockClock::setup(m_clock);
}
void TestGroup::cleanup()
{
TestClock::teardown();
MockClock::teardown();
m_clock = nullptr;
}
@@ -493,57 +493,64 @@ void TestGroup::testFindEntry()
Entry* entry;
entry = db->rootGroup()->findEntry(entry1->uuidToHex());
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByUuid(entry1->uuid());
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry1"));
entry = db->rootGroup()->findEntry(QString("entry1"));
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByPath(QString("entry1"));
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry1"));
// We also can find the entry with the leading slash.
entry = db->rootGroup()->findEntry(QString("/entry1"));
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByPath(QString("/entry1"));
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry1"));
// But two slashes should not be accepted.
entry = db->rootGroup()->findEntry(QString("//entry1"));
QVERIFY(entry == nullptr);
entry = db->rootGroup()->findEntryByPath(QString("//entry1"));
QVERIFY(!entry);
entry = db->rootGroup()->findEntry(entry2->uuidToHex());
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByUuid(entry2->uuid());
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry2"));
entry = db->rootGroup()->findEntry(QString("group1/entry2"));
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByPath(QString("group1/entry2"));
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry2"));
entry = db->rootGroup()->findEntry(QString("/entry2"));
QVERIFY(entry == nullptr);
entry = db->rootGroup()->findEntryByPath(QString("/entry2"));
QVERIFY(!entry);
// We also can find the entry with the leading slash.
entry = db->rootGroup()->findEntry(QString("/group1/entry2"));
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByPath(QString("/group1/entry2"));
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry2"));
// Should also find the entry only by title.
entry = db->rootGroup()->findEntry(QString("entry2"));
QVERIFY(entry != nullptr);
entry = db->rootGroup()->findEntryByPath(QString("entry2"));
QVERIFY(entry);
QCOMPARE(entry->title(), QString("entry2"));
entry = db->rootGroup()->findEntry(QString("invalid/path/to/entry2"));
QVERIFY(entry == nullptr);
entry = db->rootGroup()->findEntryByPath(QString("invalid/path/to/entry2"));
QVERIFY(!entry);
entry = db->rootGroup()->findEntry(QString("entry27"));
QVERIFY(entry == nullptr);
entry = db->rootGroup()->findEntryByPath(QString("entry27"));
QVERIFY(!entry);
// A valid UUID that does not exist in this database.
entry = db->rootGroup()->findEntry(QString("febfb01ebcdf9dbd90a3f1579dc75281"));
QVERIFY(entry == nullptr);
entry = db->rootGroup()->findEntryByUuid(QUuid("febfb01ebcdf9dbd90a3f1579dc75281"));
QVERIFY(!entry);
// An invalid UUID.
entry = db->rootGroup()->findEntry(QString("febfb01ebcdf9dbd90a3f1579dc"));
QVERIFY(entry == nullptr);
entry = db->rootGroup()->findEntryByUuid(QUuid("febfb01ebcdf9dbd90a3f1579dc"));
QVERIFY(!entry);
// Empty strings
entry = db->rootGroup()->findEntryByUuid({});
QVERIFY(!entry);
entry = db->rootGroup()->findEntryByPath({});
QVERIFY(!entry);
}
void TestGroup::testFindGroupByPath()
@@ -561,51 +568,51 @@ void TestGroup::testFindGroupByPath()
Group* group;
group = db->rootGroup()->findGroupByPath("/");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), db->rootGroup()->uuid());
// We also accept it if the leading slash is missing.
group = db->rootGroup()->findGroupByPath("");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), db->rootGroup()->uuid());
group = db->rootGroup()->findGroupByPath("/group1/");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), group1->uuid());
// We also accept it if the leading slash is missing.
group = db->rootGroup()->findGroupByPath("group1/");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), group1->uuid());
// Too many slashes at the end
group = db->rootGroup()->findGroupByPath("group1//");
QVERIFY(group == nullptr);
QVERIFY(!group);
// Missing a slash at the end.
group = db->rootGroup()->findGroupByPath("/group1");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), group1->uuid());
// Too many slashes at the start
group = db->rootGroup()->findGroupByPath("//group1");
QVERIFY(group == nullptr);
QVERIFY(!group);
group = db->rootGroup()->findGroupByPath("/group1/group2/");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), group2->uuid());
// We also accept it if the leading slash is missing.
group = db->rootGroup()->findGroupByPath("group1/group2/");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), group2->uuid());
group = db->rootGroup()->findGroupByPath("group1/group2");
QVERIFY(group != nullptr);
QVERIFY(group);
QCOMPARE(group->uuid(), group2->uuid());
group = db->rootGroup()->findGroupByPath("invalid");
QVERIFY(group == nullptr);
QVERIFY(!group);
}
void TestGroup::testPrint()
@@ -697,7 +704,7 @@ void TestGroup::testLocate()
QVERIFY(results.contains("/entry1"));
results = db->rootGroup()->locate("invalid");
QVERIFY(results.size() == 0);
QVERIFY(results.isEmpty());
results = db->rootGroup()->locate("google");
QVERIFY(results.size() == 1);
@@ -725,37 +732,37 @@ void TestGroup::testAddEntryWithPath()
group2->setParent(group1);
Entry* entry = db->rootGroup()->addEntryWithPath("entry1");
QVERIFY(entry != nullptr);
QVERIFY(entry);
QVERIFY(!entry->uuid().isNull());
entry = db->rootGroup()->addEntryWithPath("entry1");
QVERIFY(entry == nullptr);
QVERIFY(!entry);
entry = db->rootGroup()->addEntryWithPath("/entry1");
QVERIFY(entry == nullptr);
QVERIFY(!entry);
entry = db->rootGroup()->addEntryWithPath("entry2");
QVERIFY(entry != nullptr);
QVERIFY(entry);
QVERIFY(entry->title() == "entry2");
QVERIFY(!entry->uuid().isNull());
entry = db->rootGroup()->addEntryWithPath("/entry3");
QVERIFY(entry != nullptr);
QVERIFY(entry);
QVERIFY(entry->title() == "entry3");
QVERIFY(!entry->uuid().isNull());
entry = db->rootGroup()->addEntryWithPath("/group1/entry4");
QVERIFY(entry != nullptr);
QVERIFY(entry);
QVERIFY(entry->title() == "entry4");
QVERIFY(!entry->uuid().isNull());
entry = db->rootGroup()->addEntryWithPath("/group1/group2/entry5");
QVERIFY(entry != nullptr);
QVERIFY(entry);
QVERIFY(entry->title() == "entry5");
QVERIFY(!entry->uuid().isNull());
entry = db->rootGroup()->addEntryWithPath("/group1/invalid_group/entry6");
QVERIFY(entry == nullptr);
QVERIFY(!entry);
delete db;
}

View File

@@ -37,7 +37,7 @@ void TestKdbx2::initTestCase()
/**
* Helper method for verifying contents of the sample KDBX 2 file.
*/
void TestKdbx2::verifyKdbx2Db(Database* db)
void TestKdbx2::verifyKdbx2Db(QSharedPointer<Database> db)
{
QVERIFY(db);
QCOMPARE(db->rootGroup()->name(), QString("Format200"));
@@ -67,12 +67,13 @@ void TestKdbx2::testFormat200()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/Format200.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("a"));
auto db = QSharedPointer<Database>::create();
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
QVERIFY(reader.readDatabase(filename, key, db.data()));
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_2 & KeePass2::FILE_VERSION_CRITICAL_MASK);
QVERIFY2(!reader.hasError(), reader.errorString().toStdString().c_str());
verifyKdbx2Db(db.data());
verifyKdbx2Db(db);
}
void TestKdbx2::testFormat200Upgrade()
@@ -80,8 +81,9 @@ void TestKdbx2::testFormat200Upgrade()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/Format200.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("a"));
auto db = QSharedPointer<Database>::create();
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
reader.readDatabase(filename, key, db.data());
QVERIFY2(!reader.hasError(), reader.errorString().toStdString().c_str());
QVERIFY(!db.isNull());
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_2 & KeePass2::FILE_VERSION_CRITICAL_MASK);
@@ -92,20 +94,21 @@ void TestKdbx2::testFormat200Upgrade()
// write KDBX 3 to upgrade it
KeePass2Writer writer;
writer.writeDatabase(&buffer, db.data());
QVERIFY(writer.writeDatabase(&buffer, db.data()));
if (writer.hasError()) {
QFAIL(qPrintable(QString("Error while writing database: %1").arg(writer.errorString())));
}
// read buffer back
buffer.seek(0);
QScopedPointer<Database> targetDb(reader.readDatabase(&buffer, key));
auto targetDb = QSharedPointer<Database>::create();
QVERIFY(reader.readDatabase(&buffer, key, targetDb.data()));
if (reader.hasError()) {
QFAIL(qPrintable(QString("Error while reading database: %1").arg(reader.errorString())));
}
// database should now be upgraded to KDBX 3 without data loss
verifyKdbx2Db(targetDb.data());
verifyKdbx2Db(targetDb);
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_3_1 & KeePass2::FILE_VERSION_CRITICAL_MASK);
QCOMPARE(targetDb->kdf()->uuid(), KeePass2::KDF_AES_KDBX3);
}

View File

@@ -32,7 +32,7 @@ private slots:
void testFormat200Upgrade();
private:
void verifyKdbx2Db(Database* db);
void verifyKdbx2Db(QSharedPointer<Database> db);
};
#endif // KEEPASSXC_TEST_KDBX2_H

View File

@@ -33,7 +33,7 @@ void TestKdbx3::initTestCaseImpl()
{
}
Database* TestKdbx3::readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString)
QSharedPointer<Database> TestKdbx3::readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString)
{
KdbxXmlReader reader(KeePass2::FILE_VERSION_3_1);
reader.setStrictMode(strictMode);
@@ -43,7 +43,7 @@ Database* TestKdbx3::readXml(const QString& path, bool strictMode, bool& hasErro
return db;
}
Database* TestKdbx3::readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString)
QSharedPointer<Database> TestKdbx3::readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString)
{
KdbxXmlReader reader(KeePass2::FILE_VERSION_3_1);
reader.setStrictMode(strictMode);
@@ -63,12 +63,12 @@ void TestKdbx3::writeXml(QBuffer* buf, Database* db, bool& hasError, QString& er
void TestKdbx3::readKdbx(QIODevice* device,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString)
{
KeePass2Reader reader;
db.reset(reader.readDatabase(device, key));
reader.readDatabase(device, key, db.data());
hasError = reader.hasError();
if (hasError) {
errorString = reader.errorString();
@@ -78,12 +78,12 @@ void TestKdbx3::readKdbx(QIODevice* device,
void TestKdbx3::readKdbx(const QString& path,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString)
{
KeePass2Reader reader;
db.reset(reader.readDatabase(path, key));
reader.readDatabase(path, key, db.data());
hasError = reader.hasError();
if (hasError) {
errorString = reader.errorString();
@@ -108,7 +108,8 @@ void TestKdbx3::testFormat300()
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("a"));
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
auto db = QSharedPointer<Database>::create();
QVERIFY(reader.readDatabase(filename, key, db.data()));
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_3);
QVERIFY(db.data());
QVERIFY(!reader.hasError());
@@ -123,11 +124,12 @@ void TestKdbx3::testNonAscii()
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create(QString::fromUtf8("\xce\x94\xc3\xb6\xd8\xb6")));
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
QVERIFY(db.data());
QVERIFY(!reader.hasError());
QCOMPARE(db->metadata()->name(), QString("NonAsciiTest"));
QCOMPARE(db->compressionAlgo(), Database::CompressionNone);
QCOMPARE(db->compressionAlgorithm(), Database::CompressionNone);
}
void TestKdbx3::testCompressed()
@@ -136,11 +138,12 @@ void TestKdbx3::testCompressed()
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create(""));
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
QVERIFY(db.data());
QVERIFY(!reader.hasError());
QCOMPARE(db->metadata()->name(), QString("Compressed"));
QCOMPARE(db->compressionAlgo(), Database::CompressionGZip);
QCOMPARE(db->compressionAlgorithm(), Database::CompressionGZip);
}
void TestKdbx3::testProtectedStrings()
@@ -149,7 +152,8 @@ void TestKdbx3::testProtectedStrings()
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("masterpw"));
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(filename, key, nullptr, false));
QVERIFY(db.data());
QVERIFY(!reader.hasError());
QCOMPARE(db->metadata()->name(), QString("Protected Strings Test"));
@@ -175,8 +179,6 @@ void TestKdbx3::testBrokenHeaderHash()
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/BrokenHeaderHash.kdbx");
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create(""));
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
QVERIFY(!db.data());
QVERIFY(reader.hasError());
auto db = QSharedPointer<Database>::create();
QVERIFY(!db->open(filename, key, nullptr, false));
}

View File

@@ -34,18 +34,18 @@ private slots:
protected:
void initTestCaseImpl() override;
Database* readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString) override;
Database* readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString) override;
QSharedPointer<Database> readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString) override;
QSharedPointer<Database> readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString) override;
void writeXml(QBuffer* buf, Database* db, bool& hasError, QString& errorString) override;
void readKdbx(QIODevice* device,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString) override;
void readKdbx(const QString& path,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString) override;
void writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString) override;

View File

@@ -37,7 +37,7 @@ void TestKdbx4::initTestCaseImpl()
m_kdbxSourceDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)));
}
Database* TestKdbx4::readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString)
QSharedPointer<Database> TestKdbx4::readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString)
{
KdbxXmlReader reader(KeePass2::FILE_VERSION_4);
reader.setStrictMode(strictMode);
@@ -47,7 +47,7 @@ Database* TestKdbx4::readXml(const QString& path, bool strictMode, bool& hasErro
return db;
}
Database* TestKdbx4::readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString)
QSharedPointer<Database> TestKdbx4::readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString)
{
KdbxXmlReader reader(KeePass2::FILE_VERSION_4);
reader.setStrictMode(strictMode);
@@ -67,12 +67,12 @@ void TestKdbx4::writeXml(QBuffer* buf, Database* db, bool& hasError, QString& er
void TestKdbx4::readKdbx(QIODevice* device,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString)
{
KeePass2Reader reader;
db.reset(reader.readDatabase(device, key));
reader.readDatabase(device, key, db.data());
hasError = reader.hasError();
if (hasError) {
errorString = reader.errorString();
@@ -82,12 +82,12 @@ void TestKdbx4::readKdbx(QIODevice* device,
void TestKdbx4::readKdbx(const QString& path,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString)
{
KeePass2Reader reader;
db.reset(reader.readDatabase(path, key));
reader.readDatabase(path, key, db.data());
hasError = reader.hasError();
if (hasError) {
errorString = reader.errorString();
@@ -116,7 +116,8 @@ void TestKdbx4::testFormat400()
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("t"));
KeePass2Reader reader;
QScopedPointer<Database> db(reader.readDatabase(filename, key));
auto db = QSharedPointer<Database>::create();
reader.readDatabase(filename, key, db.data());
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_4);
QVERIFY(db.data());
QVERIFY(!reader.hasError());
@@ -174,7 +175,8 @@ void TestKdbx4::testFormat400Upgrade()
// read buffer back
buffer.seek(0);
KeePass2Reader reader;
QScopedPointer<Database> targetDb(reader.readDatabase(&buffer, key));
auto targetDb = QSharedPointer<Database>::create();
reader.readDatabase(&buffer, key, targetDb.data());
if (reader.hasError()) {
QFAIL(qPrintable(QString("Error while reading database: %1").arg(reader.errorString())));
}
@@ -199,12 +201,12 @@ void TestKdbx4::testFormat400Upgrade_data()
auto constexpr kdbx3 = KeePass2::FILE_VERSION_3_1 & KeePass2::FILE_VERSION_CRITICAL_MASK;
auto constexpr kdbx4 = KeePass2::FILE_VERSION_4 & KeePass2::FILE_VERSION_CRITICAL_MASK;
QTest::newRow("Argon2 + AES") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES << false << kdbx4;
QTest::newRow("AES-KDF + AES") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES << false << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES << false << kdbx3;
QTest::newRow("Argon2 + AES + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES << true << kdbx4;
QTest::newRow("AES-KDF + AES + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES << true << kdbx4;
QTest::newRow("Argon2 + AES") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES256 << false << kdbx4;
QTest::newRow("AES-KDF + AES") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << false << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << false << kdbx3;
QTest::newRow("Argon2 + AES + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("AES-KDF + AES + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("Argon2 + ChaCha20") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_CHACHA20 << false << kdbx4;
QTest::newRow("AES-KDF + ChaCha20") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << false << kdbx4;
@@ -292,14 +294,15 @@ void TestKdbx4::testUpgradeMasterKeyIntegrity()
// paranoid check that we cannot decrypt the database without a key
buffer.seek(0);
KeePass2Reader reader;
QScopedPointer<Database> db2;
db2.reset(reader.readDatabase(&buffer, QSharedPointer<CompositeKey>::create()));
auto db2 = QSharedPointer<Database>::create();
reader.readDatabase(&buffer, QSharedPointer<CompositeKey>::create(), db2.data());
QVERIFY(reader.hasError());
// check that we can read back the database with the original composite key,
// i.e., no components have been lost on the way
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKey));
db2 = QSharedPointer<Database>::create();
reader.readDatabase(&buffer, compositeKey, db2.data());
if (reader.hasError()) {
QFAIL(qPrintable(reader.errorString()));
}
@@ -317,11 +320,11 @@ void TestKdbx4::testUpgradeMasterKeyIntegrity_data()
QTest::newRow("Upgrade (explicit): kdf-argon2") << QString("kdf-argon2") << KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (explicit): kdf-aes-kdbx4") << QString("kdf-aes-kdbx4") << KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): public-customdata") << QString("public-customdata") << KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): rootgroup-customdata") << QString("rootgroup-customdata")
<< KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): rootgroup-customdata")
<< QString("rootgroup-customdata") << KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): group-customdata") << QString("group-customdata") << KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): rootentry-customdata") << QString("rootentry-customdata")
<< KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): rootentry-customdata")
<< QString("rootentry-customdata") << KeePass2::FILE_VERSION_4;
QTest::newRow("Upgrade (implicit): entry-customdata") << QString("entry-customdata") << KeePass2::FILE_VERSION_4;
}
@@ -396,7 +399,8 @@ void TestKdbx4::testCustomData()
// read buffer back
buffer.seek(0);
KeePass2Reader reader;
QSharedPointer<Database> newDb(reader.readDatabase(&buffer, QSharedPointer<CompositeKey>::create()));
auto newDb = QSharedPointer<Database>::create();
reader.readDatabase(&buffer, QSharedPointer<CompositeKey>::create(), newDb.data());
// test all custom data are read back successfully from KDBX
QCOMPARE(newDb->publicCustomData(), publicCustomData);

View File

@@ -35,18 +35,18 @@ private slots:
protected:
void initTestCaseImpl() override;
Database* readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString) override;
Database* readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString) override;
QSharedPointer<Database> readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString) override;
QSharedPointer<Database> readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString) override;
void writeXml(QBuffer* buf, Database* db, bool& hasError, QString& errorString) override;
void readKdbx(const QString& path,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString) override;
void readKdbx(QIODevice* device,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString) override;
void writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString) override;

View File

@@ -177,15 +177,13 @@ void TestKeePass1Reader::testFileKey()
QString dbFilename = QString("%1/%2.kdb").arg(QString(KEEPASSX_TEST_DATA_DIR), name);
QString keyFilename = QString("%1/%2.key").arg(QString(KEEPASSX_TEST_DATA_DIR), name);
Database* db = reader.readDatabase(dbFilename, QString(), keyFilename);
auto db = reader.readDatabase(dbFilename, QString(), keyFilename);
QVERIFY(db);
QVERIFY(!reader.hasError());
QCOMPARE(db->rootGroup()->children().size(), 1);
QCOMPARE(db->rootGroup()->children().at(0)->name(), name);
reopenDatabase(db, QString(), keyFilename);
delete db;
}
void TestKeePass1Reader::testFileKey_data()
@@ -205,15 +203,13 @@ void TestKeePass1Reader::testCompositeKey()
QString dbFilename = QString("%1/%2.kdb").arg(QString(KEEPASSX_TEST_DATA_DIR), name);
QString keyFilename = QString("%1/FileKeyHex.key").arg(QString(KEEPASSX_TEST_DATA_DIR));
Database* db = reader.readDatabase(dbFilename, "mypassword", keyFilename);
auto db = reader.readDatabase(dbFilename, "mypassword", keyFilename);
QVERIFY(db);
QVERIFY(!reader.hasError());
QCOMPARE(db->rootGroup()->children().size(), 1);
QCOMPARE(db->rootGroup()->children().at(0)->name(), name);
reopenDatabase(db, "mypassword", keyFilename);
delete db;
}
void TestKeePass1Reader::testTwofish()
@@ -224,13 +220,11 @@ void TestKeePass1Reader::testTwofish()
QString dbFilename = QString("%1/%2.kdb").arg(QString(KEEPASSX_TEST_DATA_DIR), name);
Database* db = reader.readDatabase(dbFilename, "masterpw", 0);
auto db = reader.readDatabase(dbFilename, "masterpw", 0);
QVERIFY(db);
QVERIFY(!reader.hasError());
QCOMPARE(db->rootGroup()->children().size(), 1);
QCOMPARE(db->rootGroup()->children().at(0)->name(), name);
delete db;
}
void TestKeePass1Reader::testCP1252Password()
@@ -242,18 +236,15 @@ void TestKeePass1Reader::testCP1252Password()
QString dbFilename = QString("%1/%2.kdb").arg(QString(KEEPASSX_TEST_DATA_DIR), name);
QString password = QString::fromUtf8("\xe2\x80\x9e\x70\x61\x73\x73\x77\x6f\x72\x64\xe2\x80\x9d");
Database* db = reader.readDatabase(dbFilename, password, 0);
auto db = reader.readDatabase(dbFilename, password, 0);
QVERIFY(db);
QVERIFY(!reader.hasError());
QCOMPARE(db->rootGroup()->children().size(), 1);
QCOMPARE(db->rootGroup()->children().at(0)->name(), name);
delete db;
}
void TestKeePass1Reader::cleanupTestCase()
{
delete m_db;
}
QDateTime TestKeePass1Reader::genDT(int year, int month, int day, int hour, int min)
@@ -263,18 +254,20 @@ QDateTime TestKeePass1Reader::genDT(int year, int month, int day, int hour, int
return QDateTime(date, time, Qt::UTC);
}
void TestKeePass1Reader::reopenDatabase(Database* db, const QString& password, const QString& keyfileName)
void TestKeePass1Reader::reopenDatabase(QSharedPointer<Database> db,
const QString& password,
const QString& keyfileName)
{
QBuffer buffer;
buffer.open(QIODevice::ReadWrite);
KeePass2Writer writer;
writer.writeDatabase(&buffer, db);
writer.writeDatabase(&buffer, db.data());
QVERIFY(!writer.hasError());
QVERIFY(buffer.seek(0));
auto key = QSharedPointer<CompositeKey>::create();
if (!password.isNull()) {
if (!password.isEmpty()) {
key->addKey(QSharedPointer<PasswordKey>::create(password));
}
if (!keyfileName.isEmpty()) {
@@ -284,7 +277,7 @@ void TestKeePass1Reader::reopenDatabase(Database* db, const QString& password, c
}
KeePass2Reader reader;
QScopedPointer<Database> newDb(reader.readDatabase(&buffer, key));
QVERIFY(newDb);
auto newDb = QSharedPointer<Database>::create();
QVERIFY(reader.readDatabase(&buffer, key, newDb.data()));
QVERIFY(!reader.hasError());
}

View File

@@ -20,6 +20,7 @@
#include <QDateTime>
#include <QObject>
#include <QSharedPointer>
class Database;
@@ -43,9 +44,9 @@ private slots:
private:
static QDateTime genDT(int year, int month, int day, int hour, int min);
static void reopenDatabase(Database* db, const QString& password, const QString& keyfileName);
static void reopenDatabase(QSharedPointer<Database> db, const QString& password, const QString& keyfileName);
Database* m_db;
QSharedPointer<Database> m_db;
};
#endif // KEEPASSX_TESTKEEPASS1READER_H

View File

@@ -17,7 +17,7 @@
#include "TestKeePass2Format.h"
#include "TestGlobal.h"
#include "stub/TestClock.h"
#include "mock/MockClock.h"
#include "core/Metadata.h"
#include "crypto/Crypto.h"
@@ -34,7 +34,7 @@ void TestKeePass2Format::initTestCase()
// read raw XML database
bool hasError;
QString errorString;
m_xmlDb.reset(readXml(QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml"), true, hasError, errorString));
m_xmlDb = readXml(QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml"), true, hasError, errorString);
if (hasError) {
QFAIL(qPrintable(QString("Error while reading XML: ").append(errorString)));
}
@@ -44,7 +44,7 @@ void TestKeePass2Format::initTestCase()
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("test"));
m_kdbxSourceDb.reset(new Database());
m_kdbxSourceDb = QSharedPointer<Database>::create();
m_kdbxSourceDb->setKey(key);
m_kdbxSourceDb->metadata()->setName("TESTDB");
Group* group = m_kdbxSourceDb->rootGroup();
@@ -78,14 +78,14 @@ void TestKeePass2Format::testXmlMetadata()
{
QCOMPARE(m_xmlDb->metadata()->generator(), QString("KeePass"));
QCOMPARE(m_xmlDb->metadata()->name(), QString("ANAME"));
QCOMPARE(m_xmlDb->metadata()->nameChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 53));
QCOMPARE(m_xmlDb->metadata()->nameChanged(), MockClock::datetimeUtc(2010, 8, 8, 17, 24, 53));
QCOMPARE(m_xmlDb->metadata()->description(), QString("ADESC"));
QCOMPARE(m_xmlDb->metadata()->descriptionChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 27, 12));
QCOMPARE(m_xmlDb->metadata()->descriptionChanged(), MockClock::datetimeUtc(2010, 8, 8, 17, 27, 12));
QCOMPARE(m_xmlDb->metadata()->defaultUserName(), QString("DEFUSERNAME"));
QCOMPARE(m_xmlDb->metadata()->defaultUserNameChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 27, 45));
QCOMPARE(m_xmlDb->metadata()->defaultUserNameChanged(), MockClock::datetimeUtc(2010, 8, 8, 17, 27, 45));
QCOMPARE(m_xmlDb->metadata()->maintenanceHistoryDays(), 127);
QCOMPARE(m_xmlDb->metadata()->color(), QColor(0xff, 0xef, 0x00));
QCOMPARE(m_xmlDb->metadata()->masterKeyChanged(), TestClock::datetimeUtc(2012, 4, 5, 17, 9, 34));
QCOMPARE(m_xmlDb->metadata()->masterKeyChanged(), MockClock::datetimeUtc(2012, 4, 5, 17, 9, 34));
QCOMPARE(m_xmlDb->metadata()->masterKeyChangeRec(), 101);
QCOMPARE(m_xmlDb->metadata()->masterKeyChangeForce(), -1);
QCOMPARE(m_xmlDb->metadata()->protectTitle(), false);
@@ -96,9 +96,9 @@ void TestKeePass2Format::testXmlMetadata()
QCOMPARE(m_xmlDb->metadata()->recycleBinEnabled(), true);
QVERIFY(m_xmlDb->metadata()->recycleBin() != nullptr);
QCOMPARE(m_xmlDb->metadata()->recycleBin()->name(), QString("Recycle Bin"));
QCOMPARE(m_xmlDb->metadata()->recycleBinChanged(), TestClock::datetimeUtc(2010, 8, 25, 16, 12, 57));
QCOMPARE(m_xmlDb->metadata()->recycleBinChanged(), MockClock::datetimeUtc(2010, 8, 25, 16, 12, 57));
QVERIFY(m_xmlDb->metadata()->entryTemplatesGroup() == nullptr);
QCOMPARE(m_xmlDb->metadata()->entryTemplatesGroupChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 19));
QCOMPARE(m_xmlDb->metadata()->entryTemplatesGroupChanged(), MockClock::datetimeUtc(2010, 8, 8, 17, 24, 19));
QVERIFY(m_xmlDb->metadata()->lastSelectedGroup() != nullptr);
QCOMPARE(m_xmlDb->metadata()->lastSelectedGroup()->name(), QString("NewDatabase"));
QVERIFY(m_xmlDb->metadata()->lastTopVisibleGroup() == m_xmlDb->metadata()->lastSelectedGroup());
@@ -136,17 +136,18 @@ void TestKeePass2Format::testXmlGroupRoot()
QCOMPARE(group->iconUuid(), QUuid());
QVERIFY(group->isExpanded());
TimeInfo ti = group->timeInfo();
QCOMPARE(ti.lastModificationTime(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 27));
QCOMPARE(ti.creationTime(), TestClock::datetimeUtc(2010, 8, 7, 17, 24, 27));
QCOMPARE(ti.lastAccessTime(), TestClock::datetimeUtc(2010, 8, 9, 9, 9, 44));
QCOMPARE(ti.expiryTime(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 17));
QCOMPARE(ti.lastModificationTime(), MockClock::datetimeUtc(2010, 8, 8, 17, 24, 27));
QCOMPARE(ti.creationTime(), MockClock::datetimeUtc(2010, 8, 7, 17, 24, 27));
QCOMPARE(ti.lastAccessTime(), MockClock::datetimeUtc(2010, 8, 9, 9, 9, 44));
QCOMPARE(ti.expiryTime(), MockClock::datetimeUtc(2010, 8, 8, 17, 24, 17));
QVERIFY(!ti.expires());
QCOMPARE(ti.usageCount(), 52);
QCOMPARE(ti.locationChanged(), TestClock::datetimeUtc(2010, 8, 8, 17, 24, 27));
QCOMPARE(ti.locationChanged(), MockClock::datetimeUtc(2010, 8, 8, 17, 24, 27));
QCOMPARE(group->defaultAutoTypeSequence(), QString(""));
QCOMPARE(group->autoTypeEnabled(), Group::Inherit);
QCOMPARE(group->searchingEnabled(), Group::Inherit);
QCOMPARE(group->lastTopVisibleEntry()->uuid(), QUuid::fromRfc4122(QByteArray::fromBase64("+wSUOv6qf0OzW8/ZHAs2sA==")));
QCOMPARE(group->lastTopVisibleEntry()->uuid(),
QUuid::fromRfc4122(QByteArray::fromBase64("+wSUOv6qf0OzW8/ZHAs2sA==")));
QCOMPARE(group->children().size(), 3);
QVERIFY(m_xmlDb->metadata()->recycleBin() == m_xmlDb->rootGroup()->children().at(2));
@@ -203,13 +204,13 @@ void TestKeePass2Format::testXmlEntry1()
QCOMPARE(entry->tags(), QString("a b c"));
const TimeInfo ti = entry->timeInfo();
QCOMPARE(ti.lastModificationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 19, 25));
QCOMPARE(ti.creationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
QCOMPARE(ti.lastAccessTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 19, 25));
QCOMPARE(ti.expiryTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 12, 57));
QCOMPARE(ti.lastModificationTime(), MockClock::datetimeUtc(2010, 8, 25, 16, 19, 25));
QCOMPARE(ti.creationTime(), MockClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
QCOMPARE(ti.lastAccessTime(), MockClock::datetimeUtc(2010, 8, 25, 16, 19, 25));
QCOMPARE(ti.expiryTime(), MockClock::datetimeUtc(2010, 8, 25, 16, 12, 57));
QVERIFY(!ti.expires());
QCOMPARE(ti.usageCount(), 8);
QCOMPARE(ti.locationChanged(), TestClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
QCOMPARE(ti.locationChanged(), MockClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
QList<QString> attrs = entry->attributes()->keys();
QCOMPARE(entry->attributes()->value("Notes"), QString("Notes"));
@@ -308,7 +309,7 @@ void TestKeePass2Format::testXmlEntryHistory()
const Entry* entry = entryMain->historyItems().at(0);
QCOMPARE(entry->uuid(), entryMain->uuid());
QVERIFY(!entry->parent());
QCOMPARE(entry->timeInfo().lastModificationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
QCOMPARE(entry->timeInfo().lastModificationTime(), MockClock::datetimeUtc(2010, 8, 25, 16, 13, 54));
QCOMPARE(entry->timeInfo().usageCount(), 3);
QCOMPARE(entry->title(), QString("Sample Entry"));
QCOMPARE(entry->url(), QString("http://www.somesite.com/"));
@@ -318,7 +319,7 @@ void TestKeePass2Format::testXmlEntryHistory()
const Entry* entry = entryMain->historyItems().at(1);
QCOMPARE(entry->uuid(), entryMain->uuid());
QVERIFY(!entry->parent());
QCOMPARE(entry->timeInfo().lastModificationTime(), TestClock::datetimeUtc(2010, 8, 25, 16, 15, 43));
QCOMPARE(entry->timeInfo().lastModificationTime(), MockClock::datetimeUtc(2010, 8, 25, 16, 15, 43));
QCOMPARE(entry->timeInfo().usageCount(), 7);
QCOMPARE(entry->title(), QString("Sample Entry 1"));
QCOMPARE(entry->url(), QString("http://www.somesite.com/"));
@@ -332,11 +333,11 @@ void TestKeePass2Format::testXmlDeletedObjects()
delObj = objList.takeFirst();
QCOMPARE(delObj.uuid, QUuid::fromRfc4122(QByteArray::fromBase64("5K/bzWCSmkCv5OZxYl4N/w==")));
QCOMPARE(delObj.deletionTime, TestClock::datetimeUtc(2010, 8, 25, 16, 14, 12));
QCOMPARE(delObj.deletionTime, MockClock::datetimeUtc(2010, 8, 25, 16, 14, 12));
delObj = objList.takeFirst();
QCOMPARE(delObj.uuid, QUuid::fromRfc4122(QByteArray::fromBase64("80h8uSNWgkKhKCp1TgXF7g==")));
QCOMPARE(delObj.deletionTime, TestClock::datetimeUtc(2010, 8, 25, 16, 14, 14));
QCOMPARE(delObj.deletionTime, MockClock::datetimeUtc(2010, 8, 25, 16, 14, 14));
QVERIFY(objList.isEmpty());
}
@@ -351,7 +352,7 @@ void TestKeePass2Format::testXmlBroken()
QVERIFY(QFile::exists(xmlFile));
bool hasError;
QString errorString;
QScopedPointer<Database> db(readXml(xmlFile, strictMode, hasError, errorString));
auto db = readXml(xmlFile, strictMode, hasError, errorString);
if (hasError) {
qWarning("Reader error: %s", qPrintable(errorString));
}
@@ -392,7 +393,7 @@ void TestKeePass2Format::testXmlEmptyUuids()
QVERIFY(QFile::exists(xmlFile));
bool hasError;
QString errorString;
QScopedPointer<Database> dbp(readXml(xmlFile, true, hasError, errorString));
auto db = readXml(xmlFile, true, hasError, errorString);
if (hasError) {
qWarning("Reader error: %s", qPrintable(errorString));
}
@@ -446,7 +447,7 @@ void TestKeePass2Format::testXmlInvalidXmlChars()
QVERIFY(!hasError);
buffer.seek(0);
QScopedPointer<Database> dbRead(readXml(&buffer, true, hasError, errorString));
auto dbRead = readXml(&buffer, true, hasError, errorString);
if (hasError) {
qWarning("Database read error: %s", qPrintable(errorString));
}
@@ -474,7 +475,7 @@ void TestKeePass2Format::testXmlRepairUuidHistoryItem()
QVERIFY(QFile::exists(xmlFile));
bool hasError;
QString errorString;
QScopedPointer<Database> db(readXml(xmlFile, false, hasError, errorString));
auto db = readXml(xmlFile, false, hasError, errorString);
if (hasError) {
qWarning("Database read error: %s", qPrintable(errorString));
}
@@ -503,6 +504,7 @@ void TestKeePass2Format::testReadBackTargetDb()
QString errorString;
m_kdbxTargetBuffer.seek(0);
m_kdbxTargetDb = QSharedPointer<Database>::create();
readKdbx(&m_kdbxTargetBuffer, key, m_kdbxTargetDb, hasError, errorString);
if (hasError) {
QFAIL(qPrintable(QString("Error while reading database: ").append(errorString)));
@@ -548,7 +550,7 @@ void TestKeePass2Format::testKdbxDeviceFailure()
QScopedPointer<Database> db(new Database());
db->setKey(key);
// Disable compression so we write a predictable number of bytes.
db->setCompressionAlgo(Database::CompressionNone);
db->setCompressionAlgorithm(Database::CompressionNone);
auto entry = new Entry();
entry->setParent(db->rootGroup());
@@ -569,7 +571,7 @@ void TestKeePass2Format::testKdbxDeviceFailure()
*/
void TestKeePass2Format::testDuplicateAttachments()
{
QScopedPointer<Database> db(new Database());
auto db = QSharedPointer<Database>::create();
db->setKey(QSharedPointer<CompositeKey>::create());
const QByteArray attachment1("abc");

View File

@@ -21,7 +21,7 @@
#include <QBuffer>
#include <QDateTime>
#include <QObject>
#include <QScopedPointer>
#include <QSharedPointer>
#include "core/Database.h"
@@ -67,25 +67,25 @@ private slots:
protected:
virtual void initTestCaseImpl() = 0;
virtual Database* readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString) = 0;
virtual Database* readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString) = 0;
virtual QSharedPointer<Database> readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString) = 0;
virtual QSharedPointer<Database> readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString) = 0;
virtual void writeXml(QBuffer* buf, Database* db, bool& hasError, QString& errorString) = 0;
virtual void readKdbx(QIODevice* device,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString) = 0;
virtual void readKdbx(const QString& path,
QSharedPointer<const CompositeKey> key,
QScopedPointer<Database>& db,
QSharedPointer<Database> db,
bool& hasError,
QString& errorString) = 0;
virtual void writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString) = 0;
QScopedPointer<Database> m_xmlDb;
QScopedPointer<Database> m_kdbxSourceDb;
QScopedPointer<Database> m_kdbxTargetDb;
QSharedPointer<Database> m_xmlDb;
QSharedPointer<Database> m_kdbxSourceDb;
QSharedPointer<Database> m_kdbxTargetDb;
private:
QBuffer m_kdbxTargetBuffer;

View File

@@ -87,8 +87,8 @@ void TestKeys::testFileKey()
compositeKey->addKey(fileKey);
QScopedPointer<Database> db(reader.readDatabase(dbFilename, compositeKey));
QVERIFY(db);
auto db = QSharedPointer<Database>::create();
QVERIFY(db->open(dbFilename, compositeKey, nullptr, false));
QVERIFY(!reader.hasError());
QCOMPARE(db->metadata()->name(), QString("%1 Database").arg(name));
}
@@ -152,7 +152,8 @@ void TestKeys::testCreateAndOpenFileKey()
dbBuffer.reset();
KeePass2Reader reader;
QScopedPointer<Database> dbRead(reader.readDatabase(&dbBuffer, compositeKey));
auto dbRead = QSharedPointer<Database>::create();
reader.readDatabase(&dbBuffer, compositeKey, dbRead.data());
if (reader.hasError()) {
QFAIL(reader.errorString().toUtf8().constData());
}
@@ -226,7 +227,7 @@ void TestKeys::testCompositeKeyComponents()
auto fileKeyEnc = QSharedPointer<FileKey>::create();
QString error;
fileKeyEnc->load(QString("%1/%2").arg(QString(KEEPASSX_TEST_DATA_DIR), "FileKeyHashed.key"), &error);
if (!error.isNull()) {
if (!error.isEmpty()) {
QFAIL(qPrintable(error));
}
auto challengeResponseKeyEnc = QSharedPointer<MockChallengeResponseKey>::create(QByteArray(16, 0x10));
@@ -236,7 +237,7 @@ void TestKeys::testCompositeKeyComponents()
compositeKeyEnc->addKey(fileKeyEnc);
compositeKeyEnc->addChallengeResponseKey(challengeResponseKeyEnc);
QScopedPointer<Database> db1(new Database());
auto db1 = QSharedPointer<Database>::create();
db1->setKey(compositeKeyEnc);
KeePass2Writer writer;
@@ -245,27 +246,27 @@ void TestKeys::testCompositeKeyComponents()
QVERIFY(writer.writeDatabase(&buffer, db1.data()));
buffer.seek(0);
QScopedPointer<Database> db2;
auto db2 = QSharedPointer<Database>::create();
KeePass2Reader reader;
auto compositeKeyDec1 = QSharedPointer<CompositeKey>::create();
// try decryption and subsequently add key components until decryption is successful
db2.reset(reader.readDatabase(&buffer, compositeKeyDec1));
QVERIFY(!reader.readDatabase(&buffer, compositeKeyDec1, db2.data()));
QVERIFY(reader.hasError());
compositeKeyDec1->addKey(passwordKeyEnc);
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKeyDec1));
QVERIFY(!reader.readDatabase(&buffer, compositeKeyDec1, db2.data()));
QVERIFY(reader.hasError());
compositeKeyDec1->addKey(fileKeyEnc);
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKeyDec1));
QVERIFY(!reader.readDatabase(&buffer, compositeKeyDec1, db2.data()));
QVERIFY(reader.hasError());
compositeKeyDec1->addChallengeResponseKey(challengeResponseKeyEnc);
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKeyDec1));
QVERIFY(reader.readDatabase(&buffer, compositeKeyDec1, db2.data()));
// now we should be able to open the database
if (reader.hasError()) {
QFAIL(qPrintable(reader.errorString()));
@@ -277,20 +278,20 @@ void TestKeys::testCompositeKeyComponents()
compositeKeyDec2->addKey(fileKeyEnc);
compositeKeyDec2->addChallengeResponseKey(challengeResponseKeyEnc);
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKeyDec2));
QVERIFY(!reader.readDatabase(&buffer, compositeKeyDec2, db2.data()));
QVERIFY(reader.hasError());
auto compositeKeyDec3 = QSharedPointer<CompositeKey>::create();
compositeKeyDec3->addKey(passwordKeyEnc);
auto fileKeyWrong = QSharedPointer<FileKey>::create();
fileKeyWrong->load(QString("%1/%2").arg(QString(KEEPASSX_TEST_DATA_DIR), "FileKeyHashed2.key"), &error);
if (!error.isNull()) {
if (!error.isEmpty()) {
QFAIL(qPrintable(error));
}
compositeKeyDec3->addKey(fileKeyWrong);
compositeKeyDec3->addChallengeResponseKey(challengeResponseKeyEnc);
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKeyDec3));
QVERIFY(!reader.readDatabase(&buffer, compositeKeyDec3, db2.data()));
QVERIFY(reader.hasError());
auto compositeKeyDec4 = QSharedPointer<CompositeKey>::create();
@@ -298,6 +299,6 @@ void TestKeys::testCompositeKeyComponents()
compositeKeyDec4->addKey(fileKeyEnc);
compositeKeyDec4->addChallengeResponseKey(QSharedPointer<MockChallengeResponseKey>::create(QByteArray(16, 0x20)));
buffer.seek(0);
db2.reset(reader.readDatabase(&buffer, compositeKeyDec4));
QVERIFY(!reader.readDatabase(&buffer, compositeKeyDec4, db2.data()));
QVERIFY(reader.hasError());
}

View File

@@ -17,12 +17,14 @@
#include "TestMerge.h"
#include "TestGlobal.h"
#include "stub/TestClock.h"
#include "mock/MockClock.h"
#include "core/Merger.h"
#include "core/Metadata.h"
#include "crypto/Crypto.h"
#include <QSignalSpy>
QTEST_GUILESS_MAIN(TestMerge)
namespace
@@ -34,8 +36,8 @@ namespace
return timeInfo;
}
TestClock* m_clock = nullptr;
}
MockClock* m_clock = nullptr;
} // namespace
void TestMerge::initTestCase()
{
@@ -47,13 +49,13 @@ void TestMerge::initTestCase()
void TestMerge::init()
{
Q_ASSERT(m_clock == nullptr);
m_clock = new TestClock(2010, 5, 5, 10, 30, 10);
TestClock::setup(m_clock);
m_clock = new MockClock(2010, 5, 5, 10, 30, 10);
MockClock::setup(m_clock);
}
void TestMerge::cleanup()
{
TestClock::teardown();
MockClock::teardown();
m_clock = nullptr;
}
@@ -125,7 +127,7 @@ void TestMerge::testResolveConflictNewer()
QVERIFY(groupDestinationInitial != nullptr);
QCOMPARE(groupDestinationInitial->entries().size(), 2);
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entrySourceInitial != nullptr);
QVERIFY(entrySourceInitial->group() == groupSourceInitial);
@@ -159,7 +161,7 @@ void TestMerge::testResolveConflictNewer()
QCOMPARE(groupDestinationMerged->entries().size(), 2);
QCOMPARE(groupDestinationMerged->timeInfo(), groupDestinationInitialTimeInfo);
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMerged != nullptr);
QVERIFY(entryDestinationMerged->group() != nullptr);
QCOMPARE(entryDestinationMerged->password(), QString("password"));
@@ -192,7 +194,7 @@ void TestMerge::testResolveConflictExisting()
QVERIFY(groupDestinationInitial != nullptr);
QCOMPARE(groupSourceInitial->entries().size(), 2);
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entrySourceInitial != nullptr);
QVERIFY(entrySourceInitial->group() == groupSourceInitial);
@@ -213,7 +215,7 @@ void TestMerge::testResolveConflictExisting()
QPointer<Group> groupDestinationUpdated = dbDestination->rootGroup()->findChildByName("group1");
QVERIFY(groupDestinationUpdated != nullptr);
QCOMPARE(groupDestinationUpdated->entries().size(), 2);
QPointer<Entry> entryDestinationUpdated = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationUpdated = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationUpdated != nullptr);
QVERIFY(entryDestinationUpdated->group() == groupDestinationUpdated);
@@ -244,7 +246,7 @@ void TestMerge::testResolveConflictExisting()
QCOMPARE(groupDestinationMerged->entries().size(), 2);
QCOMPARE(groupDestinationMerged->timeInfo(), groupDestinationUpdatedNewerTimeInfo);
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMerged != nullptr);
QCOMPARE(entryDestinationMerged->password(), QString("password2"));
QCOMPARE(entryDestinationMerged->timeInfo(), entryDestinationUpdatedNewerTimeInfo);
@@ -300,7 +302,9 @@ void TestMerge::testResolveConflictDuplicate()
"KeepBoth should not reuse the UUIDs when cloning.");
}
void TestMerge::testResolveConflictTemplate(int mergeMode, std::function<void(Database*, const QMap<const char*, QDateTime>&)> verification)
void TestMerge::testResolveConflictTemplate(
int mergeMode,
std::function<void(Database*, const QMap<const char*, QDateTime>&)> verification)
{
QMap<const char*, QDateTime> timestamps;
timestamps["initialTime"] = m_clock->currentDateTimeUtc();
@@ -382,9 +386,9 @@ void TestMerge::testResolveConflictTemplate(int mergeMode, std::function<void(Da
m_clock->advanceMinute(1);
QPointer<Entry> deletedEntryDestination = dbDestination->rootGroup()->findEntry("deletedDestination");
QPointer<Entry> deletedEntryDestination = dbDestination->rootGroup()->findEntryByPath("deletedDestination");
dbDestination->recycleEntry(deletedEntryDestination);
QPointer<Entry> deletedEntrySource = dbSource->rootGroup()->findEntry("deletedSource");
QPointer<Entry> deletedEntrySource = dbSource->rootGroup()->findEntryByPath("deletedSource");
dbSource->recycleEntry(deletedEntrySource);
m_clock->advanceMinute(1);
@@ -428,11 +432,12 @@ void TestMerge::testResolveConflictTemplate(int mergeMode, std::function<void(Da
verification(dbDestination.data(), timestamps);
QVERIFY(dbDestination->rootGroup()->findEntry("entryDestination"));
QVERIFY(dbDestination->rootGroup()->findEntry("entrySource"));
QVERIFY(dbDestination->rootGroup()->findEntryByPath("entryDestination"));
QVERIFY(dbDestination->rootGroup()->findEntryByPath("entrySource"));
}
void TestMerge::testDeletionConflictTemplate(int mergeMode, std::function<void(Database*, const QMap<QString, QUuid>&)> verification)
void TestMerge::testDeletionConflictTemplate(int mergeMode,
std::function<void(Database*, const QMap<QString, QUuid>&)> verification)
{
QMap<QString, QUuid> identifiers;
m_clock->currentDateTimeUtc();
@@ -607,7 +612,7 @@ void TestMerge::assertDeletionNewerOnly(Database* db, const QMap<QString, QUuid>
QVERIFY(db->containsDeletedObject(identifiers["EntryDeletedInTargetAfterEntryUpdatedInSource"]));
}
void TestMerge::assertDeletionLocalOnly(Database* db, const QMap<QString, QUuid> &identifiers)
void TestMerge::assertDeletionLocalOnly(Database* db, const QMap<QString, QUuid>& identifiers)
{
QPointer<Group> mergedRootGroup = db->rootGroup();
@@ -645,66 +650,80 @@ void TestMerge::assertDeletionLocalOnly(Database* db, const QMap<QString, QUuid>
QVERIFY(db->containsDeletedObject(identifiers["EntryDeletedInTargetAfterEntryUpdatedInSource"]));
}
void TestMerge::assertUpdateMergedEntry1(Entry *mergedEntry1, const QMap<const char *, QDateTime> &timestamps)
void TestMerge::assertUpdateMergedEntry1(Entry* mergedEntry1, const QMap<const char*, QDateTime>& timestamps)
{
QCOMPARE(mergedEntry1->historyItems().count(), 4);
QCOMPARE(mergedEntry1->historyItems().at(0)->notes(), QString(""));
QCOMPARE(mergedEntry1->historyItems().at(0)->timeInfo().lastModificationTime(), timestamps["initialTime"]);
QCOMPARE(mergedEntry1->historyItems().at(1)->notes(), QString(""));
QCOMPARE(mergedEntry1->historyItems().at(1)->timeInfo().lastModificationTime(), timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(1)->timeInfo().lastModificationTime(),
timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(2)->notes(), QString("1 Common"));
QCOMPARE(mergedEntry1->historyItems().at(2)->timeInfo().lastModificationTime(), timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(2)->timeInfo().lastModificationTime(),
timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(3)->notes(), QString("2 Source"));
QCOMPARE(mergedEntry1->historyItems().at(3)->timeInfo().lastModificationTime(), timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(3)->timeInfo().lastModificationTime(),
timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry1->notes(), QString("3 Destination"));
QCOMPARE(mergedEntry1->timeInfo().lastModificationTime(), timestamps["newestDivergingHistoryTime"]);
}
void TestMerge::assertUpdateReappliedEntry2(Entry *mergedEntry2, const QMap<const char *, QDateTime> &timestamps)
void TestMerge::assertUpdateReappliedEntry2(Entry* mergedEntry2, const QMap<const char*, QDateTime>& timestamps)
{
QCOMPARE(mergedEntry2->historyItems().count(), 5);
QCOMPARE(mergedEntry2->historyItems().at(0)->notes(), QString(""));
QCOMPARE(mergedEntry2->historyItems().at(0)->timeInfo().lastModificationTime(), timestamps["initialTime"]);
QCOMPARE(mergedEntry2->historyItems().at(1)->notes(), QString(""));
QCOMPARE(mergedEntry2->historyItems().at(1)->timeInfo().lastModificationTime(), timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(1)->timeInfo().lastModificationTime(),
timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(2)->notes(), QString("1 Common"));
QCOMPARE(mergedEntry2->historyItems().at(2)->timeInfo().lastModificationTime(), timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(2)->timeInfo().lastModificationTime(),
timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(3)->notes(), QString("2 Destination"));
QCOMPARE(mergedEntry2->historyItems().at(3)->timeInfo().lastModificationTime(), timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(3)->timeInfo().lastModificationTime(),
timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(4)->notes(), QString("3 Source"));
QCOMPARE(mergedEntry2->historyItems().at(4)->timeInfo().lastModificationTime(), timestamps["newestDivergingHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(4)->timeInfo().lastModificationTime(),
timestamps["newestDivergingHistoryTime"]);
QCOMPARE(mergedEntry2->notes(), QString("2 Destination"));
QCOMPARE(mergedEntry2->timeInfo().lastModificationTime(), timestamps["mergeTime"]);
}
void TestMerge::assertUpdateReappliedEntry1(Entry *mergedEntry1, const QMap<const char *, QDateTime> &timestamps)
void TestMerge::assertUpdateReappliedEntry1(Entry* mergedEntry1, const QMap<const char*, QDateTime>& timestamps)
{
QCOMPARE(mergedEntry1->historyItems().count(), 5);
QCOMPARE(mergedEntry1->historyItems().at(0)->notes(), QString(""));
QCOMPARE(mergedEntry1->historyItems().at(0)->timeInfo().lastModificationTime(), timestamps["initialTime"]);
QCOMPARE(mergedEntry1->historyItems().at(1)->notes(), QString(""));
QCOMPARE(mergedEntry1->historyItems().at(1)->timeInfo().lastModificationTime(), timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(1)->timeInfo().lastModificationTime(),
timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(2)->notes(), QString("1 Common"));
QCOMPARE(mergedEntry1->historyItems().at(2)->timeInfo().lastModificationTime(), timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(2)->timeInfo().lastModificationTime(),
timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(3)->notes(), QString("2 Source"));
QCOMPARE(mergedEntry1->historyItems().at(3)->timeInfo().lastModificationTime(), timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(3)->timeInfo().lastModificationTime(),
timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(4)->notes(), QString("3 Destination"));
QCOMPARE(mergedEntry1->historyItems().at(4)->timeInfo().lastModificationTime(), timestamps["newestDivergingHistoryTime"]);
QCOMPARE(mergedEntry1->historyItems().at(4)->timeInfo().lastModificationTime(),
timestamps["newestDivergingHistoryTime"]);
QCOMPARE(mergedEntry1->notes(), QString("2 Source"));
QCOMPARE(mergedEntry1->timeInfo().lastModificationTime(), timestamps["mergeTime"]);
}
void TestMerge::assertUpdateMergedEntry2(Entry *mergedEntry2, const QMap<const char *, QDateTime> &timestamps)
void TestMerge::assertUpdateMergedEntry2(Entry* mergedEntry2, const QMap<const char*, QDateTime>& timestamps)
{
QCOMPARE(mergedEntry2->historyItems().count(), 4);
QCOMPARE(mergedEntry2->historyItems().at(0)->notes(), QString(""));
QCOMPARE(mergedEntry2->historyItems().at(0)->timeInfo().lastModificationTime(), timestamps["initialTime"]);
QCOMPARE(mergedEntry2->historyItems().at(1)->notes(), QString(""));
QCOMPARE(mergedEntry2->historyItems().at(1)->timeInfo().lastModificationTime(), timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(1)->timeInfo().lastModificationTime(),
timestamps["oldestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(2)->notes(), QString("1 Common"));
QCOMPARE(mergedEntry2->historyItems().at(2)->timeInfo().lastModificationTime(), timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(2)->timeInfo().lastModificationTime(),
timestamps["newestCommonHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(3)->notes(), QString("2 Destination"));
QCOMPARE(mergedEntry2->historyItems().at(3)->timeInfo().lastModificationTime(), timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry2->historyItems().at(3)->timeInfo().lastModificationTime(),
timestamps["oldestDivergingHistoryTime"]);
QCOMPARE(mergedEntry2->notes(), QString("3 Source"));
QCOMPARE(mergedEntry2->timeInfo().lastModificationTime(), timestamps["newestDivergingHistoryTime"]);
}
@@ -790,7 +809,7 @@ void TestMerge::testMoveEntry()
QScopedPointer<Database> dbSource(
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entrySourceInitial != nullptr);
QPointer<Group> groupSourceInitial = dbSource->rootGroup()->findChildByName("group2");
@@ -807,7 +826,7 @@ void TestMerge::testMoveEntry()
Merger merger(dbSource.data(), dbDestination.data());
merger.merge();
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMerged != nullptr);
QCOMPARE(entryDestinationMerged->group()->name(), QString("group2"));
QCOMPARE(dbDestination->rootGroup()->entriesRecursive().size(), 2);
@@ -824,7 +843,7 @@ void TestMerge::testMoveEntryPreserveChanges()
QScopedPointer<Database> dbSource(
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entrySourceInitial != nullptr);
QPointer<Group> group2Source = dbSource->rootGroup()->findChildByName("group2");
@@ -835,7 +854,7 @@ void TestMerge::testMoveEntryPreserveChanges()
entrySourceInitial->setGroup(group2Source);
QCOMPARE(entrySourceInitial->group()->name(), QString("group2"));
QPointer<Entry> entryDestinationInitial = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationInitial = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationInitial != nullptr);
m_clock->advanceSecond(1);
@@ -849,7 +868,7 @@ void TestMerge::testMoveEntryPreserveChanges()
Merger merger(dbSource.data(), dbDestination.data());
merger.merge();
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMerged != nullptr);
QCOMPARE(entryDestinationMerged->group()->name(), QString("group2"));
QCOMPARE(dbDestination->rootGroup()->entriesRecursive().size(), 2);
@@ -892,7 +911,7 @@ void TestMerge::testMoveEntryIntoNewGroup()
groupSourceCreated->setUuid(QUuid::createUuid());
groupSourceCreated->setParent(dbSource->rootGroup());
QPointer<Entry> entrySourceMoved = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceMoved = dbSource->rootGroup()->findEntryByPath("entry1");
entrySourceMoved->setGroup(groupSourceCreated);
m_clock->advanceSecond(1);
@@ -907,7 +926,7 @@ void TestMerge::testMoveEntryIntoNewGroup()
QCOMPARE(groupDestinationMerged->name(), QString("group3"));
QCOMPARE(groupDestinationMerged->entries().size(), 1);
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMerged != nullptr);
QCOMPARE(entryDestinationMerged->group()->name(), QString("group3"));
}
@@ -929,7 +948,7 @@ void TestMerge::testUpdateEntryDifferentLocation()
m_clock->advanceSecond(1);
QPointer<Entry> entryDestinationMoved = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMoved = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMoved != nullptr);
entryDestinationMoved->setGroup(groupDestinationCreated);
QUuid uuidBeforeSyncing = entryDestinationMoved->uuid();
@@ -938,7 +957,7 @@ void TestMerge::testUpdateEntryDifferentLocation()
// Change the entry in the source db.
m_clock->advanceSecond(1);
QPointer<Entry> entrySourceMoved = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceMoved = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entrySourceMoved != nullptr);
entrySourceMoved->beginUpdate();
entrySourceMoved->setUsername("username");
@@ -954,7 +973,7 @@ void TestMerge::testUpdateEntryDifferentLocation()
QCOMPARE(dbDestination->rootGroup()->entriesRecursive().size(), 2);
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entryDestinationMerged != nullptr);
QVERIFY(entryDestinationMerged->group() != nullptr);
QCOMPARE(entryDestinationMerged->username(), QString("username"));
@@ -983,7 +1002,7 @@ void TestMerge::testUpdateGroup()
dbSource->metadata()->addCustomIcon(customIconId, customIcon);
groupSourceInitial->setIcon(customIconId);
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entrySourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entrySourceInitial != nullptr);
entrySourceInitial->setGroup(groupSourceInitial);
entrySourceInitial->setTitle("entry1 renamed");
@@ -996,7 +1015,7 @@ void TestMerge::testUpdateGroup()
QCOMPARE(dbDestination->rootGroup()->entriesRecursive().size(), 2);
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntry("entry1 renamed");
QPointer<Entry> entryDestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1 renamed");
QVERIFY(entryDestinationMerged != nullptr);
QVERIFY(entryDestinationMerged->group() != nullptr);
QCOMPARE(entryDestinationMerged->group()->name(), QString("group2 renamed"));
@@ -1125,7 +1144,7 @@ void TestMerge::testDeletedEntry()
m_clock->advanceSecond(1);
QPointer<Entry> entry1SourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1SourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1SourceInitial != nullptr);
QUuid entry1Uuid = entry1SourceInitial->uuid();
delete entry1SourceInitial;
@@ -1133,7 +1152,7 @@ void TestMerge::testDeletedEntry()
m_clock->advanceSecond(1);
QPointer<Entry> entry2DestinationInitial = dbDestination->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2DestinationInitial = dbDestination->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2DestinationInitial != nullptr);
QUuid entry2Uuid = entry2DestinationInitial->uuid();
delete entry2DestinationInitial;
@@ -1144,10 +1163,10 @@ void TestMerge::testDeletedEntry()
Merger merger(dbSource.data(), dbDestination.data());
merger.merge();
QPointer<Entry> entry1DestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1DestinationMerged);
QVERIFY(!dbDestination->containsDeletedObject(entry1Uuid));
QPointer<Entry> entry2DestinationMerged = dbDestination->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2DestinationMerged);
// Uuid in db and deletedObjects is intended according to KeePass #1752
QVERIFY(dbDestination->containsDeletedObject(entry2Uuid));
@@ -1176,9 +1195,9 @@ void TestMerge::testDeletedGroup()
QPointer<Group> group1SourceInitial = dbSource->rootGroup()->findChildByName("group1");
QVERIFY(group1SourceInitial != nullptr);
QPointer<Entry> entry1SourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1SourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1SourceInitial != nullptr);
QPointer<Entry> entry2SourceInitial = dbSource->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2SourceInitial = dbSource->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2SourceInitial != nullptr);
QUuid group1Uuid = group1SourceInitial->uuid();
QUuid entry1Uuid = entry1SourceInitial->uuid();
@@ -1206,11 +1225,11 @@ void TestMerge::testDeletedGroup()
QVERIFY(!dbDestination->containsDeletedObject(entry2Uuid));
QVERIFY(!dbDestination->containsDeletedObject(group2Uuid));
QPointer<Entry> entry1DestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1DestinationMerged);
QPointer<Entry> entry2DestinationMerged = dbDestination->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2DestinationMerged);
QPointer<Entry> entry3DestinationMerged = dbDestination->rootGroup()->findEntry("entry3");
QPointer<Entry> entry3DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry3");
QVERIFY(entry3DestinationMerged);
QPointer<Group> group1DestinationMerged = dbDestination->rootGroup()->findChildByName("group1");
QVERIFY(group1DestinationMerged);
@@ -1228,7 +1247,7 @@ void TestMerge::testDeletedRevertedEntry()
m_clock->advanceSecond(1);
QPointer<Entry> entry1DestinationInitial = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1DestinationInitial = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1DestinationInitial != nullptr);
QUuid entry1Uuid = entry1DestinationInitial->uuid();
delete entry1DestinationInitial;
@@ -1236,7 +1255,7 @@ void TestMerge::testDeletedRevertedEntry()
m_clock->advanceSecond(1);
QPointer<Entry> entry2SourceInitial = dbSource->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2SourceInitial = dbSource->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2SourceInitial != nullptr);
QUuid entry2Uuid = entry2SourceInitial->uuid();
delete entry2SourceInitial;
@@ -1244,11 +1263,11 @@ void TestMerge::testDeletedRevertedEntry()
m_clock->advanceSecond(1);
QPointer<Entry> entry1SourceInitial = dbSource->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1SourceInitial = dbSource->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1SourceInitial != nullptr);
entry1SourceInitial->setNotes("Updated");
QPointer<Entry> entry2DestinationInitial = dbDestination->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2DestinationInitial = dbDestination->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2DestinationInitial != nullptr);
entry2DestinationInitial->setNotes("Updated");
@@ -1259,10 +1278,10 @@ void TestMerge::testDeletedRevertedEntry()
QVERIFY(dbDestination->containsDeletedObject(entry1Uuid));
QVERIFY(!dbDestination->containsDeletedObject(entry2Uuid));
QPointer<Entry> entry1DestinationMerged = dbDestination->rootGroup()->findEntry("entry1");
QPointer<Entry> entry1DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry1");
QVERIFY(entry1DestinationMerged);
QVERIFY(entry1DestinationMerged->notes() == "Updated");
QPointer<Entry> entry2DestinationMerged = dbDestination->rootGroup()->findEntry("entry2");
QPointer<Entry> entry2DestinationMerged = dbDestination->rootGroup()->findEntryByPath("entry2");
QVERIFY(entry2DestinationMerged);
QVERIFY(entry2DestinationMerged->notes() == "Updated");
}
@@ -1355,6 +1374,37 @@ void TestMerge::testResolveGroupConflictOlder()
QVERIFY(groupDestinationMerged != nullptr);
}
void TestMerge::testMergeNotModified()
{
QScopedPointer<Database> dbDestination(createTestDatabase());
QScopedPointer<Database> dbSource(
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
QSignalSpy modifiedSignalSpy(dbDestination.data(), SIGNAL(databaseModified()));
Merger merger(dbSource.data(), dbDestination.data());
merger.merge();
QTRY_VERIFY(modifiedSignalSpy.empty());
}
void TestMerge::testMergeModified()
{
QScopedPointer<Database> dbDestination(createTestDatabase());
QScopedPointer<Database> dbSource(
createTestDatabaseStructureClone(dbDestination.data(), Entry::CloneNoFlags, Group::CloneIncludeEntries));
QSignalSpy modifiedSignalSpy(dbDestination.data(), SIGNAL(databaseModified()));
// Make sure the two changes have a different timestamp.
QTest::qSleep(1);
Entry* entry = dbSource->rootGroup()->findEntryByPath("entry1");
entry->beginUpdate();
entry->setTitle("new title");
entry->endUpdate();
Merger merger(dbSource.data(), dbDestination.data());
merger.merge();
QTRY_VERIFY(!modifiedSignalSpy.empty());
}
Database* TestMerge::createTestDatabase()
{
Database* db = new Database();

View File

@@ -36,6 +36,8 @@ private slots:
void testResolveConflictNewer();
void testResolveConflictExisting();
void testResolveGroupConflictOlder();
void testMergeNotModified();
void testMergeModified();
void testResolveConflictDuplicate();
void testResolveConflictEntry_Synchronize();
void testResolveConflictEntry_KeepLocal();
@@ -64,15 +66,16 @@ private slots:
private:
Database* createTestDatabase();
Database* createTestDatabaseStructureClone(Database* source, int entryFlags, int groupFlags);
void testResolveConflictTemplate(int mergeMode, std::function<void(Database*, const QMap<const char*, QDateTime>&)> verification);
void testDeletionConflictTemplate(int mergeMode, std::function<void(Database*, const QMap<QString, QUuid>&)> verification);
static void assertDeletionNewerOnly(Database *db, const QMap<QString, QUuid> &identifiers);
static void assertDeletionLocalOnly(Database *db, const QMap<QString, QUuid> &identifiers);
static void assertUpdateMergedEntry1(Entry *entry, const QMap<const char*, QDateTime> &timestamps);
static void assertUpdateReappliedEntry2(Entry *entry, const QMap<const char*, QDateTime> &timestamps);
static void assertUpdateReappliedEntry1(Entry *entry, const QMap<const char*, QDateTime> &timestamps);
static void assertUpdateMergedEntry2(Entry *entry, const QMap<const char *, QDateTime> &timestamps);
void testResolveConflictTemplate(int mergeMode,
std::function<void(Database*, const QMap<const char*, QDateTime>&)> verification);
void testDeletionConflictTemplate(int mergeMode,
std::function<void(Database*, const QMap<QString, QUuid>&)> verification);
static void assertDeletionNewerOnly(Database* db, const QMap<QString, QUuid>& identifiers);
static void assertDeletionLocalOnly(Database* db, const QMap<QString, QUuid>& identifiers);
static void assertUpdateMergedEntry1(Entry* entry, const QMap<const char*, QDateTime>& timestamps);
static void assertUpdateReappliedEntry2(Entry* entry, const QMap<const char*, QDateTime>& timestamps);
static void assertUpdateReappliedEntry1(Entry* entry, const QMap<const char*, QDateTime>& timestamps);
static void assertUpdateMergedEntry2(Entry* entry, const QMap<const char*, QDateTime>& timestamps);
};
#endif // KEEPASSX_TESTMERGE_H

View File

@@ -16,7 +16,7 @@
*/
#include "TestModified.h"
#include "stub/TestClock.h"
#include "mock/MockClock.h"
#include <QSignalSpy>
#include <QTest>
@@ -31,7 +31,7 @@ QTEST_GUILESS_MAIN(TestModified)
namespace
{
TestClock* m_clock = nullptr;
MockClock* m_clock = nullptr;
}
void TestModified::initTestCase()
@@ -42,13 +42,13 @@ void TestModified::initTestCase()
void TestModified::init()
{
Q_ASSERT(m_clock == nullptr);
m_clock = new TestClock(2010, 5, 5, 10, 30, 10);
TestClock::setup(m_clock);
m_clock = new MockClock(2010, 5, 5, 10, 30, 10);
MockClock::setup(m_clock);
}
void TestModified::cleanup()
{
TestClock::teardown();
MockClock::teardown();
m_clock = nullptr;
}
@@ -61,67 +61,83 @@ void TestModified::testSignals()
QScopedPointer<Database> db(new Database());
auto* root = db->rootGroup();
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
db->setKey(compositeKey);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
auto* group1 = new Group();
group1->setParent(root);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
auto* group2 = new Group();
group2->setParent(root);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group2->setParent(root, 0);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
auto* entry1 = new Entry();
entry1->setGroup(group1);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
QScopedPointer<Database> db2(new Database());
auto* root2 = db2->rootGroup();
QSignalSpy spyModified2(db2.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified2(db2.data(), SIGNAL(databaseModified()));
group1->setParent(root2);
QCOMPARE(spyModified.count(), ++spyCount);
QCOMPARE(spyModified2.count(), ++spyCount2);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
++spyCount2;
QTRY_COMPARE(spyModified2.count(), spyCount2);
entry1->setTitle("test");
QCOMPARE(spyModified.count(), spyCount);
QCOMPARE(spyModified2.count(), ++spyCount2);
QTRY_COMPARE(spyModified.count(), spyCount);
++spyCount2;
QTRY_COMPARE(spyModified2.count(), spyCount2);
auto* entry2 = new Entry();
entry2->setGroup(group2);
QCOMPARE(spyModified.count(), ++spyCount);
QCOMPARE(spyModified2.count(), spyCount2);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified2.count(), spyCount2);
entry2->setGroup(root2);
QCOMPARE(spyModified.count(), ++spyCount);
QCOMPARE(spyModified2.count(), ++spyCount2);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
++spyCount2;
QTRY_COMPARE(spyModified2.count(), spyCount2);
entry2->setTitle("test2");
QCOMPARE(spyModified.count(), spyCount);
QCOMPARE(spyModified2.count(), ++spyCount2);
QTRY_COMPARE(spyModified.count(), spyCount);
++spyCount2;
QTRY_COMPARE(spyModified2.count(), spyCount2);
auto* group3 = new Group();
group3->setParent(root);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
auto* group4 = new Group();
group4->setParent(group3);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
delete group4;
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
delete entry2;
QCOMPARE(spyModified2.count(), ++spyCount2);
++spyCount2;
QTRY_COMPARE(spyModified2.count(), spyCount2);
QCOMPARE(spyModified.count(), spyCount);
QCOMPARE(spyModified2.count(), spyCount2);
QTRY_COMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified2.count(), spyCount2);
}
void TestModified::testGroupSets()
@@ -133,58 +149,67 @@ void TestModified::testGroupSets()
auto* group = new Group();
group->setParent(root);
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
root->setUuid(QUuid::createUuid());
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
root->setUuid(root->uuid());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
root->setName("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
root->setName(root->name());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
root->setNotes("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
root->setNotes(root->notes());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
root->setIcon(1);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
root->setIcon(root->iconNumber());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
root->setIcon(QUuid::createUuid());
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
root->setIcon(root->iconUuid());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
group->setUuid(QUuid::createUuid());
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group->setUuid(group->uuid());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
group->setName("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group->setName(group->name());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
group->setNotes("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group->setNotes(group->notes());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
group->setIcon(1);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group->setIcon(group->iconNumber());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
group->setIcon(QUuid::createUuid());
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group->setIcon(group->iconUuid());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
}
void TestModified::testEntrySets()
@@ -198,106 +223,127 @@ void TestModified::testEntrySets()
auto* entry = new Entry();
entry->setGroup(group);
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
entry->setUuid(QUuid::createUuid());
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setUuid(entry->uuid());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setTitle("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setTitle(entry->title());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setUrl("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setUrl(entry->url());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setUsername("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setUsername(entry->username());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setPassword("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setPassword(entry->password());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setNotes("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setNotes(entry->notes());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setIcon(1);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setIcon(entry->iconNumber());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setIcon(QUuid::createUuid());
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setIcon(entry->iconUuid());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setTags("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setTags(entry->tags());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setExpires(true);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setExpires(entry->timeInfo().expires());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setExpiryTime(Clock::currentDateTimeUtc().addYears(1));
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setExpiryTime(entry->timeInfo().expiryTime());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setAutoTypeEnabled(false);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setAutoTypeEnabled(entry->autoTypeEnabled());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setAutoTypeObfuscation(1);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setAutoTypeObfuscation(entry->autoTypeObfuscation());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setDefaultAutoTypeSequence("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setDefaultAutoTypeSequence(entry->defaultAutoTypeSequence());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setForegroundColor(Qt::red);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setForegroundColor(entry->foregroundColor());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setBackgroundColor(Qt::red);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setBackgroundColor(entry->backgroundColor());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setOverrideUrl("test");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->setOverrideUrl(entry->overrideUrl());
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->attributes()->set("test key", "test value", false);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->attributes()->set("test key", entry->attributes()->value("test key"), false);
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->attributes()->set("test key", entry->attributes()->value("test key"), true);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->attributes()->set("test key", "new test value", true);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->attributes()->set("test key2", "test value2", true);
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->attributes()->set("test key2", entry->attributes()->value("test key2"), true);
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
}
void TestModified::testHistoryItems()
@@ -601,20 +647,23 @@ void TestModified::testCustomData()
auto* entry = new Entry();
entry->setGroup(group);
QSignalSpy spyModified(db.data(), SIGNAL(modifiedImmediate()));
QSignalSpy spyModified(db.data(), SIGNAL(databaseModified()));
db->metadata()->customData()->set("Key", "Value");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
db->metadata()->customData()->set("Key", "Value");
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
entry->customData()->set("Key", "Value");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
entry->customData()->set("Key", "Value");
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
group->customData()->set("Key", "Value");
QCOMPARE(spyModified.count(), ++spyCount);
++spyCount;
QTRY_COMPARE(spyModified.count(), spyCount);
group->customData()->set("Key", "Value");
QCOMPARE(spyModified.count(), spyCount);
QTRY_COMPARE(spyModified.count(), spyCount);
}

View File

@@ -90,38 +90,36 @@ void TestOpenSSHKey::testParseDSA()
void TestOpenSSHKey::testDecryptRSAAES128CBC()
{
const QString keyString = QString(
"-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-128-CBC,804E4D214D1263FF94E3743FE799DBB4\n"
"\n"
"lM9TDfOTbiRhaGGDh7Hn+rqw8CCWcYBZYu7smyYLdnWKXKPmbne8CQFZBAS1FJwZ\n"
"6Mj6n075yFGyzN9/OfeqKiUA4adlbwLbGwB+yyKsC2FlsvRIEr4hup02WWM47vHj\n"
"DS4TRmNkE7MKFLhpNCyt5OGGM45s+/lwVTw51K0Hm99TBd72IrX4jfY9ZxAVbL3l\n"
"aTohL8x6oOTe7q318QgJoFi+DjJhDWLGLLJ7fBqD2imz2fmrY4j8Jpw2sDe1rj82\n"
"gMqqNG3FrfN0S4uYlWYH5pAh+BUcB1UdmTU/rV5wJMK1oUytmZv/J2+X/0k3Y93F\n"
"aw6JWOy28OizW+TQXvv8gREWsp5PEclqUZhhGQbVbCQCiDOxg+xiXNySdRH1IqjR\n"
"zQiKgD4SPzkxQekExPaIQT/KutWZdMNYybEqooCx8YyeDoN31z7Wa2rv6OulOn/j\n"
"wJFvyd2PT/6brHKI4ky8RYroDf4FbVYKfyEW5CSAg2OyL/tY/kSPgy/k0WT7fDwq\n"
"dPSuYM9yeWNL6kAhDqDOv8+s3xvOVEljktBvQvItQwVLmHszC3E2AcnaxzdblKPu\n"
"e3+mBT80NXHjERK2ht+/9JYseK1ujNbNAaG8SbKfU3FF0VlyJ0QW6TuIEdpNnymT\n"
"0fm0cDfKNaoeJIFnBRZhgIOJAic9DM0cTe/vSG69DaUYsaQPp36al7Fbux3GpFHS\n"
"OtJEySYGro/6zvJ9dDIEfIGZjA3RaMt6+DuyJZXQdT2RNXa9j60xW7dXh0En4n82\n"
"JUKTxYhDPLS5c8BzpJqoopxpKwElmrJ7Y3xpd6z2vIlD8ftuZrkk6siTMNQ2s7MI\n"
"Xl332O+0H4k7uSfczHPOOw36TFhNjGQAP0b7O+0/RVG0ttOIoAn7ZkX3nfdbtG5B\n"
"DWKvDaopvrcC2/scQ5uLUnqnBiGw1XiYpdg5ang7knHNzHZAIekVaYYZigpCAKp+\n"
"OtoaDeUEzqFhYVmF8ad1fgvC9ZUsuxS4XUHCKl0H6CJcvW9MJPVbveqYoK+j9qKd\n"
"iMIkQBP1kE2rzGZVGUkZTpM9LVD9nP0nsbr6E8BatFcNgRirsg2BTJglNpXlCmY6\n"
"ldzJ/ELBbzoXIn+0wTGai0o4eBPx55baef69JfPuZqEB9pLNE+mHstrqIwcfqYu4\n"
"M+Vzun1QshRMj9a1PVkIHfs1fLeebI4QCHO0vJlc9K4iYPM4rsDNO3YaAgGRuARS\n"
"f3McGiGFxkv5zxe8i05ZBnn+exE77jpRKxd223jAMe2wu4WiFB7ZVo4Db6b5Oo2T\n"
"TPh3VuY7TNMEKkcUi+mGLKjroocQ5j8WQYlfnyOaTalUVQDzOTNb67QIIoiszR0U\n"
"+AXGyxHj0QtotZFoPME+AbS9Zqy3SgSOuIzPBPU5zS4uoKNdD5NPE5YAuafCjsDy\n"
"MT4DVy+cPOQYUK022S7T2nsA1btmvUvD5LL2Mc8VuKsWOn/7FKZua6OCfipt6oX0\n"
"1tzYrw0/ALK+CIdVdYIiPPfxGZkr+JSLOOg7u50tpmen9GzxgNTv63miygwUAIDF\n"
"u0GbQwOueoA453/N75FcXOgrbqTdivyadUbRP+l7YJk/SfIytyJMOigejp+Z1lzF\n"
"-----END RSA PRIVATE KEY-----\n"
);
const QString keyString = QString("-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-128-CBC,804E4D214D1263FF94E3743FE799DBB4\n"
"\n"
"lM9TDfOTbiRhaGGDh7Hn+rqw8CCWcYBZYu7smyYLdnWKXKPmbne8CQFZBAS1FJwZ\n"
"6Mj6n075yFGyzN9/OfeqKiUA4adlbwLbGwB+yyKsC2FlsvRIEr4hup02WWM47vHj\n"
"DS4TRmNkE7MKFLhpNCyt5OGGM45s+/lwVTw51K0Hm99TBd72IrX4jfY9ZxAVbL3l\n"
"aTohL8x6oOTe7q318QgJoFi+DjJhDWLGLLJ7fBqD2imz2fmrY4j8Jpw2sDe1rj82\n"
"gMqqNG3FrfN0S4uYlWYH5pAh+BUcB1UdmTU/rV5wJMK1oUytmZv/J2+X/0k3Y93F\n"
"aw6JWOy28OizW+TQXvv8gREWsp5PEclqUZhhGQbVbCQCiDOxg+xiXNySdRH1IqjR\n"
"zQiKgD4SPzkxQekExPaIQT/KutWZdMNYybEqooCx8YyeDoN31z7Wa2rv6OulOn/j\n"
"wJFvyd2PT/6brHKI4ky8RYroDf4FbVYKfyEW5CSAg2OyL/tY/kSPgy/k0WT7fDwq\n"
"dPSuYM9yeWNL6kAhDqDOv8+s3xvOVEljktBvQvItQwVLmHszC3E2AcnaxzdblKPu\n"
"e3+mBT80NXHjERK2ht+/9JYseK1ujNbNAaG8SbKfU3FF0VlyJ0QW6TuIEdpNnymT\n"
"0fm0cDfKNaoeJIFnBRZhgIOJAic9DM0cTe/vSG69DaUYsaQPp36al7Fbux3GpFHS\n"
"OtJEySYGro/6zvJ9dDIEfIGZjA3RaMt6+DuyJZXQdT2RNXa9j60xW7dXh0En4n82\n"
"JUKTxYhDPLS5c8BzpJqoopxpKwElmrJ7Y3xpd6z2vIlD8ftuZrkk6siTMNQ2s7MI\n"
"Xl332O+0H4k7uSfczHPOOw36TFhNjGQAP0b7O+0/RVG0ttOIoAn7ZkX3nfdbtG5B\n"
"DWKvDaopvrcC2/scQ5uLUnqnBiGw1XiYpdg5ang7knHNzHZAIekVaYYZigpCAKp+\n"
"OtoaDeUEzqFhYVmF8ad1fgvC9ZUsuxS4XUHCKl0H6CJcvW9MJPVbveqYoK+j9qKd\n"
"iMIkQBP1kE2rzGZVGUkZTpM9LVD9nP0nsbr6E8BatFcNgRirsg2BTJglNpXlCmY6\n"
"ldzJ/ELBbzoXIn+0wTGai0o4eBPx55baef69JfPuZqEB9pLNE+mHstrqIwcfqYu4\n"
"M+Vzun1QshRMj9a1PVkIHfs1fLeebI4QCHO0vJlc9K4iYPM4rsDNO3YaAgGRuARS\n"
"f3McGiGFxkv5zxe8i05ZBnn+exE77jpRKxd223jAMe2wu4WiFB7ZVo4Db6b5Oo2T\n"
"TPh3VuY7TNMEKkcUi+mGLKjroocQ5j8WQYlfnyOaTalUVQDzOTNb67QIIoiszR0U\n"
"+AXGyxHj0QtotZFoPME+AbS9Zqy3SgSOuIzPBPU5zS4uoKNdD5NPE5YAuafCjsDy\n"
"MT4DVy+cPOQYUK022S7T2nsA1btmvUvD5LL2Mc8VuKsWOn/7FKZua6OCfipt6oX0\n"
"1tzYrw0/ALK+CIdVdYIiPPfxGZkr+JSLOOg7u50tpmen9GzxgNTv63miygwUAIDF\n"
"u0GbQwOueoA453/N75FcXOgrbqTdivyadUbRP+l7YJk/SfIytyJMOigejp+Z1lzF\n"
"-----END RSA PRIVATE KEY-----\n");
const QByteArray keyData = keyString.toLatin1();
@@ -180,65 +178,61 @@ void TestOpenSSHKey::testParseRSA()
void TestOpenSSHKey::testParseRSACompare()
{
const QString oldKeyString = QString(
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpAIBAAKCAQEAsCHtJicDPWnvHSIKbnTZaJkIB9vgE0pmLdK580JUqBuonVbB\n"
"y1QTy0ZQ7/TtqvLPgwPK88TR46OLO/QGCzo2+XxgJ85uy0xfuyUYRmSuw0drsErN\n"
"mH8vU91lSBxsGDp9LtBbgHKoR23vMWZ34IxFRc55XphrIH48ijsMaL6bXBwF/3tD\n"
"9T3lm2MpP1huyVNnIY9+GRRWCy4f9LMj/UGu/n4RtwwfpOZBBRwYkq5QkzA9lPm/\n"
"VzF3MP1rKTMkvAw+Nfb383mkmc6MRnsa6uh6iDa9aVB7naegM13UJQX/PY1Ks6pO\n"
"XDpy/MQ7iCh+HmYNq5dRmARyaNl9xIXJNhz1cQIDAQABAoIBAQCnEUc1LUQxeM5K\n"
"wANNCqE+SgoIClPdeHC7fmrLh1ttqe6ib6ybBUFRS31yXs0hnfefunVEDKlaV8K2\n"
"N52UAMAsngFHQNRvGh6kEWeZPd9Xc+N98TZbNCjcT+DGKc+Om8wqH5DrodZlCq4c\n"
"GaoT4HnE4TjWtZTH2XXrWF9I66PKFWf070R44nvyVcvaZi4pC2YmURRPuGF6K1iK\n"
"dH8zM6HHG1UGu2W6hLNn+K01IulG0Lb8eWNaNYMmtQWaxyp7I2IWkkecUs3nCuiR\n"
"byFOoomCjdh8r9yZFvwxjGUhgtkALN9GCU0Mwve+s11IB2gevruN+q9/Qejbyfdm\n"
"IlgLAeTRAoGBANRcVzW9CYeobCf+U9hKJFEOur8XO+J2mTMaELA0EjWpTJFAeIT7\n"
"KeRpCRG4/vOSklxxRF6vP1EACA4Z+5BlN+FTipHHs+bSEgqkPZiiANDH7Zot5Iqv\n"
"1q0fRyldNRZNZK7DWp08BPNVWGA/EnEuKJiURxnxBaxNXbUyMCdjxvMvAoGBANRT\n"
"utbrqS/bAa/DcHKn3V6DRqBl3TDOfvCNjiKC84a67F2uXgzLIdMktr4d1NyCZVJd\n"
"7/zVgWORLIdg1eAi6rYGoOvNV39wwga7CF+m9sBY0wAaKYCELe6L26r4aQHVCX6n\n"
"rnIgUv+4o4itmU2iP0r3wlmDC9pDRQP82vfvQPlfAoGASwhleANW/quvq2HdViq8\n"
"Mje2HBalfhrRfpDTHK8JUBSFjTzuWG42GxJRtgVbb8x2ElujAKGDCaetMO5VSGu7\n"
"Fs5hw6iAFCpdXY0yhl+XUi2R8kwM2EPQ4lKO3jqkq0ClNmqn9a5jQWcCVt9yMLNS\n"
"fLbHeI8EpiCf34ngIcrLXNkCgYEAzlcEZuKkC46xB+dNew8pMTUwSKZVm53BfPKD\n"
"44QRN6imFbBjU9mAaJnwQbfp6dWKs834cGPolyM4++MeVfB42iZ88ksesgmZdUMD\n"
"szkl6O0pOJs0I+HQZVdjRbadDZvD22MHQ3+oST1dJ3FVXz3Cdo9qPuT8esMO6f4r\n"
"qfDH2s8CgYAXC/lWWHQ//PGP0pH4oiEXisx1K0X1u0xMGgrChxBRGRiKZUwNMIvJ\n"
"TqUu7IKizK19cLHF/NBvxHYHFw+m7puNjn6T1RtRCUjRZT7Dx1VHfVosL9ih5DA8\n"
"tpbZA5KGKcvHtB5DDgT0MHwzBZnb4Q//Rhovzn+HXZPsJTTgHHy3NQ==\n"
"-----END RSA PRIVATE KEY-----\n"
);
const QString oldKeyString = QString("-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpAIBAAKCAQEAsCHtJicDPWnvHSIKbnTZaJkIB9vgE0pmLdK580JUqBuonVbB\n"
"y1QTy0ZQ7/TtqvLPgwPK88TR46OLO/QGCzo2+XxgJ85uy0xfuyUYRmSuw0drsErN\n"
"mH8vU91lSBxsGDp9LtBbgHKoR23vMWZ34IxFRc55XphrIH48ijsMaL6bXBwF/3tD\n"
"9T3lm2MpP1huyVNnIY9+GRRWCy4f9LMj/UGu/n4RtwwfpOZBBRwYkq5QkzA9lPm/\n"
"VzF3MP1rKTMkvAw+Nfb383mkmc6MRnsa6uh6iDa9aVB7naegM13UJQX/PY1Ks6pO\n"
"XDpy/MQ7iCh+HmYNq5dRmARyaNl9xIXJNhz1cQIDAQABAoIBAQCnEUc1LUQxeM5K\n"
"wANNCqE+SgoIClPdeHC7fmrLh1ttqe6ib6ybBUFRS31yXs0hnfefunVEDKlaV8K2\n"
"N52UAMAsngFHQNRvGh6kEWeZPd9Xc+N98TZbNCjcT+DGKc+Om8wqH5DrodZlCq4c\n"
"GaoT4HnE4TjWtZTH2XXrWF9I66PKFWf070R44nvyVcvaZi4pC2YmURRPuGF6K1iK\n"
"dH8zM6HHG1UGu2W6hLNn+K01IulG0Lb8eWNaNYMmtQWaxyp7I2IWkkecUs3nCuiR\n"
"byFOoomCjdh8r9yZFvwxjGUhgtkALN9GCU0Mwve+s11IB2gevruN+q9/Qejbyfdm\n"
"IlgLAeTRAoGBANRcVzW9CYeobCf+U9hKJFEOur8XO+J2mTMaELA0EjWpTJFAeIT7\n"
"KeRpCRG4/vOSklxxRF6vP1EACA4Z+5BlN+FTipHHs+bSEgqkPZiiANDH7Zot5Iqv\n"
"1q0fRyldNRZNZK7DWp08BPNVWGA/EnEuKJiURxnxBaxNXbUyMCdjxvMvAoGBANRT\n"
"utbrqS/bAa/DcHKn3V6DRqBl3TDOfvCNjiKC84a67F2uXgzLIdMktr4d1NyCZVJd\n"
"7/zVgWORLIdg1eAi6rYGoOvNV39wwga7CF+m9sBY0wAaKYCELe6L26r4aQHVCX6n\n"
"rnIgUv+4o4itmU2iP0r3wlmDC9pDRQP82vfvQPlfAoGASwhleANW/quvq2HdViq8\n"
"Mje2HBalfhrRfpDTHK8JUBSFjTzuWG42GxJRtgVbb8x2ElujAKGDCaetMO5VSGu7\n"
"Fs5hw6iAFCpdXY0yhl+XUi2R8kwM2EPQ4lKO3jqkq0ClNmqn9a5jQWcCVt9yMLNS\n"
"fLbHeI8EpiCf34ngIcrLXNkCgYEAzlcEZuKkC46xB+dNew8pMTUwSKZVm53BfPKD\n"
"44QRN6imFbBjU9mAaJnwQbfp6dWKs834cGPolyM4++MeVfB42iZ88ksesgmZdUMD\n"
"szkl6O0pOJs0I+HQZVdjRbadDZvD22MHQ3+oST1dJ3FVXz3Cdo9qPuT8esMO6f4r\n"
"qfDH2s8CgYAXC/lWWHQ//PGP0pH4oiEXisx1K0X1u0xMGgrChxBRGRiKZUwNMIvJ\n"
"TqUu7IKizK19cLHF/NBvxHYHFw+m7puNjn6T1RtRCUjRZT7Dx1VHfVosL9ih5DA8\n"
"tpbZA5KGKcvHtB5DDgT0MHwzBZnb4Q//Rhovzn+HXZPsJTTgHHy3NQ==\n"
"-----END RSA PRIVATE KEY-----\n");
const QString newKeyString = QString(
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"
"NhAAAAAwEAAQAAAQEAsCHtJicDPWnvHSIKbnTZaJkIB9vgE0pmLdK580JUqBuonVbBy1QT\n"
"y0ZQ7/TtqvLPgwPK88TR46OLO/QGCzo2+XxgJ85uy0xfuyUYRmSuw0drsErNmH8vU91lSB\n"
"xsGDp9LtBbgHKoR23vMWZ34IxFRc55XphrIH48ijsMaL6bXBwF/3tD9T3lm2MpP1huyVNn\n"
"IY9+GRRWCy4f9LMj/UGu/n4RtwwfpOZBBRwYkq5QkzA9lPm/VzF3MP1rKTMkvAw+Nfb383\n"
"mkmc6MRnsa6uh6iDa9aVB7naegM13UJQX/PY1Ks6pOXDpy/MQ7iCh+HmYNq5dRmARyaNl9\n"
"xIXJNhz1cQAAA8DLsKINy7CiDQAAAAdzc2gtcnNhAAABAQCwIe0mJwM9ae8dIgpudNlomQ\n"
"gH2+ATSmYt0rnzQlSoG6idVsHLVBPLRlDv9O2q8s+DA8rzxNHjo4s79AYLOjb5fGAnzm7L\n"
"TF+7JRhGZK7DR2uwSs2Yfy9T3WVIHGwYOn0u0FuAcqhHbe8xZnfgjEVFznlemGsgfjyKOw\n"
"xovptcHAX/e0P1PeWbYyk/WG7JU2chj34ZFFYLLh/0syP9Qa7+fhG3DB+k5kEFHBiSrlCT\n"
"MD2U+b9XMXcw/WspMyS8DD419vfzeaSZzoxGexrq6HqINr1pUHudp6AzXdQlBf89jUqzqk\n"
"5cOnL8xDuIKH4eZg2rl1GYBHJo2X3Ehck2HPVxAAAAAwEAAQAAAQEApxFHNS1EMXjOSsAD\n"
"TQqhPkoKCApT3Xhwu35qy4dbbanuom+smwVBUUt9cl7NIZ33n7p1RAypWlfCtjedlADALJ\n"
"4BR0DUbxoepBFnmT3fV3PjffE2WzQo3E/gxinPjpvMKh+Q66HWZQquHBmqE+B5xOE41rWU\n"
"x9l161hfSOujyhVn9O9EeOJ78lXL2mYuKQtmJlEUT7hheitYinR/MzOhxxtVBrtluoSzZ/\n"
"itNSLpRtC2/HljWjWDJrUFmscqeyNiFpJHnFLN5wrokW8hTqKJgo3YfK/cmRb8MYxlIYLZ\n"
"ACzfRglNDML3vrNdSAdoHr67jfqvf0Ho28n3ZiJYCwHk0QAAAIAXC/lWWHQ//PGP0pH4oi\n"
"EXisx1K0X1u0xMGgrChxBRGRiKZUwNMIvJTqUu7IKizK19cLHF/NBvxHYHFw+m7puNjn6T\n"
"1RtRCUjRZT7Dx1VHfVosL9ih5DA8tpbZA5KGKcvHtB5DDgT0MHwzBZnb4Q//Rhovzn+HXZ\n"
"PsJTTgHHy3NQAAAIEA1FxXNb0Jh6hsJ/5T2EokUQ66vxc74naZMxoQsDQSNalMkUB4hPsp\n"
"5GkJEbj+85KSXHFEXq8/UQAIDhn7kGU34VOKkcez5tISCqQ9mKIA0Mftmi3kiq/WrR9HKV\n"
"01Fk1krsNanTwE81VYYD8ScS4omJRHGfEFrE1dtTIwJ2PG8y8AAACBANRTutbrqS/bAa/D\n"
"cHKn3V6DRqBl3TDOfvCNjiKC84a67F2uXgzLIdMktr4d1NyCZVJd7/zVgWORLIdg1eAi6r\n"
"YGoOvNV39wwga7CF+m9sBY0wAaKYCELe6L26r4aQHVCX6nrnIgUv+4o4itmU2iP0r3wlmD\n"
"C9pDRQP82vfvQPlfAAAABmlkX3JzYQECAwQ=\n"
"-----END OPENSSH PRIVATE KEY-----\n"
);
const QString newKeyString = QString("-----BEGIN OPENSSH PRIVATE KEY-----\n"
"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"
"NhAAAAAwEAAQAAAQEAsCHtJicDPWnvHSIKbnTZaJkIB9vgE0pmLdK580JUqBuonVbBy1QT\n"
"y0ZQ7/TtqvLPgwPK88TR46OLO/QGCzo2+XxgJ85uy0xfuyUYRmSuw0drsErNmH8vU91lSB\n"
"xsGDp9LtBbgHKoR23vMWZ34IxFRc55XphrIH48ijsMaL6bXBwF/3tD9T3lm2MpP1huyVNn\n"
"IY9+GRRWCy4f9LMj/UGu/n4RtwwfpOZBBRwYkq5QkzA9lPm/VzF3MP1rKTMkvAw+Nfb383\n"
"mkmc6MRnsa6uh6iDa9aVB7naegM13UJQX/PY1Ks6pOXDpy/MQ7iCh+HmYNq5dRmARyaNl9\n"
"xIXJNhz1cQAAA8DLsKINy7CiDQAAAAdzc2gtcnNhAAABAQCwIe0mJwM9ae8dIgpudNlomQ\n"
"gH2+ATSmYt0rnzQlSoG6idVsHLVBPLRlDv9O2q8s+DA8rzxNHjo4s79AYLOjb5fGAnzm7L\n"
"TF+7JRhGZK7DR2uwSs2Yfy9T3WVIHGwYOn0u0FuAcqhHbe8xZnfgjEVFznlemGsgfjyKOw\n"
"xovptcHAX/e0P1PeWbYyk/WG7JU2chj34ZFFYLLh/0syP9Qa7+fhG3DB+k5kEFHBiSrlCT\n"
"MD2U+b9XMXcw/WspMyS8DD419vfzeaSZzoxGexrq6HqINr1pUHudp6AzXdQlBf89jUqzqk\n"
"5cOnL8xDuIKH4eZg2rl1GYBHJo2X3Ehck2HPVxAAAAAwEAAQAAAQEApxFHNS1EMXjOSsAD\n"
"TQqhPkoKCApT3Xhwu35qy4dbbanuom+smwVBUUt9cl7NIZ33n7p1RAypWlfCtjedlADALJ\n"
"4BR0DUbxoepBFnmT3fV3PjffE2WzQo3E/gxinPjpvMKh+Q66HWZQquHBmqE+B5xOE41rWU\n"
"x9l161hfSOujyhVn9O9EeOJ78lXL2mYuKQtmJlEUT7hheitYinR/MzOhxxtVBrtluoSzZ/\n"
"itNSLpRtC2/HljWjWDJrUFmscqeyNiFpJHnFLN5wrokW8hTqKJgo3YfK/cmRb8MYxlIYLZ\n"
"ACzfRglNDML3vrNdSAdoHr67jfqvf0Ho28n3ZiJYCwHk0QAAAIAXC/lWWHQ//PGP0pH4oi\n"
"EXisx1K0X1u0xMGgrChxBRGRiKZUwNMIvJTqUu7IKizK19cLHF/NBvxHYHFw+m7puNjn6T\n"
"1RtRCUjRZT7Dx1VHfVosL9ih5DA8tpbZA5KGKcvHtB5DDgT0MHwzBZnb4Q//Rhovzn+HXZ\n"
"PsJTTgHHy3NQAAAIEA1FxXNb0Jh6hsJ/5T2EokUQ66vxc74naZMxoQsDQSNalMkUB4hPsp\n"
"5GkJEbj+85KSXHFEXq8/UQAIDhn7kGU34VOKkcez5tISCqQ9mKIA0Mftmi3kiq/WrR9HKV\n"
"01Fk1krsNanTwE81VYYD8ScS4omJRHGfEFrE1dtTIwJ2PG8y8AAACBANRTutbrqS/bAa/D\n"
"cHKn3V6DRqBl3TDOfvCNjiKC84a67F2uXgzLIdMktr4d1NyCZVJd7/zVgWORLIdg1eAi6r\n"
"YGoOvNV39wwga7CF+m9sBY0wAaKYCELe6L26r4aQHVCX6nrnIgUv+4o4itmU2iP0r3wlmD\n"
"C9pDRQP82vfvQPlfAAAABmlkX3JzYQECAwQ=\n"
"-----END OPENSSH PRIVATE KEY-----\n");
const QByteArray oldKeyData = oldKeyString.toLatin1();
const QByteArray newKeyData = newKeyString.toLatin1();
@@ -295,38 +289,36 @@ void TestOpenSSHKey::testDecryptOpenSSHAES256CBC()
void TestOpenSSHKey::testDecryptRSAAES256CBC()
{
const QString keyString = QString(
"-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-256-CBC,D51E3F558B621BD9384627762CBD16AC\n"
"\n"
"b6nr/06Gj8/Nw3ZFMePFyZeuBodExvZZtZPSH3t/2ArcxXOkoqUhLmlcY/JrvnBF\n"
"JHc34wx/6Yng7mqtUMuk2iMemTzOj3JRx8zHUhwPLnjM/tmeOm0wBUb3WB4+rFZW\n"
"s1PaIgeKywKgFK0UkcSRpMuSaxheWmHrtJkBsHTF7Tg3ogPL8Dc+nhQlbe/ZGaQb\n"
"vMdSYcBMaXngS5ZiOafXeY8+l+IMMOZwy5vPTFQGqKHIzOxFhShs1hSExnwOXy69\n"
"wxrA/QftjNEy5ixIeGT7iQfRB04tEVg0DjYphTPmI2ophzFlwJVBjhj2cmmnsMZg\n"
"a2TdT/78KZsw2cA5ieMcU6d7Yz5p5nu5dyTbZonn6qWficdZRJwZnVb5ikPnJYbZ\n"
"1YJRHHND+RWtpanxz7WhStscTCLeI9w9j2gqBJSjKDPgJaoMiA+tyEoakNlPYg+9\n"
"DadJkBGP0g5E9zw0n4niqQ7eCxk7qolmW6Wtn2zL4UyeJKGi9NWFSGW9x/PmAIse\n"
"E2KVodiJMRNa8/qUZcW58ZG2uRnFTsW4BXdmzOy/Zp53TVGWStBVLDcldSD03ItD\n"
"JIWQWDgWp5xyVqPl+8mkW7xDY0GRVSJCyRkctQeGTGysy0BcNjgQQtiA3lPC0rY5\n"
"m2VxrCYU1KuyHsAjs/V8THcW4a1UdPcVBg1QbCh29bMoM6u4MuXVt7rkwxAV9HJa\n"
"VbwPsKy7V6G60KaAFIiOs0wdOzBZBoPGd9vBQOEzATh2FYJruDo2OfzEnhv25RxE\n"
"1q+C/Jds9cWqaNY8kNtUG799XIKkjrC6KvnoV6UA4BkGs2DAcO9rnwtl/hToEoBe\n"
"ZVj72dlTuS6l9rHqKaz2GI0k0SEt/ZoakPHeDRgPNcDvEZWitV8MuD6Mwb47Y88u\n"
"sjBmS5k4sJOtB4bLg/UShcqYfkv2OTsK90qGQtba9vMk04Xh1FuxB4fHa5VoKrsX\n"
"Th/LB34xoYugd16NPmLuawhSo70o4bT70GYpxnb4brGfjWiuthRdegAG9ESSX+M6\n"
"rNKQPnn2GSroIpkoA4k0PaflcE5tpzeIiJdv0h65N3vw6MFnCaWy8sRSy9fMyRim\n"
"U8QZB2jcp+YjUU/eny3scuh0Vqt6g1tfFbI84pCC5bArBirf63MeMtwDU/IVImax\n"
"xzKOzl7k8ropA+rhAJ4Z9X35EmUncBXhf8g39w6nFuSlqjE6rMxCrsrehljQ1Iuz\n"
"bujaJ2PKpf98OejHDKnMDOfBBq0DdeERCYWlCcqWSgrEgHh4vB5dEQAPP5bAkdZj\n"
"m0Dq+gF99yadioxf3/MUZVTa1dHklBJJkXTYVPeyH07Th5j7bGCcVb9Zd2Ao/Dia\n"
"MPWf6xViCC6d0njCLQY2R8mOR5OMVsdlFrsKZMQ/lqjS/WSM6URDkuGb0Cq94TQd\n"
"7DoblcA50FTwYrVXMygWygbjzJxhcoJDHztzwoqLT/ghh+6zRg6R/fY222tHHbhz\n"
"nePf421NILzfxnuW+GOwRCM5+IHE3OBS/PYDGijjRFHU4ky0rRRDE64m9CeFzeBh\n"
"CnFvW6Yx3Hrh5tXBP7kRZ6KjyrPP7tI4ciVSJceSBLRzFmoBr10kRMm+VsUh2xZH\n"
"-----END RSA PRIVATE KEY-----\n"
);
const QString keyString = QString("-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-256-CBC,D51E3F558B621BD9384627762CBD16AC\n"
"\n"
"b6nr/06Gj8/Nw3ZFMePFyZeuBodExvZZtZPSH3t/2ArcxXOkoqUhLmlcY/JrvnBF\n"
"JHc34wx/6Yng7mqtUMuk2iMemTzOj3JRx8zHUhwPLnjM/tmeOm0wBUb3WB4+rFZW\n"
"s1PaIgeKywKgFK0UkcSRpMuSaxheWmHrtJkBsHTF7Tg3ogPL8Dc+nhQlbe/ZGaQb\n"
"vMdSYcBMaXngS5ZiOafXeY8+l+IMMOZwy5vPTFQGqKHIzOxFhShs1hSExnwOXy69\n"
"wxrA/QftjNEy5ixIeGT7iQfRB04tEVg0DjYphTPmI2ophzFlwJVBjhj2cmmnsMZg\n"
"a2TdT/78KZsw2cA5ieMcU6d7Yz5p5nu5dyTbZonn6qWficdZRJwZnVb5ikPnJYbZ\n"
"1YJRHHND+RWtpanxz7WhStscTCLeI9w9j2gqBJSjKDPgJaoMiA+tyEoakNlPYg+9\n"
"DadJkBGP0g5E9zw0n4niqQ7eCxk7qolmW6Wtn2zL4UyeJKGi9NWFSGW9x/PmAIse\n"
"E2KVodiJMRNa8/qUZcW58ZG2uRnFTsW4BXdmzOy/Zp53TVGWStBVLDcldSD03ItD\n"
"JIWQWDgWp5xyVqPl+8mkW7xDY0GRVSJCyRkctQeGTGysy0BcNjgQQtiA3lPC0rY5\n"
"m2VxrCYU1KuyHsAjs/V8THcW4a1UdPcVBg1QbCh29bMoM6u4MuXVt7rkwxAV9HJa\n"
"VbwPsKy7V6G60KaAFIiOs0wdOzBZBoPGd9vBQOEzATh2FYJruDo2OfzEnhv25RxE\n"
"1q+C/Jds9cWqaNY8kNtUG799XIKkjrC6KvnoV6UA4BkGs2DAcO9rnwtl/hToEoBe\n"
"ZVj72dlTuS6l9rHqKaz2GI0k0SEt/ZoakPHeDRgPNcDvEZWitV8MuD6Mwb47Y88u\n"
"sjBmS5k4sJOtB4bLg/UShcqYfkv2OTsK90qGQtba9vMk04Xh1FuxB4fHa5VoKrsX\n"
"Th/LB34xoYugd16NPmLuawhSo70o4bT70GYpxnb4brGfjWiuthRdegAG9ESSX+M6\n"
"rNKQPnn2GSroIpkoA4k0PaflcE5tpzeIiJdv0h65N3vw6MFnCaWy8sRSy9fMyRim\n"
"U8QZB2jcp+YjUU/eny3scuh0Vqt6g1tfFbI84pCC5bArBirf63MeMtwDU/IVImax\n"
"xzKOzl7k8ropA+rhAJ4Z9X35EmUncBXhf8g39w6nFuSlqjE6rMxCrsrehljQ1Iuz\n"
"bujaJ2PKpf98OejHDKnMDOfBBq0DdeERCYWlCcqWSgrEgHh4vB5dEQAPP5bAkdZj\n"
"m0Dq+gF99yadioxf3/MUZVTa1dHklBJJkXTYVPeyH07Th5j7bGCcVb9Zd2Ao/Dia\n"
"MPWf6xViCC6d0njCLQY2R8mOR5OMVsdlFrsKZMQ/lqjS/WSM6URDkuGb0Cq94TQd\n"
"7DoblcA50FTwYrVXMygWygbjzJxhcoJDHztzwoqLT/ghh+6zRg6R/fY222tHHbhz\n"
"nePf421NILzfxnuW+GOwRCM5+IHE3OBS/PYDGijjRFHU4ky0rRRDE64m9CeFzeBh\n"
"CnFvW6Yx3Hrh5tXBP7kRZ6KjyrPP7tI4ciVSJceSBLRzFmoBr10kRMm+VsUh2xZH\n"
"-----END RSA PRIVATE KEY-----\n");
const QByteArray keyData = keyString.toLatin1();
@@ -375,38 +367,36 @@ void TestOpenSSHKey::testDecryptOpenSSHAES256CTR()
void TestOpenSSHKey::testDecryptRSAAES256CTR()
{
const QString keyString = QString(
"-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-256-CTR,192421854316290DFA8F469A1E8CB9BB\n"
"\n"
"3h7gUWua+jcvhYj1vUusbMdOG9j8SmNWFV5Hfersi8nF4ddsWEQDnMrRuhtIn4tU\n"
"GcLY+SXguim5XXwF8gG1tmvpvFMhudTfX+0cIAX7eAVmqLy2RTA18DWqDwWokVP0\n"
"RJPgRJJSorjMtu2F0YGVVjElW7pHIal7luNk3BDgYUMlgSg0BGOWb+9BkXcEnfc8\n"
"KEwsJw2onoR2eXo6rYnczGaqPhAPu+I+PfUn0J8PFiffWc1KebRntLdRWeNsBS4p\n"
"oxtqByzMYIu/WPSJJ5iFoNdKaWQPiZJB+juwI1wNLEtpzKkhpc7/6mOy87h+0eGV\n"
"fF7javrbHv37eE+k2iZXrcLfvRpiBqt5+uhhCaM8TivBeUho5J38ru/wt/dk+OvY\n"
"tzXboWA4zVnaYmqta1CkXYKOmb5a8TWEwtxmAuE6kCz/n3pPa6gwkwsyGI65IEyX\n"
"ycJsbwUilAzXTcz5bIruGx38Sa9fndAN9llOQMS/hdyNs5W5dO1XZ5gU+ARPce+j\n"
"+A2R8oCUv+2ciEu8z3F++U9aTRmTlD3xeIM0IWUFXKt8Y9fSRC5XoPCbZYNxnV6/\n"
"hn9NPKCb890Faxies3MABOB5IZ0aTPWkx9ntxFhMaXyfkX2YthNO0GzAENPP9Knt\n"
"DYhQePlKQ7sNi8+wzsHNeDxNuL/+Rib2MN3ankDtHIsqFz/Em+rD0+3ya8bLy3pP\n"
"eeUiNpezL+uxI5llq/pikzK4sOgvH1r5YEkMxt9I09grkBwxR7DMBo0vgRE2MLiL\n"
"nlri8TDwArC1+0gE8NspkkClsBOHXuVlGZo5lup2tn5MzERQcLvuFnAby/GnaVXQ\n"
"Hm76teb1wMdL58FrdZsKR6e80E+F6JpTsz0a3XJqptgAwGsoxqizkUNJG5hRP8bi\n"
"NBCFQZPeYi/GxgN5O2UkxhgRkKAcrHg+G87nhLk1ipsc214rb6iOspNizP6fGDuv\n"
"/bsNTpYRgMNxCLh5Nv0HSUqckoNKOcIVe/9nF5/LLFGfhz95agjKTbBygThFK28N\n"
"bnHq5fO9yKCMrGCRBQ6No1wwexyS4IAq17LcQP3k4w4n+Wt2GjO5HIldGOEyGqCE\n"
"zeHYrPpGXF/yf3XTm00XghdQtVtRJptdddXVGZN3EN2w7/ghOSIIlsJO9C4IRgU3\n"
"WkhX7oOpSE4wmXd5Ada+D1U46snW5nWANWko2NmQNVDeJcvuymL6t2ccNYeFWiA+\n"
"Hlv0avBnqng7ZWPxYacqZI3+vU0rN9usN1pzwY/4NsBa34o3M7u6KvzEkyewbyUT\n"
"VfXLJ8XRzb2u4NqQv0WiTBIRxvVB1sRPcrwB4HWKHwRFT8T7f1fefteROrKV7aKm\n"
"Q48pckidDM0ORh1yIET8u24Mreo5eeWXjVJ9MHoM0486VySYxMwk8yp4tnaHx5kd\n"
"fGlBbbwFOifhzjAk0u3KJRAG85t2GZhfTMo1IHS2kdu4Xs1N00ZmK0hjeGG+DCwy\n"
"06ZKHOF5BHWU3SpQEjCsPDwfIpOINWGAJJnp6NIVf7FkHwViV50GWWGSZal4NqZy\n"
"kR19buHiOb7KnGoPCw8MUmIym8v30FePhM4YQ7ASmRtsXlAhQNRX\n"
"-----END RSA PRIVATE KEY-----\n"
);
const QString keyString = QString("-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-256-CTR,192421854316290DFA8F469A1E8CB9BB\n"
"\n"
"3h7gUWua+jcvhYj1vUusbMdOG9j8SmNWFV5Hfersi8nF4ddsWEQDnMrRuhtIn4tU\n"
"GcLY+SXguim5XXwF8gG1tmvpvFMhudTfX+0cIAX7eAVmqLy2RTA18DWqDwWokVP0\n"
"RJPgRJJSorjMtu2F0YGVVjElW7pHIal7luNk3BDgYUMlgSg0BGOWb+9BkXcEnfc8\n"
"KEwsJw2onoR2eXo6rYnczGaqPhAPu+I+PfUn0J8PFiffWc1KebRntLdRWeNsBS4p\n"
"oxtqByzMYIu/WPSJJ5iFoNdKaWQPiZJB+juwI1wNLEtpzKkhpc7/6mOy87h+0eGV\n"
"fF7javrbHv37eE+k2iZXrcLfvRpiBqt5+uhhCaM8TivBeUho5J38ru/wt/dk+OvY\n"
"tzXboWA4zVnaYmqta1CkXYKOmb5a8TWEwtxmAuE6kCz/n3pPa6gwkwsyGI65IEyX\n"
"ycJsbwUilAzXTcz5bIruGx38Sa9fndAN9llOQMS/hdyNs5W5dO1XZ5gU+ARPce+j\n"
"+A2R8oCUv+2ciEu8z3F++U9aTRmTlD3xeIM0IWUFXKt8Y9fSRC5XoPCbZYNxnV6/\n"
"hn9NPKCb890Faxies3MABOB5IZ0aTPWkx9ntxFhMaXyfkX2YthNO0GzAENPP9Knt\n"
"DYhQePlKQ7sNi8+wzsHNeDxNuL/+Rib2MN3ankDtHIsqFz/Em+rD0+3ya8bLy3pP\n"
"eeUiNpezL+uxI5llq/pikzK4sOgvH1r5YEkMxt9I09grkBwxR7DMBo0vgRE2MLiL\n"
"nlri8TDwArC1+0gE8NspkkClsBOHXuVlGZo5lup2tn5MzERQcLvuFnAby/GnaVXQ\n"
"Hm76teb1wMdL58FrdZsKR6e80E+F6JpTsz0a3XJqptgAwGsoxqizkUNJG5hRP8bi\n"
"NBCFQZPeYi/GxgN5O2UkxhgRkKAcrHg+G87nhLk1ipsc214rb6iOspNizP6fGDuv\n"
"/bsNTpYRgMNxCLh5Nv0HSUqckoNKOcIVe/9nF5/LLFGfhz95agjKTbBygThFK28N\n"
"bnHq5fO9yKCMrGCRBQ6No1wwexyS4IAq17LcQP3k4w4n+Wt2GjO5HIldGOEyGqCE\n"
"zeHYrPpGXF/yf3XTm00XghdQtVtRJptdddXVGZN3EN2w7/ghOSIIlsJO9C4IRgU3\n"
"WkhX7oOpSE4wmXd5Ada+D1U46snW5nWANWko2NmQNVDeJcvuymL6t2ccNYeFWiA+\n"
"Hlv0avBnqng7ZWPxYacqZI3+vU0rN9usN1pzwY/4NsBa34o3M7u6KvzEkyewbyUT\n"
"VfXLJ8XRzb2u4NqQv0WiTBIRxvVB1sRPcrwB4HWKHwRFT8T7f1fefteROrKV7aKm\n"
"Q48pckidDM0ORh1yIET8u24Mreo5eeWXjVJ9MHoM0486VySYxMwk8yp4tnaHx5kd\n"
"fGlBbbwFOifhzjAk0u3KJRAG85t2GZhfTMo1IHS2kdu4Xs1N00ZmK0hjeGG+DCwy\n"
"06ZKHOF5BHWU3SpQEjCsPDwfIpOINWGAJJnp6NIVf7FkHwViV50GWWGSZal4NqZy\n"
"kR19buHiOb7KnGoPCw8MUmIym8v30FePhM4YQ7ASmRtsXlAhQNRX\n"
"-----END RSA PRIVATE KEY-----\n");
const QByteArray keyData = keyString.toLatin1();
@@ -423,16 +413,14 @@ void TestOpenSSHKey::testDecryptRSAAES256CTR()
void TestOpenSSHKey::testDecryptUTF8()
{
const QString keyString = QString(
"-----BEGIN OPENSSH PRIVATE KEY-----\n"
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDtSl4OvT\n"
"H/wHay2dvjOnpIAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIIhrBrn6rb+d3GwF\n"
"ifpJ6gYut95lXvwypiQmu9ZpA8H9AAAAsD85Gpn2mbVEWq3ygx11wBnN5mUQXnMuP48rLv\n"
"0qwm12IihOkrR925ledwN2Sa5mkkL0XjDz6SsKfIFhFa84hUHQdw5zPR8yVGRWLzkNDmo7\n"
"WXNpnoE4ebsX2j0TsBNjP80RUcJdjSXidkt3+aZjaCfquO8cBQn4GJJSDSPwFJYlJeSD/h\n"
"vpb72MEQchOD3NNMORYTJ5sOJ73RayhhmwjTVlrG+zYAw6fXW0YXX3+5LE\n"
"-----END OPENSSH PRIVATE KEY-----\n"
);
const QString keyString = QString("-----BEGIN OPENSSH PRIVATE KEY-----\n"
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDtSl4OvT\n"
"H/wHay2dvjOnpIAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIIhrBrn6rb+d3GwF\n"
"ifpJ6gYut95lXvwypiQmu9ZpA8H9AAAAsD85Gpn2mbVEWq3ygx11wBnN5mUQXnMuP48rLv\n"
"0qwm12IihOkrR925ledwN2Sa5mkkL0XjDz6SsKfIFhFa84hUHQdw5zPR8yVGRWLzkNDmo7\n"
"WXNpnoE4ebsX2j0TsBNjP80RUcJdjSXidkt3+aZjaCfquO8cBQn4GJJSDSPwFJYlJeSD/h\n"
"vpb72MEQchOD3NNMORYTJ5sOJ73RayhhmwjTVlrG+zYAw6fXW0YXX3+5LE\n"
"-----END OPENSSH PRIVATE KEY-----\n");
const QByteArray keyData = keyString.toLatin1();

View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TestPasswordGenerator.h"
#include "core/PasswordGenerator.h"
#include "crypto/Crypto.h"
#include <QRegularExpression>
#include <QTest>
QTEST_GUILESS_MAIN(TestPasswordGenerator)
void TestPasswordGenerator::initTestCase()
{
QVERIFY(Crypto::init());
}
void TestPasswordGenerator::testCharClasses()
{
PasswordGenerator generator;
QVERIFY(!generator.isValid());
generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters);
generator.setLength(16);
QVERIFY(generator.isValid());
QCOMPARE(generator.generatePassword().size(), 16);
generator.setLength(2000);
QString password = generator.generatePassword();
QCOMPARE(password.size(), 2000);
QRegularExpression regex(R"(^[a-z]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::UpperLetters);
password = generator.generatePassword();
regex.setPattern(R"(^[A-Z]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Numbers);
password = generator.generatePassword();
regex.setPattern(R"(^\d+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Braces);
password = generator.generatePassword();
regex.setPattern(R"(^[\(\)\[\]\{\}]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Punctuation);
password = generator.generatePassword();
regex.setPattern(R"(^[\.,:;]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Quotes);
password = generator.generatePassword();
regex.setPattern(R"(^["']+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Dashes);
password = generator.generatePassword();
regex.setPattern(R"(^[\-/\\_|]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Math);
password = generator.generatePassword();
regex.setPattern(R"(^[!\*\+\-<=>\?]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Logograms);
password = generator.generatePassword();
regex.setPattern(R"(^[#`~%&^$@]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::EASCII);
password = generator.generatePassword();
regex.setPattern(R"(^[^a-zA-Z0-9\.,:;"'\-/\\_|!\*\+\-<=>\?#`~%&^$@]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
| PasswordGenerator::CharClass::Braces);
password = generator.generatePassword();
regex.setPattern(R"(^[a-zA-Z\(\)\[\]\{\}]+$)");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::Quotes | PasswordGenerator::CharClass::Numbers
| PasswordGenerator::CharClass::Dashes);
password = generator.generatePassword();
regex.setPattern(R"(^["'\d\-/\\_|]+$)");
QVERIFY(regex.match(password).hasMatch());
}
void TestPasswordGenerator::testLookalikeExclusion()
{
PasswordGenerator generator;
generator.setLength(2000);
generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters);
QVERIFY(generator.isValid());
QString password = generator.generatePassword();
QCOMPARE(password.size(), 2000);
generator.setFlags(PasswordGenerator::GeneratorFlag::ExcludeLookAlike);
password = generator.generatePassword();
QRegularExpression regex("^[^lI0]+$");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
| PasswordGenerator::CharClass::Numbers);
password = generator.generatePassword();
regex.setPattern("^[^lI01]+$");
QVERIFY(regex.match(password).hasMatch());
generator.setCharClasses(PasswordGenerator::CharClass::LowerLetters | PasswordGenerator::CharClass::UpperLetters
| PasswordGenerator::CharClass::Numbers | PasswordGenerator::CharClass::EASCII);
password = generator.generatePassword();
regex.setPattern("^[^lI01﹒]+$");
QVERIFY(regex.match(password).hasMatch());
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_TESTPASSWORDGENERATOR_H
#define KEEPASSXC_TESTPASSWORDGENERATOR_H
#include <QObject>
class TestPasswordGenerator : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testCharClasses();
void testLookalikeExclusion();
};
#endif // KEEPASSXC_TESTPASSWORDGENERATOR_H

View File

@@ -26,76 +26,171 @@
#include "streams/SymmetricCipherStream.h"
QTEST_GUILESS_MAIN(TestSymmetricCipher)
Q_DECLARE_METATYPE(SymmetricCipher::Algorithm);
Q_DECLARE_METATYPE(SymmetricCipher::Mode);
Q_DECLARE_METATYPE(SymmetricCipher::Direction);
void TestSymmetricCipher::initTestCase()
{
QVERIFY(Crypto::init());
}
void TestSymmetricCipher::testAes128CbcEncryption()
void TestSymmetricCipher::testAlgorithmToCipher()
{
QCOMPARE(SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm::Aes128), KeePass2::CIPHER_AES128);
QCOMPARE(SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm::Aes256), KeePass2::CIPHER_AES256);
QCOMPARE(SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm::Twofish), KeePass2::CIPHER_TWOFISH);
QCOMPARE(SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm::ChaCha20), KeePass2::CIPHER_CHACHA20);
QCOMPARE(SymmetricCipher::algorithmToCipher(SymmetricCipher::Algorithm::InvalidAlgorithm), QUuid());
}
// clang-format off
void TestSymmetricCipher::testEncryptionDecryption_data()
{
QTest::addColumn<SymmetricCipher::Algorithm>("algorithm");
QTest::addColumn<SymmetricCipher::Mode>("mode");
QTest::addColumn<SymmetricCipher::Direction>("direction");
QTest::addColumn<QByteArray>("key");
QTest::addColumn<QByteArray>("iv");
QTest::addColumn<QByteArray>("plainText");
QTest::addColumn<QByteArray>("cipherText");
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
QTest::newRow("AES128-CBC Encryption")
<< SymmetricCipher::Aes128
<< SymmetricCipher::Cbc
<< SymmetricCipher::Encrypt
<< QByteArray::fromHex("2b7e151628aed2a6abf7158809cf4f3c")
<< QByteArray::fromHex("000102030405060708090a0b0c0d0e0f")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
<< QByteArray::fromHex("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2");
QTest::newRow("AES128-CBC Decryption")
<< SymmetricCipher::Aes128
<< SymmetricCipher::Cbc
<< SymmetricCipher::Decrypt
<< QByteArray::fromHex("2b7e151628aed2a6abf7158809cf4f3c")
<< QByteArray::fromHex("000102030405060708090a0b0c0d0e0f")
<< QByteArray::fromHex("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51");
QTest::newRow("AES256-CBC Encryption")
<< SymmetricCipher::Aes256
<< SymmetricCipher::Cbc
<< SymmetricCipher::Encrypt
<< QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4")
<< QByteArray::fromHex("000102030405060708090a0b0c0d0e0f")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
<< QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d");
QTest::newRow("AES256-CBC Decryption")
<< SymmetricCipher::Aes256
<< SymmetricCipher::Cbc
<< SymmetricCipher::Decrypt
<< QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4")
<< QByteArray::fromHex("000102030405060708090a0b0c0d0e0f")
<< QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51");
QTest::newRow("AES256-CTR Encryption")
<< SymmetricCipher::Aes256
<< SymmetricCipher::Ctr
<< SymmetricCipher::Encrypt
<< QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4")
<< QByteArray::fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
<< QByteArray::fromHex("601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5");
QTest::newRow("AES256-CTR Decryption")
<< SymmetricCipher::Aes256
<< SymmetricCipher::Ctr
<< SymmetricCipher::Decrypt
<< QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4")
<< QByteArray::fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
<< QByteArray::fromHex("601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51");
}
// clang-format on
void TestSymmetricCipher::testEncryptionDecryption()
{
QFETCH(SymmetricCipher::Algorithm, algorithm);
QFETCH(SymmetricCipher::Mode, mode);
QFETCH(SymmetricCipher::Direction, direction);
QFETCH(QByteArray, key);
QFETCH(QByteArray, iv);
QFETCH(QByteArray, plainText);
QFETCH(QByteArray, cipherText);
QByteArray key = QByteArray::fromHex("2b7e151628aed2a6abf7158809cf4f3c");
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a");
plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"));
QByteArray cipherText = QByteArray::fromHex("7649abac8119b246cee98e9b12e9197d");
cipherText.append(QByteArray::fromHex("5086cb9b507219ee95db113a917678b2"));
bool ok;
SymmetricCipher cipher(SymmetricCipher::Aes128, SymmetricCipher::Cbc, SymmetricCipher::Encrypt);
SymmetricCipher cipher(algorithm, mode, direction);
QVERIFY(cipher.init(key, iv));
QCOMPARE(cipher.blockSize(), 16);
QCOMPARE(cipher.process(plainText, &ok), cipherText);
QVERIFY(ok);
QBuffer buffer;
SymmetricCipherStream stream(&buffer, SymmetricCipher::Aes128, SymmetricCipher::Cbc, SymmetricCipher::Encrypt);
QVERIFY(stream.init(key, iv));
buffer.open(QIODevice::WriteOnly);
QVERIFY(stream.open(QIODevice::WriteOnly));
QVERIFY(stream.reset());
if (mode == SymmetricCipher::Cbc) {
QBuffer buffer;
SymmetricCipherStream stream(&buffer, algorithm, mode, direction);
QVERIFY(stream.init(key, iv));
buffer.open(QIODevice::WriteOnly);
QVERIFY(stream.open(QIODevice::WriteOnly));
QVERIFY(stream.reset());
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(16)), qint64(16));
QCOMPARE(buffer.data(), cipherText.left(16));
QVERIFY(stream.reset());
// make sure padding is written
QCOMPARE(buffer.data().size(), 32);
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(16)), qint64(16));
QCOMPARE(buffer.data(), cipherText.left(16));
QVERIFY(stream.reset());
// make sure padding is written
QCOMPARE(buffer.data().size(), 32);
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(10)), qint64(10));
QVERIFY(buffer.data().isEmpty());
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(10)), qint64(10));
QVERIFY(buffer.data().isEmpty());
QVERIFY(stream.reset());
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(10)), qint64(10));
stream.close();
QCOMPARE(buffer.data().size(), 16);
QVERIFY(stream.reset());
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(10)), qint64(10));
stream.close();
QCOMPARE(buffer.data().size(), 16);
}
}
void TestSymmetricCipher::testAes128CbcDecryption()
void TestSymmetricCipher::testAesCbcPadding_data()
{
QByteArray key = QByteArray::fromHex("2b7e151628aed2a6abf7158809cf4f3c");
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
QByteArray cipherText = QByteArray::fromHex("7649abac8119b246cee98e9b12e9197d");
cipherText.append(QByteArray::fromHex("5086cb9b507219ee95db113a917678b2"));
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a");
plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"));
bool ok;
QTest::addColumn<QByteArray>("key");
QTest::addColumn<QByteArray>("iv");
QTest::addColumn<QByteArray>("cipherText");
QTest::addColumn<QByteArray>("plainText");
QTest::addColumn<QByteArray>("padding");
SymmetricCipher cipher(SymmetricCipher::Aes128, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
QVERIFY(cipher.init(key, iv));
QCOMPARE(cipher.blockSize(), 16);
QCOMPARE(cipher.process(cipherText, &ok), plainText);
QVERIFY(ok);
QTest::newRow("AES128") << QByteArray::fromHex("2b7e151628aed2a6abf7158809cf4f3c")
<< QByteArray::fromHex("000102030405060708090a0b0c0d0e0f")
<< QByteArray::fromHex("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
<< QByteArray::fromHex("55e21d7100b988ffec32feeafaf23538");
QTest::newRow("AES256") << QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4")
<< QByteArray::fromHex("000102030405060708090a0b0c0d0e0f")
<< QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51")
<< QByteArray::fromHex("3a3aa5e0213db1a9901f9036cf5102d2");
}
void TestSymmetricCipher::testAesCbcPadding()
{
QFETCH(QByteArray, key);
QFETCH(QByteArray, iv);
QFETCH(QByteArray, cipherText);
QFETCH(QByteArray, plainText);
QFETCH(QByteArray, padding);
// padded with 16 0x10 bytes
QByteArray cipherTextPadded = cipherText + QByteArray::fromHex("55e21d7100b988ffec32feeafaf23538");
QByteArray cipherTextPadded = cipherText + padding;
QBuffer buffer(&cipherTextPadded);
SymmetricCipherStream stream(&buffer, SymmetricCipher::Aes128, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
QVERIFY(stream.init(key, iv));
@@ -114,126 +209,47 @@ void TestSymmetricCipher::testAes128CbcDecryption()
QCOMPARE(stream.read(100), plainText);
}
void TestSymmetricCipher::testAes256CbcEncryption()
void TestSymmetricCipher::testInplaceEcb_data()
{
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
QTest::addColumn<QByteArray>("key");
QTest::addColumn<QByteArray>("plainText");
QTest::addColumn<QByteArray>("cipherText");
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a");
plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"));
QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6");
cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d"));
bool ok;
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt);
QVERIFY(cipher.init(key, iv));
QCOMPARE(cipher.blockSize(), 16);
QCOMPARE(cipher.process(plainText, &ok), cipherText);
QVERIFY(ok);
QBuffer buffer;
SymmetricCipherStream stream(&buffer, SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt);
QVERIFY(stream.init(key, iv));
buffer.open(QIODevice::WriteOnly);
QVERIFY(stream.open(QIODevice::WriteOnly));
QVERIFY(stream.reset());
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(16)), qint64(16));
QCOMPARE(buffer.data(), cipherText.left(16));
QVERIFY(stream.reset());
// make sure padding is written
QCOMPARE(buffer.data().size(), 32);
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(10)), qint64(10));
QVERIFY(buffer.data().isEmpty());
QVERIFY(stream.reset());
buffer.reset();
buffer.buffer().clear();
QCOMPARE(stream.write(plainText.left(10)), qint64(10));
stream.close();
QCOMPARE(buffer.data().size(), 16);
QTest::newRow("AES128") << QByteArray::fromHex("2b7e151628aed2a6abf7158809cf4f3c")
<< QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a")
<< QByteArray::fromHex("3ad77bb40d7a3660a89ecaf32466ef97");
}
void TestSymmetricCipher::testAes256CbcDecryption()
void TestSymmetricCipher::testInplaceEcb()
{
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f");
QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6");
cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d"));
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a");
plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"));
bool ok;
QFETCH(QByteArray, key);
QFETCH(QByteArray, plainText);
QFETCH(QByteArray, cipherText);
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
QVERIFY(cipher.init(key, iv));
QCOMPARE(cipher.blockSize(), 16);
SymmetricCipher cipherInPlaceEnc(SymmetricCipher::Aes128, SymmetricCipher::Ecb, SymmetricCipher::Encrypt);
QVERIFY(cipherInPlaceEnc.init(key, QByteArray(16, 0)));
QCOMPARE(cipherInPlaceEnc.blockSize(), 16);
auto data = QByteArray(plainText);
QVERIFY(cipherInPlaceEnc.processInPlace(data));
QCOMPARE(data, cipherText);
QCOMPARE(cipher.process(cipherText, &ok), plainText);
QVERIFY(ok);
SymmetricCipher cipherInPlaceDec(SymmetricCipher::Aes128, SymmetricCipher::Ecb, SymmetricCipher::Decrypt);
QVERIFY(cipherInPlaceDec.init(key, QByteArray(16, 0)));
QCOMPARE(cipherInPlaceDec.blockSize(), 16);
QVERIFY(cipherInPlaceDec.processInPlace(data));
QCOMPARE(data, plainText);
// padded with 16 0x16 bytes
QByteArray cipherTextPadded = cipherText + QByteArray::fromHex("3a3aa5e0213db1a9901f9036cf5102d2");
QBuffer buffer(&cipherTextPadded);
SymmetricCipherStream stream(&buffer, SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
QVERIFY(stream.init(key, iv));
buffer.open(QIODevice::ReadOnly);
QVERIFY(stream.open(QIODevice::ReadOnly));
SymmetricCipher cipherInPlaceEnc2(SymmetricCipher::Aes128, SymmetricCipher::Ecb, SymmetricCipher::Encrypt);
QVERIFY(cipherInPlaceEnc2.init(key, QByteArray(16, 0)));
QCOMPARE(cipherInPlaceEnc2.blockSize(), 16);
data = QByteArray(plainText);
QVERIFY(cipherInPlaceEnc2.processInPlace(data, 100));
QCOMPARE(stream.read(10), plainText.left(10));
buffer.reset();
QVERIFY(stream.reset());
QCOMPARE(stream.read(20), plainText.left(20));
buffer.reset();
QVERIFY(stream.reset());
QCOMPARE(stream.read(16), plainText.left(16));
buffer.reset();
QVERIFY(stream.reset());
QCOMPARE(stream.read(100), plainText);
}
void TestSymmetricCipher::testAes256CtrEncryption()
{
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
QByteArray ctr = QByteArray::fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a");
plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"));
QByteArray cipherText = QByteArray::fromHex("601ec313775789a5b7a7f504bbf3d228");
cipherText.append(QByteArray::fromHex("f443e3ca4d62b59aca84e990cacaf5c5"));
bool ok;
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ctr, SymmetricCipher::Encrypt);
QVERIFY(cipher.init(key, ctr));
QCOMPARE(cipher.blockSize(), 16);
QCOMPARE(cipher.process(plainText, &ok), cipherText);
QVERIFY(ok);
}
void TestSymmetricCipher::testAes256CtrDecryption()
{
QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
QByteArray ctr = QByteArray::fromHex("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
QByteArray cipherText = QByteArray::fromHex("601ec313775789a5b7a7f504bbf3d228");
cipherText.append(QByteArray::fromHex("f443e3ca4d62b59aca84e990cacaf5c5"));
QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a");
plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51"));
bool ok;
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ctr, SymmetricCipher::Decrypt);
QVERIFY(cipher.init(key, ctr));
QCOMPARE(cipher.blockSize(), 16);
QCOMPARE(cipher.process(cipherText, &ok), plainText);
QVERIFY(ok);
SymmetricCipher cipherInPlaceDec2(SymmetricCipher::Aes128, SymmetricCipher::Ecb, SymmetricCipher::Decrypt);
QVERIFY(cipherInPlaceDec2.init(key, QByteArray(16, 0)));
QCOMPARE(cipherInPlaceDec2.blockSize(), 16);
QVERIFY(cipherInPlaceDec2.processInPlace(data, 100));
QCOMPARE(data, plainText);
}
void TestSymmetricCipher::testTwofish256CbcEncryption()

View File

@@ -27,12 +27,13 @@ class TestSymmetricCipher : public QObject
private slots:
void initTestCase();
void testAes128CbcEncryption();
void testAes128CbcDecryption();
void testAes256CbcEncryption();
void testAes256CbcDecryption();
void testAes256CtrEncryption();
void testAes256CtrDecryption();
void testAlgorithmToCipher();
void testEncryptionDecryption_data();
void testEncryptionDecryption();
void testAesCbcPadding_data();
void testAesCbcPadding();
void testInplaceEcb_data();
void testInplaceEcb();
void testTwofish256CbcEncryption();
void testTwofish256CbcDecryption();
void testSalsa20();

View File

@@ -28,7 +28,7 @@ namespace
{
return wholes + QLocale().decimalPoint() + fractions + " " + unit;
}
}
} // namespace
void TestTools::testHumanReadableFileSize()
{

Binary file not shown.

Binary file not shown.

View File

@@ -15,6 +15,6 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_unit_test(NAME testgui SOURCES TestGui.cpp TemporaryFile.cpp LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testgui SOURCES TestGui.cpp ../util/TemporaryFile.cpp LIBS ${TEST_LIBRARIES})
add_unit_test(NAME testguipixmaps SOURCES TestGuiPixmaps.cpp LIBS ${TEST_LIBRARIES})

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2016 Danny Su <contact@dannysu.com>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TemporaryFile.h"
#include <QFileInfo>
#ifdef Q_OS_WIN
const QString TemporaryFile::SUFFIX = ".win";
TemporaryFile::~TemporaryFile()
{
if (m_tempFile.autoRemove()) {
m_file.remove();
}
}
#endif
bool TemporaryFile::open()
{
#ifdef Q_OS_WIN
// Still call QTemporaryFile::open() so that it figures out the temporary
// file name to use. Assuming that by appending the SUFFIX to whatever
// QTemporaryFile chooses is also an available file.
bool tempFileOpened = m_tempFile.open();
if (tempFileOpened) {
m_file.setFileName(filePath());
return m_file.open(QIODevice::WriteOnly);
}
return false;
#else
return m_tempFile.open();
#endif
}
void TemporaryFile::close()
{
m_tempFile.close();
#ifdef Q_OS_WIN
m_file.close();
#endif
}
qint64 TemporaryFile::write(const char* data, qint64 maxSize)
{
#ifdef Q_OS_WIN
return m_file.write(data, maxSize);
#else
return m_tempFile.write(data, maxSize);
#endif
}
qint64 TemporaryFile::write(const QByteArray& byteArray)
{
#ifdef Q_OS_WIN
return m_file.write(byteArray);
#else
return m_tempFile.write(byteArray);
#endif
}
QString TemporaryFile::fileName() const
{
#ifdef Q_OS_WIN
return QFileInfo(m_tempFile).fileName() + TemporaryFile::SUFFIX;
#else
return QFileInfo(m_tempFile).fileName();
#endif
}
QString TemporaryFile::filePath() const
{
#ifdef Q_OS_WIN
return m_tempFile.fileName() + TemporaryFile::SUFFIX;
#else
return m_tempFile.fileName();
#endif
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright (C) 2016 Danny Su <contact@dannysu.com>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_TEMPORARYFILE_H
#define KEEPASSX_TEMPORARYFILE_H
#include <QFile>
#include <QObject>
#include <QTemporaryFile>
/**
* QTemporaryFile::close() doesn't actually close the file according to
* http://doc.qt.io/qt-5/qtemporaryfile.html: "For as long as the
* QTemporaryFile object itself is not destroyed, the unique temporary file
* will exist and be kept open internally by QTemporaryFile."
*
* This behavior causes issues when running tests on Windows. If the file is
* not closed, the testSave test will fail due to Access Denied. The
* auto-reload test also fails from Windows not triggering file change
* notification because the file isn't actually closed by QTemporaryFile.
*
* This class isolates the Windows specific logic that uses QFile to really
* close the test file when requested to.
*/
class TemporaryFile : public QObject
{
Q_OBJECT
public:
#ifdef Q_OS_WIN
~TemporaryFile();
#endif
bool open();
void close();
qint64 write(const char* data, qint64 maxSize);
qint64 write(const QByteArray& byteArray);
QString fileName() const;
QString filePath() const;
private:
QTemporaryFile m_tempFile;
#ifdef Q_OS_WIN
QFile m_file;
static const QString SUFFIX;
#endif
};
#endif // KEEPASSX_TEMPORARYFILE_H

File diff suppressed because it is too large Load Diff

View File

@@ -19,17 +19,19 @@
#ifndef KEEPASSX_TESTGUI_H
#define KEEPASSX_TESTGUI_H
#include "TemporaryFile.h"
#include "gui/MainWindow.h"
#include "util/TemporaryFile.h"
#include <QAbstractItemModel>
#include <QObject>
#include <QPointer>
#include <QScopedPointer>
#include <QSharedPointer>
class Database;
class DatabaseTabWidget;
class DatabaseWidget;
class QAbstractItemView;
class MainWindow;
class TestGui : public QObject
{
@@ -84,12 +86,12 @@ private:
Qt::MouseButton button,
Qt::KeyboardModifiers stateKey = 0);
QPointer<MainWindow> m_mainWindow;
QScopedPointer<MainWindow> m_mainWindow;
QPointer<DatabaseTabWidget> m_tabWidget;
QPointer<DatabaseWidget> m_dbWidget;
QPointer<Database> m_db;
QSharedPointer<Database> m_db;
QByteArray m_dbData;
TemporaryFile m_dbFile;
QScopedPointer<TemporaryFile> m_dbFile;
QString m_dbFileName;
QString m_dbFilePath;
};

View File

@@ -13,7 +13,7 @@
*
* 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 "MockChallengeResponseKey.h"

View File

@@ -13,7 +13,7 @@
*
* 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 KEEPASSXC_MOCKCHALLENGERESPONSEKEY_H
#define KEEPASSXC_MOCKCHALLENGERESPONSEKEY_H

View File

@@ -15,72 +15,72 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TestClock.h"
#include "MockClock.h"
TestClock::TestClock(int year, int month, int day, int hour, int min, int second)
MockClock::MockClock(int year, int month, int day, int hour, int min, int second)
: Clock()
, m_utcCurrent(datetimeUtc(year, month, day, hour, min, second))
{
}
TestClock::TestClock(QDateTime utcBase)
MockClock::MockClock(QDateTime utcBase)
: Clock()
, m_utcCurrent(utcBase)
{
}
const QDateTime& TestClock::advanceSecond(int seconds)
const QDateTime& MockClock::advanceSecond(int seconds)
{
m_utcCurrent = m_utcCurrent.addSecs(seconds);
return m_utcCurrent;
}
const QDateTime& TestClock::advanceMinute(int minutes)
const QDateTime& MockClock::advanceMinute(int minutes)
{
m_utcCurrent = m_utcCurrent.addSecs(minutes * 60);
return m_utcCurrent;
}
const QDateTime& TestClock::advanceHour(int hours)
const QDateTime& MockClock::advanceHour(int hours)
{
m_utcCurrent = m_utcCurrent.addSecs(hours * 60 * 60);
return m_utcCurrent;
}
const QDateTime& TestClock::advanceDay(int days)
const QDateTime& MockClock::advanceDay(int days)
{
m_utcCurrent = m_utcCurrent.addDays(days);
return m_utcCurrent;
}
const QDateTime& TestClock::advanceMonth(int months)
const QDateTime& MockClock::advanceMonth(int months)
{
m_utcCurrent = m_utcCurrent.addMonths(months);
return m_utcCurrent;
}
const QDateTime& TestClock::advanceYear(int years)
const QDateTime& MockClock::advanceYear(int years)
{
m_utcCurrent = m_utcCurrent.addYears(years);
return m_utcCurrent;
}
void TestClock::setup(Clock* clock)
void MockClock::setup(Clock* clock)
{
Clock::setInstance(clock);
}
void TestClock::teardown()
void MockClock::teardown()
{
Clock::resetInstance();
}
QDateTime TestClock::currentDateTimeUtcImpl() const
QDateTime MockClock::currentDateTimeUtcImpl() const
{
return m_utcCurrent;
}
QDateTime TestClock::currentDateTimeImpl() const
QDateTime MockClock::currentDateTimeImpl() const
{
return m_utcCurrent.toLocalTime();
}

View File

@@ -22,12 +22,12 @@
#include <QDateTime>
class TestClock : public Clock
class MockClock : public Clock
{
public:
TestClock(int year, int month, int day, int hour, int min, int second);
MockClock(int year, int month, int day, int hour, int min, int second);
TestClock(QDateTime utcBase = QDateTime::currentDateTimeUtc());
MockClock(QDateTime utcBase = QDateTime::currentDateTimeUtc());
const QDateTime& advanceSecond(int seconds);
const QDateTime& advanceMinute(int minutes);

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TemporaryFile.h"
#ifdef Q_OS_WIN
TemporaryFile::TemporaryFile()
: TemporaryFile(nullptr)
{
}
TemporaryFile::TemporaryFile(const QString& templateName)
: TemporaryFile(templateName, nullptr)
{
}
TemporaryFile::TemporaryFile(QObject* parent)
: QFile(parent)
{
QTemporaryFile tmp;
tmp.open();
QFile::setFileName(tmp.fileName());
tmp.close();
}
TemporaryFile::TemporaryFile(const QString& templateName, QObject* parent)
: QFile(parent)
{
QTemporaryFile tmp(templateName);
tmp.open();
QFile::setFileName(tmp.fileName());
tmp.close();
}
bool TemporaryFile::open()
{
return QFile::open(QIODevice::ReadWrite);
}
#endif

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSXC_TEMPORARYFILE_H
#define KEEPASSXC_TEMPORARYFILE_H
#include <QTemporaryFile>
#ifdef Q_OS_WIN
/**
* QTemporaryFile does not actually close a file when close() is
* called, which causes the file to be locked on Windows.
* This class extends a QFile with the extra functionality
* of a QTemporaryFile to circumvent this problem.
*/
class TemporaryFile : public QFile
#else
class TemporaryFile : public QTemporaryFile
#endif
{
Q_OBJECT
#ifdef Q_OS_WIN
public:
TemporaryFile();
explicit TemporaryFile(const QString& templateName);
explicit TemporaryFile(QObject* parent);
TemporaryFile(const QString& templateName, QObject* parent);
~TemporaryFile() override = default;
using QFile::open;
bool open();
#endif
};
#endif // KEEPASSXC_TEMPORARYFILE_H