From a663d0f199fd101d3c1a53d9d29ae0238dc4b300 Mon Sep 17 00:00:00 2001
From: Benedikt Magnus <magnus@magnuscraft.de>
Date: Fri, 12 Nov 2021 23:43:46 +0100
Subject: [PATCH] Basic tests for the assignment module

---
 .../wichtelbot.message.module.assignment.ts   | 234 ++++++++++++++++++
 tests/utility/contact.ts                      |  13 +-
 tests/utility/relationship.ts                 |  86 +++++++
 3 files changed, 332 insertions(+), 1 deletion(-)
 create mode 100644 tests/tests/wichtelbot.message.module.assignment.ts
 create mode 100644 tests/utility/relationship.ts

diff --git a/tests/tests/wichtelbot.message.module.assignment.ts b/tests/tests/wichtelbot.message.module.assignment.ts
new file mode 100644
index 0000000..9dc2e75
--- /dev/null
+++ b/tests/tests/wichtelbot.message.module.assignment.ts
@@ -0,0 +1,234 @@
+import 'mocha';
+import { assert } from 'chai';
+import { AssignmentModule } from '../../scripts/wichtelbot/message/modules/assignmentModule';
+import ContactTestUtility from '../utility/contact';
+import Database from '../../scripts/wichtelbot/database';
+import GiftType from '../../scripts/wichtelbot/types/giftType';
+import Member from '../../scripts/wichtelbot/classes/member';
+import { RelationshipTestUtility } from '../utility/relationship';
+
+describe('assignment module',
+    function ()
+    {
+        let database: Database;
+        let assignmentModule: AssignmentModule;
+
+        beforeEach(
+            function ()
+            {
+                // Initialise dependencies:
+                database = new Database('mainTest', 'logTest', true);
+                assignmentModule = new AssignmentModule(database);
+            }
+        );
+
+        afterEach(
+            function ()
+            {
+                database.close();
+            }
+        );
+
+        it('can assign three simple members.',
+            function ()
+            {
+                const newMembers: Member[] = [];
+
+                for (let i = 0; i < 3; i++)
+                {
+                    const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+
+                    newMembers.push(newMember);
+                    database.saveContact(newMember);
+                    database.saveMember(newMember);
+                }
+
+                const successful = assignmentModule.assign();
+
+                assert.isTrue(successful);
+
+                const relationships = database.getRelationships();
+
+                assert.equal(relationships.length, 3);
+
+                RelationshipTestUtility.assertValidity(relationships, newMembers);
+            }
+        );
+
+        it('can assign three members all with analogue gift types',
+            function ()
+            {
+                const newMembers: Member[] = [];
+
+                for (let i = 0; i < 3; i++)
+                {
+                    const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+                    newMember.information.giftTypeAsGiver = GiftType.Analogue;
+                    newMember.information.giftTypeAsTaker = GiftType.Analogue;
+
+                    newMembers.push(newMember);
+                    database.saveContact(newMember);
+                    database.saveMember(newMember);
+                }
+
+                const successful = assignmentModule.assign();
+
+                assert.isTrue(successful);
+
+                const relationships = database.getRelationships();
+
+                assert.equal(relationships.length, 3);
+
+                RelationshipTestUtility.assertValidity(relationships, newMembers);
+            }
+        );
+
+        it('can assign three members all with digital gift types',
+            function ()
+            {
+                const newMembers: Member[] = [];
+
+                for (let i = 0; i < 3; i++)
+                {
+                    const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+                    newMember.information.giftTypeAsGiver = GiftType.Digital;
+                    newMember.information.giftTypeAsTaker = GiftType.Digital;
+
+                    newMembers.push(newMember);
+                    database.saveContact(newMember);
+                    database.saveMember(newMember);
+                }
+
+                const successful = assignmentModule.assign();
+
+                assert.isTrue(successful);
+
+                const relationships = database.getRelationships();
+
+                assert.equal(relationships.length, 3);
+
+                RelationshipTestUtility.assertValidity(relationships, newMembers);
+            }
+        );
+
+        it('can assign members, one with analogue, one with digital und two with all gift type',
+            function ()
+            {
+                const newMembers: Member[] = [];
+
+                for (let i = 0; i < 4; i++)
+                {
+                    const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+
+                    newMembers.push(newMember);
+                }
+
+                newMembers[0].information.giftTypeAsGiver = GiftType.Analogue;
+                newMembers[0].information.giftTypeAsTaker = GiftType.Analogue;
+                newMembers[0].id = 'Analogue';
+                newMembers[1].information.giftTypeAsGiver = GiftType.Digital;
+                newMembers[1].information.giftTypeAsTaker = GiftType.Digital;
+                newMembers[1].id = 'Digital';
+                newMembers[2].information.giftTypeAsGiver = GiftType.All;
+                newMembers[2].information.giftTypeAsTaker = GiftType.All;
+                newMembers[2].id = 'All 1';
+                newMembers[3].information.giftTypeAsGiver = GiftType.All;
+                newMembers[3].information.giftTypeAsTaker = GiftType.All;
+                newMembers[3].id = 'All 2';
+
+                for (const newMember of newMembers)
+                {
+                    newMember.information.contactId = newMember.id;
+
+                    database.saveContact(newMember);
+                    database.saveMember(newMember);
+                }
+
+                const successful = assignmentModule.assign();
+
+                assert.isTrue(successful);
+
+                const relationships = database.getRelationships();
+
+                assert.equal(relationships.length, 4);
+
+                RelationshipTestUtility.assertValidity(relationships, newMembers);
+                RelationshipTestUtility.assertCompatibility(relationships, newMembers);
+            }
+        );
+
+        it('cannot assign with zero members',
+            function ()
+            {
+                const successful = assignmentModule.assign();
+
+                assert.isFalse(successful);
+            }
+        );
+
+        it('cannot assign with one member',
+            function ()
+            {
+                const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+
+                database.saveContact(newMember);
+                database.saveMember(newMember);
+
+                const successful = assignmentModule.assign();
+
+                assert.isFalse(successful);
+            }
+        );
+
+        it('cannot assign with two members',
+            function ()
+            {
+                const newMembers: Member[] = [];
+
+                for (let i = 0; i < 2; i++)
+                {
+                    const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+
+                    newMembers.push(newMember);
+                    database.saveContact(newMember);
+                    database.saveMember(newMember);
+                }
+
+                const successful = assignmentModule.assign();
+
+                assert.isFalse(successful);
+            }
+        );
+
+        it('cannot assign members, two with analogue and one with digital gift type',
+            function ()
+            {
+                const newMembers: Member[] = [];
+
+                for (let i = 0; i < 3; i++)
+                {
+                    const newMember = ContactTestUtility.createRandomMemberWithMostCompatibleInformation();
+
+                    newMembers.push(newMember);
+                    database.saveContact(newMember);
+                }
+
+                newMembers[0].information.giftTypeAsGiver = GiftType.Analogue;
+                newMembers[0].information.giftTypeAsTaker = GiftType.Analogue;
+                newMembers[1].information.giftTypeAsGiver = GiftType.Analogue;
+                newMembers[1].information.giftTypeAsTaker = GiftType.Analogue;
+                newMembers[2].information.giftTypeAsGiver = GiftType.Digital;
+                newMembers[2].information.giftTypeAsTaker = GiftType.Digital;
+
+                for (const newMember of newMembers)
+                {
+                    database.saveMember(newMember);
+                }
+
+                const successful = assignmentModule.assign();
+
+                assert.isFalse(successful);
+            }
+        );
+    }
+);
diff --git a/tests/utility/contact.ts b/tests/utility/contact.ts
index 3eed181..d135f46 100644
--- a/tests/utility/contact.ts
+++ b/tests/utility/contact.ts
@@ -101,11 +101,22 @@ export default abstract class ContactTestUtility
     public static createRandomMember (): Member
     {
         const contact = ContactTestUtility.createRandomContact();
-        const information = ContactTestUtility.createRandomMemberInformation();
+        const information = ContactTestUtility.createRandomMemberInformation(contact.id);
 
         const member = new Member(contact, information);
         member.type = ContactType.Member;
 
         return member;
     }
+
+    public static createRandomMemberWithMostCompatibleInformation (): Member
+    {
+        const member = ContactTestUtility.createRandomMember();
+        member.information.country = 'deutschland';
+        member.information.giftTypeAsGiver = GiftType.All;
+        member.information.giftTypeAsTaker = GiftType.All;
+        member.information.internationalAllowed = true;
+
+        return member;
+    }
 }
diff --git a/tests/utility/relationship.ts b/tests/utility/relationship.ts
new file mode 100644
index 0000000..745f660
--- /dev/null
+++ b/tests/utility/relationship.ts
@@ -0,0 +1,86 @@
+import { assert } from "chai";
+import GiftType from "../../scripts/wichtelbot/types/giftType";
+import Member from "../../scripts/wichtelbot/classes/member";
+import { Relationship } from "../../scripts/wichtelbot/classes/relationship";
+
+export abstract class RelationshipTestUtility
+{
+    /**
+     * Validate the relationship by checking that for every member exactly one relationship with him as giver and one as taker exists.
+     */
+    public static assertValidity (relationships: Relationship[], members: Member[]): void
+    {
+        for (const member of members)
+        {
+            let foundGiver = false;
+            let foundTaker = false;
+
+            for (const relationship of relationships)
+            {
+                assert.notEqual(relationship.giverId, relationship.takerId);
+
+                if (relationship.giverId === member.id)
+                {
+                    assert.isFalse(foundGiver);
+                    foundGiver = true;
+                }
+                else if (relationship.takerId === member.id)
+                {
+                    assert.isFalse(foundTaker);
+                    foundTaker = true;
+                }
+            }
+
+            assert.isTrue(foundGiver);
+            assert.isTrue(foundTaker);
+        }
+    }
+
+    /**
+     * Proofs the compatibility of every relationship.
+    */
+    public static assertCompatibility (relationships: Relationship[], members: Member[]): void
+    {
+        for (const relationship of relationships)
+        {
+            let giver: Member|null = null;
+            let taker: Member|null = null;
+
+            for (const member of members)
+            {
+                if (member.id === relationship.giverId)
+                {
+                    giver = member;
+                }
+                else if (member.id === relationship.takerId)
+                {
+                    taker = member;
+                }
+            }
+
+            if (giver === null || taker === null)
+            {
+                // NOTE: One should think that an assert would assert a type, but it doesn't...
+
+                assert.isNotNull(giver);
+                assert.isNotNull(taker);
+
+                continue;
+            }
+
+            const giftTypesAreTheSame = giver.information.giftTypeAsGiver === taker.information.giftTypeAsTaker;
+            const giverHasAllGiftType = giver.information.giftTypeAsGiver === GiftType.All;
+            const takerHasAllGiftType = taker.information.giftTypeAsTaker === GiftType.All;
+            const isGiftTypeCompatible = giftTypesAreTheSame || giverHasAllGiftType || takerHasAllGiftType;
+
+            assert.isTrue(isGiftTypeCompatible);
+
+            const countriesAreTheSame = giver.information.country === taker.information.country;
+            const noneHasAnalogueGiftType = giver.information.giftTypeAsGiver === GiftType.Analogue
+                || taker.information.giftTypeAsTaker === GiftType.Analogue;
+            const isInternationalCompatible = countriesAreTheSame || noneHasAnalogueGiftType || giver.information.internationalAllowed;
+
+            assert.isTrue(isInternationalCompatible);
+        }
+    }
+}
-- 
GitLab