commit e7cfc35a78ed46e4112ad150ce71ae532dad22fb
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Tue Oct 27 00:34:24 2015 +0100

    extended test stuff

diff --git a/tests/em/em.pro b/tests/em/em.pro
new file mode 100644
index 0000000..0d4ef0b
--- /dev/null
+++ b/tests/em/em.pro
@@ -0,0 +1,24 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-10-11T20:35:07
+#
+#-------------------------------------------------
+include(../tests.pri)
+
+QT       += sql testlib
+
+QT       -= gui
+
+TARGET = tst_em
+CONFIG   += console
+CONFIG   -= app_bundle
+
+TEMPLATE = app
+
+
+SOURCES += tst_em.cpp \
+    ../models.cpp
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+HEADERS += \
+    ../models.h
diff --git a/tests/em/tst_em.cpp b/tests/em/tst_em.cpp
new file mode 100644
index 0000000..baeb703
--- /dev/null
+++ b/tests/em/tst_em.cpp
@@ -0,0 +1,183 @@
+#include <QString>
+#include <QtTest>
+#include "entitymanager.h"
+#include "databasemigration.h"
+#include "../models.h"
+class Em : public QObject {
+    Q_OBJECT
+
+  public:
+    Em();
+
+  private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void testCheckDuplicates();
+    void testBasics();
+    void init();
+    void cleanup();
+    void testFindById();
+    void testFindId();
+    void testHasChanged();
+    void testValidate();
+    void testRelations();
+
+  private:
+    CuteEntityManager::EntityManager *e;
+};
+
+Em::Em() {
+}
+
+void Em::initTestCase() {
+    CuteEntityManager::EntityInstanceFactory::registerClass<Group>();
+    CuteEntityManager::EntityInstanceFactory::registerClass<Person>();
+    CuteEntityManager::EntityInstanceFactory::registerClass<Article>();
+    this->e = new CuteEntityManager::EntityManager("QSQLITE",
+            ":memory:", "", "", "", "", true, "foreign_keys = ON");
+}
+
+void Em::cleanupTestCase() {
+    if (this->e) {
+        delete this->e;
+        this->e = nullptr;
+    }
+}
+
+void Em::testCheckDuplicates() {
+    QSharedPointer<Article> article = QSharedPointer<Article>(new Article(10,
+                                      QString("TestItem")));
+    QSharedPointer<Entity> entity = article.objectCast<Entity>();
+    QVERIFY(this->e->create(entity));
+    QSharedPointer<Entity> copy = QSharedPointer<Entity>(article->copy());
+    QVERIFY(!this->e->create(copy, true, true));
+}
+
+void Em::testBasics() {
+    QSharedPointer<Article> article = QSharedPointer<Article>(new Article(10,
+                                      QString("TestItem")));
+    QSharedPointer<Entity> entity = article.objectCast<Entity>();
+    QVERIFY(this->e->create(entity));
+    article->setPrice(20);
+    article->setName("NewTestItem");
+    QVERIFY(this->e->save(entity));
+    QHash<QString, QVariant> attrs = QHash<QString, QVariant>();
+    attrs.insert("price", 20);
+    attrs.insert("name", "NewTestItem");
+    QSharedPointer<Article> article2 = this->e->findEntityByAttributes<Article>
+                                       (attrs);
+    QVERIFY(article2);
+    entity = article2.objectCast<Entity>();
+    QVERIFY(this->e->remove(entity));
+    QCOMPARE(this->e->count("article"), (quint8)0);
+}
+
+void Em::init() {
+    QStringList inits = QStringList() << "Person" << "Group" << "Article";
+    QVERIFY2(this->e->startup("test0.1", inits), "Failure");
+    auto tableNames = this->e->getSchema()->getTableNames();
+    QVERIFY(tableNames.contains("article"));
+    QVERIFY(tableNames.contains("person"));
+    QVERIFY(tableNames.contains("group"));
+    QVERIFY(tableNames.contains("group_persons"));
+    QVERIFY(tableNames.contains("cuteentitymanager::databasemigration"));
+    auto migrations = this->e->findAll<CuteEntityManager::DatabaseMigration>();
+    QCOMPARE(migrations.size(), 1);
+    QCOMPARE(migrations.at(0)->getVersion(), QString("test0.1"));
+}
+
+void Em::cleanup() {
+    auto qb = this->e->getQueryBuilder();
+    QVERIFY(this->e->executeQuery(qb->dropTable("group_persons")));
+    QVERIFY(this->e->executeQuery(qb->dropTable("group")));
+    QVERIFY(this->e->executeQuery(qb->dropTable("person")));
+    QVERIFY(this->e->executeQuery(qb->dropTable("article")));
+    auto tableNames = this->e->getSchema()->getTableNames();
+    QVERIFY(!tableNames.contains("person"));
+    QVERIFY(!tableNames.contains("group"));
+    QVERIFY(!tableNames.contains("article"));
+    QVERIFY(!tableNames.contains("group_persons"));
+    QVERIFY(this->e->removeAll("cuteentitymanager::databasemigration"));
+}
+
+void Em::testFindById() {
+    QSharedPointer<Person> p = QSharedPointer<Person>(new Person("Max", "Mustermann",
+                               Person::Gender::MALE, "max.jpeg", "", "Maxi", QDate(2000, 1, 1)));
+    auto ent = p.objectCast<Entity>();
+    QVERIFY(this->e->create(ent));
+    auto id = p->getId();
+    QVERIFY(id > -1);
+    QVERIFY(this->e->findById(id, p->getClassname()));
+}
+
+void Em::testFindId() {
+    QSharedPointer<Person> p = QSharedPointer<Person>(new Person("Max", "Mustermann",
+                               Person::Gender::MALE, "max.jpeg", "", "Maxi", QDate(2000, 1, 1)));
+    auto ent = p.objectCast<Entity>();
+    QVERIFY(this->e->create(ent));
+    auto entity = QSharedPointer<Entity>(p->copy());
+    auto foundId = this->e->findId(entity);
+    QVERIFY(foundId  > -1 && foundId == ent->getId());
+}
+
+void Em::testHasChanged() {
+    QSharedPointer<Person> p = QSharedPointer<Person>(new Person("Max", "Mustermann",
+                               Person::Gender::MALE, "max.jpeg", "", "Maxi", QDate(2000, 1, 1)));
+    auto ent = p.objectCast<Entity>();
+    QVERIFY(this->e->create(ent));
+    p->setFirstName("Charlotte");
+    p->setFamilyName("Musterfrau");
+    p->setBirthday(QDate(200, 1, 2));
+    QVERIFY(this->e->hasChanged(ent));
+}
+
+void Em::testValidate() {
+    QSharedPointer<Person> p = QSharedPointer<Person>(new Person("Max", "Mustermann",
+                               Person::Gender::MALE, "max.jpeg", "", "Maxi", QDate(2000, 1, 1)));
+    auto ent = p.objectCast<Entity>();
+    QVERIFY(this->e->validate(ent));
+    p->setFirstName("M");
+    QVERIFY(!this->e->validate(ent) && ent->getErrors().size() == 1);
+    p->setBirthday(QDate(2030, 10, 10));
+    QVERIFY(!this->e->validate(ent) && ent->getErrors().size() == 2);
+}
+
+void Em::testRelations() {
+    QSharedPointer<Person> p1 = QSharedPointer<Person>(new Person("Max", "Mustermann",
+                                Person::Gender::MALE, "max.jpeg", "", "Maxi", QDate(2000, 1, 1)));
+    QSharedPointer<Person> p2 = QSharedPointer<Person>(new Person("Marie", "Musterfrau",
+                                Person::Gender::FEMALE, "max.jpeg", "", "", QDate(2000, 1, 1)));
+    QSharedPointer<Person> p3 = QSharedPointer<Person>(new Person("Fenja", "Musterfrau",
+                                Person::Gender::FEMALE, "max.jpeg", "", "Fenni", QDate(2000, 1, 1)));
+    QSharedPointer<Group> g = QSharedPointer<Group>(new Group());
+    g->setName("TestGroup");
+    g->setLeader(p1);
+    g->setPersons({p1});
+    auto gEnt = g.objectCast<Entity>();
+    auto pEnt = p3.objectCast<Entity>();
+    QVERIFY(this->e->save(gEnt));
+    QVERIFY(p1->getId() > -1);
+    QVERIFY(p1->getMaintainedGroups().size() > 0);
+    QVERIFY(p1->getGroups().size() > 0);
+    g->addPerson(p2);
+    g->setName("TestGroupExtended");
+    QVERIFY(this->e->save(gEnt));
+    p3->setGroups({g});
+    QVERIFY(this->e->save(pEnt, true, true));
+    QVERIFY(g->getPersons().size() == 3);
+    QList<QSharedPointer<Group>> groups;
+    p3->setGroups(groups);
+    QVERIFY(this->e->save(pEnt, true, true));
+    this->e->refresh(gEnt);
+    QVERIFY(g->getPersons().size() == 2);
+    auto firstPerson = g->getPersons().first();
+    g->removePerson(firstPerson);
+    QVERIFY(this->e->save(gEnt, true, true));
+    auto entityFp = firstPerson.objectCast<Entity>();
+    this->e->refresh(entityFp);
+    QVERIFY(firstPerson->getGroups().size() == 0 && g->getPersons().size() == 1);
+}
+
+QTEST_APPLESS_MAIN(Em)
+
+#include "tst_em.moc"
diff --git a/tests/models.cpp b/tests/models.cpp
index 65adc03..9b76719 100644
--- a/tests/models.cpp
+++ b/tests/models.cpp
@@ -101,19 +101,19 @@ void Person::setCustomPictureFileName(const QString &value) {
     customPictureFileName = value;
 }
 
-QList<QSharedPointer<Group> > Person::getGroups() const {
+QList<QSharedPointer<Group>> Person::getGroups() const {
     return groups;
 }
 
-void Person::setGroups(const QList<QSharedPointer<Group> > &value) {
+void Person::setGroups(const QList<QSharedPointer<Group>> &value) {
     groups = value;
 }
 
-QList<QSharedPointer<Group> > Person::getMaintainedGroups() const {
+QList<QSharedPointer<Group>> Person::getMaintainedGroups() const {
     return maintainedGroups;
 }
 
-void Person::setMaintainedGroups(const QList<QSharedPointer<Group> > &value) {
+void Person::setMaintainedGroups(const QList<QSharedPointer<Group>> &value) {
     maintainedGroups = value;
 }
 
@@ -145,37 +145,40 @@ void Group::setLeader(const QSharedPointer<Person> &value) {
     leader = value;
 }
 
-QList<QSharedPointer<Person> > Group::getPersons() const {
+QList<QSharedPointer<Person>> Group::getPersons() const {
     return persons;
 }
 
-void Group::setPersons(const QList<QSharedPointer<Person> > &value) {
+void Group::addPerson(const QSharedPointer<Person> &value) {
+    this->persons.append(value);
+}
+
+void Group::setPersons(const QList<QSharedPointer<Person>> &value) {
     persons = value;
 }
 
+void Group::removePerson(const QSharedPointer<Person> &value) {
+    this->persons.removeOne(value);
+}
+
 
-double Article::getPrice() const
-{
+double Article::getPrice() const {
     return price;
 }
 
-void Article::setPrice(double value)
-{
+void Article::setPrice(double value) {
     price = value;
 }
 
-QString Article::getName() const
-{
+QString Article::getName() const {
     return name;
 }
 
-void Article::setName(const QString &value)
-{
+void Article::setName(const QString &value) {
     name = value;
 }
 
 Article::~Article() {
-
 }
 
 Article::Article() {
@@ -186,3 +189,12 @@ Article::Article(double price, QString name) {
     this->price = price;
     this->name = name;
 }
+
+QList<CuteEntityManager::ValidationRule> Person::validationRules() const {
+    QList<CuteEntityManager::ValidationRule> rules =
+        QList<CuteEntityManager::ValidationRule>();
+    rules.append(ValidationRule("length", {"firstName", "familyName"}, "min", 2));
+    QList<Param> params = {Param("past"), Param("min", QDate(1970, 1, 1))};
+    rules.append(ValidationRule("date", "birthday", params));
+    return rules;
+}
diff --git a/tests/models.h b/tests/models.h
index e0bec0a..7efe92f 100644
--- a/tests/models.h
+++ b/tests/models.h
@@ -11,6 +11,7 @@
 using namespace CuteEntityManager;
 class Group;
 class Person: public Entity {
+
     Q_OBJECT
     Q_PROPERTY(QString firstName READ getFirstName WRITE setFirstName)
     Q_PROPERTY(QString familyName READ getFamilyName WRITE setFamilyName)
@@ -26,6 +27,7 @@ class Person: public Entity {
 
   public:
     enum class Gender {MALE, FEMALE, UNKNOWNGENDER};
+    Q_ENUM(Gender)
     enum class NameOrder {FIRST_FAMILY_NAME_ORDER, FAMILY_FIRST_NAME_ORDER};
     Q_INVOKABLE explicit Person(QObject *parent = 0);
     Person(QString firstName, QString familyName,
@@ -61,11 +63,12 @@ class Person: public Entity {
     QString getCustomPictureFileName() const;
     void setCustomPictureFileName(const QString &value);
 
-    QList<QSharedPointer<Group> > getGroups() const;
-    void setGroups(const QList<QSharedPointer<Group> > &value);
+    QList<QSharedPointer<Group>> getGroups() const;
+    void setGroups(const QList<QSharedPointer<Group>> &value);
 
-    QList<QSharedPointer<Group> > getMaintainedGroups() const;
-    void setMaintainedGroups(const QList<QSharedPointer<Group> > &value);
+    QList<QSharedPointer<Group>> getMaintainedGroups() const;
+    void setMaintainedGroups(const QList<QSharedPointer<Group>> &value);
+    virtual QList<ValidationRule> validationRules() const override;
 
   protected:
     QString firstName;
@@ -98,8 +101,10 @@ class Group: public CuteEntityManager::Entity {
     QSharedPointer<Person> getLeader() const;
     void setLeader(const QSharedPointer<Person> &value);
 
-    QList<QSharedPointer<Person> > getPersons() const;
-    void setPersons(const QList<QSharedPointer<Person> > &value);
+    QList<QSharedPointer<Person>> getPersons() const;
+    void addPerson(const QSharedPointer<Person> &value);
+    void setPersons(const QList<QSharedPointer<Person>> &value);
+    void removePerson(const QSharedPointer<Person> &value);
 
   protected:
     QList<QSharedPointer<Person>> persons;
diff --git a/tests/querybuilder/querybuilder.pro b/tests/querybuilder/querybuilder.pro
new file mode 100644
index 0000000..997396f
--- /dev/null
+++ b/tests/querybuilder/querybuilder.pro
@@ -0,0 +1,19 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-10-26T13:13:18
+#
+#-------------------------------------------------
+
+QT       += sql testlib
+
+QT       -= gui
+
+TARGET = tst_querybuildertest
+CONFIG   += console
+CONFIG   -= app_bundle
+
+TEMPLATE = app
+
+
+SOURCES += tst_querybuildertest.cpp
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
diff --git a/tests/querybuilder/tst_querybuildertest.cpp b/tests/querybuilder/tst_querybuildertest.cpp
new file mode 100644
index 0000000..cbe1c5d
--- /dev/null
+++ b/tests/querybuilder/tst_querybuildertest.cpp
@@ -0,0 +1,44 @@
+#include <QString>
+#include <QtTest>
+
+class QuerybuilderTest : public QObject
+{
+    Q_OBJECT
+
+public:
+    QuerybuilderTest();
+
+private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void testCase1_data();
+    void testCase1();
+};
+
+QuerybuilderTest::QuerybuilderTest()
+{
+}
+
+void QuerybuilderTest::initTestCase()
+{
+}
+
+void QuerybuilderTest::cleanupTestCase()
+{
+}
+
+void QuerybuilderTest::testCase1_data()
+{
+    QTest::addColumn<QString>("data");
+    QTest::newRow("0") << QString();
+}
+
+void QuerybuilderTest::testCase1()
+{
+    QFETCH(QString, data);
+    QVERIFY2(true, "Failure");
+}
+
+QTEST_APPLESS_MAIN(QuerybuilderTest)
+
+#include "tst_querybuildertest.moc"
diff --git a/tests/tables/tables.pro b/tests/tables/tables.pro
deleted file mode 100644
index 06f578a..0000000
--- a/tests/tables/tables.pro
+++ /dev/null
@@ -1,24 +0,0 @@
-#-------------------------------------------------
-#
-# Project created by QtCreator 2015-10-11T20:35:07
-#
-#-------------------------------------------------
-include(../tests.pri)
-
-QT       += sql testlib
-
-QT       -= gui
-
-TARGET = tst_tables
-CONFIG   += console
-CONFIG   -= app_bundle
-
-TEMPLATE = app
-
-
-SOURCES += tst_tables.cpp \
-    ../models.cpp
-DEFINES += SRCDIR=\\\"$$PWD/\\\"
-
-HEADERS += \
-    ../models.h
diff --git a/tests/tables/tst_tables.cpp b/tests/tables/tst_tables.cpp
deleted file mode 100644
index 49634bb..0000000
--- a/tests/tables/tst_tables.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <QString>
-#include <QtTest>
-#include "entitymanager.h"
-#include "databasemigration.h"
-#include "../models.h"
-class Tables : public QObject {
-    Q_OBJECT
-
-  public:
-    Tables();
-
-  private Q_SLOTS:
-    void initTestCase();
-    void cleanupTestCase();
-    void testStartup();
-    void testBasics();
-//    void init();
-//    void cleanup();
-  private:
-    CuteEntityManager::EntityManager *e;
-};
-
-Tables::Tables() {
-}
-
-void Tables::initTestCase() {
-    CuteEntityManager::EntityInstanceFactory::registerClass<Group>();
-    CuteEntityManager::EntityInstanceFactory::registerClass<Person>();
-    CuteEntityManager::EntityInstanceFactory::registerClass<Article>();
-    this->e = new CuteEntityManager::EntityManager("QSQLITE",
-            ":memory:", "", "", "", "", true, "foreign_keys = ON");
-}
-
-void Tables::cleanupTestCase() {
-    if (this->e) {
-        delete this->e;
-        this->e = nullptr;
-    }
-}
-
-void Tables::testStartup() {
-    QStringList inits = QStringList() << "Person" << "Group";
-    QVERIFY2(this->e->startup("test0.1", inits), "Failure");
-    auto tableNames = this->e->getSchema()->getTableNames();
-    QVERIFY(tableNames.contains("person"));
-    QVERIFY(tableNames.contains("group"));
-    QVERIFY(tableNames.contains("group_persons"));
-    QVERIFY(tableNames.contains("cuteentitymanager::databasemigration"));
-    auto migrations = this->e->findAll<CuteEntityManager::DatabaseMigration>();
-    QCOMPARE(migrations.size(), 1);
-    QCOMPARE(migrations.at(0)->getVersion(), QString("test0.1"));
-}
-
-void Tables::testBasics() {
-    this->e->createTable("Article");
-    QVERIFY(this->e->getSchema()->getTableNames().contains("article"));
-    QSharedPointer<Article> article = QSharedPointer<Article>(new Article(10,
-                                      QString("TestItem")));
-    QSharedPointer<Entity> entity = article.objectCast<Entity>();
-    QVERIFY(this->e->create(entity));
-    article->setPrice(20);
-    article->setName("NewTestItem");
-    QVERIFY(this->e->save(entity));
-    QHash<QString, QVariant> attrs = QHash<QString, QVariant>();
-    attrs.insert("price", 20);
-    attrs.insert("name", "NewTestItem");
-    QSharedPointer<Article> article2 = this->e->findEntityByAttributes<Article>
-                                       (attrs);
-    QVERIFY(article2);
-    entity = article2.objectCast<Entity>();
-    QVERIFY(this->e->remove(entity));
-    QCOMPARE(this->e->count("article"), (quint8)0);
-    this->e->getDb()->exec(this->e->getQueryBuilder()->dropTable("article"));
-    QVERIFY(!this->e->getSchema()->getTableNames().contains("article"));
-}
-
-QTEST_APPLESS_MAIN(Tables)
-
-#include "tst_tables.moc"
diff --git a/tests/tests.pro b/tests/tests.pro
index 076aff8..f752f68 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -1,3 +1,5 @@
 TEMPLATE = subdirs
 SUBDIRS += \
-    tables
+    em \
+    querybuilder \
+    validators
diff --git a/tests/validators/tst_validatorstest.cpp b/tests/validators/tst_validatorstest.cpp
new file mode 100644
index 0000000..ed9950e
--- /dev/null
+++ b/tests/validators/tst_validatorstest.cpp
@@ -0,0 +1,44 @@
+#include <QString>
+#include <QtTest>
+
+class ValidatorsTest : public QObject
+{
+    Q_OBJECT
+
+public:
+    ValidatorsTest();
+
+private Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+    void testCase1_data();
+    void testCase1();
+};
+
+ValidatorsTest::ValidatorsTest()
+{
+}
+
+void ValidatorsTest::initTestCase()
+{
+}
+
+void ValidatorsTest::cleanupTestCase()
+{
+}
+
+void ValidatorsTest::testCase1_data()
+{
+    QTest::addColumn<QString>("data");
+    QTest::newRow("0") << QString();
+}
+
+void ValidatorsTest::testCase1()
+{
+    QFETCH(QString, data);
+    QVERIFY2(true, "Failure");
+}
+
+QTEST_APPLESS_MAIN(ValidatorsTest)
+
+#include "tst_validatorstest.moc"
diff --git a/tests/validators/validators.pro b/tests/validators/validators.pro
new file mode 100644
index 0000000..79f5707
--- /dev/null
+++ b/tests/validators/validators.pro
@@ -0,0 +1,19 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2015-10-26T13:28:32
+#
+#-------------------------------------------------
+
+QT       += testlib
+
+QT       -= gui
+
+TARGET = tst_validatorstest
+CONFIG   += console
+CONFIG   -= app_bundle
+
+TEMPLATE = app
+
+
+SOURCES += tst_validatorstest.cpp
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
