/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/IntegrationTest/Harness/XUnitShared/Threading/IdeFactDiscoverer.cs
294 строки
11 KB
David Barbet
Shorten file paths to prevent long path issues opening the slnx
10 дек 2025, 22:44
10 дек 2025, 22:44
7830fcf
Код
Авторство
О чём код?
// 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. namespace Xunit.Threading { using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using Xunit.Abstractions; using Xunit.Harness; using Xunit.Sdk; public class IdeFactDiscoverer : IXunitTestCaseDiscoverer { private readonly IMessageSink _diagnosticMessageSink; public IdeFactDiscoverer(IMessageSink diagnosticMessageSink) { _diagnosticMessageSink = diagnosticMessageSink; } public IEnumerable<IXunitTestCase> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) { if (testMethod is null) { throw new ArgumentNullException(nameof(testMethod)); } if (!testMethod.Method.GetParameters().Any()) { if (!testMethod.Method.IsGenericMethodDefinition) { foreach (var supportedInstance in GetSupportedInstances(testMethod, factAttribute)) { yield return new IdeTestCase(_diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, supportedInstance); if (IdeInstanceTestCase.TryCreateNewInstanceForFramework(discoveryOptions, _diagnosticMessageSink, supportedInstance) is { } instanceTestCase) { yield return instanceTestCase; } } } else { yield return new ExecutionErrorTestCase(_diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "[IdeFact] methods are not allowed to be generic."); } } else { yield return new ExecutionErrorTestCase(_diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "[IdeFact] methods are not allowed to have parameters. Did you mean to use [IdeTheory]?"); } } internal static ITestMethod CreateVisualStudioTestMethod() { var testAssembly = new TestAssembly(new ReflectionAssemblyInfo(typeof(Instances).Assembly)); var testCollection = new TestCollection(testAssembly, collectionDefinition: null, nameof(Instances)); var testClass = new TestClass(testCollection, new ReflectionTypeInfo(typeof(Instances))); var testMethod = testClass.Class.GetMethods(false).Single(method => method.Name == nameof(Instances.VisualStudio)); return new TestMethod(testClass, testMethod); } internal static IEnumerable<VisualStudioInstanceKey> GetSupportedInstances(ITestMethod testMethod, IAttributeInfo factAttribute) { var rootSuffix = GetRootSuffix(testMethod, factAttribute); var maxAttempts = GetMaxAttempts(testMethod, factAttribute); var environmentVariables = GetEnvironmentVariables(testMethod, factAttribute); return GetSupportedVersions(factAttribute, GetSettingsAttributes(testMethod).ToArray()) .Select(version => new VisualStudioInstanceKey(version, rootSuffix, maxAttempts, environmentVariables)); } private static string GetRootSuffix(ITestMethod testMethod, IAttributeInfo factAttribute) { return GetRootSuffix(factAttribute, GetSettingsAttributes(testMethod).ToArray()); } private static int GetMaxAttempts(ITestMethod testMethod, IAttributeInfo factAttribute) { return GetMaxAttempts(factAttribute, GetSettingsAttributes(testMethod).ToArray()); } private static string[] GetEnvironmentVariables(ITestMethod testMethod, IAttributeInfo factAttribute) { return GetEnvironmentVariables(factAttribute, GetSettingsAttributes(testMethod).ToArray()); } private static IEnumerable<IAttributeInfo> GetSettingsAttributes(ITestMethod testMethod) { foreach (var attributeData in testMethod.Method.GetCustomAttributes(typeof(IdeSettingsAttribute))) { yield return attributeData; } foreach (var attributeData in testMethod.TestClass.Class.GetCustomAttributes(typeof(IdeSettingsAttribute))) { yield return attributeData; } } private static IEnumerable<VisualStudioVersion> GetSupportedVersions(IAttributeInfo factAttribute, IAttributeInfo[] settingsAttributes) { var minVersion = GetNamedArgument( factAttribute, settingsAttributes, nameof(IIdeSettingsAttribute.MinVersion), static value => value is not VisualStudioVersion.Unspecified, defaultValue: VisualStudioVersion.VS2012); var maxVersion = GetNamedArgument( factAttribute, settingsAttributes, nameof(IIdeSettingsAttribute.MaxVersion), static value => value is not VisualStudioVersion.Unspecified, defaultValue: VisualStudioVersion.VS18); for (var version = minVersion; version <= maxVersion; version++) { #if MERGED_PIA if (version >= VisualStudioVersion.VS2012 && version < VisualStudioVersion.VS2022) { continue; } #else if (version >= VisualStudioVersion.VS2022) { continue; } #endif yield return version; } } private static string GetRootSuffix(IAttributeInfo factAttribute, IAttributeInfo[] settingsAttributes) { return GetNamedArgument( factAttribute, settingsAttributes, nameof(IIdeSettingsAttribute.RootSuffix), static value => value is not null, defaultValue: "Exp"); } private static int GetMaxAttempts(IAttributeInfo factAttribute, IAttributeInfo[] settingsAttributes) { return GetNamedArgument( factAttribute, settingsAttributes, nameof(IIdeSettingsAttribute.MaxAttempts), static value => value > 0, defaultValue: 1); } private static string[] GetEnvironmentVariables(IAttributeInfo factAttribute, IAttributeInfo[] settingsAttributes) { return GetNamedArgument( factAttribute, settingsAttributes, nameof(IIdeSettingsAttribute.EnvironmentVariables), static value => value != null, (inherited, current) => MergeEnvironmentVariables(inherited, current), defaultValue: new string[0]); } private static string[] MergeEnvironmentVariables(string[] inherited, string[] current) { if (inherited.Length == 0) { return current; } else if (current.Length == 0) { return inherited; } var set = new HashSet<string>(KeyOnlyComparerIgnoreCase.Instance); foreach (var value in current) { set.Add(value); } foreach (var value in inherited) { set.Add(value); } return set.ToArray(); } private static TValue GetNamedArgument<TValue>(IAttributeInfo factAttribute, IAttributeInfo[] settingsAttributes, string argumentName, Func<TValue, bool> isValidValue, TValue defaultValue) { return GetNamedArgument( factAttribute, settingsAttributes, argumentName, isValidValue, merge: null, defaultValue); } private static TValue GetNamedArgument<TValue>(IAttributeInfo factAttribute, IAttributeInfo[] settingsAttributes, string argumentName, Func<TValue, bool> isValidValue, Func<TValue, TValue, TValue>? merge, TValue defaultValue) { StrongBox<TValue>? result = null; if (TryGetNamedArgument(factAttribute, argumentName, isValidValue, out var value)) { if (merge is null) { return value; } result = new StrongBox<TValue>(value); } foreach (var attribute in settingsAttributes) { if (TryGetNamedArgument(attribute, argumentName, isValidValue, out value)) { if (merge is null) { return value; } else if (result is null) { result = new StrongBox<TValue>(value); } else { result.Value = merge(value, result.Value); } return value; } } if (result is not null) { return result.Value; } return defaultValue; static bool TryGetNamedArgument(IAttributeInfo attribute, string argumentName, Func<TValue, bool> isValidValue, out TValue value) { value = attribute.GetNamedArgument<TValue>(argumentName); return isValidValue(value); } } private class KeyOnlyComparerIgnoreCase : IEqualityComparer<string?> { public static readonly KeyOnlyComparerIgnoreCase Instance = new KeyOnlyComparerIgnoreCase(); private KeyOnlyComparerIgnoreCase() { } public bool Equals(string? x, string? y) { if (x is null) { return y is null; } else if (y is null) { return false; } return StringComparer.OrdinalIgnoreCase.Equals(GetKey(x), GetKey(y)); } public int GetHashCode(string? obj) { if (obj is null) { return 0; } return StringComparer.OrdinalIgnoreCase.GetHashCode(GetKey(obj)); } private static string GetKey(string s) { var keyEnd = s.IndexOf('='); if (keyEnd < 0) { return s; } return s.Substring(0, keyEnd); } } } }