/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Interactive/HostTest/AbstractInteractiveHostTests.cs
222 строки
8 KB
Jason Malinowski
Switch code that was using Assert.True/False as a replacement for .Fail
21 апр 2026, 23:28
21 апр 2026, 23:28
3bf59ba
Код
Авторство
О чём код?
// 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. extern alias InteractiveHost; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.CSharp.Scripting.Hosting; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests.Interactive { using InteractiveHost::Microsoft.CodeAnalysis.Interactive; using Xunit.Abstractions; public abstract class AbstractInteractiveHostTests : CSharpTestBase, IAsyncLifetime { private SynchronizedStringWriter _synchronizedOutput = null!; private SynchronizedStringWriter _synchronizedErrorOutput = null!; private int[] _outputReadPosition = [0, 0]; internal readonly InteractiveHost Host; internal readonly ITestOutputHelper TestOutputHelper; // DOTNET_ROOT must be set in order to run host process on .NET Core on machines (like CI) // that do not have the required version of the runtime installed globally. // // If it was not set the process would fail with exit code -2147450749: // "A fatal error occurred. The required library hostfxr.dll could not be found." // // See https://github.com/dotnet/runtime/issues/38462. static AbstractInteractiveHostTests() { if (Environment.GetEnvironmentVariable("DOTNET_ROOT") == null) { var dir = RuntimeEnvironment.GetRuntimeDirectory(); // find directory above runtime dir that contains dotnet.exe while (dir != null && !File.Exists(Path.Combine(dir, "dotnet.exe"))) { dir = Path.GetDirectoryName(dir); } // dotnet.exe not found Assert.NotNull(dir); Environment.SetEnvironmentVariable("DOTNET_ROOT", dir); } } protected AbstractInteractiveHostTests(ITestOutputHelper testOutputHelper) { TestOutputHelper = testOutputHelper; Host = new InteractiveHost(typeof(CSharpReplServiceProvider), ".", millisecondsTimeout: -1, joinOutputWritingThreadsOnDisposal: true); Host.InteractiveHostProcessCreationFailed += (exception, exitCode) => testOutputHelper.WriteLine((exception?.Message ?? "Host process terminated unexpectedly.") + $" Exit code: {exitCode?.ToString() ?? "<unknown>"}"); RedirectOutput(); } internal abstract InteractiveHostPlatform DefaultPlatform { get; } internal abstract bool UseDefaultInitializationFile { get; } public async Task InitializeAsync() { var initializationFileName = UseDefaultInitializationFile ? "CSharpInteractive.rsp" : null; await Host.ResetAsync(InteractiveHostOptions.CreateFromDirectory(TestUtils.HostRootPath, initializationFileName, CultureInfo.InvariantCulture, CultureInfo.InvariantCulture, DefaultPlatform)); // assert and remove logo: var output = SplitLines(await ReadOutputToEnd()); var errorOutput = await ReadErrorOutputToEnd(); AssertEx.AssertEqualToleratingWhitespaceDifferences("", errorOutput); var expectedOutput = new List<string> { string.Format(CSharpScriptingResources.LogoLine1, CommonCompiler.GetProductVersion(typeof(CSharpReplServiceProvider))) }; if (UseDefaultInitializationFile) { expectedOutput.Add(string.Format(InteractiveHostResources.Loading_context_from_0, initializationFileName)); } expectedOutput.Add(InteractiveHostResources.Type_Sharphelp_for_more_information); AssertEx.Equal(expectedOutput, output); // remove logo: ClearOutput(); } public async Task DisposeAsync() { var service = await Host.TryGetServiceAsync(); Assert.NotNull(service); var process = service!.Process; Host.Dispose(); // the process should be terminated if (process != null && !process.HasExited) { process.WaitForExit(); } } public void RedirectOutput() { _synchronizedOutput = new SynchronizedStringWriter(); _synchronizedErrorOutput = new SynchronizedStringWriter(); ClearOutput(); Host.SetOutputs(_synchronizedOutput, _synchronizedErrorOutput); } public static ImmutableArray<string> SplitLines(string text) { return ImmutableArray.Create(text.Split(["\r\n"], StringSplitOptions.RemoveEmptyEntries)); } public async Task<bool> LoadReference(string reference) { return await Execute($"#r \"{reference}\""); } public async Task<bool> Execute(string code) { var task = await Host.ExecuteAsync(code); return task.Success; } public Task<string> ReadErrorOutputToEnd() { return ReadOutputToEnd(isError: true); } public void ClearOutput() { _outputReadPosition = [0, 0]; _synchronizedOutput.Clear(); _synchronizedErrorOutput.Clear(); } public async Task RestartHost() { ClearOutput(); await Host.ResetAsync(InteractiveHostOptions.CreateFromDirectory(TestUtils.HostRootPath, initializationFileName: null, CultureInfo.InvariantCulture, CultureInfo.InvariantCulture, InteractiveHostPlatform.Desktop64)); } public async Task<string> ReadOutputToEnd(bool isError = false) { // writes mark to the STDOUT/STDERR pipe in the remote process: var remoteService = await Host.TryGetServiceAsync().ConfigureAwait(false); if (remoteService == null) { Assert.Fail(@$" Remote service unavailable STDERR: {_synchronizedErrorOutput} STDOUT: {_synchronizedOutput} "); } var writer = isError ? _synchronizedErrorOutput : _synchronizedOutput; var markPrefix = '\uFFFF'; var mark = markPrefix + Guid.NewGuid().ToString(); await remoteService!.JsonRpc.InvokeAsync(nameof(InteractiveHost.Service.RemoteConsoleWriteAsync), InteractiveHost.OutputEncoding.GetBytes(mark), isError).ConfigureAwait(false); while (true) { var data = writer.Prefix(mark, ref _outputReadPosition[isError ? 0 : 1]); if (data != null) { return data; } await Task.Delay(10); } } public static (string Path, ImmutableArray<byte> Image) CompileLibrary( TempDirectory dir, string fileName, string assemblyName, string source, params MetadataReference[] references) { var file = dir.CreateFile(fileName); var compilation = CreateEmptyCompilation( new[] { source }, assemblyName: assemblyName, references: TargetFrameworkUtil.GetReferences(TargetFramework.NetStandard20, references), options: fileName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) ? TestOptions.ReleaseExe : TestOptions.ReleaseDll); var image = compilation.EmitToArray(); file.WriteAllBytes(image); return (file.Path, image); } public static string PrintSearchPaths(params string[] paths) => paths.Length == 0 ? "SearchPaths { }" : $"SearchPaths {{ {string.Join(", ", paths.Select(p => "\"" + p.Replace("\\", "\\\\") + "\""))} }}"; public async Task<string> GetHostRuntimeDirectoryAsync() { var remoteService = await Host.TryGetServiceAsync().ConfigureAwait(false); Assert.NotNull(remoteService); return await remoteService!.JsonRpc.InvokeAsync<string>(nameof(InteractiveHost.Service.GetRuntimeDirectoryAsync)).ConfigureAwait(false); } } }