// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;
using Xunit;

namespace Microsoft.AspNetCore.Testing
{
    public class EnvironmentVariableSkipConditionTest
    {
        private readonly string _skipReason = "Test skipped on environment variable with name '{0}' and value '{1}'" +
            $" for the '{nameof(EnvironmentVariableSkipConditionAttribute.RunOnMatch)}' value of '{{2}}'.";

        [Theory]
        [InlineData("false")]
        [InlineData("")]
        [InlineData(null)]
        public void IsMet_DoesNotMatch(string environmentVariableValue)
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("Run", environmentVariableValue),
                "Run",
                "true");

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.False(isMet);
        }

        [Theory]
        [InlineData("True")]
        [InlineData("TRUE")]
        [InlineData("true")]
        public void IsMet_DoesCaseInsensitiveMatch_OnValue(string environmentVariableValue)
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("Run", environmentVariableValue),
                "Run",
                "true");

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.True(isMet);
            Assert.Equal(
                string.Format(CultureInfo.InvariantCulture, _skipReason, "Run", environmentVariableValue, attribute.RunOnMatch),
                attribute.SkipReason);
        }

        [Fact]
        public void IsMet_DoesSuccessfulMatch_OnNull()
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("Run", null),
                "Run",
                "true", null); // skip the test when the variable 'Run' is explicitly set to 'true' or is null (default)

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.True(isMet);
            Assert.Equal(
                string.Format(CultureInfo.InvariantCulture, _skipReason, "Run", "(null)", attribute.RunOnMatch),
                attribute.SkipReason);
        }

        [Theory]
        [InlineData("false")]
        [InlineData("")]
        [InlineData(null)]
        public void IsMet_MatchesOnMultipleSkipValues(string environmentVariableValue)
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("Run", environmentVariableValue),
                "Run",
                "false", "", null);

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.True(isMet);
        }

        [Fact]
        public void IsMet_DoesNotMatch_OnMultipleSkipValues()
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("Build", "100"),
                "Build",
                "125", "126");

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.False(isMet);
        }

        [Theory]
        [InlineData("CentOS")]
        [InlineData(null)]
        [InlineData("")]
        public void IsMet_Matches_WhenRunOnMatchIsFalse(string environmentVariableValue)
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("LinuxFlavor", environmentVariableValue),
                "LinuxFlavor",
                "Ubuntu14.04")
            {
                // Example: Run this test on all OSes except on "Ubuntu14.04"
                RunOnMatch = false
            };

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.True(isMet);
        }

        [Fact]
        public void IsMet_DoesNotMatch_WhenRunOnMatchIsFalse()
        {
            // Arrange
            var attribute = new EnvironmentVariableSkipConditionAttribute(
                new TestEnvironmentVariable("LinuxFlavor", "Ubuntu14.04"),
                "LinuxFlavor",
                "Ubuntu14.04")
            {
                // Example: Run this test on all OSes except on "Ubuntu14.04"
                RunOnMatch = false
            };

            // Act
            var isMet = attribute.IsMet;

            // Assert
            Assert.False(isMet);
        }

        private struct TestEnvironmentVariable : IEnvironmentVariable
        {
            private readonly string _varName;

            public TestEnvironmentVariable(string varName, string value)
            {
                _varName = varName;
                Value = value;
            }

            public string Value { get; private set; }

            public string Get(string name)
            {
                if(string.Equals(name, _varName, System.StringComparison.OrdinalIgnoreCase))
                {
                    return Value;
                }
                return string.Empty;
            }
        }
    }
}
