1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-03-28 14:56:28 +01:00

Bug 569839: Provide a new JUnit5 base and utility classes

Change-Id: I8682f4702cfa0cad7d0452ca48d1ab74eeb1dbdb
This commit is contained in:
Jonah Graham 2020-12-19 14:29:24 -05:00
parent 3b680c8d8e
commit 5c82be881d
11 changed files with 484 additions and 163 deletions

View file

@ -27,6 +27,7 @@ import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.core.testplugin.util.ModelJoiner;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.cdt.core.tests" version="2">
<resource path="suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase5.java" type="org.eclipse.cdt.core.testplugin.util.BaseTestCase5$ModelJoiner">
<filter comment="This is ok - there is just no way of marking @noreference as having friends." id="640712815">
<message_arguments>
<message_argument value="CCorePlugin"/>
<message_argument value="ModelJoiner"/>
<message_argument value="createStatus(String, Throwable)"/>
</message_arguments>
</filter>
</resource>
</component>

View file

@ -48,3 +48,4 @@ Bundle-Vendor: %providerName
Bundle-RequiredExecutionEnvironment: JavaSE-11
Automatic-Module-Name: org.eclipse.cdt.core.tests
Bundle-Localization: plugin
Import-Package: org.junit.jupiter.api;version="5.7.0"

View file

@ -29,6 +29,7 @@ import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.util.ModelJoiner;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences;
import org.eclipse.core.resources.IFile;

View file

@ -31,6 +31,7 @@ import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.CTestPlugin;
import org.eclipse.cdt.core.testplugin.util.ModelJoiner;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;

View file

@ -38,6 +38,7 @@ import org.eclipse.cdt.core.parser.tests.VisibilityAsserts;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.CTestPlugin;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.core.testplugin.util.ModelJoiner;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.pdom.PDOM;

View file

@ -20,36 +20,21 @@ import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ElementChangedEvent;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.IElementChangedListener;
import org.eclipse.cdt.core.testplugin.ResourceHelper;
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
import org.eclipse.cdt.internal.core.CCoreInternals;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.core.pdom.CModelListener;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
@ -58,29 +43,33 @@ import junit.framework.TestFailure;
import junit.framework.TestResult;
import junit.framework.TestSuite;
/**
* @deprecated Please migrate tests away from JUnit3 style to JUnit5 style by using {@link BaseTestCase5}
* as base class.
*/
@Deprecated
public abstract class BaseTestCase extends TestCase {
private static final String DEFAULT_INDEXER_TIMEOUT_SEC = "10";
private static final String INDEXER_TIMEOUT_PROPERTY = "indexer.timeout";
private static final String DEFAULT_INDEXER_TIMEOUT_SEC = BaseTestCase5.DEFAULT_INDEXER_TIMEOUT_SEC;
private static final String INDEXER_TIMEOUT_PROPERTY = BaseTestCase5.INDEXER_TIMEOUT_PROPERTY;
/**
* Indexer timeout used by tests. To avoid this timeout expiring during debugging add
* -Dindexer.timeout=some_large_number to VM arguments of the test launch configuration.
*/
protected static final int INDEXER_TIMEOUT_SEC = Integer
.parseInt(System.getProperty(INDEXER_TIMEOUT_PROPERTY, DEFAULT_INDEXER_TIMEOUT_SEC));
protected static final int INDEXER_TIMEOUT_MILLISEC = INDEXER_TIMEOUT_SEC * 1000;
protected static final int INDEXER_TIMEOUT_SEC = BaseTestCase5.INDEXER_TIMEOUT_SEC;
protected static final int INDEXER_TIMEOUT_MILLISEC = BaseTestCase5.INDEXER_TIMEOUT_MILLISEC;
/**
* The GCC version to emulate when running tests.
* We emulate the latest version whose extensions we support.
*/
protected static final int GCC_MAJOR_VERSION_FOR_TESTS = 10;
protected static final int GCC_MINOR_VERSION_FOR_TESTS = 1;
protected static final int GCC_MAJOR_VERSION_FOR_TESTS = BaseTestCase5.GCC_MAJOR_VERSION_FOR_TESTS;
protected static final int GCC_MINOR_VERSION_FOR_TESTS = BaseTestCase5.GCC_MINOR_VERSION_FOR_TESTS;
/**
* This provides the systems new line separator. Use this if you do String comparisons in tests
* instead of hard coding '\n' or '\r\n' respectively.
*/
protected static final String NL = System.getProperty("line.separator");
protected static final String NL = BaseTestCase5.NL;
private boolean fExpectFailure;
private int fBugNumber;
@ -187,74 +176,13 @@ public abstract class BaseTestCase extends TestCase {
@Override
public void runBare() throws Throwable {
final List<IStatus> statusLog = Collections.synchronizedList(new ArrayList());
ILogListener logListener = new ILogListener() {
@Override
public void logging(IStatus status, String plugin) {
if (!status.isOK() && status.getSeverity() != IStatus.INFO) {
switch (status.getCode()) {
case IResourceStatus.NOT_FOUND_LOCAL:
case IResourceStatus.NO_LOCATION_LOCAL:
case IResourceStatus.FAILED_READ_LOCAL:
case IResourceStatus.RESOURCE_NOT_LOCAL:
// Logged by the resources plugin.
return;
}
statusLog.add(status);
}
}
};
final CCorePlugin corePlugin = CCorePlugin.getDefault();
if (corePlugin != null) { // Iff we don't run as a JUnit Plugin Test.
corePlugin.getLog().addLogListener(logListener);
}
Throwable testThrowable = null;
LogMonitoring monitoring = new LogMonitoring();
monitoring.start();
try {
try {
super.runBare();
} catch (Throwable e) {
testThrowable = e;
}
if (statusLog.size() != fExpectedLoggedNonOK) {
StringBuilder msg = new StringBuilder("Expected number (").append(fExpectedLoggedNonOK).append(") of ");
msg.append("Non-OK status objects in log differs from actual (").append(statusLog.size())
.append(").\n");
Throwable cause = null;
if (!statusLog.isEmpty()) {
synchronized (statusLog) {
for (IStatus status : statusLog) {
IStatus[] ss = { status };
ss = status instanceof MultiStatus ? ((MultiStatus) status).getChildren() : ss;
for (IStatus s : ss) {
msg.append('\t').append(s.getMessage()).append(' ');
Throwable t = s.getException();
cause = cause != null ? cause : t;
if (t != null) {
msg.append(
t.getMessage() != null ? t.getMessage() : t.getClass().getCanonicalName());
}
msg.append("\n");
}
}
}
}
cause = cause != null ? cause : testThrowable;
AssertionFailedError afe = new AssertionFailedError(msg.toString());
afe.initCause(cause);
throw afe;
}
super.runBare();
} finally {
if (corePlugin != null) {
corePlugin.getLog().removeLogListener(logListener);
}
monitoring.stop(fExpectedLoggedNonOK);
}
if (testThrowable != null)
throw testThrowable;
}
@Override
@ -302,97 +230,29 @@ public abstract class BaseTestCase extends TestCase {
fExpectedLoggedNonOK = count;
}
/**
* Some test steps need synchronizing against a CModel event. This class
* is a very basic means of doing that.
*/
static protected class ModelJoiner implements IElementChangedListener {
private final boolean[] changed = new boolean[1];
public ModelJoiner() {
CoreModel.getDefault().addElementChangedListener(this);
}
public void clear() {
synchronized (changed) {
changed[0] = false;
changed.notifyAll();
}
}
public void join() throws CoreException {
try {
synchronized (changed) {
while (!changed[0]) {
changed.wait();
}
}
} catch (InterruptedException e) {
throw new CoreException(CCorePlugin.createStatus("Interrupted", e));
}
}
public void dispose() {
CoreModel.getDefault().removeElementChangedListener(this);
}
@Override
public void elementChanged(ElementChangedEvent event) {
// Only respond to post change events
if (event.getType() != ElementChangedEvent.POST_CHANGE)
return;
synchronized (changed) {
changed[0] = true;
changed.notifyAll();
}
}
}
public static void waitForIndexer(ICProject project) throws InterruptedException {
Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_REFRESH, null);
assertTrue(CCoreInternals.getPDOMManager().joinIndexer(INDEXER_TIMEOUT_SEC * 1000, npm()));
BaseTestCase5.waitForIndexer(project);
}
public static void waitUntilFileIsIndexed(IIndex index, IFile file) throws Exception {
TestSourceReader.waitUntilFileIsIndexed(index, file, INDEXER_TIMEOUT_SEC * 1000);
BaseTestCase5.waitUntilFileIsIndexed(index, file);
}
// Assertion helpers
// Assertion helpers (redirected to the common implementation)
protected static <T> T assertInstance(Object o, Class<T> clazz, Class... cs) {
assertNotNull("Expected object of " + clazz.getName() + " but got a null value", o);
assertTrue("Expected " + clazz.getName() + " but got " + o.getClass().getName(), clazz.isInstance(o));
for (Class c : cs) {
assertNotNull("Expected object of " + c.getName() + " but got a null value", o);
assertTrue("Expected " + c.getName() + " but got " + o.getClass().getName(), c.isInstance(o));
}
return clazz.cast(o);
return BaseTestCase5.assertInstance(o, clazz, cs);
}
protected static void assertValue(IValue value, long expectedValue) {
assertNotNull(value);
assertTrue(value.numberValue() instanceof Long);
assertEquals(expectedValue, value.numberValue().longValue());
BaseTestCase5.assertValue(value, expectedValue);
}
protected static void assertVariableValue(IVariable var, long expectedValue) {
assertValue(var.getInitialValue(), expectedValue);
BaseTestCase5.assertVariableValue(var, expectedValue);
}
protected static String formatForPrinting(IASTName name) {
String signature = name.getRawSignature();
boolean saved = CPPASTNameBase.sAllowNameComputation;
CPPASTNameBase.sAllowNameComputation = true;
try {
String nameStr = name.toString();
if (signature.replace(" ", "").equals(nameStr.replace(" ", "")))
return signature;
return nameStr + " in " + signature;
} catch (Throwable e) {
return signature;
} finally {
CPPASTNameBase.sAllowNameComputation = saved;
}
return BaseTestCase5.formatForPrinting(name);
}
}

View file

@ -0,0 +1,284 @@
/*******************************************************************************
* Copyright (c) 2006, 2020 Wind River Systems, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.core.testplugin.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.testplugin.ResourceHelper;
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
import org.eclipse.cdt.internal.core.CCoreInternals;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.core.pdom.CModelListener;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInfo;
import junit.framework.TestResult;
/**
* BaseTestCase for JUnit5.
*/
public abstract class BaseTestCase5 {
protected static final String DEFAULT_INDEXER_TIMEOUT_SEC = "10";
protected static final String INDEXER_TIMEOUT_PROPERTY = "indexer.timeout";
/**
* Indexer timeout used by tests. To avoid this timeout expiring during debugging add
* -Dindexer.timeout=some_large_number to VM arguments of the test launch configuration.
*/
protected static final int INDEXER_TIMEOUT_SEC = Integer
.parseInt(System.getProperty(INDEXER_TIMEOUT_PROPERTY, DEFAULT_INDEXER_TIMEOUT_SEC));
protected static final int INDEXER_TIMEOUT_MILLISEC = INDEXER_TIMEOUT_SEC * 1000;
/**
* The GCC version to emulate when running tests.
* We emulate the latest version whose extensions we support.
*/
protected static final int GCC_MAJOR_VERSION_FOR_TESTS = 10;
protected static final int GCC_MINOR_VERSION_FOR_TESTS = 1;
/**
* This provides the systems new line separator. Use this if you do String comparisons in tests
* instead of hard coding '\n' or '\r\n' respectively.
*/
protected static final String NL = System.getProperty("line.separator");
private boolean fExpectFailure;
private int fBugNumber;
private int fExpectedLoggedNonOK;
private Deque<File> filesToDeleteOnTearDown = new ArrayDeque<>();
private TestInfo testInfo;
LogMonitoring logMonitoring = new LogMonitoring();
/**
* Backwards support for JUnit3 style test that had a getName. This is not 100% the same, but close
* enough for the general use case of getName.
*/
public String getName() {
return testInfo.getDisplayName();
}
public static NullProgressMonitor npm() {
return new NullProgressMonitor();
}
@BeforeEach
protected void setupBase(TestInfo testInfo) throws Exception {
this.testInfo = testInfo;
logMonitoring.start();
CPPASTNameBase.sAllowRecursionBindings = false;
CPPASTNameBase.sAllowNameComputation = false;
CModelListener.sSuppressUpdateOfLastRecentlyUsed = true;
}
@AfterEach
protected void tearDownBase() throws Exception {
for (File file; (file = filesToDeleteOnTearDown.pollLast()) != null;) {
file.delete();
}
ResourceHelper.cleanUp(getName());
TestScannerProvider.clear();
logMonitoring.stop(fExpectedLoggedNonOK);
}
protected void deleteOnTearDown(File file) {
filesToDeleteOnTearDown.add(file);
}
protected File createTempFile(String prefix, String suffix) throws IOException {
File file = File.createTempFile(prefix, suffix);
filesToDeleteOnTearDown.add(file);
return file;
}
protected File nonExistentTempFile(String prefix, String suffix) {
File file = new File(System.getProperty("java.io.tmpdir"), prefix + System.currentTimeMillis() + suffix);
filesToDeleteOnTearDown.add(file);
return file;
}
/**
* The last value passed to this method in the body of a testXXX method
* will be used to determine whether or not the presence of non-OK status objects
* in the log should fail the test. If the logged number of non-OK status objects
* differs from the last value passed, the test is failed. If this method is not called
* at all, the expected number defaults to zero.
* @param count the expected number of logged error and warning messages
*/
public void setExpectedNumberOfLoggedNonOKStatusObjects(int count) {
fExpectedLoggedNonOK = count;
}
public static void waitForIndexer(ICProject project) throws InterruptedException {
Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_REFRESH, null);
assertTrue(CCoreInternals.getPDOMManager().joinIndexer(INDEXER_TIMEOUT_SEC * 1000, npm()));
}
public static void waitUntilFileIsIndexed(IIndex index, IFile file) throws Exception {
TestSourceReader.waitUntilFileIsIndexed(index, file, INDEXER_TIMEOUT_SEC * 1000);
}
// Assertion helpers
/**
* Asserts that the file does exist and prints a niceish error message if not.
*/
public static void assertExists(File f) {
assertTrue(f.exists(), "File " + f + " does not exist");
}
/**
* Asserts that the resource does exist and prints a niceish error message if not.
*/
public static void assertExists(IResource f) {
assertTrue(f.exists(), "Resource " + f + " does not exist");
}
/**
* Asserts that the file does exist and prints a niceish error message if not.
*/
public static void assertNotExists(File f) {
assertFalse(f.exists(), "File " + f + " should not exist");
}
/**
* Asserts that the Resource does exist and prints a niceish error message if not.
*/
public static void assertNotExists(IResource f) {
assertFalse(f.exists(), "Resource " + f + " should not exist");
}
public static <T> T assertInstance(Object o, Class<T> clazz, Class... cs) {
assertNotNull(o, "Expected object of " + clazz.getName() + " but got a null value");
assertTrue(clazz.isInstance(o), "Expected " + clazz.getName() + " but got " + o.getClass().getName());
for (Class c : cs) {
assertNotNull(o, "Expected object of " + c.getName() + " but got a null value");
assertTrue(c.isInstance(o), "Expected " + c.getName() + " but got " + o.getClass().getName());
}
return clazz.cast(o);
}
public static void assertValue(IValue value, long expectedValue) {
assertNotNull(value);
assertTrue(value.numberValue() instanceof Long);
assertEquals(expectedValue, value.numberValue().longValue());
}
public static void assertVariableValue(IVariable var, long expectedValue) {
assertValue(var.getInitialValue(), expectedValue);
}
public static String formatForPrinting(IASTName name) {
String signature = name.getRawSignature();
boolean saved = CPPASTNameBase.sAllowNameComputation;
CPPASTNameBase.sAllowNameComputation = true;
try {
String nameStr = name.toString();
if (signature.replace(" ", "").equals(nameStr.replace(" ", "")))
return signature;
return nameStr + " in " + signature;
} catch (Throwable e) {
return signature;
} finally {
CPPASTNameBase.sAllowNameComputation = saved;
}
}
// These methods help migrate from JUnit3 to JUnit5 version by providing errors as early as possible
// in the migration cycle
public BaseTestCase5() {
// This constructor is expected to be called
}
/**
* This JUnit3 style constructor is not supported.
*/
private BaseTestCase5(String name) {
fail("Test not migrated properly to JUnit5 yet.");
}
/**
* This method is declared as final to help transition to JUnit5 to ensure that
* accidental override of the method is not left in subclasses when migrating.
*/
final protected void setUp() {
fail("Test not migrated properly to JUnit5 yet.");
}
/**
* This method is declared as final to help transition to JUnit5 to ensure that
* accidental override of the method is not left in subclasses when migrating.
*/
final protected void tearDown() {
fail("Test not migrated properly to JUnit5 yet.");
}
/**
* This method is declared as final to help transition to JUnit5 to ensure that
* accidental override of the method is not left in subclasses when migrating.
*/
final protected void runBare() {
fail("Test not migrated properly to JUnit5 yet.");
}
/**
* This method is declared as final to help transition to JUnit5 to ensure that
* accidental override of the method is not left in subclasses when migrating.
*/
final protected void run(TestResult result) {
fail("Test not migrated properly to JUnit5 yet.");
}
/**
* This method is declared as final to help transition to JUnit5 to ensure that
* accidental override of the method is not left in subclasses when migrating.
*/
final protected void runTest() throws Throwable {
fail("Test not migrated properly to JUnit5 yet.");
}
/**
* Setting expected failures in this way is not support with the BaseTestCase5. If this
* is functionality that is needed, please find a new way to do it.
*/
public void setExpectFailure(int bugNumber) {
fail("Test not migrated properly to JUnit5 yet.");
}
}

View file

@ -0,0 +1,90 @@
/*******************************************************************************
* Copyright (c) 2006, 2020 Wind River Systems, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.core.testplugin.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import junit.framework.AssertionFailedError;
class LogMonitoring {
private List<IStatus> statusLog;
private ILogListener logListener;
private CCorePlugin corePlugin;
void start() {
statusLog = Collections.synchronizedList(new ArrayList());
logListener = new ILogListener() {
@Override
public void logging(IStatus status, String plugin) {
if (!status.isOK() && status.getSeverity() != IStatus.INFO) {
switch (status.getCode()) {
case IResourceStatus.NOT_FOUND_LOCAL:
case IResourceStatus.NO_LOCATION_LOCAL:
case IResourceStatus.FAILED_READ_LOCAL:
case IResourceStatus.RESOURCE_NOT_LOCAL:
// Logged by the resources plugin.
return;
}
statusLog.add(status);
}
}
};
corePlugin = CCorePlugin.getDefault();
if (corePlugin != null) { // Iff we don't run as a JUnit Plugin Test.
corePlugin.getLog().addLogListener(logListener);
}
}
void stop(int expectedLoggedNonOK) {
if (statusLog.size() != expectedLoggedNonOK) {
StringBuilder msg = new StringBuilder("Expected number (").append(expectedLoggedNonOK).append(") of ");
msg.append("Non-OK status objects in log differs from actual (").append(statusLog.size()).append(").\n");
Throwable cause = null;
if (!statusLog.isEmpty()) {
synchronized (statusLog) {
for (IStatus status : statusLog) {
IStatus[] ss = { status };
ss = status instanceof MultiStatus ? ((MultiStatus) status).getChildren() : ss;
for (IStatus s : ss) {
msg.append('\t').append(s.getMessage()).append(' ');
Throwable t = s.getException();
cause = cause != null ? cause : t;
if (t != null) {
msg.append(t.getMessage() != null ? t.getMessage() : t.getClass().getCanonicalName());
}
msg.append("\n");
}
}
}
}
AssertionFailedError afe = new AssertionFailedError(msg.toString());
afe.initCause(cause);
throw afe;
}
if (corePlugin != null) {
corePlugin.getLog().removeLogListener(logListener);
}
}
}

View file

@ -0,0 +1,69 @@
/*******************************************************************************
* Copyright (c) 2006, 2016 Wind River Systems, Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.core.testplugin.util;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ElementChangedEvent;
import org.eclipse.cdt.core.model.IElementChangedListener;
import org.eclipse.core.runtime.CoreException;
/**
* Some test steps need synchronizing against a CModel event. This class
* is a very basic means of doing that.
*/
public class ModelJoiner implements IElementChangedListener {
private final boolean[] changed = new boolean[1];
public ModelJoiner() {
CoreModel.getDefault().addElementChangedListener(this);
}
public void clear() {
synchronized (changed) {
changed[0] = false;
changed.notifyAll();
}
}
public void join() throws CoreException {
try {
synchronized (changed) {
while (!changed[0]) {
changed.wait();
}
}
} catch (InterruptedException e) {
throw new CoreException(CCorePlugin.createStatus("Interrupted", e));
}
}
public void dispose() {
CoreModel.getDefault().removeElementChangedListener(this);
}
@Override
public void elementChanged(ElementChangedEvent event) {
// Only respond to post change events
if (event.getType() != ElementChangedEvent.POST_CHANGE)
return;
synchronized (changed) {
changed[0] = true;
changed.notifyAll();
}
}
}

View file

@ -27,6 +27,7 @@ import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.FileManager;
import org.eclipse.cdt.core.testplugin.util.ModelJoiner;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;