Fix parser and add unit tests.

This commit is contained in:
Felix Geyer 2010-08-13 18:08:06 +02:00
parent b64dbce2da
commit bd1ea05017
18 changed files with 690 additions and 103 deletions

View File

@ -13,13 +13,15 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
project(keepassx)
project(KeePassX)
cmake_minimum_required(VERSION 2.6.0)
set( keepassx_VERSION "0.9.0" )
option(WITH_TESTS "Enable building of unit tests" ON)
add_Definitions(-D'KEEPASSX_VERSION="${keepassx_VERSION}"')
set( KEEPASSX_VERSION "0.9.0" )
add_definitions(-DQT_NO_KEYWORDS -Wall)
if( APPLE OR MINGW )
set( PROGNAME KeePassX )
@ -27,10 +29,19 @@ else( APPLE OR MINGW )
set( PROGNAME keepassx )
endif( APPLE OR MINGW )
set(QT_MIN_VERSION "4.3.0")
set(QT_USE_QTXML TRUE)
if( WITH_TESTS )
enable_testing()
set(QT_USE_QTTEST TRUE)
endif( WITH_TESTS )
set(QT_MIN_VERSION "4.6.0")
set(QT_USE_QTMAIN TRUE)
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
find_package(Automoc4 REQUIRED)
add_subdirectory(src)
if( WITH_TESTS )
add_subdirectory(tests)
endif( WITH_TESTS )

View File

@ -13,8 +13,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_BINARY_DIR} )
configure_file( config-keepassx.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepassx.h )
set(keepassx_SOURCES
main.cpp
core/Database.cpp
core/DbAttribute.cpp
core/Entry.cpp
@ -25,18 +28,7 @@ set(keepassx_SOURCES
core/Uuid.cpp
)
set(keepassx_HEADERS
core/Database.h
core/DbAttribute.h
core/Entry.h
core/Group.h
core/Metadata.h
core/Parser.h
core/TimeInfo.h
core/Uuid.h
)
automoc4_add_library( keepassx_core STATIC ${keepassx_SOURCES} )
qt4_wrap_cpp( keepassx_MOC ${keepassx_HEADERS} )
add_executable( ${PROGNAME} WIN32 MACOSX_BUNDLE ${keepassx_SOURCES} ${keepassx_MOC} )
target_link_libraries( ${PROGNAME} ${QT_LIBRARIES} )
add_executable( ${PROGNAME} WIN32 MACOSX_BUNDLE main.cpp )
target_link_libraries( ${PROGNAME} keepassx_core ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} )

View File

@ -0,0 +1,3 @@
/* config-keepassx.h. Generated by cmake from config-keepassx.h.cmake */
#define KEEPASSX_VERSION "${KEEPASSX_VERSION}"

View File

@ -20,12 +20,12 @@
#include <QtCore/QFile>
#include <QtCore/QXmlStreamReader>
#include "Metadata.h"
#include "Parser.h"
Database::Database(const QString& filename)
Database::Database()
{
m_filename = filename;
m_metadata = new Metadata(this);
}
Group* Database::rootGroup()
@ -35,8 +35,8 @@ Group* Database::rootGroup()
void Database::setRootGroup(Group* group)
{
Q_ASSERT(group == 0 || group->parent() == this);
m_rootGroup = group;
group->setParent(this);
}
Metadata* Database::metadata()
@ -44,12 +44,6 @@ Metadata* Database::metadata()
return m_metadata;
}
void Database::open()
{
Parser* parser = new Parser(this);
parser->parse(m_filename);
}
QImage Database::icon(int number)
{
// TODO implement

View File

@ -32,7 +32,7 @@ class Database : public QObject
Q_OBJECT
public:
Database(const QString& filename);
Database();
Group* rootGroup();
void setRootGroup(Group* group);
Metadata* metadata();
@ -42,11 +42,9 @@ public:
Group* resolveGroup(const Uuid& uuid);
private:
void open();
Entry* recFindEntry(const Uuid& uuid, Group* group);
Group* recFindGroup(const Uuid& uuid, Group* group);
QString m_filename;
Metadata* m_metadata;
Group* m_rootGroup;
QHash<Uuid, QImage> m_customIcons;

View File

@ -19,8 +19,9 @@
#include "Group.h"
Entry::Entry() : m_group(0)
Entry::Entry()
{
m_group = 0;
}
Uuid Entry::uuid() const
@ -31,6 +32,7 @@ Uuid Entry::uuid() const
QImage Entry::icon() const
{
// TODO implement
return QImage();
}
QColor Entry::foregroundColor() const
@ -85,6 +87,7 @@ const QHash<QString, QByteArray>& Entry::attachments() const
void Entry::setUuid(const Uuid& uuid)
{
Q_ASSERT(!uuid.isNull());
m_uuid = uuid;
}
@ -153,7 +156,7 @@ void Entry::addAttachment(const QString& key, const QByteArray& value)
void Entry::setGroup(Group* group)
{
if (m_group) {
group->removeEntry(this);
m_group->removeEntry(this);
}
group->addEntry(this);
m_group = group;

View File

@ -22,8 +22,10 @@
#include "Database.h"
Group::Group() : m_parent(0)
Group::Group()
{
m_parent = 0;
m_db = 0;
}
Uuid Group::uuid() const
@ -118,23 +120,38 @@ void Group::setLastTopVisibleEntry(Entry* entry)
void Group::setParent(Group* parent)
{
Q_ASSERT(parent != 0);
if (m_parent) {
m_parent->m_children.removeAll(this);
}
else if (m_db) {
m_db->setRootGroup(0);
}
m_parent = parent;
m_db = parent->m_db;
QObject::setParent(parent);
parent->m_children << this;
}
void Group::setParent(Database* db)
{
if (m_db) {
Q_ASSERT(db != 0);
if (m_parent) {
m_parent->m_children.removeAll(this);
}
else if (m_db) {
m_db->setRootGroup(0);
}
m_parent = 0;
m_db = db;
QObject::setParent(db);
db->setRootGroup(this);
}
QList<Group*> Group::children() const

View File

@ -17,8 +17,16 @@
#include "Metadata.h"
Metadata::Metadata()
#include "Database.h"
Metadata::Metadata(Database* parent) : QObject(parent)
{
m_generator = "KeePassX";
m_maintenanceHistoryDays = 365;
m_recycleBin = 0;
m_entryTemplatesGroup = 0;
m_lastSelectedGroup = 0;
m_lastTopVisibleGroup = 0;
}
QString Metadata::generator() const
@ -101,9 +109,9 @@ bool Metadata::recycleBinEnabled() const
return m_recycleBinEnabled;
}
Uuid Metadata::recycleBinUuid() const
const Group* Metadata::recycleBin() const
{
return m_recycleBinUuid;
return m_recycleBin;
}
QDateTime Metadata::recycleBinChanged() const
@ -111,7 +119,7 @@ QDateTime Metadata::recycleBinChanged() const
return m_recycleBinChanged;
}
Uuid Metadata::entryTemplatesGroup() const
const Group* Metadata::entryTemplatesGroup() const
{
return m_entryTemplatesGroup;
}
@ -121,12 +129,12 @@ QDateTime Metadata::entryTemplatesGroupChanged() const
return m_entryTemplatesGroupChanged;
}
Uuid Metadata::lastSelectedGroup() const
const Group* Metadata::lastSelectedGroup() const
{
return m_lastSelectedGroup;
}
Uuid Metadata::lastTopVisibleGroup() const
const Group* Metadata::lastTopVisibleGroup() const
{
return m_lastTopVisibleGroup;
}
@ -208,6 +216,7 @@ void Metadata::setAutoEnableVisualHiding(bool value)
void Metadata::addCustomIcon(const Uuid& uuid, const QImage& image)
{
Q_ASSERT(!uuid.isNull());
Q_ASSERT(!m_customIcons.contains(uuid));
m_customIcons.insert(uuid, image);
@ -215,6 +224,7 @@ void Metadata::addCustomIcon(const Uuid& uuid, const QImage& image)
void Metadata::removeCustomIcon(const Uuid& uuid)
{
Q_ASSERT(!uuid.isNull());
Q_ASSERT(m_customIcons.contains(uuid));
m_customIcons.remove(uuid);
@ -225,9 +235,9 @@ void Metadata::setRecycleBinEnabled(bool value)
m_recycleBinEnabled = value;
}
void Metadata::setRecycleBinUuid(const Uuid& value)
void Metadata::setRecycleBin(Group* group)
{
m_recycleBinUuid = value;
m_recycleBin = group;
}
void Metadata::setRecycleBinChanged(const QDateTime& value)
@ -235,9 +245,9 @@ void Metadata::setRecycleBinChanged(const QDateTime& value)
m_recycleBinChanged = value;
}
void Metadata::setEntryTemplatesGroup(const Uuid& value)
void Metadata::setEntryTemplatesGroup(Group* group)
{
m_entryTemplatesGroup = value;
m_entryTemplatesGroup = group;
}
void Metadata::setEntryTemplatesGroupChanged(const QDateTime& value)
@ -245,14 +255,14 @@ void Metadata::setEntryTemplatesGroupChanged(const QDateTime& value)
m_entryTemplatesGroupChanged = value;
}
void Metadata::setLastSelectedGroup(const Uuid& value)
void Metadata::setLastSelectedGroup(Group* group)
{
m_lastSelectedGroup = value;
m_lastSelectedGroup = group;
}
void Metadata::setLastTopVisibleGroup(const Uuid& value)
void Metadata::setLastTopVisibleGroup(Group* group)
{
m_lastTopVisibleGroup = value;
m_lastTopVisibleGroup = group;
}
void Metadata::addCustomField(const QString& key, const QString& value)

View File

@ -24,10 +24,15 @@
#include <QtCore/QHash>
#include <QtGui/QImage>
class Metadata
class Database;
class Group;
class Metadata : public QObject
{
Q_OBJECT
public:
Metadata();
Metadata(Database* parent);
QString generator() const;
QString name() const;
@ -45,12 +50,12 @@ public:
bool autoEnableVisualHiding() const;
QHash<Uuid, QImage> customIcons() const;
bool recycleBinEnabled() const;
Uuid recycleBinUuid() const;
const Group* recycleBin() const;
QDateTime recycleBinChanged() const;
Uuid entryTemplatesGroup() const;
const Group* entryTemplatesGroup() const;
QDateTime entryTemplatesGroupChanged() const;
Uuid lastSelectedGroup() const;
Uuid lastTopVisibleGroup() const;
const Group* lastSelectedGroup() const;
const Group* lastTopVisibleGroup() const;
QHash<QString, QString> customFields() const;
void setGenerator(const QString& value);
@ -70,12 +75,12 @@ public:
void addCustomIcon(const Uuid& uuid, const QImage& image);
void removeCustomIcon(const Uuid& uuid);
void setRecycleBinEnabled(bool value);
void setRecycleBinUuid(const Uuid& value);
void setRecycleBin(Group* group);
void setRecycleBinChanged(const QDateTime& value);
void setEntryTemplatesGroup(const Uuid& value);
void setEntryTemplatesGroup(Group* group);
void setEntryTemplatesGroupChanged(const QDateTime& value);
void setLastSelectedGroup(const Uuid& value);
void setLastTopVisibleGroup(const Uuid& value);
void setLastSelectedGroup(Group* group);
void setLastTopVisibleGroup(Group* group);
void addCustomField(const QString& key, const QString& value);
void removeCustomField(const QString& key);
@ -99,12 +104,12 @@ private:
QHash<Uuid, QImage> m_customIcons;
bool m_recycleBinEnabled;
Uuid m_recycleBinUuid;
Group* m_recycleBin;
QDateTime m_recycleBinChanged;
Uuid m_entryTemplatesGroup;
Group* m_entryTemplatesGroup;
QDateTime m_entryTemplatesGroupChanged;
Uuid m_lastSelectedGroup;
Uuid m_lastTopVisibleGroup;
Group* m_lastSelectedGroup;
Group* m_lastTopVisibleGroup;
QHash<QString, QString> m_customFields;
};

View File

@ -17,6 +17,7 @@
#include "Parser.h"
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include "Database.h"
@ -35,24 +36,31 @@ bool Parser::parse(const QString& filename)
m_xml.setDevice(&file);
m_tmpParent = new Group();
m_tmpParent->setParent(m_db);
if (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "KeePassFile") {
parseKeePassFile();
}
else {
raiseError();
}
}
if (!m_tmpParent->children().isEmpty()) {
delete m_tmpParent;
if (!m_xml.error() && !m_tmpParent->children().isEmpty()) {
raiseError();
}
delete m_tmpParent;
return !m_xml.error();
}
QString Parser::errorMsg()
{
return QString("%1\nLine %2, column %3")
.arg(m_xml.errorString())
.arg(m_xml.lineNumber())
.arg(m_xml.columnNumber());
}
void Parser::parseKeePassFile()
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile");
@ -65,7 +73,7 @@ void Parser::parseKeePassFile()
parseRoot();
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -109,28 +117,28 @@ void Parser::parseMeta()
m_meta->setRecycleBinEnabled(readBool());
}
else if (m_xml.name() == "RecycleBinUUID") {
m_meta->setRecycleBinUuid(readUuid());
m_meta->setRecycleBin(getGroup(readUuid()));
}
else if (m_xml.name() == "RecycleBinChanged") {
m_meta->setRecycleBinChanged(readDateTime());
}
else if (m_xml.name() == "EntryTemplatesGroup") {
m_meta->setEntryTemplatesGroup(readUuid());
m_meta->setEntryTemplatesGroup(getGroup(readUuid()));
}
else if (m_xml.name() == "EntryTemplatesGroupChanged") {
m_meta->setEntryTemplatesGroupChanged(readDateTime());
}
else if (m_xml.name() == "LastSelectedGroup") {
m_meta->setLastSelectedGroup(readUuid());
m_meta->setLastSelectedGroup(getGroup(readUuid()));
}
else if (m_xml.name() == "LastTopVisibleGroup") {
m_meta->setLastTopVisibleGroup(readUuid());
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
}
else if (m_xml.name() == "CustomData") {
parseCustomData();
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -159,7 +167,7 @@ void Parser::parseMemoryProtection()
m_meta->setAutoEnableVisualHiding(readBool());
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -173,7 +181,7 @@ void Parser::parseCustomIcons()
parseIcon();
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -193,7 +201,7 @@ void Parser::parseIcon()
m_meta->addCustomIcon(uuid, image);
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -202,7 +210,10 @@ void Parser::parseCustomData()
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData");
// TODO
// TODO implement
while (!m_xml.error() && m_xml.readNextStartElement()) {
skipCurrentElement();
}
}
void Parser::parseRoot()
@ -218,9 +229,10 @@ void Parser::parseRoot()
}
else if (m_xml.name() == "DeletedObjects") {
// TODO implement
skipCurrentElement();
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -237,7 +249,7 @@ Group* Parser::parseGroup()
raiseError();
}
else {
group = getGroup(uuid);
group = getGroup(uuid);
}
}
else if (m_xml.name() == "Name") {
@ -268,16 +280,14 @@ Group* Parser::parseGroup()
}
else if (m_xml.name() == "EnableAutoType") {
// TODO implement
skipCurrentElement();
}
else if (m_xml.name() == "EnableSearching") {
// TODO implement
skipCurrentElement();
}
else if (m_xml.name() == "LastTopVisibleEntry") {
Uuid uuid = readUuid();
if (uuid.isNull())
group->setLastTopVisibleEntry(0);
else
group->setLastTopVisibleEntry(getEntry(uuid));
group->setLastTopVisibleEntry(getEntry(readUuid()));
}
else if (m_xml.name() == "Group") {
Group* newGroup = parseGroup();
@ -292,7 +302,7 @@ Group* Parser::parseGroup()
}
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
@ -349,9 +359,11 @@ Entry* Parser::parseEntry()
parseEntryHistory();
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
return entry;
}
void Parser::parseEntryString(Entry *entry)
@ -367,7 +379,7 @@ void Parser::parseEntryString(Entry *entry)
entry->addAttribute(key, readString());
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -385,7 +397,7 @@ void Parser::parseEntryBinary(Entry *entry)
entry->addAttachment(key, readBinary());
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -408,7 +420,7 @@ void Parser::parseAutoType(Entry* entry)
parseAutoTypeAssoc(entry);
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -427,7 +439,7 @@ void Parser::parseAutoTypeAssoc(Entry *entry)
entry->addAutoTypeAssociation(assoc);
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -439,9 +451,10 @@ void Parser::parseEntryHistory()
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Entry") {
// TODO implement
skipCurrentElement();
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
}
@ -474,7 +487,7 @@ TimeInfo Parser::parseTimes()
timeInfo.setLocationChanged(readDateTime());
}
else {
m_xml.skipCurrentElement();
skipCurrentElement();
}
}
@ -490,14 +503,15 @@ bool Parser::readBool()
{
QString str = readString();
if (str == "True") {
if (str.compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) {
return true;
}
else if (str == "False") {
else if (str.compare(QLatin1String("False"), Qt::CaseInsensitive) == 0) {
return false;
}
else {
raiseError();
return false;
}
}
@ -516,6 +530,11 @@ QDateTime Parser::readDateTime()
QColor Parser::readColor()
{
QString colorStr = readString();
if (colorStr.isEmpty()) {
return QColor();
}
if (colorStr.length() != 7 || colorStr[0] != '#') {
raiseError();
return QColor();
@ -525,7 +544,7 @@ QColor Parser::readColor()
for (int i=0; i<= 2; i++) {
QString rgbPartStr = colorStr.mid(1 + 2*i, 2);
bool ok;
int rgbPart = rgbPartStr.toInt(&ok);
int rgbPart = rgbPartStr.toInt(&ok, 16);
if (!ok || rgbPart > 255) {
raiseError();
return QColor();
@ -563,7 +582,7 @@ Uuid Parser::readUuid()
return Uuid();
}
else {
return Uuid(readBinary());
return Uuid(uuidBin);
}
}
@ -574,6 +593,10 @@ QByteArray Parser::readBinary()
Group* Parser::getGroup(const Uuid& uuid)
{
if (uuid.isNull()) {
return 0;
}
Q_FOREACH (Group* group, m_groups) {
if (group->uuid() == uuid) {
return group;
@ -589,6 +612,10 @@ Group* Parser::getGroup(const Uuid& uuid)
Entry* Parser::getEntry(const Uuid& uuid)
{
if (uuid.isNull()) {
return 0;
}
Q_FOREACH (Entry* entry, m_entries) {
if (entry->uuid() == uuid) {
return entry;
@ -606,3 +633,9 @@ void Parser::raiseError()
{
m_xml.raiseError(tr("Invalid database file"));
}
void Parser::skipCurrentElement()
{
qDebug() << "Parser::skipCurrentElement(): skip: " << m_xml.name();
m_xml.skipCurrentElement();
}

View File

@ -37,6 +37,7 @@ class Parser : public QObject
public:
Parser(Database* db);
bool parse(const QString& filename);
QString errorMsg();
private:
void parseKeePassFile();
@ -66,6 +67,7 @@ private:
Group* getGroup(const Uuid& uuid);
Entry* getEntry(const Uuid& uuid);
void raiseError();
void skipCurrentElement();
QXmlStreamReader m_xml;
Database* m_db;

View File

@ -39,10 +39,9 @@ Uuid::Uuid(const QByteArray& data)
m_data = data;
}
QString Uuid::toString() const
QString Uuid::toBase64() const
{
return m_data.toHex();
return m_data.toBase64();
}
QByteArray Uuid::toByteArray() const

View File

@ -27,7 +27,7 @@ public:
Uuid();
Uuid(bool generate);
Uuid(const QByteArray& data);
QString toString() const;
QString toBase64() const;
QByteArray toByteArray() const;
bool isNull() const;
bool operator==(const Uuid& other) const;

70
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,70 @@
# Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
#
# 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/>.
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src)
set( KEEPASSX_TEST_TREE ${CMAKE_SOURCE_DIR}/tests )
configure_file( config-keepassx-tests.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-keepassx-tests.h )
macro (ADD_UNIT_TEST _test_NAME)
set(_srcList ${ARGN})
set(_targetName ${_test_NAME})
if( ${ARGV1} STREQUAL "TESTNAME" )
set(_targetName ${ARGV2})
list(REMOVE_AT _srcList 0 1)
endif( ${ARGV1} STREQUAL "TESTNAME" )
set(_nogui)
list(GET ${_srcList} 0 first_PARAM)
if( ${first_PARAM} STREQUAL "NOGUI" )
set(_nogui "NOGUI")
endif( ${first_PARAM} STREQUAL "NOGUI" )
automoc4_add_executable( ${_test_NAME} ${_srcList} )
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")
get_target_property( loc ${_test_NAME} LOCATION )
if (KDE4_TEST_OUTPUT STREQUAL "xml")
add_test( ${_targetName} ${loc} -xml -o ${_targetName}.tml)
else (KDE4_TEST_OUTPUT STREQUAL "xml")
add_test( ${_targetName} ${loc} )
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(NOT _buildtestsAdded)
add_dependencies(buildtests ${_test_NAME})
endif (NOT WITH_TESTS)
endif (NOT MSVC_IDE)
endmacro (ADD_UNIT_TEST)
add_unit_test( testparser TestParser.cpp )
target_link_libraries( testparser keepassx_core ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} )
add_unit_test( testgroup TestGroup.cpp )
target_link_libraries( testgroup keepassx_core ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTTEST_LIBRARY} )

287
tests/NewDatabase.xml Normal file
View File

@ -0,0 +1,287 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<KeePassFile>
<Meta>
<Generator>KeePass</Generator>
<DatabaseName>ANAME</DatabaseName>
<DatabaseNameChanged>2010-08-08T17:24:53Z</DatabaseNameChanged>
<DatabaseDescription>ADESC</DatabaseDescription>
<DatabaseDescriptionChanged>2010-08-08T17:27:12Z</DatabaseDescriptionChanged>
<DefaultUserName>DEFUSERNAME</DefaultUserName>
<DefaultUserNameChanged>2010-08-08T17:27:45Z</DefaultUserNameChanged>
<MaintenanceHistoryDays>127</MaintenanceHistoryDays>
<MemoryProtection>
<ProtectTitle>False</ProtectTitle>
<ProtectUserName>True</ProtectUserName>
<ProtectPassword>False</ProtectPassword>
<ProtectURL>True</ProtectURL>
<ProtectNotes>False</ProtectNotes>
<AutoEnableVisualHiding>True</AutoEnableVisualHiding>
</MemoryProtection>
<RecycleBinEnabled>True</RecycleBinEnabled>
<RecycleBinUUID>7PAwxNhPaE2klutz45i2xg==</RecycleBinUUID>
<RecycleBinChanged>2010-08-08T17:24:17Z</RecycleBinChanged>
<EntryTemplatesGroup>AAAAAAAAAAAAAAAAAAAAAA==</EntryTemplatesGroup>
<EntryTemplatesGroupChanged>2010-08-08T17:24:19Z</EntryTemplatesGroupChanged>
<LastSelectedGroup>zKuE27EWr0mlU75b2SRkTQ==</LastSelectedGroup>
<LastTopVisibleGroup>zKuE27EWr0mlU75b2SRkTQ==</LastTopVisibleGroup>
<CustomData />
</Meta>
<Root>
<Group>
<UUID>zKuE27EWr0mlU75b2SRkTQ==</UUID>
<Name>NewDatabase</Name>
<Notes />
<IconID>49</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:27Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:27Z</CreationTime>
<LastAccessTime>2010-08-09T09:09:44Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>2</UsageCount>
<LocationChanged>2010-08-08T17:24:27Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>QW4G0r/z90qql4iKZ0RwlA==</LastTopVisibleEntry>
<Entry>
<UUID>QW4G0r/z90qql4iKZ0RwlA==</UUID>
<IconID>0</IconID>
<ForegroundColor>#0000FF</ForegroundColor>
<BackgroundColor>#000000</BackgroundColor>
<OverrideURL>OMGAURL</OverrideURL>
<Times>
<LastModificationTime>2010-08-09T09:09:31Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-09T09:09:31Z</LastAccessTime>
<ExpiryTime>2011-08-08T17:25:58Z</ExpiryTime>
<Expires>True</Expires>
<UsageCount>6</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<String>
<Key>customfield</Key>
<Value>customfield value</Value>
</String>
<String>
<Key>Notes</Key>
<Value>Notes</Value>
</String>
<String>
<Key>Password</Key>
<Value>Password</Value>
</String>
<String>
<Key>Title</Key>
<Value>Sample Entry</Value>
</String>
<String>
<Key>URL</Key>
<Value>bleh</Value>
</String>
<String>
<Key>UserName</Key>
<Value>User Name</Value>
</String>
<AutoType>
<Enabled>True</Enabled>
<DataTransferObfuscation>1</DataTransferObfuscation>
<DefaultSequence>{USERNAME}{TAB}{PASSWORD}{ENTER}</DefaultSequence>
<Association>
<Window>Target Window</Window>
<KeystrokeSequence>{USERNAME}{TAB}{PASSWORD}{TAB}{ENTER}</KeystrokeSequence>
</Association>
<Association>
<Window>Edit Entry</Window>
<KeystrokeSequence>{Title}{UserName}{UserName}</KeystrokeSequence>
</Association>
</AutoType>
<History />
</Entry>
<Group>
<UUID>abLbFtNUfEi5TmbaxiW6yg==</UUID>
<Name>General</Name>
<Notes />
<IconID>48</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:53Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-08T17:24:53Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>0</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
</Group>
<Group>
<UUID>u1lTRAICOkWv5QSl2xyU8w==</UUID>
<Name>Windows</Name>
<Notes />
<IconID>38</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:53Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-08T17:24:53Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>0</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
</Group>
<Group>
<UUID>bFe1/LfewEuvlTsT8nJRRg==</UUID>
<Name>Network</Name>
<Notes />
<IconID>3</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:53Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-08T17:24:53Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>0</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
</Group>
<Group>
<UUID>wHmj/+6vTkOpG/eeVp3yjg==</UUID>
<Name>Internet</Name>
<Notes />
<IconID>1</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:53Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-08T17:24:53Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>0</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
</Group>
<Group>
<UUID>9QLqqFgc5EC7ptm2TI1hDA==</UUID>
<Name>eMail</Name>
<Notes />
<IconID>19</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:53Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-08T17:24:53Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>0</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
</Group>
<Group>
<UUID>wQru0ArOaEOy0uUio3subA==</UUID>
<Name>Homebanking</Name>
<Notes />
<IconID>37</IconID>
<Times>
<LastModificationTime>2010-08-08T17:24:53Z</LastModificationTime>
<CreationTime>2010-08-08T17:24:53Z</CreationTime>
<LastAccessTime>2010-08-08T17:24:53Z</LastAccessTime>
<ExpiryTime>2010-08-08T17:24:17Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>0</UsageCount>
<LocationChanged>2010-08-08T17:24:53Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>null</EnableAutoType>
<EnableSearching>null</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
</Group>
<Group>
<UUID>7PAwxNhPaE2klutz45i2xg==</UUID>
<Name>Recycle Bin</Name>
<Notes />
<IconID>43</IconID>
<Times>
<LastModificationTime>2010-08-09T09:09:44Z</LastModificationTime>
<CreationTime>2010-08-09T09:09:44Z</CreationTime>
<LastAccessTime>2010-08-09T09:09:44Z</LastAccessTime>
<ExpiryTime>2010-08-09T09:07:16Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>1</UsageCount>
<LocationChanged>2010-08-09T09:09:44Z</LocationChanged>
</Times>
<IsExpanded>True</IsExpanded>
<DefaultAutoTypeSequence />
<EnableAutoType>false</EnableAutoType>
<EnableSearching>false</EnableSearching>
<LastTopVisibleEntry>AAAAAAAAAAAAAAAAAAAAAA==</LastTopVisibleEntry>
<Entry>
<UUID>KIeQe6yDN0SbjIJ83NB++Q==</UUID>
<IconID>0</IconID>
<ForegroundColor />
<BackgroundColor />
<OverrideURL />
<Times>
<LastModificationTime>2010-08-09T09:09:40Z</LastModificationTime>
<CreationTime>2010-08-09T09:09:37Z</CreationTime>
<LastAccessTime>2010-08-09T09:09:44Z</LastAccessTime>
<ExpiryTime>2010-08-09T09:07:16Z</ExpiryTime>
<Expires>False</Expires>
<UsageCount>2</UsageCount>
<LocationChanged>2010-08-09T09:09:44Z</LocationChanged>
</Times>
<String>
<Key>Notes</Key>
<Value />
</String>
<String>
<Key>Password</Key>
<Value>5Ciyy3kcVSPFUFqTuK1o</Value>
</String>
<String>
<Key>Title</Key>
<Value>test</Value>
</String>
<String>
<Key>URL</Key>
<Value />
</String>
<String>
<Key>UserName</Key>
<Value>DEFUSERNAME</Value>
</String>
<AutoType>
<Enabled>True</Enabled>
<DataTransferObfuscation>0</DataTransferObfuscation>
</AutoType>
<History />
</Entry>
</Group>
</Group>
<DeletedObjects />
</Root>
</KeePassFile>

68
tests/TestGroup.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <QtTest/QTest>
#include "core/Database.h"
class TestGroup : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testParenting();
};
void TestGroup::testParenting()
{
Database* db = new Database();
Group* tmpRoot = new Group();
tmpRoot->setParent(db);
Group* g1 = new Group();
Group* g2 = new Group();
Group* g3 = new Group();
Group* g4 = new Group();
g1->setParent(tmpRoot);
g2->setParent(tmpRoot);
g3->setParent(tmpRoot);
g4->setParent(tmpRoot);
g2->setParent(g1);
g4->setParent(g3);
g3->setParent(g1);
g1->setParent(db);
QVERIFY(g1->parent() == db);
QVERIFY(g2->parent() == g1);
QVERIFY(g3->parent() == g1);
QVERIFY(g4->parent() == g3);
QVERIFY(tmpRoot->children().size() == 0);
QVERIFY(g1->children().size() == 2);
QVERIFY(g2->children().size() == 0);
QVERIFY(g3->children().size() == 1);
QVERIFY(g4->children().size() == 0);
QVERIFY(g1->children().contains(g2));
QVERIFY(g1->children().contains(g3));
QVERIFY(g3->children().contains(g4));
}
QTEST_MAIN(TestGroup);
#include "TestGroup.moc"

92
tests/TestParser.cpp Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 <QtTest/QTest>
#include "core/Database.h"
#include "core/Metadata.h"
#include "core/Parser.h"
#include "config-keepassx-tests.h"
class TestParser : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testMetadata();
void testGroups();
private:
QDateTime genDT(int year, int month, int day, int hour, int min, int second);
Database* m_db;
};
QDateTime TestParser::genDT(int year, int month, int day, int hour, int min, int second)
{
QDate date(year, month, day);
QTime time(hour, min, second);
return QDateTime(date, time, Qt::UTC);
}
void TestParser::initTestCase()
{
m_db = new Database();
Parser* parser = new Parser(m_db);
QString xmlFile = QString(KEEPASSX_TEST_DIR).append("/NewDatabase.xml");
QVERIFY(parser->parse(xmlFile));
}
void TestParser::testMetadata()
{
QCOMPARE(m_db->metadata()->generator(), QLatin1String("KeePass"));
QCOMPARE(m_db->metadata()->name(), QLatin1String("ANAME"));
QCOMPARE(m_db->metadata()->nameChanged(), genDT(2010, 8, 8, 17, 24, 53));
QCOMPARE(m_db->metadata()->description(), QLatin1String("ADESC"));
QCOMPARE(m_db->metadata()->descriptionChanged(), genDT(2010, 8, 8, 17, 27, 12));
QCOMPARE(m_db->metadata()->defaultUserName(), QLatin1String("DEFUSERNAME"));
QCOMPARE(m_db->metadata()->defaultUserNameChanged(), genDT(2010, 8, 8, 17, 27, 45));
QCOMPARE(m_db->metadata()->maintenanceHistoryDays(), 127);
QCOMPARE(m_db->metadata()->protectTitle(), false);
QCOMPARE(m_db->metadata()->protectUsername(), true);
QCOMPARE(m_db->metadata()->protectPassword(), false);
QCOMPARE(m_db->metadata()->protectUrl(), true);
QCOMPARE(m_db->metadata()->protectNotes(), false);
QCOMPARE(m_db->metadata()->autoEnableVisualHiding(), true);
QCOMPARE(m_db->metadata()->recycleBinEnabled(), true);
QVERIFY(m_db->metadata()->recycleBin() != 0);
QCOMPARE(m_db->metadata()->recycleBin()->name(), QLatin1String("Recycle Bin"));
QCOMPARE(m_db->metadata()->recycleBinChanged(), genDT(2010, 8, 8, 17, 24, 17));
QVERIFY(m_db->metadata()->entryTemplatesGroup() == 0);
QCOMPARE(m_db->metadata()->entryTemplatesGroupChanged(), genDT(2010, 8, 8, 17, 24, 19));
QVERIFY(m_db->metadata()->lastSelectedGroup() != 0);
QCOMPARE(m_db->metadata()->lastSelectedGroup()->name(), QLatin1String("NewDatabase"));
QVERIFY(m_db->metadata()->lastTopVisibleGroup() != 0);
QCOMPARE(m_db->metadata()->lastTopVisibleGroup()->name(), QLatin1String("NewDatabase"));
}
void TestParser::testGroups()
{
QVERIFY(m_db->rootGroup()->name() == QLatin1String("NewDatabase"));
QVERIFY(m_db->rootGroup()->uuid().toBase64() == QLatin1String("zKuE27EWr0mlU75b2SRkTQ=="));
QVERIFY(m_db->rootGroup()->isExpanded() == true);
}
QTEST_MAIN(TestParser);
#include "TestParser.moc"

View File

@ -0,0 +1,3 @@
/* config-keepassx-tests.h. Generated by cmake from config-keepassx-tests.h.cmake */
#define KEEPASSX_TEST_DIR "${KEEPASSX_TEST_TREE}"