Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Context when running Boost test runners #507

Merged
merged 3 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.testsrunner.boost;singleton:=true
Bundle-Version: 7.2.0.qualifier
Bundle-Version: 7.2.100.qualifier
Bundle-Activator: org.eclipse.cdt.testsrunner.internal.boost.BoostTestsRunnerPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2011, 2012 Anton Gorenkov.
* Copyright (c) 2011, 2023 Anton Gorenkov and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -21,6 +21,10 @@ public class BoostTestsRunnerMessages extends NLS {
public static String BoostTestsRunner_io_error_prefix;
public static String BoostTestsRunner_wrong_tests_paths_count;
public static String BoostTestsRunner_xml_error_prefix;
public static String BoostXmlLogHandler_ContextHeader;
public static String BoostXmlLogHandler_ContextOverflow;
public static String BoostXmlLogHandler_ContextPrefix;
public static String BoostXmlLogHandler_ContextSuffix;
public static String BoostXmlLogHandler_exception_suffix;
public static String BoostXmlLogHandler_wrong_tag_name;
static {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2011 Anton Gorenkov
# Copyright (c) 2011, 2023 Anton Gorenkov and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -15,5 +15,9 @@ BoostTestsRunner_error_format={0}: {1}
BoostTestsRunner_io_error_prefix=I/O Error
BoostTestsRunner_wrong_tests_paths_count=Only on test suite or test case should be specified to rerun
BoostTestsRunner_xml_error_prefix=XML parse error
BoostXmlLogHandler_ContextHeader=\nContext:\u0020
BoostXmlLogHandler_ContextOverflow=...
BoostXmlLogHandler_ContextPrefix=\u0020[
BoostXmlLogHandler_ContextSuffix=]
BoostXmlLogHandler_exception_suffix=\nLast check point was here.
BoostXmlLogHandler_wrong_tag_name=Invalid XML format: Element "{0}" is not accepted\!
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2011, 2013 Anton Gorenkov and others.
* Copyright (c) 2011, 2023 Anton Gorenkov and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -15,9 +15,6 @@
package org.eclipse.cdt.testsrunner.internal.boost;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.eclipse.cdt.testsrunner.model.ITestItem;
Expand Down Expand Up @@ -49,25 +46,21 @@ public class BoostXmlLogHandler extends DefaultHandler {
private static final String XML_NODE_ERROR = "Error"; //$NON-NLS-1$
private static final String XML_NODE_FATAL_ERROR = "FatalError"; //$NON-NLS-1$
private static final String XML_NODE_EXCEPTION = "Exception"; //$NON-NLS-1$
private static final String XML_NODE_CONTEXT = "Context"; //$NON-NLS-1$
private static final String XML_NODE_FRAME = "Frame"; //$NON-NLS-1$

// Boost.Test XML log attributes
private static final String XML_ATTR_TEST_SUITE_NAME = "name"; //$NON-NLS-1$
private static final String XML_ATTR_TEST_CASE_NAME = "name"; //$NON-NLS-1$
private static final String XML_ATTR_MESSAGE_FILE = "file"; //$NON-NLS-1$
private static final String XML_ATTR_MESSAGE_LINE = "line"; //$NON-NLS-1$

/** Maps the string message level representation to the Tests Runner internal enum code. */
private static final Map<String, ITestMessage.Level> STRING_TO_MESSAGE_LEVEL;
static {
Map<String, ITestMessage.Level> aMap = new HashMap<>();
aMap.put(XML_NODE_INFO, ITestMessage.Level.Info);
aMap.put(XML_NODE_MESSAGE, ITestMessage.Level.Message);
aMap.put(XML_NODE_WARNING, ITestMessage.Level.Warning);
aMap.put(XML_NODE_ERROR, ITestMessage.Level.Error);
aMap.put(XML_NODE_FATAL_ERROR, ITestMessage.Level.FatalError);
// NOTE: Exception node is processed separately
STRING_TO_MESSAGE_LEVEL = Collections.unmodifiableMap(aMap);
}
/**
* The context can be of arbitrary length, to prevent excessively long strings
* in the tree limit the context to this length in the tree. The full context
* is available in the details tab.
*/
private static final int MAX_CONTEXT_LENGTH_IN_TREE = 50;

/** The default file name for test message location. */
private static final String DEFAULT_LOCATION_FILE = null;
Expand Down Expand Up @@ -97,6 +90,10 @@ public class BoostXmlLogHandler extends DefaultHandler {
private String lastTestCaseName = ""; //$NON-NLS-1$
private static final int SAME_TEST_CASE_NAME_COUNT_START = 2;
private int sameTestCaseNameCount = SAME_TEST_CASE_NAME_COUNT_START;
private StringBuilder context = new StringBuilder();

private boolean testCaseEnterDeferred = false;
private StringBuilder testCaseName = new StringBuilder();

BoostXmlLogHandler(ITestModelUpdater modelUpdater) {
this.modelUpdater = modelUpdater;
Expand All @@ -106,41 +103,61 @@ public class BoostXmlLogHandler extends DefaultHandler {
public void startElement(String namespaceURI, String localName, String qName, Attributes attrs)
throws SAXException {

if (qName == null) {
throw createAndLogExceptionForElement(qName);
}

elementDataStack.push(new StringBuilder());
if (qName == XML_NODE_TEST_SUITE) {
switch (qName) {
case XML_NODE_TEST_SUITE:
String testSuiteName = attrs.getValue(XML_ATTR_TEST_SUITE_NAME);
modelUpdater.enterTestSuite(testSuiteName);
break;

} else if (qName == XML_NODE_TEST_CASE) {
String testCaseName = attrs.getValue(XML_ATTR_TEST_CASE_NAME);
case XML_NODE_TEST_CASE:
testCaseName.setLength(0);
testCaseName.append(attrs.getValue(XML_ATTR_TEST_CASE_NAME));

if (lastTestCaseName.equals(testCaseName)) {
testCaseName += " (" + sameTestCaseNameCount + ")"; //$NON-NLS-1$ //$NON-NLS-2$
if (lastTestCaseName.equals(testCaseName.toString())) {
testCaseName.append(" (" + sameTestCaseNameCount + ")"); //$NON-NLS-1$ //$NON-NLS-2$
++sameTestCaseNameCount;
} else {
lastTestCaseName = testCaseName;
lastTestCaseName = testCaseName.toString();
sameTestCaseNameCount = SAME_TEST_CASE_NAME_COUNT_START;
}

modelUpdater.enterTestCase(testCaseName);
testCaseEnterDeferred = true;
testStatus = Status.Passed;

} else if (STRING_TO_MESSAGE_LEVEL.containsKey(qName) || qName == XML_NODE_LAST_CHECKPOINT) {
break;

case XML_NODE_INFO:
case XML_NODE_MESSAGE:
case XML_NODE_WARNING:
case XML_NODE_ERROR:
case XML_NODE_FATAL_ERROR:
case XML_NODE_LAST_CHECKPOINT:
fileName = attrs.getValue(XML_ATTR_MESSAGE_FILE);
String lineNumberStr = attrs.getValue(XML_ATTR_MESSAGE_LINE);
lineNumber = lineNumberStr != null ? Integer.parseInt(lineNumberStr.trim()) : DEFAULT_LOCATION_LINE;
break;

} else if (qName == XML_NODE_EXCEPTION) {
case XML_NODE_EXCEPTION:
fileName = DEFAULT_LOCATION_FILE;
lineNumber = DEFAULT_LOCATION_LINE;
break;

} else if (qName == XML_NODE_TESTING_TIME) {
case XML_NODE_CONTEXT:
case XML_NODE_FRAME:
/* handle in endElement */
break;

} else if (qName == XML_NODE_TEST_LOG) {
case XML_NODE_TESTING_TIME:
case XML_NODE_TEST_LOG:
/* just skip, do nothing */
break;

} else {
logAndThrowErrorForElement(qName);
default:
throw createAndLogExceptionForElement(qName);
}
}

Expand All @@ -151,7 +168,26 @@ public void startElement(String namespaceURI, String localName, String qName, At
* @param level test message level
*/
private void addCurrentMessage(ITestMessage.Level level) {
modelUpdater.addTestMessage(fileName, lineNumber, level, elementDataStack.peek().toString());
String text = elementDataStack.peek().toString().trim();
if (testCaseEnterDeferred) {
if (!context.isEmpty()) {
testCaseName.append(BoostTestsRunnerMessages.BoostXmlLogHandler_ContextPrefix);
if (context.length() > MAX_CONTEXT_LENGTH_IN_TREE) {
testCaseName.append(context.subSequence(0, MAX_CONTEXT_LENGTH_IN_TREE));
testCaseName.append(BoostTestsRunnerMessages.BoostXmlLogHandler_ContextOverflow);
} else {
testCaseName.append(context);
}
testCaseName.append(BoostTestsRunnerMessages.BoostXmlLogHandler_ContextSuffix);
}
modelUpdater.enterTestCase(testCaseName.toString());
testCaseEnterDeferred = false;
}
if (!context.isEmpty()) {
text += BoostTestsRunnerMessages.BoostXmlLogHandler_ContextHeader + context.toString().trim();
context.setLength(0);
}
modelUpdater.addTestMessage(fileName, lineNumber, level, text.trim());
fileName = DEFAULT_LOCATION_FILE;
lineNumber = DEFAULT_LOCATION_LINE;
if (level == ITestMessage.Level.Error || level == ITestMessage.Level.FatalError) {
Expand All @@ -167,30 +203,68 @@ private void addCurrentMessage(ITestMessage.Level level) {
@Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {

if (qName == XML_NODE_TEST_SUITE) {
if (qName == null) {
throw createAndLogExceptionForElement(qName);
}
switch (qName) {
case XML_NODE_TEST_SUITE:
modelUpdater.exitTestSuite();
break;

} else if (qName == XML_NODE_TEST_CASE) {
case XML_NODE_TEST_CASE:
if (testCaseEnterDeferred) {
modelUpdater.enterTestCase(testCaseName.toString());
testCaseEnterDeferred = false;
}
modelUpdater.setTestStatus(testStatus);
modelUpdater.exitTestCase();
break;

} else if (qName == XML_NODE_TESTING_TIME) {
case XML_NODE_TESTING_TIME:
modelUpdater.setTestingTime(Integer.parseInt(elementDataStack.peek().toString().trim()) / 1000);

} else if (STRING_TO_MESSAGE_LEVEL.containsKey(qName)) {
addCurrentMessage(STRING_TO_MESSAGE_LEVEL.get(qName));

} else if (qName == XML_NODE_EXCEPTION) {
break;

case XML_NODE_INFO:
addCurrentMessage(ITestMessage.Level.Info);
break;
case XML_NODE_MESSAGE:
addCurrentMessage(ITestMessage.Level.Message);
break;
case XML_NODE_WARNING:
addCurrentMessage(ITestMessage.Level.Warning);
break;
case XML_NODE_ERROR:
addCurrentMessage(ITestMessage.Level.Error);
break;
case XML_NODE_FATAL_ERROR:
addCurrentMessage(ITestMessage.Level.FatalError);
break;

case XML_NODE_EXCEPTION:
if (fileName != DEFAULT_LOCATION_FILE && !fileName.isEmpty() && lineNumber >= 0) {
elementDataStack.peek().append(BoostTestsRunnerMessages.BoostXmlLogHandler_exception_suffix);
StringBuilder current = elementDataStack.peek();
String trimmed = current.toString().trim();
current.setLength(0);
current.append(trimmed);
current.append(BoostTestsRunnerMessages.BoostXmlLogHandler_exception_suffix);
}
addCurrentMessage(ITestMessage.Level.Exception);
break;

case XML_NODE_CONTEXT:
context.insert(0, elementDataStack.peek().toString().trim());
break;
case XML_NODE_FRAME:
context.append(elementDataStack.peek().toString().trim());
break;

} else if (qName == XML_NODE_TEST_LOG || qName == XML_NODE_LAST_CHECKPOINT) {
case XML_NODE_TEST_LOG:
case XML_NODE_LAST_CHECKPOINT:
/* just skip, do nothing */
break;

} else {
logAndThrowErrorForElement(qName);
default:
throw createAndLogExceptionForElement(qName);
}
elementDataStack.pop();
}
Expand All @@ -207,22 +281,13 @@ public void characters(char[] ch, int start, int length) {
* Throws the testing exception for the specified XML tag.
*
* @param tagName XML tag name
* @throws SAXException the exception that will be thrown
*/
private void logAndThrowErrorForElement(String tagName) throws SAXException {
logAndThrowError(MessageFormat.format(BoostTestsRunnerMessages.BoostXmlLogHandler_wrong_tag_name, tagName));
}

/**
* Throws the testing exception with the specified message.
*
* @param message the reason
* @throws SAXException the exception that will be thrown
* @return SAXException the exception that will be thrown
*/
private void logAndThrowError(String message) throws SAXException {
SAXException e = new SAXException(message);
private SAXException createAndLogExceptionForElement(String tagName) {
SAXException e = new SAXException(
MessageFormat.format(BoostTestsRunnerMessages.BoostXmlLogHandler_wrong_tag_name, tagName));
BoostTestsRunnerPlugin.log(e);
throw e;
return e;
}

@Override
Expand Down
Loading