Add Language Server Tests Back In (#1576)
This commit is contained in:
Родитель
16c5e86de2
Коммит
82e9304d61
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28809.33
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33103.184
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompilationManager", "src\QsCompiler\CompilationManager\CompilationManager.csproj", "{8990670B-B9D2-4485-AA5B-34A301A11CD3}"
|
||||
EndProject
|
||||
|
@ -73,6 +73,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "App", "src\QsFmt\App\App.fs
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Telemetry", "src\Telemetry\Library\Telemetry.csproj", "{2A562128-2FD0-47CF-B457-DDF3C19CCDAC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.LanguageServer", "src\QsCompiler\Tests.LanguageServer\Tests.LanguageServer.csproj", "{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -431,6 +433,18 @@ Global
|
|||
{2A562128-2FD0-47CF-B457-DDF3C19CCDAC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2A562128-2FD0-47CF-B457-DDF3C19CCDAC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2A562128-2FD0-47CF-B457-DDF3C19CCDAC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -454,6 +468,7 @@ Global
|
|||
{4D1F507F-7382-4F5B-9923-58398A565D8B} = {755A6971-AD80-4519-A64E-0333B89C1E9D}
|
||||
{AD350766-EE10-4DE3-A834-129D026487FB} = {755A6971-AD80-4519-A64E-0333B89C1E9D}
|
||||
{2A562128-2FD0-47CF-B457-DDF3C19CCDAC} = {755A6971-AD80-4519-A64E-0333B89C1E9D}
|
||||
{A9E3087B-F21A-45D4-A0A8-DF1DB0043233} = {B4A9484D-31FC-4A27-9E26-4C8DE3E02D77}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B921C36B-4574-4025-8FE3-E5BD2D3D2B81}
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace Microsoft.Quantum.QsCompiler.CompilationBuilder
|
|||
/// </remarks>
|
||||
public bool QueueForExecution<T>(Func<T> execute, [MaybeNull] out T result)
|
||||
{
|
||||
T res = default(T);
|
||||
T res = default;
|
||||
var succeeded = true;
|
||||
this.QueueForExecutionAsync(() =>
|
||||
{
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace Microsoft.Quantum.QsCompiler.CompilationBuilder
|
|||
? path ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
private ImmutableDictionary<string, string?> BuildProperties { get; }
|
||||
internal ImmutableDictionary<string, string?> BuildProperties { get; }
|
||||
|
||||
public static ProjectProperties Empty =>
|
||||
new ProjectProperties(ImmutableDictionary<string, string?>.Empty);
|
||||
|
@ -123,7 +123,7 @@ namespace Microsoft.Quantum.QsCompiler.CompilationBuilder
|
|||
{
|
||||
public delegate bool Loader(Uri projectFile, [NotNullWhen(true)] out ProjectInformation? projectInfo);
|
||||
|
||||
internal ProjectProperties Properties { get; }
|
||||
public ProjectProperties Properties { get; }
|
||||
|
||||
public ImmutableArray<string> SourceFiles { get; }
|
||||
|
||||
|
@ -309,6 +309,16 @@ namespace Microsoft.Quantum.QsCompiler.CompilationBuilder
|
|||
.ToImmutableHashSet();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the currently set project information that is used to load the project.
|
||||
/// </summary>
|
||||
internal ProjectInformation GetProjectInformation() =>
|
||||
new ProjectInformation(
|
||||
sourceFiles: this.specifiedSourceFiles.Select(uri => uri.AbsolutePath),
|
||||
projectReferences: this.specifiedProjectReferences.Select(uri => uri.AbsolutePath),
|
||||
references: this.specifiedReferences.Select(uri => uri.AbsolutePath),
|
||||
buildProperties: this.Properties.BuildProperties);
|
||||
|
||||
/// <summary>
|
||||
/// If the project is not yet loaded, loads all specified source file, dll references and project references
|
||||
/// using <paramref name="projectOutputPaths"/> to resolve the dll output paths for project references.
|
||||
|
@ -1441,14 +1451,8 @@ namespace Microsoft.Quantum.QsCompiler.CompilationBuilder
|
|||
/// This method waits for all currently running or queued tasks to finish
|
||||
/// before getting the file content.
|
||||
/// </remarks>
|
||||
public string[]? FileContentInMemory(TextDocumentIdentifier textDocument)
|
||||
{
|
||||
if (textDocument?.Uri == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
this.load.QueueForExecution(
|
||||
public string[]? FileContentInMemory(TextDocumentIdentifier textDocument) =>
|
||||
textDocument?.Uri != null && this.load.QueueForExecution(
|
||||
() =>
|
||||
{
|
||||
// NOTE: the call below prevents any consolidating of the processing queues
|
||||
|
@ -1456,9 +1460,28 @@ namespace Microsoft.Quantum.QsCompiler.CompilationBuilder
|
|||
var manager = this.Manager(textDocument.Uri);
|
||||
return manager?.FileContentInMemory(textDocument);
|
||||
},
|
||||
out var content);
|
||||
return content;
|
||||
}
|
||||
out var content)
|
||||
? content : null;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the project information stored for the project defined by
|
||||
/// the given <paramref name="projectFile"/>, if it is listed as a
|
||||
/// project with this manager.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns null if the given project file is null or the project is not
|
||||
/// registered with this manager.
|
||||
/// <para/>
|
||||
/// This method waits for all currently running or queued tasks to finish
|
||||
/// before getting the file content.
|
||||
/// </remarks>
|
||||
public ProjectInformation? GetProjectInformation(TextDocumentIdentifier projectFile) =>
|
||||
projectFile?.Uri != null && this.load.QueueForExecution(
|
||||
() => this.projects.TryGetValue(projectFile.Uri, out Project project)
|
||||
? project.GetProjectInformation()
|
||||
: null,
|
||||
out var info)
|
||||
? info : null;
|
||||
|
||||
/* static routines related to loading the content needed for compilation */
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
// commands for diagnostic purposes
|
||||
internal const string FileContentInMemory = "qsLanguageServer/fileContentInMemory";
|
||||
internal const string FileDiagnostics = "qsLanguageServer/fileDiagnostics";
|
||||
internal const string ProjectInformation = "qsLanguageServer/projectInformation";
|
||||
}
|
||||
|
||||
public class ProtocolError
|
||||
|
|
|
@ -34,8 +34,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
/// needed to determine if the reality of a source file that has changed on disk is indeed given by the content on disk,
|
||||
/// or whether its current state as it is in the editor needs to be preserved
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<Uri, FileContentManager> openFiles =
|
||||
new ConcurrentDictionary<Uri, FileContentManager>();
|
||||
private readonly ConcurrentDictionary<Uri, FileContentManager> openFiles = new();
|
||||
|
||||
private FileContentManager? GetOpenFile(Uri key) => this.openFiles.TryGetValue(key, out var file) ? file : null;
|
||||
|
||||
|
@ -203,7 +202,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
/// and publishes suitable diagnostics for it.
|
||||
/// </summary>
|
||||
public Task LoadProjectsAsync(IEnumerable<Uri> projects) =>
|
||||
this.projectLoader is object ?
|
||||
this.projectLoader is not null ?
|
||||
this.projects.LoadProjectsAsync(projects, this.QsProjectLoader, this.GetOpenFile) :
|
||||
Task.CompletedTask;
|
||||
|
||||
|
@ -212,7 +211,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
/// updates that project in the list of tracked projects or adds it if needed, and publishes suitable diagnostics for it.
|
||||
/// </summary>
|
||||
public Task ProjectDidChangeOnDiskAsync(Uri project) =>
|
||||
this.projectLoader is object ?
|
||||
this.projectLoader is not null ?
|
||||
this.projects.ProjectChangedOnDiskAsync(project, this.QsProjectLoader, this.GetOpenFile) :
|
||||
Task.CompletedTask;
|
||||
|
||||
|
@ -545,7 +544,48 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
internal Diagnostic[]? FileDiagnostics(TextDocumentIdentifier textDocument)
|
||||
{
|
||||
var allDiagnostics = this.projects.GetDiagnostics(textDocument?.Uri);
|
||||
return allDiagnostics?.Count() == 1 ? allDiagnostics.Single().Diagnostics : null; // count is > 1 if the given uri corresponds to a project file
|
||||
return allDiagnostics?.Length == 1 ? allDiagnostics.Single().Diagnostics : null; // count is > 1 if the given uri corresponds to a project file
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for all currently running or queued tasks to finish before getting the project information.
|
||||
/// -> Method to be used for testing/diagnostic purposes only!
|
||||
/// </summary>
|
||||
internal string? ProjectInformation(TextDocumentIdentifier textDocument)
|
||||
{
|
||||
var projectInfo = this.projects.GetProjectInformation(textDocument);
|
||||
if (projectInfo is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var stringWriter = new StringWriter();
|
||||
var writer = System.Xml.XmlWriter.Create(stringWriter);
|
||||
void WriteElementGroup(string groupName, IEnumerable<string> paths)
|
||||
{
|
||||
writer.WriteStartElement(groupName);
|
||||
foreach (var path in paths)
|
||||
{
|
||||
writer.WriteStartElement("File");
|
||||
writer.WriteAttributeString("Path", path);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("ProjectInfo");
|
||||
writer.WriteAttributeString("OutputPath", projectInfo.Properties.DllOutputPath);
|
||||
writer.WriteAttributeString("TargetCapability", projectInfo.Properties.TargetCapability.Name);
|
||||
writer.WriteAttributeString("ProcessorArchitecture", projectInfo.Properties.ProcessorArchitecture);
|
||||
WriteElementGroup("Sources", projectInfo.SourceFiles);
|
||||
WriteElementGroup("ProjectReferences", projectInfo.ProjectReferences);
|
||||
WriteElementGroup("References", projectInfo.References);
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndDocument();
|
||||
writer.Flush();
|
||||
return stringWriter.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Quantum.QsCompiler;
|
||||
using Microsoft.Quantum.QsCompiler.CompilationBuilder;
|
||||
|
@ -19,8 +18,8 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
/// <summary>
|
||||
/// This class provides a basic file watcher for the LSP that sends notifications on watched files
|
||||
/// when they change on disk (i.e. are added, removed, or edited).
|
||||
/// The implemeneted mechanism is far from perfect and will fail in some cases -
|
||||
/// in particular I expect it to fail (silently) for autogenerated file system edits generated in rapid succession,
|
||||
/// The implemented mechanism is far from perfect and will fail in some cases -
|
||||
/// in particular I expect it to fail (silently) for auto-generated file system edits generated in rapid succession,
|
||||
/// especially in combination with large batch edits in the file system.
|
||||
/// However, all in all splitting out the logic to generate notifications for individual files here (even if it is less than perfect),
|
||||
/// seems better and overall less error prone than having to deal with less abstraction on the server side.
|
||||
|
@ -28,7 +27,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
/// </summary>
|
||||
internal class FileWatcher
|
||||
{
|
||||
private readonly ConcurrentBag<System.IO.FileSystemWatcher> watchers;
|
||||
private readonly ConcurrentBag<FileSystemWatcher> watchers;
|
||||
private readonly Action<Exception> onException;
|
||||
|
||||
private void OnBufferOverflow(object sender, ErrorEventArgs e)
|
||||
|
@ -61,7 +60,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
public FileWatcher(Action<Exception> onException)
|
||||
{
|
||||
this.onException = onException;
|
||||
this.watchers = new ConcurrentBag<System.IO.FileSystemWatcher>();
|
||||
this.watchers = new ConcurrentBag<FileSystemWatcher>();
|
||||
this.watchedDirectories = new Dictionary<Uri, ImmutableHashSet<string>>();
|
||||
this.processing = new ProcessingQueue(this.onException, "error in file system watcher");
|
||||
this.globPatterns = new ConcurrentDictionary<Uri, IEnumerable<string>>();
|
||||
|
@ -71,9 +70,9 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
/// Returns a file system watcher for the given folder and pattern, with the proper event handlers added.
|
||||
/// IMPORTANT: The returned watcher is disabled and needs to be enabled by setting EnableRaisingEvents to true.
|
||||
/// </summary>
|
||||
private System.IO.FileSystemWatcher GetWatcher(string folder, string pattern, NotifyFilters notifyOn)
|
||||
private FileSystemWatcher GetWatcher(string folder, string pattern, NotifyFilters notifyOn)
|
||||
{
|
||||
var watcher = new System.IO.FileSystemWatcher
|
||||
var watcher = new FileSystemWatcher
|
||||
{
|
||||
NotifyFilter = notifyOn,
|
||||
Filter = pattern,
|
||||
|
@ -206,7 +205,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
public void OnCreated(object source, FileSystemEventArgs e)
|
||||
{
|
||||
var directories = new Dictionary<Uri, ImmutableHashSet<string>>();
|
||||
if (source is System.IO.FileSystemWatcher watcher &&
|
||||
if (source is FileSystemWatcher watcher &&
|
||||
this.globPatterns.TryGetValue(new Uri(watcher.Path), out var globPatterns))
|
||||
{
|
||||
var maxNrTries = 10; // copied directories need some time until they are on disk -> todo: better solution?
|
||||
|
|
|
@ -761,6 +761,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
this.rpc.InvokeWithParameterObjectAsync<ApplyWorkspaceEditResponse>(Methods.WorkspaceApplyEditName, edit)) :
|
||||
param.Command == CommandIds.FileContentInMemory ? CastAndExecute<TextDocumentIdentifier>(this.editorState.FileContentInMemory) :
|
||||
param.Command == CommandIds.FileDiagnostics ? CastAndExecute<TextDocumentIdentifier>(this.editorState.FileDiagnostics) :
|
||||
param.Command == CommandIds.ProjectInformation ? CastAndExecute<TextDocumentIdentifier>(this.editorState.ProjectInformation) :
|
||||
null;
|
||||
}
|
||||
catch
|
||||
|
|
|
@ -37,12 +37,19 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
HelpText = "Port to use for TCP/IP connections.")]
|
||||
public int Port { get; set; }
|
||||
|
||||
[Option(
|
||||
"unnamed",
|
||||
Required = false,
|
||||
SetName = ConnectionViaPipe,
|
||||
HelpText = "Connect via anonymous pipes.")]
|
||||
internal bool UseAnonymousPipes { get; set; }
|
||||
|
||||
[Option(
|
||||
'w',
|
||||
"writer",
|
||||
Required = true,
|
||||
SetName = ConnectionViaPipe,
|
||||
HelpText = "Named pipe to write to.")]
|
||||
HelpText = "Name of handle of the pipe to write to.")]
|
||||
public string? WriterPipeName { get; set; }
|
||||
|
||||
[Option(
|
||||
|
@ -50,7 +57,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
"reader",
|
||||
Required = true,
|
||||
SetName = ConnectionViaPipe,
|
||||
HelpText = "Named pipe to read from.")]
|
||||
HelpText = "Name of handle of the pipe to read from.")]
|
||||
public string? ReaderPipeName { get; set; }
|
||||
|
||||
[Option(
|
||||
|
@ -133,7 +140,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
server = options.UseStdInOut
|
||||
? ConnectViaStdInOut(options.LogFile)
|
||||
: options.ReaderPipeName != null && options.WriterPipeName != null
|
||||
? ConnectViaNamedPipe(options.WriterPipeName, options.ReaderPipeName, options.LogFile)
|
||||
? ConnectViaPipes(options.WriterPipeName, options.ReaderPipeName, options.UseAnonymousPipes, options.LogFile)
|
||||
: ConnectViaSocket(port: options.Port, logFile: options.LogFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -181,7 +188,12 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
return new QsLanguageServer(Console.OpenStandardOutput(), Console.OpenStandardInput());
|
||||
}
|
||||
|
||||
internal static QsLanguageServer ConnectViaNamedPipe(string writerName, string readerName, string? logFile = null)
|
||||
internal static QsLanguageServer ConnectViaPipes(string writer, string reader, bool useAnonymousPipes, string? logFile = null) =>
|
||||
useAnonymousPipes
|
||||
? ConnectViaAnonymousPipes(writer, reader, logFile)
|
||||
: ConnectViaNamedPipes(writer, reader, logFile);
|
||||
|
||||
internal static QsLanguageServer ConnectViaNamedPipes(string writerName, string readerName, string? logFile = null)
|
||||
{
|
||||
Log($"Connecting via named pipe. {Environment.NewLine}ReaderPipe: \"{readerName}\" {Environment.NewLine}WriterPipe: \"{writerName}\"", logFile, stdout: true);
|
||||
var writerPipe = new NamedPipeClientStream(writerName);
|
||||
|
@ -202,6 +214,20 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
return new QsLanguageServer(writerPipe, readerPipe);
|
||||
}
|
||||
|
||||
internal static QsLanguageServer ConnectViaAnonymousPipes(string writerHandle, string readerHandle, string? logFile = null)
|
||||
{
|
||||
Log($"Connecting via anonymous pipe.", logFile, stdout: true);
|
||||
|
||||
var writerPipe = new AnonymousPipeClientStream(PipeDirection.Out, writerHandle);
|
||||
var readerPipe = new AnonymousPipeClientStream(PipeDirection.In, readerHandle);
|
||||
if (!writerPipe.IsConnected || !readerPipe.IsConnected)
|
||||
{
|
||||
Log($"[ERROR] Connection failed.", logFile);
|
||||
}
|
||||
|
||||
return new QsLanguageServer(writerPipe, readerPipe);
|
||||
}
|
||||
|
||||
internal static QsLanguageServer ConnectViaSocket(string hostname = "localhost", int port = 8008, string? logFile = null)
|
||||
{
|
||||
Log($"Connecting via socket. {Environment.NewLine}Port number: {port}", logFile, stdout: true);
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Microsoft.Quantum.QsLanguageServer
|
|||
}
|
||||
|
||||
private static readonly Regex TargetFrameworkMoniker =
|
||||
new Regex(@"(netstandard[1-9]\.[0-9])|(netcoreapp[1-9]\.[0-9])|(net[1-9][0-9][0-9]?)|(net[1-9]\.[0-9])");
|
||||
new(@"(netstandard[1-9]\.[0-9])|(netcoreapp[1-9]\.[0-9])|(net[1-9][0-9][0-9]?)|(net[1-9]\.[0-9])");
|
||||
|
||||
private readonly ImmutableArray<string> supportedQsFrameworks =
|
||||
ImmutableArray.Create("netstandard2.", "netcoreapp2.", "netcoreapp3.", "net6.");
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ExecutionTarget>ionq.qpu</ExecutionTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ using Microsoft.Build.Locator;
|
|||
|
||||
namespace Microsoft.Quantum.QsLanguageServer.Testing
|
||||
{
|
||||
internal static class VisualStudioInstanceWrapper
|
||||
internal static class MsBuildDefaults
|
||||
{
|
||||
public static Lazy<VisualStudioInstance> LazyVisualStudioInstance { get; }
|
||||
public static Lazy<VisualStudioInstance> LazyRegistration { get; }
|
||||
= new Lazy<VisualStudioInstance>(MSBuildLocator.RegisterDefaults);
|
||||
}
|
||||
}
|
|
@ -2,8 +2,11 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Quantum.QsCompiler;
|
||||
using Microsoft.Quantum.QsCompiler.CompilationBuilder;
|
||||
using Microsoft.Quantum.QsCompiler.ReservedKeywords;
|
||||
|
@ -12,25 +15,73 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|||
|
||||
namespace Microsoft.Quantum.QsLanguageServer.Testing
|
||||
{
|
||||
[TestClass]
|
||||
public class ProjectLoaderTests
|
||||
public partial class BasicFunctionality
|
||||
{
|
||||
private static string ProjectFileName(string project) =>
|
||||
Path.Combine("TestProjects", project, $"{project}.csproj");
|
||||
|
||||
internal static Uri ProjectUri(string project) =>
|
||||
new Uri(Path.GetFullPath(ProjectFileName(project)));
|
||||
new(Path.GetFullPath(ProjectFileName(project)));
|
||||
|
||||
internal static (Uri, ProjectInformation?) Context(string project)
|
||||
internal async Task<(Uri, ProjectInformation?)> GetProjectInformationAsync(string project)
|
||||
{
|
||||
var uri = ProjectUri(project);
|
||||
return (uri, CompilationContext.Load(uri));
|
||||
}
|
||||
var projDir = Path.GetDirectoryName(uri.AbsolutePath) ?? "";
|
||||
|
||||
[TestInitialize]
|
||||
public void RunMSBuildLocator()
|
||||
{
|
||||
_ = VisualStudioInstanceWrapper.LazyVisualStudioInstance.Value;
|
||||
var initParams = TestUtils.GetInitializeParams();
|
||||
initParams.RootUri = new Uri(projDir);
|
||||
await this.rpc.NotifyWithParameterObjectAsync(Methods.Initialize.Name, initParams);
|
||||
|
||||
var projectInfo = await this.GetProjectInformationAsync(uri);
|
||||
if (projectInfo is null)
|
||||
{
|
||||
return (uri, null);
|
||||
}
|
||||
|
||||
var stringReader = new StringReader(projectInfo);
|
||||
var reader = System.Xml.XmlReader.Create(stringReader);
|
||||
|
||||
void ReadElementGroup(string groupName, out List<string> paths)
|
||||
{
|
||||
paths = new List<string>();
|
||||
if (!reader.IsStartElement(groupName))
|
||||
{
|
||||
reader.ReadToNextSibling(groupName);
|
||||
}
|
||||
|
||||
reader.ReadStartElement(groupName);
|
||||
while (reader.IsStartElement("File"))
|
||||
{
|
||||
paths.Add(reader.GetAttribute("Path") ?? "");
|
||||
reader.ReadToNextSibling("File");
|
||||
}
|
||||
}
|
||||
|
||||
var outputPath = reader.IsStartElement("ProjectInfo")
|
||||
? reader.GetAttribute("OutputPath")
|
||||
: null;
|
||||
var targetCapability = reader.GetAttribute("TargetCapability");
|
||||
var processorArch = reader.GetAttribute("ProcessorArchitecture");
|
||||
|
||||
reader.ReadStartElement("ProjectInfo");
|
||||
ReadElementGroup("Sources", out var sources);
|
||||
ReadElementGroup("ProjectReferences", out var projectRefs);
|
||||
ReadElementGroup("References", out var references);
|
||||
reader.ReadEndElement();
|
||||
|
||||
var projectProperties = new Dictionary<string, string?>
|
||||
{
|
||||
{ MSBuildProperties.TargetPath, outputPath },
|
||||
{ MSBuildProperties.ResolvedTargetCapability, targetCapability },
|
||||
{ MSBuildProperties.ResolvedProcessorArchitecture, processorArch },
|
||||
};
|
||||
|
||||
var infos = new ProjectInformation(
|
||||
sourceFiles: sources,
|
||||
projectReferences: projectRefs,
|
||||
references: references,
|
||||
projectProperties);
|
||||
return (uri, infos);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -99,7 +150,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadNonQSharpProjects()
|
||||
public async Task LoadNonQSharpProjectsAsync()
|
||||
{
|
||||
var invalidProjects = new string[]
|
||||
{
|
||||
|
@ -110,16 +161,16 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
|
||||
foreach (var project in invalidProjects)
|
||||
{
|
||||
var (_, context) = Context(project);
|
||||
var (_, context) = await this.GetProjectInformationAsync(project);
|
||||
Assert.IsNull(context);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadOutdatedQSharpProject()
|
||||
public async Task LoadUnsupportedQSharpProjectAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test9");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test9");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test9.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -132,14 +183,16 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsTrue(context.UsesIntrinsics());
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadQSharpCoreLibraries()
|
||||
public async Task LoadUnsupportedQSharpCoreLibrariesAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test3");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test3");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test3.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -155,15 +208,21 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsTrue(context.UsesIntrinsics());
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
(projectFile, context) = Context("test12");
|
||||
projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task LoadQSharpCoreLibrariesAsync()
|
||||
{
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test12");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test12.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
||||
qsFiles = new string[]
|
||||
var qsFiles = new string[]
|
||||
{
|
||||
Path.Combine(projDir, "format", "Unformatted.qs"),
|
||||
Path.Combine(projDir, "Operation12a.qs"),
|
||||
|
@ -176,14 +235,16 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsFalse(context.UsesIntrinsics());
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadQSharpFrameworkLibrary()
|
||||
public async Task LoadQSharpFrameworkLibraryAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test7");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test7");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test7.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -196,14 +257,16 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsTrue(context.UsesIntrinsics());
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadQSharpConsoleApps()
|
||||
public async Task LoadUnsupportedQSharpConsoleAppAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test4");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test4");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test4.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -217,44 +280,58 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
Assert.IsTrue(context.UsesProject("test3.csproj"));
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
(projectFile, context) = Context("test10");
|
||||
projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task LoadOutdatedQSharpConsoleAppAsync()
|
||||
{
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test10");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test10.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
||||
qsFiles = new string[]
|
||||
var qsFiles = new string[]
|
||||
{
|
||||
Path.Combine(projDir, "Operation10.qs"),
|
||||
};
|
||||
|
||||
Assert.IsTrue(context.UsesIntrinsics());
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
(projectFile, context) = Context("test11");
|
||||
projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task LoadQSharpConsoleAppAsync()
|
||||
{
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test11");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test11.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
||||
qsFiles = new string[]
|
||||
var qsFiles = new string[]
|
||||
{
|
||||
Path.Combine(projDir, "Operation11.qs"),
|
||||
};
|
||||
|
||||
Assert.IsTrue(context.UsesIntrinsics());
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadTargetedQSharpExecutable()
|
||||
public async Task LoadTargetedQSharpExecutableAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test17");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test17");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test17.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -272,14 +349,16 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsFalse(context.UsesDll("Microsoft.Quantum.Type3.Core.dll"));
|
||||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadQSharpUnitTest()
|
||||
public async Task LoadQSharpUnitTestAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test5");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test5");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test5.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -296,14 +375,16 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsTrue(context.UsesXunitHelper());
|
||||
Assert.IsTrue(context.UsesProject("test3.csproj"));
|
||||
Assert.IsTrue(context.UsesProject("test4.csproj"));
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LoadQSharpMultiFrameworkLibrary()
|
||||
public async Task LoadQSharpMultiFrameworkLibraryAsync()
|
||||
{
|
||||
var (projectFile, context) = Context("test6");
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var (projectFile, context) = await this.GetProjectInformationAsync("test6");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
Assert.IsNotNull(context);
|
||||
Assert.AreEqual("test6.dll", Path.GetFileName(context!.Properties.DllOutputPath));
|
||||
Assert.IsTrue((Path.GetDirectoryName(context.Properties.DllOutputPath) ?? "").StartsWith(projDir));
|
||||
|
@ -319,7 +400,9 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsTrue(context.UsesCanon());
|
||||
Assert.IsFalse(context.UsesXunitHelper());
|
||||
Assert.IsTrue(context.UsesProject("test3.csproj"));
|
||||
CollectionAssert.AreEquivalent(qsFiles, context.SourceFiles.ToArray());
|
||||
|
||||
var expected = qsFiles.Select(Path.GetFullPath).Select(p => new Uri(p).AbsolutePath).ToArray();
|
||||
CollectionAssert.AreEquivalent(expected, context.SourceFiles.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,10 +412,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Console.WriteLine($"[{level}]: {msg}");
|
||||
|
||||
internal static EditorState Editor =>
|
||||
new EditorState(new ProjectLoader(LogOutput), null, null, null, null);
|
||||
|
||||
internal static ProjectInformation? Load(Uri projectFile) =>
|
||||
Editor.QsProjectLoader(projectFile, out var loaded) ? loaded : null;
|
||||
new(new ProjectLoader(LogOutput), null, null, null, null);
|
||||
|
||||
internal static bool UsesDll(this ProjectInformation info, string dll) => info.References.Any(r => r.EndsWith(dll));
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ using System.Linq;
|
|||
using Microsoft.Quantum.QsCompiler.TextProcessing;
|
||||
using Microsoft.VisualStudio.LanguageServer.Protocol;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Builder = Microsoft.Quantum.QsCompiler.CompilationBuilder.Utils;
|
||||
|
||||
namespace Microsoft.Quantum.QsLanguageServer.Testing
|
||||
{
|
||||
|
@ -48,12 +47,12 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
return current;
|
||||
}
|
||||
|
||||
private static string[] allKeywords = Keywords.ReservedKeywords.ToArray();
|
||||
private static readonly string[] AllKeywords = Keywords.ReservedKeywords.ToArray();
|
||||
|
||||
internal string[] GetRandomLines(int nrLines, bool withLanguageKeywords = true)
|
||||
{
|
||||
var lines = new string[nrLines];
|
||||
string GetKeyword() => $" {allKeywords[this.rnd.Next(0, allKeywords.Length)]} ";
|
||||
string GetKeyword() => $" {AllKeywords[this.rnd.Next(0, AllKeywords.Length)]} ";
|
||||
for (var nr = 0; nr < nrLines; ++nr)
|
||||
{
|
||||
lines[nr] = this.GetRandomLine();
|
||||
|
@ -70,7 +69,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
{
|
||||
var filename = Path.Combine(TestInputDirectory, Path.GetRandomFileName()) + (withQsExtension ? ".qs" : "z"); // guarantee .qs extension exists or not
|
||||
var content = this.GetRandomLines(nrLines, withLanguageKeywords);
|
||||
using (StreamWriter sw = new StreamWriter(filename))
|
||||
using (StreamWriter sw = new(filename))
|
||||
{
|
||||
foreach (var line in content)
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Runtime.InteropServices;
|
||||
|
@ -22,9 +23,9 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
|
||||
private Connection? connection;
|
||||
private JsonRpc rpc = null!; // Initialized in SetupServerConnectionAsync.
|
||||
private readonly RandomInput inputGenerator = new RandomInput();
|
||||
private readonly Stack<PublishDiagnosticParams> receivedDiagnostics = new Stack<PublishDiagnosticParams>();
|
||||
private readonly ManualResetEvent projectLoaded = new ManualResetEvent(false);
|
||||
private readonly RandomInput inputGenerator = new();
|
||||
private readonly Stack<PublishDiagnosticParams> receivedDiagnostics = new();
|
||||
private readonly ManualResetEvent projectLoaded = new(false);
|
||||
|
||||
public Task<string[]> GetFileContentInMemoryAsync(string filename) =>
|
||||
this.rpc.InvokeWithParameterObjectAsync<string[]>(
|
||||
|
@ -36,6 +37,11 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Methods.WorkspaceExecuteCommand.Name,
|
||||
TestUtils.ServerCommand(CommandIds.FileDiagnostics, filename == null ? new TextDocumentIdentifier { Uri = new Uri("file://unknown") } : TestUtils.GetTextDocumentIdentifier(filename)));
|
||||
|
||||
public Task<string> GetProjectInformationAsync(Uri projectFile) =>
|
||||
this.rpc.InvokeWithParameterObjectAsync<string>(
|
||||
Methods.WorkspaceExecuteCommand.Name,
|
||||
TestUtils.ServerCommand(CommandIds.ProjectInformation, new TextDocumentIdentifier() { Uri = projectFile }));
|
||||
|
||||
public Task SetupAsync()
|
||||
{
|
||||
var initParams = TestUtils.GetInitializeParams();
|
||||
|
@ -55,9 +61,10 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
[TestInitialize]
|
||||
public async Task SetupServerConnectionAsync()
|
||||
{
|
||||
// Need to run MSBuildLocator for some tests like UpdateProjectFileAsync
|
||||
_ = VisualStudioInstanceWrapper.LazyVisualStudioInstance.Value;
|
||||
// Need to run MSBuildLocator for some tests.
|
||||
_ = MsBuildDefaults.LazyRegistration.Value;
|
||||
|
||||
var logFile = Path.GetTempFileName();
|
||||
Directory.CreateDirectory(RandomInput.TestInputDirectory);
|
||||
var outputDir = new DirectoryInfo(RandomInput.TestInputDirectory);
|
||||
foreach (var file in outputDir.GetFiles())
|
||||
|
@ -73,18 +80,20 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
var readerPipe = new NamedPipeServerStream(serverWriterPipe, PipeDirection.InOut, 4, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 256, 256);
|
||||
var writerPipe = new NamedPipeServerStream(serverReaderPipe, PipeDirection.InOut, 4, PipeTransmissionMode.Message, PipeOptions.Asynchronous, 256, 256);
|
||||
|
||||
var server = Server.ConnectViaNamedPipe(serverWriterPipe, serverReaderPipe);
|
||||
Server.ConnectViaNamedPipes(serverWriterPipe, serverReaderPipe);
|
||||
|
||||
await readerPipe.WaitForConnectionAsync().ConfigureAwait(true);
|
||||
await writerPipe.WaitForConnectionAsync().ConfigureAwait(true);
|
||||
this.connection = new Connection(readerPipe, writerPipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
var readerPipe = new System.IO.Pipelines.Pipe();
|
||||
var writerPipe = new System.IO.Pipelines.Pipe();
|
||||
var readerPipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
|
||||
var writerPipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
|
||||
|
||||
var server = new QsLanguageServer(sender: writerPipe.Writer.AsStream(), reader: readerPipe.Reader.AsStream());
|
||||
this.connection = new Connection(writerPipe.Reader.AsStream(), readerPipe.Writer.AsStream());
|
||||
Server.ConnectViaAnonymousPipes(readerPipe.GetClientHandleAsString(), writerPipe.GetClientHandleAsString());
|
||||
|
||||
this.connection = new Connection(readerPipe, writerPipe);
|
||||
}
|
||||
|
||||
this.rpc = new JsonRpc(this.connection.Writer, this.connection.Reader, this)
|
||||
|
|
|
@ -17,10 +17,8 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
{
|
||||
internal static class TestUtils
|
||||
{
|
||||
internal static Uri GetUri(string filename)
|
||||
{
|
||||
return new Uri(Path.GetFullPath(filename));
|
||||
}
|
||||
internal static Uri GetUri(string filename) =>
|
||||
new(Path.GetFullPath(filename));
|
||||
|
||||
internal static List<string> GetContent(string filename)
|
||||
{
|
||||
|
@ -38,14 +36,11 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
return content;
|
||||
}
|
||||
|
||||
internal static TextDocumentIdentifier GetTextDocumentIdentifier(string filename)
|
||||
{
|
||||
return new TextDocumentIdentifier { Uri = GetUri(filename) };
|
||||
}
|
||||
internal static TextDocumentIdentifier GetTextDocumentIdentifier(string filename) =>
|
||||
new() { Uri = GetUri(filename) };
|
||||
|
||||
internal static InitializeParams GetInitializeParams()
|
||||
{
|
||||
return new InitializeParams
|
||||
internal static InitializeParams GetInitializeParams() =>
|
||||
new()
|
||||
{
|
||||
ProcessId = -1,
|
||||
InitializationOptions = null,
|
||||
|
@ -56,7 +51,6 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Experimental = new object(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
internal static DidOpenTextDocumentParams GetOpenFileParams(string filename)
|
||||
{
|
||||
|
@ -90,7 +84,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
}
|
||||
|
||||
internal static ExecuteCommandParams ServerCommand(string command, params object[] args) =>
|
||||
new ExecuteCommandParams { Command = command, Arguments = args };
|
||||
new() { Command = command, Arguments = args };
|
||||
|
||||
// does not modify range
|
||||
internal static int GetRangeLength(Range range, IReadOnlyList<string> content)
|
||||
|
@ -118,14 +112,14 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
}
|
||||
|
||||
Assert.IsTrue(IsValidRange(change.Range) && change.Text != null);
|
||||
Assert.IsTrue(change.Range.End.Line < content.Count());
|
||||
Assert.IsTrue(change.Range.End.Line < content.Count);
|
||||
Assert.IsTrue(change.Range.Start.Character <= content[change.Range.Start.Line].Length);
|
||||
Assert.IsTrue(change.Range.End.Character <= content[change.Range.End.Line].Length);
|
||||
|
||||
var (startLine, startChar) = (change.Range.Start.Line, change.Range.Start.Character);
|
||||
var (endLine, endChar) = (change.Range.End.Line, change.Range.End.Character);
|
||||
|
||||
var newText = string.Concat(content[startLine].Substring(0, startChar), change.Text, content[endLine].Substring(endChar));
|
||||
var newText = string.Concat(content[startLine][..startChar], change.Text, content[endLine][endChar..]);
|
||||
if (startLine > 0)
|
||||
{
|
||||
newText = content[--startLine] + newText;
|
||||
|
@ -133,11 +127,11 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
|
||||
if (endLine + 1 < content.Count)
|
||||
{
|
||||
newText = newText + content[++endLine];
|
||||
newText += content[++endLine];
|
||||
}
|
||||
|
||||
var lineChanges = Builder.SplitLines(newText);
|
||||
if (lineChanges.Length == 0 || (endLine + 1 == content.Count() && Builder.EndOfLine.Match(lineChanges.Last()).Success))
|
||||
if (lineChanges.Length == 0 || (endLine + 1 == content.Count && Builder.EndOfLine.Match(lineChanges.Last()).Success))
|
||||
{
|
||||
lineChanges = lineChanges.Concat(new string[] { string.Empty }).ToArray();
|
||||
}
|
||||
|
@ -153,8 +147,8 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
static bool IsBeforeOrEqual(Position a, Position b) =>
|
||||
a.Line < b.Line || (a.Line == b.Line && a.Character <= b.Character);
|
||||
|
||||
return !(range?.Start is null) &&
|
||||
!(range.End is null) &&
|
||||
return range?.Start is not null &&
|
||||
range.End is not null &&
|
||||
IsValidPosition(range.Start) &&
|
||||
IsValidPosition(range.End) &&
|
||||
IsBeforeOrEqual(range.Start, range.End);
|
||||
|
@ -207,7 +201,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
/// <returns>The project manager for the fully loaded project.</returns>
|
||||
internal static async Task<ProjectManager> LoadProjectAsync(this Uri projectFile, SendTelemetryHandler? telemetryHandler = null)
|
||||
{
|
||||
ManualResetEvent eventSignal = new ManualResetEvent(false);
|
||||
ManualResetEvent eventSignal = new(false);
|
||||
void CheckForLoadingCompleted(string msg, MessageType messageType)
|
||||
{
|
||||
Console.WriteLine($"[{messageType}]: {msg}");
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.LanguageServer.Client" Version="17.2.2105" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
|
||||
<PackageReference Include="System.IO.Pipelines" Version="6.0.1" />
|
||||
<PackageReference Include="System.IO.Pipes" Version="4.3.0" />
|
||||
<PackageReference Include="NuGet.Frameworks" Version="6.2.1-rc.7" />
|
||||
<PackageReference Include="NuGet.Frameworks" Version="6.2.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -32,21 +32,21 @@
|
|||
<ItemGroup>
|
||||
<Content Include="..\TestProjects\**\*proj">
|
||||
<Link>TestProjects\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\TestProjects\**\*.qs">
|
||||
<Link>TestProjects\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PublishQsFmt" BeforeTargets="BeforeCompile">
|
||||
<Target Name="PublishTools" BeforeTargets="BeforeCompile">
|
||||
<Message Importance="high" Text="Publishing QsFmt"/>
|
||||
<PropertyGroup>
|
||||
<QsFmtPublishPath>$(OutputPath)\qsfmt\</QsFmtPublishPath>
|
||||
<QsFmtPublishCommand>dotnet publish "$(EnlistmentRoot)src/QsFmt/App/App.fsproj" -o "$(QsFmtPublishPath)"</QsFmtPublishCommand>
|
||||
</PropertyGroup>
|
||||
<MakeDir Directories="$(OutputPath)\qsfmt" />
|
||||
<MakeDir Directories="$(QsFmtPublishPath)" />
|
||||
<Exec Command="$(QsFmtPublishCommand)" IgnoreExitCode="false" ContinueOnError="ErrorAndContinue">
|
||||
<Output TaskParameter="ExitCode" PropertyName="QsFmtPublishExitCode" />
|
||||
</Exec>
|
||||
|
|
|
@ -32,8 +32,8 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
public async Task ShutdownAsync()
|
||||
{
|
||||
// the shutdown request should *not* result in the server exiting, and calling multiple times is fine
|
||||
_ = await this.rpc.InvokeAsync<object>(Methods.Shutdown.Name);
|
||||
var response = await this.rpc.InvokeAsync<object>(Methods.Shutdown.Name);
|
||||
response = await this.rpc.InvokeAsync<object>(Methods.Shutdown.Name);
|
||||
Assert.IsNull(response);
|
||||
Assert.IsNotNull(this.rpc);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
await this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidClose.Name, TestUtils.GetCloseFileParams(filename));
|
||||
|
||||
// verify that a file can be closed immediately after it was opened
|
||||
var openTask = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename));
|
||||
_ = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename));
|
||||
await this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidClose.Name, TestUtils.GetCloseFileParams(filename));
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
await this.SetupAsync();
|
||||
|
||||
// verify that safe notification can be sent immediately after sending the open notification (even if the latter has not yet finished processing)
|
||||
var openFileTask = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename));
|
||||
_ = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename));
|
||||
await this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidSave.Name, TestUtils.GetSaveFileParams(filename, content));
|
||||
|
||||
// check that the file content is indeed updated on save, according to the passed parameter
|
||||
|
@ -169,13 +169,13 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
// and the file can be closed and no diagnostics are left even if some changes are still queued for processing
|
||||
var edits = this.inputGenerator.MakeRandomEdits(50, ref content, fileSize, false);
|
||||
Task[] processing = new Task[edits.Length];
|
||||
var openFileTask = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename));
|
||||
_ = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidOpen.Name, TestUtils.GetOpenFileParams(filename));
|
||||
for (var i = 0; i < edits.Length; ++i)
|
||||
{
|
||||
processing[i] = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidChange.Name, TestUtils.GetChangedFileParams(filename, new[] { edits[i] }));
|
||||
}
|
||||
|
||||
var closeFileTask = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidClose.Name, TestUtils.GetCloseFileParams(filename));
|
||||
_ = this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidClose.Name, TestUtils.GetCloseFileParams(filename));
|
||||
var finalDiagnostics = await this.GetFileDiagnosticsAsync(filename);
|
||||
|
||||
// check that the file is no longer present in the default manager after closing (final diagnostics are null), and
|
||||
|
@ -210,14 +210,14 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
var expected = Builder.JoinLines(expectedContent.ToArray());
|
||||
var got = Builder.JoinLines(trackedContent);
|
||||
Assert.IsNotNull(trackedContent);
|
||||
Assert.AreEqual(expectedContent.Count(), trackedContent.Count(), $"expected: \n{expected} \ngot: \n{got}");
|
||||
Assert.AreEqual(expectedContent.Count, trackedContent.Length, $"expected: \n{expected} \ngot: \n{got}");
|
||||
Assert.AreEqual(expected, got);
|
||||
|
||||
// check whether a single array of changes is processed correctly
|
||||
var edits = this.inputGenerator.MakeRandomEdits(50, ref expectedContent, fileSize, false);
|
||||
await this.rpc.InvokeWithParameterObjectAsync<Task>(Methods.TextDocumentDidChange.Name, TestUtils.GetChangedFileParams(filename, edits));
|
||||
trackedContent = await this.GetFileContentInMemoryAsync(filename);
|
||||
Assert.AreEqual(expectedContent.Count(), trackedContent.Count());
|
||||
Assert.AreEqual(expectedContent.Count, trackedContent.Length);
|
||||
Assert.AreEqual(Builder.JoinLines(expectedContent.ToArray()), Builder.JoinLines(trackedContent));
|
||||
|
||||
// check if changes are also processed correctly if many changes (array of length one) are given in rapid succession
|
||||
|
@ -240,7 +240,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
|
||||
expected = Builder.JoinLines(expectedContent.ToArray());
|
||||
got = Builder.JoinLines(trackedContent);
|
||||
Assert.AreEqual(expectedContent.Count(), trackedContent.Count(), $"expected: \n{expected} \ngot: \n{got}");
|
||||
Assert.AreEqual(expectedContent.Count, trackedContent.Length, $"expected: \n{expected} \ngot: \n{got}");
|
||||
Assert.AreEqual(expected, got);
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
var expected = Builder.JoinLines(expectedContent.ToArray());
|
||||
var got = Builder.JoinLines(trackedContent);
|
||||
Assert.IsNotNull(trackedContent);
|
||||
Assert.AreEqual(expectedContent.Count(), trackedContent.Count(), $"expected: \n{expected} \ngot: \n{got}");
|
||||
Assert.AreEqual(expectedContent.Count, trackedContent.Length, $"expected: \n{expected} \ngot: \n{got}");
|
||||
Assert.AreEqual(expected, got);
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
[TestMethod]
|
||||
public async Task TargetPackageIntrinsicsAsync()
|
||||
{
|
||||
var projectFile = ProjectLoaderTests.ProjectUri("test17");
|
||||
var projectFile = ProjectUri("test17");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
var programFile = Path.Combine(projDir, "MeasureBell.qs");
|
||||
|
||||
|
@ -311,7 +311,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
[TestMethod]
|
||||
public async Task UpdateProjectFileAsync()
|
||||
{
|
||||
var projectFile = ProjectLoaderTests.ProjectUri("test14");
|
||||
var projectFile = ProjectUri("test14");
|
||||
var projDir = Path.GetDirectoryName(projectFile.AbsolutePath) ?? "";
|
||||
var programFile = Path.Combine(projDir, "Teleport.qs");
|
||||
var projectFileContent = XDocument.Load(projectFile.AbsolutePath);
|
||||
|
@ -363,7 +363,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
{
|
||||
async Task RunFormattingTestAsync(string projectName)
|
||||
{
|
||||
var projectFile = ProjectLoaderTests.ProjectUri(projectName);
|
||||
var projectFile = ProjectUri(projectName);
|
||||
var projDir = Path.GetDirectoryName(projectFile.LocalPath) ?? "";
|
||||
var telemetryEvents = new List<(string, int)>();
|
||||
var projectManager = await projectFile.LoadProjectAsync(
|
||||
|
@ -381,7 +381,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
Assert.IsNotNull(edits);
|
||||
Assert.AreEqual(1, edits!.Length);
|
||||
Assert.AreEqual(expectedContent, edits[0].NewText);
|
||||
Assert.AreEqual(1, telemetryEvents.Count());
|
||||
Assert.AreEqual(1, telemetryEvents.Count);
|
||||
Assert.AreEqual("formatting", telemetryEvents[0].Item1);
|
||||
Assert.AreEqual(edits.Length, telemetryEvents[0].Item2);
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
[TestMethod]
|
||||
public async Task TestLambdaHoverInfoAsync()
|
||||
{
|
||||
var projectFile = ProjectLoaderTests.ProjectUri("test16");
|
||||
var projectFile = ProjectUri("test16");
|
||||
var projectManager = await LoadProjectFileAsync(projectFile);
|
||||
var lambdaFile = new Uri(projectFile, "Lambda.qs");
|
||||
|
||||
|
@ -463,7 +463,7 @@ namespace Microsoft.Quantum.QsLanguageServer.Testing
|
|||
[TestMethod]
|
||||
public async Task TestLambdaReferencesAsync()
|
||||
{
|
||||
var projectFile = ProjectLoaderTests.ProjectUri("test16");
|
||||
var projectFile = ProjectUri("test16");
|
||||
var projectManager = await LoadProjectFileAsync(projectFile);
|
||||
var lambdaFile = new Uri(projectFile, "Lambda.qs");
|
||||
|
||||
|
|
|
@ -43,6 +43,6 @@
|
|||
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.9.0" ExcludeAssets="runtime" />
|
||||
<PackageReference Include="NuGet.ProjectModel" Version="6.2.1" />
|
||||
<PackageReference Include="NuGet.Frameworks" Version="6.2.1" />
|
||||
<PackageReference Include="NuGet.Frameworks" Version="6.2.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="$(SolutionDir)src\QsCompiler\Tests.Compiler\TestCases\**\*.qs">
|
||||
<Content Include="$(MSBuildThisFileDirectory)..\..\QsCompiler\Tests.Compiler\TestCases\**\*.qs">
|
||||
<Link>TestCases\%(FileName)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Compile Include="Tests.fs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Microsoft.Quantum.Telemetry.Commands
|
|||
{
|
||||
var isPii = this.Args.PiiProperties.ContainsKey(property.Key);
|
||||
if (!logEventCommand.Args.Properties.TryGetValue(property.Key, out var value)
|
||||
|| !object.Equals(value, property.Value)
|
||||
|| !Equals(value, property.Value)
|
||||
|| (isPii && !logEventCommand.Args.PiiProperties.ContainsKey(property.Key)))
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Microsoft.Quantum.Telemetry.Commands
|
|||
|
||||
public override bool Equals(object? obj) =>
|
||||
(obj is SetContextCommand setContextCommand)
|
||||
&& object.Equals(this.Args, setContextCommand.Args);
|
||||
&& Equals(this.Args, setContextCommand.Args);
|
||||
|
||||
public override int GetHashCode() =>
|
||||
this.CommandType.GetHashCode() ^ this.Args.GetHashCode();
|
||||
|
@ -52,10 +52,10 @@ namespace Microsoft.Quantum.Telemetry.Commands
|
|||
{
|
||||
if (obj is SetContextArgs setContextArgs)
|
||||
{
|
||||
return object.Equals(setContextArgs.IsPii, this.IsPii)
|
||||
&& object.Equals(setContextArgs.Name, this.Name)
|
||||
&& object.Equals(setContextArgs.PropertyType, this.PropertyType)
|
||||
&& object.Equals(setContextArgs.Value, this.Value);
|
||||
return Equals(setContextArgs.IsPii, this.IsPii)
|
||||
&& Equals(setContextArgs.Name, this.Name)
|
||||
&& Equals(setContextArgs.PropertyType, this.PropertyType)
|
||||
&& Equals(setContextArgs.Value, this.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -20,8 +20,7 @@ namespace Microsoft.Quantum.Telemetry
|
|||
internal static PiiKind ToPiiKind(this bool isPii) =>
|
||||
isPii ? PiiKind.GenericData : PiiKind.None;
|
||||
|
||||
private static Dictionary<TelemetryPropertyType, Action<ILogger, string, object, PiiKind>> setContextActions =
|
||||
new Dictionary<TelemetryPropertyType, Action<ILogger, string, object, PiiKind>>()
|
||||
private static readonly Dictionary<TelemetryPropertyType, Action<ILogger, string, object, PiiKind>> SetContextActions = new()
|
||||
{
|
||||
{ TelemetryPropertyType.Boolean, (logger, name, value, piiKind) => logger.SetContext(name, (bool)value, piiKind) },
|
||||
{ TelemetryPropertyType.DateTime, (logger, name, value, piiKind) => logger.SetContext(name, (DateTime)value, piiKind) },
|
||||
|
@ -32,7 +31,7 @@ namespace Microsoft.Quantum.Telemetry
|
|||
};
|
||||
|
||||
internal static void SetContext(this ILogger logger, string name, object value, TelemetryPropertyType propertyType, bool isPii) =>
|
||||
setContextActions[propertyType](logger, name, value, isPii.ToPiiKind());
|
||||
SetContextActions[propertyType](logger, name, value, isPii.ToPiiKind());
|
||||
|
||||
private static Dictionary<TelemetryPropertyType, Action<EventProperties, string, object, PiiKind>> setPropertyMethods =
|
||||
new Dictionary<TelemetryPropertyType, Action<EventProperties, string, object, PiiKind>>()
|
||||
|
@ -55,7 +54,7 @@ namespace Microsoft.Quantum.Telemetry
|
|||
{
|
||||
if (value != null)
|
||||
{
|
||||
var convertedValue = TypeConversionHelper.ConvertValue(value, serializeJson);
|
||||
var convertedValue = ConvertValue(value, serializeJson);
|
||||
if (convertedValue != null)
|
||||
{
|
||||
eventProperties.SetProperty(name, convertedValue.Item2, convertedValue.Item1, isPii.ToPiiKind());
|
||||
|
|
Загрузка…
Ссылка в новой задаче