builder/com.nokia.carbide.cdt.builder.test/src/com/nokia/carbide/cdt/builder/test/errorParsers/CarbideErrorParserTestHarness.java
fixed GCCE error parser & tests to work with CDT 6.0 changes.
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* This is a test harness implementing as a warper to Carbide.c++ error parsing,
* any test written using this harness will cover all production code involved
* in error parsing.
* 1. Provides redirection of error parser input/output to junit(programmatic) friendly format
* 2. Provides facility for preparing, diffing control result in XML format
*
*/
package com.nokia.carbide.cdt.builder.test.errorParsers;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.eclipse.cdt.core.ProblemMarkerInfo;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.DefaultJDOMFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.filter.ElementFilter;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import com.nokia.carbide.cdt.builder.builder.CarbideCommandLauncher;
import com.nokia.carbide.cdt.builder.test.TestPlugin;
import com.nokia.cpp.internal.api.utils.core.FileUtils;
public class CarbideErrorParserTestHarness extends CarbideCommandLauncher {
static final String EMPTY = "^EMPTY^";
static final String MARKER_INFO = "marker_info";
static final String FILE = "file";
static final String LINE_NUMBER = "line_number";
static final String MESSAGE = "message";
static final String SEVERITY = "severity";
static final String VARIABLE_NAME = "variable_name";
static final String EXTERNAL_PATH_STRING = "external_path_string";
IProject project;
ArrayList<ProblemMarkerInfo> ideProblemMarkerInfoList;
ArrayList<ProblemMarkerInfo> xmlFilePromblemMarkerInfoList;
boolean debug = false;
public CarbideErrorParserTestHarness(IProject project,
IProgressMonitor monitor,
String[] errorParserIds,
IPath workingDir) {
super(project, monitor, errorParserIds, workingDir);
this.project = project;
ideProblemMarkerInfoList = new ArrayList<ProblemMarkerInfo>();
xmlFilePromblemMarkerInfoList = new ArrayList<ProblemMarkerInfo>();
}
public void resetInternalLists() {
ideProblemMarkerInfoList.clear();
xmlFilePromblemMarkerInfoList.clear();
}
private String readFile(java.io.File consoleOutput) {
FileReader consoleReader;
StringBuffer sb = new StringBuffer();
try {
consoleReader = new FileReader(consoleOutput);
char[] buf = new char[1024];
int len;
while ((len = consoleReader.read(buf)) > 0) {
sb.append(buf, 0, len);
}
consoleReader.close();
} catch (FileNotFoundException e) {
Assert.fail();
} catch (IOException e) {
Assert.fail();
}
return sb.toString();
}
public void writeFileContentsToStdout(java.io.File consoleOutput) {
writeStringToStdout(readFile(consoleOutput));
}
// Drive the whole parsing mechanism, stdout is output normally came from console outout
public void writeStringToStdout(String consoleOutput) {
// pick out the stdout stream directly, where CDT error parser sniff
// for error messages from build console
try {
stdoutStream.getProject().deleteMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); // clear UI list before we start
stdoutStream.clearScratchBuffer(); // some error parser do multiple lines
consoleOutput += "\n"; // force the input file to flush all lines
stdoutStream.write(consoleOutput.getBytes());
stdoutStream.flush();
} catch (IOException e) {
Assert.fail();
} catch (CoreException e) {
Assert.fail();
}
}
// this is ridiculous, project.findMarkers returns array of reverse order on every alternate runs...
// need to intercept and keep track ourself
// reportProblems() calls this from base class
public void addMarker(ProblemMarkerInfo problemMarkerInfo) {
ideProblemMarkerInfoList.add(problemMarkerInfo);
super.addMarker(problemMarkerInfo);
}
// Read in error markers from IDE to this test harness and set up internal marker list
public void getMarkersFromIde() {
// flush out markers into project, that's the only way to tap into
// markers reported by error parsers in current API
ideProblemMarkerInfoList.clear();
stdoutStream.reportProblems();
}
/**
* Do the comparison of the parsed results from the console and the expected results (control file)
* @param consoleOutput - The output from the real build
* @param controlXml - The XML file with the expected results
* @return true on success, otherwise false.
*/
public boolean parseStringAndTestAgainstXML(java.io.File consoleOutput, java.io.File controlXml) {
try {
return parseStringAndTestAgainstXML(readFile(consoleOutput), new FileInputStream(controlXml));
} catch (FileNotFoundException e) {
Assert.fail();
}
return false;
}
/**
* Wrapper for parseStringAndTestAgainstXML().
* @param consoleOutput - The output from the real build
* @param xmlInputStream - The XML file with the expected results
* @return
*/
public boolean parseStringAndTestAgainstXML (String consoleOutput, InputStream xmlInputStream) {
writeStringToStdout(consoleOutput);
return testIdeMarkerAgainstXML (xmlInputStream);
}
/**
* Diff the IDE marker list against XML, assuming former is set up properly
*/
public boolean testIdeMarkerAgainstXML(InputStream xmlInputStream) {
// load data from IDE and control file
getMarkersFromIde();
readControlXML(xmlInputStream);
if (ideProblemMarkerInfoList.size() != xmlFilePromblemMarkerInfoList.size()) {
if (debug) {
java.io.File file;
try {
file = FileUtils.pluginRelativeFile(TestPlugin.getDefault(), "data/currentOutput.xml");
writeRegressionXMLFile(new java.io.PrintStream(file));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Assert.fail("IDE contains " + ideProblemMarkerInfoList.size() + " markers and Control file contains " + xmlFilePromblemMarkerInfoList.size());
return false;
}
for (int i = 0; i < ideProblemMarkerInfoList.size(); i++) {
if (markerCompare(ideProblemMarkerInfoList.get(i), xmlFilePromblemMarkerInfoList.get(i)) == false) {
Assert.fail("IDE differs from control file in item index " + i + "\n");
return false;
}
}
return true;
}
/** Compares two problem markers for each field. If any field of either input doesn't match, the test fails
*
* @param result - The actual parsed result
* @param expected - The expected marker info.
* @return - true on success, false on any failure.
*/
public boolean markerCompare(ProblemMarkerInfo result, ProblemMarkerInfo expected) {
/* CarbideCommandLauncher.addMarker() does not set file
if (result.file.toString().equals(expected.file.toString() == false) {
Assert.fail("Location from IDE marker is " + result.file.toString() +
", expected value is " + expected.file.toString());
return false;
}
*/
if (result.lineNumber != expected.lineNumber) {
Assert.fail("Location from IDE marker is " + result.lineNumber +
", expected value is " + expected.lineNumber);
return false;
}
if (result.description.equals(expected.description) == false) {
if (expected.description.equals(EMPTY) == false) {
Assert.fail("Unexpected message: EXPECTED value is: " + expected.description + ", ACTUAL: " + result.description);
}
} else {
if (result.description.equals(expected.description) == false) {
Assert.fail("Message from IDE marker is " + result.description +
", expected value is " + expected.description);
return false;
}
}
if (result.severity != expected.severity) {
Assert.fail("Severity from IDE marker is " + result.severity +
", expected value is " + expected.severity);
return false;
}
if (result.variableName == null) {
if (expected.variableName.equals(EMPTY) == false) {
Assert.fail("Variable name from IDE marker is null, expected value is " + expected.variableName);
}
} else {
if (result.variableName.equals(expected.variableName) == false) {
Assert.fail("Variable name from IDE marker is " + result.variableName +
",expected value is " + expected.variableName);
return false;
}
}
if (result.externalPath == null) {
if (expected.externalPath.toString().equals(EMPTY) == false) {
Assert.fail("External path string IDE marker is null, expected value is " + expected.externalPath);
}
} else {
if (result.externalPath.equals(expected.externalPath) == false) {
Assert.fail("External path string from IDE marker is " + result.externalPath +
", expected value is " + expected.externalPath);
return false;
}
}
return true;
}
// read control case from a XML file and setup internal list
public void readControlXML(InputStream xmlInputStream) {
try {
SAXBuilder docBuilder = new SAXBuilder();
Document doc = docBuilder.build(xmlInputStream);
Element root = doc.getRootElement();
ElementFilter elementFilter = new ElementFilter(MARKER_INFO);
List<?> allMarkerInfo = root.getContent(elementFilter);
xmlFilePromblemMarkerInfoList.clear();
int markerInfoListSize = allMarkerInfo.size();
for (int i = 0; i < markerInfoListSize; i++) {
Object info = allMarkerInfo.get(i);
IResource file = null;
int lineNumber;
String description;
int severity;
String variableName;
IPath externalPath;
Assert.assertTrue(info instanceof Element);
Element markerInfo = (Element)info;
Attribute locationNode = markerInfo.getAttribute(LINE_NUMBER);
lineNumber = Integer.parseInt(locationNode.getValue());
Attribute messageNode = markerInfo.getAttribute(MESSAGE);
description = messageNode.getValue();
Attribute severityNode = markerInfo.getAttribute(SEVERITY);
severity = Integer.parseInt(severityNode.getValue());
Attribute variableNameNode = markerInfo.getAttribute(VARIABLE_NAME);
variableName = variableNameNode.getValue();
Attribute externalPathStringNode = markerInfo.getAttribute(EXTERNAL_PATH_STRING);
externalPath = new org.eclipse.core.runtime.Path(externalPathStringNode.getValue());
ProblemMarkerInfo details = new ProblemMarkerInfo(file, lineNumber, description, severity, variableName, externalPath);
xmlFilePromblemMarkerInfoList.add(details);
}
} catch (JDOMException e) {
Assert.fail();
} catch (IOException e) {
Assert.fail();
}
}
// One could prepare control case with this function
// printSteam could be System.out or new PrintStream(java.io.File file)
/**
* This is used to write the regression file for the console output.
* i.e. these are the expected results. This isn't part of the test, just a utility
* to help generate the results for for comparision during the acutal test.
*/
public void writeRegressionXMLFile(PrintStream printStream) {
try {
DefaultJDOMFactory jdomFactory = new DefaultJDOMFactory();
Document jdomdoc = jdomFactory.document(jdomFactory.element("root"));
Element root = jdomdoc.getRootElement();
int index = 0;
for (ProblemMarkerInfo marker : ideProblemMarkerInfoList)
{
Element child = jdomFactory.element(MARKER_INFO);
Comment comment = jdomFactory.comment("Error Marker at index " + index);
++index;
/* CarbideCommandLauncher.addMarker() does not set file
file = marker.getAttribute(IMarker.LOCATION, 0);
child.setAttribute(LOCATION, new Integer(file).toString());
*/
child.setAttribute(FILE, EMPTY); // file
child.setAttribute(LINE_NUMBER, new Integer(marker.lineNumber).toString());
String description;
if (marker.description == null || marker.description.equals("")) {
description = EMPTY;
} else {
description = marker.description;
}
child.setAttribute(MESSAGE, description);
child.setAttribute(SEVERITY, new Integer(marker.severity).toString());
String variableName;
if (marker.variableName == null || marker.variableName.equals("")) {
variableName = EMPTY;
} else {
variableName = marker.variableName;
}
child.setAttribute(VARIABLE_NAME, variableName);
String externalPathString;
if (marker.externalPath == null || marker.externalPath.equals("")) {
externalPathString = EMPTY;
} else {
externalPathString = marker.externalPath.toString();
}
child.setAttribute(EXTERNAL_PATH_STRING, externalPathString);
root.addContent(comment);
root.addContent(child);
}
// drop JAXP for JDOM
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(jdomdoc, printStream);
// print xml
printStream.flush();
printStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}