public async Task ExplorationResultIsCorrect( CSharpFlowGraphProvider graphProvider, IMethodSymbol methodSymbol, InvocationExpressionSyntax targetSyntax) { string assertionName = ((MemberAccessExpressionSyntax)targetSyntax.Expression).Name.Identifier.Text; bool isAssertion = assertionName.EndsWith("Assert"); bool shouldFindPath = assertionName.Contains("Invalid"); var methodLocation = new MethodLocation(methodSymbol); var flowGraph = await graphProvider.GetFlowGraphAsync(methodLocation); var displayGraph = graphProvider.GetDisplayGraph(flowGraph.Id); var displayNode = displayGraph.Nodes.First(n => n.Span.Contains(targetSyntax.Span)); var displayRecord = displayNode.Records.Last(); var startInfo = new StartingNodeInfo(displayRecord.FlowNode, displayRecord.OperationIndex, isAssertion); var options = new ExplorationOptions() { FinalNodeRecognizer = new PublicMethodEntryRecognizer(), TimeoutSeconds = 60 }; var exploration = new ExplorationContext(graphProvider, new ContextFactory(), startInfo, options); // Cancel after the first found path to save time bool success = !shouldFindPath; var cancelSource = new CancellationTokenSource(); exploration.ExecutionModelsObservable .Subscribe(m => { success = shouldFindPath; cancelSource.Cancel(); }, cancelSource.Token); bool wasExhaustive = await exploration.ExploreAsync(cancelSource); string message = shouldFindPath ? "No path was found" : "A path was found, although it shouldn't have been"; if (success && !shouldFindPath && !wasExhaustive) { success = false; message = $"No path was found during the {options.TimeoutSeconds} second timeout"; } Assert.IsTrue(success, message); }
private static ResultRow[] EvaluateProgram( CSharpFlowGraphProvider graphProvider, string programName, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocation) { string assertionName = ((MemberAccessExpressionSyntax)invocation.Expression).Name.Identifier.Text; bool isAssertion = assertionName.EndsWith("Assert"); bool shouldFindPath = assertionName.Contains("Invalid"); var methodLocation = new MethodLocation(methodSymbol); var flowGraph = graphProvider.GetFlowGraphAsync(methodLocation).Result; var displayGraph = graphProvider.GetDisplayGraph(flowGraph.Id); var displayNode = displayGraph.Nodes.First(n => n.Span.Contains(invocation.Span)); var displayRecord = displayNode.Records.Last(); var startInfo = new StartingNodeInfo(displayRecord.FlowNode, displayRecord.OperationIndex, isAssertion); var options = new ExplorationOptions() { FinalNodeRecognizer = new PublicMethodEntryRecognizer(), TimeoutSeconds = 40 }; var heuristics = GetHeuristicFactories().ToArray(); var results = new ResultRow[heuristics.Length * RepeatCount]; int j = 0; foreach ((string heuristicName, var heuristicFactory) in heuristics) { options.SmtHeuristicFactory = heuristicFactory; for (int i = 0; i < RepeatCount; i++) { var stopwatch = new Stopwatch(); long?ticksFirst = null; int? callsFirst = null; var exploration = new ExplorationContext(graphProvider, new ContextFactory(), startInfo, options); exploration.ExecutionModelsObservable .Subscribe(m => { ticksFirst = stopwatch.ElapsedTicks; callsFirst = Explorer.SolverCallCount; }); stopwatch.Start(); exploration.ExploreAsync().ContinueWith(t => stopwatch.Stop()).Wait(); long ticksTotal = stopwatch.ElapsedTicks; results[j * RepeatCount + i] = new ResultRow { Heuristic = heuristicName, Program = programName, FirstCounterexampleTime = ticksFirst / (double)Stopwatch.Frequency, FirstCounterexampleCalls = callsFirst, TotalTime = ticksTotal / (double)Stopwatch.Frequency, TotalCalls = Explorer.SolverCallCount }; } j++; } return(results); }
private async void Explore(bool isAssertCheck) { if (this.IsExploring) { return; } this.SelectedPath = null; this.Paths.Clear(); this.foundModels.Clear(); this.Messages.Clear(); this.Messages.Add("Analyzing the code on the caret position..."); this.UpdateCurrentSolution(); var info = await this.GatherInformationForCurrentCaretPosition(); if (!info.IsComplete) { this.Messages.Add("Unable to start the exploration from the selected statement. Ensure the caret is on a valid position and the method contains only supported constructs."); this.Messages.Add("Note: The tool is currently unable to recognize the statement when its trailing semicolon is selected, please place the cursor in the middle of it."); return; } else if (isAssertCheck && !info.IsAssertion) { this.Messages.Add("Only the correctness of assertions can be verified."); return; } Contract.Assert(info.SelectedDisplayNode.Records.Any()); var flowNodeRecord = info.SelectedDisplayNode.Records.Last(); var startNode = new StartingNodeInfo( flowNodeRecord.FlowNode, flowNodeRecord.OperationIndex, isAssertCheck); var z3ContextFactory = new ContextFactory(); var options = new ExplorationOptions { FinalNodeRecognizer = new PublicMethodEntryRecognizer(), TimeoutSeconds = (this.Timeout > 0) ? this.Timeout : (int?)null, IgnoredMethods = string.IsNullOrEmpty(this.IgnoredMethods) ? ImmutableArray <string> .Empty : this.IgnoredMethods.Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToImmutableArray() }; this.ExplorationContext = new ExplorationContext(this.GraphProvider, z3ContextFactory, startNode, options); try { await this.ExploreImpl(isAssertCheck); } catch (Exception e) { this.Messages.Add($"Error during the exploration: {e.Message}"); Trace.WriteLine(e.ToString()); if (this.explorationCancelSource != null) { this.explorationCancelSource.Cancel(); } this.IsExploring = false; this.CallGraph.Redraw(); } }