/// <summary> /// Get a pre-formatted html string which contains PTF conf and test result stats from specified log file. /// </summary> /// <param name="filename">file name of log file</param> /// <param name="logAnalyzer">Test log file analyzer</param> /// <returns>a pre-formatted html contains PTF conf and test result stats.</returns> private string GetLogStatsHTML(string filename, XmlLogAnalyzer logAnalyzer) { StringBuilder logOutput = new StringBuilder(Resource.LogTable); StringBuilder protocols = new StringBuilder(); uint verifiedRequirements = 0; foreach (string protocol in logAnalyzer.Protocols) { protocols.Append(protocol + ';'); } logOutput.Replace(@"$PROTOCOL$", HttpUtility.HtmlEncode(protocols.ToString())); logOutput.Replace(@"$FILENAME$", HttpUtility.HtmlEncode(Path.GetFileName(filename))); // get all PTF confs from log file StringBuilder config = new StringBuilder(); foreach (KeyValuePair<string, string> ptfconf in logAnalyzer.PTFConfigurations) { config.Append(@" <tr> <td> " + HttpUtility.HtmlEncode(ptfconf.Key) + @"</td> <td> " + HttpUtility.HtmlEncode(ptfconf.Value) + @"</td> </tr>"); } logOutput.Replace(@"$CONFIG$", config.ToString()); // start output test result from log file StringBuilder testresult = new StringBuilder(); uint total = 0; if (logAnalyzer.TestResult.ContainsKey("TestsExecuted")) { total = uint.Parse(logAnalyzer.TestResult["TestsExecuted"]); } foreach (KeyValuePair<string, string> result in logAnalyzer.TestResult) { if (result.Key == "TimeStamp") { testresult.Append(@" <tr> <td> " + HttpUtility.HtmlEncode(result.Key) + @"</td> <td> " + HttpUtility.HtmlEncode(result.Value) + @"</td> </tr>"); continue; } uint actual = uint.Parse(result.Value); float percent = (total == 0) ? 0 : actual / (float)total; testresult.Append(@" <tr> <td> " + HttpUtility.HtmlEncode(result.Key) + @"</td> <td> " + actual + " (" + percent.ToString("P") + @")</td> </tr>"); } logOutput.Replace(@"$TESTRESULT$", testresult.ToString()); foreach (KeyValuePair<string, string> kvp in logAnalyzer.CoveredRequirements) { string req_id = tableAnalyzer.GetRequirementId(kvp.Key, false); //the requirement id in log file should always the full req id. if (!string.IsNullOrEmpty(req_id)) { if (tableAnalyzer.RequirementsToVerify.ContainsKey(req_id)) { verifiedRequirements++; } else if (tableAnalyzer.RequirementsNotToVerify.ContainsKey(req_id)) { LogTraceWarning("The test log file covers an unverifiable requirement : " + kvp.Key); } else { LogTraceWarning("The test log file covers a deleted requirement : " + kvp.Key); } } else { LogTraceWarning("The test log file covers a non-existed requirement :" + kvp.Key); } } logOutput.Replace(@"$Verified$", verifiedRequirements.ToString("D")); return logOutput.ToString(); }
/// <summary> /// Generate a html result page from given information in <c ref="param"></c> /// </summary> private void Generate() { string tempFile = string.Empty; try { Dictionary<string, List<string>> globalVerifiedRequirements = new Dictionary<string, List<string>>(); Dictionary<string, string> globleVerifiedRequirementsTimestamp = new Dictionary<string, string>(); Dictionary<string, string> inconsistencyErrors = new Dictionary<string, string>(); StringBuilder sb = new StringBuilder(); Dictionary<string, ExclRequirementInfo> globalExcludedRequirements = new Dictionary<string, ExclRequirementInfo>(); // write html header sb.Append(Resource.HtmlTemplateHeader); foreach (string filename in param.XmlLogs) { // get xml log analyzer XmlLogAnalyzer logAnalyzer = new XmlLogAnalyzer(filename); // get failed test cases and exclued requirements foreach (KeyValuePair<string, string> kvp in logAnalyzer.ExcludedRequirements) { //the requirement covered in one passed case, it will never be excluded. if (!logAnalyzer.CoveredRequirements.ContainsKey(kvp.Key) && !globalExcludedRequirements.ContainsKey(kvp.Key)) { //add test case which the req belong to //add the test case result //add the timestamp //add the log file name which contain the req globalExcludedRequirements[kvp.Key] = new ExclRequirementInfo(kvp.Value, logAnalyzer.AllTestCases[kvp.Value], logAnalyzer.ExcludedRequirementsTimestamp[kvp.Key], filename); } } foreach (KeyValuePair<string, string> kvp in logAnalyzer.CoveredRequirements) { string rsId = tableAnalyzer.GetRequirementId(kvp.Key, false); if (!string.IsNullOrEmpty(rsId)) { //the logged ID should be 1-1 mapping to the Req_ID if (tableAnalyzer.RequirementsToVerify.ContainsKey(rsId)) { //unverified requirements were captured. if (string.Compare(tableAnalyzer.RequirementVerifications[rsId], VerificationValues.UNVERIFIED, true) == 0) { if (!inconsistencyErrors.ContainsKey(rsId)) inconsistencyErrors.Add(rsId, tableAnalyzer.RequirementVerifications[rsId]); continue; } if (!globalVerifiedRequirements.ContainsKey(rsId)) { globalVerifiedRequirements[rsId] = new List<string>(); globalVerifiedRequirements[rsId].Add(filename); if (!globleVerifiedRequirementsTimestamp.ContainsKey(rsId)) { globleVerifiedRequirementsTimestamp[rsId] = kvp.Value; } } else { if (!globalVerifiedRequirements[rsId].Contains(filename)) globalVerifiedRequirements[rsId].Add(filename); else continue; } } else { //non-testable, deleted, non-exist requirements were captured. if (string.Compare(tableAnalyzer.RequirementVerifications[rsId], VerificationValues.ADAPTER, true) != 0 && string.Compare(tableAnalyzer.RequirementVerifications[rsId], VerificationValues.TESTCASE, true) != 0) { if (!inconsistencyErrors.ContainsKey(rsId)) inconsistencyErrors.Add(rsId, tableAnalyzer.RequirementVerifications[rsId]); } } } else { if (!inconsistencyErrors.ContainsKey(kvp.Key)) { inconsistencyErrors.Add(kvp.Key, VerificationValues.NONEXIST); } } } // write whole table of ptfconf/test result from log to html string logOutput = GetLogStatsHTML(filename, logAnalyzer); sb.Append(logOutput); // output a line break to make source clear sb.Append("\r\n"); // write a horizontal line to separate results from different logs sb.Append("<hr />"); } // write html footer sb.Append(Resource.HtmlTemplateFooter); sb.Replace("$GLOBALSTAT$", GetGlobalStat(globalVerifiedRequirements, globleVerifiedRequirementsTimestamp)); if (verboseMode && globalExcludedRequirements.Count > 0) { sb.Replace("$EXCLUDEDREQUIREMENTS$", GetExcludedRequirements(globalExcludedRequirements, inconsistencyErrors)); } else { sb.Replace("$EXCLUDEDREQUIREMENTS$", string.Empty); } sb.Replace("$GLOBALRSINCONSISTENCY$", GetGlobalRSInconsistenies( tableAnalyzer.RSValicationErrors, tableAnalyzer.RSValidationWarnings)); sb.Replace("$GLOBALINCONSISTENCY$", GetGlobalInconsistencise(globalVerifiedRequirements, inconsistencyErrors)); tempFile = Path.GetTempFileName(); using (StreamWriter sw = new StreamWriter(tempFile, false, Encoding.UTF8)) { sw.Write(sb.ToString()); } string outputDirectory = Path.GetDirectoryName(Path.GetFullPath(param.OutputFile)); if (!Directory.Exists(outputDirectory)) { throw new InvalidOperationException( string.Format("Test report output directory does not exist: {0}", outputDirectory) ); } // move temp file to output file. File.Delete(param.OutputFile); File.Move(tempFile, param.OutputFile); Console.WriteLine("[NOTICE] Report file generated: \r\n" + " " + param.OutputFile); if (verboseMode) { string fileName = "ReqCoveredStatus.xml"; string outputDir = Path.GetDirectoryName(param.OutputFile); string outputPath = Path.Combine(outputDir, fileName); DumpReqsCaptureStatus(globalVerifiedRequirements, inconsistencyErrors, outputPath); Console.WriteLine("[NOTICE] Requirement coverage report generated: \r\n" + " " + outputPath); } } catch (Exception) { throw; } finally { // delete temporary file if (!String.IsNullOrEmpty(tempFile) && File.Exists(tempFile)) { File.Delete(tempFile); } } }