Ejemplo n.º 1
0
        private Mock <IMeetingMessage> MakeMockMessage(
            string prefix,
            string args,
            MeetingAction action,
            CommandRestriction restriction
            )
        {
            Mock <IMeetingMessage> message = new Mock <IMeetingMessage>(MockBehavior.Strict);

            message.Setup(
                m => m.CommandPrefix
                ).Returns(prefix);

            message.Setup(
                m => m.CommandArgs
                ).Returns(args);

            message.Setup(
                m => m.MeetingAction
                ).Returns(action);

            message.Setup(
                m => m.Restriction
                ).Returns(restriction);

            return(message);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Adds a normal message to the meeting notes,
        /// and returns the message that was added.
        /// </summary>
        private IMeetingMessage AddMessage(
            string message,
            string user,
            ParseMessageResult expectedResult = ParseMessageResult.Success,
            DateTime?timestamp = null
            )
        {
            const string             prefix   = "";
            string                   args     = message;
            const MeetingAction      action   = MeetingAction.Unknown;
            const CommandRestriction restrict = CommandRestriction.Unknown;

            IMeetingMessage msg = MakeMessage(
                prefix,
                args,
                action,
                restrict
                );

            ParseMessageResult result = this.uut.ParseMessage(msg, user, timestamp ?? this.testTime);

            Assert.AreEqual(expectedResult, result);

            return(msg);
        }
Ejemplo n.º 3
0
        public void OwnerCantUnchairThemselfTest()
        {
            // Ensure owner can unchair chair.
            {
                const string             prefix   = "#unchair";
                const string             args     = owner;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should have correct error message and added to list.
                Assert.AreEqual(ParseMessageResult.CanNotDoThisToOwner, result);
                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // Should still be a chair
                Assert.AreEqual(1, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }
        }
Ejemplo n.º 4
0
        public void ChairWithSeveralWhitespacesTest()
        {
            const string             prefix   = "#chair";
            string                   args     = $"  {user1}      {user2}    ";
            const MeetingAction      action   = MeetingAction.Chair;
            const CommandRestriction restrict = CommandRestriction.ChairsOnly;

            IMeetingMessage msg = MakeMessage(
                prefix,
                args,
                action,
                restrict
                );

            // Owner is chair by default.
            ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

            // Should be a successful parse.
            Assert.AreEqual(ParseMessageResult.Success, result);
            Assert.AreEqual(1, uut.MeetingNotes.Count);
            CompareNotes(msg, uut.MeetingNotes.Last(), owner);

            // New chair should show up in list.
            Assert.AreEqual(3, uut.Chairs.Count());
            Assert.IsTrue(uut.Chairs.Contains(owner));
            Assert.IsTrue(uut.Chairs.Contains(user1));
            Assert.IsTrue(uut.Chairs.Contains(user2));

            // Other lists should be empty
            Assert.AreEqual(0, uut.SilencedUsers.Count);
            Assert.AreEqual(0, uut.BannedUsers.Count);
        }
Ejemplo n.º 5
0
 private IMeetingMessage MakeMessage(
     string prefix,
     string args,
     MeetingAction action,
     CommandRestriction restriction
     )
 {
     return(MakeMockMessage(prefix, args, action, restriction).Object);
 }
Ejemplo n.º 6
0
        public void PurgeUserTest()
        {
            // Add some messages

            AddAndCheckMessage(
                "Hello World 1",
                1,
                user1
                );

            AddAndCheckMessage(
                "Hello World 2",
                2,
                user1
                );

            // Purge the user.
            {
                const string             prefix   = "#purge";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Purge;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);

                // Only 1 message should remain; the purge one.
                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                EnsureDefaultLists();
            }

            // User should still be able to chat though.  Should be 2 messages now
            // (new message + purge message).

            AddAndCheckMessage(
                "Hello World 2",
                2,
                user1
                );
        }
Ejemplo n.º 7
0
        // ---------------- Test Helpers ----------------

        private void CommandExists(
            CommandDefinitionCollection list,
            string prefix,
            MeetingAction expectedAction,
            CommandRestriction expectedRestriction
            )
        {
            IEnumerable <CommandDefinition> defs = list.CommandDefinitions.Where(d => d.Prefixes.Contains(prefix));

            // Ensure only one command is returned, or we have duplicates.
            Assert.AreEqual(1, defs.Count());

            // Ensure everything matches what we expect.
            CommandDefinition def = defs.First();

            Assert.AreEqual(expectedAction, def.MeetingAction);
            Assert.AreEqual(expectedRestriction, def.Restriction);
            Assert.IsTrue(def.IsDefault);
            Assert.IsTrue(def.GetPrefixRegex().IsMatch(prefix));
        }
Ejemplo n.º 8
0
            public async Task EnableCommandFor(CommandContext context, string userName, [RemainingText] string commandName)
            {
                var guild         = context.GetGuild();
                var nameFragments = commandName.Split(".");
                var user          = guild.FindMember(userName);

                if (user == null)
                {
                    await context.RespondAsync($"Can not find the user '{userName}'.");

                    return;
                }

                CommandRestriction restriction = _context.GetUserRestriction(guild.Id, user.Id)?.FindCommandRestriction(commandName);

                if (restriction == null)
                {
                    await context.RespondAsync("The user is already allowed to use this command.");

                    return;
                }
                string botMessage = $"Re-enable command `{restriction.CommandName}` for {user.Username}?";

                await context.CreateConfirmation(
                    botMessage,
                    async() => {
                    this._context.RemoveRestrictionForUser(
                        guild.Id,
                        user.Id,
                        restriction
                        );
                    await context.RespondAsync($"Re-enabled `{restriction.CommandName}` for {user.Username}?.");
                },
                    async() => {
                    await context.RespondAsync("Action aborted. No settings changed.");
                }
                    );
            }
Ejemplo n.º 9
0
        public void HelpTest()
        {
            const string             prefix   = "#help";
            const string             args     = "#link";
            const MeetingAction      action   = MeetingAction.Help;
            const CommandRestriction restrict = CommandRestriction.Anyone;

            IMeetingMessage msg = MakeMessage(
                prefix,
                args,
                action,
                restrict
                );

            ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

            Assert.AreEqual(ParseMessageResult.Success, result);

            EnsureDefaultLists();

            // Should be nothing in the meeting notes, helps are not added.
            Assert.AreEqual(0, uut.MeetingNotes.Count);
        }
Ejemplo n.º 10
0
        public void NormalUserCantSilenceWithChairOnlySettingTest()
        {
            const string             prefix   = "#silence";
            const string             args     = user2;
            const MeetingAction      action   = MeetingAction.Silence;
            const CommandRestriction restrict = CommandRestriction.ChairsOnly;

            IMeetingMessage silenceMsg = MakeMessage(
                prefix,
                args,
                action,
                restrict
                );

            ParseMessageResult result = this.uut.ParseMessage(silenceMsg, user1, this.testTime);

            Assert.AreEqual(ParseMessageResult.ChairOnlyCommand, result);

            EnsureDefaultLists();

            Assert.AreEqual(1, uut.MeetingNotes.Count);
            CompareNotes(silenceMsg, uut.MeetingNotes.Last(), user1, expectedMeetingAction: MeetingAction.Unknown);
        }
Ejemplo n.º 11
0
        public void BotAdminSilenceTest()
        {
            const string             prefix   = "#silence";
            const string             args     = user1;
            const MeetingAction      action   = MeetingAction.Silence;
            const CommandRestriction restrict = CommandRestriction.ChairsAndBotAdmins;

            IMeetingMessage silenceMsg = MakeMessage(
                prefix,
                args,
                action,
                restrict
                );

            ParseMessageResult result = this.uut.ParseMessage(silenceMsg, adminName, this.testTime);

            Assert.AreEqual(ParseMessageResult.Success, result);

            Assert.AreEqual(1, uut.SilencedUsers.Count);
            Assert.IsTrue(uut.SilencedUsers.Contains(user1));

            Assert.AreEqual(1, uut.MeetingNotes.Count);
            CompareNotes(silenceMsg, uut.MeetingNotes.Last(), adminName);
        }
Ejemplo n.º 12
0
        // ---------------- Test Helpers ----------------

        private IMeetingMessage AddChairMessage(
            string userToChair,
            string userThatChairs,
            ParseMessageResult expectedResult = ParseMessageResult.Success
            )
        {
            const string             prefix   = "#chair";
            string                   args     = userToChair;
            const MeetingAction      action   = MeetingAction.Chair;
            const CommandRestriction restrict = CommandRestriction.ChairsOnly;

            IMeetingMessage msg = MakeMessage(
                prefix,
                args,
                action,
                restrict
                );

            ParseMessageResult result = this.uut.ParseMessage(msg, userThatChairs, this.testTime);

            Assert.AreEqual(expectedResult, result);

            return(msg);
        }
Ejemplo n.º 13
0
        public void ChairUnchair1PersonTest()
        {
            // Chair 1 user.
            {
                const string             prefix   = "#chair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Chair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                // Owner is chair by default.
                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // New chair should show up in list.
                Assert.AreEqual(2, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));
                Assert.IsTrue(uut.Chairs.Contains(user1));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            // Ensure chair can not unchair owner.
            {
                const string             prefix   = "#unchair";
                const string             args     = owner;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, user1, this.testTime);

                // Should have correct error message and added to list.
                Assert.AreEqual(ParseMessageResult.CanNotDoThisToOwner, result);
                Assert.AreEqual(2, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), user1);

                // Chair list should not be modified.
                Assert.AreEqual(2, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));
                Assert.IsTrue(uut.Chairs.Contains(user1));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            // Ensure nonchair can not unchair chair
            {
                const string             prefix   = "#unchair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, user2, this.testTime);

                // Should have correct error message and added to list.
                Assert.AreEqual(ParseMessageResult.ChairOnlyCommand, result);
                Assert.AreEqual(3, uut.MeetingNotes.Count);

                // Invalid permission, meeting message becomes standard message so it
                // doesn't show up in the log as something special.
                IReadOnlyMeetingNote note = uut.MeetingNotes.Last();
                Assert.AreEqual(MeetingAction.Unknown, note.MeetingAction);
                Assert.AreEqual($"{msg.CommandPrefix} {msg.CommandArgs}", note.Message);
                Assert.AreEqual(user2, note.UserName);

                // Chair list should not be modified.
                Assert.AreEqual(2, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));
                Assert.IsTrue(uut.Chairs.Contains(user1));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            // Ensure owner can unchair chair.
            {
                const string             prefix   = "#unchair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should have correct error message and added to list.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(4, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // User should no longer be a chair.
                Assert.AreEqual(1, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }
        }
Ejemplo n.º 14
0
        public void CanNotSilenceOwnerOrChairTest()
        {
            // Make user1 a chair.
            AddChairMessage(user1, owner);

            // Sanity check
            Assert.IsTrue(this.uut.Chairs.Contains(user1));

            void CheckLists()
            {
                Assert.AreEqual(0, this.uut.BannedUsers.Count);
                Assert.AreEqual(0, this.uut.SilencedUsers.Count);
                Assert.AreEqual(2, this.uut.Chairs.Count);
                Assert.IsTrue(this.uut.Chairs.Contains(owner));
                Assert.IsTrue(this.uut.Chairs.Contains(user1));
            }

            // Make sure we can not silence an owner.
            {
                const string             prefix   = "#silence";
                const string             args     = owner;
                const MeetingAction      action   = MeetingAction.Silence;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, user1, this.testTime);
                // Error message is the generic "Can not do this to chair", even if we try
                // to silence the owner. It just makes things easier that way.
                Assert.AreEqual(ParseMessageResult.CanNotDoThisToChair, result);

                CheckLists();

                // 2 Messages: the first chair and the failed silence attempt.
                Assert.AreEqual(2, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), user1);
            }

            // Make sure a not-chair can not silence a chair.
            {
                const string             prefix   = "#silence";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Silence;
                const CommandRestriction restrict = CommandRestriction.Anyone;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, user2, this.testTime);
                Assert.AreEqual(ParseMessageResult.CanNotDoThisToChair, result);

                CheckLists();

                // 3 Messages: the first chair and the failed silence attempt.
                Assert.AreEqual(3, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), user2);
            }

            // Make sure chair and owner can still chat
            AddAndCheckMessage(
                "Owner Check",
                4,
                owner
                );

            AddAndCheckMessage(
                "Chair Check",
                5,
                user1
                );
        }
Ejemplo n.º 15
0
        public void SilenceVoiceTest()
        {
            // Make a standard message from a user
            AddAndCheckMessage(
                "Hello, world",
                1,
                user1
                );

            void CheckLists()
            {
                Assert.AreEqual(0, this.uut.BannedUsers.Count);
                Assert.AreEqual(1, this.uut.Chairs.Count);
                Assert.IsTrue(this.uut.Chairs.Contains(owner));
            }

            // User said something dumb, silence him!
            IMeetingMessage silenceMsg;

            {
                const string             prefix   = "#silence";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Silence;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                silenceMsg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(silenceMsg, owner, this.testTime);
                Assert.AreEqual(ParseMessageResult.Success, result);

                CheckLists();
                Assert.AreEqual(1, uut.SilencedUsers.Count);
                Assert.IsTrue(uut.SilencedUsers.Contains(user1));

                // 2 Messages: the first message and the silence.
                Assert.AreEqual(2, uut.MeetingNotes.Count);
                CompareNotes(silenceMsg, uut.MeetingNotes.Last(), owner);
            }

            // Silence user message should not be added to the logs.
            {
                AddMessage(
                    "Can you hear me?",
                    user1,
                    ParseMessageResult.UserIsSilenced
                    );

                CheckLists();
                Assert.AreEqual(1, uut.SilencedUsers.Count);
                Assert.IsTrue(uut.SilencedUsers.Contains(user1));

                // Most recent message should be the silence.
                Assert.AreEqual(2, uut.MeetingNotes.Count);
                CompareNotes(silenceMsg, uut.MeetingNotes.Last(), owner);
            }

            // Unsilence the user.
            {
                const string             prefix   = "#voice";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Voice;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);
                Assert.AreEqual(ParseMessageResult.Success, result);

                CheckLists();
                Assert.AreEqual(0, uut.SilencedUsers.Count);

                // 3 Messages: now including the voice message.
                Assert.AreEqual(3, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);
            }

            // User should now be able to chat.
            AddAndCheckMessage(
                "Hello, world, again!",
                4,
                user1
                );
        }
Ejemplo n.º 16
0
        public void BanUserTest()
        {
            // Add some messages

            AddAndCheckMessage(
                "Hello World 1",
                1,
                user1
                );

            AddAndCheckMessage(
                "Hello World 2",
                2,
                user1
                );

            void CheckLists()
            {
                // 1 user should be added to the banned users.
                Assert.AreEqual(1, uut.BannedUsers.Count);
                Assert.IsTrue(uut.BannedUsers.Contains(user1));

                // 1 Person should still be in the chairs, no one should be silenced.
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(1, uut.Chairs.Count);
                Assert.IsTrue(uut.Chairs.Contains(owner));
            }

            // Ban the user.
            IMeetingMessage banMsg;
            {
                const string             prefix   = "#ban";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Banish;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                banMsg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(banMsg, owner, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);

                // Only 1 message should remain; the ban one.
                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(banMsg, uut.MeetingNotes.Last(), owner);

                CheckLists();
            }

            // User should no longer be able to chat.
            // Last message received should still be the ban message.

            {
                AddMessage(
                    "Hello World 3",
                    user1,
                    ParseMessageResult.UserIsSilenced
                    );

                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(banMsg, uut.MeetingNotes.Last(), owner);

                CheckLists();
            }
        }
Ejemplo n.º 17
0
        public void ChairCanUnchairThemSelfTest()
        {
            // Chair 1 user.
            {
                const string             prefix   = "#chair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Chair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                // Owner is chair by default.
                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // New chair should show up in list.
                Assert.AreEqual(2, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));
                Assert.IsTrue(uut.Chairs.Contains(user1));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            // Unchair themself.
            {
                const string             prefix   = "#unchair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                // Owner is chair by default.
                ParseMessageResult result = this.uut.ParseMessage(msg, user1, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(2, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), user1);

                // No longer should appear in list.
                Assert.AreEqual(1, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }
        }
Ejemplo n.º 18
0
        public void ChairUnchairSameUserTest()
        {
            // Chair 1 user.
            {
                const string             prefix   = "#chair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Chair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                // Owner is chair by default.
                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(1, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // New chair should show up in list.
                Assert.AreEqual(2, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));
                Assert.IsTrue(uut.Chairs.Contains(user1));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            // Chair 1 user again!
            {
                const string             prefix   = "#chair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Chair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                // Owner is chair by default.
                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should be a successful parse.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(2, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // New chair should show up in list, but only once!
                Assert.AreEqual(2, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));
                Assert.IsTrue(uut.Chairs.Contains(user1));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            {
                const string             prefix   = "#unchair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should have correct error message and added to list.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(3, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // User should no longer be a chair.
                Assert.AreEqual(1, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }

            {
                const string             prefix   = "#unchair";
                const string             args     = user1;
                const MeetingAction      action   = MeetingAction.Unchair;
                const CommandRestriction restrict = CommandRestriction.ChairsOnly;

                IMeetingMessage msg = MakeMessage(
                    prefix,
                    args,
                    action,
                    restrict
                    );

                ParseMessageResult result = this.uut.ParseMessage(msg, owner, this.testTime);

                // Should have correct error message and added to list.
                Assert.AreEqual(ParseMessageResult.Success, result);
                Assert.AreEqual(4, uut.MeetingNotes.Count);
                CompareNotes(msg, uut.MeetingNotes.Last(), owner);

                // User should no longer be a chair.
                Assert.AreEqual(1, uut.Chairs.Count());
                Assert.IsTrue(uut.Chairs.Contains(owner));

                // Other lists should be empty
                Assert.AreEqual(0, uut.SilencedUsers.Count);
                Assert.AreEqual(0, uut.BannedUsers.Count);
            }
        }