blob: 1f5b176c3029ee955307d67bcc578cb48d5fc237 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ui.leaktest;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.eclipse.jdt.testplugin.util.DisplayHelper;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.jdt.ui.leaktest.reftracker.ReferenceTracker;
import org.eclipse.jdt.ui.leaktest.reftracker.ReferenceVisitor;
import org.eclipse.jdt.ui.leaktest.reftracker.ReferencedObject;
/**
* Base class for leak test cases.
*/
public class LeakTestCase {
public static class MulipleCollectorVisitor extends ReferenceVisitor {
private ReferenceVisitor[] fVisitors;
public MulipleCollectorVisitor(ReferenceVisitor[] visitors) {
fVisitors= visitors;
}
@Override
public boolean visit(ReferencedObject object, Class<?> clazz, boolean firstVisit) {
boolean visitChildren= false;
for (ReferenceVisitor visitor : fVisitors) {
boolean res= visitor.visit(object, clazz, firstVisit);
visitChildren |= res;
}
return visitChildren;
}
}
private InstancesOfTypeCollector collect(String requestedTypeName) {
InstancesOfTypeCollector requestor= new InstancesOfTypeCollector(requestedTypeName, false);
calmDown();
new ReferenceTracker(requestor).start(getClass().getClassLoader());
return requestor;
}
private InstancesOfTypeCollector[] collect(String[] requestedTypeNames) {
final InstancesOfTypeCollector[] requestors= new InstancesOfTypeCollector[requestedTypeNames.length];
for (int i= 0; i < requestors.length; i++) {
requestors[i]= new InstancesOfTypeCollector(requestedTypeNames[i], false);
}
calmDown();
ReferenceVisitor visitor= new ReferenceVisitor() {
@Override
public boolean visit(ReferencedObject object, Class<?> clazz, boolean firstVisit) {
for (InstancesOfTypeCollector requestor : requestors) {
requestor.visit(object, clazz, firstVisit);
}
return true;
}
};
new ReferenceTracker(visitor).start(getClass().getClassLoader());
return requestors;
}
/*
* @see junit.framework.TestCase#setUp()
* @since 3.4
*/
@Before
public void setUp() throws Exception {
// Ensure active page to allow test being run
IWorkbenchWindow activeWindow= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (activeWindow.getActivePage() == null) {
activeWindow.openPage(null);
}
}
private void calmDown() {
// Make sure we wait > 500, to allow e.g. TextViewer.queuePostSelectionChanged(boolean)
// and OpenStrategy to time out and release references in delayed runnables.
new DisplayHelper() {
@Override
protected boolean condition() {
return false;
}
}.waitForCondition(Display.getCurrent(), 1000);
for (int i= 0; i < 10; i++) {
System.gc();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
}
/**
* Asserts that the instance count of the given class is as expected.
*
* @param clazz the class of the instances to count
* @param expected the expected instance count
*/
public void assertInstanceCount(final Class<?> clazz, final int expected) {
int numTries= 2;
while (true) {
InstancesOfTypeCollector requestor= collect(clazz.getName());
int actual= requestor.getNumberOfResults();
if (expected == actual) {
return;
}
numTries--;
assertNotEquals("Expected instance count: " + expected + ", actual: " + actual + "\n" + requestor.getResultString(), 0, numTries);
}
}
/**
* Asserts that the instance count of the given class is as expected.
*
* @param classNames the types names of the instances to count
* @param expected the expected instance count
*/
public void assertInstanceCount(final String[] classNames, final int[] expected) {
int numTries= 2;
while (true) {
InstancesOfTypeCollector[] requestors= collect(classNames);
boolean success= true;
for (int k= 0; success && k < requestors.length; k++) {
if (expected[k] != requestors[k].getNumberOfResults()) {
success= false;
}
}
if (success)
return;
numTries--;
if (numTries == 0) {
StringBuilder buf= new StringBuilder();
for (int k= 0; k < requestors.length; k++) {
int actual= requestors[k].getNumberOfResults();
if (expected[k] != actual) {
buf.append("Expected instance count: " + expected[k] + ", actual: " + actual + "\n" + requestors[k].getResultString()).append("\n---------------------\n");
}
}
fail(buf.toString());
}
}
}
/**
* Returns the number of instances of a given class that are live (not garbage).
* @param clazz The class of the instances to count
* @return Returns the current number of instances of the given class or <code>-1</code> if
* no connection is established.
*/
protected int getInstanceCount(Class<?> clazz) {
InstancesOfTypeCollector requestor= collect(clazz.getName());
return requestor.getNumberOfResults();
}
/**
* Assert that two counts are different. The method does not fail if the profile connection has
* not established (e.g. because profiling is not supported on the given platform).
*
* @param startCount the start count
* @param endCount the end count
*/
protected void assertDifferentCount(int startCount, int endCount) {
assertDifferentCount(null, startCount, endCount);
}
/**
* Assert that two counts are different. The method does not fail if the profile connection has
* not established (e.g. because profiling is not supported on the given platform)
*
* @param message Message to be printed if the test fails.
*
* @param startCount the start count
* @param endCount the end count
*/
protected void assertDifferentCount(String message, int startCount, int endCount) {
if (startCount == endCount) {
String str= message != null ? message + ": " : "";
fail(str + "instance count is not different: (" + startCount + " / " + endCount + " )");
}
}
/**
* Assert that two counts are equal. The method does not fail if the profile connection has not
* established (e.g. because profiling is not supported on the given platform).
*
* @param startCount the start count
* @param endCount the end count
*/
protected void assertEqualCount(int startCount, int endCount) {
assertEqualCount(null, startCount, endCount);
}
/**
* Assert that two counts are equal. The method does not fail if the profile connection has not
* established (e.g. because profiling is not supported on the given platform).
*
* @param message Message to be printed if the test fails.
* @param startCount the start count
* @param endCount the end count
*/
protected void assertEqualCount(String message, int startCount, int endCount) {
if (startCount != endCount) {
// only compare if connection could be established
String str= message != null ? message + ": " : "";
fail(str + "instance count is not the same: (" + startCount + " / " + endCount + " )");
}
}
}