/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Test/Core/TestHelpers.cs
213 строк
8 KB
Jared Parsons
Pre-load lazily-loaded assemblies before assembly snapshots (#83247)
21 апр 2026, 05:42
Не верифицирован
21 апр 2026, 05:42
c5b47fb
Код
Авторство
О чём код?
// 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. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; namespace Roslyn.Test.Utilities { public static class TestHelpers { /// <summary> /// Ensures that the assembly containing <paramref name="typeHandle"/> is loaded into /// the current process via <see cref="RuntimeHelpers.RunClassConstructor"/>. The /// <paramref name="assemblyName"/> is validated against the actual assembly name so /// that callers are forced to update both if the type moves to a different assembly. /// </summary> /// <remarks> /// This is used before taking assembly snapshots in tests that verify no unexpected /// assemblies are loaded during test execution. Without this, lazily-loaded assemblies /// can appear as unexpected additions after the snapshot. /// </remarks> public static void EnsureAssemblyLoaded(string assemblyName, RuntimeTypeHandle typeHandle) { var type = Type.GetTypeFromHandle(typeHandle); Debug.Assert(type.Assembly.GetName().Name == assemblyName, $"Expected assembly '{assemblyName}' but type '{type.FullName}' is in '{type.Assembly.GetName().Name}'"); RuntimeHelpers.RunClassConstructor(typeHandle); } /// <summary> /// A long timeout used to avoid hangs in tests, where a test failure manifests as an operation never occurring. /// </summary> public static readonly TimeSpan HangMitigatingTimeout = TimeSpan.FromMinutes(4); public static ImmutableDictionary<K, V> CreateImmutableDictionary<K, V>( IEqualityComparer<K> comparer, params (K key, V value)[] entries) => ImmutableDictionary.CreateRange(comparer, entries.Select(t => KeyValuePair.Create(t.key, t.value))); public static ImmutableDictionary<K, V> CreateImmutableDictionary<K, V>(params (K key, V value)[] entries) => ImmutableDictionary.CreateRange(entries.Select(t => KeyValuePair.Create(t.key, t.value))); public static IEnumerable<Type> GetAllTypesWithStaticFieldsImplementingType(Assembly assembly, Type type) { return assembly.GetTypes().Where(t => { return t.GetFields(BindingFlags.Public | BindingFlags.Static).Any(f => type.IsAssignableFrom(f.FieldType)); }).ToList(); } public static string GetCultureInvariantString(object value) { if (value == null) return null; var valueType = value.GetType(); if (valueType == typeof(string)) { return value as string; } if (valueType == typeof(DateTime)) { return ((DateTime)value).ToString("M/d/yyyy h:mm:ss tt", CultureInfo.InvariantCulture); } if (valueType == typeof(float)) { return ((float)value).ToString(CultureInfo.InvariantCulture); } if (valueType == typeof(double)) { return ((double)value).ToString(CultureInfo.InvariantCulture); } if (valueType == typeof(decimal)) { return ((decimal)value).ToString(CultureInfo.InvariantCulture); } return value.ToString(); } /// <summary> /// <see cref="System.Xml.Linq.XComment.Value"/> is serialized with "--" replaced by "- -" /// </summary> public static string AsXmlCommentText(string text) { var builder = new StringBuilder(); for (int i = 0; i < text.Length; i++) { var c = text[i]; if ((c == '-') && (i > 0) && (text[i - 1] == '-')) { builder.Append(' '); } builder.Append(c); } var result = builder.ToString(); Debug.Assert(!result.Contains("--")); return result; } public static DiagnosticDescription Diagnostic( object code, string squiggledText = null, object[] arguments = null, LinePosition? startLocation = null, Func<SyntaxNode, bool> syntaxNodePredicate = null, bool argumentOrderDoesNotMatter = false, bool isSuppressed = false) { Debug.Assert(code is Microsoft.CodeAnalysis.CSharp.ErrorCode || code is Microsoft.CodeAnalysis.VisualBasic.ERRID || code is int || code is string); return new DiagnosticDescription( code as string ?? (object)(int)code, false, squiggledText, arguments, startLocation, syntaxNodePredicate, argumentOrderDoesNotMatter, code.GetType(), isSuppressed: isSuppressed); } internal static DiagnosticDescription Diagnostic( object code, XCData squiggledText, object[] arguments = null, LinePosition? startLocation = null, Func<SyntaxNode, bool> syntaxNodePredicate = null, bool argumentOrderDoesNotMatter = false, bool isSuppressed = false) { return Diagnostic( code, NormalizeNewLines(squiggledText), arguments, startLocation, syntaxNodePredicate, argumentOrderDoesNotMatter, isSuppressed: isSuppressed); } public static string NormalizeNewLines(XCData data) { if (ExecutionConditionUtil.IsWindows) { return data.Value.Replace("\n", "\r\n"); } return data.Value; } public static ImmutableArray<byte> HexToByte(ReadOnlySpan<char> input) { if (input.Length % 2 != 0) { throw new ArgumentException("Length of the input string must be even", nameof(input)); } var bytes = new byte[input.Length >> 1]; for (var i = 0; i < bytes.Length; i++) { bytes[i] = parseByte(input.Slice(i << 1, 2), NumberStyles.HexNumber); } return ImmutableCollectionsMarshal.AsImmutableArray(bytes); byte parseByte(ReadOnlySpan<char> input, NumberStyles numberStyle) { #if NET return byte.Parse(input, numberStyle); #else return byte.Parse(input.ToString(), numberStyle); #endif } } /// <summary> /// Create an absolute path for the current OS platform with the given suffix. /// NOTE: the path is not appropriate for actually writing files during tests, use TempRoot instead for that. /// </summary> public static string CreateAbsolutePath(string suffix) => Path.Combine(Path.GetTempPath(), suffix); public const string WindowsRoot = @"Q:\"; public const string UnixRoot = @"/q/"; public static string Root => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? WindowsRoot : UnixRoot; public static string GetRootedPath(params string[] relativePath) => Path.Combine([Root, .. relativePath]); } }