File: xunit\ConditionalTheoryDiscoverer.cs
Web Access
Project: ..\..\..\src\aspnetcore\src\Testing\src\Microsoft.AspNetCore.InternalTesting.csproj (Microsoft.AspNetCore.InternalTesting)
// 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.Linq;
using Xunit.Abstractions;
using Xunit.Sdk;
 
// Do not change this namespace without changing the usage in ConditionalTheoryAttribute
namespace Microsoft.AspNetCore.InternalTesting;
 
internal sealed class ConditionalTheoryDiscoverer : TheoryDiscoverer
{
    public ConditionalTheoryDiscoverer(IMessageSink diagnosticMessageSink)
        : base(diagnosticMessageSink)
    {
    }
 
    private sealed class OptionsWithPreEnumerationEnabled : ITestFrameworkDiscoveryOptions
    {
        private const string PreEnumerateTheories = "xunit.discovery.PreEnumerateTheories";
 
        private readonly ITestFrameworkDiscoveryOptions _original;
 
        public OptionsWithPreEnumerationEnabled(ITestFrameworkDiscoveryOptions original)
            => _original = original;
 
        public TValue GetValue<TValue>(string name)
            => (name == PreEnumerateTheories) ? (TValue)(object)true : _original.GetValue<TValue>(name);
 
        public void SetValue<TValue>(string name, TValue value)
            => _original.SetValue(name, value);
    }
 
    public override IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
        => base.Discover(new OptionsWithPreEnumerationEnabled(discoveryOptions), testMethod, theoryAttribute);
 
    protected override IEnumerable<IXunitTestCase> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
    {
        var skipReason = testMethod.EvaluateSkipConditions();
        return skipReason != null
           ? new[] { new SkippedTestCase(skipReason, DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) }
           : base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute);
    }
 
    protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
    {
        QuarantinedTestData quarantinedTestData = null;
        if (dataRow?.FirstOrDefault() is QuarantinedTestData quarantine)
        {
            quarantinedTestData = quarantine;
            dataRow = dataRow.Skip(1).ToArray();
        }
 
        var skipReason = testMethod.EvaluateSkipConditions();
        if (skipReason == null && dataRow?.Length > 0)
        {
            var obj = dataRow[0];
            if (obj != null)
            {
                var type = obj.GetType();
                var property = type.GetProperty("Skip");
                if (property != null && property.PropertyType.Equals(typeof(string)))
                {
                    skipReason = property.GetValue(obj) as string;
                }
            }
        }
 
        var testCases = (skipReason != null ?
            base.CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, skipReason)
            : base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow)).ToArray();
 
        if (quarantinedTestData is not null)
        {
            foreach (var testCase in testCases)
            {
                AddQuarantinedTrait(testCase.Traits, quarantinedTestData.Attribute);
            }
        }
 
        return testCases;
    }
 
    internal static void AddQuarantinedTrait(IDictionary<string, List<string>> traits, QuarantinedTestAttribute attribute)
    {
        if (!QuarantinedTestTraitDiscoverer.IsQuarantined(attribute))
        {
            return;
        }
 
        if (!traits.TryGetValue("Quarantined", out var values))
        {
            values = new List<string>();
            traits.Add("Quarantined", values);
        }
 
        values.Add("true");
    }
 
    protected override IEnumerable<IXunitTestCase> CreateTestCasesForSkippedDataRow(
        ITestFrameworkDiscoveryOptions discoveryOptions,
        ITestMethod testMethod,
        IAttributeInfo theoryAttribute,
        object[] dataRow,
        string skipReason)
    {
        return new[]
        {
                new WORKAROUND_SkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow),
            };
    }
 
    [Obsolete]
    protected override IXunitTestCase CreateTestCaseForSkippedDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow, string skipReason)
    {
        return new WORKAROUND_SkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow);
    }
}