001package org.w3.ldp.testsuite.reporter;
002
003import static org.rendersnake.HtmlAttributesFactory.NO_ESCAPE;
004import static org.rendersnake.HtmlAttributesFactory.class_;
005import static org.rendersnake.HtmlAttributesFactory.href;
006import static org.rendersnake.HtmlAttributesFactory.id;
007import static org.rendersnake.HtmlAttributesFactory.style;
008
009import java.io.BufferedWriter;
010import java.io.File;
011import java.io.FileWriter;
012import java.io.IOException;
013import java.io.StringWriter;
014import java.lang.reflect.Method;
015import java.util.ArrayList;
016import java.util.Arrays;
017import java.util.Date;
018import java.util.HashMap;
019import java.util.Iterator;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023
024import org.rendersnake.HtmlCanvas;
025import org.rendersnake.StringResource;
026import org.testng.IReporter;
027import org.testng.IResultMap;
028import org.testng.ISuite;
029import org.testng.ISuiteResult;
030import org.testng.ITestContext;
031import org.testng.ITestNGMethod;
032import org.testng.ITestResult;
033import org.testng.annotations.Test;
034import org.testng.internal.Utils;
035import org.testng.xml.XmlSuite;
036import org.w3.ldp.testsuite.BuildProperties;
037import org.w3.ldp.testsuite.LdpTestSuite;
038import org.w3.ldp.testsuite.annotations.SpecTest;
039import org.w3.ldp.testsuite.annotations.SpecTest.METHOD;
040import org.w3.ldp.testsuite.annotations.SpecTest.STATUS;
041
042/**
043 * HTML reporter for the LDP test suite. Takes the results of the test methods
044 * and displays the information to the user.
045 */
046public class LdpHtmlReporter implements IReporter {
047
048        private int passed = 0;
049        private int failed = 0;
050        private int skipped = 0;
051        private int mustPass = 0;
052        private int mayPass = 0;
053        private int shouldPass = 0;
054
055        private int total;
056        
057        private int mustSkip = 0;
058        private int shouldSkip = 0;
059        private int maySkip = 0;
060
061        private int mustFailed = 0;
062        private int shouldFailed;
063        private int mayFailed;
064
065        private IResultMap passedTests;
066        private IResultMap failedTests;
067        private IResultMap skippedTests;
068        
069        HashMap<String, Integer> passClasses;
070        HashMap<String, Integer> failClasses;
071        HashMap<String, Integer> skipClasses;
072
073        private HtmlCanvas html;
074        
075        private String outputName = "ldp-testsuite";
076
077        private static final String PASS = "Passed";
078        private static final String FAIL = "Failed";
079        private static final String SKIP = "Skipped";
080
081        private List<ITestNGMethod> indirect = new ArrayList<ITestNGMethod>();
082        
083        private static StringWriter graphs = new StringWriter();
084        
085        private static ArrayList<String> colors = new ArrayList<String>(Arrays.asList("#42d992", "#1cbfbb", "#1d0b4e", "#bf1c56"));
086
087        private String outputDirectory = LdpTestSuite.OUTPUT_DIR;
088
089        public void setOutputDirectory(String outputDirectory) {
090                this.outputDirectory = outputDirectory;
091        }
092
093        public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
094                try {
095                        for (ISuite suite : suites) {
096                                html = new HtmlCanvas();
097                                html.html().head();
098
099                                writeCss();
100                                html.title().content(LdpTestSuite.NAME + " Report")._head()
101                                                .body();
102                                html.h1().content(LdpTestSuite.NAME + " Summary");
103
104                                // Getting the results for the said suite
105                                Map<String, ISuiteResult> suiteResults = suite.getResults();
106
107                                for (ISuiteResult sr : suiteResults.values()) {
108
109                                        ITestContext tc = sr.getTestContext();
110                                        passedTests = tc.getPassedTests();
111                                        failedTests = tc.getFailedTests();
112                                        skippedTests = tc.getSkippedTests();
113                                }
114                                
115                                // Initialize variables for charts
116                                passClasses = getClasses(passedTests);
117                                failClasses = getClasses(failedTests);
118                                skipClasses = getClasses(skippedTests);
119                                
120                                html.h2().content("Overall Coverage Bar Charts");
121                                
122                                html.span(class_("chartStart"));
123                                html.label(class_("label")).b().write("Test Results by Specification Requirement")._b()._label();
124                                html.div(class_("barChart").id("overallChart1"))._div(); // svg chart
125                                writePassFailLegend();
126                                
127                                html._span();
128                                
129                                html.span(class_("chartStart"));
130                                html.label(class_("label")).b().write("Test Results by Test Class")._b()._label();
131                                html.div(class_("barChart").id("resourcesChart"))._div();
132                                writeTestClassLegend();
133                                html._span();
134                                
135                                html.br();
136                                generateOverallSummaryReport(suites, "summary");
137                                displayGroupsInfo(suites);
138                                displayMethodsSummary(suites);
139                                toTop();
140                                generateMethodDetails(suites);
141
142                                html.script().content(
143                                                StringResource.get("/raphael/raphael-min.js"), NO_ESCAPE);
144                                html.script().content(
145                                                StringResource.get("/prototype/prototype.js"), NO_ESCAPE);
146                                html.script().content(
147                                                StringResource.get("/grafico/grafico-min.js"), NO_ESCAPE);
148                                
149                                writeOverallBarChart();
150                                writeResourcesBarChart();
151                
152                                html.write(graphs.toString(), NO_ESCAPE);
153                                html._body()._html();
154
155                                // send html to a file
156                                createWriter(this.outputDirectory, html.toHtml(), outputName);
157                        }
158                } catch (IOException e) {
159                        e.printStackTrace();
160                }
161        }
162        
163        public void setTitle(String title) {
164                this.outputName = title;
165        }
166
167        private void writeCss() throws IOException {
168
169                html.style().write(StringResource.get("reportStyle.css"), NO_ESCAPE)
170                                ._style();
171        }
172
173        private void createWriter(String directory, String output, String title) {
174                BufferedWriter writer = null;
175                new File(directory).mkdirs();
176                try {
177                        writer = new BufferedWriter(new FileWriter(directory
178                                        + "/" + title + "-execution-report.html"));
179                        writer.write(output);
180
181                } catch (IOException e) {
182                } finally {
183                        try {
184                                if (writer != null)
185                                        writer.close();
186                        } catch (IOException e) {
187                        }
188                }
189        }
190
191        private void generateOverallSummaryReport(List<ISuite> suites, String id)
192                        throws IOException {
193                html.table(class_("summary"));
194                Date date = new Date();
195                for (ISuite suite : suites) {
196                        // Getting the results for the said suite
197                        Map<String, ISuiteResult> suiteResults = suite.getResults();
198
199                        for (ISuiteResult sr : suiteResults.values()) {
200
201                                ITestContext tc = sr.getTestContext();
202
203                                Iterator<ITestResult> passedResults = tc.getPassedTests()
204                                                .getAllResults().iterator();
205                                while (passedResults.hasNext()) {
206                                        ITestResult result = passedResults.next();
207
208                                        try {
209                                                Method m = result.getMethod().getConstructorOrMethod()
210                                                                .getMethod();
211                                                String[] groups = m.getAnnotation(Test.class).groups();
212                                                for (int i = 0; i < groups.length; i++) {
213                                                        if (groups[i].equals("MUST"))
214                                                                mustPass++;
215                                                        if (groups[i].equals("MAY"))
216                                                                mayPass++;
217                                                        if (groups[i].equals("SHOULD"))
218                                                                shouldPass++;
219
220                                                }
221                                        } catch (SecurityException e) {
222                                                e.printStackTrace();
223                                        }
224
225                                }
226                                Iterator<ITestResult> failedResults = tc.getFailedTests()
227                                                .getAllResults().iterator();
228                                while (failedResults.hasNext()) {
229                                        ITestResult result = failedResults.next();
230
231                                        try {
232                                                Method m = result.getMethod().getConstructorOrMethod()
233                                                                .getMethod();
234                                                String[] groups = m.getAnnotation(Test.class).groups();
235                                                for (int i = 0; i < groups.length; i++) {
236                                                        if (groups[i].equals("MUST"))
237                                                                mustFailed++;
238                                                        if (groups[i].equals("SHOULD"))
239                                                                shouldFailed++;
240                                                        if (groups[i].equals("MAY"))
241                                                                mayFailed++;
242                                                }
243                                        } catch (SecurityException e) {
244                                                e.printStackTrace();
245                                        }
246
247                                }
248                                Iterator<ITestResult> skippedResults = tc.getSkippedTests()
249                                                .getAllResults().iterator();
250                                while (skippedResults.hasNext()) {
251                                        ITestResult result = skippedResults.next();
252
253                                        try {
254                                                Method m = result.getMethod().getConstructorOrMethod()
255                                                                .getMethod();
256                                                String[] groups = m.getAnnotation(Test.class).groups();
257                                                for (int i = 0; i < groups.length; i++) {
258                                                        if (groups[i].equals("MUST"))
259                                                                mustSkip++;
260                                                        if (groups[i].equals("MAY"))
261                                                                maySkip++;
262                                                        if (groups[i].equals("SHOULD"))
263                                                                shouldSkip++;
264
265                                                }
266                                        } catch (SecurityException e) {
267                                                e.printStackTrace();
268                                        }
269
270                                }
271                                passed = tc.getPassedTests().getAllResults().size();
272                                failed = tc.getFailedTests().getAllResults().size();
273                                skipped = tc.getSkippedTests().getAllResults().size();
274                        }
275                        total = passed + failed + skipped;
276                        generateSummaryTableStart(date, suite.getName());
277                        generateSummaryTable();
278                        html._table();
279                }
280
281        }
282
283        private void generateSummaryTableStart(Date date, String suiteName)
284                        throws IOException {
285                html.tr().th().content("Test Suite Name");
286                html.th().content("Revision");
287                html.th().content("Report Date");
288                html.th().content("Skipped Tests");
289                html.th().content("MUST Requirements");
290                html.th().content("SHOULD Requirements");
291                html.th().content("MAY Requirements");
292                html._tr();
293
294                html.tr(class_("alt")).td().content(suiteName);
295                final String commit = BuildProperties.getRevision();
296                if (commit == null) {
297                        html.td().content("<UNKNOWN>");
298                } else {
299                        html.td().a(href("https://github.com/w3c/ldp-testsuite/commit/" + commit)).content(commit)._td();
300                }
301                html.td().content(date.toString());
302        }
303
304        private void generateSummaryTable()
305                        throws IOException {
306                printSkipCellResult();
307                printReqCellResult(mustPass, mustFailed, mustSkip);
308                printReqCellResult(shouldPass, shouldFailed, shouldSkip);
309                printReqCellResult(mayPass, mayFailed, maySkip);
310                html._tr();
311        }
312
313        private void printSkipCellResult() throws IOException {
314                if (skipped == 0)
315                        html.td().i().write("No tests of this type called")._i()._td();
316                else {
317                        html.td();
318                        html.write("(");
319                        html.b().write(skipped + "/" + total)._b();
320                        html.write(") ");
321                        html.write("of the total tests.")._td();
322                }
323                
324        }
325
326        private void printReqCellResult(int passed, int failed, int skipped) throws IOException {
327                int total = passed + failed + skipped;
328                
329                html.td().b().write(passed + "/" + total)._b();
330                html.write(" Passed");
331                
332                html.br().b().write(failed + "/" + total)._b();
333                html.write(" Failed");
334                
335                html.br().b().write(skipped + "/" + total)._b();        
336                html.write(" Skipped"); 
337                html._td();
338                
339        }
340
341        private void displayGroupsInfo(List<ISuite> suite) throws IOException {
342                for (ISuite testSuite : suite) {
343                        Map<String, ISuiteResult> tests = testSuite.getResults();
344                        for (ISuiteResult results : tests.values()) {
345                                ITestContext overview = results.getTestContext();
346                                String[] excluded = overview.getExcludedGroups();
347                                String[] included = overview.getIncludedGroups();
348                                generateList(included,
349                                                "Included Groups for " + testSuite.getName());
350                                generateList(excluded,
351                                                "Excluded Groups for " + testSuite.getName());
352                        }
353                }
354        }
355
356        private void generateList(String[] list, String title) throws IOException {
357                html.h2().write(title)._h2();
358                if (list.length == 0) {
359                        html.div(style("padding-left:2em")).i()
360                                        .content("No groups of this type found in the test suite")
361                                        ._div();
362                } else {
363                        html.ul();
364                        for (String group : list) {
365                                html.li().content(group);
366                        }
367                        html._ul();
368                }
369        }
370
371        private void displayMethodsSummary(List<ISuite> suites) throws IOException {
372                for (ISuite suite : suites) {
373                        Map<String, ISuiteResult> r = suite.getResults();
374                        for (ISuiteResult r2 : r.values()) {
375                                ITestContext testContext = r2.getTestContext();
376                                makeMethodsList(testContext);
377                        }
378                }
379        }
380
381        private void makeMethodsList(ITestContext testContext) throws IOException {
382                IResultMap failed = testContext.getFailedTests();
383                IResultMap passed = testContext.getPassedTests();
384                IResultMap skipped = testContext.getSkippedTests();
385
386                html.h1(class_("center")).content("Methods called");
387                html.a(href("#Skipped")).write("Go To Skipped Tests").br()._a();
388                html.a(href("#Passed")).write("Go To Passed Tests").br()._a();
389                html.a(href("#Indirect")).write("Go To Indirect Tests").br()._a();
390                html.br();
391                
392                makeMethodSummaryTable(failed, "Failed");
393                html.br();
394                toTop();
395                html.br();
396                makeMethodSummaryTable(skipped, "Skipped");
397                html.br();
398                toTop();
399                html.br();
400                makeMethodSummaryTable(passed, "Passed");
401                html.br();
402                toTop();
403                makeIndirectSummaryTable();
404                html.br();
405
406        }
407
408        private void makeMethodSummaryTable(IResultMap tests, String title)
409                        throws IOException {
410                html.table(class_("indented"));
411                html.tr().th(class_(title)).a(id((title))).write(title + " Test Cases")._a()._th();
412                html.th(class_(title)).content("Groups");
413                html.th(class_(title)).content("Description of Test Method")._tr();
414                for (ITestResult result : tests.getAllResults()) {
415                        ITestNGMethod method = result.getMethod();
416                        if(method.getConstructorOrMethod().getMethod().getAnnotation(SpecTest.class).testMethod().equals(METHOD.INDIRECT)){
417                                // do nothing, will add this in a separate table that specifically defines indirect tests
418                                indirect.add(method);
419                                
420                        } else {
421                                List<String> groups = Arrays.asList(method.getGroups());
422                                if (groups.contains("MUST") && result.getStatus() == ITestResult.FAILURE) {
423                                        html.tr(class_("critical"));
424                                } else {
425                                        html.tr();
426                                }
427                                
428                                String normalizedName = AbstractEarlReporter.createTestCaseName(
429                                                method.getTestClass().getName(), method.getMethodName());
430                                html.td()
431                                        .a(href("#" + method.getTestClass().getName() + "_"
432                                                        + method.getMethodName()))
433                                        .write(normalizedName)._a();
434                                if (method.getConstructorOrMethod().getMethod().getAnnotation(SpecTest.class).approval() == STATUS.WG_PENDING) {
435                                        html.br().b().em().write("WG Approval Pending")._em()._b();
436                                }
437                                html._td();
438                                html.td().content(Arrays.toString(method.getGroups()));
439                                html.td().content(
440                                        (method.getDescription() != null ? method.getDescription()
441                                                        : "No Description found"));
442                                html._tr();
443                        }
444                }
445                html._table();
446        }
447        
448        private void makeIndirectSummaryTable() throws IOException {
449                html.table(class_("indented"));
450                html.tr().th().a(id(("Indirect"))).write("Indirectly Tested Test Cases")._a()._th();
451                html.th().content("Overall Test Result");
452                html.th().content("Description of Test Method")._tr();
453
454                for(ITestNGMethod method : indirect){
455                        html.tr();
456                        String normalizedName = AbstractEarlReporter.createTestCaseName(
457                                        method.getTestClass().getName(), method.getMethodName());
458                        html.td()
459                                .a(href("#" + method.getTestClass().getName() + "_"
460                                + method.getMethodName())).write(normalizedName)._a()._td();
461                        ArrayList<String> result = new ArrayList<String>();
462                        Method m = method.getConstructorOrMethod().getMethod();
463                        SpecTest spec = m.getAnnotation(SpecTest.class);
464                        for(Class<?> className : spec.coveredByTests()){
465                                Method[] classMethod = className.getDeclaredMethods();
466                                for(Method methodName : classMethod) {
467                                        if(methodName.getAnnotation(Test.class) != null) {
468                                                String group = Arrays.toString(methodName.getAnnotation(Test.class).groups()); 
469                                                for(String groupCover : spec.coveredByGroups()) {
470                                                        if(group.contains(groupCover) && !methodName.getName().contains("Conforms")) {
471                                                                result.add(findTestResult(methodName.getName()));
472                                                        }                                                               
473                                                }
474                                        }
475                                }
476                        }
477                        // evaluate the testResults for the Indirect Test
478                        // if one of the tests fails, then the entire indirect test fails
479                        // if there are only pass and skipped tests (none failed), then it passes
480                        // if there are only skipped (none passed or failed), then it is skipped
481                        if(result.size() > 0){
482                                if(result.contains(FAIL))
483                                        html.td(class_("Failed")).content(FAIL);
484                                else if(result.contains(PASS) && !result.contains(FAIL))
485                                        html.td(class_("Passed")).content(PASS);
486                                else if(result.contains(SKIP) && !result.contains(FAIL) && !result.contains(PASS))
487                                        html.td(class_("Skipped")).content(SKIP);
488                        }
489                        html.td().content(
490                                        (method.getDescription() != null ? method.getDescription()
491                                                        : "No Description found"));
492                        html._tr();
493                }
494                
495                html._table();
496        }
497
498        private void generateMethodDetails(List<ISuite> suites) throws IOException {
499                html.h1().content("Test Method Details");
500                for (ISuite suite : suites) {
501                        Map<String, ISuiteResult> r = suite.getResults();
502                        for (ISuiteResult r2 : r.values()) {
503                                ITestContext testContext = r2.getTestContext();
504
505                                generateDetail(testContext.getFailedTests());
506                                generateDetail(testContext.getSkippedTests());
507                                generateDetail(testContext.getPassedTests());
508                        }
509                }
510        }
511
512        private void generateDetail(IResultMap tests) throws IOException {
513                for (ITestResult m : tests.getAllResults()) {
514                        ITestNGMethod method = m.getMethod();
515                        String normalizedName = AbstractEarlReporter.createTestCaseName(
516                                        m.getTestClass().getName(), method.getMethodName());
517                        html.h2()
518                                        .a(id(m.getTestClass().getName() + "_"
519                                                        + method.getMethodName()))
520                                        .write(normalizedName)._a()._h2();
521                        getAdditionalInfo(m, method);
522                        html.p(class_("indented"))
523                                        .b()
524                                        .write("Description: ")
525                                        ._b()
526                                        .write((method.getDescription() != null ? method
527                                                        .getDescription()
528                                                        : "No description for this test method found"))
529                                        ._p();
530                        String groups = "";
531                        for (String group : method.getGroups()) {
532                                groups += group + " ";
533                        }
534                        html.p(class_("indented")).b().write("Requirement Level: ")._b()
535                                        .write(groups)._p();
536
537                        toTop();
538                
539                }       
540
541        }
542
543        private void getAdditionalInfo(ITestResult m, ITestNGMethod method)
544                        throws IOException {
545                if (m.getThrowable() != null) {
546                        Throwable thrown = m.getThrowable();
547                        String exception = thrown.getClass().getName();
548                        if (exception.contains("Skip")) {
549                                createSkipExceptionTable(thrown);
550                        } else {
551                                createThrownTable(thrown);
552                        }
553                }
554
555                if (m.getParameters() != null && m.getParameters().length != 0) {
556                        Object[] params = m.getParameters();
557                        String parameters = "";
558                        for (Object p : params) {
559                                if (p != null)
560                                        parameters += p.toString() + " ";
561                        }
562                        html.p(class_("indented")).b().write("Parameters: ")._b()
563                                        .write(parameters)._p();
564                }
565
566                if (m.getMethod().getConstructorOrMethod().getMethod()
567                                .getAnnotation(SpecTest.class) != null) {
568                        SpecTest testLdp = m.getMethod().getConstructorOrMethod().getMethod()
569                                        .getAnnotation(SpecTest.class);
570                        if(!testLdp.comment().equals(""))
571                                html.p(class_("note")).b().write("NOTE: ")._b()
572                                        .write(testLdp.comment())._p();
573                        if(testLdp.steps().length != 0)
574                                writeSteps(testLdp.steps(), m.getName());
575                        if(testLdp.coveredByTests().length > 0 && testLdp.coveredByGroups().length > 0){
576                                html.p().b().content("Test Case is covered Indirectly by the following:")._p();
577                                html.ul();
578                                for(Class<?> className : testLdp.coveredByTests()){
579                                        Method[] classMethod = className.getDeclaredMethods();
580                                        for(Method methodName : classMethod) {
581                                                if(methodName.getAnnotation(Test.class) != null) {
582                                                        String group = Arrays.toString(methodName.getAnnotation(Test.class).groups()); 
583                                                        for(String groupCover : testLdp.coveredByGroups()) {
584                                                                if(group.contains(groupCover) && !methodName.getName().contains("Conforms")) {
585                                                                        String testCaseName = methodName.getDeclaringClass().getSimpleName();
586                                                                        String normalizedName = AbstractEarlReporter.createTestCaseName(testCaseName, methodName.getName());
587                                                                        html.li().b().write(normalizedName)._b();
588                                                                        html.write(" - [Test " + findTestResult(methodName.getName()) + "]");
589                                                                        html._li();
590                                                                }                                                               
591                                                        }
592                                                }
593                                        }
594                                }
595                                html._ul();
596                        }
597                        html.p(class_("indented")).b().write("Reference URI: ")._b()
598                                        .a(href(testLdp.specRefUri())).write(testLdp.specRefUri())._a()._p();
599                }
600                
601        }
602
603        private String  findTestResult(String methodName) {
604                Iterator<ITestNGMethod> passed = passedTests.getAllMethods().iterator();
605                while(passed.hasNext()){
606                        ITestNGMethod method = passed.next();
607                        if(method.getMethodName().equals(methodName)){
608                                return PASS;
609                        }
610                }
611                
612                Iterator<ITestNGMethod> skipped = skippedTests.getAllMethods().iterator();
613                while(skipped.hasNext()){
614                        ITestNGMethod method = skipped.next();
615                        if(method.getMethodName().equals(methodName)){
616                                return SKIP;
617                        }
618                }
619                
620                Iterator<ITestNGMethod> failed = failedTests.getAllMethods().iterator();
621                while(failed.hasNext()){
622                        ITestNGMethod method = failed.next();
623                        if(method.getMethodName().equals(methodName)){
624                                return FAIL;
625                        }
626                }
627                
628                return null;
629                
630        }
631
632        private void writeSteps(String[] steps, String title) throws IOException {
633                html.p().content("How to Run " + title);
634                html.ul();
635                for(String step : steps)
636                        html.li().content(step);
637                html._ul();
638        }
639
640        private void createSkipExceptionTable(Throwable thrown) throws IOException {
641                html.table(class_("indented"));
642                html.tr(class_("center")).th(class_("Skipped"))
643                                .content("[SKIPPED TEST]")._tr();
644                html.tr().td().content(thrown.getMessage())._tr();
645                html._table();
646
647        }
648
649        private void createThrownTable(Throwable thrown) throws IOException {
650                html.table(class_("indented"));
651                html.tr(class_("center")).th(class_("Failed")).content("[FAILED TEST]")
652                                ._tr();
653                html.tr().td(class_("throw")).content(Utils.stackTrace(thrown, false)[0])._tr();
654
655                html._table();
656
657        }
658
659        private void toTop() throws IOException {
660                html.p(class_("totop")).a(href("#top")).content("Back to Top")._p();
661        }
662        private void writeOverallBarChart() throws IOException {
663                graphs.write("<script>");
664                graphs.write("Event.observe(window, 'load', function() {");
665                graphs.write("var summary_bar = new Grafico.StackedBarGraph($('overallChart1'),");
666                graphs.write("{ passed: [ " + mustPass + ", " + shouldPass + ", "
667                                + mayPass + " ],");
668                graphs.write("failed: [" + mustFailed + ", " + shouldFailed + ", "
669                                + mayFailed + " ], ");
670                graphs.write("skipped: [" + mustSkip + ", " + shouldSkip + ", " + maySkip + " ]");
671                graphs.write("},");
672                graphs.write("{ labels: [ \"MUST\", \"SHOULD\", \"MAY\" ],");
673                graphs.write("colors: { passed: '#a2bf2f', failed: '#a80000', skipped: '#606060' },");
674                graphs.write("hover_color: \"#ccccff\",");
675
676                graphs.write("datalabels: { passed: [ \"" + mustPass + " Passed\", \""
677                                + shouldPass + " Passed\", \"" + mayPass + " Passed\"],");
678                graphs.write("failed: [ \"" + mustFailed + " Failed\" , \""
679                                + shouldFailed + " Failed\" , \"" + mayFailed
680                                + " Failed\" ],");
681                graphs.write("skipped: [ \"" + mustSkip + " Skipped\", \"" + shouldSkip
682                                + " Skipped\", \"" + maySkip + " Skipped\" ]");
683                graphs.write("},");
684
685                graphs.write("}); });");
686                graphs.write("</script>");
687        }
688
689        private void writeResourcesBarChart() throws IOException {
690
691                graphs.write("<script>");
692                graphs.write("Event.observe(window, 'load', function() {");
693                graphs.write("var resource_bar = new Grafico.StackedBarGraph($('resourcesChart'),");
694                writeChartValues(passClasses, failClasses, skipClasses);
695                graphs.write("{ labels: [ \"Passed\", \"Failed\", \"Skipped\" ],");
696                graphs.write("hover_color: \"#ccccff\",");
697                writeChartColors(passClasses);
698                writeChartLabels(passClasses, failClasses, skipClasses);
699                graphs.write("}); });");
700                graphs.write("</script>");
701        }
702        
703        private void writePassFailLegend() throws IOException {
704                html.write("<svg id=\"passFailLegend\" width=\"150\" height=\"250\">", NO_ESCAPE);
705                html.write("<rect width=\"15\" height=\"15\" x=\"0\" y=\"0\" style=\"fill:#a2bf2f\"/>", NO_ESCAPE);
706                html.write("<text x=\"20\" y=\"13\" fill=\"black\">Passed Tests</text>", NO_ESCAPE);
707                html.write("<rect width=\"15\" height=\"15\" x=\"0\" y=\"20\" style=\"fill:#a80000\"/>", NO_ESCAPE);
708                html.write("<text x=\"20\" y=\"33\" fill=\"black\">Failed Tests</text>", NO_ESCAPE);
709                html.write("<rect width=\"15\" height=\"15\" x=\"0\" y=\"40\" style=\"fill:#606060\"/>", NO_ESCAPE);
710                html.write("<text x=\"20\" y=\"53\" fill=\"black\">Skipped Tests</text>", NO_ESCAPE);
711                html.write("</svg>");
712        }
713        
714        private void writeTestClassLegend() throws IOException {
715                html.write("<svg id=\"testClassLegend\" width=\"175\" height=\"250\">", NO_ESCAPE);
716                
717                Set<String> names = passClasses.keySet();
718                Iterator<String> label = names.iterator();
719                int textY = 13;
720                int rectY = 0;
721                int getColor = 0;
722                
723                while (label.hasNext() && getColor != colors.size()) {
724                        String className = label.next();
725                        html.write("<rect width=\"15\" height=\"15\" x=\"0\" y=\"" + rectY
726                                        + "\" style=\"fill:" + colors.get(getColor) + "\"/>",
727                                        NO_ESCAPE);
728                        html.write("<text x=\"20\" y=\"" + textY + "\" fill=\"black\">"
729                                        + className + "</text>", NO_ESCAPE);
730
731                        textY += 20;
732                        rectY += 20;
733                        getColor++;
734                
735                }
736                html.write("</svg>");
737        }
738        
739        private void writeChartLabels(HashMap<String, Integer> passClasses,
740                        HashMap<String, Integer> failClasses,
741                        HashMap<String, Integer> skipClasses) {
742                graphs.write("datalabels: {");
743                Set<String> names = passClasses.keySet();
744                Iterator<String> label = names.iterator();
745                while (label.hasNext()) {
746                        String className = label.next();
747                        graphs.write(className + ": [ \"" + passClasses.get(className)
748                                        + " " + className + "\", \"" + failClasses.get(className)
749                                        + " " + className + "\", \"" + skipClasses.get(className)
750                                        + " " + className + "\" ]");
751                        if (label.hasNext())
752                                graphs.write(",");
753                }
754                graphs.write("},");
755        }
756        
757        private void writeChartColors(HashMap<String, Integer> passClasses) {
758                graphs.write("colors: {");
759                Set<String> names = passClasses.keySet();
760                Iterator<String> label = names.iterator();
761                int getColor = 0;
762                while (label.hasNext() && getColor != colors.size()) {
763                        String className = label.next();
764
765                        if (label.hasNext())
766                                graphs.write(className + ": '" + colors.get(getColor) + "', ");
767                        else
768                                graphs.write(className+ ": '" + colors.get(getColor) + "' },");
769                        getColor++;
770                }
771        }
772
773        private void writeChartValues(HashMap<String, Integer> passClasses,
774                        HashMap<String, Integer> failClasses,
775                        HashMap<String, Integer> skipClasses) {
776                graphs.write("{");
777                Set<String> names = passClasses.keySet();
778                Iterator<String> label = names.iterator();
779                while (label.hasNext()) {
780                        String className = label.next();
781
782                        graphs.write(className + ": [" + passClasses.get(className) + ", "
783                                        + failClasses.get(className) + ", "
784                                        + skipClasses.get(className) + " ]");
785                        if (label.hasNext())
786                                graphs.write(",");
787                }
788                graphs.write(" },");
789        }
790
791        private HashMap<String, Integer> getClasses(IResultMap tests) {
792                HashMap<String, Integer> classes = new HashMap<String, Integer>();
793                Iterator<ITestResult> results = tests.getAllResults().iterator();
794                while (results.hasNext()) {
795                        String name = results.next().getTestClass().getName().toString();
796                        name = name.substring(name.lastIndexOf(".") + 1);
797
798                        if (!classes.containsKey(name))
799                                classes.put(name, 1);
800                        else
801                                classes.put(name, classes.get(name) + 1);
802                }
803                return classes;
804        }
805
806}