public override ColorTextBuilder Write(object parameters = null) { var builder = new ColorTextBuilder(); WriteRoundBox(builder, $"Top {_configuration.SlowestTestsCount} slowest assemblies"); var allAssembliesByName = _runContext.Runs .SelectMany(x => x.Key.EventEntries) .Where(x => x.Event.Event == EventNames.StartAssembly || x.Event.Event == EventNames.EndAssembly) .GroupBy(x => x.Event.TestSuite); var slowestAssemblies = allAssembliesByName .SelectMany(x => x.Select(y => y.Event)) .Where(x => x.Event == EventNames.EndAssembly) .OrderByDescending(x => x.Duration) .GroupBy(x => x.TestSuite) .Take(_configuration.SlowestTestsCount); foreach (var test in slowestAssemblies) { builder.Append($" {UTF8Constants.Bullet} "); builder.Append(DisplayUtil.GetPrettyTestName(test.FirstOrDefault().TestSuite, _colorScheme.DarkDefault, _colorScheme.Default, _colorScheme.DarkDefault)); builder.AppendLine($" {test.FirstOrDefault().Duration.ToElapsedTime()}", _colorScheme.Duration); } builder.AppendLine(Environment.NewLine); return(builder); }
/// <summary> /// Plot an XY chart /// </summary> /// <param name="data">Data dictionary Key = X, Value = Y</param> /// <param name="foregroundColor"></param> /// <param name="backgroundColor"></param> /// <returns></returns> public ColorTextBuilder GraphXY(Dictionary <DateTime, double> data, Color foregroundColor, Color backgroundColor) { var chart = new ColorTextBuilder(); char emptyValueChar; char valueChar; switch (ChartStyle) { case AsciiChartStyle.Block: emptyValueChar = '\u2581'; // ▁ valueChar = '\u2588'; // █ break; case AsciiChartStyle.InvertedBlock: emptyValueChar = '\u2587'; // █ valueChar = '\u2581'; // ▁ break; case AsciiChartStyle.Gradient: default: emptyValueChar = '\u2591'; // ░ valueChar = '\u2593'; // ▓ break; case AsciiChartStyle.InvertedGradient: emptyValueChar = '\u2593'; // ▓ valueChar = '\u2591'; // ░ break; } // sort the data into time slices to fit the X access on the chart var slicedData = GetXYSlices(data, Width, Height); for (var y = Height; y >= 0; y--) { // for each x value (time), print a character for the y axis for (var x = 0; x < slicedData.Count; x++) { var val = slicedData.Skip(x).Select(z => z.Value).FirstOrDefault(); if (val >= y) { chart.Append(valueChar.ToString(), foregroundColor); } else { chart.Append(emptyValueChar.ToString(), backgroundColor); } } chart.AppendLine(); } return(chart); }
public void ColorTextBuilder_ColorTextBuilder_ShouldAppendLine() { var builder = new ColorTextBuilder(); builder.Append(ColorTextBuilder.Create.Append("Test")); builder.AppendLine(ColorTextBuilder.Create.Append("Two")); builder.Append(ColorTextBuilder.Create.Append("Three")); var str = builder.ToString(); Assert.AreEqual($"TestTwo{Environment.NewLine}Three", str); }
public void ColorTextBuilder_String_ShouldAppend() { var builder = new ColorTextBuilder(); builder.Append("Test"); builder.Append("Two"); builder.Append("Three"); var str = builder.ToString(); Assert.AreEqual("TestTwoThree", str); }
public void ColorTextBuilder_GetWidth() { var builder = new ColorTextBuilder(); builder.Append("Test"); builder.Append("Two"); builder.AppendLine("Three"); builder.Append("Four"); builder.Append("Five"); builder.AppendLine("Six"); builder.Append("Seven"); builder.AppendLine("This is the final string"); var width = builder.Width; Assert.AreEqual("SevenThis is the final string".Length, width); }
private static void WriteValue(ColorTextBuilder builder, string value, JTokenType type, ColorScheme colorScheme) { switch (type) { case JTokenType.String: case JTokenType.Uri: case JTokenType.Guid: var val = value; // detect stack traces if (val.Contains(" at ") && val.Contains(" in ") && val.Contains(":line")) { if (!Console.IsOutputRedirected) { builder.Append(@""""); // don't encode the contents with valid json, we are more concerned about readability here builder.Append(StackTracePrettify.Format(val, colorScheme)); builder.Append(@""""); } else { builder.Append(Quote(Encode(val)), colorScheme.Default); } } else { builder.Append(Quote(Encode(val)), colorScheme.Default); } break; case JTokenType.Null: builder.Append("null", colorScheme.DarkDuration); break; case JTokenType.Comment: // this doesn't work with Newtonsoft's current JObject parser. builder.Append(value, colorScheme.DarkSuccess); break; case JTokenType.Boolean: builder.Append(value.ToLower(), colorScheme.Duration); break; case JTokenType.Undefined: case JTokenType.Bytes: case JTokenType.Date: case JTokenType.Float: case JTokenType.Integer: case JTokenType.TimeSpan: builder.Append(value, colorScheme.Duration); break; } }
public void ColorTextBuilder_GetHeightTrailingNewline() { var builder = new ColorTextBuilder(); builder.Append("Test"); builder.Append("Two"); builder.AppendLine("Three"); builder.Append("Four"); builder.Append("Five"); builder.AppendLine("Six"); builder.Append("Seven"); builder.AppendLine("This is the final string"); builder.AppendLine(); var height = builder.Height; Assert.AreEqual(4, height); }
public void ColorTextBuilder_MoreRightColorTextBuilder_ShouldInterlaceInColumnsAndTruncate() { var builder = new ColorTextBuilder(); var builder2 = new ColorTextBuilder(); builder.AppendLine("Left"); builder.AppendLine("Left side:2"); builder2.AppendLine("Right"); builder2.AppendLine("Right side:2"); builder2.Append("Right"); builder2.AppendLine(" side:3"); builder2.AppendLine("Right side:4 is too long"); var interlaced = builder.Interlace(builder2, 2, 15); var str = interlaced.ToString(); // data should be seperated into 2 columns 15 chars wide, plus 2 char padding Assert.AreEqual($"Left Right{Environment.NewLine}Left side:2 Right side:2{Environment.NewLine} Right side:3{Environment.NewLine} Right side:4 is{Environment.NewLine}", str); }
public override ColorTextBuilder Write(object parameters = null) { const string longTimeFormat = "hh:mm:ss.fff tt"; var allReports = (IEnumerable <DataEvent>)parameters; var builder = new ColorTextBuilder(); var headerLine = new string(UTF8Constants.BoxHorizontal, DefaultBorderWidth); var startTime = _runContext.Runs.Select(x => x.Key.StartTime).OrderBy(x => x).FirstOrDefault(); var endTime = _runContext.Runs.Select(x => x.Key.EndTime).OrderByDescending(x => x).FirstOrDefault(); if (endTime == DateTime.MinValue) { endTime = DateTime.Now; } var totalDuration = _runContext.Elapsed; builder.AppendLine(); builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxTopLeft}{headerLine}{headerLine}", _colorScheme.Highlight).Append($"{UTF8Constants.BoxHorizontal}", _colorScheme.DarkHighlight).Append($"{UTF8Constants.BoxHorizontal}", _colorScheme.DarkHighlight2).AppendLine($"{UTF8Constants.BoxHorizontal}", _colorScheme.DarkHighlight3) .AppendLine($"{UTF8Constants.BoxVertical} NUnit.Commander Test Report", _colorScheme.Highlight)); var testRunIds = allReports.GroupBy(x => x.TestRunId).Select(x => x.Key); if (testRunIds?.Any() == true) { builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" Test Run Id(s): {string.Join(", ", testRunIds)}")); } var frameworks = _runContext.Runs.SelectMany(x => x.Key.Frameworks).Distinct(); if (frameworks.Any() == true) { builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" Framework(s): {string.Join(", ", frameworks)}")); } var frameworkRuntimes = _runContext.Runs.SelectMany(x => x.Key.FrameworkRuntimes).Distinct(); if (frameworkRuntimes.Any() == true) { builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" Framework Runtime(s): {string.Join(", ", frameworkRuntimes)}")); } builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).Append($" Job Start: {startTime.ToString(longTimeFormat)}")); builder.Append($" Job End: {endTime.ToString(longTimeFormat)}"); builder.AppendLine($" Total Job Duration: {endTime.Subtract(startTime)}"); builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" Settings:")); builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" Test Runtime={totalDuration}")); if (_console.IsOutputRedirected) { builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" LogMode=Enabled")); } else { builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxVertical}", _colorScheme.Highlight).AppendLine($" LogMode=Disabled")); } builder.Append(ColorTextBuilder.Create.Append($"{UTF8Constants.BoxBottomLeft}{headerLine}{headerLine}", _colorScheme.Highlight).Append($"{UTF8Constants.BoxHorizontal}", _colorScheme.DarkHighlight).Append($"{UTF8Constants.BoxHorizontal}", _colorScheme.DarkHighlight2).AppendLine($"{UTF8Constants.BoxHorizontal}", _colorScheme.DarkHighlight3)); return(builder); }
public static ColorTextBuilder Format(string text, ColorScheme colorScheme) { try { var builder = new ColorTextBuilder(); var colors = typeof(IColorScheme).GetPublicProperties(); if (!text.Contains("\n")) { text = text.Replace("at ", $"{Environment.NewLine}at ").Replace("--- E", $"{Environment.NewLine}--- E"); } var formatted = StackTraceFormatter.FormatHtml(text, new StackTraceHtmlFragments { BeforeType = $"<{nameof(colorScheme.DarkDefault)}>", AfterType = $"</{nameof(colorScheme.DarkDefault)}>", BeforeParameters = $"<{nameof(colorScheme.DarkDefault)}>", AfterParameters = $"</{nameof(colorScheme.DarkDefault)}>", BeforeFile = $"<{nameof(colorScheme.DarkDuration)}>", AfterFile = $"</{nameof(colorScheme.DarkDuration)}>", BeforeMethod = $"<{nameof(colorScheme.Duration)}>", AfterMethod = $"</{nameof(colorScheme.Duration)}>", BeforeLine = $"<{nameof(colorScheme.Error)}>", AfterLine = $"</{nameof(colorScheme.Error)}>", }, false); // indent each line var indentBy = " "; formatted = indentBy + formatted.Replace(Environment.NewLine, $"{Environment.NewLine}{indentBy}"); var chunk = string.Empty; var startIndex = -1; var endIndex = -1; // todo: this is horribly inefficient, but I will readdress later if (formatted.Length > 0) { foreach (var c in formatted) { chunk += c; foreach (var colorProperty in colors) { var colorStartTag = $"<{colorProperty.Name}>"; var colorEndTag = $"</{colorProperty.Name}>"; startIndex = chunk.IndexOf(colorStartTag); if (startIndex >= 0) { // add everything before this point if (startIndex > 0) { builder.Append(chunk.Substring(0, startIndex), colorScheme.Default); } chunk = chunk.Substring(startIndex + colorStartTag.Length, chunk.Length - colorStartTag.Length - startIndex); } endIndex = chunk.IndexOf(colorEndTag); if (endIndex >= 0) { // add everything before this point builder.Append(chunk.Substring(0, endIndex), colorScheme.GetColor(colorProperty.Name)); chunk = chunk.Substring(endIndex + colorEndTag.Length, chunk.Length - colorEndTag.Length - endIndex); } } } if (startIndex == -1 && endIndex == -1 && builder.Length == 0) { builder.AppendLine(text, colorScheme.Default); } } else { // formatted text not found, output the full original text builder.AppendLine(text, colorScheme.Default); } return(builder); } catch (Exception) { // something went wrong return(ColorTextBuilder.Create.Append(text)); } }
public override ColorTextBuilder Write(object parameters = null) { var builder = new ColorTextBuilder(); var chartWidth = 30; var chartHeight = 10; var chartSpacing = 3; var testConcurrency = new ColorTextBuilder(); var testData = _runContext.Runs.SelectMany(x => x.Key.PerformanceLog.GetAll(PerformanceLog.PerformanceType.TestConcurrency)); if (testData.Sum(x => x.Value) > 0) { WriteRoundBox(testConcurrency, $"Test Concurrency", 8); var testConcurrencyChart = new AsciiChart(chartWidth, chartHeight); var testChartData = testData.ToDictionary(key => key.TimeSlot, value => value.Value); testConcurrency.Append(testConcurrencyChart.GraphXY(testChartData, _colorScheme.DarkSuccess, _colorScheme.DarkDefault)); testConcurrency.AppendLine(); } var testFixtureConcurrency = new ColorTextBuilder(); var testFixtureData = _runContext.Runs.SelectMany(x => x.Key.PerformanceLog.GetAll(PerformanceLog.PerformanceType.TestFixtureConcurrency)); if (testFixtureData.Sum(x => x.Value) > 0) { WriteRoundBox(testFixtureConcurrency, "Test Fixture Concurrency"); var testFixtureConcurrencyChart = new AsciiChart(chartWidth, chartHeight); var testFixtureChartData = testFixtureData.ToDictionary(key => key.TimeSlot, value => value.Value); testFixtureConcurrency.Append(testFixtureConcurrencyChart.GraphXY(testFixtureChartData, _colorScheme.DarkHighlight, _colorScheme.DarkDefault)); testFixtureConcurrency.AppendLine(); } var assemblyConcurrency = new ColorTextBuilder(); var assemblyData = _runContext.Runs.SelectMany(x => x.Key.PerformanceLog.GetAll(PerformanceLog.PerformanceType.AssemblyConcurrency)); if (assemblyData.Sum(x => x.Value) > 0) { WriteRoundBox(assemblyConcurrency, "Assembly Concurrency", 4); var assemblyConcurrencyChart = new AsciiChart(chartWidth, chartHeight); var assemblyChartData = assemblyData.ToDictionary(key => key.TimeSlot, value => value.Value); assemblyConcurrency.Append(assemblyConcurrencyChart.GraphXY(assemblyChartData, _colorScheme.DarkError, _colorScheme.DarkDefault)); assemblyConcurrency.AppendLine(); } var cpuUsage = new ColorTextBuilder(); var cpuUsageData = _runContext.Runs.SelectMany(x => x.Key.PerformanceLog.GetAll(PerformanceLog.PerformanceType.CpuUsed)); if (cpuUsageData.Sum(x => x.Value) > 0) { WriteRoundBox(cpuUsage, "CPU Usage"); var cpuUsageChart = new AsciiChart(chartWidth, chartHeight); var cpuUsageChartData = cpuUsageData.ToDictionary(key => key.TimeSlot, value => value.Value); cpuUsage.Append(cpuUsageChart.GraphXY(cpuUsageChartData, _colorScheme.Default, _colorScheme.DarkDefault)); cpuUsage.AppendLine(); } // stack the graphs horizontally, until they won't fit on the console var chartRows = new List <ColorTextBuilder>(); var isNewRow = false; var charts = testConcurrency; chartRows.Add(charts); chartRows[chartRows.Count - 1] = StackGraph(chartRows.Last(), testFixtureConcurrency, chartSpacing, out isNewRow); if (isNewRow) { chartRows.Add(ColorTextBuilder.Create.Append(testFixtureConcurrency)); } chartRows[chartRows.Count - 1] = StackGraph(chartRows.Last(), assemblyConcurrency, chartSpacing, out isNewRow); if (isNewRow) { chartRows.Add(ColorTextBuilder.Create.Append(assemblyConcurrency)); } chartRows[chartRows.Count - 1] = StackGraph(chartRows.Last(), cpuUsage, chartSpacing, out isNewRow); if (isNewRow) { chartRows.Add(ColorTextBuilder.Create.Append(cpuUsage)); } foreach (var chartRow in chartRows) { builder.AppendLine(chartRow); } return(builder); }
public override ColorTextBuilder Write(object parameters = null) { var allReports = (IEnumerable <DataEvent>)parameters; var builder = new ColorTextBuilder(); var lineSeparator = new string(UTF8Constants.HorizontalLine, !_console.IsOutputRedirected ? (Console.WindowWidth - 1) : DefaultBorderWidth); var showErrors = _configuration.GenerateReportType.HasFlag(GenerateReportType.Errors); var showStackTraces = _configuration.GenerateReportType.HasFlag(GenerateReportType.StackTraces); var showTestOutput = _configuration.GenerateReportType.HasFlag(GenerateReportType.TestOutput); if (showErrors || showStackTraces || showTestOutput) { var isPassed = allReports .SelectMany(x => x.Report.TestReports) .Count(x => x.TestStatus == TestStatus.Fail) == 0; if (!isPassed) { WriteRoundBox(builder, "FAILED TESTS", 0, _colorScheme.Error); } var testIndex = 0; var groupedByRun = allReports .GroupBy(x => x.RunNumber); var failedTestCases = groupedByRun .ToDictionary(x => x.Key, value => value.SelectMany(y => y.Report.TestReports.Where(z => z.TestStatus == TestStatus.Fail))); var lineSeparatorColor = _colorScheme.RaisedBackground; foreach (var testGroup in failedTestCases) { var runNumber = testGroup.Key; foreach (var test in testGroup.Value) { testIndex++; // write the failed test header if (!_console.IsOutputRedirected) { builder.AppendLine($"{DisplayUtil.Pad(Console.WindowWidth - 1)}", _colorScheme.Error, _colorScheme.DarkError); } var testIndexStr = $"#{testIndex}) "; if (failedTestCases.Count() > 1) { testIndexStr = $"#{runNumber}-{testIndex}) "; } builder.Append(testIndexStr, _colorScheme.DarkError); // write the test name only builder.Append(test.TestName, _colorScheme.Error); if (!_console.IsOutputRedirected) { builder.AppendLine($"{DisplayUtil.Pad(Console.WindowWidth - testIndexStr.Length - test.TestName.Length - 1)}", _colorScheme.Error); } else { builder.AppendLine(); } // write the test path + name (for Stack Trace Explorer) var fullName = $"{DisplayUtil.Pad(testIndexStr.Length)}{test.FullName}"; builder.Append(fullName, _colorScheme.DarkDuration); if (!_console.IsOutputRedirected) { builder.AppendLine($"{DisplayUtil.Pad(Console.WindowWidth - fullName.Length - 1)}", _colorScheme.Error); } else { builder.AppendLine(); } var runtimeVersion = $"{DisplayUtil.Pad(testIndexStr.Length)}{test.RuntimeVersion}"; builder.Append($"{runtimeVersion}", _colorScheme.DarkDefault); if (!_console.IsOutputRedirected) { builder.AppendLine($"{DisplayUtil.Pad(Console.WindowWidth - runtimeVersion.Length)}", _colorScheme.Error); } else { builder.AppendLine(); } builder.Append($" Duration ", _colorScheme.DarkDefault); builder.AppendLine($"{test.Duration.ToElapsedTime()}", _colorScheme.Duration); if (showErrors && !string.IsNullOrEmpty(test.ErrorMessage)) { builder.AppendLine($" Error Output ", _colorScheme.Bright); builder.AppendLine(lineSeparator, lineSeparatorColor); if (!_configuration.DontPrettify) { var errorMessage = ErrorEncoding.Format(test.ErrorMessage, _colorScheme); builder.Append(errorMessage); } else { builder.Append(test.ErrorMessage); } builder.AppendLine(); builder.AppendLine(lineSeparator, lineSeparatorColor); } if (showStackTraces && !string.IsNullOrEmpty(test.StackTrace)) { builder.AppendLine($" Stack Trace:", _colorScheme.Bright); builder.AppendLine(lineSeparator, lineSeparatorColor); if (!_configuration.DontPrettify) { builder.Append(StackTracePrettify.Format(test.StackTrace, _colorScheme)); } else { builder.Append(test.StackTrace); } builder.AppendLine(); builder.AppendLine(lineSeparator, lineSeparatorColor); } if (showTestOutput && !string.IsNullOrEmpty(test.TestOutput)) { builder.AppendLine($" Test Output: ", _colorScheme.Bright); builder.AppendLine(lineSeparator, lineSeparatorColor); if (!_configuration.DontPrettify) { builder.Append(ErrorEncoding.Format(test.TestOutput, _colorScheme)); } else { builder.Append(test.TestOutput); } builder.AppendLine(); builder.AppendLine(lineSeparator, lineSeparatorColor); } builder.AppendLine(Environment.NewLine); } } } return(builder); }
public ColorTextBuilder BuildReport() { var str = new ColorTextBuilder(); str.Append($" Total Runs Analyzed: {UTF8Constants.LeftBracket}", _colorScheme.Bright).Append($"{TotalDataPoints}", _colorScheme.Highlight).AppendLine($"{UTF8Constants.RightBracket}", _colorScheme.Bright); str.AppendLine(); str.Append(" Unstable Tests:", _colorScheme.Bright); if (UnstableTests.Count == 0) { str.AppendLine(" <none>"); } else { str.AppendLine(); foreach (var test in UnstableTests) { str.Append($" {_bulletChar} ") .Append(DisplayUtil.GetPrettyTestName(test.FullName, _colorScheme.DarkDefault, _colorScheme.Default, _colorScheme.DarkDefault)) .Append($"{UTF8Constants.LeftBracket}", _colorScheme.Bright) .Append(string.Format("{0:0.0}% failures", test.Percentage * 100.0), _colorScheme.Error) .Append(", ") .Append(test.Ratio, _colorScheme.Error) .AppendLine($"{UTF8Constants.RightBracket}", _colorScheme.Bright); } } str.AppendLine(); str.Append(" Duration Anomalies:", _colorScheme.Bright); if (DurationAnomalyTests.Count == 0) { str.AppendLine(" <none>"); } else { str.AppendLine(); foreach (var test in DurationAnomalyTests) { // test got slower var color = _colorScheme.Error; var direction = "+"; if (test.DurationChange.Ticks < 0) { // test got faster color = _colorScheme.DarkSuccess; direction = ""; } str.Append($" {_bulletChar} ") .Append(DisplayUtil.GetPrettyTestName(test.FullName, _colorScheme.DarkDefault, _colorScheme.Default, _colorScheme.DarkDefault)) .Append($"Diff", _colorScheme.Bright) .Append($"{UTF8Constants.LeftBracket}", _colorScheme.Bright) .Append($"{direction}{test.DurationChange.ToElapsedTime()}", color) .Append($"{UTF8Constants.RightBracket}", _colorScheme.Bright) .Append($" Time", _colorScheme.Bright) .Append($"{UTF8Constants.LeftBracket}", _colorScheme.Bright) .Append($"{test.Duration.ToElapsedTime()}", _colorScheme.Duration) .Append($"{UTF8Constants.RightBracket}", _colorScheme.Bright) .Append($" Median", _colorScheme.Bright) .Append($"{UTF8Constants.LeftBracket}", _colorScheme.Bright) .Append($"{test.Average.ToElapsedTime()}", _colorScheme.Duration) .AppendLine($"{UTF8Constants.RightBracket}", _colorScheme.Bright); } } str.AppendLine(); return(str); }
public void Draw(ViewContext context, long ticks) { if (_startTicks == 0) { _startTicks = ticks; context.Console.Clear(); } if (!context.Console.IsOutputRedirected) { // if the user has scrolled the page don't perform any drawing if (Console.WindowTop > 0) { return; } Console.CursorVisible = false; _performFullDraw = (_startTicks - ticks) % DefaultTickWait == 0; var windowWidth = Console.WindowWidth; var windowHeight = Console.WindowHeight; if (windowHeight != _previousWindowHeight) { _performFullDraw = true; } _previousWindowHeight = windowHeight; if (_performFullDraw) { ClearScreen(context); } var lineSeparator = DisplayUtil.Pad(Console.WindowWidth - 1, UTF8Constants.HorizontalLine); var yPos = 0; // figure out how many tests we can fit on screen var maxActiveTestsToDisplay = Console.WindowHeight - yPos - 2; var totalActiveTests = context.ActiveTests.Count(x => !x.IsQueuedForRemoval); var totalActiveTestFixtures = context.ActiveTestFixtures.Count(x => !x.IsQueuedForRemoval); var totalActiveAssemblies = context.ActiveAssemblies.Count(x => !x.IsQueuedForRemoval); if (totalActiveTests > 0 && totalActiveTestFixtures == 0) { // fix for older versions of nUnit that don't send the start test fixture event // it will still be incorrect, as it will treat parents of tests with multiple cases as a testfixture var parentIds = context.ActiveTests .Where(x => !x.IsQueuedForRemoval && !string.IsNullOrEmpty(x.Event.ParentId)) .Select(x => x.Event.ParentId) .Distinct(); totalActiveTestFixtures = context.ActiveTestSuites.Count(x => !x.IsQueuedForRemoval && parentIds.Contains(x.Event.Id)); } var totalPasses = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Pass); var totalFails = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Fail); var totalIgnored = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Skipped); var totalTestsProcessed = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest); WriteHeader(context); // write the summary of all test state context.Console.WriteAt(ColorTextBuilder.Create .Append("Tests state: ", context.ColorScheme.Bright) .Append($"Tests=", context.ColorScheme.Default) .Append($"{totalActiveTests} ", context.ColorScheme.Highlight) .Append($"Fixtures=", context.ColorScheme.Default) .Append($"{totalActiveTestFixtures} ", context.ColorScheme.Highlight) .Append($"Assemblies=", context.ColorScheme.Default) .Append($"{totalActiveAssemblies} ", context.ColorScheme.Highlight) .Append($"Pass="******"{totalPasses} ", context.ColorScheme.Success) .AppendIf(totalPasses == 0, $"{totalPasses} ", context.ColorScheme.Default) .Append($"Fail=", context.ColorScheme.Default) .AppendIf(totalFails > 0, $"{totalFails} ", context.ColorScheme.DarkError) .AppendIf(totalFails == 0, $"{totalFails} ", context.ColorScheme.Default) .AppendIf(!context.Console.IsOutputRedirected, $"Ignored=", context.ColorScheme.Default) .AppendIf(!context.Console.IsOutputRedirected, $"{totalIgnored} ", context.ColorScheme.DarkDefault) .Append($"Total=", context.ColorScheme.Default) .Append($"{totalTestsProcessed} ", context.ColorScheme.DarkDefault) .AppendIf(context.TotalTestsQueued > 0, $"of ", context.ColorScheme.Default) .AppendIf(context.TotalTestsQueued > 0, $"{context.TotalTestsQueued} ", context.ColorScheme.DarkDefault) .AppendIf(context.TotalTestsQueued > 0, $"{UTF8Constants.LeftBracket}", context.ColorScheme.Bright) .AppendIf(context.TotalTestsQueued > 0, $"{((totalTestsProcessed / (double)context.TotalTestsQueued) * 100.0):F0}%", context.ColorScheme.DarkDuration) .AppendIf(context.TotalTestsQueued > 0, $"{UTF8Constants.RightBracket}", context.ColorScheme.Bright) //.Append(context.Client.IsWaitingForConnection ? $"{UTF8Constants.LeftBracket}waiting{UTF8Constants.RightBracket}" : "", context.ColorScheme.DarkDuration) .AppendIf(!context.Console.IsOutputRedirected, (length) => DisplayUtil.Pad(windowWidth - length)), 0, yPos + 1, DirectOutputMode.Static); // don't display this as often as its expensive to write if (_performFullDraw) { context.Console.SetCursorPosition(0, 2); var allCompletedAssemblies = context.EventLog .Where(x => x.Event.Event == EventNames.EndAssembly) .GroupBy(x => x.Event.TestSuite) .Select(x => x.FirstOrDefault()) .OrderByDescending(x => x.Event.Duration); var allPendingAssemblies = context.EventLog .Where(x => x.Event.Event == EventNames.StartAssembly && !allCompletedAssemblies.Select(y => y.Event.TestSuite).Contains(x.Event.TestSuite)) .GroupBy(x => x.Event.TestSuite) .Select(x => x.FirstOrDefault()) .OrderByDescending(x => x.DateAdded); var completedAssemblies = allCompletedAssemblies.Take(20); var pendingAssemblies = allPendingAssemblies.Take(20); var completedAssembliesBuilder = new ColorTextBuilder(); completedAssembliesBuilder.Append($"Completed Assemblies ", context.ColorScheme.Bright) .Append("[").Append($"{allCompletedAssemblies.Count()}", context.ColorScheme.Duration).Append("]") .AppendLine(); if (completedAssemblies.Any()) { foreach (var assembly in completedAssemblies) { var entryOutput = new ColorTextBuilder(); var completionTime = assembly.DateAdded; var duration = DateTime.Now.Subtract(assembly.Event.StartTime); if (assembly.Event.EndTime != DateTime.MinValue) { duration = assembly.Event.Duration; } var prettyTestName = DisplayUtil.GetPrettyTestName(assembly.Event.TestSuite, context.ColorScheme.DarkDefault, context.ColorScheme.Default, context.ColorScheme.DarkDefault, context.MaxTestCaseArgumentLength); // print out this test name and duration entryOutput .Append($"[{completionTime.ToString(TimeFormat)}] ", context.ColorScheme.DarkDuration) .Append(prettyTestName) .Append($" {duration.ToTotalElapsedTime()}", context.ColorScheme.Duration); completedAssembliesBuilder.AppendLine(entryOutput); } } var activeAssembliesBuilder = new ColorTextBuilder(); activeAssembliesBuilder.Append($"Running Assemblies", context.ColorScheme.Bright) .Append("[").Append($"{allPendingAssemblies.Count()}", context.ColorScheme.Duration).Append("]") .AppendLine(); if (pendingAssemblies.Any()) { foreach (var assembly in pendingAssemblies) { var entryOutput = new ColorTextBuilder(); var completionTime = assembly.DateAdded; var duration = DateTime.Now.Subtract(assembly.Event.StartTime); if (assembly.Event.EndTime != DateTime.MinValue) { duration = assembly.Event.Duration; } var prettyTestName = DisplayUtil.GetPrettyTestName(assembly.Event.TestSuite, context.ColorScheme.DarkDefault, context.ColorScheme.Default, context.ColorScheme.DarkDefault, context.MaxTestCaseArgumentLength); // print out this test name and duration entryOutput .Append(prettyTestName) .Append($" {duration.ToTotalElapsedTime()}", context.ColorScheme.Duration); activeAssembliesBuilder.AppendLine(entryOutput); } } // write builders side-by-side var columnSpacing = 2; var columnWidth = (context.Console.WindowWidth / 2) - (columnSpacing * 2); var output = completedAssembliesBuilder.Interlace(activeAssembliesBuilder, columnSpacing, columnWidth); context.Console.WriteLine(output); // output complete context.Console.SetCursorPosition(0, 0); } } }
public override ColorTextBuilder Write(object parameters = null) { var allReports = (IEnumerable<DataEvent>)parameters; var builder = new ColorTextBuilder(); var totalDuration = TimeSpan.FromTicks(allReports.Sum(x => x.Duration.Ticks)); var isPassed = allReports.Sum(x => x.Failed) == 0; if (_runContext.Runs.Count > 1) { var runNumber = 0; foreach (var run in _runContext.Runs) { runNumber++; var allSuccess = run.Value.Sum(x => x.Failed) == 0; var anyFailure = run.Value.Sum(x => x.Failed) > 0; var statusColor = _colorScheme.Error; var successColor = _colorScheme.Default; var failuresColor = _colorScheme.Default; var errorsColor = _colorScheme.Default; var warningsColor = _colorScheme.Default; var testRunner = run.Value.Select(x => x.TestRunner).FirstOrDefault(); var testRuntime = run.Value.Select(x => x.Runtime).FirstOrDefault(); var testCount = run.Value.Sum(x => x.TestCount); var passed = run.Value.Sum(x => x.Passed); var failed = run.Value.Sum(x => x.Failed); var warnings = run.Value.Sum(x => x.Warnings); var asserts = run.Value.Sum(x => x.Asserts); var inconclusive = run.Value.Sum(x => x.Inconclusive); var errors = run.Value.SelectMany(x => x.Report.TestReports.Where(t => t.TestStatus == TestStatus.Fail && !string.IsNullOrEmpty(t.ErrorMessage))).Count(); var skipped = run.Value.Sum(x => x.Skipped); var totalRuns = run.Value.GroupBy(x => x.RunNumber).Count(); if (allSuccess) { successColor = _colorScheme.Success; statusColor = _colorScheme.Success; } if (failed > 0) failuresColor = _colorScheme.Error; if (errors > 0) errorsColor = _colorScheme.DarkError; if (warnings > 0) warningsColor = _colorScheme.DarkHighlight; WriteRoundBox(builder, $"Test Run #{runNumber} Summary", 0, _colorScheme.DarkHighlight); builder.Append($" Result: ", _colorScheme.Default); builder.AppendLine(allSuccess ? "Passed" : "Failed", statusColor); builder.Append($" Duration: ", _colorScheme.Default); builder.Append($"{testCount:N0} ", _colorScheme.Bright); builder.Append($"tests run in ", _colorScheme.Default); builder.AppendLine($"{run.Key.EndTime.Subtract(run.Key.StartTime).ToTotalElapsedTime()}", _colorScheme.Duration); builder.Append($" Test Framework: ", _colorScheme.Default); builder.AppendLine($"{testRuntime:N0} ", _colorScheme.Bright); builder.Append($" Test Runner: ", _colorScheme.DarkDefault); builder.AppendLine($"{testRunner:N0} ", _colorScheme.Default); builder.AppendLine(""); builder.Append($" Test Runs: ", _colorScheme.Default); builder.AppendLine($"{totalRuns}", _colorScheme.Bright); builder.Append($" Test Count: ", _colorScheme.Default); builder.Append($"{testCount:N0}", _colorScheme.Bright); builder.Append($", Passed: ", _colorScheme.Default); builder.Append($"{passed:N0}", successColor); builder.Append($", Failed: ", _colorScheme.Default); builder.AppendLine($"{failed:N0}", failuresColor); builder.Append($" Errors: ", _colorScheme.DarkDefault); builder.Append($"{errors:N0}", errorsColor); builder.Append($", Warnings: ", _colorScheme.DarkDefault); builder.Append($"{warnings:N0}", warningsColor); builder.Append($", Ignored: ", _colorScheme.DarkDefault); builder.AppendLine($"{skipped}", _colorScheme.Default); builder.Append($" Asserts: ", _colorScheme.DarkDefault); builder.Append($"{asserts:N0}", _colorScheme.Default); builder.Append($", Inconclusive: ", _colorScheme.DarkDefault); builder.AppendLine($"{inconclusive:N0}", _colorScheme.Default); builder.Append($" Peak Cpu: ", _colorScheme.DarkDefault); builder.Append($"{run.Key.Performance.PeakCpuUsed:N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{run.Key.Performance.MedianCpuUsed:N0}%", _colorScheme.Default); builder.Append($" Peak Memory: ", _colorScheme.DarkDefault); builder.Append($"{DisplayUtil.GetFriendlyBytes((long)run.Key.Performance.PeakMemoryUsed)}", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{DisplayUtil.GetFriendlyBytes((long)run.Key.Performance.MedianMemoryUsed)}", _colorScheme.Default); builder.Append($" Peak Disk Time: ", _colorScheme.DarkDefault); builder.Append($"{run.Key.Performance.PeakDiskTime:N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{run.Key.Performance.MedianDiskTime:N0}%", _colorScheme.Default); builder.Append($" Peak Test Concurrency: ", _colorScheme.DarkDefault); builder.Append($"{run.Key.Performance.PeakTestConcurrency:N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{run.Key.Performance.MedianTestConcurrency:N0}%", _colorScheme.Default); builder.Append($" Peak Test Fixture Concurrency: ", _colorScheme.DarkDefault); builder.Append($"{run.Key.Performance.PeakTestFixtureConcurrency:N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{run.Key.Performance.MedianTestFixtureConcurrency:N0}%", _colorScheme.Default); builder.Append($" Peak Assembly Concurrency: ", _colorScheme.DarkDefault); builder.Append($"{run.Key.Performance.PeakAssemblyConcurrency:N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{run.Key.Performance.MedianAssemblyConcurrency:N0}%", _colorScheme.Default); builder.Append($" Run Id: ", _colorScheme.Default); builder.AppendLine(run.Key.CommanderRunId.ToString(), _colorScheme.DarkDefault); builder.AppendLine(Environment.NewLine); } } return builder; }
/// <summary> /// Format a json string /// </summary> /// <param name="text"></param> /// <param name="colorScheme"></param> /// <returns></returns> public static ColorTextBuilder Format(string text, ColorScheme colorScheme) { try { var builder = new ColorTextBuilder(); // fix badly encoded strings if (text.Contains(@"\r") || text.Contains(@"\n")) { text = text.Replace("\r", "").Replace("\n", ""); text = text.Replace(@"\r", "\r"); text = text.Replace(@"\n", "\n"); } text = text.Replace(@"\\\\", @"\\"); var startIndex = text.IndexOf('<'); if (startIndex > 0) { builder.AppendLine(text.Substring(0, startIndex), colorScheme.DarkDefault); text = text.Substring(startIndex, text.Length - startIndex); } var parser = new HtmlParser(); parser.Error += Parser_Error; parser.Parsing += Parser_Parsing; var document = parser.ParseDocument(text); var writer = new StringWriter(); document.ToHtml(writer, new PrettyMarkupFormatter { Indentation = " ", NewLine = Environment.NewLine }); var html = writer.ToString(); if (html.Length > 0) { // html is prettified, now we need to color code it var buffer = new StringBuilder(); var contentsColor = colorScheme.Default; var isInComment = false; foreach (var c in html) { if (c == '>' && isInComment) { // comment detection buffer.Append(c); var val = buffer.ToString(); if (val.EndsWith("-->")) { isInComment = false; // if this is a stack trace, find the start var stStartIndex = val.IndexOf(" at "); if (stStartIndex >= 0 && val.Contains(" in ")) { // found a stack trace in a comment if (stStartIndex > 0) { builder.Append(val.Substring(0, stStartIndex), contentsColor); } var stEndIndex = val.IndexOf("-->"); var stackTrace = val.Substring(stStartIndex, stEndIndex - stStartIndex); builder.AppendLine(StackTracePrettify.Format(stackTrace, colorScheme)); if (stEndIndex < val.Length) { builder.Append(val.Substring(stEndIndex, val.Length - stEndIndex), contentsColor); } } else { builder.Append(val, contentsColor); } buffer.Clear(); contentsColor = colorScheme.Default; continue; } } if (isInComment) { buffer.Append(c); continue; } if (c == '<' && buffer.Length > 0 && !isInComment) { // add contents of tag var val = buffer.ToString(); // detect stack traces if (val.Contains("<!--")) { // stack traces in ASP.Net are usually embedded in an html comment contentsColor = colorScheme.DarkSuccess; isInComment = true; buffer.Append(c); continue; } if (val.Contains(" at ") && val.Contains(" in ")) { if (!Console.IsOutputRedirected) { builder.Append(StackTracePrettify.Format(HttpUtility.HtmlDecode(val), colorScheme)); } else { builder.Append(HttpUtility.HtmlDecode(val), contentsColor); } } else { builder.Append(HttpUtility.HtmlDecode(val), contentsColor); } buffer.Clear(); } buffer.Append(c); var match = Regex.Match(buffer.ToString(), "<.+?>"); if (match.Success) { // matched a tag, append it contentsColor = colorScheme.Default; var color = colorScheme.DarkDefault; var tag = buffer.ToString(); switch (tag.ToLower().Replace("<", "").Replace(">", "").Replace("/", "")) { case "code": case "pre": color = colorScheme.DarkDuration; contentsColor = colorScheme.Default; break; } if (tag.Contains("<!--")) { color = colorScheme.DarkSuccess; } builder.Append(tag, color); buffer.Clear(); } } } else { // html not found, output the full original text builder.AppendLine(text, colorScheme.Default); } return(builder); } catch (Exception) { // something went wrong return(ColorTextBuilder.Create.Append(text)); } }
/// <summary> /// Write the final report to the console output /// </summary> /// <param name="allReports"></param> /// <param name="eventLog"></param> public TestStatus WriteFinalReport() { var overallTestStatus = TestStatus.Fail; var uniqueRunIds = _runContext.Runs.Select(x => x.Key.CommanderRunId).Distinct(); var commanderIdMap = new Dictionary <Guid, ICollection <Guid> >(); foreach (var commanderRunId in uniqueRunIds) { commanderIdMap.Add(commanderRunId, _runContext.Runs.SelectMany(x => x.Value.Select(y => y.TestRunId)).Distinct().ToList()); } var allReports = _runContext.Runs.SelectMany(x => x.Value); var startTime = _runContext.Runs.Select(x => x.Key.StartTime).OrderBy(x => x).FirstOrDefault(); var endTime = _runContext.Runs.Select(x => x.Key.EndTime).OrderByDescending(x => x).FirstOrDefault(); var totalDuration = TimeSpan.FromTicks(allReports.Sum(x => x.Duration.Ticks)); var isPassed = allReports .SelectMany(x => x.Report.TestReports) .Count(x => x.TestStatus == TestStatus.Fail) == 0; if (isPassed) { overallTestStatus = TestStatus.Pass; } // *********************** // Total Run Summary // *********************** var passFail = _reportFactory.Create <ReportSummary>(allReports); // *********************** // Multiple Run Summary // *********************** var passFailByRun = _reportFactory.Create <ReportRunsSummary>(allReports); // *********************** // Slowest Test Summary // *********************** var performance = new ColorTextBuilder(); if (_configuration.GenerateReportType.HasFlag(GenerateReportType.Performance)) { performance.Append(_reportFactory.Create <SlowestTestSummary>()); } // *********************** // Slowest Assemblies Summary // *********************** if (_configuration.GenerateReportType.HasFlag(GenerateReportType.Performance)) { performance.Append(_reportFactory.Create <SlowestAssembliesSummary>()); } // *********************** // Charts // *********************** if (_configuration.GenerateReportType.HasFlag(GenerateReportType.Charts)) { performance.Append(_reportFactory.Create <StackedCharts>()); } // *********************** // Failed Tests Output // *********************** var testOutput = _reportFactory.Create <FailedTestsReport>(allReports); // *********************** // Total Run Overview // *********************** var overview = _reportFactory.Create <Overview>(allReports); // *********************** // Historical analysis // *********************** var historicalAnalysis = _reportFactory.Create <Overview>(allReports); // *********************** // Print all reports to console // *********************** _console.WriteLine(overview); if (isPassed) { _console.WriteAscii(ColorTextBuilder.Create.Append("PASSED", _colorScheme.Success)); } else { _console.WriteAscii(ColorTextBuilder.Create.Append("FAILED", _colorScheme.Error)); } if (performance.Length > 0) { _console.WriteLine(performance); } if (testOutput.Length > 0) { _console.WriteLine(testOutput); } if (historicalAnalysis.Length > 0) { _console.WriteLine(historicalAnalysis); } if (passFailByRun.Length > 0) { _console.WriteLine(passFailByRun); } if (passFail.Length > 0) { _console.WriteLine(passFail); } if (_allowFileOperations) { EnsurePathIsCreated(_configuration.LogPath); if (_configuration.EnableReportLog) { var builder = new StringBuilder(); builder.AppendLine(overview.ToString()); builder.AppendLine(performance.ToString()); builder.AppendLine(testOutput.ToString()); builder.AppendLine(historicalAnalysis.ToString()); builder.AppendLine(passFailByRun); builder.AppendLine(passFail); var reportFilename = Path.GetFullPath(Path.Combine(_configuration.LogPath, $"{uniqueRunIds.FirstOrDefault()}-report.log")); File.WriteAllText(reportFilename, builder.ToString()); _console.Write(ColorTextBuilder.Create.AppendLine($"Wrote summary report to {reportFilename}", _colorScheme.DarkDefault)); } if (_configuration.EnableTestLog) { // write out test logs for each run foreach (var run in _runContext.Runs) { var builder = new StringBuilder(); builder.AppendLine($"FullName,Duration,TestStatus,StartTime,EndTime,RuntimeVersion"); foreach (var test in run.Value.SelectMany(x => x.Report.TestReports).Where(x => x.TestStatus != TestStatus.Skipped).OrderBy(x => x.StartTime)) { // encode quotes in the test name with double quotes var testName = test.FullName.Replace("\"", "\"\""); builder.AppendLine($"\"{testName}\",\"{test.Duration.TotalMilliseconds:N2}ms\",\"{test.TestStatus}\",\"{test.StartTime.ToString(Constants.TimeFormat)}\",\"{test.EndTime.ToString(Constants.TimeFormat)}\",\"{test.RuntimeVersion}\""); } var reportFilename = Path.GetFullPath(Path.Combine(_configuration.LogPath, $"{run.Key.CommanderRunId}-tests.log")); File.WriteAllText(reportFilename, builder.ToString()); _console.Write(ColorTextBuilder.Create.AppendLine($"Wrote tests report to {reportFilename}", _colorScheme.DarkDefault)); } } } return(overallTestStatus); }
public override ColorTextBuilder Write(object parameters = null) { var allReports = (IEnumerable <DataEvent>)parameters; var builder = new ColorTextBuilder(); var totalDuration = _runContext.Elapsed; var isPassed = allReports.Sum(x => x.Failed) == 0; if (_configuration.GenerateReportType.HasFlag(GenerateReportType.PassFail)) { var statusColor = _colorScheme.Error; var successColor = _colorScheme.Default; var failuresColor = _colorScheme.Default; var errorsColor = _colorScheme.Default; var warningsColor = _colorScheme.Default; var allSuccess = allReports.Sum(x => x.Failed) == 0; var anyFailure = allReports.Sum(x => x.Failed) > 0; var testCount = allReports.Sum(x => x.TestCount); var passed = allReports.Sum(x => x.Passed); var failed = allReports.Sum(x => x.Failed); var warnings = allReports.Sum(x => x.Warnings); var asserts = allReports.Sum(x => x.Asserts); var inconclusive = allReports.Sum(x => x.Inconclusive); var errors = allReports.SelectMany(x => x.Report.TestReports.Where(t => t.TestStatus == TestStatus.Fail && !string.IsNullOrEmpty(t.ErrorMessage))).Count(); var skipped = allReports.Sum(x => x.Skipped); var totalRuns = allReports.GroupBy(x => x.RunNumber).Count(); if (allSuccess) { successColor = _colorScheme.Success; statusColor = _colorScheme.Success; } if (failed > 0) { failuresColor = _colorScheme.Error; } if (errors > 0) { errorsColor = _colorScheme.DarkError; } if (warnings > 0) { warningsColor = _colorScheme.DarkHighlight; } WriteSquareBox(builder, "Test Run Summary"); builder.Append($" Overall result: ", _colorScheme.Default); builder.AppendLine(isPassed ? "Passed" : "Failed", statusColor); builder.Append($" Duration: ", _colorScheme.Default); builder.Append($"{testCount:N0} ", _colorScheme.Bright); builder.Append($"tests run in ", _colorScheme.Default); builder.AppendLine($"{totalDuration.ToTotalElapsedTime()}", _colorScheme.Duration); builder.AppendLine(""); builder.Append($" Test Runs: ", _colorScheme.Default); builder.AppendLine($"{totalRuns}", _colorScheme.Bright); builder.Append($" Test Count: ", _colorScheme.Default); builder.Append($"{testCount:N0}", _colorScheme.Bright); builder.Append($", Passed: ", _colorScheme.Default); builder.Append($"{passed:N0}", successColor); builder.Append($", Failed: ", _colorScheme.Default); builder.AppendLine($"{failed:N0}", failuresColor); builder.Append($" Errors: ", _colorScheme.DarkDefault); builder.Append($"{errors:N0}", errorsColor); builder.Append($", Warnings: ", _colorScheme.DarkDefault); builder.Append($"{warnings:N0}", warningsColor); builder.Append($", Ignored: ", _colorScheme.DarkDefault); builder.AppendLine($"{skipped}", _colorScheme.Default); builder.Append($" Asserts: ", _colorScheme.DarkDefault); builder.Append($"{asserts:N0}", _colorScheme.Default); builder.Append($", Inconclusive: ", _colorScheme.DarkDefault); builder.AppendLine($"{inconclusive:N0}", _colorScheme.Default); if (_runContext.Runs?.Any() == true) { builder.Append($" Peak Cpu: ", _colorScheme.DarkDefault); builder.Append($"{_runContext.Runs.Max(x => x.Key.Performance.PeakCpuUsed):N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{_runContext.Runs.Median(x => x.Key.Performance.MedianCpuUsed):N0}%", _colorScheme.Default); builder.Append($" Peak Memory: ", _colorScheme.DarkDefault); builder.Append($"{DisplayUtil.GetFriendlyBytes((long)_runContext.Runs.Max(x => x.Key.Performance.PeakMemoryUsed))}", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{DisplayUtil.GetFriendlyBytes((long)_runContext.Runs.Median(x => x.Key.Performance.MedianMemoryUsed))}", _colorScheme.Default); builder.Append($" Peak Disk Time: ", _colorScheme.DarkDefault); builder.Append($"{_runContext.Runs.Max(x => x.Key.Performance.PeakDiskTime):N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{_runContext.Runs.Median(x => x.Key.Performance.MedianDiskTime):N0}%", _colorScheme.Default); builder.Append($" Peak Test Concurrency: ", _colorScheme.DarkDefault); builder.Append($"{_runContext.Runs.Max(x => x.Key.Performance.PeakTestConcurrency):N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{_runContext.Runs.Max(x => x.Key.Performance.MedianTestConcurrency):N0}%", _colorScheme.Default); builder.Append($" Peak Test Fixture Concurrency: ", _colorScheme.DarkDefault); builder.Append($"{_runContext.Runs.Max(x => x.Key.Performance.PeakTestFixtureConcurrency):N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{_runContext.Runs.Max(x => x.Key.Performance.MedianTestFixtureConcurrency):N0}%", _colorScheme.Default); builder.Append($" Peak Assembly Concurrency: ", _colorScheme.DarkDefault); builder.Append($"{_runContext.Runs.Max(x => x.Key.Performance.PeakAssemblyConcurrency):N0}%", _colorScheme.Default); builder.Append($", Median: ", _colorScheme.DarkDefault); builder.AppendLine($"{_runContext.Runs.Max(x => x.Key.Performance.MedianAssemblyConcurrency):N0}%", _colorScheme.Default); } builder.AppendLine(Environment.NewLine); } return(builder); }
private static void WriteNode(ColorTextBuilder builder, string key, JToken value, int tabCount, ColorScheme colorScheme) { if (!string.IsNullOrEmpty(key)) { builder.Append(Repeat(TabValue, tabCount)); builder.Append(Quote(key) + ": ", colorScheme.DarkDefault); } var childrenCount = 0; var item = 0; switch (value.Type) { case JTokenType.Array: childrenCount = value.Count(); var isLargeArray = childrenCount > 2; if (isLargeArray) { builder.Append("[", colorScheme.DarkDefault); } else { builder.AppendLine("[", colorScheme.DarkDefault); } var isTightArray = false; foreach (var node in value) { item++; isTightArray = isLargeArray && node.Type != JTokenType.Object && node.Type != JTokenType.Array; if (isTightArray) { // print arrays without line breaks WriteNode(builder, string.Empty, node, (tabCount + 1), colorScheme); if (item < childrenCount) { builder.Append($", ", colorScheme.DarkDefault); } } else { if (item == 1) { builder.AppendLine(); } builder.Append(Repeat(TabValue, (tabCount + 1))); WriteNode(builder, string.Empty, node, (tabCount + 1), colorScheme); if (item < childrenCount) { builder.AppendLine($", ", colorScheme.DarkDefault); } else { builder.AppendLine(); } } } if (!isTightArray) { builder.Append(Repeat(TabValue, tabCount)); } builder.Append("]", colorScheme.DarkDefault); break; case JTokenType.Object: builder.AppendLine("{", colorScheme.DarkDefault); childrenCount = value.Count(); foreach (JProperty node in value) { item++; WriteNode(builder, node.Name, node.Value, (tabCount + 1), colorScheme); if (item < childrenCount) { builder.AppendLine($",", colorScheme.DarkDefault); } else { builder.AppendLine(); } } builder.Append(Repeat(TabValue, tabCount)); builder.Append("}", colorScheme.DarkDefault); break; default: WriteValue(builder, value.Value <string>(), value.Type, colorScheme); break; } }
public void Draw(ViewContext context, long ticks) { if (_startTicks == 0) { _startTicks = ticks; context.Console.Clear(); } if (!context.Console.IsOutputRedirected) { // if the user has scrolled the page don't perform any drawing if (Console.WindowTop > 0) { return; } Console.CursorVisible = false; _performFullDraw = (_startTicks - ticks) % DefaultTickWait == 0; var windowWidth = Console.WindowWidth; var windowHeight = Console.WindowHeight; if (windowHeight != _previousWindowHeight) { _performFullDraw = true; } _previousWindowHeight = windowHeight; if (_performFullDraw) { ClearScreen(context); } var lineSeparator = DisplayUtil.Pad(Console.WindowWidth - 1, UTF8Constants.HorizontalLine); var yPos = 0; WriteHeader(context); // figure out how many tests we can fit on screen var maxActiveTestsToDisplay = Console.WindowHeight - yPos - 2; var totalActive = context.ActiveTests.Count(x => !x.IsQueuedForRemoval); var totalPasses = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Pass); var totalFails = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Fail); var totalIgnored = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Skipped); var totalTestsProcessed = context.EventLog.Count(x => x.Event.Event == EventNames.EndTest); // write the summary of all test state context.Console.WriteAt(ColorTextBuilder.Create .Append("Tests state: ", context.ColorScheme.Bright) .Append($"Active=", context.ColorScheme.Default) .Append($"{totalActive} ", context.ColorScheme.Highlight) .Append($"Pass="******"{totalPasses} ", context.ColorScheme.Success) .AppendIf(totalPasses == 0, $"{totalPasses} ", context.ColorScheme.Default) .Append($"Fail=", context.ColorScheme.Default) .AppendIf(totalFails > 0, $"{totalFails} ", context.ColorScheme.DarkError) .AppendIf(totalFails == 0, $"{totalFails} ", context.ColorScheme.Default) .AppendIf(!context.Console.IsOutputRedirected, $"Ignored=", context.ColorScheme.Default) .AppendIf(!context.Console.IsOutputRedirected, $"{totalIgnored} ", context.ColorScheme.DarkDefault) .Append($"Total=", context.ColorScheme.Default) .Append($"{totalTestsProcessed} ", context.ColorScheme.DarkDefault) .AppendIf(context.TotalTestsQueued > 0, $"of ", context.ColorScheme.Default) .AppendIf(context.TotalTestsQueued > 0, $"{context.TotalTestsQueued} ", context.ColorScheme.DarkDefault) .AppendIf(context.TotalTestsQueued > 0, $"{UTF8Constants.LeftBracket}", context.ColorScheme.Bright) .AppendIf(context.TotalTestsQueued > 0, $"{((totalTestsProcessed / (double)context.TotalTestsQueued) * 100.0):F0}%", context.ColorScheme.DarkDuration) .AppendIf(context.TotalTestsQueued > 0, $"{UTF8Constants.RightBracket}", context.ColorScheme.Bright) //.Append(context.Client.IsWaitingForConnection ? $"{UTF8Constants.LeftBracket}waiting{UTF8Constants.RightBracket}" : "", context.ColorScheme.DarkDuration) .AppendIf(!context.Console.IsOutputRedirected, (length) => DisplayUtil.Pad(windowWidth - length)), 0, yPos + 1, DirectOutputMode.Static); var failedTests = context.EventLog .Where(x => x.Event.Event == EventNames.EndTest && x.Event.TestStatus == TestStatus.Fail) .GroupBy(x => x.Event.TestName) .Select(x => x.FirstOrDefault()) .OrderByDescending(x => x.DateAdded) .Take(context.Configuration.MaxFailedTestsToDisplay); context.Console.WriteAt(ColorTextBuilder.Create.AppendLine($"Failed Tests Report", context.ColorScheme.Error), 0, yPos + 2, DirectOutputMode.Static); if (!failedTests.Any()) { context.Console.WriteAt(ColorTextBuilder.Create.AppendLine($"There are no failed tests.", context.ColorScheme.Default), 0, yPos + 4, DirectOutputMode.Static); } else { // don't display this as often as its expensive to write if (_performFullDraw) { context.Console.SetCursorPosition(0, yPos + 5); foreach (var test in failedTests) { var testOutput = new ColorTextBuilder(); var errorTime = test.DateAdded; var duration = DateTime.Now.Subtract(test.Event.StartTime); if (test.Event.EndTime != DateTime.MinValue) { duration = test.Event.Duration; } var prettyTestName = DisplayUtil.GetPrettyTestName(test.Event.FullName, context.ColorScheme.DarkDefault, context.ColorScheme.Default, context.ColorScheme.DarkDefault, context.MaxTestCaseArgumentLength); // print out this test name and duration testOutput.Append(ColorTextBuilder.Create .Append($" {UTF8Constants.Bullet} ") .Append(prettyTestName) .Append($" {duration.ToTotalElapsedTime()}", context.ColorScheme.Duration) .Append($" {UTF8Constants.LeftBracket}", context.ColorScheme.Bright) .Append("FAILED", context.ColorScheme.Error) .Append($"{UTF8Constants.RightBracket}", context.ColorScheme.Bright) // clear out the rest of the line .AppendIf((length) => !context.Console.IsOutputRedirected && length < windowWidth, (length) => DisplayUtil.Pad(windowWidth - length)) .Truncate(windowWidth)); testOutput.Append(ColorTextBuilder.Create.Append(" Failed at: ", context.ColorScheme.Default).AppendLine($"{errorTime.ToString(Constants.TimeFormat)}", context.ColorScheme.DarkDuration)); // print out errors if (!string.IsNullOrEmpty(test.Event.ErrorMessage)) { testOutput.AppendLine($" Error Output: ", context.ColorScheme.Bright); testOutput.AppendLine(lineSeparator, context.ColorScheme.DarkDefault); if (!context.Configuration.DontPrettify) { testOutput.Append(ErrorEncoding.Format(test.Event.ErrorMessage, context.ColorScheme)); } else { testOutput.Append(test.Event.ErrorMessage); } testOutput.AppendLine(); testOutput.AppendLine(lineSeparator, context.ColorScheme.DarkDefault); } if (!string.IsNullOrEmpty(test.Event.StackTrace)) { testOutput.AppendLine($" Stack Trace:", context.ColorScheme.Bright); testOutput.AppendLine(lineSeparator, context.ColorScheme.DarkDefault); if (!context.Configuration.DontPrettify) { testOutput.Append(StackTracePrettify.Format(test.Event.StackTrace, context.ColorScheme)); } else { testOutput.Append(test.Event.StackTrace); } testOutput.AppendLine(); testOutput.AppendLine(lineSeparator, context.ColorScheme.DarkDefault); } if (!string.IsNullOrEmpty(test.Event.TestOutput)) { testOutput.AppendLine($" Test Output: ", context.ColorScheme.Bright); testOutput.AppendLine(lineSeparator, context.ColorScheme.DarkDefault); if (!context.Configuration.DontPrettify) { testOutput.Append(ErrorEncoding.Format(test.Event.TestOutput, context.ColorScheme)); } else { testOutput.Append(test.Event.TestOutput); } testOutput.AppendLine(); testOutput.AppendLine(lineSeparator, context.ColorScheme.DarkDefault); } testOutput.AppendLine(); testOutput.AppendLine(); context.Console.WriteLine(testOutput); } context.Console.SetCursorPosition(0, 0); } } } }