public async Task DecrementMultiCancel()
        {               //****************************************
            var MyCounter = new AsyncCounter();

            //****************************************

            using (var MySource = new CancellationTokenSource())
            {
                var MyTask1 = MyCounter.Decrement(MySource.Token);
                var MyTask2 = MyCounter.Decrement();

                Assert.IsFalse(MyTask1.IsCompleted, "Decremented too early");
                Assert.IsFalse(MyTask2.IsCompleted, "Decremented too early");

                MySource.Cancel();

                Assert.IsTrue(MyTask1.IsCanceled, "Wait not cancelled");
                Assert.IsFalse(MyTask2.IsCanceled, "Wait cancelled");

                MyCounter.Increment();

                await MyTask2;
            }

            //****************************************

            Assert.AreEqual(0, MyCounter.CurrentCount, "Counter not decremented");
            Assert.AreEqual(0, MyCounter.WaitingCount, "Tasks unexpectedly waiting");
        }
        public void DecrementCancel()
        {               //****************************************
            var       MyCounter = new AsyncCounter();
            ValueTask MyTask;

            //****************************************

            using (var MySource = new CancellationTokenSource())
            {
                MyTask = MyCounter.Decrement(MySource.Token);

                Assert.IsFalse(MyTask.IsCompleted, "Decremented too early");

                MySource.Cancel();

                Assert.IsTrue(MyTask.IsCanceled, "Wait not cancelled");
            }

            // Since there are no waiters that aren't cancelled, this should succeed immediately
            MyCounter.Increment();

            //****************************************

            Assert.AreEqual(1, MyCounter.CurrentCount, "Counter still decremented");
            Assert.AreEqual(0, MyCounter.WaitingCount, "Tasks unexpectedly waiting");
        }
        public void DecrementInitial()
        {               //****************************************
            var MyCounter = new AsyncCounter(1);
            //****************************************

            var MyTask = MyCounter.Decrement();

            //****************************************

            Assert.IsTrue(MyTask.IsCompleted, "Still waiting to decrement");

            Assert.AreEqual(0, MyCounter.CurrentCount, "Counter not decremented");
            Assert.AreEqual(0, MyCounter.WaitingCount, "Tasks unexpectedly waiting");
        }
        public void DisposeDecrement()
        {               //****************************************
            var MyLock = new AsyncCounter();

            //****************************************

            MyLock.DisposeAsync();

            Assert.ThrowsAsync <ObjectDisposedException>(() => MyLock.Decrement().AsTask());

            //****************************************

            Assert.AreEqual(0, MyLock.WaitingCount, "Waiter still registered");
            Assert.AreEqual(0, MyLock.CurrentCount, "Count not zero");
        }
        public async Task StackBlow()
        {               //****************************************
            var  MyLock = new AsyncCounter();
            Task ResultTask;

            Task[] Results;
            //****************************************

            Results = Enumerable.Range(1, 40000).Select(
                async count =>
            {
                await MyLock.Decrement();

                MyLock.Increment();
            }).ToArray();

            ResultTask = Results[^ 1].ContinueWith(task => System.Diagnostics.Debug.WriteLine("Done to " + new System.Diagnostics.StackTrace(false).FrameCount.ToString()), TaskContinuationOptions.ExecuteSynchronously);
        public void DecrementTimeoutNone()
        {               //****************************************
            var MyCounter = new AsyncCounter();

            //****************************************

            MyCounter.Increment();

            var MyTask = MyCounter.Decrement(TimeSpan.FromMilliseconds(50));

            //****************************************

            Assert.IsTrue(MyTask.IsCompleted, "Still waiting to decrement");

            Assert.AreEqual(0, MyCounter.WaitingCount, "Waiter still registered");
            Assert.AreEqual(0, MyCounter.CurrentCount, "Count not zero");
        }
        public async Task DecrementTimeoutDelayed()
        {               //****************************************
            var MyCounter = new AsyncCounter();
            //****************************************

            var MyTask = MyCounter.Decrement(TimeSpan.FromMilliseconds(50));

            MyCounter.Increment();

            //****************************************

            await MyTask;

            //****************************************

            Assert.AreEqual(0, MyCounter.WaitingCount, "Waiter still registered");
            Assert.AreEqual(0, MyCounter.CurrentCount, "Count not zero");
        }
        public async Task DecrementAdd()
        {         //****************************************
            var MyCounter = new AsyncCounter();
            //****************************************

            var MyTask = MyCounter.Decrement();

            Assert.IsFalse(MyTask.IsCompleted, "Decremented too early");

            MyCounter.Add(10);

            //****************************************

            await MyTask;

            Assert.AreEqual(9, MyCounter.CurrentCount, "Counter not decremented");
            Assert.AreEqual(0, MyCounter.WaitingCount, "Tasks unexpectedly waiting");
        }
        public async Task DecrementTimeout()
        {               //****************************************
            var MyCounter = new AsyncCounter();

            //****************************************

            try
            {
                await MyCounter.Decrement(TimeSpan.FromMilliseconds(10));

                Assert.Fail("Task did not cancel");
            }
            catch (TimeoutException)
            {
            }

            //****************************************

            //MyCounter.Dispose();

            //Assert.AreEqual(0, MyCounter.WaitingCount, "Waiter still registered");
            Assert.AreEqual(0, MyCounter.CurrentCount, "Count not zero");
        }
        public async Task DecrementDispose()
        {               //****************************************
            var MyLock = new AsyncCounter();
            //****************************************

            var MyTask = MyLock.Decrement();

            _ = MyLock.DisposeAsync();

            try
            {
                await MyTask;

                Assert.Fail("Should never reach this point");
            }
            catch (ObjectDisposedException)
            {
            }

            //****************************************

            Assert.AreEqual(0, MyLock.WaitingCount, "Waiter still registered");
            Assert.AreEqual(0, MyLock.CurrentCount, "Count not zero");
        }