File: xunit\ConditionAttribute.cs
Web Access
Project: src\src\System.Private.ServiceModel\tests\Common\Infrastructure\Infrastructure.Common.csproj (Infrastructure.Common)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit.Abstractions;
 
namespace Infrastructure.Common
{
    // The [Condition] attribute can be applied to any test method that
    // is marked with [WcfFact] or [WcfTheory].  It provides zero or more
    // member names to be evaluated at runtime to determine whether the
    // test should be run or skipped.
    // Examples: 
    //  [Condition(nameof(Root_Certificate_Installed))]
    //  [Condition(nameof(Root_Certificate_Installed), nameof(Client_Certificate_Installed))]
 
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class ConditionAttribute : WcfSkippableAttribute
    {
        public string[] Conditions { get; private set; }
 
        public ConditionAttribute(params string[] conditions)
        {
            Conditions = conditions;
        }
 
        public override string GetSkipReason(ITestMethod testMethod)
        {
            // A null or empty list of conditions is treated as "no conditions",
            // and the test cases will not be skipped.
            // Example: [Condition()] or [Condition((string[]) null)]
            int conditionCount = Conditions == null ? 0 : Conditions.Length;
            if (conditionCount == 0)
            {
                return null;
            }
 
            MethodInfo testMethodInfo = testMethod.Method.ToRuntimeMethod();
            Type testMethodDeclaringType = testMethodInfo.DeclaringType;
 
            List<string> falseConditions = new List<string>(conditionCount);
 
            foreach (string entry in Conditions)
            {
                string conditionMemberName = entry;
 
                // Null condition member names are silently tolerated
                if (string.IsNullOrWhiteSpace(conditionMemberName))
                {
                    continue;
                }
 
                string[] symbols = conditionMemberName.Split('.');
                Type declaringType = testMethodDeclaringType;
 
                if (symbols.Length == 2)
                {
                    conditionMemberName = symbols[1];
                    ITypeInfo type = testMethod.TestClass.Class.Assembly.GetTypes(false).Where(t => t.Name.Contains(symbols[0])).SingleOrDefault();
                    if (type != null)
                    {
                        declaringType = type.ToRuntimeType();
                    }
                }
 
                MethodInfo conditionMethodInfo;
                if ((conditionMethodInfo = LookupConditionalMethod(declaringType, conditionMemberName)) == null)
                {
                    falseConditions.Add(String.Format("Condition \"{0}\" not found in type \"{1}\".",
                                                      conditionMemberName, testMethodDeclaringType.FullName));
                    continue;
                }
 
                // In the case of multiple conditions, collect the results of all
                // of them to produce a summary skip reason.
                try
                {
                    if (!(bool)conditionMethodInfo.Invoke(null, null))
                    {
                        falseConditions.Add(conditionMemberName);
                    }
                }
                catch (Exception exc)
                {
                    falseConditions.Add(String.Format("Condition \"{0}\" threw exception {1}: \"{2}\".",
                                                      conditionMemberName, 
                                                      exc.GetType().Name,
                                                      exc.Message));
                }
            }
 
            if (falseConditions.Count == 0)
            {
                return null;
            }
 
            return String.Format("{0}", String.Join(", ", falseConditions));
        }
 
 
        internal static MethodInfo LookupConditionalMethod(Type t, string name)
        {
            if (t == null || name == null)
                return null;
 
            TypeInfo ti = t.GetTypeInfo();
 
            MethodInfo mi = ti.GetDeclaredMethod(name);
            if (mi != null && mi.IsStatic && mi.GetParameters().Length == 0 && mi.ReturnType == typeof(bool))
                return mi;
 
            PropertyInfo pi = ti.GetDeclaredProperty(name);
            if (pi != null && pi.PropertyType == typeof(bool) && pi.GetMethod != null && pi.GetMethod.IsStatic && pi.GetMethod.GetParameters().Length == 0)
                return pi.GetMethod;
 
            return LookupConditionalMethod(ti.BaseType, name);
        }
    }
}