public async Task TestAcceptAsync()
        {
            using (DoubleAccumulator maxProgress = new DoubleAccumulator(0))
                using (ProgressEventHandler progressEventHandler =
                           new ProgressEventHandler(update => maxProgress.Accumulate(update.GetProgress())))
                {
                    EventHandlers eventHandlers =
                        EventHandlers.CreateBuilder().Add <ProgressEvent>(progressEventHandler.Accept).Build();

                    // Adds root, child1, and child1Child.
                    await MultithreadedExecutor.InvokeAsync(() => eventHandlers.Dispatch(new ProgressEvent(root, 0L)))
                    .ConfigureAwait(false);

                    await MultithreadedExecutor.InvokeAsync(() => eventHandlers.Dispatch(new ProgressEvent(child1, 0L)))
                    .ConfigureAwait(false);

                    await MultithreadedExecutor
                    .InvokeAsync(() => eventHandlers.Dispatch(new ProgressEvent(child1Child, 0L)))
                    .ConfigureAwait(false);

                    Assert.AreEqual(0.0, maxProgress.Get(), DOUBLE_ERROR_MARGIN);

                    // Adds 50 to child1Child and 100 to child2.
                    List <Action> callables = new List <Action>(150);
                    callables.AddRange(
                        Enumerable.Repeat((Action)(() => eventHandlers.Dispatch(new ProgressEvent(child1Child, 1L))), 50));
                    callables.AddRange(
                        Enumerable.Repeat((Action)(() => eventHandlers.Dispatch(new ProgressEvent(child2, 1L))), 100));

                    await MultithreadedExecutor.InvokeAllAsync(callables).ConfigureAwait(false);

                    Assert.AreEqual(
                        (1.0 / 2 / 100 * 50) + (1.0 / 2 / 200 * 100), maxProgress.Get(), DOUBLE_ERROR_MARGIN);

                    // 0 progress doesn't do anything.
                    await MultithreadedExecutor
                    .InvokeAllAsync(Enumerable.Repeat((Action)(() =>
                                                               eventHandlers.Dispatch(new ProgressEvent(child1, 0L))), 100))
                    .ConfigureAwait(false);

                    Assert.AreEqual(
                        (1.0 / 2 / 100 * 50) + (1.0 / 2 / 200 * 100), maxProgress.Get(), DOUBLE_ERROR_MARGIN);

                    // Adds 50 to child1Child and 100 to child2 to finish it up.
                    await MultithreadedExecutor.InvokeAllAsync(callables).ConfigureAwait(false);

                    Assert.AreEqual(1.0, maxProgress.Get(), DOUBLE_ERROR_MARGIN);
                }
        }
        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());
        }