Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
        /// <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);
        }
Example #5
0
        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);
        }
Example #6
0
        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;
            }
        }
Example #7
0
        public void ColorTextBuilder_ColorTextBuilder_ShouldInterlaceInColumnsAndTruncate()
        {
            var builder  = new ColorTextBuilder();
            var builder2 = new ColorTextBuilder();

            builder.AppendLine("Left side:1 with a really long string that is too wide to fit in a single column");
            builder.AppendLine("Left side:2");
            builder2.AppendLine("Right side:1");
            builder2.AppendLine("Right side:2 is really too long as well");

            var interlaced = builder.Interlace(builder2, 2, 15);
            var str        = interlaced.ToString();

            Assert.AreEqual($"Left side:1 wit  Right side:1{Environment.NewLine}Left side:2      Right side:2 is{Environment.NewLine}", str);
        }
        public override ColorTextBuilder Write(object parameters = null)
        {
            var builder = new ColorTextBuilder();

            if (_configuration.GenerateReportType.HasFlag(GenerateReportType.TestAnalysis))
            {
                WriteRoundBox(builder, "Historical Analysis Report");
                // write the analysis report
                if (_runContext.HistoryReport != null)
                {
                    builder.AppendLine(_runContext.HistoryReport.BuildReport());
                }
            }
            return(builder);
        }
Example #9
0
        public void ColorTextBuilder_ColorTextBuilder_ShouldInterlace()
        {
            var builder  = new ColorTextBuilder();
            var builder2 = new ColorTextBuilder();

            builder.AppendLine("Left side:1");
            builder.AppendLine("Left side:2");
            builder2.AppendLine("Right side:1");
            builder2.AppendLine("Right side:2");

            var interlaced = builder.Interlace(builder2);
            var str        = interlaced.ToString();

            Assert.AreEqual($"Left side:1Right side:1{Environment.NewLine}Left side:2Right side:2{Environment.NewLine}", str);
        }
Example #10
0
        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);
        }
Example #11
0
        public void ColorTextBuilder_ColorTextBuilder_ShouldInterlaceInColumns()
        {
            var builder  = new ColorTextBuilder();
            var builder2 = new ColorTextBuilder();

            builder.AppendLine("Left");
            builder.AppendLine("Left side:2");
            builder2.AppendLine("Right");
            builder2.AppendLine("Right side:2");

            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}", str);
        }
Example #12
0
 private ColorTextBuilder StackGraph(ColorTextBuilder existingChart, ColorTextBuilder newChart, int chartSpacing, out bool isNewRow)
 {
     isNewRow = false;
     if (newChart.Length > 0)
     {
         if (!_console.IsOutputRedirected && _console.WindowWidth > existingChart.Width + newChart.Width + chartSpacing)
         {
             existingChart = existingChart.Interlace(newChart, chartSpacing);
         }
         else
         {
             isNewRow = true;
         }
     }
     return(existingChart);
 }
Example #13
0
        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 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);
        }
Example #15
0
        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);
        }
Example #16
0
        /// <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));
            }
        }
        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;
        }
Example #18
0
        /// <summary>
        /// Format a json string
        /// </summary>
        /// <param name="text"></param>
        /// <param name="colorScheme"></param>
        /// <returns></returns>
        public static ColorTextBuilder Format(string text, ColorScheme colorScheme)
        {
            var builder = new ColorTextBuilder();

            try
            {
                // find the json in a response
                var startIndex = text.IndexOf("{");
                var endIndex   = text.LastIndexOf("}");
                // make sure braces are all present to validate the json
                var braceCount = text.Count(c => c == '{') + text.Count(c => c == '}');
                var json       = string.Empty;
                if (startIndex >= 0 && endIndex > 0 && braceCount % 2 == 0)
                {
                    json = text.Substring(startIndex, (endIndex + 1) - startIndex);
                    // fix badly encoded strings
                    json = json.Replace(@"\\r\\n", @"\r\n");
                    json = json.Replace(@"\\\\", @"\\");
                }

                // append any text before the json content
                if (startIndex > 0)
                {
                    builder.AppendLine(text.Substring(0, startIndex), colorScheme.Default);
                }

                if (!string.IsNullOrEmpty(json))
                {
                    var parsed = JObject.Parse(json, new JsonLoadSettings {
                        CommentHandling = CommentHandling.Load,
                        DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Ignore,
                        LineInfoHandling = LineInfoHandling.Load
                    });
                    var childrenCount = parsed.Count;
                    var item          = 0;
                    builder.AppendLine("{", colorScheme.DarkDefault);
                    foreach (JProperty node in parsed.Children())
                    {
                        item++;
                        WriteNode(builder, node.Name, node.Value, 1, colorScheme);
                        if (item < childrenCount)
                        {
                            builder.AppendLine($",");
                        }
                        else
                        {
                            builder.AppendLine();
                        }
                    }
                    builder.AppendLine("}", colorScheme.DarkDefault);
                }
                else
                {
                    // json not found, output the full original text
                    builder.AppendLine(text, colorScheme.Default);
                }

                // append any text after the json content
                if (endIndex < text.Length)
                {
                    builder.AppendLine(text.Substring(endIndex + 1, text.Length - (endIndex + 1)), 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 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 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);
                }
            }
        }
Example #22
0
        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);
        }
Example #23
0
 internal void WriteRoundBox(ColorTextBuilder builder, string str, int leftPadding = 0, Color?color = null)
 {
     builder.AppendLine($"{UTF8Constants.RoundBoxTopLeft}{DisplayUtil.Pad(str.Length + 4, UTF8Constants.RoundBoxHorizontal)}{UTF8Constants.RoundBoxTopRight}{DisplayUtil.Pad(leftPadding)}", color ?? _colorScheme.Highlight);
     builder.AppendLine($"{UTF8Constants.RoundBoxVertical}  {str}  {UTF8Constants.RoundBoxVertical}{DisplayUtil.Pad(leftPadding)}", color ?? _colorScheme.Highlight);
     builder.AppendLine($"{UTF8Constants.RoundBoxBottomLeft}{DisplayUtil.Pad(str.Length + 4, UTF8Constants.RoundBoxHorizontal)}{UTF8Constants.RoundBoxBottomRight}{DisplayUtil.Pad(leftPadding)}", color ?? _colorScheme.Highlight);
 }
        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));
            }
        }
Example #25
0
        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;
            }
        }
Example #26
0
        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);
                    }
                }
            }
        }