mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -28,7 +28,6 @@ import com.intellij.openapi.extensions.*;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.StreamUtil;
|
||||
import com.intellij.openapi.util.io.ZipFileCache;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
@@ -614,7 +613,7 @@ public class PluginManagerCore {
|
||||
String fileURL = StringUtil.replace(file.toURI().toASCIIString(), "!", "%21");
|
||||
URL jarURL = new URL("jar:" + fileURL + "!/META-INF/" + fileName);
|
||||
|
||||
ZipFile zipFile = ZipFileCache.acquire(file.getPath());
|
||||
ZipFile zipFile = new ZipFile(file);
|
||||
try {
|
||||
ZipEntry entry = zipFile.getEntry("META-INF/" + fileName);
|
||||
if (entry != null) {
|
||||
@@ -625,7 +624,7 @@ public class PluginManagerCore {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ZipFileCache.release(zipFile);
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
catch (XmlSerializationException e) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -18,7 +18,6 @@ package com.intellij.openapi.vfs.impl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.ZipFileCache;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import gnu.trove.THashMap;
|
||||
@@ -43,7 +42,7 @@ public class ZipHandler extends ArchiveHandler {
|
||||
Map<String, EntryInfo> map = new THashMap<String, EntryInfo>();
|
||||
map.put("", createRootEntry());
|
||||
|
||||
ZipFile zip = getZipFile();
|
||||
ZipFile zip = new ZipFile(getFileToUse());
|
||||
try {
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
@@ -51,7 +50,7 @@ public class ZipHandler extends ArchiveHandler {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ZipFileCache.release(zip);
|
||||
zip.close();
|
||||
}
|
||||
|
||||
return map;
|
||||
@@ -62,11 +61,6 @@ public class ZipHandler extends ArchiveHandler {
|
||||
return getFile();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ZipFile getZipFile() throws IOException {
|
||||
return ZipFileCache.acquire(getFileToUse().getPath());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private EntryInfo getOrCreate(ZipEntry entry, Map<String, EntryInfo> map, ZipFile zip) {
|
||||
boolean isDirectory = entry.isDirectory();
|
||||
@@ -117,7 +111,7 @@ public class ZipHandler extends ArchiveHandler {
|
||||
@NotNull
|
||||
@Override
|
||||
public byte[] contentsToByteArray(@NotNull String relativePath) throws IOException {
|
||||
ZipFile zip = getZipFile();
|
||||
ZipFile zip = new ZipFile(getFileToUse());
|
||||
try {
|
||||
ZipEntry entry = zip.getEntry(relativePath);
|
||||
if (entry != null) {
|
||||
@@ -133,7 +127,7 @@ public class ZipHandler extends ArchiveHandler {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ZipFileCache.release(zip);
|
||||
zip.close();
|
||||
}
|
||||
|
||||
return ArrayUtil.EMPTY_BYTE_ARRAY;
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.intellij.execution.console;
|
||||
|
||||
import com.intellij.codeInsight.lookup.Lookup;
|
||||
import com.intellij.codeInsight.lookup.LookupManager;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
@@ -76,7 +77,8 @@ public class ConsoleExecuteAction extends DumbAwareAction {
|
||||
if (enabled) {
|
||||
Lookup lookup = LookupManager.getActiveLookup(editor);
|
||||
// we should check getCurrentItem() also - fast typing could produce outdated lookup, such lookup reports isCompletion() true
|
||||
enabled = lookup == null || !lookup.isCompletion() || lookup.getCurrentItem() == null;
|
||||
enabled = lookup == null || !lookup.isCompletion() || lookup.getCurrentItem() == null ||
|
||||
(lookup instanceof LookupImpl && ((LookupImpl)lookup).getFocusDegree() == LookupImpl.FocusDegree.UNFOCUSED);
|
||||
}
|
||||
|
||||
e.getPresentation().setEnabled(enabled);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -44,7 +44,7 @@ public abstract class RefreshQueue {
|
||||
refresh(async, recursive, finishRunnable, getDefaultModalityState(), files);
|
||||
}
|
||||
|
||||
public final void refresh(boolean async, boolean recursive, @Nullable Runnable finishRunnable, @NotNull Collection<VirtualFile> files) {
|
||||
public final void refresh(boolean async, boolean recursive, @Nullable Runnable finishRunnable, @NotNull Collection<? extends VirtualFile> files) {
|
||||
refresh(async, recursive, finishRunnable, getDefaultModalityState(), files);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public abstract class RefreshQueue {
|
||||
boolean recursive,
|
||||
@Nullable Runnable finishRunnable,
|
||||
@NotNull ModalityState state,
|
||||
@NotNull Collection<VirtualFile> files) {
|
||||
@NotNull Collection<? extends VirtualFile> files) {
|
||||
RefreshSession session = createSession(async, recursive, finishRunnable, state);
|
||||
session.addAllFiles(files);
|
||||
session.launch();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -33,7 +33,7 @@ public abstract class RefreshSession {
|
||||
|
||||
public abstract void addFile(@NotNull VirtualFile file);
|
||||
|
||||
public abstract void addAllFiles(@NotNull Collection<VirtualFile> files);
|
||||
public abstract void addAllFiles(@NotNull Collection<? extends VirtualFile> files);
|
||||
|
||||
public void addAllFiles(@NotNull VirtualFile... files) {
|
||||
addAllFiles(Arrays.asList(files));
|
||||
|
||||
@@ -37,15 +37,17 @@ public class IntelliJCheckBoxUI extends DarculaCheckBoxUI {
|
||||
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
|
||||
g.setStroke(new BasicStroke(JBUI.scale(1) *2.0f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
|
||||
|
||||
g.setPaint(getShadowColor(enabled, true));
|
||||
final int x1 = JBUI.scale(5);
|
||||
final int y1 = JBUI.scale(9);
|
||||
final int x2 = JBUI.scale(7);
|
||||
final int y2 = JBUI.scale(11);
|
||||
g.drawLine(x1, y1, x2, y2);
|
||||
g.drawLine(x2, y2, w-JBUI.scale(2) - 1, JBUI.scale(5));
|
||||
if (enabled) {
|
||||
g.setPaint(getShadowColor(true, true));
|
||||
g.drawLine(x1, y1, x2, y2);
|
||||
g.drawLine(x2, y2, w - JBUI.scale(2) - 1, JBUI.scale(5));
|
||||
}
|
||||
g.setPaint(getCheckSignColor(enabled, true));
|
||||
g.drawLine(x1, y1 - 2, x2, y2 - 2);
|
||||
g.drawLine(x2, y2 - 2, w-JBUI.scale(2) - 1, JBUI.scale(5) - 2);
|
||||
g.drawLine(x2, y2 - 2, w - JBUI.scale(2) - 1, JBUI.scale(5) - 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 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.
|
||||
@@ -77,7 +77,7 @@ public class RefreshSessionImpl extends RefreshSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllFiles(@NotNull Collection<VirtualFile> files) {
|
||||
public void addAllFiles(@NotNull Collection<? extends VirtualFile> files) {
|
||||
for (VirtualFile file : files) {
|
||||
if (file == null) {
|
||||
LOG.error("null passed among " + files);
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.ZipFileCache;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VFileProperty;
|
||||
@@ -297,7 +296,7 @@ public class VfsImplUtil {
|
||||
}
|
||||
|
||||
private static class InvalidationState {
|
||||
private Map<String, VirtualFile> rootsToRefresh;
|
||||
private Set<NewVirtualFile> myRootsToRefresh;
|
||||
|
||||
@Nullable
|
||||
public static InvalidationState invalidate(@Nullable InvalidationState state, final String path) {
|
||||
@@ -323,19 +322,18 @@ public class VfsImplUtil {
|
||||
private void registerPathToRefresh(String path, ArchiveFileSystem vfs) {
|
||||
NewVirtualFile root = ManagingFS.getInstance().findRoot(vfs.composeRootPath(path), vfs);
|
||||
if (root != null) {
|
||||
if (rootsToRefresh == null) rootsToRefresh = ContainerUtil.newHashMap();
|
||||
rootsToRefresh.put(path, root);
|
||||
if (myRootsToRefresh == null) myRootsToRefresh = ContainerUtil.newHashSet();
|
||||
myRootsToRefresh.add(root);
|
||||
}
|
||||
}
|
||||
|
||||
public void scheduleRefresh() {
|
||||
if (rootsToRefresh != null) {
|
||||
for (VirtualFile root : rootsToRefresh.values()) {
|
||||
((NewVirtualFile)root).markDirtyRecursively();
|
||||
if (myRootsToRefresh != null) {
|
||||
for (NewVirtualFile root : myRootsToRefresh) {
|
||||
root.markDirtyRecursively();
|
||||
}
|
||||
ZipFileCache.reset(rootsToRefresh.keySet());
|
||||
boolean async = !ApplicationManager.getApplication().isUnitTestMode();
|
||||
RefreshQueue.getInstance().refresh(async, true, null, rootsToRefresh.values());
|
||||
RefreshQueue.getInstance().refresh(async, true, null, myRootsToRefresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +259,11 @@ public abstract class AbstractExpandableItemsHandler<KeyType, ComponentType exte
|
||||
if (forceUpdate || !Comparing.equal(myKey, selected)) {
|
||||
handleSelectionChange(selected, true);
|
||||
}
|
||||
|
||||
// Temporary workaround
|
||||
if (e.getClickCount() == 2) {
|
||||
hideHint();
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleSelectionChange(KeyType selected) {
|
||||
|
||||
+2
@@ -50,6 +50,8 @@ public abstract class GeneralTestEventsProcessor implements Disposable {
|
||||
|
||||
// tree construction events
|
||||
|
||||
public void onRootPresentationAdded(String rootName, String comment) {}
|
||||
|
||||
public void onSuiteTreeNodeAdded(String testName, String locationHint) { }
|
||||
|
||||
public void onSuiteTreeStarted(String suiteName, String locationHint) { }
|
||||
|
||||
+11
@@ -114,6 +114,17 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRootPresentationAdded(final String rootName, final String comment) {
|
||||
addToInvokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myTestsRootNode.setPresentation(rootName);
|
||||
myTestsRootNode.setComment(comment);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuiteTreeNodeAdded(final String testName, final String locationHint) {
|
||||
myTreeBuildBeforeStart = true;
|
||||
|
||||
+14
@@ -214,6 +214,14 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void fireRootPresentationAdded(String rootName, @Nullable String comment) {
|
||||
final GeneralTestEventsProcessor processor = myProcessor;
|
||||
if (processor != null) {
|
||||
processor.onRootPresentationAdded(rootName, comment);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireOnSuiteTreeStarted(String suiteName, String locationHint) {
|
||||
|
||||
final GeneralTestEventsProcessor processor = myProcessor;
|
||||
@@ -308,6 +316,8 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer
|
||||
@NonNls private static final String SUITE_TREE_STARTED = "suiteTreeStarted";
|
||||
@NonNls private static final String SUITE_TREE_ENDED = "suiteTreeEnded";
|
||||
@NonNls private static final String SUITE_TREE_NODE = "suiteTreeNode";
|
||||
@NonNls private static final String ROOT_PRESENTATION = "rootName";
|
||||
|
||||
@NonNls private static final String ATTR_KEY_STATUS = "status";
|
||||
@NonNls private static final String ATTR_VALUE_STATUS_ERROR = "ERROR";
|
||||
@NonNls private static final String ATTR_VALUE_STATUS_WARNING = "WARNING";
|
||||
@@ -489,6 +499,10 @@ public class OutputToGeneralTestEventsConverter implements ProcessOutputConsumer
|
||||
else if (SUITE_TREE_NODE.equals(name)) {
|
||||
fireOnSuiteTreeNodeAdded(msg.getAttributes().get("name"), msg.getAttributes().get(ATTR_KEY_LOCATION_URL));
|
||||
}
|
||||
else if (ROOT_PRESENTATION.equals(name)) {
|
||||
final Map<String, String> attributes = msg.getAttributes();
|
||||
fireRootPresentationAdded(attributes.get("name"), attributes.get("comment"));
|
||||
}
|
||||
else {
|
||||
GeneralToSMTRunnerEventsConvertor.logProblem(LOG, "Unexpected service message:" + name, myTestFrameworkName);
|
||||
}
|
||||
|
||||
@@ -740,6 +740,9 @@ public class SMTestProxy extends AbstractTestProxy {
|
||||
public static class SMRootTestProxy extends SMTestProxy {
|
||||
private boolean myTestsReporterAttached; // false by default
|
||||
|
||||
private String myPresentation;
|
||||
private String myComment;
|
||||
|
||||
public SMRootTestProxy() {
|
||||
super("[root]", true, null);
|
||||
}
|
||||
@@ -752,6 +755,22 @@ public class SMTestProxy extends AbstractTestProxy {
|
||||
return myTestsReporterAttached;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
return myPresentation;
|
||||
}
|
||||
|
||||
public void setPresentation(String presentation) {
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
myComment = comment;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return myComment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractState determineSuiteStateOnFinished() {
|
||||
if (isLeaf() && !isTestsReporterAttached()) {
|
||||
|
||||
+8
-1
@@ -145,7 +145,10 @@ public class TestsPresentationUtil {
|
||||
final TestStateInfo.Magnitude magnitude = testProxy.getMagnitudeInfo();
|
||||
|
||||
final String text;
|
||||
if (magnitude == TestStateInfo.Magnitude.RUNNING_INDEX) {
|
||||
final String presentableName = testProxy.getPresentation();
|
||||
if (presentableName != null) {
|
||||
text = presentableName;
|
||||
} else if (magnitude == TestStateInfo.Magnitude.RUNNING_INDEX) {
|
||||
text = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.running.tests");
|
||||
} else if (magnitude == TestStateInfo.Magnitude.TERMINATED_INDEX) {
|
||||
text = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.was.terminated");
|
||||
@@ -153,6 +156,10 @@ public class TestsPresentationUtil {
|
||||
text = SMTestsRunnerBundle.message("sm.test.runner.ui.tests.tree.presentation.labels.test.results");
|
||||
}
|
||||
renderer.append(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
final String comment = testProxy.getComment();
|
||||
if (comment != null) {
|
||||
renderer.append(" (" + comment + ")", SimpleTextAttributes.GRAY_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
|
||||
public static void formatRootNodeWithoutChildren(final SMTestProxy.SMRootTestProxy testProxy,
|
||||
|
||||
@@ -15,259 +15,26 @@
|
||||
*/
|
||||
package com.intellij.openapi.util.io;
|
||||
|
||||
import com.intellij.openapi.diagnostic.LogUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* <p>Utility class which tries to keep frequently requested .zip files open
|
||||
* to avoid time loss on closing/reopening ZipFile instances.</p>
|
||||
*
|
||||
* <p>Clients obtain a file by calling {@link #acquire(String)}
|
||||
* and indicate the loss of interest to it via {@link #release(ZipFile)}.
|
||||
* Released files are closed after some period of time (about 30 seconds),
|
||||
* unless requested again within the period.</p>
|
||||
*
|
||||
* <p>Since ZipFiles are read-only objects allowing concurrent access,
|
||||
* a same instance may be returned to a different threads requesting a same path.
|
||||
* A file may be closed only after being released by all applicants.</p>
|
||||
*
|
||||
* <p>The class does not expect .zip files on a disk to be changed,
|
||||
* so it may return an outdated instance of ZipFile (reading from it
|
||||
* may return inaccurate data or even cause an exceptions to happen).
|
||||
* It's a clients' responsibility to keep a track of .zip files
|
||||
* and call the {@link #reset(Collection)} method for a paths
|
||||
* which are possibly changed. Reset paths are removed from the cache
|
||||
* and are closed immediately after being released.</p>
|
||||
*/
|
||||
/** @deprecated use {@link ZipFile#ZipFile(String)} and {@link ZipFile#close()} instead (to be removed in IDEA 17) */
|
||||
@SuppressWarnings("unused")
|
||||
public class ZipFileCache {
|
||||
private static final int PERIOD = 10000; // disposer schedule, ms
|
||||
private static final int TIMEOUT = 30000; // released file close delay, ms
|
||||
|
||||
private static class CacheRecord {
|
||||
private final String path;
|
||||
private final ZipFile file;
|
||||
private int count = 1;
|
||||
private long released = 0;
|
||||
|
||||
private CacheRecord(@NotNull String path, @NotNull ZipFile file) throws IOException {
|
||||
this.path = path;
|
||||
this.file = file;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object ourLock = new Object();
|
||||
private static final Map<String, CacheRecord> ourPathCache = ContainerUtil.newTroveMap(FileUtil.PATH_HASHING_STRATEGY);
|
||||
private static final Map<ZipFile, CacheRecord> ourFileCache = ContainerUtil.newHashMap();
|
||||
private static final Map<ZipFile, Integer> ourQueue = ContainerUtil.newHashMap();
|
||||
|
||||
private static final ScheduledThreadPoolExecutor ourExecutor;
|
||||
|
||||
static {
|
||||
ourExecutor = ConcurrencyUtil.newSingleScheduledThreadExecutor("ZipFileCache Dispose", Thread.MIN_PRIORITY);
|
||||
ourExecutor.scheduleWithFixedDelay(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<ZipFile> toClose = getFilesToClose(0, System.currentTimeMillis() - TIMEOUT);
|
||||
if (toClose != null) {
|
||||
close(toClose);
|
||||
}
|
||||
}
|
||||
}, PERIOD, PERIOD, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ZipFile acquire(@NotNull String path) throws IOException {
|
||||
path = toCanonicalPath(path);
|
||||
|
||||
synchronized (ourLock) {
|
||||
CacheRecord record = ourPathCache.get(path);
|
||||
if (record != null) {
|
||||
record.count++;
|
||||
return record.file;
|
||||
}
|
||||
}
|
||||
|
||||
CacheRecord record;
|
||||
ZipFile file = tryOpen(path);
|
||||
|
||||
synchronized (ourLock) {
|
||||
record = ourPathCache.get(path);
|
||||
if (record == null) {
|
||||
record = new CacheRecord(path, file);
|
||||
ourPathCache.put(path, record);
|
||||
ourFileCache.put(file, record);
|
||||
return file;
|
||||
}
|
||||
else {
|
||||
record.count++;
|
||||
}
|
||||
}
|
||||
|
||||
close(file);
|
||||
return record.file;
|
||||
}
|
||||
|
||||
private static String toCanonicalPath(@NotNull String path) {
|
||||
path = FileUtil.toSystemDependentName(path);
|
||||
|
||||
File file = new File(path);
|
||||
try {
|
||||
return file.getCanonicalPath();
|
||||
}
|
||||
catch (IOException e) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
private static ZipFile tryOpen(String path) throws IOException {
|
||||
debug("opening %s", path);
|
||||
try {
|
||||
return new ZipFile(path);
|
||||
}
|
||||
catch (IOException e) {
|
||||
String reason = e.getMessage();
|
||||
if ("too many open files".equalsIgnoreCase(reason) && tryCloseFiles() > 0) {
|
||||
return new ZipFile(path);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int tryCloseFiles() {
|
||||
List<ZipFile> toClose = getFilesToClose(5, 0);
|
||||
if (toClose == null) return 0;
|
||||
close(toClose);
|
||||
logger().warn("too many open files, closed: " + toClose.size());
|
||||
return toClose.size();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<ZipFile> getFilesToClose(int limit, long timeout) {
|
||||
List<ZipFile> toClose = null;
|
||||
|
||||
synchronized (ourLock) {
|
||||
Iterator<CacheRecord> i = ourPathCache.values().iterator();
|
||||
while (i.hasNext() && (limit == 0 || toClose == null || toClose.size() < limit)) {
|
||||
CacheRecord record = i.next();
|
||||
if (record.count <= 0 && (timeout == 0 || record.released <= timeout)) {
|
||||
i.remove();
|
||||
ourFileCache.remove(record.file);
|
||||
if (toClose == null) toClose = ContainerUtil.newArrayList();
|
||||
toClose.add(record.file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toClose;
|
||||
return new ZipFile(path);
|
||||
}
|
||||
|
||||
public static void release(@NotNull ZipFile file) {
|
||||
synchronized (ourLock) {
|
||||
CacheRecord record = ourFileCache.get(file);
|
||||
if (record != null) {
|
||||
record.count--;
|
||||
record.released = System.currentTimeMillis();
|
||||
logger().assertTrue(record.count >= 0, record.path);
|
||||
return;
|
||||
}
|
||||
|
||||
Integer count = ourQueue.get(file);
|
||||
if (count != null) {
|
||||
count--;
|
||||
if (count == 0) {
|
||||
ourQueue.remove(file);
|
||||
close(file);
|
||||
}
|
||||
else {
|
||||
ourQueue.put(file, count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger().warn(new IllegalArgumentException("stray file: " + file.getName()));
|
||||
close(file);
|
||||
try { file.close(); }
|
||||
catch (IOException ignored) { }
|
||||
}
|
||||
|
||||
public static void reset(@NotNull Collection<String> paths) {
|
||||
debug("resetting %s", paths);
|
||||
public static void reset(Collection<String> paths) { }
|
||||
|
||||
List<ZipFile> toClose = ContainerUtil.newSmartList();
|
||||
|
||||
paths = ContainerUtil.map(paths, new Function<String, String>() {
|
||||
@Override
|
||||
public String fun(String path) {
|
||||
return toCanonicalPath(path);
|
||||
}
|
||||
});
|
||||
|
||||
synchronized (ourLock) {
|
||||
for (String path : paths) {
|
||||
CacheRecord record = ourPathCache.remove(path);
|
||||
if (record != null) {
|
||||
ourFileCache.remove(record.file);
|
||||
if (record.count > 0) {
|
||||
ourQueue.put(record.file, record.count);
|
||||
}
|
||||
else {
|
||||
toClose.add(record.file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(toClose);
|
||||
}
|
||||
|
||||
private static void close(@NotNull List<ZipFile> files) {
|
||||
for (ZipFile file : files) {
|
||||
close(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void close(@NotNull ZipFile file) {
|
||||
debug("closing %s", file.getName());
|
||||
try {
|
||||
file.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger().info(file.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Logger logger() {
|
||||
return Logger.getInstance(ZipFileCache.class);
|
||||
}
|
||||
|
||||
private static void debug(@NotNull String format, Object... args) {
|
||||
LogUtil.debug(logger(), format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* ZipFileCache maintains a background thread. In server environments, this thread may run indefinitely and prevent the class loader from
|
||||
* being gc-ed. Thus it's necessary to invoke this method to stop that thread and let the classes be garbage-collected.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void stopBackgroundThread() {
|
||||
if (ourExecutor != null) {
|
||||
ourExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
public static void stopBackgroundThread() { }
|
||||
}
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
package com.intellij.util.lang;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.ZipFileCache;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import sun.misc.Resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
@@ -32,15 +32,14 @@ import java.util.zip.ZipFile;
|
||||
|
||||
class JarLoader extends Loader {
|
||||
private final URL myURL;
|
||||
private final boolean myCanLockJar;
|
||||
private SoftReference<JarMemoryLoader> myMemoryLoader;
|
||||
|
||||
JarLoader(URL url, boolean canLockJar, int index, boolean preloadJarContents) throws IOException {
|
||||
// todo drop unused parameter
|
||||
JarLoader(URL url, @SuppressWarnings("unused") boolean canLockJar, int index, boolean preloadJarContents) throws IOException {
|
||||
super(new URL(URLUtil.JAR_PROTOCOL, "", -1, url + "!/"), index);
|
||||
myURL = url;
|
||||
myCanLockJar = canLockJar;
|
||||
|
||||
ZipFile zipFile = acquireZipFile();
|
||||
ZipFile zipFile = new ZipFile(getFileUrl());
|
||||
try {
|
||||
if (preloadJarContents) {
|
||||
JarMemoryLoader loader = JarMemoryLoader.load(zipFile, getBaseURL());
|
||||
@@ -50,29 +49,23 @@ class JarLoader extends Loader {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
releaseZipFile(zipFile);
|
||||
}
|
||||
}
|
||||
|
||||
private ZipFile acquireZipFile() throws IOException {
|
||||
String path = FileUtil.unquote(myURL.getFile());
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
return myCanLockJar ? ZipFileCache.acquire(path) : new ZipFile(path);
|
||||
}
|
||||
|
||||
private void releaseZipFile(ZipFile zipFile) throws IOException {
|
||||
if (myCanLockJar) {
|
||||
ZipFileCache.release(zipFile);
|
||||
}
|
||||
else {
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
private File getFileUrl() throws IOException {
|
||||
try {
|
||||
return new File(myURL.toURI());
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClasspathCache.LoaderData buildData() throws IOException {
|
||||
ZipFile zipFile = acquireZipFile();
|
||||
ZipFile zipFile = new ZipFile(getFileUrl());
|
||||
try {
|
||||
ClasspathCache.LoaderData loaderData = new ClasspathCache.LoaderData();
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
@@ -85,7 +78,7 @@ class JarLoader extends Loader {
|
||||
return loaderData;
|
||||
}
|
||||
finally {
|
||||
releaseZipFile(zipFile);
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +92,7 @@ class JarLoader extends Loader {
|
||||
}
|
||||
|
||||
try {
|
||||
ZipFile zipFile = acquireZipFile();
|
||||
ZipFile zipFile = new ZipFile(getFileUrl());
|
||||
try {
|
||||
ZipEntry entry = zipFile.getEntry(name);
|
||||
if (entry != null) {
|
||||
@@ -107,7 +100,7 @@ class JarLoader extends Loader {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
releaseZipFile(zipFile);
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
<stacktrace.fold substring="at org.junit.Assert.assert"/>
|
||||
<stacktrace.fold substring="at com.intellij.junit3."/>
|
||||
<stacktrace.fold substring="at com.intellij.junit4."/>
|
||||
<stacktrace.fold substring="at junit.framework.TestSuite.run"/>
|
||||
<stacktrace.fold substring="at junit.framework.TestCase.run"/>
|
||||
<stacktrace.fold substring="at junit.framework.TestResult"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
|
||||
+222
-66
@@ -25,6 +25,9 @@ import org.junit.runner.Result;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JUnitTreeByDescriptionHierarchyTest {
|
||||
@Test
|
||||
@@ -35,32 +38,96 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
@Test
|
||||
public void test2Parameterized() throws Exception {
|
||||
final Description root = Description.createSuiteDescription("root");
|
||||
final ArrayList<Description> tests = new ArrayList<Description>();
|
||||
for (String className : new String[]{"a.TestA", "a.TestB"}) {
|
||||
final Description aTestClass = Description.createSuiteDescription(className);
|
||||
root.addChild(aTestClass);
|
||||
for (String paramName : new String[]{"[0]", "[1]"}) {
|
||||
final Description param1 = Description.createSuiteDescription(paramName);
|
||||
aTestClass.addChild(param1);
|
||||
param1.addChild(Description.createTestDescription(className, "testName" + paramName));
|
||||
}
|
||||
|
||||
attachParameterizedTests(className, aTestClass, tests);
|
||||
}
|
||||
doTest(root, "##teamcity[suiteTreeStarted name='TestA' locationHint='java:suite://a.TestA']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://a.TestA.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://a.TestA.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='TestA']\n" +
|
||||
"##teamcity[suiteTreeStarted name='TestB' locationHint='java:suite://a.TestB']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://a.TestB.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://a.TestB.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://a.TestB.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://a.TestB.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='TestB']\n");
|
||||
doTest(root, tests,
|
||||
"##teamcity[suiteTreeStarted name='TestA' locationHint='java:suite://a.TestA']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://a.TestA.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://a.TestA.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='TestA']\n" +
|
||||
"##teamcity[suiteTreeStarted name='TestB' locationHint='java:suite://a.TestB']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://a.TestB.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://a.TestB.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://a.TestB.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://a.TestB.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='TestB']\n",
|
||||
|
||||
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"\n" +
|
||||
"##teamcity[rootName name = 'root']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='root']\n" +
|
||||
"##teamcity[testSuiteStarted name ='TestA']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n" +
|
||||
"##teamcity[testSuiteStarted name ='TestB']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestB.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestB.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='TestB']\n" +
|
||||
"\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleParameterizedClass() throws Exception {
|
||||
final String className = "a.TestA";
|
||||
final Description aTestClassDescription = Description.createSuiteDescription(className);
|
||||
final ArrayList<Description> tests = new ArrayList<Description>();
|
||||
attachParameterizedTests(className, aTestClassDescription, tests);
|
||||
doTest(aTestClassDescription, tests,
|
||||
//tree
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://a.TestA.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://a.TestA.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n",
|
||||
//start
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"\n" +
|
||||
"##teamcity[rootName name = 'TestA' comment = 'a']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n" +
|
||||
"\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -68,17 +135,76 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
final Description root = Description.createSuiteDescription("root");
|
||||
final String className = "ATest";
|
||||
final String methodName = "test1";
|
||||
final List<Description> tests = new ArrayList<Description>();
|
||||
for( String suiteName : new String[] {"ASuite1", "ASuite2"}) {
|
||||
final Description aSuite = Description.createSuiteDescription(suiteName);
|
||||
root.addChild(aSuite);
|
||||
final Description aTest = Description.createSuiteDescription(className);
|
||||
aSuite.addChild(aTest);
|
||||
aTest.addChild(Description.createTestDescription(className, methodName));
|
||||
final Description testDescription = Description.createTestDescription(className, methodName);
|
||||
tests.add(testDescription);
|
||||
aTest.addChild(testDescription);
|
||||
}
|
||||
|
||||
doTest(root, "##teamcity[suiteTreeStarted name='ATest' locationHint='java:suite://ATest']\n" +
|
||||
"##teamcity[suiteTreeNode name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ATest']\n");
|
||||
|
||||
doTest(root, tests,
|
||||
//expected tree
|
||||
"##teamcity[suiteTreeStarted name='ASuite1' locationHint='java:suite://ASuite1']\n" +
|
||||
"##teamcity[suiteTreeStarted name='ATest' locationHint='java:suite://ATest']\n" +
|
||||
"##teamcity[suiteTreeNode name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ATest']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ASuite1']\n" +
|
||||
"##teamcity[suiteTreeStarted name='ASuite2' locationHint='java:suite://ASuite2']\n" +
|
||||
"##teamcity[suiteTreeStarted name='ATest' locationHint='java:suite://ATest']\n" +
|
||||
"##teamcity[suiteTreeNode name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ATest']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ASuite2']\n",
|
||||
|
||||
//started
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"\n" +
|
||||
"##teamcity[rootName name = 'root']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='root']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ASuite1']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testStarted name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='test1']\n" +
|
||||
"##teamcity[testSuiteFinished name='ATest']\n" +
|
||||
"##teamcity[testSuiteFinished name='ASuite1']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ASuite2']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testStarted name='test1' locationHint='java:test://ATest.test1']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='test1']\n" +
|
||||
"##teamcity[testSuiteFinished name='ATest']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='ASuite2']\n" +
|
||||
"\n");
|
||||
}
|
||||
|
||||
private static void doTest(Description root, List<Description> tests, String expectedTree, String expectedStart) throws Exception {
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
final SMTestSender sender = new SMTestSender(new PrintStream(new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
buf.append(new String(new byte[]{(byte)b}));
|
||||
}
|
||||
}));
|
||||
sender.sendTree(root);
|
||||
|
||||
Assert.assertEquals("output: " + buf, expectedTree, StringUtil.convertLineSeparators(buf.toString()));
|
||||
|
||||
buf.setLength(0);
|
||||
|
||||
sender.testRunStarted(root);
|
||||
for (Description test : tests) {
|
||||
sender.testStarted(test);
|
||||
sender.testFinished(test);
|
||||
}
|
||||
sender.testRunFinished(new Result());
|
||||
|
||||
Assert.assertEquals("output: " + buf, expectedStart, StringUtil.convertLineSeparators(buf.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -92,27 +218,70 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
final Description root = Description.createSuiteDescription("root");
|
||||
final Description aTestClass = Description.createSuiteDescription("ATest");
|
||||
root.addChild(aTestClass);
|
||||
for (String paramName : new String[]{"[0]", "[1]"}) {
|
||||
final Description param1 = Description.createSuiteDescription(paramName);
|
||||
aTestClass.addChild(param1);
|
||||
param1.addChild(Description.createTestDescription("ATest", "testName" + paramName));
|
||||
}
|
||||
final ArrayList<Description> tests = new ArrayList<Description>();
|
||||
attachParameterizedTests("ATest", aTestClass, tests);
|
||||
final Description suiteDescription = Description.createSuiteDescription("suite");
|
||||
root.addChild(suiteDescription);
|
||||
final Description aTestClassWithJUnit3Test = Description.createSuiteDescription("ATest");
|
||||
suiteDescription.addChild(aTestClassWithJUnit3Test);
|
||||
aTestClassWithJUnit3Test.addChild(Description.createTestDescription("ATest", "test"));
|
||||
doTest(root, "##teamcity[suiteTreeStarted name='ATest' locationHint='java:suite://ATest']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://ATest.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://ATest.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='test' locationHint='java:test://ATest.test']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ATest']\n");
|
||||
final Description testDescription = Description.createTestDescription("ATest", "test");
|
||||
aTestClassWithJUnit3Test.addChild(testDescription);
|
||||
tests.add(testDescription);
|
||||
doTest(root, tests,
|
||||
"##teamcity[suiteTreeStarted name='ATest' locationHint='java:suite://ATest']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[0|]' locationHint='java:suite://ATest.|[0|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[0|]']\n" +
|
||||
"##teamcity[suiteTreeStarted name='|[1|]' locationHint='java:suite://ATest.|[1|]']\n" +
|
||||
"##teamcity[suiteTreeNode name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='|[1|]']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ATest']\n" +
|
||||
"##teamcity[suiteTreeStarted name='suite' locationHint='java:suite://suite']\n" +
|
||||
"##teamcity[suiteTreeStarted name='ATest' locationHint='java:suite://ATest']\n" +
|
||||
"##teamcity[suiteTreeNode name='test' locationHint='java:test://ATest.test']\n" +
|
||||
"##teamcity[suiteTreeEnded name='ATest']\n" +
|
||||
"##teamcity[suiteTreeEnded name='suite']\n",
|
||||
|
||||
//start
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"\n" +
|
||||
"##teamcity[rootName name = 'root']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='root']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[0|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[0|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[0|]']\n" +
|
||||
"##teamcity[testSuiteStarted name ='|[1|]']\n" +
|
||||
"##teamcity[testStarted name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='testName|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='|[1|]']\n" +
|
||||
"##teamcity[testSuiteFinished name='ATest']\n" +
|
||||
"##teamcity[testSuiteStarted name ='suite']\n" +
|
||||
"##teamcity[testSuiteStarted name ='ATest']\n" +
|
||||
"##teamcity[testStarted name='test' locationHint='java:test://ATest.test']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='test']\n" +
|
||||
"##teamcity[testSuiteFinished name='ATest']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testSuiteFinished name='suite']\n" +
|
||||
"\n");
|
||||
}
|
||||
|
||||
|
||||
private static void attachParameterizedTests(String className, Description aTestClass, List<Description> tests) {
|
||||
for (String paramName : new String[]{"[0]", "[1]"}) {
|
||||
final Description param1 = Description.createSuiteDescription(paramName);
|
||||
aTestClass.addChild(param1);
|
||||
final Description testDescription = Description.createTestDescription(className, "testName" + paramName);
|
||||
tests.add(testDescription);
|
||||
param1.addChild(testDescription);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doTest(Description description, String expected) {
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
new SMTestSender(new PrintStream(new OutputStream() {
|
||||
@@ -130,31 +299,18 @@ public class JUnitTreeByDescriptionHierarchyTest {
|
||||
final Description description = Description.createSuiteDescription("TestA");
|
||||
final Description emptyDescription = Description.createTestDescription(SMTestSender.EMPTY_SUITE_NAME, SMTestSender.EMPTY_SUITE_WARNING);
|
||||
description.addChild(emptyDescription);
|
||||
doTest(description, Collections.singletonList(emptyDescription),
|
||||
"##teamcity[suiteTreeNode name='warning' locationHint='java:test://TestA.warning']\n",
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
final PrintStream printStream = new PrintStream(new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
buf.append(new String(new byte[]{(byte)b}));
|
||||
}
|
||||
});
|
||||
|
||||
final SMTestSender sender = new SMTestSender(printStream);
|
||||
|
||||
sender.sendTree(description);
|
||||
|
||||
sender.testRunStarted(description);
|
||||
sender.testStarted(emptyDescription);
|
||||
sender.testFinished(emptyDescription);
|
||||
sender.testRunFinished(new Result());
|
||||
|
||||
Assert.assertEquals("output: " + buf, "##teamcity[suiteTreeNode name='warning' locationHint='java:test://junit.framework.TestSuite$1.warning']\n" +
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"\n" +
|
||||
"##teamcity[testStarted name='warning' locationHint='java:test://junit.framework.TestSuite$1.warning']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='warning']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n" +
|
||||
"\n", StringUtil.convertLineSeparators(buf.toString()));
|
||||
"##teamcity[enteredTheMatrix]\n" +
|
||||
"\n" +
|
||||
"##teamcity[rootName name = 'TestA']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testStarted name='warning' locationHint='java:test://junit.framework.TestSuite$1.warning']\n" +
|
||||
"\n" +
|
||||
"##teamcity[testFinished name='warning']\n" +
|
||||
"##teamcity[testSuiteFinished name='TestA']\n" +
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class JUnit4IdeaTestRunner implements IdeaTestRunner {
|
||||
description = getFilteredDescription(request, description);
|
||||
}
|
||||
TreeSender.sendTree(this, description, sendTree);
|
||||
if (myTestsListener instanceof SMTestSender) {
|
||||
if (myTestsListener instanceof SMTestSender && sendTree) {
|
||||
((SMTestSender)myTestsListener).sendTree(description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,14 @@ public class SMTestSender extends RunListener {
|
||||
public static final String EMPTY_SUITE_NAME = "junit.framework.TestSuite$1";
|
||||
public static final String EMPTY_SUITE_WARNING = "warning";
|
||||
|
||||
private String myCurrentSuiteName;
|
||||
private String myCurrentClassName;
|
||||
private String myParamName;
|
||||
|
||||
private PrintStream myPrintStream = System.out;
|
||||
private final Map myParents = new HashMap();
|
||||
private final Map mySuites = new HashMap();
|
||||
|
||||
|
||||
public SMTestSender() {}
|
||||
|
||||
@@ -58,6 +62,20 @@ public class SMTestSender extends RunListener {
|
||||
|
||||
public void testRunStarted(Description description) throws Exception {
|
||||
myPrintStream.println("##teamcity[enteredTheMatrix]\n");
|
||||
if (myCurrentClassName != null && !myCurrentClassName.startsWith("[")) {
|
||||
int lastPointIdx = myCurrentClassName.lastIndexOf('.');
|
||||
String name = myCurrentClassName;
|
||||
String comment = null;
|
||||
if (lastPointIdx >= 0) {
|
||||
name = myCurrentClassName.substring(lastPointIdx + 1);
|
||||
comment = myCurrentClassName.substring(0, lastPointIdx);
|
||||
}
|
||||
|
||||
myPrintStream.println("##teamcity[rootName name = \'" + escapeName(name) +
|
||||
(comment != null ? ("\' comment = \'" + escapeName(comment)) : "") +
|
||||
"\']\n");
|
||||
myCurrentClassName = getShortName(myCurrentClassName);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRunFinished(Result result) throws Exception {
|
||||
@@ -67,6 +85,9 @@ public class SMTestSender extends RunListener {
|
||||
if (myCurrentClassName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myCurrentClassName) + "\']\n");
|
||||
}
|
||||
if (myCurrentSuiteName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(getShortName(myCurrentSuiteName)) + "\']\n");
|
||||
}
|
||||
}
|
||||
|
||||
public void testStarted(Description description) throws Exception {
|
||||
@@ -77,10 +98,35 @@ public class SMTestSender extends RunListener {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myParamName) + "\']");
|
||||
myParamName = null;
|
||||
}
|
||||
|
||||
final List suites = (List)myParents.get(description);
|
||||
if (suites != null && !suites.isEmpty()) {
|
||||
String currentSuite = (String)suites.get(0);
|
||||
List descriptors = (List)mySuites.get(currentSuite);
|
||||
|
||||
if (descriptors.isEmpty()) {
|
||||
currentSuite = (String)suites.get(1);
|
||||
descriptors = (List)mySuites.get(currentSuite);
|
||||
}
|
||||
|
||||
if (!currentSuite.equals(myCurrentSuiteName)) {
|
||||
finishCurrentSuite();
|
||||
myCurrentSuiteName = currentSuite;
|
||||
myPrintStream.println("##teamcity[testSuiteStarted name =\'" + escapeName(getShortName(myCurrentSuiteName)) + "\']");
|
||||
}
|
||||
|
||||
descriptors.remove(description);
|
||||
}
|
||||
else if (myCurrentSuiteName != null){
|
||||
finishCurrentSuite();
|
||||
myCurrentSuiteName = null;
|
||||
}
|
||||
|
||||
String className = getShortName(classFQN);
|
||||
if (!myEmptyTests.isEmpty() && isWarning(methodName, classFQN)) {
|
||||
className = (String)myEmptyTests.remove(0);
|
||||
}
|
||||
|
||||
if (!className.equals(myCurrentClassName)) {
|
||||
if (myCurrentClassName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myCurrentClassName) + "\']");
|
||||
@@ -99,6 +145,16 @@ public class SMTestSender extends RunListener {
|
||||
getTestMethodLocation(methodName, classFQN) + "]");
|
||||
}
|
||||
|
||||
private void finishCurrentSuite() {
|
||||
if (myCurrentClassName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(myCurrentClassName) + "\']");
|
||||
myCurrentClassName = null;
|
||||
}
|
||||
if (myCurrentSuiteName != null) {
|
||||
myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(getShortName(myCurrentSuiteName)) + "\']");
|
||||
}
|
||||
}
|
||||
|
||||
public void testFinished(Description description) throws Exception {
|
||||
myPrintStream.println("\n##teamcity[testFinished name=\'" + escapeName(JUnit4ReflectionUtil.getMethodName(description)) + "\']");
|
||||
}
|
||||
@@ -194,31 +250,49 @@ public class SMTestSender extends RunListener {
|
||||
|
||||
private final List myEmptyTests = new ArrayList();
|
||||
|
||||
private void sendTree(Description description, Map groups, Description parent) {
|
||||
final String className = JUnit4ReflectionUtil.getClassName(description);
|
||||
private void sendTree(Description description, Description parent, Description suiteParent) {
|
||||
String className = JUnit4ReflectionUtil.getClassName(description);
|
||||
if (description.getChildren().isEmpty()) {
|
||||
final String methodName = JUnit4ReflectionUtil.getMethodName((Description)description);
|
||||
if (methodName != null) {
|
||||
myPrintStream.println("##teamcity[suiteTreeNode name=\'" + escapeName(methodName) + "\' " + getTestMethodLocation(methodName, className) + "]");
|
||||
if (isWarning(methodName, className)) {
|
||||
myEmptyTests.add(getShortName(JUnit4ReflectionUtil.getClassName(parent)));
|
||||
className = JUnit4ReflectionUtil.getClassName(parent);
|
||||
myEmptyTests.add(getShortName(className));
|
||||
}
|
||||
myPrintStream.println("##teamcity[suiteTreeNode name=\'" + escapeName(methodName) + "\' " + getTestMethodLocation(methodName, className) + "]");
|
||||
}
|
||||
|
||||
if (suiteParent != null ) {
|
||||
final String parentFQName = JUnit4ReflectionUtil.getClassName(suiteParent);
|
||||
if (!myCurrentClassName.equals(parentFQName)) {
|
||||
List parents = (List)myParents.get(description);
|
||||
if (parents == null) {
|
||||
parents = new ArrayList();
|
||||
myParents.put(description, parents);
|
||||
}
|
||||
if (!parents.contains(parentFQName)) {
|
||||
parents.add(parentFQName);
|
||||
}
|
||||
|
||||
List descriptors = (List)mySuites.get(parentFQName);
|
||||
if (descriptors == null) {
|
||||
descriptors = new ArrayList();
|
||||
mySuites.put(parentFQName, descriptors);
|
||||
}
|
||||
descriptors.add(description);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
List tests = (List)groups.get(description);
|
||||
if (isParameter(description)) {
|
||||
tests = description.getChildren();
|
||||
}
|
||||
if (tests == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List tests = description.getChildren();
|
||||
boolean pass = false;
|
||||
for (Iterator iterator = tests.iterator(); iterator.hasNext(); ) {
|
||||
final Object next = iterator.next();
|
||||
final List childTests = ((Description)next).getChildren();
|
||||
final Description nextDescription = (Description)next;
|
||||
if (((myCurrentClassName == null || !myCurrentClassName.equals(getShortName(className))) && childTests.isEmpty() && JUnit4ReflectionUtil.getMethodName(nextDescription) != null || isParameter(nextDescription)) && !pass) {
|
||||
final List childTests = nextDescription.getChildren();
|
||||
if ((myCurrentClassName == null || !myCurrentClassName.equals(className)) && !pass) {
|
||||
pass = true;
|
||||
String locationHint = className;
|
||||
if (isParameter((Description)description)) {
|
||||
@@ -231,14 +305,12 @@ public class SMTestSender extends RunListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
myPrintStream.println("##teamcity[suiteTreeStarted name=\'" + escapeName(getShortName(className)) +
|
||||
"\' locationHint=\'java:suite://" + escapeName(locationHint) + "\']");
|
||||
myPrintStream.println("##teamcity[suiteTreeStarted name=\'" + escapeName(getShortName(className)) + "\' locationHint=\'java:suite://" + escapeName(locationHint) + "\']");
|
||||
}
|
||||
sendTree(nextDescription, groups, description);
|
||||
sendTree(nextDescription, description, isParameter(description) ? null : childTests.isEmpty() && parent != null ? parent : description);
|
||||
}
|
||||
if (pass) {
|
||||
myPrintStream.println("##teamcity[suiteTreeEnded name=\'" + escapeName(getShortName(JUnit4ReflectionUtil.getClassName((Description)description))) + "\']");
|
||||
groups.remove(description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,34 +322,14 @@ public class SMTestSender extends RunListener {
|
||||
return "locationHint=\'java:test://" + escapeName(className + "." + methodName) + "\'";
|
||||
}
|
||||
|
||||
private static void groupTests(Object description, Map found) {
|
||||
if (!isParameter((Description)description)) {
|
||||
ArrayList childTests = ((Description)description).getChildren();
|
||||
List children = (List)found.get(description);
|
||||
if (children == null) {
|
||||
children = new ArrayList();
|
||||
found.put(description, children);
|
||||
} else {
|
||||
childTests = new ArrayList(childTests);
|
||||
childTests.removeAll(children);
|
||||
}
|
||||
children.addAll(childTests);
|
||||
for (Iterator iterator = childTests.iterator(); iterator.hasNext(); ) {
|
||||
groupTests(iterator.next(), found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isParameter(Description description) {
|
||||
String displayName = description.getDisplayName();
|
||||
return displayName.startsWith("[") && displayName.endsWith("]");
|
||||
}
|
||||
|
||||
public void sendTree(Description description) {
|
||||
myCurrentClassName = getShortName(JUnit4ReflectionUtil.getClassName((Description)description));
|
||||
final HashMap group = new HashMap();
|
||||
groupTests(description, group);
|
||||
sendTree(description, group, null);
|
||||
myCurrentClassName = JUnit4ReflectionUtil.getClassName((Description)description);
|
||||
sendTree(description, null, null);
|
||||
}
|
||||
|
||||
private static String getShortName(String fqName) {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 415 B |
Binary file not shown.
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 970 B |
Reference in New Issue
Block a user