blob: fcf0e225ea5fcaab240e0c8d4875badc5041fa7c [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.testFramework;
import com.intellij.concurrency.JobSchedulerImpl;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.ide.util.treeView.AbstractTreeStructure;
import com.intellij.idea.Bombed;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.extensions.ExtensionsArea;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.util.*;
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.VirtualFileFilter;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.io.ZipUtil;
import com.intellij.util.ui.UIUtil;
import junit.framework.AssertionFailedError;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.junit.Assert;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.InvocationEvent;
import java.io.*;
import java.lang.ref.SoftReference;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.JarFile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author yole
*/
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public class PlatformTestUtil {
public static final boolean COVERAGE_ENABLED_BUILD = "true".equals(System.getProperty("idea.coverage.enabled.build"));
private static final boolean SKIP_HEADLESS = GraphicsEnvironment.isHeadless();
private static final boolean SKIP_SLOW = Boolean.getBoolean("skip.slow.tests.locally");
public static <T> void registerExtension(final ExtensionPointName<T> name, final T t, final Disposable parentDisposable) {
registerExtension(Extensions.getRootArea(), name, t, parentDisposable);
}
public static <T> void registerExtension(final ExtensionsArea area, final ExtensionPointName<T> name, final T t, final Disposable parentDisposable) {
final ExtensionPoint<T> extensionPoint = area.getExtensionPoint(name.getName());
extensionPoint.registerExtension(t);
Disposer.register(parentDisposable, new Disposable() {
@Override
public void dispose() {
extensionPoint.unregisterExtension(t);
}
});
}
@Nullable
protected static String toString(@Nullable Object node, @Nullable Queryable.PrintInfo printInfo) {
if (node instanceof AbstractTreeNode) {
if (printInfo != null) {
return ((AbstractTreeNode)node).toTestString(printInfo);
}
else {
@SuppressWarnings({"deprecation", "UnnecessaryLocalVariable"})
final String presentation = ((AbstractTreeNode)node).getTestPresentation();
return presentation;
}
}
if (node == null) {
return "NULL";
}
return node.toString();
}
public static String print(JTree tree, boolean withSelection) {
return print(tree, withSelection, null);
}
public static String print(JTree tree, boolean withSelection, @Nullable Condition<String> nodePrintCondition) {
StringBuilder buffer = new StringBuilder();
final Collection<String> strings = printAsList(tree, withSelection, nodePrintCondition);
for (String string : strings) {
buffer.append(string).append("\n");
}
return buffer.toString();
}
public static Collection<String> printAsList(JTree tree, boolean withSelection, @Nullable Condition<String> nodePrintCondition) {
Collection<String> strings = new ArrayList<String>();
Object root = tree.getModel().getRoot();
printImpl(tree, root, strings, 0, withSelection, nodePrintCondition);
return strings;
}
private static void printImpl(JTree tree,
Object root,
Collection<String> strings,
int level,
boolean withSelection,
@Nullable Condition<String> nodePrintCondition) {
DefaultMutableTreeNode defaultMutableTreeNode = (DefaultMutableTreeNode)root;
final Object userObject = defaultMutableTreeNode.getUserObject();
String nodeText;
if (userObject != null) {
nodeText = toString(userObject, null);
}
else {
nodeText = "null";
}
if (nodePrintCondition != null && !nodePrintCondition.value(nodeText)) return;
final StringBuilder buff = new StringBuilder();
StringUtil.repeatSymbol(buff, ' ', level);
final boolean expanded = tree.isExpanded(new TreePath(defaultMutableTreeNode.getPath()));
if (!defaultMutableTreeNode.isLeaf()) {
buff.append(expanded ? "-" : "+");
}
final boolean selected = tree.getSelectionModel().isPathSelected(new TreePath(defaultMutableTreeNode.getPath()));
if (withSelection && selected) {
buff.append("[");
}
buff.append(nodeText);
if (withSelection && selected) {
buff.append("]");
}
strings.add(buff.toString());
int childCount = tree.getModel().getChildCount(root);
if (expanded) {
for (int i = 0; i < childCount; i++) {
printImpl(tree, tree.getModel().getChild(root, i), strings, level + 1, withSelection, nodePrintCondition);
}
}
}
public static void assertTreeEqual(JTree tree, @NonNls String expected) {
assertTreeEqual(tree, expected, false);
}
public static void assertTreeEqualIgnoringNodesOrder(JTree tree, @NonNls String expected) {
assertTreeEqualIgnoringNodesOrder(tree, expected, false);
}
public static void assertTreeEqual(JTree tree, String expected, boolean checkSelected) {
String treeStringPresentation = print(tree, checkSelected);
assertEquals(expected, treeStringPresentation);
}
public static void assertTreeEqualIgnoringNodesOrder(JTree tree, String expected, boolean checkSelected) {
final Collection<String> actualNodesPresentation = printAsList(tree, checkSelected, null);
final List<String> expectedNodes = StringUtil.split(expected, "\n");
UsefulTestCase.assertSameElements(actualNodesPresentation, expectedNodes);
}
@TestOnly
public static void waitForAlarm(final int delay) throws InterruptedException {
assert !ApplicationManager.getApplication().isWriteAccessAllowed(): "It's a bad idea to wait for an alarm under the write action. Somebody creates an alarm which requires read action and you are deadlocked.";
assert ApplicationManager.getApplication().isDispatchThread();
final AtomicBoolean invoked = new AtomicBoolean();
final Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
alarm.addRequest(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
alarm.addRequest(new Runnable() {
@Override
public void run() {
invoked.set(true);
}
}, delay);
}
});
}
}, delay);
UIUtil.dispatchAllInvocationEvents();
boolean sleptAlready = false;
while (!invoked.get()) {
UIUtil.dispatchAllInvocationEvents();
//noinspection BusyWait
Thread.sleep(sleptAlready ? 10 : delay);
sleptAlready = true;
}
UIUtil.dispatchAllInvocationEvents();
}
@TestOnly
public static void dispatchAllInvocationEventsInIdeEventQueue() throws InterruptedException {
assert SwingUtilities.isEventDispatchThread() : Thread.currentThread();
final EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
while (true) {
AWTEvent event = eventQueue.peekEvent();
if (event == null) break;
AWTEvent event1 = eventQueue.getNextEvent();
if (event1 instanceof InvocationEvent) {
IdeEventQueue.getInstance().dispatchEvent(event1);
}
}
}
private static Date raidDate(Bombed bombed) {
final Calendar instance = Calendar.getInstance();
instance.set(Calendar.YEAR, bombed.year());
instance.set(Calendar.MONTH, bombed.month());
instance.set(Calendar.DAY_OF_MONTH, bombed.day());
instance.set(Calendar.HOUR_OF_DAY, bombed.time());
instance.set(Calendar.MINUTE, 0);
return instance.getTime();
}
public static boolean bombExplodes(Bombed bombedAnnotation) {
Date now = new Date();
return now.after(raidDate(bombedAnnotation));
}
public static boolean isRotten(Bombed bomb) {
long bombRotPeriod = 30L * 24 * 60 * 60 * 1000; // month
return new Date().after(new Date(raidDate(bomb).getTime() + bombRotPeriod));
}
public static StringBuilder print(AbstractTreeStructure structure,
Object node,
int currentLevel,
@Nullable Comparator comparator,
int maxRowCount,
char paddingChar,
@Nullable Queryable.PrintInfo printInfo) {
StringBuilder buffer = new StringBuilder();
doPrint(buffer, currentLevel, node, structure, comparator, maxRowCount, 0, paddingChar, printInfo);
return buffer;
}
private static int doPrint(StringBuilder buffer,
int currentLevel,
Object node,
AbstractTreeStructure structure,
@Nullable Comparator comparator,
int maxRowCount,
int currentLine,
char paddingChar,
@Nullable Queryable.PrintInfo printInfo) {
if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine;
StringUtil.repeatSymbol(buffer, paddingChar, currentLevel);
buffer.append(toString(node, printInfo)).append("\n");
currentLine++;
Object[] children = structure.getChildElements(node);
if (comparator != null) {
ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children));
@SuppressWarnings({"UnnecessaryLocalVariable", "unchecked"}) Comparator<Object> c = comparator;
Collections.sort(list, c);
children = ArrayUtil.toObjectArray(list);
}
for (Object child : children) {
currentLine = doPrint(buffer, currentLevel + 1, child, structure, comparator, maxRowCount, currentLine, paddingChar, printInfo);
}
return currentLine;
}
public static String print(Object[] objects) {
return print(Arrays.asList(objects));
}
public static String print(Collection c) {
StringBuilder result = new StringBuilder();
for (Iterator iterator = c.iterator(); iterator.hasNext();) {
Object each = iterator.next();
result.append(toString(each, null));
if (iterator.hasNext()) {
result.append("\n");
}
}
return result.toString();
}
public static String print(ListModel model) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < model.getSize(); i++) {
result.append(toString(model.getElementAt(i), null));
result.append("\n");
}
return result.toString();
}
public static String print(JTree tree) {
return print(tree, false);
}
public static void assertTreeStructureEquals(final AbstractTreeStructure treeStructure, final String expected) {
assertEquals(expected, print(treeStructure, treeStructure.getRootElement(), 0, null, -1, ' ', null).toString());
}
public static void invokeNamedAction(final String actionId) {
final AnAction action = ActionManager.getInstance().getAction(actionId);
assertNotNull(action);
final Presentation presentation = new Presentation();
@SuppressWarnings("deprecation") final DataContext context = DataManager.getInstance().getDataContext();
final AnActionEvent event = new AnActionEvent(null, context, "", presentation, ActionManager.getInstance(), 0);
action.update(event);
Assert.assertTrue(presentation.isEnabled());
action.actionPerformed(event);
}
public static void assertTiming(final String message, final long expectedMs, final long actual) {
if (COVERAGE_ENABLED_BUILD) return;
final long expectedOnMyMachine = Math.max(1, expectedMs * Timings.MACHINE_TIMING / Timings.ETALON_TIMING);
// Allow 10% more in case of test machine is busy.
String logMessage = message;
if (actual > expectedOnMyMachine) {
int percentage = (int)(100.0 * (actual - expectedOnMyMachine) / expectedOnMyMachine);
logMessage += ". Operation took " + percentage + "% longer than expected";
}
logMessage += ". Expected on my machine: " + expectedOnMyMachine + "." +
" Actual: " + actual + "." +
" Expected on Standard machine: " + expectedMs + ";" +
" Actual on Standard: " + actual * Timings.ETALON_TIMING / Timings.MACHINE_TIMING + ";" +
" Timings: CPU=" + Timings.CPU_TIMING +
", I/O=" + Timings.IO_TIMING + "." +
" (" + (int)(Timings.MACHINE_TIMING*1.0/Timings.ETALON_TIMING*100) + "% of the Standard)" +
".";
final double acceptableChangeFactor = 1.1;
if (actual < expectedOnMyMachine) {
System.out.println(logMessage);
TeamCityLogger.info(logMessage);
}
else if (actual < expectedOnMyMachine * acceptableChangeFactor) {
TeamCityLogger.warning(logMessage, null);
}
else {
// throw AssertionFailedError to try one more time
throw new AssertionFailedError(logMessage);
}
}
/**
* example usage: startPerformanceTest("calculating pi",100, testRunnable).cpuBound().assertTiming();
*/
public static TestInfo startPerformanceTest(@NonNls @NotNull String message, int expectedMs, @NotNull ThrowableRunnable test) {
return new TestInfo(test, expectedMs,message);
}
// calculates average of the median values in the selected part of the array. E.g. for part=3 returns average in the middle third.
public static long averageAmongMedians(@NotNull long[] time, int part) {
assert part >= 1;
int n = time.length;
Arrays.sort(time);
long total = 0;
for (int i= n /2- n / part /2; i< n /2+ n / part /2; i++) {
total += time[i];
}
int middlePartLength = n / part;
return middlePartLength == 0 ? 0 : total / middlePartLength;
}
public static boolean canRunTest(@NotNull Class testCaseClass) {
if (!SKIP_SLOW && !SKIP_HEADLESS) {
return true;
}
for (Class<?> clazz = testCaseClass; clazz != null; clazz = clazz.getSuperclass()) {
if (SKIP_HEADLESS && clazz.getAnnotation(SkipInHeadlessEnvironment.class) != null) {
System.out.println("Class '" + testCaseClass.getName() + "' is skipped because it requires working UI environment");
return false;
}
if (SKIP_SLOW && clazz.getAnnotation(SkipSlowTestLocally.class) != null) {
System.out.println("Class '" + testCaseClass.getName() + "' is skipped because it is dog slow");
return false;
}
}
return true;
}
public static void assertPathsEqual(@Nullable String expected, @Nullable String actual) {
if (expected != null) expected = FileUtil.toSystemIndependentName(expected);
if (actual != null) actual = FileUtil.toSystemIndependentName(actual);
assertEquals(expected, actual);
}
@NotNull
public static String getRtJarPath() {
String home = System.getProperty("java.home");
return SystemInfo.isAppleJvm ? FileUtil.toCanonicalPath(home + "/../Classes/classes.jar") : home + "/lib/rt.jar";
}
public static class TestInfo {
private final ThrowableRunnable test; // runnable to measure
private final int expectedMs; // millis the test is expected to run
private ThrowableRunnable setup; // to run before each test
private boolean usesAllCPUCores; // true if the test runs faster on multi-core
private int attempts = 4; // number of retries if performance failed
private final String message; // to print on fail
private boolean adjustForIO = true; // true if test uses IO, timings need to be re-calibrated according to this agent disk performance
private boolean adjustForCPU = true; // true if test uses CPU, timings need to be re-calibrated according to this agent CPU speed
private TestInfo(@NotNull ThrowableRunnable test, int expectedMs, String message) {
this.test = test;
this.expectedMs = expectedMs;
assert expectedMs > 0 : "Expected must be > 0. Was: "+ expectedMs;
this.message = message;
}
public TestInfo setup(@NotNull ThrowableRunnable setup) { assert this.setup==null; this.setup = setup; return this; }
public TestInfo usesAllCPUCores() { assert adjustForCPU : "This test configured to be io-bound, it cannot use all cores"; usesAllCPUCores = true; return this; }
public TestInfo cpuBound() { adjustForIO = false; adjustForCPU = true; return this; }
public TestInfo ioBound() { adjustForIO = true; adjustForCPU = false; return this; }
public TestInfo attempts(int attempts) { this.attempts = attempts; return this; }
public void assertTiming() {
assert expectedMs != 0 : "Must call .expect() before run test";
if (COVERAGE_ENABLED_BUILD) return;
Timings.getStatistics(); // warm-up, measure
while (true) {
attempts--;
long start;
try {
if (setup != null) setup.run();
start = System.currentTimeMillis();
test.run();
}
catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
long finish = System.currentTimeMillis();
long duration = finish - start;
int expectedOnMyMachine = expectedMs;
if (adjustForCPU) {
expectedOnMyMachine = adjust(expectedOnMyMachine, Timings.CPU_TIMING, Timings.ETALON_CPU_TIMING);
expectedOnMyMachine = usesAllCPUCores ? expectedOnMyMachine * 8 / JobSchedulerImpl.CORES_COUNT : expectedOnMyMachine;
}
if (adjustForIO) {
expectedOnMyMachine = adjust(expectedOnMyMachine, Timings.IO_TIMING, Timings.ETALON_IO_TIMING);
}
// Allow 10% more in case of test machine is busy.
String logMessage = message;
if (duration > expectedOnMyMachine) {
int percentage = (int)(100.0 * (duration - expectedOnMyMachine) / expectedOnMyMachine);
logMessage += ": " + percentage + "% longer";
}
logMessage +=
". Expected: " + formatTime(expectedOnMyMachine) + ". Actual: " + formatTime(duration) + "." + Timings.getStatistics();
final double acceptableChangeFactor = 1.1;
if (duration < expectedOnMyMachine) {
int percentage = (int)(100.0 * (expectedOnMyMachine - duration) / expectedOnMyMachine);
logMessage = percentage + "% faster. " + logMessage;
TeamCityLogger.info(logMessage);
System.out.println("SUCCESS: " + logMessage);
}
else if (duration < expectedOnMyMachine * acceptableChangeFactor) {
TeamCityLogger.warning(logMessage, null);
System.out.println("WARNING: " + logMessage);
}
else {
// try one more time
if (attempts == 0) {
//try {
// Object result = Class.forName("com.intellij.util.ProfilingUtil").getMethod("captureCPUSnapshot").invoke(null);
// System.err.println("CPU snapshot captured in '"+result+"'");
//}
//catch (Exception e) {
//}
throw new AssertionFailedError(logMessage);
}
System.gc();
System.gc();
System.gc();
String s = "Another epic fail (remaining attempts: " + attempts + "): " + logMessage;
TeamCityLogger.warning(s, null);
System.err.println(s);
//if (attempts == 1) {
// try {
// Class.forName("com.intellij.util.ProfilingUtil").getMethod("startCPUProfiling").invoke(null);
// }
// catch (Exception e) {
// }
//}
continue;
}
break;
}
}
private static String formatTime(long millis) {
String hint = "";
DecimalFormat format = new DecimalFormat("#.0", DecimalFormatSymbols.getInstance(Locale.US));
if (millis >= 60 * 1000) hint = format.format(millis / 60 / 1000.f) + "m";
if (millis >= 1000) hint += (hint.isEmpty() ? "" : " ") + format.format(millis / 1000.f) + "s";
String result = millis + "ms";
if (!hint.isEmpty()) {
result = result + " (" + hint + ")";
}
return result;
}
private static int adjust(int expectedOnMyMachine, long thisTiming, long ethanolTiming) {
// most of our algorithms are quadratic. sad but true.
double speed = 1.0 * thisTiming / ethanolTiming;
double delta = speed < 1
? 0.9 + Math.pow(speed - 0.7, 2)
: 0.45 + Math.pow(speed - 0.25, 2);
expectedOnMyMachine *= delta;
return expectedOnMyMachine;
}
}
public static void assertTiming(String message, long expected, @NotNull Runnable actionToMeasure) {
assertTiming(message, expected, 4, actionToMeasure);
}
public static long measure(@NotNull Runnable actionToMeasure) {
long start = System.currentTimeMillis();
actionToMeasure.run();
long finish = System.currentTimeMillis();
return finish - start;
}
public static void assertTiming(String message, long expected, int attempts, @NotNull Runnable actionToMeasure) {
while (true) {
attempts--;
long duration = measure(actionToMeasure);
try {
assertTiming(message, expected, duration);
break;
}
catch (AssertionFailedError e) {
if (attempts == 0) throw e;
System.gc();
System.gc();
System.gc();
String s = "Another epic fail (remaining attempts: " + attempts + "): " + e.getMessage();
TeamCityLogger.warning(s, null);
System.err.println(s);
}
}
}
private static HashMap<String, VirtualFile> buildNameToFileMap(VirtualFile[] files, @Nullable VirtualFileFilter filter) {
HashMap<String, VirtualFile> map = new HashMap<String, VirtualFile>();
for (VirtualFile file : files) {
if (filter != null && !filter.accept(file)) continue;
map.put(file.getName(), file);
}
return map;
}
public static void assertDirectoriesEqual(VirtualFile dirAfter, VirtualFile dirBefore) throws IOException {
assertDirectoriesEqual(dirAfter, dirBefore, null);
}
@SuppressWarnings("UnsafeVfsRecursion")
public static void assertDirectoriesEqual(VirtualFile dirAfter, VirtualFile dirBefore, @Nullable VirtualFileFilter fileFilter) throws IOException {
FileDocumentManager.getInstance().saveAllDocuments();
VirtualFile[] childrenAfter = dirAfter.getChildren();
if (dirAfter.isInLocalFileSystem() && dirAfter.getFileSystem() != TempFileSystem.getInstance()) {
File[] ioAfter = new File(dirAfter.getPath()).listFiles();
shallowCompare(childrenAfter, ioAfter);
}
VirtualFile[] childrenBefore = dirBefore.getChildren();
if (dirBefore.isInLocalFileSystem() && dirBefore.getFileSystem() != TempFileSystem.getInstance()) {
File[] ioBefore = new File(dirBefore.getPath()).listFiles();
shallowCompare(childrenBefore, ioBefore);
}
HashMap<String, VirtualFile> mapAfter = buildNameToFileMap(childrenAfter, fileFilter);
HashMap<String, VirtualFile> mapBefore = buildNameToFileMap(childrenBefore, fileFilter);
Set<String> keySetAfter = mapAfter.keySet();
Set<String> keySetBefore = mapBefore.keySet();
assertEquals(dirAfter.getPath(), keySetAfter, keySetBefore);
for (String name : keySetAfter) {
VirtualFile fileAfter = mapAfter.get(name);
VirtualFile fileBefore = mapBefore.get(name);
if (fileAfter.isDirectory()) {
assertDirectoriesEqual(fileAfter, fileBefore, fileFilter);
}
else {
assertFilesEqual(fileAfter, fileBefore);
}
}
}
private static void shallowCompare(VirtualFile[] vfs, @Nullable File[] io) {
List<String> vfsPaths = new ArrayList<String>();
for (VirtualFile file : vfs) {
vfsPaths.add(file.getPath());
}
List<String> ioPaths = new ArrayList<String>();
if (io != null) {
for (File file : io) {
ioPaths.add(file.getPath().replace(File.separatorChar, '/'));
}
}
assertEquals(sortAndJoin(vfsPaths), sortAndJoin(ioPaths));
}
private static String sortAndJoin(List<String> strings) {
Collections.sort(strings);
StringBuilder buf = new StringBuilder();
for (String string : strings) {
buf.append(string);
buf.append('\n');
}
return buf.toString();
}
public static void assertFilesEqual(VirtualFile fileAfter, VirtualFile fileBefore) throws IOException {
try {
assertJarFilesEqual(VfsUtilCore.virtualToIoFile(fileAfter), VfsUtilCore.virtualToIoFile(fileBefore));
}
catch (IOException e) {
FileDocumentManager manager = FileDocumentManager.getInstance();
Document docBefore = manager.getDocument(fileBefore);
boolean canLoadBeforeText = !fileBefore.getFileType().isBinary() || fileBefore.getFileType() == FileTypes.UNKNOWN;
String textB = docBefore != null
? docBefore.getText()
: !canLoadBeforeText
? null
: LoadTextUtil.getTextByBinaryPresentation(fileBefore.contentsToByteArray(false), fileBefore).toString();
Document docAfter = manager.getDocument(fileAfter);
boolean canLoadAfterText = !fileBefore.getFileType().isBinary() || fileBefore.getFileType() == FileTypes.UNKNOWN;
String textA = docAfter != null
? docAfter.getText()
: !canLoadAfterText
? null
: LoadTextUtil.getTextByBinaryPresentation(fileAfter.contentsToByteArray(false), fileAfter).toString();
if (textA != null && textB != null) {
assertEquals(fileAfter.getPath(), textA, textB);
}
else {
Assert.assertArrayEquals(fileAfter.getPath(), fileAfter.contentsToByteArray(), fileBefore.contentsToByteArray());
}
}
}
public static void assertJarFilesEqual(File file1, File file2) throws IOException {
final File tempDirectory1;
final File tempDirectory2;
final JarFile jarFile1 = new JarFile(file1);
try {
final JarFile jarFile2 = new JarFile(file2);
try {
tempDirectory1 = PlatformTestCase.createTempDir("tmp1");
tempDirectory2 = PlatformTestCase.createTempDir("tmp2");
ZipUtil.extract(jarFile1, tempDirectory1, null);
ZipUtil.extract(jarFile2, tempDirectory2, null);
}
finally {
jarFile2.close();
}
}
finally {
jarFile1.close();
}
final VirtualFile dirAfter = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempDirectory1);
assertNotNull(tempDirectory1.toString(), dirAfter);
final VirtualFile dirBefore = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempDirectory2);
assertNotNull(tempDirectory2.toString(), dirBefore);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
dirAfter.refresh(false, true);
dirBefore.refresh(false, true);
}
});
assertDirectoriesEqual(dirAfter, dirBefore);
}
public static void assertElementsEqual(final Element expected, final Element actual) throws IOException {
if (!JDOMUtil.areElementsEqual(expected, actual)) {
assertEquals(printElement(expected), printElement(actual));
}
}
public static void assertElementEquals(final String expected, final Element actual) {
try {
assertElementsEqual(JDOMUtil.loadDocument(expected).getRootElement(), actual);
}
catch (IOException e) {
throw new AssertionError(e);
}
catch (JDOMException e) {
throw new AssertionError(e);
}
}
public static String printElement(final Element element) throws IOException {
final StringWriter writer = new StringWriter();
JDOMUtil.writeElement(element, writer, "\n");
return writer.getBuffer().toString();
}
public static String getCommunityPath() {
final String homePath = PathManager.getHomePath();
if (new File(homePath, "community/.idea").isDirectory()) {
return homePath + File.separatorChar + "community";
}
return homePath;
}
public static Comparator<AbstractTreeNode> createComparator(final Queryable.PrintInfo printInfo) {
return new Comparator<AbstractTreeNode>() {
@Override
public int compare(final AbstractTreeNode o1, final AbstractTreeNode o2) {
String displayText1 = o1.toTestString(printInfo);
String displayText2 = o2.toTestString(printInfo);
return Comparing.compare(displayText1, displayText2);
}
};
}
@NotNull
public static <T> T notNull(@Nullable T t) {
assertNotNull(t);
return t;
}
@NotNull
public static String loadFileText(@NotNull String fileName) throws IOException {
return StringUtil.convertLineSeparators(FileUtil.loadFile(new File(fileName)));
}
public static void tryGcSoftlyReachableObjects() {
List<Object> list = ContainerUtil.newArrayList();
for (int i = 0; i < 100; i++) {
list.add(new SoftReference<byte[]>(new byte[(int)Runtime.getRuntime().freeMemory() / 2]));
}
}
public static void withEncoding(@NotNull String encoding, @NotNull final Runnable r) {
withEncoding(encoding, new ThrowableRunnable() {
@Override
public void run() throws Throwable {
r.run();
}
});
}
public static void withEncoding(@NotNull String encoding, @NotNull ThrowableRunnable r) {
Charset oldCharset = Charset.defaultCharset();
try {
try {
patchSystemFileEncoding(encoding);
r.run();
}
finally {
patchSystemFileEncoding(oldCharset.name());
}
}
catch (Throwable t) {
throw new RuntimeException(t);
}
}
private static void patchSystemFileEncoding(String encoding) throws NoSuchFieldException, IllegalAccessException {
ReflectionUtil.resetField(Charset.class, Charset.class, "defaultCharset");
System.setProperty("file.encoding", encoding);
}
public static void withStdErrSuppressed(@NotNull Runnable r) {
PrintStream std = System.err;
System.setErr(new PrintStream(NULL));
try {
r.run();
}
finally {
System.setErr(std);
}
}
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
private static final OutputStream NULL = new OutputStream() {
@Override
public void write(int b) throws IOException { }
};
}