Switch to 201 platform

This commit is contained in:
Nikolay Krasko
2020-06-30 19:50:57 +03:00
parent 50863b6985
commit 21fa2bf98c
186 changed files with 1877 additions and 1878 deletions
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.test.testFramework;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory;
import com.intellij.diagnostic.PerformanceWatcher;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
@@ -23,20 +25,33 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.impl.DocumentCommitProcessor;
import com.intellij.psi.impl.DocumentCommitThread;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.rt.execution.junit.FileComparisonFailure;
import com.intellij.testFramework.*;
import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
import com.intellij.util.Consumer;
import com.intellij.util.ReflectionUtil;
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.containers.PeekableIterator;
import com.intellij.util.containers.PeekableIteratorWrapper;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.FileBasedIndexImpl;
import com.intellij.util.lang.CompoundRuntimeException;
import com.intellij.util.ui.UIUtil;
import gnu.trove.Equality;
@@ -47,11 +62,11 @@ import org.jdom.Element;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.test.IdeaSystemPropertiesForParallelRunConfigurator;
import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
import org.jetbrains.kotlin.types.AbstractTypeChecker;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
import org.junit.Assert;
import org.junit.ComparisonFailure;
import java.io.File;
import java.io.FileNotFoundException;
@@ -61,14 +76,16 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@SuppressWarnings("UseOfSystemOutOrSystemErr")
@SuppressWarnings("ALL")
public abstract class KtUsefulTestCase extends TestCase {
public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
private static final String TEMP_DIR_MARKER = "unitTest_";
public static final String TEMP_DIR_MARKER = "unitTest_";
public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
@@ -79,24 +96,34 @@ public abstract class KtUsefulTestCase extends TestCase {
private Application application;
static {
IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
//TODO: investigate and enable
//IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
Logger.setFactory(TestLoggerFactory.class);
}
protected static final Logger LOG = Logger.getInstance(KtUsefulTestCase.class);
@NotNull
protected final Disposable myTestRootDisposable = new TestDisposable();
private final Disposable myTestRootDisposable = new TestDisposable();
private static final String ourPathToKeep = null;
static Path ourPathToKeep;
private final List<String> myPathsToKeep = new ArrayList<>();
private File myTempDir;
private String myTempDir;
private static final String DEFAULT_SETTINGS_EXTERNALIZED;
private static final CodeInsightSettings defaultSettings = new CodeInsightSettings();
static {
// Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
System.setProperty("apple.awt.UIElement", "true");
try {
Element oldS = new Element("temp");
defaultSettings.writeExternal(oldS);
DEFAULT_SETTINGS_EXTERNALIZED = JDOMUtil.writeElement(oldS);
}
catch (Exception e) {
throw new RuntimeException(e);
}
// -- KOTLIN ADDITIONAL START --
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
@@ -105,6 +132,42 @@ public abstract class KtUsefulTestCase extends TestCase {
// -- KOTLIN ADDITIONAL END --
}
/**
* Pass here the exception you want to be thrown first
* E.g.<pre>
* {@code
* void tearDown() {
* try {
* doTearDowns();
* }
* catch(Exception e) {
* addSuppressedException(e);
* }
* finally {
* super.tearDown();
* }
* }
* }
* </pre>
*
*/
protected void addSuppressedException(@NotNull Throwable e) {
List<Throwable> list = mySuppressedExceptions;
if (list == null) {
mySuppressedExceptions = list = new SmartList<>();
}
list.add(e);
}
private List<Throwable> mySuppressedExceptions;
public KtUsefulTestCase() {
}
public KtUsefulTestCase(@NotNull String name) {
super(name);
}
protected boolean shouldContainTempFiles() {
return true;
}
@@ -122,11 +185,17 @@ public abstract class KtUsefulTestCase extends TestCase {
super.setUp();
if (shouldContainTempFiles()) {
String testName = FileUtil.sanitizeFileName(getTestName(true));
if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
String testName = null;
if (policy != null) {
testName = policy.getPerTestTempDirName();
}
if (testName == null) {
testName = FileUtil.sanitizeFileName(getTestName(true));
}
testName = new File(testName).getName(); // in case the test name contains file separators
myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER + testName, "", false).getPath();
FileUtil.resetCanonicalTempPathCache(myTempDir);
}
boolean isStressTest = isStressTest();
@@ -137,6 +206,16 @@ public abstract class KtUsefulTestCase extends TestCase {
// turn off Disposer debugging for performance tests
Disposer.setDebugMode(!isStressTest);
if (isIconRequired()) {
// ensure that IconLoader will use dummy empty icon
IconLoader.deactivate();
//IconManager.activate();
}
}
protected boolean isIconRequired() {
return false;
}
@Override
@@ -145,6 +224,11 @@ public abstract class KtUsefulTestCase extends TestCase {
// don't use method references here to make stack trace reading easier
//noinspection Convert2MethodRef
new RunAll(
() -> {
if (isIconRequired()) {
//IconManager.deactivate();
}
},
() -> disposeRootDisposable(),
() -> cleanupSwingDataStructures(),
() -> cleanupDeleteOnExitHookList(),
@@ -153,7 +237,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (shouldContainTempFiles()) {
FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
if (hasTmpFilesToKeep()) {
File[] files = myTempDir.listFiles();
File[] files = new File(myTempDir).listFiles();
if (files != null) {
for (File file : files) {
if (!shouldKeepTmpFile(file)) {
@@ -163,15 +247,14 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
else {
FileUtil.delete(myTempDir);
FileUtil.delete(new File(myTempDir));
}
}
},
() -> UIUtil.removeLeakingAppleListeners()
).run();
() -> waitForAppLeakingThreads(10, TimeUnit.SECONDS)
).run(ObjectUtils.notNull(mySuppressedExceptions, Collections.emptyList()));
}
finally {
super.tearDown();
// -- KOTLIN ADDITIONAL START --
TestApplicationUtilKt.resetApplicationToNull(application);
application = null;
@@ -188,12 +271,12 @@ public abstract class KtUsefulTestCase extends TestCase {
}
private boolean hasTmpFilesToKeep() {
return ourPathToKeep != null && FileUtil.isAncestor(myTempDir.getPath(), ourPathToKeep, false) || !myPathsToKeep.isEmpty();
return ourPathToKeep != null && FileUtil.isAncestor(myTempDir, ourPathToKeep.toString(), false) || !myPathsToKeep.isEmpty();
}
private boolean shouldKeepTmpFile(@NotNull File file) {
String path = file.getPath();
if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
if (FileUtil.pathsEqual(path, ourPathToKeep.toString())) return true;
for (String pathToKeep : myPathsToKeep) {
if (FileUtil.pathsEqual(path, pathToKeep)) return true;
}
@@ -201,7 +284,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
private static final Class DELETE_ON_EXIT_HOOK_CLASS;
private static final Class<?> DELETE_ON_EXIT_HOOK_CLASS;
static {
Class<?> aClass;
try {
@@ -237,12 +320,45 @@ public abstract class KtUsefulTestCase extends TestCase {
@SuppressWarnings("ConstantConditions")
private static void cleanupSwingDataStructures() throws Exception {
Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
Map componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
Map<?, ?> componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
componentKeyStrokeMap.clear();
Map containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
Map<?, ?> containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
containerMap.clear();
}
static void doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings, @NotNull CodeStyleSettings currentCodeStyleSettings) {
final CodeInsightSettings settings = CodeInsightSettings.getInstance();
// don't use method references here to make stack trace reading easier
//noinspection Convert2MethodRef
new RunAll()
.append(() -> {
try {
checkCodeInsightSettingsEqual(defaultSettings, settings);
}
catch (AssertionError error) {
CodeInsightSettings clean = new CodeInsightSettings();
for (Field field : clean.getClass().getFields()) {
try {
ReflectionUtil.copyFieldValue(clean, settings, field);
}
catch (Exception ignored) {
}
}
throw error;
}
})
.append(() -> {
currentCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA);
try {
checkCodeStyleSettingsEqual(oldCodeStyleSettings, currentCodeStyleSettings);
}
finally {
currentCodeStyleSettings.clearCodeStyleSettings();
}
})
.run();
}
@NotNull
public Disposable getTestRootDisposable() {
return myTestRootDisposable;
@@ -252,13 +368,11 @@ public abstract class KtUsefulTestCase extends TestCase {
protected void runTest() throws Throwable {
final Throwable[] throwables = new Throwable[1];
AtomicBoolean completed = new AtomicBoolean(false);
Runnable runnable = () -> {
try {
//TestLoggerFactory.onTestStarted();
TestLoggerFactory.onTestStarted();
super.runTest();
TestLoggerFactory.onTestFinished(true);
completed.set(true);
}
catch (InvocationTargetException e) {
TestLoggerFactory.onTestFinished(false);
@@ -281,9 +395,6 @@ public abstract class KtUsefulTestCase extends TestCase {
if (throwables[0] != null) {
throw throwables[0];
}
if (!completed.get()) {
throw new IllegalStateException("test didn't start");
}
}
protected boolean shouldRunTest() {
@@ -291,19 +402,18 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
//IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
//if (policy != null && !policy.runInDispatchThread()) {
// runnable.run();
//}
//else {
if (runInDispatchThread()) {
EdtTestUtilKt.runInEdtAndWait(() -> {
runnable.run();
return null;
});
//}
}
else {
runnable.run();
}
}
private void defaultRunBare() throws Throwable {
protected void defaultRunBare() throws Throwable {
Throwable exception = null;
try {
long setupStart = System.nanoTime();
@@ -324,11 +434,17 @@ public abstract class KtUsefulTestCase extends TestCase {
logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
}
catch (Throwable tearingDown) {
if (exception == null) exception = tearingDown;
else exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
if (exception == null) {
exception = tearingDown;
}
else {
exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
}
}
}
if (exception != null) throw exception;
if (exception != null) {
throw exception;
}
}
/**
@@ -368,7 +484,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (runInDispatchThread()) {
TestRunnerUtil.replaceIdeEventQueueSafely();
com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
}
else {
defaultRunBare();
@@ -376,13 +492,20 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected boolean runInDispatchThread() {
//IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
//if (policy != null) {
// return policy.runInDispatchThread();
//}
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
if (policy != null) {
return policy.runInDispatchThread();
}
return true;
}
/**
* If you want a more shorter name than runInEdtAndWait.
*/
protected void edt(@NotNull ThrowableRunnable<Throwable> runnable) {
EdtTestUtil.runInEdtAndWait(runnable);
}
@NotNull
public static String toString(@NotNull Iterable<?> collection) {
if (!collection.iterator().hasNext()) {
@@ -515,9 +638,20 @@ public abstract class KtUsefulTestCase extends TestCase {
}
public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
ArrayList<T> copy = new ArrayList<>(collection);
copy.retainAll(expected);
assertOrderedEquals(toString(collection), copy, expected);
PeekableIterator<T> expectedIt = new PeekableIteratorWrapper<>(expected.iterator());
PeekableIterator<T> actualIt = new PeekableIteratorWrapper<>(collection.iterator());
while (actualIt.hasNext() && expectedIt.hasNext()) {
T expectedElem = expectedIt.peek();
T actualElem = actualIt.peek();
if (expectedElem.equals(actualElem)) {
expectedIt.next();
}
actualIt.next();
}
if (expectedIt.hasNext()) {
throw new ComparisonFailure("", toString(expected), toString(collection));
}
}
@SafeVarargs
@@ -592,7 +726,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (collection.size() != checkers.length) {
Assert.fail(toString(collection));
}
Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
Set<Consumer<T>> checkerSet = ContainerUtil.set(checkers);
int i = 0;
Throwable lastError = null;
for (final T actual : collection) {
@@ -767,7 +901,7 @@ public abstract class KtUsefulTestCase extends TestCase {
//noinspection UseOfSystemOutOrSystemErr
System.out.println("File " + filePath + " created.");
}
fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
fileText = FileUtil.loadFile(new File(filePath), StandardCharsets.UTF_8);
}
catch (FileNotFoundException e) {
VfsTestUtil.overwriteTestData(filePath, actualText);
@@ -784,14 +918,14 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
Class aClass = test.getClass();
Class<?> aClass = test.getClass();
while (aClass != null) {
clearDeclaredFields(test, aClass);
aClass = aClass.getSuperclass();
}
}
public static void clearDeclaredFields(@NotNull Object test, @NotNull Class aClass) throws IllegalAccessException {
public static void clearDeclaredFields(@NotNull Object test, @NotNull Class<?> aClass) throws IllegalAccessException {
for (final Field field : aClass.getDeclaredFields()) {
final String name = field.getDeclaringClass().getName();
if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
@@ -817,6 +951,14 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
private static void checkCodeInsightSettingsEqual(@NotNull CodeInsightSettings oldSettings, @NotNull CodeInsightSettings settings) {
if (!oldSettings.equals(settings)) {
Element newS = new Element("temp");
settings.writeExternal(newS);
Assert.assertEquals("Code insight settings damaged", DEFAULT_SETTINGS_EXTERNALIZED, JDOMUtil.writeElement(newS));
}
}
public boolean isPerformanceTest() {
String testName = getName();
String className = getClass().getSimpleName();
@@ -843,6 +985,21 @@ public abstract class KtUsefulTestCase extends TestCase {
return name != null && (name.contains("Stress") || name.contains("Slow"));
}
public static void doPostponedFormatting(@NotNull Project project) {
DocumentUtil.writeInRunUndoTransparentAction(() -> {
PsiDocumentManager.getInstance(project).commitAllDocuments();
PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();
});
}
/**
* Checks that code block throw corresponding exception.
*
* @param exceptionCase Block annotated with some exception type
*/
protected void assertException(@NotNull AbstractExceptionCase<?> exceptionCase) {
assertException(exceptionCase, null);
}
/**
* Checks that code block throw corresponding exception with expected error msg.
@@ -856,6 +1013,42 @@ public abstract class KtUsefulTestCase extends TestCase {
assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
}
/**
* Checks that the code block throws an exception of the specified class.
*
* @param exceptionClass Expected exception type
* @param runnable Block annotated with some exception type
*/
public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
@NotNull ThrowableRunnable<T> runnable) {
assertThrows(exceptionClass, null, runnable);
}
/**
* Checks that the code block throws an exception of the specified class with expected error msg.
* If expected error message is null it will not be checked.
*
* @param exceptionClass Expected exception type
* @param expectedErrorMsgPart expected error message, of any
* @param runnable Block annotated with some exception type
*/
@SuppressWarnings({"unchecked", "SameParameterValue"})
public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
@Nullable String expectedErrorMsgPart,
@NotNull ThrowableRunnable<T> runnable) {
assertExceptionOccurred(true, new AbstractExceptionCase() {
@Override
public Class<Throwable> getExpectedExceptionClass() {
return (Class<Throwable>)exceptionClass;
}
@Override
public void tryClosure() throws Throwable {
runnable.run();
}
}, expectedErrorMsgPart);
}
/**
* Checks that code block doesn't throw corresponding exception.
*
@@ -878,21 +1071,23 @@ public abstract class KtUsefulTestCase extends TestCase {
private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
@NotNull AbstractExceptionCase<T> exceptionCase,
String expectedErrorMsg) throws T {
String expectedErrorMsgPart) throws T {
boolean wasThrown = false;
try {
exceptionCase.tryClosure();
}
catch (Throwable e) {
Throwable cause = e;
if (shouldOccur) {
wasThrown = true;
final String errorMessage = exceptionCase.getAssertionErrorMessage();
assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), e.getClass());
if (expectedErrorMsg != null) {
assertEquals("Compare error messages", expectedErrorMsg, e.getMessage());
assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), cause.getClass());
if (expectedErrorMsgPart != null) {
assertTrue(cause.getMessage(), cause.getMessage().contains(expectedErrorMsgPart));
}
}
else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
else if (exceptionCase.getExpectedExceptionClass().equals(cause.getClass())) {
wasThrown = true;
//noinspection UseOfSystemOutOrSystemErr
@@ -900,7 +1095,7 @@ public abstract class KtUsefulTestCase extends TestCase {
//noinspection UseOfSystemOutOrSystemErr
e.printStackTrace(System.out);
fail("Exception isn't expected here. Exception message: " + e.getMessage());
fail("Exception isn't expected here. Exception message: " + cause.getMessage());
}
else {
throw e;
@@ -937,7 +1132,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
public static void refreshRecursively(@NotNull VirtualFile file) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<Void>() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
file.getChildren();
@@ -947,11 +1142,27 @@ public abstract class KtUsefulTestCase extends TestCase {
file.refresh(false, true);
}
@Nullable
public static VirtualFile refreshAndFindFile(@NotNull final File file) {
return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
}
public static void waitForAppLeakingThreads(long timeout, @NotNull TimeUnit timeUnit) {
EdtTestUtil.runInEdtAndWait(() -> {
Application app = ApplicationManager.getApplication();
if (app != null && !app.isDisposed()) {
FileBasedIndexImpl index = (FileBasedIndexImpl)app.getServiceIfCreated(FileBasedIndex.class);
if (index != null) {
index.getChangedFilesCollector().waitForVfsEventsExecuted(timeout, timeUnit);
}
DocumentCommitThread commitThread = (DocumentCommitThread)app.getServiceIfCreated(DocumentCommitProcessor.class);
if (commitThread != null) {
commitThread.waitForAllCommits(timeout, timeUnit);
}
}
});
}
protected class TestDisposable implements Disposable {
private volatile boolean myDisposed;
@@ -972,5 +1183,5 @@ public abstract class KtUsefulTestCase extends TestCase {
String testName = getTestName(false);
return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
}
};
}
}
}
@@ -16,8 +16,6 @@
package org.jetbrains.kotlin.test.testFramework;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory;
import com.intellij.diagnostic.PerformanceWatcher;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
@@ -25,33 +23,20 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.impl.DocumentCommitProcessor;
import com.intellij.psi.impl.DocumentCommitThread;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.rt.execution.junit.FileComparisonFailure;
import com.intellij.testFramework.*;
import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
import com.intellij.util.*;
import com.intellij.util.Consumer;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.PeekableIterator;
import com.intellij.util.containers.PeekableIteratorWrapper;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.FileBasedIndexImpl;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.lang.CompoundRuntimeException;
import com.intellij.util.ui.UIUtil;
import gnu.trove.Equality;
@@ -62,11 +47,11 @@ import org.jdom.Element;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.test.IdeaSystemPropertiesForParallelRunConfigurator;
import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
import org.jetbrains.kotlin.types.AbstractTypeChecker;
import org.jetbrains.kotlin.types.FlexibleTypeImpl;
import org.junit.Assert;
import org.junit.ComparisonFailure;
import java.io.File;
import java.io.FileNotFoundException;
@@ -76,16 +61,14 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@SuppressWarnings("ALL")
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public abstract class KtUsefulTestCase extends TestCase {
public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
public static final String TEMP_DIR_MARKER = "unitTest_";
private static final String TEMP_DIR_MARKER = "unitTest_";
public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
@@ -96,34 +79,24 @@ public abstract class KtUsefulTestCase extends TestCase {
private Application application;
static {
IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
//TODO: investigate and enable
//IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
Logger.setFactory(TestLoggerFactory.class);
}
protected static final Logger LOG = Logger.getInstance(KtUsefulTestCase.class);
@NotNull
private final Disposable myTestRootDisposable = new TestDisposable();
protected final Disposable myTestRootDisposable = new TestDisposable();
static Path ourPathToKeep;
private static final String ourPathToKeep = null;
private final List<String> myPathsToKeep = new ArrayList<>();
private String myTempDir;
private File myTempDir;
private static final String DEFAULT_SETTINGS_EXTERNALIZED;
private static final CodeInsightSettings defaultSettings = new CodeInsightSettings();
static {
// Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
System.setProperty("apple.awt.UIElement", "true");
try {
Element oldS = new Element("temp");
defaultSettings.writeExternal(oldS);
DEFAULT_SETTINGS_EXTERNALIZED = JDOMUtil.writeElement(oldS);
}
catch (Exception e) {
throw new RuntimeException(e);
}
// -- KOTLIN ADDITIONAL START --
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
@@ -132,42 +105,6 @@ public abstract class KtUsefulTestCase extends TestCase {
// -- KOTLIN ADDITIONAL END --
}
/**
* Pass here the exception you want to be thrown first
* E.g.<pre>
* {@code
* void tearDown() {
* try {
* doTearDowns();
* }
* catch(Exception e) {
* addSuppressedException(e);
* }
* finally {
* super.tearDown();
* }
* }
* }
* </pre>
*
*/
protected void addSuppressedException(@NotNull Throwable e) {
List<Throwable> list = mySuppressedExceptions;
if (list == null) {
mySuppressedExceptions = list = new SmartList<>();
}
list.add(e);
}
private List<Throwable> mySuppressedExceptions;
public KtUsefulTestCase() {
}
public KtUsefulTestCase(@NotNull String name) {
super(name);
}
protected boolean shouldContainTempFiles() {
return true;
}
@@ -185,17 +122,11 @@ public abstract class KtUsefulTestCase extends TestCase {
super.setUp();
if (shouldContainTempFiles()) {
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
String testName = null;
if (policy != null) {
testName = policy.getPerTestTempDirName();
}
if (testName == null) {
testName = FileUtil.sanitizeFileName(getTestName(true));
}
String testName = FileUtil.sanitizeFileName(getTestName(true));
if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
testName = new File(testName).getName(); // in case the test name contains file separators
myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER + testName, "", false).getPath();
FileUtil.resetCanonicalTempPathCache(myTempDir);
myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
}
boolean isStressTest = isStressTest();
@@ -206,16 +137,6 @@ public abstract class KtUsefulTestCase extends TestCase {
// turn off Disposer debugging for performance tests
Disposer.setDebugMode(!isStressTest);
if (isIconRequired()) {
// ensure that IconLoader will use dummy empty icon
IconLoader.deactivate();
//IconManager.activate();
}
}
protected boolean isIconRequired() {
return false;
}
@Override
@@ -224,11 +145,6 @@ public abstract class KtUsefulTestCase extends TestCase {
// don't use method references here to make stack trace reading easier
//noinspection Convert2MethodRef
new RunAll(
() -> {
if (isIconRequired()) {
//IconManager.deactivate();
}
},
() -> disposeRootDisposable(),
() -> cleanupSwingDataStructures(),
() -> cleanupDeleteOnExitHookList(),
@@ -237,7 +153,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (shouldContainTempFiles()) {
FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
if (hasTmpFilesToKeep()) {
File[] files = new File(myTempDir).listFiles();
File[] files = myTempDir.listFiles();
if (files != null) {
for (File file : files) {
if (!shouldKeepTmpFile(file)) {
@@ -247,14 +163,15 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
else {
FileUtil.delete(new File(myTempDir));
FileUtil.delete(myTempDir);
}
}
},
() -> waitForAppLeakingThreads(10, TimeUnit.SECONDS)
).run(ObjectUtils.notNull(mySuppressedExceptions, Collections.emptyList()));
() -> UIUtil.removeLeakingAppleListeners()
).run();
}
finally {
super.tearDown();
// -- KOTLIN ADDITIONAL START --
TestApplicationUtilKt.resetApplicationToNull(application);
application = null;
@@ -271,12 +188,12 @@ public abstract class KtUsefulTestCase extends TestCase {
}
private boolean hasTmpFilesToKeep() {
return ourPathToKeep != null && FileUtil.isAncestor(myTempDir, ourPathToKeep.toString(), false) || !myPathsToKeep.isEmpty();
return ourPathToKeep != null && FileUtil.isAncestor(myTempDir.getPath(), ourPathToKeep, false) || !myPathsToKeep.isEmpty();
}
private boolean shouldKeepTmpFile(@NotNull File file) {
String path = file.getPath();
if (FileUtil.pathsEqual(path, ourPathToKeep.toString())) return true;
if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
for (String pathToKeep : myPathsToKeep) {
if (FileUtil.pathsEqual(path, pathToKeep)) return true;
}
@@ -284,7 +201,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
private static final Class<?> DELETE_ON_EXIT_HOOK_CLASS;
private static final Class DELETE_ON_EXIT_HOOK_CLASS;
static {
Class<?> aClass;
try {
@@ -320,45 +237,12 @@ public abstract class KtUsefulTestCase extends TestCase {
@SuppressWarnings("ConstantConditions")
private static void cleanupSwingDataStructures() throws Exception {
Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
Map<?, ?> componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
Map componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
componentKeyStrokeMap.clear();
Map<?, ?> containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
Map containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
containerMap.clear();
}
static void doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings, @NotNull CodeStyleSettings currentCodeStyleSettings) {
final CodeInsightSettings settings = CodeInsightSettings.getInstance();
// don't use method references here to make stack trace reading easier
//noinspection Convert2MethodRef
new RunAll()
.append(() -> {
try {
checkCodeInsightSettingsEqual(defaultSettings, settings);
}
catch (AssertionError error) {
CodeInsightSettings clean = new CodeInsightSettings();
for (Field field : clean.getClass().getFields()) {
try {
ReflectionUtil.copyFieldValue(clean, settings, field);
}
catch (Exception ignored) {
}
}
throw error;
}
})
.append(() -> {
currentCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA);
try {
checkCodeStyleSettingsEqual(oldCodeStyleSettings, currentCodeStyleSettings);
}
finally {
currentCodeStyleSettings.clearCodeStyleSettings();
}
})
.run();
}
@NotNull
public Disposable getTestRootDisposable() {
return myTestRootDisposable;
@@ -368,11 +252,13 @@ public abstract class KtUsefulTestCase extends TestCase {
protected void runTest() throws Throwable {
final Throwable[] throwables = new Throwable[1];
AtomicBoolean completed = new AtomicBoolean(false);
Runnable runnable = () -> {
try {
TestLoggerFactory.onTestStarted();
//TestLoggerFactory.onTestStarted();
super.runTest();
TestLoggerFactory.onTestFinished(true);
completed.set(true);
}
catch (InvocationTargetException e) {
TestLoggerFactory.onTestFinished(false);
@@ -395,6 +281,9 @@ public abstract class KtUsefulTestCase extends TestCase {
if (throwables[0] != null) {
throw throwables[0];
}
if (!completed.get()) {
throw new IllegalStateException("test didn't start");
}
}
protected boolean shouldRunTest() {
@@ -402,18 +291,19 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
if (runInDispatchThread()) {
//IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
//if (policy != null && !policy.runInDispatchThread()) {
// runnable.run();
//}
//else {
EdtTestUtilKt.runInEdtAndWait(() -> {
runnable.run();
return null;
});
}
else {
runnable.run();
}
//}
}
protected void defaultRunBare() throws Throwable {
private void defaultRunBare() throws Throwable {
Throwable exception = null;
try {
long setupStart = System.nanoTime();
@@ -434,17 +324,11 @@ public abstract class KtUsefulTestCase extends TestCase {
logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
}
catch (Throwable tearingDown) {
if (exception == null) {
exception = tearingDown;
}
else {
exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
}
if (exception == null) exception = tearingDown;
else exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
}
}
if (exception != null) {
throw exception;
}
if (exception != null) throw exception;
}
/**
@@ -484,7 +368,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (runInDispatchThread()) {
TestRunnerUtil.replaceIdeEventQueueSafely();
EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
}
else {
defaultRunBare();
@@ -492,20 +376,13 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected boolean runInDispatchThread() {
IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
if (policy != null) {
return policy.runInDispatchThread();
}
//IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
//if (policy != null) {
// return policy.runInDispatchThread();
//}
return true;
}
/**
* If you want a more shorter name than runInEdtAndWait.
*/
protected void edt(@NotNull ThrowableRunnable<Throwable> runnable) {
EdtTestUtil.runInEdtAndWait(runnable);
}
@NotNull
public static String toString(@NotNull Iterable<?> collection) {
if (!collection.iterator().hasNext()) {
@@ -638,20 +515,9 @@ public abstract class KtUsefulTestCase extends TestCase {
}
public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
PeekableIterator<T> expectedIt = new PeekableIteratorWrapper<>(expected.iterator());
PeekableIterator<T> actualIt = new PeekableIteratorWrapper<>(collection.iterator());
while (actualIt.hasNext() && expectedIt.hasNext()) {
T expectedElem = expectedIt.peek();
T actualElem = actualIt.peek();
if (expectedElem.equals(actualElem)) {
expectedIt.next();
}
actualIt.next();
}
if (expectedIt.hasNext()) {
throw new ComparisonFailure("", toString(expected), toString(collection));
}
ArrayList<T> copy = new ArrayList<>(collection);
copy.retainAll(expected);
assertOrderedEquals(toString(collection), copy, expected);
}
@SafeVarargs
@@ -726,7 +592,7 @@ public abstract class KtUsefulTestCase extends TestCase {
if (collection.size() != checkers.length) {
Assert.fail(toString(collection));
}
Set<Consumer<T>> checkerSet = ContainerUtil.set(checkers);
Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
int i = 0;
Throwable lastError = null;
for (final T actual : collection) {
@@ -901,7 +767,7 @@ public abstract class KtUsefulTestCase extends TestCase {
//noinspection UseOfSystemOutOrSystemErr
System.out.println("File " + filePath + " created.");
}
fileText = FileUtil.loadFile(new File(filePath), StandardCharsets.UTF_8);
fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
}
catch (FileNotFoundException e) {
VfsTestUtil.overwriteTestData(filePath, actualText);
@@ -918,14 +784,14 @@ public abstract class KtUsefulTestCase extends TestCase {
}
protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
Class<?> aClass = test.getClass();
Class aClass = test.getClass();
while (aClass != null) {
clearDeclaredFields(test, aClass);
aClass = aClass.getSuperclass();
}
}
public static void clearDeclaredFields(@NotNull Object test, @NotNull Class<?> aClass) throws IllegalAccessException {
public static void clearDeclaredFields(@NotNull Object test, @NotNull Class aClass) throws IllegalAccessException {
for (final Field field : aClass.getDeclaredFields()) {
final String name = field.getDeclaringClass().getName();
if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
@@ -951,14 +817,6 @@ public abstract class KtUsefulTestCase extends TestCase {
}
}
private static void checkCodeInsightSettingsEqual(@NotNull CodeInsightSettings oldSettings, @NotNull CodeInsightSettings settings) {
if (!oldSettings.equals(settings)) {
Element newS = new Element("temp");
settings.writeExternal(newS);
Assert.assertEquals("Code insight settings damaged", DEFAULT_SETTINGS_EXTERNALIZED, JDOMUtil.writeElement(newS));
}
}
public boolean isPerformanceTest() {
String testName = getName();
String className = getClass().getSimpleName();
@@ -985,21 +843,6 @@ public abstract class KtUsefulTestCase extends TestCase {
return name != null && (name.contains("Stress") || name.contains("Slow"));
}
public static void doPostponedFormatting(@NotNull Project project) {
DocumentUtil.writeInRunUndoTransparentAction(() -> {
PsiDocumentManager.getInstance(project).commitAllDocuments();
PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();
});
}
/**
* Checks that code block throw corresponding exception.
*
* @param exceptionCase Block annotated with some exception type
*/
protected void assertException(@NotNull AbstractExceptionCase<?> exceptionCase) {
assertException(exceptionCase, null);
}
/**
* Checks that code block throw corresponding exception with expected error msg.
@@ -1013,42 +856,6 @@ public abstract class KtUsefulTestCase extends TestCase {
assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
}
/**
* Checks that the code block throws an exception of the specified class.
*
* @param exceptionClass Expected exception type
* @param runnable Block annotated with some exception type
*/
public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
@NotNull ThrowableRunnable<T> runnable) {
assertThrows(exceptionClass, null, runnable);
}
/**
* Checks that the code block throws an exception of the specified class with expected error msg.
* If expected error message is null it will not be checked.
*
* @param exceptionClass Expected exception type
* @param expectedErrorMsgPart expected error message, of any
* @param runnable Block annotated with some exception type
*/
@SuppressWarnings({"unchecked", "SameParameterValue"})
public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
@Nullable String expectedErrorMsgPart,
@NotNull ThrowableRunnable<T> runnable) {
assertExceptionOccurred(true, new AbstractExceptionCase() {
@Override
public Class<Throwable> getExpectedExceptionClass() {
return (Class<Throwable>)exceptionClass;
}
@Override
public void tryClosure() throws Throwable {
runnable.run();
}
}, expectedErrorMsgPart);
}
/**
* Checks that code block doesn't throw corresponding exception.
*
@@ -1071,23 +878,21 @@ public abstract class KtUsefulTestCase extends TestCase {
private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
@NotNull AbstractExceptionCase<T> exceptionCase,
String expectedErrorMsgPart) throws T {
String expectedErrorMsg) throws T {
boolean wasThrown = false;
try {
exceptionCase.tryClosure();
}
catch (Throwable e) {
Throwable cause = e;
if (shouldOccur) {
wasThrown = true;
final String errorMessage = exceptionCase.getAssertionErrorMessage();
assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), cause.getClass());
if (expectedErrorMsgPart != null) {
assertTrue(cause.getMessage(), cause.getMessage().contains(expectedErrorMsgPart));
assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), e.getClass());
if (expectedErrorMsg != null) {
assertEquals("Compare error messages", expectedErrorMsg, e.getMessage());
}
}
else if (exceptionCase.getExpectedExceptionClass().equals(cause.getClass())) {
else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
wasThrown = true;
//noinspection UseOfSystemOutOrSystemErr
@@ -1095,7 +900,7 @@ public abstract class KtUsefulTestCase extends TestCase {
//noinspection UseOfSystemOutOrSystemErr
e.printStackTrace(System.out);
fail("Exception isn't expected here. Exception message: " + cause.getMessage());
fail("Exception isn't expected here. Exception message: " + e.getMessage());
}
else {
throw e;
@@ -1132,7 +937,7 @@ public abstract class KtUsefulTestCase extends TestCase {
}
public static void refreshRecursively(@NotNull VirtualFile file) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<Void>() {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
file.getChildren();
@@ -1142,27 +947,11 @@ public abstract class KtUsefulTestCase extends TestCase {
file.refresh(false, true);
}
@Nullable
public static VirtualFile refreshAndFindFile(@NotNull final File file) {
return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
}
public static void waitForAppLeakingThreads(long timeout, @NotNull TimeUnit timeUnit) {
EdtTestUtil.runInEdtAndWait(() -> {
Application app = ApplicationManager.getApplication();
if (app != null && !app.isDisposed()) {
FileBasedIndexImpl index = (FileBasedIndexImpl)app.getServiceIfCreated(FileBasedIndex.class);
if (index != null) {
index.getChangedFilesCollector().waitForVfsEventsExecuted(timeout, timeUnit);
}
DocumentCommitThread commitThread = (DocumentCommitThread)app.getServiceIfCreated(DocumentCommitProcessor.class);
if (commitThread != null) {
commitThread.waitForAllCommits(timeout, timeUnit);
}
}
});
}
protected class TestDisposable implements Disposable {
private volatile boolean myDisposed;
@@ -1183,5 +972,5 @@ public abstract class KtUsefulTestCase extends TestCase {
String testName = getTestName(false);
return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
}
}
}
};
}