public static async Task NextPromptShouldBeBrowseAsync(this IRSession session) { var tracer = await session.TraceExecutionAsync(); // Grab the next available prompt, and verify that it's Browse> using (var inter = await session.BeginInteractionAsync()) { inter.Contexts.IsBrowser().Should().BeTrue("Next available prompt should be a Browse> prompt"); } // Now wait until session tells us that it has noticed the prompt and processed it. // Note that even if we register the handler after it has already noticed, but // before the interaction completed, it will still invoke the handler. var browseTask = EventTaskSources.IRExecutionTracer.Browse.Create(tracer); // Spin until either Browse is raised, or we see a different non-Browse prompt. // If the latter happens, we're not going to see Browse raised for that prompt that we've // seen initially, because something had interfered asynchronously, which shouldn't happen // in a test - and if it does, the test should be considered failed at that point, because // the state is indeterminate. while (true) { var interTask = session.BeginInteractionAsync(); var completedTask = await Task.WhenAny(browseTask, interTask); if (completedTask == browseTask) { interTask.ContinueWith(t => t.Result.Dispose(), TaskContinuationOptions.OnlyOnRanToCompletion).DoNotWait(); return; } using (var inter = await interTask) { inter.Contexts.IsBrowser().Should().BeTrue(); } } }
public async System.Threading.Tasks.Task ClearAllAsync() { if (_rSession == null) { return; } using (var eval = await _rSession.BeginInteractionAsync(false)) { await eval.ClearPlotHistoryAsync(); } }
public async Task InteractDuringBrowse() { using (var debugSession = new DebugSession(_session)) { using (var sf = new SourceFile("x <- 'old'; browser()")) { var browse = new TaskCompletionSource <bool>(); debugSession.Browse += (s, e) => { browse.TrySetResult(true); }; await sf.Source(_session); await browse.Task; using (var inter = await _session.BeginInteractionAsync()) { await inter.RespondAsync("x <- 'new'\n"); } REvaluationResult x; using (var eval = await _session.BeginEvaluationAsync()) { x = await eval.EvaluateAsync("x"); } x.StringResult.Should().Be("new"); } } }
public async Task InteractDuringBrowse() { var tracer = await _session.TraceExecutionAsync(); using (var sf = new SourceFile("x <- 'old'; browser()")) { var browse = new TaskCompletionSource <bool>(); tracer.Browse += (s, e) => { browse.TrySetResult(true); }; await sf.Source(_session); await browse.Task; using (var inter = await _session.BeginInteractionAsync()) { await inter.RespondAsync("x <- 'new'\n"); } string x; using (var eval = await _session.BeginEvaluationAsync()) { x = await eval.EvaluateAsync <string>("x", REvaluationKind.Normal); } x.Should().Be("new"); } }
private async Task ExitBrowserAsync(IRSession session) { await TaskUtilities.SwitchToBackgroundThread(); var cts = new CancellationTokenSource(1000); IRSessionInteraction inter; try { inter = await session.BeginInteractionAsync(true, cts.Token); } catch (OperationCanceledException) { // If we couldn't get a prompt to put "Q" into within a reasonable timeframe, just // abort the current interaction; await session.CancelAllAsync(); return; } using (inter) { // Check if this is still the same prompt as the last Browse prompt that we've seen. // If it isn't, then session has moved on already, and there's nothing for us to exit. RBrowseEventArgs currentBrowseDebugEventArgs; lock (_browseLock) { currentBrowseDebugEventArgs = _currentBrowseEventArgs; } if (currentBrowseDebugEventArgs != null && currentBrowseDebugEventArgs.Context.Contexts == inter.Contexts) { await inter.RespondAsync("Q\n"); } } }
public RCodeBlockTest() { _shell = TestCoreShell.CreateSubstitute(); _session = _shell.SetupSessionSubstitute(); _interaction = Substitute.For <IRSessionInteraction>(); _session.BeginInteractionAsync(Arg.Any <bool>(), Arg.Any <CancellationToken>()).Returns(Task.FromResult(_interaction)); }
private async Task ExecuteAndCaptureOutputAsync(IRSession session, string expression, CancellationToken cancellationToken) { _output = new StringBuilder(); _errors = new StringBuilder(); using (var inter = await session.BeginInteractionAsync(isVisible: true, cancellationToken: cancellationToken)) { await inter.RespondAsync(expression); } }
private async Task ExecuteAndCaptureOutputAsync(IRSession session, string expression, CancellationToken cancellationToken) { _output = new StringBuilder(); _errors = new StringBuilder(); try { using (var inter = await session.BeginInteractionAsync(true, cancellationToken)) { await inter.RespondAsync(expression); } } catch (OperationCanceledException) { } }
public async Task CallStack() { using (var debugSession = new DebugSession(_session)) { const string code1 = @"f <- function(n) { if (n > 0) { g(n - 1) } else { return() } }"; const string code2 = @"g <- function(n) { if (n > 0) { f(n - 1) } else { return() } }"; using (var sf1 = new SourceFile(code1)) using (var sf2 = new SourceFile(code2)) { await debugSession.EnableBreakpointsAsync(true); await sf1.Source(_session); await sf2.Source(_session); var bp = await debugSession.CreateBreakpointAsync(sf1, 5); var bpHit = new BreakpointHitDetector(bp); using (var inter = await _session.BeginInteractionAsync()) { await inter.RespondAsync("f(4)\n"); } await bpHit.ShouldBeHitAtNextPromptAsync(); (await debugSession.GetStackFramesAsync()).Should().HaveTail(new MatchDebugStackFrames { { (string)null, null, "f(4)" }, { sf1, 3, "g(n - 1)" }, { sf2, 3, "f(n - 1)" }, { sf1, 3, "g(n - 1)" }, { sf2, 3, "f(n - 1)" }, { sf1, 5, MatchAny <string> .Instance }, }); } } }
public async Task CallStack() { var tracer = await _session.TraceExecutionAsync(); const string code1 = @"f <- function(n) { if (n > 0) { g(n - 1) } else { return() } }"; const string code2 = @"g <- function(n) { if (n > 0) { f(n - 1) } else { return() } }"; using (var sf1 = new SourceFile(code1)) using (var sf2 = new SourceFile(code2)) { await tracer.EnableBreakpointsAsync(true); await sf1.Source(_session); await sf2.Source(_session); var bp = await tracer.CreateBreakpointAsync(sf1, 5); var bpHit = new BreakpointHitDetector(bp); using (var inter = await _session.BeginInteractionAsync()) { await inter.RespondAsync("f(4)\n"); } await bpHit.ShouldBeHitAtNextPromptAsync(); await _session.ShouldHaveTracebackAsync(new TracebackBuilder { { null, null, "f(4)", "<environment: R_GlobalEnv>" }, { sf1, 3, "g(n - 1)", null }, { sf2, 3, "f(n - 1)", null }, { sf1, 3, "g(n - 1)", null }, { sf2, 3, "f(n - 1)", null }, { sf1, 5, TracebackBuilder.Any, null } }); } }
public async Task InitializeAsync() { await _sessionProvider.TrySwitchBrokerAsync(nameof(GridDataTest)); await _session.StartHostAsync(new RHostStartupInfo(), new RHostClientTestApp(), 50000); var packages = (await _session.InstalledPackagesAsync()).Select(p => p.ToObject <RPackage>()).ToList(); if (!packages.Any(p => p.Package.EqualsIgnoreCase("quantmod"))) { using (var request = await _session.BeginInteractionAsync()) { await request.InstallPackageAsync("quantmod"); } } }
public async Task <ExecutionResult> ExecuteCodeAsync(string text) { var start = 0; var end = text.IndexOf('\n'); if (end == -1) { return(ExecutionResult.Success); } try { using (Session.DisableMutatedOnReadConsole()) { while (end != -1) { var line = text.Substring(start, end - start + 1); start = end + 1; end = text.IndexOf('\n', start); using (var request = await Session.BeginInteractionAsync()) { using (_evaluatorRequest.Increment()) { if (line.Length >= request.MaxLength) { CurrentWindow.WriteErrorLine(string.Format(Resources.InputIsTooLong, request.MaxLength)); return(ExecutionResult.Failure); } await request.RespondAsync(line); } } } } return(ExecutionResult.Success); } catch (RHostDisconnectedException rhdex) { WriteError(rhdex.Message); return(ExecutionResult.Success); } catch (OperationCanceledException) { // Cancellation reason was already reported via RSession.Error and printed out; // Return success cause connection lost doesn't mean that RHost died return(ExecutionResult.Success); } catch (Exception ex) { await _coreShell.ShowErrorMessageAsync(ex.ToString()); return(ExecutionResult.Failure); } finally { History.AddToHistory(text); } }
public async Task <ExecutionResult> ExecuteCodeAsync(string text) { var start = 0; var end = text.IndexOf('\n'); if (end == -1) { return(ExecutionResult.Success); } try { Session.BeforeRequest -= SessionOnBeforeRequest; using (Session.DisableMutatedOnReadConsole()) { while (end != -1) { var line = text.Substring(start, end - start + 1); start = end + 1; end = text.IndexOf('\n', start); using (var request = await Session.BeginInteractionAsync()) { if (line.Length >= request.MaxLength) { CurrentWindow.WriteErrorLine(string.Format(Resources.InputIsTooLong, request.MaxLength)); return(ExecutionResult.Failure); } await request.RespondAsync(line); } } } return(ExecutionResult.Success); } catch (RException) { // It was already reported via RSession.Error and printed out; just return failure. return(ExecutionResult.Failure); } catch (OperationCanceledException) { // Cancellation reason was already reported via RSession.Error and printed out; just return failure. return(ExecutionResult.Failure); } catch (Exception ex) { await _coreShell.DispatchOnMainThreadAsync(() => _coreShell.ShowErrorMessage(ex.ToString())); return(ExecutionResult.Failure); } finally { Session.BeforeRequest += SessionOnBeforeRequest; History.AddToHistory(text); } }
public async Task Source(IRSession session, bool debug = true) { using (IRSessionInteraction eval = await session.BeginInteractionAsync()) { await eval.RespondAsync($"{(debug ? "rtvs::debug_source" : "source")}({FilePath.ToRStringLiteral()})" + Environment.NewLine); } }
private async Task Environments(string script, params IREnvironment[] expectedEnvs) { // Detach all packages that can be detached before doing anything else. The only two that // cannot be detached are .GlobalEnv, which is the first in the list, and package:base, // which is the last. So, just keep detaching the 2nd item until the list only has 2 left. await _session.ExecuteAsync("while (length(search()) > 2) detach(2)"); // Wait for prompt to appear. using (var eval = await _session.BeginInteractionAsync()) { } var envProvider = new REnvironmentProvider(_session); var envTcs = new TaskCompletionSource <IREnvironment[]>(); envProvider.Environments.CollectionChanged += (sender, args) => { envTcs.TrySetResult(envProvider.Environments.ToArray()); }; using (var inter = await _session.BeginInteractionAsync()) { inter.RespondAsync(script + "\n").DoNotWait(); } // Wait until we hit the Browse> prompt. using (var inter = await _session.BeginInteractionAsync()) { inter.Contexts.IsBrowser().Should().BeTrue(); } var actualEnvs = await envTcs.Task; actualEnvs.ShouldAllBeEquivalentTo(expectedEnvs, options => options .Including(env => env.Name) .Including(env => env.Kind) .WithStrictOrdering()); // Validating EnvironmentExpression: // For environments that are on the search list, we can validate it by retrieving environment by name, // and verifying that it is indeed the same. format() generates comparable string values - it returns strings // that are unique for any given environment (using its name if it has one, and its memory address otherwise). // For all other environments, we validate by looking at a variable named 'tag' in that environment, and // comparing its value to the name of the function extracted from the call (i.e. environment name). var expectedObjects = new List <string>(); var actualObjects = new List <string>(); foreach (var env in actualEnvs) { if (env == null) { expectedObjects.Add(null); actualObjects.Add(null); } else if (env.Kind == REnvironmentKind.Function) { int tagEnd = env.Name.IndexOf("("); tagEnd.Should().BePositive(); string tag = env.Name.Substring(0, tagEnd); expectedObjects.Add(tag); actualObjects.Add(await _session.EvaluateAsync <string>( $"({env.EnvironmentExpression})$tag", REvaluationKind.Normal)); } else { expectedObjects.Add(await _session.EvaluateAsync <string>( $"format(as.environment({env.Name.ToRStringLiteral()}))", REvaluationKind.Normal)); actualObjects.Add(await _session.EvaluateAsync <string>( $"format({env.EnvironmentExpression})", REvaluationKind.Normal)); } } actualObjects.Should().Equal(expectedObjects); }
private async Task ExitBrowserAsync(IRSession session) { await TaskUtilities.SwitchToBackgroundThread(); var cts = new CancellationTokenSource(1000); IRSessionInteraction inter; try { inter = await session.BeginInteractionAsync(true, cts.Token); } catch (OperationCanceledException) { // If we couldn't get a prompt to put "Q" into within a reasonable timeframe, just // abort the current interaction; await session.CancelAllAsync(); return; } using (inter) { // Check if this is still the same prompt as the last Browse prompt that we've seen. // If it isn't, then session has moved on already, and there's nothing for us to exit. RBrowseEventArgs currentBrowseDebugEventArgs; lock (_browseLock) { currentBrowseDebugEventArgs = _currentBrowseEventArgs; } if (currentBrowseDebugEventArgs != null && currentBrowseDebugEventArgs.Context.Contexts == inter.Contexts) { await inter.RespondAsync("Q\n"); } } }
private async Task ExecuteRCode(IRSession session, string expression) { using (var interaction = await session.BeginInteractionAsync(isVisible: false)) { await interaction.RespondAsync(expression); } }
private async Task ExecuteRCode(IRSession session, string expression) { using (var interaction = await session.BeginInteractionAsync(isVisible: false)) { await interaction.RespondAsync(expression).SilenceException<RException>(); } }
public async Task SetAndHitBreakpointInsideLoadedFunction() { const string code = @"f <- function() { 0 }"; var tracer = await _session.TraceExecutionAsync(); using (var sf = new SourceFile(code)) { await tracer.EnableBreakpointsAsync(true); await sf.Source(_session); var bp = await tracer.CreateBreakpointAsync(new RSourceLocation(sf.FilePath, 2)); var bpHit = new BreakpointHitDetector(bp); using (var inter = await _session.BeginInteractionAsync()) { await inter.RespondAsync("f()\n"); } await bpHit.ShouldBeHitAtNextPromptAsync(); } }
public async Task Source(IRSession session) { using (IRSessionInteraction eval = await session.BeginInteractionAsync()) { await eval.RespondAsync($"rtvs::debug_source({FilePath.ToRStringLiteral()})" + Environment.NewLine); } }