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(" ");
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 }