public void InvokesOnlyOneAtTheTimeAndLastOneWins()
        {
            var it = new InvocationThrottle(min: TimeSpan.FromMilliseconds(1), max: TimeSpan.FromMilliseconds(2));

            int im_doing_stuff = 0;
            bool hasException = false;

            int invocation_count = 0;

            ConcurrentBag<AutoResetEvent> ares = new ConcurrentBag<AutoResetEvent>();

            for (int i = 0; i < 10; i++)
            {
                var local_i = i;

                it.Invoke(() => 
                    {
                        var are = new AutoResetEvent(initialState: false);
                        ares.Add(are);

                        try
                        {
                            Interlocked.Increment(ref invocation_count);
                            LongAction(ref im_doing_stuff);

                            if((local_i < 9 && invocation_count != 1) || (local_i == 9 && invocation_count != 2))
                            {
                                throw new Exception();
                            }
                        }
                        catch(Exception ex)
                        {
                            hasException = true;
                        }

                        are.Set();
                    });

                Thread.Sleep(1);
            }

            Thread.Sleep(200);

            OnMtaThread(() => AutoResetEvent.WaitAll(ares.ToArray()));

            if (hasException)
                Assert.Fail();

        }
        public void ActionIsInvokedOnDifferentThread()
        {
            var it = new InvocationThrottle(TimeSpan.MinValue);

            var are = new AutoResetEvent(initialState: false);

            var tid = Thread.CurrentThread.ManagedThreadId;

            it.Invoke(() => 
                {
                    Assert.AreNotEqual(tid, Thread.CurrentThread.ManagedThreadId);

                    are.Set();
                });
            
            are.WaitOne();

            Assert.IsTrue(true);
        }
        public void WaitsMinTimespanBeforeExecuting()
        {
            var min = TimeSpan.FromMilliseconds(100);

            var it = new InvocationThrottle(min);
            var tid = Thread.CurrentThread.ManagedThreadId;

            var are = new AutoResetEvent(initialState: false);

            it.Invoke(() =>
                    {
                        Assert.AreNotEqual(tid, Thread.CurrentThread.ManagedThreadId);
                        are.Set();
                    });

            var sw = Stopwatch.StartNew();
            
            are.WaitOne();

            sw.Stop();

            Assert.IsTrue(sw.Elapsed.TotalMilliseconds >= min.TotalMilliseconds);
        }
        public void MultipleRequestsForInvocationDelayActualInvocationUntilMaxTimespanElapsed()
        {
            var min = TimeSpan.FromMilliseconds(100);
            var max = TimeSpan.FromMilliseconds(500);

            var it = new InvocationThrottle(min, max);
            var tid = Thread.CurrentThread.ManagedThreadId;

            var are = new AutoResetEvent(initialState: false);

            var t = new Task(() =>
            {
                bool keep_going = true;

                while(keep_going)
                {
                    it.Invoke(() =>
                    {
                        Assert.AreNotEqual(tid, Thread.CurrentThread.ManagedThreadId);
                        are.Set();
                        keep_going = false;
                    });
                }
            });

            var sw = Stopwatch.StartNew();

            t.Start();

            are.WaitOne();

            sw.Stop();

            Trace.WriteLine(sw.Elapsed.TotalMilliseconds + " , " + max.TotalMilliseconds);

            Assert.IsTrue(sw.Elapsed.TotalMilliseconds >= max.TotalMilliseconds);
        }