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 */
020package org.sonar.plugins.core.testdetailsviewer.client;
021
022import com.google.gwt.gen2.table.override.client.FlexTable;
023import com.google.gwt.gen2.table.override.client.FlexTable.FlexCellFormatter;
024import com.google.gwt.i18n.client.Dictionary;
025import com.google.gwt.user.client.DOM;
026import com.google.gwt.user.client.ui.*;
027import com.google.gwt.xml.client.Document;
028import com.google.gwt.xml.client.Element;
029import com.google.gwt.xml.client.NodeList;
030import com.google.gwt.xml.client.XMLParser;
031import org.sonar.gwt.Metrics;
032import org.sonar.gwt.ui.ExpandCollapseLink;
033import org.sonar.gwt.ui.Loading;
034import org.sonar.wsclient.gwt.AbstractCallback;
035import org.sonar.wsclient.gwt.Sonar;
036import org.sonar.wsclient.services.Measure;
037import org.sonar.wsclient.services.Resource;
038import org.sonar.wsclient.services.ResourceQuery;
039
040public 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}