/// <summary> /// Called when a test result is received. /// </summary> private void TestResultHandler(object sender, TestResultEventArgs e) { if (e.Result.Outcome == TestOutcome.NotFound) { return; } DataType.TestCaseDetail caseDetail = ConvertToTestCase(e.Result); results.TryAdd(caseDetail.Name, caseDetail); // Generate txt log file string txtFileName = Path.Combine( txtResultFolderPath, string.Format("{0}_{1}_{2}.txt", caseDetail.StartTime.ToLocalTime().ToString("yyyy-MM-dd-HH-mm-ss"), caseDetail.Result, caseDetail.Name) ); File.WriteAllText(txtFileName, ConstructCaseTxtReport(caseDetail)); // Generate html log file string htmlFileName = Path.Combine(htmlResultFolderPath, $"{caseDetail.Name}.html"); File.WriteAllText(htmlFileName, ConstructCaseHtml(caseDetail)); }
/// <summary> /// Constructs details of test case. /// 1. Gets log from the test case detail /// 2. Copies capture to the log folder, and saves the path. /// </summary> /// <param name="caseDetail">The informatoin of each test case which contains the detail log</param> /// <param name="captureFolder">Capture folder path</param> /// <returns>return the log information in Json format</returns> public string ConstructCaseDetail(DataType.TestCaseDetail caseDetail, string captureFolder) { caseDetail.CapturePath = CopyCaptureAndReturnPath(caseDetail.FullyQualifiedName, captureFolder); var caseDetailForJson = new DataType.TestCaseDetailForJson(); caseDetailForJson.Update(caseDetail); return(Serialize(caseDetailForJson)); }
/// <summary> /// Inserts the corresponding script to the template html and generates the [testcase].html /// </summary> private string ConstructCaseHtml(DataType.TestCaseDetail caseDetail) { // Insert script to the template html (testcase.html) StringBuilder sb = new StringBuilder(); sb.Append(ConstructDetailObj(caseDetail)); sb.AppendLine("var titleObj = document.getElementById(\"right_sidebar_case_title\");"); sb.Append(string.Format("CreateText(titleObj, \"{0}\");", caseDetail.Name)); return(InsertScriptToTemplate(Properties.Resources.testcase, sb.ToString())); }
/// <summary> /// Constructs detailObj used in each [caseName].html /// </summary> private string ConstructDetailObj(DataType.TestCaseDetail caseDetail) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.Append("var detailObj="); sb.Append(txtToJSON.ConstructCaseDetail(caseDetail, captureFolderPath)); sb.AppendLine(";"); return(sb.ToString()); }
/// <summary> /// Called when a test result is received. /// </summary> private void TestResultHandler(object sender, TestResultEventArgs e) { if (e.Result.Outcome == TestOutcome.NotFound) { return; } DataType.TestCaseDetail caseDetail = ConvertToTestCase(e.Result); results.TryAdd(caseDetail.FullyQualifiedName, caseDetail); // Generate html log file string htmlFileName = Path.Combine(htmlResultFolderPath, $"{caseDetail.FullyQualifiedName}.html"); File.WriteAllText(htmlFileName, ConstructCaseHtml(caseDetail)); }
/// <summary> /// Inserts the corresponding script to the template html and generates the [testcase].html /// </summary> private string ConstructCaseTxtReport(DataType.TestCaseDetail caseDetail) { StringBuilder sb = new StringBuilder(); if (DateTimeOffset.Compare(testRunStartTime, caseDetail.StartTime.ToLocalTime()) > 0) { testRunStartTime = caseDetail.StartTime.ToLocalTime(); } if (DateTimeOffset.Compare(testRunEndTime, caseDetail.EndTime.ToLocalTime()) < 0) { testRunEndTime = caseDetail.EndTime.ToLocalTime(); } sb.AppendLine(caseDetail.Name); sb.AppendLine("Start Time: " + caseDetail.StartTime.ToLocalTime().ToString("MM/dd/yyyy HH:mm:ss")); sb.AppendLine("End Time: " + caseDetail.EndTime.ToLocalTime().ToString("MM/dd/yyyy HH:mm:ss")); sb.AppendLine("Result: " + caseDetail.Result); sb.AppendLine(caseDetail.Source); if (caseDetail.ErrorStackTrace.Count() > 0) { sb.AppendLine("===========ErrorStackTrace==========="); caseDetail.ErrorStackTrace.ForEach(line => sb.AppendLine(line)); } if (caseDetail.ErrorMessage.Count() > 0) { sb.AppendLine("===========ErrorMessage=============="); caseDetail.ErrorMessage.ForEach(line => sb.AppendLine(line)); } if (caseDetail.StandardOut.Count() > 0) { sb.AppendLine("===========StandardOut==============="); caseDetail.StandardOut.ForEach(stdout => sb.AppendLine(stdout.Content)); } return(sb.ToString()); }
/// <summary> /// Constructs details of test case. /// 1. Gets log from the txt file /// 2. Copies capture to the log folder, and saves the path. /// </summary> /// <param name="txtfile">The path to the log txt file which contains the detail log</param> /// <returns>Returns the log information</returns> public string ConstructCaseDetail(DataType.TestCaseDetail caseDetail, string captureFolder) { caseDetail.CapturePath = CopyCaptureAndReturnPath(caseDetail.Name, captureFolder); return(serializer.Serialize(caseDetail)); }
/// <summary> /// Constructs details of test case. /// 1. Gets log from the txt file /// 2. Copies capture to the log folder, and saves the path. /// </summary> /// <param name="txtfile">The path to the log txt file which contains the detail log</param> /// <returns>Returns the log information</returns> public string ConstructCaseDetail(string txtfile, string captureFolder) { FileStream fs = new FileStream(txtfile, FileMode.Open); string type = ""; // Help judge whether the line is the end of the file, help distinguish file content StreamReader sr = new StreamReader(fs); string line; string content = ""; string standardOutType = ""; DataType.TestCaseDetail caseDetail = new DataType.TestCaseDetail(sr.ReadLine(), sr.ReadLine(), sr.ReadLine(), sr.ReadLine()); DataType.StandardOutDetail stdDetail; string dllFile = sr.ReadLine(); if (!dllFiles.Contains(dllFile)) { dllFiles.Add(dllFile); } while ((line = sr.ReadLine()) != null) { if (line == "") //Rule out blank line continue; if (line.StartsWith("===========")) { type = line.Replace("=", ""); continue; } LogType eType = (LogType)Enum.Parse(typeof(LogType), type); switch (eType) { case LogType.ErrorStackTrace: caseDetail.ErrorStackTrace.Add(line); break; case LogType.ErrorMessage: caseDetail.ErrorMessage.Add(line); break; case LogType.StandardOut: int begin = line.IndexOf('['); int end = line.IndexOf(']'); if (begin != -1 && end != -1) { if (standardOutType != "") { stdDetail = new DataType.StandardOutDetail() { Content = content, Type = standardOutType }; caseDetail.StandardOut.Add(stdDetail); } if (end > begin && end < line.Length) { standardOutType = line.Substring(begin + 1, end - begin - 1); if (!caseDetail.StandardOutTypes.Contains(standardOutType)) caseDetail.StandardOutTypes.Add(standardOutType); } content = line; } else content += line; break; default: break; } } stdDetail = new DataType.StandardOutDetail() { Content = content, Type = standardOutType }; fs.Close(); caseDetail.StandardOut.Add(stdDetail); caseDetail.CapturePath = CopyCaptureAndReturnPath(caseDetail.Name, captureFolder); return (serializer.Serialize(caseDetail)); }
/// <summary> /// Constructs details of test case. /// 1. Gets log from the txt file /// 2. Copies capture to the log folder, and saves the path. /// </summary> /// <param name="txtfile">The path to the log txt file which contains the detail log</param> /// <returns>Returns the log information</returns> public string ConstructCaseDetail(string txtfile, string captureFolder) { FileStream fs = new FileStream(txtfile, FileMode.Open); string type = ""; // Help judge whether the line is the end of the file, help distinguish file content StreamReader sr = new StreamReader(fs); string line; string content = ""; string standardOutType = ""; DataType.TestCaseDetail caseDetail = new DataType.TestCaseDetail(sr.ReadLine(), sr.ReadLine(), sr.ReadLine(), sr.ReadLine()); DataType.StandardOutDetail stdDetail; string dllFile = sr.ReadLine(); if (!dllFiles.Contains(dllFile)) { dllFiles.Add(dllFile); } while ((line = sr.ReadLine()) != null) { if (line == "") //Rule out blank line { continue; } if (line.StartsWith("===========")) { type = line.Replace("=", ""); continue; } LogType eType = (LogType)Enum.Parse(typeof(LogType), type); switch (eType) { case LogType.ErrorStackTrace: caseDetail.ErrorStackTrace.Add(line); break; case LogType.ErrorMessage: caseDetail.ErrorMessage.Add(line); break; case LogType.StandardOut: int begin = line.IndexOf('['); int end = line.IndexOf(']'); if (begin != -1 && end != -1) { if (standardOutType != "") { stdDetail = new DataType.StandardOutDetail() { Content = content, Type = standardOutType }; caseDetail.StandardOut.Add(stdDetail); } if (end > begin && end < line.Length) { standardOutType = line.Substring(begin + 1, end - begin - 1); if (!caseDetail.StandardOutTypes.Contains(standardOutType)) { caseDetail.StandardOutTypes.Add(standardOutType); } } content = line; } else { content += line; } break; default: break; } } stdDetail = new DataType.StandardOutDetail() { Content = content, Type = standardOutType }; fs.Close(); caseDetail.StandardOut.Add(stdDetail); caseDetail.CapturePath = CopyCaptureAndReturnPath(caseDetail.Name, captureFolder); return(serializer.Serialize(caseDetail)); }
/// <summary> /// Constructs details of test case. /// 1. Gets log from the txt file /// 2. Copies capture to the log folder, and saves the path. /// </summary> /// <param name="txtfile">The path to the log txt file which contains the detail log</param> /// <returns>Returns the log information</returns> public string ConstructCaseDetail(DataType.TestCaseDetail caseDetail, string captureFolder) { caseDetail.CapturePath = CopyCaptureAndReturnPath(caseDetail.Name, captureFolder); return(specificDateTimeOffsetSerializer(caseDetail)); }
/// <summary> /// Convert a vstest TestResult object to TestCaseDetail /// </summary> private DataType.TestCaseDetail ConvertToTestCase(TestResult result) { var eolSeparators = new char[] { '\r', '\n' }; string caseName = !string.IsNullOrEmpty(result.TestCase.DisplayName) ? result.TestCase.DisplayName : result.TestCase.FullyQualifiedName.Split('.').Last(); string outcome = result.Outcome == TestOutcome.Skipped ? "Inconclusive" : result.Outcome.ToString(); string classType = result.TestCase.FullyQualifiedName.Split('.').Reverse().ElementAtOrDefault(1); List <string> testCategories = GetCustomPropertyValueFromTestCase(result.TestCase, categoryPropertyKey); var ret = new DataType.TestCaseDetail(caseName, result.TestCase.FullyQualifiedName, result.StartTime, result.EndTime, outcome, result.TestCase.Source, classType, testCategories); if (!String.IsNullOrEmpty(result.ErrorStackTrace)) { ret.ErrorStackTrace.AddRange(result.ErrorStackTrace.Split(eolSeparators, StringSplitOptions.RemoveEmptyEntries)); } if (!String.IsNullOrEmpty(result.ErrorMessage)) { ret.ErrorMessage.AddRange(result.ErrorMessage.Split(eolSeparators, StringSplitOptions.RemoveEmptyEntries)); } var stdout = new List <string>(); foreach (TestResultMessage m in result.Messages) { if (m.Category == TestResultMessage.StandardOutCategory && !String.IsNullOrEmpty(m.Text)) { stdout.AddRange(m.Text.Split(eolSeparators, StringSplitOptions.RemoveEmptyEntries)); } } foreach (string line in stdout) { string pattern = @"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} \[(\w+)\] "; Regex r = new Regex(pattern, RegexOptions.IgnoreCase); Match m = r.Match(line); if (m.Success) { string type = m.Groups[1].Value; ret.StandardOut.Add(new DataType.StandardOutDetail() { Content = line, Type = type }); } else { // There must be at least one record in the list. // Just to make the logger robust, let's do a check here. // (But it won't happen) int stdoutCount = ret.StandardOut.Count; if (stdoutCount == 0) { continue; } else { var lastOutput = ret.StandardOut[stdoutCount - 1]; lastOutput.Content = lastOutput.Content + '\n' + line; } } } ret.StandardOutTypes = ret.StandardOut.Select(output => output.Type).Distinct().ToList(); return(ret); }