Beispiel #1
0
        /// <summary>
        /// Discover test cases from a test method. By default, if the method is generic, or
        /// it contains arguments, returns a single <see cref="ExecutionErrorTestCase"/>;
        /// otherwise, it returns the result of calling <see cref="CreateTestCase"/>.
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="factAttribute">The fact attribute attached to the test method.</param>
        /// <returns>Returns zero or more test cases represented by the test method.</returns>
        public virtual IEnumerable <IXunitTestCase> Discover(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo factAttribute)
        {
            Guard.ArgumentNotNull(nameof(discoveryOptions), discoveryOptions);
            Guard.ArgumentNotNull(nameof(testMethod), testMethod);
            Guard.ArgumentNotNull(nameof(factAttribute), factAttribute);

            IXunitTestCase testCase;

            if (testMethod.Method.GetParameters().Any())
            {
                testCase = ErrorTestCase(discoveryOptions, testMethod, "[Fact] methods are not allowed to have parameters. Did you mean to use [Theory]?");
            }
            else if (testMethod.Method.IsGenericMethodDefinition)
            {
                testCase = ErrorTestCase(discoveryOptions, testMethod, "[Fact] methods are not allowed to be generic.");
            }
            else
            {
                testCase = CreateTestCase(discoveryOptions, testMethod, factAttribute);
            }

            return(new[] { testCase });
        }
Beispiel #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FrontControllerFindSettings"/> class.
 /// </summary>
 /// <param name="options">The discovery options</param>
 /// <param name="filters">The optional filters (when not provided, finds all tests)</param>
 public FrontControllerFindSettings(
     _ITestFrameworkDiscoveryOptions options,
     XunitFilters?filters = null)
 {
     Options = Guard.ArgumentNotNull(options);
     Filters = filters ?? new XunitFilters();
 }
 protected sealed override bool FindTestsForType(
     _ITestClass testClass,
     IMessageBus messageBus,
     _ITestFrameworkDiscoveryOptions discoveryOptions)
 {
     return(FindTestsForClass(testClass));
 }
        /// <summary>
        /// Sets the flags that determine the default display options for test methods.
        /// </summary>
        public static void SetMethodDisplayOptions(
            this _ITestFrameworkDiscoveryOptions discoveryOptions,
            TestMethodDisplayOptions?value)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            discoveryOptions.SetValue(TestOptionsNames.Discovery.MethodDisplayOptions, value.HasValue ? value.GetValueOrDefault().ToString() : null);
        }
        /// <summary>
        /// Sets a flag that determines whether discovered test cases should include source information.
        /// Note that not all runners have access to source information, so this flag does not guarantee
        /// that source information will be provided.
        /// </summary>
        public static void SetIncludeSourceInformation(
            this _ITestFrameworkDiscoveryOptions discoveryOptions,
            bool?value)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            discoveryOptions.SetValue(TestOptionsNames.Discovery.IncludeSourceInformation, value);
        }
Beispiel #6
0
 public FactDiscovererTests()
 {
     aggregator = new ExceptionAggregator();
     cancellationTokenSource = new CancellationTokenSource();
     factAttribute           = Mocks.FactAttribute();
     messageBus = new SpyMessageBus();
     options    = _TestFrameworkOptions.ForDiscovery();
 }
        /// <summary>
        /// Sets a flag that determines whether theories are pre-enumerated. If they enabled, then the
        /// discovery system will return a test case for each row of test data; they are disabled, then the
        /// discovery system will return a single test case for the theory.
        /// </summary>
        public static void SetPreEnumerateTheories(
            this _ITestFrameworkDiscoveryOptions discoveryOptions,
            bool?value)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            discoveryOptions.SetValue(TestOptionsNames.Discovery.PreEnumerateTheories, value);
        }
        /// <summary>
        /// Sets a flag that determines whether internal diagnostic messages will be emitted.
        /// </summary>
        public static void SetInternalDiagnosticMessages(
            this _ITestFrameworkDiscoveryOptions discoveryOptions,
            bool?value)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            discoveryOptions.SetValue(TestOptionsNames.Discovery.InternalDiagnosticMessages, value);
        }
        /// <summary>
        /// Gets a flag that determines the default display name format for test methods.
        /// </summary>
        public static TestMethodDisplay?GetMethodDisplay(this _ITestFrameworkDiscoveryOptions discoveryOptions)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            var methodDisplayString = discoveryOptions.GetValue <string>(TestOptionsNames.Discovery.MethodDisplay);

            return(methodDisplayString != null ? (TestMethodDisplay?)Enum.Parse(typeof(TestMethodDisplay), methodDisplayString) : null);
        }
        /// <summary>
        /// Sets the culture to use for discovering tests. <c>null</c> uses the default OS culture;
        /// <see cref="string.Empty"/> uses the invariant culture; any other value passes the
        /// provided value to <see cref="CultureInfo(string)"/> and uses the resulting object
        /// with <see cref="CultureInfo.DefaultThreadCurrentCulture"/> and
        /// <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>.
        /// </summary>
        public static void SetCulture(
            this _ITestFrameworkDiscoveryOptions discoveryOptions,
            string?culture)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            discoveryOptions.SetValue(TestOptionsNames.Discovery.Culture, culture);
        }
        /// <summary>
        /// Sets a flag that determines whether xUnit.net should report test results synchronously.
        /// </summary>
        public static void SetSynchronousMessageReporting(
            this _ITestFrameworkDiscoveryOptions discoveryOptions,
            bool?value)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            discoveryOptions.SetValue(TestOptionsNames.Discovery.SynchronousMessageReporting, value);
        }
Beispiel #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FrontControllerFindSettings"/> class.
 /// </summary>
 /// <param name="discoveryOptions">The options used during discovery</param>
 /// <param name="executionOptions">The options used during execution</param>
 /// <param name="filters">The optional filters (when not provided, finds all tests)</param>
 public FrontControllerFindAndRunSettings(
     _ITestFrameworkDiscoveryOptions discoveryOptions,
     _ITestFrameworkExecutionOptions executionOptions,
     XunitFilters?filters = null)
 {
     DiscoveryOptions = Guard.ArgumentNotNull(nameof(discoveryOptions), discoveryOptions);
     ExecutionOptions = Guard.ArgumentNotNull(nameof(executionOptions), executionOptions);
     Filters          = filters ?? new XunitFilters();
 }
Beispiel #13
0
 ExecutionErrorTestCase ErrorTestCase(
     _ITestFrameworkDiscoveryOptions discoveryOptions,
     _ITestMethod testMethod,
     string message) =>
 new ExecutionErrorTestCase(
     DiagnosticMessageSink,
     discoveryOptions.MethodDisplayOrDefault(),
     discoveryOptions.MethodDisplayOptionsOrDefault(),
     testMethod,
     message
     );
Beispiel #14
0
        /// <summary>
        /// Creates test cases for the entire theory. This is used when one or more of the theory data items
        /// are not serializable, or if the user has requested to skip theory pre-enumeration. By default,
        /// returns a single instance of <see cref="XunitDelayEnumeratedTheoryTestCase"/>, which performs the data discovery
        /// at runtime.
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <returns>The test case</returns>
        protected virtual ValueTask <IReadOnlyCollection <IXunitTestCase> > CreateTestCasesForTheory(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute)
        {
            var testCase = new XunitDelayEnumeratedTheoryTestCase(
                discoveryOptions.MethodDisplayOrDefault(),
                discoveryOptions.MethodDisplayOptionsOrDefault(),
                testMethod
                );

            return(new(new[] { testCase }));
        }
Beispiel #15
0
        /// <summary>
        /// Creates test cases for the entire theory. This is used when one or more of the theory data items
        /// are not serializable, or if the user has requested to skip theory pre-enumeration. By default,
        /// returns a single instance of <see cref="XunitDelayEnumeratedTheoryTestCase"/>, which performs the data discovery
        /// at runtime.
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <returns>The test case</returns>
        protected virtual IEnumerable <IXunitTestCase> CreateTestCasesForTheory(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute)
        {
            var testCase = new XunitDelayEnumeratedTheoryTestCase(
                DiagnosticMessageSink,
                discoveryOptions.MethodDisplayOrDefault(),
                discoveryOptions.MethodDisplayOptionsOrDefault(),
                testMethod
                );

            return(new[] { testCase });
        }
Beispiel #16
0
        /// <summary>
        /// Creates a single <see cref="XunitTestCase"/> for the given test method.
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method.</param>
        /// <param name="factAttribute">The attribute that decorates the test method.</param>
        protected virtual IXunitTestCase CreateTestCase(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo factAttribute)
        {
            Guard.ArgumentNotNull(discoveryOptions);
            Guard.ArgumentNotNull(testMethod);
            Guard.ArgumentNotNull(factAttribute);

            return(new XunitTestCase(
                       discoveryOptions.MethodDisplayOrDefault(),
                       discoveryOptions.MethodDisplayOptionsOrDefault(),
                       testMethod
                       ));
        }
Beispiel #17
0
        /// <summary>
        /// Creates test cases for a skipped theory. By default, returns a single instance of <see cref="XunitTestCase"/>
        /// (which inherently discovers the skip reason via the fact attribute).
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <param name="skipReason">The skip reason that decorates <paramref name="theoryAttribute"/>.</param>
        /// <returns>The test cases</returns>
        protected virtual ValueTask <IReadOnlyCollection <IXunitTestCase> > CreateTestCasesForSkippedTheory(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute,
            string skipReason)
        {
            // TODO: Skip reason should be passed down into the test case
            var testCase = new XunitTestCase(
                discoveryOptions.MethodDisplayOrDefault(),
                discoveryOptions.MethodDisplayOptionsOrDefault(),
                testMethod
                );

            return(new(new[] { testCase }));
        }
        /// <inheritdoc/>
        protected override bool FindTestsForType(
            _ITestClass testClass,
            IMessageBus messageBus,
            _ITestFrameworkDiscoveryOptions discoveryOptions)
        {
            foreach (var method in testClass.Class.GetMethods(true))
            {
                var testMethod = new TestMethod(testClass, method);
                if (!FindTestsForMethod(testMethod, messageBus, discoveryOptions))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #19
0
        /// <summary>
        /// Creates test cases for a skipped theory. By default, returns a single instance of <see cref="XunitTestCase"/>
        /// (which inherently discovers the skip reason via the fact attribute).
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <param name="skipReason">The skip reason that decorates <paramref name="theoryAttribute"/>.</param>
        /// <returns>The test cases</returns>
        protected virtual IEnumerable <IXunitTestCase> CreateTestCasesForSkip(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute,
            string skipReason)
        {
            // TODO: Skip reason should be passed down into the test case
            var testCase = new XunitTestCase(
                DiagnosticMessageSink,
                discoveryOptions.MethodDisplayOrDefault(),
                discoveryOptions.MethodDisplayOptionsOrDefault(),
                testMethod
                );

            return(new[] { testCase });
        }
        protected override IEnumerable <IXunitTestCase> CreateTestCasesForTheory(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute)
        {
            var cultures = GetCultures(theoryAttribute);

            return(cultures.Select(
                       culture => new CulturedXunitTheoryTestCase(
                           DiagnosticMessageSink,
                           discoveryOptions.MethodDisplayOrDefault(),
                           discoveryOptions.MethodDisplayOptionsOrDefault(),
                           testMethod,
                           culture
                           )
                       ).ToList());
        }
Beispiel #21
0
        protected override ValueTask <IReadOnlyCollection <IXunitTestCase> > CreateTestCasesForTheory(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute)
        {
            var cultures = GetCultures(theoryAttribute);
            var result   = cultures.Select(
                culture => new CulturedXunitTheoryTestCase(
                    discoveryOptions.MethodDisplayOrDefault(),
                    discoveryOptions.MethodDisplayOptionsOrDefault(),
                    testMethod,
                    culture
                    )
                ).CastOrToReadOnlyCollection();

            return(new(result));
        }
Beispiel #22
0
        /// <summary>
        /// Creates test cases for a single row of skipped data. By default, returns a single instance of <see cref="XunitSkippedDataRowTestCase"/>
        /// with the data row inside of it.
        /// </summary>
        /// <remarks>If this method is overridden, the implementation will have to override <see cref="TestMethodTestCase.SkipReason"/> otherwise
        /// the default behavior will look at the <see cref="TheoryAttribute"/> and the test case will not be skipped.</remarks>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <param name="dataRow">The row of data for this test case.</param>
        /// <param name="skipReason">The reason this test case is to be skipped</param>
        /// <returns>The test cases</returns>
        protected virtual IEnumerable <IXunitTestCase> CreateTestCasesForSkippedDataRow(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute,
            object?[] dataRow,
            string skipReason)
        {
            var testCase = new XunitSkippedDataRowTestCase(
                DiagnosticMessageSink,
                discoveryOptions.MethodDisplayOrDefault(),
                discoveryOptions.MethodDisplayOptionsOrDefault(),
                testMethod,
                dataRow
                ,
                skipReason);

            return(new[] { testCase });
        }
Beispiel #23
0
        /// <summary>
        /// Creates test cases for a single row of data. By default, returns a single instance of <see cref="XunitTestCase"/>
        /// with the data row inside of it.
        /// </summary>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <param name="displayName">The optional display name for the test</param>
        /// <param name="traits">The traits associated with the test case.</param>
        /// <param name="dataRow">The row of data for this test case.</param>
        /// <returns>The test cases</returns>
        protected virtual ValueTask <IReadOnlyCollection <IXunitTestCase> > CreateTestCasesForDataRow(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute,
            string?displayName,
            Dictionary <string, List <string> >?traits,
            object?[] dataRow)
        {
            var testCase = new XunitPreEnumeratedTheoryTestCase(
                discoveryOptions.MethodDisplayOrDefault(),
                discoveryOptions.MethodDisplayOptionsOrDefault(),
                testMethod,
                dataRow,
                traits: traits,
                displayName: displayName
                );

            return(new(new[] { testCase }));
        }
Beispiel #24
0
        public ValueTask <IReadOnlyCollection <IXunitTestCase> > Discover(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo factAttribute)
        {
            var ctorArgs = factAttribute.GetConstructorArguments().ToArray();
            var cultures = Reflector.ConvertArguments(ctorArgs, new[] { typeof(string[]) }).Cast <string[]>().Single();

            if (cultures == null || cultures.Length == 0)
            {
                cultures = new[] { "en-US", "fr-FR" }
            }
            ;

            var methodDisplay        = discoveryOptions.MethodDisplayOrDefault();
            var methodDisplayOptions = discoveryOptions.MethodDisplayOptionsOrDefault();

            var result =
                cultures
                .Select(culture => CreateTestCase(testMethod, culture, methodDisplay, methodDisplayOptions))
                .CastOrToReadOnlyCollection();

            return(new(result));
        }

        CulturedXunitTestCase CreateTestCase(
            _ITestMethod testMethod,
            string culture,
            TestMethodDisplay methodDisplay,
            TestMethodDisplayOptions methodDisplayOptions)
        {
            return(new CulturedXunitTestCase(
                       methodDisplay,
                       methodDisplayOptions,
                       testMethod,
                       culture
                       ));
        }
    }
Beispiel #25
0
        protected override ValueTask <IReadOnlyCollection <IXunitTestCase> > CreateTestCasesForDataRow(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute,
            string?displayName,
            Dictionary <string, List <string> >?traits,
            object?[] dataRow)
        {
            var cultures = GetCultures(theoryAttribute);
            var result   = cultures.Select(
                culture => new CulturedXunitTestCase(
                    discoveryOptions.MethodDisplayOrDefault(),
                    discoveryOptions.MethodDisplayOptionsOrDefault(),
                    testMethod,
                    culture,
                    dataRow,
                    traits,
                    displayName)
                ).CastOrToReadOnlyCollection();

            return(new(result));
        }
Beispiel #26
0
        public IEnumerable <IXunitTestCase> Discover(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo factAttribute)
        {
            var ctorArgs = factAttribute.GetConstructorArguments().ToArray();
            var cultures = Reflector.ConvertArguments(ctorArgs, new[] { typeof(string[]) }).Cast <string[]>().Single();

            if (cultures == null || cultures.Length == 0)
            {
                cultures = new[] { "en-US", "fr-FR" }
            }
            ;

            var methodDisplay        = discoveryOptions.MethodDisplayOrDefault();
            var methodDisplayOptions = discoveryOptions.MethodDisplayOptionsOrDefault();

            return
                (cultures
                 .Select(culture => CreateTestCase(testMethod, culture, methodDisplay, methodDisplayOptions))
                 .ToList());
        }

        CulturedXunitTestCase CreateTestCase(
            _ITestMethod testMethod,
            string culture,
            TestMethodDisplay methodDisplay,
            TestMethodDisplayOptions methodDisplayOptions)
        {
            return(new CulturedXunitTestCase(
                       diagnosticMessageSink,
                       methodDisplay,
                       methodDisplayOptions,
                       testMethod,
                       culture
                       ));
        }
    }
Beispiel #27
0
        /// <summary>
        /// Discover test cases from a test method.
        /// </summary>
        /// <remarks>
        /// This method performs the following steps:
        /// - If the theory attribute is marked with Skip, returns the single test case from <see cref="CreateTestCasesForSkippedTheory"/>;
        /// - If pre-enumeration is off, or any of the test data is non serializable, returns the single test case from <see cref="CreateTestCasesForTheory"/>;
        /// - If there is no theory data, returns a single test case of <see cref="ExecutionErrorTestCase"/> with the error in it;
        /// - Otherwise, it returns one test case per data row, created by calling <see cref="CreateTestCasesForDataRow"/> or <see cref="CreateTestCasesForSkippedDataRow"/> if the data attribute has a skip reason.
        /// </remarks>
        /// <param name="discoveryOptions">The discovery options to be used.</param>
        /// <param name="testMethod">The test method the test cases belong to.</param>
        /// <param name="theoryAttribute">The theory attribute attached to the test method.</param>
        /// <returns>Returns zero or more test cases represented by the test method.</returns>
        public virtual async ValueTask <IReadOnlyCollection <IXunitTestCase> > Discover(
            _ITestFrameworkDiscoveryOptions discoveryOptions,
            _ITestMethod testMethod,
            _IAttributeInfo theoryAttribute)
        {
            Guard.ArgumentNotNull(discoveryOptions);
            Guard.ArgumentNotNull(testMethod);
            Guard.ArgumentNotNull(theoryAttribute);

            // Special case Skip, because we want a single Skip (not one per data item); plus, a skipped test may
            // not actually have any data (which is quasi-legal, since it's skipped).
            var skipReason = theoryAttribute.GetNamedArgument <string>("Skip");

            if (skipReason != null)
            {
                return(await CreateTestCasesForSkippedTheory(discoveryOptions, testMethod, theoryAttribute, skipReason));
            }

            var preEnumerate =
                discoveryOptions.PreEnumerateTheoriesOrDefault() &&
                !theoryAttribute.GetNamedArgument <bool>(nameof(TheoryAttribute.DisableDiscoveryEnumeration));

            if (preEnumerate)
            {
                try
                {
                    var dataAttributes = testMethod.Method.GetCustomAttributes(typeof(DataAttribute));
                    var results        = new List <IXunitTestCase>();

                    foreach (var dataAttribute in dataAttributes)
                    {
                        var             discovererAttribute = dataAttribute.GetCustomAttributes(typeof(DataDiscovererAttribute)).First();
                        IDataDiscoverer?discoverer;
                        try
                        {
                            discoverer = ExtensibilityPointFactory.GetDataDiscoverer(discovererAttribute);
                        }
                        catch (InvalidCastException)
                        {
                            if (dataAttribute is _IReflectionAttributeInfo reflectionAttribute)
                            {
                                results.Add(
                                    new ExecutionErrorTestCase(
                                        discoveryOptions.MethodDisplayOrDefault(),
                                        discoveryOptions.MethodDisplayOptionsOrDefault(),
                                        testMethod,
                                        $"Data discoverer specified for {reflectionAttribute.Attribute.GetType()} on {testMethod.TestClass.Class.Name}.{testMethod.Method.Name} does not implement IDataDiscoverer."
                                        )
                                    );
                            }
                            else
                            {
                                results.Add(
                                    new ExecutionErrorTestCase(
                                        discoveryOptions.MethodDisplayOrDefault(),
                                        discoveryOptions.MethodDisplayOptionsOrDefault(),
                                        testMethod,
                                        $"A data discoverer specified on {testMethod.TestClass.Class.Name}.{testMethod.Method.Name} does not implement IDataDiscoverer."
                                        )
                                    );
                            }

                            continue;
                        }

                        if (discoverer == null)
                        {
                            if (dataAttribute is _IReflectionAttributeInfo reflectionAttribute)
                            {
                                results.Add(
                                    new ExecutionErrorTestCase(
                                        discoveryOptions.MethodDisplayOrDefault(),
                                        discoveryOptions.MethodDisplayOptionsOrDefault(),
                                        testMethod,
                                        $"Data discoverer specified for {reflectionAttribute.Attribute.GetType()} on {testMethod.TestClass.Class.Name}.{testMethod.Method.Name} does not exist."
                                        )
                                    );
                            }
                            else
                            {
                                results.Add(
                                    new ExecutionErrorTestCase(
                                        discoveryOptions.MethodDisplayOrDefault(),
                                        discoveryOptions.MethodDisplayOptionsOrDefault(),
                                        testMethod,
                                        $"A data discoverer specified on {testMethod.TestClass.Class.Name}.{testMethod.Method.Name} does not exist."
                                        )
                                    );
                            }

                            continue;
                        }

                        skipReason = dataAttribute.GetNamedArgument <string>("Skip");

                        if (!discoverer.SupportsDiscoveryEnumeration(dataAttribute, testMethod.Method))
                        {
                            return(await CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute));
                        }

                        var data = await discoverer.GetData(dataAttribute, testMethod.Method);

                        if (data == null)
                        {
                            results.Add(
                                new ExecutionErrorTestCase(
                                    discoveryOptions.MethodDisplayOrDefault(),
                                    discoveryOptions.MethodDisplayOptionsOrDefault(),
                                    testMethod,
                                    $"Test data returned null for {testMethod.TestClass.Class.Name}.{testMethod.Method.Name}. Make sure it is statically initialized before this test method is called."
                                    )
                                );

                            continue;
                        }

                        foreach (var dataRow in data)
                        {
                            // Determine whether we can serialize the test case, since we need a way to uniquely
                            // identify a test and serialization is the best way to do that. If it's not serializable,
                            // this will throw and we will fall back to a single theory test case that gets its data at runtime.
                            // Also, if we can, we should attempt to resolve it to its parameter type right now, because
                            // the incoming data might be serializable but the actual parameter value that it gets converted
                            // to might not be, and serialization uses the resolved argument and not the input argument.
                            var resolvedData      = dataRow.GetData();
                            var dataRowSkipReason = skipReason ?? dataRow.Skip;
                            if (testMethod.Method is _IReflectionMethodInfo reflectionMethodInfo)
                            {
                                resolvedData = reflectionMethodInfo.MethodInfo.ResolveMethodArguments(resolvedData);
                            }

                            if (!resolvedData.All(d => SerializationHelper.IsSerializable(d)))
                            {
                                var typeNames =
                                    resolvedData
                                    .Select(x => x?.GetType().FullName)
                                    .WhereNotNull()
                                    .Select(x => $"'{x}'")
                                    .ToList();

                                TestContext.Current?.SendDiagnosticMessage(
                                    "Non-serializable data (one or more of: {0}) found for '{1}.{2}'; falling back to single test case.",
                                    string.Join(", ", typeNames),
                                    testMethod.TestClass.Class.Name,
                                    testMethod.Method.Name
                                    );

                                return(await CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute));
                            }

                            try
                            {
                                var testCases =
                                    dataRowSkipReason != null
                                                                                ? CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow.TestDisplayName, dataRow.Traits, resolvedData, dataRowSkipReason)
                                                                                : CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow.TestDisplayName, dataRow.Traits, resolvedData);

                                results.AddRange(await testCases);
                            }
                            catch (Exception ex)
                            {
                                TestContext.Current?.SendDiagnosticMessage(
                                    "Error creating theory test case for for '{0}.{1}'; falling back to single test case. Exception message: '{2}'",
                                    testMethod.TestClass.Class.Name,
                                    testMethod.Method.Name,
                                    ex.Message
                                    );

                                return(await CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute));
                            }
                        }
                    }

                    if (results.Count == 0)
                    {
                        results.Add(
                            new ExecutionErrorTestCase(
                                discoveryOptions.MethodDisplayOrDefault(),
                                discoveryOptions.MethodDisplayOptionsOrDefault(),
                                testMethod,
                                $"No data found for {testMethod.TestClass.Class.Name}.{testMethod.Method.Name}"
                                )
                            );
                    }

                    return(results);
                }
                catch (Exception ex)                    // If something goes wrong, fall through to return just the XunitTestCase
                {
                    TestContext.Current?.SendDiagnosticMessage(
                        "Exception thrown during theory discovery on '{0}.{1}'; falling back to single test case.{2}{3}",
                        testMethod.TestClass.Class.Name,
                        testMethod.Method.Name,
                        Environment.NewLine,
                        ex
                        );
                }
            }

            return(await CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute));
        }
        /// <summary>
        /// Gets a flag that determines whether discovered test cases should include source information.
        /// Note that not all runners have access to source information, so this flag does not guarantee
        /// that source information will be provided. If the flag is not present, returns the default
        /// value (<c>false</c>).
        /// </summary>
        public static bool GetIncludeSourceInformationOrDefault(this _ITestFrameworkDiscoveryOptions discoveryOptions)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            return(discoveryOptions.GetIncludeSourceInformation() ?? false);
        }
        /// <summary>
        /// Gets a flag that determines whether internal diagnostic messages will be emitted.
        /// </summary>
        public static bool?GetInternalDiagnosticMessages(this _ITestFrameworkDiscoveryOptions discoveryOptions)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            return(discoveryOptions.GetValue <bool?>(TestOptionsNames.Discovery.InternalDiagnosticMessages));
        }
        /// <summary>
        /// Gets a flag that determines whether internal diagnostic messages will be emitted. If the flag is not
        /// set, returns the default value (<c>false</c>).
        /// </summary>
        public static bool GetInternalDiagnosticMessagesOrDefault(this _ITestFrameworkDiscoveryOptions discoveryOptions)
        {
            Guard.ArgumentNotNull(discoveryOptions);

            return(discoveryOptions.GetInternalDiagnosticMessages() ?? false);
        }