public void TestNoBlock()
        {
            BlockingThreadPool threadPool = new BlockingThreadPool(2, 2);
            MessageLog log = new MessageLog();

            for (int i = 0; i < TestIterationsCount; i++)
            {
                log.Clear();

                Assert.That(threadPool.Execute(() =>
                {
                    log.Log("task 1: started"); // T = 0
                    Thread.Sleep(200);
                    log.Log("task 1: finished"); // T = 200
                }, 100), Is.True);

                Thread.Sleep(50); // T = 50

                Assert.That(threadPool.Execute(() =>
                {
                    log.Log("task 2: started"); // T = 50
                    Thread.Sleep(200);
                    log.Log("task 2: finished"); // T = 250
                }, 100), Is.True);

                Thread.Sleep(50);
                log.Log("main: wait started"); // T = 100
                Thread.Sleep(200);
                log.Log("main: wait finished"); // T = 300

                Assert.That(log.GetLog(), Is.EqualTo(new string[]
                {
                    "task 1: started",
                    "task 2: started",
                    "main: wait started",
                    "task 1: finished",
                    "task 2: finished",
                    "main: wait finished"
                }));
            }

            Assert.That(threadPool.Stop(1000), Is.True);
        }
        public void TestSmoke()
        {
            MessageLog log = new MessageLog();
            ActionPerformer performer = new ActionPerformer(log);
            EventManager eventManager = new EventManager();

            const string eventType1 = "ET1";
            const string eventType2 = "ET2";

            eventManager.Watch(eventType1, performer.Action1);
            eventManager.Watch(eventType2, performer.Action2);

            eventManager.Start();

            log.Log($"Fired {eventType1} event.");
            eventManager.Notify(eventType1);

            Thread.Sleep(200);

            log.Log($"Fired {eventType2} event.");
            eventManager.Notify(eventType2);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                $"Fired {eventType1} event.",
                $"Action1 invoked.",
                $"Fired {eventType2} event.",
                $"Action2 invoked."
            }));

            // testing that attempt to remove non-existent event listeners does not affect existing watchers
            eventManager.Unwatch(eventType1, performer.Action2);
            eventManager.Unwatch(eventType2, performer.Action1);

            log.Clear();
            log.Log("Attempted to remove non-existent event listeners.");

            log.Log($"Fired {eventType1} event.");
            eventManager.Notify(eventType1);

            Thread.Sleep(200);

            log.Log($"Fired {eventType2} event.");
            eventManager.Notify(eventType2);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                $"Attempted to remove non-existent event listeners.",
                $"Fired {eventType1} event.",
                $"Action1 invoked.",
                $"Fired {eventType2} event.",
                $"Action2 invoked."
            }));

            eventManager.Unwatch(eventType1, performer.Action1);

            log.Clear();
            log.Log($"Removed event-listener for {eventType1}.");

            log.Log($"Fired {eventType1} event.");
            eventManager.Notify(eventType1);

            log.Log($"Fired {eventType2} event.");
            eventManager.Notify(eventType2);

            Thread.Sleep(200);

            Assert.That(log.GetLog(), Is.EqualTo(new string[]
            {
                $"Removed event-listener for {eventType1}.",
                $"Fired {eventType1} event.",
                $"Fired {eventType2} event.",
                $"Action2 invoked."
            }));
        }
        public void TestStopBusy()
        {
            MessageLog log = new MessageLog();

            for (int i = 0; i < TestIterationsCount; i++)
            {
                BlockingThreadPool threadPool = new BlockingThreadPool(3, 3);
                log.Clear();

                threadPool.Execute(() =>
                {
                    log.Log("task 1: started"); // T = 0
                    try
                    {
                        // finally block is required to ignore Thread.Interrupt and Thread.Abort
                    }
                    finally
                    {
                        Thread.Sleep(200);
                    }
                    log.Log("task 1: finished"); // T = 200
                }, 100);

                Thread.Sleep(50); // T = 50

                threadPool.Execute(() =>
                {
                    log.Log("task 2: started"); // T = 50
                    try
                    {
                        // finally block is required to ignore Thread.Interrupt and Thread.Abort
                    }
                    finally
                    {
                        Thread.Sleep(250);
                    }
                    log.Log("task 2: finished"); // T = 300
                }, 100);

                Thread.Sleep(50); // T = 50

                threadPool.Execute(() =>
                {
                    log.Log("task 3: started"); // T = 100
                    log.Log($"task 4 queued: {threadPool.Execute(() => { }, 300)}"); // T = 150
                    log.Log("task 3: finished"); // T = 150
                }, 100);

                Thread.Sleep(50); // T = 150

                Stopwatch sw = Stopwatch.StartNew();
                Assert.That(threadPool.Stop(100), Is.False); // T = 250
                Assert.That(sw.ElapsedMilliseconds, Is.GreaterThan(75).And.LessThan(125));

                sw.Restart();
                Assert.That(threadPool.Execute(() => { }, 100), Is.False);
                Assert.That(sw.ElapsedMilliseconds, Is.LessThan(25));

                sw.Restart();
                Assert.That(threadPool.Stop(100), Is.True); // T = 300
                Assert.That(sw.ElapsedMilliseconds, Is.GreaterThan(25).And.LessThan(75));

                //check that Stop does not fail on a stopped pool
                sw.Restart();
                Assert.That(threadPool.Stop(100), Is.True); // T = 300
                Assert.That(sw.ElapsedMilliseconds, Is.LessThan(25));

                Assert.That(log.GetLog(), Is.EqualTo(new string[]
                {
                    "task 1: started",
                    "task 2: started",
                    "task 3: started",
                    "task 4 queued: False",
                    "task 3: finished",
                    "task 1: finished",
                    "task 2: finished"
                }));
            }
        }