001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.plugins.core.testdetailsviewer.client;
021    
022    import com.google.gwt.gen2.table.override.client.FlexTable;
023    import com.google.gwt.gen2.table.override.client.FlexTable.FlexCellFormatter;
024    import com.google.gwt.i18n.client.Dictionary;
025    import com.google.gwt.user.client.DOM;
026    import com.google.gwt.user.client.ui.*;
027    import com.google.gwt.xml.client.Document;
028    import com.google.gwt.xml.client.Element;
029    import com.google.gwt.xml.client.NodeList;
030    import com.google.gwt.xml.client.XMLParser;
031    import org.sonar.gwt.Metrics;
032    import org.sonar.gwt.ui.ExpandCollapseLink;
033    import org.sonar.gwt.ui.Loading;
034    import org.sonar.wsclient.gwt.AbstractCallback;
035    import org.sonar.wsclient.gwt.Sonar;
036    import org.sonar.wsclient.services.Measure;
037    import org.sonar.wsclient.services.Resource;
038    import org.sonar.wsclient.services.ResourceQuery;
039    
040    public class TestsPanel extends Composite {
041    
042      private final Panel panel;
043      private Loading loading;
044    
045      public TestsPanel(Resource resource) {
046        panel = new VerticalPanel();
047        loading = new Loading();
048        panel.add(loading);
049        initWidget(panel);
050        setStyleName("gwt-TestDetailsPanel");
051        getElement().setId("gwt-TestDetailsPanel");
052        loadData(resource);
053      }
054    
055      private void loadData(Resource resource) {
056        ResourceQuery query = ResourceQuery.createForResource(resource, Metrics.TEST_DATA);
057        Sonar.getInstance().find(query, new TestDetailsMeasureHandler());
058      }
059    
060      private class TestDetailsMeasureHandler extends AbstractCallback<Resource> {
061    
062        public TestDetailsMeasureHandler() {
063          super(loading);
064        }
065    
066        @Override
067        protected void doOnResponse(Resource resource) {
068          loading.removeFromParent();
069          if (resource != null) {
070            Measure measure = resource.getMeasure(Metrics.TEST_DATA);
071            processTestDetails(measure.getData());
072          }
073        }
074    
075        private void processTestDetails(String testXMLData) {
076          Document parsed = XMLParser.parse(testXMLData);
077          NodeList testcasesXML = parsed.getElementsByTagName("testcase");
078    
079          Dictionary l10n = Dictionary.getDictionary("l10n");
080          FlexTable table = new FlexTable();
081          table.setStylePrimaryName("detailsTable");
082          table.setText(0, 0, "");
083          table.setText(0, 1, "");
084          table.setText(0, 2, l10n.get("unittest.duration"));
085          table.setText(0, 3, l10n.get("unittest.name"));
086          table.getCellFormatter().getElement(0, 1).setId("iCol");
087          table.getCellFormatter().getElement(0, 2).setId("dCol");
088          setRowStyle(0, table, "header", false);
089    
090          int rowCounter = 1;
091          for (int i = 0; i < testcasesXML.getLength(); i++) {
092            Element testcaseXML = (Element) testcasesXML.item(i);
093            String time = testcaseXML.getAttribute("time");
094            String name = testcaseXML.getAttribute("name");
095            String status = testcaseXML.getAttribute("status");
096            Element error = getFirstElement("error", testcaseXML);
097            Element failure = getFirstElement("failure", testcaseXML);
098            Element stackTrace = status.equals("error") ? error : failure;
099            renderTestDetails(rowCounter, i, status, stackTrace, name, time, table);
100            rowCounter += 2;
101          }
102          panel.add(table);
103        }
104    
105        private Element getFirstElement(String elementName, Element node) {
106          NodeList elements = node.getElementsByTagName(elementName);
107          return elements.getLength() > 0 ? (Element) elements.item(0) : null;
108        }
109    
110        private void renderTestDetails(int row, int testCounter, String testCaseStatus, Element stackTrace, String name, String timeMS, FlexTable table) {
111          HTML icon = new HTML("&nbsp;");
112          icon.setStyleName(testCaseStatus);
113          table.setWidget(row, 1, icon);
114          table.setText(row, 2, timeMS + " ms");
115    
116          table.setText(row, 3, name);
117          String style = (testCounter % 2 == 0) ? "odd" : "even";
118          setRowStyle(row, table, style, false);
119    
120          if (stackTrace != null) {
121            Panel stackPanel = new SimplePanel();
122            stackPanel.setStyleName("stackPanel");
123            stackPanel.getElement().setId("stack-panel" + name);
124            stackPanel.setVisible(false);
125            fillStackPanel(stackPanel, stackTrace);
126    
127            FlexCellFormatter frmt = (FlexCellFormatter) table.getCellFormatter();
128            frmt.setColSpan(row + 1, 1, 3);
129            table.setWidget(row + 1, 1, stackPanel);
130            table.setWidget(row, 0, new ExpandCollapseLink(stackPanel));
131            table.getCellFormatter().getElement(row, 0).setId("expandCollapseCol");
132            setRowStyle(row + 1, table, style, true);
133          }
134        }
135    
136        private void setRowStyle(int row, FlexTable table, String style, boolean isPanelRow) {
137          table.getCellFormatter().setStyleName(row, 0, style);
138          table.getCellFormatter().setStyleName(row, 1, style);
139          if (!isPanelRow) {
140            table.getCellFormatter().setStyleName(row, 2, style);
141            table.getCellFormatter().setStyleName(row, 3, style);
142          }
143          table.getCellFormatter().getElement(row, 0).setId("noLinkExpandCollapseCol");
144        }
145      }
146    
147      private void fillStackPanel(Panel p, Element stackElement) {
148        String message = stackElement.getAttribute("message");
149        if (message.length() > 0) {
150          p.getElement().setInnerHTML(escapeHtml(message) + "<br/>" + stackLineBreaks(stackElement.getFirstChild().getNodeValue()));
151        } else {
152          p.getElement().setInnerHTML(stackLineBreaks(stackElement.getFirstChild().getNodeValue()));
153        }
154      }
155    
156      private String escapeHtml(String maybeHtml) {
157        com.google.gwt.dom.client.Element div = DOM.createDiv();
158        div.setInnerText(maybeHtml);
159        return div.getInnerHTML();
160      }
161    
162      private String stackLineBreaks(String s) {
163        StringBuilder stack = new StringBuilder(256);
164        for (String el : s.split("\n")) {
165          stack.append(el.trim()).append("<br/>");
166        }
167        return stack.toString();
168      }
169    }