diff --git a/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.java b/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.java index 71911af35d5..37ea0c1003c 100644 --- a/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.java +++ b/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.java @@ -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 @@ -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 { diff --git a/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.properties b/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.properties index ba5709f28a4..e1ed91dac5b 100644 --- a/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.properties +++ b/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostTestsRunnerMessages.properties @@ -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 @@ -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\! diff --git a/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostXmlLogHandler.java b/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostXmlLogHandler.java index 1f7e75900c7..27c498def0a 100644 --- a/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostXmlLogHandler.java +++ b/testsrunner/org.eclipse.cdt.testsrunner.boost/src/org/eclipse/cdt/testsrunner/internal/boost/BoostXmlLogHandler.java @@ -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 @@ -46,6 +46,8 @@ 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$ @@ -53,6 +55,13 @@ public class BoostXmlLogHandler extends DefaultHandler { private static final String XML_ATTR_MESSAGE_FILE = "file"; //$NON-NLS-1$ private static final String XML_ATTR_MESSAGE_LINE = "line"; //$NON-NLS-1$ + /** + * 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; @@ -81,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; @@ -102,17 +115,18 @@ public void startElement(String namespaceURI, String localName, String qName, At break; case XML_NODE_TEST_CASE: - String testCaseName = attrs.getValue(XML_ATTR_TEST_CASE_NAME); + 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; break; @@ -132,6 +146,11 @@ public void startElement(String namespaceURI, String localName, String qName, At lineNumber = DEFAULT_LOCATION_LINE; break; + case XML_NODE_CONTEXT: + case XML_NODE_FRAME: + /* handle in endElement */ + break; + case XML_NODE_TESTING_TIME: case XML_NODE_TEST_LOG: /* just skip, do nothing */ @@ -149,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().trim()); + 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) { @@ -174,6 +212,10 @@ public void endElement(String namespaceURI, String localName, String qName) thro break; case XML_NODE_TEST_CASE: + if (testCaseEnterDeferred) { + modelUpdater.enterTestCase(testCaseName.toString()); + testCaseEnterDeferred = false; + } modelUpdater.setTestStatus(testStatus); modelUpdater.exitTestCase(); break; @@ -209,6 +251,13 @@ public void endElement(String namespaceURI, String localName, String qName) thro 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; + case XML_NODE_TEST_LOG: case XML_NODE_LAST_CHECKPOINT: /* just skip, do nothing */ diff --git a/testsrunner/org.eclipse.cdt.testsrunner.tests/src/org/eclipse/cdt/testsrunner/testsrunners/BoostTestCase.java b/testsrunner/org.eclipse.cdt.testsrunner.tests/src/org/eclipse/cdt/testsrunner/testsrunners/BoostTestCase.java index 9527732d6c7..000ef5aaaa4 100644 --- a/testsrunner/org.eclipse.cdt.testsrunner.tests/src/org/eclipse/cdt/testsrunner/testsrunners/BoostTestCase.java +++ b/testsrunner/org.eclipse.cdt.testsrunner.tests/src/org/eclipse/cdt/testsrunner/testsrunners/BoostTestCase.java @@ -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 @@ -507,4 +507,136 @@ public void testParameterizedTests() { mockModelUpdater.exitTestCase(); mockModelUpdater.exitTestSuite(); } + + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + public void testWithContextTests() { + mockModelUpdater.skipCalls("setTestStatus"); + + mockModelUpdater.enterTestSuite("MainTS"); + mockModelUpdater.enterTestCase("single-context [context 1 message here]"); + mockModelUpdater.addTestMessage("file1.cpp", 1, ITestMessage.Level.Info, "Context: context 1 message here"); + mockModelUpdater.exitTestCase(); + mockModelUpdater.enterTestCase("single-context-and-info-message [context 2 message here]"); + mockModelUpdater.addTestMessage("file2.cpp", 2, ITestMessage.Level.Info, + "info 2 message here\nContext: context 2 message here"); + mockModelUpdater.exitTestCase(); + + // I am not convinced the handling of this is correct, there is an assumption in the code that the first + // context seen in an info (or error/warning/etc) message is the one to display next to the test case + // name. This works if all the info messages have the same context, but is that an oversimplification? + // See https://github.com/eclipse-cdt/cdt/issues/459#issuecomment-1677589998 + mockModelUpdater.enterTestCase("multi-context [context 3a message here]"); + mockModelUpdater.addTestMessage("file3.cpp", 1, ITestMessage.Level.Info, "Context: context 3a message here"); + mockModelUpdater.addTestMessage("file3.cpp", 2, ITestMessage.Level.Info, "Context: context 3b message here"); + mockModelUpdater.exitTestCase(); + + mockModelUpdater.enterTestCase("error-message [context 4 message here]"); + mockModelUpdater.addTestMessage("file4.cpp", 1, ITestMessage.Level.Error, + "error 4 message here\nContext: context 4 message here"); + mockModelUpdater.exitTestCase(); + + // These tests make sure there is no off-by-one error when shortening context strings + mockModelUpdater.enterTestCase("off-by-one-check-a [very very very long context off-by-one-check 01234...]"); + mockModelUpdater.addTestMessage("off-by-one.cpp", 1, ITestMessage.Level.Error, + "Context: very very very long context off-by-one-check 01234567890"); + mockModelUpdater.exitTestCase(); + mockModelUpdater.enterTestCase("off-by-one-check-b [very very very long context off-by-one-check 01234...]"); + mockModelUpdater.addTestMessage("off-by-one.cpp", 1, ITestMessage.Level.Error, + "Context: very very very long context off-by-one-check 012345"); + mockModelUpdater.exitTestCase(); + mockModelUpdater.enterTestCase("off-by-one-check-c [very very very long context off-by-one-check 01234]"); + mockModelUpdater.addTestMessage("off-by-one.cpp", 1, ITestMessage.Level.Error, + "Context: very very very long context off-by-one-check 01234"); + mockModelUpdater.exitTestCase(); + mockModelUpdater.enterTestCase("off-by-one-check-d [very very very long context off-by-one-check 0123]"); + mockModelUpdater.addTestMessage("off-by-one.cpp", 1, ITestMessage.Level.Error, + "Context: very very very long context off-by-one-check 0123"); + mockModelUpdater.exitTestCase(); + + mockModelUpdater.exitTestSuite(); + } }