File: DiscovererHelpers.cs
Web Access
Project: src\src\Microsoft.DotNet.XUnitExtensions\src\Microsoft.DotNet.XUnitExtensions.csproj (Microsoft.DotNet.XUnitExtensions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Xunit;
 
namespace Microsoft.DotNet.XUnitExtensions
{
    internal static class DiscovererHelpers
    {
        private static readonly Lazy<bool> s_isMonoRuntime = new Lazy<bool>(() => Type.GetType("Mono.RuntimeStructs") != null);
        public static bool IsMonoRuntime => s_isMonoRuntime.Value;
        public static bool IsRunningOnNetCoreApp { get; } = (Environment.Version.Major >= 5 || !RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase));
        public static bool IsRunningOnNetFramework { get; } = RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase);
 
        public static bool TestPlatformApplies(TestPlatforms platforms) =>
                (platforms.HasFlag(TestPlatforms.Any)) ||
                (platforms.HasFlag(TestPlatforms.FreeBSD) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"))) ||
                (platforms.HasFlag(TestPlatforms.Linux) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) ||
                (platforms.HasFlag(TestPlatforms.NetBSD) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"))) ||
                (platforms.HasFlag(TestPlatforms.OSX) && RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) ||
                (platforms.HasFlag(TestPlatforms.illumos) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("ILLUMOS"))) ||
                (platforms.HasFlag(TestPlatforms.Solaris) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("SOLARIS"))) ||
                (platforms.HasFlag(TestPlatforms.iOS) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")) && !RuntimeInformation.IsOSPlatform(OSPlatform.Create("MACCATALYST"))) ||
                (platforms.HasFlag(TestPlatforms.tvOS) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS"))) ||
                (platforms.HasFlag(TestPlatforms.MacCatalyst) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("MACCATALYST"))) ||
                (platforms.HasFlag(TestPlatforms.LinuxBionic) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ANDROID_STORAGE"))) ||
                (platforms.HasFlag(TestPlatforms.Android) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"))) ||
                (platforms.HasFlag(TestPlatforms.Browser) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"))) ||
                (platforms.HasFlag(TestPlatforms.Wasi) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("WASI"))) ||
                (platforms.HasFlag(TestPlatforms.Haiku) && RuntimeInformation.IsOSPlatform(OSPlatform.Create("HAIKU"))) ||
                (platforms.HasFlag(TestPlatforms.Windows) && RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
 
        public static bool TestRuntimeApplies(TestRuntimes runtimes) =>
                (runtimes.HasFlag(TestRuntimes.Mono) && IsMonoRuntime) ||
                (runtimes.HasFlag(TestRuntimes.CoreCLR) && !IsMonoRuntime); // assume CoreCLR if it's not Mono
 
        public static bool TestFrameworkApplies(TargetFrameworkMonikers frameworks) =>
                (frameworks.HasFlag(TargetFrameworkMonikers.Netcoreapp) && IsRunningOnNetCoreApp) ||
                (frameworks.HasFlag(TargetFrameworkMonikers.NetFramework) && IsRunningOnNetFramework);
 
        internal static bool Evaluate(Type calleeType, string[] conditionMemberNames)
        {
            foreach (string entry in conditionMemberNames)
            {
                // Null condition member names are silently tolerated.
                if (string.IsNullOrWhiteSpace(entry)) continue;
 
                Func<bool> conditionFunc = ConditionalTestDiscoverer.LookupConditionalMember(calleeType, entry);
                if (conditionFunc == null)
                {
                    throw new InvalidOperationException($"Unable to get member, please check input for {entry}.");
                }
 
                if (!conditionFunc()) return false;
            }
 
            return true;
        }
 
        internal static IEnumerable<KeyValuePair<string, string>> EvaluateArguments(IEnumerable<object> ctorArgs,string category, int skipFirst=1)
        {
            Debug.Assert(ctorArgs.Count() >= 2);
 
            TestPlatforms platforms = TestPlatforms.Any;
            TargetFrameworkMonikers frameworks = TargetFrameworkMonikers.Any;
            TestRuntimes runtimes = TestRuntimes.Any;
            Type calleeType = null;
            string[] conditionMemberNames = null;
 
            foreach (object arg in ctorArgs.Skip(skipFirst)) // First argument is the issue number or reason.
            {
                if (arg is TestPlatforms)
                {
                    platforms = (TestPlatforms)arg;
                }
                else if (arg is TargetFrameworkMonikers)
                {
                    frameworks = (TargetFrameworkMonikers)arg;
                }
                else if (arg is TestRuntimes)
                {
                    runtimes = (TestRuntimes)arg;
                }
                else if (arg is Type)
                {
                    calleeType = (Type)arg;
                }
                else if (arg is string[])
                {
                    conditionMemberNames = (string[])arg;
                }
            }
 
            if (calleeType != null && conditionMemberNames != null)
            {
                if (DiscovererHelpers.Evaluate(calleeType, conditionMemberNames))
                {
                    yield return new KeyValuePair<string, string>(XunitConstants.Category, category);
                }
            }
            else if (DiscovererHelpers.TestPlatformApplies(platforms) &&
                DiscovererHelpers.TestRuntimeApplies(runtimes) &&
                DiscovererHelpers.TestFrameworkApplies(frameworks))
            {
                yield return new KeyValuePair<string, string>(XunitConstants.Category, category);
            }
        }
 
        internal static string AppendAdditionalMessage(this string message, string additionalMessage)
            => !string.IsNullOrWhiteSpace(additionalMessage) ? $"{message} {additionalMessage}" : message;
    }
}