htmlgen.nim 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #
  2. #
  3. # Nim Tester
  4. # (c) Copyright 2017 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## HTML generator for the tester.
  10. import cgi, backend, strutils, json, os, tables, times
  11. import "testamenthtml.templ"
  12. proc generateTestResultPanelPartial(outfile: File, testResultRow: JsonNode) =
  13. let
  14. trId = htmlQuote(testResultRow["category"].str & "_" & testResultRow["name"].str).
  15. multiReplace({".": "_", " ": "_", ":": "_"})
  16. name = testResultRow["name"].str.htmlQuote()
  17. category = testResultRow["category"].str.htmlQuote()
  18. target = testResultRow["target"].str.htmlQuote()
  19. action = testResultRow["action"].str.htmlQuote()
  20. result = htmlQuote testResultRow["result"].str
  21. expected = testResultRow["expected"].getStr
  22. gotten = testResultRow["given"].getStr
  23. timestamp = "unknown"
  24. var
  25. panelCtxClass, textCtxClass, bgCtxClass: string
  26. resultSign, resultDescription: string
  27. case result
  28. of "reSuccess":
  29. panelCtxClass = "success"
  30. textCtxClass = "success"
  31. bgCtxClass = "success"
  32. resultSign = "ok"
  33. resultDescription = "PASS"
  34. of "reDisabled", "reJoined":
  35. panelCtxClass = "info"
  36. textCtxClass = "info"
  37. bgCtxClass = "info"
  38. resultSign = "question"
  39. resultDescription = if result != "reJoined": "SKIP" else: "JOINED"
  40. else:
  41. panelCtxClass = "danger"
  42. textCtxClass = "danger"
  43. bgCtxClass = "danger"
  44. resultSign = "exclamation"
  45. resultDescription = "FAIL"
  46. outfile.generateHtmlTestresultPanelBegin(
  47. trId, name, target, category, action, resultDescription,
  48. timestamp, result, resultSign, panelCtxClass, textCtxClass, bgCtxClass
  49. )
  50. if expected.isNilOrWhitespace() and gotten.isNilOrWhitespace():
  51. outfile.generateHtmlTestresultOutputNone()
  52. else:
  53. outfile.generateHtmlTestresultOutputDetails(
  54. expected.strip().htmlQuote,
  55. gotten.strip().htmlQuote
  56. )
  57. outfile.generateHtmlTestresultPanelEnd()
  58. type
  59. AllTests = object
  60. data: JSonNode
  61. totalCount, successCount, ignoredCount, failedCount: int
  62. successPercentage, ignoredPercentage, failedPercentage: BiggestFloat
  63. proc allTestResults(onlyFailing = false): AllTests =
  64. result.data = newJArray()
  65. for file in os.walkFiles("testresults/*.json"):
  66. let data = parseFile(file)
  67. if data.kind != JArray:
  68. echo "[ERROR] ignoring json file that is not an array: ", file
  69. else:
  70. for elem in data:
  71. let state = elem["result"].str
  72. inc result.totalCount
  73. if state.contains("reSuccess"): inc result.successCount
  74. elif state.contains("reDisabled") or state.contains("reJoined"):
  75. inc result.ignoredCount
  76. if not onlyFailing or not(state.contains("reSuccess")):
  77. result.data.add elem
  78. result.successPercentage = 100 *
  79. (result.successCount.toBiggestFloat / result.totalCount.toBiggestFloat)
  80. result.ignoredPercentage = 100 *
  81. (result.ignoredCount.toBiggestFloat / result.totalCount.toBiggestFloat)
  82. result.failedCount = result.totalCount -
  83. result.successCount - result.ignoredCount
  84. result.failedPercentage = 100 *
  85. (result.failedCount.toBiggestFloat / result.totalCount.toBiggestFloat)
  86. proc generateTestResultsPanelGroupPartial(outfile: File, allResults: JsonNode) =
  87. for testresultRow in allResults:
  88. generateTestResultPanelPartial(outfile, testresultRow)
  89. proc generateAllTestsContent(outfile: File, allResults: AllTests,
  90. onlyFailing = false) =
  91. if allResults.data.len < 1: return # Nothing to do if there is no data.
  92. # Only results from one test run means that test run environment info is the
  93. # same for all tests
  94. let
  95. firstRow = allResults.data[0]
  96. commit = htmlQuote firstRow["commit"].str
  97. branch = htmlQuote firstRow["branch"].str
  98. machine = htmlQuote firstRow["machine"].str
  99. outfile.generateHtmlAllTestsBegin(
  100. machine, commit, branch,
  101. allResults.totalCount,
  102. allResults.successCount,
  103. formatBiggestFloat(allResults.successPercentage, ffDecimal, 2) & "%",
  104. allResults.ignoredCount,
  105. formatBiggestFloat(allResults.ignoredPercentage, ffDecimal, 2) & "%",
  106. allResults.failedCount,
  107. formatBiggestFloat(allResults.failedPercentage, ffDecimal, 2) & "%",
  108. onlyFailing
  109. )
  110. generateTestResultsPanelGroupPartial(outfile, allResults.data)
  111. outfile.generateHtmlAllTestsEnd()
  112. proc generateHtml*(filename: string, onlyFailing: bool) =
  113. let
  114. currentTime = getTime().local()
  115. timestring = htmlQuote format(currentTime, "yyyy-MM-dd HH:mm:ss 'UTC'zzz")
  116. var outfile = open(filename, fmWrite)
  117. outfile.generateHtmlBegin()
  118. generateAllTestsContent(outfile, allTestResults(onlyFailing), onlyFailing)
  119. outfile.generateHtmlEnd(timestring)
  120. outfile.flushFile()
  121. close(outfile)
  122. proc dumpJsonTestResults*(prettyPrint, onlyFailing: bool) =
  123. var
  124. outfile = stdout
  125. jsonString: string
  126. let results = allTestResults(onlyFailing)
  127. if prettyPrint:
  128. jsonString = results.data.pretty()
  129. else:
  130. jsonString = $ results.data
  131. outfile.writeLine(jsonString)