diff options
-rw-r--r-- | tests/testament/css/boilerplate.css | 138 | ||||
-rw-r--r-- | tests/testament/css/style.css | 114 | ||||
-rw-r--r-- | tests/testament/htmlgen.nim | 328 | ||||
-rw-r--r-- | tests/testament/testamenthtml.templ | 318 |
4 files changed, 504 insertions, 394 deletions
diff --git a/tests/testament/css/boilerplate.css b/tests/testament/css/boilerplate.css deleted file mode 100644 index b209b5aa1..000000000 --- a/tests/testament/css/boilerplate.css +++ /dev/null @@ -1,138 +0,0 @@ -/* ==== Scroll down to find where to put your styles :) ==== */ - -/* HTML5 ✰ Boilerplate */ - -html, body, div, span, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, -small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, figcaption, figure, -footer, header, hgroup, menu, nav, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} - -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} - -blockquote, q { quotes: none; } -blockquote:before, blockquote:after, -q:before, q:after { content: ''; content: none; } -ins { background-color: #ff9; color: #000; text-decoration: none; } -mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; } -del { text-decoration: line-through; } -abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; } -table { border-collapse: collapse; border-spacing: 0; } -hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } -input, select { vertical-align: middle; } - -body { font:13px/1.231 sans-serif; *font-size:small; } -select, input, textarea, button { font:99% sans-serif; } -pre, code, kbd, samp { font-family: monospace, sans-serif; } - -html { overflow-y: scroll; } -a:hover, a:active { outline: none; } -ul, ol { margin-left: 2em; } -ol { list-style-type: decimal; } -nav ul, nav li { margin: 0; list-style:none; list-style-image: none; } -small { font-size: 85%; } -strong, th { font-weight: bold; } -td { vertical-align: top; } - -sub, sup { font-size: 75%; line-height: 0; position: relative; } -sup { top: -0.5em; } -sub { bottom: -0.25em; } - -pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; } -textarea { overflow: auto; } -.ie6 legend, .ie7 legend { margin-left: -7px; } -input[type="radio"] { vertical-align: text-bottom; } -input[type="checkbox"] { vertical-align: bottom; } -.ie7 input[type="checkbox"] { vertical-align: baseline; } -.ie6 input { vertical-align: text-bottom; } -label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; } -button, input, select, textarea { margin: 0; } -input:valid, textarea:valid { } -input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; } -.no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; } - -a:link { -webkit-tap-highlight-color: #FF5E99; } - -button { width: auto; overflow: visible; } -.ie7 img { -ms-interpolation-mode: bicubic; } - -body, select, input, textarea { color: #444; } -h1, h2, h3, h4, h5, h6 { font-weight: bold; } -a, a:active, a:visited { color: #607890; } -a:hover { color: #036; } - -/* - // ========================================== \\ - || || - || Your styles ! || - || || - \\ ========================================== // -*/ - - - - - - - - - - - - - - - -.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; } -.hidden { display: none; visibility: hidden; } -.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } -.visuallyhidden.focusable:active, -.visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } -.invisible { visibility: hidden; } -.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; } -.clearfix:after { clear: both; } -.clearfix { zoom: 1; } - - -@media all and (orientation:portrait) { - -} - -@media all and (orientation:landscape) { - -} - -@media screen and (max-device-width: 480px) { - - /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */ -} - - -@media print { - * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important; - -ms-filter: none !important; } - a, a:visited { color: #444 !important; text-decoration: underline; } - a[href]:after { content: " (" attr(href) ")"; } - abbr[title]:after { content: " (" attr(title) ")"; } - .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } - pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } - thead { display: table-header-group; } - tr, img { page-break-inside: avoid; } - @page { margin: 0.5cm; } - p, h2, h3 { orphans: 3; widows: 3; } - h2, h3{ page-break-after: avoid; } -} diff --git a/tests/testament/css/style.css b/tests/testament/css/style.css deleted file mode 100644 index 43a8add68..000000000 --- a/tests/testament/css/style.css +++ /dev/null @@ -1,114 +0,0 @@ -body { - font-size: medium; -} - -div#header { - font-size: 2em; - background-color: #3d3d3d; - border-bottom: solid 2px #000000; - padding: 0.25em; - color: #ffffff; -} - -div#content { - margin: 0.5em; -} - -table { - text-align: left; - margin-bottom: 0.5em; -} - -table td, table th { - padding: 0.15em 0.5em; -} - -tr:nth-child(even) { - background-color: #eee; -} - -/* Awesome buttons :P */ - -a.button { - border-radius: 2px 2px 2px 2px; - background: -moz-linear-gradient(top, #f7f7f7, #ebebeb); - background: -webkit-linear-gradient(top, #f7f7f7, #ebebeb); - background: -o-linear-gradient(top, #f7f7f7, #ebebeb); - text-decoration: none; - color: #3d3d3d; - padding: 5px; - border: solid 1px #9d9d9d; - display: inline-block; - position: relative; - text-align: center; - font-size: small; -} - -a.button.active { - background: -moz-linear-gradient(top, #00B40C, #03A90E); - background: -webkit-linear-gradient(top, #00B40C, #03A90E); - background: -o-linear-gradient(top, #00B40C, #03A90E); - border: solid 1px #148420; - color: #ffffff; -} - -a.button.left { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -a.button.middle { - border-radius: 0; - border-left: 0; -} - -a.button.right { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-left: 0; -} - -a.button:hover { - background: -moz-linear-gradient(top, #0099c7, #0294C1); - background: -webkit-linear-gradient(top, #0099c7, #0294C1); - background: -o-linear-gradient(top, #0099c7, #0294C1); - border: solid 1px #077A9C; - color: #ffffff; -} - -a.button.middle:hover, a.button.right:hover { - border-left: 0; -} - -a.button span.download { - background-image: url("../images/icons.png"); - background-repeat: no-repeat; - display: inline-block; - margin: auto 3px auto auto; - height: 15px; - width: 14px; - position: relative; - background-position: 0 -30px; - top: 3px; -} - -a.button span.book { - background-image: url("../images/icons.png"); - background-repeat: no-repeat; - display: inline-block; - margin: auto 3px auto auto; - height: 15px; - width: 14px; - position: relative; - background-position: 0 0; - top: 3px; -} - -a.button.active span.download, a.button:hover span.download { - background-position: 0 -45px; -} - -a.button.active span.book, a.button:hover span.book { - background-position: 0 -15px; -} - diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index 15960f09a..d607732ad 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -11,155 +11,198 @@ import db_sqlite, cgi, backend, strutils, json -const - TableHeader = """<table border="1"> - <tr><td>Test</td><td>Category</td><td>Target</td> - <td>Action</td> - <td>Expected</td> - <td>Given</td> - <td>Success</td></tr>""" - TableFooter = "</table>" - HtmlBegin = """<html> - <head> - <title>Test results</title> - <style type="text/css"> - <!--""" & slurp("css/boilerplate.css") & "\n" & - slurp("css/style.css") & - """ -ul#tabs { list-style-type: none; margin: 30px 0 0 0; padding: 0 0 0.3em 0; } -ul#tabs li { display: inline; } -ul#tabs li a { color: #42454a; background-color: #dedbde; - border: 1px solid #c9c3ba; border-bottom: none; - padding: 0.3em; text-decoration: none; } -ul#tabs li a:hover { background-color: #f1f0ee; } -ul#tabs li a.selected { color: #000; background-color: #f1f0ee; - font-weight: bold; padding: 0.7em 0.3em 0.38em 0.3em; } -div.tabContent { border: 1px solid #c9c3ba; - padding: 0.5em; background-color: #f1f0ee; } -div.tabContent.hide { display: none; } - --> - </style> - <script> - - var tabLinks = new Array(); - var contentDivs = new Array(); - - function init() { - // Grab the tab links and content divs from the page - var tabListItems = document.getElementById('tabs').childNodes; - for (var i = 0; i < tabListItems.length; i++) { - if (tabListItems[i].nodeName == "LI") { - var tabLink = getFirstChildWithTagName(tabListItems[i], 'A'); - var id = getHash(tabLink.getAttribute('href')); - tabLinks[id] = tabLink; - contentDivs[id] = document.getElementById(id); - } - } - // Assign onclick events to the tab links, and - // highlight the first tab - var i = 0; - for (var id in tabLinks) { - tabLinks[id].onclick = showTab; - tabLinks[id].onfocus = function() { this.blur() }; - if (i == 0) tabLinks[id].className = 'selected'; - i++; - } - // Hide all content divs except the first - var i = 0; - for (var id in contentDivs) { - if (i != 0) contentDivs[id].className = 'tabContent hide'; - i++; - } - } - - function showTab() { - var selectedId = getHash(this.getAttribute('href')); - - // Highlight the selected tab, and dim all others. - // Also show the selected content div, and hide all others. - for (var id in contentDivs) { - if (id == selectedId) { - tabLinks[id].className = 'selected'; - contentDivs[id].className = 'tabContent'; - } else { - tabLinks[id].className = ''; - contentDivs[id].className = 'tabContent hide'; - } - } - // Stop the browser following the link - return false; - } - - function getFirstChildWithTagName(element, tagName) { - for (var i = 0; i < element.childNodes.length; i++) { - if (element.childNodes[i].nodeName == tagName) return element.childNodes[i]; - } - } - function getHash(url) { - var hashPos = url.lastIndexOf('#'); - return url.substring(hashPos + 1); - } - </script> - - </head> - <body onload="init()">""" - - HtmlEnd = "</body></html>" - -proc td(s: string): string = - result = "<td>" & s.substr(0, 200).xmlEncode & "</td>" +import "testamenthtml.templ" -proc getCommit(db: DbConn, c: int): string = - var commit = c - for thisCommit in db.rows(sql"select id from [Commit] order by id desc"): - if commit == 0: result = thisCommit[0] - inc commit +proc generateTestRunTabListItemPartial(outfile: File, testRunRow: Row, firstRow = false) = + let + # The first tab gets the bootstrap class for a selected tab + firstTabActiveClass = if firstRow: "active" + else: "" + commitId = testRunRow[0] + hash = htmlQuote(testRunRow[1]) + branch = htmlQuote(testRunRow[2]) + machineId = testRunRow[3] + machineName = htmlQuote(testRunRow[4]) + + outfile.generateHtmlTabListItem( + firstTabActiveClass, + commitId, + machineId, + branch, + hash, + machineName + ) + +proc generateTestResultPanelPartial(outfile: File, testResultRow: Row, onlyFailing = false) = + let + trId = testResultRow[0] + name = testResultRow[1].htmlQuote() + category = testResultRow[2].htmlQuote() + target = testResultRow[3].htmlQuote() + action = testResultRow[4].htmlQuote() + result = testResultRow[5] + expected = testResultRow[6] + gotten = testResultRow[7] + timestamp = testResultRow[8] + var panelCtxClass, textCtxClass, bgCtxClass, resultSign, resultDescription: string + case result + of "reSuccess": + if onlyFailing: + return + panelCtxClass = "success" + textCtxClass = "success" + bgCtxClass = "success" + resultSign = "ok" + resultDescription = "PASS" + of "reIgnored": + if onlyFailing: + return + panelCtxClass = "info" + textCtxClass = "info" + bgCtxClass = "info" + resultSign = "question" + resultDescription = "SKIP" + else: + panelCtxClass = "danger" + textCtxClass = "danger" + bgCtxClass = "danger" + resultSign = "exclamation" + resultDescription = "FAIL" + + outfile.generateHtmlTestresultPanelBegin( + trId, name, target, category, action, resultDescription, + timestamp, + result, resultSign, + panelCtxClass, textCtxClass, bgCtxClass + ) + if expected.isNilOrWhitespace() and gotten.isNilOrWhitespace(): + outfile.generateHtmlTestresultOutputNone() + else: + outfile.generateHtmlTestresultOutputDetails( + expected.strip().htmlQuote, + gotten.strip().htmlQuote + ) + outfile.generateHtmlTestresultPanelEnd() + +proc generateTestResultsPanelGroupPartial(outfile: File, db: DbConn, commitid, machineid: string, onlyFailing = false) = + const testResultsSelect = sql""" +SELECT [tr].[id] + , [tr].[name] + , [tr].[category] + , [tr].[target] + , [tr].[action] + , [tr].[result] + , [tr].[expected] + , [tr].[given] + , [tr].[created] +FROM [TestResult] AS [tr] +WHERE [tr].[commit] = ? + AND [tr].[machine] = ?""" + for testresultRow in db.rows(testResultsSelect, commitid, machineid): + generateTestResultPanelPartial(outfile, testresultRow, onlyFailing) + +proc generateTestRunTabContentPartial(outfile: File, db: DbConn, testRunRow: Row, onlyFailing = false, firstRow = false) = + let + # The first tab gets the bootstrap classes for a selected and displaying tab content + firstTabActiveClass = if firstRow: " in active" + else: "" + commitId = testRunRow[0] + hash = htmlQuote(testRunRow[1]) + branch = htmlQuote(testRunRow[2]) + machineId = testRunRow[3] + machineName = htmlQuote(testRunRow[4]) + os = htmlQuote(testRunRow[5]) + cpu = htmlQuote(testRunRow[6]) + + const + totalClause = """ +SELECT COUNT(*) +FROM [TestResult] AS [tr] +WHERE [tr].[commit] = ? + AND [tr].[machine] = ?""" + successClause = totalClause & "\L" & """ + AND [tr].[result] LIKE 'reSuccess'""" + ignoredClause = totalClause & "\L" & """ + AND [tr].[result] LIKE 'reIgnored'""" + let + totalCount = db.getValue(sql(totalClause), commitId, machineId).parseBiggestInt() + successCount = db.getValue(sql(successClause), commitId, machineId).parseBiggestInt() + successPercentage = 100 * (successCount.toBiggestFloat() / totalCount.toBiggestFloat()) + ignoredCount = db.getValue(sql(ignoredClause), commitId, machineId).parseBiggestInt() + ignoredPercentage = 100 * (ignoredCount.toBiggestFloat() / totalCount.toBiggestFloat()) + failedCount = totalCount - successCount - ignoredCount + failedPercentage = 100 * (failedCount.toBiggestFloat() / totalCount.toBiggestFloat()) + + outfile.generateHtmlTabPageBegin( + firstTabActiveClass, commitId, + machineId, branch, hash, machineName, os, cpu, + totalCount, + successCount, formatBiggestFloat(successPercentage, ffDecimal, 2) & "%", + ignoredCount, formatBiggestFloat(ignoredPercentage, ffDecimal, 2) & "%", + failedCount, formatBiggestFloat(failedPercentage, ffDecimal, 2) & "%" + ) + generateTestResultsPanelGroupPartial(outfile, db, commitId, machineId, onlyFailing) + outfile.generateHtmlTabPageEnd() + +proc generateTestRunsHtmlPartial(outfile: File, db: DbConn, onlyFailing = false) = + # Select a cross-join of Commits and Machines ensuring that the selected combination + # contains testresults + const testrunSelect = sql""" +SELECT [c].[id] AS [CommitId] + , [c].[hash] as [Hash] + , [c].[branch] As [Branch] + , [m].[id] AS [MachineId] + , [m].[name] AS [MachineName] + , [m].[os] AS [OS] + , [m].[cpu] AS [CPU] +FROM [Commit] AS [c], [Machine] AS [m] +WHERE ( + SELECT COUNT(*) + FROM [TestResult] AS [tr] + WHERE [tr].[commit] = [c].[id] + AND [tr].[machine] = [m].[id] + ) > 0 +ORDER BY [c].[id] DESC +""" + # Iterating the results twice, get entire result set in one go + var testRunRowSeq = db.getAllRows(testrunSelect) + + outfile.generateHtmlTabListBegin() + var firstRow = true + for testRunRow in testRunRowSeq: + generateTestRunTabListItemPartial(outfile, testRunRow, firstRow) + if firstRow: + firstRow = false + outfile.generateHtmlTabListEnd() + + outfile.generateHtmlTabContentsBegin() + firstRow = true + for testRunRow in testRunRowSeq: + generateTestRunTabContentPartial(outfile, db, testRunRow, onlyFailing, firstRow) + if firstRow: + firstRow = false + outfile.generateHtmlTabContentsEnd() proc generateHtml*(filename: string, commit: int; onlyFailing: bool) = - const selRow = """select name, category, target, action, - expected, given, result - from TestResult - where [commit] = ? and machine = ? - order by category""" var db = open(connection="testament.db", user="testament", password="", database="testament") - # search for proper commit: - let lastCommit = db.getCommit(commit) - var outfile = open(filename, fmWrite) - outfile.write(HtmlBegin) - - let commit = db.getValue(sql"select hash from [Commit] where id = ?", - lastCommit) - let branch = db.getValue(sql"select branch from [Commit] where id = ?", - lastCommit) - outfile.write("<p><b>$# $#</b></p>" % [branch, commit]) - - # generate navigation: - outfile.write("""<ul id="tabs">""") - for m in db.rows(sql"select id, name, os, cpu from Machine order by id"): - outfile.writeLine """<li><a href="#$#">$#: $#, $#</a></li>""" % m - outfile.write("</ul>") - - for currentMachine in db.rows(sql"select id from Machine order by id"): - let m = currentMachine[0] - outfile.write("""<div class="tabContent" id="$#">""" % m) - - outfile.write(TableHeader) - for row in db.rows(sql(selRow), lastCommit, m): - if onlyFailing and row.len > 0 and row[row.high] == "reSuccess": - discard - else: - outfile.write("<tr>") - for x in row: - outfile.write(x.td) - outfile.write("</tr>") - - outfile.write(TableFooter) - outfile.write("</div>") - outfile.write(HtmlEnd) - close(db) + + outfile.generateHtmlBegin() + + generateTestRunsHtmlPartial(outfile, db, onlyFailing) + + outfile.generateHtmlEnd() + + outfile.flushFile() close(outfile) + close(db) + +proc getCommit(db: DbConn, c: int): string = + var commit = c + for thisCommit in db.rows(sql"select id from [Commit] order by id desc"): + if commit == 0: result = thisCommit[0] + inc commit proc generateJson*(filename: string, commit: int) = const @@ -226,3 +269,4 @@ proc generateJson*(filename: string, commit: int) = outfile.writeLine "}" close(db) close(outfile) + diff --git a/tests/testament/testamenthtml.templ b/tests/testament/testamenthtml.templ new file mode 100644 index 000000000..f7477f3aa --- /dev/null +++ b/tests/testament/testamenthtml.templ @@ -0,0 +1,318 @@ +#? stdtmpl(subsChar = '%', metaChar = '#', emit = "outfile.write") +#import strutils +# +#proc htmlQuote*(raw: string): string = +# result = raw.multiReplace( +# ("&", "&"), +# ("\"", """), +# ("'", "'"), +# ("<", "<"), +# (">", ">") +# ) +# +#end proc +#proc generateHtmlBegin*(outfile: File) = +<!DOCTYPE html> +<html> +<head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Testament Test Results</title> + <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js" integrity="sha256-ihAoc6M/JPfrIiIeayPE9xjin4UWjsx2mjW/rtmxLM4=" crossorigin="anonymous"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous"></script> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" /> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha256-ZT4HPpdCOt2lvDkXokHuhJfdOKSPFLzeAJik5U/Q+l4=" crossorigin="anonymous" /> + <script> + /** + * Callback function that is executed for each Element in an array. + * @callback executeForElement + * @param {Element} elem Element to operate on + */ + + /** + * + * @param {number} index + * @param {Element[]} elemArray + * @param {executeForElement} executeOnItem + */ + function executeAllAsync(elemArray, index, executeOnItem) { + for (var i = 0; index < elemArray.length && i < 100; i++ , index++) { + var item = elemArray[index]; + executeOnItem(item); + } + if (index < elemArray.length) { + setTimeout(executeAllAsync, 0, elemArray, index, executeOnItem); + } + } + + /** @param {Element} elem */ + function executeShowOnElement(elem) { + while (elem.classList.contains("hidden")) { + elem.classList.remove("hidden"); + } + } + + /** @param {Element} elem */ + function executeHideOnElement(elem) { + if (!elem.classList.contains("hidden")) { + elem.classList.add("hidden"); + } + } + + /** @param {Element} elem */ + function executeExpandOnElement(elem) { + $(elem).collapse("show"); + } + + /** @param {Element} elem */ + function executeCollapseOnElement(elem) { + $(elem).collapse("hide"); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + * @param {executeForElement} executeOnEachPanel + */ + function wholePanelAll(tabId, category, executeOnEachPanel) { + var selector = "div.panel"; + if (typeof category === "string" && category) { + selector += "-" + category; + } + + var jqPanels = $(selector, $("#" + tabId)); + /** @type {Element[]} */ + var elemArray = jqPanels.toArray(); + + setTimeout(executeAllAsync, 0, elemArray, 0, executeOnEachPanel); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + * @param {executeForElement} executeOnEachPanel + */ + function panelBodyAll(tabId, category, executeOnEachPanelBody) { + var selector = "div.panel"; + if (typeof category === "string" && category) { + selector += "-" + category; + } + + var jqPanels = $(selector, $("#" + tabId)); + + var jqPanelBodies = $("div.panel-body", jqPanels); + /** @type {Element[]} */ + var elemArray = jqPanelBodies.toArray(); + + setTimeout(executeAllAsync, 0, elemArray, 0, executeOnEachPanelBody); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function showAll(tabId, category) { + wholePanelAll(tabId, category, executeShowOnElement); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function hideAll(tabId, category) { + wholePanelAll(tabId, category, executeHideOnElement); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function expandAll(tabId, category) { + panelBodyAll(tabId, category, executeExpandOnElement); + } + + /** + * @param {string} tabId The id of the tabpanel div to search. + * @param {string} [category] Optional bootstrap panel context class (danger, warning, info, success) + */ + function collapseAll(tabId, category) { + panelBodyAll(tabId, category, executeCollapseOnElement); + } + </script> +</head> +<body> + <div class="container"> + <h1>Testament Test Results <small>Nim Tester</small></h1> +#end proc +#proc generateHtmlTabListBegin*(outfile: File) = + <ul class="nav nav-tabs" role="tablist"> +#end proc +#proc generateHtmlTabListItem*(outfile: File, firstTabActiveClass, commitId, +# machineId, branch, hash, machineName: string) = + <li role="presentation" class="%firstTabActiveClass"> + <a href="#tab-commit-%commitId-machine-%machineId" aria-controls="tab-commit-%commitId-machine-%machineId" role="tab" data-toggle="tab"> + %branch#%hash@%machineName + </a> + </li> +#end proc +#proc generateHtmlTabListEnd*(outfile: File) = + </ul> +#end proc +#proc generateHtmlTabContentsBegin*(outfile: File) = + <div class="tab-content"> +#end proc +#proc generateHtmlTabPageBegin*(outfile: File, firstTabActiveClass, commitId, +# machineId, branch, hash, machineName, os, cpu: string, totalCount: BiggestInt, +# successCount: BiggestInt, successPercentage: string, +# ignoredCount: BiggestInt, ignoredPercentage: string, +# failedCount: BiggestInt, failedPercentage: string) = + <div id="tab-commit-%commitId-machine-%machineId" class="tab-pane fade%firstTabActiveClass" role="tabpanel"> + <h2>%branch#%hash@%machineName</h2> + <dl class="dl-horizontal"> + <dt>Branch</dt> + <dd>%branch</dd> + <dt>Commit Hash</dt> + <dd><code>%hash</code></dd> + <dt>Machine Name</dt> + <dd>%machineName</dd> + <dt>OS</dt> + <dd>%os</dd> + <dt title="CPU Architecture">CPU</dt> + <dd>%cpu</dd> + <dt>All Tests</dt> + <dd> + <span class="glyphicon glyphicon-th-list"></span> + %totalCount + </dd> + <dt>Successful Tests</dt> + <dd> + <span class="glyphicon glyphicon-ok-sign"></span> + %successCount (%successPercentage) + </dd> + <dt>Skipped Tests</dt> + <dd> + <span class="glyphicon glyphicon-question-sign"></span> + %ignoredCount (%ignoredPercentage) + </dd> + <dt>Failed Tests</dt> + <dd> + <span class="glyphicon glyphicon-exclamation-sign"></span> + %failedCount (%failedPercentage) + </dd> + </dl> + <div class="table-responsive"> + <table class="table table-condensed"> + <tr> + <th class="text-right" style="vertical-align:middle">All Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Successful Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'success');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'success');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'success');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'success');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Skipped Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'info');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'info');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'info');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'info');">Collapse All</button> + </div> + </td> + </tr> + <tr> + <th class="text-right" style="vertical-align:middle">Failed Tests</th> + <td> + <div class="btn-group"> + <button class="btn btn-default" type="button" onclick="showAll('tab-commit-%commitId-machine-%machineId', 'danger');">Show All</button> + <button class="btn btn-default" type="button" onclick="hideAll('tab-commit-%commitId-machine-%machineId', 'danger');">Hide All</button> + <button class="btn btn-default" type="button" onclick="expandAll('tab-commit-%commitId-machine-%machineId', 'danger');">Expand All</button> + <button class="btn btn-default" type="button" onclick="collapseAll('tab-commit-%commitId-machine-%machineId', 'danger');">Collapse All</button> + </div> + </td> + </tr> + </table> + </div> + <div class="panel-group"> +#end proc +#proc generateHtmlTestresultPanelBegin*(outfile: File, trId, name, target, category, +# action, resultDescription, timestamp, result, resultSign, +# panelCtxClass, textCtxClass, bgCtxClass: string) = + <div id="panel-testResult-%trId" class="panel panel-%panelCtxClass"> + <div class="panel-heading" style="cursor:pointer" data-toggle="collapse" data-target="#panel-body-testResult-%trId" aria-controls="panel-body-testResult-%trId" aria-expanded="false"> + <div class="row"> + <h4 class="col-xs-3 col-sm-1 panel-title"> + <span class="glyphicon glyphicon-%resultSign-sign"></span> + <strong>%resultDescription</strong> + </h4> + <h4 class="col-xs-1 panel-title"><span class="badge">%target</span></h4> + <h4 class="col-xs-5 col-sm-7 panel-title" title="%name"><code class="text-%textCtxClass">%name</code></h4> + <h4 class="col-xs-3 col-sm-3 panel-title text-right"><span class="badge">%category</span></h4> + </div> + </div> + <div id="panel-body-testResult-%trId" class="panel-body collapse bg-%bgCtxClass"> + <dl class="dl-horizontal"> + <dt>Name</dt> + <dd><code class="text-%textCtxClass">%name</code></dd> + <dt>Category</dt> + <dd><span class="badge">%category</span></dd> + <dt>Timestamp</dt> + <dd>%timestamp</dd> + <dt>Nim Action</dt> + <dd><code class="text-%textCtxClass">%action</code></dd> + <dt>Nim Backend Target</dt> + <dd><span class="badge">%target</span></dd> + <dt>Code</dt> + <dd><code class="text-%textCtxClass">%result</code></dd> + </dl> +#end proc +#proc generateHtmlTestresultOutputDetails*(outfile: File, expected, gotten: string) = + <div class="table-responsive"> + <table class="table table-condensed"> + <thead> + <tr> + <th>Expected</th> + <th>Actual</th> + </tr> + </thead> + <tbody> + <tr> + <td><pre>%expected</pre></td> + <td><pre>%gotten</pre></td> + </tr> + </tbody> + </table> + </div> +#end proc +#proc generateHtmlTestresultOutputNone*(outfile: File) = + <p class="sr-only">No output details</p> +#end proc +#proc generateHtmlTestresultPanelEnd*(outfile: File) = + </div> + </div> +#end proc +#proc generateHtmlTabPageEnd*(outfile: File) = + </div> + </div> +#end proc +#proc generateHtmlTabContentsEnd*(outfile: File) = + </div> +#end proc +#proc generateHtmlEnd*(outfile: File) = + </div> +</body> +</html> \ No newline at end of file |