public void SkipsInstallation()
        {
            // Setup
            _fileSystemMock
            .Setup(x => x.DirectoryExists(It.IsAny <string>()))
            .Returns(true);

            var collection = CreateMockServiceCollection();

            _task.ConfigureServices(collection);

            // Act
            using var provider = collection.BuildServiceProvider();
            _task.InvokeExecute(provider).Should().BeTrue();

            // Verify
            _commandFactoryMock
            .Verify(
                x => x.Create(
                    It.Is <string>(dotnet => dotnet == _dotnetPath),
                    It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))),
                Times.Never);

            _commandMock.Verify(x => x.Execute(), Times.Never);
        }
        public async Task InstallsInParallelWithRealMutex()
        {
            // Setup
            var fileSystemMock1 = new Mock <IFileSystem>();

            fileSystemMock1
            .Setup(x => x.DirectoryExists(It.IsAny <string>()))
            .Returns(false);

            var fileSystemMock2 = new Mock <IFileSystem>();

            fileSystemMock2
            .Setup(x => x.DirectoryExists(It.IsAny <string>()))
            .Returns(true);

            var helpers = new Helpers();
            var hangingCommandCalled = new TaskCompletionSource <bool>();
            var dotnetToolInstalled  = new TaskCompletionSource <bool>();

            var hangingCommand = new Mock <ICommand>();

            hangingCommand
            .Setup(x => x.Execute())
            .Callback(() =>
            {
                hangingCommandCalled.SetResult(true);
                dotnetToolInstalled.Task.GetAwaiter().GetResult();
            })
            .Returns(new CommandResult(new ProcessStartInfo(), 0, "Tool installed", null));

            var hangingCommandFactoryMock = new Mock <ICommandFactory>();

            hangingCommandFactoryMock
            .Setup(x => x.Create(
                       It.Is <string>(s => s == _dotnetPath),
                       It.Is <IEnumerable <string> >(args => args.All(y => _expectedArgs.Contains(y)))))
            .Returns(hangingCommand.Object)
            .Verifiable();

            var collection1 = new ServiceCollection();

            collection1.AddSingleton(hangingCommandFactoryMock.Object);
            collection1.AddSingleton(fileSystemMock1.Object);
            collection1.AddTransient <IHelpers, Helpers>();

            var collection2 = new ServiceCollection();

            collection2.AddSingleton(_commandFactoryMock.Object);
            collection2.AddSingleton(fileSystemMock2.Object);
            collection2.AddTransient <IHelpers, Helpers>();

            var task1 = new InstallDotNetTool()
            {
                DestinationPath = InstallPath,
                Name            = ToolName,
                Version         = ToolVersion,
                BuildEngine     = new MockBuildEngine(),
            };

            var task2 = new InstallDotNetTool()
            {
                DestinationPath = InstallPath,
                Name            = ToolName,
                Version         = ToolVersion,
                BuildEngine     = new MockBuildEngine(),
            };

            // Act
            using var provider1 = collection1.BuildServiceProvider();
            using var provider2 = collection2.BuildServiceProvider();

            var installationTask = Task.Run(() => task1.InvokeExecute(provider1).Should().BeTrue());

            // Let's wait for the first `dotnet tool install` to be called (it will stay spinning)
            await hangingCommandCalled.Task;

            var skipTask = Task.Run(() => task2.InvokeExecute(provider2).Should().BeTrue());

            // The first command must have been executed, let's verify the parameters
            hangingCommandFactoryMock
            .Verify(
                x => x.Create(
                    It.Is <string>(dotnet => dotnet == _dotnetPath),
                    It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))),
                Times.Once);

            // The other command is waiting on the Mutex now
            skipTask.IsCompleted.Should().BeFalse();

            _commandFactoryMock
            .Verify(
                x => x.Create(
                    It.Is <string>(dotnet => dotnet == _dotnetPath),
                    It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))),
                Times.Never);

            // We now let `dotnet tool install` run to completion
            dotnetToolInstalled.SetResult(true);

            // Let's give the installation task time to evaluate the command result
            // Let's give the skip task get its own Mutex and verify existence of the installation
            await Task.WhenAll(installationTask, skipTask);

            // Verify
            _commandFactoryMock
            .Verify(
                x => x.Create(
                    It.Is <string>(dotnet => dotnet == _dotnetPath),
                    It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))),
                Times.Never);

            task1.ToolPath.Should().Be(task2.ToolPath);
            task1.ToolPath.Should().Be(s_installedPath);
        }