blob: c1adfb97bbae4a96cc29482f7cb6dc8aa9d45820 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2016 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.reporting.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.rcptt.ecl.core.ProcessStatus;
import org.eclipse.rcptt.ecl.gen.ast.ScriptProcessStatus;
import org.eclipse.rcptt.reporting.ItemKind;
import org.eclipse.rcptt.reporting.Q7Info;
import org.eclipse.rcptt.reporting.Q7Statistics;
import org.eclipse.rcptt.reporting.ReportingFactory;
import org.eclipse.rcptt.reporting.core.IQ7ReportConstants;
import org.eclipse.rcptt.reporting.core.SimpleSeverity;
import org.eclipse.rcptt.reporting.util.internal.Plugin;
import org.eclipse.rcptt.sherlock.core.model.sherlock.EclipseStatus;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Event;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.EventSource;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Node;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Report;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.ReportFactory;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Screenshot;
import org.eclipse.rcptt.sherlock.core.model.sherlock.report.Snaphot;
import org.eclipse.rcptt.sherlock.core.reporting.SimpleReportGenerator;
import org.eclipse.rcptt.tesla.core.info.AdvancedInformation;
import org.eclipse.rcptt.tesla.core.utils.AdvancedInformationGenerator;
import org.eclipse.rcptt.verifications.status.EVerificationStatus;
import org.eclipse.rcptt.verifications.status.VerificationStatusData;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
public class ReportUtils {
private static final Function<? super VerificationStatusData, String> datumToMessage = new Function<VerificationStatusData, String>() {
@Override
public String apply(VerificationStatusData input) {
return input.getMessage();
}
};
public static Q7Statistics calculateStatistics(Iterable<Report> iterator) {
return calculateStatistics(iterator.iterator());
}
public static Q7Statistics calculateStatistics(Iterator<Report> iterator) {
Q7Statistics statistics = ReportingFactory.eINSTANCE.createQ7Statistics();
long startTime = Long.MAX_VALUE;
long endTime = Long.MIN_VALUE;
long totalTime = 0;
int total = 0;
int failed = 0;
int passed = 0;
int skipped = 0;
while (iterator.hasNext()) {
Report report = iterator.next();
if (report == null) {
continue;
}
Node localRoot = report.getRoot();
if (localRoot == null) {
Plugin.UTILS.log(new NullPointerException("Report should always have root"));
continue;
}
total += 1;
Q7Info q7info = (Q7Info) localRoot.getProperties().get(IQ7ReportConstants.ROOT);
SimpleSeverity severity = SimpleSeverity.create(q7info);
switch (severity) {
case CANCEL:
skipped++;
break;
case ERROR:
failed++;
break;
case OK:
passed++;
break;
}
startTime = Math.min(startTime, localRoot.getStartTime());
endTime = Math.max(endTime, localRoot.getEndTime());
totalTime += (localRoot.getDuration());
}
statistics.setTime((int) totalTime);
statistics.setTotal(total);
statistics.setFailed(failed);
statistics.setPassed(passed);
statistics.setSkipped(skipped);
return statistics;
}
/**
* Create complex report from individual parts
*
*
* @param session
* @return
*/
public static Report combineReports(Iterable<Report> reports, int len, IProgressMonitor monitor) {
monitor.beginTask("Combine Q7 testcase reports", len * 10);
Report report = ReportFactory.eINSTANCE.createReport();
Node rootNode = ReportFactory.eINSTANCE.createNode();
report.setRoot(rootNode);
Iterator<Report> iterator = reports.iterator();
while (iterator.hasNext()) {
Report copy = iterator.next();
// report.getSources().addAll(copy.getSources());
Map<EventSource, EventSource> toUpdate = new HashMap<EventSource, EventSource>();
EList<EventSource> copySources = copy.getSources();
EList<EventSource> sources = report.getSources();
List<EventSource> repSources = new ArrayList<EventSource>();
for (EventSource source : copySources) {
boolean exist = false;
for (EventSource rootSource : sources) {
if (compareSources(source, rootSource)) {
toUpdate.put(source, rootSource);
exist = true;
break;
}
}
if (!exist) {
repSources.add(source);
}
}
sources.addAll(repSources);
for (EventSource source : toUpdate.keySet()) {
updateSource(copy, source, toUpdate.get(source));
}
rootNode.getChildren().add(copy.getRoot());
monitor.worked(10);
}
monitor.done();
return report;
}
private static boolean compareSources(EventSource source, EventSource rootSource) {
if (source == null || rootSource == null) {
return false;
}
EMap<String, EObject> properties = source.getProperties();
EMap<String, EObject> properties2 = rootSource.getProperties();
if (properties.size() != properties2.size()) {
return false;
}
Set<String> keySet = properties.keySet();
for (String s : keySet) {
EObject v1 = properties.get(s);
EObject v2 = properties2.get(s);
if (!EcoreUtil.equals(v1, v2)) {
return false;
}
}
return true;
}
private static void updateSource(Report copy, EventSource source, EventSource rootSource) {
TreeIterator<EObject> contents = copy.eAllContents();
List<Event> eventsToUpdate = new ArrayList<Event>();
while (contents.hasNext()) {
EObject next = contents.next();
if (next instanceof Event) {
EventSource eSource = ((Event) next).getSource();
if (eSource != null) {
if (source.equals(eSource)) {
eventsToUpdate.add((Event) next);
}
}
}
}
for (Event event : eventsToUpdate) {
event.setSource(rootSource);
}
}
public static String getScenarioTags(Node item) {
EList<Node> children = item.getChildren();
for (Node node : children) {
Q7Info info = (Q7Info) node.getProperties().get(IQ7ReportConstants.ROOT);
if (info != null && info.getType() == ItemKind.SCRIPT) {
return info.getTags();
}
}
return "";
}
public static String getScenarioDescription(Node item) {
EList<Node> children = item.getChildren();
for (Node node : children) {
Q7Info info = (Q7Info) node.getProperties().get(IQ7ReportConstants.ROOT);
if (info != null && info.getType() == ItemKind.SCRIPT) {
return info.getDescription();
}
}
return null;
}
/**
* Is it a 'trace' or 'take-screenshot' command?
*/
public static boolean isLoggedCommand(String name) {
return isTraceCommand(name) || isScreenshotCommand(name);
}
public static boolean isTraceCommand(String name) {
return name.equals("trace");
}
public static boolean isScreenshotCommand(String name) {
return name.equals("take-screenshot");
}
public static final String formatTime(long duration) {
return String.format("%d.%03d", duration / 1000, duration % 1000);
}
public static String replaceEscapeSymbols(String text) {
if (text == null) {
return null;
}
return text.replace("\"", "&quot;").replace("<", "&lt;").replace(">", "&gt;");
}
public static List<Screenshot> findScreenshots(Node node) {
List<Screenshot> result = new ArrayList<Screenshot>();
collectScreenshots(node, result);
return result;
}
private static void collectScreenshots(Node node, List<Screenshot> acc) {
for (Snaphot snapshot : node.getSnapshots()) {
if (snapshot.getData() instanceof Screenshot) {
acc.add((Screenshot) snapshot.getData());
}
}
for (Node child : node.getChildren()) {
collectScreenshots(child, acc);
}
}
public static String getFailMessage(Node item) {
Q7Info current = (Q7Info) item.getProperties().get(IQ7ReportConstants.ROOT);
if (current == null) {
return "Non Q7 report node";
}
return getFailMessage(current.getResult(), true);
}
private static String getFailMessage(ProcessStatus result, boolean addExtra) {
StringBuilder extraFailures = new StringBuilder();
ProcessStatus firstFail = getFirstFail(result.getChildren(), extraFailures);
String resultMessage = getDirectFailMessage(result);
if (firstFail != null) {
String childrenMessage = getFailMessage(firstFail, false);
if (!resultMessage.equals(childrenMessage)) {
String basePart = getLineMessage(firstFail) + resultMessage + ": " + childrenMessage;
if (addExtra) {
String extraMsg = extraFailures.toString().replace(childrenMessage, "").replace("\n", " " );
return basePart + " " + extraMsg;
} else {
return basePart;
}
}
}
if (addExtra) {
String extraMsg = extraFailures.toString().replace(resultMessage, "").replace("\n", " " );;
return resultMessage + " " + extraMsg;
} else {
return resultMessage;
}
}
private static String getDirectFailMessage(ProcessStatus result) {
StringBuilder sb = new StringBuilder(result.getMessage());
if (result instanceof EVerificationStatus) {
EVerificationStatus vs = (EVerificationStatus) result;
sb.append(" ");
sb.append(Joiner.on(", ").join(Iterables.transform(vs.getData(), datumToMessage)));
}
return sb.toString();
}
private static String getLineMessage(ProcessStatus firstFail) {
if (firstFail.eContainer() instanceof ScriptProcessStatus) {
return "Line " + ((ScriptProcessStatus) firstFail.eContainer()).getLine() + ": ";
}
return "";
}
private static ProcessStatus getFirstFail(List<ProcessStatus> children, StringBuilder extraFailures) {
ProcessStatus result = null;
for (ProcessStatus processStatus : children) {
if (processStatus.getSeverity() != IStatus.OK) {
ProcessStatus grandChild = getFirstFail(processStatus.getChildren(), extraFailures);
if (result == null) {
result = grandChild != null ? grandChild : processStatus;
}
if (result != grandChild) {
extraFailures.append(getFailMessage(processStatus, false)).append(" ");
}
}
}
return result;
}
public static String replaceHtmlEntities(String string) {
string = string.replace("&", "&amp;");
string = string.replace("<", "&lt;");
string = string.replace(">", "&gt;");
return string;
}
public static String replaceLineBreaks(String string) {
if (string == null)
return null;
string = string.replace("\r\n", "<br />");
string = string.replace("\n", "<br />");
string = string.replace("\r", "<br />");
return string;
}
public static String getDetails(Node item) {
// Collect and print all snapshots
StringBuilder builder = new StringBuilder();
collectDetails(item, builder);
return maskIllegalChars(builder.toString());
}
/**
* see http://jira4.xored.com/browse/QS-1334
*
* @param str
* @return
*/
private static String maskIllegalChars(String str) {
StringBuilder sb = new StringBuilder();
if (str == null || str.length() == 0) {
return str;
}
for (char c : str.toCharArray()) {
boolean isControl = c == '\t' || c == ' ' || c == '\r' || c == '\n' || c == '.' || c == ';' || c == ':'
|| c == '-' || c == '+' || c == '=' || c == '#' || c == '$' || c == '%' || c == '^' || c == '*'
|| c == '(' || c == ')' || c == '{' || c == '}' || c == '\"' || c == '\'' || c == '|' || c == '\\'
|| c == '/' || c == '<' || c == '>' || c == '!' || c == '@' || c == ',' || c == '_' || c == '['
|| c == ']';
if (!(Character.isLetterOrDigit(c) || isControl || Character.isAlphabetic(c))) {
sb.append("(0x").append(Integer.toHexString(c)).append(")");
} else {
sb.append(c);
}
}
return sb.toString().replace("\0", "\\0").replace("]]>", "]] >");
}
public static String combineNames(EList<String> list, String separator) {
if (list == null || separator == null)
return null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
if (i < list.size() - 1) {
sb.append(separator);
}
}
return sb.toString();
}
public static void collectDetails(Node item, StringBuilder result) {
try {
EList<Snaphot> snapshots = item.getSnapshots();
for (Snaphot snaphot : snapshots) {
EObject data = snaphot.getData();
if (data != null) {
if (data instanceof AdvancedInformation) {
StringWriter writer = new StringWriter();
new AdvancedInformationGenerator(new PrintWriter(writer))
.writeAdvanced((AdvancedInformation) data, 0);
result.append(writer.toString()).append("\n");
} else {
new SimpleReportGenerator().toString(result, 2, data);
result.append("\n");
}
}
}
EList<Event> events = item.getEvents();
for (Event event : events) {
if (event.getData() instanceof EclipseStatus) {
EclipseStatus data = (EclipseStatus) event.getData();
new SimpleReportGenerator().toString(result, 1, data);
result.append("\n");
}
}
EList<Node> children = item.getChildren();
for (Node node : children) {
collectDetails(node, result);
}
} catch (IOException e) {
// String builder does not throw
throw new RuntimeException(e);
}
}
public static String getID(String value) {
if (value == null) {
return null;
}
String textResult = "";
for (char c : value.toCharArray()) {
if (!Character.isLetterOrDigit(c)) {
textResult += '_';
} else {
textResult += c;
}
}
return textResult;
}
public static final String getTime(Node nde) {
return formatTime(nde.getDuration());
}
}