public async Task it_formats_func_instances(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.CSharp => new[] { "Func<int> func = () => 1;", "func()", "func" }, Language.FSharp => new[] { "let func () = 1", "func()", "func" }, }; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .Count(e => e is CommandHandled) .Should() .Be(3); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Should() .Contain(e => ((SubmitCode)e.Command).Code == source[1]) .And .Contain(e => ((SubmitCode)e.Command).Code == source[2]); }
public async Task it_can_load_assembly_references_using_r_directive() { var kernel = CreateKernel(); var dll = new FileInfo(typeof(JsonConvert).Assembly.Location).FullName; await kernel.SendAsync( new SubmitCode($"#r \"{dll}\"")); await kernel.SendAsync( new SubmitCode(@" using Newtonsoft.Json; var json = JsonConvert.SerializeObject(new { value = ""hello"" }); json ")); KernelEvents.ValuesOnly() .Should() .ContainSingle(e => e is ReturnValueProduced); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Single() .Value .Should() .Be(new { value = "hello" }.ToJson()); }
public async Task it_can_load_assembly_references_using_r_directive_at_quotedpaths(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; var source = language switch { Language.FSharp => new[] { $"#r @\"{dllPath}\"", @" open Newtonsoft.Json let json = JsonConvert.SerializeObject( struct {| value = ""hello"" |} ) json " } }; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .Should() .ContainSingle(e => e is ReturnValueProduced); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Single() .Value .Should() .Be(new { value = "hello" }.ToJson()); }
public async Task it_produces_a_final_value_if_the_code_expression_evaluates(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => @" open System Console.Write(""value one"") Console.Write(""value two"") Console.Write(""value three"") 5", Language.CSharp => @" Console.Write(""value one""); Console.Write(""value two""); Console.Write(""value three""); 5", }; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .OfType <StandardOutputValueProduced>() .Should() .HaveCount(3); KernelEvents .ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value.Should().Be(5); }
public async Task it_remembers_state_between_submissions(Language language) { var source = language switch { Language.FSharp => new[] { "let add x y = x + y", "add 2 3" }, Language.CSharp => new[] { "int Add(int x, int y) { return x + y; }", "Add(2, 3)" } }; var kernel = CreateKernel(language); await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(5); }
//[InlineData(Language.FSharp)] // Todo: teach fsi about returning exceptions // > open System;; // > raise(new NotImplementedException());; // raise(new NotImplementedException());; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // stdin(7,1) : error FS0030: Value restriction.The value 'it' has been inferred to have generic type // val it : '_a // Either define 'it' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. // > public async Task it_returns_exceptions_thrown_in_user_code(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => new[] { "open System", "raise (new NotImplementedException())" }, Language.CSharp => new[] { "using System;", "throw new NotImplementedException();" } }; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .Where(x => x.GetType() != typeof(KernelIdle) && x.GetType() != typeof(KernelBusy)) .Last() .Should() .BeOfType <CommandFailed>() .Which .Exception .Should() .BeOfType <NotImplementedException>(); }
//[InlineData(Language.FSharp)] // Todo: FSI interrupt command_failed : cancelled command public async Task it_can_cancel_execution(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => "System.Threading.Thread.Sleep(3000)", Language.CSharp => "System.Threading.Thread.Sleep(3000);" }; var submitCodeCommand = new SubmitCode(source); var codeSubmission = kernel.SendAsync(submitCodeCommand); var interruptionCommand = new CancelCurrentCommand(); await kernel.SendAsync(interruptionCommand); await codeSubmission; KernelEvents .ValuesOnly() .Single(e => e is CurrentCommandCancelled); KernelEvents .ValuesOnly() .OfType <CommandFailed>() .Should() .BeEquivalentTo(new CommandFailed(null, interruptionCommand, "Command cancelled")); }
public async Task it_produces_values_when_executing_Console_output(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => @" open System Console.Write(""value one"") Console.Write(""value two"") Console.Write(""value three"")", Language.CSharp => @" Console.Write(""value one""); Console.Write(""value two""); Console.Write(""value three"");", }; var kernelCommand = await SubmitCode(kernel, source); KernelEvents .ValuesOnly() .OfType <StandardOutputValueProduced>() .Should() .BeEquivalentTo( new StandardOutputValueProduced("value one", kernelCommand, new[] { new FormattedValue("text/plain", "value one"), }), new StandardOutputValueProduced("value two", kernelCommand, new[] { new FormattedValue("text/plain", "value two"), }), new StandardOutputValueProduced("value three", kernelCommand, new[] { new FormattedValue("text/plain", "value three"), })); }
public async Task it_aggregates_multiple_submissions(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => new[] { // Todo: decide what to do with F# not auto-opening System.Collections.Generic, System.Linq "open System.Collections.Generic", "open System.Linq", "let x = List<int>([|1;2|])", "x.Add(3)", "x.Max()" }, Language.CSharp => new[] { "var x = new List<int>{1,2};", "x.Add(3);", "x.Max()" } }; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(3); }
public async Task Javascript_helper_emits_string_as_content_within_a_script_element(Language language) { var kernel = CreateKernel(language); var scriptContent = "alert('Hello World!');"; var submission = language switch { Language.CSharp => $@"Javascript(""{scriptContent}"");", Language.FSharp => $@"Javascript(""{scriptContent}"")", }; await kernel.SendAsync(new SubmitCode(submission)); var formatted = KernelEvents .ValuesOnly() .OfType <DisplayedValueProduced>() .SelectMany(v => v.FormattedValues) .ToArray(); formatted .Should() .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains($@"<script type=""text/javascript"">{scriptContent}</script>")); }
public async Task it_can_load_assembly_references_using_r_directive_at_triplequotedpaths(Language language) { var kernel = CreateKernel(language); var dllPath = new FileInfo(typeof(JsonConvert).Assembly.Location).FullName; var source = language switch { Language.FSharp => new[] { $"#r \"\"\"{dllPath}\"\"\"", @" open Newtonsoft.Json let json = JsonConvert.SerializeObject( struct {| value = ""hello"" |} ) json " }, }; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .Should() .ContainSingle(e => e is ReturnValueProduced); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Single() .Value .Should() .Be(new { value = "hello" }.ToJson()); }
//[InlineData(Language.FSharp)] //Todo: completion for F# public async Task it_returns_completion_list_for_previously_declared_variables(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.FSharp => @"let alpha = new Random()", Language.CSharp => @"var alpha = new Random();" }; await SubmitCode(kernel, source); await kernel.SendAsync(new RequestCompletion("al", 2)); KernelEvents.ValuesOnly() .Should() .ContainSingle(e => e is CompletionRequestReceived); KernelEvents.ValuesOnly() .OfType <CompletionRequestCompleted>() .Single() .CompletionList .Should() .Contain(i => i.DisplayText == "alpha"); }
private void AssertLastValue(object value) { KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(value); }
public async Task it_can_analyze_code_submissions() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("var a = 12", submissionType : SubmissionType.Diagnose)); var analysisResult = KernelEvents.ValuesOnly() .Single(e => e is IncompleteCodeSubmissionReceived); }
public async Task it_returns_the_result_of_a_non_null_expression() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("123")); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(123); }
public async Task expression_evaluated_to_null_has_result_with_null_value() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("null")); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .BeNull(); }
public async Task it_returns_a_result_for_a_if_expressions(Language language, string expression) { var kernel = CreateKernel(language); await SubmitCode(kernel, expression); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(25); }
public async Task it_returns_the_result_of_a_non_null_expression(Language language) { var kernel = CreateKernel(language); await SubmitCode(kernel, "123"); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(123); }
public async Task it_supports_csharp_8() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("var text = \"meow? meow!\";")); await kernel.SendAsync(new SubmitCode("text[^5..^0]")); KernelEvents.ValuesOnly() .OfType <DisplayedValueProduced>() .Last() .Value .Should() .Be("meow!"); }
public async Task kernel_captures_stderr(Language language) { var kernel = CreateKernel(language); var source = "eprintf \"hello from F#\""; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .OfType <StandardErrorValueProduced>() .Last() .Value .Should() .Be("hello from F#"); }
public async Task it_returns_exceptions_thrown_in_user_code() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("using System;")); await kernel.SendAsync(new SubmitCode("throw new NotImplementedException();")); KernelEvents.ValuesOnly() .Last() .Should() .BeOfType <CommandFailed>() .Which .Exception .Should() .BeOfType <NotImplementedException>(); }
public async Task it_aggregates_multiple_submissions() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("var x = new List<int>{1,2};")); await kernel.SendAsync(new SubmitCode("x.Add(3);")); await kernel.SendAsync(new SubmitCode("x.Max()")); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(3); }
public async Task it_returns_diagnostics() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("using System;")); await kernel.SendAsync(new SubmitCode("aaaadd")); KernelEvents.ValuesOnly() .Last() .Should() .BeOfType <CommandFailed>() .Which .Message .Should() .Be("(1,1): error CS0103: The name 'aaaadd' does not exist in the current context"); }
public async Task it_notifies_when_submission_is_incomplete() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("var a =")); KernelEvents .Should() .NotContain(e => e.Value is ValueProduced); KernelEvents .ValuesOnly() .Should() .Contain(e => e is CodeSubmissionEvaluated) .And .Contain(e => e is IncompleteCodeSubmissionReceived); }
public async Task it_returns_completion_list_for_types() { var kernel = CreateKernel(); await kernel.SendAsync(new RequestCompletion("System.Console.", 15)); KernelEvents.ValuesOnly() .Should() .ContainSingle(e => e is CompletionRequestReceived); KernelEvents.ValuesOnly() .OfType <CompletionRequestCompleted>() .Single() .CompletionList .Should() .Contain(i => i.DisplayText == "ReadLine"); }
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", "csharp"); await kernel.SendAsync(kernelCommand); KernelEvents.ValuesOnly() .OfType <ValueProduced>() .Should() .HaveCount(4) .And .ContainSingle(e => e.IsLastValue); }
public async Task Display_helper_can_be_called_without_specifying_class_name() { var kernel = CreateKernel(); await kernel.SendAsync(new SubmitCode("display(b(\"hi!\"));")); var formatted = KernelEvents .ValuesOnly() .OfType <ValueProduced>() .SelectMany(v => v.FormattedValues); formatted .Should() .ContainSingle(v => v.MimeType == "text/html" && v.Value.ToString().Contains("<b>hi!</b>")); }
public async Task kernel_base_ignores_command_line_directives(Language language) { // The text `[1;2;3;4]` parses as a System.CommandLine directive; ensure it's not consumed and is passed on to the kernel. var kernel = CreateKernel(language); var source = @" [1;2;3;4] |> List.sum"; await SubmitCode(kernel, source); KernelEvents.ValuesOnly() .OfType <ReturnValueProduced>() .Last() .Value .Should() .Be(10); }
// no F# equivalent, because it doesn't have the concept of complete/incomplete submissions public async Task it_can_analyze_incomplete_submissions(Language language) { var kernel = CreateKernel(language); var source = language switch { Language.CSharp => "var a =" }; await SubmitCode(kernel, source, submissionType : SubmissionType.Diagnose); KernelEvents .ValuesOnly() .Single(e => e is IncompleteCodeSubmissionReceived); KernelEvents .Should() .Contain(e => e.Value is IncompleteCodeSubmissionReceived); }
public async Task it_produces_values_when_executing_Console_output() { var kernel = CreateKernel(); var kernelCommand = new SubmitCode(@" Console.Write(""value one""); Console.Write(""value two""); Console.Write(""value three"");"); await kernel.SendAsync(kernelCommand); KernelEvents .ValuesOnly() .OfType <DisplayedValueProduced>() .Should() .BeEquivalentTo( new DisplayedValueProduced("value one", kernelCommand, new[] { new FormattedValue("text/plain", "value one"), }), new DisplayedValueProduced("value two", kernelCommand, new[] { new FormattedValue("text/plain", "value two"), }), new DisplayedValueProduced("value three", kernelCommand, new[] { new FormattedValue("text/plain", "value three"), })); }