/*
 * Copyright (C) 2014-2022 CZ.NIC
 *
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * 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/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSet>
#include <QSignalSpy>
#include <QString>
#include <QtTest/QtTest>

#include "src/datovka_shared/graphics/colour.h"
#include "src/datovka_shared/log/log.h"
#include "src/global.h"
#include "src/io/tag_db.h"
#include "src/tags/tag_assignment.h"
#include "src/tags/tag_entry.h"
#include "tests/test_tag_db.h"

class TestTagDb : public QObject {
	Q_OBJECT

public:
	TestTagDb(void);

private slots:
	void initTestCase(void);

	void cleanupTestCase(void);

	void tagEntry(void);

	void tagEntryCompare(void);

	void tagEntryConstructor(void);

	void tagEntryCopy(void);

	void tagEntrySetValues(void);

	void tagEntryMisc(void);

	void tagAssignment(void);

	void tagAssignmentCompare(void);

	void tagAssignmentConstructor(void);

	void tagAssignmentCopy(void);

	void tagAssignmentSetvalues(void);

	void testTagDbInsert(void);

	void testTagDbUpdate(void);

	void testTagDbDelete(void);

	void testTagDbAssignmentChange(void);

private:
	void _init(void);

	void _cleanup(void);

	const QString m_connectionPrefix; /*!< SQL connection prefix. */
	const QString m_dbLocationPath; /*!< Directory path. */
	QDir m_dbDir;  /*!< Directory containing testing databases. */
	const QString m_dbName; /*!< Database file name. */
	const QString m_dbPath;
};

TestTagDb::TestTagDb(void)
    : m_connectionPrefix(QLatin1String("TAGDB")),
    m_dbLocationPath(QDir::currentPath() + QDir::separator() + QLatin1String("_db")),
    m_dbDir(m_dbLocationPath),
    m_dbName(QLatin1String("tag.db")),
    m_dbPath(m_dbLocationPath + QDir::separator() + m_dbName)
{
}

void TestTagDb::initTestCase(void)
{
	QVERIFY(GlobInstcs::logPtr == Q_NULLPTR);
	GlobInstcs::logPtr = new (::std::nothrow) LogDevice;
	QVERIFY(GlobInstcs::logPtr != Q_NULLPTR);

	/* Pointer must be null before initialisation. */
	QVERIFY(GlobInstcs::tagDbPtr == Q_NULLPTR);

	QVERIFY(m_dbDir.removeRecursively());
	QVERIFY(!m_dbDir.exists());

	QVERIFY(m_dbDir.mkpath("."));
}

void TestTagDb::cleanupTestCase(void)
{
	QVERIFY(GlobInstcs::tagDbPtr == Q_NULLPTR);

	delete GlobInstcs::logPtr; GlobInstcs::logPtr = Q_NULLPTR;

	QVERIFY(m_dbDir.removeRecursively());
	QVERIFY(!m_dbDir.exists());
}

void TestTagDb::tagEntry(void)
{
	TagEntry e1, e2;
	int id = 1;
	QString name("name");
	QString colour("000000");

	/* Must be null. */
	QVERIFY(e1.id() == -1);
	QVERIFY(e1.name().isNull());
	QVERIFY(e1.colour().isNull());
	QVERIFY(e2.id() == -1);
	QVERIFY(e2.name().isNull());
	QVERIFY(e2.colour().isNull());

	QVERIFY(e1.isNull());
	QVERIFY(e2.isNull());
	QVERIFY(e1 == e2);

	/* Check whether values are not cross-linked. */
	e1.setId(id);
	e1.setName(name);
	e1.setColour(colour);

	QVERIFY(e1.id() == id);
	QVERIFY(e1.name() == name);
	QVERIFY(e1.colour() == colour);

	QVERIFY(!e1.isNull());
	QVERIFY(e2.isNull());
	QVERIFY(e1 != e2);

	/* Check value copying. */
	e2 = e1;

	QVERIFY(e2.id() == id);
	QVERIFY(e2.name() == name);
	QVERIFY(e2.colour() == colour);

	QVERIFY(!e1.isNull());
	QVERIFY(!e2.isNull());
	QVERIFY(e1 == e2);

	/* Clear value. */
	e1 = TagEntry();

	QVERIFY(e1.id() == -1);
	QVERIFY(e1.name().isNull());
	QVERIFY(e1.colour().isNull());
	QVERIFY(e2.id() == id);
	QVERIFY(e2.name() == name);
	QVERIFY(e2.colour() == colour);

	QVERIFY(e1.isNull());
	QVERIFY(!e2.isNull());
	QVERIFY(e1 != e2);
}

void TestTagDb::tagEntryCompare(void)
{
	TagEntry e1, e2;
	int id = 1;
	QString name("name");
	QString colour("000000");

	e1.setId(id);
	e1.setName(name);
	e1.setColour(colour);
	e2.setId(id);
	e2.setName(name);
	e2.setColour(colour);

	QVERIFY(e1 == e2);

	e2.setId(0);
	QVERIFY(e1 != e2);
	e2.setId(id);
	QVERIFY(e1 == e2);

	e2.setName("");
	QVERIFY(e1 != e2);
	e2.setName(name);
	QVERIFY(e1 == e2);

	e2.setColour("");
	QVERIFY(e1 != e2);
	e2.setColour(colour);
	QVERIFY(e1 == e2);
}

void TestTagDb::tagEntryConstructor(void)
{
	const QString cName("name");
	const QString cColour("000000");

	{
		TagEntry e;

		QVERIFY(e.isNull());
		QVERIFY(!e.isValid());

		QVERIFY(e.id() == -1);
		QVERIFY(e.name().isNull());
		QVERIFY(e.colour().isNull());
	}

	{
		int id = 1;
		QString name(cName);
		QString colour(cColour);
		TagEntry e(id, name, colour);

		QVERIFY(!e.isNull());
		QVERIFY(e.isValid());

		QVERIFY(e.id() == id);
		QVERIFY(e.name() == name);
		QVERIFY(e.colour() == colour);

		QVERIFY(name == cName);
		QVERIFY(colour == cColour);
	}

#ifdef Q_COMPILER_RVALUE_REFS
	{
		int id = 1;
		QString name(cName);
		QString colour(cColour);
		TagEntry e(id, ::std::move(name), ::std::move(colour));

		QVERIFY(!e.isNull());
		QVERIFY(e.isValid());

		QVERIFY(e.id() == id);
		QVERIFY(e.name() == cName);
		QVERIFY(e.colour() == cColour);

		QVERIFY(name.isNull());
		QVERIFY(colour == "ffffff"); /* Constructor creates "ffffff" by default. */
	}
#endif /* Q_COMPILER_RVALUE_REFS */
}

void TestTagDb::tagEntryCopy(void)
{
	TagEntry e1;
	int id = 1;
	QString name("name");
	QString colour("000000");

	e1.setId(id);
	e1.setName(name);
	e1.setColour(colour);

	/* Constructor. */
	{
		TagEntry e2(e1);

		QVERIFY(!e1.isNull());
		QVERIFY(!e2.isNull());
		QVERIFY(e1 == e2);

#ifdef Q_COMPILER_RVALUE_REFS
		/* Move. */
		TagEntry e3(::std::move(e2));

		QVERIFY(e2.isNull());
		QVERIFY(e1 != e2);

		QVERIFY(!e1.isNull());
		QVERIFY(!e3.isNull());
		QVERIFY(e1 == e3);
#endif /* Q_COMPILER_RVALUE_REFS */
	}

	/* Assignment operator. */
	{
		TagEntry e2;

		QVERIFY(e2.isNull());

		e2 = e1;

		QVERIFY(!e1.isNull());
		QVERIFY(!e2.isNull());
		QVERIFY(e1 == e2);

#ifdef Q_COMPILER_RVALUE_REFS
		/* Move. */
		TagEntry e3;

		QVERIFY(e3.isNull());

		e3 = ::std::move(e2);

		QVERIFY(e2.isNull());
		QVERIFY(e1 != e2);

		QVERIFY(!e1.isNull());
		QVERIFY(!e3.isNull());
		QVERIFY(e1 == e3);
#endif /* Q_COMPILER_RVALUE_REFS */
	}
}

void TestTagDb::tagEntrySetValues(void)
{
	const QString cName("name");
	const QString cColour("000000");

	TagEntry e;
	//int id = 1;
	QString name(cName);
	QString colour(cColour);

	QVERIFY(e.name().isNull());
	e.setName(name);
	QVERIFY(e.name() == cName);
	QVERIFY(name == cName);
#ifdef Q_COMPILER_RVALUE_REFS
	e.setName("other_name");
	QVERIFY(e.name() != cName);
	e.setName(::std::move(name));
	QVERIFY(e.name() == cName);
	QVERIFY(name != cName);
#endif /* Q_COMPILER_RVALUE_REFS */

	QVERIFY(e.colour() == "ffffff");
	e.setColour(colour);
	QVERIFY(e.colour() == cColour);
	QVERIFY(colour == cColour);
#ifdef Q_COMPILER_RVALUE_REFS
	e.setColour("000001");
	QVERIFY(e.colour() != cColour);
	e.setColour(::std::move(colour));
	QVERIFY(e.colour() == cColour);
	QVERIFY(colour != cColour);
#endif /* Q_COMPILER_RVALUE_REFS */
}

void TestTagDb::tagEntryMisc(void)
{
	QVERIFY(!Colour::isValidColourStr(QString()));
	QVERIFY(!Colour::isValidColourStr(""));
	QVERIFY(!Colour::isValidColourStr("0"));
	QVERIFY(!Colour::isValidColourStr("00"));
	QVERIFY(!Colour::isValidColourStr("000"));
	QVERIFY(!Colour::isValidColourStr("0000"));
	QVERIFY(!Colour::isValidColourStr("00000"));
	QVERIFY(Colour::isValidColourStr("000000"));
	QVERIFY(!Colour::isValidColourStr("0000000"));
	QVERIFY(!Colour::isValidColourStr("#000000"));

	QVERIFY(Colour::isValidColourStr("012345"));
	QVERIFY(Colour::isValidColourStr("6789ab"));
	QVERIFY(Colour::isValidColourStr("cdef00"));

	QVERIFY(Colour::isValidColourStr("000000"));
}

void TestTagDb::tagAssignment(void)
{
	TagAssignment a1, a2;
	QString username("username");
	bool testing = true;
	qint64 dmId = 1;
	QList<TagEntry> entries =
	    QList<TagEntry>() << TagEntry(1, "name", "000000");

	/* Must be null. */
	QVERIFY(a1.username().isNull());
	QVERIFY(a1.testing() == false);
	QVERIFY(a1.dmId() == -1);
	QVERIFY(a1.entries().isEmpty());
	QVERIFY(a2.username().isNull());
	QVERIFY(a2.testing() == false);
	QVERIFY(a2.dmId() == -1);
	QVERIFY(a2.entries().isEmpty());

	QVERIFY(a1.isNull());
	QVERIFY(a2.isNull());
	QVERIFY(a1 == a2);

	/* Check whether values are not cross-linked. */
	a1.setUsername(username);
	a1.setTesting(testing);
	a1.setDmId(dmId);
	a1.setEntries(entries);

	QVERIFY(a1.username() == username);
	QVERIFY(a1.testing() == testing);
	QVERIFY(a1.dmId() == dmId);
	QVERIFY(a1.entries() == entries);

	QVERIFY(!a1.isNull());
	QVERIFY(a2.isNull());
	QVERIFY(a1 != a2);

	/* Check value copying. */
	a2 = a1;

	QVERIFY(a2.username() == username);
	QVERIFY(a2.testing() == testing);
	QVERIFY(a2.dmId() == dmId);
	QVERIFY(a2.entries() == entries);

	QVERIFY(!a1.isNull());
	QVERIFY(!a2.isNull());
	QVERIFY(a1 == a2);

	/* Clear value. */
	a1 = TagAssignment();

	QVERIFY(a1.username().isNull());
	QVERIFY(a1.testing() == false);
	QVERIFY(a1.dmId() == -1);
	QVERIFY(a1.entries().isEmpty());
	QVERIFY(a2.username() == username);
	QVERIFY(a2.testing() == testing);
	QVERIFY(a2.dmId() == dmId);
	QVERIFY(a2.entries() == entries);

	QVERIFY(a1.isNull());
	QVERIFY(!a2.isNull());
	QVERIFY(a1 != a2);
}

void TestTagDb::tagAssignmentCompare(void)
{
	TagAssignment a1, a2;
	QString username("username");
	bool testing = true;
	qint64 dmId = 1;
	QList<TagEntry> entries =
	    QList<TagEntry>() << TagEntry(1, "name", "000000");

	a1.setUsername(username);
	a1.setTesting(testing);
	a1.setDmId(dmId);
	a1.setEntries(entries);
	a2.setUsername(username);
	a2.setTesting(testing);
	a2.setDmId(dmId);
	a2.setEntries(entries);

	QVERIFY(a1 == a2);

	a1.setUsername("");
	QVERIFY(a1 != a2);
	a1.setUsername(username);
	QVERIFY(a1 == a2);

	a1.setTesting(false);
	QVERIFY(a1 != a2);
	a1.setTesting(testing);
	QVERIFY(a1 == a2);

	a1.setDmId(0);
	QVERIFY(a1 != a2);
	a1.setDmId(dmId);
	QVERIFY(a1 == a2);

	a1.setEntries(QList<TagEntry>());
	QVERIFY(a1 != a2);
	a1.setEntries(entries);
	QVERIFY(a1 == a2);
}

void TestTagDb::tagAssignmentConstructor(void)
{
	const QString cUsername("username");
	const QList<TagEntry> cEntries =
	    QList<TagEntry>() << TagEntry(1, "name", "000000");

	{
		TagAssignment a;

		QVERIFY(a.username().isNull());
		QVERIFY(a.testing() == false);
		QVERIFY(a.dmId() == -1);
		QVERIFY(a.entries().isEmpty());
	}

	{
		QString username(cUsername);
		bool testing = true;
		qint64 dmId = 1;
		QList<TagEntry> entries(cEntries);
		TagAssignment a(username, testing, dmId, entries);

		QVERIFY(a.username() == username);
		QVERIFY(a.testing() == testing);
		QVERIFY(a.dmId() == dmId);
		QVERIFY(a.entries() == entries);

		QVERIFY(username == cUsername);
		QVERIFY(entries == cEntries);
	}

#ifdef Q_COMPILER_RVALUE_REFS
	{
		QString username(cUsername);
		bool testing = true;
		qint64 dmId = 1;
		QList<TagEntry> entries(cEntries);
		TagAssignment a(::std::move(username), testing, dmId, ::std::move(entries));

		QVERIFY(a.username() == cUsername);
		QVERIFY(a.testing() == testing);
		QVERIFY(a.dmId() == dmId);
		QVERIFY(a.entries() == cEntries);

		QVERIFY(username.isNull());
		QVERIFY(entries.isEmpty());
	}
#endif /* Q_COMPILER_RVALUE_REFS */
}

void TestTagDb::tagAssignmentCopy(void)
{
	TagAssignment a1;
	QString username("username");
	bool testing = true;
	qint64 dmId = 1;
	QList<TagEntry> entries =
	    QList<TagEntry>() << TagEntry(1, "name", "000000");

	a1.setUsername(username);
	a1.setTesting(testing);
	a1.setDmId(dmId);
	a1.setEntries(entries);

	/* Constructor. */
	{
		TagAssignment a2(a1);

		QVERIFY(!a1.isNull());
		QVERIFY(!a2.isNull());
		QVERIFY(a1 == a2);

#ifdef Q_COMPILER_RVALUE_REFS
		/* Move. */
		TagAssignment a3(::std::move(a2));

		QVERIFY(a2.isNull());
		QVERIFY(a1 != a2);

		QVERIFY(!a1.isNull());
		QVERIFY(!a3.isNull());
		QVERIFY(a1 == a3);
#endif /* Q_COMPILER_RVALUE_REFS */
	}

	/* Assignment operator. */
	{
		TagAssignment a2;

		QVERIFY(a2.isNull());

		a2 = a1;

		QVERIFY(!a1.isNull());
		QVERIFY(!a2.isNull());
		QVERIFY(a1 == a2);

#ifdef Q_COMPILER_RVALUE_REFS
		/* Move. */
		TagAssignment a3;

		QVERIFY(a3.isNull());

		a3 = ::std::move(a2);

		QVERIFY(a2.isNull());
		QVERIFY(a1 != a2);

		QVERIFY(!a1.isNull());
		QVERIFY(!a3.isNull());
		QVERIFY(a1 == a3);
#endif /* Q_COMPILER_RVALUE_REFS */
	}
}

void TestTagDb::tagAssignmentSetvalues(void)
{
	const QString cUsername("username");
	const QList<TagEntry> cEntries =
	    QList<TagEntry>() << TagEntry(1, "name", "000000");

	TagAssignment a;
	QString username(cUsername);
	//bool testing = true;
	//qint64 dmId = 1;
	QList<TagEntry> entries(cEntries);

	QVERIFY(a.username().isNull());
	a.setUsername(username);
	QVERIFY(a.username() == cUsername);
	QVERIFY(username == cUsername);
#ifdef Q_COMPILER_RVALUE_REFS
	a.setUsername("other_username");
	QVERIFY(a.username() != cUsername);
	a.setUsername(::std::move(username));
	QVERIFY(a.username() == cUsername);
	QVERIFY(username != cUsername);
#endif /* Q_COMPILER_RVALUE_REFS */

	QVERIFY(a.entries().isEmpty());
	a.setEntries(entries);
	QVERIFY(a.entries() == cEntries);
	QVERIFY(entries == cEntries);
#ifdef Q_COMPILER_RVALUE_REFS
	a.setEntries(QList<TagEntry>() << TagEntry(2, "name", "000000"));
	QVERIFY(a.entries() != cEntries);
	a.setEntries(::std::move(entries));
	QVERIFY(a.entries() == cEntries);
	QVERIFY(entries != cEntries);
#endif /* Q_COMPILER_RVALUE_REFS */
}

void TestTagDb::testTagDbInsert(void)
{
	TagEntry entry;
	QList<TagEntry> entries;
	int tagId = -1;

	_init();

	GlobInstcs::tagDbPtr = new (::std::nothrow) TagDb(m_connectionPrefix, false);
	QVERIFY(GlobInstcs::tagDbPtr != Q_NULLPTR);
	QVERIFY(GlobInstcs::tagDbPtr->openDb(m_dbPath, SQLiteDb::CREATE_MISSING));
	QVERIFY(QFileInfo::exists(m_dbPath));

	QSignalSpy spyInserted(GlobInstcs::tagDbPtr, SIGNAL(tagInserted(QList<TagEntry>)));
	QSignalSpy spyUpdated(GlobInstcs::tagDbPtr, SIGNAL(tagUpdated(QList<TagEntry>)));
	QSignalSpy spyDeleted(GlobInstcs::tagDbPtr, SIGNAL(tagDeleted(QList<int>)));
	QSignalSpy spyAssignmentChanged(GlobInstcs::tagDbPtr, SIGNAL(tagAssignmentChanged(QList<TagAssignment>)));

	entry = GlobInstcs::tagDbPtr->getTagData(-1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	QVERIFY(!entry.isValid());

	entry = GlobInstcs::tagDbPtr->getTagData(0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	QVERIFY(!entry.isValid());

	entry = GlobInstcs::tagDbPtr->getTagData(1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	QVERIFY(!entry.isValid());

	/* Null name should fail. */
	QVERIFY(!GlobInstcs::tagDbPtr->insertTag(QString(), "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Empty name should fail. */
	QVERIFY(!GlobInstcs::tagDbPtr->insertTag("", "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Null colour should fail. */
	QVERIFY(!GlobInstcs::tagDbPtr->insertTag("tag001", QString()));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Empty colour should fail. */
	QVERIFY(!GlobInstcs::tagDbPtr->insertTag("tag001", ""));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Inserting valid tag. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag001", "000000"));
		QCOMPARE(spyInserted.count(), 1);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyInserted.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagEntry> >());
		const QList<TagEntry> entries =
		    qvariant_cast< QList<TagEntry> >(arguments.at(0));
		QCOMPARE(entries.size(), 1);
		const TagEntry &entry = entries.at(0);
		QVERIFY(entry.id() >= 0);
		QCOMPARE(entry.name(), "tag001");
		QCOMPARE(entry.colour(), "000000");

		tagId = entry.id();
	}

	/* Re-inserting should fail. */
	QVERIFY(!GlobInstcs::tagDbPtr->insertTag("tag001", "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Read tag data. */
	entry = GlobInstcs::tagDbPtr->getTagData(tagId);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	QVERIFY(entry.isValid());
	QCOMPARE(entry.id(), tagId);
	QCOMPARE(entry.name(), "tag001");
	QCOMPARE(entry.colour(), "000000");

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	entry = entries.at(0);
	QVERIFY(entry.isValid());
	QCOMPARE(entry.id(), tagId);
	QCOMPARE(entry.name(), "tag001");
	QCOMPARE(entry.colour(), "000000");

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(-1), 0);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId), 0);

	_cleanup();
}

void TestTagDb::testTagDbUpdate(void)
{
	TagEntry entry;
	QList<TagEntry> entries;
	int tagId1 = -1;
	int tagId2 = -1;

	_init();

	GlobInstcs::tagDbPtr = new (::std::nothrow) TagDb(m_connectionPrefix, false);
	QVERIFY(GlobInstcs::tagDbPtr != Q_NULLPTR);
	QVERIFY(GlobInstcs::tagDbPtr->openDb(m_dbPath, SQLiteDb::CREATE_MISSING));
	QVERIFY(QFileInfo::exists(m_dbPath));

	QSignalSpy spyInserted(GlobInstcs::tagDbPtr, SIGNAL(tagInserted(QList<TagEntry>)));
	QSignalSpy spyUpdated(GlobInstcs::tagDbPtr, SIGNAL(tagUpdated(QList<TagEntry>)));
	QSignalSpy spyDeleted(GlobInstcs::tagDbPtr, SIGNAL(tagDeleted(QList<int>)));
	QSignalSpy spyAssignmentChanged(GlobInstcs::tagDbPtr, SIGNAL(tagAssignmentChanged(QList<TagAssignment>)));

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag001", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId1 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag002", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId2 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	/* Updating non-existent tag. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(-1, "tag001", "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to null name. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(tagId1, QString(), "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to empty name. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(tagId1, "", "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to null colour. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(tagId1, "tag001", QString()));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to empty colour. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(tagId1, "tag001", ""));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to same values. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(tagId1, "tag001", "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to other existent name. */
	QVERIFY(!GlobInstcs::tagDbPtr->updateTag(tagId1, "tag002", "000000"));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Updating to non-existent name. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->updateTag(tagId1, "tag003", "000000"));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 1);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyUpdated.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagEntry> >());
		const QList<TagEntry> entries =
		    qvariant_cast< QList<TagEntry> >(arguments.at(0));
		QCOMPARE(entries.size(), 1);
		const TagEntry &entry = entries.at(0);
		QVERIFY(entry.id() == tagId1);
		QCOMPARE(entry.name(), "tag003");
		QCOMPARE(entry.colour(), "000000");
	}

	/* Updating to non-existent name and changing colour. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->updateTag(tagId1, "tag001", "000001"));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 1);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyUpdated.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagEntry> >());
		const QList<TagEntry> entries =
		    qvariant_cast< QList<TagEntry> >(arguments.at(0));
		QCOMPARE(entries.size(), 1);
		const TagEntry &entry = entries.at(0);
		QVERIFY(entry.id() == tagId1);
		QCOMPARE(entry.name(), "tag001");
		QCOMPARE(entry.colour(), "000001");
	}

	/* Changing colour. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->updateTag(tagId1, "tag001", "000000"));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 1);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyUpdated.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagEntry> >());
		const QList<TagEntry> entries =
		    qvariant_cast< QList<TagEntry> >(arguments.at(0));
		QCOMPARE(entries.size(), 1);
		const TagEntry &entry = entries.at(0);
		QVERIFY(entry.id() == tagId1);
		QCOMPARE(entry.name(), "tag001");
		QCOMPARE(entry.colour(), "000000");
	}

	/* Read tag data. */
	entry = GlobInstcs::tagDbPtr->getTagData(tagId1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	QVERIFY(entry.isValid());
	QCOMPARE(entry.id(), tagId1);
	QCOMPARE(entry.name(), "tag001");
	QCOMPARE(entry.colour(), "000000");

	entry = GlobInstcs::tagDbPtr->getTagData(tagId2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	QVERIFY(entry.isValid());
	QCOMPARE(entry.id(), tagId2);
	QCOMPARE(entry.name(), "tag002");
	QCOMPARE(entry.colour(), "000000");

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	_cleanup();
}

void TestTagDb::testTagDbDelete(void)
{
	TagEntry entry;
	QList<TagEntry> entries;
	int tagId1 = -1;
	int tagId2 = -1;
	int tagId3 = -1;

	_init();

	GlobInstcs::tagDbPtr = new (::std::nothrow) TagDb(m_connectionPrefix, false);
	QVERIFY(GlobInstcs::tagDbPtr != Q_NULLPTR);
	QVERIFY(GlobInstcs::tagDbPtr->openDb(m_dbPath, SQLiteDb::CREATE_MISSING));
	QVERIFY(QFileInfo::exists(m_dbPath));

	QSignalSpy spyInserted(GlobInstcs::tagDbPtr, SIGNAL(tagInserted(QList<TagEntry>)));
	QSignalSpy spyUpdated(GlobInstcs::tagDbPtr, SIGNAL(tagUpdated(QList<TagEntry>)));
	QSignalSpy spyDeleted(GlobInstcs::tagDbPtr, SIGNAL(tagDeleted(QList<int>)));
	QSignalSpy spyAssignmentChanged(GlobInstcs::tagDbPtr, SIGNAL(tagAssignmentChanged(QList<TagAssignment>)));

	/* Deleting empty database. */
	QVERIFY(GlobInstcs::tagDbPtr->deleteAllTags());
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Populate. */
	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag001", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId1 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag002", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId2 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag003", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId3 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 3);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Deleting non-existent tags. */
	QVERIFY(!GlobInstcs::tagDbPtr->deleteTags(QList<int>()));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	QVERIFY(!GlobInstcs::tagDbPtr->deleteTags(QList<int>() << 100 << 101));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Deleting non-existent and existing tags. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->deleteTags(QList<int>() << tagId3 << 101));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 1);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyDeleted.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<int> >());
		const QList<int> ids =
		    qvariant_cast< QList<int> >(arguments.at(0));
		QCOMPARE(ids.size(), 1);
		QCOMPARE(ids.at(0), tagId3);
	}

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Repopulate. */
	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag003", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId3 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 3);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Deleting existing tags. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->deleteTags(QList<int>() << tagId2 << tagId3));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 1);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyDeleted.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<int> >());
		const QList<int> ids =
		    qvariant_cast< QList<int> >(arguments.at(0));
		QCOMPARE(ids.size(), 2);
		QSet<int> deletedSet = QSet<int>() << ids.at(0) << ids.at(1);
		QCOMPARE(deletedSet.size(), 2);
		QVERIFY(deletedSet.contains(tagId2));
		QVERIFY(deletedSet.contains(tagId3));
	}

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Repopulate. */
	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag002", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId2 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag003", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId3 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 3);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Deleting all existing tags by listing. */
	{
		/* Intentionally repeating one identifier. */
		QVERIFY(GlobInstcs::tagDbPtr->deleteTags(QList<int>() << tagId1 << tagId1 <<tagId2 << tagId3));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 1);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyDeleted.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<int> >());
		const QList<int> ids =
		    qvariant_cast< QList<int> >(arguments.at(0));
		QCOMPARE(ids.size(), 3);
		QSet<int> deletedSet = QSet<int>() << ids.at(0) << ids.at(1) << ids.at(2);
		QCOMPARE(deletedSet.size(), 3);
		QVERIFY(deletedSet.contains(tagId1));
		QVERIFY(deletedSet.contains(tagId2));
		QVERIFY(deletedSet.contains(tagId3));
	}

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Repopulate. */
	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag001", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId1 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag002", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId2 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag003", "000000"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId3 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 3);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Deleting all existing tags by listing. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->deleteAllTags());
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 1);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QList<QVariant> arguments = spyDeleted.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<int> >());
		const QList<int> ids =
		    qvariant_cast< QList<int> >(arguments.at(0));
		QCOMPARE(ids.size(), 3);
		QSet<int> deletedSet = QSet<int>() << ids.at(0) << ids.at(1) << ids.at(2);
		QCOMPARE(deletedSet.size(), 3);
		QVERIFY(deletedSet.contains(tagId1));
		QVERIFY(deletedSet.contains(tagId2));
		QVERIFY(deletedSet.contains(tagId3));
	}

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	_cleanup();
}

void TestTagDb::testTagDbAssignmentChange(void)
{
	TagEntry entry;
	QList<TagEntry> entries;
	int tagId1 = -1;
	int tagId2 = -1;
	int tagId3 = -1;

	_init();

	GlobInstcs::tagDbPtr = new (::std::nothrow) TagDb(m_connectionPrefix, false);
	QVERIFY(GlobInstcs::tagDbPtr != Q_NULLPTR);
	QVERIFY(GlobInstcs::tagDbPtr->openDb(m_dbPath, SQLiteDb::CREATE_MISSING));
	QVERIFY(QFileInfo::exists(m_dbPath));

	QSignalSpy spyInserted(GlobInstcs::tagDbPtr, SIGNAL(tagInserted(QList<TagEntry>)));
	QSignalSpy spyUpdated(GlobInstcs::tagDbPtr, SIGNAL(tagUpdated(QList<TagEntry>)));
	QSignalSpy spyDeleted(GlobInstcs::tagDbPtr, SIGNAL(tagDeleted(QList<int>)));
	QSignalSpy spyAssignmentChanged(GlobInstcs::tagDbPtr, SIGNAL(tagAssignmentChanged(QList<TagAssignment>)));

	/* Deleting empty database. */
	QVERIFY(GlobInstcs::tagDbPtr->deleteAllTags());
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Populate. */
	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag001", "000001"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId1 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag002", "000002"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId2 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	QVERIFY(GlobInstcs::tagDbPtr->insertTag("tag003", "000003"));
	QCOMPARE(spyInserted.count(), 1);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);
	tagId3 = qvariant_cast< QList<TagEntry> >(spyInserted.takeFirst().at(0)).at(0).id();

	entries = GlobInstcs::tagDbPtr->getAllTags();
	QCOMPARE(entries.size(), 3);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Check assignment. */
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(-1), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId1), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId2), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId3), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags(QString(), 1);
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Nothing assigned. */
	QVERIFY(!GlobInstcs::tagDbPtr->removeAllTagsFromMsg("username", true, 1001));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Assign non-existent tags. */
	QVERIFY(!GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1001, QList<int>() << 100 << 101));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Assign existent and non-existent tags. */
	QVERIFY(!GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1001, QList<int>() << tagId1 << 101));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 0);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Assign existent tags. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1001, QList<int>() << tagId1 << tagId2));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 1001);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 2);
		if (entries.at(0).id() == tagId1) {
			QCOMPARE(entries.at(0).id(), tagId1);
			QCOMPARE(entries.at(0).name(), "tag001");
			QCOMPARE(entries.at(0).colour(), "000001");
			QCOMPARE(entries.at(1).id(), tagId2);
			QCOMPARE(entries.at(1).name(), "tag002");
			QCOMPARE(entries.at(1).colour(), "000002");
		} else if (entries.at(0).id() == tagId2) {
			QCOMPARE(entries.at(1).id(), tagId1);
			QCOMPARE(entries.at(1).name(), "tag001");
			QCOMPARE(entries.at(1).colour(), "000001");
			QCOMPARE(entries.at(0).id(), tagId2);
			QCOMPARE(entries.at(0).name(), "tag002");
			QCOMPARE(entries.at(0).colour(), "000002");
		} else {
			QVERIFY(false);
		}
	}

	{
		entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
		QCOMPARE(entries.size(), 2);
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QCOMPARE(entries.size(), 2);
		if (entries.at(0).id() == tagId1) {
			QCOMPARE(entries.at(0).id(), tagId1);
			QCOMPARE(entries.at(0).name(), "tag001");
			QCOMPARE(entries.at(0).colour(), "000001");
			QCOMPARE(entries.at(1).id(), tagId2);
			QCOMPARE(entries.at(1).name(), "tag002");
			QCOMPARE(entries.at(1).colour(), "000002");
		} else if (entries.at(0).id() == tagId2) {
			QCOMPARE(entries.at(1).id(), tagId1);
			QCOMPARE(entries.at(1).name(), "tag001");
			QCOMPARE(entries.at(1).colour(), "000001");
			QCOMPARE(entries.at(0).id(), tagId2);
			QCOMPARE(entries.at(0).name(), "tag002");
			QCOMPARE(entries.at(0).colour(), "000002");
		} else {
			QVERIFY(false);
		}
	}

	/* Assign already assigned tags. */
	QVERIFY(!GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1001, QList<int>() << tagId1 << tagId2));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Assign new existent and a non-existent tag. */
	QVERIFY(!GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1001, QList<int>() << tagId3 << 101));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Remove unassigned tags. */
	QVERIFY(!GlobInstcs::tagDbPtr->removeTagFromMsg("username", true, 1001, QList<int>() << 100 << 101));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Remove unassigned and assigned tags. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->removeTagFromMsg("username", true, 1001, QList<int>() << tagId2 << 101));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 1001);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 1);
		QCOMPARE(entries.at(0).id(), tagId1);
		QCOMPARE(entries.at(0).name(), "tag001");
		QCOMPARE(entries.at(0).colour(), "000001");
	}

	entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
	QCOMPARE(entries.size(), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Assign existent assigned and unassigned tags. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1001, QList<int>() << tagId1 << tagId2));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 1001);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 2);
		if (entries.at(0).id() == tagId1) {
			QCOMPARE(entries.at(0).id(), tagId1);
			QCOMPARE(entries.at(0).name(), "tag001");
			QCOMPARE(entries.at(0).colour(), "000001");
			QCOMPARE(entries.at(1).id(), tagId2);
			QCOMPARE(entries.at(1).name(), "tag002");
			QCOMPARE(entries.at(1).colour(), "000002");
		} else if (entries.at(0).id() == tagId2) {
			QCOMPARE(entries.at(1).id(), tagId1);
			QCOMPARE(entries.at(1).name(), "tag001");
			QCOMPARE(entries.at(1).colour(), "000001");
			QCOMPARE(entries.at(0).id(), tagId2);
			QCOMPARE(entries.at(0).name(), "tag002");
			QCOMPARE(entries.at(0).colour(), "000002");
		} else {
			QVERIFY(false);
		}
	}

	{
		QVERIFY(GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1002, QList<int>() << tagId2));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 1002);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 1);
		QCOMPARE(entries.at(0).id(), tagId2);
		QCOMPARE(entries.at(0).name(), "tag002");
		QCOMPARE(entries.at(0).colour(), "000002");
	}

	{
		QVERIFY(GlobInstcs::tagDbPtr->assignTagToMsg("username", true, 1003, QList<int>() << tagId3));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 1003);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 1);
		QCOMPARE(entries.at(0).id(), tagId3);
		QCOMPARE(entries.at(0).name(), "tag003");
		QCOMPARE(entries.at(0).colour(), "000003");
	}

	{
		entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1001);
		QCOMPARE(entries.size(), 2);
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		if (entries.at(0).id() == tagId1) {
			QCOMPARE(entries.at(0).id(), tagId1);
			QCOMPARE(entries.at(0).name(), "tag001");
			QCOMPARE(entries.at(0).colour(), "000001");
			QCOMPARE(entries.at(1).id(), tagId2);
			QCOMPARE(entries.at(1).name(), "tag002");
			QCOMPARE(entries.at(1).colour(), "000002");
		} else if (entries.at(0).id() == tagId2) {
			QCOMPARE(entries.at(1).id(), tagId1);
			QCOMPARE(entries.at(1).name(), "tag001");
			QCOMPARE(entries.at(1).colour(), "000001");
			QCOMPARE(entries.at(0).id(), tagId2);
			QCOMPARE(entries.at(0).name(), "tag002");
			QCOMPARE(entries.at(0).colour(), "000002");
		} else {
			QVERIFY(false);
		}
	}

	{
		entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1002);
		QCOMPARE(entries.size(), 1);
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QCOMPARE(entries.at(0).id(), tagId2);
		QCOMPARE(entries.at(0).name(), "tag002");
		QCOMPARE(entries.at(0).colour(), "000002");
	}

	{
		entries = GlobInstcs::tagDbPtr->getMessageTags("username", 1003);
		QCOMPARE(entries.size(), 1);
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QCOMPARE(entries.at(0).id(), tagId3);
		QCOMPARE(entries.at(0).name(), "tag003");
		QCOMPARE(entries.at(0).colour(), "000003");
	}

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId1), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId2), 2);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId3), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Remove all tags from a single message. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->removeAllTagsFromMsg("username", true, 1002));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 1002);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 0);
	}

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId1), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId2), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId3), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Remove all remaining tags from messages of a different account. */
	QVERIFY(!GlobInstcs::tagDbPtr->removeAllMsgTagsFromAccount("another_username", true));
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId1), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId2), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId3), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	{
		QVERIFY(GlobInstcs::tagDbPtr->assignTagToMsg("another_username", true, 2003, QList<int>() << tagId3));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 1);

		const TagAssignment &assignment = assignments.at(0);
		QCOMPARE(assignment.username(), "another_username");
		QCOMPARE(assignment.testing(), true);
		QCOMPARE(assignment.dmId(), 2003);
		const QList<TagEntry> &entries = assignment.entries();
		QCOMPARE(entries.size(), 1);
		QCOMPARE(entries.at(0).id(), tagId3);
		QCOMPARE(entries.at(0).name(), "tag003");
		QCOMPARE(entries.at(0).colour(), "000003");
	}

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId1), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId2), 1);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId3), 2);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	/* Remove all remaining tags from the messages. */
	{
		QVERIFY(GlobInstcs::tagDbPtr->removeAllMsgTagsFromAccount("username", true));
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 1);

		QList<QVariant> arguments = spyAssignmentChanged.takeFirst();
		QCOMPARE(arguments.size(), 1);
		QVERIFY(arguments.at(0).canConvert< QList<TagAssignment> >());
		const QList<TagAssignment> assignments =
		    qvariant_cast< QList<TagAssignment> >(arguments.at(0));
		QCOMPARE(assignments.size(), 2);

		foreach (const TagAssignment &assignment, assignments) {
			switch (assignment.dmId()) {
			case 1001:
				QCOMPARE(assignment.username(), "username");
				QCOMPARE(assignment.testing(), true);
				QCOMPARE(assignment.dmId(), 1001);
				QCOMPARE(assignment.entries().size(), 0);
				break;
			case 1003:
				QCOMPARE(assignment.username(), "username");
				QCOMPARE(assignment.testing(), true);
				QCOMPARE(assignment.dmId(), 1003);
				QCOMPARE(assignment.entries().size(), 0);
				break;
			default:
				QVERIFY(false);
				break;
			}
		}
	}

	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId1), 0);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId2), 0);
	QCOMPARE(GlobInstcs::tagDbPtr->getTagAssignmentCount(tagId3), 1);
	QCOMPARE(spyInserted.count(), 0);
	QCOMPARE(spyUpdated.count(), 0);
	QCOMPARE(spyDeleted.count(), 0);
	QCOMPARE(spyAssignmentChanged.count(), 0);

	{
		entries = GlobInstcs::tagDbPtr->getMessageTags("another_username", 2003);
		QCOMPARE(entries.size(), 1);
		QCOMPARE(spyInserted.count(), 0);
		QCOMPARE(spyUpdated.count(), 0);
		QCOMPARE(spyDeleted.count(), 0);
		QCOMPARE(spyAssignmentChanged.count(), 0);

		QCOMPARE(entries.at(0).id(), tagId3);
		QCOMPARE(entries.at(0).name(), "tag003");
		QCOMPARE(entries.at(0).colour(), "000003");
	}

	_cleanup();
}

void TestTagDb::_init(void)
{
	QVERIFY(GlobInstcs::tagDbPtr == Q_NULLPTR);

	QFile(m_dbPath).remove();

	QVERIFY(!QFileInfo::exists(m_dbPath));
}

void TestTagDb::_cleanup(void)
{
	delete GlobInstcs::tagDbPtr; GlobInstcs::tagDbPtr = Q_NULLPTR;
}

QObject *newTestTagDb(void)
{
	return new (::std::nothrow) TestTagDb();
}

//QTEST_MAIN(TestTagDb)
#include "test_tag_db.moc"
