aboutsummaryrefslogtreecommitdiff
path: root/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java')
-rw-r--r--src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java623
1 files changed, 340 insertions, 283 deletions
diff --git a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java
index cad8bee..f0461d4 100644
--- a/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java
+++ b/src/batchtools/headless/src/main/java/com/galois/fiveui/Reporter.java
@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import com.google.common.collect.Lists;
import com.googlecode.jatl.Html;
/**
@@ -40,292 +41,346 @@ import com.googlecode.jatl.Html;
* generated in HTML and returned as human readable strings by getSummaryPage(),
* getURLPage(), and getRulePage(). The client is responsible for writing them
* to .html files (or whatever).
- *
+ *
* @author bjones
- *
+ *
*/
public class Reporter {
- /** see sortBy* and computeSummaryStats methods for map semantics */
- private final Map<String, List<Result>> _byURLMap;
- private final Map<String, List<Result>> _byRuleMap;
- private final Map<String, int[]> _passFailMap;
- private Map<String, String> _ruleNameToDesc;
- private static String GLOBAL_CSS =
- "h1 { font-size: 150%; }" +
- "h2 { font-size: 110%; }" +
- "li { margin: 5 0 0 0; }" +
- "table { border: 1px solid grey; cellpadding: 5%; width: 200px; }\n" +
- "td.pass-number{ text-align: right;color: green; }\n" +
- "td.fail-number{ text-align: right;color: red; }\n" +
- "td.text{ text-align: left; }\n" +
- "th { font-weight: bold; }\n" +
- "td, th { border: 1px solid grey; }\n" +
- ".hlRow { background: #EEEEEE; }\n" +
- ".regRow { background: #FFFFFF; }\n";
+ /** see sortBy* and computeSummaryStats methods for map semantics */
+ private final Map<String, List<Result>> _byURLMap;
+ private final Map<String, List<Result>> _byRuleMap;
+ private final Map<String, int[]> _passFailMap;
+ private Map<String, String> _ruleNameToDesc;
+ private static String GLOBAL_CSS = "h1 { font-size: 150%; }"
+ + "h2 { font-size: 110%; }"
+ + "li { margin: 5 0 0 0; }"
+ + "table { border: 1px solid grey; cellpadding: 5%; width: 200px; }\n"
+ + "td.pass-number{ text-align: right;color: green; }\n"
+ + "td.fail-number{ text-align: right;color: red; }\n"
+ + "td.text{ text-align: left; }\n" + "th { font-weight: bold; }\n"
+ + "td, th { border: 1px solid grey; }\n"
+ + ".hlRow { background: #EEEEEE; }\n"
+ + ".regRow { background: #FFFFFF; }\n";
+
+ /**
+ * Construct a Reporter object. The constructor takes a list of results and
+ * uses them to populate various maps used in reporting.
+ *
+ * @param results
+ * a list of Result objects
+ */
+ public Reporter(List<Result> results) {
+ this._byURLMap = sortByURL(results);
+ this._byRuleMap = sortByRule(results);
+ this._passFailMap = computeSummaryStats(results);
+ this._ruleNameToDesc = extractRuleDesc(results);
+ }
+
+ /**
+ * Build the HTML markup for a summary page based on the precomputed map
+ * this._passFailMap.
+ *
+ * @return String containing human-readable HTML representing a summary page
+ */
+ public String getSummary() {
+ StringWriter summaryPage = new StringWriter();
+ final Map<String, int[]> scopedMap = this._passFailMap;
+ Html page = new Html(summaryPage);
+ page = makeHead(page, "Summary of Results");
+ page = new Html(page) {
+ {
+ h1().text("Headless Run Summary").end();
+ p();
+ ul();
+ li().a().href("byURL.html").text("Results organized by URL")
+ .end().end();
+ li().a().href("byRule.html").text("Results organized by Rule")
+ .end().end();
+ end();
+ end();
+ p();
+ div().id("stats");
+ makeSummaryStats(scopedMap);
+ end();
+ end();
+ endAll();
+ done();
+ }
- /**
- * Construct a Reporter object. The constructor takes a list of results
- * and uses them to populate various maps used in reporting.
- *
- * @param results a list of Result objects
- */
- public Reporter(List<Result> results) {
- this._byURLMap = sortByURL(results);
- this._byRuleMap = sortByRule(results);
- this._passFailMap = computeSummaryStats(results);
- this._ruleNameToDesc = extractRuleDesc(results);
- }
+ /**
+ * Report statistics on the headless run. Note, "pass" means the URL
+ * passed all tests in the ruleset, but "fail" can be reported for
+ * the same test on multiple offenders in the page.
+ */
+ Html makeSummaryStats(Map<String, int[]> passFailMap) {
+ int uniqueURLs = passFailMap.size();
+ int[] passFailList;
- /**
- * Build the HTML markup for a summary page based on the precomputed map
- * this._passFailMap.
- *
- * @return String containing human-readable HTML representing a summary page
- */
- public String getSummary() {
- StringWriter summaryPage = new StringWriter();
- final Map<String, int[]> scopedMap = this._passFailMap;
- Html page = new Html(summaryPage);
- page = makeHead(page, "Summary of Results");
- page = new Html(page) {{
- h1().text("Headless Run Summary").end();
- p();
- ul();
- li().a().href("byURL.html").text("Results organized by URL").end().end();
- li().a().href("byRule.html").text("Results organized by Rule").end().end();
- end();
- end();
- p();
- div().id ("stats");
- makeSummaryStats(scopedMap);
- end();
- end();
- endAll();
- done();
- }
- /**
- * Report statistics on the headless run. Note, "pass"
- * means the URL passed all tests in the ruleset, but "fail" can be
- * reported for the same test on multiple offenders in the page.
- */
- Html makeSummaryStats(Map<String, int[]> passFailMap) {
- int uniqueURLs = passFailMap.size();
- int[] passFailList;
+ p();
+ h3().text("Unique URLs: ");
+ span().classAttr("number").text(String.valueOf(uniqueURLs))
+ .end();
+ end().end();
- p();
- h3().text("Unique URLs: ");
- span().classAttr("number").text(String.valueOf(uniqueURLs)).end();
- end().end();
+ p();
+ table().id("stats-table");
+ tr();
+ th().text("URL").end();
+ th().text("Pass").end();
+ th().text("Fail").end();
+ end();
+ int i = 0; // index for **alternate row highlighting**
+ List<String> sortedKeys = Lists.newArrayList();
+ sortedKeys.addAll(passFailMap.keySet());
+ Collections.sort(sortedKeys);
+ for (String key : sortedKeys) {
+ passFailList = passFailMap.get(key);
+ tr().classAttr(i % 2 == 0 ? "hlRow" : "regRow");
+ td().classAttr("text").a().href(key).text(key).end().end();
+ td().classAttr("pass-number")
+ .text(String.valueOf(passFailList[0])).end();
+ td().classAttr("fail-number")
+ .text(String.valueOf(passFailList[1])).end();
+ end();
+ i++;
+ }
+ end(); // end <table>
+ return end(); // end <p>
+ }
+ };
+ return summaryPage.getBuffer().toString();
+ }
+
+ /**
+ * Build the HTML markup for a report page sorted by URL.
+ *
+ * @return String containing human-readable HTML representing a report page
+ */
+ public String getByURL() {
+ StringWriter byURLPage = new StringWriter();
+ final Map<String, List<Result>> scopedMap = this._byURLMap;
+ Html page = new Html(byURLPage);
+ page = makeHead(page, "Results sorted by URL");
+ page = new Html(page) {
+ {
+ body();
+ h1().text("Results by URL").end();
+ ol();
+ List<String> sortedKeys = Lists.newArrayList();
+ sortedKeys.addAll(scopedMap.keySet());
+ Collections.sort(sortedKeys);
+ for (String url : sortedKeys) {
+ li().h2().a().href(url).text(url).end().end();
+ ul();
+ int i = 0;
+ for (Result r : scopedMap.get(url)) {
+ String cAttr = i % 2 == 0 ? "hlRow" : "regRow";
+
+ // format an individual Result for this url:
+ li().classAttr(cAttr).b().text(r.getRuleName()).end();
+ resultToHtml(this, r, cAttr);
+ end();
+ i++;
+ }
+ end();
+ end();
+ }
+ endAll();
+ done();
+ }
+
+ };
+ return byURLPage.getBuffer().toString();
+ }
+
+
+
+ /**
+ * Build the HTML markup for a report page sorted by rule name.
+ *
+ * @return String containing human-readable HTML representing a report page
+ */
+ public String getByRule() {
+ StringWriter byRulePage = new StringWriter();
+ final Map<String, List<Result>> scopedMap = this._byRuleMap;
+ final Map<String, String> scopedRuleNameToDesc = this._ruleNameToDesc;
+ Html page = new Html(byRulePage);
+ page = makeHead(page, "Results sorted by rule");
+ page = new Html(page) {
+ {
+ h1().text("Results by Rule").end();
+ ul();
+ List<String> sortedKeys = new ArrayList<String>();
+ sortedKeys.addAll(scopedMap.keySet());
+ Collections.sort(sortedKeys);
+ for (String rule : sortedKeys) {
+ li();
+ b().text(rule).end()
+ .text(": " + scopedRuleNameToDesc.get(rule));
+ ul();
+ int i = 0;
+ for (Result r : scopedMap.get(rule)) {
+ String cAttr = i % 2 == 0 ? "hlRow" : "regRow";
+
+ li().classAttr(cAttr).b().text(r.getURL()).end();
+ resultToHtml(this, r, cAttr);
+ end();
+ i++;
+ }
+ end();
+ end();
+ }
+ endAll();
+ done();
+ }
+ };
+ return byRulePage.getBuffer().toString();
+ }
- p();
- table().id("stats-table");
- tr();
- th().text("URL").end();
- th().text("Pass").end();
- th().text("Fail").end();
- end();
- int i = 0; // index for **alternate row highlighting**
- List<String> sortedKeys = new ArrayList<String>();
- sortedKeys.addAll(passFailMap.keySet());
- Collections.sort(sortedKeys);
- for (String key: sortedKeys) {
- passFailList = passFailMap.get(key);
- tr().classAttr(i % 2 == 0 ? "hlRow" : "regRow");
- td().classAttr("text").a().href(key).text(key).end().end();
- td().classAttr("pass-number").text(String.valueOf(passFailList[0])).end();
- td().classAttr("fail-number").text(String.valueOf(passFailList[1])).end();
- end();
- i++;
- }
- end(); // end <table>
- return end(); // end <p>
- }
- };
- return summaryPage.getBuffer().toString();
- }
- /**
- * Build the HTML markup for a report page sorted by URL.
- *
- * @return String containing human-readable HTML representing a report page
- */
- public String getByURL() {
- StringWriter byURLPage = new StringWriter();
- final Map<String, List<Result>> scopedMap = this._byURLMap;
- Html page = new Html(byURLPage);
- page = makeHead(page, "Results sorted by URL");
- page = new Html(page) {{
- body();
- h1().text("Results by URL").end();
- ol();
- List<String> sortedKeys = new ArrayList<String>();
- sortedKeys.addAll(scopedMap.keySet());
- Collections.sort(sortedKeys);
- for (String url: sortedKeys) {
- li().h2().a().href(url).text(url).end().end();
- ul();
- int i = 0;
- for (Result r: scopedMap.get(url)) {
- li().classAttr(i % 2 == 0 ? "regRow" : "hlRow");
- text(r.getRuleName() + ": " + r.getRuleDesc()).br();
- text(r.getProblem()).end();
- i++;
- }
- end();
- end();
- }
- endAll();
- done();
- }};
- return byURLPage.getBuffer().toString();
- }
+ private void resultToHtml(Html html, Result r, String cAttr) {
+
+ html.ul();
+ html.li().b().text("Description:").end();
+ html.text(r.getRuleDesc()).end();
+
+ html.li().b().text("Message:").end();
+ html.text(r.getMsg()).end();
- /**
- * Build the HTML markup for a report page sorted by rule name.
- *
- * @return String containing human-readable HTML representing a report page
- */
- public String getByRule() {
- StringWriter byRulePage = new StringWriter();
- final Map<String, List<Result>> scopedMap = this._byRuleMap;
- final Map<String, String> scopedRuleNameToDesc = this._ruleNameToDesc;
- Html page = new Html(byRulePage);
- page = makeHead(page, "Results sorted by rule");
- page = new Html(page) {{
- h1().text("Results by Rule").end();
- ul();
- List<String> sortedKeys = new ArrayList<String>();
- sortedKeys.addAll(scopedMap.keySet());
- Collections.sort(sortedKeys);
- for (String rule: sortedKeys) {
- li();
- b().text(rule).end().text(": " + scopedRuleNameToDesc.get(rule));
- ul();
- int i = 0;
- for (Result r: scopedMap.get(rule)) {
- li().classAttr(i % 2 == 0 ? "regRow" : "hlRow");
- text("Problem: " + r.getProblem()).br();
- text("URL: ").a().href(r.getURL()).text(r.getURL()).end().end();
- i++;
- }
- end();
- end();
- }
- endAll();
- done();
- }};
- return byRulePage.getBuffer().toString();
- }
+ html.li().b().text("xpath:").end();
+ html.text(r.getXpath()).end();
+
+ html.li().b().text("Severity:").end();
+ html.text(r.getType().toString()).end();
+
+ html.li().b().text("Browser:").end();
+ html.text(r.getDriver().toString()).end();
+
+ html.li().b().text("Url:").end();
+ html.a().href(r.getURL()).text(r.getURL()).end().end();
- /**
- * Utility method to take all the reports and write them to standard file
- * names under a given directory.
- *
- * @param dirName name of the directory where the reports should be written
- * @throws IOException
- */
- public void writeReportsToDir(String dirName) throws IOException {
- PrintWriter summaryFile = new PrintWriter(new FileWriter(dirName + File.separator + "summary.html"));
- PrintWriter byURLFile = new PrintWriter(new FileWriter(dirName + File.separator + "byURL.html"));
- PrintWriter byRuleFile = new PrintWriter(new FileWriter(dirName + File.separator + "byRule.html"));
- summaryFile.write(this.getSummary());
- summaryFile.close();
- byURLFile.write(this.getByURL());
- byURLFile.close();
- byRuleFile.write(this.getByRule());
- byRuleFile.close();
- }
+ html.end();
+ }
+
+ /**
+ * Utility method to take all the reports and write them to standard file
+ * names under a given directory.
+ *
+ * @param dirName
+ * name of the directory where the reports should be written
+ * @throws IOException
+ */
+ public void writeReportsToDir(String dirName) throws IOException {
+ PrintWriter summaryFile = new PrintWriter(new FileWriter(dirName
+ + File.separator + "summary.html"));
+ PrintWriter byURLFile = new PrintWriter(new FileWriter(dirName
+ + File.separator + "byURL.html"));
+ PrintWriter byRuleFile = new PrintWriter(new FileWriter(dirName
+ + File.separator + "byRule.html"));
+ summaryFile.write(this.getSummary());
+ summaryFile.close();
+ byURLFile.write(this.getByURL());
+ byURLFile.close();
+ byRuleFile.write(this.getByRule());
+ byRuleFile.close();
+ }
- /** Private fields **/
+ /** Private fields **/
- private Html makeHead(Html page, final String title) {
- return new Html(page) {{
- html();
- head();
- title().text(title).end();
- style().type("text/css").text(GLOBAL_CSS).end();
- end();
- body();
- }};
- }
+ private Html makeHead(Html page, final String title) {
+ return new Html(page) {
+ {
+ html();
+ head();
+ title().text(title).end();
+ style().type("text/css").text(GLOBAL_CSS).end();
+ end();
+ body();
+ }
+ };
+ }
- /**
- * Populate a Map<String, List<Result>> representing the results sorted by
- * URL.
- *
- * @param results a list of results
- * @return a map representing the results sorted by URL.
- */
- private Map<String, List<Result>>sortByURL(List<Result> results) {
- /** map semantics: Map< url, [rule1, rule2, ...] > */
- Map<String, List<Result>> map = new HashMap<String, List<Result>>();
- String url;
- List<Result> list;
- for (Result r: results) {
- url = r.getURL();
- if (map.containsKey(url)) {
- list = map.get(url);
- list.add(r);
- } else {
- list = new ArrayList<Result>();
- list.add(r);
- map.put(url, list);
- }
- }
- return map;
- }
+ /**
+ * Populate a Map<String, List<Result>> representing the results sorted by
+ * URL.
+ *
+ * @param results
+ * a list of results
+ * @return a map representing the results sorted by URL.
+ */
+ private Map<String, List<Result>> sortByURL(List<Result> results) {
+ /** map semantics: Map< url, [rule1, rule2, ...] > */
+ Map<String, List<Result>> map = new HashMap<String, List<Result>>();
+ String url;
+ List<Result> list;
+ for (Result r : results) {
+ url = r.getURL();
+ if (map.containsKey(url)) {
+ list = map.get(url);
+ list.add(r);
+ } else {
+ list = new ArrayList<Result>();
+ list.add(r);
+ map.put(url, list);
+ }
+ }
+ return map;
+ }
- /**
- * Populate a Map<String, List<Result>> representing the results sorted by
- * rule name.
- *
- * @param results a list of results
- * @return a map representing the results sorted by rule name.
- */
- private Map<String, List<Result>>sortByRule(List<Result> results) {
- /** map semantics: Map< rule, [url1, url2, ...] > */
- Map<String, List<Result>> map = new HashMap<String, List<Result>>();
- String rule;
- List<Result> list;
- for (Result r: results) {
- rule = r.getRuleName();
- if (map.containsKey(rule)) {
- list = map.get(rule);
- list.add(r);
- } else {
- list = new ArrayList<Result>();
- list.add(r);
- map.put(rule, list);
- }
- }
- return map;
- }
+ /**
+ * Populate a Map<String, List<Result>> representing the results sorted by
+ * rule name.
+ *
+ * @param results
+ * a list of results
+ * @return a map representing the results sorted by rule name.
+ */
+ private Map<String, List<Result>> sortByRule(List<Result> results) {
+ /** map semantics: Map< rule, [url1, url2, ...] > */
+ Map<String, List<Result>> map = new HashMap<String, List<Result>>();
+ String rule;
+ List<Result> list;
+ for (Result r : results) {
+ rule = r.getRuleName();
+ if (map.containsKey(rule)) {
+ list = map.get(rule);
+ list.add(r);
+ } else {
+ list = new ArrayList<Result>();
+ list.add(r);
+ map.put(rule, list);
+ }
+ }
+ return map;
+ }
- /**
- * Build a map of ruleName -> ruleDesc entries occurring in the given list of
- * results.
- *
- * @param results a list of results
- * @return a map associating rule names to rule descriptions
- */
- private Map<String, String> extractRuleDesc(List<Result> results) {
- Map<String, String> assoc = new HashMap<String, String>();
- for (Result r: results)
- if (!assoc.containsKey(r.getRuleName()))
- assoc.put(r.getRuleName(), r.getRuleDesc());
- return assoc;
- }
+ /**
+ * Build a map of ruleName -> ruleDesc entries occurring in the given list
+ * of results.
+ *
+ * @param results
+ * a list of results
+ * @return a map associating rule names to rule descriptions
+ */
+ private Map<String, String> extractRuleDesc(List<Result> results) {
+ Map<String, String> assoc = new HashMap<String, String>();
+ for (Result r : results)
+ if (!assoc.containsKey(r.getRuleName()))
+ assoc.put(r.getRuleName(), r.getRuleDesc());
+ return assoc;
+ }
- /**
+ /**
* Compute summary statistics from the results list. This includes number of
* passes and fails for each URL checked.
- *
- * @param results a list of results
+ *
+ * @param results
+ * a list of results
* @return a map representing the results sorted by rule name.
*/
private Map<String, int[]> computeSummaryStats(List<Result> results) {
- /** passFailMap semantics: Map<url, {#pass, #fail}> */
+ /** passFailMap semantics: Map<url, {#pass, #fail}> */
Map<String, int[]> passFailMap = new HashMap<String, int[]>();
String url;
int pass, fail;
@@ -334,26 +389,28 @@ public class Reporter {
Matcher matcher;
for (Result result : results) {
- pass = fail = 0;
- url = result.getURL();
- if (result.getType() == ResType.Pass) {
- // now we have to parse out how many tests passed
- matcher = numberPassedPattern.matcher(result.getMsg());
- if (matcher.find())
- pass = Integer.parseInt(matcher.group(1)); // throws exception if parse fails
- } else if (result.getType() == ResType.Error) {
- // each error result corresponds to one test
- fail = 1;
- }
+ pass = fail = 0;
+ url = result.getURL();
+ if (result.getType() == ResType.Pass) {
+ // now we have to parse out how many tests passed
+ matcher = numberPassedPattern.matcher(result.getMsg());
+ if (matcher.find())
+ pass = Integer.parseInt(matcher.group(1)); // throws
+ // exception if
+ // parse fails
+ } else if (result.getType() == ResType.Error) {
+ // each error result corresponds to one test
+ fail = 1;
+ }
- if (passFailMap.containsKey(url)) {
- passFailList = passFailMap.get(url);
- } else {
- passFailList = new int[] { 0, 0};
- passFailMap.put(url, passFailList);
- }
- passFailList[0] += pass;
- passFailList[1] += fail;
+ if (passFailMap.containsKey(url)) {
+ passFailList = passFailMap.get(url);
+ } else {
+ passFailList = new int[] { 0, 0 };
+ passFailMap.put(url, passFailList);
+ }
+ passFailList[0] += pass;
+ passFailList[1] += fail;
}
return passFailMap;
}