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 it_returns_completion_list_for_previously_declared_items(Language language) { var kernel = CreateKernel(language, openTestingNamespaces: true); var source = language switch { Language.FSharp => @"let alpha = new Random()", Language.CSharp => @"var alpha = new Random();", Language.PowerShell => @"function alpha { 5 }", }; await SubmitCode(kernel, source); await kernel.SendAsync(new RequestCompletions("al", new LinePosition(0, 2))); KernelEvents .OfType <CompletionsProduced>() .Single() .Completions .Should() .Contain(i => i.DisplayText == "alpha"); }
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 it_returns_completion_list_for_types_imported_at_runtime(Language language) { var kernel = CreateKernel(language); var dll = new FileInfo(typeof(JsonConvert).Assembly.Location).FullName; var code = language switch { Language.CSharp => $"#r \"{dll}\"", Language.FSharp => $"#r @\"{dll}\"" }; await kernel.SendAsync(new SubmitCode(code)); await kernel.SendAsync(new RequestCompletions("Newtonsoft.Json.JsonConvert.", new LinePosition(0, 28))); KernelEvents.Single(e => e is CompletionsProduced) .As <CompletionsProduced>() .Completions .Should() .Contain(i => i.DisplayText == "SerializeObject"); }
public async Task it_produces_a_final_value_if_the_code_expression_evaluates() { var kernel = CreateKernel(); var kernelCommand = new SubmitCode(@" Console.Write(""value one""); Console.Write(""value two""); Console.Write(""value three""); 5"); await kernel.SendAsync(kernelCommand); KernelEvents.ValuesOnly() .OfType <DisplayedValueProduced>() .Should() .HaveCount(3); KernelEvents .ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value.Should().Be(5); }
public async Task Value_display_and_update_are_in_right_order(Language language) { var kernel = CreateKernel(language); var submission = language switch { Language.CSharp => "var d = display(b(\"hello\")); d.Update(b(\"world\"));", Language.FSharp => "let d = display(b.innerHTML(\"hello\"))\nd.Update(b.innerHTML(\"world\"))", }; await kernel.SendAsync(new SubmitCode(submission)); var valueEvents = KernelEvents .OrderBy(e => e.Timestamp) .Where(e => e.Value is DisplayedValueProduced || e.Value is DisplayedValueUpdated) .Select(e => e.Value) .ToList(); valueEvents.First().Should().BeOfType <DisplayedValueProduced>(); valueEvents.Last().Should().BeOfType <DisplayedValueUpdated>(); }
public async Task diagnostics_can_be_produced_from_multiple_subkernels() { var kernel = CreateCompositeKernel(Language.FSharp); var code = @" #!fsharp printfnnn """" #!csharp Console.WriteLin(); "; await SubmitCode(kernel, code); KernelEvents .OfType <DiagnosticsProduced>() .SelectMany(dp => dp.Diagnostics) .Should() .ContainSingle(d => d.Code.StartsWith("CS")) .And .ContainSingle(d => d.Code.StartsWith("FS")); }
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 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 => !string.IsNullOrEmpty(ci.Documentation) && ci.Documentation.Contains("Represents JavaScript's null as a string. This field is read-only.")); }
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}")); }
public async Task Display_helper_can_be_called_without_specifying_class_name(Language language) { var kernel = CreateKernel(language); var submission = language switch { Language.CSharp => "display(b(\"hi!\"));", Language.FSharp => "display(b.innerHTML(\"hi!\"));", }; await kernel.SendAsync(new SubmitCode(submission)); var formatted = KernelEvents .OfType <DisplayedValueProduced>() .SelectMany(v => v.FormattedValues); formatted .Should() .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains("<b>hi!</b>")); }
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); }
// [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 Displayed_value_can_be_updated() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("var d = display(b(\"hello\")); d.Update(b(\"world\"));")); var formatted = KernelEvents .OrderBy(e => e.Timestamp) .ValuesOnly() .OfType <ValueProduced>() .SelectMany(v => v.FormattedValues); formatted .Should() .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains("<b>hello</b>")) .And .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains("<b>world</b>")); }
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 it_returns_diagnostics(Language language) { 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 error = language switch { Language.FSharp => "input.fsx (1,1)-(1,7) typecheck error The value or constructor 'aaaadd' is not defined.", Language.CSharp => "(1,1): error CS0103: The name 'aaaadd' does not exist in the current context", }; KernelEvents .Where(x => x.GetType() != typeof(KernelIdle) && x.GetType() != typeof(KernelBusy)) .Last() .Should() .BeOfType <CommandFailed>() .Which .Message .Should() .Be(error); }
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 -- 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); } }
// [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"); }
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 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 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 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 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>(); }
private void ListenForPackagesToScanForExtensions() => RegisterForDisposal(KernelEvents .OfType <PackageAdded>() .Where(pa => pa?.PackageReference.PackageRoot != null) .Distinct(pa => pa.PackageReference.PackageRoot) .Subscribe(added => _packagesToCheckForExtensions.Enqueue(added)));
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); }