File: ShellShimTests\WindowsEnvironmentPathTests.cs
Web Access
Project: ..\..\..\test\dotnet.Tests\dotnet.Tests.csproj (dotnet.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Cli.ShellShim;
using Microsoft.DotNet.Cli.Utils;
 
namespace Microsoft.DotNet.ShellShim.Tests
{
    public class WindowsEnvironmentPathTests
    {
        public WindowsEnvironmentPathTests()
        {
            _reporter = new BufferedReporter();
            _mockPathInternal = new MockPathInternal();
            var mockEnvironmentProvider = new MockEnvironmentProvider(_mockPathInternal);
            var mockEnvironmentPathEditor = new MockEnvironmentPathEditor(_mockPathInternal);
            _windowsEnvironmentPath = new WindowsEnvironmentPath(
                _toolsPath,
                @"%USERPROFILE%\.dotnet\tools",
                mockEnvironmentProvider,
                mockEnvironmentPathEditor,
                _reporter
            );
        }
 
        private readonly BufferedReporter _reporter;
        private readonly WindowsEnvironmentPath _windowsEnvironmentPath;
        private readonly MockPathInternal _mockPathInternal;
        private const string _toolsPath = @"C:\Users\username\.dotnet\tools";
 
        [Fact]
        public void GivenPathIsNullItItAddsToEnvironment()
        {
            _mockPathInternal.UserLevelPath = null;
 
            _windowsEnvironmentPath.AddPackageExecutablePathToUserPath();
 
            _reporter.Lines.Should().BeEmpty();
            _mockPathInternal.UserLevelPath.Should().Be(@"%USERPROFILE%\.dotnet\tools");
        }
 
        [Fact]
        public void GivenPathNotSetInProcessItPrintsReopenNoticeAndNoChangeInEnvironment()
        {
            _mockPathInternal.UserLevelPath = @"%USERPROFILE%\.dotnet\tools";
 
            _windowsEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist();
 
            _reporter.Lines.Should().Equal(CliStrings.EnvironmentPathWindowsNeedReopen);
        }
 
        [Fact]
        public void GivenPathNotSetInProcessWhenAddPackageExecutablePathToUserPathItPrintsReopenNoticeAndNoChangeInEnvironment()
        {
            _mockPathInternal.UserLevelPath = @"%USERPROFILE%\Other;%USERPROFILE%\.dotnet\tools";
 
            _windowsEnvironmentPath.AddPackageExecutablePathToUserPath();
 
            _reporter.Lines.Should().BeEmpty("No message since this happens in first run experience");
            _mockPathInternal.UserLevelPath.Should()
                .Be(@"%USERPROFILE%\Other;%USERPROFILE%\.dotnet\tools", "no change");
        }
 
        [Fact]
        public void GivenPathNotSetItAddsToEnvironment()
        {
            _mockPathInternal.UserLevelPath = @"%USERPROFILE%\Other";
 
            _windowsEnvironmentPath.AddPackageExecutablePathToUserPath();
 
            _reporter.Lines.Should().BeEmpty();
            _mockPathInternal.UserLevelPath.Should().Be(@"%USERPROFILE%\Other;%USERPROFILE%\.dotnet\tools");
        }
 
        [Fact]
        public void GivenPathNotSetItPrintsManualInstructions()
        {
            _mockPathInternal.UserLevelPath = @"%USERPROFILE%\Other";
            _windowsEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist();
 
            _reporter.Lines.Should().Equal(
                string.Format(
                    CliStrings.EnvironmentPathWindowsManualInstructions,
                    _toolsPath));
        }
 
        [Fact]
        public void GivenPathSetInProcessAndEnvironmentItPrintsNothingAndNoChangeInEnvironment()
        {
            var pathWithToolPath = @"%USERPROFILE%\Other;%USERPROFILE%\.dotnet\tools";
            _mockPathInternal.UserLevelPath = pathWithToolPath;
            _mockPathInternal.ProcessLevelPath = pathWithToolPath;
 
            _windowsEnvironmentPath.PrintAddPathInstructionIfPathDoesNotExist();
 
            _reporter.Lines.Should().BeEmpty();
        }
 
        [Fact]
        public void GivenPathSetItDoesNotAddPathToEnvironment()
        {
            var pathWithToolPath = @"%USERPROFILE%\Other;%USERPROFILE%\.dotnet\tools";
            _mockPathInternal.UserLevelPath = pathWithToolPath;
            _mockPathInternal.ProcessLevelPath = pathWithToolPath;
 
            _windowsEnvironmentPath.AddPackageExecutablePathToUserPath();
 
            _reporter.Lines.Should().BeEmpty();
            _mockPathInternal.UserLevelPath.Should().Be(pathWithToolPath, "no change");
        }
 
        private class MockPathInternal
        {
            public string MachineLevelPath { get; set; }
            public string UserLevelPath { get; set; }
            public string ProcessLevelPath { get; set; }
        }
 
        private class MockEnvironmentProvider : IEnvironmentProvider
        {
            private readonly MockPathInternal _mockPathInternal;
 
            public MockEnvironmentProvider(MockPathInternal mockPathInternal)
            {
                _mockPathInternal = mockPathInternal ?? throw new ArgumentNullException(nameof(mockPathInternal));
            }
 
            public IEnumerable<string> ExecutableExtensions { get; }
 
            public string GetCommandPath(string commandName, params string[] extensions)
            {
                throw new NotImplementedException();
            }
 
            public string GetCommandPathFromRootPath(string rootPath, string commandName, params string[] extensions)
            {
                throw new NotImplementedException();
            }
 
            public string GetCommandPathFromRootPath(string rootPath, string commandName,
                IEnumerable<string> extensions)
            {
                throw new NotImplementedException();
            }
 
            public bool GetEnvironmentVariableAsBool(string name, bool defaultValue)
            {
                throw new NotImplementedException();
            }
 
            public string GetEnvironmentVariable(string name)
            {
                throw new NotImplementedException();
            }
 
            public string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
            {
                if (variable != "PATH")
                {
                    throw new ArgumentException("should only read PATH");
                }
 
                switch (target)
                {
                    case EnvironmentVariableTarget.Process:
                        return Expand(_mockPathInternal.ProcessLevelPath);
                    case EnvironmentVariableTarget.User:
                        return Expand(_mockPathInternal.UserLevelPath);
                    case EnvironmentVariableTarget.Machine:
                        return Expand(_mockPathInternal.MachineLevelPath);
                    default:
                        throw new ArgumentOutOfRangeException(nameof(target), target, null);
                }
            }
 
            public void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target)
            {
                throw new NotImplementedException();
            }
 
            public int? GetEnvironmentVariableAsNullableInt(string variable)
            {
                throw new NotImplementedException();
            }
 
            private static string Expand(string path)
            {
                return path?.Replace("%USERPROFILE%", @"C:\Users\username");
            }
        }
 
        private class MockEnvironmentPathEditor : IWindowsRegistryEnvironmentPathEditor
        {
            private readonly MockPathInternal _mockPathInternal;
 
            public MockEnvironmentPathEditor(MockPathInternal mockPathInternal)
            {
                _mockPathInternal = mockPathInternal;
            }
 
            public string Get(SdkEnvironmentVariableTarget sdkEnvironmentVariableTarget)
            {
                switch (sdkEnvironmentVariableTarget)
                {
                    case SdkEnvironmentVariableTarget.DotDefault:
                        return "";
                    case SdkEnvironmentVariableTarget.CurrentUser:
                        return _mockPathInternal.UserLevelPath;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(sdkEnvironmentVariableTarget),
                            sdkEnvironmentVariableTarget, null);
                }
            }
 
            public void Set(string value, SdkEnvironmentVariableTarget sdkEnvironmentVariableTarget)
            {
                switch (sdkEnvironmentVariableTarget)
                {
                    case SdkEnvironmentVariableTarget.DotDefault:
                        throw new InvalidOperationException("Should never touch DotDefault's EnvironmentVariable.");
                    case SdkEnvironmentVariableTarget.CurrentUser:
                        _mockPathInternal.UserLevelPath = value;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(sdkEnvironmentVariableTarget),
                            sdkEnvironmentVariableTarget, null);
                }
            }
        }
    }
}