| /******************************************************************************* |
| * Copyright (c) 2006, 2016 Wind River Systems, 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: |
| * Markus Schorn - initial API and implementation |
| * Andrew Ferguson (Symbian) |
| * Sergey Prigogin (Google) |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.nd.util; |
| |
| import junit.framework.AssertionFailedError; |
| import junit.framework.Test; |
| import junit.framework.TestCase; |
| import junit.framework.TestFailure; |
| import junit.framework.TestResult; |
| import junit.framework.TestSuite; |
| |
| import org.eclipse.core.resources.IResourceStatus; |
| import org.eclipse.core.runtime.ILog; |
| 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 java.io.File; |
| 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; |
| |
| public class BaseTestCase extends TestCase { |
| private static final String DEFAULT_INDEXER_TIMEOUT_SEC = "10"; |
| private 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; |
| |
| private boolean fExpectFailure; |
| private int fBugNumber; |
| private int fExpectedLoggedNonOK; |
| private Deque<File> filesToDeleteOnTearDown= new ArrayDeque<>(); |
| |
| public BaseTestCase() { |
| super(); |
| } |
| |
| public BaseTestCase(String name) { |
| super(name); |
| } |
| |
| public static NullProgressMonitor npm() { |
| return new NullProgressMonitor(); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| //CModelListener.sSuppressUpdateOfLastRecentlyUsed= true; |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| for (File file; (file = this.filesToDeleteOnTearDown.pollLast()) != null;) { |
| file.delete(); |
| } |
| ResourceHelper.cleanUp(); |
| //TestScannerProvider.clear(); |
| super.tearDown(); |
| } |
| |
| protected void deleteOnTearDown(File file) { |
| this.filesToDeleteOnTearDown.add(file); |
| } |
| |
| protected File createTempFile(String prefix, String suffix) throws IOException { |
| File file = File.createTempFile(prefix, suffix); |
| this.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); |
| this.filesToDeleteOnTearDown.add(file); |
| return file; |
| } |
| |
| public static TestSuite suite(Class<? extends BaseTestCase> clazz) { |
| return suite(clazz, null); |
| } |
| |
| protected static TestSuite suite(Class<? extends BaseTestCase> clazz, String failingTestPrefix) { |
| TestSuite suite= new TestSuite(clazz); |
| Test failing= getFailingTests(clazz, failingTestPrefix); |
| if (failing != null) { |
| suite.addTest(failing); |
| } |
| return suite; |
| } |
| |
| private static Test getFailingTests(Class<? extends BaseTestCase> clazz, String prefix) { |
| TestSuite suite= new TestSuite("Failing Tests"); |
| HashSet<String> names= new HashSet<>(); |
| Class<?> superClass= clazz; |
| while (Test.class.isAssignableFrom(superClass) && !TestCase.class.equals(superClass)) { |
| Method[] methods= superClass.getDeclaredMethods(); |
| for (Method method : methods) { |
| addFailingMethod(suite, method, names, clazz, prefix); |
| } |
| superClass= superClass.getSuperclass(); |
| } |
| if (suite.countTestCases() == 0) { |
| return null; |
| } |
| return suite; |
| } |
| |
| private static void addFailingMethod(TestSuite suite, Method m, Set<String> names, |
| Class<? extends BaseTestCase> clazz, String prefix) { |
| String name = m.getName(); |
| if (!names.add(name)) { |
| return; |
| } |
| if (name.startsWith("test") || (prefix != null && !name.startsWith(prefix))) { |
| return; |
| } |
| if (name.equals("tearDown") || name.equals("setUp") || name.equals("runBare")) { |
| return; |
| } |
| if (Modifier.isPublic(m.getModifiers())) { |
| Class<?>[] parameters = m.getParameterTypes(); |
| Class<?> returnType = m.getReturnType(); |
| if (parameters.length == 0 && returnType.equals(Void.TYPE)) { |
| Test test = TestSuite.createTest(clazz, name); |
| ((BaseTestCase) test).setExpectFailure(0); |
| suite.addTest(test); |
| } |
| } |
| } |
| |
| @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 ILog log = Package.getLog(); |
| if (log != null) { // Iff we don't run as a JUnit Plugin Test. |
| log.addLogListener(logListener); |
| } |
| |
| Throwable testThrowable= null; |
| try { |
| try { |
| super.runBare(); |
| } catch (Throwable e) { |
| testThrowable= e; |
| } |
| |
| if (statusLog.size() != this.fExpectedLoggedNonOK) { |
| StringBuilder msg= new StringBuilder("Expected number (" + this.fExpectedLoggedNonOK + ") of "); |
| msg.append("Non-OK status objects in log differs from actual (" + statusLog.size() + ").\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" + s.getMessage() + " "); |
| |
| 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; |
| } |
| } finally { |
| if (log != null) { |
| log.removeLogListener(logListener); |
| } |
| } |
| |
| if (testThrowable != null) |
| throw testThrowable; |
| } |
| |
| @Override |
| public void run(TestResult result) { |
| if (!this.fExpectFailure || Boolean.parseBoolean(System.getProperty("SHOW_EXPECTED_FAILURES"))) { |
| super.run(result); |
| return; |
| } |
| |
| result.startTest(this); |
| |
| TestResult r = new TestResult(); |
| super.run(r); |
| if (r.failureCount() == 1) { |
| TestFailure failure= r.failures().nextElement(); |
| String msg= failure.exceptionMessage(); |
| if (msg != null && msg.startsWith("Method \"" + getName() + "\"")) { |
| result.addFailure(this, new AssertionFailedError(msg)); |
| } |
| } else if (r.errorCount() == 0 && r.failureCount() == 0) { |
| String err = "Unexpected success of " + getName(); |
| if (this.fBugNumber > 0) { |
| err += ", bug #" + this.fBugNumber; |
| } |
| result.addFailure(this, new AssertionFailedError(err)); |
| } |
| |
| result.endTest(this); |
| } |
| |
| public void setExpectFailure(int bugNumber) { |
| this.fExpectFailure= true; |
| this.fBugNumber= bugNumber; |
| } |
| |
| /** |
| * 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) { |
| this.fExpectedLoggedNonOK= count; |
| } |
| } |