/// <summary> /// Deserializes the results.xml file to CoverageSession /// </summary> /// <returns>OpenCover execution results</returns> internal CoverageSession GetExecutionResults() { CoverageSession coverageSession = null; try { var serializer = new XmlSerializer(typeof(CoverageSession), new[] { typeof(Module), typeof(OpenCover.Framework.Model.File), typeof(Class) }); using (var stream = System.IO.File.Open(_openCoverResultsFile, FileMode.Open)) { coverageSession = serializer.Deserialize(stream) as CoverageSession; } if (_commandLineParameterReader.ReadConfiguration(_currentWorkingDirectory)) { ExecuteTestResultPostProcessor(_testResultsFile); ExecuteCoverageResultPostProcessor(_openCoverResultsFile); } if (!System.Diagnostics.Debugger.IsAttached) { System.IO.File.Delete(_openCoverResultsFile); } } catch (Exception ex) { IDEHelper.WriteToOutputWindow(ex.Message); IDEHelper.WriteToOutputWindow(ex.StackTrace); } return(coverageSession); }
/// <summary> /// Reads the test results file. /// </summary> protected override void ReadTestResults() { try { if (File.Exists(_testResultsFile)) { var testResultsFile = XDocument.Load(_testResultsFile); _executionStatus.Clear(); var assemblies = GetElementsByAttribute(testResultsFile, "test-suite", "type", "Assembly"); foreach (var assembly in assemblies) { var testCases = GetElementsByAttribute(assembly, "test-suite", "type", "TestFixture"); var testMethods = testCases.Elements("results").Elements("test-case").Select(tc => GetTestResult(tc, null)); testMethods = testMethods.Union(testCases.Elements("results").Elements("test-suite").Select(ts => ReadTestCase(ts))); _executionStatus.Add(assembly.Attribute("name").Value, testMethods); } } else { IDEHelper.WriteToOutputWindow("Test Results File does not exist: {0}", _testResultsFile); } } catch (Exception ex) { IDEHelper.WriteToOutputWindow(ex.Message); IDEHelper.WriteToOutputWindow(ex.StackTrace); } }
/// <summary> /// Reads the test results file. /// </summary> protected override void ReadTestResults() { try { if (File.Exists(_testResultsFile)) { var testResultsFile = XDocument.Load(_testResultsFile); _executionStatus.Clear(); var rootAssemblies = testResultsFile.Elements("assemblies"); var assemblies = rootAssemblies.Elements().Where(e => e.Name == "assembly"); foreach (var assembly in assemblies) { var testCases = assembly.Elements("collection"); var testMethods = testCases.Elements("test").Select(tc => GetTestResult(tc, null)); _executionStatus.Add(assembly.Attribute("name").Value.ToLower(), testMethods); } } else { IDEHelper.WriteToOutputWindow("Test Results File does not exist: {0}", _testResultsFile); } } catch (Exception ex) { IDEHelper.WriteToOutputWindow(ex.Message); IDEHelper.WriteToOutputWindow(ex.StackTrace); } }
/// <summary> /// Starts OpenCover.Console.exe to start CodeCoverage session. /// </summary> /// <returns>Test results (trx) and OpenCover results files' paths</returns> internal Tuple <string, string> Execute() { var openCoverStartInfo = GetOpenCoverProcessInfo(_commandLineArguments); if (!System.IO.File.Exists(openCoverStartInfo.FileName)) { MessageBox.Show("Please install OpenCover and execute tests!", "OpenCover not found!", MessageBoxButton.OK); return(null); } Process process = Process.Start(openCoverStartInfo); var consoleOutputReaderBuilder = new StringBuilder(); // TODO: See if this loop has any performance bottlenecks while (true) { if (process.HasExited) { break; } string nextLine = process.StandardOutput.ReadLine(); IDEHelper.WriteToOutputWindow(nextLine); consoleOutputReaderBuilder.AppendLine(nextLine); } process.WaitForExit(); IDEHelper.WriteToOutputWindow(process.StandardError.ReadToEnd()); ReadTestResults(); return(new Tuple <string, string>(_testResultsFile, _openCoverResultsFile)); }
/// <summary> /// Discovers all tests in the selected assemblies. /// </summary> /// <returns></returns> public void Discover(Action <List <TestClass> > discoveryDone) { if (_dlls != null) { var assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var testDiscovererPath = Path.Combine(assemblyPath, "OpenCover.UI.TestDiscoverer.exe"); if (File.Exists(testDiscovererPath)) { var builder = new StringBuilder(); foreach (var dll in _dlls) { builder.AppendFormat("\"{0}\" ", dll); } if (builder.Length == 0) { return; } StartTestDiscovery(discoveryDone, testDiscovererPath, builder.ToString()); } else { IDEHelper.WriteToOutputWindow("{0} not found. OpenCover cannot discover tests", testDiscovererPath); } } return; }
/// <summary> /// Starts the test discovery by starting the process OpenCover.UI.TestDiscoverer.exe. /// </summary> /// <param name="discoveryDone">The delegate that needs to be called after test discovery is done.</param> /// <param name="testDiscovererPath">The test discoverer path.</param> /// <param name="tests">The tests.</param> private void StartTestDiscovery(Action <List <TestClass> > discoveryDone, string testDiscovererPath, String testsDLLs) { List <TestClass> tests = new List <TestClass>(); string pipeGuid = Guid.NewGuid().ToString(); var pipeServer = new NamedPipeServerStream(pipeGuid, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); pipeServer.BeginWaitForConnection(res => { if (res.IsCompleted) { pipeServer.EndWaitForConnection(res); var newTests = ReadObject <OpenCover.UI.Model.Test.TestClass[]>(pipeServer); if (newTests != null && newTests.Length > 0) { tests.AddRange(newTests); } tests.ForEach(TestMethodWrapper => TestMethodWrapper.UpdateChildren()); IDEHelper.WriteToOutputWindow("{0} tests found", tests.Sum(test => test.TestMethods != null ? test.TestMethods.Length : 0)); discoveryDone(tests); } }, null); var processInfo = new ProcessStartInfo(testDiscovererPath, String.Format("{0} {1}", pipeGuid, testsDLLs)) { CreateNoWindow = true, UseShellExecute = false }; Process.Start(processInfo); }
/// <summary> /// Starts OpenCover.Console.exe to start CodeCoverage session. /// </summary> /// <returns>Test results (trx) and OpenCover results files' paths</returns> public Tuple <string, string> Execute() { var openCoverStartInfo = GetOpenCoverProcessInfo(); Process process = Process.Start(openCoverStartInfo); var consoleOutputReaderBuilder = new StringBuilder(); // TODO: See if this loop has any performance bottlenecks while (true) { if (process.HasExited) { break; } string nextLine = process.StandardOutput.ReadLine(); if (!String.IsNullOrWhiteSpace(nextLine) && nextLine.StartsWith("Results File:")) { _testResultsFile = nextLine.Replace("Results File: ", ""); } Debug.WriteLine(nextLine); consoleOutputReaderBuilder.AppendLine(nextLine); } process.WaitForExit(); Debug.WriteLine(process.StandardError.ReadToEnd()); IDEHelper.OpenFile(_package.DTE, _testResultsFile); return(new Tuple <string, string>(_testResultsFile, _openCoverResultsFile)); }
private T AddToolWindow <T>() where T : ToolWindowPane { try { T toolWindow = FindToolWindow(typeof(T), 0, true) as T; ToolWindows.Add(toolWindow); if (toolWindow == null || toolWindow.Frame == null) { throw new NotSupportedException(Resources.CanNotCreateWindow); } else { ((IVsWindowFrame)toolWindow.Frame).ShowNoActivate(); } return(toolWindow); } catch (Exception ex) { IDEHelper.WriteToOutputWindow(ex.Message); IDEHelper.WriteToOutputWindow(ex.StackTrace); } return(null); }
/// <summary> /// Initializes the control by adding handlers to BuildDone, SolutionOpened & SolutionClosing events. /// </summary> /// <param name="package">The package.</param> internal void Initialize(OpenCoverUIPackage package) { _package = package; _package.VSEventsHandler.BuildSucceeded += DiscoverTests; _package.VSEventsHandler.BuildFailed += () => { IDEHelper.WriteToOutputWindow("Build failed. Please make sure your solution builds properly before refreshing this window."); }; _package.VSEventsHandler.SolutionOpened += DiscoverTests; _package.VSEventsHandler.SolutionClosing += ClearTestsTreeViewChildren; }
/// <summary> /// Initializes a new instance of the <see cref="ExecuteSelectedTestsCommand"/> class. /// </summary> /// <param name="package">The Visual Studio Extension Package.</param> public ExecuteSelectedTestsCommand(OpenCoverUIPackage package, IVsUIShell uiShell) : base(package, new CommandID(GuidList.GuidOpenCoverUICmdSet, (int)PkgCmdIDList.CmdidCoverWithOpenCover)) { this._package = package; this._uiShell = uiShell; this._testTreeControl = IDEHelper.GetTestTreeControl(_uiShell); this._testTreeControl.LayoutUpdated += EnableDisableCommand; base.Enabled = false; }
/// <summary> /// Returns the word spans based on covered lines. /// </summary> /// <param name="snapshot">The text snapshot of file being opened.</param> /// <returns>Collection of word spans</returns> private List<SnapshotSpan> GetWordSpans(ITextSnapshot snapshot) { var wordSpans = new List<SnapshotSpan>(); // If the file was opened by CodeCoverageResultsControl, if (_codeCoverageResultsControl != null && _codeCoverageResultsControl.IsFileOpening) { // Get covered sequence points try { var sequencePoints = _codeCoverageResultsControl.GetActiveDocumentSequencePoints(); if (sequencePoints != null) { var covered = false; foreach (var sequencePoint in sequencePoints) { if (sequencePoint.VisitCount == 0) { covered = false; } else { covered = true; } int sequencePointStartLine = sequencePoint.StartLine - 1; int sequencePointEndLine = sequencePoint.EndLine - 1; var startLine = snapshot.Lines.FirstOrDefault(line => line.LineNumber == sequencePointStartLine); if (sequencePoint.EndLine == sequencePoint.StartLine) { AddWordSpan(wordSpans, snapshot, startLine.Extent.Start.Position + sequencePoint.StartColumn - 1, sequencePoint.EndColumn - sequencePoint.StartColumn + 1, covered); } else { // Get selected lines AddWordSpansForSequencePointsCoveringMultipleLines(snapshot, wordSpans, sequencePoint, sequencePointStartLine, sequencePointEndLine, covered); } } } } catch (Exception ex) { IDEHelper.WriteToOutputWindow(ex.Message); IDEHelper.WriteToOutputWindow(ex.StackTrace); } } return (wordSpans); }
/// <summary> /// Discovers the tests. /// </summary> private void DiscoverTests() { System.Threading.Tasks.Task.Factory.StartNew(new Action(() => { var potentialTestDLLs = IDEHelper.GetPotentialTestDLLs(); var testDiscoverer = new Discoverer(potentialTestDLLs); testDiscoverer.Discover(UpdateTreeView); })); }
/// <summary> /// Gets the coverage infor (sequence points) for the editor's document /// </summary> /// <returns></returns> protected IEnumerable <SequencePoint> GetSequencePointsForActiveDocument() { // Get the sequence points of the current file if (_codeCoverageResultsControl != null && _codeCoverageResultsControl.CoverageSession != null) { return(_codeCoverageResultsControl.CoverageSession.GetSequencePoints(IDEHelper.GetFileName(_textView))); } else { return(new List <SequencePoint>()); } }
/// <summary> /// Returns start information to launch OpenCover.Console.exe /// </summary> /// <returns>Open Cover process start information</returns> private ProcessStartInfo GetOpenCoverProcessInfo(string arguments) { var openCoverStartInfo = new ProcessStartInfo(_openCoverPath, arguments) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, WorkingDirectory = _currentTestWorkingDirectory.FullName }; IDEHelper.WriteToOutputWindow(openCoverStartInfo.Arguments); return(openCoverStartInfo); }
/// <summary> /// Runs OpenCover for gathering code coverage details. This testResult gets called after the build is completed /// </summary> private void RunOpenCover() { // TODO: Check validity of tests Task.Factory.StartNew( () => { var control = _package.GetToolWindow <CodeCoverageResultsToolWindow>().CodeCoverageResultsControl; var testsExplorer = _package.GetToolWindow <TestExplorerToolWindow>().TestExplorerControl; try { control.IsLoading = true; Tuple <string, string> files = _testExecutor.Execute(); var finalResults = _testExecutor.GetExecutionResults(); _testExecutor.UpdateTestMethodsExecution(TestExplorer.Tests); testsExplorer.ChangeGroupBy(TestMethodGroupingField.Outcome); if (finalResults != null) { control.UpdateCoverageResults(finalResults); // if the tool window is hidden, show it again. ShowCodeCoverageResultsToolWindow(); } else { control.IsLoading = false; } } catch (Exception ex) { IDEHelper.WriteToOutputWindow(ex.Message); IDEHelper.WriteToOutputWindow(ex.StackTrace); MessageBox.Show(String.Format("An exception occured: {0}\nPlease refer to output window for more details", ex.Message), Resources.MessageBoxTitle, MessageBoxButton.OK); control.IsLoading = false; } finally { Enabled = true; _isRunningCodeCoverage = false; } }); _package.VSEventsHandler.BuildDone -= RunOpenCover; }
internal override void UpdateTestMethodsExecution(IEnumerable <TestClass> tests) { var executedTests = tests.SelectMany(t => t.TestMethods) .Join(_execution, t => new { d = t.Class.DLLPath, n = t.FullyQualifiedName }, t => new { d = t.Item1, n = t.Item2.MethodName }, (testMethod, result) => new { TestMethod = testMethod, Result = result }); foreach (var test in executedTests) { test.TestMethod.ExecutionResult = test.Result.Item2; } if (File.Exists(_testResultsFile)) { IDEHelper.OpenFile(OpenCoverUIPackage.Instance.DTE, _testResultsFile); } }
/// <summary> /// TreeViewItem double click event handler. /// Opens the corresponding file if the clicked node represents either a class or a method. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="MouseButtonEventArgs"/> instance containing the event data.</param> private void TreeViewItemDoubleClicked(object sender, MouseButtonEventArgs e) { Method method = null; var treeView = sender as ICSharpCode.TreeView.SharpTreeView; if (treeView.SelectedItem is ClassNode) { method = (treeView.SelectedItem as ClassNode).Class.Methods.FirstOrDefault(); } else if (treeView.SelectedItem is MethodNode) { method = (treeView.SelectedItem as MethodNode).Method; } if (method != null) { var sequencePoints = CoverageSession.GetSequencePoints().Where(ig => ig.Key == method.FileRef.UniqueId); var coveredFiles = CoverageSession.GetFiles(); if (coveredFiles != null) { try { var file = coveredFiles.FirstOrDefault(f => f.UniqueId == method.FileRef.UniqueId); IDEHelper.CloseFile(_package.DTE, file.FullPath); _fileOpening = true; _lastSelectedFile = file.FullPath; IDEHelper.OpenFile(_package.DTE, file.FullPath); IDEHelper.GoToLine(_package.DTE, method.SequencePoints.FirstOrDefault().StartLine); } catch { } } e.Handled = true; } }
private void TestsTreeView_MouseDoubleClick(object sender, MouseButtonEventArgs e) { try { var treeView = sender as ICSharpCode.TreeView.SharpTreeView; var selectedItem = treeView.SelectedItem; var testMethod = selectedItem as TestMethod; if (testMethod != null) { var fullyQualifiedMethodName = testMethod.FullyQualifiedName; IDEHelper.WriteToOutputWindow("Navigating to test method: {0}", fullyQualifiedMethodName); IDEHelper.OpenFileByFullyQualifiedMethodName(fullyQualifiedMethodName); } } catch (Exception exception) { IDEHelper.WriteToOutputWindow(exception.Message); } }
/// <summary> /// Executes the post processor. /// </summary> /// <param name="command">The command.</param> /// <param name="resultsFile">The results file.</param> private void ExecutePostProcessor(string command, string resultsFile) { var normalizedCommand = Path.Combine(_currentWorkingDirectory.FullName, command); if (System.IO.File.Exists(normalizedCommand) && System.IO.File.Exists(resultsFile)) { if (!String.IsNullOrWhiteSpace(String.Format("cmd /C {0}", normalizedCommand))) { var postProcessorInfo = new ProcessStartInfo(normalizedCommand, resultsFile) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true, WorkingDirectory = _currentWorkingDirectory.FullName }; IDEHelper.WriteToOutputWindow("{0} {1}", command, postProcessorInfo.Arguments); Process process = Process.Start(postProcessorInfo); Debug.Assert(process != null, "process != null"); while (!process.HasExited) { var nextLine = process.StandardOutput.ReadLine(); IDEHelper.WriteToOutputWindow(nextLine); } process.WaitForExit(); IDEHelper.WriteToOutputWindow(process.StandardError.ReadToEnd()); } } else { IDEHelper.WriteToOutputWindow("Cannot find '{0}', when executing on {1}", normalizedCommand, resultsFile); } }
/// <summary> /// Converts a value. /// </summary> /// <param name="value">The value produced by the binding source.</param> /// <param name="targetType">The type of the binding target property.</param> /// <param name="parameter">The converter parameter to use.</param> /// <param name="culture">The culture to use in the converter.</param> /// <returns> /// A converted value. If the method returns null, the valid null value is used. /// </returns> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return(IDEHelper.GetImageURL(IDEHelper.GetIcon((TestExecutionStatus)value))); }