001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2011 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 }