public async Task new_commands_issued_after_cancel_are_executed() { var kernel = CreateKernel() .LogCommandsToPocketLogger() .LogEventsToPocketLogger(); var commandToCancel = new SubmitCode(@" using Microsoft.DotNet.Interactive; while(!KernelInvocationContext.Current.CancellationToken.IsCancellationRequested){ await Task.Delay(10); }", targetKernelName: "csharp"); var _ = kernel.SendAsync(commandToCancel); await kernel.SendAsync(new Cancel()); var followingCommand = new SubmitCode("1"); await kernel.SendAsync(followingCommand); KernelEvents .Should() .ContainSingle <CommandSucceeded>(c => c.Command == followingCommand); }
public async Task it_returns_completion_list_for_types_imported_at_runtime() { var kernel = CreateKernel(); var dll = new FileInfo(typeof(JsonConvert).Assembly.Location).FullName; await kernel.SendAsync( new SubmitCode($"#r \"{dll}\"")); await kernel.SendAsync(new RequestCompletion("Newtonsoft.Json.JsonConvert.", 28)); KernelEvents.Should() .ContainSingle(e => e.Value is CompletionRequestReceived); KernelEvents.Single(e => e.Value is CompletionRequestCompleted) .Value .As <CompletionRequestCompleted>() .CompletionList .Should() .Contain(i => i.DisplayText == "SerializeObject"); }
public async Task can_cancel_user_loop_using_CancellationToken() { var kernel = CreateKernel(); var cancelCommand = new Cancel(); var commandToCancel = new SubmitCode(@" using Microsoft.DotNet.Interactive; while(!KernelInvocationContext.Current.CancellationToken.IsCancellationRequested){ await Task.Delay(10); }", targetKernelName: "csharp"); var resultForCommandToCancel = kernel.SendAsync(commandToCancel); await kernel.SendAsync(cancelCommand); await resultForCommandToCancel; KernelEvents .Should() .ContainSingle <CommandFailed>(c => c.Command == commandToCancel); }
public async Task Should_load_extension_in_directory() { var directory = Create.EmptyWorkspace().Directory; const string nugetPackageName = "myNugetPackage"; var nugetPackageDirectory = new InMemoryDirectoryAccessor( directory.Subdirectory($"{nugetPackageName}/2.0.0")) .CreateFiles(); var extensionsDir = (FileSystemDirectoryAccessor)nugetPackageDirectory.GetDirectoryAccessorForRelativePath(new RelativeDirectoryPath("interactive-extensions/dotnet/cs")); var extensionDll = await KernelExtensionTestHelper.CreateExtensionInDirectory( directory, @"await kernel.SendAsync(new SubmitCode(""using System.Reflection;""));", extensionsDir); var kernel = CreateKernel(); await kernel.SendAsync(new LoadExtensionsInDirectory(nugetPackageDirectory)); KernelEvents.Should() .ContainSingle(e => e.Value is ExtensionLoaded && e.Value.As <ExtensionLoaded>().ExtensionPath.FullName.Equals(extensionDll.FullName)); KernelEvents.Should() .ContainSingle(e => e.Value is CommandHandled && e.Value .As <CommandHandled>() .Command .As <SubmitCode>() .Code .Contains("using System.Reflection;")); KernelEvents.Should().ContainSingle(e => e.Value is DisplayedValueProduced && e.Value.As <DisplayedValueProduced>() .Value .ToString() .Contains($"Loaded kernel extension TestKernelExtension from assembly {extensionDll.FullName}")); }
public async Task correct_signature_help_is_displayed(Language language, string submittedCode, string markupCode, int activeSignature, string signaureLabel, int activeParameter, string parameterName) { var kernel = CreateKernel(language); await kernel.SubmitCodeAsync(submittedCode); MarkupTestFile.GetLineAndColumn(markupCode, out var code, out var line, out var column); await kernel.SendAsync(new RequestSignatureHelp(code, new LinePosition(line, column))); KernelEvents .Should() .ContainSingle <SignatureHelpProduced>() .Which .Signatures .Should() .HaveCountGreaterThan(activeSignature) .And .ContainSingle(signatureInfo => signatureInfo.Label == signaureLabel && signatureInfo.Parameters.Count > activeParameter && signatureInfo.Parameters[activeParameter].Label == parameterName); }
public async Task Completions_are_available_for_symbols_members(Language language) { var declaration = language switch { Language.CSharp => new SubmitCode("var fileInfo = new System.IO.FileInfo(\"temp.file\");"), Language.FSharp => new SubmitCode("let fileInfo = new System.IO.FileInfo(\"temp.file\")") }; var kernel = CreateKernel(language); await kernel.SendAsync(declaration); MarkupTestFile.GetLineAndColumn("fileInfo.$$", out var useInput, out var line, out var column); await kernel.SendAsync(new RequestCompletions(useInput, new LinePosition(line, column))); KernelEvents .Should() .ContainSingle <CompletionsProduced>() .Which .Completions .Should() .Contain(item => item.DisplayText == "AppendText"); }
public async Task completion_commands_and_events_have_offsets_normalized_when_switching_languages() { // switch to PowerShell from an F# kernel/cell using var kernel = CreateCompositeKernel(Language.FSharp); var fullMarkupCode = string.Join("\r\n", new[] { "let x = 1", "#!pwsh", "Get-$$" }); MarkupTestFile.GetLineAndColumn(fullMarkupCode, out var code, out var line, out var character); await kernel.SendAsync(new RequestCompletions(code, new LinePosition(line, character))); KernelEvents .Should() .ContainSingle <CompletionsProduced>() .Which .LinePositionSpan .Should() .Be(new LinePositionSpan(new LinePosition(line, 0), new LinePosition(line, 4))); }
public async Task csharp_signature_help_can_read_doc_comments_from_nuget_packages_after_forcing_the_assembly_to_load() { using var kernel = CreateKernel(Language.CSharp); await SubmitCode(kernel, "#r \"nuget: Newtonsoft.Json, 12.0.3\""); // The following line forces the assembly and the doc comments to be loaded await SubmitCode(kernel, "var _unused = Newtonsoft.Json.JsonConvert.Null;"); var markupCode = "Newtonsoft.Json.JsonConvert.DeserializeObject($$"; MarkupTestFile.GetLineAndColumn(markupCode, out var code, out var line, out var character); await kernel.SendAsync(new RequestSignatureHelp(code, new LinePosition(line, character))); KernelEvents .Should() .ContainSingle <SignatureHelpProduced>() .Which .Signatures .Should() .ContainSingle(sh => sh.Documentation.Value.Contains("Deserializes the JSON to a .NET object.")); }
public async Task csharp_completions_can_read_doc_comments_from_nuget_packages_after_forcing_the_assembly_to_load() { using var kernel = CreateKernel(Language.CSharp); await SubmitCode(kernel, "#r \"nuget: Newtonsoft.Json, 12.0.3\""); // The following line forces the assembly and the doc comments to be loaded await SubmitCode(kernel, "var _unused = Newtonsoft.Json.JsonConvert.Null;"); var markupCode = "Newtonsoft.Json.JsonConvert.Nu$$"; MarkupTestFile.GetLineAndColumn(markupCode, out var code, out var line, out var character); await kernel.SendAsync(new RequestCompletions(code, new LinePosition(line, character))); KernelEvents .Should() .ContainSingle <CompletionsProduced>() .Which .Completions .Should() .ContainSingle(ci => ci.Documentation != null && ci.Documentation.Contains("Represents JavaScript's null as a string. This field is read-only.")); }
public async Task it_can_load_assembly_references_using_r_directive_separate_submissions(Language language) { var kernel = CreateKernel(language); // F# strings treat \ as an escape character. So do C# strings, except #r in C# is special, and doesn't. F# usually uses @ strings for paths @"c:\temp\...." var dllPath = new FileInfo(typeof(JsonConvert).Assembly.Location).FullName.Replace('\\', '/'); var source = language switch { Language.FSharp => new[] { $"#r \"{dllPath}\"", "open Newtonsoft.Json", @"let json = JsonConvert.SerializeObject( struct {| value = ""hello"" |} )", "json" }, Language.CSharp => new[] { $"#r \"{dllPath}\"", "using Newtonsoft.Json;", @"var json = JsonConvert.SerializeObject(new { value = ""hello"" });", "json" } }; await SubmitCode(kernel, source); KernelEvents .Should() .ContainSingle(e => e is ReturnValueProduced); KernelEvents .OfType <ReturnValueProduced>() .Single() .Value .Should() .Be(new { value = "hello" }.ToJson()); }
public async Task Display_indicates_when_a_value_is_null(Language language) { var kernel = CreateKernel(language); var submission = language switch { Language.CSharp => "display(null);", Language.FSharp => "display(null)" }; await kernel.SendAsync(new SubmitCode(submission)); KernelEvents.Should().NotContainErrors(); KernelEvents .OfType <DisplayedValueProduced>() .SelectMany(v => v.FormattedValues) .Should() .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains(Formatter.NullString.HtmlEncode().ToString())); }
public async Task Should_load_extension_in_directory() { var directory = DirectoryUtility.CreateDirectory(); const string nugetPackageName = "myNugetPackage"; var nugetPackageDirectory = new DirectoryInfo( Path.Combine( directory.FullName, nugetPackageName, "2.0.0")); var extensionsDir = new DirectoryInfo( Path.Combine( nugetPackageDirectory.FullName, "interactive-extensions", "dotnet", "cs")); var extensionDll = await KernelExtensionTestHelper.CreateExtensionInDirectory( directory, @"await kernel.SendAsync(new SubmitCode(""using System.Reflection;""));", extensionsDir); var kernel = CreateKernel(); await kernel.SendAsync(new LoadExtensionsInDirectory(nugetPackageDirectory)); KernelEvents.Should() .ContainSingle(e => e is ExtensionLoaded && e.As <ExtensionLoaded>().ExtensionPath.FullName.Equals(extensionDll.FullName)); KernelEvents.Should() .ContainSingle(e => e is DisplayedValueProduced && e .As <DisplayedValueProduced>() .Value .ToString() .Contains($"Loaded kernel extension TestKernelExtension from assembly {extensionDll.FullName}")); }
// [InlineData(Language.FSharp)] // Todo: do 1 returns a value it shouldn't public async Task it_does_not_return_a_result_for_a_statement(Language language) { var kernel = CreateKernel(language); var source = language switch { // Closest F# has to a statement do discards the result Language.FSharp => "do 1", // if is a statement in C# Language.CSharp => "var x = 1;" }; await SubmitCode(kernel, source, submissionType : SubmissionType.Run); KernelEvents .Should() .NotContain(e => e.Value is StandardOutputValueProduced); KernelEvents .Should() .NotContain(e => e.Value is ReturnValueProduced); }
public async Task requested_diagnostics_are_remapped_to_the_appropriate_span(Language language, string languageSpecificCode) { var kernel = CreateKernel(language); var fullCode = $@" #!time $${languageSpecificCode} "; MarkupTestFile.GetLineAndColumn(fullCode, out var code, out var line, out var _column); await kernel.SendAsync(new RequestDiagnostics(code)); KernelEvents .Should() .ContainSingle <DiagnosticsProduced>(d => d.Diagnostics.Count == 1) .Which .Diagnostics .Should() .ContainSingle(diag => diag.LinePositionSpan.Start.Line == line); }
public async Task CSharp_generic_type_completions_are_returned_as_a_snippet() { // in general F# prefers to infer generic types, not specify them var kernel = CreateKernel(Language.CSharp); var markupCode = "System.Collections.Generic.IEnu$$"; MarkupTestFile.GetLineAndColumn(markupCode, out var code, out var line, out var character); await kernel.SendAsync(new RequestCompletions(code, new LinePosition(line, character))); KernelEvents .Should() .ContainSingle <CompletionsProduced>() .Which .Completions .Should() .Contain(item => item.DisplayText == "IEnumerable<>" && item.InsertText == "IEnumerable<$1>" && item.InsertTextFormat == InsertTextFormat.Snippet); }
public async Task when_code_contains_compile_time_warnings_diagnostics_are_produced(Language language, string diagnosticMessage) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => new[] { "System.AppDomain.GetCurrentThreadId()" }, Language.CSharp => new[] { "System.AppDomain.GetCurrentThreadId()", } }; await SubmitCode(kernel, source); using var _ = new AssertionScope(); KernelEvents .Should() .ContainSingle <ReturnValueProduced>(); KernelEvents .Should() .ContainSingle <DiagnosticsProduced>(d => d.Diagnostics.Count > 0) .Which .Diagnostics .Should() .ContainSingle(diagnostic => true) .Which .Message .Should() .StartWith(diagnosticMessage); }
//Not implemented: [InlineData(Language.FSharp)] public async Task it_can_load_script_files_using_load_directive_with_relative_path_after_command_changeWorkingDirectory(Language language) { var currentDirectory = Directory.GetCurrentDirectory(); DisposeAfterTest(() => Directory.SetCurrentDirectory(currentDirectory)); var kernel = CreateKernel(language); var absolutePathOneLevelHigher = Directory.GetParent(currentDirectory).FullName; await kernel.SendAsync(new ChangeWorkingDirectory(absolutePathOneLevelHigher)); var relativePath = Path.GetRelativePath(absolutePathOneLevelHigher, currentDirectory); var code = language switch { Language.CSharp => $"#load \"{relativePath}/RelativeLoadingSample.csx\"", Language.FSharp => $"#load \"{relativePath}/RelativeLoadingSample.fsx\"" }; var command = new SubmitCode(code); await kernel.SendAsync(command); KernelEvents.Should() .ContainSingle <StandardOutputValueProduced>(e => e.FormattedValues.Any(v => v.Value.Contains("hello!"))); }
// [InlineData(Language.FSharp)] // Todo: need to generate CompletionRequestReceived event ... perhaps public async Task it_returns_completion_list_for_types(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => @"System.Console.", Language.CSharp => @"System.Console." }; await kernel.SendAsync(new RequestCompletion(source, 15)); KernelEvents .Should() .ContainSingle(e => e is CompletionRequestReceived); KernelEvents .OfType <CompletionRequestCompleted>() .Single() .CompletionList .Should() .Contain(i => i.DisplayText == "ReadLine"); }
// [InlineData(Language.FSharp)] TODO -- Uncomment when FSharp is inserted public async Task it_can_load_assembly_referenced_from_refs_folder_in_nugetpackage(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => @" #r ""nuget:Microsoft.ML.OnnxTransformer,1.4.0"" open System open System.Numerics.Tensors let inputValues = [| 12.0; 10.0; 17.0; 5.0 |] let tInput = new DenseTensor<float>(inputValues.AsMemory(), new ReadOnlySpan<int>([|4|])) tInput.Length ", Language.CSharp => @" #r ""nuget:Microsoft.ML.OnnxTransformer,1.4.0"" using System; using System.Numerics.Tensors; var inputValues = new[] { 12f, 10f, 17f, 5f }; var tInput = new DenseTensor<float>(inputValues.AsMemory(), new ReadOnlySpan<int>(new[] { 4 })); tInput.Length" }; await SubmitCode(kernel, source); KernelEvents .Should() .ContainSingle <ReturnValueProduced>() .Which .Value .Should() .Be(4); } }
public async Task it_returns_a_similarly_shaped_error(Language language) { var kernel = CreateKernel(language, openTestingNamespaces: true); var(source, errorFragments) = language switch { Language.CSharp => ("using Not.A.Namespace;", new[] { "(1,7): error CS0246:", "Not", "using" }), Language.FSharp => ("open Not.A.Namespace", new[] { @"input.fsx (1,6)-(1,9) typecheck error", "Not" }) }; await SubmitCode(kernel, source); KernelEvents .Should() .ContainSingle <DiagnosticsProduced>(d => d.Diagnostics.Count > 0) .Which .FormattedDiagnostics .Should() .ContainSingle(fv => true) .Which .Value .Should() .ContainAll(errorFragments); }
public async Task Completions_are_available_for_symbols_declared_in_the_previous_submission(Language language) { var variableName = "aaaaaaa"; var declarationSubmission = language switch { Language.CSharp => $"var {variableName} = 123;", Language.FSharp => $"let {variableName} = 123" }; var kernel = CreateKernel(language); await kernel.SubmitCodeAsync(declarationSubmission); await kernel.SendAsync(new RequestCompletions("aaa", new LinePosition(0, 3))); KernelEvents .Should() .ContainSingle <CompletionsProduced>() .Which .Completions .Should() .Contain(item => item.DisplayText == variableName); }
public async Task diagnostics_are_produced_on_command_succeeded(Language language, string code, string errorCode, params string[] diagnosticMessageFragments) { var kernel = CreateKernel(language); await kernel.SubmitCodeAsync(code); using var _ = new AssertionScope(); KernelEvents .Should() .ContainSingle <CommandSucceeded>(); KernelEvents .Should() .ContainSingle <DiagnosticsProduced>(d => d.Diagnostics.Count > 0) .Which .Diagnostics .Should() .ContainSingle(diag => diag.Code == errorCode && diagnosticMessageFragments.All( frag => diag.Message.Contains(frag) )); }
public async Task Null_return_value_is_formatted_as_null(Language language) { var kernel = CreateKernel(language); var submission = language switch { Language.CSharp => "null", Language.FSharp => "let o : obj = null\no" }; await kernel.SendAsync(new SubmitCode(submission)); KernelEvents.Should().NotContainErrors(); KernelEvents .Should() .ContainSingle <ReturnValueProduced>() .Which .FormattedValues .Should() .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains(Formatter.NullString.HtmlEncode().ToString())); }
public async Task quit_command_fails_when_not_configured() { var kernel = CreateKernel(); var quit = new Quit(); await kernel.SendAsync(quit); using var _ = new AssertionScope(); KernelEvents .Should().ContainSingle <CommandFailed>() .Which .Command .Should() .Be(quit); KernelEvents .Should().ContainSingle <CommandFailed>() .Which .Exception .Should() .BeOfType <InvalidOperationException>(); }
public async Task when_code_contains_compile_time_error_diagnostics_are_produced(Language language, string code, string diagnosticMessage, string errorMessage) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => new[] { "open System", "aaaadd" }, Language.CSharp => new[] { "using System;", "aaaadd" } }; await SubmitCode(kernel, source); var diagnosticRange = new LinePositionSpan( new LinePosition(0, 0), new LinePosition(0, 6)); using var _ = new AssertionScope(); // The CommandFailed message is populated KernelEvents .Should() .ContainSingle <CommandFailed>() .Which .Message .Should() .Be(errorMessage); // The Diagnostics of DiagnosticsProduced event are populated KernelEvents .Should() .ContainSingle <DiagnosticsProduced>(d => d.Diagnostics.Count > 0) .Which .Diagnostics .Should() .ContainSingle(diag => diag.LinePositionSpan == diagnosticRange && diag.Code == code && diag.Message == diagnosticMessage); // The FormattedValues are populated of DiagnosticsProduced event are populated KernelEvents .Should() .ContainSingle <DiagnosticsProduced>(d => d.Diagnostics.Count > 0) .Which .FormattedDiagnostics .Should() .ContainSingle(fv => true) .Which .Value .Should() .Be(errorMessage); }