@NotNull
 public static char[] adaptiveLoadText(@NotNull Reader reader) throws IOException {
   char[] chars = new char[4096];
   List<char[]> buffers = null;
   int count = 0;
   int total = 0;
   while (true) {
     int n = reader.read(chars, count, chars.length - count);
     if (n <= 0) break;
     count += n;
     if (total > 1024 * 1024 * 10) throw new FileTooBigException("File too big " + reader);
     total += n;
     if (count == chars.length) {
       if (buffers == null) {
         buffers = new ArrayList<char[]>();
       }
       buffers.add(chars);
       int newLength = Math.min(1024 * 1024, chars.length * 2);
       chars = new char[newLength];
       count = 0;
     }
   }
   char[] result = new char[total];
   if (buffers != null) {
     for (char[] buffer : buffers) {
       System.arraycopy(buffer, 0, result, result.length - total, buffer.length);
       total -= buffer.length;
     }
   }
   System.arraycopy(chars, 0, result, result.length - total, total);
   return result;
 }
 @NotNull
 public static byte[] adaptiveLoadBytes(@NotNull InputStream stream) throws IOException {
   byte[] bytes = new byte[4096];
   List<byte[]> buffers = null;
   int count = 0;
   int total = 0;
   while (true) {
     int n = stream.read(bytes, count, bytes.length - count);
     if (n <= 0) break;
     count += n;
     if (total > 1024 * 1024 * 10) throw new FileTooBigException("File too big " + stream);
     total += n;
     if (count == bytes.length) {
       if (buffers == null) {
         buffers = new ArrayList<byte[]>();
       }
       buffers.add(bytes);
       int newLength = Math.min(1024 * 1024, bytes.length * 2);
       bytes = new byte[newLength];
       count = 0;
     }
   }
   byte[] result = new byte[total];
   if (buffers != null) {
     for (byte[] buffer : buffers) {
       System.arraycopy(buffer, 0, result, result.length - total, buffer.length);
       total -= buffer.length;
     }
   }
   System.arraycopy(bytes, 0, result, result.length - total, total);
   return result;
 }
 private void insertChildAt(@NotNull VirtualFileSystemEntry file, int negativeIndex) {
   @NotNull VirtualFileSystemEntry[] array = myChildren;
   VirtualFileSystemEntry[] appended = new VirtualFileSystemEntry[array.length + 1];
   int i = -negativeIndex - 1;
   System.arraycopy(array, 0, appended, 0, i);
   appended[i] = file;
   System.arraycopy(array, i, appended, i + 1, array.length - i);
   myChildren = appended;
 }
  public static void importConfigsTo(@NotNull String newConfigPath) {
    ConfigImportSettings settings = getConfigImportSettings();

    File newConfigDir = new File(newConfigPath);
    File oldConfigDir = findOldConfigDir(newConfigDir, settings.getCustomPathsSelector());
    do {
      ImportOldConfigsPanel dialog = new ImportOldConfigsPanel(oldConfigDir, settings);
      dialog.setModalityType(Dialog.ModalityType.TOOLKIT_MODAL);
      AppUIUtil.updateWindowIcon(dialog);
      dialog.setVisible(true);
      if (dialog.isImportEnabled()) {
        File installationHome = dialog.getSelectedFile();
        oldConfigDir = getOldConfigDir(installationHome, settings);
        if (!validateOldConfigDir(installationHome, oldConfigDir, settings)) {
          continue;
        }

        assert oldConfigDir != null;
        doImport(newConfigDir, oldConfigDir, settings, installationHome);
        settings.importFinished(newConfigPath);
        System.setProperty(CONFIG_IMPORTED_IN_CURRENT_SESSION_KEY, Boolean.TRUE.toString());
      }

      break;
    } while (true);
  }
 private static File getTempFile(@NotNull String originalFileName, @NotNull File parent) {
   int randomSuffix = (int) (System.currentTimeMillis() % 1000);
   for (int i = randomSuffix; ; i++) {
     @NonNls String name = "___" + originalFileName + i + ASYNC_DELETE_EXTENSION;
     File tempFile = new File(parent, name);
     if (!tempFile.exists()) return tempFile;
   }
 }
Ejemplo n.º 6
0
  static {
    // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
    System.setProperty("apple.awt.UIElement", "true");

    try {
      CodeInsightSettings defaultSettings = new CodeInsightSettings();
      Element oldS = new Element("temp");
      defaultSettings.writeExternal(oldS);
      DEFAULT_SETTINGS_EXTERNALIZED = JDOMUtil.writeElement(oldS, "\n");
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  // null means we were unable to get roots, so do not check access
  @Nullable
  @TestOnly
  private static Set<String> allowedRoots() {
    if (insideGettingRoots) return null;

    Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
    if (openProjects.length == 0) return null;

    final Set<String> allowed = new THashSet<String>();
    allowed.add(FileUtil.toSystemIndependentName(PathManager.getHomePath()));

    try {
      URL outUrl = Application.class.getResource("/");
      String output = new File(outUrl.toURI()).getParentFile().getParentFile().getPath();
      allowed.add(FileUtil.toSystemIndependentName(output));
    } catch (URISyntaxException ignored) {
    }

    allowed.add(FileUtil.toSystemIndependentName(SystemProperties.getJavaHome()));
    allowed.add(
        FileUtil.toSystemIndependentName(new File(FileUtil.getTempDirectory()).getParent()));
    allowed.add(FileUtil.toSystemIndependentName(System.getProperty("java.io.tmpdir")));
    allowed.add(FileUtil.toSystemIndependentName(SystemProperties.getUserHome()));

    for (Project project : openProjects) {
      if (!project.isInitialized()) {
        return null; // all is allowed
      }
      for (VirtualFile root : ProjectRootManager.getInstance(project).getContentRoots()) {
        allowed.add(root.getPath());
      }
      for (VirtualFile root : getAllRoots(project)) {
        allowed.add(StringUtil.trimEnd(root.getPath(), JarFileSystem.JAR_SEPARATOR));
      }
      String location = project.getBasePath();
      assert location != null : project;
      allowed.add(FileUtil.toSystemIndependentName(location));
    }

    allowed.addAll(ourAdditionalRoots);

    return allowed;
  }
/** @author max */
public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
  private static final Logger LOG =
      Logger.getInstance("#com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl");
  public static boolean CHECK = ApplicationManager.getApplication().isUnitTestMode();

  static final VirtualDirectoryImpl NULL_VIRTUAL_FILE =
      new VirtualDirectoryImpl("*?;%NULL", null, LocalFileSystem.getInstance(), -42, 0) {
        public String toString() {
          return "NULL";
        }
      };

  private final NewVirtualFileSystem myFS;

  /**
   * The array is logically divided into the two parts: - left subarray for storing real child files
   * - right subarray for storing "adopted children" files. "Adopted children" are fake files which
   * are used for storing names which were accessed via findFileByName() or similar calls. We have
   * to store these unsuccessful find attempts to be able to correctly refresh in the future. See
   * usages of {@link #getSuspiciousNames()} in the {@link
   * com.intellij.openapi.vfs.newvfs.persistent.RefreshWorker}
   *
   * <p>Guarded by this, files in each subarray are sorted according to the compareNameTo()
   * comparator TODO: revise the whole adopted scheme
   */
  private VirtualFileSystemEntry[] myChildren = EMPTY_ARRAY;

  public VirtualDirectoryImpl(
      @NonNls @NotNull final String name,
      @Nullable final VirtualDirectoryImpl parent,
      @NotNull final NewVirtualFileSystem fs,
      final int id,
      @PersistentFS.Attributes final int attributes) {
    super(name, parent, id, attributes);
    myFS = fs;
  }

  @Override
  @NotNull
  public NewVirtualFileSystem getFileSystem() {
    return myFS;
  }

  @Nullable
  private VirtualFileSystemEntry findChild(
      @NotNull String name,
      final boolean doRefresh,
      boolean ensureCanonicalName,
      @NotNull NewVirtualFileSystem delegate) {
    boolean ignoreCase = !delegate.isCaseSensitive();
    Comparator comparator = getComparator(name, ignoreCase);
    VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, delegate, comparator);
    if (result == NULL_VIRTUAL_FILE) {
      result = doRefresh ? createAndFindChildWithEventFire(name, delegate) : null;
    } else if (result != null) {
      if (doRefresh && delegate.isDirectory(result) != result.isDirectory()) {
        RefreshQueue.getInstance().refresh(false, false, null, result);
        result = findChild(name, false, ensureCanonicalName, delegate);
      }
    }

    if (result == null) {
      addToAdoptedChildren(name, !delegate.isCaseSensitive(), comparator);
    }
    return result;
  }

  private synchronized void addToAdoptedChildren(
      @NotNull final String name, final boolean ignoreCase, @NotNull Comparator comparator) {
    long r = findIndexInBoth(myChildren, comparator);
    int indexInReal = (int) (r >> 32);
    int indexInAdopted = (int) r;
    if (indexInAdopted >= 0) return; // already added
    if (!allChildrenLoaded()) {
      insertChildAt(new AdoptedChild(name), indexInAdopted);
    }

    if (indexInReal >= 0) {
      // there suddenly can be that we ask to add name to adopted whereas it already contains in the
      // real part
      // in this case we should remove it from there
      removeFromArray(indexInReal);
    }
    assertConsistency(myChildren, ignoreCase, name);
  }

  private static class AdoptedChild extends VirtualFileImpl {
    private AdoptedChild(String name) {
      super(name, NULL_VIRTUAL_FILE, -42, -1);
    }
  }

  @Nullable // null if there can't be a child with this name, NULL_VIRTUAL_FILE
  private synchronized VirtualFileSystemEntry doFindChildInArray(@NotNull Comparator comparator) {
    VirtualFileSystemEntry[] array = myChildren;
    long r = findIndexInBoth(array, comparator);
    int indexInReal = (int) (r >> 32);
    int indexInAdopted = (int) r;
    if (indexInAdopted >= 0) return NULL_VIRTUAL_FILE;

    if (indexInReal >= 0) {
      return array[indexInReal];
    }
    return null;
  }

  @Nullable // null if there can't be a child with this name, NULL_VIRTUAL_FILE if cached as absent,
  // the file if found
  private VirtualFileSystemEntry doFindChild(
      @NotNull String name,
      boolean ensureCanonicalName,
      @NotNull NewVirtualFileSystem delegate,
      @NotNull Comparator comparator) {
    if (name.isEmpty()) {
      return null;
    }

    VirtualFileSystemEntry found = doFindChildInArray(comparator);
    if (found != null) return found;

    if (allChildrenLoaded()) {
      return NULL_VIRTUAL_FILE;
    }

    if (ensureCanonicalName) {
      VirtualFile fake = new FakeVirtualFile(this, name);
      name = delegate.getCanonicallyCasedName(fake);
      if (name.isEmpty()) return null;
    }

    synchronized (this) {
      // maybe another doFindChild() sneaked in the middle
      VirtualFileSystemEntry[] array = myChildren;
      long r = findIndexInBoth(array, comparator);
      int indexInReal = (int) (r >> 32);
      int indexInAdopted = (int) r;
      if (indexInAdopted >= 0) return NULL_VIRTUAL_FILE;
      // double check
      if (indexInReal >= 0) {
        return array[indexInReal];
      }

      // do not extract getId outside the synchronized block since it will cause a concurrency
      // problem.
      int id = ourPersistence.getId(this, name, delegate);
      if (id <= 0) {
        return null;
      }
      String shorty = new String(name);
      VirtualFileSystemEntry child =
          createChild(
              shorty, id, delegate); // So we don't hold whole char[] buffer of a lengthy path

      VirtualFileSystemEntry[] after = myChildren;
      if (after != array) {
        // in tests when we call assertAccessInTests it can load a huge number of files which lead
        // to children modification
        // so fall back to slow path
        addChild(child);
      } else {
        insertChildAt(child, indexInReal);
        assertConsistency(myChildren, !delegate.isCaseSensitive(), name);
      }
      return child;
    }
  }

  @NotNull
  private static Comparator getComparator(@NotNull final String name, final boolean ignoreCase) {
    return new Comparator() {
      @Override
      public int compareMyKeyTo(@NotNull VirtualFileSystemEntry file) {
        return -file.compareNameTo(name, ignoreCase);
      }
    };
  }

  private synchronized VirtualFileSystemEntry[] getArraySafely() {
    return myChildren;
  }

  @NotNull
  public VirtualFileSystemEntry createChild(
      @NotNull String name, int id, @NotNull NewVirtualFileSystem delegate) {
    VirtualFileSystemEntry child;

    final int attributes = ourPersistence.getFileAttributes(id);
    if (PersistentFS.isDirectory(attributes)) {
      child = new VirtualDirectoryImpl(name, this, delegate, id, attributes);
    } else {
      child = new VirtualFileImpl(name, this, id, attributes);
      //noinspection TestOnlyProblems
      assertAccessInTests(child, delegate);
    }

    if (delegate.markNewFilesAsDirty()) {
      child.markDirty();
    }

    return child;
  }

  private static final boolean IS_UNDER_TEAMCITY =
      System.getProperty("bootstrap.testcases") != null;
  private static final boolean SHOULD_PERFORM_ACCESS_CHECK =
      System.getenv("NO_FS_ROOTS_ACCESS_CHECK") == null;

  private static final Collection<String> ourAdditionalRoots = new THashSet<String>();

  @TestOnly
  public static void allowRootAccess(@NotNull String... roots) {
    for (String root : roots) {
      ourAdditionalRoots.add(FileUtil.toSystemIndependentName(root));
    }
  }

  @TestOnly
  public static void disallowRootAccess(@NotNull String... roots) {
    for (String root : roots) {
      ourAdditionalRoots.remove(FileUtil.toSystemIndependentName(root));
    }
  }

  @TestOnly
  private static void assertAccessInTests(
      @NotNull VirtualFileSystemEntry child, @NotNull NewVirtualFileSystem delegate) {
    final Application application = ApplicationManager.getApplication();
    if (IS_UNDER_TEAMCITY
        && SHOULD_PERFORM_ACCESS_CHECK
        && application.isUnitTestMode()
        && application instanceof ApplicationImpl
        && ((ApplicationImpl) application).isComponentsCreated()) {
      if (delegate != LocalFileSystem.getInstance() && delegate != JarFileSystem.getInstance()) {
        return;
      }
      // root' children are loaded always
      if (child.getParent() == null || child.getParent().getParent() == null) return;

      Set<String> allowed = allowedRoots();
      boolean isUnder = allowed == null;
      if (!isUnder) {
        String childPath = child.getPath();
        if (delegate == JarFileSystem.getInstance()) {
          VirtualFile local = JarFileSystem.getInstance().getVirtualFileForJar(child);
          assert local != null : child;
          childPath = local.getPath();
        }
        for (String root : allowed) {
          if (FileUtil.startsWith(childPath, root)) {
            isUnder = true;
            break;
          }
          if (root.startsWith(JarFileSystem.PROTOCOL_PREFIX)) {
            String rootLocalPath =
                FileUtil.toSystemIndependentName(PathUtil.toPresentableUrl(root));
            isUnder = FileUtil.startsWith(childPath, rootLocalPath);
            if (isUnder) break;
          }
        }
      }

      assert isUnder || allowed.isEmpty()
          : "File accessed outside allowed roots: "
              + child
              + ";\nAllowed roots: "
              + new ArrayList<String>(allowed);
    }
  }

  // null means we were unable to get roots, so do not check access
  @Nullable
  @TestOnly
  private static Set<String> allowedRoots() {
    if (insideGettingRoots) return null;

    Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
    if (openProjects.length == 0) return null;

    final Set<String> allowed = new THashSet<String>();
    allowed.add(FileUtil.toSystemIndependentName(PathManager.getHomePath()));

    try {
      URL outUrl = Application.class.getResource("/");
      String output = new File(outUrl.toURI()).getParentFile().getParentFile().getPath();
      allowed.add(FileUtil.toSystemIndependentName(output));
    } catch (URISyntaxException ignored) {
    }

    allowed.add(FileUtil.toSystemIndependentName(SystemProperties.getJavaHome()));
    allowed.add(
        FileUtil.toSystemIndependentName(new File(FileUtil.getTempDirectory()).getParent()));
    allowed.add(FileUtil.toSystemIndependentName(System.getProperty("java.io.tmpdir")));
    allowed.add(FileUtil.toSystemIndependentName(SystemProperties.getUserHome()));

    for (Project project : openProjects) {
      if (!project.isInitialized()) {
        return null; // all is allowed
      }
      for (VirtualFile root : ProjectRootManager.getInstance(project).getContentRoots()) {
        allowed.add(root.getPath());
      }
      for (VirtualFile root : getAllRoots(project)) {
        allowed.add(StringUtil.trimEnd(root.getPath(), JarFileSystem.JAR_SEPARATOR));
      }
      String location = project.getBasePath();
      assert location != null : project;
      allowed.add(FileUtil.toSystemIndependentName(location));
    }

    allowed.addAll(ourAdditionalRoots);

    return allowed;
  }

  private static boolean insideGettingRoots;

  @TestOnly
  private static VirtualFile[] getAllRoots(@NotNull Project project) {
    insideGettingRoots = true;
    final Set<VirtualFile> roots = new THashSet<VirtualFile>();

    final OrderEnumerator enumerator = ProjectRootManager.getInstance(project).orderEntries();
    ContainerUtil.addAll(roots, enumerator.getClassesRoots());
    ContainerUtil.addAll(roots, enumerator.getSourceRoots());

    insideGettingRoots = false;
    return VfsUtilCore.toVirtualFileArray(roots);
  }

  @Nullable
  private VirtualFileSystemEntry createAndFindChildWithEventFire(
      @NotNull String name, @NotNull NewVirtualFileSystem delegate) {
    final VirtualFile fake = new FakeVirtualFile(this, name);
    final FileAttributes attributes = delegate.getAttributes(fake);
    if (attributes == null) return null;
    final String realName = delegate.getCanonicallyCasedName(fake);
    final VFileCreateEvent event =
        new VFileCreateEvent(null, this, realName, attributes.isDirectory(), true);
    RefreshQueue.getInstance().processSingleEvent(event);
    return findChild(realName);
  }

  @Override
  @Nullable
  public NewVirtualFile refreshAndFindChild(@NotNull String name) {
    return findChild(name, true, true, getFileSystem());
  }

  private static int findIndexInOneHalf(
      final VirtualFileSystemEntry[] array,
      int start,
      int end,
      final boolean isAdopted,
      @NotNull final Comparator comparator) {
    return binSearch(
        array,
        start,
        end,
        new Comparator() {
          @Override
          public int compareMyKeyTo(@NotNull VirtualFileSystemEntry file) {
            if (isAdopted && !isAdoptedChild(file)) return 1;
            if (!isAdopted && isAdoptedChild(file)) return -1;
            return comparator.compareMyKeyTo(file);
          }
        });
  }

  // returns two int indices packed into one long. left index is for the real file array half, right
  // is for the adopted children name array
  private static long findIndexInBoth(
      @NotNull VirtualFileSystemEntry[] array, @NotNull Comparator comparator) {
    int high = array.length - 1;
    if (high == -1) {
      return pack(-1, -1);
    }
    int low = 0;
    boolean startInAdopted = isAdoptedChild(array[low]);
    boolean endInAdopted = isAdoptedChild(array[high]);
    if (startInAdopted == endInAdopted) {
      int index = findIndexInOneHalf(array, low, high + 1, startInAdopted, comparator);
      int otherIndex = startInAdopted ? -1 : -array.length - 1;
      return startInAdopted ? pack(otherIndex, index) : pack(index, otherIndex);
    }
    boolean adopted = false;
    int cmp = -1;
    int mid = -1;
    int foundIndex = -1;
    while (low <= high) {
      mid = low + high >>> 1;
      VirtualFileSystemEntry file = array[mid];
      cmp = comparator.compareMyKeyTo(file);
      adopted = isAdoptedChild(file);
      if (cmp == 0) {
        foundIndex = mid;
        break;
      }
      if ((adopted || cmp <= 0) && (!adopted || cmp >= 0)) {
        int indexInAdopted = findIndexInOneHalf(array, mid + 1, high + 1, true, comparator);
        int indexInReal = findIndexInOneHalf(array, low, mid, false, comparator);
        return pack(indexInReal, indexInAdopted);
      }

      if (cmp > 0) {
        low = mid + 1;
      } else {
        high = mid - 1;
      }
    }

    // key not found.
    if (cmp != 0) foundIndex = -low - 1;
    int newStart = adopted ? low : mid + 1;
    int newEnd = adopted ? mid + 1 : high + 1;
    int theOtherHalfIndex =
        newStart < newEnd
            ? findIndexInOneHalf(array, newStart, newEnd, !adopted, comparator)
            : -newStart - 1;
    return adopted ? pack(theOtherHalfIndex, foundIndex) : pack(foundIndex, theOtherHalfIndex);
  }

  private static long pack(int indexInReal, int indexInAdopted) {
    return (long) indexInReal << 32 | (indexInAdopted & 0xffffffffL);
  }

  @Override
  @Nullable
  public synchronized NewVirtualFile findChildIfCached(@NotNull String name) {
    final boolean ignoreCase = !getFileSystem().isCaseSensitive();
    Comparator comparator = getComparator(name, ignoreCase);
    VirtualFileSystemEntry found = doFindChildInArray(comparator);
    return found == NULL_VIRTUAL_FILE ? null : found;
  }

  @Override
  @NotNull
  public Iterable<VirtualFile> iterInDbChildren() {
    if (!ourPersistence.wereChildrenAccessed(this)) {
      return Collections.emptyList();
    }

    if (!ourPersistence.areChildrenLoaded(this)) {
      final String[] names = ourPersistence.listPersisted(this);
      final NewVirtualFileSystem delegate = PersistentFS.replaceWithNativeFS(getFileSystem());
      for (String name : names) {
        findChild(name, false, false, delegate);
      }
    }
    return getCachedChildren();
  }

  @Override
  @NotNull
  public synchronized VirtualFile[] getChildren() {
    VirtualFileSystemEntry[] children = myChildren;
    NewVirtualFileSystem delegate = getFileSystem();
    final boolean ignoreCase = !delegate.isCaseSensitive();
    if (allChildrenLoaded()) {
      assertConsistency(children, ignoreCase);
      return children;
    }

    final FSRecords.NameId[] childrenIds = ourPersistence.listAll(this);
    VirtualFileSystemEntry[] result;
    if (childrenIds.length == 0) {
      result = EMPTY_ARRAY;
    } else {
      Arrays.sort(
          childrenIds,
          new java.util.Comparator<FSRecords.NameId>() {
            @Override
            public int compare(FSRecords.NameId o1, FSRecords.NameId o2) {
              String name1 = o1.name;
              String name2 = o2.name;
              int cmp = compareNames(name1, name2, ignoreCase);
              if (cmp == 0 && name1 != name2) {
                LOG.error(
                    ourPersistence
                        + " returned duplicate file names("
                        + name1
                        + ","
                        + name2
                        + ")"
                        + " ignoreCase: "
                        + ignoreCase
                        + " SystemInfo.isFileSystemCaseSensitive: "
                        + SystemInfo.isFileSystemCaseSensitive
                        + " SystemInfo.OS: "
                        + SystemInfo.OS_NAME
                        + " "
                        + SystemInfo.OS_VERSION
                        + " in the dir: "
                        + VirtualDirectoryImpl.this
                        + ";"
                        + " children: "
                        + Arrays.toString(childrenIds));
              }
              return cmp;
            }
          });
      result = new VirtualFileSystemEntry[childrenIds.length];
      int delegateI = 0;
      int i = 0;

      int cachedEnd = getAdoptedChildrenStart();
      // merge (sorted) children[0..cachedEnd) and childrenIds into the result array.
      // file that is already in children array must be copied into the result as is
      // for the file name that is new in childrenIds the file must be created and copied into
      // result
      while (delegateI < childrenIds.length) {
        FSRecords.NameId nameId = childrenIds[delegateI];
        while (i < cachedEnd && children[i].compareNameTo(nameId.name, ignoreCase) < 0)
          i++; // skip files that are not in childrenIds

        VirtualFileSystemEntry resultFile;
        if (i < cachedEnd && children[i].compareNameTo(nameId.name, ignoreCase) == 0) {
          resultFile = children[i++];
        } else {
          resultFile = createChild(nameId.name, nameId.id, delegate);
        }
        result[delegateI++] = resultFile;
      }

      assertConsistency(result, ignoreCase, children, cachedEnd, childrenIds);
    }

    if (getId() > 0) {
      myChildren = result;
      setChildrenLoaded();
    }

    return result;
  }

  private void assertConsistency(
      @NotNull VirtualFileSystemEntry[] array, boolean ignoreCase, @NotNull Object... details) {
    if (!CHECK) return;
    boolean allChildrenLoaded = allChildrenLoaded();
    for (int i = 0; i < array.length; i++) {
      VirtualFileSystemEntry file = array[i];
      boolean isAdopted = isAdoptedChild(file);
      assert !isAdopted || !allChildrenLoaded;
      if (isAdopted && i != array.length - 1) {
        assert isAdoptedChild(array[i + 1]);
      }
      if (i != 0) {
        VirtualFileSystemEntry prev = array[i - 1];
        String prevName = prev.getName();
        int cmp = file.compareNameTo(prevName, ignoreCase);
        if (cmp == 0) {
          Function<VirtualFileSystemEntry, String> verboseToString =
              new Function<VirtualFileSystemEntry, String>() {
                @Override
                public String fun(VirtualFileSystemEntry entry) {
                  return entry
                      + " (name: '"
                      + entry.getName()
                      + "', "
                      + entry.getClass()
                      + ", parent:"
                      + entry.getParent()
                      + "; id:"
                      + entry.getId()
                      + "; FS:"
                      + entry.getFileSystem()
                      + "; delegate.attrs:"
                      + entry.getFileSystem().getAttributes(entry)
                      + "; caseSensitive:"
                      + entry.getFileSystem().isCaseSensitive()
                      + "; canonical:"
                      + entry.getFileSystem().getCanonicallyCasedName(entry)
                      + ") ";
                }
              };
          String children = StringUtil.join(array, verboseToString, ",");
          throw new AssertionError(
              verboseToString.fun(prev)
                  + " equals to "
                  + verboseToString.fun(file)
                  + "; children: "
                  + children
                  + "\nDetails: "
                  + ContainerUtil.map(
                      details,
                      new Function<Object, Object>() {
                        @Override
                        public Object fun(Object o) {
                          return o instanceof Object[] ? Arrays.toString((Object[]) o) : o;
                        }
                      }));
        }

        if (isAdopted == isAdoptedChild(prev)) {
          assert cmp > 0 : "Not sorted. " + Arrays.toString(details);
        }
      }
    }
  }

  @Override
  @Nullable
  public VirtualFileSystemEntry findChild(@NotNull final String name) {
    return findChild(name, false, true, getFileSystem());
  }

  public VirtualFileSystemEntry findChildById(int id, boolean cachedOnly) {
    VirtualFile[] array = getArraySafely();
    VirtualFileSystemEntry result = null;
    for (VirtualFile file : array) {
      VirtualFileSystemEntry withId = (VirtualFileSystemEntry) file;
      if (withId.getId() == id) {
        result = withId;
        break;
      }
    }
    if (result != null) return result;
    if (cachedOnly) return null;

    String name = ourPersistence.getName(id);
    return findChild(name, false, false, getFileSystem());
  }

  @NotNull
  @Override
  public byte[] contentsToByteArray() throws IOException {
    throw new IOException("Cannot get content of directory: " + this);
  }

  public synchronized void addChild(@NotNull VirtualFileSystemEntry child) {
    VirtualFileSystemEntry[] array = myChildren;
    final String childName = child.getName();
    final boolean ignoreCase = !getFileSystem().isCaseSensitive();
    long r = findIndexInBoth(array, getComparator(childName, ignoreCase));
    int indexInReal = (int) (r >> 32);
    int indexInAdopted = (int) r;

    if (indexInAdopted >= 0) {
      // remove Adopted first
      removeFromArray(indexInAdopted);
    }
    if (indexInReal < 0) {
      insertChildAt(child, indexInReal);
    }
    // else already stored
    assertConsistency(myChildren, ignoreCase, child);
  }

  private void insertChildAt(@NotNull VirtualFileSystemEntry file, int negativeIndex) {
    @NotNull VirtualFileSystemEntry[] array = myChildren;
    VirtualFileSystemEntry[] appended = new VirtualFileSystemEntry[array.length + 1];
    int i = -negativeIndex - 1;
    System.arraycopy(array, 0, appended, 0, i);
    appended[i] = file;
    System.arraycopy(array, i, appended, i + 1, array.length - i);
    myChildren = appended;
  }

  public synchronized void removeChild(@NotNull VirtualFile file) {
    boolean ignoreCase = !getFileSystem().isCaseSensitive();
    String name = file.getName();

    addToAdoptedChildren(name, ignoreCase, getComparator(name, ignoreCase));
    assertConsistency(myChildren, ignoreCase, file);
  }

  private void removeFromArray(int index) {
    myChildren =
        ArrayUtil.remove(
            myChildren,
            index,
            new ArrayFactory<VirtualFileSystemEntry>() {
              @NotNull
              @Override
              public VirtualFileSystemEntry[] create(int count) {
                return new VirtualFileSystemEntry[count];
              }
            });
  }

  public boolean allChildrenLoaded() {
    return getFlagInt(CHILDREN_CACHED);
  }

  private void setChildrenLoaded() {
    setFlagInt(CHILDREN_CACHED, true);
  }

  @NotNull
  public synchronized List<String> getSuspiciousNames() {
    List<VirtualFile> suspicious =
        new SubList<VirtualFile>(myChildren, getAdoptedChildrenStart(), myChildren.length);
    return ContainerUtil.map2List(
        suspicious,
        new Function<VirtualFile, String>() {
          @Override
          public String fun(VirtualFile file) {
            return file.getName();
          }
        });
  }

  private int getAdoptedChildrenStart() {
    int index =
        binSearch(
            myChildren,
            0,
            myChildren.length,
            new Comparator() {
              @Override
              public int compareMyKeyTo(@NotNull VirtualFileSystemEntry v) {
                return isAdoptedChild(v) ? -1 : 1;
              }
            });
    return -index - 1;
  }

  private static boolean isAdoptedChild(@NotNull VirtualFileSystemEntry v) {
    return v.getParent() == NULL_VIRTUAL_FILE;
  }

  private interface Comparator {
    int compareMyKeyTo(@NotNull VirtualFileSystemEntry file);
  }

  private static int binSearch(
      @NotNull VirtualFileSystemEntry[] array, int start, int end, @NotNull Comparator comparator) {
    int low = start;
    int high = end - 1;
    assert low >= 0 && low <= array.length;

    while (low <= high) {
      int mid = low + high >>> 1;
      int cmp = comparator.compareMyKeyTo(array[mid]);
      if (cmp > 0) {
        low = mid + 1;
      } else if (cmp < 0) {
        high = mid - 1;
      } else {
        return mid; // key found
      }
    }
    return -(low + 1); // key not found.
  }

  @Override
  public boolean isDirectory() {
    return true;
  }

  @Override
  @NotNull
  public synchronized List<VirtualFile> getCachedChildren() {
    return new SubList<VirtualFile>(myChildren, 0, getAdoptedChildrenStart());
  }

  @Override
  public InputStream getInputStream() throws IOException {
    throw new IOException("getInputStream() must not be called against a directory: " + getUrl());
  }

  @Override
  @NotNull
  public OutputStream getOutputStream(
      final Object requestor, final long newModificationStamp, final long newTimeStamp)
      throws IOException {
    throw new IOException("getOutputStream() must not be called against a directory: " + getUrl());
  }

  @Override
  public void markDirtyRecursively() {
    markDirty();
    markDirtyRecursivelyInternal();
  }

  // optimisation: do not travel up unnecessary
  private void markDirtyRecursivelyInternal() {
    for (VirtualFileSystemEntry child : getArraySafely()) {
      if (isAdoptedChild(child)) break;
      child.markDirtyInternal();
      if (child instanceof VirtualDirectoryImpl) {
        ((VirtualDirectoryImpl) child).markDirtyRecursivelyInternal();
      }
    }
  }
}
Ejemplo n.º 9
0
/** @author peter */
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public abstract class UsefulTestCase extends TestCase {
  public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;

  public static final String IDEA_MARKER_CLASS =
      "com.intellij.openapi.components.impl.stores.IdeaProjectStoreImpl";
  public static final String TEMP_DIR_MARKER = "unitTest_";

  protected static boolean OVERWRITE_TESTDATA = false;

  private static final String DEFAULT_SETTINGS_EXTERNALIZED;
  private static final Random RNG = new SecureRandom();
  private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();

  protected final Disposable myTestRootDisposable =
      new Disposable() {
        @Override
        public void dispose() {}

        @Override
        public String toString() {
          String testName = getTestName(false);
          return UsefulTestCase.this.getClass()
              + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
        }
      };

  protected static String ourPathToKeep = null;

  private CodeStyleSettings myOldCodeStyleSettings;
  private String myTempDir;

  protected static final Key<String> CREATION_PLACE = Key.create("CREATION_PLACE");

  static {
    // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
    System.setProperty("apple.awt.UIElement", "true");

    try {
      CodeInsightSettings defaultSettings = new CodeInsightSettings();
      Element oldS = new Element("temp");
      defaultSettings.writeExternal(oldS);
      DEFAULT_SETTINGS_EXTERNALIZED = JDOMUtil.writeElement(oldS, "\n");
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  protected boolean shouldContainTempFiles() {
    return true;
  }

  @Override
  protected void setUp() throws Exception {
    super.setUp();

    if (shouldContainTempFiles()) {
      String testName = getTestName(true);
      if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
      testName = new File(testName).getName(); // in case the test name contains file separators
      myTempDir =
          FileUtil.toSystemDependentName(
              ORIGINAL_TEMP_DIR + "/" + TEMP_DIR_MARKER + testName + "_" + RNG.nextInt(1000));
      FileUtil.resetCanonicalTempPathCache(myTempDir);
    }
    //noinspection AssignmentToStaticFieldFromInstanceMethod
    DocumentImpl.CHECK_DOCUMENT_CONSISTENCY = !isPerformanceTest();
  }

  @Override
  protected void tearDown() throws Exception {
    try {
      Disposer.dispose(myTestRootDisposable);
      cleanupSwingDataStructures();
      cleanupDeleteOnExitHookList();
    } finally {
      if (shouldContainTempFiles()) {
        FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
        if (ourPathToKeep != null && FileUtil.isAncestor(myTempDir, ourPathToKeep, false)) {
          File[] files = new File(myTempDir).listFiles();
          if (files != null) {
            for (File file : files) {
              if (!FileUtil.pathsEqual(file.getPath(), ourPathToKeep)) {
                FileUtil.delete(file);
              }
            }
          }
        } else {
          FileUtil.delete(new File(myTempDir));
        }
      }
    }

    UIUtil.removeLeakingAppleListeners();
    super.tearDown();
  }

  private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
  private static final Class DELETE_ON_EXIT_HOOK_CLASS;

  static {
    Class<?> aClass = null;
    Set<String> files = null;
    try {
      aClass = Class.forName("java.io.DeleteOnExitHook");
      files = ReflectionUtil.getField(aClass, null, Set.class, "files");
    } catch (Exception ignored) {
    }
    DELETE_ON_EXIT_HOOK_CLASS = aClass;
    DELETE_ON_EXIT_HOOK_DOT_FILES = files;
  }

  public static void cleanupDeleteOnExitHookList()
      throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
    // try to reduce file set retained by java.io.DeleteOnExitHook
    List<String> list;
    synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
      if (DELETE_ON_EXIT_HOOK_DOT_FILES.isEmpty()) return;
      list = new ArrayList<String>(DELETE_ON_EXIT_HOOK_DOT_FILES);
    }
    for (int i = list.size() - 1; i >= 0; i--) {
      String path = list.get(i);
      if (FileSystemUtil.getAttributes(path) == null || new File(path).delete()) {
        synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
          DELETE_ON_EXIT_HOOK_DOT_FILES.remove(path);
        }
      }
    }
  }

  private static void cleanupSwingDataStructures() throws Exception {
    Class<?> aClass = Class.forName("javax.swing.KeyboardManager");

    Method get = aClass.getMethod("getCurrentManager");
    get.setAccessible(true);
    Object manager = get.invoke(null);
    {
      Field mapF = aClass.getDeclaredField("componentKeyStrokeMap");
      mapF.setAccessible(true);
      Object map = mapF.get(manager);
      ((Map) map).clear();
    }
    {
      Field mapF = aClass.getDeclaredField("containerMap");
      mapF.setAccessible(true);
      Object map = mapF.get(manager);
      ((Map) map).clear();
    }
  }

  protected CompositeException checkForSettingsDamage() throws Exception {
    Application app = ApplicationManager.getApplication();
    if (isPerformanceTest() || app == null || app instanceof MockApplication) {
      return new CompositeException();
    }

    CodeStyleSettings oldCodeStyleSettings = myOldCodeStyleSettings;
    myOldCodeStyleSettings = null;

    return doCheckForSettingsDamage(oldCodeStyleSettings, getCurrentCodeStyleSettings());
  }

  public static CompositeException doCheckForSettingsDamage(
      @NotNull CodeStyleSettings oldCodeStyleSettings,
      @NotNull CodeStyleSettings currentCodeStyleSettings)
      throws Exception {
    CompositeException result = new CompositeException();
    final CodeInsightSettings settings = CodeInsightSettings.getInstance();
    try {
      Element newS = new Element("temp");
      settings.writeExternal(newS);
      Assert.assertEquals(
          "Code insight settings damaged",
          DEFAULT_SETTINGS_EXTERNALIZED,
          JDOMUtil.writeElement(newS, "\n"));
    } catch (AssertionError error) {
      CodeInsightSettings clean = new CodeInsightSettings();
      Element temp = new Element("temp");
      clean.writeExternal(temp);
      settings.loadState(temp);
      result.add(error);
    }

    currentCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA);
    try {
      checkSettingsEqual(
          oldCodeStyleSettings, currentCodeStyleSettings, "Code style settings damaged");
    } catch (AssertionError e) {
      result.add(e);
    } finally {
      currentCodeStyleSettings.clearCodeStyleSettings();
    }

    try {
      InplaceRefactoring.checkCleared();
    } catch (AssertionError e) {
      result.add(e);
    }
    try {
      StartMarkAction.checkCleared();
    } catch (AssertionError e) {
      result.add(e);
    }

    return result;
  }

  protected void storeSettings() {
    if (!isPerformanceTest() && ApplicationManager.getApplication() != null) {
      myOldCodeStyleSettings = getCurrentCodeStyleSettings().clone();
      myOldCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA);
    }
  }

  protected CodeStyleSettings getCurrentCodeStyleSettings() {
    if (CodeStyleSchemes.getInstance().getCurrentScheme() == null) return new CodeStyleSettings();
    return CodeStyleSettingsManager.getInstance().getCurrentSettings();
  }

  public Disposable getTestRootDisposable() {
    return myTestRootDisposable;
  }

  @Override
  protected void runTest() throws Throwable {
    final Throwable[] throwables = new Throwable[1];

    Runnable runnable =
        new Runnable() {
          @Override
          public void run() {
            try {
              UsefulTestCase.super.runTest();
            } catch (InvocationTargetException e) {
              e.fillInStackTrace();
              throwables[0] = e.getTargetException();
            } catch (IllegalAccessException e) {
              e.fillInStackTrace();
              throwables[0] = e;
            } catch (Throwable e) {
              throwables[0] = e;
            }
          }
        };

    invokeTestRunnable(runnable);

    if (throwables[0] != null) {
      throw throwables[0];
    }
  }

  protected boolean shouldRunTest() {
    return PlatformTestUtil.canRunTest(getClass());
  }

  public static void edt(Runnable r) {
    UIUtil.invokeAndWaitIfNeeded(r);
  }

  protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
    UIUtil.invokeAndWaitIfNeeded(runnable);
    // runnable.run();
  }

  protected void defaultRunBare() throws Throwable {
    super.runBare();
  }

  @Override
  public void runBare() throws Throwable {
    if (!shouldRunTest()) return;

    if (runInDispatchThread()) {
      final Throwable[] exception = {null};
      UIUtil.invokeAndWaitIfNeeded(
          new Runnable() {
            @Override
            public void run() {
              try {
                defaultRunBare();
              } catch (Throwable tearingDown) {
                if (exception[0] == null) exception[0] = tearingDown;
              }
            }
          });
      if (exception[0] != null) throw exception[0];
    } else {
      defaultRunBare();
    }
  }

  protected boolean runInDispatchThread() {
    return true;
  }

  @NonNls
  public static String toString(Iterable<?> collection) {
    if (!collection.iterator().hasNext()) {
      return "<empty>";
    }

    final StringBuilder builder = new StringBuilder();
    for (final Object o : collection) {
      if (o instanceof THashSet) {
        builder.append(new TreeSet<Object>((THashSet) o));
      } else {
        builder.append(o);
      }
      builder.append("\n");
    }
    return builder.toString();
  }

  public static <T> void assertOrderedEquals(T[] actual, T... expected) {
    assertOrderedEquals(Arrays.asList(actual), expected);
  }

  public static <T> void assertOrderedEquals(Iterable<T> actual, T... expected) {
    assertOrderedEquals(null, actual, expected);
  }

  public static void assertOrderedEquals(@NotNull byte[] actual, @NotNull byte[] expected) {
    assertEquals(actual.length, expected.length);
    for (int i = 0; i < actual.length; i++) {
      byte a = actual[i];
      byte e = expected[i];
      assertEquals("not equals at index: " + i, e, a);
    }
  }

  public static <T> void assertOrderedEquals(
      final String errorMsg, @NotNull Iterable<T> actual, @NotNull T... expected) {
    Assert.assertNotNull(actual);
    Assert.assertNotNull(expected);
    assertOrderedEquals(errorMsg, actual, Arrays.asList(expected));
  }

  public static <T> void assertOrderedEquals(
      final Iterable<? extends T> actual, final Collection<? extends T> expected) {
    assertOrderedEquals(null, actual, expected);
  }

  public static <T> void assertOrderedEquals(
      final String erroMsg,
      final Iterable<? extends T> actual,
      final Collection<? extends T> expected) {
    ArrayList<T> list = new ArrayList<T>();
    for (T t : actual) {
      list.add(t);
    }
    if (!list.equals(new ArrayList<T>(expected))) {
      String expectedString = toString(expected);
      String actualString = toString(actual);
      Assert.assertEquals(erroMsg, expectedString, actualString);
      Assert.fail(
          "Warning! 'toString' does not reflect the difference.\nExpected: "
              + expectedString
              + "\nActual: "
              + actualString);
    }
  }

  public static <T> void assertOrderedCollection(T[] collection, @NotNull Consumer<T>... checkers) {
    Assert.assertNotNull(collection);
    assertOrderedCollection(Arrays.asList(collection), checkers);
  }

  public static <T> void assertSameElements(T[] collection, T... expected) {
    assertSameElements(Arrays.asList(collection), expected);
  }

  public static <T> void assertSameElements(Collection<? extends T> collection, T... expected) {
    assertSameElements(collection, Arrays.asList(expected));
  }

  public static <T> void assertSameElements(
      Collection<? extends T> collection, Collection<T> expected) {
    assertSameElements(null, collection, expected);
  }

  public static <T> void assertSameElements(
      String message, Collection<? extends T> collection, Collection<T> expected) {
    assertNotNull(collection);
    assertNotNull(expected);
    if (collection.size() != expected.size()
        || !new HashSet<T>(expected).equals(new HashSet<T>(collection))) {
      Assert.assertEquals(message, toString(expected, "\n"), toString(collection, "\n"));
      Assert.assertEquals(message, new HashSet<T>(expected), new HashSet<T>(collection));
    }
  }

  public <T> void assertContainsOrdered(Collection<? extends T> collection, T... expected) {
    assertContainsOrdered(collection, Arrays.asList(expected));
  }

  public <T> void assertContainsOrdered(
      Collection<? extends T> collection, Collection<T> expected) {
    ArrayList<T> copy = new ArrayList<T>(collection);
    copy.retainAll(expected);
    assertOrderedEquals(toString(collection), copy, expected);
  }

  public <T> void assertContainsElements(Collection<? extends T> collection, T... expected) {
    assertContainsElements(collection, Arrays.asList(expected));
  }

  public <T> void assertContainsElements(
      Collection<? extends T> collection, Collection<T> expected) {
    ArrayList<T> copy = new ArrayList<T>(collection);
    copy.retainAll(expected);
    assertSameElements(toString(collection), copy, expected);
  }

  public static String toString(Object[] collection, String separator) {
    return toString(Arrays.asList(collection), separator);
  }

  public <T> void assertDoesntContain(Collection<? extends T> collection, T... notExpected) {
    assertDoesntContain(collection, Arrays.asList(notExpected));
  }

  public <T> void assertDoesntContain(
      Collection<? extends T> collection, Collection<T> notExpected) {
    ArrayList<T> expected = new ArrayList<T>(collection);
    expected.removeAll(notExpected);
    assertSameElements(collection, expected);
  }

  public static String toString(Collection<?> collection, String separator) {
    List<String> list =
        ContainerUtil.map2List(
            collection,
            new Function<Object, String>() {
              @Override
              public String fun(final Object o) {
                return String.valueOf(o);
              }
            });
    Collections.sort(list);
    StringBuilder builder = new StringBuilder();
    boolean flag = false;
    for (final String o : list) {
      if (flag) {
        builder.append(separator);
      }
      builder.append(o);
      flag = true;
    }
    return builder.toString();
  }

  public static <T> void assertOrderedCollection(
      Collection<? extends T> collection, Consumer<T>... checkers) {
    Assert.assertNotNull(collection);
    if (collection.size() != checkers.length) {
      Assert.fail(toString(collection));
    }
    int i = 0;
    for (final T actual : collection) {
      try {
        checkers[i].consume(actual);
      } catch (AssertionFailedError e) {
        System.out.println(i + ": " + actual);
        throw e;
      }
      i++;
    }
  }

  public static <T> void assertUnorderedCollection(T[] collection, Consumer<T>... checkers) {
    assertUnorderedCollection(Arrays.asList(collection), checkers);
  }

  public static <T> void assertUnorderedCollection(
      Collection<? extends T> collection, Consumer<T>... checkers) {
    Assert.assertNotNull(collection);
    if (collection.size() != checkers.length) {
      Assert.fail(toString(collection));
    }
    Set<Consumer<T>> checkerSet = new HashSet<Consumer<T>>(Arrays.asList(checkers));
    int i = 0;
    Throwable lastError = null;
    for (final T actual : collection) {
      boolean flag = true;
      for (final Consumer<T> condition : checkerSet) {
        Throwable error = accepts(condition, actual);
        if (error == null) {
          checkerSet.remove(condition);
          flag = false;
          break;
        } else {
          lastError = error;
        }
      }
      if (flag) {
        lastError.printStackTrace();
        Assert.fail("Incorrect element(" + i + "): " + actual);
      }
      i++;
    }
  }

  private static <T> Throwable accepts(final Consumer<T> condition, final T actual) {
    try {
      condition.consume(actual);
      return null;
    } catch (Throwable e) {
      return e;
    }
  }

  public static <T> T assertInstanceOf(Object o, Class<T> aClass) {
    Assert.assertNotNull("Expected instance of: " + aClass.getName() + " actual: " + null, o);
    Assert.assertTrue(
        "Expected instance of: " + aClass.getName() + " actual: " + o.getClass().getName(),
        aClass.isInstance(o));
    @SuppressWarnings("unchecked")
    T t = (T) o;
    return t;
  }

  public static <T> T assertOneElement(Collection<T> collection) {
    Assert.assertNotNull(collection);
    Assert.assertEquals(toString(collection), 1, collection.size());
    return collection.iterator().next();
  }

  public static <T> T assertOneElement(T[] ts) {
    Assert.assertNotNull(ts);
    Assert.assertEquals(Arrays.asList(ts).toString(), 1, ts.length);
    return ts[0];
  }

  public static <T> void assertOneOf(T value, T... values) {
    boolean found = false;
    for (T v : values) {
      if (value == v || value != null && value.equals(v)) {
        found = true;
      }
    }
    Assert.assertTrue(value + " should be equal to one of " + Arrays.toString(values), found);
  }

  public static void printThreadDump() {
    PerformanceWatcher.dumpThreadsToConsole("Thread dump:");
  }

  public static void assertEmpty(final Object[] array) {
    assertOrderedEquals(array);
  }

  public static void assertNotEmpty(final Collection<?> collection) {
    if (collection == null) return;
    assertTrue(!collection.isEmpty());
  }

  public static void assertEmpty(final Collection<?> collection) {
    assertEmpty(collection.toString(), collection);
  }

  public static void assertNullOrEmpty(final Collection<?> collection) {
    if (collection == null) return;
    assertEmpty(null, collection);
  }

  public static void assertEmpty(final String s) {
    assertTrue(s, StringUtil.isEmpty(s));
  }

  public static <T> void assertEmpty(final String errorMsg, final Collection<T> collection) {
    assertOrderedEquals(errorMsg, collection);
  }

  public static void assertSize(int expectedSize, final Object[] array) {
    assertEquals(toString(Arrays.asList(array)), expectedSize, array.length);
  }

  public static void assertSize(int expectedSize, final Collection<?> c) {
    assertEquals(toString(c), expectedSize, c.size());
  }

  protected <T extends Disposable> T disposeOnTearDown(final T disposable) {
    Disposer.register(myTestRootDisposable, disposable);
    return disposable;
  }

  public static void assertSameLines(String expected, String actual) {
    String expectedText = StringUtil.convertLineSeparators(expected.trim());
    String actualText = StringUtil.convertLineSeparators(actual.trim());
    Assert.assertEquals(expectedText, actualText);
  }

  public static void assertExists(File file) {
    assertTrue("File should exist " + file, file.exists());
  }

  public static void assertDoesntExist(File file) {
    assertFalse("File should not exist " + file, file.exists());
  }

  protected String getTestName(boolean lowercaseFirstLetter) {
    String name = getName();
    return getTestName(name, lowercaseFirstLetter);
  }

  public static String getTestName(String name, boolean lowercaseFirstLetter) {
    if (name == null) {
      return "";
    }
    name = StringUtil.trimStart(name, "test");
    if (StringUtil.isEmpty(name)) {
      return "";
    }
    return lowercaseFirstLetter(name, lowercaseFirstLetter);
  }

  public static String lowercaseFirstLetter(String name, boolean lowercaseFirstLetter) {
    if (lowercaseFirstLetter && !isAllUppercaseName(name)) {
      name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
    }
    return name;
  }

  public static boolean isAllUppercaseName(String name) {
    int uppercaseChars = 0;
    for (int i = 0; i < name.length(); i++) {
      if (Character.isLowerCase(name.charAt(i))) {
        return false;
      }
      if (Character.isUpperCase(name.charAt(i))) {
        uppercaseChars++;
      }
    }
    return uppercaseChars >= 3;
  }

  protected String getTestDirectoryName() {
    final String testName = getTestName(true);
    return testName.replaceAll("_.*", "");
  }

  protected static void assertSameLinesWithFile(String filePath, String actualText) {
    String fileText;
    try {
      if (OVERWRITE_TESTDATA) {
        VfsTestUtil.overwriteTestData(filePath, actualText);
        System.out.println("File " + filePath + " created.");
      }
      fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8);
    } catch (FileNotFoundException e) {
      VfsTestUtil.overwriteTestData(filePath, actualText);
      throw new AssertionFailedError("No output text found. File " + filePath + " created.");
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    String expected = StringUtil.convertLineSeparators(fileText.trim());
    String actual = StringUtil.convertLineSeparators(actualText.trim());
    if (!Comparing.equal(expected, actual)) {
      throw new FileComparisonFailure(null, expected, actual, filePath);
    }
  }

  public static void clearFields(final Object test) throws IllegalAccessException {
    Class aClass = test.getClass();
    while (aClass != null) {
      clearDeclaredFields(test, aClass);
      aClass = aClass.getSuperclass();
    }
  }

  public static void clearDeclaredFields(Object test, Class aClass) throws IllegalAccessException {
    if (aClass == null) return;
    for (final Field field : aClass.getDeclaredFields()) {
      @NonNls final String name = field.getDeclaringClass().getName();
      if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
        final int modifiers = field.getModifiers();
        if ((modifiers & Modifier.FINAL) == 0
            && (modifiers & Modifier.STATIC) == 0
            && !field.getType().isPrimitive()) {
          field.setAccessible(true);
          field.set(test, null);
        }
      }
    }
  }

  @SuppressWarnings("deprecation")
  protected static void checkSettingsEqual(
      JDOMExternalizable expected, JDOMExternalizable settings, String message) throws Exception {
    if (expected == null || settings == null) return;

    Element oldS = new Element("temp");
    expected.writeExternal(oldS);
    Element newS = new Element("temp");
    settings.writeExternal(newS);

    String newString = JDOMUtil.writeElement(newS, "\n");
    String oldString = JDOMUtil.writeElement(oldS, "\n");
    Assert.assertEquals(message, oldString, newString);
  }

  public boolean isPerformanceTest() {
    String name = getName();
    return name != null && name.contains("Performance")
        || getClass().getName().contains("Performance");
  }

  public static void doPostponedFormatting(final Project project) {
    DocumentUtil.writeInRunUndoTransparentAction(
        new Runnable() {
          @Override
          public void run() {
            PsiDocumentManager.getInstance(project).commitAllDocuments();
            PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();
          }
        });
  }

  protected static void checkAllTimersAreDisposed() {
    try {
      Class<?> aClass = Class.forName("javax.swing.TimerQueue");

      Method inst = aClass.getDeclaredMethod("sharedInstance");
      inst.setAccessible(true);
      Object queue = inst.invoke(null);
      Field field = aClass.getDeclaredField("firstTimer");
      field.setAccessible(true);
      Object firstTimer = field.get(queue);
      if (firstTimer != null) {
        try {
          fail("Not disposed Timer: " + firstTimer.toString() + "; queue:" + queue);
        } finally {
          field.set(queue, null);
        }
      }
    } catch (Throwable e) {
      // Ignore
    }
  }

  /**
   * Checks that code block throw corresponding exception.
   *
   * @param exceptionCase Block annotated with some exception type
   * @throws Throwable
   */
  protected void assertException(final AbstractExceptionCase exceptionCase) throws Throwable {
    assertException(exceptionCase, null);
  }

  /**
   * Checks that code block throw corresponding exception with expected error msg. If expected error
   * message is null it will not be checked.
   *
   * @param exceptionCase Block annotated with some exception type
   * @param expectedErrorMsg expected error messge
   * @throws Throwable
   */
  protected void assertException(
      final AbstractExceptionCase exceptionCase, @Nullable final String expectedErrorMsg)
      throws Throwable {
    assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
  }

  /**
   * Checks that code block doesn't throw corresponding exception.
   *
   * @param exceptionCase Block annotated with some exception type
   * @throws Throwable
   */
  protected void assertNoException(final AbstractExceptionCase exceptionCase) throws Throwable {
    assertExceptionOccurred(false, exceptionCase, null);
  }

  protected void assertNoThrowable(final Runnable closure) {
    String throwableName = null;
    try {
      closure.run();
    } catch (Throwable thr) {
      throwableName = thr.getClass().getName();
    }
    assertNull(throwableName);
  }

  private static void assertExceptionOccurred(
      boolean shouldOccur, AbstractExceptionCase exceptionCase, String expectedErrorMsg)
      throws Throwable {
    boolean wasThrown = false;
    try {
      exceptionCase.tryClosure();
    } catch (Throwable 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());
        }
      } else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
        wasThrown = true;

        System.out.println("");
        e.printStackTrace(System.out);

        fail("Exception isn't expected here. Exception message: " + e.getMessage());
      } else {
        throw e;
      }
    } finally {
      if (shouldOccur && !wasThrown) {
        fail(exceptionCase.getAssertionErrorMessage());
      }
    }
  }

  protected boolean annotatedWith(@NotNull Class annotationClass) {
    Class<?> aClass = getClass();
    String methodName = "test" + getTestName(false);
    boolean methodChecked = false;
    while (aClass != null && aClass != Object.class) {
      if (aClass.getAnnotation(annotationClass) != null) return true;
      if (!methodChecked) {
        try {
          Method method = aClass.getDeclaredMethod(methodName);
          if (method.getAnnotation(annotationClass) != null) return true;
          methodChecked = true;
        } catch (NoSuchMethodException ignored) {
        }
      }
      aClass = aClass.getSuperclass();
    }
    return false;
  }

  protected String getHomePath() {
    return PathManager.getHomePath().replace(File.separatorChar, '/');
  }

  protected static boolean isInHeadlessEnvironment() {
    return GraphicsEnvironment.isHeadless();
  }

  public static void refreshRecursively(@NotNull VirtualFile file) {
    VfsUtilCore.visitChildrenRecursively(
        file,
        new VirtualFileVisitor() {
          @Override
          public boolean visitFile(@NotNull VirtualFile file) {
            file.getChildren();
            return true;
          }
        });
    file.refresh(false, true);
  }

  @NotNull
  public static Test filteredSuite(@RegExp String regexp, @NotNull Test test) {
    final Pattern pattern = Pattern.compile(regexp);
    final TestSuite testSuite = new TestSuite();
    new Processor<Test>() {

      @Override
      public boolean process(Test test) {
        if (test instanceof TestSuite) {
          for (int i = 0, len = ((TestSuite) test).testCount(); i < len; i++) {
            process(((TestSuite) test).testAt(i));
          }
        } else if (pattern.matcher(test.toString()).find()) {
          testSuite.addTest(test);
        }
        return false;
      }
    }.process(test);
    return testSuite;
  }
}