public void TestGetUnfinishedLeafTasks_differentUpdateOrder()
        {
            AllocationCompletionTracker tracker = new AllocationCompletionTracker();

            tracker.UpdateProgress(root, 0);
            Assert.AreEqual(new [] { "root" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child2, 0);
            Assert.AreEqual(new [] { "child2" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child1, 0);
            Assert.AreEqual(new [] { "child2", "child1" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child1Child, 0);
            Assert.AreEqual(new [] { "child2", "child1Child" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child1Child, 50);
            Assert.AreEqual(new [] { "child2", "child1Child" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child2, 100);
            Assert.AreEqual(new [] { "child2", "child1Child" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child1Child, 50);
            Assert.AreEqual(new [] { "child2" }, tracker.GetUnfinishedLeafTasks());

            tracker.UpdateProgress(child2, 100);
            Assert.AreEqual(new List <string>(), tracker.GetUnfinishedLeafTasks());
        }
        public void TestGetUnfinishedAllocations_singleThread()
        {
            AllocationCompletionTracker allocationCompletionTracker = new AllocationCompletionTracker();

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(root, 0L));
            Assert.AreEqual(
                new List <Allocation> {
                root
            },
                allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(child1, 0L));
            Assert.AreEqual(
                new [] { root, child1 },
                allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(child1Child, 0L));
            Assert.AreEqual(
                new [] { root, child1, child1Child },
                allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(child1Child, 50L));
            Assert.AreEqual(
                new [] { root, child1, child1Child },
                allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(child1Child, 50L));
            Assert.AreEqual(
                new List <Allocation> {
                root
            },
                allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(child2, 100L));
            Assert.AreEqual(
                new [] { root, child2 },
                allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsTrue(allocationCompletionTracker.UpdateProgress(child2, 100L));
            Assert.AreEqual(
                new List <Allocation>(), allocationCompletionTracker.GetUnfinishedAllocations());

            Assert.IsFalse(allocationCompletionTracker.UpdateProgress(child2, 0L));
            Assert.AreEqual(
                new List <Allocation>(), allocationCompletionTracker.GetUnfinishedAllocations());

            try
            {
                allocationCompletionTracker.UpdateProgress(child1, 1L);
                Assert.Fail();
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual("Progress exceeds max for 'child1': 1 more beyond 1", ex.Message);
            }
        }
        public async Task TestGetUnfinishedAllocations_multipleThreadsAsync()
        {
            AllocationCompletionTracker allocationCompletionTracker = new AllocationCompletionTracker();

            // Adds root, child1, and child1Child.
            Assert.AreEqual(
                true,
                await MultithreadedExecutor.InvokeAsync(
                    () => allocationCompletionTracker.UpdateProgress(root, 0L)).ConfigureAwait(false));
            Assert.AreEqual(
                true,
                await MultithreadedExecutor.InvokeAsync(
                    () => allocationCompletionTracker.UpdateProgress(child1, 0L)).ConfigureAwait(false));
            Assert.AreEqual(
                true,
                await MultithreadedExecutor.InvokeAsync(
                    () => allocationCompletionTracker.UpdateProgress(child1Child, 0L)).ConfigureAwait(false));
            Assert.AreEqual(
                new [] { root, child1, child1Child },
                allocationCompletionTracker.GetUnfinishedAllocations());

            // Adds 50 to child1Child and 100 to child2.
            List <Func <bool> > callables = new List <Func <bool> >(150);

            callables.AddRange(
                Enumerable.Repeat((Func <bool>)(() => allocationCompletionTracker.UpdateProgress(child1Child, 1L)), 50));
            callables.AddRange(
                Enumerable.Repeat((Func <bool>)(() => allocationCompletionTracker.UpdateProgress(child2, 1L)), 100));

            CollectionAssert.AreEqual(
                Enumerable.Repeat(true, 150), await MultithreadedExecutor.InvokeAllAsync(callables).ConfigureAwait(false));
            Assert.AreEqual(
                new[]
            {
                root,
                child1,
                child1Child,
                child2
            },
                allocationCompletionTracker.GetUnfinishedAllocations());

            // 0 progress doesn't do anything.
            Assert.AreEqual(
                Enumerable.Repeat(false, 100),
                await MultithreadedExecutor.InvokeAllAsync(
                    Enumerable.Repeat((Func <bool>)(() => allocationCompletionTracker.UpdateProgress(child1, 0L)), 100)).ConfigureAwait(false));
            Assert.AreEqual(
                new[]
            {
                root,
                child1,
                child1Child,
                child2
            },
                allocationCompletionTracker.GetUnfinishedAllocations());

            // Adds 50 to child1Child and 100 to child2 to finish it up.
            CollectionAssert.AreEqual(
                Enumerable.Repeat(true, 150), await MultithreadedExecutor.InvokeAllAsync(callables).ConfigureAwait(false));
            CollectionAssert.AreEqual(
                new List <Allocation>(), allocationCompletionTracker.GetUnfinishedAllocations());
        }